Base CMS Made Simple page template with automated metatags

  Previous article Next article  

How to build a CMS Made Simple™ page template and show the news/blog title as the page title, get the correct canonical value for module detail pages, pass a correct image to social media websites, etc... I will describe here how to do that with just clever use of Smarty in your templates.

Important is to first understand the way templates are processed in CMSMS™.
The Core::Page template contains three different areas:

<!-- Area 1 -->

<head> <!-- Area 2 --> </head>

<!-- Area 3 -->

The areas are rendered in the order: one, three and two!

To pass data between these areas this order is important. To use a parameter it has to be processed in the same area or in an area before it.
The advantage of processing parameters in the top of the page template (area 1) is you can use the parameters globally.
The module output will be processed at first, after that the content blocks. When that is done and variables don't have a value the default values are entered. No need for if this than that or else... logic in the top or the content of a template.

Because I re-use the values in other template areas/scopes I added scope=global to the assigned parameters.
Read here much more about Smarty scope »

  How to use

 The base Core::Page template

The content of the template in Design Manager:

{* ++++++++++++++++++++++++ Area 1 ++++++++++++++++++++++++ *}

    {$theme_url = "{root_url}/assets/themes/name" scope=global}

    {$content = "{content}" scope=global}

    {$canonical_url = $canonical_url|default:"{$content_obj->GetURL()|lower|default:''}" scope=global}
    {*RedirectCanonical canonical_url=$canonical_url exclude=''*} {* -> *}
    {$root_url = $root_url|default:"{root_url}" scope=global}
    {$short_url = $short_url|default:$canonical_url scope=global}
    {$previous_url = $previous_url|default:"{cms_selflink dir='prev' urlonly=1}" scope=global}
    {$next_url = $next_url|default:"{cms_selflink dir='next' urlonly=1}" scope=global}

    {$site_name = $site_name|default:"{sitename}" scope=global}

    {$page_breadcrumbs = $page_breadcrumbs|default:"{nav_breadcrumbs}" scope=global}
    {$page_description = $page_description|default:"{description}"}
    {$page_description = $page_description|default:$content|strip_tags:false|strip|trim|truncate:300|default:'' scope=global}
    {$page_image = $page_image|default:"{$theme_url}/page_image.png" scope=global}
    {$page_lang = $page_lang|default:'en' scope=global}
    {$page_modified = $page_modified|default:"{modified_date format='%e-%m-%Y'}" scope=global}
    {$page_title = $page_title|default:"{title}" scope=global}

<html lang="{$page_lang}">

{* ++++++++++++++++++++++++ Area 2 ++++++++++++++++++++++++ *}


    <title>{$page_title} - {$site_name}</title>

    <meta charset="utf-8">



{* ++++++++++++++++++++++++ Area 3 ++++++++++++++++++++++++ *}

        <h1><a href="{$root_url}">{$site_name}</a></h1>




        <p>This page is last modified: {$page_modified}.</p>

Available global parameters in the template


To output the regular content block in the main content area


The canonical url for a regular page and if set in a module overwritten to the detail url for the module detail page.


The root url of the website. Can be useful in multi domain websites.


The shortened url of a regular page or if set in a module overwritten to the shortened detail url for the module detail page.


This tag is set so it can be used at multiple spots in your templates. If you move the website or template you only need to change the path once.
In this example all theme files are stored in


The website name


Create your custom breadcrumb trail for modules. How? Read this tutorial ».


The description of the page. First looks at the description field in the content page, second if a module has the description set and third a summarize of the content tag.


The full path to the image that is used when the website url is linked from social media websites and apps.
The default website image is named page_image.png and is stored in = {$theme_url}.
If you have a separate image set in your news/blog module this one will be used instead.
Don't make the image to small otherwise it will be ignored by Facebook. I don't know what the "official" requirements are, but in my experience it must be at least 500px.


Set the language once. Is useful for multilingual websites.


When is the page or module detail information last modified.


The page title, first the title set in the page editor and if set in the module detail template the title of the i.e. news article.

 Pass data from modules to the page template

Two examples how to use module data in the Core::Page template.

News module

Move this code to the top of your News module detail template:

{$canonical_url = $entry->canonical|lower scope=global}
{$page_description = $entry->summary|default:$entry->content|strip_tags:false|strip|truncate:300 scope=global}
{$page_modified = $entry->modified_date|date_format:'%e-%m-%Y' scope=global}
{$page_title = $entry->title|cms_escape:htmlall scope=global}

Optional: First create field definition Image: "photo".

