{"id":540,"date":"2017-07-11T16:34:16","date_gmt":"2017-07-11T14:34:16","guid":{"rendered":"http:\/\/evileu.de\/zum-schwarzen-pinguin\/?p=540"},"modified":"2017-07-11T16:37:52","modified_gmt":"2017-07-11T14:37:52","slug":"andere-importer-zentrale-datenhaltung-und-custom-fields","status":"publish","type":"post","link":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/2017\/07\/11\/andere-importer-zentrale-datenhaltung-und-custom-fields\/","title":{"rendered":"Andere Importer, zentrale Datenhaltung und Custom Fields"},"content":{"rendered":"<h2>Noch mehr Testberichte?<\/h2>\n<p>Nein, da mu\u00df ich euch entt\u00e4uschen. Ich hab zwar noch eine ganze Latte anderer Import-Plugins ausprobiert, eine Auswahl davon findet ihr <a href=\"https:\/\/www.wpmayor.com\/best-csv-import-plugins-for-wordpress\/\">hier bei winningWP<\/a>, 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\u00f6nnen allesamt keine Benutzerdefinierten Felder (Custom Fields). Zumindestenst nicht die Free Editions, die kostenpflichtigen Pro-Ausgaben sollens dann schon k\u00f6nnen. Aber die, wie ich schonmal gesagt hatte, kommen bei mir nicht zum Einsatz &#8211; mir fehlt das n\u00f6tige Kleingeld, und mir gehts auch ums Prinzip. Open Source, sie wissen schon.<\/p>\n<h2>Warum mir die Custom Fields so wichtig sind<\/h2>\n<p>Da muss ich ein bi\u00dfchen ausholen. Ich (und einige Legionen anderer WordPress-Entwickler da draussen) stehe immer wieder vor der Herausforderung, bestehende Unternehmensdaten in WordPress integrieren zu m\u00fcssen. Dar\u00fcber habe ich mich <a href=\"http:\/\/evileu.de\/zum-schwarzen-pinguin\/2017\/07\/09\/ein-cms-muss-sowas-koennen-datenimport-auch-en-masse\/\">in diesem Artikel<\/a> k\u00fcrzlich ausf\u00fchrlicher ausgelassen, das will ich jetzt nicht alles wiederholen. Bleiben wir bei einem einfachen Beispiel:<\/p>\n<h2>Der Turnverein Wei\u00df-Blau mit dem Mitgliederverzeichnis<\/h2>\n<p>Gehen wir davon aus, da\u00df beim Kickoff unseres WordPress-Projekts bereits Mitgliederdaten vorhanden sind, das ist schlie\u00dflich der Normalfall.\u00a0 Gehen wir weiter davon aus, da\u00df diese Daten als Excel-Liste gef\u00fchrt 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\u00fcr 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\u00e4ferenzen) in den Post Content, und fertig.<\/p>\n<h2>Fertig? Nein, jetzt gehts erst los!<\/h2>\n<p>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 \u00e4ndern, und &#8211; halt, Stopp. Da haben wir jetzt einen ganz wichtigen Knackpunkt erwischt. Was ist zu tun, wenn sich Mitgliederdaten \u00e4ndern? Jemand hat eine neue Telefonnummer oder ist umgezogen und die ganze Adresse \u00e4ndert sich, jemand interessiert sich jetzt auch noch f\u00fcr Aerobic und m\u00f6chte das eingetragen haben, oder -Gott bewahre! &#8211; es kommen nach dem CSV-Import noch neue Mitglieder dazu&#8230; was ist dann zu tun?<\/p>\n<h2>Die schwierige Entscheidung: was ist das f\u00fchrende System?<\/h2>\n<p>Diese Frage stellt sich bei nahezu jedem IT-Projekt, und wenn man das nicht fr\u00fchzeitig entscheidet, kommt man in Teufels K\u00fcche. Ich habe da selbst in Gro\u00dfprojekten, 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\u00fchrende System ist. Dabei ist es im Prinzip ganz einfach. Man mu\u00df festlegen, wo die Datenpflege passiert. In der Praxis hei\u00dft das meistens, wo die Inserts von neuen Datens\u00e4tzen und die Updates von bereits existierenden Bestandsdaten erfolgen. Im Regelfall wird das eine Tabelle sein, oder bei komplexeren Systemen auch mehrere verkn\u00fcpfte 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\u00fcr, da\u00df der neue Mitgliederdatensatz ordentlich angelegt wird, mit eindeutiger Mitgliedsnummer (ID) und allem Pipapo. Ebenso bei der \u00c4nderung von Daten eines bereits vorhandenen Mitglieds, da wird man im Regelfall den zu \u00e4ndernden Datensatz anhand der Mitgliedsnummer identifizieren und updaten. Alles klar soweit? Und dann?<\/p>\n<h2>Jetzt kommts: alle anderen Systeme referenzieren auf das f\u00fchrende System<\/h2>\n<p>Sinn und Zweck der ganzen \u00dcbung ist nat\u00fcrlich der: man m\u00f6chte Daten\u00e4nderungen nur zentral an einer Stelle im System vornehmen und es nicht an -zig verschiedenen Stellen (Huhu SAP!) eintragen m\u00fcssen, wenn sich irgendwo zum Beispiel eine Telefonnummer oder eine Bankverbindung \u00e4ndert. 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\u00fcr eine dynamische Verkn\u00fcpfung, so da\u00df bei einer \u00c4nderung in den Stammdaten die abh\u00e4ngigen Systeme in Echtzeit mitkriegen, da\u00df was passiert ist.<\/p>\n<h2>Ganz einfache Beispiele<\/h2>\n<p>Der Vorstand unseres Turnvereins m\u00f6chte gerne wissen, wie viele unserer Turnvereinsmitglieder sich f\u00fcr Aerobic interessieren. Fr\u00fcher ist man da in die Excel-Liste gegangen, hat einen Filter auf die Spalte &#8222;Aerobic&#8220; gesetzt und abgez\u00e4hlt bei wie vielen Mitgliedern da ein &#8222;ja&#8220; drinstand. Ein bi\u00dfchen EDV zu Fu\u00df, aber es hat funktioniert.<\/p>\n<p>Oder die Pressereferentin m\u00f6chte alle weiblichen Mitglieder anschreiben und nachfragen, ob Interesse an einem Mutter-Kind-Training besteht &#8211; 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.<\/p>\n<p>Sie sehen, auf was ich hinauswill? Nennt sich zentrale Datenhaltung, oder neudeutsch &#8222;Data Warehousing&#8220;. In unserem Fall, dem ganz konkreten Mitgliederverzeichnis des Turnvereins, stellt sich die zentrale Frage:<\/p>\n<h2>Was ist unser f\u00fchrendes System: WordPress oder Excel?<\/h2>\n<p>Wenn wir unsere Mitgliederdaten per CSV-Import schon so sch\u00f6n in Wordpess reinjongliert haben, m\u00f6chte unser Kunde mit an Sicherheit grenzender Wahrscheinlichkeit jetzt auch weiterhin mit WordPress arbeiten. Neue Mitglieder hinzuf\u00fcgen, Bestandsdaten \u00e4ndern, kleine Datenauswertungen (siehe oben) f\u00fcr 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\u00e4mlich erstmal nicht.<\/p>\n<h2>Text ist Text, da bei\u00dft die Maus keinen Faden ab<\/h2>\n<p>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\u00a0 editieren, aber wenn man sich jetzt z.B. alle M\u00fcnchner Adressen rausfischen will, steht man schon am Ende der Fahnenstange. Ja nee, man k\u00f6nnte mit einem &#8222;post_content like %M\u00fcnchen%&#8220; vielleicht die meisten Datens\u00e4tze erwischen, aber sauber ist das nicht. Und wenn man jetzt alle Datens\u00e4tze herausholen will, die bei Aerobic ein &#8222;ja&#8220; drinstehen haben, ist endg\u00fcltig Schlu\u00df, das geht so nicht.<\/p>\n<h2>Jetzt endlich: Custom Fields, ihr Einsatz!<\/h2>\n<p>Um bei dem Beispiel mit den M\u00fcnchnern zu bleiben: wenn man den Ort aus der Exceltabelle in ein Custom Field namens &#8222;ort&#8220; importieren k\u00f6nnte, k\u00f6nnte man sp\u00e4ter einen sauberen Select \u00fcber &#8222;ort = &#8218;M\u00fcnchen'&#8220; fahren. Wir erinnern uns nochmal kurz an die Logik der Custom Fields:<\/p>\n<blockquote><p>Ich habe z.B. ein neues Benutzerdefiniertes Feld &#8222;Preis&#8220; mit dem Wert 12,80 angelegt. In der Tabelle wp_postmeta landet ein neuer Eintrag mit einer laufenden meta_id:<\/p>\n<div id=\"attachment_336\" style=\"width: 891px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-336\" decoding=\"async\" loading=\"lazy\" class=\"size-full wp-image-336\" src=\"http:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-content\/uploads\/2017\/03\/post_meta_custom_field.jpg\" alt=\"post_meta_custom_field\" width=\"881\" height=\"96\" srcset=\"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-content\/uploads\/2017\/03\/post_meta_custom_field.jpg 881w, https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-content\/uploads\/2017\/03\/post_meta_custom_field-300x33.jpg 300w, https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-content\/uploads\/2017\/03\/post_meta_custom_field-768x84.jpg 768w, https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-content\/uploads\/2017\/03\/post_meta_custom_field-624x68.jpg 624w\" sizes=\"(max-width: 881px) 100vw, 881px\" \/><p id=\"caption-attachment-336\" class=\"wp-caption-text\">post_meta_custom_field<\/p><\/div>\n<p>Hier wird \u00fcber die post_id der Name (meta_key) und der Wert (meta_value) des benutzerdefinierten Feldes festgehalten.<\/p><\/blockquote>\n<p>Ich h\u00e4tte also f\u00fcr unseren Ort den meta_key &#8222;ort&#8220; und bei jedem Datensatz (erkenntlich an der post_id) entsprechend den meta_value &#8222;M\u00fcnchen&#8220; oder eben einen anderen Ort. Da geht im Schnellschuss mal ein Join der wp_posts auf die wp_postmeta, das k\u00f6nnte etwa so aussehen:<\/p>\n<pre>Select * fom wp_posts left join wp_postmeta on wp_posts.ID = wp_postmeta.post_id \r\nwhere\u00a0 wp_postmeta.meta_key = \"ort\" and wp_postmeta.meta_value = \"M\u00fcnchen\"<\/pre>\n<p>Damit h\u00e4tte man zumindest mal sauber alle M\u00fcnchner herausgefiltert. Auch wenn ich die WordPress-Puristen hier schon maulen h\u00f6re: daf\u00fcr gibts doch vordefinierte Funktionen, get_post_meta() zum Beispiel! Ja, ich wei\u00df. Aber Hier gehts ums Prinzip, n\u00e4mlich der programmtechnischen Auswertbarkeit von in WordPress enthaltenen Daten.<\/p>\n<h2>Die schlechte Nachricht: wie sieht der Select bei mehreren Custom Fields aus?<\/h2>\n<p>Da wirds ein bi\u00dfchen un\u00fcbersichtlich. Mit der eben beschriebenen Merthode m\u00fc\u00dfte man tats\u00e4chlich f\u00fcr jedes weitere Custom Field einen weiteren Join hinzuf\u00fcgen, ich hab mir da mal ein Beispiel mit vier Feldern bei <a href=\"https:\/\/stackoverflow.com\/questions\/26319613\/improving-a-query-using-a-lot-of-inner-joins-to-wp-postmeta-a-key-value-table\">stackoverflow<\/a> ausgeliehen:<\/p>\n<pre class=\"lang-sql prettyprint prettyprinted\"><code><span class=\"kwd\">SELECT<\/span><span class=\"pln\"> wp_posts<\/span><span class=\"pun\">.<\/span><span class=\"pln\">ID<\/span><span class=\"pun\">,<\/span><span class=\"pln\"> wp_posts<\/span><span class=\"pun\">.<\/span><span class=\"pln\">post_title<\/span><span class=\"pun\">,<\/span><span class=\"pln\"> wp_posts<\/span><span class=\"pun\">.<\/span><span class=\"pln\">whatever<\/span><span class=\"pun\">,<\/span><span class=\"pln\">\r\n            color<\/span><span class=\"pun\">.<\/span><span class=\"pln\">meta_value        <\/span><span class=\"kwd\">AS<\/span><span class=\"pln\"> color<\/span><span class=\"pun\">,<\/span><span class=\"pln\">\r\n            transmission<\/span><span class=\"pun\">.<\/span><span class=\"pln\">meta_value <\/span><span class=\"kwd\">AS<\/span><span class=\"pln\"> transmission<\/span><span class=\"pun\">,<\/span><span class=\"pln\">\r\n            model<\/span><span class=\"pun\">.<\/span><span class=\"pln\">meta_value        <\/span><span class=\"kwd\">AS<\/span><span class=\"pln\"> model<\/span><span class=\"pun\">,<\/span><span class=\"pln\">\r\n            brand<\/span><span class=\"pun\">.<\/span><span class=\"pln\">meta_value        <\/span><span class=\"kwd\">AS<\/span><span class=\"pln\"> brand\r\n       <\/span><span class=\"kwd\">FROM<\/span><span class=\"pln\"> wp_posts\r\n\r\n  <\/span><span class=\"kwd\">LEFT<\/span> <span class=\"kwd\">JOIN<\/span><span class=\"pln\"> wp_postmeta  <\/span><span class=\"kwd\">AS<\/span><span class=\"pln\"> color \r\n         <\/span><span class=\"kwd\">ON<\/span><span class=\"pln\"> wp_posts<\/span><span class=\"pun\">.<\/span><span class=\"pln\">ID <\/span><span class=\"pun\">=<\/span><span class=\"pln\"> color<\/span><span class=\"pun\">.<\/span><span class=\"pln\">post_id        <\/span><span class=\"kwd\">AND<\/span><span class=\"pln\"> color<\/span><span class=\"pun\">.<\/span><span class=\"pln\">meta_key<\/span><span class=\"pun\">=<\/span><span class=\"str\">'color'<\/span>\r\n\r\n  <span class=\"kwd\">LEFT<\/span> <span class=\"kwd\">JOIN<\/span><span class=\"pln\"> wp_postmeta  <\/span><span class=\"kwd\">AS<\/span><span class=\"pln\"> transmission\r\n         <\/span><span class=\"kwd\">ON<\/span><span class=\"pln\"> wp_posts<\/span><span class=\"pun\">.<\/span><span class=\"pln\">ID <\/span><span class=\"pun\">=<\/span><span class=\"pln\"> transmission<\/span><span class=\"pun\">.<\/span><span class=\"pln\">post_id <\/span><span class=\"kwd\">AND<\/span><span class=\"pln\"> transmission<\/span><span class=\"pun\">.<\/span><span class=\"pln\">meta_key<\/span><span class=\"pun\">=<\/span><span class=\"str\">'transmission'<\/span>\r\n\r\n  <span class=\"kwd\">LEFT<\/span> <span class=\"kwd\">JOIN<\/span><span class=\"pln\"> wp_postmeta  <\/span><span class=\"kwd\">AS<\/span><span class=\"pln\"> model\r\n         <\/span><span class=\"kwd\">ON<\/span><span class=\"pln\"> wp_posts<\/span><span class=\"pun\">.<\/span><span class=\"pln\">ID <\/span><span class=\"pun\">=<\/span><span class=\"pln\"> model<\/span><span class=\"pun\">.<\/span><span class=\"pln\">post_id        <\/span><span class=\"kwd\">AND<\/span><span class=\"pln\"> model<\/span><span class=\"pun\">.<\/span><span class=\"pln\">meta_key<\/span><span class=\"pun\">=<\/span><span class=\"str\">'model'<\/span>\r\n\r\n  <span class=\"kwd\">LEFT<\/span> <span class=\"kwd\">JOIN<\/span><span class=\"pln\"> wp_postmeta  <\/span><span class=\"kwd\">AS<\/span><span class=\"pln\">  brand\r\n         <\/span><span class=\"kwd\">ON<\/span><span class=\"pln\"> wp_posts<\/span><span class=\"pun\">.<\/span><span class=\"pln\">ID <\/span><span class=\"pun\">=<\/span><span class=\"pln\"> brand<\/span><span class=\"pun\">.<\/span><span class=\"pln\">post_id        <\/span><span class=\"kwd\">AND<\/span><span class=\"pln\"> brand<\/span><span class=\"pun\">.<\/span><span class=\"pln\">meta_key<\/span><span class=\"pun\">=<\/span><span class=\"str\">'brand'<\/span>\r\n\r\n      <span class=\"kwd\">WHERE<\/span><span class=\"pln\"> wp_posts<\/span><span class=\"pun\">.<\/span><span class=\"pln\">post_status <\/span><span class=\"pun\">=<\/span> <span class=\"str\">'publish'<\/span>\r\n        <span class=\"kwd\">AND<\/span><span class=\"pln\"> wp_posts<\/span><span class=\"pun\">.<\/span><span class=\"pln\">post_type <\/span><span class=\"pun\">=<\/span> <span class=\"str\">'car'<\/span>\r\n   <span class=\"kwd\">ORDER<\/span> <span class=\"kwd\">BY<\/span><span class=\"pln\"> wp_posts<\/span><span class=\"pun\">.<\/span><span class=\"pln\">post_title<\/span><\/code><\/pre>\n<p>Beeindruckend, nicht wahr? Aber nicht wirklich sch\u00f6n. Der ganze Heckmeck ist n\u00f6tig, weil die Tabelle wp_postmeta eine sogenannte Pivot-Struktur (Excel-Fexe kennen das) f\u00fcr die Custom Fields einsetzt, und daf\u00fcr gibts in MySQL keine einfachere Auswertelogik. <a href=\"https:\/\/stackoverflow.com\/questions\/24375572\/select-multiple-values-from-a-single-column-in-wordpress-database\">Hier ebenfalls bei Stackoverflow<\/a> ist ein interessanter Beitrag mit einem anderen L\u00f6sungsansatz, aber das f\u00fchrt 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\u00fcr unbedingt notwendig halte, und werde mich im n\u00e4chsten Beitrag darum k\u00fcmmern, die Custom Fields auch angezeigt zu bekommen. Wollen doch mal sehen, wie sich WordPress als f\u00fchrendes System so anl\u00e4sst.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Noch mehr Testberichte? Nein, da mu\u00df ich euch entt\u00e4uschen. 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 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1,18,25,7,2],"tags":[],"_links":{"self":[{"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/posts\/540"}],"collection":[{"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/comments?post=540"}],"version-history":[{"count":5,"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/posts\/540\/revisions"}],"predecessor-version":[{"id":545,"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/posts\/540\/revisions\/545"}],"wp:attachment":[{"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/media?parent=540"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/categories?post=540"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/tags?post=540"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}