Archiv der Kategorie: WordPress

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.

 

 

 

Wir basteln uns einen kleinen Schmuckladen

Da ich mit konkreten Beispielen immer am Besten arbeite, basteln wir uns jetzt einen kleinen Online-Shop für meinen Glasperlenschmuck. Da haben wir übersichtliche Produktdaten und eine hübsche Fotoauswahl. Ich habe das Theme Twentysixteen genommen und mir gleich mal ein Child Theme erstellt, das brauchen wir bestimmt noch. Jetzt noch schnell wooCommerce installiert, und es kann losgehen.

Der erste Eindruck: sie sehen, daß sie nichts sehen

Woo legt uns ein paar neue Seiten an (näheres später) und stellt uns den Shop als Startseite ein. Da wir noch keine Waren in unserem Shop haben, sieht das Ganze erstmal ziemlich leer aus.

shop_leer

shop_leer

Ein kurzer Blick auf die Datenbank

Ach du liebes Lieschen, wie sieht dann das aus! Woo hat sage und schreibe 14 neue Tabellen erstellt!

woo_tabellen

woo_tabellen

Immer mit der Ruhe, die nehmen wir uns der Reihe nach vor, wie wir sie brauchen. Und ich kann ihnen gleich zur Beruhigung sagen: die meisten davon brauchen wir erstmal noch gar nicht. Ein wenig Geduld, wir machen schon noch ein bißchen Spaß auf der Datenbank. Jetzt füllen wir erstmal unseren Shop mit Leben.

Produkte hinzufügen

Woo beschert uns zwei neue Menüpunkte im Dashboard, „WooCommerce“ und „Produkte“.

woo_menus

woo_menus

Wir nehmen eine Abkürzung und gehen gleich mal auf „Produkt hinzufügen“, alles andere später. Der Produkteditor ist recht übersichtlich, das ist nix anderes als eine Variante des gewohnten Beitragseditors. Wir fügen jetzt mal ein paar Produkte hinzu, damit unser Shop lebendiger wird. Wir haben pro Produkt fünf Attribute, die wir in unseren Shop einpflegen wollen:

  • den Produktnamen
  • die Kategorie
  • die Beschreibung
  • Angaben zur Größe
  • den Preis

Das Produktfoto muß auch noch rein, aber das wars. Ich verteile meine Produktdaten wie folgt:

  1. Produktname in den Titel
  2. Beschreibung in den Text
  3. Preis in das Feld „regulärer Preis“

Und dann noch die Größenangabe… tscha, und da hakts schon zum ersten mal. Sollen wir dafür ein Benutzerdefiniertes Feld anlegen? Lieber nicht. Weiter unten gibt es noch ein Textfeld „Produkt Kurzbeschreibung“, das nehmen wir, das sieht freundlich aus.

produkt_kurzbeschreibung

produkt_kurzbeschreibung

Für die Produktkategorien gibt es rechts ein „Produktkategorien“-Untermenü, das nehmen wir natürlich auch gleich noch mit. Ich trage mal gleich ein paar Kategorien ein, die werden wir ja später noch brauchen… aber Obacht! Nichts verwechseln, das sind jetzt woo-eigene Kategorien, die nichts mit den gewohnten Beitragskategorien zu tun haben. Da lauert Verwechslungsgefahr, das muß man unterscheiden. Aber ich trag mal trotzdem hier was ein:

produkt_kategorien

produkt_kategorien

So, fehlt noch das Foto, das kommt rechts bei „Produktbild“ rein, die Produktgalerie lassen wir jetzt noch aussen vor. Alles drin? Dann werfen wir jetzt mal einen Blick auf unseren Shop.

Shop mit einem Produkt

Das sieht doch schon mal ganz nett aus.ein_produkt

ein_produkt

Wenn man auf das Produktbild draufklickt, kommt man in die Einzelansicht, hier werden auch die restlichen Daten zum Produkt angezeigt, und hier kann man das Produkt in gewünschter Stückzahl in den Warenkorb packen, oder auch eine Produktbewertung abgeben.

einzelansicht

einzelansicht

Momentchen noch: in meinem Schmuckladen gibt es nur Unikate, das heißt jedes Produkt ist genau einmal vorhanden. Da dürfte beim Warenkorb genau genommen keine Stückzahl > 1 angegeben werden – aber ja, ich hörs schon, sie haben recht, das sind Feinheiten, um die kümmern wir uns später.

Das reicht uns jetzt mal fürs erste, geben sie mal zwei, drei Produkte ein, und wenn sie das haben gehts weiter. In einem neuen Beitrag.

 

 

 

 

Das bekannteste eCommerce-Plugin: wooCommerce unter der Lupe

Warum WooCommerce so beliebt ist

Wer einen Online-Shop mit WordPress betreiben will, wird sich in den meisten Fällen erstmal für wooCommerce entscheiden. Erstens ist es kostenlos und trotzdem praxistauglich, zweitens reich an Features und nahezu unbegrenzt erweiterbar, und drittens gibt es hervorragenden (ebenfalls kostenlosen) Support dafür. Mit bis dato ca. 15 Millionen Downloads (schlag nach bei Wiki) eine echte OpenSource-Perle – möchte man meinen. Ich hab dazu eine eigene Meinung. Wir werden uns im Folgenden aus der zugegeben nicht unparteiischen Sicht einer alten Datenbankerin näher mit WooCommerce befassen, und ich denke ich werde im Verlauf dieses neuen Themas schon ein bißchen klar machen können, wo es meiner Meinung nach hakt.

WooCommerce: Pfusch auf der Datenbank?

Ja. Zwar auf sehr hohem Niveau, aber Pfusch bleibt Pfusch. WooCommerce klemmt sich nunmal ins enge, überalterte Datenkorsett von Madame WordPress, und da gibt es abenteuerliche Konstrukte – aber dazu später mehr. Seid ihr bereit für eine Achterbahnfahrt auf der Datenbank? Dann mal los, zieht euch eine neue WordPress-Instanz auf und installiert euch WooCommerce zum Testen, da ist nichts weiter dabei. Morgen gehts dann los – ich habe euch wieder ein bißchen Spaß auf Datenbank versprochen, aber ich kann nicht garantieren daß es nicht an manchen Stellen zur Kuriositätensammlung mutiert…

WordPress als führendes System für die Mitgliederverwaltung? Ein Fazit

Ich habe mich jetzt in etlichen Beiträgen mit dem CSV-Import eigener Daten für eine Mitgliederverwaltung in WordPress herumgeschlagen, da wird es Zeit, ein Resumee zu ziehen.

Ist die Lösung mit dem CSV-Import praxistauglich?

Zur Erinnerung: ich habe mich dafür entschieden, immer die komplette CSV-Datei zu importieren, und einen Select vorzuschalten, der bereits vorhandene Datensätze (kenntlich an der eindeutigen ID/Mitgliedsnummer) unberührt stehenläßt.

