shopwareshopware-6shopware-coreplugin-entwicklungvuejavascriptopen-sourcedebugging

Shopware-6-Datumsfilter: Zwei Upstream-PRs am Core

| 15 Min. Lesezeit | Huzaifa Mustafa

Ein Kunde hat zwei Filter-Regression-Tickets zu einem Document-Overview-Plugin eröffnet, das ich gerade ausgeliefert hatte. Beide sahen auf den ersten Blick so aus, als wäre mein Code falsch.

Eine Woche später war die Arbeit an einem Punkt gelandet, den ich nicht erwartet hatte: zwei Pull Requests, die ich am Shopware-6-Core eingereicht hatte, beide für Milestone 6.7.10.0 getaggt. Einer hat einen positiven Review von einem Community-Contributor und wartet auf Maintainer-Review. Der andere liegt in der Triage-Queue und wartet auf seinen ersten Review. Beide Fixes landen direkt in der Core-Komponente sw-date-filter, von der jeder Shopware-6-Admin profitiert.

Das ist eine Geschichte über das Überschreiben von Admin-Komponenten, die Bugs, die man dabei erbt, und den dualen Ansatz, einen lokalen Fix auszuliefern und gleichzeitig die Ursache upstream zu beheben. Der Kunde bekam seinen Fix mit dem nächsten Plugin-Build. Alle anderen auf Shopware 6 bekommen ihn mit 6.7.10.0.

Das Plugin, das den Bug zutage förderte

Das fragliche Plugin ist ein Document-Overview-Modul, das ich für einen deutschen Shopware-Händler gebaut habe. Es fügt eine Admin-Route hinzu, die generierte Dokumente (Rechnungen, Lieferscheine, Gutschriften) über alle Bestellungen hinweg auflistet, mit rollenbasierten Leserechten und einem individuellen Spaltenlayout. Das Buchhaltungsteam des Händlers verwendet es täglich, um offene Rechnungen für das aktuelle Quartal, die Lieferungen dieses Monats und andere zeitlich begrenzte Reporting-Fenster abzugleichen.

Datumsfilterung ist für diesen Anwendungsfall kein Nice-to-have. Es ist der primäre Weg, um eine Liste von zehntausenden Dokumenten auf die Zeilen zu reduzieren, an denen das Team tatsächlich arbeiten muss. Allein der Timeframe “Last Quarter” wird hunderte Male im Monat ausgeführt.

Die Komponente, die diese Filterung übernimmt, ist sw-date-filter. Mein Plugin erweitert sie über einen Component-Override, um das berechtigungsbasierte Spaltenrendering hinzuzufügen, aber die Filterlogik selbst wird unverändert geerbt. Genau dieses Detail ist der Grund, warum es diese Geschichte gibt.

Was der Kunde tatsächlich gemeldet hat

Innerhalb derselben Woche kamen zwei Tickets herein.

Das erste: “Last Quarter zeigt das gesamte Vorjahr plus das aktuelle Jahr bisher an.” Ein Screenshot war beigefügt, der ein from-Datum vom 1. Oktober des Vorjahres und ein to-Datum vom 31. Dezember des aktuellen Jahres zeigte. Etwa fünfzehn Monate statt drei.

Das zweite, zwei Tage später: “Wenn ich nach ‘heute’ filtere, zeigt die Liste die Dokumente von gestern an und überspringt eines, das ich heute Morgen erstellt habe.” Dieses Ticket kam mit einem Profilscreenshot, der die Zeitzone des Benutzers auf eine Nicht-UTC-Zone gesetzt zeigte.

Erste Reaktion auf beide: lokal getestet, nicht reproduzierbar.

Das erste war schliesslich reproduzierbar, aber erst, nachdem ich die Systemuhr meiner Dev-Maschine auf ein Q1-Datum gestellt hatte. Bis zu diesem Moment war jeder Test, den ich auf “Last Quarter” ausgeführt hatte, aus April heraus erfolgt, einem Quartal, in dem der Bug unsichtbar ist. Diese Eigenschaft ist es wert, noch einmal gelesen zu werden. Der Bug war real, und mein Live-Testen war einfach ausserhalb der Monate erfolgt, in denen er auftritt.

Das zweite hat länger gedauert. Meine Dev-Umgebung, die Umgebung meines Testers und die Staging-Instanz waren alle auf UTC-Profilen. Das Buchhaltungsteam des Kunden nicht. Sobald ich meine Profil-Zeitzone auf eine US-Zone umgestellt und das Listing neu geladen hatte, trat das Off-by-one-day-Verhalten beim ersten Versuch auf.

