4

We have a content type that is added to the drupal system Programmatically when we install one of our custom modules. Essentially the module handle incoming property data from a 3rd party and creates a node entity for each property.

The content type created is named properties and as such its template suggestion shown in Twig debugging is node--properties--full.html.twig, see below:

enter image description here

I am creating a second custom module called lrg_property_display and my intention is that this module will handle all the rendering related functionality as I want to keep the API import related functionality separate from the rendering. My module structure is shown below:

enter image description here

I have created my module and followed a couple sites suggestions that I simply create a template file in my module and in the .module file implement the HOOK_THEME method, which I have done as shown:

function lrg_property_display_theme($existing, $type, $theme, $path)
{
    $theme['node__property_display__full'] = [
        'template' => 'node--property-display--full',
        'base hook' => 'node'
    ];

    return $theme;
}

Clearing cache and refreshing the page though is showing that the theme is not been applied.

Where am I going wrong with this please? I basically need the node--property-display--full.html.twig template within the module to be used whenever a node of the type Properties is viewed.

UPDATE

I added the following code to my theme file (Theme name is white_label) which seemed to produce an error which suggests it 'almost' works, albiet I'd prefer not having to do a suggestion in the theme but want it in the module. I can live with it though if this works for the short/medium term:

function white_label_theme($existing, $type, $theme, $path)
{
    return array(
        'node__properties__full' => array(
            'render element' => 'elements',
            'template' => 'node--property-display--full',
            'base hook' => 'node',
            'path' => drupal_get_path('module', 'lrg_property_display') . '/templates',
        )
    );
}

This then looks for the template node--property-display--full.html.twig but its looking in the main theme directory not in the module, even with the path specification.

The error returned was:

he website encountered an unexpected error. Please try again later.Twig_Error_Loader: Template "themes/custom/white_label/templates/nodes/node--property-display--full.html.twig" is not defined.

Reference image for comment in @Leigh's answer

enter image description here

7
  • In the second example the name of the content type changed, is this correct?
    – 4uk4
    Jan 30, 2019 at 13:04
  • It looks like you’re taking an incoming argument, modifying and returning it - does it need to be passed by reference? &$theme?
    – Kevin
    Jan 30, 2019 at 13:23
  • @4k4 Content type name is still the same and its suggestion is node--properties--full.html.twig. So when a viewer hits a node which is of type properties I want it to use my module template node--property-display--full.html.twig instead. @Kevin I am unsure, the arguments for the theme hook suggest its not by reference, see api.drupal.org/api/drupal/…
    – John Cogan
    Jan 30, 2019 at 13:47
  • If the content type name is the same then use node--properties--full.html.twig in the module, too.
    – 4uk4
    Jan 30, 2019 at 14:10
  • @4k4 - I tried that originally, doesn't get picked up.
    – John Cogan
    Jan 30, 2019 at 14:23

3 Answers 3

4

Isn't your array key wrong? It should be:

 $theme['node__property__full'] = [
    'template' => 'node--property-display--full',
    'base hook' => 'node'
];

If you're wanting to target the "full" display and your content type has a machine name of "property"

I'm doing something similar targetting a node of type "news" and display node "teaser":

function mymodule_theme($existing, $type, $theme, $path) {
  return [
   'node__news__teaser' => [
      'template' => 'node--news--teaser',
      'base hook' => 'node'
    ],
  ];
}

And my folder structure is:

/modules/custom/mymodule/templates/node--news--teaser.html.twig

10
  • 1
    Just tried this and it ends up simply using the base node.html.twig * node--42--full.html.twig * node--42.html.twig * node--properties--full.html.twig * node--properties.html.twig * node--full.html.twig x node.html.twig
    – John Cogan
    Jan 30, 2019 at 14:46
  • And you've cleared the cache? As I'm doing essentially the same thing but with the "teaser" display mode and it's working fine
    – Leigh
    Jan 30, 2019 at 14:50
  • Yea I drush cr everytime. Could you show your folder structure for your test module etc so I can compare please? Its possible I have missed something quite small somewhere.
    – John Cogan
    Jan 30, 2019 at 15:07
  • Yeah no problem ive just pasted in exactly what im doing. I think its similar to yours apart from the template file name but that can actually be whatever you want, you just have to specify it in the array in the 'template' key
    – Leigh
    Jan 30, 2019 at 15:16
  • I've done exactly like yours apart from the teaser mode and just doesnt want to work. See last image in question for new structure that matches yours
    – John Cogan
    Jan 30, 2019 at 16:32
1

This should help

function MYMODULE_theme_registry_alter(&$theme_registry) {

        $extension   = '.html.twig';
        $module_path = drupal_get_path('module', 'MYMODULE');
        $files       = file_scan_directory($module_path . '/templates', '/' . preg_quote($extension) . '$/');

        $fs = \Drupal::service('file_system');

        foreach ($files as $file) {
          $template = $fs->basename($file->filename, $extension);
          $theme    = str_replace('-', '_', $template);
          $__expt = explode('__', $theme, 2);
          $base_theme = empty($__expt[0]) ? null : $__expt[0];
          $specific = empty($__expt[1]) ? null : $__expt[1];
          if (!empty($specific) && isset($theme_registry[$base_theme])) {
            $theme_info = array(
              'template'   => $template,
              'path'       => $fs->dirname($file->uri),
              'render element'  => $theme_registry[$base_theme]['render element'],
              'base hook'  => $base_theme,
              'type'       => 'module',
              'theme path' => $module_path,
              'preprocess functions' => $theme_registry[$base_theme]['preprocess functions'],
            );

            $theme_registry[$theme] = $theme_info;
          }
        }
}
0

Have you enabled the theme suggestion?

MYMODULE.module:

// This first function here.

/**
 ** Implements hook_theme_suggestions_hook().
 **/
function lrg_property_display_theme_suggestions_node(array $variables) {
  return [
    'node__properties'
  ];
}

/**
 ** Implements hook_theme().
 **/
function lrg_property_display_theme($existing, $type, $theme, $path) {
  return [
    'node__properties' => [
      'template' => 'node--properties',
      'base hook' => 'node',
    ],
  ];
}

You can also declare a specific template file:

function hook_theme_suggestions_hook(array $variables) {
  return [
    'my_very_specific_template'
  ];
}

function hook_theme($existing, $type, $theme, $path) {
  return [
    'my_very_specific_template' => [
      'base hook' => 'node',
    ],
  ];
}
6
  • 1
    I've just tried this without any success, its rendering the node using the core node template
    – John Cogan
    Jan 30, 2019 at 16:47
  • I would test without the --full part as suggested in the other answer. Disable the module, do you still see the theme suggestions in inspection? Maybe that content type suggestion is already loaded from your theme? Can you break the site with some gibberish in each of the above functions to ensure they are running? In a module, you need to load the theme files and add the theme suggestions. Jan 30, 2019 at 16:51
  • XDebug didnt stop on breakpoints within both the functions, so can only assume the are not been called. Ill disable etc and see what happens.
    – John Cogan
    Jan 30, 2019 at 16:54
  • Maybe need to double check folder names, file names, and function names, etc. for typos. If you type gibberish inside one of those functions you should get a PHP error. Jan 30, 2019 at 17:02
  • Yea I get ParseError: syntax error, unexpected 'return' (T_RETURN) in Drupal\Core\Extension\Extension->load() (line 23 of modules/custom/lrg_property_display/lrg_property_display.module).
    – John Cogan
    Jan 30, 2019 at 17:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.