26

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?

49

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.

  • 1
    @Letharion Yeah I feel just a little bit guilty every time I do it ;) – Clive May 25 '12 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 '12 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 '12 at 12:20
  • 1
    A single line solution $nid = ($node = menu_get_object()) ? $node->nid : NULL; – timofey.com Dec 5 '13 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 '14 at 23:10
1

In D8:

$node = \Drupal::routeMatch()->getParameter('node');
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);
}
4

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

if (arg(0) == 'node' && is_numeric(arg(1))) {
  $nid = arg(1);
}
-1
<?php
if (isset($node->nid) && count($node->nid) > 0){
  $mynodeid = $node->nid;
}
?>
  • 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 '15 at 9:06
  • It first checks if the node is defined before executing. – cptstarling Jan 31 '15 at 17:25
1

This linked helped me: http://www.webomelette.com/node-id-nid-url-path-alias - Go to Content and filter downt to find the content you want to see the Node ID for and hover over the Edit link. Look down to see the hyperlink your browser tells you it will follow if you click on Edit.

  • Hi Ana, welcome to Drupal Answers. Your answer is good (and I have voted it up for the attempt), however the question is asking how to get the nid programatically since it contains 'from a module' in the title. – Darvanen Oct 24 '14 at 2:47
-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.

  • 1
    This is the same thing but with an expensive watchdog call on all paths that aren't nodes. – beth Sep 16 '14 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. – sheldonkreger Sep 17 '14 at 17:31
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

  • 2
    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. – sheldonkreger Sep 15 '14 at 22:49
  • 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 '15 at 16:34
  • 1
    @RobLoach but arg() doesn't exist in D8 – Pouya Sanooei Aug 6 '15 at 21:21

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.