Zwei Reproduzierbarkeits-Probleme mit derselben Form: Der Bug ist umgebungsabhängig, und die Umgebung, in der die meisten Entwickler testen, maskiert ihn zufällig.

Über den eigenen Override hinaus, hinein in sw-date-filter

Mein Override von sw-date-filter ist klein. Er fügt eine Berechtigungsprüfung hinzu, bevor der Filter überhaupt gerendert wird, und passt die Beschriftung des aktiven Filter-Chips in der Toolbar an. Die Kernmethoden, die Timeframe-Berechnung, die Emit-Logik, das Date-Input-Handling, nichts davon wird angefasst.

Das ist die Designintention von Admin-Component-Overrides. Man legt etwas oben drauf. Man erbt die computed properties und methods des Parents, sofern man sie nicht explizit ersetzt. Es ist das richtige Pattern für fast jede Erweiterung, die ich schreibe. Es ist auch der Grund, warum die Bugs jetzt in meinem Listing sassen.

Beim “Last Quarter”-Issue habe ich den Aufruf von der Dropdown-Auswahl durch onTimeframeSelect in getPreviousQuarterDates verfolgt und auf einer einzeiligen Diskrepanz in der Konstruktion des Enddatums angehalten. Beim Zeitzonen-Issue habe ich den Wertfluss vom Date-Input durch updateFilter verfolgt, ihn durch ein Paar setHours()-Aufrufe laufen sehen und beobachtet, wie die resultierenden ISO-Strings dem Criteria-Objekt als UTC-Grenzen angefügt wurden.

Keiner der beiden Pfade kreuzte Code, den ich geschrieben hatte. Beide Bugs lagen in der Parent-Komponente. Meine Optionen reduzierten sich auf zwei: den Parent innerhalb meines Overrides monkey-patchen und das einen Fix nennen, oder die Bugs zu ihren Wurzeln im Core verfolgen und Upstream-PRs einreichen.

Ich habe beides gemacht. Der lokale Patch ging zuerst an den Kunden; die PRs folgten.

PR #16380: Der Last-Quarter-Jahresbug, der sich neun Monate im Jahr versteckt

Der Timeframe “Last Quarter” wird von getPreviousQuarterDates berechnet, das den Anfang und das Ende des vorherigen Kalenderquartals relativ zu heute ableitet. Die Funktion sieht auf den ersten Blick korrekt aus. Sie konstruiert das Startdatum aus date.getFullYear(), dem aktuellen Quartalsindex und einem Monatsoffset. Sie konstruiert das Enddatum auf dieselbe Weise.

Genau dieser letzte Satz ist das Problem.

// Vorher — endDate verwendet das heutige Jahr, was in Q1 nach vorn springt
const endDate = new Date(date.getFullYear(), startDate.getMonth() + 3, 0, 23, 59, 59);

// Nachher — endDate bleibt am Startjahr des Quartals verankert
const endDate = new Date(startDate.getFullYear(), startDate.getMonth() + 3, 0, 23, 59, 59);

Der Fix ist ein Identifier. Von April bis Dezember liefern date.getFullYear() und startDate.getFullYear() denselben Wert, sodass das Enddatum korrekt im selben Jahr wie das Startdatum landet. Im Januar, Februar und März hat das vorherige Quartal im Vorjahr begonnen (Oktober bis Dezember), aber date.getFullYear() liefert das aktuelle Jahr. Das Enddatum wird dann im aktuellen Jahr konstruiert, drei Monate nach dem Startmonat des vorherigen Quartals, was es ans Ende des Dezembers des aktuellen Jahres setzt. Das Ergebnis ist ein Bereich von fünfzehn Monaten, der zwei Kalenderjahre umspannt.

Der Bug ist neun Monate im Jahr unsichtbar. Das ist keine Metapher. Es ist die wörtliche Eigenschaft des Bugs: vom 1. April bis zum 31. Dezember stimmt die Mathematik zufällig mit sich selbst überein.

Der Regressions-Test pinnt die Systemzeit auf ein Q1-Datum und prüft, dass die emittierten Grenzen im Vorjahr liegen:

