Kundengruppen-spezifische Preisanzeige im Hyvä-Theme: B2B-Preise, Login-Sperre und Cache-Fallstricke
AI generated
Hyvä
phtml
Hyvä Theme
Kundengruppen-spezifische Preisanzeige im Hyvä-Theme
B2B-Nettopreise, gesperrte Preise und Cache-Fallstricke sauber lösen

Wer Preise je Kundengruppe unterschiedlich anzeigt, muss Full Page Cache, GraphQL-Kontext und private content gemeinsam denken. Sonst sieht ein Gast plötzlich den B2B-Nettopreis eines fremden Kunden, weil eine gecachte Seite den falschen Preis konserviert hat.

12 Min. Lesezeit B2B-Preise Full Page Cache GraphQL Context Login für Preis

1. 1. Kundengruppen in Magento: Tier Price, Group Price und Catalog Price Rules einordnen

Jeder Kunde in Magento gehört zu genau einer Kundengruppe: NOT LOGGED IN für Gäste, General für normale Endkunden, dazu beliebig viele eigene Gruppen für B2B-Segmente, Großhändler oder Vertragskunden. Diese Gruppenzugehörigkeit ist die zentrale Achse, entlang der Magento Preise unterschiedlich berechnen kann, und sie ist der Grund, warum ein und derselbe Produkt-Slug für zwei Besucher zwei völlig verschiedene Preise ausliefern muss.

Für die Preisdifferenzierung stehen drei Mechanismen zur Verfügung, die man als Frontend-Entwickler nicht verwechseln sollte. Tier Price ist ein Staffelpreis, der ab einer definierten Mindestmenge greift und je Kundengruppe eigene Stufen haben kann. Group Price ist technisch nichts anderes als ein Tier Price mit Mengenschwelle eins, wirkt also wie ein Fixpreis je Gruppe, wird in der Praxis aber oft fälschlich als eigenständiges Feature behandelt. Catalog Price Rules sind dagegen regelbasierte Rabatte, die über Bedingungen wie Kundengruppe, Website oder Kategorie definiert werden und erst durch den Preisindex beziehungsweise den Cron-Reindex in die tatsächlich angezeigten Preise einfließen.

Für das Theme spielt es letztlich keine Rolle, welcher dieser drei Mechanismen den finalen Preis erzeugt hat. Wichtig ist nur die Konsequenz: der Preis ist zur Laufzeit von der Kundengruppe des anfragenden Besuchers abhängig, und genau diese Abhängigkeit macht ihn zu einem der heikelsten Kandidaten für Caching-Fehler im gesamten Shop.

2. 2. Preisauflösung im Frontend-Kontext: warum ein Fragment nicht für alle Kundengruppen identisch gecacht werden darf

Der Full Page Cache speichert eine gerenderte Seite pro URL, nicht pro Besucher. Wird der Preis-Block serverseitig mit dem Preis der gerade anfragenden Kundengruppe gerendert und die komplette Seite anschließend als öffentlicher Cache-Eintrag abgelegt, landet genau dieser Preis im Cache und wird an jeden folgenden Besucher derselben URL ausgeliefert, unabhängig von dessen tatsächlicher Kundengruppe.

Magentos Antwort darauf ist die Trennung zwischen öffentlichem, cachebarem Inhalt und privatem, personalisiertem Inhalt. Öffentliche Blöcke dürfen im Full Page Cache landen, weil sie für jeden Besucher gleich aussehen sollen. Private Blöcke, zu denen kundengruppen-abhängige Preise fast immer gehören, müssen entweder explizit von der Cachebarkeit ausgenommen oder erst nach dem Ausliefern der gecachten Seite über einen separaten Request nachgeladen werden.

