<p>I was speaking with Andy Harris on IM earlier, and he told me that there was no need to pass the meta data from the entry template to the layout template. Instead, he said I can just put the metadata code straight into the layout template, and it would parse for the individual entries (I had it in my head that I had to pass this information from the entry template to the layout template).</p>

<p>So I no longer have meta code repeated in each template, and instead, I just have the following in my _layout.html template:</p>

<pre><code>{% if entry.metaTitle %}
  &lt;title&gt;{{ entry.metaTitle }} | {{ siteName }}&lt;/title&gt;
{% else %}
  &lt;title&gt;{{ entry.title }} | {{ siteName }}&lt;/title&gt;
{% endif %}

{% if entry.metaDescription %}
  &lt;meta name="description" content="{{ entry.metaDescription }}" /&gt;
{% else %}
  &lt;meta name="description" content="{{ globalMetadata.metaDescription }}" /&gt;
{% endif %}

{% if entry.metaKeywords %}
  &lt;meta name="keywords" content="{{ entry.metaKeywords }}" /&gt;
{% else %}
  &lt;meta name="keywords" content="{{ globalMetadata.metaKeywords }}" /&gt;
{% endif %}
</code></pre>

CC BY-SA 3.0
2015-01-20T00:25:57.987Z
2015-01-20T00:25:57.987Z
Stephen
<p>What I do is to handle the metadata in a macro that I call from <code>_layout</code>, which is passed the <code>_context</code> <a href="http://twig.sensiolabs.org/doc/templates.html#global-variables" rel="nofollow">twig global variable</a></p>

<p>In <code>_layout.html</code>:</p>

<pre><code>{% import '_macros/_metaData' as m_metaData %}
&lt;head&gt;
  {{m_metaData.output(_context)}}
...
</code></pre>

<p>Here is the content of <code>_macros/_metaData.html</code>. The <code>output</code> macro constructs a metaData object, based on what is in the context, and the <code>_printIt</code> macro actually outputs the metadata.</p>

<pre><code>{% macro _printIt(m) %}
  &lt;title&gt;{{m.title ? m.title~' | '}}{{siteName}}&lt;/title&gt;
  {% if m.description %}
    &lt;meta name="description" content="{{m.description}}"/&gt;
  {% endif %}
  {% if m.keywords %}
    &lt;meta name="keywords" content="{{m.keywords}}"/&gt;
  {% endif %}
{% endmacro %}

