Markus Michalski FAQ

Sylius SEO Suite Pro: Installation

Installing Sylius SEO Suite Pro: Composer via Packeton, bundle and routes, setup command, opting in the per-product and per-category fields, update, cron jobs and uninstall.

Deutsche Version

Back to overview

Sylius SEO Suite Pro: Installation

This page takes you from composer require to a running plugin. The settings in the admin area are covered on the Configuration page.

Prerequisites

Check the versions in the requirements table of the overview before you install. Important: the plugin only runs on MySQL 8 or MariaDB. On other databases the migrations are skipped and the plugin's tables are not created.

Installation

Packeton

The plugin lives in a private Composer repository. Add it to your shop's composer.json:

{
    "repositories": [
        { "type": "composer", "url": "https://packeton.markus-michalski.net" }
    ]
}

Then install the package:

composer require mmd/sylius-seo-suite-pro-plugin

You receive the credentials for the repository after purchase. The second tab shows how to store them.

Credentials (auth.json)

Put the credentials into an auth.json next to your composer.json (do not commit it):

{
    "http-basic": {
        "packeton.markus-michalski.net": {
            "username": "<username>",
            "password": "<token>"
        }
    }
}

Alternatively, store them once globally:

composer config --global --auth http-basic.packeton.markus-michalski.net <username> <token>

Step 1: Register the bundle

Add the bundle to config/bundles.php:

Mmd\SyliusSeoSuiteProPlugin\MmdSyliusSeoSuiteProPlugin::class => ['all' => true],

Step 2: Import the routes

Create the file config/routes/mmd_sylius_seo_suite_pro.yaml with the two imports:

mmd_sylius_seo_suite_pro_admin:
    resource: "@MmdSyliusSeoSuiteProPlugin/config/routes/admin.yaml"

mmd_sylius_seo_suite_pro_shop:
    resource: "@MmdSyliusSeoSuiteProPlugin/config/routes/shop.yaml"

Import the shop routes at the top level, not under the /{_locale} prefix of the Sylius shop routes. Crawlers request /robots.txt at the root of the host. The same applies to the route of the OG images under /seo/og/....

The admin routes live under the path given by the %sylius_admin.path_name% parameter (default admin).

If the admin routes are missing, the menu entry in the admin area is silently left out. That is not a menu bug, it is the hint that the import is missing.

Step 3: Run the setup

The setup creates the plugin's tables:

bin/console mmd:seo-suite-pro:setup

The command does the following:

Nine tables are created, all with the prefix mmd_sylius_seo_suite_pro_: channel settings, SEO templates, schema, hreflang and OG image settings, redirects, the 404 log and two audit tables. There are no foreign keys to Sylius core tables. The details are on the Technical Details page.

You can also run doctrine:migrations:migrate yourself instead. The setup command is the gentler option because it touches nothing else.

Step 4: Assets and cache

The plugin ships no frontend assets of its own, so no assets:install is needed for it. Clear the cache after installing:

bin/console cache:clear

Step 5: Opt in the per-product and per-category fields (optional)

Meta title, canonical path and the per-page robots settings are columns in the translation tables of products and categories. A plugin cannot swap the Doctrine models of your shop by itself, so you opt in to these fields deliberately. It is the same procedure Sylius describes for adding any extra field to a core model.

Without this step everything else keeps working: titles fall back to the name (or an SEO template), pages are index, follow, and the admin area simply does not show the per-product and per-category fields.

1. Extend the models and apply the trait. Core products and categories create their translation with a hard-coded new, so Product and Taxon need a subclass too:

// src/Entity/Product/ProductTranslation.php
namespace App\Entity\Product;

use Doctrine\ORM\Mapping as ORM;
use Mmd\SyliusSeoSuiteProPlugin\Model\SeoAwareTranslationInterface;
use Mmd\SyliusSeoSuiteProPlugin\Model\SeoAwareTranslationTrait;

