Same filename and directory in other branches
  1. 7.x-1.x page_example/page_example.module
  2. 8.x-1.x page_example/page_example.module

This is an example outlining how a module can be used to display a custom page at a given URL.

File

page_example/page_example.module
View source
<?php

/**
 * @file
 * This is an example outlining how a module can be used to display a
 * custom page at a given URL.
 */

/**
 * @defgroup page_example Example: Page
 * @ingroup examples
 * @{
 * Create a page in a module. (Drupal 6)
 *
 * This example demonstrates how a module can be used to display a
 * custom page at a given URL.
 *
 * This example is part of the Examples for Developers Project
 * which you can download and experiment with here:
 * http://drupal.org/project/examples
 */

/**
 * Implementation of hook_help().
 */
function page_example_help($path, $arg) {
  switch ($path) {
    case 'admin/help#page_example':
      $output = page_example_description();
      $output .= '<p>';
      $output .= t("The simple page requires 'access simple page'\n        permission. The different permissions page requires\n        'access content' permission. The custom access\n        callback page requires 'access content' permission\n        and the visitor to be signed in. The arguments page\n        requires 'access arguments page' permission.");
      $output .= '</p>';
      return $output;
  }
}

/**
 * Implementation of hook_perm().
 *
 * Since the access to our new custom pages will be granted based on
 * special permissions, we need to define what those permissions are here.
 * This ensures that they are available to enable on the user role
 * administration pages.
 */
function page_example_perm() {

  // Defining permissions for your module is as simple as returning an array of
  // strings.
  return array(
    'access simple page',
    'access arguments page',
  );
}

/**
 * Implementation of hook_menu().
 *
 * hook_menu() must be implemented to emit items to place in the main menu.
 * This is a required step for modules wishing to display their own pages,
 * because the process of creating the links also tells Drupal what
 * callback function to use for a given URL. The menu items returned
 * here provide this information to the menu system.
 *
 * With the below menu definitions, URLs will be interpreted as follows:
 *
 * Note that the URLs below are written as though Clean URLs are not
 * enabled on the site.
 *
 * If the user accesses http://example.com/?q=examples/page_example, then the
 * menu system will look for a menu item with that path. In this case it will
 * find a match, and execute page_example_description().
 *
 * If the user accesses http://example.com/?q=examples/page_example/simple but
 * does not have the required 'access simple page' permission, access will be
 * denied.
 *
 * If http://example.com/?q=examples/page_example/arguments/1/2 is accessed,
 * the menu system will first look for examples/page_example/arguments/1/2. Not
 * finding a match, it will look for examples/page_example/arguments/1/%. Again
 * not finding a match, it will look for examples/page_example/arguments/%/2.
 * Yet again not finding a match, it will look for example/arguments/%/%. This
 * time it finds a match, and so will execute page_example_arguments(1, 2).
 * Note the parameters being passed; this is a very useful technique.
 *
 * If http://example.com/?q=examples/page_example/arguments/1 is accessed, the
 * menu system will match 'examples/page_example', and not
 * 'examples/page_example/arguments/%/%'. The menu entries for the latter
 * require 5 arguments. All the elements included in the menu entry definition
 * should be present for the menu system to match the request.
 *
 * If the user accesses
 * http://example.com/?q=examples/page_example/different-permission but
 * does not have the required 'access content' permission, access will be
 * denied.
 *
 * If the user accesses
 * http://example.com/?q=examples/page_example/custom-access-callback but
 * does not have the required 'access content' permission and/or
 * is not signed in, access will be denied.
 *
 * The @link menu_example.module Menu Example @endlink provides more extensive
 * examples for hook_menu().
 */
function page_example_menu() {

  // This is the minimum information you can provide for a menu item. This menu
  // item will be created in the default menu (Navigation).
  // Specifying 'access callback' => TRUE causes this menu item to be
  // available for all roles.
  $items['examples/page_example'] = array(
    'title' => 'Page Example',
    'page callback' => 'page_example_description',
    'access callback' => TRUE,
    'expanded' => TRUE,
  );

  // This example checks if the user has permission to access the page. Users
  // that do not have the 'access simple page' permission will be denied. An
  // array containing the required permissions is given in 'access arguments'
  // and here we use the default 'access callback', which is 'user_access'.
  $items['examples/page_example/simple'] = array(
    'title' => 'Simple - no arguments',
    'page callback' => 'page_example_simple',
    'access arguments' => array(
      'access simple page',
    ),
  );

  // By using the MENU_CALLBACK type, we can register the callback for this
  // path but not have the item show up in the menu.
  //
  // Notice that the 'page arguments' is an array of numbers. These will be
  // replaced with the corresponding parts of the menu path. In this case a 0
  // would be replaced by 'examples', a 1 by 'page_example', a 2 by 'arguments'
  // and likewise 3 and 4 will be replaced by whatever the user provides. We
  // will pass these last two as arguments to the page_example_arguments()
  // function.
  //
  // Only users with the 'access arguments page' permission have access.
  $items['examples/page_example/arguments/%/%'] = array(
    'title' => 'Page example with arguments',
    'page callback' => 'page_example_arguments',
    'page arguments' => array(
      3,
      4,
    ),
    'access arguments' => array(
      'access arguments page',
    ),
    'type' => MENU_CALLBACK,
  );

  // You are not limited to checking for permissions defined by
  // this module. You can also check for permissions defined by
  // other modules. In this case, we will check for permissions
  // defined by node.module
  $items['examples/page_example/different-permission'] = array(
    'title' => 'Page example checking for other permissions',
    'page callback' => 'page_example_other_permissions',
    'access arguments' => array(
      'access content',
    ),
  );

  // You can also define your own access callback function.
  $items['examples/page_example/custom-access-callback'] = array(
    'title' => 'Page example using a custom access callback',
    'page callback' => 'page_example_custom_access_page',
    'access callback' => 'page_example_custom_access_callback',
  );
  return $items;
}