describe('lastQuarter boundary when today is in Q1', () => {
    beforeEach(() => {
        jest.setSystemTime(new Date(1337, 1, 15));
    });

    it('should compute last quarter as Oct-Dec of the previous year', async () => {
        // ...
        wrapper.vm.onTimeframeSelect('lastQuarter');

        expect(wrapper.emitted()['filter-update']).toEqual([
            [
                'releaseDate',
                [{
                    field: 'releaseDate',
                    parameters: {
                        gte: '1336-10-01T00:00:00.000Z',
                        lte: '1336-12-31T23:59:59.000Z',
                    },
                    type: 'range',
                }],
                {
                    from: '1336-10-01T00:00:00.000Z',
                    timeframe: 'lastQuarter',
                    to: '1336-12-31T23:59:59.000Z',
                },
            ],
        ]);
    });
});

Die Systemzeit ist absichtlich auf den 15. Februar des Jahres 1337 gepinnt. Ohne den Pin würde der Test neun von zwölf Mal bestehen, je nachdem, in welchem Monat er läuft. Mit dem Pin ist die Assertion verlässlich, und der Test scheitert ohne den Fix laut.

Ich habe den PR am 22. April eröffnet; er wurde für Milestone 6.7.10.0 getaggt. Ein Community-Contributor hat ihn am nächsten Morgen mit einem positiven Kommentar geprüft. Maintainer-Review steht noch aus. PR #16380 auf GitHub.

PR #16439: Wenn Shopwares Datumsfilter die Benutzer-Zeitzone ignoriert

Die Charakterisierung des Zeitzonen-Bugs hat länger gedauert, weil tatsächlich zwei Defekte in derselben Codezeile lagen, und ich den zweiten erst beim Schreiben des Tests für den ersten bemerkt habe.

Hier der ursprüngliche Block:

if (this.dateValue.from) {
    const from = new Date(this.dateValue.from);
    from.setHours(0, 0, 0);
    this.dateValue.from = from.toISOString();
}

if (this.dateValue.to) {
    const to = new Date(this.dateValue.to);
    to.setHours(23, 59, 59);
    this.dateValue.to = to.toISOString();
}

this.$emit('filter-update', this.filter.name, params, this.dateValue);

Date.setHours(0, 0, 0) mutiert die lokalen Stunden-, Minuten- und Sekunden-Komponenten eines JavaScript-Date-Objekts. Das Date-Objekt wird dann via toISOString() zurück zu ISO serialisiert, was UTC ist. Das “lokal” in setHours ist die lokale Zeit der Runtime, was auf einer server-gerenderten Admin-Seite zur Zeit, in der sie über SSR-äquivalente Pfade den Browser erreicht, UTC bedeutet, und auf einer frisch geladenen Admin-Seite die lokale Zeitzone des Host-Browsers, die der Benutzer ändern kann, ohne seine Shopware-Profilzeitzone zu ändern.

So oder so hat die hier abgeleitete Tagesgrenze nichts mit der Profil-timeZone des Benutzers zu tun. Listen-Datumsspalten dagegen formatieren Anzeigewerte mit der Profilzeitzone. Ein Benutzer in America/Los_Angeles, der nach dem 22. Januar filtert, würde also 2021-01-22T00:00:00Z bis 2021-01-22T23:59:59Z (UTC) anfragen, während die Datumsspalte das Datum jeder Zeile in LA anzeigt. Zeilen aus 2021-01-21T17:00:00Z (die in LA als 21. Januar angezeigt werden) werden fälschlich eingeschlossen. Zeilen aus 2021-01-22T20:00:00Z (die in LA als 22. Januar angezeigt werden) werden herausgefiltert.

Der zweite Defekt: this.dateValue.from = from.toISOString() mutiert das reaktive dateValue der Komponente. Der Parent sw-range-filter deep-watcht value, sodass diese Mutation den Watcher erneut feuert und für jede einzelne Feldänderung ein doppeltes filter-update-Event produziert. Die ursprüngliche Test-Suite hat das sogar mit einem Kommentar bestätigt: “[1] is a duplicate emission from sw-date-filter mutating dateValue.from to ISO (triggers sw-range-filter watch again)”. Die Dopplung wurde als erwartetes Verhalten behandelt, in einer Assertion festgehalten und ausgeliefert.

Der Fix musste beide Defekte im selben Durchgang adressieren.

