vaersaagod/seomate

Not displaying SEO fields when the section is selected based on routing

Closed this issue · 9 comments

I have a section called products which displays products from a category.

The routing is

products/*/slug

I display the product selecting by the any() category in the route and then the slug.

The

CleanShot 2023-07-16 at 14 43 31

But the product page section has no URI format as that is set in the routes.

The product pages do have both the seoTitle and title fields in the page data.

The issue is that all product pages display only the site name in the title tag. The seo fields are not being used - apart from the site name field.

All other sections do display the content of the seoTitle field or the title field as specified in the config.

Any idea on how to get the seoTitle field to display for the product templates?

<?php

return [

    'includeSitenameInTitle' => true,
    'cacheEnabled' => false, // for testing in ddev

    'defaultProfile' => 'standard',

    'fieldProfiles' => [
        'standard' => [
            'title' => ['seoTitle', 'title'],
            'description' => ['seoDescription', 'summary'],
            'image' => ['seoImage', 'mainImage']
        ],
    ],

    'sitemapEnabled' => false,
    'sitemapLimit' => 500,
    'sitemapConfig' => [
        'elements' => [
            'pages' => ['changefreq' => 'daily', 'priority' => 1],
            'products' => ['changefreq' => 'daily', 'priority' => 0.5],
        ],
    ],
];

PHP version | 8.0.28
Linux 5.15.49-linuxkit-pr
MariaDB 10.4.28
Imagick 3.7.0 (ImageMagick 6.9.11-60)
Craft Solo 4.4.15
2.0.47
v3.4.3
7.7.0

If the URI (i.e. products/something/slug) doesn't match an element's URI (i.e. there is no entry or category variable injected in the template), SEOMate has no way of knowing what element to use for the meta data.

In such cases you'll need to tell SEOMate which element to use, by overriding SEOMate's meta data in the relevant template, setting the element to your product entry:

{% set seomate = {
    element: product,
} %}

Thank you for replying to this!

It seems like the entry variable is set, but the fields info is not getting included.

From the product detail template:

  {% set entry = craft.entries()
      .section('products')
      .slug(slug)
      .one() %}

    {# add the seomate override #}
    {% set seomate = { element: entry } %}

An idea on how to debug this?

A dump of the entry:

craft\elements\Entry {[#1684 ▼](https://test.ddev.site/products/%D0%BF%D1%80%D1%8F%D1%81%D0%BD%D0%BE-%D0%B8%D0%B7%D1%86%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8-%D1%81%D0%BE%D0%BA%D0%BE%D0%B2%D0%B5/%D0%BF%D1%80%D1%8F%D1%81%D0%BD%D0%BE-%D0%B8%D0%B7%D1%86%D0%B5%D0%B4%D0%B5%D0%BD-%D1%81%D0%BE%D0%BA-%D0%BE%D1%82-%D0%BB%D0%B8%D0%BC%D0%BE%D0%BD#sf-dump-94574140-ref21684)
  +sectionId: 3
  +postDate: DateTime @1688022000 {#1689 ▶}
  +expiryDate: null
  +deletedWithEntryType: false
  +_authorId: 1
  -_author: null
  -_typeId: 6
  -_oldTypeId: 6
  #revisionCreatorId: null
  #revisionNotes: null
  -_canonicalId: null
  -_canonical: null
  -_canonicalAnySite: null
  -_canonicalUid: null
  -_outdatedAttributes: null
  -_modifiedAttributes: null
  -_outdatedFields: null
  -_modifiedFields: null
  -_initialized: true
  -_fieldsByHandle: []
  -_fieldParamNamePrefix: null
  -_normalizedFieldValues: null
  -_allDirty: false
  -_dirtyAttributes: []
  -_savedTitle: "the title"
  -_dirtyFields: []
  -_nextElement: false
  -_prevElement: false
  -_parentId: null
  -_parent: null
  -_hasNewParent: null
  -_prevSibling: null
  -_nextSibling: null
  -_eagerLoadedElements: []
  -_eagerLoadedElementCounts: []
  -_currentRevision: null
  -_enabledForSite: true
  -_uiLabel: null
  -_uiLabelPath: []
  -_isFresh: null
  -_errors: null
  -_validators: null
  -_scenario: "default"
  -_events: []
  -_eventWildcards: []
  -_behaviors: array:1 [▶]
  +id: 1450
  +tempId: null
  +draftId: null
  +revisionId: null
  +isProvisionalDraft: false
  +uid: "a23803f5-d760-41a0-806b-b7cbedbd86db"
  +siteSettingsId: 1450
  +fieldLayoutId: null
  +structureId: null
  +contentId: 404
  +enabled: true
  +archived: false
  +siteId: 1
  +title: "the title"
  +slug: "the-slug"
  +uri: null
  +dateCreated: DateTime @1689294139 {#1685 ▶}
  +dateUpdated: DateTime @1689554207 {#1688 ▶}
  +dateLastMerged: null
  +dateDeleted: null
  +root: null
  +lft: null
  +rgt: null
  +level: null
  +searchScore: null
  +trashed: false
  +awaitingFieldValues: false
  +propagating: false
  +propagateAll: false
  +newSiteIds: []
  +isNewForSite: false
  +resaving: false
  +duplicateOf: null
  +firstSave: false
  +mergingCanonicalChanges: false
  +updatingFromDerivative: false
  +previewing: false
  +hardDelete: false
}


Can you give a more complete example for the product detail page template?

The {% set seomate = ... part needs to sit outside any {% block %} tags, assuming the page template is using template extension.

Here's the full template.

{% extends "_layouts/_base" %}

{% block head %}
  {{ parent() }}
{% endblock %}

{% block settings_block %}
  {% set bodyAttributes = {id: 'body'} %}
{% endblock %}



{% block body %}
  {% block content %}

    {% set entry = craft.entries()
      .section('products')
      .slug(slug)
      .one() %}

    {# add the seomate override #}
    {% set seomate = { element: entry } %}

    <pre>{{ dump(entry) }}</pre>


    <div class="o-container">
      <div class="o-content -wide">
        <div class="o-content__intro mt-m">
          <h1>{{entry.title}}</h1>
        </div>
        <div class="product-detail">
          <div class="product-detail__main">
            {% if entry.productImage|length %}
              {% set the_image = entry.productImage.one() %}
              <img src="{{the_image.getUrl()}}" alt="{{the_image.title}}">
            {% endif %}
            {{ entry.productDescription }}

            <div class="product-detail__seal">
              <img src="{{ productsSealOfQuality.theImage.one().getUrl() }}" alt="{{productsSealOfQuality.theImage.one().title}}">
              {{ productsSealOfQuality.richText }}
            </div>
          </div>

          <div class="product-detail__label">
            <p>
                {# ... display product details #}
            </p>

              {% set label = entry.productLabel.one() %}

            {# ... display product details #}
          </div>
        </div>
      </div>
      <div class="o-content -centered">
        <a class="link--back" href="/products"><svg class="icon icon-arrow-left2"><use xlink:href="#icon-arrow-left2"></use></svg>Products </a>
      </div>
    </div>




  {% endblock %}
{% endblock %}


Thanks for the extended example. You'll need to move this part out to the root of the template (i.e. same level as the {% extends %} tag:

{% set entry = craft.entries()
      .section('products')
      .slug(slug)
      .one() %}

{# add the seomate override #}
{% set seomate = { element: entry } %}

So that it looks like this:

{% extends "_layouts/_base" %}

{% block head %}
  {{ parent() }}
{% endblock %}

{% block settings_block %}
  {% set bodyAttributes = {id: 'body'} %}
{% endblock %}

{% set entry = craft.entries()
    .section('products')
    .slug(slug)
    .one() %}

{# add the seomate override #}
{% set seomate = { element: entry } %}

{% block body %}
  {% block content %}
      ...

Per your suggestion I moved the override outside of the code blocks and now it does display the title info.

Thank you.

Wondering - would I need to create overrides for the sitemap, too, given the unconventional treatment of the URI?

I am seeing the details of the override instructions - and these should also handle the sitemap.

Thank you again for helping me navigate the documentation. Appreciate your work and support - seomate is incredibly useful.

Great! I'm probably stating the obvious, but in general you'd have an easier time if you could have a URI format on the products section, instead of using a route. For example, if the category/product relationship is defined in a category field on the product entry, your "Products" section could use the URI format products/{categoryFieldHandle.one().slug}/{slug}.

@mmikkel this was not obvious to me! I did not know I could use an API call in the URI field.

Also, it's multiple categories - a parent one and one or more sub-categories... I'd need to select the parent category. I'm going to try this out - would make things much simpler.