Von Access nach WordPress

WordPress ist das gängigste System für die Erstellung und Pflege eines Blogs. Mittlerweile gibt es so viele Erweiterungen, dass ein Blog nur noch eine von vielen Möglichkeiten ist, eine Webseite über die WordPress-Plattform zu bauen. Da für Access im Unternehmen der Umzug auf ein moderneres System anstand, haben wir uns für WordPress entschieden. Es bietet gleichzeitig viele Möglichkeiten und ist dennoch recht einfach zu bedienen. Das gilt allerdings auch nur, wenn Sie keine besonderen Anforderungen haben – was in unserem Fall anders aussieht: Immerhin sollen mehr als 1.000 Beiträge samt Bildern und Downloads übertragen werden. Und es darf auch nicht jeder alle Beiträge vollständig betrachten, sondern nur über eine Benutzerverwaltung erfasste Abonnenten. Wie wir das realisiert haben, zeigen wir in diesem Beitrag.

Aus Alt mach Neu

Am Anfang stand die Erkenntnis, dass das im Jahre 2003 aufgesetzte Typo3-System zwar noch klaglos seinen Dienst tut, aber leider nicht der Server, auf dem das Content-Management-System läuft. Bei einem 16 Jahre alten Gerät muss man sich freuen, dass es überhaupt noch läuft. Leider wurden keine regelmäßigen Updates gemacht, sodass es nur mit erheblichem Aufwand möglich gewesen wäre, das System nochmal auf eine aktuellere Version zu übertragen. Also musste ein neues System her, und zwar WordPress.

Zwei WordPress-Varianten

Es gibt zwei WordPress-Varianten: WordPress.com bietet die Software inklusive Hosting an. Sie melden dort eine neue WordPress-Seite an und bekommen die komplette Infrastruktur gestellt. Dafür gibt es allerdings auch Einschränkungen: Sie können nicht nach Lust und Laune auf Datenbank, Dateien und sonstige Elemente zugreifen, was unseren Spieltrieb und auch die Flexibilität erheblich einschränkte.

Die zweite WordPress-Variante findet sich auf WordPress.org zum Download und kann auf Ihrem eigenen oder gemieteten Webserver installiert werden. Einige Anbieter bieten auch Pakete an, auf denen alle Voraussetzungen für den Einsatz von WordPress vorliegen. Hier können Sie je nach den durch den Hoster angebotenen Möglichkeiten auf alle notwendigen Bereiche zugreifen, also auf die Datenbank, das Dateisystem und mehr. Diese Variante haben wir gewählt. Als Hoster nutzen wir aixpro.de.

Voraussetzungen

Schon unter Verwendung des in die Jahre gekommen Typo3-Systems sah der Workflow für die Veröffentlichung der Beiträge wie folgt aus: Die Beiträge wurden in InDesign geschrieben und gesetzt.

Von dort haben wir die PDFs für den Drucker erstellt und auch die für den Downloadbereich für registrierte Abonnenten. Außerdem haben wir daraus per VBA eine HTML-Version erstellt, die wir in einer Access-Datenbank gespeichert haben.

Es gibt eine Tabelle für die Beiträge namens tblBeitraege, eine Tabelle für die Kategorien (tblKategorien) sowie eine Verknüpfungstabelle, damit wir den Kategorien die Beiträge zuweisen konnten (tblBeitraegeKategorien). Dies sind die wesentlichen Tabellen, die wir für die Übertragung der Inhalte in das WordPress-System benötigen. In der Beispieldatenbank haben wir diese Tabellen mit ein paar Beispielartikeln im HTML-Format untergebracht.

Wichtig ist noch zu wissen, dass die HTML-Version mit Verweisen auf Bilder versehen sind, die sich in einem speziellen Unterverzeichnis befinden. Dieses kann man also so, wie es ist, auf den Webserver legen.

Und auch die Beispieldatenbanken und sonstige Downloaddateien liegen in einer bestimmten Verzeichnisstruktur vor, die man problemlos so auf den Server übertragen kann. Hier sind nur die Verlinkungen in den Beiträgen noch anzupassen.

Eine weitere Voraussetzung ist natürlich das Vorhandensein einer WordPress-Installation, auf deren SQL-Datenbank Sie auf irgendeinen Weg Zugriff haben – mehr dazu weiter unten.

