Magento 2 Store View Konfiguration: Best Practices für Scopes
AI generated
M2
di.xml
Magento 2 · Multi Store · Konfiguration
Magento 2 Store View Konfiguration
Best Practices für saubere Scope-Hierarchien

Eine falsch gesetzte Magento 2 Store View Konfiguration bleibt oft wochenlang unentdeckt, bis ein Kunde auf der falschen Domain die falsche Preisanzeige sieht. Die Scope-Hierarchie aus Default, Website und Store View entscheidet, welcher Wert wirklich greift, und wer diese Reihenfolge nicht verinnerlicht, produziert Konfigurationsfehler, die sich erst im Live-Betrieb zeigen.

18 Min. Lesezeit Scope-Hierarchie · core_config_data · CLI Magento 2.4.x

1. Warum Store View Konfiguration ein eigenes Thema ist

Wer Magento 2 nur mit einer einzigen Website und einem einzigen Store View betreibt, bekommt von der Komplexität der Magento 2 Store View Konfiguration kaum etwas mit. Sobald aber ein zweiter Markt, eine zweite Sprache oder eine zweite Marke hinzukommt, wird aus der einfachen Einstellungsseite im Backend ein mehrdimensionales System mit drei übereinanderliegenden Ebenen. Jede dieser Ebenen kann denselben Konfigurationspfad mit einem unterschiedlichen Wert belegen, und Magento entscheidet nach einer festen Regel, welcher Wert am Ende tatsächlich ausgeliefert wird.

Das eigentliche Risiko liegt nicht in der Technik selbst, sondern darin, dass eine fehlerhafte Store View Konfiguration selten sofort auffällt. Ein falsch gesetzter Wert auf Website-Ebene überschreibt möglicherweise eine bewusst gesetzte Store-View-Einstellung, ohne dass im Admin-Grid ein Warnhinweis erscheint. Erst wenn ein Kunde in einem bestimmten Store die falsche Versandoption sieht oder eine E-Mail mit dem falschen Absendernamen erhält, wird die Ursache sichtbar. Die folgenden Abschnitte zeigen, wie die Scope-Hierarchie tatsächlich funktioniert und mit welchen Praktiken sich solche Fehler von Anfang an vermeiden lassen.

2. Die Scope-Hierarchie: Default, Website, Store, Store View

Magento 2 kennt vier Konfigurationsebenen, auch wenn im Admin-Backend meist nur von drei sichtbaren Scopes die Rede ist. Ganz oben steht default, die globale Fallback-Ebene, die für alle Websites gilt, solange keine spezifischere Einstellung existiert. Darunter folgt die website-Ebene, die mehrere Store Groups zu einer wirtschaftlichen Einheit bündelt, etwa weil sie dieselbe Zahlungsabwicklung oder denselben Produktkatalog teilen. Innerhalb einer Website liegt die store-Ebene, in Magento auch Store Group genannt, die den Produktkatalog und die Kategoriebaumstruktur definiert. Ganz unten, und für die Store View Konfiguration am wichtigsten, liegt die store view-Ebene: die tatsächlich vom Kunden im Frontend erlebte Sprach- und Darstellungsvariante.

Die Regel, nach der Magento einen Wert auflöst, ist einfach, wird aber trotzdem oft falsch verstanden: Magento sucht zuerst auf der spezifischsten Ebene nach einem Eintrag, dann bei der Website und zuletzt bei Default. Existiert für einen Store View kein eigener Eintrag in core_config_data, fällt Magento automatisch auf den Website-Wert zurück, existiert auch dieser nicht, greift der Default-Wert. Diese Fallback-Kette bedeutet in der Praxis: Ein einmal auf Store-View-Ebene gesetzter Wert bleibt bestehen, auch wenn später der Default-Wert geändert wird, was bei Migrationen und Rollouts neuer Features regelmäßig übersehen wird.


<?php

declare(strict_types=1);

namespace Mironsoft\StoreConfig\ViewModel;

use Magento\Framework\View\Element\Block\ArgumentInterface;
use Magento\Store\Model\ScopeInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;

/**
 * ViewModel resolving a config value across the Magento scope hierarchy.
 */
final class ScopeResolver implements ArgumentInterface
{
    /**
     * @param ScopeConfigInterface $scopeConfig Magento scope config reader
     */
    public function __construct(
        private readonly ScopeConfigInterface $scopeConfig
    ) {
    }

