Live Demo: Try this and other plugins live β no installation, no risk: demo.markus-michalski.net
| 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. |
cache.object pool is used. The key contains identifier and language ID, so every language has its own entry.A subscriber (Mmd\ProductSnippets\Subscriber\CacheInvalidationSubscriber) listens to the entity events mmd_product_snippet.written and mmd_product_snippet.deleted:
active field, so there is no invalidation either. A deactivated snippet therefore stays visible, and a newly activated one stays in the cache as "not found".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.
| 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.
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.
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.