Ins HTML-Format

Wenn Sie Beiträge aus einer Datenbank in eine WordPress-Anwendung übertragen wollen, ist es sinnvoll, wenn diese Daten bereits im HTML-Format in der Tabelle tblBeitraege gespeichert sind. Aber woher überhaupt kommen die Beiträge, die Sie mit der Datenbank verwalten und nach WordPress überführen wollen In meinem Fall kommen diese, wie oben beschrieben, aus InDesign. InDesign bietet die Möglichkeit, Dateien in das HTML-Format zu exportieren. Das Ergebnis dieses Exports war jedoch für meine Zwecke nicht passend, sodass ich den Export selbst programmiert habe.

Da vermutlich nicht viele Entwickler mit InDesign arbeiten werden, hier nur eine kurze Zusammenfassung: InDesign bietet eine VBA-Bibliothek für den VBA-gesteuerten Zugriff auf das Objektmodell. Auf dieser Basis habe ich einen Satz von Routinen geschrieben, die das InDesign-Dokument Absatz für Absatz durchlaufen und prüfen, welches Absatzformat vorliegt, und einen entsprechenden HTML-Absatz daraus erstellen. Aus einem Absatz mit dem Absatzformat Fliesstext wird dann etwa ein Text, der von den entsprechenden HTML-Tags eingefasst wird, beispielsweise

.

Die Programmierung geht jedoch über diese recht einfache Vorgehensweise hinaus, denn die Texte enthalten auch Verweise auf Bilder oder Listings in Kästen. Diese werden von den Routinen identifiziert und entsprechend behandelt. Bei einem Bild, das im InDesign-Satz unabhängig vom Fließtext in einem Kasten an beliebiger Stelle im Dokument platziert ist, landet etwa das -Element direkt hinter dem

-Absatz, der im Originaldokument auf das Bild verweist.

Gleiches gilt für Kästen mit Listings. Die Bilder im InDesign-Dokument werden ähnlich wie in Word über Verknüpfungen angezeigt. Diese Verknüpfungen können wir auch über VBA auslesen und so den Pfad der angezeigten Bilder ermitteln.

Die Bilder aus dem Originaldokument kopiere ich dann ebenfalls per VBA in ein Verzeichnis, das alle Bilddateien für das entsprechende Dokument enthält.

Damit erhalte ich also für jeden Artikel einen Datensatz in der Tabelle tblBeitrage, der den Titel des Artikels in einem Feld enthält, außerdem die Ausgabe, das Erscheinungsjahr und den HTML-Code in einem Memofeld.

Die Kategorie des Artikels füge ich dann selbst über die Benutzeroberfläche hinzu. Und auch die Ausgabe und das Erscheinungsjahr wähle ich im Formular für die importierten Artikel aus. Damit ergibt sich dann das Datenmodell aus Bild 1.

Datenmodell der Access-Anwendung

Bild 1: Datenmodell der Access-Anwendung

Formular zur Anzeige der Beiträge

Um die Prozeduren zum Erstellen der WordPress-Daten aufrufen zu können, erstellen wir uns noch ein Formular namens frmBeitraege, mit dem wir die einzelnen Datensätze der Tabelle tblBeitraege anzeigen (siehe Bild 2). Aus dieser Tabelle zeigen wir dabei die Werte der Felder BeitragID, Titel, Jahr, Ausgabe, Kurztext und Inhalt an.

Formular mit den Beiträgen und den Schaltflächen zum Übertragen nach WordPress

Bild 2: Formular mit den Beiträgen und den Schaltflächen zum Übertragen nach WordPress

Außerdem liefert ein Unterformular namens sfmKategorien die Daten der Verknüpfungstabelle tblBeitraegeKategorien, genau genommen die des Feldes KategorieID. Damit können wir die zugeordneten Kategorien auswählen.

Unten im Formular legen wir zwei Schaltflächen an. Die erste heißt cmdBeitragNachWordpress. Sie soll den aktuell angezeigten Beitrag behandeln. Die zweite namens cmdAlleNachWordpress soll sich um alle Beiträge kümmern, die sich in der Tabelle tblBeitraege befinden.

