Last updated January 31, 2014. Created by jhodgdon on November 13, 2009.
Edited by batigolix, lostkangaroo, arianek, samirnassar. Log in to edit this page.

Drupal modules can provide help text to users in the .info file, and by implementing hook_help(). A hook_help() implementation defines help text for the URLs your module provides (settings pages, editing forms, etc.), indexed by the path to the page. In addition, the special path 'admin/help#modulename' should be used to define an overview help page for each module. The help hooks depend on the Help module to display.

Short Description

A short description of your module goes in the mymodule.info file, in element "description"; this description is displayed on the Modules administration screen, to tell a site administrator what your module does. The description should start with a verb and be relatively concise. Example (from the core Content Translation module in Drupal 7):

description = Allows content to be translated into different languages.

Help text for your module's paths

Help text for individual paths in your module is generally fairly brief, as it is displayed either at the top of the page or in a block, depending on which version of Drupal you are running. Here is an example of an individual path's help text, from the translate content page in the Content Translation module [this is part of the translation_help() implementation of hook_help()]:

   case 'node/%/translate':
      $output = '<p>' . t('Translations of a piece of content are managed with translation sets. Each translation set has one source post and any number of translations in any of the <a href="!languages">enabled languages</a>. All translations are tracked to be up to date or outdated based on whether the source post was modified significantly.', array('!languages' =>\Drupal::url('language.admin_overview'))) . '</p>';
      return $output;

Overview help page for module

See the note about the url() function in Drupal 8

