Archiv für den Monat: August 2017

Noch mehr postmeta: benutzerdefinierte Felder in wooCommerce

Falls ihnen die 48 vordefinierten Felder in wooCommerce noch nicht reichen, haben sie auch die Möglichkeit, zusätzliche Felder anzulegen. Diese laufen unter dem Stichwort „benutzerdefinierte Felder“ und können im Produkt-Editor angelegt werden.

Ein Feld für Material

Zu dem in meinem Online-Lädchen verkauften Glasperlenschmuck lege ich jetzt mal ein benutzerdefiniertes Feld „Material“ an.  Das kriegt dann zum Beispiel den Wert „Böhmische Glasperlen“, das sieht im Editor so aus:

benutzerdefinierte_felder

benutzerdefinierte_felder

Keine Hexerei, und was auf der Datenbank passiert kann man leicht erraten:

material_postmeta

material_postmeta

Es wird ein neuer Datensatz mit dem meta_key „Material“ angelegt, der kriegt den meta_value „Böhnmische Glasschliffperlen“. Das war’s schon, mehr ist nicht passiert.

Wie verwendet man nun diese Felder?

wooCommerce weist einen da höflich auf den Codex zum Thema Custom Fields hin. Das ist zwar gut gemeint, aber nicht besonders hilfreich. Deswegen gibts bei Tante Google auch jede Menge Einträge, wenn man nach „woocommerce show custom fields“ sucht, hier ist ein besonders netter von Theme Location

Der Knackpunkt ist: man muss die wooCommerce-Templates editieren, wenn man seine benutzerdefinierten Felder auch beim Produkt angezeigt kriegen will. Wir versuchen uns mal an einem einfachen Beispiel. Da sollen wir eine Zeile im Template content-single-product.php ergänzen:

<?php echo get_post_meta( get_the_ID(), ‘Material’, true ); ?>

Edit die content-single-product.php – ja, wie?

Also, erstmal muss man das richtige Template finden, und das ist bei der endlosen Latte von wooCommerce-Templates gar nicht so einfach. Schauen sie mal rein unter Plugins/wooCommerce/Bearbeiten, das ist alles andere als übersichtlich. Die content-single-product.php steht in der langen Liste ziemlich weit unten.

„At the appropriate place“ soll diese Zeile rein, heißt es im Tutorial, und das ist eine Runde Trial and Error. Ich habs jetzt im ersten Anlauf noch nicht hingekriegt, da muss ich nochmal ne Runde googlen. So richtig Spaß macht das nicht, die wooCommerce-templates sind viel zu schlecht dokumentiert, das ist eine einzige Raterei.

Anderer Ansatz: wooCommerce Hooks

Ich hatte jetzt relativ schnell die Schn… voll von der Rumprobiererei und bin auf einen anderen Lösungsansatz gestossen, um unser benutzerdefiniertes Feld auch anzeigen zu lassen. WooCommerce bietet eine lange Latte von vordefinierten Hooks, in die man sich einklinken kann, das ist hier bei BusinessBloomer recht ausführlich dokumentiert, man muss sich allerdings anmelden, um das Tutorial anschauen zu können, und dazu hatte ich keine Lust. Ein andermal vielleicht…

Prinzipiell sollte es so funktionieren: man editiert die functions.php und fügt den entsprechenden Hook hinzu, in dem ruft man die zugehörige selbstdefinierte Funktion auf, und die Funktion letztendlich sollte unser Custom Field dann auch anzeigen. Ich habs nicht hingekriegt, jedenfalls nicht in unter einer Stunde, und da hatte ich dann einfach keinen Bock mehr. Ist vielleicht nicht mein Tag zum Rumprobieren heute.

Noch ein Versuch: vielleicht mit einem Plugin?

Das hier sieht ganz gut aus:

WooCommerce Custom Product Data Fields

Das schau ich mir mal an, aber ich glaube, ich brauch erstmal ’ne Pause. Ja kruzitürken, kann das denn so schwer sein, so ein lumpiges Custom Field auch anzeigen zu lassen?

Ist echt nicht mein Tag heute, die Doku zu dem Plugin ist gerade nicht erreichbar.

acf_nicht_ereichbar

acf_nicht_ereichbar

Hab ich noch ein anderes Plugin probiert, ACF for WooCommerce.

ACF  = Advanced Custom Fields. Aber zu früh gefreut: auch kein Glück, da muß ich mal direkt die Support-Seite zitieren:

  • It seems only to work on Checkout Page. How do I show field on the Product Page?

    Any answer is most welcome, thank you.

Viewing 6 replies – 1 through 6 (of 6 total)

Tscha, Pech gehabt. Die Anzeige der Custom Fields in der Single Product Ansicht geht hier nur mit der kostenpflichtigen Pro-Version des Plugins, und die kostet 29 $. No way, José.

Jetzt reichts mit der Probiererei – noch einmal mit System.

Also, wir fangen nochmal sauber von vorne an. Wo soll unser benutzerdefiniertes Feld „Material“ erscheinen? In der Startseite des Shops, jedenfalls reicht mir das für’s erste. Direkt nach dem Titel, vor dem Warenkorb-Button.

Dafür editieren wir die woocommerce/templates/content-product.php.

Durch schlichtes Ausprobieren und Raten habe ich schließlich die richtige Position gefunden: nach der Zeile:

do_action( ‚woocommerce_shop_loop_item_title‘ );

Das hat nicht auf Anhieb funktioniert, da WordPress im Template anscheinend die get_post_meta()-Funktion nur mit ein bißchen Überredungskunst akzeptiert. Ich habe dann folgendes Snippet gefunden, damit kriegen wir endlich den meta_value unseres Custom Fields „Material“ angezeigt :

global $wp_query;
$postid = $wp_query->post->ID;
echo get_post_meta($postid, ‚Material‚, true);
wp_reset_query();

Ergebnis- meine benutzerdefinierten Felder werden jetzt direkt unter dem Titel jedes Produkts angezeigt:

shop_mit_cf

shop_mit_cf

Na bitte, geht doch. Aber ein Gfrett war das jetzt schon!

Wie gehts jetzt weiter?

