In Drupal 7, if I wanted to get the node id of the currently displayed node (e.g. node/145
) I could get it with the arg()
function. In this case, arg(1)
would return 145.
How can I achieve the same in Drupal 8?
The parameter will have been upcasted from nid to full node object by the time you get access to it, so:
$node = \Drupal::routeMatch()->getParameter('node');
if ($node instanceof \Drupal\node\NodeInterface) {
// You can get nid and anything else you need from the node object.
$nid = $node->id();
}
See the change record for more information.
/taxonomy/term/{tid}
?
menu_get_object
?
Commented
May 2, 2018 at 17:09
{}
in your route. For taxonomy terms the route paramater is called taxonomy_term
, route definition /taxonomy/term/{taxonomy_term}
. Here you can get it like this, \Drupal::routeMatch()->getParameter('taxonomy_term')
.
$node = \Drupal::requestStack()->getCurrentRequest()->get('node');
will correctly load the node.
It is correct to use \Drupal::routeMatch()->getParameter('node')
. If you just need the node ID, you can use \Drupal::routeMatch()->getRawParameter('node')
.
Note on the node preview page, the following doesn't work:
$node = \Drupal::routeMatch()->getParameter('node');
$nid = $node->id();
For the node preview page, you have to load the node this way:
$node = \Drupal::routeMatch()->getParameter('node_preview');
$nid = $node->id();
if you are using or creating custom block then you have to follow this code to get current url node id.
// add libraries
use Drupal\Core\Cache\Cache;
// code to get nid
$node = \Drupal::routeMatch()->getParameter('node');
$node->id() // get current node id (current url node id)
// for cache
public function getCacheTags() {
//With this when your node change your block will rebuild
if ($node = \Drupal::routeMatch()->getParameter('node')) {
//if there is node add its cachetag
return Cache::mergeTags(parent::getCacheTags(), array('node:' . $node->id()));
} else {
//Return default tags instead.
return parent::getCacheTags();
}
}
public function getCacheContexts() {
//if you depends on \Drupal::routeMatch()
//you must set context of this block with 'route' context tag.
//Every new route this block will rebuild
return Cache::mergeContexts(parent::getCacheContexts(), array('route'));
}
By using Service,
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Provides a 'UtilitiesDataService' service.
*/
class MyClass {
/**
* The route match.
*
* @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $routeMatch;
/**
* Constructs a new service.
*
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
* The route match.
*/
public function __construct(RouteMatchInterface $route_match) {
$this->routeMatch = $route_match;
}
public function getNodeId(){
$nid = $this->routeMatch->getParameter('node')->id();
}
}
In services.yml file,
services:
my_module.get_data_service:
class: Drupal\my_module\MyClass
arguments: ['@current_route_match']
\Drupal
. In this case, using the service defined in this answer or the current_route_match service doesn't make any difference, which means the static call isn't removed.
Blocks are context aware and you should be using them. This will allow using the blocks in places where the route itself doesn't have a node but some subsystem provides the context anyways.
Example from core:
/**
* Provides a 'Node Context Test' block.
*
* @Block(
* id = "node_block_test_context",
* label = @Translation("Node Context Test"),
* context_definitions = {
* "node" = @ContextDefinition("entity:node", label = @Translation("Node"))
* }
* )
*/
class NodeContextTestBlock extends BlockBase {
public function build() {
/** @var \Drupal\node\NodeInterface $node */
$node = $this->getContextValue('node');
You can also see how easy it is to get the node. The test this block is used for is instructional: it tests whether the block appears on the preview page. This is not doable with the route match approach as the /node/preview/{node_preview}/{view_mode_id}
route doesn't contain a node at all.
This will also make the node context required so there's no need to check whether there is a node at all. It's possible to make the node optional, of course:
* "node" = @ContextDefinition("entity:node", label = @Translation("Node"), required = FALSE)
the order of options after the first argument does not matter.