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.
Related
I am awfully new to Symfony 4 and Twig 2.
All I want to do is get the basic functionality of extending templates to work.
Unfortunately the documentation of Symfony and Twig do not explain what I am looking for (Twig documentation is mostly just a collection of code with only minimal explanations). Or I don't understand... :)
This is simple.
I got the usual base.html.twig:
base.html.twig
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}Welcome!{% endblock %}</title>
{% block stylesheets %}{% endblock %}
</head>
<body>
{% block body %}Old Content{% endblock %}
{% block javascripts %}{% endblock %}
</body>
</html>
I only added some default text into the body block.
Next a simple file that should extend the one above:
body.html.twig
{% extends "base.html.twig" %}
{% block body %}
New content
{% endblock %}
To output all this I created a controller:
baseController.php
<?php
namespace App\Controller;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class baseController extends AbstractController
{
/**
* #Route("/")
*/
public function base()
{
return $this->render('base.html.twig');
}
}
?>
Tested the templates in twigfiddle.com and all worked well, so they are surely fine.
The above setup outputs the base.html.twig just fine (see the "Old Content" text, but completely ignore the body.html.twig. So the obvious question: what am I overlooking/which basic concept am I not grasping?
Thank you for your kind help.
base.html.twig is your skeleton and body.html.twig is your page specific implementation. Your controller should always render the body.html.twig, which will override blocks found inside the extended base.html.twig.
Some examples from the top of my head:
base.html.twig:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}Welcome!{% endblock %}</title>
{% block stylesheets %}{% endblock %}
</head>
<body>
{% include 'header.html.twig' %}
{% block body %}{% endblock %}
{% include 'footer.html.twig' %}
</body>
{% block javascripts %}{% endblock %}
</html>
home.html.twig:
{% extends "base.html.twig" %}
{% block body %}
<h1>header of this page</h1>
{% include 'newsletter-subscribe.html.twig' %}
{% include 'greeting.html.twig' with { name: 'Max' } %}
<p>Some content</p>
{% endblock %}
greeting.html.twig:
Hello {{ name }}
just creat the header and footer yourself. ensure you render home.html.twig in your controller.
If you want to dive into it and must use nested blocks, make use of https://twig.symfony.com/doc/2.x/functions/parent.html
base.html.twig:
{% block body %}
Hello World
{% endblock %}
home.html.twig:
{% extends 'base.html.twig' %}
{% block body %}
{{ parent() }}
how are you
{% endblock %}
should output Hello world how are you. I would discourage that function though, because the dependency is not clear from a designers perspective. Also be careful with embed, it has a higher impact on twig then include or simple blocks.
In my base template, I have a list of object that I loop through to populate my navbar link to others templates. When I extend my base template with another template I have an error saying that this variable does not exist.
base.html.twig
<head>
....
</head>
<body>
{% block navbar %}
{% for e in event %}
<li>
{{ e.getName() }}
</li>
{% endfor %}
{% endblock %}
</body>
What's the best way to use the event object in every controller/template ?
I have an existing django application that includes its own templates, now I want to use the capability of django CMS to enable the editing and updating of content in the front end easily. I have read the documentation and I understand that you use {% placeholder "" %} to include sections that you want to update, but I'm still not sure how or where to place the tags on my template or how to create them on the django CMS admin either.
Any explanation on this would be really appreciated.
Here's an example base template I've got;
<!DOCTYPE html>
{% load cms_tags menu_tags sekizai_tags cache i18n %}
{% load static from staticfiles %}
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
{% render_block "css" %}
{% render_block "js" %}
</head>
<body class="body-page">
{% cms_toolbar %}
{% block header %}
{% block banner %}{% endblock banner %}
<header class="masterhead container-fluid">
<div class="row">
</div>
{% show_menu 1 100 100 100 "partials/menu.html" %}
</header>
{% endblock header %}
<div class="container-fluid">
{% block content %}
{% endblock content %}
{% block highlights %}
{% endblock highlights %}
</div>
</body>
</html>
The important part is to include {% cms_toolbar %} at the beginning of the <body> which gives you the CMS menu. If you then include cms_tags you can use the placeholders and if you include menu_tags you can generate menus from your page tree.
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.
My problem:
I have 3 templates:
main.html.twig (main layout file)
layout.html.twig (a bundle specific layout override which contains some bundle specific JS tags)
create.html.twig (a page specific template file which also contains some page specific JS tags)
I am defining a block called 'javascript' in my base layout (main.html.twig), then overriding it (but calling {{ parent() }} in layout.html.twig. This works fine, and the JS tags from the main template file are still included above those in the layout.html.twig template.
I then do the same in the create.html.twig file, overriding the block as follows:
{% block javascripts %}
{{ parent() }}
{% javascripts '#BundleName/Resources/public/js/application.album.uploader.js'
'#BundleName/Resources/public/js/jquery.uploadify.js'
'#BundleName/Resources/public/js/swfuploadify.js' filter='?yui_js' %}
<script src='{{ asset_url }}' type='text/javascript'></script>
{% endjavascripts %}
{% endblock %}
At this point, instead of just overriding the javascript block in the parent (layout.html.twig) and including all the scripts defined in the templates above it, it does the following:
Dumps the <script> tags in the middle of the output (which causes an error, because in my main.html.twig file I am only including the jQuery library at the end of the HTML markup
Then it also dumps the scripts out along with the rest of the others (as I would expect it to)
I am not sure what is causing the scripts to be dumped in the middle of the create.html.twig template, and I'm also confused as to why they're being dumped to the screen twice (once in the middle of the create and then once at the bottom along with all the rest of my scripts from main.html.twig and layout.html.twig.
Has anyone got any ideas? Let me know if anything is unclear or if I can provide some more information.
EDIT:
File contents are below...
main.html.twig: https://gist.github.com/7f29353eaca0947528ce
layout.html.twig: https://gist.github.com/734947e9118b7765715e
create.html.twig: https://gist.github.com/c60c8d5c61e00ff86912
EDIT 2:
I've been having another look at the issue this morning and it looks as though its doing the same thing for stylesheets. I tried to define a new block called pagescripts in my layout.html.twig and then use the block in my create.html.twig but this had the same outcome, it just seems to dump the scripts and stylesheets wherever I use the
{% block pagescripts %}
(scripts here)
{% endblock}
I found the issue. In create.html.twig I was defining my {% block javascripts %} content inside inside my {% block content %}, so I assume Twig was rendering the output of the javascripts block inside the content block.
Moving the {% block javascripts %} content outside of the {% block content %} block fixed the issue.
Here is an example of main.html.twig:
<body>
{% block stylesheets %}
{% endblock %}
{% block jsscript %}
{% endblock %}
{% block content %}
{% endblock %}
</body>
into your create.html.twig
{% extends '::base.html.twig' %}
{% block jsscript %}
my javascript files...
{% endblock %}
{% block content %}
<h1>Create</h1>
<form action="{{ path('entity_create') }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<p>
<button type="submit">Create</button>
</p>
</form>
{% endblock %}
If you still have issue, you can add a document ready function :
$(document).ready(function() {
// put all your jQuery goodness in here.
});