Das kann man wirklich so machen, da im WordPress-Beitragseditor vorgenommene Änderungen an Mitgliederdaten so erhalten bleiben. Man muß halt nur konsequent sein, und eventuelle Änderungen von Adress- oder sonstigen Daten wirklich in WordPress einpflegen und nicht in der Excel-Liste, die ja nach wie vor weitergeführt wird.

Was nicht so schön ist: die Vergabe einer neuen Mitgliedsnummer muß in der Excel-Liste manuell erfolgen. Man könnte zwar auf die Idee kommen, die beim Anlegen eines Beitrags erzeugte WordPress-ID aus der Tabelle wp_posts als Mitgliedsnummer zu verwenden. Aber das ist ziemlich unbefriedigend, weil WordPress ja allen möglichen Ruß in der wp_posts speichert, Bilder und andere Attachments und Seiten und und und….

In der Praxis wird man hier früher oder später von der Excel-Liste auf eine separate Datenbanktabelle umstellen, sei es nun MySQL oder Access oder was auch immer. Hier hat man die Möglichkeit, die neue ID für ein neues Vereinsmitglied per AutoIncrement automatisch erzeugen zu lassen, das schließt Fehler bei der Vergabe einer neuen ID effektiv aus, und man kann seinen Nummernkreis selbst bestimmen.

Ja aber – wenn wirs schon in einer Datenbanktabelle haben…

Genau! Meine Rede! Wir entscheiden uns für eine MySQL-Lösung, und dann gehen wir weit, weit zurück und erinnern uns, was ich in etlichen Beiträgen vor langer Zeit über die Einbindung eigener Tabellen in WordPress erzählt habe. Es ist relativ einfach zu realisieren, die Datenpflege kann über unseren selbstgeschriebenen Datenbankeditor sehr komfortabel erfolgen, es kann in der eigenen Tabelle sehr gezielt nach den unterschiedlichsten Kriterien gesucht werden, um nur einige Pluspunkte zu nennen. Das bringt mich auf was, das ich beinahe vergessen hätte:

Benutzerdefinierte Felder sind importiert, und nun?

Wir können sie auch relativ problemlos anzeigen, aber was ist, wenn ich mal eine gezielte Suchauswertung über mehrere Custom Fields fahren will? Zum Beispiel alle Mitglieder herausfinden, die in München wohnen, männlich sind und an Fußball interessiert.

Da hakts nämlich kräftig. WordPress bietet so ad hoc keine Möglichkeit dafür. Ja ich hörs schon, es gibt Plugins die einem da behilflich sind und eine gezielte Suche nach benutzerdefinierten Feldern ermöglichen, aber wie sieht das Ergebnis aus? Krieg ich halt die Ergebnisse meiner Suche auf einer WordPress-Seite als HTML angezeigt.Na prima.

Und was ist wenn ich das weiterverarbeiten will, z.B. für eine gezielte Mailing-Aktion an alle meine Münchner Fußballmänner? Da muss ich schon auf die Datenbank.

Nochmal langsam zum Nachvollziehen: für jedes Custom Field ein Join

Zur Erinnerung, meine benutzerdefinierten Felder stecken in der wp_postmeta und sind dort über die post_id den Datensätzen in der wp_posts zugeordnet. Das Feld für den Ort hat den meta_key „ort“ und als meta_value den entsprechenden Eintrag, z.B. München. Um jetzt alle Datensätze herauszufischen, die in der wp_postmeta beim meta_key einen Ort haben, muß ich die Tabellen über die post_id joinen, das sieht dann in etwa so aus:

SELECT wp_postmeta.meta_id, wp_postmeta.post_id, wp_postmeta.meta_key, wp_postmeta.meta_value, wp_posts.post_title, wp_posts.post_content, wp_posts.post_status
FROM wp_posts INNER JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id
WHERE (((wp_postmeta.meta_key) Like „ort“) AND ((wp_posts.post_status) Like „publish“));

Ganz schön viel Holz für ein einzelnes Feld, nicht wahr? Wenn ich jetzt zusätzlich noch ein zweites Feld, z.B. die Postleitzahl, mit dazuhaben möchte, muß ich tatsächlich die Tabellen ein zweites Mal  joinen und die where-Klausel nochmal stellen mit wp_postmeta.meta_key) Like „plz“, das sieht dann schon so aus:

SELECT wp_postmeta.meta_id, wp_postmeta.post_id, wp_postmeta.meta_key, wp_postmeta.meta_value, wp_posts.post_title, wp_posts.post_content, wp_posts.post_status, wp_postmeta_1.meta_key, wp_postmeta_1.meta_value
FROM wp_postmeta AS wp_postmeta_1 INNER JOIN (wp_posts INNER JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id) ON wp_postmeta_1.post_id = wp_posts.ID
WHERE (((wp_postmeta.meta_key) Like „ort“) AND ((wp_posts.post_status) Like „publish“) AND ((wp_postmeta_1.meta_key) Like „plz“));

Das, liebe Freunde, gefällt mir überhaupt nicht. Auf meiner eigenen Datenbanktabelle würde der Select nämlich ungefähr so aussehen:

Select ID, vorname, nachname, ort, plz from meine_tabelle

Fertig. Ist irgendwie hübscher, nicht wahr?

Mein Fazit

Mir ist für so etwas die simple MySQL-Abfrage auf der eigenen Datenbanktabelle -zigfach sympathischer als der mühsame mehrfache Join von wp_posts und wp_postmeta. Das ist meine persönliche Präferenz als alte Datenbankerin.

Und mein Fazit lautet: Ich würde meinem Kunden auf jeden Fall die Lösung mit der eigenen Datenbanktabelle als die wesentlich flexiblere und übersichtlichere Methode nahelegen. Aber wie gesagt, ich bin da vorbelastet, ich lieeebe Datenbanklösungen und spiele gern mit MySQL. Am Ende muß jeder selber entscheiden, was ihm bzw. seinem Kunden besser taugt.

Ich lass es jetzt mal gut sein und überlege mir ein neues Thema für etwas praktischen Spaß auf der Datenbank. Stay tuned!

Nachtrag zu Evis CSV-Importer

Euer Wunsch ist mir Befehl

Ich bin gebeten worden, die Mechanik wie man abfragt ob ein Datensatz beim Import schon vorhanden ist, doch noch mal näher zu erläutern. Also, eigentlich ist die Sache ganz einfach. Wir haben ja die Konvention, daß der Beitragstitel für einen Mitgliedsbeitrag immer mit der eindeutigen ID (mnr) beginnt, danach folgt ein Leerzeichen, danach Vorname, Leerzeichen, Nachname. Da die ID eindeutig ist, reicht es völlig aus auf einen Substring zu prüfen. der Select sieht im einfachsten Fall so aus:

