I created a block using hook_block_view() and hook_block_info(), then set-up the page with hook_menu() using page arguments but this seems to only work for node/id/page?

This is what I have right now:

$items['node/%node/text'] = array(
    'page callback' = 'my_module_function',
    'page arguments' = 'array(1)',

I need it to work for the nodes alias which might be article/node title/ or journal/node title/ - they are for two different content types. Going to just article/ or just journal/ shows a View page that displays all the articles or everything from the journal.

Currently whenever I try to go to:

article/node title/page

the article/ Panel page is loaded. However disabling the panel for article/ then going to article/node title/page causes a Page not found error, so it seems it's something to do with my hook_menu() not registering the URL aliases of the nodes?

As node/node id/page works perfectly fine.

Edit: unsure how to reopen, see comments

  • The canonical hook_menu() question will answer this (and then some). As a hint you're looking to pass page arguments to your callback function. Have a look at the section labelled Arguments in the linked answer
    – Clive
    Commented Jul 5, 2013 at 8:34
  • @Clive I knew I was on to the right track but wasn't sure what to pass to the arguments, array(1) - not sure how that passes $node but it's not working yet... seems to load the /article view page that shows all articles, might be the view overriding it though.
    – dan2k3k4
    Commented Jul 5, 2013 at 9:06
  • @Clive I have it working for /node/100/text but not for the alias version of the mode like: /article/my-article/text, updated question
    – dan2k3k4
    Commented Jul 5, 2013 at 9:53
  • For now this seems to unclear to tell if it's a duplicate or deserves reopening. If it's collision with views, how can we know without any info about view settings?
    – Mołot
    Commented Jul 5, 2013 at 10:34
  • @Mołot I speculated that it could be the Views but the Views are only for other page URLs like article-list/, and I use Panels for the article/ page but have article/node_title/ set as the URL alias to node/nid - doesn't seem to be anything to do with the Views. Disabling the Panel for article/ causes article/node_title/text page to show as Page Not Found
    – dan2k3k4
    Commented Jul 5, 2013 at 11:57

1 Answer 1


You have two options.

1. Using the Sub-pathauto (Sub-path URL Aliases) module.

This is based on pathauto, and will create additional aliases for node sub-pages.

This also works for other entity types such as user/123/contact -> people/geronimo/contact, if user/123 has the alias people/geronimo.

2. Write a custom wildcard loader (far more work).

I am going to use the word "slug" here, which I remember from Wordpress.

The usual node path is node/%node, which will trigger the node_load() wildcard loader. This wildcard loader only takes node ids. It does not work with node titles. So, node_load(123) gets you the node with that id, but node_load('node title') will return NULL.

You could now create a new module "mymodule", and use hook_menu() to define a separate path article/%mymodule_article_slug, and sub-paths article/%mymodule_article_slug/page, article/%mymodule_article_slug/edit, etc.

This is going to be some work, you need to look into node.module and the hook_menu() implementation found there, and copy a lot from there. Or you could use hook_menu_alter() instead of hook_menu(), and copy some of the data already registered for node/% and friends.

The essential trick now is to define a wildcard loader for %mymodule_article_slug.

 * Wildcard loader callback for '%mymodule_article_slug'.
 * @param string $slug
 *   Part of the url identifying the node, e.g. "pink-elephant"
 * @return object|null
 *   The node object, usually an instance of stdClass, or
 *   NULL, if no such node exists.
function mymodule_article_slug_load($slug) {
  // Load the node identified by $slug.
  $node = ...;
  return $node;

Now it gets insteresting. How do you load the node identified by the "slug"? There are different ways.

  1. You could store the slug in a field on the node, and then use EntityFieldQuery to load the node with that field value. You also need to decide what to do if more than one node has the same slug.

  2. You could use path + pathauto and find the node where the alias is "article/" . $slug. drupal_get_normal_path() can help you with that.

With method 2, your code would look like this:

function mymodule_article_slug_load($slug) {
  // Load the node identified by $slug.
  $normalpath = drupal_get_normal_path('article/' . $slug);
  if ($normalpath && preg_match('#/node\/(\d+)$/', $normalpath, $m)) {
    $nid = (int)$m[1];
    if ($nid > 0) {
      return node_load($nid);

EDIT: This only works if the "slug" does not contain any slashes by itself!

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.