27

I've pored over this old thread on drupal.org and it just kind of makes my head spin around. Pulling down the path and trying to parse out the NID from within it? There has to be a better way.

And solutions like

global $node;
$nid = $node->nid;

don't work in my custom module (though I'm told they work in templates?). No error or anything, it just instantiates $node with a NULL value.

It feels like there must be something really obvious that I'm missing.

So, how do you get the NID of the current node without a template, while following best practices and building a reasonably robust module?

7 Answers 7

56

Assuming your code is running for a node page, the methods I see used most often in core/contrib modules are either using menu_get_object() or arg():

if ($node = menu_get_object()) {
  // Get the nid
  $nid = $node->nid;
}

or

if (arg(0) == 'node' && is_numeric(arg(1))) {
  // Get the nid
  $nid = arg(1);

  // Load the node if you need to
  $node = node_load($nid);
}

I personally prefer the first method (even though assignment in condition isn't considered a good idea by some people), but both are perfectly valid.

13
  • 1
    @Letharion Yeah I feel just a little bit guilty every time I do it ;)
    – Clive
    May 25, 2012 at 21:38
  • 1
    @beth What function are you calling it from? And is it definitely a node page you're calling it on?
    – Clive
    May 25, 2012 at 21:39
  • 1
    @beth They 100% will work with path aliasing enabled. Path aliasing has nothing to do with the router path of the menu item, which is node/1, node/2 etc. If you're still having trouble it might be worth posting another question with the exact code you're using, and provide a bit of context. Then we might be able to pinpoint where the problem's happening
    – Clive
    May 29, 2012 at 12:20
  • 1
    A single line solution $nid = ($node = menu_get_object()) ? $node->nid : NULL; Dec 5, 2013 at 23:20
  • 3
    @sheldonkreger The node's already loaded by that point, menu_get_object() (or even node_load()) is just getting it from static cache. Even if you call it early on, it's still going to be loaded by a core module later on in the page build (as this is a node page), in that case you'd just be warming the static cache for the next process
    – Clive
    Sep 15, 2014 at 23:10
5

Easiest way to do this in Drupal 8 since arg() no longer works:

$path_args = explode('/', current_path());
print $path_args[1];

Change record

3
  • 3
    This also works in Drupal 7. However, if you are on a page which isn't a node, such as admin/structure/blocks , then you will receive an invalid value (in this case, 'structure'). Simply check to see if path_args[1] is an integer and you're probably fine. Sep 15, 2014 at 22:49
  • 1
    You will likely want to use arg(1) instead of explode, since it has already done that for you: api.drupal.org/api/drupal/includes%21bootstrap.inc/function/arg/…
    – RobLoach
    Aug 4, 2015 at 16:34
  • 1
    @RobLoach but arg() doesn't exist in D8 Aug 6, 2015 at 21:21
4

arg(0) returns 'node' and arg(1) returns node nid.

if (arg(0) == 'node' && is_numeric(arg(1))) {
  $nid = arg(1);
}
3

In D8:

$node = \Drupal::routeMatch()->getParameter('node');
2
  • Better wrap the output like shown in drupal.stackexchange.com/a/145826/15055. And also worth to note that this won't work on node preview pages and node revision pages.
    – leymannx
    Nov 26, 2018 at 17:10
  • This is the cleanest answer for d8 if looking for a node.
    – Christian
    May 4, 2021 at 2:53
1

The second method in the currently accepted answer is the cleanest in D7. The first answer:

if ($node = menu_get_object()) {
  // Get the nid
  $nid = $node->nid;
}

is only visually cleaner. In fact, menu_get_object() is calling quite a lot of code and may lead to unforeseen errors. I was using it inside a hook_node_grants() function and ran into a PHP Fatal error:

Maximum function nesting level of '256' reached, aborting!

The explanation, found at https://drupal.stackexchange.com/a/69232/9158

The infinite loop you are noticing is caused from the fact that menu_get_object() causes Drupal to verify the currently logged-in user has access to the node, which causes your implementation of hook_node_grants() to be invoked again, which calls menu_get_object(), which causes your implementation of hook_node_grants() to be invoked again, which...

This was solved by using the second method:

if (arg(0) == 'node' && is_numeric(arg(1))) {
  // Get the nid
  $nid = arg(1);

  // Load the node if you need to
  $node = node_load($nid);
}
-1

Another option, in D7:

function _my_module_get_nid() {
  $path_args = explode('/', current_path());
  //$nid = $path_args[1];
  if(is_int($path_args)) {
    return($path_args[1]);
  }
  // Log that we failed to load a NID.
  else {
    watchdog('my_module', 'Unable to gather NID at: ' . current_path(),  WATCHDOG_WARNING, NULL);
  return FALSE;
  }
}

If you plan to use the function outside your module, do not use the leading _ at the begining of the name of the function.

2
  • 1
    This is the same thing but with an expensive watchdog call on all paths that aren't nodes.
    – beth
    Sep 16, 2014 at 22:34
  • I like to know if my code is failing unexpectedly. I wouldn't want this code being executed on non-nodes, watchdog will show me where that is happening so I can fix it. Otherwise I'll have no trace that this code is running for no reason (on non-nodes). Otherwise it's the same as the D8 method mentioned above. Sep 17, 2014 at 17:31
-1
<?php
if (isset($node->nid) && count($node->nid) > 0){
  $mynodeid = $node->nid;
}
?>
3
  • 1
    Could you please add some "whys" and "hows" to your answer?Code-only answer might work, but it hardly helps to understand one's mistakes.
    – Mołot
    Jan 16, 2015 at 9:06
  • It first checks if the node is defined before executing. Jan 31, 2015 at 17:25
  • count($node->nid) > 0 where $node->nid is an integer doesn't make any sense, since count() counts the number of items in an array. It's would causes a PHP Warning: count(): Parameter must be an array or an object that implements Countable.
    – apaderno
    Mar 31, 2021 at 22:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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