{% macro output(context) %}
{% import _self as self %}
  {% if context.meta is defined %}
    {# if someone gave us a meta object, use that #}
    {% set metaData = context.meta %}
  {% elseif context.entry is defined %}
    {# if we have an entry, use that #}
    {% set metaData = {
      title: context.entry.metaTitle|default(context.entry.title),
      description: context.entry.metaDescription,
      keywords: context.entry.metaKeywords
    } %}
  {% else %}
    {# we got nothing #}
    {% set metaData = {
      title: '',
      description: '',
      keywords: ''
    } %}
  {% endif %}
  {{self._printIt(metaData)}}
{% endmacro %}
</code></pre>

<p>For regular templates which have an <code>entry</code>, I don't have to do anything in the template. If there is no entry, but there is some sensible metadata, then I can set it in the template:</p>

<pre><code>{% set meta = {
  title: 'some title',
  description: 'this is the meta description',
  keywords: 'meta, keywords'
} %}
</code></pre>

<p>And if there is no <code>entry</code>, and no <code>meta</code> is set, I get no metadata, but no errors either.</p>

CC BY-SA 3.0
2015-01-20T02:40:07.000Z
This is a much more efficient way of doing it. Thanks marion
since1976
CC BY-SA 3.0
2015-01-19T09:41:56.413Z
2015-01-19T09:41:56.413Z
Marion Newlevant
<p>That seo code will need to be in a block of its own. 
Create a seo block in your _layout template and then wrap your seo code in your include template with block tags of the same name.  </p>

CC BY-SA 3.0
2015-01-19T04:41:43.937Z
2015-01-19T04:41:43.937Z
since1976
<p>Another little thing to consider, instead of using:</p>

<pre><code>{% if entry.metaDescription != '' %}{% endif %}
</code></pre>

<p>which effectively means 'if this field is not equal to nothing', try using Twigs <code>|length</code> <a href="http://twig.sensiolabs.org/doc/filters/length.html" rel="nofollow">filter</a>:</p>

<pre><code>{% if entry.metaDescription|length %}{% endif %}
</code></pre>

<p>But yes to answer your question, since1976 has already said it but you will just need to wrap your SEO code (from <code>{# START OF SEO CODE #}</code> to <code>{# END OF SEO CODE #}</code>) in a block, and then add that block to the template you are including.</p>

CC BY-SA 3.0
2015-01-19T18:29:07.937Z
Or since an empty string evaluates to `false`, just test: `{% if entry.metaDescription %}...{% endif %}`
Marion Newlevant
CC BY-SA 3.0
2015-01-19T13:12:06.250Z
2015-01-19T13:12:06.250Z
Jamie Wade
<p>I'm new to Craft and have created some SEO fields <a href="https://craftcms.stackexchange.com/a/2990/179">similar to this</a>, and the template code appears in all templates as shown below. I don't want to be repeating all that code in every template though, so I thought I'd be better of putting it in an include template (assuming that's how best to handle this in Craft).</p>

<p>But I'm getting an error when I try to do this, so can anyone show me the correct way of doing this please?</p>

<p>Here's my starting code, where I'm repeating the SEO code in every template (see the start and end comments):</p>

<pre><code>{% extends "_layout" %}

{# START OF SEO CODE #}
{% if entry.metaTitle != '' %}
  {% set title = entry.metaTitle %}
{% else %}
  {% set title = entry.title %}
{% endif %}

{% if entry.metaDescription != '' %}
  {% set description = entry.metaDescription %}
{% endif %}

{% if entry.metaKeywords != '' %}
  {% set keywords = entry.metaKeywords %}
{% endif %}
{# END OF SEO CODE #}

{% block content %}

  &lt;article class="grid-60"&gt;

    &lt;h1&gt;{{ entry.title }}&lt;/h1&gt;

    {{ entry.body }}

  &lt;/article&gt;&lt;!-- grid-60 --&gt;

{% endblock %}
</code></pre>

<p>And for completeness, I have the following in my _layout template:</p>

<pre><code>{% set metaTitle = globalMetadata.metaTitle %}
{% set metaDescription = globalMetadata.metaDescription %}
{% set metaKeywords = globalMetadata.metaKeywords %}

&lt;title&gt;{% if title is defined %}{{ title }}{% else %}{{ globalMetadata.metaTitle }}{% endif %} | {{ siteName }}&lt;/title&gt;
&lt;meta name="description" content="{% if description is defined %}{{ description }}{% else %}{{ globalMetadata.metaDescription }}{% endif %}" /&gt;
&lt;meta name="keywords" content="{% if keywords is defined %}{{ keywords }}{% else %}{{ globalMetadata.metaKeywords }}{% endif %}" /&gt;
</code></pre>

<p>So I've tried moving the SEO code out of the entry template, and into the following include template: _includes/seo_meta:</p>

<pre><code>{# START OF SEO CODE #}
{% if entry.metaTitle != '' %}
  {% set title = entry.metaTitle %}
{% else %}
  {% set title = entry.title %}
{% endif %}

{% if entry.metaDescription != '' %}
  {% set description = entry.metaDescription %}
{% endif %}

{% if entry.metaKeywords != '' %}
  {% set keywords = entry.metaKeywords %}
{% endif %}
{# END OF SEO CODE #}
</code></pre>

<p>And am trying to call it from my entry template like this:</p>

<pre><code>{% include "_includes/seo_meta" %}
</code></pre>

<p>But I'm getting the following error message, and the error is highlighting my include line:</p>

<pre><code>A template that extends another one cannot have a body.
</code></pre>

<p>Thanks in advance for any help, Stephen.</p>

<templating><error-message><include>
How to move repeating code into an include template
# How to move repeating code into an include template

(Asked by: username_0 on 2015-01-19)

I'm new to Craft and have created some SEO fields similar to this, and the template code appears in all templates as shown below. I don't want to be repeating all that code in every template though, so I thought I'd be better of putting it in an include template (assuming that's how best to handle this in Craft).
But I'm getting an error when I try to do this, so can anyone show me the correct way of doing this please?
Here's my starting code, where I'm repeating the SEO code in every template (see the start and end comments):
{% extends "_layout" %}

{# START OF SEO CODE #}
{% if entry.metaTitle != '' %}
  {% set title = entry.metaTitle %}
{% else %}
  {% set title = entry.title %}
{% endif %}

{% if entry.metaDescription != '' %}
  {% set description = entry.metaDescription %}
{% endif %}

{% if entry.metaKeywords != '' %}
  {% set keywords = entry.metaKeywords %}
{% endif %}
{# END OF SEO CODE #}

{% block content %}

  

    {{ entry.title }}

    {{ entry.body }}

  

{% endblock %}

And for completeness, I have the following in my _layout template:
{% set metaTitle = globalMetadata.metaTitle %}
{% set metaDescription = globalMetadata.metaDescription %}
{% set metaKeywords = globalMetadata.metaKeywords %}

{% if title is defined %}{{ title }}{% else %}{{ globalMetadata.metaTitle }}{% endif %} | {{ siteName }}



So I've tried moving the SEO code out of the entry template, and into the following include template: _includes/seo_meta:
{# START OF SEO CODE #}
{% if entry.metaTitle != '' %}
  {% set title = entry.metaTitle %}
{% else %}
  {% set title = entry.title %}
{% endif %}

{% if entry.metaDescription != '' %}
  {% set description = entry.metaDescription %}
{% endif %}

{% if entry.metaKeywords != '' %}
  {% set keywords = entry.metaKeywords %}
{% endif %}
{# END OF SEO CODE #}

And am trying to call it from my entry template like this:
{% include "_includes/seo_meta" %}

But I'm getting the following error message, and the error is highlighting my include line:
A template that extends another one cannot have a body.

Thanks in advance for any help, username_0.

**Tags:** templating, error-message, include


---

## 4 answers

### Answer by username_0 on 2015-01-20. Score: 3 | Accepted answer

I was speaking with Andy Harris on IM earlier, and he told me that there was no need to pass the meta data from the entry template to the layout template. Instead, he said I can just put the metadata code straight into the layout template, and it would parse for the individual entries (I had it in my head that I had to pass this information from the entry template to the layout template).
So I no longer have meta code repeated in each template, and instead, I just have the following in my _layout.html template:
{% if entry.metaTitle %}
  {{ entry.metaTitle }} | {{ siteName }}
{% else %}
  {{ entry.title }} | {{ siteName }}
{% endif %}

{% if entry.metaDescription %}
  
{% else %}
  
{% endif %}

{% if entry.metaKeywords %}
  
{% else %}
  
{% endif %}


---

### Answer by username_1 on 2015-01-19. Score: 4

What I do is to handle the metadata in a macro that I call from _layout, which is passed the _context twig global variable
In _layout.html:
{% import '_macros/_metaData' as m_metaData %}

  {{m_metaData.output(_context)}}
...

Here is the content of _macros/_metaData.html. The output macro constructs a metaData object, based on what is in the context, and the _printIt macro actually outputs the metadata.
{% macro _printIt(m) %}
  {{m.title ? m.title~' | '}}{{siteName}}
  {% if m.description %}
    
  {% endif %}
  {% if m.keywords %}
    
  {% endif %}
{% endmacro %}

{% macro output(context) %}
{% import _self as self %}
  {% if context.meta is defined %}
    {# if someone gave us a meta object, use that #}
    {% set metaData = context.meta %}
  {% elseif context.entry is defined %}
    {# if we have an entry, use that #}
    {% set metaData = {
      title: context.entry.metaTitle|default(context.entry.title),
      description: context.entry.metaDescription,
      keywords: context.entry.metaKeywords
    } %}
  {% else %}
    {# we got nothing #}
    {% set metaData = {
      title: '',
      description: '',
      keywords: ''
    } %}
  {% endif %}
  {{self._printIt(metaData)}}
{% endmacro %}

For regular templates which have an entry, I don't have to do anything in the template. If there is no entry, but there is some sensible metadata, then I can set it in the template:
{% set meta = {
  title: 'some title',
  description: 'this is the meta description',
  keywords: 'meta, keywords'
} %}

And if there is no entry, and no meta is set, I get no metadata, but no errors either.

> **Comments:**
> **username_2**: This is a much more efficient way of doing it. Thanks marion  

---

### Answer by username_2 on 2015-01-19. Score: 4

That seo code will need to be in a block of its own.
Create a seo block in your \_layout template and then wrap your seo code in your include template with block tags of the same name.


---

### Answer by username_3 on 2015-01-19. Score: 2

Another little thing to consider, instead of using:
{% if entry.metaDescription != '' %}{% endif %}

which effectively means 'if this field is not equal to nothing', try using Twigs |length filter:
{% if entry.metaDescription|length %}{% endif %}

But yes to answer your question, username_2 has already said it but you will just need to wrap your SEO code (from {# START OF SEO CODE #} to {# END OF SEO CODE #}) in a block, and then add that block to the template you are including.

> **Comments:**
> **username_1**: Or since an empty string evaluates to `false`, just test: `{% if entry.metaDescription %}...{% endif %}`  

---

