5

I'm trying to create a module which adds a page, the controller works but I cannot render a twig template for it.

The page layout is displayed without the page I created and this warning is reported in the logs:

"Theme hook eu_calendar not found."

but I do have the hook defined

This is the controller:

class EuCalendarController extends ControllerBase {

    public function index() {
        return [
            '#title' => 'my title',
            '#theme' => 'eu_calendar',
            '#description' => 'description test',
        ];
    }
}

Module file:

function eu_calendar_theme($existing, $type, $theme, $path) {
    return [
        'eu_calendar' => [
            'template' => 'index',
        ],
    ];
}

I also tried adding variables like

function eu_calendar_theme($existing, $type, $theme, $path) {
    return [
        'eu_calendar' => [
            'variables' => [
                'test_var' => NULL,
            ],
            'template' => 'index',
        ],
    ];
}

What am I missing here?

And do I need to configure anything with the regions, I want my module to be displayed in the content region by default...

Any documentation or tutorial is also welcome, I read a bunch of them none of them is explaining the options and details.

4
  • You are missing render element/variables. Template is redundant.
    – user21641
    Sep 29, 2017 at 8:16
  • @IvanJaros I tried adding variables, nothing changed. I want /modules/eu_calendar/templates/index.html.twig to be rendered so I thought 'template' => 'index' is about that...
    – madpoet
    Sep 29, 2017 at 8:20
  • You sure the file saved to the correct server?
    – No Sssweat
    Sep 30, 2017 at 9:34
  • I had saved the file as...mymodule.theme *facepalm* Just to clarify, it's supposed to be saved in the mymodule.module. Mar 27, 2018 at 1:16

4 Answers 4

2

myModule.module

function myModule_theme($existing, $type, $theme, $path) {    
return array(
 'pagina_3' => array(
   'variables' => array(
     'titulo' => 'title', 
     'descripcion' => 'description',
     'formulario'   => NULL
      ),
    'template' => 'pagina_3'
   )
  );


}

mymodule/templates/pagina_3.html.twig

<div class="row">

    <div class="col-md-6">
        <h2>{{ titulo }}</h2>
        <p>{{ descripcion }}</p>
    </div>

    <div class="col-md-6">
        {{ formulario }}
    </div>

</div>

myModuleController.php

public function verPagina3() {

    $form = $this->formBuilder()->getForm('Drupal\myModule\Form\InsertarGastoForm');

    // Le pasamos el formulario y demás a la vista (tema configurado en el module)
        return [
            '#theme' => 'pagina_3',
            '#titulo' => $this->t('Formulario crear empresa'),
            '#descripcion' => 'Formulario para crear una nueva empresa en Drupal 8',
            '#formulario' => $form
        ];


   }
1
  • 3
    '#titulo', '#descripcion', '#formulario'. It's news to me that Render Arrays allow using Spanish words as properties.
    – No Sssweat
    Sep 30, 2017 at 9:15
2

I guess I couldn't be able to clear the caches or something. I changed the hook name, uninstalled the module and installed it back, cleared the caches, restarted php-fpm and memcached etc. and it started working somehow.

For reference this is how theming works, may help other newcomers like me:

First the theme and the variables that needs to be passed is defined inside the *.module file. The trick is the variables key, without it Drupal ignores the definition.

The key of the array is also the name of the twig file by default, which can be overridden with template. So no need to pass template if it's the same with the key.

The theme definition to be rendered is defined inside the controller with #theme. Any variable that is not defined in the theme definition are not sent to the template even it's sent in the controller.

So the final working code is:

Module: (modules/eu_calendar/eu_calendar.module)

function eu_calendar_theme($existing, $type, $theme, $path) {
    return [
        'index' => [
            'variables' => [
               'featured' => [],
               'events' => [],
            ],
        ],
    ];
}

Controller: (modules/eu_calendar/src/Controller/EuCalendarController.php)

namespace Drupal\eu_calendar\Controller;