#[ORM\Entity]
#[ORM\Table(name: 'sylius_product_translation')]
class ProductTranslation extends \Sylius\Component\Core\Model\ProductTranslation implements SeoAwareTranslationInterface
{
    use SeoAwareTranslationTrait;
}
// src/Entity/Product/Product.php
namespace App\Entity\Product;

use Doctrine\ORM\Mapping as ORM;
use Sylius\Component\Product\Model\ProductTranslationInterface;

#[ORM\Entity]
#[ORM\Table(name: 'sylius_product')]
class Product extends \Sylius\Component\Core\Model\Product
{
    protected function createTranslation(): ProductTranslationInterface
    {
        return new ProductTranslation();
    }
}

Do the same for categories: App\Entity\Taxon\Taxon extends Sylius\Component\Core\Model\Taxon (table sylius_taxon), App\Entity\Taxon\TaxonTranslation extends Sylius\Component\Taxonomy\Model\TaxonTranslation (table sylius_taxon_translation). Interface and trait both come from the namespace Mmd\SyliusSeoSuiteProPlugin\Model.

2. Register the classes as resource models:

# config/packages/_sylius.yaml
sylius_product:
    resources:
        product:
            classes:
                model: App\Entity\Product\Product
            translation:
                classes:
                    model: App\Entity\Product\ProductTranslation

sylius_taxonomy:
    resources:
        taxon:
            classes:
                model: App\Entity\Taxon\Taxon
            translation:
                classes:
                    model: App\Entity\Taxon\TaxonTranslation

3. Generate and run the migration. The columns belong to your tables, so the migration belongs to your application, not to the plugin:

bin/console doctrine:migrations:diff
bin/console doctrine:migrations:migrate

The migration adds four columns to each of the two translation tables. The result corresponds to this SQL (for sylius_product_translation and sylius_taxon_translation):

ALTER TABLE sylius_product_translation
    ADD mmd_seo_suite_pro_meta_title VARCHAR(255) DEFAULT NULL,
    ADD mmd_seo_suite_pro_canonical_path_override VARCHAR(255) DEFAULT NULL,
    ADD mmd_seo_suite_pro_robots_index TINYINT(1) DEFAULT 1 NOT NULL,
    ADD mmd_seo_suite_pro_robots_follow TINYINT(1) DEFAULT 1 NOT NULL;

The defaults are index, follow, so the migration does not change any existing page.

