1

Short version; I am trying to override the default page.html.twig (in D8) for a controller from my module and the following examples I've found have not worked:

My company is developing a custom module to embed a React app we originally built for another system inside the admin side of Drupal. As such, we would like to keep the admin navigation visible but the main body of the page should just be the react app.

So far, I have successfully embedded the app as the content of a page, but still have the page's header, footer, breadcrumbs, etc. I'm not sure if I'm declaring my module's theme incorrectly, or if my naming is wrong for my template, or something else.

Result of /hello is not using overridden page twig

Thanks in advance!

Module name: my_module


my_module.info.yaml

name: Overriding page module 
description: "Module with a template that overrides the default page.html.twig" 
package: mystuff

type: module 
core: 8.x

my_module.module

function my_module_theme() {
    $theme['page__my_module'] = [
        'template' => 'page--my_module',
    ];

    return $theme;
}

my_module.routing.yml

my_module.content:
  path: '/hello'
  defaults:
    _controller: '\Drupal\my_module\Controller\HelloController::content'
    _title: 'Hello World'
  requirements:
    _permission: 'access content'

templates/page--my_module.html.twig

{#
  Taken from https://api.drupal.org/api/drupal/core%21themes%21seven%21templates%21page.html.twig/8.2.x
#}

  <header class="content-header clearfix">
    <div class="layout-container">
      {{ page.header }}
    </div>
  </header>

  <div class="layout-container">
    {{ page.pre_content }}
    {{ page.breadcrumb }}
    <main class="page-content clearfix" role="main">
      <div class="visually-hidden"><a id="main-content" tabindex="-1"></a></div>
      {{ page.highlighted }}
      {% if page.help %}
        <div class="help">
          {{ page.help }}
        </div>
      {% endif %}
      <h1 style="color:pink;">WHY DOESN'T THIS TEMPLATE GET USED!?</h1>
      {{ page.content }}
    </main>

  </div>

src/Controller/HelloController.php

<?php

namespace Drupal\my_module\Controller;

use Drupal\Core\Controller\ControllerBase;

class HelloController extends ControllerBase {
    public function content() {
        return array(
            '#type' => 'markup',
            '#theme' => 'my_module',
            '#markup' => $this->t('Hello World!')
        );
    }
}

UPDATED

Thanks to @kiamlaluno, I found I could use the theme suggestions hook to tell drupal what theme to apply. I changed my_module.module to:

<?php

function my_module_theme_suggestions_page(array $variables) {
  $path = explode('/', trim(\Drupal::service('path.current')->getPath(), '/'));
  if (isset($path[0]) && $path[0] == 'hello') {
    return 'page--my-module';
  }
} 

function my_module_theme() {
    $theme['page--my-module'] = [
        'template' => 'page--my_module',
    ];

    return $theme;
}

and removed the #theme item from the controller's render array. It works now!

1
  • I almost want to say the template name should be page--my-module.html.twig. At the same time, have you enabled twig debugging to see if this suggestion makes it into the source output of the page?
    – Kevin
    Commented Apr 12, 2017 at 20:51

1 Answer 1

2

What the code is missing is the code that sets those variables the template file is using. Since you are using page--mymodule as template name, the module needs to implement template_preprocess_page__mymodule().

Alternatively, you can suggest a template file using hook_theme_suggestions_page().

function my_module_theme_suggestions_page(array $variables) {
  $path = explode('/', trim(\Drupal::service('path.current')->getPath(), '/'));
  if (isset($path[0]) && $path[0] == 'hello') {
    return 'page--mymodule';
  }
} 

Implementing hook_theme_suggestions_page() like I show, page--mymodule.html.twig will get the variables set in template_preprocess_page(), which are the same variables passed to page.html.twig.

1
  • Hats off to you wise one! That was exactly what I needed.
    – turnerd18
    Commented Apr 13, 2017 at 13:54

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.