In der Praxis ist genau das der Fehler, der Preisanzeigen im Hyvä-Theme am häufigsten sabotiert: ein Entwickler baut den Preis direkt in ein normales .phtml-Template ein, ohne zu prüfen, ob der umgebende Block cachebar ist. Solange nur mit einer einzigen Kundengruppe getestet wird, fällt das nicht auf. Erst wenn Varnish oder der Built-in Full Page Cache warmgelaufen ist und eine zweite Kundengruppe dieselbe URL aufruft, wird sichtbar, dass der falsche Preis konserviert wurde.

3. 3. B2B-Nettopreise darstellen: Steueranzeige-Konfiguration je Kundengruppe

Viele B2B-Kunden erwarten Nettopreise, während Endkunden Bruttopreise inklusive Mehrwertsteuer sehen wollen. Magento steuert das über die Kombination aus Steuerklasse je Kundengruppe und der globalen Tax-Konfiguration für die Preisanzeige. In der Praxis bekommt eine B2B-Kundengruppe häufig eine eigene Steuerklasse, etwa für Reverse-Charge-Fälle, und das Theme muss zusätzlich entscheiden, ob der Preis mit oder ohne Steuerhinweis angezeigt wird.

Diese Entscheidung gehört nicht verstreut in einzelne Templates, sondern zentral in ein ViewModel. So bleibt sie testbar und lässt sich an einer einzigen Stelle erweitern, wenn eine neue B2B-Gruppe hinzukommt. Das folgende Beispiel zeigt ein ViewModel, das anhand der aktuellen Kundengruppe entscheidet, ob Netto- oder Bruttopreis samt passendem Label ausgegeben wird.

Wichtig ist, die Gruppenliste konfigurierbar zu halten statt Gruppen-IDs im Code zu hinterlegen. In der Dependency-Injection-Konfiguration lässt sich die Liste der Netto-Gruppen als Argument injizieren, sodass ein neuer B2B-Kunde ohne Deployment über di.xml-Anpassung oder eine Konfigurationsoption ergänzt werden kann.


<?php

declare(strict_types=1);

namespace Mironsoft\PriceDisplay\ViewModel;

use Magento\Customer\Model\Session as CustomerSession;
use Magento\Framework\View\Element\Block\ArgumentInterface;

/**
 * Ermittelt, ob für die aktuelle Kundengruppe Netto- oder Bruttopreise angezeigt werden.
 */
class CustomerGroupPriceDisplay implements ArgumentInterface
{
    /**
     * @param CustomerSession $customerSession Aktuelle Kundensession für die Gruppenermittlung.
     * @param int[] $netPriceGroupIds Kundengruppen-IDs, die grundsätzlich Nettopreise sehen.
     */
    public function __construct(
        private readonly CustomerSession $customerSession,
        private readonly array $netPriceGroupIds = [],
    ) {
    }

    /**
     * Prueft, ob die aktuelle Kundengruppe Nettopreise sehen soll.
     *
     * @return bool
     */
    public function shouldShowNetPrice(): bool
    {
        $groupId = (int) $this->customerSession->getCustomerGroupId();

        return in_array($groupId, $this->netPriceGroupIds, true);
    }

    /**
     * Liefert das passende Preislabel zur Steueranzeige der Kundengruppe.
     *
     * @return string
     */
    public function getPriceLabel(): string
    {
        return $this->shouldShowNetPrice() ? __('zzgl. MwSt.') : __('inkl. MwSt.');
    }
}

4. 4. Gesperrte Preise für Gäste: das Login-für-Preis-Pattern

Manche B2B-Shops zeigen Preise ausschließlich angemeldeten Kunden. Für die Kundengruppe NOT LOGGED IN erscheint an der Stelle des Preises stattdessen ein Login-Hinweis oder ein Call-to-Action wie Login für Preis. Das Produkt selbst bleibt über Kategorie und Suche auffindbar, nur der konkrete Betrag wird zurückgehalten, was sowohl vertriebliche als auch vertragsrechtliche Gründe haben kann.