Was aber heißt „behandeln“ oder „kümmern“ in diesem Fall Das müssen wir noch klären.

Übertragen der Artikel nach WordPress

Es gibt verschiedene Möglichkeiten, wie wir die HTML-Artikel nach WordPress übertragen. WordPress hat logischerweise ebenfalls eine Datenbank, welche die enthaltenen Artikel und weitere Daten speichert. Theoretisch könnten wir die Tabellen dieser meist unter MySQL verwalteten Datenbank in unsere Access-Datenbank einbinden und so direkt auf diese Tabellen zugreifen. Aus Sicherheitsgründen bieten die meisten Provider dies jedoch nicht an.

Das Übertragen von Daten aus den Tabellen einer lokalen Tabelle in die verknüpften Tabellen einer Datenbank auf einem Webserver ist aber auch nicht besonders herausfordernd.

Also gehen wir direkt den alternativen Weg, der von den meisten Providern angeboten werden sollte: die Möglichkeit, SQL-Skripte auszuführen. Das können Sie, wenn Sie kompletten Zugriff auf den Server etwa über eine Konsole haben, erledigen, indem Sie die Datei mit den entsprechenden SQL-Anweisungen auf den Server kopieren und diese dort in der Konsole aufrufen.

Unser Provider Aixpro stellt uns eine komfortable Benutzeroberfläche für die Verwaltung unserer Webseiten zur Verfügung stellt.

Die Benutzeroberfläche heißt Plesk und bietet die Möglichkeit, die Webseiten zu administrieren, Dateien zu verwalten und ein Tool für den Zugriff auf die SQL-Datenbanken zu öffnen, nämlich phpMyAdmin.

Diese Tools sind wirklich sehr hilfreich, wenn es um die Verwaltung von Webanwendungen geht. phpMyAdmin bietet die Möglichkeit, SQL-Skripte als Datei hochzuladen und diese direkt in der aktuell angezeigten Datenbank auszuführen.

Unser Ziel ist es also auf jeden Fall, eine Datei mit den auszuführenden SQL-Anweisungen zu erstellen, die wir dann auf dem Webserver laden und dort ausführen können. Dies ist dann auch der kleinste gemeinsame Nenner für die verschiedenen Konfigurationsmöglichkeiten für eine WordPress-Installation.

Die relevanten Tabellen von WordPress

WordPress hat in der Basisinstallation, also ohne zusätzliche Plugins, ein recht überschaubares Datenmodell. Die für uns interessanten Tabellen befinden sich auf der Übersicht des Datenmodells, die wir der Webseite https://codex.wordpress.org entnommen haben, im markierten Bereich (siehe Bild 3).

Datenmodell von WordPress

Bild 3: Datenmodell von WordPress

Die Tabelle wp_posts enthält die einzelnen Artikel. Das Feld postTitle nimmt dabei den Titel auf, das Feld post_content (im Screenshot post_content_filtered benannt) nimmt den Artikel selbst auf. Die Kategorien können wir in der Tabelle wp_Terms hinterlegen. Die Tabelle wp_term_taxonomy weist den Kategorien aus wp_terms eine Funktion zu, nämlich Kategorie, Link oder Tag, und definiert die Hierarchie der Einträge der Tabelle wp_Terms – das ist für die Erschaffung einer Kategorien-Hierarchie wichtig.

Die Hierarchie wird über das Feld parent erzeugt, das auf das Primärschlüsselfeld term_taxonomy_id der gleichen Tabelle verweist. Die Tabelle wp_term_relationsships verknüpft wiederum die Einträge der Tabelle wp_term_taxonomy und die Artikel aus der Tabelle wp_posts miteinander. Für uns ist diese Tabelle also wichtig, weil wir über diese die Artikel den Kategorien zuweisen können, die wir in der Tabelle wp_terms definiert haben.

Zu beachten

Bevor wir die Daten einfach von Access in die WordPress-Tabellen übertragen, ist etwas unter Umständen sehr wichtiges zu beachten – zumindest war das bei meinem Projekt der Fall. Die Artikel existierten ja zuvor bereits auf einer anderen Webseite, in diesem Fall einer auf Basis des CMS-Systems Typo3. Hier sind die Links auf die Artikel wie folgt aufgebaut:

http://www.access-im-unternehmen.de/index1.phpid=300&BeitragID=1

Dabei war die einzige Variable die Zahl für den Parameter BeitragID. Wenn man eine Webseite neu aufbaut, die bei Google bereits ein gutes Ranking erreicht hat, sollte man sicherstellen, dass die Adresse, unter welcher die gerankten Artikel erreichbar sind, gleich bleibt. Natürlich gibt es technische Möglichkeiten, dafür zu sorgen, dass wenn der Benutzer einen Google-Link auf die Seite anklickt, auch die auf dem neuen Server unter einer anderen Adresse gespeicherte Seite angezeigt wird. Unter WordPress sehen die Links normalerweise wie folgt aus:

http://www.access-im-unternehmen.de/p=1

Man kann nun auf dem Server bestimmte Regeln einrichten, nach denen etwa der obige, alte Link in den neuen Link umbenannt wird – das ist allerdings ein Thema, das wir in diesem Beitrag nicht mehr anreißen wollen.

Für uns ist nur interessant, dass es zum Definieren einer solchen Regel einfach ist, wenn wir den dynamischen Teil der alten Adresse, hier also den Parameter BeitragID, auslesen und diesen dann in Form des Parameters p für den Link zur neuen Webseite nutzen können.

Mein Plan war also zunächst, die Artikel in der Tabelle wp_posts genauso zu nummerieren wie in der Tabelle tblBeitraege. So wäre es dann am einfachsten, per URL auf die Artikel zuzugreifen.

Das hat auch zu Beginn gut geklappt, nämlich als die WordPress-Datenbank und speziell die Tabelle wp_posts noch komplett leer war. Dann allerdings habe ich zum Beispiel einen Beitrag bearbeitet oder Menüeinträge hinzugefügt.

Und sowohl für die Bearbeitungsstände von WordPress-Artikeln als auch für Menüeinträge werden neue Datensätze in der Tabelle wp_posts angelegt. Ich hatte zwar nun die Datensätze mit den Primärschlüsselwerten bis etwa 1.200 mit Beiträgen gefüllt und jeder dieser Artikel hatte den seiner ID entsprechenden Primärschlüsselwert.

Die angelegten Menüs und die Bearbeitungsstände der editierten Artikel haben dann allerdings die Primärschlüsselwerte ab 1.200 in Beschlag genommen – die nächsten Werte wie 1.201, 1.202 und so weiter waren also belegt. Neue Beiträge hätte ich dann also mit Lücken in den ID-Werten hinzufügen müssen. Das war erstens ein Problem, weil ich die Beitrag-IDs zumindest einigermaßen lückenlos halten wollte und zweitens die Beiträge ja bereits weit vor der Veröffentlichung in der Artikeldatenbank angelegt wurden und somit bereits feste ID-Werte erhalten haben. Also sollten diese dann auch unter den vergebenen ID-Werten in der Tabelle wp_posts landen.

Es musste also eine alternative Lösung her, die zukunftssicher war und gleichzeitig die IDs der Beiträge im Primärschlüsselfeld enthielt. Also habe ich mich entschieden, einfach eine recht große Zahl zu den IDs hinzuzuaddieren – in diesem Fall 55.000.000 – und somit für alle Zeiten genügend freie IDs für alle sonstigen Zwecke vorzuhalten. Der Beitrag mit der ID 1.201 würde also in der Tabelle wp_posts unter dem Primärschlüsselwert 55.001.201 abgespeichert werden.

Sie mögen jetzt einwerfen, dass man dann nicht mehr so einfach über einer URL wie www.access-im-unternehmen.de/1201 auf den Beitrag zugreifen kann. Das hätte natürlich gravierende Folgen, denn wir haben diese Nummern in jedem Beitrag in den gedruckten Heften angegeben, damit die Leser darunter die Downloads mit den Beispieldatenbanken zu dem jeweiligen Beitrag beziehen können.

