Archiv der Kategorie: Plugins

Noch mehr postmeta: benutzerdefinierte Felder in wooCommerce

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

Ein Feld für Material

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

benutzerdefinierte_felder

benutzerdefinierte_felder

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

material_postmeta

material_postmeta

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

Wie verwendet man nun diese Felder?

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

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

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

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

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

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

Anderer Ansatz: wooCommerce Hooks

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

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

Noch ein Versuch: vielleicht mit einem Plugin?

Das hier sieht ganz gut aus:

WooCommerce Custom Product Data Fields

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

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

acf_nicht_ereichbar

acf_nicht_ereichbar

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

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

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

    Any answer is most welcome, thank you.

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

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

Jetzt reichts mit der Probiererei – noch einmal mit System.

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

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

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

do_action( ‚woocommerce_shop_loop_item_title‘ );

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

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

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

shop_mit_cf

shop_mit_cf

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

Wie gehts jetzt weiter?

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

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

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.

 

 

 

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.

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.

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.

 

 

 

 

 

Tabelleneditor Nachschlag: Adressenliste als Ausgangspunkt

Ihr Wunsch ist mir Befehl: Tabellarische Adressenliste

Ich bin gebeten worden, einmal exemplarisch darzustellen, wie man den Tabelleneditor ausgehend von einer Liste aller Mitglieder aufruft. Das ist jetzt zwar echt wieder reines PHP, aber wenns gewünscht wird, na bitte, dann machen wir das auch noch. Wie soll das ganze aussehen? Also, zuerst zeigen wir mal eine Liste ausgewählter Mitgliederdaten an. In jeder Tabellenzeile soll es einen „Edit“-Button geben, und der soll das Tabelleneditorfenster zum aktuellen Datensatz aufmachen, hier die Funktionalität wie gehabt mit editieren und speichern der einzelnen Felder. Von hier aus solls auch wieder zurückgehen in die tabellarische Übersicht. Soweit OK?

Damit das nicht langweilig wird, arbeiten wir mit einer zweiten PHP-Datei für das Editor-Fenster, da kommen dann noch ein paar kleine Tricks mit dazu, wie man die WordPress-Funktionalität in eigenen PHP-Skripten nutzen kann, aber dazu später mehr, jetzt fangen wir mal ganz langsam an.

Die Ausgangsbasis: Tabellarische Mitgliederliste

Das ist auch nichts Neues, wir lassen einen Select* auf unsere Adressentabelle los und bauen uns erstmal eine tabellarische Ausgabe ausgewählter Felder. Das haben wir schon oft genug gemacht, das stell ich mal kommentarlos hier hin.

/*****Haupttabelle Name als Konstante definieren*******/
        define(„MAINTABLE“,“mitglieder_stamm“);
        echo „<h2>Mitglieder Adressenliste</h2>“;
        echo „Aktuelle Tabelle =&nbsp“.MAINTABLE.“<br>“;
        
        //Originalcode alle Datensätze holen
        global $wpdb;
        $alleposts = $wpdb->get_results( „SELECT * from „.MAINTABLE.““);

echo „<table‘>“;    
    
    // Titelzeile ausgeben
    echo „<thead>“;
    echo „<th>ID</th><th>Vorname</th><th>Nachname</th><th>PLZ</th><th>Ort</th><th>StrasseHausnr</th>“;
    echo „</thead>“;

    echo „<tbody>“;
    //Eine Zeile pro Datensatz ausgeben
    foreach ( $alleposts as $einpost ) {     
        
        echo „<tr><td>“.$einpost->id.“</td>“;
        echo „<td>“.$einpost->vorname.“</td>“;
        echo „<td>“.$einpost->nachname.“</td>“;
        echo „<td>“.$einpost->plz.“</td>“;
        echo „<td>“.$einpost->ort.“</td>“;
        echo „<td>“.$einpost->strassehausnummer.“</td>“;
        echo „</tr>“;
    }
    echo „</tbody>“;
echo „</table>“;
//Ende Originalcode Datensätze holen

Wo kommt jetzt unser „Edit“-Button hin?

In ein Formular natürlich. Das wickeln wir wieder in unsere Foreach-Schleife mit ein, mit einer entscheidenden Änderung: das Formular kriegt einen Action-Tag, in dem wird definiert, welche Datei beim Klicken auf den Submit-Button aufgerufen werden soll. Das sieht so aus:

foreach ( $alleposts as $einpost ) {     
        
        echo ‚<form method=“post“ action = „‚.$meinplugin_URL.'“>‘;
        echo „<tr><td>ID: &nbsp“.$einpost->id.“<input type=’text‘ name=’id‘ value = „.$einpost->id.“ hidden/></td>“;
        echo „<td>“.$einpost->vorname.“</td>“;
        echo „<td>“.$einpost->nachname.“</td>“;
        echo „<td>“.$einpost->plz.“</td>“;
        echo „<td>“.$einpost->ort.“</td>“;
        echo „<td>“.$einpost->strassehausnummer.“</td>“;
        echo ‚<td><input type=“submit“ name = „edit“ value=“Edit“/>‘;
        echo ‚</form></td>‘;
        echo „</tr>“;
        
    } // end foreach

