Der Loop von WordPress ist ein sehr mächtiges Werkzeug. Die meisten Nutzer werden wohl den Standard-Loop verwenden. Mit Hilfe einiger Funktionen kann man aber den Loop sehr schön an bestimmte Anforderungen und Bedürfnisse anpassen. Ein Beispiel habe ich schon im letzten Beitrag für Feeds gezeigt.
Einige Beispiele, die für mein Empfinden eher selten genutzt werden, was schade ist und immer wieder zu Fragen bei den Nutzern führt, möchte ich in diesem Beitrag aufzeigen; kurz und knapp - verwenden und lernen.
Seitenumbruch mit eigenem WP-Query
Nutzt man eigene Loops, die über die Variable $wp_query definiert werden, kreiert diese also mit dem WP-Query, dann wird im Standard keine Pagination (Seitenumbruch) dargestellt. Zwei Beispiele mit unterschiedlichen Herangehensweisen.
<?php
$my_query = new WP_Query('cat=-21&showposts=3&paged='.$paged);
if ($my_query->have_posts()) {
while ( $my_query->have_posts() ) : $my_query->the_post();
?>
<?php if (have_posts()) : ?>
<?php $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
query_posts("category_name=somecat&paged=$paged"); ?>
<?php while (have_posts()) : the_post(); ?>
Wer den einen oder anderen Sonderfall mit dem Loop bauen will, der sollte sich den Array dieser Variable näher anschauen, denn viele nützliche Inhalte sind vorhanden und können die eine oder andere Lösung ersetzen. Die Ausgabe kann mich sich sehr schön mit folgendem einfach Syntax anschauen.
var_dump( $wp_query );
Für PHPler nichts neues, für den einen oder anderen Theme-Autor aber vielleicht doch.
Kategorien oder Tag nicht im Loop ausgeben
Nicht selten möchte man die eine oder andere Kategorie nicht im Loop haben. Ein typisches Beispiel ist, wenn man einen Side- oder Thumbler-Blog mit WordPress parallel bedient. Dafür braucht man kein Plugin. Man kann beispielsweise eine Kategorie nehmen, diese im Sidebar via extra Loop ausgeben und so seine kleinen Tipps und Links posten. Auf der Seite des Blog grenzt man diese Kategorie im Blog einfach aus und hat so dort nur die Beiträge mir mehr Inhalt.
<?php query_posts('cat=-2'); ?>
Ähnlich geht das auch für Tags, der Unterschied liegt hier in der Übergabe des Tag-Namen und nicht die ID.
<?php query_posts('tag=mytag'); ?>
Standard-Loop, der allerdings die Kategorie mit ID 21 nicht berücksichtigt
Im einfachsten Fall baut man den Loop wie folgt, nimmt die Kategorie raus und damit geht auch die Pagination. Hier mal der Loop im Ganzen, so dass man ihn nur mit Inhalt füllen muss.
<?php
$my_query = new WP_Query('cat=-21');
if ( $my_query->have_posts() ) :
while ( $my_query->have_posts() ) : $my_query->the_post();
?>
<div id="post-<?php the_ID(); ?>">
. . .
</div>
<?php endwhile; else: ?>
<p><?php _e('Nichts gefunden, was den Suchkriterien entspricht.'); ?></p>
<?php endif; ?>
Loop, der nur die Artikel ausgibt, die Tag mytag haben
<?php
$my_query = new WP_Query('tag=mytag');
if ( $my_query->have_posts() ) :
while ( $my_query->have_posts() ) : $my_query->the_post();
?>
<div id="post-<?php the_ID(); ?>"
. . .
</div>
<?php endwhile; else: ?>
<p><?php _e('Nichts gefunden, was den Suchkriterien entspricht.'); ?></p>
<?php endif; ?>
Eigener Loop, der Paged definiert
<?php
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
query_posts($query_string . "&cat=-2&paged=$paged");
?>
Loop mit Paged nur für Tag mytag
<?php if ( have_posts() ) :
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
query_posts($query_string . "tag=mytag&paged=$paged");
while ( have_posts() ) : the_post();
?>
<div id="post-<?php the_ID(); ?>">
. . .
</div>
<?php endwhile; else: ?>
<p><?php _e('Nichts gefunden, was den Suchkriterien entspricht.'); ?></p>
<?php endif; ?>
Loop Beiträge aus der Zukunft
<?php
$my_query = new WP_Query('post_status=future&order=DESC&showposts=5');
if ( $my_query->have_posts() ) {
_e('<h2>Vorgesehene Beiträge</h2>');
echo '<ul>';
while ( $my_query->have_posts() ) :
$my_query->the_post();
$do_not_duplicate = $post->ID;
echo '<li>' . get_the_title() . __(' (erscheint am ') . get_the_time('d.m.Y') . __(')') . '</li>';
endwhile;
echo '</ul>';
}
?>
Loop auf Basis benutzerdefinierten Felder
<?php query_posts( 'meta_key=my_type&meta_value=my_value' );
if (have_posts()) :
while ( have_posts() ) : the_post(); ?>
Loop auf Basis benutzerdefinierten Felder, der die nach diesen sortiert
query_posts('meta_key=my_type&meta_compare=<=&my_value=20&orderby=my_value');
if (have_posts()) :
while ( have_posts() ) : the_post(); ?>
Inhalt genauer einer Seite laden
// lade Seite mit Namen: kontakt; alternativ page_id oder name (slug)
<?php query_posts( 'pagename=kontakt' );
if (have_posts()) :
while ( have_posts() ) : the_post(); ?>
Reset Query
Probleme mit einem eigenen Query? Wenn man mehrere Loops einsetzt und dabei Fehler in der Ausgabe entdeckt, dann kann ein Reset helfen. Wenige dokumentiert, aber sehr nützlich, wie ich finde. Ich setze diesen immer ein, wenn ich mehrere Queries lade oder Probleme bei der Ausgabe habe.
Der klassische Reset geschieht mit der folgenden Funktion und wird nach einem query_posts() eingesetzt.
rewind_posts();
Dazu ein kleines Beispiel.
query_posts('category_name=cattest');
while ( have_posts() ) :
the_post();
// im loop
endwhile;
//loop reset
rewind_posts();
// 2. loop
while ( have_posts() ) :
the_post();
// im Loop
endwhile;
Reset $wp_query
Diese Funktion resetet den globalen $wp_query - also nach einem eigenen WP_Query zu nutzen. Nach oder vor einem Query query_posts() gesetzt, kann es wahre Wunder bewirken.
/**
* Destroy the previous query and setup a new query.
*
* This should be used after {@link query_posts()} and before another {@link
* query_posts()}. This will remove obscure bugs that occur when the previous
* wp_query object is not destroyed properly before another is setup.
*
* @since 2.3.0
* @uses $wp_query
*/
wp_reset_query();
Auch dazu ein kleines Beispiel. Der erste Loop gibt die Anzahl der Beiträge zurück, die man bei einer Suche erhält. Danach setze ich einen Reset und fahre dann mit einem Standard-Loop die Ausgabe. Zur Ausgabe der Suche gab es bereits einen Artikel, der Hintergründe darlegt.
<?php if (have_posts()) : ?>
<h2>Search Results<br /><small>
<?php /* Search Count */
$allsearch = new WP_Query("s=$s&showposts=-1");
$key = wp_specialchars($s, 1);
$count = $allsearch->post_count;
_e('term: ');
echo $key;
_e(' — ');
echo $count . ' ';
_e('posts'); wp_reset_query(); ?></small></h2>
<?php while (have_posts()) : the_post(); ?>
Custom Post Type und Custom Taxonomie im Loop
Ab WordPress 3.0 stehen diese beiden Möglichkeiten zur Verfügung und können direkt im Loop berücksichtigt werden. Einiges zum Thema habe ich schon bei WPD und WPEngineer berichtet.
global $wp_query;
query_posts( array(
'post_type' => 'message' ,
"taxonomy_name" => "term_name",
'showposts' => 10 )
);
Custom Post Type und multiple Taxonomie
Manchmal will man den Tag der taxonomie mit in den Loop bekommen, ein kleiner Trick im SQL hilft.
$result = new WP_Query( 'post_type=message&tax_terms=term_name:tag_1,term_name:tag_2' );
foreach ($result->posts as $post) {
$title .= $post->post_title. "\n";
}
Den Befehl "wp_reset_query" kannte ich nicht. Werde ich bestimmt mal brauchen... Merci.
Tausend Dank für diesen Tipp! Ich habe schon eine halbe Ewigkeit nach einem solchen Loop gesucht, um eine Kategorie als Page mit funktionierender Pagination auszugeben.
danke für den tipp - werde versuchen dies auf meiner seite umzusetzen. leider bin ich nicht zu fit für sämtliche pc geschichten - kann mir das sogar jemand umsetzen falls ich das nicht selber hinbekomme?
Sehr schöne Tipps. Ich hab vor ’ner Weile versucht, ein, halt dich fest, Plugin für Minibeträge, also eine Art Sideblog, einzubinden. Aber hat ja alles nüscht genützt. Und die Tage hab ich wieder damit befasst und über meine eigene Blödheit geärgert, da man ja theoretischerweise alles über den Loop regeln kann. Arrr, und jetzt der Gedankensprung hierhin – perfekt!
Gibt es eine Möglichkeit, unter einer Seite auch noch eine Liste von Artikeln einer Bestimmten Kategorie anzuzeigen?
Ich habe folgendes versucht:
<a href="" rel="bookmark" title="Permanent Link: "></a>Wie bei dir auf der Seite WordPress plugins?? Ich habe mehr nicht rausbekommen
Ja das geht, dazu muss man nur einen eigenen Loop im Template hinterlegen oder via PHP-Plugin auch im Editor der Seite.
Einen Query wie oben beschrieben kann man dazu nutzen.
Auch meine Plugin-Seite macht nix anderes, liest lediglich diese eine Kategorie aus.
spitze. das mit den meta keys im wp query habe ich genau gesucht! danke!
Kann man damit eigentlich auch nur den neuesten Beitrag ausgeben?
ich will auf der Startseite den Titel des neusten Beitrages in h1 setzen und die Titel der anderen Beiträge in h2.
@Christian: dazu genügt ein Zähler, der letzte Beitrag, also der erste im Loop bekommt h1;
Frank, vielen Dank, hätte ich echt selber drauf kommen können.
Hat super funktioniert.
DANKE!!!
Hast mir den Tag gerettet!!
Super, vielen Dank hat mir auf die Sprünge geholfen und mich animiert mich mal mit "query" auseinander zusetzen. Gerne hätte ich noch die Möglichkeiten mir z.B. alle Seiten der bis zur zweiten Ebene anzuzeigen also ähnlich wie 'depth=2' bei wp_list_pages. Alternativ würde mich auch reichen wenn ich mit folgender Query
mehrere Pages auswählen kann. Würde zwar den manuellen Aufwand erhöhen, könnte ich aber mit Leben, gibt es da eine Möglichkeit? Vielen Dank!hallo frank,
bin ja über deinen Code gestolpert, den du unter *Eigener Loop, der Paged definiert* liegen hast.
Nach längerem stolpern bin ich dann dahinter gekommen das fast alles richtig war, der Code aber korrekt so geschrieben sein muss:
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;query_posts('cat=-1&posts_per_page=35&paged='.$paged);
Achte auf das .$paged am Ende!
Bei der Gelegenheit wäre es sehr nett, wenn du mir den Weg zeigen könntest, wie ich die Einstellungen für das Plugin Post_Notification für Redakteure als Benutzer angezeigt bekomme.
Habe das mittels add_role bzw. add_cap versucht....aber bislang nicht zum Ergebnis gelangt.
Habe allerdings gesehen, das Du das in deinem Plugin *Adminimize* schon gemacht hast.
Ich möchte jetzt nicht deshalb das ganze Plugin installieren.
Wäre Dir daher dankbar, wenn du mir den Weg zeigt.
liebe Grüße
thomas
@thomas: der Code ist bei mir auch richtig, da die Variable $paged innerhalb von " interpretiert wird, ist also nur eine andere Schreibweise.
Die Meta Box von Post Notification blende ich via Adminimize mit JS/CSS aus - die Rechte dieser Box sind nicht extra möglich. Daher würde ich einfach eine Funktion schreiben, die die Rechte abfrage und wenn nicht ausreichend, dann wird die Box entfernt:
if ( !current_user_can('manage_options') ) { remove_meta_box( 'post_notification','post', 'normal' ); remove_meta_box( 'post_notification','page', 'normal' ); }Hallo Frank,
vielen Dank für deine Antwort.
Hatte vor ein paar Tagen schon mal versucht zu antworten....aber da war wohl irgendwas schief gelaufen beim absenden. Mal schauen obs jetzt klappt.
Nun ja...ich bin mit nur $paged nicht weitergekommen sondern eben erst mit ='.$paged);
Hier im Zusammenspiel mit diesem -->Pagination Script<--, wobei ich das dort angesprochene Problem noch nicht gelöst habe (!).
Was die Post_Notification angeht:Mir ging es nicht um die Meta Box vom Post Notification beim Artikel schreiben für die Redakteure. Die soll schön dort bleiben.
Vielmehr sollen die Redakteure auch an das Admin Fenster (Einstellungen>Post Notification) von Post Notification ran, weil die erst dort an die Listen der eingetragenen Mail-Adressen gelangen - und das geht bislang nur über den Umweg der vollen Admin Rechte...bzw. hab noch keine andere Lösung gefunden.
Deine vorgeschlagene Funktion habe ich allerdings schon im Einsatz um den Redakteuren und Authoren die *trackbacksdiv* und die *postcustom* Felder zu entfernen.
liebe Grüße
thomas
@thomas: doe paged-Funktion muss als Varible da sein, muss also via PHP ansprechbar sein; insofern ist eventuell der Fehler in der Syntax.
Wenn du die Optionen von Post Notification an andere User mit weniger Rechten geben willst, dann musst du das Plugin ändern, oder das Rechteobjekt an diese Rolle übergeben; das kann man am einfachsten via Plugin Members machen. Allerdings hat diese Rolle dann die Rechte auf alles, was dieses Plugin als Min-Rechte-Objekt verlangt. Aktuell fragt das Plugin User-Level 8 ab, was veraltet ist und dann in die Rechte übersetzt wird. Insofern wäre wohl ein Mail an den Autor gut, das er ein eigenes Objekt nutzt, dann kann jeder dies entsprechend für sich nutzen und anpassen. In deinem Fall würde ich statt der 8 das Objekt
unfiltered_htmlabfragen und deinen Autoren dies geben, bzw Editoren haben das Objekt.Hallo Frank, ich nutze aktuell diesen Code, um auf der Hauptseite die Kategorie 321 nicht mit anzuzeigen:
function limit_front_page() {if(is_home()){
global $wp_query;
query_posts(
array_merge(
array('cat' => -321),
$wp_query->query
)
);
}
}
add_action('thesis_hook_before_content', 'limit_front_page');
Nur wie muss ich jetzt die Zeile
array('cat' => -321),erweitern, um auch die Kategorien '-5, -321, -407, -415' aus zu blenden.Hab schon mit Komma dazwischen, ohne Komma versucht - klappt nicht.
Vielen Dank vorab.
@Frank: sollte eigentlich reichen, wenn du die IDs auch in ein Array packst array('cat' => array('-321', '21') ); alternativ hier eine Lösung von mir, wo nur der Conditional Tag ausgetauscht werden muss - zu is_home.
function limit_front_page() {
if(is_home()){
global $wp_query;
query_posts(
array_merge(
array('cat' => array('-5', '-407', '-415') );
$wp_query->query
)
);
}
}
add_action('thesis_hook_before_content', 'limit_front_page');
Hm, funktioniert nicht: Parse error: syntax error, unexpected ';' in /is/htdocs...
Hast du eine Alternative - bitte?
Frank, oder dieser funktioniert - fast.
function limit_front_page() {global $query_string;
if (is_home()) {
query_posts(array('category__not_in' => array(5,321,407,415)));
}
}
add_action('thesis_hook_before_content', 'limit_front_page');
Die Kategorien werden alle korrekt ausgeblendet auf der Home-Seite.
Nur es tritt der Effekt auf, dass auf der Home-Seite (und nur da) beim Klick auf den Link für frühere Beiträge) - dieser befindet sich ganz unten - sich zwar der Link im Browser korrekt ändert - aber die Beiträge dazu nicht; es bleiben die selben.
Was könnte da falsch sein - an dem Code?
Danke dir schon mal.
@Frank: wenn du nur auf der home-Seite limitieren willst, dann würde ich eher per Template und query_posts arbeiten, da kannst du auch die Pagination mitgeben. Dann spielt sich alles im Template ab und kostet keine Filteraktion an anderer Stellen.
Der Bueltge wieder! Danke für den Tipp mit der Pagination. Jetzt kann ich endlich auch custom post types auf einer separaten Seite ausgeben und nach x Beiträgen umbrechen.
)
Hallo Frank,
jetzt muss ich mich doch mal an dich direkt wenden x.X
ich habe auf meiner Startseite einen Querie der die neuesten Inhalte ausgeben soll, die Aufteilung auf die Seiten stimmt, und auch die Pagination wird angezeigt. Aber anscheinend habe ich ein Problem mit der $paged-Variable auf der Startseite ist sie 0 (Was ja auch stimmt) auf alles anderen Seiten ist sie aber leer, wodurch auch auf Seite 2,3,4 usw (nach der URL: /page/2) trotzdem immer die ersten Artikel angezeigt werden. Was mache ich falsch?
Ich habe schon umfassend mit rewind und reset rumprobiert, auch andere queries auf der Seite habe ich entfernt aber das hat alles nichts geholfen ._.
@Grandy: klingt mir nach einem Problem; eventuell eine Plugin oder was anderes, was Einfluss auf den Loop hat. Im Standard würde dies sonst klappen; da hilft nur suchen; alle plugins deaktivieren, usw.
Ich habe das gleiche Problem wie Grandy. Ich möchte eine Kategorie auf meiner Startseite ausschließen, im Archiv etc. aber anzeigen. Ich habe folgenden Code integriert: Die Kategorie wird ausgeblendet, aber die Navigation unter den Artikeln 'Ältere Posts' versagt. Es wird auf jeder folgenden Seite die Startseite angezeigt. Da ich mich nicht besonders gut auskenne, war mein erster Gedanke, dass ich den Code an der falschen Stelle eingefügt habe. Ich nutze TwentyTen und weiß im Grunde nicht, wo der richtige Platz für den Befehl ist. Plugins nutze ich kaum. Für einen kleinen Hinweis, wie ich den Fehler beheben kann, wäre ich dankbar. Viele Grüße
@Nicole: du kannst auch über den Hook pre_get_posts gehen und via Plugin ausschließen, z.B: http://bueltge.de/beitrage-aus-dem-suchergebnis-von-wordpress-auschliesen/1248/
Hm ich sehe, dass mein Query Code nicht dargestellt wurde:
Ich möchte die Kategorie nicht aus dem Suchergebnis ausschließen, sondern die Artikel dieser Kategorie sollen nicht auf der Startseite angezeigt werden. Mein Code scheint richtig, allerdings versagt die Navigation unter den Posts und zeigt statt der 2., 3. oder 4. Seite immer die Startseite an. Das muss doch ohne Plugin zu beheben sein oder?
@Nicole: dies habe ich schon verstanden, dazu muss lediglich die Abfrage geändert werden, ist es im Bsp. is_search, so ist die Startseite is_home oder is_front_page.
Hi, tolle Erläuterungen!
Hat jemand eine Ahnung wie ich die URL umbenennen kann, also /page/2/ in /seite/2/ ?
greez und vielen Dank!
@Gecko: dafür gibt es eine Lösung, in diesem Beitrag nachzulesen.
Super, vielen Dank hat funktioniert