Markus Michalski FAQ

Product Snippets: Technical Details

Product Snippets for Shopware - replacement flow, caching, data model and plugin structure, plus the verified differences between the plugin lines for Shopware 6.7 and for 6.5/6.6

Deutsche Version

Back to overview

Product Snippets: Technical Details

Live Demo: Try this and other plugins live β€” no installation, no risk: demo.markus-michalski.net

Replacement flow

graph TD
    A["Twig filter mmd_snippets"] --> B["SnippetReplacer"]
    B --> C["SnippetParser: regex finds placeholders"]
    C --> D["SnippetRegistry: one lookup per identifier"]
    D --> E{"In cache?"}
    E -->|"Yes"| G["Content from cache"]
    E -->|"No"| F["Repository search: identifier and active"]
    F --> G
    G --> H["HtmlSanitizer cleans the content"]
    H --> I["Placeholder is replaced"]
Step Class Behavior
Filter Mmd\ProductSnippets\Twig\SnippetExtension Filter mmd_snippets and function mmd_snippet. Takes the context from the current request. Without a request the text is returned unchanged.
Replace Mmd\ProductSnippets\Core\Content\Snippet\SnippetReplacer Collects the identifiers, loads the snippets, replaces via regex and sanitizes each content with the HtmlSanitizer. Placeholders without a hit (unknown, inactive or without content in the current language) stay in place.
Parse Mmd\ProductSnippets\Core\Content\Snippet\SnippetParser Regex {{ snippet:<identifier> }} or {{ textbaustein:<identifier> }}, identifier made of a-z, A-Z, 0-9, - and _, case-insensitive.
Load Mmd\ProductSnippets\Core\Content\Snippet\SnippetRegistry Cache layer in front of the mmd_product_snippet repository.

Caching

Invalidation

A subscriber (Mmd\ProductSnippets\Subscriber\CacheInvalidationSubscriber) listens to the entity events mmd_product_snippet.written and mmd_product_snippet.deleted:

In the last two cases the change appears after the 3600 seconds have expired at the latest, or immediately after bin/console cache:clear. The plugin also does not invalidate the HTTP cache of product pages.

Data model

Table Contents
mmd_product_snippet id, identifier (VARCHAR 255, UNIQUE, collation utf8mb4_unicode_ci), active (default 1), timestamps
mmd_product_snippet_translation mmd_product_snippet_id, language_id, name, content (LONGTEXT), timestamps. Deleting the snippet cascades to its translations.

The entity is named mmd_product_snippet (fields identifier, active, name, content). All fields are exposed to the Admin API, so snippets can also be read and written through it. There is no identifier validation there either.

Plugin structure

src/
β”œβ”€β”€ MmdProductSnippets.php          # Plugin class, drops the tables on uninstall
β”œβ”€β”€ Content/Snippet/                # Entity definitions (snippet and translation)
β”œβ”€β”€ Core/Content/Snippet/           # Parser, replacer, registry
β”œβ”€β”€ Migration/                      # Creates the two tables
β”œβ”€β”€ Subscriber/                     # CacheInvalidationSubscriber
β”œβ”€β”€ Twig/                           # SnippetExtension (filter, function)
└── Resources/
    β”œβ”€β”€ app/administration/         # Admin module (list and detail page)
    β”œβ”€β”€ config/services.xml
    └── views/storefront/           # Three template overrides, two are effective under Shopware 6.7

Of the three template overrides, storefront/page/product-detail/description.html.twig is inactive under Shopware 6.7 because the core no longer provides this template. Details are on the Storefront Integration page.

Differences of the plugin line for Shopware 6.5 and 6.6

The line mmd/sw66-product-snippets (Shopware ~6.5.0 || ~6.6.0) has the same feature set and essentially the same source code. Comparing both lines, mainly these points differ:

Area Line 6.7 Line 6.5 / 6.6
Composer package and Shopware requirement mmd/sw67-product-snippets, ~6.7.0 mmd/sw66-product-snippets, ~6.5.0 \|\| ~6.6.0
Reading the content (SnippetRegistry) Direct access to the entity's content field (current language only) getTranslation('content') (reads the translated array, which includes the language fallback chain)
Admin pages (list and detail) Page title via head(), mixins via Shopware.Mixin.getByName() Page title via metaInfo(), mixins from the destructured Mixin
Shipped admin bundle Vite build under Resources/public/administration/assets Files under Resources/public/administration/js and .../css
Entity-layer classes final, properties identifier and mmdProductSnippetId with a typed default value '' not final, properties without a default value
Comment in the template box-standard.html.twig Note about \|raw without this note (comment only, no behavior)

The difference in reading the content affects behavior: if the content is missing in the current language, the 6.5/6.6 line may fall back to the default language, while in the 6.7 line the placeholder stays unreplaced. That getTranslation() takes the fallback chain into account is Shopware core behavior and cannot be proven from the plugin's source code.

Service definitions (services.xml), migration, tables, placeholder syntax, Twig filter and function, the template files and the admin texts match in both lines.