Wie importiere ich Posts von einer externen Seite?

In diesem Tutorial erfährst Du, wie Du mit ein wenig PHP und SQL WordPress-Posts einer externen Seite abfragen und auf Deiner Seite ausgeben kannst.

Zugegeben, das Anzeigen von Artikeln aus einer anderen, aber eigenen WordPress-Seite ist sicherlich nicht ein alltäglicher Anwendungsfall.

In Verbindung mit meinem Foodblog Just Yum Yum und dem dazugehörigen Onlineshop JUST YUM YUM Kitchen kam diese Funktion aber gleich zwei Mal zum Einsatz.

Einmal um meine eigenen Rezepte auf der Startseite des Onlineshops anzeigen zu lassen, und zum anderen, um die Rezepte aus der Community JUST YUM YUM Foodies.

Die anfängliche Anmerkung „aber eigenen Seite“ spielt für das Nachfolgende eine ganz wichtige Rolle. Da wir direkt auf externe Datenbanken zugreifen werden, benötigst Du zwingend die Zugangsdaten der Quell-Datenbank.

Warum das Ganze?

Damit Du den nachstehenden Anwendungsfall besser verstehen kannst, muss ich vielleicht kurz das Setup meines Blogs etwas besser erklären.

Als mein Blog 2016 live ging, war mein ursprünglicher Plan, wirklich nur diesen einen Blog zu betreiben. Aber wie das so ist mit Plänen: sie ändern sich.

Und so sind mittlerweile sind einige Projekte dazugekommen, entweder schon fertiggestellt oder noch in der Entwicklung. Darunter ein Onlineshop, ein Foodevent-Kalender und ein Küchen-ABC.

Aufgrund meines ursprünglichen Plans habe ich die WordPress-Instanz des Blogs als sogenannten Single Site Install aufgesetzt. Da die meisten Projekte aber thematisch unter der Hauptdomain aufgehängt sind, wäre im Nachhinein vielleicht eine Installation einer WordPress Multisite sinnvoller gewesen.

„Hätte hätte, Fahrradkette…!“

Zwar wird das nachträgliche Ändern einer Single Site Installation zu einer Multisite Installation seitens WordPress unterstützt, aber nicht empfohlen. Und wenn, dann besser nur in Verbindung mit Subdomains.

Aus eigener Erfahrung kann ich nur dazu raten, dieser Empfehlung zu folgen.

Der andere Weg, wäre einer manueller Umbau der bestehenden Single Site Installation. Dies ist jedoch sehr aufwendig und risikoreich, da hier doch massiv in die bestehende Datenbank eingegriffen werden muss. Man sollte also ziemlich genau verstehen, was man da tut.

Da von Vornherein klar war, dass die neuen Projekte auch andere Themes und Plugins verwenden werden, habe ich daher einen anderen Weg gewählt: Jedes neue Projekt wird als Single Site Install in einem Unterordern der Hauptinstallation aufgesetzt.

Meine derzeitiges Setup sieht also ungefähr so aus:

Jeder Unterordner repräsentiert dabei eine eigene, von den anderen völlig unabhängige WordPress-Instanz.

Der Anwendungsfall

Auch wenn es für den Besucher aufgrund der URLs anders aussieht, sind also sowohl der Foodblog als auch der Onlineshop zwei vollkommen eigenständige WordPress-Instanzen.

Das ist dann ein Nachteil, der im übrigen auch für Mulitsite-Installationen von WordPress gilt, wenn nun Inhalte aus einer oder auch aus mehreren WordPress-Instanzen auf einer anderen Instanz angezeigt werden sollen.

Im konkreten Beispiel will ich aber nun eine inhaltliche Verzahnung zwischen meinem Foodblog und meinem Onlineshop erreichen: Es sollen zufällige Rezepte des Blogs auf der Startseite des Shops angezeigt werden.

Meine Lösungsansatz

Die Verbindung zwischen den beiden Instanzen lässt sich relativ einfach herstellen. Dazu muss die WordPress-Instanz, auf der die Inhalte angezeigt werden sollen, eine Verbindung zur Datenbank der WordPress-Instanz herstellen, auf der die gewünschten Inhalte liegen.

In meinem Fall heißt das konkret, dass der Onlineshop eine Abfrage an die Datenbank meines Foodblogs senden muss und dort die erforderlichen Daten abruft.

Dazu werden wir uns später ein SQL-Statement basteln.