$schon_da = $wpdb->get_results( "SELECT * from wp_posts 
                where post_status like 'publish'
                and SUBSTRING_INDEX( post_title,' ',1) like ".$arr_akt_zeile[0]."");

Der SUBSTRING_INDEX() holt uns alle Zeichen des Post Title vor dem ersten Leerzeichen, und das vergleichen wir mit der aktuellen Mitgliedsnummer, die im Array $arr_akt_zeile[0] steckt. Den post status checken wir noch ab, und das wars schon!

Man kann dann bequem die Anzahl der zurückgegebenen Datensätze mit num_rows abholen:

$anzahl_gefunden = $wpdb->num_rows;

Dann packt man den ganzen Programmabschnitt zur Anlage des neuen Datensatz in eine If-Abfrage, die nur ausgeführt wird wenn noch kein Datensatz mit der aktuellen ID vorhanden ist. Ich hänge mal noch eine Debug-Ausgabe in den else-Zweig, aber das reicht jetzt wirklich.

if ($anzahl_gefunden == 0) {

... neuen Beitrag anlegen und benutzerdefinierte Felder füllen...

} else {
        
        echo "Datensatz mit der ID ".$arr_akt_zeile[0]." Ist bereits vorhanden <br>";
        
    }

 

Nützlicher Helfer: Bulk Delete

Wahrscheinlich gehts euch wie mir, beim Testen hab ich -zig Beiträge neu angelegt, und die in WordPress oder im phpmyadmin einzeln wieder rauszuloschen, ist ein mühselig Spiel.Nein, da kann man lange suchen, es gibt im WordPress-Beitragseditor keine Möglichkeit „Alle Beiträge“ zu selektieren.

Dafür gibts ein praktisches Plugin: Bulk Delete erlaubt die selektive Löschung von Beiträgen etc. en masse, das kann man hier ganz gut gebrauchen. Schauts euch mal an, ist immer wieder mal nützlich!

 

 

Evis CSV-Importer die Zweite: ein Beitrag pro Mitglied

Die Vorgabe wie gehabt

Für jedes Mitglied wird ein Beitrag in WordPress angelegt. Der Beitragstitel besteht aus der ID (Mitgliedsnummer), dem Vornamen und dem Nachnamen, das ganze mit Leerzeichen getrennt. Die restlichen Mitgliedsdaten kommen in benutzerdefinierte Felder. Soweit alles klar? dann wollen wir mal.

Zeilenweise Verarbeitung der CSV-Datei

Unsere CSV-Datei haben wir zeilenweise eingelesen, wir arbeiten sie jetzt innerhalb der while (!feof)-Schleife bis zum Dateiende ab. Nur mal kurz zum Rekapitulieren, die Debug-Ausgabe sollte in etwa so aussehen:

csv_debugausgabe

csv_debugausgabe

Wir haben pro Mitglied (=pro Zeile) 9 Datenfelder jeweils in ein Array eingelesen, die holen wir uns mit dem Index 0..8, das sah für die Debug-Ausgabe so aus:

//Debug-Ausgabe des Arrays
 echo $arr_akt_zeile[0]."<br>";
 echo $arr_akt_zeile[1]."<br>";
 echo $arr_akt_zeile[2]."<br>";
 echo $arr_akt_zeile[3]."<br>";
 echo $arr_akt_zeile[4]."<br>";
 echo $arr_akt_zeile[5]."<br>";
 echo $arr_akt_zeile[6]."<br>";
 echo $arr_akt_zeile[7]."<br>";
 echo $arr_akt_zeile[8]."<br><br>";

Jetzt müssen wir nur noch die Feldnamen für die einzelnen Datenfelder zuordnen, dann können wir. Ich mach da mal eine einfache Liste:

0 mnr
1 vorname
2 nachname
3 geschlecht
4 email
5 plz
6 ort
7 strassehausnummer
8 telefon

Alles paletti? Jetzt bauen wir uns für jede Input-Zeile einen neuen Beitrag.

Die Funktion wp_insert_post() ganz minimalistisch

Welche Parameter man der Funktion zum Erzeugen eines neuen Beitrags alle mitgeben, kann jeder selber im Codex nachlesen. Wir begnügen uns hier mit ganz wenigen Feldern:

  1. Titel: Mitgliedsnummer, Vorname und Name, mit Leerzeichen getrennt
  2. Content: ich geb hier einfach die Mitgliedsnummer nochmal aus
  3. Status publish
  4. Author, 1 ist mein Admin:
// Beitragsobjekt anlegen
    $my_post = array();
    $my_post['post_title']    = $arr_akt_zeile[0]." ".$arr_akt_zeile[1]." ".$arr_akt_zeile[2];
    $my_post['post_content']  = "Mitgliedsnummer: ".$arr_akt_zeile[0];
    $my_post['post_status']   = 'publish';
    $my_post['post_author']   = 1;

    // Beitrag in Datenbank einfügen
    $neue_id = wp_insert_post( $my_post );

Wichtig: mit der letzten Anweisung $neue_id=… holen wir uns den Rückgabewert der Funktion wp_insert_post, das ist die WordPress-ID des neuen Beitrags. Die brauchen wir nämlich gleich noch für die beutzerdefinierten Felder. Aber jetzt lassen wir die ganze Sache einfach mal laufen, und wenn alles paßt, sollte unser CSV-Importer-Plugin jetzt brav 10 neue Beiträge anlegen:

zehn_neue_beiträge

zehn_neue_beiträge

Hinweis: sollte ein Beitrag mehr als erwartet (ohne Titel) angelegt werden, ist am Ende der CSV-Datei ein CR/LF zuviel, das erzeugt eine leere Zeile. Im Notepad++ rauslöschen, dann paßts.

Wir befüllen jetzt noch die benutzerdefinierten Felder

Dazu benutzen wir die Funktion add_post_meta(), die sieht minimalistisch abgespeckt so aus:

add_post_meta( $post_id, $meta_key, $meta_value)

Dabei ist zu beachten, daß man über die $post_id die WordPress-ID des aktuellen Beitrags mitgeben muß. Aber die haben wir uns ja weiter oben schon geholt, die steckt in der Variablen $neue_id. Also, wir fügen jetzt mal nur zwei Felder zum Testen ein:

//*** Benutzerdefinierte Felder füllen
    
    //Postleitzahl
    add_post_meta( $neue_id,'plz', $arr_akt_zeile[5]);
    
    //Ort
    add_post_meta( $neue_id,'ort', $arr_akt_zeile[6]);
    
    //*** Ende Benutzerdefinierte Felder füllen

Wenn man den Import jetzt nochmal laufen läßt und in einen der neu erzeugten Beiträge reinschaut, sollte man etwa Folgendes sehen:

zwei_benutzerdef_felder

zwei_benutzerdef_felder

Das wars!

Fertig ist unser hausgemachter CSV-Importer, der – man sehe und staune! – auch Custom Fields befüllen kann. Wirklich keine Hexerei, oder?

Die Anzeige der benutzerdefinierten Felder basteln wir wie gehabt in einen Shortcode oder ins Template rein und benutzen dafür die Funktion get_post_meta(), das haben wir alles schon gehabt, das muß ich jetzt nicht wirklich nochmal ausführlich beschreiben.

Ja aber, was ist jetzt mit den neuen Mitgliedern?

Das ist eine sehr berechtigte Frage. Ich stelle das Szenario nochmal kurz vor:

  1. Die existierende Excel-Liste mit Mitgliederdaten ist als CSV-Datei bereits einmal importiert worden
  2. Änderungen an den Mitglieder-Daten werden ab jetzt in WordPress durch Editieren des jeweilige Beitrags gepflegt, d.h. wir definieren WordPress als unser führendes System
  3. Was geschieht jetzt, wenn neue Mitglieder nach dem ersten Import hinzukommen?

Wie bereits mal kurz erwähnt könnte man jetzt für jedes neue Mitglied manuell einen neuen Beitrag mit ID und Name im Titel anlegen, und auch die benötigten benutzerdefinierten Felder manuell nachziehen. Das gefällt mir allerdings überhaupt nicht, weil es 1. viel Handarbeit und 2. sehr fehleranfällig ist. Deswegen entscheide ich mich für eine

Hybrid-Lösung:

  1. Die alte Excel-Liste wird weiter gepflegt, die Mitgliedsnummern werden fortlaufend weiter vergeben.
  2. Wenn genügend neue Mitglieder hinzugekommen sind (z.B. zum Monatsende) wird die Excel-Liste neu importiert, und zwar ganz.
  3. Ich ergänze das Import-Plugin um einen Select, der vor dem Anlegen eines neuen Beitrages abfragt, ob in der Tabelle wp_posts bereits ein Beitrag mit dem Titel nach dem Muster mnr+vorname+nachname vorhanden ist. Falls ja (if-Abfrage), wird für den aktuellen Datensatz kein neuer Beitrag angelegt, der betreffende Datensatz wird einfach übersprungen.

So stelle ich sicher, daß nur für die neu hinzugekommenen Mitglieder auch neue Beiträge angelegt werden, und daß bereits vorhandene Daten nicht überschrieben werden. Wie das mit dem Select dann praktisch aussieht, daß kann jeder selber ausprobieren, nicht vergessen global $wpdb zu deklarieren, dann klappt das schon.

 

 

Jetzt wirds mir doch zu dumm: wir basteln uns einen CSV-Importer

Kostenpflichtige Plugins – seh ich doch gar nicht ein!

Wie ich schon mehrfach gesagt habe, habe ich erstens nicht das Budget, mir zu Testzwecken kostenpflichtige Plugins zu kaufen, und zweitens bin ich eine große Anhängerin der Open-Source-Idee. Das ist ja mit der Hauptgrund, warum WordPress so erfolgreich ist, es ist Open Source und kostenlos, es gibt fantastische Supportforen, es gibt für nahezu jedes Programmierproblem eine Lösung, ohne daß man Bares dafür hinlegen muß.

Da alle CSV-Import-Plugins die ich getestet habe in den kostenfreien Versionen keinen Import von Custom Fields können und ich diese Möglichkeit aber unbedingt brauche, gehen wir jetzt einen anderen Weg:

Wir schreiben unseren eigenen CSV-Importer

Ich bleibe dabei beim Beispiel des Turnverein Weiß-Blau mit dem Mitgliederverzeichnis. Die Vorgaben bleiben gleich:

  • die Adressdaten liegen als CSV-Datei vor (Spezifikation folgt)
  • für jeden Mitgliederdatensatz soll ein eigener Beitrag angelegt werden
  • im Beitragstitel brauchen wir die Mitgliedsnummer (ID) und den Namen
  • die restlichen Adressdaten sollen in Benutzerdefinierte Felder geschrieben werden.

Alles klar soweit? Na, dann wollen wir mal!

Die Spezifikation der CSV-Datei

Ich nehme da mal was ganz Rudimentäres, das kann sich jeder selber mit Excel und im Notepad++ zurechtschnitzen. Pro Datensatz eine Zeile, Zeilenende mit CR/LF markiert, Trennzeichen ein Semikolon (;), kein Textbegrenzungszeichen. Kodierung UTF-8 ohne BOM. Wir haben zehn Datensätze:

import_notepad

import_notepad

Der Anfang: wir basteln uns ein neues Plugin

Das haben wir schon ein paar mal gemacht, das wiederhole ich nur im Schnelldurchgang. Plugin-Verzeichnis anlegen, PHP-Datei anlegen, Header richtig ausfüllen, AdminScreen anlegen:

/*
Plugin Name: Evis CSV Importer
Plugin URI: http://localhost/wordpress/wp-content/plugins/evis-csv_importer
Description: Importiert eine CSV-Datei
Version: 1.0
Author: Evi Leu
Author URI: http://www.evileu.de
*/
add_action('admin_menu', 'evisbasicPluginMenu');

function evisbasicPluginMenu() {
$appName = 'EvisCSVImporter';
$appID = 'evis-csv-importer';
add_menu_page($appName, $appName, 'administrator', $appID, 'importerpluginAdminScreen');
}

function importerpluginAdminScreen() {
    echo "<h1>Importiere CSV Datei</h1>";
}

Import starten mit Button

Zum starten des Imports brauchen wir noch einen Button, den legen wir wie schon oft gehabt mit einem kleinen Formular an, das kommt als erstes in die Funktion importerpluginAdminScreen:

//Begin Formular
echo '<form method="post">';
echo '<input type="submit" name = "starten" value="Import starten"/>'."<br>";
echo "</form>";
// End Formular

if (isset($_POST['starten'])){

...

}

Pfad und Dateiname der Import-Datei fest verdrahtet

In die if-isset-Abfrage legen wir jetzt unsere Import-Funktionalität. Natürlich wäre es schick wenn man hier die Import-Datei mit einem Datei-öffnen-Dialog auswählen könnte, aber dazu brauchts eine Runde Javascript, und das sprengt hier definitiv den Rahmen. Ich machs mir einfach: da ich immer mit der selben Import-Datei arbeite, verdrahte ich den Pfad und den Dateinamen im Code, das kann sich dann jeder selber zurechtbiegen wie er es braucht. Jedenfalls wird die CSV-Datei mit fopen() geöffnet:

//Pfad zur Import-Datei fest verdrahtet
$datei=fopen("C:/xampp/htdocs/alte_programmierer/wp-content/plugins/evis-csv-importer/nur_adressen.csv","r+");

Datei zeilenweise einlesen und Debug-Ausgabe

Dann lege ich eine While-Schleife bis zum Dateiende (feof) an und lese mit fgets() zeilenweise ein. Jede Zeile wird mit explode() am Semikolon in ein Array eingespeist, und damit man gleich mal was sieht, gebe ich dieses Array dann noch zeilenweise aus, das ist nur zum Debuggen und fliegt später wieder raus. Ja, ich hörs schon, das müßte man mit einer for…next i Schleife machen, aber ich finde es so übersichtlicher.

//Begin Importdatei zeilenweise einlesen
while(!feof($datei))
{
    $zeile = fgets($datei);
    echo $zeile."<br>";

    //aktuelle Zeile am Semikolon in Array explodieren
    $arr_akt_zeile = explode(';',$zeile);

    //Debug-Ausgabe des Arrays
    echo $arr_akt_zeile[0]."<br>";
    echo $arr_akt_zeile[1]."<br>";
    echo $arr_akt_zeile[2]."<br>";
    echo $arr_akt_zeile[3]."<br>";
    echo $arr_akt_zeile[4]."<br>";
    echo $arr_akt_zeile[5]."<br>";
    echo $arr_akt_zeile[6]."<br>";
    echo $arr_akt_zeile[7]."<br>";
    echo $arr_akt_zeile[8]."<br>";
} //Ende Importdatei zeilenweise einlesen

fclose($datei);  

Am Ende nicht vergessen mit fclose() die Importdatei wieder zu schließen.

(Zwischenbemerkung: ja, ich kenne die Funktion fgetcsv(), die ist aber ein bißchen hakelig in der Bedienung. wir nehmen lieber fgets().)

So, das wars schon mit dem zeilenweisen Import der CSV-Datei. Jetzt müssen wir die eingelesenen Daten noch entsprechend verarbeiten, aber dazu gibt es einen neuen Beitrag.

WordPress als führendes System für das Mitgliederverzeichnis: ein Anfang

Erstmal eine Hypothese

Ich habs ja sonst nicht so mit theoretischen Konstrukten, ich bin eher praktisch veranlagt. Aber der Turnverein Weiß-Blau möchte seine Mitgliederstammdaten in Zukunft mit WordPress verwalten, also an die Arbeit. Ich gehe mal davon aus, daß der Import zumindest der Adressdaten mit Custom Fields geklappt hat und unser bestehender Mitgliederstamm jetzt sauber in den WordPress-eigenen Tabellen abgelegt ist.Notfalls mit einem kostenpflichtigen Plugin, das wars uns jetzt wert.

Erstmal sehen sie: nichts.

Kurz zur Erinnerung: für jedes Mitglied gibt es einen eigenen Beitrag. Im Beitragstitel steht die Mitgliedsnummer und der Name. Im Beitragsinhalt möchten wir die Adressdaten sehen. Wieso möchten? Die haben wir doch importiert? Ja aaaber – nach dem Import sehen wir im Beitrag jetzt erst einmal – nichts. Nur wenn man im Dashboard auf „Alle Beiträge“ geht und da bei einem Beitrag „Bearbeiten“ wählt und dann ein bißchen runterscrollt, dann sieht man die Benutzerdefinierten Felder mit ihren Inhalten.

fridolin_CF

fridolin_CF

Das ist unser Editor für Bestandsdaten. Wenn sich an den Adressdaten eines Mitglieds etwas ändern sollte, suchen wir uns den entsprechenden Beitrag und gehen in den Bearbeitungsmodus, hier können wir unsere Änderungen direkt einpflegen. Kann ich damit leben, die Benutzer brauchen halt eine kurze Einweisung in den Beitragseditor und sollten auch nicht vergessen auf „Aktualisieren“ zu klicken, dann funktioniert das schon.

Und wenn es neue Mitglieder einzutragen gibt?

Natürlich könnte man einfach in WordPress einen neuen Beitrag erstellen und die Daten manuell eingeben, aber das ist dann schon ein bisschen sperriger in der Benutzerführung. Man muß nämlich die relevanten Benutzerdefinierten Felder einzeln hinzufügen, und das ist aufwendig und fehlerträchtig. Ausserdem muss man sich genau überlegen, woher man die Mitgliedsnummer nimmt, unsere so wichtige eindeutige ID. Was gibt es für Alternativen?

Man könnte die neuen Benutzer in der alten Excel-Liste eintragen, die Mitgliedsnummern fortlaufend weiterführen und einen neuen Import fahren, aber was passiert dann mit unseren Bestandsdaten? Werden die „alten“ Mitgliederdaten dann überschrieben? Was passiert mit Änderungen, die ich in den Bestandsdaten eventuell bereits gemacht habe? Wäre dann die Excel-Datei unser führendes System, und nicht WordPress? Lauter Fragen, auf die es so ad hoc keine einfachen Antworten gibt.

Noch ’ne Hypothese

Viele CSV-Import-Plugins, die ich ausprobiert habe, bieten zumindest in der Pro Edition ein Feature, mit dem man auswählen kann ob bereits bestehende Datensätze upgedated werden sollen oder nicht. Ausprobieren konnte ich das nicht, aber es scheint mir die einzig praktikable Lösung zu sein, wenn man neue Mitglieder-Datensätze nicht einzeln manuell eingeben, sondern per neuem Import hinzufügen möchte. Das würde natürlich bedeuten daß wir von unserer alten Excel-Tabelle nicht wegkommen, aber sei’s drum. Gehen wir mal davon aus, dass das funktioniert mit dem selektiven Import, und kümmern wir uns mal um das nächstliegende Problem:

Die immer noch unsichtbaren Custom Fields

Man sieht die benutzerdefinierten Felder ja nach wie vor nur im Beitragseditor, und das soll sich jetzt schnellstens ändern. Eine sehr kurze und praktische Lösung ist ein Shortcode, den wir wie gewohnt in die functions.php unseres Child-Themes setzen. Der kann zum Beispiel so aussehen:

function ms(){
    
    $aktID=get_the_id();
    $strassehsnr= get_post_meta($aktID, 'strassehausnummer', true);
    echo $strassehsnr;
        
}
add_shortcode('meinshortcode','ms');

Ich habs ein bisschen ausführlicher als unbedingt nötig hingeschrieben, aber so läßt sichs besser erklären. Die Funktion ms() macht Folgendes:

  • get_the_id() holt die WordPress-ID des aktuellen Beitrags
  • get_post_meta() holt zur aktuellen Beitrags-ID den Wert des Custom Field namens „strassehausnummer“, das „true“ am Ende bewirkt, daß eine Einzelvariable ausgegeben wird und kein Array
  • echo gibt die ganze Chose aus.

Fertig! Shortcode in einen Beitrag einsetzen, Beitrag ansehen und da steht sie, die Strasse und Hausnummer. Die anderen Custom Fields holt man sich mit genau der gleichen Mechanik, man muß halt nur den get_post_meta() mit dem korrekten Namen des Feldes füttern. Also, damit kann ich jetzt echt leben!

Verwendung im Theme

Man kann die Funktion get_post_meta() natürlich auch in einem Template nutzen, sie z.B. an geeigneter Stelle in ein Child seiner single.php einbauen, aber das ist sehr Theme-spezifisch, da muss jeder selber rumdoktern, das versuche ich zu vermeiden wo es nur geht. In der Praxis wird man sich wahrscheinlich einen benutzerdefinierten Post Type anlegen und dort die entsprechenden Ergänzungen vornehmen, aber davon laß ich hier mal die Finger, das sieht wie gesagt in jedem Theme anders aus. Mir reicht mein funktionaler Shortcode, der ist universell einsetzbar.

Ja, aber was ist jetzt mit dem Anlegen neuer Mitglieder?

Machen wir das echt im alten Excel?
Gute Frage, und ich glaube, dazu brauchts einen neuen Beitrag.

Andere Importer, zentrale Datenhaltung und Custom Fields

Noch mehr Testberichte?

Nein, da muß ich euch enttäuschen. Ich hab zwar noch eine ganze Latte anderer Import-Plugins ausprobiert, eine Auswahl davon findet ihr hier bei winningWP, aber so richtig begeistert war ich von keinem davon. Die mit den meisten Features sind nahezu beliebig kompliziert in der Bedienung und erfordern einen erheblichen Einarbeitungsaufwand, und die einfacheren Genossen können allesamt keine Benutzerdefinierten Felder (Custom Fields). Zumindestenst nicht die Free Editions, die kostenpflichtigen Pro-Ausgaben sollens dann schon können. Aber die, wie ich schonmal gesagt hatte, kommen bei mir nicht zum Einsatz – mir fehlt das nötige Kleingeld, und mir gehts auch ums Prinzip. Open Source, sie wissen schon.

Warum mir die Custom Fields so wichtig sind

Da muss ich ein bißchen ausholen. Ich (und einige Legionen anderer WordPress-Entwickler da draussen) stehe immer wieder vor der Herausforderung, bestehende Unternehmensdaten in WordPress integrieren zu müssen. Darüber habe ich mich in diesem Artikel kürzlich ausführlicher ausgelassen, das will ich jetzt nicht alles wiederholen. Bleiben wir bei einem einfachen Beispiel:

Der Turnverein Weiß-Blau mit dem Mitgliederverzeichnis

Gehen wir davon aus, daß beim Kickoff unseres WordPress-Projekts bereits Mitgliederdaten vorhanden sind, das ist schließlich der Normalfall.  Gehen wir weiter davon aus, daß diese Daten als Excel-Liste geführt werden. Auch das ist eher der Normalfall, und da kommen wir relativ simpel an unser CSV ran. Wir klemmen uns ein Import-Plugin, erzeugen uns für jeden Mitgliederdatensatz einen Beitrag in WordPress, schubsen unsere Mitgliedsnummer, den Vornamen und den Nachnamen in die Titelzeile und den Rest (Adresse, Email, Telefonnummer und sportliche Präferenzen) in den Post Content, und fertig.

Fertig? Nein, jetzt gehts erst los!

Der Kunde ist erfreut, man kann sich die Liste der Mitglieder sowohl auf der Blogseite als auch im Dashboard anschauen, man kann suchen, z.B. nach Namen oder nach Ort, man kann (im Beitragseditor) die kompletten Mitgliederdaten anschauen und auch ändern, und – halt, Stopp. Da haben wir jetzt einen ganz wichtigen Knackpunkt erwischt. Was ist zu tun, wenn sich Mitgliederdaten ändern? Jemand hat eine neue Telefonnummer oder ist umgezogen und die ganze Adresse ändert sich, jemand interessiert sich jetzt auch noch für Aerobic und möchte das eingetragen haben, oder -Gott bewahre! – es kommen nach dem CSV-Import noch neue Mitglieder dazu… was ist dann zu tun?

Die schwierige Entscheidung: was ist das führende System?

Diese Frage stellt sich bei nahezu jedem IT-Projekt, und wenn man das nicht frühzeitig entscheidet, kommt man in Teufels Küche. Ich habe da selbst in Großprojekten, an denen ganze Mannschaften von Programmierern monatelang schufteten, schon die tollsten Pleiten erlebt, nur weil nicht von Anfang an entschieden wurde, was denn nun de Facto das führende System ist. Dabei ist es im Prinzip ganz einfach. Man muß festlegen, wo die Datenpflege passiert. In der Praxis heißt das meistens, wo die Inserts von neuen Datensätzen und die Updates von bereits existierenden Bestandsdaten erfolgen. Im Regelfall wird das eine Tabelle sein, oder bei komplexeren Systemen auch mehrere verknüpfte Tabellen. Wenn man es richtig macht, implementiert man eine Logik die festlegt was zu tun ist wenn z.B. ein neues Mitglied im Turnverein hinzukommt, und sorgt programmtechnisch dafür, daß der neue Mitgliederdatensatz ordentlich angelegt wird, mit eindeutiger Mitgliedsnummer (ID) und allem Pipapo. Ebenso bei der Änderung von Daten eines bereits vorhandenen Mitglieds, da wird man im Regelfall den zu ändernden Datensatz anhand der Mitgliedsnummer identifizieren und updaten. Alles klar soweit? Und dann?

Jetzt kommts: alle anderen Systeme referenzieren auf das führende System

Sinn und Zweck der ganzen Übung ist natürlich der: man möchte Datenänderungen nur zentral an einer Stelle im System vornehmen und es nicht an -zig verschiedenen Stellen (Huhu SAP!) eintragen müssen, wenn sich irgendwo zum Beispiel eine Telefonnummer oder eine Bankverbindung ändert. Wenn die zentralen Daten an anderer Stelle in der IT-Architektur des Unternehmens gebraucht werden (Beispiele kommen gleich) greift man auf die zentrale Datenhaltung zu und saugt sich die entsprechenden Daten aktuell ab. Im Idealfall sorgt der Entwickler sogar für eine dynamische Verknüpfung, so daß bei einer Änderung in den Stammdaten die abhängigen Systeme in Echtzeit mitkriegen, daß was passiert ist.

Ganz einfache Beispiele

Der Vorstand unseres Turnvereins möchte gerne wissen, wie viele unserer Turnvereinsmitglieder sich für Aerobic interessieren. Früher ist man da in die Excel-Liste gegangen, hat einen Filter auf die Spalte „Aerobic“ gesetzt und abgezählt bei wie vielen Mitgliedern da ein „ja“ drinstand. Ein bißchen EDV zu Fuß, aber es hat funktioniert.

Oder die Pressereferentin möchte alle weiblichen Mitglieder anschreiben und nachfragen, ob Interesse an einem Mutter-Kind-Training besteht – ja echt, sowas ist der Renner in unserem Stadtteilzentrum! Wieder kommt unsere Excel-Liste zum Einsatz, wir filtern nach Geschlecht und holen uns nur die Spalten mit den Namen und Adressdaten heraus, und die Mailing-Aktion kann starten.

Sie sehen, auf was ich hinauswill? Nennt sich zentrale Datenhaltung, oder neudeutsch „Data Warehousing“. In unserem Fall, dem ganz konkreten Mitgliederverzeichnis des Turnvereins, stellt sich die zentrale Frage:

Was ist unser führendes System: WordPress oder Excel?

Wenn wir unsere Mitgliederdaten per CSV-Import schon so schön in Wordpess reinjongliert haben, möchte unser Kunde mit an Sicherheit grenzender Wahrscheinlichkeit jetzt auch weiterhin mit WordPress arbeiten. Neue Mitglieder hinzufügen, Bestandsdaten ändern, kleine Datenauswertungen (siehe oben) für den Vorstand, die Buchhaltung und sonst noch etliche Anwender fahren, das hatten wir ja gerade. Gehts, oder gehts nicht? Das kommt ganz schwer darauf an, und jetzt kommen wir endlich zu den Custom Fields. Es geht nämlich erstmal nicht.

Text ist Text, da beißt die Maus keinen Faden ab

So wie die meisten CSV-Importer (zumindest die Free Editions) funktionieren, landen unsere Mitgliederdaten erstmal gesammelt im Post Content. Das ist ein Longtext. Da kann man die Daten zwar anschauen oder  editieren, aber wenn man sich jetzt z.B. alle Münchner Adressen rausfischen will, steht man schon am Ende der Fahnenstange. Ja nee, man könnte mit einem „post_content like %München%“ vielleicht die meisten Datensätze erwischen, aber sauber ist das nicht. Und wenn man jetzt alle Datensätze herausholen will, die bei Aerobic ein „ja“ drinstehen haben, ist endgültig Schluß, das geht so nicht.

Jetzt endlich: Custom Fields, ihr Einsatz!

Um bei dem Beispiel mit den Münchnern zu bleiben: wenn man den Ort aus der Exceltabelle in ein Custom Field namens „ort“ importieren könnte, könnte man später einen sauberen Select über „ort = ‚München'“ fahren. Wir erinnern uns nochmal kurz an die Logik der Custom Fields:

Ich habe z.B. ein neues Benutzerdefiniertes Feld „Preis“ mit dem Wert 12,80 angelegt. In der Tabelle wp_postmeta landet ein neuer Eintrag mit einer laufenden meta_id:

post_meta_custom_field

post_meta_custom_field

Hier wird über die post_id der Name (meta_key) und der Wert (meta_value) des benutzerdefinierten Feldes festgehalten.

Ich hätte also für unseren Ort den meta_key „ort“ und bei jedem Datensatz (erkenntlich an der post_id) entsprechend den meta_value „München“ oder eben einen anderen Ort. Da geht im Schnellschuss mal ein Join der wp_posts auf die wp_postmeta, das könnte etwa so aussehen:

Select * fom wp_posts left join wp_postmeta on wp_posts.ID = wp_postmeta.post_id 
where  wp_postmeta.meta_key = "ort" and wp_postmeta.meta_value = "München"

Damit hätte man zumindest mal sauber alle Münchner herausgefiltert. Auch wenn ich die WordPress-Puristen hier schon maulen höre: dafür gibts doch vordefinierte Funktionen, get_post_meta() zum Beispiel! Ja, ich weiß. Aber Hier gehts ums Prinzip, nämlich der programmtechnischen Auswertbarkeit von in WordPress enthaltenen Daten.

Die schlechte Nachricht: wie sieht der Select bei mehreren Custom Fields aus?

Da wirds ein bißchen unübersichtlich. Mit der eben beschriebenen Merthode müßte man tatsächlich für jedes weitere Custom Field einen weiteren Join hinzufügen, ich hab mir da mal ein Beispiel mit vier Feldern bei stackoverflow ausgeliehen:

SELECT wp_posts.ID, wp_posts.post_title, wp_posts.whatever,
            color.meta_value        AS color,
            transmission.meta_value AS transmission,
            model.meta_value        AS model,
            brand.meta_value        AS brand
       FROM wp_posts

  LEFT JOIN wp_postmeta  AS color 
         ON wp_posts.ID = color.post_id        AND color.meta_key='color'

  LEFT JOIN wp_postmeta  AS transmission
         ON wp_posts.ID = transmission.post_id AND transmission.meta_key='transmission'

  LEFT JOIN wp_postmeta  AS model
         ON wp_posts.ID = model.post_id        AND model.meta_key='model'

  LEFT JOIN wp_postmeta  AS  brand
         ON wp_posts.ID = brand.post_id        AND brand.meta_key='brand'

      WHERE wp_posts.post_status = 'publish'
        AND wp_posts.post_type = 'car'
   ORDER BY wp_posts.post_title

Beeindruckend, nicht wahr? Aber nicht wirklich schön. Der ganze Heckmeck ist nötig, weil die Tabelle wp_postmeta eine sogenannte Pivot-Struktur (Excel-Fexe kennen das) für die Custom Fields einsetzt, und dafür gibts in MySQL keine einfachere Auswertelogik. Hier ebenfalls bei Stackoverflow ist ein interessanter Beitrag mit einem anderen Lösungsansatz, aber das führt mir jetzt wirklich zu weit, und ausserdem ist dieser Beitrag schon lang genug. Ich hoffe, dass ich einigermassen klarmachen konnte, warum ich den Datenimport in Custom Fields für unbedingt notwendig halte, und werde mich im nächsten Beitrag darum kümmern, die Custom Fields auch angezeigt zu bekommen. Wollen doch mal sehen, wie sich WordPress als führendes System so anlässt.

Der erste Kandidat: WP All Import

Die Ausgangsbasis

Mal sehen, was wir alles brauchen. Namen, Adressen, Telefonnummern, E-Mail, da ist nichts weiter ungewöhnliches dabei. Wichtig ist die Mitgliedsnummer (die ID aus der Datenbank), schließlich können wir ja auch zwei Peter Huber haben oder Susi Müller und müssen die unterscheiden können, und die Buchführung braucht die Mitgliedsnummer auch. Die sportlichen Präferenzen lassen wir im ersten Schritt erstmal weg, hier geht es ums Prinzip, und bei zu vielen Feldern geht schnell der Überblick verloren. Wir nehmen also nur die Adressdaten und die Mitgliedsnummer, das reicht für den Anfang.

Die Anforderung

Es soll für jedes Mitglied ein eigener Beitrag erstellt werden, in dem die vollständigen persönlichen Daten aufgelistet werden. Die Mitgliedsnummer soll aus dem Beitragstitel ersichtlich sein. Das wars eigentlich schon – mal sehen, was die Import-Plugins draus machen.

Der erste Kandidat: WP All Import

Nach eigener Aussage:

The most powerful solution for importing XML and CSV files to WordPress

Na, da können wir ja mal gespannt sein. Nach der Installation und Aktivierung präsentiert sich All Import mit einem eigenen Menüpunkt im Admin Panel, hier wählen wir „New Import“, und unter „Datei hochladen“ suchen wir uns unsere CSV-Datei. Die Default-Einstellungen können wir lassen wie sie sind, es sollen neue Beiträge erstellt werden, einer für jeden Datensatz in der CSV-Datei. Kleiner Meckerpunkt am Rande: die Benutzerführung ist gemischt deutsch/englisch und sehr uneinheitlich übersetzt.

Wir machen mit den Default-Einstellungen weiter zu Schritt 3, und da wirds interessant: das sieht jetzt dem WordPress-Beitragseditor sehr ähnlich. Man hat eine Titelzeile und ein Editorfenster mit allen gewohnten Formatierungsoptionen. Zusätzlich gibt es auf der rechten Seite ein Vorschaufenster mit den importierten Datensätzen aus der CSV-Datei, aus dem man die Felder per Drag&Drop in den Editor ziehen kann. Ich schiebe mal gleich die Mitgliedsnummer und den Vornamen in die Titelzeile, so hatten wir das in unserem „alten“ Mitgliederverzeichnis auch angelegt. Das sieht dann so aus:

allimport-drag-and-drop

allimport-drag-and-drop

Wissen sie, an was mich das ganz stark erinnert? Das sieht aus wie ein Serienbrief, und genau genommen ist es das wohl auch, aber dazu gleich mehr.

Wir schubsen noch die restlichen Felder mit den Adressdaten ins Editorfenster, machen ein paar Zeilenumbrüche dazwischen und gehen mal kurz auf den Button „Vorschau“ – ah, sehr schick, man kann hier durch alle Datensätze durchblättern, das gefällt mir gut – da scheint alles zu passen.

allimport-vorschau

allimport-vorschau

Na dann wollen wir mal. Vorschau schließen, Continue to step 4 (Benutzerführung wieder sehr gemischtsprachig). All Import möchte jetzt einen Unique Identifier haben, da geben wir ihm doch unsere Mitgliedsnummer. Die restlichen Optionen schauen wir uns später an. Ein Klick auf „weiter“, und jetzt kann man den Import starten. Wer möchte kann noch das Kleingedruckte lesen, die Default-Einstellungen passen aber soweit.

Das Ergebnis

Die neue Beiträgen wurden angelegt, 10 Stück sind das in meinem Testfall.

allimport-ergebnis

allimport-ergebnis

Die Beiträge sehen auch aus wie erwartet, Mitgliedsnummer und Vorname bilden die Titelzeile, der Rest der Adressdaten den Beitragsinhalt:

allimport-beitrag-einzel

allimport-beitrag-einzel

So weit so gut. Aber was, so fragen die alten Hasen natürlich gleich, ist dahinter auf der Datenbank passiert? Nichts weiter Aufregendes. Es wurden 10 neue Posts angelegt, mit der Mitgliedsnummer und dem Vornamen als Post Title, und den restlichen Daten der Adresse im Post Content.

allimport_wp_posts

allimport_wp_posts

Was gibts da zu meckern?

Auf den ersten Blick nicht viel, die Adressdaten sind ja sauber in die Beiträge eingefügt worden. Aber ich denke mal einen Schritt weiter. Erinnern sie sich noch an unseren schicken Adresseneditor mit den Edit-Buttons?

adresseneditor

adresseneditor

Das, liebe Gemeinde, ist mit dem All-Edit-Plugin leider nicht machbar. Weil unsere Datensätze aus der CSV-Datei nicht jeweils als einzelne Datensätze mit den entsprechenden Feldern abgelegt werden, sondern zu einem String zusammengebappt und als reiner Text in den Post Title und in den Post Content gesteckt werden. Einbahnstrasse, genau genommen sogar ein Medienbruch. Der Vergleich mit dem Serienbrief war schon ganz richtig, da werden aus einer Steuerdatei im CSV- (oder sonst einem elektronisch verarbeitbaren) Format rein textuelle Ausgabedateien erzeugt, die sich zwar prima ausdrucken lassen, aber keinerlei Möglichkeiten zur weiteren Verarbeitung bieten. Man kann nichts mehr filtern,  gruppieren oder sortieren, die Verbindung zur Ausgangstabelle ist komplett abgehängt.  Bei einem Word-Serienbrief ist das akzeptabel, das ist einfach Funktionalität. Aber von einem CMS erwarte ich da ein bißchen mehr.

Wer ganz genau aufgepaßt hat: was war das mit den individuellen Felder?

WP All Import bietet auch die Oprion, „Individuelle Felder“ zu importieren – das müßten eigentlich die Benutzerdefinierten Felder oder Custom Fields von WordPress sein. Wenn wir unsere Datenfelder aus der CSV-Datei da drin unterbringen würden, hätten wir zumindest eine Datenbasis, mit der man weiterarbeiten kann. Ich bin nicht der größte Fan von benutzerdefinierten Feldern, aber besser als nix. Jedoch, nicht zu früh freuen, meine lieben alten Datenschubser. Diese Option gibts nur für die Pro Edition.

allimport_pro_edition

allimport_pro_edition

Und die langen da ordentlich hin mit den Preisen:

allimport-preise

allimport-preise

Das sprengt das Budget unseres Turnvereins aber komplett – mal ganz davon abgesehen, daß ich hier aus Prinzip keine kostenpflichtigen Plugins testen werde. Ich hab erstens das nötige Kleingeld nicht. Zweitens bin ich der Überzeugung, dass es für eine Software, die sich den Open-Source-Gedanken so groß auf die Fahne geschrieben hat wie unser WordPress, für jedes Programmierproblem auch eine kostenfreie Lösung geben sollte. Sei es daß man sich in den Supportforen auf wpde.org Hilfe holt, sei es daß man sich durch eine Reihe alternativer Plugins testet, sei es eine selbst programmierte Lösung, da gibt es viele Möglichkeiten. Aber Kaufsoftware kommt mir hier nicht in die Tüte. Wir schauen mal weiter, was es sonst noch so an Import-Plugins gibt, aber dazu gibt es auch einen neuen Artikel.