Markus Michalski FAQ

Sylius SEO Suite Pro: SEO Audit

The SEO audit checks products and categories for missing, too long and duplicate titles and descriptions, missing images and noindex. Start it from the dashboard button or a cron job, with snapshot, lock and limits.

Deutsche Version

Back to overview

Sylius SEO Suite Pro: SEO Audit

The SEO audit checks the products and categories of a channel for SEO problems you can fix in the admin, and lists what it found with a link to the product or category concerned. You start it with a button on the dashboard or with a console command. You reach it through the "SEO audit" button at the top of the "SEO Suite Pro" page.

The audit looks at what the storefront really delivers: the title and description of a page after the priority chain (manual text, then template, then fallback, see SEO Templates). A product whose title comes from a template is therefore not reported as missing a title.

What it checks

The audit runs per channel and per language of the channel, for every enabled product and category that is available in the channel. Disabled products and categories, and those of other channels, are not looked at. A product without a translation in a language is not checked in that language.

Code Checks Severity Threshold
title_missing No manual meta title and no title template applies, so the page title is just the name warning none
title_too_long The delivered title is too long (the detail shows the length) warning more than 60 characters (seo_templates.title_max_length)
title_duplicate The same title on more than one product (or category) of the channel in the same language (the detail shows how many share it) warning from 2 identical titles
description_missing The delivered meta description is empty warning none
description_too_long The delivered meta description is too long (the detail shows the length) info more than 155 characters (seo_templates.description_max_length)
description_duplicate The same description on more than one product (or category), as for titles warning from 2 identical descriptions
product_without_image A product without any image (reported once per product, not per language) warning no image
noindex The product or category is set to noindex; often intended, listed so that a forgotten setting is noticed info none

The severities that exist are error, warning and info. The eight built-in checks only use warning and info; error is available to your own checks. Duplicates ignore upper/lower case and runs of whitespace. An empty text is never a duplicate, it is reported as missing instead. The length thresholds are not audit settings of their own: they follow the limits of the SEO templates, so the audit and the template truncation use the same yardstick.

Below the channels the dashboard also shows the ten most requested 404 paths that no active redirect covers, read live from the 404 log (see Redirects). Each path has a link that opens the redirect form prefilled. This block is not part of the snapshot and works without the audit tables.

What it does not check

Own checks are possible, see below.

How a run works

A run is a snapshot: it writes its findings into mmd_sylius_seo_suite_pro_audit_issue and the run itself into mmd_sylius_seo_suite_pro_audit_run (status running, done or failed, plus the number of findings per check). The dashboard and the list only read these tables, nothing is computed when you open them.

Only a successful (done) run is the current state. The list and the counters show the newest done run of each channel. A run that failed (its findings are partial) never replaces it: the dashboard then says that the last run failed and keeps showing the last good one.

graph TD
    A["Start for one channel"] --> B{"Channel lock free?"}
    B -->|"no, heartbeat fresh"| C["Refused: audit already running"]
    B -->|"yes, or heartbeat older than stale_after_minutes"| D["Take lock, create run as running"]
    D --> E["Load and check a page of page_size products"]
    E --> F["Write findings of the page, set heartbeat, clear memory"]
    F --> G{"More pages and below max_subjects?"}
    G -->|"yes"| E
    G -->|"max_subjects reached"| H["Truncated: run ends as done with hint max_subjects"]
    G -->|"no"| I["Duplicate checks write their findings"]
    I --> J["Close run as done, release lock"]
    H --> J
    J --> K["Delete runs beyond keep_runs"]
    E -->|"error"| L["Close run as failed, release lock"]

audit.max_subjects (20000) limits the products and, separately, the categories per channel. A larger channel is cut off: the run ends as done with the hint "stopped at the subject limit". What it found is real but covers only part of the catalogue. The console command reports this as a failure (exit code 1), so you notice it in a cron job.

Starting an audit

Dashboard

In the admin: "Run audit now" on the card of a channel on the audit dashboard (a POST with a CSRF token). The route sits behind the admin firewall like every other admin screen. The request lasts as long as the run (the PHP time limit is set to 600 seconds, and the session is released before the run so other admin tabs do not wait). The result appears as a flash message: success, a warning when truncated or "already running", an error for missing tables or an unknown channel.

The button runs synchronously and is limited to 600 seconds. The run also clears the entity manager, which detaches everything the request loaded, among them the administrator's user object (it is reloaded with the next request). That is fine for a small catalogue; for a large one use the console command or a cron job.

Console

For every channel or one specific channel:

bin/console mmd:seo-suite-pro:audit:run
bin/console mmd:seo-suite-pro:audit:run --channel=shop

The exit code is 0 when every run finished, 1 when a run was refused (already running), stopped at the subject limit or failed, and 2 for an unknown channel. A nightly cron job at 03:30:

30 3 * * * cd /var/www/shop && bin/console mmd:seo-suite-pro:audit:run --no-interaction

The dashboard and the list

The dashboard shows, per channel, the newest run with counters per check, the button to start a run, and the 404 paths without a redirect. The findings list is a read-only grid with the state of the newest done run of each channel, filterable by product or category code, channel, check, severity and type.

Own checks

Implement Mmd\SyliusSeoSuiteProPlugin\Audit\AuditCheckInterface (or extend AbstractAuditCheck). Any service implementing the interface is tagged mmd_sylius_seo_suite_pro.audit_check automatically; give the tag a priority to set the order. The runner calls start() once per run, inspect() for every product and category in every language, and finish() at the end. A complete example, including the translation keys for the labels, is on the Extending page.

Settings

All keys are optional and live under mmd_sylius_seo_suite_pro.audit:

Setting Default Description
audit.keep_runs 3 Number of runs per channel that are kept
audit.max_subjects 20000 Products and, separately, categories one run checks per channel at most
audit.stale_after_minutes 10 A run without a heartbeat for this long counts as dead and no longer blocks
audit.page_size 200 Products or categories loaded at once
mmd_sylius_seo_suite_pro:
    audit:
        keep_runs: 3
        max_subjects: 20000
        stale_after_minutes: 10
        page_size: 200

Cost

A run reads every enabled product and category of the channel once. Without SEO templates, a page of 200 products needs a constant number of queries (the ids, the products with all translations, the image counts, the channel). With templates the placeholder providers add their own queries (attribute values per product, {taxon.main} per product), exactly what rendering the product page costs. The number of queries then grows with the number of products. Writing the findings is one bulk insert per page. None of this runs on a shop request: the storefront and the Shop API never touch the audit tables.

Host steps

After every update of the plugin run mmd:seo-suite-pro:setup (see Installation), which creates the two audit tables. Without them the dashboard shows a hint instead of the figures, the console command reports the missing migration, the findings list answers with an error, and the 404 block keeps working. The storefront and the Shop API are not affected. If something goes wrong, see Troubleshooting.

Shop API / Headless

The audit is a back office feature: an administrator starts it and reads it in the admin, no visitor and no headless frontend consumes it. The logic lives in AuditRunnerInterface, shared by the console command and the dashboard button. There is therefore no API resource for it. What the Shop API delivers is the SEO resource of the pages themselves.