Adventskalender Tag 13: Vermeidung einer zusätzlichen WP_Query auf der Startseite

In meinen Beitrag von Tag 6 hatte ich ja erwähnt, dass die Funktion, die ich gebastelt habe, mit meinem Theme nicht funktioniert hat. Das Parent-Theme das ich verwende ist schon über dreieinhalb Jahre alt und ich muss gestehen, dass auch ich damals nicht gewusst hätte, was an dem Code falsch ist und wie man ihn verbessern kann. Im heutigen Beitrag möchte ich daher kurz erläutern, was genau der „Fehler“ ist, welche Folgen es hat und wie man es besser machen kann.

Der Grund für die zweite WP_Query

Das Theme, das ich verwende hat zwei Layout-Optionen. Eine mit nur zwei Spalten (Artikel und Sidebar) und eine mit einer zusätzlichen Spalte für „Sticky Posts“. Hierbei handelt es sich um solche Beiträge, die unter „Veröffentlichen -> Sichtbarkeit“ die Kontrollbox „Beitrag auf der Startseite halten“ aktiviert habe.

sticky-posts-options

Wenn ein Artikel als „sticky“ markiert ist, dann wird er auf der Startseite immer ganz oben angezeigt, gefolgt von allen anderen Beiträgen in ihrer chronologischen Reihenfolge. Da es aber mit der zweiten Layout-Option eine weitere Spalte gibt, macht es keinen Sinn, auch in der ersten Spalte die Beiträge oben zu platzieren, sonst würden auf der Startseite oben jeweils die gleichen stehen:

sticky-posts-beitraege

Aktuelle Lösung im Parent-Theme

Damit Sticky Posts nicht ganz oben platziert werden, kann man diese Funktion durch einen zusätzlichen Parameter ignore_sticky_posts vermeiden. In der index.php Datei des Parent-Themes wurde es wie folgt gelöst:

...
<?php /* Start the Loop */ ?>
<?php global $query_string;
	query_posts( $query_string . '&ignore_sticky_posts=1' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<?php get_template_part( 'content', get_post_format() ); ?>

	<?php endwhile; // end of the loop. ?>
<?php wp_reset_query(); // reset the query ?>
...

In Zeile 16 wird eine neue WP_Query gestartet und dabei die Option ignore_sticky_posts angehängt, die vermeidet, dass solche Beiträge ganz oben angezeigt werden. Wieso das keine gute Idee ist, hat Andrew Nacin mal in einem sehenswerten Vortrag beim WordCamp Netherlands 2012 erläutert. Vereinfacht gesagt sollte man die Funktion query_posts niemals direkt verwenden, da sie nur für den „Main-Loop“ vorgesehen ist. Dies wird auch im CODEX so beschrieben. Verwendet man sie dennoch, muss WordPress im schlimmsten Fall zwei sehr aufwändige Datenbankabfragen durchführen.

Vermeidung der zweiten WP_Query

Genau für diese Grund gibt es einen Hook: pre_get_posts. Hiermit ist es möglich, den „Main-Loop“ noch vor der Ausführung zu verändern. Zuerst einmal müssen wir aber die index.php Datei anpassen. Wir entfernen hier also erst einmal die zweite WP_Query. Dazu kopieren wir die index.php Datei in unser Child-Theme und löschen die Zeilen 15 und 16:

...
<?php /* Start the Loop */ ?>
	<?php while ( have_posts() ) : the_post(); ?>

		<?php get_template_part( 'content', get_post_format() ); ?>

	<?php endwhile; // end of the loop. ?>
<?php wp_reset_query(); // reset the query ?>
...

Nun können wir den zusätzlichen Parameter in der functions.php Datei des Child-Themes verwenden und damit die Sortierung der Sticky Posts an den Anfang wieder deaktivieren:

function skip_sticky_posts_on_front_page( $query ) {
	if ( ! is_admin() && $query->is_main_query() ) {
		$query->set( 'ignore_sticky_posts', 1 );
	}
}
add_action( 'pre_get_posts', 'skip_sticky_posts_on_front_page' );

Wir prüfen in der Funktion, ob es sich um die „Main Query“ handelt und wir uns nicht im Backend befinden. Wenn dies der Fall ist, dann fügen wir den zusätzlichen Parameter einfach an.

Fazit

Der Hook pre_get_posts gehört zu einem der mächtigsten Filter in WordPress. Er wird aber von vielen vermieden, da sie ihn nicht verstehen oder die Seiteneffekte nicht bekannt sind (wenn man z.B. die Prüfung is_admin() vergisst). Ich gebe zu, dass auch ich anfangs nicht so richtig mit dem Filter klargekommen bin. Ich kann aber jedem nur empfehlen, sich genauer mit dem Filter zu beschäftigen. Im Optimalfall muss man dann noch nicht einmal die Template-Dateien kopieren und ändern oder spezielle Archiv-Seiten oder ähnliches erstellen.

Veröffentlicht von

Bernhard ist fest angestellter Webentwickler, entwickelt in seiner Freizeit Plugins, schreibt in seinem Blog über WordPress und andere Themen, treibt sich gerne bei den WP Meetups in Berlin und Potsdam herum und läuft nach Feierabend den ein oder anderen Halbmarathon.

Schreibe einen Kommentar

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