Backend
Wie aus der Elementkonfiguration eine Store-API-Abfrage wird.
Kein Resolver
Das Plugin bringt keinen serverseitigen CMS-Element-Resolver mit. Die Twig-Vorlage storefront/element/cms-element-ajax-listing.html.twig baut die Filterabfrage und legt sie als data-ajax-listing-options an das Element; das Storefront-JavaScript reicht sie unverändert an POST /store-api/product weiter.
Der Adminbereich geht einen anderen Weg: collect() in src/main.ts baut dieselbe Abfrage als Criteria und holt die Produkte über die Admin-API. Beide Seiten müssen daher dieselbe Abbildung beherrschen — festgehalten wird das durch src/Test/fixtures/filter-cases.json, das von beiden Testseiten gelesen wird.
Die Abbildung
Vergleich | erzeugte Abfrage |
|---|---|
ist gleich |
|
ist ungleich |
|
≥ / ≤ |
|
liegt zwischen |
|
enthält |
|
Alle Bedingungen zusammen stehen in einer multi/and-Hülle. Eine Zeile ohne Wert wird übersprungen. Bleibt keine Zeile übrig, sendet das Element bewusst {field: 'id', value: null, type: 'equals'} — eine Abfrage, die nichts trifft.
Welche Felder angeboten werden
Nicht jedes Feld der Produkt-Entität taugt als Filter. config/index.ts entscheidet anhand der Merker der Entitätsdefinition:
runtime— wird zur Laufzeit berechnet und kann gar nicht gefiltert werden (translated,variation).read_protected— nennt die erlaubten API-Quellen. FehltSalesChannelApiSource, weist die Store-API den Filter ab.api_criteria_aware— sticht die Leseeinschränkung:pricedarf gefiltert werden, obwohl es nur die Admin-API lesen darf. Genau daran unterscheidet es sich vonprices.Eine Zu-viele-Verknüpfung hat keine eigene Spalte; ihr
localFieldist die Produkt-Id. Sie wird deshalb als<name>.idangeboten — sonst filterte »Kategorien« in Wahrheit auf das Produkt selbst.
Dazu kommt die Liste NOT_OFFERED: Felder, die zwar funktionieren, aber in einem Produktlisting nichts zu suchen haben. Sie ist im Quelltext je Gruppe begründet.
Feldnamen
Shopware führt kein allgemeines Register übersetzter Feldnamen — nur für Entitäten (global.entities.*). Die Beschriftungen kommen deshalb aus einer Kette:
plugin.leoparden.AjaxListing.config.fields.<feld>— der eigene Textbaustein,sw-product-stream.filter.values.<feld>— die dynamischen Produktgruppen, die dasselbe Problem lösen und rund 70 Feldnamen zweisprachig mitbringen,global.entities.<entität>bei Verknüpfungen,sonst der technische Name.
Der eigene Baustein steht vorn, damit eine Formulierung überschrieben werden kann, die im Streamzusammenhang passt und hier nicht.