Definition der aufzurufenden PHP-Datei

Hoppala! Was hat das $meinplugin_URL zu bedeuten? Das ist eine Variable, auf die ich vorher die aufzurufende Datei mit dem kompletten Pfad gelegt habe. Die Variablendefinition sieht so aus:

/*Pfad zum plugin-Verzeichnis*/
$meinplugin_URL = plugins_url();
/*Verzeichnis des aktuellen Plugins dranhängen*/
$meinplugin_URL=$meinplugin_URL.‘/adresse-tabelle/edit-adresse.php‚;

Ich hole mir erst mit der Funktion plugins_url() den Pfad zum Plugins-Verzeichnis meiner WordPress-Instanz. Dann hänge ich noch das Verzeichnis meines Plugins und den Namen der aufzurufenden Datei dran. Die Datei muss natürlich existieren, deswegen legen wir sie uns zum Testen jetzt einfach an. Sie muss erstmal gar nix machen ausser:

<?php
echo „Ich bin die Datei edit-adresse.php“;
?>

Soweit alles Roger? Wenn das Plugin aktiviert ist, sollte es jetzt etwa so aussehen:

adressenliste_edit

adressenliste_edit

Und was kommt bei Klick auf einen Edit-Button?

Nicht viel, wir haben ja nicht viel gemacht. Ein grosses weisses Browserfenster, auf dem nur steht:

Ich bin die Datei edit-adresse.php

Wo ist unsere WordPress-Umgebung hinverschwunden? Header und Sidebars und das Titelbild und alles – nix da, aber auch gar nix. Tscha, so einfach ist das nicht mit unserer „nackerten“ PHP-Datei, aber darum kümmern wir uns später, jetzt geht es erstmal um die Funktionalität.

Wir brauchen die ID des aktuellen Datensatzes!

Und die kriegen wir auch, nämlich aus unserem abgeschickten Formular. Wir ergänzen die Datei edit-adresse.php so:

<?php
$akt_id = $_POST[„id“];
echo „Ich bin die Datei edit-adresse.php und die aktuelle ID ist: &nbsp“.$akt_id;
?>

Für das $_POST[„id“] muss natürlich der Feldname aus dem Formular stimmen, sonst klappt das nicht. Aber wenn das alles hinhaut, sollte die Ausgabe jetzt so aussehen:

Ich bin die Datei edit-adresse.php und die aktuelle ID ist:  7

Vorausgesetzt, sie haben den Datensatz mit der ID 7 angeklickt. Also, damit kann man jetzt arbeiten. Wir zeigen den Datensatz zur aktuellen ID an und machens mit dem editieren und speichern ganz genauso wie im vorigen Plugin. Oder doch nicht?

Uns fehlt noch das wpdb-Objekt!

Das steht nämlich in unserer Datei edit-adresse.php so wie sie ist erstmal nicht zur Verfügung. Noch nicht, wir holen uns die Funktionalität schon noch, aber dazu gibts einen neuen Beitrag.

Datenbankeditor die Letzte: Source als ZIP und Ausblick

Der Datenbankeditor kann jetzt marschieren

Das war jetzt (fast) reines HTML/PHP, und man kann das Prinzip des Datenbankeditors ja auch auf MySQL-Tabellen ausserhalb von WordPress anwenden, dann gehts halt nicht mit der $wpdb->update Methode, sondern mit einem pdo und einem Prepared Statement. Das hat jetzt aber wirklich gar nichts mehr mit WordPress zu tun, da schenke ich mir jetzt eine längere Erklärung und verweise für den Update in PHP auf diesen Artikel . Lieber gebe ich hier noch einen kleinen Ausblick.

Editor für alle Fälle, für jede eigene Tabelle

Jedenfalls habe ich hoffentlich verständlich dargestellt, wie man in WordPress Datensätze aus beliebigen MYSQL-Tabellen anzeigen, editieren und wieder wegschreiben kann. Diese Funktionalität ist immer wieder mal gefragt, besonders wenn man mit eigenen Tabellen arbeitet, für die hat man ja in WordPress erstmal kein Benutzerinterface. Ich habs jetzt mal als Plugin gezeigt, das nur der Admin bedienen darf. Wenn sie einen Tabelleneditor für die Benutzerseite anlegen wollen, packen sie die Funktionalität in einen Shortdode, geht genauso.

Man könnte jetzt noch ehrgeizig werden und zum Beispiel statt der manuellen Eingabe der ID (in unserem Fall der Mitgliedsnummer) auch die Auswahl aus einer Liste anbieten wollen, oder man könnte eine Liste aller Mitglieder ausgeben und nach jedem Datensatz einen „Ändern“-Button anzeigen, der dann  in den Datenbankeditor springt, oder oder oder… aber da gehts echt verschärft nach PHP, das darf sich jeder selber austüfteln.

Jetzt gibts noch wie versprochen hier das Plugin adressen-editor als ZIP-Datei, und damit lassen wir es gut sein. Viel Spaß beim Anpassen an ihre eigenen Tabellen!