Wenn man das benutzerdefinierte Feld noch woanders anzeigen möchte: tscha, das wird jetzt ein Exempel in Trial&Error. Für jede Seite im Shop herausfinden, welches Template für die Anzeige verwendet wird, dort die Stelle suchen an welcher das Custom Field erscheinen soll, da das obige Code Snippet einfügen und hoffen dass es funkioniert. Viel Spaß mit Tante Google und der wooCommerce-Doku…

Ich finde das Thema Custom Fields in wooCommerce insgesamt wahnsinnig unübersichtlich und lausig schlecht dokumentiert. Anscheinend gibt es einige Plugins, die einem da das Leben leichter machen sollen, aber ich hab bislang nur kostenpflichtige Exemplare gefunden, die das auch können was wir brauchen. Und ich zahle nicht für Plugins, Punktum. OpenSource, sie wissen schon. So, und das ist ein schöner Schlußsatz für diesen Beitrag, lassen wir es mal gut sein.

Die bessere Alternative zum -zigfachen Join: Kreuztabelle

Also, zuerst mal dieses: ich habe versucht herauszufinden, ob MySQL Kreuztabellen (Pivot Tables) kann oder nicht, und die Tendenz beim Googlen geht zu eher nicht. Jedenfalls gibt es keinen Transform-Befehl, man muß sich da irgendwie anders behelfen.

Ich habe da die tollsten Konstrukte gefunden, hier ein besonders Hübsches mit einem Case für jedes Feld… na, das ist ja wohl nicht der Weisheit letzter Schluß. Da greife ich doch lieber auf meine Leib- und Magendatenbank zurück, nämlich Microsoft Access. Ich bin ja sonst kein Microsoft-Fan, aber das gute alte Access ist einfach eine tolle Datenbank mit einem sagenhaften Bedienkomfort im Entwurfsmodus. Auch wenn die zugrundeliegende Jet-Engine schon viele Jahre auf dem Buckel hat, im intuitiven Zusammenstellen aller möglichen Arten von Abfragen ist Access echt ungeschlagen.

Was wollen wir erreichen?

Wir haben ja im letzten Artikel gesehen, daß wooCommerce zu jeder Bestellung mindestens 48 Einträge in der wp_postmeta anlegt. Ich hätte jetzt gerne einen tabellarischen Überblick über alle Bestellungen, mit allen 48 Werten aus der wp_postmeta zu jeder Bestellung.

Das heißt im Klartext: eine Tabelle mit den relevanten Daten aus der wp_posts, und allen 48 Meta Keys als Felder in einer Zeile. Auf jeden Fall brauchen wir einen Join von der wp_posts auf die wp_postmeta über die ID der Bestellung, und dann noch die Meta Keys als Feldnamen, befüllt mit den Meta Values. Klingt schaurig kompliziert, ist aber in Access relativ einfach machbar, nämlich mit einer Kreuztabelle.

Der SQL für die Kreuztabelle

…sieht so aus:

TRANSFORM First(postmeta_alle_orders.meta_value) AS ErsterWertvonmeta_value
SELECT postmeta_alle_orders.post_id, postmeta_alle_orders.post_title, postmeta_alle_orders.post_status, postmeta_alle_orders.post_type
FROM postmeta_alle_orders
GROUP BY postmeta_alle_orders.post_id, postmeta_alle_orders.post_title, postmeta_alle_orders.post_status, postmeta_alle_orders.post_type
PIVOT postmeta_alle_orders.meta_key;

Den kann man sich mit Hiilfe des Kreuztabellen-Assistenten erstellen und dann im Entwurfsmodus komfortabel editieren.

Das Ergebnis der Kreuztabelle

Ich habs mal schnell der Übersichtlichkeit halber in ein Formular gepackt (auch hierfür hat Access einen prima Assistenten), da sieht dann z.B. unser Datensatz mit der Nummer 42 so aus:

formular_kreuztabelle

formular_kreuztabelle

Na, da hat man wenigstens mal alle Felder im Blick. Wenn man jetzt noch wüßte, für was die alle gut sind… aber da lasse ich jeden selber raten, anhand der Feldnamen müßte man da relativ weit kommen.

Wie kann man es übersichtlicher machen?

Wir haben jetzt wenigstens ein bißchen den Überblick gewonnen, mit 7 Zeilen Jet-SQL statt 48 mal Join und Case. Die Krux ist halt, dass es von vorne herein ein Unding ist, einem Datensatz so viele Werte redundant zuzuordnen.

Wenn sie nur mal die vielen Felder anschauen, die etwas mit Adressen zu tun haben, die gehören ausgelagert! Da gehört ein Fremdschlüssel auf die Kundennummer rein, und zu den Kunden-Basisdaten in einer eigenen Tabelle legen wir uns noch eine schnuckelige zweite Tabelle mit Rechnungsadresse und Lieferadresse (falls abweichend) des Kunden an, das wars dann und ist sauber gelöst.,

Damit können die ganzen Adressfelder aus den Bestellungen rausfliegen, das macht so über den Daumen gepeilt schon mal etwas mehr als 20 Felder weniger. Genauso sieht es mit den Zahlungsmodalitäten und den Steuerinformationen aus, auch die gehören normalisiert und ausgelagert, das wären dann noch mal ein rundes Dutzend Felder weniger.

Aber… die wooCommerce-Entwickler wissen ja anscheinend nicht, wie man Daten normalisiert und Detailtabellen anlegt, deshalb dieser unüberschaubare Datenwust. Das ist einfach nur grottenschlecht programmiert, da beißt die Maus kein Faden ab. Es kann sich ja jeder selber überlegen, wie ein sauberes Datenmodell für die Bestellungen aussehen könnte, so als Fingerübung zum Entspannen 😉

Ich mach hier mal Schluß, und überleg mir ein neues Thema. See you demnächst, ich wünsche gute Erholung vom wooCommerce-Datenchaos!

Nix für schwache Nerven: wooCommerce-Bestellungen auf der Datenbank

1 Bestellung = 1 Beitrag

Wenn jetzt endlich ein Kunde etwas in unserem Online-Shop gekauft hat, landet die Bestellung – wie könnte es anders sein – in der wp_posts mit dem Post Type „shop_order“. Das schauen wir uns mal ganz kurz an. Ich nehme nur ein paar ausgewählte Felder, sonst wirds unübersichtlich:

SELECT wp_posts.ID, wp_posts.post_author, wp_posts.post_content, wp_posts.post_title, wp_posts.post_status, wp_posts.post_name, wp_posts.post_type, wp_posts.comment_count
FROM wp_posts
WHERE (((wp_posts.post_type) Like „shop_order“));

Ergebnis:

shop_orders

shop_orders

Der post_status scheint noch interessant zu sein, da steht nur einer auf wc-completed, alle anderen auf wc-on-hold. Was ein comment_count von 3 bedeuten soll ist mir allerdings ein Rätsel – und es ist mir schnuppe.

Eine Bestellung, wie viele Einträge in der wp_postmeta?

Wir klemmen uns mal die erste Order-ID, das ist die 42, und gehen in der wp_postmeta suchen, was dazu alles abgespeichert ist. Zur Erinnerung: in der wp_postmeta ist jedem Datensatz die zugehörige post_id aus der wp_posts zugeordnet.

SELECT wp_postmeta.meta_id, wp_postmeta.post_id, wp_postmeta.meta_key, wp_postmeta.meta_value, wp_posts.ID, wp_posts.post_title, wp_posts.post_status, wp_posts.post_type
FROM wp_postmeta INNER JOIN wp_posts ON wp_postmeta.post_id = wp_posts.ID
WHERE (((wp_postmeta.post_id)=“42″) AND ((wp_posts.post_type) Like „shop_order“));

Das – halleluja! Spuckt 48 Datensätze aus. Achtundvierzig. Will heissen, zu Order Nr. 42 hat wooCommerce 48 Einträge in der wp_postmeta angelegt und dort irgendwelche Daten gespeichert. Ich stelle hier mal spaßeshalber eine Liste der Meta-Keys rein:

 

order_42
meta_key
_order_key
_customer_user
_payment_method
_payment_method_title
_transaction_id
_customer_ip_address
_customer_user_agent
_created_via
_date_completed
_completed_date
_date_paid
_paid_date
_cart_hash
_billing_first_name
_billing_last_name
_billing_company
_billing_address_1
_billing_address_2
_billing_city
_billing_state
_billing_postcode
_billing_country
_billing_email
_billing_phone
_shipping_first_name
_shipping_last_name
_shipping_company
_shipping_address_1
_shipping_address_2
_shipping_city
_shipping_state
_shipping_postcode
_shipping_country
_order_currency
_cart_discount
_cart_discount_tax
_order_shipping
_order_shipping_tax
_order_tax
_order_total
_order_version
_prices_include_tax
_billing_address_index
_shipping_address_index
_shipping_method
_recorded_sales
_recorded_coupon_usage_counts
_order_stock_reduced

Hübsch, nicht wahr? Wenigstens haben die wooCommerce_Entwickler recht sprechende Namen für die Meta-Keys verwendet, da kann man sich in den meisten Fällen wenigstens denken, was das sein soll.

Und das sind nur die Einträge zu einer einzigen ausgewählten Bestellung!

Was, wenn ich Auswertungen über die Bestellungen fahren will?

Aber ja verehrtes Publikum, sowas kommt vor. Daß man wissen will, wie viele Bestellungen an einem bestimmten Tag eingegangen sind. Oder wie viele davon per Scheck bezahlt wurden. Oder Bestellungen nach Postleitzahlen geordnet oder oder… sie wissen schon, was da so alles beim Kunden anliegt.

Das hatten wir schon ein paar mal, wenn man aus der wp_postmeta die meta_values zu einer bestimmten ID aus der wp_posts herauskriegen will, muß man pro Meta Key einen Join auf die wp_postmeta anlegen. Würde im Ernstfall hier einen 48fachen Join verlangen, das muß man sich mal so richtig reinziehen…

Eine andere Möglichkeit wäre eine Kreuztabelle (Microsoft Access kann sowas, bei MySQL bin ich mir nicht sicher), aber die hätte dann mehr als 48 Felder, das ist auch eher von der unhandlichen Sorte.

Ja Kruzitürken, haben die noch nie etwas von Fremdschlüsseln und Detailtabellen gehört?

Ein Beispiel wie man’s NICHT macht

Wir nehmen nur mal ein Beispiel:

Beim meta_key _payment_method steht in meinem Datensatz Nr. 42 der meta_value „cheque“. Dann nehmen wir den meta_key _payment_method_title noch mit, der hat den Wert „Scheckzahlung“

Und wenn ich jetzt ein paar Hundert oder Tausend Bestellungen habe, stehen der cheque und die Scheckzahlung eben auch Hundert oder Tausend mal in der wp_postmeta. Das, verehrtes Publikum, ist Redundanz, und zwar so richtig kriminelle Redundanz. So macht man sowas nicht. Da nimmt man eine Detailtabelle mit den Zahlungsarten (Scheck, Nachname, Bar bei Abholung…), von denen kriegt jede eine ID, die wird zu den Bestellungen dann als Fremdschlüssel gespeichert. Das ist Datennormalisierung für Anfänger, erstes Semester.

Und damit, liebe Leser, lasse ich euch mal mit den 48 Meta Keys allein meditieren, das langt für einen Beitrag.

 

In eigener Sache: Let’s talk about SEO, baby!

An diesem Wochenende hat mein Besucherzähler auf dieser Seite die 5.000er-Marke geknackt, und das ist eine respektable Zahl für einen sehr spezialisierten kleinen Blog wie den schwarzen Pinguin. Gezählt wird hier seit Februar diesen Jahres (2017), also hab ich hier rund gerechnet 5.000 Besucher in einem halben Jahr gehabt. Das freut mich persönlich sehr und ermutigt mich, mit meiner lockeren Plauderei über IT am Feierabend und WordPress im Speziellen weiterzumachen. Mir geht auch so schnell der Stoff nicht aus, keine Bange, nächste Woche gibts dann wieder Spaß auf der Datenbank!

Barrierefreiheit als SEO-Booster

Da wir gerade beim Thema sind: der Renner auf evileu.de ist nach wie vor das Inselfisch-Kochbuch mit aktuell 33.648 Besuchern, und da sind die Besucherzahlen nach einem eh schon guten Start nochmal kräftig in die Höhe gegangen, seit ich das Kochbuch in Sachen Barrierefreiheit  komplett umgebaut habe. Auch nicht schlecht läuft meine Oddballs-Handarbeitsseite, hier sind es immerhin auch schon 11.297 Besucher in einem halben Jahr. Das ist wirklich nicht übel für eine rein private Webseite, und ich werde oft gefragt, wie ich das denn gemacht habe.

