Using the Pathauto API Drupal Module: A Simple Example

Pathauto is a wonderful tool. It’s definitely my oldest friend when it comes to Drupal modules. As the module has progressed, the API has become easier to use. This means we can make clean and beautiful URLs for our custom Drupal implementations, painlessly. For this example we are going to create a menu callback to display extra information about the blog content type. We will then use the Pathauto API to create the customizable url aliases.

Create the menu item

Here, we’re using the standard hook_menu, with the %node argument so we’ll have the entire node available to us in the page callback. Make sure to clear your cache anytime you modify the hook_menu.

[php]
/**
* Implements hook_menu.
*/
function node_extras_menu() {
$items[‘node/%node/extra’] = array(
‘page callback’ => ‘node_extras_extra’,
‘page arguments’ => array(1),
‘access arguments’ => array(‘access content’),
‘type’ => MENU_CALLBACK,
);
return $items;
}
[/php]

Make the page callback

Our page callback sets the title, and returns a couple of paragraphs; one with the node title in it, the other with a link back to the full node.

[php]
/**
* callback function to show our extra info.
*/
function node_extras_extra($node) {
drupal_set_title($node->title);
return "<p>Here is some extra info about node: " . $node->title . ‘.</p><p>’ . l(‘Go back to the full node’, ‘node/’ . $node->nid) . ‘</p>’;
}
[/php]

Now if you visit node/[your blog nid]/extra you will see something like this:

Expose our module to pathauto

In order to expose our module to pathauto, we need to use hook_pathauto. The settings are pretty basic. First we define the module and the group header. Next we define the default description and pattern. Since we’re working with a node, we want to use the ‘node’ token set. The patternitems setting is an associative array. Each entry adds a new pattern text field on the URL Aliases page. Finally, we have the batch_update_callback setting. This allows us to bulk update our aliases using the provided function, node_extras_pathauto_bulkupdate. We will write this function in a few steps.

[php]
/**
* Implements hook_pathauto.
*/
function node_extras_pathauto($op) {
$settings = new stdClass();
$settings->module = ‘node_extras’;
$settings->groupheader = t(‘Node Extras Paths’);
$settings->patterndescr = t(‘Default path pattern’);
$settings->patterndefault = ‘blog/[node:title]/extras’;
$settings->token_type = ‘node’;
$settings->patternitems = array(‘extra’ => ‘Node Extras’);
$settings->batch_update_callback = ‘node_extras_pathauto_bulkupdate’;
return $settings;
}
[/php]

Go ahead and clear your cache and you will be able to the Node Extras Paths on the Patterns tab of the URL Aliases settings page:

A helper function to create the alias

Now, we’re going to create a helper function that is going to create the alias for us. It’s more efficient to use a helper function since we will be creating aliases in 3 places: hook_node_insert, hook_node_update, and node_extras_pathauto_bulkupdate. We’ve got 2 arguments for this helper, $node and $op. The $node argument will be the node object, and the $op will be either ‘insert’, ‘update’ or ‘bulkupdate’. The first line of the function simply loads up the pathauto.inc file so we can use the pathauto_create_alias function. The arguments of the pathauto_create_alias function are:

module
the name of our module (node_extras)
operation
either ‘insert’, ‘update’ or ‘bulkupdate’
source path
the actual path to create an alias for (corresponds to the menu path we created in hook_menu)
data
supporting data such as the $node object
type
the type of pattern to use for the alias (corresponds to $settings->patternitems array values in hook_pathauto)

[php]
/**
* helper function to create the alias
*/
function node_extras_create_alias($node, $op) {
module_load_include(‘inc’, ‘pathauto’);
pathauto_create_alias(‘node_extras’, $op, ‘node/’ . $node->nid . ‘/extra’, array(‘node’ => $node), ‘extra’);
}
[/php]

Node inserts and updates

Now that we’ve got our alias creating helper function created, we can use hook_node_insert and hook_node_update to create and update our aliases when nodes are created or modified.

[php]
/**
* Implements hook_node_insert.
*/
function node_extras_node_insert($node) {
if($node->type == ‘blog’) {
node_extras_create_alias($node, ‘insert’);
}
}

/**
* Implements hook_node_update.
*/
function node_extras_node_update($node) {
if($node->type == ‘blog’) {
node_extras_create_alias($node, ‘update’);
}
}
[/php]

Bulk update function

The final step is to create our bulk update function. This function is going to find all of the blog nodes, then create an alias for each one. We are using a $count variable so we can display how many aliases were created at the end of the operation.

[php]
/**
* Implements hook_pathauto_bulkupdate.
*/
function node_extras_pathauto_bulkupdate() {
// find all node ids for the store content type
$query = db_select(‘node’, ‘n’);
$query
->condition(‘n.type’, ‘blog’)
->fields(‘n’, array(‘nid’));
$results = $query->execute()->fetchCol();
$count = 0;
foreach($results as $nid) {
$node = node_load($nid);
node_extras_create_alias($node, ‘bulkupdate’);
$count++;
}
drupal_set_message($count . ‘ node extras were updated.’);
}
[/php]

Now, you’ you’ll be able to use the Bulk Update function:

Done!

And after running the bulk update we get our new alias:

The entire example

[php]
/**
* Implements hook_menu.
*/
function node_extras_menu() {
$items[‘node/%node/extra’] = array(
‘page callback’ => ‘node_extras_extra’,
‘page arguments’ => array(1),
‘access arguments’ => array(‘access content’),
‘type’ => MENU_CALLBACK,
);
return $items;
}

/**
* callback function to show our extra info.
*/
function node_extras_extra($node) {
drupal_set_title($node->title);
return "<p>Here is some extra info about node: " . $node->title . ‘.</p><p>’ . l(‘Go back to the full node’, ‘node/’ . $node->nid) . ‘</p>’;
}

/**
* Implements hook_pathauto.
*/
function node_extras_pathauto($op) {
$settings = new stdClass();
$settings->module = ‘node_extras’;
$settings->groupheader = t(‘Node Extras Paths’);
$settings->patterndescr = t(‘Default path pattern’);
$settings->patterndefault = ‘blog/[node:title]/extras’;
$settings->token_type = ‘node’;
$settings->patternitems = array(‘extra’ => ‘Node Extras’);
$settings->batch_update_callback = ‘node_extras_pathauto_bulkupdate’;
return $settings;
}

/**
* helper function to create the alias
*/
function node_extras_create_alias($node, $op) {
module_load_include(‘inc’, ‘pathauto’);
pathauto_create_alias(‘node_extras’, $op, ‘node/’ . $node->nid . ‘/extra’, array(‘node’ => $node), ‘extra’);
}

/**
* Implements hook_node_insert.
*/
function node_extras_node_insert($node) {
if($node->type == ‘blog’) {
node_extras_create_alias($node, ‘insert’);
}
}

/**
* Implements hook_node_update.
*/
function node_extras_node_update($node) {
if($node->type == ‘blog’) {
node_extras_create_alias($node, ‘update’);
}
}

/**
* Implements hook_pathauto_bulkupdate.
*/
function node_extras_pathauto_bulkupdate() {
// find all node ids for the store content type
$query = db_select(‘node’, ‘n’);
$query
->condition(‘n.type’, ‘blog’)
->fields(‘n’, array(‘nid’));
$results = $query->execute()->fetchCol();
$count = 0;
foreach($results as $nid) {
$node = node_load($nid);
node_extras_create_alias($node, ‘bulkupdate’);
$count++;
}
drupal_set_message($count . ‘ node extras were updated.’);
}
[/php]