Technisch entsteht dieselbe Kundengruppen-Abhängigkeit wie bei jedem anderen Preis, mit der zusätzlichen Anforderung, dass strukturierte Daten wie das Product-Schema weiterhin valide bleiben müssen, auch wenn kein Preis ausgegeben wird. Die Sichtbarkeitsentscheidung selbst darf, wie im vorherigen Abschnitt beschrieben, nicht in einem öffentlich gecachten Block hartkodiert sein, sondern muss entweder über cacheable="false" laufen oder clientseitig nach dem Laden der Seite aufgelöst werden.

Das folgende Template-Fragment zeigt das Pattern mit Alpine.js: der Sichtbarkeitszustand wird aus einem ViewModel übernommen und über einfache x-if-Templates zwischen Preis und Login-Link umgeschaltet, ohne zusätzliches JavaScript-Framework und ohne Knockout-Abhängigkeit.


<?php
/** @var \Magento\Catalog\Block\Product\ListProduct $block */
/** @var \Mironsoft\PriceDisplay\ViewModel\PriceVisibility $priceViewModel */
$priceViewModel = $block->getData('price_visibility_view_model');
?>
<div class="price-box"
     x-data="{ visible: <?= $priceViewModel->isPriceVisibleForCurrentGroup() ? 'true' : 'false' ?> }">
    <template x-if="visible">
        <span class="text-lg font-semibold text-gray-900">
            <?= $block->getProductPriceHtml($product) ?>
        </span>
    </template>
    <template x-if="!visible">
        <a href="<?= $block->escapeUrl($block->getUrl('customer/account/login')) ?>"
           class="inline-flex items-center rounded-md border border-gray-300 px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50">
            <?= $block->escapeHtml(__('Login für Preis')) ?>
        </a>
    </template>
</div>

5. 5. GraphQL-Preisauflösung je nach Kontext: Customer Group Context und price_range

Bei der Magento-GraphQL-API gibt es keinen Header, mit dem ein Client einfach eine beliebige Kundengruppe anfordern kann. Die Kundengruppe ergibt sich implizit: ohne Authorization-Header behandelt die API die Anfrage als Gast und liefert Preise der Gruppe NOT LOGGED IN. Wird ein gültiges Customer-Token mitgesendet, leitet Magento die Kundengruppe aus dem zugehörigen Kundenkonto ab und löst price_range entsprechend auf.

Zusätzlich ist der Store-Header verpflichtend, weil er Store-View, Währung und Preisanzeige-Konfiguration festlegt. Für Testzwecke bedeutet das: eine B2B-Preisanfrage lässt sich nicht durch einen frei erfundenen Header simulieren, sondern nur durch ein echtes Customer-Token der jeweiligen Kundengruppe, was bei automatisierten Tests häufig übersehen wird und zu falschen Grün-Ergebnissen führt.

Das price_range-Feld liefert sowohl minimum_price als auch maximum_price mit jeweils regular_price und final_price, bereits vollständig für den anfragenden Kontext aufgelöst. Rabattlogik, Tier Price und Catalog Price Rules müssen im Frontend nicht mehr nachgebildet werden, solange der richtige Kontext über Store-Header und Authorization-Token mitgegeben wird.


# Store-Header ist Pflicht, die Kundengruppe wird über den Customer-Token abgeleitet
query ProductPrice($sku: String!) {
  products(filter: { sku: { eq: $sku } }) {
    items {
      sku
      price_range {
        minimum_price {
          regular_price {
            value
            currency
          }
          final_price {
            value
            currency
          }
        }
      }
    }
  }
}

# HTTP-Header für den Request:
# Store: default
# Authorization: Bearer <customer_token>

6. 6. Full Page Cache und X-Magento-Vary: konkrete Fallstricke bei Preisen

Die HTML-Antwort einer Kategorie- oder Produktseite wird von Varnish oder dem Built-in Full Page Cache pro URL gespeichert, nicht pro Kundengruppe. Damit eine kundengruppen-abhängige Preisanzeige nicht in dieser gemeinsamen HTML-Variante landet, muss der betroffene Block explizit als nicht cachebar markiert werden, entweder über das Attribut cacheable="false" im Layout-XML oder indem der Preis erst nachträglich per Ajax oder GraphQL nachgeladen wird.

Das X-Magento-Vary-Cookie ist Magentos Signal dafür, dass ein Besucher einen privaten Kontext besitzt, der nicht mit der anonymen, öffentlich gecachten Seitenvariante bedient werden darf. Wird dieses Signal bei einem preisrelevanten Block ignoriert, weil der Block fälschlich als cachebar konfiguriert wurde, entsteht genau das Leck aus Abschnitt zwei: der zuerst gerenderte Preis, meist der der Gruppe NOT LOGGED IN, wird für alle folgenden Besucher eingefroren.

Das folgende Layout-XML-Fragment zeigt, wie ein Preis-Block innerhalb des Produktinfobereichs explizit von der Cachebarkeit ausgenommen wird. Diese Konfiguration allein reicht in Hyvä nicht aus, sie muss mit dem Nachlade-Pattern aus dem folgenden Abschnitt kombiniert werden, damit der Block trotzdem performant bleibt.


<referenceContainer name="product.info.price">
    <block class="Mironsoft\PriceDisplay\Block\CustomerGroupPrice"
           name="customer.group.price"
           template="Mironsoft_PriceDisplay::product/price.phtml"
           cacheable="false" />
</referenceContainer>

7. 7. ViewModel- und Alpine-Pattern für Preis-Platzhalter bis private content geladen ist

Ein Block mit cacheable="false" löst das Korrektheitsproblem, verschenkt aber die Cache-Trefferquote der gesamten Seite, wenn er zu grob geschnitten ist. Der in Hyvä übliche Weg ist deshalb, in der cachebaren HTML einen Platzhalterpreis oder einen Skeleton-Zustand auszugeben und den tatsächlichen Preis erst nach dem Laden der Seite über eine kleine Alpine-Komponente per GraphQL nachzuladen.

Für Gäste, bei denen der öffentliche Preis der Gruppe NOT LOGGED IN ohnehin korrekt ist, kann das Nachladen entfallen. Für angemeldete Kunden ersetzt die Komponente den Platzhalter durch den über price_range aufgelösten, kundengruppen-spezifischen Preis, sobald die Antwort eintrifft, ohne dass die restliche Seite aus dem Full Page Cache verdrängt werden muss.

Wichtig ist ein sauberer Ladezustand, damit kein Layout-Sprung entsteht: die Preis-Fläche behält während des Nachladens ihre Größe, ein dezenter Skeleton-Zustand signalisiert, dass noch aufgelöst wird, und erst mit der Antwort wird der endgültige Betrag formatiert eingesetzt.


document.addEventListener('alpine:init', () => {
    Alpine.data('customerGroupPrice', (sku, fallbackPriceHtml) => ({
        priceHtml: fallbackPriceHtml,
        loading: true,

        async init() {
            // Für Gäste keine Nachladung, der öffentliche Preis bleibt gültig
            if (!window.customerAuthToken) {
                this.loading = false;
                return;
            }

            const response = await fetch('/graphql', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Store': window.storeCode,
                    'Authorization': `Bearer ${window.customerAuthToken}`,
                },
                body: JSON.stringify({
                    query: `query($sku:String!){ products(filter:{sku:{eq:$sku}}) { items { price_range { minimum_price { final_price { value currency } } } } } }`,
                    variables: { sku },
                }),
            });

            const { data } = await response.json();
            const price = data?.products?.items?.[0]?.price_range?.minimum_price?.final_price;

            if (price) {
                this.priceHtml = new Intl.NumberFormat('de-DE', {
                    style: 'currency',
                    currency: price.currency,
                }).format(price.value);
            }

            this.loading = false;
        },
    }));
});

8. 8. Vary-Header und Context korrekt setzen: GraphQL-Caching mit Varnish und PWA

Auch GraphQL-Antworten können auf Varnish-Ebene gecacht werden. Magento setzt dafür den Response-Header X-Magento-Cache-Id, der Store, Währung und Kundengruppen-Kontext bereits einrechnet. Eine Varnish-VCL, die GraphQL-Antworten nur nach URL oder Query-Body cached und diesen Header ignoriert, kann einem Gast versehentlich den zwischengespeicherten B2B-Preis eines anderen Kunden ausliefern, weil zwei unterschiedliche Kundengruppen aus Sicht der VCL identisch aussehen.

Bei headless-Aufbauten mit vorgeschaltetem CDN oder Edge-Cache gilt dieselbe Regel verschärft: authentifizierte GraphQL-Preisabfragen sollten am CDN grundsätzlich nicht gecacht werden, sondern mit Cache-Control: private beantwortet werden, während nur anonyme, öffentliche Preisabfragen für eine kurze Zeitspanne öffentlich gecacht werden dürfen. Der Authorization-Header muss entweder in den Cache-Key einfließen oder das Caching für diese Anfragen vollständig deaktivieren.

In der Praxis lässt sich das schnell mit curl überprüfen, indem man dieselbe Preisabfrage einmal als Gast und einmal mit einem gültigen Customer-Token stellt und die relevanten Cache-Header vergleicht. Unterscheiden sich X-Magento-Cache-Id oder Cache-Control nicht zwischen beiden Anfragen, ist das ein starkes Indiz für eine fehlerhafte Cache-Konfiguration.


# Preis für einen Gast abfragen und Cache-Header prüfen
curl -s -D - -o /dev/null https://shop.example.com/graphql \
  -H 'Content-Type: application/json' \
  -H 'Store: default' \
  -d '{"query":"{ products(filter:{sku:{eq:\"24-MB01\"}}) { items { price_range { minimum_price { final_price { value } } } } } }"}' \
  | grep -i 'x-magento-cache-id\|cache-control'

9. 9. Testing-Strategie: verschiedene Kundengruppen systematisch gegen falsches Caching prüfen

Fehler bei kundengruppen-abhängigen Preisen zeigen sich fast nie in einer lokalen Entwicklungsumgebung ohne Full Page Cache. Sie treten erst auf, wenn Varnish oder der Built-in Cache warmgelaufen ist und eine zweite Kundengruppe dieselbe URL aufruft. Deshalb sollte jede Teststrategie für Preisanzeige eine echte Cache-Schicht einschließen, nicht nur den PHP-Entwicklungsserver.

Sinnvoll ist eine Testmatrix, die für jede relevante Kundengruppe, also mindestens Gast, Standardkunde und die wichtigsten B2B-Gruppen, dieselbe Produkt- oder Kategorie-URL zweimal aufruft: einmal bei kaltem und einmal bei bereits warmem Cache. Geprüft werden der tatsächliche Preiswert, die Steueranzeige und relevante Cache-Header wie Age oder X-Magento-Cache-Id.

Ergänzend hilft ein einfacher manueller Smoke-Test vor jedem Release: Cache leeren, als B2B-Kunde in einem Browser ein Produkt öffnen, dieselbe URL parallel in einem Inkognito-Fenster als Gast laden, Preise vergleichen, und anschließend die B2B-Session ein zweites Mal aufrufen, nachdem der anonyme Aufruf den Cache gefüllt hat. Weichen die Preise dabei unerwartet an, liegt fast immer ein fehlkonfigurierter cachebarer Block zugrunde.


#!/usr/bin/env bash
# Prüft, ob dieselbe Produkt-URL für verschiedene Kundengruppen korrekte Preise liefert
set -euo pipefail

declare -A TOKENS=(
  ["guest"]=""
  ["general"]="$GENERAL_TOKEN"
  ["wholesale"]="$WHOLESALE_TOKEN"
)

for group in "${!TOKENS[@]}"; do
  token="${TOKENS[$group]}"
  header=()
  if [[ -n "$token" ]]; then
    header=(-H "Authorization: Bearer $token")
  fi

  price=$(curl -s "${header[@]}" -H 'Store: default' -H 'Content-Type: application/json' \
    -d '{"query":"{ products(filter:{sku:{eq:\"24-MB01\"}}) { items { price_range { minimum_price { final_price { value } } } } } }"}' \
    https://shop.example.com/graphql | jq -r '.data.products.items[0].price_range.minimum_price.final_price.value')

  echo "Gruppe: $group -> Preis: $price"
done
Mechanismus Preis-Quelle Caching-Ebene Kundengruppen-Bezug Typischer Fallstrick
Tier Price Staffelpreis je Menge und Gruppe Produkt- und Preisindex direkt an group_id gebunden Reindex nach Preisänderung vergessen
Group Price Fixpreis je Gruppe, Tier Price mit Menge eins Produkt- und Preisindex direkt an group_id gebunden mit echtem Staffelpreis verwechselt
Catalog Price Rule regelbasierter Rabatt nach Bedingungen Cron-Reindex, zeitgesteuert über Regel-Bedingungen an Gruppe geknüpft Regel wirkt erst nach dem nächsten Cronlauf
GraphQL price_range über Store-Header und Customer-Token aufgelöst Varnish/CDN via X-Magento-Cache-Id implizit über Authorization-Token Cache-Id am CDN ignoriert
phtml-Preis-Block serverseitig gerenderter Preis-Block Full Page Cache, abhängig vom cacheable-Flag abhängig von korrekter Layout-Konfiguration Block fälschlich als cachebar markiert
Private-Content-Platzhalter clientseitig nachgeladener Preis kein Full Page Cache, eigener Ajax- oder GraphQL-Call pro Request neu über Session oder Token Platzhalter bleibt bei deaktiviertem JavaScript stehen

Mironsoft

Hyvä-Theme-Entwicklung und Luma-Migration

Noch auf Luma unterwegs oder ein Hyvä-Theme, das nicht rund läuft?

Wir entwickeln Hyvä-Themes für Magento von Grund auf oder migrieren bestehende Luma-Shops sauber, mit Tailwind CSS, Alpine.js und ohne unnötiges JavaScript-Gepäck.

Luma-zu-Hyvä-Migration

Bestehenden Shop strukturiert und ohne Funktionsverlust auf Hyvä umstellen.

Custom-Theme-Entwicklung

Individuelles Hyvä-Theme nach Design-Vorgaben von Grund auf umsetzen.

Performance-Optimierung

Core Web Vitals und Ladezeiten im Hyvä-Frontend gezielt verbessern.

10. Zusammenfassung

Kundengruppen-Preisanzeige

Preisquelle trennen

Tier Price, Group Price und Catalog Price Rules erzeugen den Preis unterschiedlich, für das Theme zählt am Ende nur, dass der Wert kundengruppen-abhängig ist.

Cache-Grenze ziehen

Kundengruppen-abhängige Preis-Blöcke gehören nicht in öffentlich gecachte HTML, sondern hinter cacheable false oder eine clientseitige Nachladung.

GraphQL-Kontext respektieren

Store-Header und Authorization-Token bestimmen die aufgelöste Kundengruppe, ein frei erfundener Header ersetzt kein echtes Customer-Token.

Mit warmem Cache testen

Preisfehler zeigen sich erst bei warmem Varnish oder Full Page Cache, deshalb muss die Testmatrix jede Kundengruppe gegen eine echte Cache-Schicht prüfen.

11. FAQ: Kundengruppen-Preisanzeige

1Kann eine Full-Page-Cache-Seite unterschiedliche Preise für verschiedene Kundengruppen anzeigen?
Nicht direkt in der gecachten HTML-Datei selbst. Die gecachte Seite enthält entweder einen öffentlichen Platzhalterpreis oder gar keinen Preis, die tatsächliche kundengruppen-spezifische Preisanzeige wird über einen separaten, nicht gecachten Aufruf nachgeladen, etwa per GraphQL oder über einen als cacheable false markierten Block.
2Was ist der Unterschied zwischen Tier Price und Group Price in Magento?
Tier Price ist ein Staffelpreis, der ab einer bestimmten Menge greift und je Kundengruppe unterschiedlich konfiguriert werden kann. Group Price ist technisch ein Tier Price mit der Mengenschwelle eins, wirkt also wie ein Fixpreis je Gruppe ohne Mengenrabatt.
3Wie unterscheiden sich Catalog Price Rules von Tier Price?
Catalog Price Rules sind regelbasierte Rabatte, die über Bedingungen wie Kundengruppe, Website oder Kategorie definiert werden und über den Cron-Reindex in den Preisindex einfließen. Tier Price wird dagegen direkt am Produkt für eine Kundengruppe hinterlegt und wirkt ohne separate Regelauswertung.
4Wie zeigt man B2B-Kunden Nettopreise im Hyvä-Theme an?
Über eine Kombination aus Steuerklassen je Kundengruppe und einer ViewModel-Logik, die anhand der aktuellen Kundengruppe entscheidet, ob der Preis inklusive oder exklusive Steuer angezeigt wird. Diese Entscheidung sollte zentral im ViewModel liegen, nicht verstreut in einzelnen Templates.
5Wie funktioniert das Login-für-Preis-Pattern technisch?
Der Preis wird für die Kundengruppe NOT LOGGED IN nicht ausgegeben, stattdessen erscheint ein Login-Link. Da diese Entscheidung kundengruppenabhängig ist, darf sie nicht in einem öffentlich gecachten Block liegen, sondern muss über cacheable false oder eine clientseitige Nachladung erfolgen.
6Woher weiß die GraphQL-API, welche Kundengruppe gerade anfragt?
Bei angemeldeten Kunden wird die Kundengruppe implizit aus dem im Authorization-Header mitgesendeten Customer-Token abgeleitet. Ohne diesen Token behandelt die API die Anfrage als Gast und liefert die Preise der Gruppe NOT LOGGED IN.
7Was hat das X-Magento-Vary-Cookie mit Preisen zu tun?
Es signalisiert, dass ein Besucher einen privaten Kontext besitzt, der nicht mit der anonymen, öffentlich gecachten Seitenvariante bedient werden darf. Wird dieser Kontext bei preisrelevanten Blöcken ignoriert, können falsch gecachte Preise zwischen Kundengruppen durchsickern.
8Warum sollte man GraphQL-Preisabfragen nicht pauschal am CDN cachen?
Weil das Ergebnis vom Authorization-Token und damit von der Kundengruppe abhängt. Ein CDN, das nur nach Query-Body cached und den Token ignoriert, liefert einem Gast womöglich den zwischengespeicherten B2B-Preis eines anderen Kunden aus.
9Wie testet man kundengruppen-abhängige Preise gegen Caching-Fehler?
Mit einer Testmatrix, die jede relevante Kundengruppe zweimal gegen dieselbe URL prüft, einmal bei kaltem und einmal bei warmem Cache, und dabei den erwarteten Preis sowie relevante Cache-Header vergleicht. Wichtig ist, gegen eine echte Varnish- oder Full-Page-Cache-Umgebung zu testen, nicht nur gegen den PHP-Entwicklungsserver.
10Ersetzt ein Preis-Platzhalter mit Alpine.js die Notwendigkeit von cacheable false?
Nein, beide Mechanismen ergänzen sich. Der Platzhalter sorgt für ein layoutstabiles Nachladen im Frontend, cacheable false beziehungsweise private content verhindert, dass der kundengruppen-spezifische Preis überhaupt erst in die öffentlich gecachte HTML-Antwort gelangt.