Learn how to programatically create a Drupal page

In this tutorial you are going to learn how to create a new page programmatically by registering a path in a menu hook.

You will create the custom path by adding an implementation of hook_menu() and adding the first element of the $item array. We are going to keep it to the bare minimum at the moment, and build from there.

When you implement a hook, you create a new function and follow a specific pattern. The pattern is <module_name>_hook(). So if you want to implement hook_menu() and your module name is starting_drupal_dev, you need to create a function called starting_drupal_dev_menu(), as follows:

  1. function starting_drupal_dev_menu() {
  3. }

You also need a comment, stating that you have implemented a hook.

  1. /**
  2. * Implements hook_menu().
  3. */
  4. function starting_drupal_dev_menu() {
  6. }

You need to return an associative array defining the paths, title, call back function and access arguments.

  1. /**
  2. * Implements hook_menu().
  3. */
  4. function starting_drupal_dev_menu() {
  5. $items['starting_drupal_dev/custom'] = array(
  6. 'title' => 'Custom page',
  7. 'page callback' => 'starting_drupal_dev_custom',
  8. 'access arguments' => array('access content'),
  9. );
  11. return $items;
  12. }

You have registered path of starting_drupal_dev/custom in the array key. You have given it a title of “Custom page”, which will be used as a title when viewing the page and used as link text for the menu item. You have defined a callback function called starting_drupal_dev_custom(). And finally, you have provided access arguments of access content, so anyone with the necessary permission to access content will be able to view our page.

In order for the menu to be added to the menu registry, you need to clear the menu cache.

You can do this by going to Configuration and Performance and hitting Clear Cache, or you can run the following Drush command:

$ drush cc menu

Now you need to add callback function, so that Drupal knows what to do when you visit the new path and what to return to the browser. So go ahead and add the following code:

  1. /**
  2. * Custom callback function.
  3. */
  4. function starting_drupal_dev_custom() {
  5. return '<p>Hello world</p>';
  6. }

Now visit the page - http://yoursite.com/starting_drupal_dev/custom. You should see a page with a title of “Custom page” and “Hello world” printed.

Custom page

Ok, we are getting somewhere. But you really should not return HTML markup directly from the callback function. We should use the Drupal's Render API. So let’s change the callback function to include a render element. A render element is an associative array containing properties that the theme system needs to render it as HTML.

  1. /**
  2. * Custom callback function.
  3. */
  4. function starting_drupal_dev_custom() {
  5. $content['raw_markup'] = array(
  6. '#type' => 'markup',
  7. '#markup' => '<p>Hello world</p>',
  8. );
  10. return $content;
  11. }

This is a very simple example of a render element, with just two properties, the type and markup. This might seem confusing and unnecessary, but it does add another layer of flexibility as it allows module developers and themers to alter the page content and layout before it is displayed to the user.

And that is it. You have successfully created a custom path and displayed a string.

This tutorial is part of the Starting Drupal Development course. If you would like to receive all of the lessons, please add your details in the box below.

To scale the Drupal development learning curve faster, check out my book Master Drupal Development. It will help you master module development faster to become a fully fledged Drupal developer.


Great stuff! Very readable approach!

http://sitename.com/starting_drupal_dev/custom/abc also renders the page.
How to restrict the url to just two arguments only, , ie http://sitename.com/starting_drupal_dev/custom
and anything beyond that to display 'Page not found'

Blair Wadman's picture

By design, Drupal allows additional arguments to be passed in. However, if you need to restrict to just two arguments, you could call func_get_args() from within the callback function. This will return the arguments. You can then check how many there are and if there are more than 2, call drupal_not_found().

Like so:

  1. function starting_drupal_dev_custom() {
  2. $args = func_get_args();
  3. if (count($args) > 2) {
  4. drupal_not_found();
  5. }
  7. $content['raw_markup'] = array(
  8. '#type' => 'markup',
  9. '#markup' => '<p>Hello world</p>',
  10. );
  12. return $content;
  13. }

Hi Blair Thank you for this post. It helped me great.

New comments for this tutorial have been turned off.