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.

Datenschubserei für Fortgeschrittene: wir nehmen CSV

 Ausgangsbasis: Fehlanzeige

Vielleicht hat man ja schon mal ganz hoffnungsvoll reingeguckt, was sich im Dashboard unter Werkzeuge/Daten importieren oder exportieren verbirgt, aber da kommen wir leider nicht  weiter. Hier kann man nur WordPress-eigene XML-Dateien erzeugen oder hochladen, mit denen sich Beiträge und Seiten aus einem Blog herausexportieren und in einen anderen Blog wieder reinladen lassen. Wir brauchen ganz was anderes, und da wollen wir uns mal umsehen, was der Plugin-Markt so hergibt. Aber zuerst einmal ein paar Sätze zum Datenformat.

Unser Format der Wahl: CSV

CSV oder „Comma separated values“ ist das wohl verbreitetste Transportmittel für tabellarische Daten jeder Art. Es enthält normalerweise eine Kopfzeile, in der die Feldnamen stehen, und dann in jeder weiteren Zeile jeweils einen Datensatz.  Die meisten Anwender kennen die Möglichkeit, Excel-Tabellen als CSV zu speichern, und solche Listen werden wir in den meisten Fällen verwenden.  Ich zeig hier mal nur ein ganz einfaches Beispiel:

id;vorname;nachname
1;Fridolin;Hackmann
2; Marius ;Bishop
3;Yvonne;Green
4; Lina ;Ward
5; Tara; Sell
6; Antonia ; David 
7; Lorena ; Peter 
8; Franz ;Pfaff
9; Maja ; Bartels 
10; Laurin ; Selle

Das sind einfach zehn Datensätze, die Feldnamen kann man in der ersten Zeile lesen: id, vorname, nachname. Diese erste Zeile wird auch „Header“ genannt und wird uns bei unseren Importbemühungen noch öfter begegnen. Sie legt fest, in welcher Reihenfolge und mit welcher Benennung die einzelnen Datensätze zu lesen sind. Ob dahinter nun eine Liste mit 10 oder 10.000 Datensätze steht kann uns völlig wurst sein, Hauptsache die Struktur stimmt.

CSV geht (fast) immer

Ich habe schon viele Stunden meiner IT-Laufbahn damit verbracht, den unterschiedlichsten Systemen CSV-Dateien zu entlocken, und die gute Nachricht ist: meistens gehts schon irgendwie. Ob das nun DATEV, SAP, Lexware oder WISO meinBüro ist, oder eine MySQL- oder Oracle- oder sonst eine Datenbank, in den meisten Fällen verbirgt sich irgendwo eine Exportfunktion für CSV, man muß oft nur ein bißchen suchen. Manchmal muß man noch ein bißchen mit den Optionen experimentieren, ein beliebtes Spiel ist dass Umlaute und Sonderzeichen (ÄÖÜ%$§…) erstmal nicht so codiert sind wie man sie braucht, aber für die alten Datenbankfexe da draussen erzähle ich hier nichts Neues. Im schlimmsten Fall muss man da mit dem Notepad++ und etlichen Suchen&Ersetzen-Läufen nachkorrigieren, aber meistens hält sich der Aufwand in Grenzen. Es ist im Normalfall gar nicht so schwierig, eine funktionale CSV-Datei aus dem vorhandenen Datenbestand zu erhalten.

Was ist mit XML?

Das lassen wir mal aussen vor. Im Otto-Normal-Büro wird man in den seltensten Fällen Bestandsdaten als XML antreffen, auch wenn heutzutage nahezu jede Datenbank auch XML-Export und Import beherrscht. Wir halten uns an die schlichten CSV-Listen, das ist für unsere Anwendungen völlig ausreichend.

Wie gehts jetzt weiter mit dem CSV?

Da läßt sich leider keine allgemeingültige Anleitung formulieren, hier muß man schon sehr spezifisch einsteigen, was denn nun mit den Daten passieren soll. Ich werde ab jetzt mit konkreten Beispielen arbeiten, damit die Kuh vom Eis kommt. Erinnern sie sich noch an den Turnverein Weiß-Blau? Da hatten wir mithilfe einer eigenen Tabellen ein Mitgliederverzeichnis erstellt. Dafür haben wir für jedes Mitglied einen eigenen Beitrag erstellt und mit der Mitglieds-ID auf die eigene Tabelle mit allen relevanten Daten verknüpft. Jetzt gehen wir mal davon aus, daß eine umfangreiche Mitgliederliste mit Adressen und allem drum und dran schon existiert. Wollen mal sehen, ob wir die in unser WordPress importiert kriegen, aber dazu gibt es einen neuen Beitrag.

Ein CMS muss sowas können: Datenimport auch en masse

Am Anfang war der Blog

Wenn man sich die alte Dame WordPress unter dem Aspekt CMS mal genau anguckt, schauen unter jedem Rockzipfel noch die Anfänge heraus. WordPress ist nunmal dafür konzipiert worden, daß auch Otto Normalblogger auf einfache und leicht erlernbare Weise seine Beiträge im Web veröffentlichen kann, auf daß sie von möglichst vielen Besuchern gelesen, kommentiert und diskutiert werden können. Das sieht man besonders an der zentralen Tabelle wp_posts, wo die meisten Felder unmittelbar mit Eigenschaften zu tun haben, wie sie ein typischer Blogbeitrag nun mal hat. Author, Erscheinungsdatum, Titel, Inhalt, Excerpt, Datum der letzten Änderung, Anzahl Kommentare usw., all das stammt noch aus den Zeiten, als sich unzählige von frischgebackenen Bloggern auf das geniale WordPress stürzten und sich damit mehr oder weniger erfolgreich im Internet darstellten. Auch die ausgefeilte Verwaltung von Kommentaren und Kategorien mit ihren diversen Verschachtelungsmöglichkeiten stammt noch aus der ursprünglichen Konzeption als Blogsoftware.

Weils so schön einfach ist: Webseiten auch mit kleinem Budget

Da es mit WordPress genauso einfach ist, statische Seiten zu erstellen wie sagen wir mal einen neuen Blogbeitrag zu schreiben, hat es sich sehr schnell zur mit grossem Abstand beliebtesten Software für kleine und mittlere Webauftritte entwickelte. Laut dieser Studie von upload magazine  beherrscht WordPress aktuell (Stand März 2017) 58,9 Prozent des CMS-Marktes. Das hat natürlich den Hauptgrund, daß WordPress Open Source und kostenlos ist, und durch unzählige Plugins erweiterbar. Die oft gestellte Frage, ob WordPress auch wirklich ein vollwertiges CMS ist, wird hiermit akademisch. Es wird als CMS millionenfach verwendet, da schaffen die Fakten die Antwort. Eigentlich ist die Frage ja auch unsinnig, denn wenn man Tante Google mal bemüht, ist die Antwort auf „Was ist ein cms?“ schlicht und ergreifend:

Ein Content Management System (kurz CMS) ist eine Software, die zur Erstellung und Verwaltung von Inhalten – in Text-, Bild-, Video- oder sonstiger Form – verwendet wird. CMS werden vor allem zum Betreiben von Websites, aber auch für „Offline-Plattformen“ (in Intranetzwerken) eingesetzt.

Alles klar? Natürlich ist WordPress ein CMS. Die Frage ist nur: wie gut?

CMS für Fortgeschrittene: wer brauchts nicht?

Ich geh mal von ein paar einfachen Anwendungsbeispielen aus. Wenn nur eine „Visitenkarte“ im Web gebraucht wird, etwa für einen Arzt, einen Anwalt, einen Steuerberater, eine Werkstatt oder einen kleinen Laden, da muß man nicht mit Kanonen auf Spatzen schießen. Eine Startseite mit Informationen „Über uns“, Eine Seite „Unser Angebot“, Öffnungszeiten und Anfahrtskizze, ein Kontaktformular, vielleicht noch eine Seite für „Termine/Aktuelles“ (hier kommt die Blogfunktionalität zum Einsatz), AGBs und Impressum, das war’s in ganz vielen Fällen schon.

Dafür ist WordPress ganz ideal, so eine Webseite kann schnell und unkompliziert erstellt werden und innerhalb weniger Tage fertig sein. Der Pflegeaufwand hält sich auch meistens in Grenzen, ein Steuerberater möchte vielleicht einmal im Monat ein Mandantenrundschreiben mit aktuellen Steuerinformationen als PDF zum Download anbieten, ein Restaurant hat eine Wochenkarte oder ein aktuelles Tagesgericht, Urlaubstermine oder aktuelle Sonderangebote gehören eingepflegt, das wars dann meistens schon. Hier ist kein weiteres technisches Brimborium nötig, da macht man einen kleinen Wartungsvertrag und pflegt die Änderungen im Einzelfall manuell ein, ist ja kein Aufwand.

Für wen reicht das nicht?

Das ist gar nicht so einfach zu beantworten. Ich fang mal so an: in jedem (und sei es auch noch so kleinen) Unternehmen gibt es Listen. Preislisten, Kunden- und Lieferantenadressen, Kassenbuch, Lagerbestände, Terminkalender, Artikelstammdaten usw usf… und alle alten Programmierer lieben Listen! Ob diese jetzt in Excel (der Otto-Normalfall), Access (hach, schön wenn’s so ist), einem kleinen oder großen ERP/CRM oder auch nur auf Papier geführt werden, die Unternehmensdaten sind da, sie leben und werden gepflegt und sind immens wichtig für den Bestand des Ladens.

Wenn man jetzt nur sowas wie die Wochenkarte eines Restaurants oder die Preisliste eines Friseurs auf die Webseite bringen will, muß man da auch nicht lange rummachen, das geht mit copy&paste auf eine statische Seite, oder (etwas vornehmer) als hübsch formatiertes PDF zum Download. Aber schon mit den Artikelstammdaten einer Metzgerei oder eines Lebensmittelgeschäfts steht man da ganz schnell am Ende der Fahnenstange. Schon bei ein paar hundert Artikeln im Tante-Emma-Laden wird die Sache sehr schnell unübersichtlich.

Die Antwort in vielen Fällen: ein Online-Shop muss her!

Und da landet man unweigerlich ganz schnell bei woocommerce, dem verbreitetsten Shopsystem-Plugin für WordPress. Es ist auf den ersten Blick recht übersichtlich, wie man ein Produkt mit den entsprechenden Daten anlegt ist recht schnell gelernt, es gibt -zig Anleitungen und Hilfeseiten bei Tante Google zu finden. Bevor sie jetzt aber vor lauter Begeisterung anfangen, ihre Wurstsorten und Fleischspezialitäten da manuell einzuhacken, ziehen wir die Notbremse. Das geht auch einfacher!

Der Knackpunkt: die Import-Funktionalität

Und das gilt nicht nur für den Online-Shop, das gilt überall, wo sie Listen mit Unternehmensdaten ins Web bringen wollen. Es ist einfach nicht zumutbar, hunderte oder tausende von Datensätzen manuell zu erfassen, das ist rausgeschmissene Arbeit und viel zu aufwendig und fehlerträchtig. Wir alten Programmierer sind alle Experten darin, existierende Unternehmensdaten, in welcher Form sie auch immer vorliegen mögen, weiterzuverarbeiten und in den meisten Fällen in unsere Datenbank zu schubsen, damit wir schön mit ihnen jonglieren können. Wie das mit WordPress funktionieren kann, darüber gibts einen neuen Artikel, der hier ist lang genug. Aber ich hoffe es ist klargeworden, warum Datenimport so eine wichtige Sache ist.

Da staunste Bauklötze: vielleicht serialized, vielleicht nicht

Wenns klemmt im Datenkorsett

Ich habe mich schon an anderer Stelle darüber ausgelassen, daß das Datenmodell von WordPress alles andere als relational wohlstrukturiert und insgesamt renovierungsbedürftig ist.  Wenn  man sich ein bißchen mit multifunktionalen Plugins wie z.B. woocommerce beschäftigt, stellt man immer wieder fest, daß Entitäten in die vorhandenen WordPress-Tabellen gequetscht werden, die eigentlich nicht wirklich hineinpassen. Um beim Beispiel woocommerce zu bleiben, weil das ja doch sehr verbreitet und gut dokumentiert ist: da werden die zu verkaufenden Produkte in der Tabelle wp_posts wie Beiträge angelegt, und was man hier an Produkteigenschaften und benutzerdefinierten Feldern nicht mehr untergebracht hat, landet in der wp_options, der wp_postmeta oder in der wp_terms und ihren Verwandten. Damit man hier auch alles unterbringt, obs jetzt logisch paßt oder nicht, kommt ein tolles Konstrukt zum Einsatz (übrigens nicht nur in WordPress, das gibts auch anderswo):

Serialized Data

Was ist das? Wenn sie einen Datenbankeintrag finden , der so aussieht:

a:1:{s:14:“pa_code“;a:6:{s:4:“name“;s:14:“pa_code“;s:5:“value“;s:0:““;s:8:“position“;i:0;s:10:“is_visible“;i:1;s:12:“is_variation“;i:0;s:11:“is_taxonomy“;i:1;}}

Das sind serialisierte Daten. Es handelt sich hier um ein Produktattribut namens „code“, das in dieser besonders verklausulierten Form abgelegt wurde. Wer genauer wissen möchte, was serialisierte Daten sind, kann hier im PHP-Manual mal nachlesen, und mir ganz ehrlich sagen wenn er auch nur die Hälfte verstanden hat. Soweit ich es kapiert habe, erlaubt es die Serialisierung, in einem einzigen Datenbankfeld mehrere Variable unterschiedlicher Datentypen zu speichern.  In einem Array, mit Hilfe eines Objekts. Aber, ich gebe wie gesagt ehrlich zu ich hab nicht genau verstanden, wie das wirklich funktioniert. Da schwirrt es in den Manuals nur so von Objekten und Klassen und Methoden, und mir fehlt echt die Geduld (und der Hang zur Verkomplizierung) mich da weiter einzulesen. Ich habs versucht, und bin dabei unter anderem auf einen besonderen Leckerbissen gestossen:

Eine Funktion namens maybe_serialize()

Allen Ernstes. Laut Codex macht die Folgendes: sie serialisiert Daten, falls nötig. Ich muß da unbedingt mal wörtlich zitieren:

Confusingly, strings that contain already serialized values are serialized again, resulting in a nested serialization. Other strings are unmodified.

Ach nee, „confusingly“, also verwirrenderweise? Da brat mir doch einer einen Storch! Und wie kriegt man die Daten da wieder raus? Gute Frage. Es gibt tatsächlich auch eine Funktion namens maybe_unserialize(), ist das nicht schön? Irgendwas muß man damit doch anfangen können… meine Recherchen haben aber noch nicht ergeben, was man sinnvollerweise damit macht.

Wofür soll das alles gut sein?

Der Knackpunkt ist: hier werden buntgemischte Daten in ein einziges Tabellenfeld geklemmt, statt sie sauber nach Datentypen getrennt in einer passenden Tabelle zu speichern. Damit bringt man mehr Informationen als vorgesehen in einer bereits vorhandenen Tabelle unter, aber das Auslesen und Weiterverarbeiten wird beliebig kompliziert und erstmal sehr verwirrend und umständlich. Und mal ganz im Ernst: eine Funktion, die „maybe“ irgendwas macht, die kann ich nicht gebrauchen. Das sind Stilblüten der objektorientierten Programmierung, die allem widersprechen, was ich über Datenmodellierung und Tabellenstrukturierung je gelernt habe.

Um beim Beispiel woocommerce zu bleiben: das Plugin gönnt sich ja ohnehin ein gutes Dutzend eigener Tabellen. Warum legt man dann für die Produktattribute nicht auch eine eigene Tabelle an, in der die nötigen Daten in lesbarer und vor allem auch per SQL auswertbarer Form gespeichert werden? Kostet auch nicht mehr, und wäre unendlich benutzerfreundlicher. Den Mumpitz mit den vielleicht oder auch nicht serialisierten Daten könnte man sich dann echt sparen.

Wahrscheinlich guckt wieder kein Schwein: Scheduled events

Was ist ein Scheduled Event?

Das ist im Prinzip so etwas wie ein Cron-Job, und hier höre ich alle alten Programmierer „Aha!“ rufen. Jeder kennt die Möglichkeit, in Unix/Linux zeitlich wiederkehrende Aufgaben per Cron-Job zu steuern. WordPress bietet mit den Scheduled events eine ähnliche zeitabhängige Funktionssteuerung, und das ist prinzipiell eine schicke Sache, aber es gilt ein paar Eigenheiten zu beachten. Man kann schon festlegen, zu welcher Uhrzeit eine Funktion ausgeführt werden soll, ob sie täglich oder zweimal am Tag oder wöchentlich ausgeführt werden soll und all sowas, aaaber…

Wahrscheinlich guckt wieder kein Schwein

Ein WordPress Scheduled event wird erst ausgeführt, wenn die Blogseite auch aufgerufen wird. Dann guckt WordPress nach, ob es Events gibt, deren festgelegte Uhrzeit bereits abgelaufen ist, und erst jetzt wird die geplante Aktion gegebenfalls ausgeführt. Heißt im Klartext: wenn kein Besucher auf die Webseite kommt, wird auch kein Event ausgeführt. Nein, ich veräppel euch nicht, das ist so. Schlimmstenfalls wird der Event erst genau dann ausgeführt, wenn man selber mal auf seine Webseite geht um zu gucken ob schon was passiert ist. Das ist natürlich datenverarbeitungstechnisch Bockmist, weil es dem reinen Zufall überlassen ist, wann die gewünschte Funktion nun tatsächlich ausgeführt wird.

Und, ist das so schlimm?

Das kommt darauf an. Wenn ich über einen Scheduled Event einen größeren Datenbankabgleich mit richtig vielen Datensätzen fahren will, hätte ich schon gern dass der wie geplant Nachts um 2:00 über die Bühne geht und nicht erst Morgens wenn der erste Besucher auf meiner Webseite hereinschneit. Wenn ich zu bestimmten Zeiten E-Mails mit Informationen über „Neues zum Tage“ an meine Abonennten verschicken möchte, sollen die schon zu einer bestimmten Tageszeit abgesetzt werden und nicht erst Stunden später. Das mal nur so als Beispiele.

Wir wollen mal nicht so kleinlich sein, in den meisten Fällen wird es nicht so gravierend sein, wenn eine geplante Funktion statt um 0:00 erst um 6:27 beim ersten Besucher der Webseite getriggert wird. Man muss es halt wissen, und sich genau überlegen ob es im Einzelfall etwas ausmacht, daß ein geplanter Event erst „irgendwann“ stattfinden wird, und nicht genau zur geplanten Zeit.

Wie plane ich einen Scheduled Event?

Dafür verweise ich auf diesen ausgezeichneten Artikel bei sitepoint, da steht alles in komprimierter, bestens verständlicher Form drin. Ich renne hier nur mal im Schnellgang durch.

Zuerst definieren wir die Funktion, die ausgeführt werden soll,