The overview help page for your module should follow a standard structure. It should begin with an "About" section (giving a brief overview of what the module does, starting with text like "The Foo Bar module [verb]", and finishing with the link to the module's handbook page) and also contain a "Uses" section (giving details of module functionality, and links to the URLs where each specific functionality can be accessed). Capitalize the name of the module (module names are proper nouns). Here is an example of an overview page from the Content Translation module. First, the hook_help() section that defines the page:

    case 'admin/help#translation':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('The Content Translation module allows content to be translated into different languages. Working with the <a href="!locale">Locale module</a> (which manages enabled languages and provides translation for the site interface), the Content Translation module is key to creating and maintaining translated site content. For more information, see <a href="!translation">the online documentation for the Content Translation module</a>.', array('!locale' => \Drupal::url('help.page', array('name' => 'locale')), '!translation' => 'https://drupal.org/documentation/modules/translation/')) . '</p>';
      $output .= '<h3>' . t('Uses') . '</h3>';
      $output .= '<dl>';
      $output .= '<dt>' . t('Configuring content types for translation') . '</dt>';
      $output .= '<dd>' . t('To configure a particular content type for translation, visit the <a href="!content-types">Content types</a> page, and click the <em>edit</em> link for the content type. In the <em>Publishing options</em> section, select <em>Enabled, with translation</em> under <em>Multilingual support</em>.', array('!content-types' => \Drupal::url('node.overview_types'))) . '</dd>';
      $output .= '<dt>' . t('Assigning a language to content') . '</dt>';
      $output .= '<dd>' . t('Use the <em>Language</em> drop down to select the appropriate language when creating or editing content.') . '</dd>';
      $output .= '<dt>' . t('Translating content') . '</dt>';
      $output .= '<dd>' . t('Users with the <em>translate content</em> permission can translate content, if the content type has been configured to allow translations. To translate content, select the <em>Translation</em> tab when viewing the content, select the language for which you wish to provide content, and then enter the content.') . '</dd>';
      $output .= '<dt>' . t('Maintaining translations') . '</dt>';
      $output .= '<dd>' . t('If editing content in one language requires that translated versions also be updated to reflect the change, use the <em>Flag translations as outdated</em> check box to mark the translations as outdated and in need of revision. Individual translations may also be marked for revision by selecting the <em>This translation needs to be updated</em> check box on the translation editing form.') . '</dd>';
      $output .= '</dl>';
      return $output;

This definition results in the following HTML:

<h3>About</h3>
<p>The Content Translation module allows content to be translated into different languages. Working with the <a href="admin/help/locale">Locale module</a> (which manages enabled languages and provides translation for the site interface), the Content Translation module is key to creating and maintaining translated site content. For more information, see the online documentation for the <a href="https://drupal.org/documentation/modules/translation/">Content Translation module</a>.</p>
<h3>Uses</h3>
<dl>
<dt>Configuring content types for translation</dt>
<dd>To configure a particular content type for translation, visit the <a href="admin/structure/types">Content types</a> page, and click the <em>edit</em> link for the content type. In the <em>Publishing options</em> section, select <em>Enabled, with translation</em> under <em>Multilingual support</em>.</dd>
<dt>Assigning a language to content</dt>
<dd>Use the <em>Language</em> drop down to select the appropriate language when creating or editing content.</dd>
<dt>Translating content</dt>
<dd>Users with the <em>translate content</em> permission can translate content, if the content type has been configured to allow translations. To translate content, select the <em>Translation</em> tab when viewing the content, select the language for which you wish to provide content, and then enter the content.</dd>
<dt>Maintaining translations</dt>
<dd>If editing content in one language requires that translated versions also be updated to reflect the change, use the <em>Flag translations as outdated</em> check box to mark the translations as outdated and in need of revision. Individual translations may also be marked for revision by selecting the <em>This translation needs to be updated</em> check box on the translation editing form.</dd>
</dl>

That HTML is rendered like this (note internal links do not work here):

About

The Content Translation module allows content to be translated into different languages. Working with the Locale module (which manages enabled languages and provides translation for the site interface), the Content Translation module is key to creating and maintaining translated site content. For more information, see the online handbook entry for Content Translation module.

Uses

Configuring content types for translation
To configure a particular content type for translation, visit the Content types page, and click the edit link for the content type. In the Publishing options section, select Enabled, with translation under Multilingual support.
Assigning a language to content
Use the Language drop down to select the appropriate language when creating or editing content.
Translating content
Users with the translate content permission can translate content, if the content type has been configured to allow translations. To translate content, select the Translation tab when viewing the content, select the language for which you wish to provide content, and then enter the content.
Maintaining translations
If editing content in one language requires that translated versions also be updated to reflect the change, use the Flag translations as outdated check box to mark the translations as outdated and in need of revision. Individual translations may also be marked for revision by selecting the This translation needs to be updated check box on the translation editing form.

Drupal 8 note about url()

The url() function is deprecated in Drupal 8 (the template above is for Drupal 7). In Drupal 8 a few changes are required:

  1. For full URLs, such as https://drupal.org/documentation/module/foo -- nothing changes.
  2. For URLs to other modules' help files, replace
    // Drupal 7
    url('admin/help/module_name')

    with
    // Drupal 8
    \Drupal::url('help.page', array('name' => 'module_name'))
  3. For URLs to other admin pages, you need to use the Drupal::url() function, and to do that, you need to know the "route machine name" of the URL. For instance, if you had this in Drupal 7:
    // Drupal 7
    url('admin/structure/views')

    In Drupal 8 you would go to the views UI module's views_ui.routing.yml file to find the route machine name. You would see:
    views_ui.list:
      pattern: '/admin/structure/views'

    which tells you the machine name for the admin/structure/views page is "views_ui.list". So, to convert the url() function call to Drupal 8, it would be:
    // Drupal 8
    \Drupal::url('views_ui.list')

If you are wondering about the difference between the instructions for the admin/help/module and admin/structure/views URLs, here's the reason. The route entry in help.routing.yml for the admin/help/(module_name) pages is:

help.page:
  pattern: 'admin/help/{name}'

So, if you want to make a URL for the Field module help, you would need to set "{name}" to "field" (which is the machine name of the Field module. In which case, you would do:
\Drupal::url('help.page', array('name' => 'field'))

Also, if you find that you need to make a link to a similar path that has variables in the "pattern" line, you can follow the same rules. For instance, from views_ui.routing.yml again:

views_ui.edit:
  pattern: '/admin/structure/views/view/{view}'

This would mean the URL call for admin/structure/views/view/my_view_name would be:
\Drupal::url('views_ui.edit', array('view' => 'my_view_name'))

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.