Score:-1

How can I override a displayed node with the content rendered by a custom module?

de flag

I have a path /application, which is rendered by a custom module (through a combination of theme hook/controller/routing/twig). It's basically a mini-application.

I also have a Drupal node /data, which is a Drupal node with content loaded by Drupal.

However, I need to load the contents of /application at /data. I tried setting the routing of my custom module to use /data instead of /application, but Drupal still loads the Drupal node content at /data rather than the custom module content. The catch is, this particular application uses fields from that node, so I don't want to delete the node. I just want to change what gets rendered when you view the node, but leave it active and editable.

What's the best way to accomplish this?

Hodba Khalaf avatar
eg flag
In order to load variables before the node is rendered, you need to use HOOK_preprocess_node, did you try that?
cn flag
Change the node’s path to something that isn’t /data. Problem solved.
Anton avatar
de flag
@Clive Ideally I'm not changing the node path because I want to retain where the node is used in menus. Is there no way to override the view of a node with a custom module?
Anton avatar
de flag
@HodbaKhalaf I tried that but can't see a way to load everything from a custom module into the node viewer. Any idea how this could be done?
apaderno avatar
us flag
Drupal first uses the path aliases, then the routes defined from modules. If you were to add a node with /admin/config/people/accounts as path alias, you won't see anymore the settings page for the accounts.
Hodba Khalaf avatar
eg flag
@Anton in the preprocessor you can unset the content and set your values generated in the custom module e.g. $variables['VARIABLE_NAME'] then you can theme it with the twig file. if you can share some code, maybe I can give you better feedback.
Score:1
us flag

Since /data is a path alias for a node, Drupal shows that node instead of showing what a controller associated to that path returns. If you were to set a node path alias to /admin/config/people/accounts, Drupal would show that node instead of the accounts setting page.

If you want to change the render array used for a node, you need to implement hook_ENTITY_TYPE_view(). You can compare $entity->id() with the node ID to which you want add data in its render array.

use \Drupal\Core\Entity\EntityInterface;
use \Drupal\Core\Entity\Display\EntityViewDisplayInterface;

/**
 * Implements hook_ENTITY_TYPE_view().
 */
function mymodule_node_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
  if ($entity->id() == 3) {
    // Change $build.
  }
}

You can also find the node ID given its path alias, for example with code similar to the following one.

use \Drupal\Core\Entity\EntityInterface;
use \Drupal\Core\Entity\Display\EntityViewDisplayInterface;

/**
 * Implements hook_ENTITY_TYPE_view().
 */
function mymodule_node_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
  $path = \Drupal::service('path_alias.manager')->getPathByAlias('/data');

  if (preg_match('/node\/(\d+)/', $path, $matches)) {
    if ($entity->id() == $matches[1]) {
      // Change $build.
    }
  }
}

See How can I get the node ID from a path alias? which also explains when to use the path_alias.manager or the path.alias_manager service.

Anton avatar
de flag
Great idea! I was able to load my custom module content instead here by adding to $build. One question I have for this is: inside hook_ENTITY_TYPE_view(), instead of using the $entity->id(), is there any elegant way to use the custom module's routing.yml to get and call the appropriate controller method dynamically? Otherwise I'm hard-coding ids which feels the same as just creating a 'node--3.html.twig' type of override, and also hard-coding what controller and method to load content from.
apaderno avatar
us flag
You can get the node ID given the path alias, as I show in the updated answer. The code is still hard-coding a value (the path alias), but it's easier to set the same path alias on different sites than getting the same node ID for nodes on different sites.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.