Wie erbt man korrekt von einem anderen Theme?

Ich habe das Theme “ExternesTheme” eingestellt. Nun möchte ich nur minimale Änderungen daran vornehmen (ein wenig JavaScript hinzufügen und ein paar View-Blöcke überschreiben) und habe dafür ein eigenes Theme “MeinTheme” erstellt.

Mein theme.js sieht so aus:

...
"style": [
    "@Storefront",
    "@ExternesTheme"
],
"script": [
    "@Storefront",
    "@ExternesTheme",
    "app/storefront/dist/storefront/js/mein-theme.js"
],
"asset": [
    "app/storefront/src/assets"
],
"views": [
    "@Storefront",
    "@ExternesTheme",
    "@MeinTheme",
    "@Plugins"
],
...

Das Problem ist, dass das Skript von ExternesTheme im Browser doppelt ausgeführt wird. Mit der Meldung “all.js:3 Uncaught Error: Plugin “ExternesThemeFoobarPlugin” is already registered.”. Wenn ich @ExternesTheme”, hingegen aus dem “script”-Array entferne, wird es gar nicht geladen.

Edit: Dasselbe gilt übrigens für CSS. Nur hindert das doppelte Laden davon die Seite natürlich nicht am Laden. 

Wie erbe ich korrekt von ExternesTheme, um meine Änderungen daran vorzunehmen?

du hast es immerhin geschafft, das irgendwas vererbt wird.
Ich schaffs nicht, dass mein Child-Theme irgendwas vom Parent-Theme weiß. Weder CSS noch TWIG-Template…

ich habe mir jetzt meine eigene Theme-Vererbung gebaut. War mir zu blöd, dass Shopware das nicht vernünftig hinkriegt. Wer Interesse hat: meldet euch

Ich arbeite da auch gerade daran. Bin sehr an deiner Lösung interessiert!

theme.json des Parent-Themes

"views": [
        "@Storefront",
        "@Plugins",
        "@ParentTheme"
      ],
      "style": [
        "app/storefront/src/scss/overrides.scss",
        "@Storefront",
        "@Plugins",
        "app/storefront/src/scss/base.scss"
      ],
      "script": [
        "@Storefront"
      ],
      "asset": [
        "app/storefront/src/assets"
      ],

und die theme.json des Child-Themes

"views": [
    "@Storefront",
    "@Plugins",
    "@ParentTheme",
    "@ChildTheme"
  ],
  "style": [
    "@ParentTheme",
    "@Plugins",
    "app/storefront/src/scss/base.scss"
  ],
  "script": [
    "@ParentTheme"
  ],

Beide Themes werden als Plugin installiert. Die Config wird komplett im Parent gemacht, im Child wird nichts eingestellt. Das Child-Theme wird dem Saleschannel als Theme zugewiesen und aktiviert.

Damit ich die Theme-Variablen aus dem Parent im Template zur Verfügung hab, musste ich die Twig-Funktion theme_config überschreiben. Im Standard hat Shopware hier nur Zugriff auf Daten des aktiven Themes (also das Child, was ja keine Config hat).

habe die Datei 1:1 aus dem Core in mein Parent-Theme kopiert und dann diese beiden Funktionen angepasst

Storefront\Framework\Twig\Extension\ConfigExtension.php

public function getFunctions(): array
    {
        return [
            new TwigFunction('theme_config', [$this, 'theme'], ['needs_context' => true])
        ];
    }

public function theme(array $context, string $key)
    {
        $valueFromActiveTheme = $this->config->theme($key, $this->getContext($context), $this->getThemeId($context));
        $valueFromBaseTheme = $this->config->theme($key, $this->getContext($context), ID_OF_PARENT_THEME);

        if ($valueFromActiveTheme != null && $valueFromActiveTheme != "")
            return $valueFromActiveTheme;
        else
            return $valueFromBaseTheme;
    }

zum Schluss musste ich noch die Variablen aus dem Parent-Theme als SCSS-Variablen im Child zur Verfügung stellen. Dazu gibts im Child-Theme einen Subscriber

class ThemeVariableSubscriber implements EventSubscriberInterface
{
    /**
     * @var SystemConfigService
     */
    private SystemConfigService $systemConfig;

    /**
     * @var EntityRepositoryInterface
     */
    private EntityRepositoryInterface $themeRepository;

    /**
     * ThemeVariableSubscriber constructor.
     * @param SystemConfigService $systemConfig
     * @param EntityRepositoryInterface $themeRepository
     */
    public function __construct(SystemConfigService $systemConfig, EntityRepositoryInterface $themeRepository)
    {
        $this->systemConfig = $systemConfig;
        $this->themeRepository = $themeRepository;
    }

    /**
     * @return string[]
     */
    public static function getSubscribedEvents(): array
    {
        return [
            ThemeCompilerEnrichScssVariablesEvent::class => 'onAddVariables'
        ];
    }

    /**
     * @param ThemeCompilerEnrichScssVariablesEvent $event
     */
    public function onAddVariables(ThemeCompilerEnrichScssVariablesEvent $event)
    {
        // add theme config variables from parent theme for correct inheritance

        $criteria = new Criteria();
        $criteria->addFilter(new EqualsFilter('technicalName', "ParentTheme"));

        $themeConfig = [];

        /** @var ThemeEntity $theme */
        foreach ($this->themeRepository->search($criteria, Context::createDefaultContext())->getElements() as $theme)
        {
            foreach ($theme->getBaseConfig()["fields"] as $configKey => $baseConfigEntry)
            {
                $themeConfig[$configKey] = $baseConfigEntry["value"];
            }

            foreach ($theme->getConfigValues() as $configKey => $configValue)
            {
                if ($configValue["value"] == null)
                    continue;

                $themeConfig[$configKey] = $configValue["value"];
            }
        }

        foreach($themeConfig as $key => $value)
        {
            if ($value == null)
                $event->addVariable($key, $value, true);
            else
                $event->addVariable($key, $value, false);
        }
    }
}