I'm trying to make a bootstrap theme for PhileCMS which uses Twig. Right now I'm working on the menu. I've been searching to find out how to make a page active, and I've been seeing stuff about blocks. Right now my index.html looks something like this
{% include 'header.html' %}
<body>
{% include 'nav.html' %}
<div class="container"}
{{ content }}
{% include 'footer.html' %}
My nav.html looks something like this:
<div class="header clearfix">
<nav>
<ul class="nav nav-pills pull-right">
<li role="presentation"><a class="{% if app.request.attributes.get('_route') starts with 'home' %}active{% endif %}">Home</a></li>
<li role="presentation"><a class="{% if app.request.attributes.get('_route') starts with 'about' %}active{% endif %}">About</a></li>
<li role="presentation"><a class="{% if app.request.attributes.get('_route') starts with 'contact' %}active{% endif %}">Contact</a></li>
</ul>
</nav>
<h3 class="text-muted">{{ site_title }}</h3>
</div>
Is this proper coding practice, or should I be doing something with blocks? I don't really understand how blocks work.
You can include whole new template with new blocks. - That is what include do. You inject a template or piece of template defined in other file. So:
{% include 'nav.html' %}
will inject whatever you have put there and it will replace this whole phrase, this line of code with content of nav.html.
On the other hand when you use {% block body %} for example you override this body block which is inherited from parent template. For example:
If you have block named body in base.html.twig and you will inherit from it like this in another template(let's say blog.html.twig):
{% extends 'base.html.twig' %}
and then do this:
{% block body %}
Hello World
{% endblock %}
You will put this hello world inside of body block in base.html.twig.
I hope it's now clear to you.
P.S
If you want to use twig make sure you use twig extension!
If you are asking for best-practices, then as mentioned in the Symfony's Templating documentation:
When building your application, you may choose to follow this method or simply make each page template extend the base application template directly (e.g. {% extends 'base.html.twig' %}). The three-template model is a best-practice method used by vendor bundles so that the base template for a bundle can be easily overridden to properly extend your application's base layout.
The idea behind this is to have:
1- a base template (level 1)
2-A layout template (level 2)
3-An individual template (level 3)
Here is a sample code that illustrates this (originally from the Symfony2) documentation
{# layout.html.twig #}
{% extends 'base.html.twig' %}
{% block body %}
<h1>Blog Application</h1>
{% block content %}{% endblock %}
{% endblock %}
{# index.html.twig #}
{% extends 'layout.html.twig' %}
{% block content %}
{% for entry in blog_entries %}
<h2>{{ entry.title }}</h2>
<p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}
p.s: Even tough you wouldn't be dealing with Symfony2, but IMHO the principle should be the same, since we are using the Twig templating engine.
Related
I have a twig file that extends base
{% extends "base.twig" %}
{% block content %}
<div> all articles </div>
{% for blog in blog_articles %}
<div><i> {{blog.post_title }}</i></div>
{% endfor %}
{% endblock %}
base.twig has an include for my global js and in my article.twig above i want to be able to add template specific JS that will appear below the global js that is in an include in base.twig
Can this be done?
To answer my own question i did this
in the base.twig
{% include 'globaljs.twig' %}
{% block javascript %}{% endblock %}
Then in the article.twig where i call the javascript block i just add my page scripts. simple
Problem
In navbar.html.twig I have a block that looks like this:
//navbar.html.twig
{% block back_link %}{% endblock %}
This navbar is included by my base.html.twig.
//base.html.twig
{% include navbar.html.twig %}
And then my page template extends the base.
//page.html.twig
{% extends base.html.twig %}
...
{% block back_link %} Things i want in the navbar. {% endblock %}
But the things I want in the navbar don't show up in the navbar, because it's included by the base, so there's no parent/child relationship there.
Question
What's a good (or any) way to let me override a block in an included template in an extended template?
if you understand your idea right, you want to have some reusable content for a navbar, separated to navbar.html.twig that will possible to use in several templates?
So you can do it with "use" http://twig.sensiolabs.org/doc/tags/use.html
In navbar.html.twig
//navbar.html.twig
{% block back_link %}{% endblock %}
In base.html.twig.
//base.html.twig
{% use '::navbar.html.twig' %}
{{ block('back_link') }}
In page.html.twig
{% extends '::base.html.twig' %}
{% block back_link %} Things i want in the navbar. {% endblock %}
On some of my pages I want to embed a toolbar with some generic functionality like sharing, reporting and bookmarking. Currently I do it like this
{# page-detail.html.twig #}
{% extends 'layout.responsive.html.twig' %}
{% block content %}
{% include "toolbar/index.html.twig" with {'foo':'bar'} %}
{# further content... #}
{% endblock %}
As the features of the toolbar require some information about the context it's embedded in, I pass this information in the with-clause. So far so good.
Now, all the buttons are invoking some JavaScript on clicking. Modal windows are popping up, dialogs are displayed, etc. I would like to put the related JS inside the toolbar template but here is the problem:
All my JS-libraries are loaded at the bottom of the page before the closing body-tag. Means, in my toolbar template I have no access to them.
So I thought of the following solutions which I am not really happy with:
move the inclusion of the JS-libraries to the top (loading js slows down page display, also JS would be scattered)
put the respective JS in the javascripts-block in "page-detail.html.twig" (toolbar code is separated from the template code and mixed with the JS-Code needed there)
use the "embed"-Tag and define a JS-Block in the toolbar-Template (won't help as I can access the blocks in the embedding parent template only within the "embed"-Tag)
use the "use"-Tag instead. Well that sounds best so far, however, Code would look like this (assuming toolbar-template defines the blocks "toolbar_content" and "toolbar_js"):
Code:
{# page-detail.html.twig #}
{% extends 'layout.responsive.html.twig' %}
{% use "toolbar/index.html.twig" %}
{% block content %}
{% block toolbar_content %}
{{ parent() }}
{% endblock %}
{# further content... #}
{% endblock %}
{% block javascripts %}
{{ parent() }}
{% block toolbar_js %}
{{ parent() }}
{% endblock %}
... local JS
{% endblock %}
Also in this solution I cannot pass the environment variables anymore using the "with"-clause as it is now used for resolving name-conflicts of the blocks.
I feel like I am missing something. How is it done right? It seems like such a common task.
Additional information
I think not essential for the question but for more clarity, here is how my layout template looks like (not complete just the relevant blocks).
{# layout.responsive.html.twig #}
{% block stylesheets %}
{# bootstrap.css, custom.css, ... #}
{% endblock %}
{% block content %}
{% endblock %}
{% block javascripts %}
{# jquery, bootstrap, ... #}
{% endblock %}
And my toolbar:
{# toolbar/index.html.twig #}
<div class="toolbar btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-default" data-toggle="modal" data-target="#report">Report</button>
</div>
<!-- more buttons -->
</div>
Is it possible to override a template block from a twig extension? How do I do it?
Edit:
I have a block in my master layout template, it is called {% block emailMenu %}, the question is, is it possible to override this block, not from another template but from inside a twig custom function?
I guess I'm confused as the best way to handle my situation, my email menu will change from page to page depending on several factors, and I thought of making a twig function to be called from the layout or from another template, the reason I am thinking along these lines is to keep my other templates free from a lot of logic, logic that I'd rather have with pure PHP. Any thoughts would be appreciated.
You can just render additional controller (not a twig extension) which renders own template (possibly dependent on the page), which overrides base template block.
I think, overriding block from twig extensions - it is not the twig purposed for.
You must create a base template:
{# src/BW/MainBundle/Resources/views/Main/base.html.twig #}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{% block title %}Test Application{% endblock %}</title>
</head>
<body>
<div id="sidebar">
{% block sidebar %}
<ul>
<li>Home</li>
<li>Blog</li>
</ul>
{% endblock %}
</div>
<div id="content">
{% block body %}{% endblock %}
</div>
</body>
</html>
And then extends parent template with extends keyword:
{# src/Acme/BlogBundle/Resources/views/Blog/index.html.twig #}
{% extends 'BWMainBundle:Main:base.html.twig' %}
{% block title %}My cool blog posts{% endblock %}
{% block body %}
{% for entry in blog_entries %}
<h2>{{ entry.title }}</h2>
<p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}
Also read this docs about templating in Symfony using Twig.
i have a lot of time programming in PHP, but im doing my first steps in Symfony.
Im try write Twigg templates, i have a public template in app/Resources/view/public.html.twig.
This file contains: http://pastebin.com/T1KGMfXL.
Now, in CloudBundle, have a base.html.twig:
{% extends '::public.html.twig' %}
{% block main %}
<div class="login_page">
<div class="login_box">
{% block content %} {% endblock %}
</div>
</div>
{% endblock %}
And the content in another twig file. For example, login.html.twig
{% extends 'base.html.twig' %}
{% block content %}
....
{% endblock %}
In the Controller, when an user try http://cloud.man.local/app.php/login:
public function staticAction($sitio)
{
// in this case, $sitio contains "login"
return $this->render("CloudBundle:Default:$sitio.html.twig");
}
So, the problem is that, only shows the footer, not show the content.
Any ideas ?.
You want to override a block which is inside another block, so in your case I think you should try this in the another twig files:
{% block main %}
{{ parent() }}
{% block content %} YOur content {% endblock %}
{% endblock %}
see http://twig.sensiolabs.org/doc/functions/parent.html
Hope it's helpful.
Best regard.