Meine SEO-Tricks

Da muß ich euch leider enttäuschen. Ich nutze kein SEO-all-in-one Pack, ich jongliere nicht mit Keywords, mir ist mein Google Ranking egal, ich schalte keine Werbung, ich mach das hier alles zu Fuß.

Was ich allerdings schon mache: ich blogge wie der Weltmeister. Im Inselfisch-Kochbuch gibts mindestens einmal die Woche ein neues Rezept, hier quassel ich auch ungefähr ebenso oft aus dem Nähkästchen der alten Programmiererin, und auf den Handarbeitsseiten gibts regelmäßig Fotos meiner aktuellen Socken, Schals und Pullover und gelegentlich auch mal eine neue Anleitung zum Download als PDF. Das heißt, auf meinen Blogseiten ist regelmäßig Neues geboten, und das lieben nicht nur die Suchmaschinen, das lieben anscheinend auch menschliche Besucher.

Beiträge mit Hand und Fuß

Und ich erzähle halt nicht nur irgendeinen Keyword-gespickten Quark, meine Beiträge haben (meistens) Hand und Fuß. Nach meinen Kochrezepten kann auch ein Anfänger kochen, wenn man einen Schal nach meiner Handarbeitsanleitung strickt, dann wird das auch was, und wenn man meinen Code hier nachprogrammiert, dann funzt das auch. Das ist mein ganzes Geheimnis.

Wiederholungstäter und Mundpropaganda

Das sind meine wichtigsten Werbemittel. Meine streng wissenschaftlichen Analysen (ich hab einfach viele Leute gefragt) haben ergeben, dass gerade das Inselfisch-Kochbuch durch Mundpropaganda immer mehr Besucher bekommt, besonders das mit der Barrierefreiheit spricht sich hübsch herum. Und dann kommen meine Besucher auch wieder, sie benutzen das Kochbuch als Nachschlagewerk. Ich hab jetzt schon von vielen weiblichen Fans gehört, dass sie im Supermarkt mit dem Smartphone schnell mal ein Rezept im Inselfisch-Kochbuch nachschlagen und schauen, was sie dafür einkaufen müssen. Da hilft es natürlich, dass ein sauber umgesetztes WordPress-Theme im Regelfall fully responsive ist und auch auf dem Smartphone vernünftig dargestellt wird.

Spezialisierung: ein Blog, ein Thema

Das mit der Spezialisierung war bei mir dringend notwendig, weil ich so breitgefächerte Interessen habe. Ich male, ich programmiere, ich koche für mein Leben gern, ich schreibe Bücher für Kinder und für Erwachsene und produziere Handarbeiten am laufenden Band, und das ist noch lang nicht alles.

Ich habe in früheren Jahren schon mehrere vergebliche Anläufe gemacht, alle meine Interessensgebiete auf einer einzigen Webseite unterzubringen, und bin jedesmal  an dieser Sysiphosarbeit gescheitert. Letztendlich war  Wordpress der Schlüssel für die erfolgreiche Realisierung des Gemischtwarenladens evileu.de.

Ich habe jedem meiner vielen Hobbies einen eigenen Blog gegönnt, in dem ich jeweils nur über ein einziges Thema blogge. Es sind jetzt insgesamt etwas mehr als 10 Blogs, nicht alle sehr aktiv, aber doch eine stolze Anzahl für eine private Homepage. Wenn man nur mal auf die Seiten über meine Malerei schaut, das Thema ist jetzt aufgesplittet in meine Biographie als Malerin, meine Aquarelle, die Serie mit den blauen Planeten und dazu noch die Computergrafiken mit GIMP. Das macht 4 Kunst-Blogs, und die sind alle proppevoll mit Bildern und meinen Texten dazu. Aber eben sauber nach Themen getrennt, sonst verzettelt man sich. Und auch die Besucher verzetteln sich wenn eine Webseite zu viele verschiedene Topics anbietet, da werden die Menüs und Untermenüs und Unter-Untermenüs so verschachtelt, dass kein Schwein mehr durchblickt, und die Besucher nicht wiederkommen, weil sie nichts wiederfinden.

Jetzt fahre ich da eine ganz klare Linie, und das hat für mich als viel-Bloggerin den Vorteil, dass ich sofort weiß wohin damit, wenn mir eine Idee zu einem neuen Beitrag kommt. Und meine Besucher kennen sich auch aus, da jeder Themenblog einen unverwechselbarenb Look&Feel hat, und man sofort weiß ob man auf der Handarbeitsseite oder im Inselfisch-Kochbuch gelandet ist. Ich bin ein Buchhalterkind, ich liebe strukturierte Ablagesysteme!

Damit sind wir ganz wunderbar beim nächsten Stichwort gelandet:

Strukturierung: h1, h2 und Co.: eigentlich HTML für Anfänger

Ob sie es glauben oder nicht, Textverarbeitung am Computer gab es schon lange vor Windows und WYSIWYG. Ich erinnere nur an TeX/LaTeX oder an Word für DOS, wo man mitnichten auf dem Bildschirm angezeigt bekam, was dann auf dem Drucker herauskam. Damals lernten wir alles über die Verwendung von sog. Textauszeichnungen, in Word für Windows heißen sie Formatvorlagen. Und da HTML nichts anderes als eine Textauszeichnungssprache ist, gibt es sie  hier genauso. Jeder kennt sie, kaum jemand wendet sie richtig an.  Für Überschriften sind h1..h6 vorgesehen, eine Tabelle formatiert man mit Hilfe des <table>-Tags, es gibt nummerierte Listen, es gibt Image-Tags für die Bilder… das sind viele, aber doch nicht endlos viele. Eine hübsche komplette Liste aller HTML5-Tags findet ihr hier bei MDN Web Docs

Trennung von Text und Formatierung

