Skip to content

2021-09-22 - Refactor theme inheritance

2021-09-22 - Refactor theme inheritance

INFO

This document represents an architecture decision record (ADR) and has been mirrored from the ADR section in our Shopware 6 repository. You can find the original version here

Context

Currently the themes can only inherit config fields from the default Storefront theme. Also this inheritence is only a snapshot by activation time of the theme - The configs are copied to the new theme and changes to the default theme config will not appear in the new theme without a re-activation. The different possibilities to inherit different parts of a theme, like scripts, templates and config, can also cause problems on later updates.

Decision

To take this points into account we have decided to add a new inheritance key for the configFields in the theme.json which allow a theme to inherit its config from other themes in a given order:

json
"configInheritance": [
        "@Storefront",
        "@PreviousTheme",
        "@MyDevelopmentTheme"
    ],
Complete theme.json with part inheritances
json
{
    "name": "MyDevelopmentTheme",
    "author": "Shopware AG",
    "views": [
        "@Storefront",
        "@Plugins",
        "@MyDevelopmentTheme"
    ],
    "style": [
        "app/storefront/src/scss/overrides.scss",
        "@Storefront",
        "app/storefront/src/scss/base.scss"
    ],
    "script": [
        "@Storefront",
        "app/storefront/dist/storefront/js/my-development-theme.js"
    ],
    "asset": [
        "@Storefront",
        "app/storefront/src/assets"
    ],
    "configInheritance": [
        "@Storefront",
        "@PreviousTheme",
        "@MyDevelopmentTheme"
    ],
    "config": {
        "blocks": {
            "exampleBlock": {
                "label": {
                    "en-GB": "Example block",
                    "de-DE": "Beispiel Block"
                }
            }
        },
        "sections": {
            "exampleSection": {
                "label": {
                    "en-GB": "Example section",
                    "de-DE": "Beispiel Sektion"
                }
            }
        },
        "fields": {
            "my-single-test-select-field": {
                "editable": false
            },
            "my-single-select-field": {
                "label": {
                    "en-GB": "Select a font size",
                    "de-DE": "Wähle ein Schriftgröße"
                },
                "type": "text",
                "value": "24",
                "custom": {
                    "componentName": "sw-single-select",
                    "options": [
                        {
                            "value": "16",
                            "label": {
                                "en-GB": "16px",
                                "de-DE": "16px"
                            }
                        },
                        {
                            "value": "20",
                            "label": {
                                "en-GB": "20px",
                                "de-DE": "20px"
                            }
                        },
                        {
                            "value": "24",
                            "label": {
                                "en-GB": "24px",
                                "de-DE": "24px"
                            }
                        }
                    ]
                },
                "editable": true,
                "block": "exampleBlock",
                "section": "exampleSection"
            },
            "usps-positions": {
                "label":
                {
                    "en-GB": "Position",
                    "de-DE": "Position"
                },
                "scss": true,
                "type": "text",
                "value": [
                    "top",
                    "bottom"
                ],
                "custom": {
                    "componentName": "sw-multi-select",
                    "options": [
                        {
                            "value": "bottom",
                            "label":
                            {
                                "en-GB": "bottom",
                                "de-DE": "unten"
                            }
                        },
                        {
                            "value": "top",
                            "label":
                            {
                                "en-GB": "top",
                                "de-DE": "oben"
                            }
                        },
                        {
                            "value": "middle",
                            "label":
                            {
                                "en-GB": "middle",
                                "de-DE": "mittel"
                            }
                        }
                    ]
                },
                "editable": true,
                "tab": "usps",
                "block": "exampleBlock",
                "section": "exampleSection"
            }
        }
    }
}

Consequences

The Consequences for the two approaches are described below:

1. New config inheritance:

  • The inheritance can still cause incompatibility errors because of missing subsets of a dependend theme.
  • The current themes will work as always but one can also add an inheritance for the config fields.
  • The inhertiance will no longer be a snapshot, but a dynamic copy of the inherited themes (The changes of child themes will be considered by the new theme automaticaly)
  • The admin for the themes will get an inheritation mechanism which allows users to decide if a field will use its inherited or a new value (simmiliar to productvariant inherited fields)
  • Themes which are dependend on other themes than the default storefront theme, need to add the other themes into there composer.json as required to prevent incomplete setups.
json
 "require": {
        "swag/previous-theme": "~1.1"
    },
Example complete composer.json
json
{
    "name": "swag/my-development-theme",
    "description": "My Development Theme",
    "type": "shopware-platform-plugin",
    "version": "1.7",
    "license": "MIT",
    "autoload": {
        "psr-4": {
            "MyDevelopmentTheme\\": "src/"
        }
    },
    "require": {
        "swag/previous-theme": "~1.1"
    },
    "extra": {
        "shopware-plugin-class": "MyDevelopmentTheme\\MyDevelopmentTheme",
        "label": {
            "de-DE": "Theme MyDevelopmentTheme plugin",
            "en-GB": "Theme MyDevelopmentTheme plugin"
        }
    }
}