I can modify the menu item title implementing the hook_menu_links_discovered_alter() hook, as illustrated in this screenprint:

enter image description here

I changed the menu item title to "Article (Only One Article can be created and edited)".

But the problem is that the same item is shown also in the /node/add page but the title of that link is not changed because it is shown by a controller. As illustrated in the above image also, the menu links are changed but the link in the /node/add page remains without changes, which is still just "Article".

How I can change that value also, i.e from "Article" to "Article (Only One Article can be created and edited)", so that it matches with the menu item title?


2 Answers 2


You should copy template_preprocess_node_add_list() into your module or theme and customize. I would advise against trying to change the value in the node type because it's the name of the bundle type across the site. It will show many places you don't want to update.

For example, to update the article link:

function mytheme_preprocess_node_add_list(&$variables) {
  foreach ($variables['content'] as $type) {
    if ($type->id() == 'article') {
      $variables['types'][$type->id()] = array(
        'label' => $type->label() . ' (Only one article can be created and edited)',
        'type' => $type->id(),
        'add_link' => \Drupal::l($type->label() . ' (Only one article can be created and edited)', new Url('node.add', array('node_type' => $type->id()))),
        'description' => array(
          '#markup' => $type->getDescription(),

Another alternative to the preprocess function is just to copy /core/modules/node/templates/node-add-list.html.twig into your theme and add your custom rules there.


Due to the question's particular requirements, I'm adding another solution that works without altering the seven theme (that conflicts with my solution above). In the solution below, we alter the output of $node_type->label() conditionally:

function mymodule_entity_type_alter(array &$entity_types) {
  $entity_types['node_type']->set('label_callback', 'mymodule_node_type_label');

function mymodule_node_type_label(NodeType $type) {

  if (\Drupal::routeMatch()->getRouteName() == 'node.add_page' && $type->id() == 'article') {
    return $type->get("name") . ' (You can only add one of these)';
  return $type->get("name");


Here's another solution that works with the seven theme. You can alter the particular node types you like in the preprocess function in your custom module. This will only alter their labels within this context.

function mymodule_preprocess_node_add_list(&$variables) {
  $article_type = $variables['content']['article'];
  $variables['content']['article']->set('name', $article_type->get('name') . ' (Only one article can be created and edited)');
  • thanks, I'm doing a custom module, not a custom theme, the problem is that if seven theme is active it use another variables for the template and always rewrite the module_preprocess variables. Commented Aug 18, 2017 at 15:59
  • take a look inside seven_preprocess_node_add_list and you will see Commented Aug 18, 2017 at 16:00
  • Yes, that's why I added the 'label' key. I think you will need to create a new admin theme to get this approach to work. Or copy seven and customize as a custom admin theme.
    – oknate
    Commented Aug 18, 2017 at 16:00
  • 'emptied' is change the code in the seven theme? Commented Aug 18, 2017 at 16:02
  • Sorry I changed the comment. So you want this module to a contrib module, so it has to work with every theme?
    – oknate
    Commented Aug 18, 2017 at 16:02

While @oknate answer is perfect for the original question, in this case an approach in a module could be to replace the NodeController class with a custom class, and use in addPage() a custom template or return a build array with the links directly:


$build = [
  '#theme' => 'node_add_list_custom',

Then set the custom controller class for the route node.add_page in a RouteSubscriber .

  • This is a workable solution, but is not ideal for a contrib module.
    – oknate
    Commented Aug 18, 2017 at 17:02
  • @oknate, I agree, your second update is the best solution, overwriting the value in the object (btw. if you put the object in a variable, you can use set() on it, because objects are always a reference). I would upvote again, if it was possible.
    – 4uk4
    Commented Aug 18, 2017 at 17:57

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.