Als ich damals unsere Beiden WordPress-Blöge (oder Blogs, oder wie schreibt man das? *kopfkratz*) zusammengelegt hab, bin ich über den Standard Export und Import von WordPress gegangen. Hierzu werde ich Mal einen gesonderten Artikel verfassen, allein schon deswegen, weil ich selbst dazu nichts im Netz gefunden hatte. Wie dem auch sei… das klappte trotz der knapp 100GB an Daten und Bildern recht gut, wobei ich die Bilder im Hintergrund per FTP umgezogen habe. Obwohl zu Beginn auf dem ersten Blick alles gut aussah, waren beim zuletzt importieren Blog (der von Hoochi) die falschen Bilder zu sehen. Kommt Euch das bekannt vor und sucht Ihr nach einer Lösung, so könnte Euch dieser Artikel – sprichwörtlich – den Arsch retten! Also verlieren wir keine Zeit und fangen an!
On Your Mark!
Bevor wir aber weiter einsteigen, gibt es einen kleinen Disclaimer, welcher eigentlich jedem klar sein sollte…
Wir hantieren hier am offenen Herzen, direkt im Hintergrund von WordPress und direkt auf mySQL-Ebene sowie mit einem direkten Inject über PHP-Snippets. Es gibt keine direkten Sicherheitsmechanismen bei allen folgenden Ausführungen, darum gilt auch hier: BACKUP, BACKUP, BACKUP!
Als langjähriger Entwickler gebe ich Euch zudem folgenden Rat und hoffe Ihr beherzigt diesen auch: Versucht zu verstehen was hier passiert und nutzt nicht stumpf einfach nur “copy & paste”. Das hilft Euch in der Regel überhaupt gar nicht und schon gar nicht wenn etwas nicht so tut wie es soll, was hier durchaus passieren kann!
Ich werde hier gewisse Dinge im Übrigen nicht näher erläutern. Wenn Euch Begriffe wie mySQL, Datenbanken, PHP und Codes fremd sind, steigt aus. Lernt zunächst die Basics und kommt dann nochmal zurück. Klingt doof, isses aber nicht, sondern einfach nur ehrlich. Das hier ist kein “try & error” sondern tatsächlich ein “dead or alive” für Euren Blog.
So, nachdem wir also das geklärt und die Sympathien verteilt hätten *lach*, steigen wir ein.
Die Ausgangslage
Nachdem ich den Merge der beiden Instanzen durchgeführt hatte, sahen die Beiträge von Hoochi etwas komisch aus. Nein. Nicht der Text… der passte. Es waren mehr die bildlichen Inhalte. Hierbei jedoch nicht die in den Beiträgen hinzugefügten einzelnen Bildern, sondern jene die durch die Standard WordPress Galerie zu sehen waren.
Hier zwei Beispiele. Seht ihr die wunderschönen Kaminöfen? Nein? Wie wärs mit…
…der harten Gartenarbeit? Auch nicht?
Also ich weiß ja nicht. Aber wenn Kaminöfen wie das innere eines Flugzeuges aussehen, dann stimmt was nicht und natürlich… manchmal landet etwas vom Garten in den Tellern, allerdings nicht gerade irgendwelche gefällten Bäume. Hier stimmte also etwas gewaltig nicht…
Ich kontrollierte alle Blogbeiträge von Hoochi und ausnahmslos alle waren fehlerbehaftet. Allerdings nur bei Ihr.
Woran konnte das liegen? Ich erkläre es Euch…
Die Ursache
Wenn ein Import durchgeführt wird, werden natürlich auch die Bilddaten migriert. Wir hatten den Vorteil, dass wir bei unseren Kameras in den Dateinamen eineindeutige Prefixe verwendet haben. Dadurch konnten somit keine Bilder doppelt vorkommen.
Wir folgen nun dem Beispiel. Was Ihr nachfolgend seht ist erstmal die URI zu dem Bild. Nach dem Merge noch mit der jeweils “falschen” URI aus dem jeweils anderen Blog.
www.dasflosen.de/wp-content/pictures/2023/01/fa_bild1.jpg
www.hoochiswelt.de/wp-content/pictures/2023/01/ho_bild1.jpg
Das ist schon Mal nicht schlecht, weil nachdem in der Datenbank die URL zu www.schickischmi.de geändert wurde, lag immer noch die Eineindeutigkeit durch den Dateinamen vor.
Die Umbenennung in der Datenbank kann übrigens über ein “Find and Replace”-Wordpress-Plugin direkt vorgenommen werden. Das Plugin habe ich früher schon benutzt, wenn die BlogURI sich ändert und man Pingbacks etc. behalten möchte. Diese werden bei einem URI-Wechsel nämlich ebenfalls nicht geändert!
Anbei die Eineideutigkeit selbst mit identischen Pfadangaben:
www.schickischmi.de/wp-content/pictures/2023/01/fa_bild1.jpg
www.schickischmi.de/wp-content/pictures/2023/01/ho_bild1.jpg
Das Problem sind nun allerdings nicht die Einzelbilder, sondern die WordPress-Galerien selbst. Diese enthalten nicht direkt die URI zum Bild, sondern nur die jeweilige Post-ID.
Wir bleiben im genannten Beispiel und ich verdeutliche das nochmals, indem ich es um die Post-ID als Präfix [ ] ergänze. Aus den getrennten Bildern, die durchaus in den zuvor eigenständigen Blog-Seiten die selbe ID haben können…
[ID=1] www.dasflosen.de/wp-content/pictures/2023/01/fa_bild1.jpg
[ID=1] www.hoochiswelt.de/wp-content/pictures/2023/01/ho_bild1.jpg
…wird die ID beim Import in der Datenbank angepasst da dieser Key eineindeutig sein muss:
[ID=1] www.schickischmi.de/wp-content/pictures/2023/01/fa_bild1.jpg
[ID=2] www.schickischmi.de/wp-content/pictures/2023/01/ho_bild1.jpg
WordPress selbst erkennt das natürlich beim Import und passt die ID’s an, bzw. das übernimmt die Datenbank im Hintergrund selbstständig, da die ID’s natürlich die Primärschlüssel darstellen. Und bevor hier fragen kommen. Ja, die Bildinformationen befinden sich ebenfalls in der “posts”-Tabelle der Datenbank. An dieser werden wir uns im Übrigen auch gleich bedienen. Ein bisschen unglücklich wie ich finde, da sich dort auch die Beiträge usw. von WordPress befinden. Quasi eine Datenbanktabelle in der sich alles befindet.
Ihr seid immer noch bei mir? Sehr gut, das war es nämlich schon und Ihr habt somit das Prinzip verstanden. Wenn man sich jetzt den Quelltext eines fehlerhaften Beitrags nun ansieht fällt auf, dass WordPress beim Import – natürlich nicht – die ID’s in den Beiträgen anpasst. Das Bild das zuvor also die “ID1” trug und nach dem Import “ID2” sein müsste, ist im Content weiterhin mit “ID1” vermerkt und zielt somit somit auf einen anderen Bildinhalt als wie gewünscht ab.
Klingt kompliziert? Naja so schlimm ist es gar nicht. Hier ein Auszug aus dem Artikel wenn wir mal in die Code-Ansicht wechseln:
In diesem Screenshot seht Ihr die falsche Galerien mit den falschen Bildern. Hinter der “ID 10827” verbirgt sich jetzt eben nicht mehr das Bild aus dem ursprünglichen Beitrag sondern ein falsches Bild. War die ID zuvor die Kettensäge aus dem Garten ist es jetzt die Flugzeugkabine. Und genau das werden wir nun ändern…
Sry wen das jetzt sehr ausführlich gewesen war, aber ich will einfach, dass man versteht um was es hier geht und was wir hier gleich tun werden.
Letzte Vorbereitungen
Bevor wir aber final loslegen, installieren wir noch kurz ein Plugin in WordPress. Da wir nicht alles auf Datenbankebene lösen können, ich kein (my)SQL-Gott bin, habe ich für die finale Aktion am Ende meine begnadeten PHP Skills ausgepackt und mir hierrüber eine kleine Hilfsfunktion gebaut und ausgeführt. Ich verwendete dieses Plugin:
Insert PHP Code Snippet – WordPress-Plugin | WordPress.org Deutsch
Es ist natürlich Euch überlassen ein anderes Snippet zu verwenden oder die Sites anders einzubauen. Evtl. könnt Ihr es auch direkt anders lösen. Für mich wars halt der schnellste Weg.
Zudem benötigt Ihr unbedingt die alten Datenbanken des vorherigen Blogs! Wenn Ihr diese nicht habt, braucht Ihr nicht mehr weiterlesen! Das ist leider Essenziell wichtig, weil wir nur so später die alten ID’s zu den Neuen zuordnen können. Oder eben umgekehrt.
Der Schlachtplan
Bevor wir einsteigen möchte ich noch kurz ein paar Begrifflichkeiten erklären, damit Ihr mir gedanklich folgen könnt.
Sourceblog = alter Blog von Hoochi
SourceDB = alte Datenbank vom alten Blog von Hoochi
Targetblog = neuer Blog -> Schickischmi
TargetDB = neue Datenbank des Merges
Tableprefix = es werden folgende Prefixe der WordPress-Tabellen verwendet: hw_ = hoochiswelt, puew_ = schickischmi
Kommen wir also nun zum pratikschen Teil. Theorie hatten wir genug. Hier nochmal unser Fahrplan was Euch erwarten wird:
SourceDB:
- Alle ID’s aus allen veröffentlichten Blogpost innerhalb des Gallery-Tags im Content extrahieren und in eine gesonderte Tabelle schreiben
- Die Tabelle entsprechend bereinigen und die ID-Strings in einzelne Zeilen aufteilen
- Tabelle exportieren
TargetDB:
- Tabelle in den neuen Blog importieren und import um 2 Spalten erweitern
- Gleiche Tabelle wie in der SourceDB in der TargetDB zum Abgleich erstellen (Punkt 1&2 aus der SourceDB werden dort also nochmal wiederholt)
- Merge der Tabelleninformationen
- Bereinigung/Ergänzung der Tabelle
- PHP Snippet erstellen
- PHP Snippet ausführen, davor noch kurz zur Beichte gehen und ID’s in den Post-Contents automatisiert ändern lassen
- Freuen oder weinen
SourceDB – Extrahieren der IDs aus den Galerie-Tags
Gehen wirs an. Wir öffnen unseren mySQL-Editor unserer Wahl und verbinden uns mit der SourceDB-mySQL. Wir wollen jetzt aus den “hw_posts” alle IDs extrahieren und in eine Zwischentabelle speichern. Der Inhalt der Blogposts ist in der Spalte “contents”.
Die Zwischentabelle nennen wir “gallery_id”. Hierzu führen wir im Editor unseres mySQL-Studios folgendes Statement aus:
CREATE TABLE
gallery_id AS
SELECT DISTINCT
p.ID AS post_id,
REPLACE(REPLACE(SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(p.post_content,'', -1),'ids="', -1), '"', ''), '</p>', '') AS gallery_ids
FROM
puew_posts p
JOIN (
SELECT
a.N + b.N * 10 + 1 AS n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS a
CROSS JOIN
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS b
) AS numbers
WHERE
p.post_type = 'post'
AND p.post_status = 'publish'
AND p.post_content LIKE '%'
ORDER BY
post_id, gallery_ids;
CREATE TABLE puew_unique_gallery_ids_with_guid (new_post_id BIGINT UNSIGNED, new_gallery_id INT,new_guid VARCHAR(255) );
INSERT INTO puew_unique_gallery_ids_with_guid (new_post_id, new_gallery_id, new_guid)
SELECT u.post_id, u.gallery_id, p.guid
FROM (
SELECT post_id,
CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(gallery_ids, ',', numbers.n), ',', -1) AS UNSIGNED) AS gallery_id
FROM new_gallery_id
JOIN (
SELECT a.N + b.N * 10 + 1 AS n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS a
CROSS JOIN
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS b
) AS numbers
ON CHAR_LENGTH(gallery_ids) - CHAR_LENGTH(REPLACE(gallery_ids, ',', '')) >= numbers.n - 1
) AS u
JOIN puew_posts p ON u.gallery_id = p.ID;
Das reicht, mehr müssen wir damit nicht tun, wir kümmern uns weiter um die von uns importierte und bereits angereicherte Tabelle aus der SourceDB.
TargetDB – Abgleich der Beiden Unique_Tabellen
Jetzt holen wir uns somit die richtige BeitragsID (PostID) in unsere importierte Tabelle aus der SourceDB. Als Schlüssel dient uns hier die GUID. Ihr erinnert Euch, wir haben die GUID geändert und der Pfad aus der GUID ist nun eineindeutig zuweißbar und perfekt für den Abgleich.
Kurz zur Veranschaulichung:
[Source GUID] www.schickischmi.de/wp-content/pictures/2023/01/ho_bild1.jpg
[Target GUID] www.schickischmi.de/wp-content/pictures/2023/01/ho_bild1.jpg
Somit holen wir uns jetzt die letzte Information über folgendes Statement:
UPDATE hw_unique_gallery_ids_with_guid t
JOIN puew_unique_gallery_ids_with_guid p ON t.old_gallery_id = p.old_gallery_id
SET t.new_post_id = p.old_post_id;
Jetzt sieht das doch schon mal nach was aus! Wir haben’s fast geschafft! Dranbleiben jetzt!
Der Beitrag “10799” aus der SourceDB entspricht in der TargetDB dem Beitrag “15400”. Die alte BildID “15054” aus dem alten Beitrag, entspricht im neuen Beitrag der BildID “15055”. Was wir aber noch sehen, sind u.U. ein paar “0”er-Einträge.
Dort hat die Zuordnung nicht ganz geklappt. Kein Problem, da wir ja gültige Zuordnungen haben und wissen dass “10799” der “15400” entspricht. Somit leiten wir daraus kurz ein Letztes und finales Statement ab:
UPDATE hw_unique_gallery_ids_with_guid AS t1
JOIN (
SELECT old_post_id, MAX(new_post_id) AS max_new_post_id
FROM hw_unique_gallery_ids_with_guid
WHERE new_post_id != 0
GROUP BY old_post_id
) AS t2 ON t1.old_post_id = t2.old_post_id
SET t1.new_post_id = t2.max_new_post_id
WHERE t1.new_post_id = 0;
Ihr könnt das Ganze im Übrigen auch nochmal Kontrollieren ob die Bilder tatsächlich auch da sind. Haben wir das aber eigentlich nicht erst? Naja, wir hätten uns da quasi selbst beschissen, denn natürlich kann das Bild über die URI aufrufbar sein wenn es im Hintergrund auf dem Server liegt, allerdings muss es auch in der WordPress Mediathek vorhanden sein! Und somit suchen wir kurz das Bild in der Mediathek. Ich würde hier ein paar Stichproben empfehlen! Betrachten wir also unser finales Werk. Wow!
Hach… eine Prachttabelle. Jetzt gehen wir rüber ins ins PHP-Snippet.
Die Finalisierung über das Snippet
Leider konnte ich die folgende Aktionen im mySQL nicht ausführen, weshalb ich mir hier WordPress und PHP zu Nutzen machte. Bisschen Coding schadet nie und es war für mich weniger aufwendiger.
Unser erstellte Tabelle wollen wir jetzt Zeile für Zeile durchgehen. Wir suchen dann in der entsprechenden “new_post_id” in der Spalte “post_content” nach der ID und ersetzen diese durch die “new_gallery_id”. Das Ganze wollen wir noch schön Protokollieren für uns damit wir auch was sehen. Wir estellen also folgenden Code:
<?php
global $wpdb;
// Select rows from your_table_name
$query = "SELECT new_post_id, old_gallery_id, new_gallery_id FROM hw_unique_gallery_ids_with_guid WHERE old_gallery_id != new_gallery_id AND new_post_id != 0 AND new_gallery_id != 0" ;
$results = $wpdb->get_results($query);
$counts = 0;
foreach($results as $rowdata){
$postId = $rowdata->new_post_id;
$oldGalleryId = $rowdata->old_gallery_id;
$newGalleryId = $rowdata->new_gallery_id;
echo "===========================<br>Starting New Row: ";
echo "<br>";
echo "Replacing...";
echo "<br>";
echo "Old Gallery ID: ";
echo $oldGalleryId;
echo "<br>";
echo "New Gallery ID: ";
echo $newGalleryId;
echo "<br>";
echo "In Post: ";
echo $postId;
echo "<br>";
echo "Replace Proccess<br>";
$updateQuery = "UPDATE puew_posts SET post_content = REPLACE(post_content, '$oldGalleryId', '$newGalleryId') WHERE ID = '$postId'";
$wpdb->query($updateQuery);
echo "Process done<br>===========================<br>";
$counts++;
}
echo "<br>===========================<br>";
echo "<br>===========================<br>";
echo "Main Rows done:";
echo $counts;
?>
Am Besten ihr versucht es zunächst mal nur an einem Beitragsblog. Ich nahm den bereits erwähnten “15400” her, welcher auch dem Eingangsbeispiel entsprach. Wichtig, es geht JETZT um die ID des Beitrags aus dem TargetBlog. Für den Test passen wir im oben aufgeführten PHP das Script noch kurz das “SELECT-Statement” an
$query = "SELECT new_post_id, old_gallery_id, new_gallery_id FROM hw_unique_gallery_ids_with_guid WHERE old_gallery_id != new_gallery_id AND new_post_id != 0 AND new_gallery_id != 0 AND new_post_id = 15400"
Jetzt speichern und ausführen. Und es sollte sich was tun!
Sieht erstmal gut aus. Wir gehen tiefer rein und checken gegen. Ihr merkt schon… Kontrolle ist immer gut und ich mag Kontrolle *lach*. Im Code-Editor des Beitrages suchen wir nach der alten ID
Fehlanzeige… keine Treffer. Gutes Zeichen! Wir suchen nach der neuen ID…
…BINGO! Wir öffnen den Artikel und siehe da… es sieht bisschen anders aus. Kaminöfen sind wieder Kaminöfen.
Und auch aus Foodporn wurde jetzt Garten
Und jetzt? Setzen wir den Filter im Snippet zurück und lassen alles durchlaufen. Das dauert jetzt u.U. etwas länger… Bei mir waren es über 2208 Bildern in den Galerien.
Und jetzt?
Freude! Wenn Ihr in Euren Posts jetzt auch wieder die richtigen Bilder seht, habt Ihr alles Richtig gemacht und ich es wohl ganz gut erklärt. Am Ende sei noch kurz gesagt:
Wenn Ihr noch Verbesserungsvorschläge habt, gerne her damit. Wahrscheinlich geht’s auch mit nem 5-Zeiler am Ende des Tages *lach* Und ja, ich mach noch nen Artikel zum allgemeinen Merge. Bis dahin… haut rein!
Schreibe den ersten Kommentar