Zunächst müssen wir uns jedoch überlegen, wie das Endergebnis auf der Zielseite, also im Onlineshop ausgeben werden.

Da ich für die Gestaltung der Startseite den Pagebuilder meines Themes nutze und auch die Verwendung der Ausgabe so flexibel wie möglich halten will, habe ich mich für einen sogenannten Shortcode entschieden.

Einen Shortcode definieren

In WordPress wird ein Shortcode über die Funktion add_shortcode(‚SHORTCODE‘,’FUNKTION‘) definiert.

Dabei steht SHORTCODE für den Namen des Shortcodes über den selbiger aufgerufen wird und FUNKTION für die PHP-Funktion, in der das auszuführende PHP-Skript des Shortcodes hinterlegt wird.

Im konkreten Beispiel sieht die Definition des Shortcodes dann so aus

add_shortcode( 'IMPORT_BLOGPOSTS', 'importBlogPosts' );

Unser Shortcode wird jetzt also auf den Namen IMPORT_BLOGPOSTS hören, das PHP-Skript in der Funktion importBlogPosts ausführen und das Ergebnis der Funktion anschließend ausgeben.

Nachdem wir also nun um den Shortcode definiert haben, erstellen wir uns nun die PHP-Funktion mit dem besagten Namen importBlogPosts:

function importBlogPosts($atts){
 // Here goes a punch of magic
}

Da ich meinem Shortcode aber auch noch Paramter mitgeben möchte, muss die Funktion außerdem noch die Variable $atts enthalten.

Parameter übergeben

Um dem Shortcode noch ein wenig mehr Kontrolle zu verpassen, möchte ich außerdem bestimmen können, aus welcher Kategorie die Artikel kommen sollen und wie viele Artikel später angezeigt werden sollen.

Dazu sage ich dem Shortcode, dass er die Paramter cat_id und limit verarbeiten soll. Außerdem gebe ich ihm Standardwerte für die beiden Parameter mit.

Werden im Shortcode also keine Parameter angeben, wird für die Kategorie automatisch der Wert 123 und für das Limit der Wert 3 verwendet.

$import_blogposts_values = shortcode_atts(array(
        'cat_id' => 123,
        'limit' => 3
        ), $atts );

Wird jedoch ein Parameter oder auch beide Parameter innerhalb des Shortcodes gesetzt, werden die Standardparameter mit den entsprechenden Werten überschrieben.

Beispiele:

/** BEISPIEL 1 **/
[IMPORT_BLOGPOSTS]
// Da weder für cat_id noch für limit abweichende keine Werte definiert wurden, werden die Standardwerte 123 und 3 verwendet.

/** BEISPIEL 2 **/
[IMPORT_BLOGPOSTS cat_id=456]
// der Standardwert von cat_id 123 wird mit dem Wert 456 überschrieben. Da für limit kein Wert definiert wurde, wird der Standardwert 3 verwendet.

/** BEISPIEL 3 **/
[IMPORT_BLOGPOSTS limit=5]
// Es wird Standardwert von cat_id 123 verwendet. Der Standardwert 3 für limit wird mit dem Wert 5 überschrieben.

/** BEISPIEL 4 **/
[IMPORT_BLOGPOSTS cat_id="456" limit=5]
// Es werden sowohl der Standardwert von cat_id 123 mit dem Wert 456 als auch der Standardwert von limit mit dem Wert 5 überschrieben.

Zugriff auf die externe Datenbank

Als nächsten müssen wir den Datenbank Zugriff auf die externe Datenbank definieren. Dazu verwende ich die WordPress PHP-Klasse wpdb, über die ich eine neue Datenbankverbindung zur Datenbank meines Foodblogs erzeuge.

$wpdb2 = new wpdb('db_user', 'db_password', 'db_name', 'db_host');

Um die erforderlichen Zugangsdaten zu finden, reicht ein Blick in die wp-config.php. Ersetzte die Werte

  • db_user mit Deinem Datenbank-Nutzer,
  • db_user mit Deinem Datenbank-Passwort,
  • db_name mit dem Namen Deiner Datenbank und
  • db_host mit Deinem Datenbank-Host.

Als Nächstes müssen wir noch eine Datenbankabfrage schreiben, mit der wir uns alle erforderlichen Informationen aus der Datenbank des Blogs holen.

In meinem Fall handelt es sich dabei um die IDs der Artikel, die Artikelnamen, die Auszugstexte als auch den vollständigen Texte der Artikel und die URLs der Beitragsbilder.