    /**
     * Resolve a config path for the current store view, falling back
     * to website and default scope automatically.
     *
     * @param string $path Config path, e.g. "general/store_information/name"
     * @param int|null $storeId Store view id, null uses current store
     * @return string|null Resolved value or null if not configured anywhere
     */
    public function resolve(string $path, ?int $storeId = null): ?string
    {
        return $this->scopeConfig->getValue(
            $path,
            ScopeInterface::SCOPE_STORE,
            $storeId
        );
    }
}

3. core_config_data verstehen: Pfad, Scope, Wert

Jeder Konfigurationswert landet technisch in genau einer Tabelle: core_config_data. Die Struktur ist bewusst simpel gehalten: eine Spalte path für den Konfigurationspfad wie general/locale/code, eine Spalte scope mit den Werten default, websites oder stores, eine Spalte scope_id mit der numerischen ID der jeweiligen Website oder des Store Views, und schließlich value mit dem eigentlichen Inhalt. Wer diese Tabelle direkt per SQL abfragt, sieht sofort, auf welcher Ebene ein Wert tatsächlich gesetzt wurde, statt sich im Backend durch mehrere Tabs zu klicken.

Ein häufiger Fehler bei der Store View Konfiguration entsteht, wenn Entwickler direkt per SQL-Skript Zeilen in core_config_data einfügen, ohne den Konfigurations-Cache danach zu invalidieren. Magento cached Konfigurationswerte aggressiv im config-Cache-Bereich, und ein per SQL eingefügter Wert wird ohne bin/magento cache:flush config oft erst nach dem nächsten Cron-Lauf sichtbar. Für produktive Systeme ist daher der CLI-Befehl config:set gegenüber direkten SQL-Eingriffen immer vorzuziehen, da er die Cache-Invalidierung automatisch anstößt.


-- Inspect which scope actually holds a value for a given path
SELECT config_id, scope, scope_id, path, value
FROM core_config_data
WHERE path = 'general/locale/code'
ORDER BY
  CASE scope
    WHEN 'default'  THEN 0
    WHEN 'websites' THEN 1
    WHEN 'stores'   THEN 2
  END;

-- Find all store-view-level overrides for a specific website
SELECT ccd.scope_id, ccd.path, ccd.value, s.name AS store_view_name
FROM core_config_data ccd
INNER JOIN store s ON s.store_id = ccd.scope_id
WHERE ccd.scope = 'stores'
  AND ccd.path LIKE 'general/store_information/%';

4. Eigene Konfigurationswerte mit korrektem Scope anlegen

Wer ein eigenes Modul entwickelt und dabei Einstellungen im Backend anbietet, muss in system.xml pro Feld explizit angeben, auf welcher Ebene ein Wert überschreibbar sein darf. Das Attribut showInDefault, showInWebsite und showInStore steuert unabhängig voneinander, ob ein Feld auf der jeweiligen Ebene sichtbar und editierbar ist. Eine sorgfältige Store View Konfiguration bedeutet hier, bewusst zu entscheiden: Soll ein Wert wirklich pro Store View unterschiedlich sein können, etwa eine Absenderadresse für Transaktions-E-Mails, oder soll er global gültig bleiben, etwa ein API-Schlüssel für einen Zahlungsanbieter, der website-weit identisch ist.

Ein zu großzügig gewährter Store-View-Scope führt in der Praxis dazu, dass Redakteure versehentlich unterschiedliche Werte pro Store View pflegen, wo eigentlich ein einheitlicher Wert gewünscht war. Umgekehrt verhindert ein zu restriktiver Scope, dass internationale Teams ihre jeweiligen Store Views unabhängig konfigurieren können. Die Faustregel: Werte, die inhaltlich mit Sprache, Währung oder rechtlichen Anforderungen des jeweiligen Marktes zusammenhängen, gehören auf Store-View-Ebene, während technische Integrationswerte meist auf Website- oder Default-Ebene bleiben sollten.


<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <section id="mironsoft_storeconfig" translate="label" sortOrder="200"
                 showInDefault="1" showInWebsite="1" showInStore="1">
            <label>Store Config Extensions</label>
            <tab>general</tab>
            <resource>Mironsoft_StoreConfig::config</resource>
            <group id="general" translate="label" sortOrder="10"
                   showInDefault="1" showInWebsite="1" showInStore="1">
                <label>General Settings</label>
                <!-- Store view scope: legitimately different per market/language -->
                <field id="support_email" translate="label" type="text"
                       sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Support Email per Store View</label>
                </field>
                <!-- Website scope only: shared payment gateway credential -->
                <field id="gateway_api_key" translate="label" type="obscure"
                       sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Gateway API Key</label>
                    <backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model>
                </field>
            </group>
        </section>
    </system>