/**
 * None of these page examples makes use of the Form API.
 * The @link form_example.module Form Example @endlink provides
 * examples that do.
 */
function page_example_description() {
  $output = '<p>';
  $output .= t('The page_example provides four pages, "simple", "arguments",
    "different permissions" and "custom access callback".');
  $output .= '</p>';
  $output .= '<p>';
  $output .= t('The <a href="@simple_link">simple page</a>,
    <a href="@dp_link">different permissions page</a> and
    <a href="@cac_link">custom access callback page</a>
    just return a string for display.
    The <a href="@arguments_link">arguments page</a> takes
    two arguments and displays them,
    as in <a href="@arguments_link">@arguments_link</a>.', array(
    '@simple_link' => url('examples/page_example/simple', array(
      'absolute' => TRUE,
    )),
    '@dp_link' => url('examples/page_example/different-permission', array(
      'absolute' => TRUE,
    )),
    '@cac_link' => url('examples/page_example/custom-access-callback', array(
      'absolute' => TRUE,
    )),
    '@arguments_link' => url('examples/page_example/arguments/23/56', array(
      'absolute' => TRUE,
    )),
  ));
  $output .= '</p>';
  $output .= '<p>';
  $output .= t('Note also that because these pages use permissions to
    limit access to the content, unprivileged or anonymous users
    will receive \'Access Denied\' errors.');
  $output .= '</p>';
  return $output;
}

/**
 * A simple page callback.
 *
 * Page callbacks are required to return the entire page. The content
 * is then usually output via a call to theme('page'), where the theme system
 * will then surround the content in the appropriate blocks, navigation, and
 * styling.
 *
 * If you do not want to use the theme system (for example for outputting an
 * image or XML), you should print the content yourself and not return anything.
 */
function page_example_simple() {
  return '<p>' . t('Simple page: The quick brown fox jumps over the lazy dog.') . '</p>';
}

/**
 * A more complex page callback that takes arguments.
 *
 * The arguments are passed in from the page URL. In our hook_menu
 * implementation we instructed the menu system to extract the last two
 * parameters of the path and pass them to this function as arguments.
 */
function page_example_arguments($first, $second) {

  // Make sure you don't trust the arguments to be safe! Always check for exploits.
  if (!is_numeric($first) || !is_numeric($second)) {

    // We will just show a standard "access denied" page in this case.
    drupal_access_denied();
    return;

    // We actually don't get here.
  }
  $list[] = t("First number was @number.", array(
    '@number' => $first,
  ));
  $list[] = t("Second number was @number.", array(
    '@number' => $second,
  ));
  $list[] = t('The total was @number.', array(
    '@number' => $first + $second,
  ));
  return theme('item_list', $list);
}

/**
 * Page callback to demonstrate checking for the 'access content' permission.
 */
function page_example_other_permissions() {
  return '<p>' . t('Evidently, you are authorized to view content on the site.') . '</p>';
}

/**
 * If your custom access callback function checks
 * for permissions, it should still use user_access.
 * You may add whatever additional logic you like, though.
 */
function page_example_custom_access_callback() {
  global $user;
  return user_access('access simple page') && $user->uid > 0;
}

/**
 * Page callback to demonstrate a custom access callback.
 */
function page_example_custom_access_page() {
  return '<p>' . t('Welcome to the custom access page, registered visitor.') . '</p>';
}

/**
 * @} End of "defgroup page_example".
 */

Functions

Namesort descending Description
page_example_arguments A more complex page callback that takes arguments.
page_example_custom_access_callback If your custom access callback function checks for permissions, it should still use user_access. You may add whatever additional logic you like, though.
page_example_custom_access_page Page callback to demonstrate a custom access callback.
page_example_description None of these page examples makes use of the Form API. The Form Example provides examples that do.
page_example_help Implementation of hook_help().
page_example_menu Implementation of hook_menu().
page_example_other_permissions Page callback to demonstrate checking for the 'access content' permission.
page_example_perm Implementation of hook_perm().
page_example_simple A simple page callback.