<p>Thanks to the outstanding support from Pixel and Tonic I can answer this with code supplied by Brad at P&amp;T.  Also thanks to Jamie for looking into this.</p>

<pre><code>{% for block in entry.seoInfo %}
    {% if block.type == "seoBasics" %}

        {% if block.seoPageTitle | length %}
            &lt;title&gt;{{ block.seoPageTitle }}&lt;/title&gt;
        {% else %}
            {% for block in seoSettings.seoInfo.type('seoBasics') %}
                &lt;title&gt;{{ block.seoPageTitle }}&lt;/title&gt;
            {% endfor %}
        {% endif %}
    {% endif %}
{% endfor %}
</code></pre>

CC BY-SA 3.0
2014-11-05T21:04:04.180Z
2014-11-05T22:17:42.007Z
2014-11-05T22:17:42.007Z
Martin
<p>We do something similar to the setup you have here, whereby if the SEO fields haven't been filled for an entry the default is used, but there is a cleaner way of doing this, especially for your clients when they want to go in and make changes.</p>

<p><a href="http://buildwithcraft.com/docs/globals" rel="nofollow">Globals</a> would be a perfect fit for what you are after. In your Global settings, create a new one called 'SEO' or similar, and in there create your fields for the various SEO attributes.</p>

<p>Globals allow you to define content and information which can be accessed from anywhere on the site, and by doing this would mean you will no longer need the DefaultSEO entry you have created.</p>

<p>All of the default information you have set in the Default SEO entry can instead be set in the Globals section, which makes for a cleaner experience for you clients.</p>

<p>I think with the very rich SEO set up you have here, you can't really get round having the <code>if</code> statements in your templates, as this is how matrix fields work.</p>

<p>But as I say, you can really tidy things up by using Globals instead:</p>