</config>

5. CLI-Workflows: config:set, config:show, config:sensitive

Der CLI-Befehl bin/magento config:set nimmt optional die Parameter --scope und --scope-code entgegen und erlaubt damit gezielte Änderungen pro Website oder Store View, ohne das Backend zu öffnen. Für Deployment-Pipelines ist das entscheidend, weil sich damit die gesamte Store View Konfiguration reproduzierbar in Skripten abbilden lässt, statt sich auf manuelle Klicks im Admin-Panel zu verlassen. Der ergänzende Befehl config:show gibt den effektiv aufgelösten Wert für einen bestimmten Scope zurück und ist damit das wichtigste Diagnose-Werkzeug, wenn ein Wert im Frontend nicht wie erwartet ankommt.

Für sensible Werte wie API-Schlüssel oder SMTP-Passwörter existiert zusätzlich config:set --lock-env, das den Wert direkt in env.php statt in core_config_data ablegt und damit vor versehentlicher Änderung über das Backend schützt. Diese Kombination aus datenbankbasierter Store View Konfiguration für inhaltliche Werte und dateibasierter Konfiguration für sicherheitsrelevante Werte ist der empfohlene Weg für produktive Multi-Store-Systeme.


#!/usr/bin/env bash
set -euo pipefail

# Set a value only for the German store view (assume store code "de")
bin/magento config:set --scope=stores --scope-code=de \
  general/locale/code de_DE

# Set a value for the entire website "main"
bin/magento config:set --scope=websites --scope-code=main \
  carriers/flatrate/active 1

# Inspect the effectively resolved value for one store view
bin/magento config:show general/locale/code --scope=stores --scope-code=at

# Lock a sensitive value into env.php instead of core_config_data
bin/magento config:set --lock-env \
  payment/mironsoft_gateway/api_key "sk_live_xxx"

# Always flush config cache after direct database changes
bin/magento cache:flush config

6. env.php versus Datenbank-Konfiguration

Ein häufiges Missverständnis bei der Store View Konfiguration betrifft die Grenze zwischen Werten in app/etc/env.php und Werten in core_config_data. Grundsätzlich gilt: env.php ist für umgebungsspezifische, sicherheitskritische oder deployment-relevante Werte gedacht, etwa Datenbankzugangsdaten, Cache-Backend-Konfiguration oder Verschlüsselungsschlüssel. Diese Werte sind pro Umgebung (Development, Staging, Production) unterschiedlich, aber innerhalb einer Umgebung für alle Stores identisch, und genau deshalb gehören sie nicht in die Store-View-Ebene der Datenbank.

Werte in core_config_data hingegen sind für inhaltliche, redaktionell pflegbare Einstellungen gedacht, die sich zwischen Stores unterscheiden dürfen und von Fachanwendern ohne Deployment geändert werden sollen. Wer versehentlich store-spezifische Werte in env.php ablegt, verliert die Möglichkeit, diese im Backend granular pro Store View zu pflegen, und muss bei jeder Änderung einen vollständigen Deployment-Zyklus durchlaufen. Die klare Trennung dieser beiden Konfigurationsebenen ist eine der wichtigsten architektonischen Entscheidungen für ein wartbares Multi-Store-Setup.

7. Cache-Invalidierung bei Scope-Änderungen

Änderungen an der Store View Konfiguration werden nicht immer sofort im Frontend sichtbar, weil Magento mehrere Cache-Ebenen zwischen der Datenbank und der ausgelieferten Seite betreibt. Der Konfigurations-Cache selbst wird bei Änderungen über das Backend automatisch invalidiert, bei direkten Datenbankänderungen oder CLI-Befehlen im Batch-Modus jedoch nicht immer zuverlässig. Zusätzlich cached der Full Page Cache ganze HTML-Fragmente, die zum Zeitpunkt der Generierung noch den alten Konfigurationswert enthielten, etwa eine im Footer angezeigte Telefonnummer.