use Drupal\Core\Controller\ControllerBase;

class EuCalendarController extends ControllerBase {
    public function index() {
        return [
            '#theme' => 'index',
            '#events' => ['event1', 'event2'],
            '#featured' => ['featured1', 'featured2'],
        ];
    }
}

Template: (modules/eu_calendar/templates/index.html.twig)

<h3>Featured Events</h3>
<ul>
    {% for featured_event in featured %}
    <li>{{ featured_event }}</li>
    {% endfor %}
</ul>

<h3>Events</h3>
<ul>
    {% for event in events %}
    <li>{{ event }}</li>
    {% endfor %}
</ul>
4
  • I just had the same thing in a Drupal 10 site... I built and installed loads of the module without a .module file... And then added the file with a correct theme hook but the hook never fired... I wonder if Drupal caches that there is no module file during install and then forever doesn't look for one again during cache clears?
    – Nick
    Dec 20, 2022 at 9:49
  • I also experienced this in a Drupal 10 site. Some combination of repeatedly uninstalling and reinstalling the module, running cron and clearing the cache eventually fixed it. Clearing the cache was not, by itself, sufficient to fix the issue.
    – arnoldbird
    Jun 20, 2023 at 15:50
  • UPDATE: For me, the problem returns again on the next cache clear. Drupal can't see the template at times.
    – arnoldbird
    Jun 20, 2023 at 15:55
  • UPDATE-2: I had to change the name of my module to fix this. Now when I clear the cache, the problem doesn't come back.
    – arnoldbird
    Jun 20, 2023 at 16:26
1

This is the controller:

public function index()
{
    $build['myelement'] = array(
        '#theme' => 'eu_calendar',
        '#title' => 'my title',
        '#description' => 'description test',
    );
    return $build;
}

Module file:

function eu_calendar_theme($existing, $type, $theme, $path)
{
    return array(
        'euCalendar' => array(
            'template' => 'index',
            'path' => $path . '/templates',
            'variables' => array(
                'title' => NULL,
                'description' => FALSE,
            ),
        ),
    );
}
0

I had a similar issue, when implementing templates for a custom block in Drupal 10.1. I propose here two important lessons I have learnt while solving it.

Matching (some) strings

Theme name, which is the value of the array element labelled #theme defined in controller's class (file MyController.php), must exactly match the name of hook returned by hook_theme() (function my_module_theme(), declared in file my_module.module).

Please, let me stress about this, as in my case it was causing the error!

Indeed I was confused by that automatic substitution of dashes instead of underscores, and initially I was incorrectly putting dashes (e.g. my-module--my-entity--card) when declaring theme name inside controller's class (MyController.php), as I would do when naming template files. But hook's name returned by my hook_theme() function (my_module_theme() from my_module.module) had underscores in place of dashes (i.e. my_module__my_entity__card) - as per the common convention of using underscores for hooks names. This way I experienced the error "Theme hook my-module--my-entity--card not found.". Then, to solve it and finally pick up the my-module--my-entity--card.html.twig template file, I simply had to rewrite declaration of theme name in controller's class (MyController.php) to my_module__my_entity__card.

Please note that, as already written in another answer, programming hook_theme() to also returns an array element labelled template is needed only if you desire to apply a template with different filename (not the same as the theme - except for underscores, which are turned to dashes).

Rebuilding cache

As usual when working wiht Drupal's templates, you do have to refresh Drupal's cache (either by running the command drush cr, or through the web interface) after you have added any new Twig template files to your /templates directories. Later, if you have properly set options for development, you do not really need to refresh cache after jsut saving changes to templates.

It is also worth mentioning that you will need to update Drupal's cache as well, whenever you add/rename a variable (to be passed to the template) into section variables of the array returned by function hook_theme() in module's file.

If you add a variable to the hook_theme(), but omit to rebuild the cache before using that variable in templates, Drupal will not raise any error; it will just treat the variable as null, although your controller might have assigned values to that variable.

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.