Die Idee dabei ist, Text und Formatierung sauber zu trennen. Ein einfaches Beispiel: eine Hauptüberschrift soll fett, in Arial und in 30 Punkt Größe angezeigt werden. Was macht der WYSIWYG-Anwender? Er markiert den betreffenden Textabschnitt, drückt auf das Icon für „fett“, wählt in der Dropdownliste für die Schriftart „Arial“ und scrollt in der Schriftgrößen-Zahleneingabe rauf bis 30. Das erzielt zwar den gewünschten Effekt, aber es ist textverarbeitungstechnisch nicht sauber. Wie gehts richtig? Die Überschrift kriegt die Tags <h1>…</h1>, und wenn man es nicht dem Browser überlassen will wie eine Überschrift erster Ordnung dargestellt wird, legt man es in seiner CSS-Datei fest. Hierhin kommen unsere Textattribute, wenn man es richtig machen will.

Saubere Gliederung

Das habe ich bei der Umarbeitung meiner Webseiten auf barrierefrei neu lernen müssen, bei mir hatte sich da über die Jahre auch eine gewisse Schlamperei eingeschlichen. Ich schreibe ja sehr viel Text, und lange Textwüsten auf einer Webseite sind absolutes Bildschirmgift, die liest kein Schwein. Also, umdenken, Text in kürzere logische Einheiten unterteilen, Zwischenüberschriften einfügen, wo es Sinn macht, Listen und Tabellen verwenden. Das erhöht die Lesbarkeit und hält den Besucher bei der Stange, weil er nicht von unstrukturierten Endlostexten gelangweilt wird.

Einfaches Beispiel: Rezepte mit Struktur

Ich hätte da wieder ein einfaches Beispiel: alle meine Rezepte im Inselfisch-Kochbuch haben die selbe logische Gliederung:

  • Einleitung
  • Zutaten
  • Zubereitung
  • Tipps

Diese Elemente sind als h2-Überschriften formatiert. H1 ist der Titel des jeweiligen Rezepts, das ist unser post_title aus WordPress. Der Text dazwischen ist einfach <p> wie Absatz. That’s all, nach diesem Muster schreibe ich alle meine Rezepte. Ich muß nicht drüber nachdenken wie ich es mache, und es hat bei meinem Publikum einen hohen Wiedererkennungswert und dient der allgemeinen Übersichtlichkeit und Verständlichkeit. Mehr ist nicht dran an der Strukturierung – machen muß man es halt!

Übrigens: Suchmaschinen lieben klar strukturierte HTML-Dokumente. Benutzer mit Handicap (Screenreader & Co.) lieben sie auch, weil sie so klar durch das Dokument navigieren können. Deswegen ist eine gute Textstrukturierung auch eine der wichtigsten Voraussetzungen der Barrierefreiheit nach WCAG.

Mehr ist nicht dran an meinem SEO-Programm

Mit dieser Strategie bin ich zu meinen stolzen Besucherzahlen gekommen, über alle Blogs gerechnet sind das jetzt insgesamt fast 50.000 seit Anfang des Jahres. Genug aus dem Nähkästchen geplaudert, ich mach hier mal die Kiste zu. Ich hab mir nämlich gerade ein neues Projekt in Sachen Barrierefreiheit angelacht, da hat der schwarze Pinguin jetzt ein bißchen Sendepause. Bis die Tage!

 

Exkurs über unsere Kundendaten

Ich wollte ja eigentlich als nächstes den Bestellvorgang beleuchten, aber rein logisch kommen erstmal unsere Kunden an die Reihe, deswegen zieh ich das hier mal kurz vor.

Anmelden oder nicht anmelden?

WooCommerce bietet den Kunden die Möglichkeit, auch ohne das Anmelden eines Kundenkontos mit Password und allem drum und dran in unserem Shop als „Gast“ einzukaufen. Und soll ich ihnen sagen, was ich bevorzuge, wenn mir ein Shop da die Wahl läßt? Ich werde auf jeden Fall die Option ohne Anmeldung wählen. Weil ich mir nicht noch ein Paßwort merken will, weil ich keinen Bock auf Newsletter und Werbesendungen habe, weil ich meine persönlichen Daten im Internet nur hergebe, wenn es unbedingt sein muß. Ehrlich, sie können darauf zählen daß ein hoher Prozentsatz ihrer Kunden genauso denkt und auch ohne Erstellung eines „offiziellen“ Kundenkontos bei ihnen einkauft.

Kundendaten sind Unternehmenskapital

Wir wollen aber an unsere Kundendaten rankommen, die Adressen, Telefonnummern und E-Mail-Adressen sind so gut wie bares Kapital für unsere Firma.

Wenn sich ein Kunde brav bei uns anmeldet, wird in der WordPress Benutzerverwaltung ein neuer User mit der Rolle „Kunde“ für ihn angelegt, das ist recht gut dokumentiert. Die Benutzer Kunden werden in der wp_users verwaltet, in der wp_usermeta findet man dann die zugehörigen Adressdaten, die sind über die User-ID verknüpft.

Aber wo stecken unsere nicht angemeldeten Kunden?

Da haben sich die wooCommerce-Programmierer eine ganz besonders pikante Lösung einfallen lassen. Die haben sie nämlich schamhaft in der wp_postmeta versteckt:

nicht_angemeldeter_kunde

nicht_angemeldeter_kunde

Als ein Feld, alle Adressdaten in einem einzigen matschigen Klumpen. Zur Bestellung über die post_id zugeordnet, kenntlich am Meta Key _billing_adress_index.

Da soll doch der Dunnerlittchen…. sorry, aber bei sowas werde ich echt sauer. Das ist richtige Stümperei auf der Datenbank, aus so einem Feld krieg ich nie und nimmer (oder nur mit hohem Programmieraufwand) meine Kundendaten sauber wieder raus. Ja klar kann man mit PHP und einem „explode“ in ein Array und dann zeilenweise auslesen… ja hört’s mir aber auf. Das ist Pfusch, richtiger Pfusch, da beißt die Maus kein Faden ab.

So, jetzt langts aber, genug gestänkert. Wir machen uns mal an die Bestellungen, im nächsten Artikel.

 

Kleiner Nachtrag zu den Produkten: wo steckt die Artikelnummer?

Da hab ich doch glatt noch was vergessen. Wir haben ja unsere CSV-Datei inklusive der Artikelnummern eingelesen, und die Feldzuordnung beim Import ging hier auf _sku. Das Feld _sku steckt in der wp_postmeta, und hier ist auch die post_id hinterlegt, die regelt zu welchem Produkt die betreffende Artikelnummer gehört.