/**
 * mt-datepicker in date-only mode may emit an ISO instant whose wall-clock
 * time is not midnight (e.g. it carries over the current time on the
 * picked day). Snap to the start of the picked day in the given timezone
 * and derive the end of that same day so filter bounds cover the full
 * intended calendar day as the list's date formatter displays it.
 */
dayBoundsInTz(iso, tz) {
    const instant = new Date(iso);
    const parts = new Intl.DateTimeFormat('en-GB', {
        timeZone: tz,
        hour12: false,
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit',
    }).formatToParts(instant);

    const read = (type) => parseInt(parts.find((p) => p.type === type)?.value ?? '0', 10);

    let hour = read('hour');
    if (hour === 24) {
        hour = 0;
    }
    const minute = read('minute');
    const second = read('second');
    const ms = instant.getUTCMilliseconds();

    const offsetIntoDayMs = ((hour * 60 + minute) * 60 + second) * 1000 + ms;
    const startMs = instant.getTime() - offsetIntoDayMs;
    const oneDayMs = 24 * 60 * 60 * 1000;

    return {
        gte: new Date(startMs).toISOString(),
        lte: new Date(startMs + oneDayMs - 1).toISOString(),
    };
},

Intl.DateTimeFormat mit explizitem timeZone liest die Wall-Clock-Komponenten des gewählten Zeitpunkts in dieser Zeitzone. Aus diesen Komponenten berechnet der Helper, wie weit in den Tag hinein der Zeitpunkt fällt, zieht diesen Offset ab, um den Anfang des Kalendertages des Benutzers zu erhalten, und addiert 24 Stunden minus 1 Millisekunde, um das Ende zu erhalten. Die Zeitzone wird aus Shopware.Store.get('session').currentUser.timeZone gezogen, mit UTC als Fallback für den nicht-authentifizierten Edge-Case.

Der Fix für die Doppel-Emission ist subtiler. updateFilter mutiert this.dateValue nicht mehr. Stattdessen baut es ein abgeleitetes Objekt mit dem neuen from und to und emittiert dieses als drittes Argument. Der konsumentenseitig sichtbare Wert ist identisch zu vorher, aber der Watcher in sw-range-filter feuert nicht mehr ein zweites Mal. Ein filter-update pro Feldänderung, nicht zwei.

Der neue Test setzt einen Session-User mit Zeitzone America/Los_Angeles, wählt zwei nicht-mitternächtige UTC-Zeitpunkte, die beide auf denselben LA-Tag fallen, und prüft, dass die emittierten Grenzen auf die LA-Tagesgrenzen zusammenfallen:

const fromInput = wrapper.find('.sw-date-filter__from').find('input');
await fromInput.setValue('2021-01-22T15:30:00.000Z');
await fromInput.trigger('input');
await flushPromises();

const toInput = wrapper.find('.sw-date-filter__to').find('input');
await toInput.setValue('2021-01-23T03:00:00.000Z');
await toInput.trigger('input');
await flushPromises();

const lastEmit = wrapper.emitted()['filter-update'].at(-1);
expect(lastEmit).toEqual([
    'releaseDate',
    [Criteria.range('releaseDate', {
        gte: '2021-01-22T08:00:00.000Z',
        lte: '2021-01-23T07:59:59.999Z',
    })],
    {
        from: '2021-01-22T08:00:00.000Z',
        to: '2021-01-23T07:59:59.999Z',
        timeframe: 'custom',
    },
]);

Beide UTC-Zeitpunkte fallen in LA auf den 22. Januar. Die emittierten Grenzen sind LA-Mitternacht des 22. Januar bis LA-Mitternacht des 23. Januar minus eine Millisekunde, ausgedrückt in UTC: 08:00:00.000Z bis 07:59:59.999Z des darauffolgenden UTC-Tages. Genau der Kalendertag, den der Benutzer gewählt hat, in der Zeitzone, in der er arbeitet.

Ich habe den PR am 24. April eröffnet; er wurde für Milestone 6.7.10.0 getaggt. Zum Zeitpunkt des Schreibens hat er null Reviews und das Label needs-triage. PR #16439 auf GitHub.

Den Fix lokal ausliefern, ohne auf 6.7.10.0 zu warten

Ein Händler, dessen Buchhaltungsteam heute offene Rechnungen abgleicht, will nichts von Milestone-Tags hören. Er will, dass der Filter diese Woche funktioniert. Die PRs können Tage, Wochen oder länger brauchen, je nach Review-Queue und Milestone-Freeze.

