Search Engine Optimisation (SEO)
To help search engine bots find and index MM content on your website, various settings can be configured.
Contao Search
For the Contao search,
content is indexed in various ways — either when a page is visited by a user, or by the
Contao crawler, which follows links on pages
and evaluates the sitemap.xml.
For indexing to work, the usual permissions must be granted in the page settings and search must not be excluded.
To support indexing of detail pages via sitemap.xml, a custom index can be set up in MM —
see Indexing.
For pages with FE filters that contain link lists, note how to exclude links from crawling.
SEO for Google & Co.
“Human-Readable” URLs
This mostly concerns linking to the detail page, e.g. from a list page. The alias of the item is typically used for filtering on the detail page. In the settings of the Alias or Translated Alias attribute, the desired combination of other attribute values can be defined.
Meta Data: Title and Description
These settings primarily apply to a detail page. In the CE/FE module MM List, there is a select field for choosing existing attributes for the title and description.
The description should concisely summarise the content of the page. While
Google does not enforce a maximum character count,
many SEO resources recommend a maximum of 150–160 characters — Contao itself limits this to
320 characters in fe_page.
For more individual control, custom text attributes can be created for title and description, allowing editors to optimise these values independently of other attributes.
As a further option, title and description can be set directly in the render template — see Templates in MetaModels. The following snippet shows how this can be done in the template:
1<?php
2// templates/metamodels_prerendered_details.html5
3use Contao\CoreBundle\Routing\ResponseContext\HtmlHeadBag\HtmlHeadBag;
4use Contao\StringUtil;
5use Contao\System;
6
7$container = System::getContainer();
8$htmlDecoder = $container->get('contao.string.html_decoder');
9$responseContext = $container->get('contao.routing.response_context_accessor')->getResponseContext();
10$htmlHeadBag = $responseContext->get(HtmlHeadBag::class);
11?>
12...
13<?php
14$htmlHeadBag->setTitle($htmlDecoder->inputEncodedToPlainText($arrItem['text']['title'] . ' - ' $arrItem['text']['art_no']));
15$htmlHeadBag->setMetaDescription(StringUtil::substr($htmlDecoder->inputEncodedToPlainText($arrItem['text']['title'] . ' - ' $arrItem['text']['description']), 160));
16?>
The $htmlHeadBag could also be provided via a helper class with injected services.
Meta Data: hreflang
If a multilingual website also outputs content in one or more other languages, a hreflang
link can be provided to help search engines. To offer language switching to frontend visitors,
various extensions are available — the most common is
“ChangeLanguage”.
This extension automatically generates hreflang metadata, provided the corresponding
relations are configured in the page settings.
The links output in the source code work without further adjustments, but only point to the page alias of the other language pages — without passing filter parameters such as those used on a detail page.
The “ChangeLanguage” extension offers an option in the page settings called “Keep query
parameters” where keys can be specified. The corresponding key-value pairs are then appended to
the other language links. However, the key auto_item is not supported natively.
For language switching on a detail page, the following configuration can be used:
Filter “Details” with filter rule “Simple lookup” for attribute “Alias” — leave “URL parameter” as
alias, do not set it toauto_itemIn the page settings under “Keep query parameters”, enter
aliason all detail pages
The result would look like this:
1<link rel="alternate" hreflang="de" href="http://my-domain.tld/de/details/alias/mayer-herbert">
2<link rel="alternate" hreflang="x-default" href="http://my-domain.tld/de/details/alias/mayer-herbert">
3<link rel="alternate" hreflang="en" href="http://my-domain.tld/en/details/alias/mayer-herbert">
If you want to create links using auto_item or include translated key-value pairs from
multilingual attributes in the URL, a custom implementation is required — for example via the
“changelanguageNavigation”
hook.
Slug vs. GET Parameters in Filter URLs
From MM 2.4, each filter rule has a setting “URL type for the parameter” that controls whether a filter parameter is passed as part of the URL path (slug) or as a classic GET parameter — see Filter rule settings.
Slug parameters (human-readable URL paths) produce clean, readable URLs — e.g.
/products/category/with-battery instead of /products?category=with-battery. These are
generally the preferred option for indexable content, as search engines treat them as distinct
pages. They are particularly suitable when filter combinations should function as standalone,
indexable landing pages. However, this can quickly lead to a large number of potential URL
variants, which should be carefully managed via canonical tags or indexing rules. With slug
parameters, using auto_item as the URL parameter hides the key — e.g. for a category:
/products/with-battery — but auto_item only works for a single URL parameter.
GET parameters (e.g. ?colour=red) are processed by search engines as well, but are
considered less “readable” and often interpreted as technical variants of the same page. They
are therefore better suited for purely functional filters that should have no independent SEO
relevance and typically do not need to be indexed. Combined with appropriate canonical URLs,
this prevents an unnecessary proliferation of duplicate content variants. Additionally, for
tracking tools such as Google Analytics, certain GET parameters can be excluded from tracking.
Recommendation:
Slug parameters should be used for filterable, SEO-relevant combinations, while GET parameters
are better suited for purely interactive or non-indexable filters. The decision ultimately
depends on whether a filter combination should function as a standalone landing page or merely
serve internal navigation.
Note: if a parameter is present as both a slug and a GET parameter, Contao returns a 404.
Pagination of List Output
Longer output lists should be paginated — both for better user readability and faster page loading, and for better ranking in search engine performance evaluations.
The output page should include a canonical URL in its metadata — this can be enabled in the page settings. Google specifies that the first page (base page) should not be marked as the canonical page — only subsequent pagination pages should be — see Google “Use URLs correctly”.
The use of rel="next" and rel="prev"
is no longer honoured by Google —
other search engines such as Bing may still evaluate them, and some browsers use these meta
links to prefetch pages.
To output these tags in the head of the page, a custom template mm_pagination.html5 can
be created and the meta tags added there — e.g.
1<?php
2// templates/mm_pagination.html5
3...
4<?php if ($this->hasPrevious): ?>
5 <?php $GLOBALS['TL_HEAD'][] = '<link rel="prev" href="' . $this->previous['href'] . '" />' ?>
6...
7<?php if ($this->hasNext): ?>
8 <?php $GLOBALS['TL_HEAD'][] = '<link rel="next" href="' . $this->next['href'] . '" />' ?>
9...
Structured Data
For semantic classification of the output content, so-called “Structured Data” can also be included in the source code.
With this supplementary data, a search engine can classify the content — for example as an FAQ, event, job listing, property ad, or recipe.
How to embed this data is described in the article “Outputting Structured Data in the FE Template”.
To include images from the File attribute — as is standard in Contao — in JSON-LD data, a
corresponding template mm_attr_file_contao_image.html5 is available. It must be selected in
the render settings for the attribute, or its content incorporated into a custom template.
There is also a template mm_attr_file_contao_image_ofpage.html5, which additionally includes
the first image as primaryImageOfPage in the JSON-LD data. If this image entry is present,
it will be displayed e.g. in Contao search results — analogous to the detail views of Contao
news and events.