Aber was ist, wenn man ein Produkt manuell eingibt – wo kommt da die Artikelnummer hin? Davon ist nämlich erst mal weit und breit nichts zu sehen.

Des Rätsels Lösung: man muß beim neu Eingeben eines Produkts den Reiter „Lager“ aktivieren, dann kann man eine Artikelnummer eingeben.

lager_sku

lager_sku

Falls sie übrigens in Versuchung kommen sollten, die Lagerverwaltung hier tatsächlich wooCommerce anzuvertrauen: tun sie’s nicht. Für sowas gibts professionelle ERP-Software (auch als Shareware), damit sind sie wesentlich besser bedient. Das aber nur mal so als kleiner Tipp am Rande.

 

Schuster, bleib bei deinem Leisten: die Stärken von wooCommerce

Also, mir machen jetzt mal eine kurze Erholungspause von der Datenbankschinderei und schauen uns unseren nagelneuen Online-Shop mal genauer an. Tun Waren in den Warenkorb, schauen uns den an und bearbeiten ihn gegebenenfalls, und dann gehen wir mal zur Kasse.

Halt stopp! Da fehlt noch eine Zahlungsart

WooCommerce kommt eigentlich mit sehr funktionalen Grundeinstallungen daher, der Bestellvorgang läuft so professionell wie man ihn sich nur wünschen kann, aber zum Austesten fehlt noch (mindestens) eine Zahlungsart. Die hinterlegen wir unter wooCommerce/Einstellungen/Kasse, hier ganz nach unten scrollen. Für Testzwecke aktivieren wir hier mal nur die Scheckzahlung und hinterlegen unsere Firmenadresse, das sieht so aus:

scheckzahlung

scheckzahlung

Mehr brauchts nicht, jetzt können wir Einkaufen gehen.

Der Einkaufs- und Bestellvorgang

Da muß ich nicht groß ausholen und erklären, das ist alles absolut professionell und funktioniert mit den Default-Einstellungen schon ganz hervorragend, Der Bestell- und Bezahlvorgang ist einleuchtend und leicht verständlich und ganz so wie man es von „grossen“ Shopsystemen gewohnt ist. Man kann den Warenkorb füllen und bearbeiten, man kann zur Kasse gehen und seine Kundendaten hinterlegen, es gibt E-Mail-Benachrichtigungen über den Bestellstatus usw usf., Ich möchte es jedem selber überlassen,  hier in die Feinheiten einzusteigen, probiert es einfach aus und schaut euch in den wooCommerce-Einstellungen mal um. Viel Spaß dabei, das ist ein sehr erfreuliches Kapitel!

Kunde hat bestellt – und nun?

Kann man die offenen Bestellungen unter wooCommerce/Bestellungen einsehen und bearbeiten. Aber was ist im Underground passiert? Wir werfen mal einen kurzen Blick auf die Datenbank. Relevant für die Bestellungen sind eigentlich nur drei Tabellen, die wp_woocommerce_order_itemmetaVerstecken und dieAuf-/ZuklappenStrukturwp_woocommerce_order_items sowie die wp_posts. Ja, das habt ihr schon richtig gelesen, die Bestellungen landen ebenfalls in der wp_posts, mit dem post_type shop_order. Wir schauen uns das jetzt mal der Reihe nach an, aber dazu gönnen wir uns einen neuen Beitrag.

 

 

 

 

Noch’n Déja vu: was ist das führende System?

Das, liebes Publikum, hatten wir  schon mal, als es um die Mitgliederdaten des Turnvereins Weiß-Blau ging – erinnert sich noch jemand? Man kann Massendaten per CSV-Upload in WordPress reinjagen, aber man muß vorher ganz klar entscheiden, was das führende System ist. Das ist jetzt noch nicht mal WordPress-spezifisch, diese Überlegung muß man immer wieder anstellen, wenn es um die elektronische Verarbeitung von Betriebsdaten geht. Dabei stellen sich immer wieder die folgenden Fragen:

  1. Was passiert, wenn nach dem ersten Load noch Datensätze dazukommen?
  2. Was passiert, wenn sich an den Stammdaten mal etwas ändert?
  3. Aus welchem System fährt man betriebliche Auswertungen und Statistiken?

Wir gehen es mal der Reihe nach durch und klopfen ab, ob sich wooCommerce als führendes System für unsere Artikelstammdaten eignet.

Hinzufügen von Datensätzen:

Wenn es wirklich nur einzelne Datensätze sind, kann man die tatsächlich per Hand einpflegen, das heißt in unserem Fall: vereinzelt dazukommende neue Artikel werden manuell in wooCommerce angelegt. Stammdaten einpflegen, Bild hochladen, fertig.
Sobald es aber mehr als sagen wir mal ein halbes Dutzend neue Datensätze pro Monat sind, ist das zu viel Aufwand und eben auch fehlerträchtig. Dann braucht man einen selektiven CSV-Upload, der die bereits existierenden Bestandsdaten unberührt läßt und nur die neu hinzugekommenen Artikel neu anlegt. Ob das funktioniert, muß man vorher abklären, ehe man sich für ein CSV-Upload-Plugin entscheidet.

Stammdaten Pflege:

Hier sieht es ähnlich aus wie oben, das kommt darauf an wieviele Änderungen man zu machen hat. Vereinzelte Datensätze kann man per Hand editieren, bei Massenänderungen an den Bestandsdaten geht man doch lieber an die Datenbank.

Ich nenne mal ein einfaches Beispiel für eine typische Massenänderung: nehmen wir mal an, die nickelfreien Ohrringhaken sind im Einkauf 20 % teurer geworden, und ich möchte in der Folge die Preise für alle Ohrringe in meinem Sortiment etwas anheben, sagen wir mal um pauschal 5 %. Das geht bei drei, vier Ohrringen in meinem Onlineshop noch per Hand, sobald das allerdings mehr werden ist eine manuelle Änderung nicht mehr zumutbar.

Was tut der EDV-Fuzzy in so einem Fall? Ja klar, wir fahren einen Update auf der Datenbank! Der SQL auf einer Produkt-Stammdaten-Tabelle sieht so oder ähnlich aus:

update products set products_price=products_price*1.05 where products_category like „Ohrringe“;

