Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-11-05T21:04:04.180Z
Answers.LastActivityDate: 2014-11-05T22:17:42.007Z
Answers.LastEditDate: 2014-11-05T22:17:42.007Z
Answers.UserDisplayName: Martin
Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-11-03T11:27:06.810Z
Answers.Text: 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)?
Answers.UserDisplayName: Martin
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-11-03T11:29:44.593Z
Answers.Text: 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.
Answers.UserDisplayName: Jamie Wade
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-11-03T15:46:32.600Z
Answers.Text: 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?! :/
Answers.UserDisplayName: Martin
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-11-03T16:03:40.227Z
Answers.Text: I've got it... I still need to wrap {% for block in seoSetup.seoSettings %} around {{ block.seoPageTitle }}
Answers.UserDisplayName: Martin
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-11-03T16:07:49.443Z
Answers.Text: You got it, sorry for the confusion. I started my code example from inside the for loop.
Answers.UserDisplayName: Jamie Wade
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-11-03T19:50:59.423Z
Answers.Text: 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?
Answers.UserDisplayName: Martin
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-11-04T10:24:21.887Z
Answers.Text: 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.
Answers.UserDisplayName: Jamie Wade
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-11-04T10:33:08.017Z
Answers.Text: Hi, yep, checked, checked and checked again :/ 'seoPageTitle'
Answers.UserDisplayName: Martin
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-11-04T12:59:06.733Z
Answers.Text: Hmm, strange. I'll set up a test Craft site tonight for you and I'll take a look.
Answers.UserDisplayName: Jamie Wade
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-11-05T21:02:38.440Z
Answers.Text: Hi Jamie, Brad at Pixel and Tonic came through with a solution!
Answers.UserDisplayName: Martin
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-11-06T09:38:34.213Z
Answers.Text: 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.
Answers.UserDisplayName: Jamie Wade
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-11-03T10:50:26.133Z
Answers.LastActivityDate: 2014-11-03T11:02:02.637Z
Answers.LastEditDate: 2014-11-03T11:02:02.637Z
Answers.UserDisplayName: Jamie Wade
Body: <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>
  
Tags: <templating>
Title: Code refinement on checking a field for content and outputting an alternative
ThreadText: # 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 %}
                                  <title>{{ block.seoPageTitle }}</title>
                              {% endfor %}
                          {% endfor %}
                      {% else %}
                          <title>{{ block.seoPageTitle }}</title>
                      {% endif %}
  
                      <meta name="description" content="{{ block.seoDescription }}" />
                      <meta name="google-site-verification" content="{{ block.googleVerificationNumber }}" />
                      <meta name="msvalidate.01" content="{{ block.bingVerificationNumber }}" />
  
                  {% elseif block.type == "seoAdditional" %}
  
                      <link rel="canonical" href="{{ block.seoCanonicalLinks }}" />
                      <meta name="robots" content="{{ block.seoRobotContent }}" />
  
                  {% elseif block.type == "seoGeographic" %}
  
                      <meta name="geo.region" content="{{ seoGeoRegion }}" />
                      <meta name="geo.placename" content="{{ seoGeoPlacename }}" />
                      <meta name="geo.position" content="{{ seoGeoLattitude }};{{ seoGeoLongitude }}" />
                      <meta name="ICBM" content="{{ seoGeoLattitude }}, {{ seoGeoLongitude }}" />
  
                 {% elseif block.type == "seoOpenGraph" %}
  
                      <meta property="og:title" content="{{ block.ogTitle }}" />
                      <meta property="og:description" content="{{ block.ogDescription }}" />
                      <meta property="og:type" content="{{ block.ogType }}" />
                      <meta property="og:url" content="{{ block.ogUrl }}" />
                      <meta property="og:image" content="{% for image in block.ogImage %}{{ image.getUrl() }}{% endfor %}" />
                      <meta property="og:author" content="{{ block.ogAuthor }}" />
                      <meta property="og:site_name" content="{{ block.ogSiteName }}" />
                      <meta property="og:locale" content="{{ block.ogLocale }}" />
                      <meta property="og:locale:alternate" content="{{ block.ogAlternativeLocale }}" />
                      <meta property="fb:admins" content="{{ block.ogFacebookAdmin }}"/>
  
                  {% elseif block.type == "twitterCard" %}
  
                      <meta name="twitter:card" content="{{ block.twitterCard }}" />
                      <meta name="twitter:title" content="{{ block.twitterTitle }}" />
                      <meta name="twitter:description" content="{{ block.twitterDescription }}" />
                      <meta name="twitter:site" content="{{ block.twitterSite }}">
                      <meta name="twitter:creator" content="{{ block.twitterCreator }}">
                      <meta name="twitter:url" content="{{ block.twitterUrl }}" />
                      <meta name="twitter:image" content="{% for image in block.twitterImage %}{{ image.getUrl() }}{% endfor %}" />
  
                  {% elseif block.type == "googlePlus" %}
  
                      <meta itemscope itemtype="http://schema.org/{{ block.schemaPageType }}" />
                      <meta itemprop="name" content="{{ block.schemaName }}" />
                      <meta itemprop="description" content="{{ block.schemaDescription }}" />
                      <meta itemprop="image" content="{% for image in block.schemaImage %}{{ image.getUrl() }}{% endfor %}" />
  
                  {% elseif block.type == "rdPartyVerification" %}
  
                      <meta name="{{ block.partyName }}" content="{{ block.partyContent }}"/>
  
                  {% 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 username_1 for looking into this.
  
  ```
  {% for block in entry.seoInfo %}
      {% if block.type == "seoBasics" %}
  
          {% if block.seoPageTitle | length %}
              <title>{{ block.seoPageTitle }}</title>
          {% else %}
              {% for block in seoSettings.seoInfo.type('seoBasics') %}
                  <title>{{ block.seoPageTitle }}</title>
              {% 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](http://buildwithcraft.com/docs/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 %}
          <title>{{ block.seoPageTitle }}</title>
  
      {# If it hasn't, use the default page title from the SEO Global #}
      {% else %}
          <title>{{ seo.seoPageTitle }}</title>
  
      {% endif %}
  
  ```
  
  I hope this helps you in the right direction, if you have any questions then let me know.
  
  > **Comments:**
  > **username_0**: Thanks username_1, 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 username_1, 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 username_1, 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.  
  
  ---
  
  