Open Source Software Technical Articles

Want the Best of the Wazi Blogs Delivered Directly to your Inbox?

Subscribe to Wazi by Email

Your email:

Connect with Us!

Current Articles | RSS Feed RSS Feed

Custom module configuration with Drupal 7

  
  
  

In this third article in her series on coding custom Drupal modules, Juliet Kemp shows us how to set up a configuration form and hook it to a Drupal menu, including code examples and dos and don'ts.

A huge part of the Drupal content management system's power and flexibility comes from its module system. A module is a collection of functions that hook into Drupal in various ways to let you add new functionality to your site. You can use Drupal's contributed modules to control and customize your site, or you can write your own.

In two previous articles, we wrote a basic custom Drupal module that accessed a database and generated a custom block. In this tutorial, we'll set up a configuration form and use it to change the database query that populates our block, and we'll use the hook_menu() function, which handles Drupal paths, to make the configuration form available. In Drupal terms, a path is the unique, last part of the URL for a specific function or piece of content. We'll keep working with the module from the last two tutorials, which displays a block of links to pages that were written by the same author as the current page.

Module configuration

Many Drupal modules have configuration options that administrators can set. Currently, our module displays the last three posts' worth of content via the range(0,3) condition in _same_author_dbquery(). Instead, let's limit it to posts from the last N days, and allow an administrator to choose how many days' worth of same-author posts should be shown.

The first step is to set up the path for the form by using hook_menu(). Despite the name, this function doesn't just manage menu items; it also does the more general job of registering and handling Drupal paths, and you can also use it to check access permissions. Here we'll simply check that the user has administration access, but you could also set up a new custom permission.

 
function same_author_menu() {
  $items = array();

  $items['admin/config/content/same_author'] = array(
    'title' => 'Same Author config',
    'description' => 'Configuration for Same Author module',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('same_author_form'),
    'access arguments' => array('access administration pages'),
    'type' => MENU_NORMAL_ITEM,
  );

  return $items;
}

Here we're setting up a single path-handling item to handle requests for the path admin/config/content/same_author, sending users to the config page. Each key/value pair added to $items handles a separate path, and as seen here, the value is a further array with multiple attributes of the path.

Note that while in general strings in Drupal should be wrapped in t() to enable localization, here the title and description values are handled directly, so it's important not to use t(). The page callback is a call to a function that will generate the contents of the page in question; when users request the specified path, the page callback function generates the data that they see. drupal_get_form handles forms, and the argument provided in the next line identifies the form function (usually a custom module function, as here) to pass into drupal_get_form().

We need something in the access arguments key for the path to show up at all. Here, we set the access to be the same as the general administration pages access. An alternative would be to show it under all circumstances (unlikely to be appropriate for a configuration link, but you might want to do it if you were setting up a path to a regular page) with this line instead of the access arguments one:

'access callback' => TRUE,

Finally, the MENU_NORMAL_ITEM value means that this path will appear as a normal menu item.

Creating a configuration form

With this function we've directed a path to a form; now we need to create the actual form. Here's the function to do that, to add to same_author.module:

 
function same_author_form($form, &$form_state) {
  $form['same_author_days'] = array(
    '#type' => 'textfield',
    '#title' => t('Days to display of same author posts'),
    '#default_value' => variable_get('same_author_days', 7),
    '#size' => 3,
    '#maxlength' => 3,
    '#description' => t('The number of days of same author posts to display in the block.'),
    '#required' => TRUE,
  );

  return system_settings_form($form);
}

As you can see, here we do use the t() function for our strings, to ensure localizability. (In almost all circumstances you should use t(); hook_menu() is a special case because of how Drupal handles it.) The form setup should be familiar from HTML. We're creating a textfield with a title, a default value, a size and maximum length, and a description; and to submit the form this textfield must be filled in. Our form has only one field, but you could create many more fields with the same setup, adding $form['same_author_VARIABLE'] = array(...) as required.

The one thing we have not seen before is the variable_get() function. Drupal uses variable_get() and variable_set() to deal with persistent variables (variables that persist between invocations of a module). Here, the default value for the form is either whatever persistent variable is stored in same_author_days, or 7 (meaning one week) if there is no such variable. You should always call your persistent variables something beginning with your module's name to keep the namespace clean.

system_settings_form() is a built-in Drupal function that provides a Submit button, automatically saves any data into persistent variables, and shows users a color-coded success (green) or failure (red) message. While you can if you need to create your own Submit function, it's good practice to use the built-in one if it is usable with your form in order to avoid reinventing wheels.

WARNING: The array key into $form in the first line of the function must match the variable name in variable_get or system_settings_form() won't work:

// this WILL NOT work! same_author_max != same_author_days
$form['same_author_max'] = array(
  // lines...
  '#default_value' => variable_get('same_author_days', 7),
  // more lines...

// but this is fine
$form['same_author_days'] = array(
  // lines...
    '#default_value' => variable_get('same_author_days', 7),
  // more lines

If you run the module and your custom variable seems not to be set, double-check that the names match.

Unenable and reenable your module (you need to do this whenever you edit hook_menu() in order to get the paths to work) then go to admin/config/content/same_author, and you should see your form. However, changing the value at this point won't do anything to the block. You still need to hook it all into the database.

Revising the database query

Let's revisit _same_author_dbquery() from the previous article and edit it to handle the new information we need to get from the database. Specifically, let's add a criterion to return posts only from the last N days, where N is the value put in by the administrator in our config page and saved as same_author_days, or 7 if there is no such variable. However, we're going to apply this limit only if the query is called as a block; otherwise, we'll deliver all the results in the database. (We won't use this functionality here, but it may be useful if we wish to extend the module to generate a page as well.)

 
function same_author_dbquery($display) {
  $same_author_days = variable_get('same_author_days', 7);
  $today = getdate();
  $start_time = mktime(0, 0, 0,$today['mon'],($today['mday'] - $same_author_days),
                        $today['year']);
  $end_time = time();

  $query = db_select('node', 'n')
    ->fields('n', array('nid', 'title', 'created', 'uid'))
    ->condition('status', 1) 
    ->condition('uid', $node->uid)
    ->condition('nid', $node->nid,'!=')
    ->orderBy('created', 'DESC');

  if ($display == 'block') {
    $query->condition('created', array($start_time, $end_time), 'BETWEEN');
  }
  return $query->execute();
}

The code at the start calculates midnight N days ago. We removed the range line we used in our prior article in the db_select() function. Also, this time, instead of adding the execute() call in with the rest of the query, we check after the orderBy() call to see whether the function was called as a block. If it was, we add a new 'created' condition, using the $start_time and $end_time from the new code, to specify that posts must have been created between now and N days ago. If the function was not called as a block, this condition is not added. Note that to make this work, we must also add $display as a parameter to _same_author_dbquery(). Finally, we call execute() on the completed query.

Final adjustments

Now that _same_author_dbquery() takes a "block" argument, we need to make sure that it is called with that argument when it is called as a block. This is straightforward: Just edit a single line in same_author_block_view(), the function that calls _same_author_dbquery():

$result = same_author_dbquery('block');

The last thing to do is to make the configuration button available. Add a single configure line to the file same_author.info, which is in the same directory as same_author.module; see the first article in this series under the heading "Telling Drupal about the module":

 
name = Same Author  
description = A block module that displays links to nodes by the same author. 
core = 7.x

configure = admin/config/content/same_author

Save, enable, and test. You should be able to alter the restrictions to show as many or as few days of recent posts as you like.

If you wanted to, you could add plenty of other configuration options. For example, you could also limit the number of same author posts you show, as well as how old you allow those posts to be. Play around with the form and the database query to see what else you can do.




This work is licensed under a Creative Commons Attribution 3.0 Unported License
Creative Commons License.

Comments

When you are spending a very high cost for your Replica Louis Vuitton Handbags you of course want it to be of a very good quality and that is what Chanel Handbags will source you with. Nonetheless, with Handbag Replicas acquiring quite popular, though not truly cost-effective, the cheap and phony kinds have made an appearance in the market. Within a lot of scenarios they may sell their Replica Luxuries bag. That signifies that if you happen to know wherever to look you may score a remarkable deal. In basic you might uncover utilized Gucci Handbags supplied for sale on the planet wide web. It feels good wearing a black on Rolex Replicas watch every now and then. Let me know what you think of the video and of this piece in particular.
Posted @ Tuesday, December 31, 2013 2:41 AM by suddy
Numerous Drupal modules have setup choices that managers can set. As of now, our module shows the last three posts' worth of substance through the range(0,3) condition in _same_author_dbquery(). Rather, we should limit it to posts from the keep going N days, and permit a chairman to pick how long worth of same-creator posts ought to be demonstrated.paraphrasing vs summarizing 
Posted @ Saturday, March 22, 2014 3:52 AM by paraphrasing vs summarizing
your current question was formerly dispatched to 6 inquiries and it is far from connected any gurus. For that cause the actual rang spammy posts, For those who desire to ask a complete doubt, Elect productive stories connected to it, Not too jsut a great deal you may see in existence. You're able to offer correct volume of post, Its quite straightforward! How discrepancy is it realize if any individual is normally the in relation or if not? Until finally you realize the individual that will there is certainly additional keywords some could go with on to assist you get access, You never ever going to control to search out out anyone code. 
iPhone 5 Cases 
iPhone 5S Cases 
iPhone 5S Cases 
iPhone 5S Cases
Posted @ Wednesday, April 30, 2014 2:25 AM by iPhone 5 Cases
Note that there is an error in the function signature above for same_author_form above. It should be: 
 
function same_author_form() 
 
NOT: 
 
function same_author_form($form, $&form_state) 
 
Maybe it's a PHP 5.5 thing, but when I used this function signature, a form.inc error was thrown. Other Drupal modules do not put arguments in this function.
Posted @ Friday, August 08, 2014 1:47 AM by Tom
asdasdasda
Posted @ Wednesday, August 27, 2014 2:30 AM by asdasa
Post Comment
Name
 *
Email
 *
Website (optional)
Comment
 *

Allowed tags: <a> link, <b> bold, <i> italics