Alle Informationen, bis auf den Link zum Beitragsbild, finden sich der Datenbanktabelle wp_posts.

SELECT DISTINCT	wp_posts.ID,
			wp_posts.post_title,
        	wp_posts.guid,
        	wp_posts.post_excerpt,
			wp_posts.post_content,
        	featured_image.guid as post_image
FROM		wp_posts
INNER JOIN	wp_postmeta ON wp_posts.ID = wp_postmeta.post_id AND wp_postmeta.meta_key = '_thumbnail_id' 
INNER JOIN	wp_posts AS featured_image ON featured_image.id = wp_postmeta.meta_value
INNER JOIN	wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN	wp_term_taxonomy ON (wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id)
WHERE		wp_posts.post_status = 'publish' 
AND			wp_posts.post_type = 'post'
AND			wp_term_taxonomy.term_id IN (' . $import_blogposts_values['cat_id'] . ')
ORDER BY RAND()
ASC
LIMIT ' . $import_blogposts_values['limit'];

Die Werte für meine Shortcode-Parameter cat_id und limit setze ich über die PHP-Einschübe der Variablen $import_blogposts_values[‚cat_id‘] und $import_blogposts_values[‚limit‘].

Wichtig: Bei dem Tabellen-Präfix wp_ handelt es sich um das Standard-Präfix von WordPress. Idealerweise hast Du dieses Präfix bei der Installation auf ein anderes Präfix geändert. Dieses geänderte Präfix musst Du stattdessen innerhalb des SQL-Statements verwenden.

Frage und Antwort

Im nächsten Schritt verbinde ich mich nun gegen die Datenbank meines Foodblogs, setzte mein SQL-Statement ab und erhalte die angefragten Daten zurück. Die zurückgelieferten Daten speichere ich in der Variablen $blogposts_query.

Dazu verwende ich die WordPress-Klasse wpdb::get_results, die eine SQL-Abfrage ausführt und das gesamte SQL-Ergebnis zurückgibt.

$blogposts_query = $wpdb2->get_results($query, OBJECT);

Die in dieser Variable enthaltenen Daten können wir jetzt verwenden und mit Hilfe einer foreach-Schleife und etwas HTML als „sichtbare“ Inhalte ausgeben.

$_output_blogpost ='';
$_output_blogpost .='<div class="jyy-single-post-import-wrapper">';
	
foreach($blogposts_query as $blogpost){
	// predefine variables
		$_blogpost_link = $blogpost->guid;
		$_blogpost_name = $blogpost->post_title;
		$_blogpost_image_url = $blogpost->post_image;
		if(!empty($_blogpost->post_excerpt)){
	$_blogpost_description = $_blogpost->post_excerpt;
		} else {
	$_blogpost_description = $_blogpost->post_content;
	$_blogpost_description = strip_tags($_blogpost_description);
	$_blogpost_description = substr($_blogpost_description,0,300) . '...';
}
	// 	end predefine variables
		
	$_output_blogpost .= '<div class="single-post-import">';
	$_output_blogpost .= '<a href="' . $_blogpost_link . '"><img class="aligncenter" src="' . $_blogpost_image_url . '" alt="'. $_blogpost_name . '" width="" height="" /></a>';
	$_output_blogpost .= '<h3><a href="' . $_blogpost_link . '">' . $_blogpost_name . '</a></h3>';
	$_output_blogpost .= '</div>';
} // close foreach
$_output_blogpost .='</div>';
	
return($_output_blogpost);

Wie unter /*predefine variables */ zu erkennen, schreibe ich die Werte aus der Variable $blogpost vor ihrer eigentlichen Verwendung nochmals in eigene Variablen.

Dies ist nicht unbedingt nötig, und kann vielleicht als eine Marotte von mir gesehen werden. Die Erfahrung hat mich allerdings gelehrt, dass es am Ende der komfortablere Weg ist. Denn es kann immer mal wieder vorkommen, dass die Werte nachbearbeitet werden müssen, wie an diesem Beispiel zu sehen:

if(!empty($_blogpost->post_excerpt)){
	$_blogpost_description = $_blogpost->post_excerpt;
		} else {
	$_blogpost_description = $_blogpost->post_content;
	$_blogpost_description = strip_tags($_blogpost_description);
	$_blogpost_description = substr($_blogpost_description,0,300) . '...';
}