function mein_event(){  // Mach irgendwas.}

Wir verknüpfen die Funktion mit einem neuen Action hook:

add_action('mein_action_hook','mein_event');

Schließlich setzen wir die Parameter für den Event, dabei nutzen wir die PHP-Funktion time(), die den UNIX-Timestamp für „jetzt“ zurückgibt:

wp_schedule_event(time(), 'hourly', 'mein_action_hook');

Das alles kommt in die functions.php unseres Child-Themes, und sollte dafür sorgen, dass unsere Funktion ab sofort stündlich ausgeführt wird… jedenfalls so ungefähr, wann halt der nächste Besucher hereinschneit. Also ehrlich, mir sträuben sich da sämtliche Nackenhaare, aber anders kann es WordPress halt nicht. Da dürfen sich die Entwickler aber schon nochmal was einfallen lassen!

Workaround und Helferlein

Ja, ich habs gehört, die alten Programmierer habens alle schon eingeworfen: dann basteln wir uns halt einen Cron-Job, der unsere WordPress-Seite automatisch aufruft, sagen wir mal eine Minute nachdem der Scheduled Event fällig war. Wie das geht steht z.B. hier bei Sebastian Widmann , aber das führt mir jetzt endgültig zu weit, das kann sich jeder der möchte selber zusammenpfriemeln.

Wenn man unbedingt mit Wordpess Scheduled events arbeiten will, kommt man an einem sehr ausgefeilten und nützlichen Plugin kaum vorbei:
WP Crontrol bietet eine komfortable Benutzeroberfläche zur Steuerung von Events und Schedules und macht einem das Leben hier deutlich leichter. Ändert zwar nix an der grundlegenden Problematik von „wahrscheinlich guckt wieder kein Schwein“, aber ist zumindest sehr einleuchtend zu bedienen und hilft einem bei mehreren Scheduled Events wirklich, den Überblick zu bewahren.

Hooks – jetzt kommt Action ins Spiel

Was sind WordPress Hooks?

Das kann man googlen, und z.B. die netzialisten haben einen sehr informativen Beitrag zu dem Thema geschrieben. Sehr kurz und knapp gesagt, Hooks sind definierte Ankerpunkte im WordPress-Code, an denen man eigene Funktionen einhängen kann. Dabei unterscheidet man zwischen Action Hooks und Filter Hooks, dazu gleich mehr. Eine umfassende Liste aller WordPress Hooks hat Adam R. Brown in seiner Hook Database zusammengetragen. Auch der Codex zur Plugin API bietet umfangreiche Information zum Thema.

Unterschied zwischen Action und Filter

Ich zitiere hier mal schlicht und unbefangen den Codex:

You can sometimes accomplish the same goal with either an action or a filter. For example, if you want your plugin to change the text of a post, you might add an action function to publish_post (so the post is modified as it is saved to the database), or a filter function to the_content (so the post is modified as it is displayed in the browser screen)

Also: wenn man Beiträge gezielt verändern möchte, z.B. eine Copyright-Zeile an jeden veröffentlichten Beitrag anhängen, gibt es (mindestens) zwei Wege zum Ziel. Hier wird empfohlen: entweder man verwendet einen action-Hook auf den Event publish_post, der beim Speichern eines Beitrags in der Datenbank die Copyright-Zeile anhängt. Oder man hakt sich mit einem Filter auf the_content an den Inhalt des Beitrags ran, und hängt die Copyright-Zeile beim Anzeigen des Beitrags in der Einzelansicht an. So weit so gut – ich hab mir allerdings einen Wolf gegooglet, um ein funktionierendes Beispiel für den action hook zu finden, leider bis jetzt ohne brauchbares Ergebnis. Das mit dem Filter dagegen geht relativ easy:

Der Filter

könnte zum Beispiel so aussehen:

function copyright_nach_post_content($content){
if (is_single()) {	
	$content .= '<p>Hier kommt dein Copyright (C) EL 2017 hin </p>';
}
	return $content;
}
add_filter( "the_content", "copyright_nach_post_content" );

Dieser Code kommt in die functions.php unseres Child-Themes und zieht jedesmal, wenn ein Beitrag aufgerufen wird. Die Abfrage auf if(is_single()) stellt sicher, dass auch wirklich nur Beiträge in der Einzelansicht betroffen sind.

Der entsprechende Action-Hook

war wie oben bereits gesagt nicht aufzufinden. Dann machen wir halt was anderes, wo richtig Action drin ist:

Wir versenden eine Email, wenn ein neuer Beitrag veröffentlicht wurde

Dabei stelle ich euch die simple, aber sehr effektive Funktion wp_mail vor. Der Code sieht so aus:

add_action('publish_post', 'send_emails_on_new_post');

function send_emails_on_new_post($post)
{
    $emails = "evi.s.leu@gmx.de"; 
    $title = get_the_title($post->ID);
    $url = get_permalink($post->ID);
    $message = "Link zum Beitrag: \n{$url}";
 
    wp_mail($emails, "Neuer Beitrag! {$title}", $message); 
}

Zuerst wird der action-hook auf das Ereignis publish_post gesetzt und mit unserer Funktion verknüpft. Diese bekommt als Parameter den $post mit, darüber können wir auf die Attribute des aktuellen Beitrags zugreifen, das tun wir mit der $post->ID. Wir holen uns den Titel und den Permalink und basteln uns daraus eine kleine E-Mail-Nachricht an den oben eingesetzten Empfänger.Die Funktion wp_mail braucht ganz minimalistisch wirklich nur 3 Parameter, den Empfänger, den Betreff und den Inhalt, und schon fluppts! Der Empfänger wird jedesmal benachrichtigt, wenn ein neuer Beitrag veröffentlicht wurde.

Ein übersichtlicher Beitrag zur wp_mail-Funktion ist hier bei OSTraining zu finden, die kompletten Informationen findet ihr natürlich im Codex.

Erstellen wir jetzt endlich mal ein eigenes Theme?

Nein.

Und das ist mein letztes Wort, ehrlich. Themes gibt es wie Sand am Meer, da ist echt für jeden Geschmack, Zweck und Funktionsumfang was dabei. Themes sind ein Konzept, das auch vom Enduser (im Zweifelsfall meinem Kunden) leicht begriffen wird, nach Themes kann jeder selber suchen und sich aus den vielen bunten Bildchen das heraussuchen, was ihm am besten gefällt. Und glauben sie mir: es wird ihm erst das eine Theme gefallen, und dann das Nächste und dann noch das Übernächste. Was bei einem Themewechsel auf sie zukommt, da haben sich andere Leute schon schlaue Gedanken gemacht, siehe z.B. dieser Artikel vom elbnetz. Bestenfalls passen nur ein paar Bildformate nicht mehr, schlimmstenfalls zerhackt es ihnen die ganzen Seitenlayouts und die ganzen schönen kundenspezifischen Funktionen.

Bedenken sie immer: als Entwickler kommen sie bei einem Themewechsel in Teufels Küche, wenn sie abhängig von einem bestimmten Theme programmiert haben, und der Kunde möchte jetzt aber unbedingt ein anderes.

Ich editiere Page Templates nur im äußersten Notfall

Weil ich aus langjähriger leidgeprüfter Praxis genau weiß, dass sich der Kunde früher oder später für ein anderes Theme entscheiden wird, greife ich wenn möglich gar nicht in die Page Templates ein. Die Arbeit ist bei einem Themewechsel grad für die Katz‘, und es ist auch nicht gesagt daß ihre Anpassungen in einem anderem Theme auch genauso funktionieren werden, dazu sind die Templates einfach zu uneinheitlich konstruiert.

Aber was ist, wenn man ein Child Theme verwendet?

Das selbe in Grün, ich setze hier keine modifizierten Page Templates ein, wenn es nicht unbedingt sein muss. Ich verwende (ausser bei ganz, ganz einfachen Blogs) immer ein Child Theme. In den seltenen Fällen, wo ich es nicht von Anfang an eingerichtet habe, kam immer früher oder später der Zeitpunkt wo ich doch eins gebraucht habe.

Die einzigen Dateien, an denen ich Änderungen vornehme, sind üblicherweise die functions.php (ganz wichtig für unsere Shortcodes) und seltener noch die style.css des Child Themes. Und das wird dann (verdammtnochmal!) ordentlich und ausführlich dokumentiert, damit man die Funktionalität im Falle des Falles ohne Beinbruch in ein neues Theme übertragen kann.

Ausnahmen bestätigen die Regel

Und falls doch mal eine Änderung an einem Template fällig ist: immer im Child Theme, und immer gut dokumentieren. Ich habe zum Beispiel auf der Seite des Turnvereins Weiß-Blau die Beitragsseiten als Mitgliederverzeichnis umgestaltet, da war ein Eingriff in die single.php notwendig, um die Daten aus der eigenen Tabelle mit den Mitglieder-Stammdaten anzeigen zu lassen. Aber ich wette mit mir selber, dass ich das auch mit einem Shortcode lösen könnte – da mach ich mir bei Gelegenheit mal mehr Gedanken drüber.

Auch wenn man bestimmte Teile des Themes loswerden möchte (keine Sidebar, kein Footer etc…) kommt man um eine Änderung der entsprechenden Templates kaum herum, aber auch hier gilt: immer im Child Theme, und immer gut aufpassen was man da wirklich macht. Die Themes sind ja, wie bereits gesagt, so uneinheitlich konstruiert (und so lausig dokumentiert, das muss auch mal gesagt werden!), dass sich hier kaum allgemeingültige Regeln aufstellen lassen, welche Änderung welchen Effekt bewirkt. Da ist immer viel Trial and Error dabei.

Änderungen in der style.css nur mikrochirurgisch

Natürlich kann man sich hier spielen und die Layouts für nahezu alle WordPress-Elemente nach eigenem Gusto verändern. Aber ich bin Fachinformatikerin, keine Webdesignerin, und überlasse das passende Styling denen, die’s gelernt haben, und das sind im Zweifelsfall nun mal die Theme-Designer. Ich greife mal ein, wenn z.B. die Umrandungen von Formularfeldern unsichtbar sind (beliebtes Manko), oder die Beschriftung von Buttons unleserlich ist. Aber das wars dann schon. Alles andere lasse ich wie es ist, die Leute vom Design haben ja schließlich grosse Mühe darauf verwendet, dass alles zusammen ein stimmiges Bild ergibt, und ich als Design-Laie kann hier bestenfalls verschlimmbessern.

Theme-unabhängig programmieren, das geht!

Sogar sehr schmerzlos. Mit Shortcodes und Plugins, Filtern und Action Hooks läßt sich fast alles  erreichen, was der Kunde anfordert, und hier kann man wirklich Theme-unabhängig arbeiten, wenn man ein bisschen aufpasst.

Grosse Styling-Änderungen reden wir unserem Kunden einfach aus, da suchen wir ihm lieber ein anderes Theme. Wir sind schließlich (ich sags nochmal) alte Programmierer und keine Designer.

WordPress möchte doch so gern ein CMS sein

Da fehlts zwar noch ein paar Meter, aber das gute alte WordPress nimmt ja für sich in Anspruch, ein vollwertiges CMS werden zu wollen. Und da ist die Trennung von Funktion und Design unverzichtbar! Will heissen, eigentlich sollte man die Themes wechseln können wie die frischen Socken, ohne dass an den Inhalten überhaupt Nacharbeiten anfallen.

Davon sind wir zwar im Moment noch einiges entfernt, aber mit der Multisite-Technologie gehts schon in die richtige Richtung, besonders wenn man geeignete Plugins zum Beispiel zum Clonen von ganzen Blogseiten einsetzt. Damit kommen zwar auch wieder neue Herausforderungen – wie schreibe ich ein Multisite-fähiges Plugin? – aber die Richtung stimmt wie gesagt schon. Ich beobachte diese Entwicklung mit grossem Interesse, und werde hier sicher noch den einen oder anderen Beitrag zum Thema CMS reinstellen. Aber ein eigenes Theme – no way Josè, das wirds hier bei mir nie geben.

Tabelleneditor revisited: und jetzt das Ganze nochmal als Shortcode

Ja, ich weiß, ich habs unterschlagen. Wir haben uns einen hübschen kleinen Tabelleneditor im Admin Panel gebastelt, mit Unterseite und allem Pipapo. Aber da kamen schon die ersten Rückfragen. Was, wenn ich meinen Besuchern die Möglichkeit anbieten möchte, Tabellendaten auf meiner Webseite zu editieren? Wie sieht das dann die Verzweigung auf die Unterseite aus? Ein Anwendungsfall wäre es zum Beispiel, wenn ich meinen Nutzern das Editieren der eigenen Adressdaten ermöglichen möchte. Da wird man zwar im Zweifelsfall ein Login vorschalten, denkbar ist z.B. daß sich der Benutzer mit seiner Mitgliedsnummer anmeldet und diese beim Aufruf des Unterformulars abgefragt wird. Das führt mir aber jetzt entschieden zu weit, ich lasse es mal bei dem Formular mit den Edit-Buttons, sonst blickt hier keiner mehr durch. Die Funktionalität wird also die selbe sein wie beim Plugin Adressen Tabelle, nur diesmal auf der Blog-Oberfläche.

Wir basteln uns einen Shortcode

Der erste Teil ist simpel. Wir schnappen uns die Funktion pluginAdressenTabelle() und schieben sie in einen Shortcode. Für den legen wir uns eine neue Seite an und fügen ihn dort ein, ich hab ihn mal [adr_tabelle] genannt. Das müsste eigentlich ohne Änderungen klappen, das Ergebnis sollte etwa so aussehen:

shortcode_adresseneditor

shortcode_adresseneditor

Wenn man jetzt auf einen „Edit“-Button klickt, landet man (logischerweise) noch im Admin Panel, und das soll natürlich nicht sein, da brauchen wir was anderes. Nämlich eine Blogseite, die nicht im Menü erscheinen soll, sondern nur durch Klick auf den Edit-Button aus der aufrufenden Seite auftauchen darf.

Seite ohne Menüeintrag? Mit Menü!

Man legt eine neue Seite an, benennt sie entsprechend, z.B. Adresseneditor Unterseite. Dann legt man unter Design/Menüs ein neues Menü an, in das man alle Seiten ausser der eben erstellten einträgt (alle markieren und dann bei der Einzelseite das Häkchen entfernen). Ist ein bißchen von hinten durch die Brust ins Auge, aber so funktionierts.

Aufzurufende Seite bei Formular-Action hinterlegen

Wir klemmen uns einfach den Permalink der soeben erstellten Unterseite und legen sie auf die Variable für den Action-Tag, das sieht dann z.B. so aus:

$meinplugin_URL = „http://localhost/turnverein/adresseneditor/adresseneditor-unterseite/“;

Das wars schon.

Wie kommt jetzt unsere Editor-Funktionalität in die Unterseite?

Per Shortcode! Mein Freund und Lieblingshelfer, ich sags immer wieder. Wir erstellen einen neuen Shortcode, mit aussagekräftigen Namen, z.B.:

add_shortcode (‚mein_adr_editor‘, ‚meinAdressenEditor‘);

Dann brauchen wir natürlich noch die Funktion zum Shortcode, die heißt jetzt meinAdressenEditor(). In diese kopieren wir uns den ganzen Inhalt der Funktion AdresseEditAusgabe() aus dem Plugin, das wir vorher erstellt haben. Nicht vergessen unten den Link zurück auf die aufrufende Seite zu aktualisieren, der sollte jetzt etwa so ausehen:

echo „<a href = ‚http://localhost/turnverein/adresseneditor/’/><h1>Zurück zur Adressenliste</h1></a>“;

Den soeben erstellten Shortcode [mein_adr_editor] in die Unterseite einfügen, speichern und feddisch, das wars! Die Bildschirmausgabe sollte etwa so aussehen:

adresseneditor_unterseite

adresseneditor_unterseite

Übrigens nicht wundern: wenn man sich die Unterseite „allein“ anschaut, also aus dem Edit-Modus mit „Seite ansehen“, sieht man – nichts. Da fehlt der Parameter mit der ID, also ergibt unser Select eine leere Ausgabe, und dann sieht mal halt nichts, punktum.

So, jetzt hab ich aber alle Aspekte des Tabelleneditors erschöpfend behandelt – hoffe ich zumindest. Wenn jetzt noch Rückfragen kommen – ich bin unbekannt verreist 😉

Statt Dirty Trick: die saubere Lösung mit Submenu Page

Na bitte, ich wußte doch dass es da eine sauberere Lösung geben muss. Ich lasse die beiden vorigen Artikel mal so stehen (wir lernen daraus) und zeige hier einen anderen Ansatz für das Unterformular, das bislang ja so nackt und weiss als reine PHP-Datei dasteht.

Der erste Vorteil: durchgängige Benutzeroberfläche

Das ist zwar eigentlich nur eine kosmetische Korrektur, funktioniert hats auch vorher, aber schöner ist es ja schon wenn man im AdminScreen-Kontext bleibt.

Der zweite Vorteil: wir sparen uns den require(wp-load.php)

Das ist schon knackiger. Es ist ja nicht „considered best practice“, wenn man den ganzen WordPress-Funktionsapparat in einem Plugin nochmal lädt. Man kanns machen, aber es ist und bleibt eine Krücke. Das können wir uns jetzt schenken, weil unsere Submenu Page alle Funktionalitäten schon mitbringt.

Submenu – wie wirds gemacht?

Wir arbeiten ab jetzt nur noch mit einer PHP-Datei für unser Plugin, da nehmen wir genau die adressen-tabelle.php aus den vorigen Beiträgen. Die ergänzen wir um einen Eintrag, der eine „elternlose“ Submenu-Seite definiert:

add_action(‚admin_menu‘, ‚Edit‘);

 function Edit(){
add_submenu_page( ‚null‚, ‚Adresse Edit‘, ‚Adresse Edit‘, ‚administrator‘, ‚adresse-edit‘, ‚AdresseEditAusgabe‚ );
 }

Das ‚null‚ im ersten Tag (das ist der für den Parent) ist hier der Knackpunkt. Das bewirkt, dass die Seite zwar aufrufbar ist, aber nicht im Admin Screen Menü auftaucht.

Der letzte Tag AdresseEditAusgabe definiert die Funktion, die bei Aufruf unseres Submenüs ausgeführt wird. Die müssen wir natürlich noch schreiben, aber das wird easy. Da kopieren wir uns einfach den gesamten Inhalt unserer Unterseite edit-adresse.php rein und schmeissen den jetzt überflüssigen WordPress-Load raus. Das wars schon… fast.

Der Aufruf unserer funkelnagelneuen Submenu Page

Der muss natürlich noch ins Action-Tag unserer aufrufenden Seite. Da tauschen wir einfach die Belegung für die Variable aus:

/*Submenu-URL zusammenbauen*/        
        $meinplugin_URL = admin_url();
        $meinplugin_URL = $meinplugin_URL.“admin.php?page=adresse-edit„;

Das admin_url() holt uns die Adresse des Admin Screens, die fett gekennzeichnete Ergänzung enthält den Slug unserer Submenu Seite.

Klappts? Wenn sie jetzt aus der Adressentabelle heraus auf einen „Edit“-Button klicken, sollte sowas ähnliches angezeigt werden:

submenu_adminscreen

submenu_adminscreen

Schon besser, oder?

Und man spart sich wie gesagt den nicht ganz sauberen Trick mit dem wp-load, da werden auch die Puristen zufrieden sein. Man spart sich auch die zweite PHP-Datei, weil jetzt die ganze Funktionalität in unserer einen Plugin-Datei adressen-tabelle.php steckt. Ich finde die Lösung mit der „elternlosen“ Submenu Page sauber, und sowas wird man immer wieder mal gebrauchen können, wenn man in einem Plugin auf eine Unterseite verzweigen möchte. Hier noch die Plugin-Datei adressen-tabelle.php als ZIP, der Vollständigkeit halber. Und jetzt viel Spaß beim Nachbauen!

 

Ein Dirty Trick: wir holen uns die wp-load.php

Wo ist unser wpdb-Objekt geblieben?

In unserer „nackten“ PHP-Datei steht es nämlich erstmal nicht zur Verfügung. Um jetzt aber trotzdem ranzukommen – wir wollen ja schließlich wieder mit $wpdb->get_results und all den praktischen Helferlein arbeiten – gibt es eine einfache, wenn auch unter WordPress-Puristen umstrittene Methode. Man holt sich mithilfe einer require()-Anweisung die Datei wp-load.php ins Boot, und schon kann man die WordPress-Funktionalitäten wieder nutzen. Wo diese Datei liegt, ist abhängig von der jeweiligen WordPress-Installation, normalerweise steckt sie im Stammverzeichnis, da wo auch wp-config.php und Konsorten zu finden sind. Falls sie also da zu finden ist, kann man sich so behelfen:

require(‚../../../wp-load.php‘);

Das ist natürlich nicht besonders Foolproof und fällt auf die Nase, wenn die Datei woanders liegen sollte.

Sauberere Methode – wenn auch etwas kryptisch

Eigentlich hasse ich es ja, Code zu verwenden, den ich nicht ganz verstehe. Aber hier mache ich mal eine Ausnahme, es funktioniert nämlich einwandfrei. Das Code Snippet stammt von Frankie Jarrets Seite, und dort kann man auch nachlesen warum man es so NICHT machen sollte…

Statt dem wie oben codierten absoluten Pfad kann man nach Frankie folgende Lösung verwenden:

$parse_uri = explode( ‚wp-content‘, $_SERVER[‚SCRIPT_FILENAME‘] );
require_once( $parse_uri[0] . ‚wp-load.php‚ );

Wie dem auch sei, wir holen uns halt unsere wp-load.php, auch wenn die Puristen Zetermordio schreien. Für unser kleines Adresseneditor-Plugin tuts diese Lösung wirklich, da werden wir keine Probleme mit Serverlast Verdopplung etc. zu erwarten haben.

Hurra, das wpdb-Objekt ist wieder da!

Und deshalb können wir den Code aus unserem ersten Adresseneditor-Plugin (fast) unverändert übernehmen. Die ID für den aktuellen Datensatz haben wir ja schon, die steckt in:

$akt_id = $_POST[„id“];

ganz am Anfang der Datei edit-adresse.php und kommt aus unserem aufrufenden Formular.

Der Select

… ist jetzt wie gehabt:

global $wpdb;
        $alleposts = $wpdb->get_results( „SELECT * from „.MAINTABLE.“ where ID = „.$akt_id.““);
      

Kleiner Negertrick in der Foreach-Schleife

Wenn wir den Foreach auch ungeändert übernehmen, kommt es nach dem Editieren des Datensatzes und Drücken des „Änderungen speichern“-Buttons zu einem unerwünschten Effekt: die Formularfelder werden auf die ursprünglichen Werte zurückgesetzt. Das führt natürlich zu heftiger Verwirrung beim Anwender, weil seine Änderungen plötzlich verschwunden sind. Dabei sind sie doch schon in der Datenbank gespeichert! Ich mach da mal kurzen Prozess und unterbinde die Anzeige des Formulars, wenn auf den „Änderungen speichern“-Button gedrückt wurde, dann siehts sauberer und für den Anwender besser logisch verständlich aus. Dazu binde ich eine IF-Abfrage mit ein, hier unten fett hervorgehoben:

foreach ( $alleposts as $einpost ) {     
    
//Begin Formular
echo ‚<form method=“post“>‘;

        if (!isset($_POST[’speichern‘])){
            echo „<div style = ‚border: 3px solid blue; padding: 10px; display: inline-block‘>“;
        echo ‚ID: &nbsp‘.$einpost->id.'<input type=“text“ name=“id“ value = „‚.$einpost->id.'“ hidden/></br>‘;
        echo ‚Vorname: <input type=“text“ name=“vorname“ value = „‚.$einpost->vorname.'“/></br>‘;
        echo ‚Nachname: <input type=“text“ name=“nachname“ value = „‚.$einpost->nachname.'“></br>‘;
       
        echo ‚<input type=“submit“ name = „speichern“ value=“Änderungen speichern“/>‘.“<br>“;
        } //end von nicht isset
        echo „</div>“;
        
echo ‚</form>‘;
// End Formular
    
} //end foreach

Damit verschwindet das Formular, sobald auf den „Änderungen speichern“-Button geklickt wurde.

Der Update wie gehabt

An der Update-Logik ändert sich auch nicht das Geringste, die übernehmen wie 1:1.

Zurück zur Adressenliste

Jetzt fehlt noch ein Link zurück zur Adressenliste, und auch das mach ich kurz und schmerzlos mit der URL der ersten Seite des Plugins:

echo „<a href = ‚http://localhost/turnverein/wp-admin/admin.php?page=adressen-tabelle’/><h1>Zurück zur Adressenliste</h1></a>“;

Sie müssen hier natürlich ihre eigene URL einsetzen, aber das sollte ja nun wirklich kein Problem sein. Funktionierts? Nach dem Klick auf  „Zurück zur Adressenliste“ sollte jetzt natürlich wieder unsere Adressentabelle auftauchen, mit den eben gemachten Änderungen.

Funktioniert – aber wie sieht denn das aus? Nacktes PHP!

Gemach, gemach, hier ging es um die Funktionalität. Zugegeben, besonders schön ist das nicht mit dem „weissen“ Unterformular ohne die gewohnte WordPress-Umgebung, aber das zu ändern ist nicht wirklich einfach, da bin ich noch am Forschen. Die Lösung könnte evtl. in diesem Artikel stecken oder auch hier, aber da bin ich noch nicht ganz durch. Ich halte euch auf dem Laufenden, wenn da mal eine Lösung in Sicht kommt.