Creating a Form in a block in Drupal 7
Recently, I had to help a colleage create a form inside a block that would allow the visitor to email a friend a link to the site with a personal message attached. Knowing that my colleage was not a php coder at all (she's a front end developer), I gave her three options:
- Search for an existing contrib module that provided this functionality out of the box
- See if the Webform module could be put inside a block and trigger an action to send an email once submitted
- Create a custom module and use Drupal's Forms API to easily create the needed form
Since I'm a PHP developer at heart, I advised that creating a custom module would probably be the easiest way to get this functionality. I do believe that it would be possible to use Webform to do this but by the time we would have figured that out I could have solved this twice over using a custom module.
So here's how we can accomplish this using a custom module. If you're not a PHP developer don't fret; We won't write a ton of code. In fact, one of the things I love about Drupal 7 is that it's very easy to create forms. Here's a breakdown of what we'll do:
- Create the [modulename].info and [modulename].module files that will define our custom module
- Implement the hook_block_info() function that will create the block to hold our form
- Implement use drupal_get_form() to create a new form
- Define our form as a render array (don't worry, it's pretty straightforward) and return the form
- Create a form validation function to make sure the provided email address is valid
- Create a form submission handler that will handle emailing the page
- Implement hook_mail() to format the email to be sent.
And here's the code. I tried to heavily document every step of the way so hopefully it's clear.
Code for tellafriend.info (tells Drupal about our custom module):
- name = Tell A Friend
- description = Creates a form that will send an email to a friend with the url to this site.
- core = 7.x
- package = Custom
Code for tellafriend.module (defines our custom module):
- /**
- * Implements hook_block_info().
- *
- * This function tells drupal about our block.
- *
- * For more information on this function, see:
- * http://api.drupal.org/api/drupal/modules block block.api.php/function/hook_block_info/7
- */
- function tellafriend_block_info() {
- // Create an array that will hold our blocks
- $blocks = array();
- // Create a key in our $blocks array that
- // defines our block. Note that the key in
- // this array can be anything. For this
- // tutorial, we use 'tellafriend_form'.
- $blocks['tellafriend_form'] = array(
- // 'info' is what you will see when viewing the blocks admin page.
- // Note that we use the t() (translate) function which lets drupal
- // translate any text passed in if needed.
- 'info' => t('Tell-A-Friend'),
- // 'cache' how this block will be cached
- 'cache' => DRUPAL_CACHE_GLOBAL,
- );
- // Note, if you wanted to define multiple blocks, you
- // could simply define more blocks just like above.
- // Finally, we return the $blocks array.
- return $blocks;
- }
- /**
- * Implements hook_block_view().
- *
- * This function tells drupal how to define our block when viewed.
- *
- * For more information on this function, see:
- * http://api.drupal.org/api/drupal/modules block block.api.php/function/hook_block_view/7
- */
- function tellafriend_block_view($delta = '') {
- // Create an array that will be returned as our block
- $block = array();
- // Since hook_block_view is called for every block,
- // Drupal passes in $delta (the key of the blocks defined
- // in hook_block_info. In our case, we're checking for
- // $delta to be 'tellafriend_form'.
- switch($delta) {
- case 'tellafriend_form':
- // Since this $delta matches our case, we'll define
- // the subject and contents.
- // 'subject' can be blank ('') or anything you wish to define.
- $block['subject'] = t('Tell A Friend');
- // 'content' are just that, the contents of the block.
- // In our case, we will be showing a form.
- // We use drupal_get_form() to return a drupal-built form.
- // Note that the parameter passed to drupal_get_form is the name
- // of the function we will build below to define our form.
- // This can be any function name we define below.
- $block['content'] = drupal_get_form('tellafriend_form');
- break;
- }
- // Finally, we return the $block array.
- return $block;
- }
- /**
- * Define the form to be returned.
- *
- * Note that drupal passes in two parameters,
- * $form - which holds all of the elements of the form
- * $form_state - a special array of settings & values needed by Drupal
- */
- function tellafriend_form($form, &$form_state) {
- // Now the fun begins. For this simple example,
- // we will only provide two form elements.
- // 1. an input for the friend's email address
- // 2. a submit button
- // You can add as much or as little to this form as
- // needed. See the forms api for all possible elements.
- $form['friends_email'] = array(
- // #type tells drupal what kind of element to build
- '#type' => 'textfield',
- // we want this field to be required
- '#required' => TRUE,
- // The "label" for this field
- '#title' => t("Your friend's email address"),
- // Optional description
- '#description' => t('Must be a valid email address'),
- );
- $form['submit'] = array(
- '#type' => 'submit',
- // #value is the text to display inside the button
- '#value' => t('Submit'),
- );
- return $form;
- }
- /*
- * Define a validation function that drupal will
- * automatically call when the submit button is pressed.
- *
- * For this example, I will use the valid_email_address()
- * function to verify that the email address looks
- * proper. If it's not, we'll use form_set_error()
- * function to tell drupal we didn't pass validation.
- */
- function tellafriend_form_validate($form, &$form_state) {
- // Drupal stows away all of the form elements into
- // $form_state['values']. We find our 'friends_email'
- // element and assign it to a variable for easy
- // reference.
- $email = $form_state['values']['friends_email'];
- // If it's not a valid email, set an error.
- if(valid_email_address($email) == 0) {
- // form_set_error() tells drupal that it should not proceed.
- // The first parameter is the form element that didn't pass
- // validation. The second is the message to tell the user.
- form_set_error('friends_email', t('Not a valid email address'));
- }
- }
- /*
- * Define a submit funciton that drupal will
- * automatically call when submit is pressed (and all validators pass)
- */
- function tellafriend_form_submit($form, &$form_state) {
- // Get the email value again
- $email = $form_state['values']['friends_email'];
- // Now we call drupal_mail() to send a message to this person.
- // Note that this basically tells drupal to call tellafriend_mail().
- $message = drupal_mail('tellafriend', 'notify', $email, language_default());
- // Check the message results and let the user know if php was able to sent the email.
- if(!empty($message['result'])) {
- drupal_set_message(t('You just told your friend about us!'));
- } else {
- drupal_set_message(t('There was a problem sending your message', 'error'));
- }
- }
- /**
- * Implements hook_mail().
- */
- function tellafriend_mail($key, &$message, $params) {
- // Get the url for this site
- global $base_url;
- // Set the subject for this email.
- $message['subject'] = t('Your friend thought you might like this site');
- // Set the body. Note how we use a token in the t() function to hold our
- // link (!link) and then tell drupal the !link = $base_url.
- $message['body'][] = t("Hello,\nYour friend thought you might like this site. Please click the link below to visit.\n\n!link", array('!link' => $base_url));
- }
Now, simply create a directory in 'sites/all/modules' (I often put my custom modules in 'sites/all/modules/custom' but it's up to you) and copy both files there. Visit the modules page and enable your fancy new module. Now visit your blocks page and assign your new block to whichever region you wish.
I hope this serves as a good example of how easy it is to do things like this in Drupal. Our tellafriend module could be expanded to do things like ask for a name, maybe even set limits on how many emails can be sent, log emails to a database, etc, but I'll leave that to your skills and time.
Hope this helped!
Tags