0

EDIT: see two paragraphs below to what I managed to get

I can't find a way to use single template for few but not all content_types. Let's say I have content_types A, B, C and D. I want to use default node.html.twig for A and B and node--other.html.twig for C and D. Later, when I add content_type E and F, I want E to use default template and F to use custom template. If I understand things properly, neither node--page.html.twig nor node--content_type.html.twig help me. I want proper template selected when user visits http://server/node/N without any other combinations.

It could be solved very easily if templates allowed wildcards and template called node--special%.html.twig would match all content_types with name starting with "special", and node.html.twig would be used for all other types.

Big thanks to Hudri.

I implemented his suggestions, I've added my_module_theme() hook (?) and it nearly works. The problem is that I don't get any data on this page. I'm using bootstrap theme. I copied node.html.twig into my_module/templates, renamed it to node--dynview.html.twig. I added:

node.f: {{ node.field_parm_eht }} cont.body.0: {{ content.body.0 }}

to see if it works. "node.f" and "cont.body.0" are displayed, but no other data is present. My hook_theme() looks like this:

function abc_theme() {
  $theme['node__dynview'] = [
          'template' => 'node--dynview'
  ];
  return $theme;
}

I've seen that there is 'variables' key available, but no matter what I pass there I don't get any content. I understand that what I put there are default values for my variables accessible to the template (I checked and they are available), but how can I tell Drupal to pass my all default variables for node.html.twig template (like content, node and what not).

FINAL UPDATE

I got it. I changed hook_theme to be:

function abc_theme() {
  $theme['node__dynview'] = [
    'template' => 'node/node--dynview',
    'render element' => 'elements',
    'base hook' => 'node',
  ];
  return $theme;
}

And it works as expected. Great.

EDIT: Question rewritten to give less details.

I need to override template for /node/n to present nodes of some content_type differently. content_type is not known in advance. I don't want to create separate view for each content_type. I don't want to override default node.html.twig from theme, as theme can change. How can it be done?

OLD QUESTION:

I have the following scenario: administrator creates new content_type (and possibly marks it somehow, whatever works). This content_type is just a representation of something else, lets say stock-exchange listings for some company. I don't want to keep this data in my database, but I want to display this information when this entity is displayed (so some View like Content (/node) page). I believe that I should do something like this:

  • mark created content_types somehow
  • create custom Twig template
  • again somehow force Twig to used this new template to display only marked content_types
  • use javascript to fetch data from external source using passed node's fields as information what should be fetched

My questions are:

  • how should I mark my content_types (new ones can be created by administrator) so that they are picked up by this mechanism
  • and most importantly, how should I name my template? I'm completely lost as to how Twig picks templates in Drupal 8 and it seems that documentation is scarce.

Thanks in advance.

EDIT: More explanation.