The canonical path must be a path on your shop (one leading slash, no full URL, no //host). The plugin prepends the scheme and host of the current page.

Optional: meta description for categories. Sylius core already has a meta description on products, so they do not get a second field. Categories have none. To add one, additionally implement MetaDescriptionAwareTranslationInterface with MetaDescriptionAwareTranslationTrait on your TaxonTranslation, and only there, not on the product translation:

use Mmd\SyliusSeoSuiteProPlugin\Model\MetaDescriptionAwareTranslationInterface;
use Mmd\SyliusSeoSuiteProPlugin\Model\MetaDescriptionAwareTranslationTrait;
use Mmd\SyliusSeoSuiteProPlugin\Model\SeoAwareTranslationInterface;
use Mmd\SyliusSeoSuiteProPlugin\Model\SeoAwareTranslationTrait;
use Sylius\Component\Taxonomy\Model\TaxonTranslation as BaseTaxonTranslation;

class TaxonTranslation extends BaseTaxonTranslation implements SeoAwareTranslationInterface, MetaDescriptionAwareTranslationInterface
{
    use SeoAwareTranslationTrait;
    use MetaDescriptionAwareTranslationTrait;
}

Your migration then needs one more column on sylius_taxon_translation:

ALTER TABLE sylius_taxon_translation ADD mmd_seo_suite_pro_meta_description VARCHAR(512) DEFAULT NULL;

The field appears in the admin as a single-line text field on the category form (at most 512 characters). Without the field, category pages get no meta description unless an SEO template applies.

Update

  1. Update the plugin:

    composer update mmd/sylius-seo-suite-pro-plugin
    
  2. Run the setup again, because a Composer update does not run migrations:

    bin/console mmd:seo-suite-pro:setup
    
  3. Clear the cache:

    bin/console cache:clear
    

Until the setup has run, the shop keeps working. If a table is missing, the storefront behaves as if the respective feature did not exist (for example no templates, a plain 404 instead of a redirect) and a warning is logged. Only the matching admin screens answer with an error.

Scheduled tasks (cron jobs)

Four commands are meant for regular operation. The setup command is not one of them, it only runs on install and update.

Command Recommended interval Description
mmd:seo-suite-pro:audit:run Nightly Creates an audit snapshot. Optionally --channel/-c for a single channel. Fails if a run is already active, the tables are missing or the audit.max_subjects limit was exceeded.
mmd:seo-suite-pro:og-image:generate Daily and after imports Pre-renders OG images. Options: --channel/-c, --type/-t (product, taxon or the type of your own provider), --subject/-s (only together with --type), --force/-f.
mmd:seo-suite-pro:og-image:prune Weekly Deletes stale and orphaned image files. Options: --days/-d (0 ignores the age), --orphans/--no-orphans (default: on), --dry-run.
mmd:seo-suite-pro:redirects:prune-log Weekly Deletes old rows of the 404 log. Option --days/-d, default 90.

An example for the shop user's crontab:

# SEO Suite Pro
15 2 * * *  cd /var/www/shop && php bin/console mmd:seo-suite-pro:audit:run --env=prod --no-interaction
45 2 * * *  cd /var/www/shop && php bin/console mmd:seo-suite-pro:og-image:generate --env=prod --no-interaction
30 3 * * 0  cd /var/www/shop && php bin/console mmd:seo-suite-pro:og-image:prune --env=prod --no-interaction
40 3 * * 0  cd /var/www/shop && php bin/console mmd:seo-suite-pro:redirects:prune-log --days=90 --env=prod --no-interaction

Two more commands (redirects:export and redirects:import) are meant for manual use, see Redirects. The options of the OG image commands are explained on the OG Images page, those of the audit on the SEO Audit page.

Uninstall

Proceed in this order, while the bundle is still registered:

  1. Remove your own code that uses the plugin: calls to the Twig functions mmd_seo_suite_pro_seo() and mmd_seo_suite_pro_json_ld(), your own hooks and templates, and your own classes that implement the plugin's interfaces. If you opted in the per-product and per-category fields, also remove the interface and trait from the translation classes and drop the mmd_seo_suite_pro_* columns with a migration of your own.

  2. Roll back the plugin's migrations with the bundle still registered, one version per call, newest first:

    bin/console doctrine:migrations:execute --down 'Mmd\SyliusSeoSuiteProPlugin\Migrations\Version20261005100000'
    bin/console doctrine:migrations:execute --down 'Mmd\SyliusSeoSuiteProPlugin\Migrations\Version20261004160000'
    bin/console doctrine:migrations:execute --down 'Mmd\SyliusSeoSuiteProPlugin\Migrations\Version20261004140000'
    bin/console doctrine:migrations:execute --down 'Mmd\SyliusSeoSuiteProPlugin\Migrations\Version20261004120000'
    bin/console doctrine:migrations:execute --down 'Mmd\SyliusSeoSuiteProPlugin\Migrations\Version20261004100000'
    bin/console doctrine:migrations:execute --down 'Mmd\SyliusSeoSuiteProPlugin\Migrations\Version20261003140000'
    bin/console doctrine:migrations:execute --down 'Mmd\SyliusSeoSuiteProPlugin\Migrations\Version20261003120000'
    bin/console doctrine:migrations:execute --down 'Mmd\SyliusSeoSuiteProPlugin\Migrations\Version20261003100000'
    
  3. Remove the file config/routes/mmd_sylius_seo_suite_pro.yaml and the entry in config/bundles.php.

  4. Remove the package:

    composer remove mmd/sylius-seo-suite-pro-plugin
    

Rolling back the migrations deletes all data of the plugin: channel settings, SEO templates, redirects and the 404 log. If you want to keep your redirects, export them first with mmd:seo-suite-pro:redirects:export.