Der lokale Fix lebt im bestehenden sw-date-filter-Override des Plugins. Der Override erweitert die Parent-Komponente bereits, also kann er getPreviousQuarterDates und updateFilter mit den korrigierten Implementierungen ersetzen:

import template from './sw-date-filter.html.twig';

const { Component, Criteria, Store } = Shopware;

Component.override('sw-date-filter', {
    template,

    methods: {
        getPreviousQuarterDates(date) {
            const quarter = Math.floor(date.getMonth() / 3);
            const startDate = new Date(date.getFullYear(), quarter * 3 - 3, 1, 0, 0, 0);
            const endDate = new Date(startDate.getFullYear(), startDate.getMonth() + 3, 0, 23, 59, 59);
            return { startDate, endDate };
        },

        // updateFilter und dayBoundsInTz analog zum Upstream-PR,
        // hier aus Platzgründen weggelassen, gleiche Form wie in PR #16439
    },
});

Der Override re-definiert die fehlerhaften Methoden mit den korrigierten Versionen aus den beiden PRs. Beim nächsten Plugin-Deploy verhält sich der Datumsfilter für den Händler korrekt, unabhängig davon, wann 6.7.10.0 ausgeliefert wird.

Das ist der duale Ansatz, der explizit erwähnt zu werden verdient. Der Override patcht das unmittelbare Symptom für einen Kunden. Die PRs beheben die Ursache für alle auf Shopware 6, und sie erlauben mir, den Override in diesem Kundenprojekt zu löschen, sobald 6.7.10.0 landet. Der lokale Fix ist per Design temporär. Der Upstream-Fix ist permanent.

Was ich daraus mitgenommen habe

Ein paar Dinge, die es wert sind, für das nächste Mal aufgeschrieben zu werden.

Overrides erben Bugs. Das ist die Designstärke von Admin-Component-Erweiterung und der Grund, warum sie für fast jedes Plugin der richtige Default ist. Es ist auch eine Falle, wenn der Parent falsch ist. Wenn Sie ein Verhalten in Ihrem Override debuggen und der relevante Code nicht in Ihrem Override liegt, ist der Bug nicht in Ihrem Override. Verfolgen Sie ihn in den Parent. Das breitere Muster habe ich in Shopware 6 Plugin-Entwicklung neu gedacht behandelt.

“Funktioniert auf meiner Maschine” ist eine Hypothese, kein Urteil. Beide Bugs in dieser Geschichte waren real und reproduzierbar. Sie brauchten ein Q1-Datum bzw. ein Nicht-UTC-Profil. Meine Dev-Umgebung hatte in dem Moment, in dem ich versucht habe zu reproduzieren, keines davon. Die diagnostische Frage ist nicht “funktioniert es bei mir”, sondern “was ist anders zwischen meiner Umgebung und ihrer”.

Tragen Sie die Ursache upstream bei, wenn Sie können. Der lokale Patch schliesst das Ticket. Der Upstream-PR schliesst den Bug. Beides sollte passieren. Der PR erledigt die Arbeit auch für jeden anderen Shopware-6-Admin-Nutzer, der das Problem noch nicht bemerkt hat, einschliesslich der nächsten Agentur, die in einer Q1-Deadline darauf stösst.

Die Antwort auf “Release-Cadence” für ungeduldige Kunden lautet “beides”. Lokal patchen, upstream beitragen, planen, den lokalen Patch zu löschen, sobald das Release ausgeliefert wird. Der Kunde muss nie warten, und die Codebasis tendiert über die Zeit zu weniger, nicht mehr individuellem Code.

Wie der Stand jetzt ist

PR #16380 ist offen mit einem positiven Review von einem Community-Contributor und wartet auf Maintainer-Review für Milestone 6.7.10.0. PR #16439 ist offen in der Triage-Queue, ebenfalls für 6.7.10.0 getaggt. Der Datumsfilter des Document-Overview-Plugins funktioniert für den Kunden seit dem Tag nach dem zweiten Ticket korrekt.

Wenn Sie einen Shopware-6-Shop betreiben und die Art von Admin-Arbeit aus diesem Beitrag die Art von Arbeit ist, die Sie ordentlich erledigt haben möchten, nehmen Sie Kontakt auf. Mehr Projekte, aus denen diese Arbeit kommt, finden Sie in den Case Studies.

Beide PRs sind öffentlich auf GitHub: #16380, #16439. Mein Contributor-Profil liegt auf github.com/zaifastafa.

