Technical SEO

Dynamic Meta Tags: Building SEO Into a CMS Template by Template

Code editor showing a list of files and highlighted source code
In this article10 sections

Dynamic meta tags are the title, meta description, canonical, robots and social preview tags that a CMS generates for every page from its data, with fallbacks when editors leave fields empty. Done well, they guarantee that every page has a unique, accurate title and description, a correct canonical URL and a sensible preview when shared, even on a site with thousands of products and articles.

Done badly, they produce the same description on every page, titles cut off before the important words, canonicals pointing to the home page and social previews with the wrong image. The solution is not more editor fields; it is a small, central SEO service with clear rules per template, plus optional overrides for the pages that deserve hand-written copy.

This guide shows the structure we use in PHP applications and the rules behind each tag.

Key takeaways

  • Centralise meta tag generation in one service, called by controllers and rendered once by the layout.
  • Give each template a fallback chain so no page ever ships without a title or description.
  • Add the brand suffix only when the full title still reads well.
  • Output canonical, robots and Open Graph tags from the same data as the page.
  • Offer editor overrides with live length guidance and a search preview.

Why dynamic meta tags belong in one place

In many projects, meta tags are scattered across templates: one view sets a title, another hard-codes a description, a plugin adds its own canonical. The result is duplicated tags, conflicting values and pages nobody remembered to handle. A central service fixes this by separating decisions from output.

  • Controllers decide: they pass the entity and any page-specific values to the SEO service.
  • The service applies rules: fallbacks, length limits, brand suffix, canonical and robots logic.
  • The layout outputs: one block in the head renders whatever the service holds, exactly once.

This structure also makes testing easy. Because every value passes through one service, a test can render any template and inspect the final head without running a browser.

// Controller
Seo::fromEntity($service, $service['title'], $service['hero_intro']);
Seo::canonical('/services/' . $service['slug']);
Seo::breadcrumbs([['Home', '/'], ['Services', '/services'], [$service['title'], null]]);

// Layout head (rendered once)
<?= Seo::render($request) ?>

Titles: fallback chain and brand suffix

Every template needs a rule for its title when the editor has not written one. The editor's override always wins, then a template-specific pattern, then the record's own title.

TemplateFallback pattern
ServiceSEO title, else service name
ArticleSEO title, else article title
CategorySEO title, else "Category name: articles and guides"
ProductSEO title, else product name and key attribute
Search and filter pagesNot indexed, so a plain descriptive title is enough

Google's documentation on title links recommends concise branding. A practical rule is to append the brand only when the combined title still fits comfortably, and otherwise show the page title alone rather than cutting it.

public static function fullTitle(string $title, string $brand, bool $final = false): string
{
    if ($final) {
        return $title;                       // editor wrote a complete title
    }
    $full = $title . ' | ' . $brand;
    return mb_strlen($full) <= 60 ? $full : $title;   // drop the brand rather than truncate the title
}

The $final flag matters. When an editor writes a complete title with the brand already included, the service should output it exactly as written rather than adding a second brand suffix. Store a simple boolean or detect the override field, and keep the decision in one place.

Our guide to title tags and meta descriptions covers the writing side for editors.

Descriptions: summarise, do not duplicate

The meta description fallback should never be a site-wide default. Duplicate descriptions across hundreds of pages are worse than none, because Google ignores them and generates snippets anyway. Build the fallback from the page's own content.

For products, a template sentence built from structured fields can work well: name, a key attribute, price from and delivery information. It is not as good as a hand-written description, but it is unique, accurate and kept up to date automatically when prices or stock change.

  1. Use the editor's SEO description when present.
  2. Otherwise use the excerpt, summary or introduction field.
  3. Otherwise take the first paragraph of the body.
  4. Strip tags, collapse whitespace and cut at a word boundary near 160 characters.
public static function description(string $text): string
{
    $clean = trim(preg_replace('/\s+/', ' ', strip_tags($text)) ?? '');
    if (mb_strlen($clean) <= 160) {
        return $clean;
    }
    $cut = mb_substr($clean, 0, 157);
    return mb_substr($cut, 0, (int) mb_strrpos($cut, ' ')) . '...';
}

Canonical and robots tags

Canonical and robots decisions belong in the same service, because they depend on the same context: the template, the record and the request.

  • Canonical: build from the route, not the request URI, keeping only parameters that genuinely change content such as later page numbers.
  • Robots: default to indexable; switch to noindex for internal search, empty listings, previews, thank-you pages and records flagged by editors.
  • Staging: force noindex on every non-production environment, and also protect it with authentication.
  • One of each: the layout should render exactly one canonical and one robots tag per page.

Previews deserve special care. Draft previews shared with clients or colleagues are often public URLs with a token. They must always carry noindex, and ideally a no-store cache header, so they never appear in search results or shared caches.

Our guides to canonical URLs and robots.txt and noindex explain the rules behind these choices.

