I'd like to do something like the following:

If a user goes to node/15, my node.tpl.php file is used, as normal, to generate HTML.

If a user goes to node/15/animal/7, then my node.tpl.php is still used, as expected, but it has a variable in scope called $animal, set to the value that I would get from loading an animal.

So, the URL schema would look something like the following: node/%node/animal/%animal. I want this behavior so that if the user goes to node/15, that's fine, but if they attempt to go to node/15/animal/100 and animal 100 does not exist, the user gets a 404.

The problem I'm running into is that this requires functionality from several distinct areas of Drupal, and I don't know how to make them work together. Adding a custom URL schema would be done in hook_menu(), which requires a page callback. Using anything other than node_page_view would cause the node not to be rendered as normal. BUT, adding a variable to the template's scope would require implementing moduleName_preprocess_hook(), which I only want to conditionally fire when the user hits this specific URL schema.

I could of course manually check the contents of the requested URL myself, perhaps during moduleName_preprocess_hook, but this seems a little too low-level. Surely Drupal has some sort of way to accomodate what I'm trying to do?

  • What is animal in your case, a node, a term? Dec 27, 2011 at 21:10
  • Neither - in this case, it's a piece of data that is not a node or a term.
    – rybosome
    Dec 27, 2011 at 21:18

1 Answer 1


You're on the right track: it'll be much more straightforward to stick this in a module where you have access to the menu system, and the most straightforward way to expose the data to the node template is through preprocess functions.

First, create an implementation of hook_menu():

function example_menu() {
  // Only two things specific to your case is page callback 
  // and page arguments. Other options taken from node_menu(): customize as
  // you see fit.
  $items['node/%node/animal/%'] = array(
    'title callback' => 'node_page_title',
    'title arguments' => array(1),
    'page callback' => 'example_animal_view', 
    'page arguments' => array(1, 3), // Pass node object and animal ID
    'access callback' => 'node_access',
    'access arguments' => array('view', 1),
  return $items;

Then create your callback, which will display the node as normal (including using the node template) if your animal check succeeds:

function example_animal_view($node, $animal) {
  if (animal_exists($animal)) { // Replace with your own check
    return node_page_view($node);
  // Return a 404 if the check failed
  return MENU_NOT_FOUND;

Now, to expose the animal ID to node.tpl.php; you could either add it to the node object via the Field API, but in this case—since you're just using it for theming purposes—it's much easier to just add it to the template variables in a preprocess function:

function example_preprocess_node(&$variables) {
  if (arg(2) == 'animal') {
    $variables['animal'] = arg(3);

You could do this last part in your theme, but I'd keep it in the custom module to encapsulate the functionality so it's available in every theme.

Finally, in node.tpl.php, just reference $animal.

  • This looks pretty good! The only problem is that a variable named animal would not be in scope in my node.tpl.php file - that's the second part of what I'm trying to accomplish.
    – rybosome
    Dec 27, 2011 at 21:18
  • 1
    @Ryan Added: you were pretty much on the right track.
    – user7
    Dec 27, 2011 at 21:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.