Datumsfilter in Shopware 6: Häufig gestellte Fragen

Was ist sw-date-filter in Shopware 6? sw-date-filter ist die Vue-Komponente, die Shopware-6-Listing-Filterpanels verwenden, um from/to-Datumsbereiche und Quick-Timeframes wie “Last Quarter” oder “Last Month” anzuwenden. Sie emittiert ein filter-update-Event mit einem Criteria.range, sodass die Listing-Query auf das gewählte Datumsfenster eingeschränkt wird. Die meisten Admin-Listen mit einer Datumsspalte (Bestellungen, Dokumente, Kunden, Produkte nach Release-Datum) verwenden sie direkt oder über eine Parent-Erweiterung.

Warum tauchen Filter-Bugs im Shopware-6-Admin manchmal nur in Q1 auf? Quartalsbasierte Datumsmathematik nutzt häufig das aktuelle Jahr für sowohl den Start als auch das Ende des vorherigen Quartals. Von April bis Dezember beginnt und endet das vorherige Quartal im selben Kalenderjahr, der Bug ist also unsichtbar. Im Januar, Februar und März begann das vorherige Quartal im Vorjahr und endete im Vorjahr, aber der fehlerhafte Code leitet das Endjahr aus dem heutigen Datum ab, sodass sich der Bereich über zwei Jahre erstreckt. PR #16380 hat genau das in sw-date-filters getPreviousQuarterDates korrigiert.

Wie behandelt Shopware 6 Benutzerzeitzonen in Admin-Datumsfiltern? Jeder Admin-Benutzer hat eine timeZone in seinem Profil, zugänglich über Shopware.Store.get('session').currentUser.timeZone. Listen-Datumsspalten formatieren Anzeigewerte in dieser Zeitzone. Filter-Inputs müssen dasselbe tun, wenn sie Tagesgrenzen ableiten, sonst stimmt der gewählte Tag in der UI nicht mit dem Tag überein, der in der Query verwendet wird. PR #16439 hat einen dayBoundsInTz-Helper eingeführt, der Intl.DateTimeFormat verwendet, um den gewählten Zeitpunkt vor dem Emittieren der gte/lte-Grenzen auf den Kalendertag des Benutzers zu snappen.

Sollte ich Shopware-6-Admin-Komponenten überschreiben oder dekorieren? Komponenten-Overrides im Admin sind Erweiterung, nicht Ersatz. Ihr Override liegt über der Basiskomponente und erbt deren computed properties, methods und templates, sofern Sie sie nicht explizit ersetzen. Das ist die Designstärke, bedeutet aber auch, dass jeder Bug in der Parent-Komponente nun ein Bug in Ihrem Override ist. Für Services in PHP ist Decoration das Äquivalent. Das Pattern funktioniert nur dann zu Ihren Gunsten, wenn der Parent korrekt ist. Ist er es nicht, patchen Sie den Parent entweder lokal oder tragen die Korrektur upstream bei. Das breitere Muster habe ich in Shopware 6 Plugin-Entwicklung neu gedacht behandelt.

Wie lange dauert es, bis ein Shopware-Core-PR in einem Release ausgeliefert wird? Beide PRs in diesem Beitrag tragen das Milestone-Label milestone/6.7.10.0, mit dem Shopware Fixes in ein bestimmtes Patch-Release einplant. Die Zeit von PR bis Release hängt von der Review-Queue, dem Milestone-Freeze-Datum und der Frage ab, ob die Änderung mehrere Bereiche betrifft. Für nicht-blockierende Admin-Fixes sind Tage bis Wochen realistisch. Wenn ein Kunde nicht auf das nächste Patch-Release warten kann, lässt sich der Fix lokal in einem Plugin-Override anwenden und entfernen, sobald die Upstream-Version ausgeliefert ist.

Artikel teilen

Fanden Sie das hilfreich? Teilen Sie es mit Ihrem Netzwerk

Huzaifa Mustafa

Huzaifa Mustafa

Shopware 6 zertifizierter Entwickler mit 164+ individuellen Plugins und 96+ Kunden in der DACH-Region. Ich schreibe über Shopware-Architektur, E-Commerce-Performance und Erfahrungen aus realen Projekten.

Brauchen Sie Hilfe mit Shopware?

Lassen Sie uns besprechen, wie ich bei Ihrem E-Commerce-Projekt helfen kann.