Für produktive Deployments empfiehlt sich daher ein fester Ablauf: zuerst config:set oder das Backend nutzen, danach cache:flush config full_page block_html layout ausführen, und bei Varnish-Einsatz zusätzlich einen expliziten Varnish-Purge für die betroffene Store View auslösen. Wer diesen Ablauf automatisiert in Deployment-Skripte integriert, vermeidet die häufige Situation, dass ein Support-Ticket über eine scheinbar falsche Einstellung eigentlich nur ein Cache-Problem ist.

8. Typische Fallstricke im Live-Betrieb

Der häufigste Fallstrick bei der Store View Konfiguration ist die Annahme, ein auf Default-Ebene geänderter Wert würde automatisch überall greifen. Existiert bereits ein spezifischerer Wert auf Website- oder Store-View-Ebene, bleibt dieser bestehen und überschreibt die Default-Änderung stillschweigend. Das führt regelmäßig zu Situationen, in denen ein globales Update, etwa eine neue rechtliche Pflichtangabe, in einem einzelnen Store View schlicht nicht ankommt, weil dort vor Jahren ein individueller Wert gesetzt wurde, an den sich niemand mehr erinnert.

Ein zweiter Fallstrick betrifft Konfigurationswerte, die programmatisch über ScopeConfigInterface::getValue() ohne expliziten Scope-Parameter abgefragt werden. Fehlt der zweite und dritte Parameter, greift Magento auf den aktuellen Store-Kontext zurück, der im Kontext eines Cron-Jobs oder eines CLI-Befehls oft der Default-Store ist und nicht der Store, für den der Code eigentlich ausgeführt werden soll. Wer eigene Module schreibt, sollte den Store-Scope daher immer explizit übergeben, statt sich auf den impliziten Kontext zu verlassen.


<?php

declare(strict_types=1);

namespace Mironsoft\StoreConfig\Cron;

use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\ScopeInterface;
use Magento\Store\Api\StoreRepositoryInterface;

/**
 * Cron job iterating explicitly over every store view instead of relying
 * on the implicit default-store context.
 */
final class SyncSupportEmails
{
    /**
     * @param ScopeConfigInterface $scopeConfig Reads config per explicit scope
     * @param StoreRepositoryInterface $storeRepository Lists all store views
     */
    public function __construct(
        private readonly ScopeConfigInterface $scopeConfig,
        private readonly StoreRepositoryInterface $storeRepository
    ) {
    }

    /**
     * Read the support email for every store view explicitly.
     *
     * @return void
     */
    public function execute(): void
    {
        foreach ($this->storeRepository->getList() as $store) {
            // WRONG: $this->scopeConfig->getValue('general/store_information/name')
            // would silently resolve against the default store in a cron context.

            // RIGHT: always pass the store scope and id explicitly.
            $email = $this->scopeConfig->getValue(
                'trans_email/ident_support/email',
                ScopeInterface::SCOPE_STORE,
                $store->getId()
            );

            if ($email !== null) {
                // ... sync $email for this specific store view
            }
        }
    }
}

9. Scope-Strategien im Vergleich

Die folgende Übersicht zeigt, welche Konfigurationsebene für welche Art von Einstellung in der Store View Konfiguration typischerweise sinnvoll ist, und welche Konsequenzen die jeweilige Wahl im Betrieb hat.

Wertetyp Falscher Scope Empfohlener Scope Begründung
API-Schlüssel Zahlungsanbieter Store View env.php (lock-env) Sicherheitskritisch, pro Umgebung, nicht pro Store
Locale-Code Default global Store View Sprache muss pro Markt unterschiedlich sein
Katalogpreisumfang Store View Website Preise gelten meist website-weit einheitlich
Support-E-Mail-Adresse Default nur Store View Marktabhängige Kontaktinformation
Cache-Backend-Verbindung core_config_data env.php Infrastrukturwert, nicht redaktionell pflegbar

Diese Zuordnung ist kein starres Regelwerk, sondern eine Orientierung, die sich an zwei Fragen ausrichtet: Muss der Wert pro Store View unterschiedlich sein, und darf der Wert von Fachanwendern ohne Deployment geändert werden. Wer beide Fragen für jeden neuen Konfigurationswert konsequent beantwortet, vermeidet den Großteil der Scope-bedingten Fehler, die in gewachsenen Multi-Store-Installationen typischerweise auftreten.

Mironsoft

Magento 2 Multi Store und Internationalisierung

Store View Konfiguration, die auch bei Rollouts stabil bleibt?

