I have my base template
<html>
<head>
.....
</head>
<body>
{% block body_content %}{% endblock %}
{% block debug_output %}{% endblock %}
</body>
</html>
and my page template
{% extends "base.html.twig" %}
{% block body_content %}
.....
{% endblock %}
Now after I have loaded the template I want to add to something to the debug_output block.
{% block debug_output %}
.....
{% endblock %}
Does anyone know how I can do this?
Not using any framework just twig as my template engine.
This is the flow of calling the template I currently have
$loader = new Twig_Loader_Filesystem();
$twig = new Twig_Environment($loader);
$template = twig->loadTemplate($page_template);
/* Add additional template to insert into debug_output block here */
$template->render($vars);
In the end I gave up and the solution I came up with was to not use a block but an object variable and loop over the properties to add the debug info I wanted. This object was merged with $vars and passed in to the $template->render($vars) line.
Related
I have a problem, I am using twig templates and am trying to use blocks to separate my code but I have the following error:
Twig_Error_Loader: Template "index.html.twig" is not defined in "requestchange/main.twig" at line 1
index.html.twig is my main template layout
I have added in: {% block content %}{% endblock %}
then in my main.twig , I am extending the index.html.twig file and then putting my content within another {% block content %}{% endblock %}
Can someone please help me here?
You should understand how Template Inheritance works in Twig.
Here is simple example:
default.twig as a default layout
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
index.twig as a home page
{% extends 'default.twig' %}
{% block title %}Home page{% endblock %}
{% block content %}
<h1>Hello world!</h1>
{% endblock %}
And be attentive with path that you point in the extends tag.
I have two templates, a parent template and a child template.
I want know if its possible to add 'properly' a class to a tag in the parent template from the child template ? and if yes, how ?
By example, if I have this parent.html.twig file :
<body>
{% block body %}{% endblock %}
{% block javascripts %}{% endblock %}
</body>
And this child.html.twig file :
{% extends 'parent.html.twig' %}
{% block body %}
{# ... #}
{% endblock %}
From the child.html.twig file, can I add a class to the body tag ? and how ?
Thanks for help :)
You should modify the parent template adding a block, as example:
parent.html.twig
<body {% block bodyclass %}{% endblock %}>
{% block body %}{% endblock %}
{% block javascripts %}{% endblock %}
</body>
and use in the child:
child.html.twig
{% extends 'parent.html.twig' %}
{% block bodyclass %}class="child-class"{% endblock %}
{% block body %}
{# ... #}
{% endblock %}
You can try in this twigfiddle
Let's say I have these twig templates:
base.twig
{# base.twig #}
<html>
<head>
{% include 'head_js.twig' %}
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
head_js.twig
{# head_js.twig #}
{% block headJS %}
<script src='/js/some-script.js'></script>
{% block headJSExtra %}{% endblock %}
{% endblock %}
page.twig (the one loaded by the controller)
{# page.twig #}
{% extends base.twig %}
{% block content %}
<p>Widget 1</p>
{% include 'widget.twig' with { name: 'foo' } %}
<p>Widget 2</p>
{% include 'widget.twig' with { name: 'bar' } %}
{% endblock %}
widget.twig
{# widget.twig #}
{% if wigetAlreadyIncluded is not defined %}
{% block headJSExtra %}
{{ parent() }}
<script src='/js/widget.js'></script>
{% endblock %}
{% set widgetAlreadyIncluded = true %}
{% endif %}
<p>My name is {{ name }}</p>
This code doesn't work (can't use parent() in widget.twig as it's not extending or using any template), but it should illustrate what I'm trying to achieve. The basic idea is:
In order to work, widget.twig requires a js library to be loaded in as a tag in the .
The widget can be rendered several times in one page.
Other widgets should be able to also add their own tags in the in this fashion, but they shouldn't override previous added tags (they should be appended).
I don't want to add more than once any tag required by any widget found in the page.
Any ideas on how can I achieve this would be greatly appreciated. I've read two SO related questions with no luck at all.
https://stackoverflow.com/a/29132604/4949663
https://stackoverflow.com/a/18160977/4949663
I finally got a good answer in the twig github issue tracker.
https://github.com/twigphp/Twig/issues/2275
I have layout template
<html>
<body>
{% block content %}{% endblock %}
</body>
</html>
And many child templates like this
{% extends 'layout/default.twig' %}
{% block content %}
<p>content</p>
{% endblock %}
And it's very annoying that every single child template in Twig must include {% block content %}...{% endblock %} to be extended by parent block, otherwise there will be error: A template that extends another one cannot have a body.
Is there any solution to bind all child template output(that is not located in any block) in some variable, and then use it to paste in parent template? Like this:
Layout
<html>
<body>
{{ _context.childOutput }
</body>
</html>
Child
{% extends 'layout/default.twig' %}
<p>content</p>
It will make child templates code more compact and there will be no dependency from parent templates blocks name.
UPD Submitted new issue on Twig's GitHub https://github.com/twigphp/Twig/issues/2027
The 2 lines you have in each template allows you aswell to redefine many blocks in one template. I can't see how the solution you want can do that.
<html>
<head>
{% block meta %}{% endblock %}
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
you can see include and embed but if you really have only one block in your templates twig is maybe not the solution you need
While seeing in this GitHub issue that you define variables in the controller, I had the following idea. I'll assume that the child template only contain static code since you didn't describe this point.
You can modify the function in your controller in order to fetch the content of the child template then pass it to the parent template directly:
function acmeAction()
{
// …
return $this->render(
'AcmeBundle:layout:default.html.twig',
array(
'title' => $title,
'description' => $description,
'content' => file_get_contents(
$this->container->get('kernel')->locateResource(
'#AcmeBundle/Resources/views/layout/child.html.twig'
)
)
)
);
}
And the parent template:
<head>
<title>{% block title %}{{ title }}{% endblock %}</title>
<meta name="description" content="{% block description %}{{ description }}{% endblock %}" />
</head>
<body>
{% block body %}{{ content }}{% endblock %}
</body>
This way you won't need to define the parent in the child template.
You can define some variables in the child and display them in the parent:
Layout
<html>
<body>
{{ myValue }
</body>
</html>
Child
{% set myValue %}
<p>content</p>
{% endset %}
{% include 'layout/default.twig' %}
This works because:
Included templates have access to the variables of the active context.
Source: http://twig.sensiolabs.org/doc/tags/include.html
And it's very annoying that every single child template in Twig must include {% block content %}...{% endblock %} to be extended by parent block
While it may sound annoying when you only have one variable, you will see the benefits of this approach when you will have to define also the title of the page, the JavaScript code, etc. In this case the use of multiple {% block … %} is really useful.
See this example:
Layout
<html>
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
{% block content %}{% endblock %}
{% block javascript %}{% endblock %}
</body>
</html>
Child
{% extends 'layout/default.twig' %}
{% block title %}
My title
{% endblock %}
{% block content %}
<p>content</p>
{% endblock %}
{% block javascript %}
<script>…</script>
{% endblock %}
This is my base.html:
<html>
<head>
{% block head %}
{% endblock %}
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
This is my meta.html:
{% extends 'templates/base.html' %}
{% block head %}
{% if page == 'index' %}
<meta name="mysite.com" content="{{page}}"></meta>
{% else %}
<meta name="mysite.com" content="other page"></meta>
{% endblock %}
This is my index.html:
{% extends 'templates/base.html' %}
{% block body %}
......
{% endblock %}
This is my view:
#view_config(route_name='index', renderer='templates/index.html', permission='view')
def index(request):
return dict(page="index")
Extending the body works, but the meta tags are not showing up at all. What am I doing wrong?
As per Jinja2 documentation on extends, "The extends tag can be used to extend a template from another one. You can have multiple of them in a file but only one of them may be executed at the time."
When you load index.html from your view, the templating engine assesses index.html. It sees {% extends 'templates/base.html' %} in index.html and uses the blocks within index.html to replace same-name blocks of the parent/extended template (base.html).
So index.html says to use base.html as the skeleton template, but to replace {% block body %} in the parent (base.html) with its own {% block body %}.
Nowhere in this instruction (neither in base.html, nor index.html, nor the view code) does meta.html get mentioned. The templating engine isn't analyzing all the templates in your directory structure to see how it can plug things in. It is only using your explicit directives.
To be explicit about using meta.html, you can use the include directive (documentation found here) in base.html. Your base.html would then look like this:
<html>
<head>
{% include 'templates/meta.html' %}
{% block head %}
{% endblock %}
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
This would pull in meta.html and replace the same-name blocks of the skeleton (base.html) with the ones that were retrieved from the included template (meta.html).
In addition, the extends statement within meta.html needs to be removed, so it doesn't create a circular template inclusion.