Kosten für 500 Produkte eintragen, ohne 500-mal zu klicken
Der Kern von WooCommerce bietet ein Kostenfeld je Produkt und keine Massenbearbeitung. Bei fünfhundert Produkten ist das kein Abend Arbeit, sondern ein Grund, die Funktion nie einzuschalten. So geht es: aus einer Tabelle über eine CSV-Datei mit einem einzigen Skript.
Aktualisiert 2026-09-06
Diese Seite setzt voraus, dass die Funktion „Kosten der verkauften Waren“ bereits eingeschaltet ist. Ist sie es nicht, kommt zuerst die Anleitung zum Einschalten, die kürzer ist als diese Seite: Solange der Schalter aus ist, erreichen die eingetragenen Kosten keine einzige Bestellung.
Rechnen Sie zuerst aus, wie viele Produkte Sie wirklich brauchen
Der erste Impuls ist, alles auszufüllen. Das ist die teuerste mögliche Reihenfolge, denn die ersten achtzig Prozent des Nutzens entstehen in der ersten Stunde, und der Rest kostet den Rest der Woche.
Ein Gewinnbericht braucht keinen vollständigen Katalog. Er braucht Abdeckung: den Anteil des Umsatzes, für den ein Wareneinsatz bekannt ist. Ein Shop, der den Wareneinsatz der fünfzig Produkte kennt, die 80 % des Umsatzes machen, hat einen brauchbaren Bericht. Ein Shop, der den Wareneinsatz von vierhundert Produkten aus dem Long Tail kennt und den seiner zehn Bestseller nicht, hat nichts.
Es gibt also nur eine sinnvolle Reihenfolge: Katalog nach Umsatz sortieren und von oben nach unten arbeiten, nicht alphabetisch und nicht nach Erstellungsdatum. Hören Sie auf, wenn die Abdeckung nicht mehr schnell genug steigt, um das Tippen zu rechtfertigen.
Das Eintragen von Kosten ändert keine Bestellungen, die schon in der Datenbank stehen. Der Wareneinsatz wird im Moment des Verkaufs in die Bestellposition geschrieben. Was Sie heute eintragen, wirkt also erst ab heute. Das ist kein Grund zu warten, sondern ein Grund, es diese Woche zu erledigen statt im nächsten Quartal.
Die Tabelle: drei Spalten und eine Entscheidung
Laden Sie die CSV-Vorlage herunter oder bauen Sie eine eigene; es kommt auf den Aufbau an:
id,sku,cost
1042,,41.50
,TSHIRT-XL-BLACK,24.00
1198,,
idodersku: eine der beiden, nicht beide. Das Skript nimmtidund sucht das Produkt, wennidleer ist, über die Artikelnummer insku.cost: Netto-Wareneinsatz für einen Artikel, mit Punkt als Dezimaltrennzeichen. Keine Währung, keine Leerzeichen, keine Symbole.- Ein leeres
costbedeutet „wir wissen es nicht“, und das Skript überspringt die Zeile. Das ist keine Höflichkeit gegenüber den Daten, sondern notwendig: Eine gespeicherte Null und ein fehlender Wareneinsatz sind in der Datenbank von WooCommerce dasselbe. Wer „vorerst“ null eintippt, löscht Information, statt welche hinzuzufügen.
Die Entscheidung, die Sie einmal vor der ersten Zeile treffen: Was bedeutet „Kosten“ in Ihrem Shop? Nur der Einkaufspreis? Mit Eingangsfracht? Zoll, Verpackung, Plattformgebühren? Jede dieser Antworten ist gültig, und keine ist für den halben Katalog gültig. Eine Marge aus zwei verschiedenen Definitionen von Kosten lässt sich mit nichts vergleichen, nicht einmal mit sich selbst vor einem Monat. Schreiben Sie die Wahl in die erste Zeile der Tabelle, damit Sie in sechs Monaten nicht raten müssen.
Woher Sie die Produktliste bekommen: WooCommerce → Produkte → Exportieren liefert eine CSV-Datei mit den Spalten ID und Artikelnummer (in der englischen Oberfläche SKU). Behalten Sie diese beiden, ergänzen Sie eine dritte und füllen Sie sie
in der Tabellenkalkulation aus, wo Sie alles auf einmal sehen.
Das Skript: ein Durchgang durch die Datei
Das Skript unten läuft über WP-CLI. Es liest die CSV-Datei, findet das Produkt, schreibt den
Wareneinsatz und meldet, was es getan hat. Es startet im Probelauf; darüber entscheidet die Zeile $DRY_RUN.
<?php
/**
* Füllt das Feld „Wareneinsatz“ von WooCommerce aus einer CSV-Datei (id,sku,cost).
* Aufruf: wp eval-file fill-costs.php costs.csv
*/
$DRY_RUN = true; // <- erst nach einem erfolgreichen Probelauf auf false setzen
$file = $args[0] ?? 'costs.csv';
$handle = fopen( $file, 'r' );
if ( ! $handle ) {
WP_CLI::error( "Cannot open file: {$file}" );
}
fgetcsv( $handle ); // Kopfzeile: id,sku,cost
$written = 0;
$skipped = 0;
$failed = 0;
while ( ( $row = fgetcsv( $handle ) ) !== false ) {
list( $id, $sku, $cost ) = array_pad( $row, 3, '' );
$cost = trim( str_replace( ',', '.', $cost ) );
if ( '' === $cost ) { // leer ist nicht null - überspringen
$skipped++;
continue;
}
if ( ! is_numeric( $cost ) || (float) $cost < 0 ) {
WP_CLI::warning( "Bad cost value: '{$cost}' (id={$id}, sku={$sku})" );
$failed++;
continue;
}
$id = (int) $id;
if ( ! $id && $sku ) {
$id = wc_get_product_id_by_sku( trim( $sku ) );
}
$product = $id ? wc_get_product( $id ) : null;
if ( ! $product ) {
WP_CLI::warning( "Product not found (id={$id}, sku={$sku})" );
$failed++;
continue;
}
if ( $DRY_RUN ) {
WP_CLI::log( sprintf( '[dry run] %d %s: %s -> %s',
$product->get_id(), $product->get_name(),
var_export( $product->get_cogs_value(), true ), $cost ) );
} else {
$product->set_cogs_value( (float) $cost );
$product->save();
WP_CLI::log( sprintf( '%d %s = %s', $product->get_id(), $product->get_name(), $cost ) );
}
$written++;
}
fclose( $handle );
WP_CLI::success( sprintf( '%s: %d, skipped (empty cost): %d, failed: %d',
$DRY_RUN ? 'To write' : 'Written', $written, $skipped, $failed ) );
Speichern Sie es als fill-costs.php neben costs.csv und führen Sie es so aus:
wp eval-file fill-costs.php costs.csv
Das Skript steht hier zum Lesen, nicht zum Herunterladen mit einem Klick, und das mit Absicht. Es schreibt in Ihre Datenbank, also sollten Sie es lesen, bevor es Ihre Produkte ändert.
Warum keine Shell-Schleife. Das verlockende wp eval, einmal je Zeile aufgerufen, startet für
jedes Produkt das ganze WordPress: Bei fünfhundert Produkten ist das eine Viertelstunde statt ein paar
Sekunden, und fünfhundert Gelegenheiten, auf halbem Weg abzubrechen. Ein Skript, ein Start.
Wenn Sie kein SSH haben. Dasselbe Methodenpaar, set_cogs_value() und save(), funktioniert
überall, wo Sie PHP innerhalb von WordPress ausführen können. Die REST-API führt denselben Wert bei den
Ressourcen products und variations, als cost_of_goods_sold mit values, total_value und, bei
Varianten, defined_value_is_additive. Zwei Dinge sollten Sie wissen, bevor Sie eine Schleife für die API schreiben: effective_value und total_value sind schreibgeschützt, und ein leeres Array values bedeutet
einen Wareneinsatz von null, mit allem, was das weiter unten auf dieser Seite bedeutet. Lesen Sie zuerst
ein Produkt zurück (GET /wp-json/wc/v3/products/<id>) und prüfen Sie den Aufbau an Ihrer eigenen
Version.
Der Probelauf, den Sie nicht überspringen sollten
- Eine Datenbanksicherung. Kein „Produktexport“, sondern eine Sicherung. Das Skript schreibt, und das Speichern eines Produkts kann mehr als ein Feld berühren.
- Erst zehn Zeilen. Kopieren Sie zehn Zeilen in
trial.csvund führen Sie alles damit aus: erst als Probelauf, dann im echten Lauf, dann sehen Sie sich diese zehn Produkte im Administrationsbereich an. - Erst dann
$DRY_RUN = falsefür die ganze Datei. - Prüfen Sie danach, im Shop, nicht in der Tabelle. Geben Sie eine Testbestellung für ein Produkt mit Wareneinsatz auf und prüfen Sie, ob die Bestellung ihn gespeichert hat. Nur dieser Test deckt die ganze Kette ab und nicht nur das Feld im Produkt.
Varianten: Darüber entscheidet nicht das Skript
Eine Variante übernimmt den Wareneinsatz des übergeordneten Produkts, bis sie einen eigenen hat. Hat sie einen, entscheidet ein Schalter, ob dieser Wert den des übergeordneten Produkts ersetzt oder dazukommt. Das ist eine Entscheidung darüber, was die Zahl bedeutet, nicht darüber, wie hoch sie ist, also trifft das Skript sie nicht.
In der Praxis: Füllen Sie per Massenimport die Kosten der übergeordneten Produkte und fassen Sie Varianten nur dort an, wo der Wareneinsatz wirklich abweicht. Den Modus stellen Sie dann bewusst im Produkt-Editor ein, wo Sie ihn sehen. Bei einem Hemd mit einem Wareneinsatz von 24 kommt die Variante „bestickt“ mit 3 im additiven Modus auf 27, im ersetzenden Modus auf 3. Einzelheiten unter Kosten bei variablen Produkten.
Eines sollten Sie beim Prüfen der Ergebnisse wissen: Die Spalte der Lookup-Tabelle von WooCommerce speichert den eingetragenen Wert, nicht den wirksamen. Eine Variante, die einfach den Wareneinsatz ihres übergeordneten Produkts übernimmt, sieht in einer SQL-Abfrage deshalb aus wie eine Variante ohne Wareneinsatz. Jede Liste „Produkte ohne Wareneinsatz“, die direkt auf dieser Spalte beruht, steckt voller Fehlalarme.
Was das nicht behebt
- Die Historie. Bestellungen, die vor dem Eintragen der Kosten eingingen, bleiben für immer ohne Wareneinsatz; nichts wird nachträglich ergänzt, und das ist kein Versehen.
- Gratisartikel. Ein Produkt, das wirklich nichts kostet, wird als gar kein Wareneinsatz gespeichert, weil der Kern den Wert löscht, statt eine Null zu schreiben. Es bleibt auf der Liste fehlender Kosten, und Sie können nichts dagegen tun.
- Erstattungen. Eine Erstattung lässt WooCommerce den Wareneinsatz jeder Position der ursprünglichen Bestellung aus dem heutigen Wareneinsatz neu berechnen. Frisch eingetragene Kosten können also genau die Historie neu schreiben, die sie beschreiben. Was dann passiert.
- Variable Kosten. Versand, Gebühren der Zahlungsanbieter und Rücksendungen an den Lieferanten sind kein Wareneinsatz, und das Kostenfeld deckt sie nicht ab. Rohertrag ist kein Nettogewinn, und wir geben ihn auch nicht dafür aus.
Checkliste
- Die Kostenfunktion eingeschaltet: Ohne sie bewirkt der Rest nichts.
- Eine Definition von Kosten, in die Tabelle geschrieben.
- Produkte exportieren →
id,sku, leere Spaltecost. - Nach Umsatz sortieren, von oben füllen.
- Sicherung, Probelauf mit zehn Zeilen, erst dann die ganze Datei.
- Eine Testbestellung, um die ganze Kette zu prüfen.
- Varianten getrennt und bewusst: ersetzender oder additiver Modus.
Verhält sich ein Schritt in Ihrem Shop anders als hier beschrieben, lohnt es sich, uns zu schreiben: Diese Seiten werden korrigiert, wenn sie sich als falsch erweisen.