Open Graph and social previews

When a page is shared in messaging apps and social networks, the preview usually comes from Open Graph tags. They should be generated from the same data as the search tags, with an image chosen per template.

<meta property="og:type" content="article">
<meta property="og:title" content="Dynamic Meta Tags: Building SEO Into Your CMS Templates">
<meta property="og:description" content="Build dynamic meta tags into a CMS...">
<meta property="og:url" content="https://example.com/blog/dynamic-meta-tags-cms">
<meta property="og:image" content="https://example.com/uploads/cover-1600.webp">
<meta name="twitter:card" content="summary_large_image">
  • Image fallback: social image override, then the page's main image, then a branded default.
  • Absolute URLs for og:url and og:image, matching the canonical host.
  • Image size: a large landscape image, commonly 1200 by 630 pixels, works across most platforms.
  • Type: article for posts, website for most other pages.

Social platforms cache previews, sometimes for days. When an image or title changes, most platforms offer a debugging tool to refresh their copy. Test previews before a campaign launches rather than after the first share looks wrong.

  • Alt text: provide og:image:alt where the platform supports it, describing the image for accessibility.

Pagination, archives and special pages

Listing pages need their own rules. Google treats each page in a paginated series as its own URL, so later pages should be indexable with self-referencing canonicals, not pointed at page one.

  • Add "Page 2", "Page 3" to titles of later pages so they are not exact duplicates.
  • Keep the first page's canonical free of ?page=1, and redirect that parameter to the clean URL.
  • Set noindex on archive pages with no items, such as empty tags or categories.
  • Return 404 for page numbers beyond the last page instead of an empty listing that returns 200.
  • Use a description such as "Page 2 of articles about technical SEO" for later pages, generated automatically.

Multilingual sites and hreflang

On sites with several languages or regional versions, the meta layer also outputs hreflang annotations that connect equivalent pages. Each language version lists every other version, including itself, plus an x-default for visitors whose language is not covered.

<link rel="alternate" hreflang="en" href="https://example.com/services/seo-services">
<link rel="alternate" hreflang="ar" href="https://example.com/ar/services/seo-services">
<link rel="alternate" hreflang="x-default" href="https://example.com/services/seo-services">
  • Generate from a translation map, not from string replacement on the URL, because translated slugs differ.
  • Make annotations reciprocal: if page A lists page B, page B must list page A.
  • Keep canonicals self-referencing on each language version; never point translations at the English page.
  • Translate titles and descriptions rather than reusing the English ones.

Hreflang errors are common and quiet. Add tests that load each language version of a sample page and check that the annotations match on every side.

Editor fields that help rather than hinder

Editors should be able to override the generated values without needing to understand the rules. A few interface details make overrides useful.

  • Show the generated fallback as a placeholder, so editors see what will be used if they leave the field empty.
  • Add live character counts with guidance ranges for titles and descriptions.
  • Show a search-result preview with the title, URL and description.
  • Keep SEO fields in a separate panel so they do not clutter the main content form.
  • Record who changed SEO fields and when, so unexpected title changes can be traced and reverted.
  • Warn when two published pages share the same title or description.

Testing meta tags

  1. Write template tests asserting exactly one title, description, canonical and robots tag per page.
  2. Assert that the canonical is absolute and points to the page itself on indexable templates.
  3. Crawl the site and report duplicate titles and descriptions across indexable pages.
  4. Check that staging and preview pages always render noindex.
  5. Validate structured data alongside the meta tags; our guide to JSON-LD structured data covers that.

Frequently asked questions

Should every page have a hand-written description?

Your most important pages, yes. For large catalogues, a good fallback from the page's own content works better than a generic default.

Is the meta keywords tag still needed?

No. Google does not use it, so there is no reason to generate it.

Should paginated pages point their canonical to page one?

No. Each page in a series has different content, so it should usually have its own self-referencing canonical.

Can JavaScript set meta tags?

It can, but tags in the initial HTML are more reliable for search engines and social previews.

Want a CMS that gets meta tags right on every page? Our SEO services include template audits, and our developers can build the SEO layer for you.

Free expert advice

Want an expert to look at your store?

Tell us what you are working on. A senior e-commerce consultant will reply within one working day with honest, practical advice. No obligation and no sales script.

  • Reply within one working day
  • Advice even if we are not the right fit
  • Your details are never shared

We use your details only to reply to you. See our privacy policy.

About the author
Pracoda Team

The Pracoda Technologies engineering team builds Magento 2 and Adobe Commerce stores, custom software, mobile apps and integrations from Lucknow, India, for clients around the world. The team has worked with Magento and PHP for more than ten years. Here it writes about technical SEO, performance, hosting and development practice, drawing on the same techniques it uses on client projects every day.

Need a consultation?

Tell us what you are building.

Share the problem, the platform and the deadline. We will come back with an approach, a team and an estimate.