Matthias Andreas Benkard | 12a5735 | 2021-12-28 18:02:04 +0100 | [diff] [blame] | 1 | ``embed`` |
| 2 | ========= |
| 3 | |
| 4 | The ``embed`` tag combines the behavior of :doc:`include<include>` and |
| 5 | :doc:`extends<extends>`. |
| 6 | It allows you to include another template's contents, just like ``include`` |
| 7 | does. But it also allows you to override any block defined inside the |
| 8 | included template, like when extending a template. |
| 9 | |
| 10 | Think of an embedded template as a "micro layout skeleton". |
| 11 | |
| 12 | .. code-block:: twig |
| 13 | |
| 14 | {% embed "teasers_skeleton.twig" %} |
| 15 | {# These blocks are defined in "teasers_skeleton.twig" #} |
| 16 | {# and we override them right here: #} |
| 17 | {% block left_teaser %} |
| 18 | Some content for the left teaser box |
| 19 | {% endblock %} |
| 20 | {% block right_teaser %} |
| 21 | Some content for the right teaser box |
| 22 | {% endblock %} |
| 23 | {% endembed %} |
| 24 | |
| 25 | The ``embed`` tag takes the idea of template inheritance to the level of |
| 26 | content fragments. While template inheritance allows for "document skeletons", |
| 27 | which are filled with life by child templates, the ``embed`` tag allows you to |
| 28 | create "skeletons" for smaller units of content and re-use and fill them |
| 29 | anywhere you like. |
| 30 | |
| 31 | Since the use case may not be obvious, let's look at a simplified example. |
| 32 | Imagine a base template shared by multiple HTML pages, defining a single block |
| 33 | named "content": |
| 34 | |
| 35 | .. code-block:: text |
| 36 | |
| 37 | ┌─── page layout ─────────────────────┐ |
| 38 | │ │ |
| 39 | │ ┌── block "content" ──┐ │ |
| 40 | │ │ │ │ |
| 41 | │ │ │ │ |
| 42 | │ │ (child template to │ │ |
| 43 | │ │ put content here) │ │ |
| 44 | │ │ │ │ |
| 45 | │ │ │ │ |
| 46 | │ └─────────────────────┘ │ |
| 47 | │ │ |
| 48 | └─────────────────────────────────────┘ |
| 49 | |
| 50 | Some pages ("foo" and "bar") share the same content structure - |
| 51 | two vertically stacked boxes: |
| 52 | |
| 53 | .. code-block:: text |
| 54 | |
| 55 | ┌─── page layout ─────────────────────┐ |
| 56 | │ │ |
| 57 | │ ┌── block "content" ──┐ │ |
| 58 | │ │ ┌─ block "top" ───┐ │ │ |
| 59 | │ │ │ │ │ │ |
| 60 | │ │ └─────────────────┘ │ │ |
| 61 | │ │ ┌─ block "bottom" ┐ │ │ |
| 62 | │ │ │ │ │ │ |
| 63 | │ │ └─────────────────┘ │ │ |
| 64 | │ └─────────────────────┘ │ |
| 65 | │ │ |
| 66 | └─────────────────────────────────────┘ |
| 67 | |
| 68 | While other pages ("boom" and "baz") share a different content structure - |
| 69 | two boxes side by side: |
| 70 | |
| 71 | .. code-block:: text |
| 72 | |
| 73 | ┌─── page layout ─────────────────────┐ |
| 74 | │ │ |
| 75 | │ ┌── block "content" ──┐ │ |
| 76 | │ │ │ │ |
| 77 | │ │ ┌ block ┐ ┌ block ┐ │ │ |
| 78 | │ │ │"left" │ │"right"│ │ │ |
| 79 | │ │ │ │ │ │ │ │ |
| 80 | │ │ │ │ │ │ │ │ |
| 81 | │ │ └───────┘ └───────┘ │ │ |
| 82 | │ └─────────────────────┘ │ |
| 83 | │ │ |
| 84 | └─────────────────────────────────────┘ |
| 85 | |
| 86 | Without the ``embed`` tag, you have two ways to design your templates: |
| 87 | |
| 88 | * Create two "intermediate" base templates that extend the master layout |
| 89 | template: one with vertically stacked boxes to be used by the "foo" and |
| 90 | "bar" pages and another one with side-by-side boxes for the "boom" and |
| 91 | "baz" pages. |
| 92 | |
| 93 | * Embed the markup for the top/bottom and left/right boxes into each page |
| 94 | template directly. |
| 95 | |
| 96 | These two solutions do not scale well because they each have a major drawback: |
| 97 | |
| 98 | * The first solution may indeed work for this simplified example. But imagine |
| 99 | we add a sidebar, which may again contain different, recurring structures |
| 100 | of content. Now we would need to create intermediate base templates for |
| 101 | all occurring combinations of content structure and sidebar structure... |
| 102 | and so on. |
| 103 | |
| 104 | * The second solution involves duplication of common code with all its negative |
| 105 | consequences: any change involves finding and editing all affected copies |
| 106 | of the structure, correctness has to be verified for each copy, copies may |
| 107 | go out of sync by careless modifications etc. |
| 108 | |
| 109 | In such a situation, the ``embed`` tag comes in handy. The common layout |
| 110 | code can live in a single base template, and the two different content structures, |
| 111 | let's call them "micro layouts" go into separate templates which are embedded |
| 112 | as necessary: |
| 113 | |
| 114 | Page template ``foo.twig``: |
| 115 | |
| 116 | .. code-block:: twig |
| 117 | |
| 118 | {% extends "layout_skeleton.twig" %} |
| 119 | |
| 120 | {% block content %} |
| 121 | {% embed "vertical_boxes_skeleton.twig" %} |
| 122 | {% block top %} |
| 123 | Some content for the top box |
| 124 | {% endblock %} |
| 125 | |
| 126 | {% block bottom %} |
| 127 | Some content for the bottom box |
| 128 | {% endblock %} |
| 129 | {% endembed %} |
| 130 | {% endblock %} |
| 131 | |
| 132 | And here is the code for ``vertical_boxes_skeleton.twig``: |
| 133 | |
| 134 | .. code-block:: html+twig |
| 135 | |
| 136 | <div class="top_box"> |
| 137 | {% block top %} |
| 138 | Top box default content |
| 139 | {% endblock %} |
| 140 | </div> |
| 141 | |
| 142 | <div class="bottom_box"> |
| 143 | {% block bottom %} |
| 144 | Bottom box default content |
| 145 | {% endblock %} |
| 146 | </div> |
| 147 | |
| 148 | The goal of the ``vertical_boxes_skeleton.twig`` template being to factor |
| 149 | out the HTML markup for the boxes. |
| 150 | |
| 151 | The ``embed`` tag takes the exact same arguments as the ``include`` tag: |
| 152 | |
| 153 | .. code-block:: twig |
| 154 | |
| 155 | {% embed "base" with {'foo': 'bar'} %} |
| 156 | ... |
| 157 | {% endembed %} |
| 158 | |
| 159 | {% embed "base" with {'foo': 'bar'} only %} |
| 160 | ... |
| 161 | {% endembed %} |
| 162 | |
| 163 | {% embed "base" ignore missing %} |
| 164 | ... |
| 165 | {% endembed %} |
| 166 | |
| 167 | .. warning:: |
| 168 | |
| 169 | As embedded templates do not have "names", auto-escaping strategies based |
| 170 | on the template name won't work as expected if you change the context (for |
| 171 | instance, if you embed a CSS/JavaScript template into an HTML one). In that |
| 172 | case, explicitly set the default auto-escaping strategy with the |
| 173 | ``autoescape`` tag. |
| 174 | |
| 175 | .. seealso:: |
| 176 | |
| 177 | :doc:`include<../tags/include>` |