My understanding of Drupal is such that each there are multiple "views" on content. And these views are suitably named Views in Drupal parlance. Also I understand that Views mainly present multiple items, not necessarily, but usually of the same content_type. So there is for example View for all (or some according to some criteria) Articles or Products. There are also displays - I think that they are meant to represent single content_type - again e.g. Article or Product. Basically what I want is to create custom display for content_type - this would include some custom Javascript code (and things not normally available in Drupal, like dynamic charts updated in real time), so I suppose it can't be simply configured from inside Drupal admin panel and some code must be written. If I'm not mistaken, such display should be created using Twig templates. It seems that if I'm simply interested in such custom display (view? page? - I can't grasp the difference yet), I can create template called "node--MYTYPENAME.html" and place it in proper folder (I don't know where yet, but this can be read in tutorials and I can check how other modules do it). Template variables would be used to provide data about Node (object) that should be display, and all other things I talked about (dynamic charts) would be implemented in Javascript and would fetch data from proper source using fields from this Node.

This seems relatively easy and I believe that if I spend some time on it I'll be able to do it. But this is only part of what I need to do. Here comes part two.

This content_type is not the only one content_type with this behavior, there are other types. Of course I could copy this template and use it repeatedly, such things are done everyday. But site will be operated by an administrator that has no access to the code, and he needs an ability to add other content_types that should use exact same page (data sources, values and their meaning is different, but mechanisms can stay the same as long as returned values are date/value pairs). I checked and content_types must be different, this is out of the question. So next part of my question is how to use single template for multiple content_types. I have written above that I could create "node--MYTYPE.html" template, but it won't work - MYTYPE is single content_type.

My current favorite solution is (but I also don't know how to do it, yet) to create custom page (so probably add route and some PHP code behind it) that accepts any NID (NodeId if I'm not mistaken), checks it's content_type (so loads object and calls bundle()) and if it starts with for example "dynobj_" it should load my custom template passing this object as an argument (and template does its own thing), otherwise it should call default template.

Or maybe I should somehow replace default template for all nodes and place there only logic that would include original template if content_type name does not start with "dynobj_" and include my custom template otherwise.

I hope this explains my problem better.

  • The way templates are selected for entities, particularly nodes, is well documented. Secondly, why not use Feeds? – Kevin Jan 3 at 23:31
  • What are Feeds in this context? Module, library? And I cannot find documentation for how templates are selected - I am quite new to Drupal and not all documentation sources are obvious to me. Do you mean drupal.org per chance? There is a lot of documentation and I couldn't find anything. Maybe I've been using wrong terms? Could you point me to something that would let me get started? – Jędrzej Dudkiewicz Jan 3 at 23:37
  • 1
    Feeds is a module. drupal.org/project/feeds – Kevin Jan 3 at 23:41
  • @kevin I assume that by Feeds you mean module. It seems that it is used for data import - I don't want to store this data. I want to present it on my custom page to the user by downloading it from other site - in this case this data is in other system that I don't control but have full access to data using rest api. – Jędrzej Dudkiewicz Jan 3 at 23:42
  • 1
    Like kevin said templates naming convention is pretty well documented drupal.org/docs/8/theming/twig/twig-template-naming-conventions. The rest of the question seems very vague to me. There is too much left up to our imagination, please make an attempt to set what you describe on a local drupal installation and come up with specific questions. Feeds are indeed importing the content to create nodes. – GiorgosK Jan 4 at 14:27
1

You can create your own template suggestions based on any logic you want:

function MYMODUDLE_theme_suggestions_node_alter(array &$suggestions, array $variables) {
  $node = $variables['elements']['#node'];

  if (strpos($node->bundle(), 'SPECIAL_NAME') === 0) {
    $MY_SUGGESTION = CALCULATE_SOMETHING($node->bundle());
    array_splice($suggestions, 3, 0, 'node__' . str_replace('-', '_',$MY_SUGGESTION ) . '__' . $variables['elements']['#view_mode']);
    array_splice($suggestions, 3, 0, 'node__' . str_replace('-', '_',$MY_SUGGESTION ));
  }
}

Replace UPPERCASE stuff with your own needs. The array_splice(...) part is needed to properly weight your new suggestion (your new suggestion should be chosen over node--BUNDLENAME.html.twig but not over node--ID.html.twig).

<!-- FILE NAME SUGGESTIONS:
   * node--ID--VIEWMODE.html.twig
   * node--ID.html.twig
   * node--MY_SUGGESTION --VIEWMODE.html.twig
   x node--MY_SUGGESTION .html.twig
   * node--BUNDLENAME--VIEWMODE.html.twig
   * node--BUNDLENAME.html.twig
   * node--VIEWMODE.html.twig
   * node.html.twig
-->

You can also do the same procedure based on a field value, e.g. $node->get(...)->value (but check for $node->hasField(...) first)

  • Please see my comment, I got it nearly working but data is not displayed (so probably not passed to the template). – Jędrzej Dudkiewicz Jan 9 at 20: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.