Updated: Comment #N

Problem/Motivation

Twig has this concept of template include and extends. Currently we have to specify the complete path to a template file to include it. This fact, makes this feature of twig unusable for contrib module and themes.

Twig docs for namespaces

Proposed resolution

Add a twig namespace for each module and theme (somewhere in CoreServiceProvider::registerTwig).

Syntax in templates without namespaces.

  {% extends "core/themes/bartik/templates/node.html.twig" %}

Syntax in templates namespaces.

  {% extends "@bartik/node.html.twig" %}

Remaining tasks

Implementations, Tests, Docs

User interface changes

None.

API changes

None. We do not use include or extends in our templates atm.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

chr.fritsch’s picture

Here is a initial patch. I don't know how to write a test for this, so maybe someone could help

webflo’s picture

Issue tags: +Twig
star-szr’s picture

@dmouse and @jmolivas have done some (as far as I know) related work around this, maybe find them on IRC to share knowledge :)

https://github.com/hechoendrupal/slang/blob/master/lib/Drupal/slang/Plug...

webflo’s picture

star-szr’s picture

Status: Active » Needs work
Issue tags: -Needs reroll +Needs tests

Patch still applies.

chr.fritsch’s picture

joelpittet’s picture

Status: Needs work » Needs review

I'm curious what testbot thinks here. That patch is small, but if it works wooo!

dawehner’s picture

I love this as it would make the life much easier for people which try to integrate some bundles into drupal.

webflo’s picture

dawehner’s picture

  1. +++ b/core/lib/Drupal/Core/Template/TwigEnvironment.php
    @@ -36,6 +36,19 @@ public function __construct(\Twig_LoaderInterface $loader = NULL, $options = arr
    +    $namespaces = \Drupal::moduleHandler()->getModuleList();
    +    foreach (\Drupal::service('theme_handler')->listInfo() as $theme => $info) {
    

    It would be cool to inject these new dependencies.

  2. +++ b/core/lib/Drupal/Core/Template/TwigEnvironment.php
    @@ -36,6 +36,19 @@ public function __construct(\Twig_LoaderInterface $loader = NULL, $options = arr
    +    foreach ($namespaces as $name => $filename) {
    +      $templatesDirectory = dirname($filename) . '/templates';
    +      if (file_exists($templatesDirectory)) {
    +        $loader->addPath($templatesDirectory, $name);
    +      }
    

    What do you think about allowing people to use templates outside of the "templates" directory

  3. +++ b/core/modules/system/lib/Drupal/system/Tests/Theme/TwigNamespaceTest.php
    @@ -0,0 +1,66 @@
    +    // Enabled module
    +    $this->assertTwigTemplate($this->twig->resolveTemplate('@node/node.html.twig'), 'Found node.tpl.php in node module.');
    +
    +    // Enabled theme
    +    $this->assertTwigTemplate($this->twig->resolveTemplate('@bartik/page.html.twig'), 'Found page.html.twig in bartik theme.');
    ...
    +    $this->assertText('This line is from twig_namespace_a/templates/test.html.twig');
    +    $this->assertText('This line is from twig_namespace_b/templates/test.html.twig');
    

    It would be also cool to have a direct test which just checks which template is used, not passive like this.

webflo’s picture

1. Ok, done :)

2. Sure its possible but, we already enforce the templates folder for themes already. Take a look at drupal_find_theme_templates().

3. I am not sure what you mean. The first part of the tests does this already. We could remove the seconds part completely. Because this tests the twig language/syntax and not the actual namespaces.

$this->assertTwigTemplate($this->twig->resolveTemplate('@node/node.html.twig'), 'Found node.tpl.php in node module.');
dawehner’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs tests

2. Sure its possible but, we already enforce the templates folder for themes already. Take a look at drupal_find_theme_templates().

Interesting, I was not aware of that.

3. I am not sure what you mean. The first part of the tests does this already. We could remove the seconds part completely. Because this tests the twig language/syntax and not the actual namespaces.

I agree this is enough test coverage.

star-szr’s picture

FileSize
8.41 KB
1.59 KB

Updated to fix two very minor nitpicks (below). I'd argue that this could be changed to a task, it will especially be useful for subthemes. Thanks for this @webflo and @chr.fritsch!

  1. +++ b/core/modules/system/lib/Drupal/system/Tests/Theme/TwigNamespaceTest.php
    @@ -0,0 +1,66 @@
    +    $this->assertTwigTemplate($this->twig->resolveTemplate('@node/node.html.twig'), 'Found node.tpl.php in node module.');
    

    Should be .html.twig instead of .tpl.php.

  2. +++ b/core/lib/Drupal/Core/Template/TwigEnvironment.php
    @@ -32,10 +34,23 @@ class TwigEnvironment extends \Twig_Environment {
    +    // Set twig path namespace for themes and modules
    

    Missing period per https://drupal.org/node/1354#drupal.

star-szr’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
8.66 KB
3.81 KB

More docs updates and minor changes. The only material change is getting rid of a call to theme() in the tests, see #2173655: Refactor theme() to _theme(); make it a private API to discourage module developers from circumventing the renderable build system. I probably should have just made this a patch review, hope you don't mind @webflo :)

Edit: Interdiff is from #11.

The last submitted patch, 13: 2143557-13.patch, failed testing.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Fine!

webflo’s picture

@Cottser thanks for moving this forward!

webchick’s picture

Category: Feature request » Task
Status: Reviewed & tested by the community » Fixed

Wow! That syntax is definitely much nicer.

While this is sorta feature-y, it's also required to finalize the Twig API, so changing to a task.

Committed and pushed to 8.x. Thanks!

webflo’s picture

Issue tags: +SprintWeekend2013, +#D8MA

Thanks!

webflo’s picture

Issue tags: -SprintWeekend2013, -#D8MA +SprintWeekend2014, +D8MA

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

markhalliwell’s picture

This is awesome. When we get #1308152: Add stream wrappers to access extension files in, we should probably change this format to use the stream wrapper syntax and just pass the path to be resolved by those.

Jeff Burnz’s picture

Status: Closed (fixed) » Active

I can't seem to get this working:

{% extends "@at_core/block.html.twig" %}

This just prints that out where the content should be.

Trying to change the branding block to extend my block.html.twig, both templates are in the base theme /templates directory, but of course my default active theme is a sub theme.

Jeff Burnz’s picture

OK, the problem is clear - you can't have templates in sub directories:

adaptivetheme/at_core/templates/block/block.html.twig will not work.

Probably something to look at in #2291449: Add Twig template inheritance based on the theme registry, enable adding Twig loaders ?

Leaving active for now, however this is a regression from D7.

star-szr’s picture

Status: Active » Closed (fixed)

With the theme registry loader you could just do {% extends "block.html.twig" %}, currently you'd have to add the 'block' directory {% extends "@at_core/block/block.html.twig" %}

This is because the namespace maps directly to the templates directory and nothing more.

I think your use case will be fixed by the theme registry loader so re-closing. Thanks!

Edited to expand code samples and add code tags.