Beginning Drupal Module Development or How I Wrote the Cacheflusher Module (Part 2)
Tags: DrupalDrupal ModulesDrupal Planet
This is the second part of Beginning Drupal Module development. If you missed the first part, you might want to review it before continuing with this tutorial.
Also thanks to drupaleasy for posting these on their site as well so they could be included in the Drupal Planet feed.
Creating Your .module File
Now that you have verified that your module's entry appears in the modules page in your development environment, it is time to add some information to your .module file.
This is where all of the work gets done and it contains all of the code for your module. Later, you can get fancy and use includes (.inc files) to help organize the module's function. For now though, you won't need any include files.
Open your favorite text editor again and on the first line add: <? php
This first line is needed to tell the web server that you are providing some php code. Don't close the tag though at the end with ?>
, this may add unneeded whitespace when your module runs.
The Drupal Framework Consists of Functions Called Hooks
Drupal modules are essentially a series of php functions that get executed by a trigger. This could be the user accessing a certain menu, saving a post, or a cron run. Your module integrates into Drupal by accessing Drupal specific triggers, that are referred to as hooks. Most modules have both hook functions as well as custom functions - which are usually there to encapsulate logic outside of a hook.
Documentation is Important
Throughout the api documentation and within Drupal core, you will find entries that use the format of hook_function_name
, if you examine other modules, you will also find that before these functions, there are code comments:
/**<br> * Implement hook_function_name()<br> */
Follow this format when you create your own module. This provides documentation to another developer about what is happening within your module and can give you some trouble-shooting tips if something goes wrong. The Drupal community likes documentation! Some module authors also prepend non-hook functions with an underscore character ("_") as a way to quickly identify them as well as ensure they don't coincidentally get used as a hook by some other module.
A Simple Module's Framework
A module should generally contain at least four functions, in addition to any other specific functions that make your module unique:hook_enable to enable your module and tell your user it was enabled.hook_disable to disable your module and tell your user it was disabled.hook_help to provide help information to your user.
And finally, hook_uninstall to clean up after yourself and tell the user the module was uninstalled.
The CacheFlusher module is a fairly simple module in it's usage of the hook_enable
hook_disable
and hook_uninstall
These functions are used in this module to only provide feedback to the user after being enabled, disabled, and uninstalled, but could do other things as well like delete a variable that was set or send a notification email. These messages are important to tell the user that what they wanted to happen did happen. If your code or module does something in response to something a user did, tell them that it worked by using the drupal_set_message function. This function prints your message on the screen and gives vital feedback to the user.
Using the t() Function for Translation
Throughout module's code you will often find a t()
function preceding the message and following the drupal_set_message
hook. This t()
function is important for language translation. Drupal gives you an easy way to avoid the need to translate your messages into additional languages. By using this t()
function with your message, the translation team can quickly and easily translate your message into the native Drupal installations language. More information can be found on the t() function's page and
Using the CacheFlusher module as an example, you can see that the first function that is being called is hook_enable
When using a function within your module, you replace the hook_function_name
with your module's name and then the Drupal function you are calling: hook_enable
becomes cacheflusher_enable
for this example.
Using api.drupal.org for reference
To find out what each function does, visit api.drupal.org and search for the specific function.
Using hook_enable
Here is the cacheflusher_enable
entry:
/**<br> * Implement hook_enable()<br> */<br>function cacheflusher_enable() {<br> drupal_set_message($message = t('The CacheFlusher module was successfully enabled.'), $type = 'status');<br>}
Notice the documentation of the hook being used at the top, starting with /** , it is important to document your code as you go and explain what you are doing.
The next entry is using the hook_enable as cacheflusher_enable. This tells Drupal that when this module is enabled, do something. That something specifically is found on the next line with an additional function call to drupal_set_message.
Now when your module is enabled, Drupal will tell the user that module was enabled.
You could save your .module file now which might look like this:
<?php<p>/**<br> * Implement hook_enable()<br> */<br>function cacheflusher_enable() {<br> drupal_set_message($message = t('The CacheFlusher module was successfully enabled.'), $type = 'status');<br>}</p>
And then open your modules page on your Drupal site and enable your module.
Congratulations! You now have a working module! Your module doesn't actually do anything except send a message to the user that it has been enabled, but you now have all of the necessary components of a functioning module.
Using hook_disable, hook_uninstall, and hook_help
You should continue implementing hook_disable, hook_uninstall, and hook_help to add to your base module's framework:
/**<br> * Implement hook_disable()<br> */<br> function cacheflusher_disable() {<br> drupal_set_message($message = t('The CacheFlusher module was successfully disabled.'), $type = 'status');<br>}<p>/** <br> * Implement hook_help()<br> */<br>function cacheflusher_help($path, $arg) {<br> switch ($path) {<br> case 'admin/help#cacheflusher':<br> $output = '';<br> $output .= '<h3>' . t('About') . '</h3>';<br> $output .= '<p>' . t("The CacheFlusher Module places a Flush Cache button on your dashboard") . '<p>';<br> return $output;<br> }<br>}</p><p>/**<br> * Implement hook_uninstall()<br> */<br> function cacheflusher_uninstall () {<br> drupal_set_message($message = t('The CacheFlusher module was successfully uninstalled. '), $type = 'status');<br>}</p>
Using hook_menu
After adding these functions, it is now time to add a menu entry and the custom CacheFlusher function to clear the site's cache.
/**<br> * Implement hook_menu()<br> */<br>function cacheflusher_menu() {<p> $items = array();<br> $items['admin/cacheflusher'] = array(<br> 'title' => 'CacheFlusher',<br> 'description' => 'Cacheflusher description',<br> 'page callback' => 'cacheflusher_cache_clear',<br> 'access arguments' => array('access administration pages'),<br> 'type' => MENU_NORMAL_ITEM,<br> 'weight' => 15,<br> );<br> return $items;<br>}</p>
The drupal function hook_menu is actually a series of nested arrays, with each array key providing things like a title for the menu entry, a description for the menu entry a page callback, access arguments, a menu entry type, and a weight to the menu.
Notice the first array key after $items
. This generates the path for our menu entry and by inserting the path [‘admin/cacheflusher’]
we are placing this menu item in the admin menu. If you visit the url for yoursite.com/admin/cacheflusher you will be taken to the first menu page for the cacheflusher menu. There actually is only one page for this example, but you could add more if your module required it.
Continuing through the array, we find an additional nested array with keys providing a title and a description. The title for the entry will actually provide the text for the menu item listed in our menu, and the description gives the user some idea of what the module does. It isn’t actually displayed to the user in this example, because this menu item shows within the top administrative menu of your site. The next key is the page_callback
this directs drupal to do something when our menu item is clicked. In this example, it redirects to the next section of our .module file, the cacheflusher_clear_cache
which we will explore shortly.
The next key is the type of menu entry we would like. As you can see, this is a MENU_NORMAL_ITEM which creates a menu item that is displayed in the page menu and breadcrumbs of the site.
The final key weight
simply tells drupal how far down in the list to display this menu entry. A weight of -100 would make it generally always displayed first, a weight of 100 would make it most likely very last. I chose 15 simply because in a stock drupal installation, there are only eleven or twelve menu entries. I wanted the CacheFlusher to display last so I made it 15.
And finally, here is the workhorse of the entire module that clears the cache and then returns that always important message to the user that the cache has actually been cleared:
function cacheflusher_cache_clear() {<br> drupal_flush_all_caches();<br> drupal_set_message($message = t('All Caches cleared. '), $type = 'status');<br> drupal_goto();<br>}
Our final function within our .module file is the cacheflusher_cache_clear
function. This is a private function that is not derived from a drupal hook and I like to name my custom functions first with the name of the module and then with a description of what the function does.
This function uses three drupal functions: drupal_flush_all_caches() that empties all of Drupal’s caches, the already familiar drupal_set_message that tells the user that the caches have been cleared, and the final function call to drupal_goto that redirects the user to the root of the site. Without drupal_goto
the user would have to use the back button or even get stuck in an infinite loop.
When the previous hook_enable, hook_install, hook_help, and hook_menu functions are added, you are done with your module and have all of the needed components to create a functioning module.
Summary
In summary, we created a directory structure bearing the same name as our module. Then when added two files, a modulename.info and a modulename.module file within this directory, again using the same name as our module.
Next we added entries to our .info file to help Drupal initialize and categorize our module.
Then we added Drupal API functions to our .module file that allowed our module to interact with the Drupal messaging system, the menu and provided feedback to our user. These functions followed the format of hook_function
with hook
being replaced by our module's name and _function
being replaced by a Drupal API specific function.
A great resource for continuing your module development education is the Drupal 7 Module Development book.