{if !empty($entry->>value)}
    {$page_image = "{uploads_url}/news/id{$entry->id}/{$entry->>value}" scope=global}

CGBlog module

Move this code to the top of your CGBlog module detail template:

{$canonical_url = $entry->canonical|lower scope=global}
{$page_description = $entry->summary|default:$entry->content|strip_tags:false|strip|truncate:300 scope=global}
{$page_modified = $entry->modified_date|date_format:'%e-%m-%Y' scope=global}
{$page_title = $entry->title|cms_escape:htmlall scope=global}

Optional: First create field definition Image: "photo".

{if !empty($entry->>value)}
    {$page_image = "{$entry->file_location}/{$entry->>value}" scope=global}

You can do similar for other modules that have detail pages, like Company Directory, Products and Uploads module. Don't forget to change the Smarty strings according the module's requirements.

 Automate your metadata tags for SEO purposes

Now we have all parameters globally available, we can use them for setting the metadata tags. A few examples:

General tags for the <head></head> area

<meta name="application-name" content="{$site_name}">
<meta name="copyright" content="Copyright (C) Your name, All Rights Reserved"> {* <- Change this *}
<meta name="description" content="{$page_description}">
<meta name="generator" content="CMS Made Simple - Copyright (C) 2004-{$|date_format:'%Y'} CMSMS™. All rights reserved.">

<link rel="canonical" href="{$canonical_url}">
<link rel="shortlink" href="{$short_url}">
<link rel="start" href="{root_url}">
{if !empty($previous_url)}<link rel="prev" href="{$previous_url}">{/if}
{if !empty($next_url)}<link rel="next" href="{$next_url}">{/if}

Open Graph tags for Facebook in the <head></head> area

<meta property="og:description" content="{$page_description}">
<meta property="og:image" content="{$page_image}">
<meta property="og:site_name" content="{$site_name}">
<meta property="og:title" content="{$page_title}">
<meta property="og:type" content="website">
<meta property="og:updated_time" content="{$page_modified}">
<meta property="og:url" content="{$short_url}">

Meta tags for Twitter in the <head></head> area

<meta name="twitter:card" content="summary">
<meta name="twitter:creator" content="@yourtwitter"> {* <- Change this *}
<meta name="twitter:description" content="{$page_description}">
<meta name="twitter:dnt" content="on"> {* do not track visitors *}
<meta name="twitter:domain" content="{$root_url}">
<meta name="twitter:image" content="{$page_image}">
<meta name="twitter:site" content="@yourtwitter"> {* <- Change this *}
<meta name="twitter:title" content="{$page_title}">
<meta name="twitter:url" content="{$short_url}">

Because the {metadata} tag is in the head area of the page template, you can also add the meta code above in the Global Metadata field in the Global Settings Admin page!

 Test and Debug Lines

Put these lines in the body area of your CMSMS Core::Page template and you can use them to test and debug your work!

{* ++++++++++++++++++++++++++++++++++++ *}
<hr />
<p><b>+++ TEST AND DEBUG LINES +++</b></p>
<p><b>$site_name:</b> {$site_name}</p>
<br />
<p><b>$canonical_url:</b> {$canonical_url}</p>
<p><b>$root_url:</b> {$root_url}</p>
<p><b>$short_url:</b> {$short_url}</p>
<p><b>$theme_url:</b> {$theme_url}</p>
<p><b>$previous_url:</b> {$previous_url}</p>
<p><b>$next_url:</b> {$next_url}</p>
<br />
<p><b>$page_breadcrumbs:</b> {$page_breadcrumbs}</p>
<p><b>$page_description:</b> {$page_description}</p>
<p><b>$page_image:</b> {$page_image}</p>
<p><b>$page_lang:</b> {$page_lang}</p>
<p><b>$page_modified:</b> {$page_modified}</p>
<p><b>$page_title:</b> {$page_title}</p>
<hr />
{* ++++++++++++++++++++++++++++++++++++ *}

When you are ready, just delete them.

  Working example

I use this at:

Buy Me A Coffee

  Comment Form


Click here to open the form



Buy Me A Coffee

CMS Made Simple - Tutorials, Tips and Tricks - CMSMS

Base CMS Made Simple page template with automated metatags

  Article optimized for CMSMS 2.x

  Last tested in: CMSMS 2.2.19
  Last updated: 14-02-2019
  Comments: 12

Buy Me A Coffee


Ads help me to help you! Thanks!

Ads help me to help you! Buy products from these advertisers!