In diesem Teil prüfe ich beispielsweise zunächst, ob es für den jeweiligen Artikel einen Auszug (excerpt) gibt. Wenn dies der Fall ist, soll der Auszug verwendet werden.

Existiert aber (noch) kein Auszug, soll stattdessen der eigentliche Artikeltext verwendet werden. Aus diesem Text werden dann mittels der PHP-Funktion strip_tags() sämtliche HTML-Tags entfernt.

Da ich nicht den kompletten Text des Artikel anzeigen lassen möchte, begrenze ich diesen „Pseudo-Auszug“ dann mit der PHP-Funktion substr() noch auf maximal 300 Zeichen.

Leider treten bei mir diese „Nachbehandlungen“ immer erst Kurz vor der Ziellinie auf. Daher hat sich für mich die Methode mit dem Definieren eigener Variablen durchaus bewährt.

Der vollständige Code

Hier nun nochmal der vollständige Code zur Ausgabe von Posts auf einer anderen WordPress- Seite. Wie das Ergebnis im Live-Betrieb aussieht, kannst auf JUST YUM YUM Kitchen unter den Unterschriften Auf der Suche nach Inspiration? und JUST YUM YUM Foodies sehen.

<?php

add_shortcode( 'IMPORT_BLOGPOSTS', 'importBlogPosts' );

function importBlogPosts($atts, $content = null){
  	add_action('wp_footer','blogPostsImportCSS',100);
  	$import_blogposts_values = '';
  	$import_blogposts_values = shortcode_atts(array(
		'cat_id' => 123,
		'limit' => 3
		), $atts );

	$wpdb2 = new wpdb('db_user', 'db_password', 'db_name', 'db_host');

	$query = '	SELECT DISTINCT		wp_posts.ID,
									wp_posts.post_title,
        							wp_posts.guid,
        							wp_posts.post_excerpt,
									wp_posts.post_content
        							featured_image.guid as post_image
				FROM 				wp_posts
				INNER JOIN 			wp_postmeta ON wp_posts.ID = wp_postmeta.post_id AND wp_postmeta.meta_key = \'_thumbnail_id\' 
				INNER JOIN 			wp_posts AS featured_image ON featured_image.id = wp_postmeta.meta_value
				INNER JOIN 			wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
				INNER JOIN 			wp_term_taxonomy ON (wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id)
				WHERE 				wp_posts.post_status = \'publish\' 
				AND 				wp_posts.post_type = \'post\'
				AND					wp_term_taxonomy.term_id IN (' . $import_blogposts_values['cat_id'] . ')
				ORDER BY RAND()
				ASC
				LIMIT ' . $import_blogposts_values['limit'];

	$blogposts_query = $wpdb2->get_results($query, OBJECT);

// generating the HTML construct
$_output_blogpost ='';
$_output_blogpost .='<div class="jyy-single-post-import-wrapper">';
	
foreach($blogposts_query as $blogpost){
// predefine variables
	$_blogpost_link = $blogpost->guid;
	$_blogpost_name = $blogpost->post_title;
	$_blogpost_image_url = $blogpost->post_image;

	if(!empty($_blogpost->post_excerpt)){
	$_blogpost_description = $_blogpost->post_excerpt;
	} else {
	$_blogpost_description = $_blogpost->post_content;
	$_blogpost_description = strip_tags($_blogpost_description);
	$_blogpost_description = substr($_blogpost_description,0,300) . '...';
}
// 	end predefine variables

$_output_blogpost .= '<div class="single-post-import">';
$_output_blogpost .= '<a href="' . $_blogpost_link . '"><img class="aligncenter" src="' . $_blogpost_image_url . '" alt="'. $_blogpost_name . '" width="" height="" /></a>';
$_output_blogpost .= '<h3><a href="' . $_blogpost_link . '">' . $_blogpost_name . '</a></h3>';
$_output_blogpost .= '</div>';
	} // close foreach
$_output_blogpost .='</div>';
	
return($_output_blogpost);
} // close function

function blogPostsImportCSS(){
	echo('<style id="blogposts-import-css"> /** Your custom CSS styles go here **/ </style>');
} // close function

Dir wird aufgefallen sein, dass sich in der ersten Zeile der Funktion importBlogPosts noch die Anweisung

add_action('wp_footer','blogPostsImportCSS',100);

befindet. Diese Anweisung dient dazu, dass sobald der Shortcode ausgeführt wird, und auch nur dann, die dazugehörigen CSS-Anweisungen vor den schließenden <body>-Tag geschrieben werden.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.