Das ist aber auch kein Problem: Wir haben ja bereits beschrieben, dass wir auf dem Server definieren können, dass URLs geändert werden können. Und so lässt sich auch aus www.access-im-unternehmen.de/1201 relativ leicht www.access-im-unternehmen.de/p=1201 erzeugen. Der Leser soll dann also sowohl über den im Heft angegebenen Link www.access-im-unternehmen.de/1201 als auch über die bei Google gespeicherten URLs wie www.access-im-unternehmen.de/index1.phpid=300&BeitragID=1201 auf die Beiträge zugreifen können. Und das können wir durch entsprechende Regeln auch erreichen, wenn die ID eigentlich 55001201 lautet.

Löschen und neu anlegen

Gerade in der Testphase wird es oft vorkommen, dass Sie die Datensätze in der WordPress-Datenbank löschen und neu anlegen wollen. Wir haben dies in den folgenden Prozeduren berücksichtigt.

Da wir nicht nur für die Beiträge Primärschlüsselwerte in einem bestimmten Bereich verwenden wollen (ab 55.000.001), sondern auch für die Kategorien in der Tabelle wp_terms (ab 88.000.001) und für die ebenfalls dort definierten Jahre (ab 99.001) und die untergeordneten Ausgaben (ab 99.000.001), können wir die Datensätze jeweils auch wieder entfernen, damit wir sie anschließend jederzeit wieder reproduzieren können.

Das ist aber nicht der alleinige Grund dafür, dass wir auch Kategorien, Ausgaben und Jahre mit solch hohen Werten gefüllt werden sollen. Der nächste Grund ist, dass wir später noch eine Menüstruktur auf Basis der Kategorien, Ausgaben und Jahre aufbauen wollen. Und damit wir diese nicht immer wieder neu erstellen müssen, wenn wir die Kategorien, Ausgaben und Jahre neu hinzugefügt haben, verwenden wir für diese genau wie für die Beiträge immer die gleichen ID-Werte.

Beiträge und Kategorien nur per Access

Damit dies funktioniert, dürfen Sie Änderungen an Beiträgen und Kategorien natürlich nur über die Datenbank durchführen. Jede Änderung, die Sie über den Editor von WordPress durchgeführt haben, wird ja sonst bei einem erneuten Einspielen der Daten der Access-Datenbank wieder überschrieben.

Prozedur zum Übertragen der Beiträge

Beginnen wir mit der Prozedur, die durch die beiden Ereignisprozeduren des Formulars aufgerufen wird. Diese beiden Ereignisprozeduren sehen wie folgt aus:

Private Sub cmdAlleNachWordpress_Click()
     WordPressExport
End Sub
Private Sub cmdBeitragNachWordpress_Click()
     WordPressExport Me!BeitragID
End Sub

Die Prozeduren rufen beide die Routine WordPressExport auf (siehe Listing 1). Diese erwartet als optionalen Parameter eine Beitrag-ID. Wird kein Wert übergeben, nimmt der Parameter lngBeitragID den Standardwert 0 an.

Public Sub WordPressExport(Optional lngBeitragID As Long)
     Dim db As DAO.Database
     Dim rst As DAO.Recordset
     Dim strSQL As String, strSQLDelete As String, strDateiname As String
     Dim strInhalt As String, strTitel As String
     Dim strKurztext As String, strWhere As String
     strDateiname = CurrentProject.Path & "SQLBeitraege.sql"
     On Error Resume Next
     Kill strDateiname
     On Error GoTo 0
     Set db = CurrentDb
     If Not lngBeitragID = 0 Then
         strWhere = "tblBeitraege.BeitragID = " & lngBeitragID & " AND NOT " & cstrFeldInhalt & " IS NULL"
     Else
         strWhere = "NOT " & cstrFeldInhalt & " IS NULL"
     End If
     Set rst = db.OpenRecordset("SELECT * FROM tblBeitraege WHERE " & strWhere, dbOpenDynaset)
     Open strDateiname For Append As #1
     Do While Not rst.EOF
         strSQLDelete = "DELETE FROM wp_posts WHERE ID = " & 55000000 + rst!BeitragID & ";" & vbCrLf
         DoEvents
         Print #1, strSQLDelete
         rst.MoveNext
     Loop
     rst.MoveFirst
     Do While Not rst.EOF
         strInhalt = rst(cstrFeldInhalt)
         strTitel = rst!Titel
         strTitel = Ersetzen(strTitel)
         strKurztext = rst!Kurztext
         strKurztext = Ersetzen(strKurztext)
         strSQL = "INSERT INTO wp_posts(ID, post_author, post_date, post_date_gmt, post_content, post_title, " _
             & "post_excerpt, post_status, comment_status, ping_status, post_name, post_parent, guid, menu_order, " _
             & "post_type, comment_count) VALUES(" & 55000000 + rst!BeitragID & ", 1, '" _
             & format(DateSerial(rst!Jahr, rst!Ausgabe * 2, 1), "yyyy-mm-dd hh:nn:ss") & "', '" & format(Now, _
             "yyyy-mm-dd hh:nn:ss") & "', '" & strInhalt & "', '" & strTitel & "', '" & strKurztext _
             & "', 'publish', 'open', 'open', '" & Replace(Replace(rst!Titel, " ", "_"), "'", "''") & "', " _
             & "0, 'http://access-im-unternehmen.aix-dev.de/aiu/p=" & rst!BeitragID & "', 0, 'post', 0);" & vbCrLf
         Print #1, strSQL
         DoEvents
         rst.MoveNext
     Loop
     Print #1, KategorienArtikel(strWhere)
     Print #1, KategorienAusgaben(strWhere)
     Close #1
