← Knowledge-Base · Code-Snippets
Nettopreise für B2B-Kunden in WooCommerce anzeigen
WooCommerce kennt nur eine Preisanzeige pro Shop: Entweder alle sehen Bruttopreise oder alle sehen Netto. Wer beide Kundengruppen bedient, muss umschalten - und dabei den Preis-Suffix mitnehmen, sonst steht am Ende „inkl. MwSt." unter einem Nettopreis.
Der Code dafür ist kurz. Die drei Dinge, die außer dem Code nachziehen müssen, sind der eigentliche Inhalt dieses Artikels: der Suffix, das Caching und die Frage, wer überhaupt Nettopreise sehen darf.
Das Problem
Unter WooCommerce → Einstellungen → Steuern gibt es zwei Schalter: „Preise im Shop anzeigen" und „Preise im Warenkorb und Kassenbereich anzeigen", jeweils inklusive oder exklusive Steuern. Beide gelten für den ganzen Shop und für alle Besucher gleich.
Für einen reinen B2B-Shop ist das kein Problem - einmal auf „exklusive" stellen, fertig. Eng wird es, sobald du beide Gruppen bedienst: Der Gewerbekunde denkt in Nettopreisen und rechnet die Steuer als durchlaufenden Posten. Der Verbraucher will wissen, was er zahlt, und hat gesetzlich Anspruch auf den Gesamtpreis.
Erste Frage: Brauchst du überhaupt Code?
Drei Alternativen, die je nach Lage besser sind:
- Ein reiner B2B-Shop. Wenn du ausschließlich an Unternehmer verkaufst, stell die Einstellung um und lass den Code weg. Das ist gleichzeitig die sauberste Rechtslage.
- Ein B2B-Plugin. Die gängigen Erweiterungen bringen Nettoanzeige, Kundengruppen, Staffelpreise und Steuerlogik mit. Wenn du mehr als nur die Anzeige brauchst, ist Nachbauen die teurere Variante.
- Zwei getrennte Shops. Klingt aufwendig, ist aber bei stark unterschiedlichen Sortimenten und Preisen oft ehrlicher - und rechtlich das eindeutigste Modell.
Der Code unten lohnt, wenn dein Sortiment identisch ist und du nur die Darstellung für eine überschaubare Gruppe eingeloggter Kunden ändern willst.
Schritt 1: Wer ist B2B-Kunde?
Die Erkennung läuft über eine eigene Benutzerrolle. Bewusst nicht über eine hinterlegte UID: Eine UID im Profil sagt, dass jemand eine Nummer eingetragen hat - nicht, dass du ihn geprüft und freigeschaltet hast.
/**
* Rolle beim Aktivieren des Plugins anlegen.
* Sie erbt die Faehigkeiten des normalen Kunden.
*/
register_activation_hook(__FILE__, function () {
$kunde = get_role('customer');
if ($kunde && !get_role('b2b_kunde')) {
add_role('b2b_kunde', 'B2B-Kunde', $kunde->capabilities);
}
});
function shop_ist_b2b_kunde() {
if (!is_user_logged_in()) {
return false;
}
$nutzer = wp_get_current_user();
return in_array('b2b_kunde', (array) $nutzer->roles, true);
}Die Freischaltung machst du danach im Backend unter Benutzer, indem du die Rolle setzt. Das ist Absicht: Ein Kunde soll sich nicht selbst zum Gewerbekunden erklären können.
Schritt 2: Die Anzeige umschalten
WooCommerce liest die beiden Einstellungen über get_option(). Damit lassen sie sich pro Aufruf überschreiben - und zwar an allen Stellen gleichzeitig: Produktseite, Kategorieübersicht, Warenkorb, Checkout, Widgets.
add_filter('option_woocommerce_tax_display_shop', 'shop_steueranzeige');
add_filter('option_woocommerce_tax_display_cart', 'shop_steueranzeige');
function shop_steueranzeige($wert) {
// Im Backend nichts veraendern - sonst zeigt die Einstellungsseite
// einen Wert an, der gar nicht gespeichert ist.
if (is_admin() && !wp_doing_ajax()) {
return $wert;
}
return shop_ist_b2b_kunde() ? 'excl' : $wert;
}Der is_admin()-Teil ist wichtiger, als er aussieht. Ohne ihn greift der Filter auch im Backend: Ein Administrator mit B2B-Rolle würde auf der Steuer-Einstellungsseite „exklusive" sehen, obwohl „inklusive" gespeichert ist - und beim nächsten Speichern die echte Einstellung überschreiben.
Schritt 3: Den Suffix mitschalten
Das ist der Schritt, der in fast jeder Anleitung fehlt - und der sichtbarste Fehler, wenn er fehlt.
Unter dem Preis steht in deutschen Shops üblicherweise ein Zusatz wie „inkl. MwSt. zzgl. Versandkosten". Der kommt aus einer eigenen Einstellung und ändert sich nicht mit, wenn du nur die Anzeigeart umschaltest. Ergebnis: Der B2B-Kunde sieht einen Nettopreis, darunter „inkl. MwSt.".
add_filter('option_woocommerce_price_display_suffix', function ($suffix) {
if (is_admin() && !wp_doing_ajax()) {
return $suffix;
}
if (!shop_ist_b2b_kunde()) {
return $suffix;
}
// Platzhalter, die WooCommerce kennt:
// {price_including_tax} Preis inkl. Steuern
// {price_excluding_tax} Preis exkl. Steuern
return 'zzgl. MwSt. ({price_including_tax} inkl. MwSt.)';
});Setzt du Germanized ein, kommen die Steuerhinweise von dort und nicht aus dieser Einstellung. Dann prüf im Frontend, welcher Text tatsächlich unter dem Preis steht, und schalte den - nicht diesen.
Wohin der Code gehört
In ein Mini-Plugin, nicht in die functions.php des Themes. Hier gilt das besonders, weil der Code eine Benutzerrolle anlegt: register_activation_hook funktioniert nur in einem Plugin.
<?php
/**
* Plugin Name: Nettopreise fuer B2B-Kunden
* Description: Zeigt eingeloggten Kunden mit der Rolle "b2b_kunde" Nettopreise.
* Version: 1.0.0
*/
if (!defined('ABSPATH')) {
exit; // Direktaufruf verhindern
}
// ... hier der Code aus den Schritten 1 bis 3Datei nach /wp-content/plugins/b2b-nettopreise/b2b-nettopreise.php, dann unter Plugins aktivieren. Beim Aktivieren wird die Rolle angelegt.
Was das Snippet nicht löst
Es ändert nur die Anzeige, nicht die Berechnung
Der wichtigste Satz des Artikels. Ob Umsatzsteuer anfällt, entscheidet WooCommerce weiterhin über Steuerklassen, Steuersätze und die Adresse des Kunden. Ein Nettopreis in der Anzeige bedeutet nicht, dass beim Kunden keine Steuer berechnet wird.
Reverse Charge bei innergemeinschaftlichen Lieferungen ist ein eigenes Thema mit eigenen Voraussetzungen - dazu steht das Nötige im Artikel zum UID-Feld im Checkout. Kurzfassung: Eine ausgefüllte Textbox ist keine Steuerbefreiung.
Es verträgt sich nicht automatisch mit Seiten-Caching
Das ist der Fehler, der in der Praxis am häufigsten weh tut. Wenn zwei Besucher unterschiedliche Preise sehen sollen, darf die Seite nicht für beide gleich ausgeliefert werden.
Typischer Ablauf: Ein Gast ruft eine Kategorieseite auf, der Cache speichert sie mit Bruttopreisen. Der B2B-Kunde loggt sich ein, ruft dieselbe Seite auf - und bekommt die gecachte Version mit Bruttopreisen. Umgekehrt genauso, und das ist der unangenehmere Fall: Ein Verbraucher sieht Nettopreise.
Die meisten Caching-Plugins schließen eingeloggte Benutzer standardmäßig aus. Verlass dich nicht darauf, sondern prüf es - besonders bei serverseitigem Caching, Varnish oder einem CDN vor der Seite. Der Test dauert zwei Minuten: einmal eingeloggt, einmal in einem privaten Fenster, dieselbe Kategorieseite.
Es beantwortet nicht, wer Nettopreise sehen darf
Gegenüber Verbrauchern ist die Angabe von Nettopreisen nicht zulässig - sie haben Anspruch auf den Gesamtpreis inklusive Steuern. Das ist keine Formalie, sondern ein klassischer Abmahngrund.
Solange nur eingeloggte, von dir freigeschaltete Kunden Netto sehen, ist die Konstruktion sauber. Kippen kann sie an zwei Stellen: wenn Gäste versehentlich Nettopreise sehen (siehe Caching), und wenn du die Rolle großzügig vergibst, ohne die Unternehmereigenschaft zu prüfen.
Wie ein Shop insgesamt erkennbar B2B wird und was daran hängt, steht in Widerruf im B2B.
Häufige Fehler
- Den Suffix vergessen. Nettopreis mit „inkl. MwSt." darunter - sichtbar für jeden Kunden, peinlich und angreifbar.
- Den
is_admin()-Guard weglassen. Die Steuer-Einstellungsseite zeigt dann einen Wert, der nicht gespeichert ist. Beim nächsten Speichern ist die echte Einstellung weg. - Nur
tax_display_shopumschalten. Dann sieht der Kunde Nettopreise im Katalog und Bruttopreise im Warenkorb. Beide Optionen gehören zusammen. - Caching nicht geprüft. Siehe oben. Der Fehler zeigt sich nicht beim Entwickeln, sondern im Live-Betrieb unter Last.
- Die Rolle über die UID vergeben. Eine eingetragene Nummer ist keine Prüfung. Wer automatisch freischaltet, hat am Ende Verbraucher mit Nettopreisen.
- Angebotspreise und Staffelpreise nicht gegengeprüft. Rabatt-Plugins rechnen teils mit Brutto-, teils mit Nettobeträgen. Nach dem Umbau einmal eine Bestellung mit Rabatt durchrechnen.
- Der Versand bleibt brutto. Versandkosten haben eigene Steuereinstellungen. Prüf im Warenkorb, ob die Darstellung durchgängig ist.
Blöcke und Block-Checkout
Weil die Umschaltung über die Optionen läuft und nicht über einzelne Templates, greift sie überall dort, wo WooCommerce diese Optionen abfragt - also auch in Produktblöcken und im block-basierten Warenkorb.
Verlassen würde ich mich nicht darauf: Prüf jede Stelle, an der Preise auftauchen, einmal mit einem B2B-Testkonto. Preise erscheinen an mehr Orten, als man beim Umbau im Kopf hat - Suchergebnisse, verwandte Produkte, Widgets, Mini-Warenkorb.
Testliste
- Testkonto mit der Rolle
b2b_kundeanlegen. - Eingeloggt: Netto auf Produktseite, Kategorieseite, im Mini-Warenkorb, im Warenkorb und im Checkout?
- Steht unter den Preisen der richtige Zusatz - nicht „inkl. MwSt." unter einem Nettopreis?
- Privates Fenster ohne Login: erscheinen wieder Bruttopreise?
- Beide Ansichten mehrfach hin- und herwechseln - bleibt es stabil, oder mischt der Cache?
- Eine Bestellung im B2B-Konto abschließen: Stimmt die Steuer in Bestellung und Rechnung?
- Backend öffnen: Steht unter Einstellungen → Steuern noch der Wert, den du gespeichert hast?
- Ein rabattiertes Produkt gegenrechnen.
Punkt sieben ist der, den man am ehesten überspringt - und der stillste Fehler, wenn er auftritt.
Weiterlesen
- UID-Feld im Checkout - die Erfassung, auf der die Freischaltung aufbaut
- Hinweis je nach Zahlungsart - dasselbe Muster, anderer Checkout-Baustein
- Widerruf im B2B - woran ein Shop als B2B-Shop erkennbar wird
- Grundpreise bei Sets und Bundles - die zweite Baustelle in der Preisauszeichnung
Tritt dein Shop eindeutig als B2B auf?
Nettopreise sind nur sauber, wenn der Shop nach außen erkennbar an Unternehmer gerichtet ist. Der kostenlose B2B-Shop-Check ruft deine Startseite auf, sucht AGB, Impressum und Widerrufsseite und benennt Widersprüche. Kein Konto, keine E-Mail-Adresse.
B2B-Shop-Check starten →Der Code ändert die Preisanzeige, nicht die Steuerberechnung. Ob und wann du Umsatzsteuer ausweisen musst, klärst du mit deinem Steuerberater. Test den Code auf einer Staging-Umgebung, bevor er in den Live-Shop geht. Stand: August 2026.
Hat dir dieser Artikel weitergeholfen?
Dann weißt du jetzt, wie wir arbeiten: ehrlich, direkt und ohne Abkürzungen. Wenn dich das überzeugt, freuen wir uns riesig über eine kurze Google-Bewertung. Das dauert keine Minute und hilft uns enorm.
Jetzt auf Google bewertenEhrlich verdient statt manipuliert - so muss das.
War diese Anleitung hilfreich?
Fehlt dir etwas oder können wir den Artikel verbessern? Sag es uns.