
WordPress Query: Datenbankabfragen verstehen & nutzen
- Was ist eine WordPress Query?
- Die Standard-Query: Main Query
- Custom Queries mit WP_Query
- Meta Queries: Filter nach Custom Fields
- Tax Queries: Filter nach Custom Taxonomies
- Date Queries: Zeitbasierte Filter
- Alternative Query-Funktionen
- Die Main Query anpassen: pre_get_posts
- Query Performance optimieren
- Pagination bei Custom Queries
- Häufige Query-Probleme und Lösungen
- Query-Sicherheit: SQL Injection verhindern
- Query-Debugging: Tipps für Entwickler
- Query-Beispiele für häufige Anwendungsfälle
- Checkliste: Query-Best-Practices
- Fazit: Queries sind die Grundlage von WordPress
- Häufig gestellte Fragen (FAQ)
Eine Query (Abfrage) ist in WordPress der Mechanismus, mit dem Inhalte aus der Datenbank abgerufen und auf deiner Website angezeigt werden. Sie ist das Herzstück jeder WordPress-Seite – von Blogarchiven über individuelle Postlisten bis zu komplexen Content-Filtern.
Jedes Mal, wenn du eine WordPress-Seite aufrufst, arbeitet im Hintergrund eine Query: Sie holt die passenden Beiträge, Seiten oder Custom Post Types aus der MySQL-Datenbank und bereitet sie für die Anzeige auf. Als Entwickler oder fortgeschrittener WordPress-Nutzer ist das Verständnis von Queries essentiell, um deine Website flexibel und performant zu gestalten.
Was ist eine WordPress Query?
Eine Query ist eine strukturierte Anfrage an die WordPress-Datenbank, die nach bestimmten Kriterien filtert. WordPress nutzt dafür die Datenbanksprache SQL (Structured Query Language), abstrahiert diese jedoch in eine PHP-freundliche Schnittstelle – die WP_Query-Klasse.
Vereinfacht gesagt: Du sagst WordPress „Zeige mir alle Beiträge der Kategorie ‚Webdesign‘ aus 2024, sortiert nach Datum“ – und WordPress übersetzt das in eine SQL-Abfrage, holt die Daten und gibt sie strukturiert zurück.
Die Hauptbestandteile einer Query:
- Query-Parameter: Die Filterkriterien (z.B. Post-Typ, Kategorie, Anzahl)
- SQL-Übersetzung: WordPress wandelt deine Parameter in SQL um
- Datenabruf: Die Datenbank liefert die Ergebnisse
- The Loop: Die Ausgabe der abgerufenen Inhalte im Template
Die Standard-Query: Main Query
Jede WordPress-Seite hat automatisch eine Main Query (Hauptabfrage). Diese wird basierend auf der aufgerufenen URL erstellt:
- Homepage: Die neuesten Beiträge (oder statische Startseite)
- Kategorie-Archiv: Alle Beiträge der Kategorie
- Einzelbeitrag: Der spezifische Post mit seiner ID
- Suchergebnisse: Beiträge, die den Suchbegriff enthalten
Die Main Query läuft automatisch ab, bevor dein Theme-Template geladen wird. Du kannst sie mit Template Tags wie have_posts() und the_post() in deinen Templates nutzen.
Beispiel einer typischen Loop:
<?php
if ( have_posts() ) :
while ( have_posts() ) : the_post();
the_title( '<h2>', '</h2>' );
the_excerpt();
endwhile;
endif;
?>Diese Loop greift auf die Main Query zu und gibt alle gefundenen Beiträge nacheinander aus.
Custom Queries mit WP_Query
Wenn die Main Query nicht ausreicht – etwa weil du eine spezielle Postliste in einer Sidebar brauchst oder einen zweiten Loop auf derselben Seite – nutzt du Custom Queries mit der WP_Query-Klasse.
Grundstruktur einer Custom Query:
<?php
$args = array(
'post_type' => 'post',
'posts_per_page' => 5,
'category_name' => 'webdesign',
'orderby' => 'date',
'order' => 'DESC'
);
$custom_query = new WP_Query( $args );
if ( $custom_query->have_posts() ) :
while ( $custom_query->have_posts() ) : $custom_query->the_post();
the_title( '<h3>', '</h3>' );
the_permalink();
endwhile;
wp_reset_postdata(); // Wichtig!
endif;
?>Wichtige Query-Parameter:
post_type: Art des Inhalts (post, page, Custom Post Type)posts_per_page: Anzahl der Ergebnisse (-1 für alle)category_name/cat: Filterung nach Kategorietag/tag_id: Filterung nach Tagauthor/author_name: Filterung nach Autordate_query: Datumsbasierte Filtermeta_query: Filter nach Custom Fieldstax_query: Filter nach Custom Taxonomiesorderby: Sortierung (date, title, rand, meta_value etc.)order: Reihenfolge (ASC aufsteigend, DESC absteigend)
Praxis-Beispiel: Portfolio-Galerie
Angenommen, du hast einen Custom Post Type „portfolio“ und möchtest die 6 neuesten Projekte mit einem bestimmten Tag anzeigen:
<?php
$portfolio_args = array(
'post_type' => 'portfolio',
'posts_per_page' => 6,
'tag' => 'featured',
'orderby' => 'date',
'order' => 'DESC'
);
$portfolio_query = new WP_Query( $portfolio_args );
if ( $portfolio_query->have_posts() ) :
echo '<div class="portfolio-grid">';
while ( $portfolio_query->have_posts() ) : $portfolio_query->the_post();
?>
<article class="portfolio-item">
<?php the_post_thumbnail('medium'); ?>
<h3><?php the_title(); ?></h3>
<a href="<?php the_permalink(); ?>">Projekt ansehen</a>
</article>
<?php
endwhile;
echo '</div>';
wp_reset_postdata();
else :
echo '<p>Keine Portfolio-Projekte gefunden.</p>';
endif;
?>Meta Queries: Filter nach Custom Fields
Wenn du mit Custom Fields (z.B. via ACF oder Pods) arbeitest, sind Meta Queries unverzichtbar. Sie erlauben Filterung nach Metadaten.
Beispiel: Events, die in der Zukunft liegen:
<?php
$today = date('Ymd');
$event_args = array(
'post_type' => 'event',
'posts_per_page' => 10,
'meta_key' => 'event_date',
'orderby' => 'meta_value_num',
'order' => 'ASC',
'meta_query' => array(
array(
'key' => 'event_date',
'value' => $today,
'compare' => '>=',
'type' => 'DATE'
)
)
);
$event_query = new WP_Query( $event_args );
?>Meta Query Operators:
=/!=: Gleich / Ungleich>/</>=/<=: VergleichsoperatorenLIKE/NOT LIKE: Teilstring-SucheIN/NOT IN: In Array enthaltenBETWEEN/NOT BETWEEN: WertebereichEXISTS/NOT EXISTS: Meta-Key vorhanden oder nicht
Tax Queries: Filter nach Custom Taxonomies
Für Custom Taxonomies nutzt du Tax Queries:
<?php
$recipe_args = array(
'post_type' => 'recipe',
'posts_per_page' => 12,
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'course',
'field' => 'slug',
'terms' => 'hauptgericht'
),
array(
'taxonomy' => 'diet',
'field' => 'slug',
'terms' => array( 'vegan', 'vegetarisch' ),
'operator' => 'IN'
)
)
);
$recipe_query = new WP_Query( $recipe_args );
?>Hier werden Rezepte abgerufen, die sowohl der Kategorie „Hauptgericht“ angehören als auch vegan oder vegetarisch sind.
Date Queries: Zeitbasierte Filter
Mit Date Queries filterst du nach Veröffentlichungsdatum:
<?php
$recent_posts_args = array(
'post_type' => 'post',
'posts_per_page' => 20,
'date_query' => array(
array(
'after' => '3 months ago',
'before' => 'today',
)
)
);
$recent_posts = new WP_Query( $recent_posts_args );
?>Oder präziser mit konkreten Daten:
'date_query' => array(
array(
'year' => 2024,
'month' => 12,
)
)Alternative Query-Funktionen
Neben WP_Query gibt es weitere Funktionen für spezifische Anwendungsfälle:
get_posts()
Eine vereinfachte Wrapper-Funktion für einfache Queries. Gibt ein Array von Post-Objekten zurück (keine Loop nötig):
<?php
$latest_posts = get_posts( array(
'numberposts' => 5,
'category' => 'news'
) );
foreach ( $latest_posts as $post ) {
setup_postdata( $post );
echo '<h4>' . get_the_title() . '</h4>';
}
wp_reset_postdata();
?>query_posts() – NICHT empfohlen!
query_posts() überschreibt die Main Query und sollte niemals verwendet werden. Es führt zu Performance-Problemen und unerwartetem Verhalten. Nutze stattdessen pre_get_posts Filter oder WP_Query.
get_pages()
Speziell für das Abrufen von Seiten:
<?php
$pages = get_pages( array(
'parent' => 0,
'sort_column' => 'menu_order'
) );
?>Die Main Query anpassen: pre_get_posts
Um die Main Query zu modifizieren (z.B. Anzahl der Beiträge in Archiven ändern), nutzt du den pre_get_posts Hook in deiner functions.php:
<?php
function meine_archiv_anpassung( $query ) {
// Nur Main Query im Frontend ändern
if ( ! is_admin() && $query->is_main_query() ) {
// Im Kategorie-Archiv 20 Beiträge anzeigen
if ( $query->is_category() ) {
$query->set( 'posts_per_page', 20 );
}
// Im Autor-Archiv nach Titel sortieren
if ( $query->is_author() ) {
$query->set( 'orderby', 'title' );
$query->set( 'order', 'ASC' );
}
}
}
add_action( 'pre_get_posts', 'meine_archiv_anpassung' );
?>Wichtig: Prüfe immer mit is_admin() und is_main_query(), um nur die gewünschte Query zu beeinflussen.
Query Performance optimieren
Queries können die Website-Performance stark beeinflussen. Hier sind Best Practices:
1. Limitiere die Ergebnisanzahl
'posts_per_page' => 10 // Statt -1 für "alle"2. Vermeide unnötige Felder
'fields' => 'ids' // Nur IDs statt voller Post-Objekte3. Nutze Caching
WordPress cached Queries automatisch, aber bei komplexen Abfragen hilft Transient-API:
<?php
$cached_query = get_transient( 'meine_custom_query' );
if ( false === $cached_query ) {
$args = array( /* deine Parameter */ );
$cached_query = new WP_Query( $args );
set_transient( 'meine_custom_query', $cached_query, 12 * HOUR_IN_SECONDS );
}
?>4. Vermeide komplexe Meta Queries
Jede Meta Query bedeutet zusätzliche JOIN-Operationen in SQL. Kombiniere Filter wenn möglich:
// Langsam: Mehrere separate Meta Queries
// Schneller: Eine Tax Query + eine Meta Query5. Nutze Query Monitor Plugin
Das Plugin „Query Monitor“ zeigt dir alle Datenbankabfragen einer Seite, deren Laufzeit und SQL-Code. Unverzichtbar für Performance-Debugging.
6. Deaktiviere unnötige Query-Komponenten
'update_post_meta_cache' => false, // Wenn du keine Post-Meta brauchst
'update_post_term_cache' => false, // Wenn du keine Terms brauchst
'no_found_rows' => true, // Wenn du keine Pagination brauchstPagination bei Custom Queries
Für Pagination bei Custom Queries nutze den paged Parameter:
<?php
$paged = ( get_query_var('paged') ) ? get_query_var('paged') : 1;
$args = array(
'post_type' => 'post',
'posts_per_page' => 10,
'paged' => $paged
);
$paged_query = new WP_Query( $args );
if ( $paged_query->have_posts() ) :
while ( $paged_query->have_posts() ) : $paged_query->the_post();
// Inhalte ausgeben
endwhile;
// Pagination anzeigen
echo paginate_links( array(
'total' => $paged_query->max_num_pages
) );
wp_reset_postdata();
endif;
?>Häufige Query-Probleme und Lösungen
Problem 1: „wp_reset_postdata() vergessen“
Symptom: Nach einer Custom Query zeigen Template Tags falsche Inhalte an.
Lösung: Immer wp_reset_postdata() nach einer Custom Query aufrufen:
<?php
$custom_query = new WP_Query( $args );
// ... Loop ...
wp_reset_postdata(); // Stellt globale $post wieder her
?>Problem 2: „Pagination funktioniert nicht“
Symptom: Pagination zeigt immer dieselben Beiträge.
Lösung: Nutze get_query_var('paged') korrekt und setze 'paged' => $paged in den Query-Args.
Problem 3: „Query zu langsam“
Symptom: Seite lädt mehrere Sekunden.
Lösung:
- Limitiere
posts_per_page - Nutze
'fields' => 'ids' - Prüfe mit Query Monitor, welche Query langsam ist
- Implementiere Caching mit Transients
Problem 4: „Sticky Posts werden nicht beachtet“
Symptom: Angeheftete Beiträge erscheinen nicht oben.
Lösung: Sticky Posts sind nur in der Main Query aktiv. Für Custom Queries:
'post__in' => get_option( 'sticky_posts' ),
'ignore_sticky_posts' => falseQuery-Sicherheit: SQL Injection verhindern
WordPress sanitiert WP_Query-Parameter automatisch. Bei direkten SQL-Queries (z.B. mit $wpdb) immer prepare() verwenden:
<?php
global $wpdb;
// FALSCH (anfällig für SQL Injection):
$results = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE post_title = '$user_input'" );
// RICHTIG:
$results = $wpdb->get_results(
$wpdb->prepare(
"SELECT * FROM $wpdb->posts WHERE post_title = %s",
$user_input
)
);
?>Query-Debugging: Tipps für Entwickler
Query-Parameter ausgeben:
<?php
$query = new WP_Query( $args );
print_r( $query->query_vars ); // Zeigt alle Parameter
?>SQL-Query anzeigen:
<?php
echo $query->request; // Zeigt die generierte SQL-Abfrage
?>Anzahl gefundener Posts:
<?php
echo $query->found_posts; // Gesamt gefundene Posts
echo $query->max_num_pages; // Anzahl Pagination-Seiten
?>Query-Beispiele für häufige Anwendungsfälle
Verwandte Beiträge (Same Category):
<?php
$current_categories = wp_get_post_categories( get_the_ID() );
$related_args = array(
'post_type' => 'post',
'posts_per_page' => 5,
'post__not_in' => array( get_the_ID() ),
'category__in' => $current_categories,
'orderby' => 'rand'
);
$related_query = new WP_Query( $related_args );
?>Zufällige Posts:
<?php
$random_args = array(
'post_type' => 'post',
'posts_per_page' => 3,
'orderby' => 'rand'
);
$random_query = new WP_Query( $random_args );
?>Posts eines bestimmten Autors:
<?php
$author_args = array(
'author' => 5, // Autor-ID
'posts_per_page' => 10
);
$author_query = new WP_Query( $author_args );
?>Suche nach Keyword:
<?php
$search_args = array(
'post_type' => 'post',
's' => 'WordPress', // Suchbegriff
);
$search_query = new WP_Query( $search_args );
?>Checkliste: Query-Best-Practices
- ✅ Nutze WP_Query für Custom Queries, nicht
query_posts() - ✅ Rufe wp_reset_postdata() nach jeder Custom Query auf
- ✅ Limitiere Ergebnisse mit
posts_per_page - ✅ Nutze pre_get_posts zum Anpassen der Main Query
- ✅ Cache komplexe Queries mit Transients
- ✅ Teste Performance mit Query Monitor
- ✅ Nutze ‚fields‘ => ‚ids‘ wenn du nur IDs brauchst
- ✅ Vermeide -1 für
posts_per_page(holt alle Posts) - ✅ Sanitize Eingaben bei direkten SQL-Queries
- ✅ Dokumentiere komplexe Queries im Code
Fazit: Queries sind die Grundlage von WordPress
Queries sind das Rückgrat jeder WordPress-Website. Sie entscheiden darüber, welche Inhalte wo und wie angezeigt werden. Ein solides Verständnis von WP_Query, Query-Parametern und Performance-Optimierung ist essentiell für jeden WordPress-Entwickler.
Die Flexibilität von WordPress-Queries erlaubt es dir, praktisch jeden Content-Bedarf abzubilden – von einfachen Blog-Archiven bis zu komplexen, gefilterten Content-Hubs. Mit den richtigen Techniken und Best Practices bleiben deine Queries performant und wartbar.
Nächste Schritte:
- Experimentiere mit verschiedenen Query-Parametern in einer Testumgebung
- Installiere Query Monitor zur Analyse deiner Queries
- Nutze
pre_get_postsfür flexible Archiv-Anpassungen - Implementiere Caching für wiederkehrende, komplexe Queries
Häufig gestellte Fragen (FAQ)
Was ist der Unterschied zwischen WP_Query und get_posts()?WP_Query ist die vollständige Query-Klasse und bietet maximale Kontrolle. get_posts() ist ein vereinfachter Wrapper, der ein Array von Posts zurückgibt – ideal für einfache Listen ohne Loop-Notwendigkeit. Für komplexe Queries oder Pagination ist WP_Query die bessere Wahl.
Warum sollte ich query_posts() nicht verwenden?query_posts() überschreibt die Main Query global und kann zu Performance-Problemen, Paginierungs-Fehlern und unerwartetem Verhalten führen. Nutze stattdessen WP_Query für Custom Queries oder pre_get_posts, um die Main Query zu modifizieren.
Wie finde ich heraus, welche Query-Parameter verfügbar sind?
Die offizielle WordPress-Dokumentation zur WP_Query-Klasse listet alle verfügbaren Parameter auf: https://developer.wordpress.org/reference/classes/wp_query/. Alternativ nutze IDE-Plugins mit Auto-Completion oder das Query Monitor Plugin.
Kann ich mehrere Queries auf einer Seite nutzen?
Ja, du kannst beliebig viele Custom Queries auf einer Seite erstellen. Wichtig ist, nach jeder Query wp_reset_postdata() aufzurufen, um die globale $post-Variable wiederherzustellen. So beeinflussen sich die Queries nicht gegenseitig.
Wie optimiere ich langsame Queries?
Beginne mit dem Query Monitor Plugin, um langsame Queries zu identifizieren. Reduziere dann posts_per_page, nutze 'fields' => 'ids' wenn möglich, vermeide komplexe Meta Queries, implementiere Caching mit Transients und optimiere Datenbankindizes für häufig genutzte Custom Fields.
Was bedeutet „Main Query“ genau?
Die Main Query ist die automatische Datenbankabfrage, die WordPress für jede Seite basierend auf der URL durchführt. Sie bestimmt, welche Inhalte standardmäßig angezeigt werden (z.B. alle Posts einer Kategorie im Kategorie-Archiv). Du kannst sie mit pre_get_posts anpassen, solltest sie aber nicht mit query_posts() überschreiben.
Mach deine Website fit für mehr Sichtbarkeit, Geschwindigkeit und Nutzerfreundlichkeit
Sichere dir jetzt deinen kostenlosen 30-Minuten Website-Check im Zoom.
Wir prüfen deine Seite auf SEO, Ladezeit, UX und Barrierefreiheit – und geben dir konkrete Tipps, die du sofort umsetzen kannst.