Wenn’s denn so einfach wäre! Ich erinnere mal kurz an den letzten Artikel: um allein an die Produktkategorie eines Artikels heranzukommen, brauche ich einen Join über mindestens 4 Tabellen, der sah so aus:

(„SELECT Wp_term_relationships.*,Wp_terms.* FROM Wp_term_relationship
LEFT JOIN Wp_posts  ON Wp_term_relationships.object_id = Wp_posts.ID
LEFT JOIN Wp_term_taxonomy ON Wp_term_taxonomy.term_taxonomy_id = Wp_term_relationships.term_taxonomy_id
LEFT JOIN Wp_terms ON Wp_terms.term_id = Wp_term_relationships.term_taxonomy_id
WHERE post_type = ‚product‘ AND taxonomy = ‚product_cat‘
AND  object_id = „.$aktuelleID.““)

Und das ist erst der Select für die Kategorie zu einem einzelnen Artikel. Einen Update auf den _regular_price aus der wp_postmeta (noch ein Join mehr) mit einer Where-Klausel wie „where wp_terms.name like „Ohrringe““ kann sich jeder selber daraus basteln.

Das, liebe alte Datenbankfüchse, ist zwar interessantes SQL, aber in der realen Anwendung eine Zumutung!

Betriebliche Auswertungen und Statistiken oder: was zum Donner ist denn nun unser führendes System?

Die Artikelliste ist mein führendes System. Ich meine diese hier:

artikelliste_excel

artikelliste_excel

Mir ist es nämlich echt zu mühselig, statistische Auswertungen meiner Stammdaten über die WordPress/wooCommerce-Tabellen zu fahren. Mein Kunde möchte zum Beispiel wissen, wieviele Ketten und Colliers über 15 € er im Sortiment hat. Oder auch nur die Anzahlen der Artikel zu den einzelnen Kategorien, oder so etwas in der Richtung. Das macht man im Zweifelsfall im Excel mit den entsprechenden Filtern, das ist ratzfatz erledigt. Über die WordPress-Datenbank geht es nur mit solchen akrobatischen Verrenkungen und Joins über mehrere Tabellen wie gerade eben gezeigt, das ist mir einfach zu umständlich.

Wie sieht das in der Praxis aus?

Stammdatenänderungen müßten dann ausschließlich in der Excel-Tabelle passieren, aber vielleicht laden wir sie ja in Access, dann gehen solche Sonderwünsche wie ein seleketiver Update auf den Preis in ein paar Minuten. Export nach CSV, selektiver Upload – da müßte man dann die Option haben, bestehende Datensätze zu aktualisieren, aber das bieten die meisten Import-Plugins schon an. WooCommerce wäre dann ganz klar das sekundäre System, und da gehört es auch hin, wenn sie mich fragen. Für eine Bestandsführung mit allem was dazugehört ist es nämlich schlicht nicht geeignet. Meine Meinung, und natürlich subjektiv aus der Sicht einer alten Datenbankerin.

Aber ich will wooCommerce nicht in Bausch und Bogen verdammen, es ist nämlich schon ein intelligenter Online-Shop und hat noch etliche interessante Features zu bieten. Dazu mehr im nächsten Artikel.

 

Kraut und Rüben auf der Datenbank: wo wooCommerce die Produktdaten speichert

Ein Produkt = Beitrag: ja, und der Rest?

Wie ihnen bei einem kurzen Blick auf die Datenbank vielleicht schon aufgefallen ist, speichert wooCommerce die Produkte in der wp_posts mit dem post_type „product“. Das kennen wir ja schon, die wp_posts muß oft für allerlei Datengemusel herhalten, das mit „posts“, also mit Beiträgen, nicht im entferntesten was zu tun hat.Die Produktbilder landen übrigens auch in der wp_posts, aber das kennen wir ja auch schon, WordPress macht das halt mit Bildern so, mit dem post_type „attachment“.

Über Sinn und Unsinn dieser Praxis kann man lange diskutieren, es wird halt oft so gemacht und sogar als Best Practice empfohlen. Und da wir uns für wooCommerce als Shopsoftware entschieden haben, leben wir halt damit. Ich mach das hier mal nur im Schnelldurchgang, die Details kann ja jeder selber nachschauen.

Kleine Wiederholung: unsere Produktdaten

  1. Feld in der CSV-Datei:
    Artikelnummer;Kategorie;Bezeichnung;Beschreibung;Format;Preis
  2. Feld in der Dropdown-Liste:
    sku; category; post_title; post_content; post_excerpt; regular_price

Die fett markierten Felder stecken in der wp_posts unter den bekannten Feldnamen. Aber wo sind die anderen? Gehen wir’s mal der Reihe nach durch.

  1. Artikelnummer: sku
    Die sku ist in der wp_postmeta abgespeichert, unter dem meta_key _sku. Wir filtern uns die mal im phpmyadmin raus:

    _sku

    _sku

    Zur Erinnerung: in der post_meta ist über die post_id zugeordnet, zu welchem Beitrag der meta_key gehört.

  2. Preis = _regular_price
    Auch der steckt in der wp_postmeta, eben unter dem meta_key _regular_price.
  3. Kategorie = category
    Obacht! Das sind von wooCommerce eigens angelegte Produktkategorien, nicht die altbekannten Beitragskategorien von WordPress. Und hier wirds jetzt richtig lustig, die zugehörigen Daten sind nämlich über die vier Terms-Tabellen verteilt. Um herauszufinden, welche Produktkategorie zu einem Produkt gehören, muß man einen Join über mindestens drei Tabellen fahren, da sieht dann der Select ungefähr so aus:

    („SELECT Wp_term_relationships.*,Wp_terms.* FROM Wp_term_relationships

                LEFT JOIN Wp_posts  ON Wp_term_relationships.object_id = Wp_posts.ID

                LEFT JOIN Wp_term_taxonomy ON Wp_term_taxonomy.term_taxonomy_id = Wp_term_relationships.term_taxonomy_id

                LEFT JOIN Wp_terms ON Wp_terms.term_id = Wp_term_relationships.term_taxonomy_id

                WHERE post_type = ‚product‘ AND taxonomy = ‚product_cat‘

                AND  object_id = „.$aktuelleID.““)

    Und das finde ich jetzt schon weniger lustig.

Und wenn ich mal alle relevanten Daten zu meinen Produkten brauche?