End Sub

Listing 1: Prozedur zum Erstellen des SQL-Skripts für die Beiträge

Die Prozedur legt zunächst einen Dateinamen fest – und zwar für die Datei, in der wir die SQL-Anweisungen speichern wollen, die wir zum Übertragen der Daten benötigen. Bei der in unserem Fall anfallenden Datenmenge reicht das Kopieren in die Zwischenablage zum direkten Eingeben in MySQL nicht mehr aus, daher legen wir gleich eine Datei mit dem Namen SQLBeitraege.sql im Verzeichnis der aktuellen Datenbank an. Danach löschen wir die Datei, falls diese schon vorhanden ist. Dann erstellen wir für die Variable db einen Verweis auf das aktuelle Database-Objekt.

Die folgende If…Then-Bedingung stellt eine WHERE-Klausel für die zu berücksichtigenden Beiträge zusammen. Diese legt auf jeden Fall fest, dass das Feld, dessen Namen wir in der Konstanten cstrFeldInhalt festlegen, nicht Null sein darf und welche Beiträge abhängig vom übergebenen Wert für den Parameter lngBeitragID berücksichtigt werden sollen. Die Konstante cstrFeldInhalt haben wir festgelegt, damit wir das Feld, das den Inhalt liefert, flexibel an einer Stelle ändern können.

Danach füllen wir eine Recordset-Variable namens rst mit einer Abfrage, die Daten der Tabelle tblBeitraege liefert – abhängig davon, ob einer oder alle Beiträge berücksichtigt werden sollen. Danach legt die Prozedur mit der Open-Anweisung die zu füllende Textdatei an.

In einer Do While-Schleife über alle Datensätze des Recordsets stellt die Prozedur in der Variablen strSQLDelete eine Anweisung zusammen, welche den Eintrag aus der Tabelle wp_posts löscht, dessen ID-Wert der Zahl 55.000.000 plus dem Primärschlüsselwert aus der Tabelle tblBeitraege entspricht. Der Inhalt der Variablen strSQLDelete wird dann mit der Print-Anweisung in die Textdatei geschrieben. Diese Anweisungen sehen dann beispielsweise wie folgt aus:

DELETE FROM wp_posts WHERE ID = 55000001;

Nachdem so alle DELETE-Anweisungen in die Textdatei geschrieben wurden, springen wir mit der MoveFirst-Methode wieder zum ersten Datensatz des Recordsets zurück und durchlaufen die Schleife erneut. Diesmal stellen wir in einigen String-Variablen die Werte aus dem Feldern der Tabelle tblBeitraege zusammen, die in der Tabelle wp_posts landen sollen.

Hier nutzen wir dann beispielsweise noch eine Funktion namens Ersetzen, die noch vorhandene Umlaute et cetera durch die entsprechenden HTML-Entitäten ersetzt. Diese Funktion stellen wir weiter unten vor.

Dann stellen wir die INSERT INTO-Anweisung in der Variablen strSQL zusammen. Diese Abfragen sind natürlich etwas umfangreicher, da sie unter anderem den kompletten HTML-Code enthalten:

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar