Usually when someone wants a custom contact form on their Drupal website the easiest solution is to use the webform module, however if you don't need to store submissions on your site, and you're only looking to add one or two fields, adding fields with a form_alter might be a better option for you.
This would probably be especially true if you had no other reason to install the webform module on your site.
First thing you're going to need is a custom module. Most sites built should have one of these anyway for all the extra 'glue code' that just doesn't really fit anywhere else. Basic things like form alter hooks to hide or change a field, cron hooks to perform some basic extra task on cron run, etc.. these are things that would constitute 'glue code'. All the custom stuff necessary for your specific site, that is required for it to function properly, but not complex enough to warrant its own standalone module.
With that in mind, the code examples that follow will use the name mysite_glue. When I build sites, this is how I generally name my glue code modules. For example on a site called foo, I would have a module called foo_glue. So for our purposes here, we'll assume your site has a glue code module named mysite_glue, and we're just going to add a couple extra functions to it. Ready? Let's jump in!
Suppose that your site needs to collect a phone number on the contact form, that's a pretty common request. First we need the normal Drupal core contact module enabled, so if it's not yet do so now.
Next, we'll need to add a form alter hook to our glue code module. Since we know the form_id (well, I do anyway, so you're about to), we can use hook_form_FORM_ID_alter(), which will only ever fire when that specific form is being built, rather than the more generic hook_form_alter() that fires when every form is built.
Ok, lets add a required text field to collect the phone number to our contact form.
/**
* Implements hook_form_FORM_ID_alter().
*/
function mysite_glue_form_contact_site_form_alter(&$form, &$form_state) {
// Add a required textfield to collect
// users phone number to the form array.
$form['phone'] = array(
'#title' => t('Phone'),
'#type' => 'textfield',
'#required' => TRUE,
);
// Re-sort the form so that we can ensure our phone number field appears
// in the right spot. We're going to do this by building an array of the
// form field keys, then looping through each and setting their weight.
//
// Default fields on the contact form are:
// name (Users Name)
// mail (Users Email Address)
// subject (Email Subject)
// cid (Category select list,
// only visible if multiple contact categories are defined)
// message (Message textarea)
// copy ('Send me a copy' checkbox)
// submit (Submit button)
$order = array(
'name',
'mail',
'phone',
'subject',
'cid',
'message',
'copy',
'submit'
);
foreach ($order as $key => $field) {
// Set/Reset the field's
// weight to the array key value
// from our order array.
$form[$field]['#weight'] = $key;
}
}
Now save your module file, clear cache, and check out your contact form. You should now see a shiny new required phone number field there. Exciting right? Not too difficult either.
All of those comments of course are for your benefit, and totally unnecessary for the code to work, so without comments we're really looking at about maybe 10 lines of code for it to remain nice and readable? Not too shabby since at least half of that is the function declaration and sorting piece of it.
If you submit the form though, you'll find that your extra field isn't being included in the email. Bummer. Since the contact form doesn't store submissions on the site, that data is gone forever, so we need to be sure it comes through in the email too. Luckily, that's pretty easily accomplished as well since drupal provides us with a hook to alter emails before they're sent.
Lets add that now.
/**
* Implements hook_mail_alter().
*/
function mysite_glue_mail_alter(&$message) {
// We only want to alter the email if it's being
// generated by the site-wide contact form page.
if ($message['id'] == 'contact_page_mail') {
$message['body'][] = t('Phone') .': '. $message['params']['phone'];
}
}
Do you see what we did there? $message['body'] is an array, so we just tacked on another item to the end of that array with the $message['body'][] = ...
As it happens, all of the fields from submission of the contact form get passed into the mail function within the 'params' key of the $message array. This means whatever we add in our previous hook_form_FORM_ID_alter(), can be added to the email body just like we did here for the phone number by accessing $message['params']['<FORM_ARRAY_KEY>']. Of course, if it were a field that isn't required, it might not be present, so for non-required fields you'd want to wrap it in an if statement.
Something like this would be good for an optional field called Foo with a form array key of foo_bar:
if (isset($message['params']['foo_bar']) && $message['params']['foo_bar'] != '') {
$message['body'][] = t('Foo') .': '. $message['params']['foo_bar'];
}
See there? The if statement checks to be sure that array key is present, and that it's value isn't just an empty string, if both of those checks pass, it's added to the message body.
Easy, peasy.. right?