<pre><code>{% if block.type == "seoBasics" %} 

    {# If a page title has been set for this entry, use that #}
    {% if block.seoPageTitle | length %}
        &lt;title&gt;{{ block.seoPageTitle }}&lt;/title&gt;

    {# If it hasn't, use the default page title from the SEO Global #}
    {% else %}
        &lt;title&gt;{{ seo.seoPageTitle }}&lt;/title&gt;

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

<p>I hope this helps you in the right direction, if you have any questions then let me know.</p>

CC BY-SA 3.0
2014-11-03T11:27:06.810Z
Thanks Jamie, before I give this a shot can you confirm the information can be changed on a page-by-page (entry-by-entry) basis?

The way I read it, I set up a Global with the information which a client can alter, but this will still apply to every page (entry)?
Martin
CC BY-SA 3.0
2014-11-03T11:29:44.593Z
Yes, you will still have the SEO fields on each entry. The improvement I suggested was to remove the DefaultSEO entry you have set up, and instead create an SEO Global where you set your default SEO information. The template code will check to see if SEO information has been set for the entry. If it has, it will use that. If it hasn't, it will grab the info you have set in the Global section.
Jamie Wade
CC BY-SA 3.0
2014-11-03T15:46:32.600Z
Hi Jamie, i've looked at using this method and can't get the 'default' content from the Global to show:

`{% if block.type == "seoBasics" %} 

    {# If a page title has been set for this entry, use that #}
    {% if block.seoPageTitle | length %}
        <title>{{ block.seoPageTitle }}</title>

    {# If it hasn't, use the default page title from the SEO Global #}
    {% else %}
        <title>{{ seoSetup.seoPageTitle }}</title>

    {% endif %}`

Where seoSetup is the handle for my Global setup.

Any ideas?

Thanks

How the hell do I show code in a Stack Exchange comment?! :/
Martin
CC BY-SA 3.0
2014-11-03T16:03:40.227Z
I've got it... I still need to wrap {% for block in seoSetup.seoSettings %} around {{ block.seoPageTitle }}
Martin
CC BY-SA 3.0
2014-11-03T16:07:49.443Z
You got it, sorry for the confusion. I started my code example from inside the for loop.
Jamie Wade
CC BY-SA 3.0
2014-11-03T19:50:59.423Z
I'm getting an error if I don't have any content in the entry SEO field.  This sort of defeats the object as it's supposed to fall back on the Global. :/

Craft\MatrixBlockModel and its behaviors do not have a method or closure named "seoPageTitle".

Any ideas?
Martin
CC BY-SA 3.0
2014-11-04T10:24:21.887Z
Check if your SEO Page Title field in the matrix has the handle of "seoPageTitle". I just used this as an example from your code, but it might be named differently in your matrix field.
Jamie Wade
CC BY-SA 3.0
2014-11-04T10:33:08.017Z
Hi, yep, checked, checked and checked again :/ 'seoPageTitle'
Martin
CC BY-SA 3.0
2014-11-04T12:59:06.733Z
Hmm, strange. I'll set up a test Craft site tonight for you and I'll take a look.
Jamie Wade
CC BY-SA 3.0
2014-11-05T21:02:38.440Z
Hi Jamie, Brad at Pixel and Tonic came through with a solution!
Martin
CC BY-SA 3.0
2014-11-06T09:38:34.213Z
Ah my bad, I didn't think of your default SEO fields being in a matrix. {{ seo.seoPageTitle }} would have worked if there was just a plain text field on it's own. Glad you got it sorted.
Jamie Wade
CC BY-SA 3.0
2014-11-03T10:50:26.133Z
2014-11-03T11:02:02.637Z
2014-11-03T11:02:02.637Z
Jamie Wade
<p>I'm setting up SEO fields (of which there are quite a few) using Matrix.</p>

<p>My plan is to offer the user the option to adjust the SEO on a page-by-page basis. This could become unwieldy and the user might not always add the SEO information. So to assist i've created a 'default' SEO entry which will always append unless the user makes changes.</p>

<p>So, the basic setup is "If the field has content, use it.  If not, use the default"</p>

<p>At the moment i have the following code (just done the title field so far), but you can see that this will become a lot of {{ ifelse }}, {{ if not }}, {{ for block }}, {{ endfor }}... etc..</p>

<p>So my question is, can this be refined into something much less intensive?</p>

<pre><code>{% for block in entry.seoSettings %}

                {% if block.type == "seoBasics" %}



                    {% if not block.seoPageTitle|length %}
                        {% for entry in craft.entries.section('defaultSeo').find() %}
                            {% for block in entry.seoSettings %}
                                &lt;title&gt;{{ block.seoPageTitle }}&lt;/title&gt;
                            {% endfor %}
                        {% endfor %}
                    {% else %}
                        &lt;title&gt;{{ block.seoPageTitle }}&lt;/title&gt;
                    {% endif %}


                    &lt;meta name="description" content="{{ block.seoDescription }}" /&gt;
                    &lt;meta name="google-site-verification" content="{{ block.googleVerificationNumber }}" /&gt;
                    &lt;meta name="msvalidate.01" content="{{ block.bingVerificationNumber }}" /&gt;

                {% elseif block.type == "seoAdditional" %}

                    &lt;link rel="canonical" href="{{ block.seoCanonicalLinks }}" /&gt;
                    &lt;meta name="robots" content="{{ block.seoRobotContent }}" /&gt;

                {% elseif block.type == "seoGeographic" %}

                    &lt;meta name="geo.region" content="{{ seoGeoRegion }}" /&gt;
                    &lt;meta name="geo.placename" content="{{ seoGeoPlacename }}" /&gt;
                    &lt;meta name="geo.position" content="{{ seoGeoLattitude }};{{ seoGeoLongitude }}" /&gt;
                    &lt;meta name="ICBM" content="{{ seoGeoLattitude }}, {{ seoGeoLongitude }}" /&gt;

               {% elseif block.type == "seoOpenGraph" %}

                    &lt;meta property="og:title" content="{{ block.ogTitle }}" /&gt;
                    &lt;meta property="og:description" content="{{ block.ogDescription }}" /&gt;
                    &lt;meta property="og:type" content="{{ block.ogType }}" /&gt;
                    &lt;meta property="og:url" content="{{ block.ogUrl }}" /&gt;
                    &lt;meta property="og:image" content="{% for image in block.ogImage %}{{ image.getUrl() }}{% endfor %}" /&gt;
                    &lt;meta property="og:author" content="{{ block.ogAuthor }}" /&gt;
                    &lt;meta property="og:site_name" content="{{ block.ogSiteName }}" /&gt;
                    &lt;meta property="og:locale" content="{{ block.ogLocale }}" /&gt;
                    &lt;meta property="og:locale:alternate" content="{{ block.ogAlternativeLocale }}" /&gt;
                    &lt;meta property="fb:admins" content="{{ block.ogFacebookAdmin }}"/&gt;

                {% elseif block.type == "twitterCard" %}

                    &lt;meta name="twitter:card" content="{{ block.twitterCard }}" /&gt;
                    &lt;meta name="twitter:title" content="{{ block.twitterTitle }}" /&gt;
                    &lt;meta name="twitter:description" content="{{ block.twitterDescription }}" /&gt;
                    &lt;meta name="twitter:site" content="{{ block.twitterSite }}"&gt;
                    &lt;meta name="twitter:creator" content="{{ block.twitterCreator }}"&gt;
                    &lt;meta name="twitter:url" content="{{ block.twitterUrl }}" /&gt;
                    &lt;meta name="twitter:image" content="{% for image in block.twitterImage %}{{ image.getUrl() }}{% endfor %}" /&gt;

                {% elseif block.type == "googlePlus" %}

                    &lt;meta itemscope itemtype="http://schema.org/{{ block.schemaPageType }}" /&gt;
                    &lt;meta itemprop="name" content="{{ block.schemaName }}" /&gt;
                    &lt;meta itemprop="description" content="{{ block.schemaDescription }}" /&gt;
                    &lt;meta itemprop="image" content="{% for image in block.schemaImage %}{{ image.getUrl() }}{% endfor %}" /&gt;

                {% elseif block.type == "rdPartyVerification" %}

                    &lt;meta name="{{ block.partyName }}" content="{{ block.partyContent }}"/&gt;

                {% endif %}

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

<p>I hope that makes sense?</p>

<p>Many thanks</p>

<p>Martin</p>

<templating>
Code refinement on checking a field for content and outputting an alternative
# Code refinement on checking a field for content and outputting an alternative

(Asked by: username_0 on 2014-11-03)

I'm setting up SEO fields (of which there are quite a few) using Matrix.
My plan is to offer the user the option to adjust the SEO on a page-by-page basis. This could become unwieldy and the user might not always add the SEO information. So to assist i've created a 'default' SEO entry which will always append unless the user makes changes.
So, the basic setup is "If the field has content, use it.  If not, use the default"
At the moment i have the following code (just done the title field so far), but you can see that this will become a lot of {{ ifelse }}, {{ if not }}, {{ for block }}, {{ endfor }}... etc..
So my question is, can this be refined into something much less intensive?
{% for block in entry.seoSettings %}

                {% if block.type == "seoBasics" %}



                    {% if not block.seoPageTitle|length %}
                        {% for entry in craft.entries.section('defaultSeo').find() %}
                            {% for block in entry.seoSettings %}
                                {{ block.seoPageTitle }}
                            {% endfor %}
                        {% endfor %}
                    {% else %}
                        {{ block.seoPageTitle }}
                    {% endif %}


                    
                    
                    

                {% elseif block.type == "seoAdditional" %}

                    
                    

                {% elseif block.type == "seoGeographic" %}

                    
                    
                    
                    

               {% elseif block.type == "seoOpenGraph" %}

                    
                    
                    
                    
                    
                    
                    
                    
                    
                    

                {% elseif block.type == "twitterCard" %}

                    
                    
                    
                    
                    
                    
                    

                {% elseif block.type == "googlePlus" %}

                    
                    
                    
                    

                {% elseif block.type == "rdPartyVerification" %}

                    

                {% endif %}

              {% endfor %}

I hope that makes sense?
Many thanks
username_0

**Tags:** templating


---

## 2 answers

### Answer by username_0 on 2014-11-05. Score: 1 | Accepted answer

Thanks to the outstanding support from Pixel and Tonic I can answer this with code supplied by Brad at P&T.  Also thanks to Jamie for looking into this.
{% for block in entry.seoInfo %}
    {% if block.type == "seoBasics" %}

        {% if block.seoPageTitle | length %}
            {{ block.seoPageTitle }}
        {% else %}
            {% for block in seoSettings.seoInfo.type('seoBasics') %}
                {{ block.seoPageTitle }}
            {% endfor %}
        {% endif %}
    {% endif %}
{% endfor %}


---

### Answer by username_1 on 2014-11-03. Score: 2

We do something similar to the setup you have here, whereby if the SEO fields haven't been filled for an entry the default is used, but there is a cleaner way of doing this, especially for your clients when they want to go in and make changes.
Globals would be a perfect fit for what you are after. In your Global settings, create a new one called 'SEO' or similar, and in there create your fields for the various SEO attributes.
Globals allow you to define content and information which can be accessed from anywhere on the site, and by doing this would mean you will no longer need the DefaultSEO entry you have created.
All of the default information you have set in the Default SEO entry can instead be set in the Globals section, which makes for a cleaner experience for you clients.
I think with the very rich SEO set up you have here, you can't really get round having the if statements in your templates, as this is how matrix fields work.
But as I say, you can really tidy things up by using Globals instead:
{% if block.type == "seoBasics" %} 

    {# If a page title has been set for this entry, use that #}
    {% if block.seoPageTitle | length %}
        {{ block.seoPageTitle }}

    {# If it hasn't, use the default page title from the SEO Global #}
    {% else %}
        {{ seo.seoPageTitle }}

    {% endif %}

I hope this helps you in the right direction, if you have any questions then let me know.

> **Comments:**
> **username_0**: Thanks Jamie, before I give this a shot can you confirm the information can be changed on a page-by-page (entry-by-entry) basis?  The way I read it, I set up a Global with the information which a client can alter, but this will still apply to every page (entry)?  
> **username_1**: Yes, you will still have the SEO fields on each entry. The improvement I suggested was to remove the DefaultSEO entry you have set up, and instead create an SEO Global where you set your default SEO information. The template code will check to see if SEO information has been set for the entry. If it has, it will use that. If it hasn't, it will grab the info you have set in the Global section.  
> **username_0**: Hi Jamie, i've looked at using this method and can't get the 'default' content from the Global to show:  `{% if block.type == "seoBasics" %}       {# If a page title has been set for this entry, use that #}     {% if block.seoPageTitle | length %}         <title>{{ block.seoPageTitle }}</title>      {# If it hasn't, use the default page title from the SEO Global #}     {% else %}         <title>{{ seoSetup.seoPageTitle }}</title>      {% endif %}`  Where seoSetup is the handle for my Global setup.  Any ideas?  Thanks  How the hell do I show code in a Stack Exchange comment?! :/  
> **username_0**: I've got it... I still need to wrap {% for block in seoSetup.seoSettings %} around {{ block.seoPageTitle }}  
> **username_1**: You got it, sorry for the confusion. I started my code example from inside the for loop.  
> **username_0**: I'm getting an error if I don't have any content in the entry SEO field.  This sort of defeats the object as it's supposed to fall back on the Global. :/  Craft\MatrixBlockModel and its behaviors do not have a method or closure named "seoPageTitle".  Any ideas?  
> **username_1**: Check if your SEO Page Title field in the matrix has the handle of "seoPageTitle". I just used this as an example from your code, but it might be named differently in your matrix field.  
> **username_0**: Hi, yep, checked, checked and checked again :/ 'seoPageTitle'  
> **username_1**: Hmm, strange. I'll set up a test Craft site tonight for you and I'll take a look.  
> **username_0**: Hi Jamie, Brad at Pixel and Tonic came through with a solution!  
> **username_1**: Ah my bad, I didn't think of your default SEO fields being in a matrix. {{ seo.seoPageTitle }} would have worked if there was just a plain text field on it's own. Glad you got it sorted.  

---