Ja, dann fahren wir halt einen Join über die wp_posts, die wp_postmeta und die bekannten Terms-Tabellen. Das wird dann so richtig übersichtlich. Darf ich bei dieser Gelegenheit mal daran erinnern, wie unsere Artikelliste ursprünglich mal aussah:

artikelliste_excel

artikelliste_excel

Ach, was war das noch schön einfach und übersichtlich! Ganz ehrlich, ich finde es schon ziemlich hanebüchen, welche Bauchaufzüge man machen muß um wooCommerce die eingegebenen Produktdaten auf Datenbankebene wieder zu entlocken.

Da kommt jetzt natürlich die berechtigte Frage: wer braucht das schon? Reicht doch, wenn wir die Produkt-Daten per CSV reinjagen und in wooCommerce verwalten. Das, liebes Publikum, ist eine extra Diskussion wert. In einem neuen Artikel.

Déja vu im Online-Shop: wollen wir das wirklich alles per Hand eingeben?

… natürlich nicht. Wie sie wahrscheinlich beim Erstellen der Test-Produkte gemerkt haben, hält das Prozedere ganz schön auf, und mehr als eine Handvoll Produkte per Hand in unseren nagelneuen Online-Shop einzupflegen ist eigentlich in der Praxis nicht zumutbar. Das dauert viel zu lang und ist auch ungeheuer fehleranfällig, das kann man keinem Kunden zumuten. Aber keine Bange, es ist Abhilfe in Sicht.

Produktliste – haben wir sehr wahrscheinlich schon

In jeder noch so kleinen Klitsche gibt es in irgendeiner Form eine Liste der Produkte für den Verkauf, dafür lege ich meine Hand ins Feuer. Das kann ein Word- oder Excel-Dokument sein, oder (im Idealfall) vielleicht sogar ein kleines Datenbankerl mit OpenOffice oder Access.

Jedenfalls haben wir mit an Sicherheit grenzender Wahrscheinlichkeit schon eine Liste unserer Verkaufsprodukte, und wahrscheinlich haben wir sogar schon einen Primärschlüssel, nämlich eine eindeutige Artikelnummer. In meinem Schmuckladen gibt es die allerdings tatsächlich nicht, da sind die Produkte nur über den (hoffentlich einmaligen) Namen eindeutig identifizierbar. Aber im Normalfall haben wir einen eindeutigen Identifikator, das kann eine EAN sein, oder eine fortlaufende Nummer, oder eine Kombination aus Zahlen und Buchstaben.

Liste? CSV, Import!

Genau! Wenn wir schon eine Produktliste haben, die wollen wir doch dem wooCommerce direkt einfüttern und uns einen Haufen Handarbeit sparen. Also dann, frisch ans Werk! Ich hab mir mal eine kleine Produktliste in Excel erstellt, die sieht so aus:

artikelliste_excel

artikelliste_excel

Wie kriegen wir die jetzt ins wooCommerce? Genau! Dafür gibt es Plugins! Zum Beispiel den

Woocommerce CSV importer v

Den installieren wir uns, und dann wird ausprobiert. Ich mach hier mal kurzen Prozess und beschreibe kurz, wie der Importer funktioniert.

  1. Man erstellt eine Header-Datei, das ist nichts anderes als ein CSV, das als einzige Zeile die Feldnamen mit Trennzeichen enthält. Das sieht so aus:

    header

    header

  2. Man erstellt sich die dazu passende Artikelliste als CSV

    schmuck_csv

    schmuck_csv

  3. Man wählt in den CSV Import Settings das richtige Trennzeichen (field seperator), wir haben ein „;“ (Semikolon)

Und dann kanns losgehen. Header laden, Feldzuordungen vornehmen, CSV-Artikelliste laden… aber mal langsam mit den jungen Pferden.

Die Feldzuordnungen beim CSV-Import: bin ich Hellseher?

Man kriegt hier in einer hübschen Dropdown-Liste die Feldnamen in WordPress/wooCommerce angezeigt, und kann hier entsprechen die Zuordnungen vornehmen. Dazu muß man alllerdings wissen, welches Feld in der Dropdownliste welchem Feld in der Artikelliste in unserer CSV-Datei entspricht.

header_feldzuordnung

header_feldzuordnung

Geht schon ganz oben los: das Feld „sku“ ist für die Artikelnummer vorgesehen, aber das muß man erstmal wissen. Jetzt wäre es halt verdammt nützlich, wenn man wüßte wie wooCommerce was in der Datenbank abspeichert, und das ist leider nicht unbedingt selbsterklärend. Das ist sogar ein kleiner Trip ins Datenchaos, aber dazu gibt es dann später einen neuen Beitrag.

Ich sag hier nur mal kurz, wie man unsere paar Import-Felder sinnvoll zuordnet. Die Logik ist wie folgt:

  1. Feld in der CSV-Datei:
    Artikelnummer;Kategorie;Bezeichnung;Beschreibung;Format;Preis
  2. Feld in der Dropdown-Liste:
    sku; category; post_title; post_content; post_excerpt; regular_price

Alles klar? Damit dürfte dem erfolgreichen Import nichts mehr im Wege stehen. Man bekommt sehr schön eine Preview angezeigt, und wenn die hinhaut, können wir die CSV-Datei laden.

import_preview

import_preview

Presto! Unsere neuen Artikel sind drin und auch gleich im Shop zu sehen.

neue_artikel

neue_artikel

Allerdings ohne Bilder. Und mit Duplikaten, weil es manche Artikel vorher schon gab, per Hand eingeklopft. Aber wer wird denn da kniefieselig sein? Ich schon. Die Duplikate kann man noch per Hand löschen, das waren nicht so viele. Und was ist mit den Bildern?

Plugins für den Bilder-Import: kosten Kohle

Es gibt unzählige Import-Plugins für wooCommerce, viele davon OpenSource und kostenlos. Ich hab allerdings noch kein freies Plugin gefunden, das auch Produktbilder importieren kann, und ich kaufe prinzipiell keine kostenpflichtigen Plugins. Sorry Freunde, aber hier ist das Ende der Fahnenstange.

Aber jetzt wirds Zeit uns mal drum zu kümmern, was wooCommerce auf der Datenbank macht, und dazu gibt es einen neuen Artikel.