From b11412efd897eb67fe78801b00f816599ed0ba87 Mon Sep 17 00:00:00 2001 From: literal Date: Thu, 10 May 2012 03:10:48 +0300 Subject: [PATCH] improve documentation for embed tag --- doc/tags/embed.rst | 148 ++++++++++++++++++++++++++++++---------------------- 1 files changed, 85 insertions(+), 63 deletions(-) diff --git a/doc/tags/embed.rst b/doc/tags/embed.rst index b75f557..454f11c 100644 --- a/doc/tags/embed.rst +++ b/doc/tags/embed.rst @@ -4,64 +4,82 @@ .. versionadded:: 1.8 The ``embed`` tag was added in Twig 1.8. -The ``embed`` statement allows you to embed a template instead of including it -from an external file (like with the ``include`` statement): +The ``embed`` tag combines the behaviour of :doc:`include` and +:doc:`extends`. +It allows you to include another template's contents, just like ``include`` +does. But it also allows you to override any block defined inside the +included template, like when extending a template. + +Think of an embedded template as a "micro layout skeleton". .. code-block:: jinja - {% embed "sidebar.twig" %} - {% block content %} - Some content for the sidebar + {% embed "teasers_skeleton.twig" %} + {# These blocks are defined in "teasers_skeleton.twig" #} + {# and we override them right here: #} + {% block left_teaser %} + Some content for the left teaser box + {% endblock %} + {% block right_teaser %} + Some content for the right teaser box {% endblock %} {% endembed %} -As it's not easy to understand in which circumstances it might come in handy, -let's take an example; imagine a base template shared by many pages with a -single block: +The ``embed`` tag takes the idea of template inheritance to the level of +content fragments. While template inheritance allows for "document skeletons", +which are filled with life by child templates, the ``embed`` tag allows you to +create "skeletons" for smaller units of content and re-use and fill them +anywhere you like. + +Since the use case may not be obvious, let's look at a simplified example. +Imagine a base template shared by multiple HTML pages, defining a single block +named "content": .. code-block:: text - ┌─── Page n ──────────────────────────┐ + ┌─── page layout ─────────────────────┐ │ │ - │ ┌─────────────────────┐ │ - │ │ │ │ - │ │ │ │ + │ ┌── block "content" ──┐ │ │ │ │ │ │ │ │ │ + │ │ (child template to │ │ + │ │ put content here) │ │ │ │ │ │ │ │ │ │ │ └─────────────────────┘ │ │ │ └─────────────────────────────────────┘ -Some pages (page 1, 2, ...) share the same structure for the block: +Some pages ("foo" and "bar") share the same content structure - +two vertically stacked boxes: .. code-block:: text - ┌─── Page 1 & 2 ──────────────────────┐ + ┌─── page layout ─────────────────────┐ │ │ - │ ┌── Base A ───────────┐ │ - │ │ ┌── content1 ─────┐ │ │ - │ │ │ content for p1 │ │ │ + │ ┌── block "content" ──┐ │ + │ │ ┌─ block "top" ───┐ │ │ + │ │ │ │ │ │ │ │ └─────────────────┘ │ │ - │ │ ┌── content2 ─────┐ │ │ - │ │ │ content for p1 │ │ │ + │ │ ┌─ block "bottom" ┐ │ │ + │ │ │ │ │ │ │ │ └─────────────────┘ │ │ │ └─────────────────────┘ │ │ │ └─────────────────────────────────────┘ -While other pages (page a, b, ...) share a different structure for the block: +While other pages ("boom" and "baz") share a different content structure - +two boxes side by side: .. code-block:: text - ┌─── Page a, b ───────────────────────┐ + ┌─── page layout ─────────────────────┐ │ │ - │ ┌── Base B ───────────┐ │ - │ │ ┌───────┐ ┌───────┐ │ │ + │ ┌── block "content" ──┐ │ + │ │ │ │ + │ │ ┌ block ┐ ┌ block ┐ │ │ + │ │ │"left" │ │"right"│ │ │ │ │ │ │ │ │ │ │ - │ │ │content│ │content│ │ │ - │ │ │a, ... │ │b, ... │ │ │ │ │ │ │ │ │ │ │ │ │ └───────┘ └───────┘ │ │ │ └─────────────────────┘ │ @@ -70,64 +88,68 @@ While other pages (page a, b, ...) share a different structure for the block: Without the ``embed`` tag, you have two ways to design your templates: - * Create two base templates (one for 1, 2, ... blocks and another one for a, - b, ... blocks) to factor out the common template code, then one template - for each page that inherits from one of the base template; + * Create two "intermediate" base templates that extend the master layout + template: one with vertically stacked boxes to be used by the "foo" and + "bar" pages and another one with side-by-side boxes for the "boom" and + "baz" pages. - * Embed each custom page content directly into each page without any use of - external templates (you need to repeat the common code for all templates). + * Embed the markup for the top/bottom and left/right boxes into each page + template directly. These two solutions do not scale well because they each have a major drawback: - * The first solution makes you create many external files (that you won't - re-use anywhere else) and so it fails to keep your templates readable (many - code and content are out of context); + * The first solution may indeed work for this simplified example. But imagine + we add a sidebar, which may again contain different, recurring structures + of content. Now we would need to create intermediate base templates for + all occurring combinations of content structure and sidebar structure... + and so on. - * The second solution makes you duplicate some common code from one template - to another (so it fails to obey the "Don't repeat yourself" principle). + * The second solution involves duplication of common code with all its negative + consequences: any change involves finding and editing all affected copies + of the structure, correctness has to be verified for each copy, copies may + go out of sync by careless modifications etc. -In such a situation, the ``embed`` tag fixes all these issues. The common code -can be factored out in base templates (as in solution 1), and the custom -content is kept in each page (as in solution 2): +In such a situation, the ``embed`` tag comes in handy. The common layout +code can live in a single base template, and the two different content structures, +let's call them "micro layouts" go into separate templates which are embedded +as necessary: -.. code-block:: jinja +Page template ``foo.twig``: - {# template for pages 1, 2, ... #} +.. code-block:: jinja - {% extends page %} + {% extends "layout_skeleton.twig" %} - {% block base %} - {% embed "base_A.twig" %} - {% block content1 %} - Content 1 for page 2 + {% block content %} + {% embed "vertical_boxes_skeleton.twig" %} + {% block top %} + Some content for the top box {% endblock %} - {% block content2 %} - Content 2 for page 2 + {% block bottom %} + Some content for the bottom box {% endblock %} {% endembed %} {% endblock %} -And here is the code for ``base_A.twig``: +And here is the code for ``vertical_boxes_skeleton.twig``: -.. code-block:: jinja +.. code-block:: html+jinja - Some code - - {% block content1 %} - Some default content - {% endblock %} - - Some other code - - {% block content2 %} - Some default content - {% endblock %} +
+ {% block content1 %} + Top box default content + {% endblock %} +
- Yet some other code +
+ {% block content2 %} + Bottom box default content + {% endblock %} +
-The goal of the ``base_a.twig`` base template being to factor out the ``Some -code``, ``Some other code``, and ``Yet some other code`` parts. +The goal of the ``vertical_boxes_skeleton.twig`` template being to factor +out the HTML markup for the boxes. The ``embed`` tag takes the exact same arguments as the ``include`` tag: -- 1.7.2.5