Wir analysieren bestehende Magento 2 Multi-Store-Setups, bereinigen die Scope-Hierarchie und automatisieren die Konfiguration über CLI-Workflows, damit Deployments reproduzierbar und fehlerfrei bleiben.

Scope-Audit

Bestehende core_config_data auf widersprüchliche Scope-Überschreibungen prüfen

CLI-Automatisierung

Konfigurationswerte als reproduzierbare Deployment-Skripte abbilden

Modul-Beratung

system.xml-Scopes für eigene Module korrekt und zukunftssicher planen

10. Zusammenfassung

Eine saubere Magento 2 Store View Konfiguration beruht auf dem Verständnis der Fallback-Kette von Store View über Website bis Default, und auf der bewussten Entscheidung, welche Werte pro Ebene überhaupt sichtbar sein dürfen. Die Tabelle core_config_data macht diese Struktur transparent, CLI-Befehle wie config:set und config:show machen sie reproduzierbar und diagnostizierbar. Sicherheitskritische Werte gehören konsequent in env.php, redaktionelle und marktabhängige Werte in die Datenbank.

Der größte Hebel gegen Fehlkonfigurationen liegt in der Disziplin, Scope-Entscheidungen einmal bewusst zu treffen und danach über CLI-Skripte konsistent auszurollen, statt Werte manuell im Backend zu pflegen. Wer zusätzlich nach jeder Änderung die relevanten Caches gezielt leert, vermeidet die häufigste Fehlerquelle im Live-Betrieb: veraltete Werte, die technisch längst korrekt gesetzt sind, aber durch Caching noch nicht ausgeliefert werden.

Magento 2 Store View Konfiguration — Das Wichtigste auf einen Blick

Scope-Hierarchie

Store View überschreibt Website, Website überschreibt Default. Fallback greift nur, wenn kein spezifischerer Wert existiert.

core_config_data

Spalten scope, scope_id und path bestimmen, auf welcher Ebene ein Wert tatsächlich liegt. Direkt per SQL abfragbar.

CLI statt Backend

config:set --scope=stores/websites für reproduzierbare Deployments, config:show zur Diagnose des effektiven Werts.

env.php für Sicherheit

Sicherheitskritische, umgebungsspezifische Werte gehören mit --lock-env in env.php, nicht in die Datenbank.

11. FAQ: Magento 2 Store View Konfiguration

1Website, Store und Store View: was ist der Unterschied?
Website ist die wirtschaftliche Einheit mit eigener Domain und Basiswährung. Store definiert Katalog und Kategoriebaum. Store View ist die konkrete Sprach- und Darstellungsvariante im Frontend.
2Welche Ebene gewinnt bei mehreren gesetzten Werten?
Immer die spezifischste: Store View vor Website vor Default. Fehlt eine Ebene, fällt Magento automatisch auf die nächsthöhere zurück.
3Warum wirkt eine Default-Änderung nicht überall?
Weil bestehende spezifischere Werte auf Website- oder Store-View-Ebene bestehen bleiben und die Default-Änderung überschreiben.
4Wie finde ich die tatsächliche Scope-Ebene eines Werts?
Per SQL in core_config_data filtern oder bin/magento config:show mit --scope und --scope-code für den effektiven Wert nutzen.
5API-Schlüssel: core_config_data oder env.php?
In env.php mit config:set --lock-env, damit sie nicht versehentlich über das Backend änderbar sind und aus DB-Backups herausbleiben.
6Wie steuere ich Scopes in system.xml?
Mit showInDefault, showInWebsite und showInStore am field-Element, unabhängig voneinander steuerbar.
7Muss nach config:set immer der Cache geleert werden?
Meist automatisch, bei direkten SQL-Änderungen jedoch nicht. Dann ist bin/magento cache:flush config zwingend.
8Warum liefert getValue() im Cron einen falschen Wert?
Ohne expliziten Scope nutzt Magento den aktuellen Store-Kontext, der im Cron oft der Default-Store ist. Scope immer explizit übergeben.
9Katalogpreisumfang: Website oder Store View?
Meist Website-Ebene, da Preise innerhalb einer Website in der Regel einheitlich sein sollen.
10Beeinflusst der Full Page Cache Scope-Änderungen?
Ja, gecachte HTML-Fragmente enthalten alte Werte. Nach Scope-Änderungen zusätzlich full_page und block_html leeren.