En av de vanligste oppgavene for WordPress-utviklere er å vise en liste med innlegg fra en bestemt kategori. Enten du bygger en nyhetsseksjon, en bloggside med tematiske innlegg, eller en portefølje, er evnen til å filtrere og hente innhold fra spesifikke kategorier helt essensielt. WordPress tilbyr flere robuste metoder for å oppnå dette, fra enkle funksjonskall til komplekse databas spørringer. I denne omfattende guiden vil vi utforske alle disse metodene i dybden, med fokus på beste praksis, optimalisering og vanlige feil som utviklere ofte støter på.
Det finnes tre hovedmetoder for å hente innlegg fra kategorier i WordPress: get_posts() for enkle lister uten behov for full løkke, WP_Query for full kontroll med paginering og avanserte filtre, og query_posts() som generelt frarådes på grunn av dens inngrep i hovedløkken. Vi vil gå gjennom hver metode i detalj, med praktiske kodeeksempler som du kan bruke direkte i dine egne prosjekter.
Kategorier og taksonomier i WordPress forklart
Før vi dykker ned i kodeeksemplene, er det viktig å forstå grunnleggende konsepter bak kategorisystemet i WordPress. Kategorier er en type taksonomi, som er en måte å organisere innhold på i WordPress. Standard taksonomiene inkluderer kategorier for innlegg og tagger, men du kan også opprette egendefinerte taksonomier for mer komplekse innholdsstrukturer. En kategori i WordPress er hierarkisk, noe som betyr at du kan ha underkategorier som igjen kan ha sine egne underkategorier. Dette hierarkiet er viktig å ta hensyn til når du skal hente innlegg, da du må bestemme om du kun vil vise innlegg fra en spesifikk kategori eller også inkludere innlegg fra dens underkategorier.
Når du arbeider med kategorier i WordPress, møter du ofte på begrepene «category ID» og «category slug». Category ID er et unikt numerisk identifikasjonsnummer som WordPress tilordner hver kategori, mens category slug er en URL-vennlig streng som identifikerer kategorien. Begge kan brukes til å filtrere innlegg, men de har ulike fordeler og ulemper. Category ID er mer presist siden det er unikt, mens category slug er mer lesbar og kan endres uten å påvirke eksisterende lenker i samme grad. Det anbefales å bruke category slug der det er praktisk mulig, da det gjør koden mer vedlikeholdsvennlig.
Hente innlegg fra kategori med get_posts()
Funksjonen get_posts() er den enkleste måten å hente innlegg fra en kategori på, og den er perfekt for situasjoner der du trenger en enkel liste uten behov for avansert løkkehåndtering. Denne funksjonen returnerer et array av innleggsobjekter som du deretter kan iterere over. En av fordelene med get_posts() er at den ikke påvirker hovedløkken i WordPress, noe som betyr at du trygt kan bruke den i sidefeltet, footer eller andre deler av siden uten å forstyrre hovedinnholdet.
<?php
$args = array(
'posts_per_page' => 5,
'category_name' => 'news',
'orderby' => 'date',
'order' => 'DESC',
'suppress_filters' => true,
);
$posts_array = get_posts( $args );
foreach ( $posts_array as $post ) :
setup_postdata( $post );
?>
<li>
<a href="<?php the_permalink(); ?>">
<?php the_title(); ?>
</a>
<span class="post-date"><?php echo get_the_date(); ?></span>
</li>
<?php endforeach;
wp_reset_postdata();
?>Dette eksemplet viser de grunnleggende parametrene du ofte vil bruke: posts_per_page bestemmer hvor mange innlegg som skal hentes, category_name filtrerer etter kategorislug, og orderby og order kontrollerer sorteringen. Merk at vi bruker setup_postdata() for å sette opp globale postdata for hvert innlegg i løkken, og wp_reset_postdata() for å tilbakestille disse dataene etter at løkken er ferdig. Dette er kritisk for å unngå at senere funksjonskall bruker feil postdata.
For å hente innlegg fra en spesifikk kategori ved hjelp av category ID istedenfor slug, kan du bruke cat-parameteren:
<?php
$args = array(
'posts_per_page' => 10,
'cat' => 12, // Category ID
'orderby' => 'title',
'order' => 'ASC',
);
$posts = get_posts( $args );
foreach ( $posts as $post ) {
setup_postdata( $post );
echo '<h3>' . get_the_title() . '</h3>';
echo '<p>' . get_the_excerpt() . '</p>';
}
wp_reset_postdata();
?>Hva get_posts endrer sammenlignet med WP_Query
get_posts() er et tynt lag som bygger en WP_Query med egne standardverdier. Kildekoden til funksjonen viser fire forskjeller som betyr noe for kategorilister:
numberpostser 5 som standard, så et kall uten grense returnerer stille fem innlegg.post_statuserpublishogsuppress_filtersertrue, såposts_whereog lignende SQL-filtre fra utvidelser kjøres ikke. Handlingenpre_get_postskjøres likevel.ignore_sticky_postsogno_found_rowstvinges alltid tiltrue. Du kan ikke bygge nummerert paginering påget_posts(), fordi totalt antall aldri beregnes.includesetterposts_per_pagetil antallet ID-er du sender inn, og overstyrer din egen grense.
En felle til gjelder når du kaller get_posts() inne i en funksjon eller en shortcode-callback. setup_postdata() klargjør mal-taggene, men the_title() og the_permalink() leser fortsatt den globale $post. Deklarer global $post; før løkken foreach ( $posts as $post ), slik eksemplene i funksjonsreferansen gjør, og avslutt med wp_reset_postdata(). Uten den deklarasjonen skriver hvert element i listen ut tittelen på siden shortcoden står på.
WP_Query med kategori og paginering
For avanserte brukstilfeller der du trenger paginering, komplekse filtre, eller full tilgang til alle WordPress-løkkefunksjoner, er WP_Query det beste valget. Denne klassen gir deg mye større kontroll over spørringen og lar deg bygge komplekse visninger som er nesten umulig med get_posts(). WP_Query er også den metoden som er best dokumentert og mest fleksibel for tilpassede maler.
<?php
$category_query = new WP_Query( array(
'category__in' => array( 12, 15, 18 ),
'posts_per_page' => 6,
'ignore_sticky_posts' => true,
'paged' => get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1,
) );
if ( $category_query->have_posts() ) :
echo '<div class="posts-grid">';
while ( $category_query->have_posts() ) :
$category_query->the_post();
?>
<article class="post-item">
<h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
<div class="post-meta">
<span class="date"><?php echo get_the_date(); ?></span>
<span class="author"><?php echo get_the_author(); ?></span>
</div>
<div class="post-excerpt">
<?php the_excerpt(); ?>
</div>
<a href="<?php the_permalink(); ?>" class="read-more">
Les mer
</a>
</article>
<?php
endwhile;
echo '</div>';
// Paginering
echo '<div class="pagination">';
echo paginate_links( array(
'total' => $category_query->max_num_pages,
'current' => max( 1, get_query_var( 'paged' ) ),
'prev_text' => __( '« Forrige' ),
'next_text' => __( 'Neste »' ),
) );
echo '</div>';
wp_reset_postdata();
endif;
?>Dette eksemplet demonstrerer flere avanserte funksjoner. Parameteren category__in lar deg spesifisere flere kategori-IDer som en array, noe som betyr at innlegg fra alle de listede kategoriene vil bli inkludert. ignore_sticky_posts sikrer at festede innlegg ikke får spesiell behandling, med mindre du eksplisitt ønsker det. paged-parameteren henter gjeldende side fra URL-en, noe som er essensielt for paginering.
For mer presis kontroll kan du bruke category__and dersom du kun vil ha innlegg som tilhører ALLE de spesifiserte kategoriene, ikke bare én av dem:
<?php
$args = array(
'category__and' => array( 12, 15 ),
'posts_per_page' => 10,
'orderby' => 'comment_count',
'order' => 'DESC',
);
$query = new WP_Query( $args );
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
// Vis innhold
}
wp_reset_postdata();
}
?>Paginere en kategorispørring på en statisk forside
En egen løkke paginerer med paged, som du leser med get_query_var( 'paged' ). Unntaket er en sidemal som er satt som statisk forside: Der lagrer WordPress sidetallet i variabelen page, og derfor sier WP_Query-referansen at du skal lese get_query_var( 'page' ). Med feil variabel viser hvert klikk på “neste” side én igjen.
$paged = ( is_front_page() && is_page() ) ? get_query_var( 'page' ) : get_query_var( 'paged' );
$paged = max( 1, (int) $paged );
$query = new WP_Query( array(
'category_name' => 'nyheter',
'posts_per_page' => 10,
'paged' => $paged,
) );Ta med underkategorier i WP_Query
Et vanlig spørsmål frå utviklere er hvordan man inkluderer innlegg fra underkategorier når man spør etter en overordnet kategori. Med cat og category_name gjør WordPress dette selv: Begge parameterne returnerer innlegg fra kategorien og alle underkategoriene. category__in, category__and og category__not_in treffer derimot bare ID-ene du oppgir. Vil du bevisst holde underkategoriene utenfor, bruker du category__in eller en tax_query med include_children satt til false.
Listen over ID-ene til en kategori med underkategorier trenger du likevel når spørringen ikke går via cat, for eksempel for category__in, for REST-parameteren categories eller for en Query Loop-blokk, som ikke tar med underkategorier av seg selv. Denne hjelpefunksjonen samler ID-ene:
<?php
function get_category_with_children( $category_slug ) {
$category = get_category_by_slug( $category_slug );
if ( ! $category ) {
return array();
}
$args = array(
'taxonomy' => 'category',
'child_of' => $category->term_id,
'hide_empty' => true,
);
$child_categories = get_categories( $args );
$category_ids = array( $category->term_id );
foreach ( $child_categories as $child ) {
$category_ids[] = $child->term_id;
}
return $category_ids;
}
// Bruk i WP_Query
$parent_slug = 'produkter';
$category_ids = get_category_with_children( $parent_slug );
$args = array(
'category__in' => $category_ids,
'posts_per_page' => 12,
'orderby' => 'date',
'order' => 'DESC',
);
$products_query = new WP_Query( $args );
if ( $products_query->have_posts() ) {
while ( $products_query->have_posts() ) {
$products_query->the_post();
// Vis produkter
}
wp_reset_postdata();
}
?>Denne funksjonen get_category_with_children() tar en overordnet kategorislug, finner underkategorier på alle nivåer via child_of og returnerer en array med alle kategori-ID-ene. I WP_Query gir 'cat' => $category->term_id samme resultat med mindre kode; funksjonen lønner seg der et grensesnitt overser underkategorier. Legg merke til hide_empty: En underkategori uten egne innlegg faller ut av listen, selv om det ligger flere nivåer med innlegg under den. Sett den til false hvis hierarkiet ditt har tomme mellomnivåer.
Hvilke kategoriparametere tar med underkategorier
Samme kategori-ID gir ulike innleggslister avhengig av hvilket grensesnitt du spør gjennom. Denne detaljen ligger bak de fleste meldinger om at “listen mangler innlegg”, og reglene står i kjernekoden, ikke i innstillinger:
| Grensesnitt | Argument | Innlegg fra underkategorier |
|---|---|---|
| WP_Query | cat | tatt med |
| WP_Query | category_name | tatt med |
| WP_Query | category__in, category__and, category__not_in | ikke tatt med |
| WP_Query | tax_query | tatt med, med mindre include_children er false |
| get_posts() | category | tatt med (alias for cat) |
| REST API | categories=5 | ikke tatt med |
| REST API | categories[terms]=5&categories[include_children]=true | tatt med |
| Query Loop-blokken | kategorifilter | ikke tatt med |
| WP-CLI | --cat, --category_name | tatt med (sendes rett til WP_Query) |
WP_Query-radene kommer fra WP_Query::parse_tax_query(): cat blir en tax query med include_children satt til true, mens category__in, category__and og category__not_in blir tax queries med include_children satt til false. WP_Query-referansen sier det samme i eksemplene sine: category__in viser ikke innlegg fra underkategorier. Raden for get_posts() følger av funksjonsreferansen, som beskriver category som et alias for cat. REST-radene kommer fra posts-kontrolleren, der include_children er false som standard og bare tilbys for hierarkiske taksonomier. Query Loop-raden kommer fra build_query_vars_from_query_block() i kjernens blocks.php, som setter include_children => false fast for hvert taksonomifilter.
Den praktiske følgen: En PHP-mal med cat => 5 og et headless-frontend som kaller /wp/v2/posts?categories=5 kan vise ulike innlegg for samme overordnede kategori. Bestem hvilken oppførsel du trenger, og velg argumentet som gir den, i stedet for å anta at de to stemmer overens.
Ekskludere kategori i WP_Query
Like viktig som det er å inkludere spesifikke kategorier, er det å ekskludere andre. WordPress tilbyr category__not_in parameteren for dette formålet. Dette er nyttig for situasjoner der du vil vise alle innlegg UNNTATT de som tilhører en bestemt kategori, for eksempel å skjule en «ukens featured» kategori fra hovedlisten.
<?php
$args = array(
'post_type' => 'post',
'posts_per_page' => 10,
'category__not_in' => array( 25, 30 ), // Ekskluder disse kategori-IDene
'post_status' => 'publish',
'ignore_sticky_posts' => true,
);
$main_query = new WP_Query( $args );
if ( $main_query->have_posts() ) {
while ( $main_query->have_posts() ) {
$main_query->the_post();
// Vis innlegg
}
wp_reset_postdata();
}
?>En vanlig brukssese er å ekskludere en kategori fra forsiden:
<?php
if ( is_front_page() ) {
$args = array(
'posts_per_page' => 5,
'category__not_in' => array( get_cat_ID( 'featured' ) ),
);
} else {
$args = array(
'posts_per_page' => 10,
);
}
$query = new WP_Query( $args );
?>Utelating fungerer på to måter, og de behandler underkategorier ulikt. En negativ ID i cat utelater kategorien og alle underkategoriene, fordi kjernen bygger en NOT IN-tax query med include_children satt til true. category__not_in utelater bare termene du lister opp, så innlegg i en underkategori vises fortsatt.
// Utelater kategori 12 og alle underkategoriene
$args = array( 'cat' => '-12' );
// Utelater bare innlegg som ligger direkte i 12 eller 34
$args = array( 'category__not_in' => array( 12, 34 ) );For bloggforsiden finnes det en ryddigere variant enn den ekstra spørringen over: Endre selve hovedspørringen. Referansen for pre_get_posts anbefaler nettopp disse betingelsene:
add_action( 'pre_get_posts', function ( $query ) {
if ( ! is_admin() && $query->is_main_query() && $query->is_home() ) {
$query->set( 'cat', '-12' );
}
} );Endre kategoriarkivet med pre_get_posts
Når du vil endre hvilke innlegg som vises på kategoriarkivene, bruker du handlingen pre_get_posts i stedet for en ekstra spørring i malen.
function modify_category_queries( $query ) {
// Endre bare kategoriarkiver i hovedspørringen
if ( $query->is_category() && $query->is_main_query() && ! is_admin() ) {
// 20 innlegg per side i stedet for standardverdien
$query->set( 'posts_per_page', 20 );
// Utelat kategori-ID 10 på arkivet "featured"
$current_cat = get_queried_object();
if ( 'featured' === $current_cat->slug ) {
$query->set( 'category__not_in', array( 10 ) );
}
}
}
add_action( 'pre_get_posts', 'modify_category_queries' );Bruk metodeversjonene av betingelsestaggene i callbacken ($query->is_category(), $query->is_main_query()). De frittstående funksjonene tester den globale $wp_query og ikke spørringsobjektet kroken får, noe krokreferansen advarer eksplisitt om.
Hvorfor query_posts er feil verktøy for å filtrere på kategori
Eldre veiledninger setter query_posts( 'cat=5' ) øverst i en mal. Docblocken til query_posts() i kjernen sier at funksjonen overstyrer hovedspørringen fullstendig, ikke er ment for utvidelser eller temaer, og i de fleste tilfeller bør erstattes av handlingen pre_get_posts. Funksjonskroppen er én linje som tilordner en ny WP_Query til den globale $wp_query. En mal kjører etter hovedspørringen, så kallet gjentar databasearbeidet og bytter ut objektet som paginering og betingelsestagger leser fra. Hver kategorioppgave som brukte query_posts(), løses enten med pre_get_posts (endre arkivet) eller med en egen WP_Query (legge til en ekstra liste).
Hente innlegg fra egendefinert taksonomi med tax_query
Mange WordPress-installasjoner bruker egendefinerte taksonomier i tillegg til standard kategorier. For eksempel kan en nettside for bøker ha en «sjanger»-taksonomi som fungerer likt som kategorier. For å spørre etter innlegg basert på egendefinerte taksonomier, må du bruke tax_query-parameteren i stedet for de vanlige category-parametrene.
<?php
$args = array(
'post_type' => 'bok',
'posts_per_page' => 12,
'tax_query' => array(
array(
'taxonomy' => 'sjanger',
'field' => 'slug',
'terms' => 'thriller',
'operator' => 'IN',
),
),
);
$thriller_books = new WP_Query( $args );
if ( $thriller_books->have_posts() ) {
while ( $thriller_books->have_posts() ) {
$thriller_books->the_post();
// Vis bøker
}
wp_reset_postdata();
}
?>Du kan også kombinere flere taksonomispørringer med AND- eller OR-operatorer:
<?php
$args = array(
'post_type' => 'bok',
'posts_per_page' => 20,
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'sjanger',
'field' => 'slug',
'terms' => array( 'thriller', 'krim' ),
),
array(
'taxonomy' => 'forfatter',
'field' => 'name',
'terms' => array( 'Jo Nesbø' ),
'operator' => 'NOT IN',
),
),
);
$query = new WP_Query( $args );
?>Gjøre kategorispørringer raskere i WordPress
Databasespørringer kan være en betydelig kilde til langsomlasting på WordPress-nettsteder, spesielt når du har mange innlegg eller komplekse filtre. Heldigvis finnes det flere teknikker du kan bruke for å optimalisere spørringene dine og redusere belastningen på databasen.
Den første og viktigste optimaliseringen er å begrense hvilke data som hentes fra databasen. WordPress henter som standard alle postfelt, inkludert innhold, ekserpter, og alle metaboxer. Hvis du bare trenger titler og permalinker, kan du spare betydelig tid ved å be om kun disse feltene:
<?php
$args = array(
'category_name' => 'news',
'posts_per_page' => 5,
'fields' => 'ids', // Kun post-IDer
'no_found_rows' => true, // Ikke tell totalt antall rader
);
$post_ids = get_posts( $args );
foreach ( $post_ids as $id ) {
$title = get_the_title( $id );
$link = get_permalink( $id );
echo '<li><a href="' . esc_url( $link ) . '">' . esc_html( $title ) . '</a></li>';
}
?>'fields' => 'ids' forteller WordPress at du kun vil ha en array med post-ID-er i stedet for fullstendige innleggsobjekter. 'no_found_rows' => true slår av tellingen av totalt antall treff. Med get_posts() er linjen riktignok overflødig, fordi funksjonen alltid setter no_found_rows til true; i en egen WP_Query uten paginering er den derimot en reell besparelse.
Argumentet fields godtar nøyaktig tre verdier, ifølge WP_Query-referansen: all (standard), ids og id=>parent. Alle andre verdier, også en matrise med kolonnenavn, returnerer stille fullstendige innleggsobjekter. To brytere til sparer arbeid for lister som bare skriver ut tittel og lenke:
$args = array(
'category_name' => 'nyheter',
'posts_per_page' => 5,
'no_found_rows' => true, // ingen SQL_CALC_FOUND_ROWS, paginering trengs ikke
'update_post_meta_cache' => false, // egendefinerte felt skrives ikke ut
'update_post_term_cache' => false, // termer skrives ikke ut
);no_found_rows hindrer WordPress i å telle totalt antall treff, som bare trengs for paginering. De to cache-flaggene er true som standard i kjernen; referansen sier at du normalt ikke trenger å endre dem, men slått av sparer de de ekstra meta- og termspørringene når listen aldri leser de dataene. La dem stå på når løkken skriver ut kategorier, stikkord eller egendefinerte felt, fordi forhåndslasting i én spørring er billigere enn én spørring per innlegg.
Cache kategorispørringer med Transients API
For spørringer som ikke endrer seg hyppig, kan du dramatiskt forbedre ytelsen ved å bufre resultatene ved hjelp av Transients API. Dette lagrer spørringsresultatene i databasen (eller en annen cache-backend) for en spesifisert tidsperiode, slik at du unngår å kjøre den samme spørringen om og om igjen.
<?php
function get_cached_category_posts( $category_slug, $posts_per_page = 5, $cache_time = HOUR_IN_SECONDS ) {
$cache_key = 'category_posts_' . $category_slug . '_' . $posts_per_page;
$cached_posts = get_transient( $cache_key );
if ( false !== $cached_posts ) {
return $cached_posts;
}
$args = array(
'category_name' => $category_slug,
'posts_per_page' => $posts_per_page,
'orderby' => 'date',
'order' => 'DESC',
);
$posts = get_posts( $args );
set_transient( $cache_key, $posts, $cache_time );
return $posts;
}
// Bruk den cachede funksjonen
$latest_news = get_cached_category_posts( 'news', 5, 15 * MINUTE_IN_SECONDS );
foreach ( $latest_news as $post ) {
setup_postdata( $post );
echo '<div class="news-item">';
the_title( '<h3>', '</h3>' );
the_excerpt();
echo '</div>';
}
wp_reset_postdata();
?>Denne funksjonen sjekker først om det finnes en cached versning av spørringsresultatene. Hvis det gjør det, returneres de umiddelbart uten å kjøre en ny spørring. Hvis ikke, kjøres spørringen, resultatene caches med set_transient(), og deretter returneres resultatene. cache_time-parameteren bestemmer hvor lenge resultatene skal være gyldige, i dette eksemplet 15 minutter.
For mer avansert caching som automatisk invaliderer når nye innlegg publiseres, kan du legge til hooker:
<?php
function clear_category_posts_cache( $post_id ) {
// Bare cache hvis det er et publisert innlegg
if ( get_post_status( $post_id ) !== 'publish' ) {
return;
}
$categories = get_the_category( $post_id );
foreach ( $categories as $category ) {
delete_transient( 'category_posts_' . $category->slug . '_5' );
delete_transient( 'category_posts_' . $category->slug . '_10' );
}
}
add_action( 'save_post', 'clear_category_posts_cache' );
add_action( 'delete_post', 'clear_category_posts_cache' );
?>Shortcode for å vise innlegg fra en kategori
En av de mest fleksible måtene å implementere kategorivisninger på er gjennom WordPress-shortcodes. Dette lar redaktører enkelt legge til kategorilister i innhold uten å måtte skrive kode.
<?php
function category_posts_shortcode( $atts ) {
global $post; // mal-taggene leser den globale $post
$atts = shortcode_atts( array(
'category' => '',
'limit' => 5,
'orderby' => 'date',
'order' => 'DESC',
'show_date' => 'yes',
'show_excerpt' => 'yes',
'template' => 'default',
), $atts, 'kategori_innlegg' );
if ( empty( $atts['category'] ) ) {
return '<p class="error">Vennligst spesifiser en kategori.</p>';
}
$args = array(
'category_name' => $atts['category'],
'posts_per_page' => intval( $atts['limit'] ),
'orderby' => $atts['orderby'],
'order' => $atts['order'],
'ignore_sticky_posts' => true,
);
$posts = get_posts( $args );
if ( empty( $posts ) ) {
return '<p>Ingen innlegg funnet i denne kategorien.</p>';
}
ob_start();
?>
<div class="category-posts category-posts--<?php echo esc_attr( $atts['template'] ); ?>">
<?php foreach ( $posts as $post ) :
setup_postdata( $post );
?>
<article class="category-post-item">
<h3 class="post-title">
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
</h3>
<?php if ( 'yes' === $atts['show_date'] ) : ?>
<time class="post-date" datetime="<?php echo esc_attr( get_the_date( 'c' ) ); ?>">
<?php echo esc_html( get_the_date() ); ?>
</time>
<?php endif; ?>
<?php if ( 'yes' === $atts['show_excerpt'] ) : ?>
<div class="post-excerpt">
<?php the_excerpt(); ?>
</div>
<?php endif; ?>
</article>
<?php endforeach;
wp_reset_postdata();
?>
</div>
<?php
return ob_get_clean();
}
add_shortcode( 'kategori_innlegg', 'category_posts_shortcode' );
?>Nå kan redaktører bruke shortcoden i innholdet sitt:
[kategori_innlegg category="nyheter" limit="5" orderby="date" show_date="yes"]For enda mer fleksibilitet kan du legge til støtte for flere kategorier:
<?php
function advanced_category_shortcode( $atts ) {
$atts = shortcode_atts( array(
'categories' => '',
'operator' => 'IN', // IN, AND, NOT IN
'limit' => 6,
'columns' => 2,
'show_thumb' => 'yes',
), $atts, 'kategorier' );
$categories = array_filter( array_map( 'trim', explode( ',', $atts['categories'] ) ) );
if ( empty( $categories ) ) {
return '<p class="shortcode-error">Vennligst spesifiser minst én kategori.</p>';
}
$category_ids = array();
foreach ( $categories as $cat_slug ) {
$cat = get_category_by_slug( $cat_slug );
if ( $cat ) {
$category_ids[] = $cat->term_id;
}
}
if ( empty( $category_ids ) ) {
return '<p class="shortcode-error">Ugyldige kategorier spesifisert.</p>';
}
$args = array(
'category__in' => $category_ids,
'posts_per_page' => intval( $atts['limit'] ),
'ignore_sticky_posts' => true,
);
if ( 'AND' === $atts['operator'] ) {
$args['category__and'] = $category_ids;
unset( $args['category__in'] );
}
$query = new WP_Query( $args );
ob_start();
?>
<div class="posts-grid columns-<?php echo esc_attr( $atts['columns'] ); ?>">
<?php if ( $query->have_posts() ) :
while ( $query->have_posts() ) : $query->the_post();
?>
<article class="post-card">
<?php if ( 'yes' === $atts['show_thumb'] && has_post_thumbnail() ) : ?>
<div class="post-thumbnail">
<a href="<?php the_permalink(); ?>">
<?php the_post_thumbnail( 'medium', array( 'loading' => 'lazy' ) ); ?>
</a>
</div>
<?php endif; ?>
<div class="post-content">
<h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
<?php the_excerpt(); ?>
</div>
</article>
<?php
endwhile;
wp_reset_postdata();
endif; ?>
</div>
<?php
return ob_get_clean();
}
add_shortcode( 'kategorier', 'advanced_category_shortcode' );
?>Laste inn flere kategoriinnlegg med AJAX
For store nettsteder med mange innlegg kan AJAX-lastning gi en mye bedre brukeropplevelse ved å laste flere innlegg asynkront uten å laste siden på nytt. Dette er spesielt nyttig for «last inn mer»-funksjonalitet.
Først registrerer du JavaScript:
<?php
function enqueue_category_ajax_scripts() {
wp_enqueue_script(
'category-ajax',
get_template_directory_uri() . '/js/category-ajax.js',
array( 'jquery' ),
'1.0',
true
);
wp_localize_script( 'category-ajax', 'categoryAjax', array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'category_ajax_nonce' ),
) );
}
add_action( 'wp_enqueue_scripts', 'enqueue_category_ajax_scripts' );
?>Deretter oppretter du AJAX-handleren:
<?php
function load_more_category_posts() {
check_ajax_referer( 'category_ajax_nonce', 'nonce' );
$page = isset( $_POST['page'] ) ? intval( $_POST['page'] ) : 1;
$category = isset( $_POST['category'] ) ? sanitize_text_field( $_POST['category'] ) : '';
$posts_per_page = isset( $_POST['posts_per_page'] ) ? intval( $_POST['posts_per_page'] ) : 6;
$args = array(
'category_name' => $category,
'posts_per_page' => $posts_per_page,
'paged' => $page,
'post_status' => 'publish',
);
$query = new WP_Query( $args );
if ( $query->have_posts() ) :
while ( $query->have_posts() ) : $query->the_post();
get_template_part( 'template-parts/post', 'card' );
endwhile;
wp_reset_postdata();
endif;
wp_die();
}
add_action( 'wp_ajax_load_category_posts', 'load_more_category_posts' );
add_action( 'wp_ajax_nopriv_load_category_posts', 'load_more_category_posts' );
?>JavaScript for håndtering av last mer-knappen:
jQuery(document).ready(function($) {
var currentPage = 1;
var isLoading = false;
var hasMore = true;
$('.load-more-category').on('click', function(e) {
e.preventDefault();
if (isLoading || !hasMore) return;
var $button = $(this);
var category = $button.data('category');
var postsPerPage = $button.data('posts-per-page') || 6;
isLoading = true;
$button.addClass('loading').text('Laster...');
$.ajax({
url: categoryAjax.ajaxurl,
type: 'POST',
data: {
action: 'load_category_posts',
nonce: categoryAjax.nonce,
page: currentPage + 1,
category: category,
posts_per_page: postsPerPage
},
success: function(response) {
if (response.trim()) {
$('.posts-grid').append(response);
currentPage++;
} else {
hasMore = false;
$button.hide();
}
},
error: function() {
alert('En feil oppstod. Vennligst prøv igjen.');
},
complete: function() {
isLoading = false;
$button.removeClass('loading').text('Last flere');
}
});
});
});Vanlige feil i WP_Query med kategorier
Selv erfarne WordPress-utviklere støter regelmessig på problemer når de arbeider med kategorispørringer. Her er de vanligste problemene og deres løsninger.
Problem: Tomme resultater selv om det finnes innlegg. Dette skyldes ofte at post_status ikke er satt korrekt. Som standard viser WP_Query bare publiserte innlegg, men hvis du tester i en utviklingsmiljø kan innleggene være i «draft» eller «pending» status.
<?php
// Vis alle publiserte innlegg
$args = array(
'category_name' => 'news',
'post_status' => 'publish',
);
// For testing: Vis alle innlegg uansett status
$test_args = array(
'category_name' => 'news',
'post_status' => array( 'publish', 'draft', 'pending', 'private' ),
);
?>Problem: Innlegg vises feil eller feil kategori. Sjekk at du bruker riktig parameter. category_name tar kategorislug (streng), mens cat tar kategori-ID (heltall). En vanlig feil er å bruke cat med en streng eller omvendt.
<?php
// Feil - cat forventer et tall
$args = array( 'cat' => 'news' ); // Fungerer ikke!
// Riktig - category_name tar en streng
$args = array( 'category_name' => 'news' );
// Riktig - cat tar et tall
$args = array( 'cat' => 42 ); // Antar at 42 er en gyldig kategori-ID
// Sjekk kategori-ID først
$category = get_category_by_slug( 'news' );
if ( $category ) {
$args = array( 'cat' => $category->term_id );
}
?>Problem: Festede innlegg vises først. Ifølge WP_Query-referansen flytter ignore_sticky_posts med standardverdien false festede innlegg til starten av resultatet. Med true står de på sin naturlige plass, og med post__not_in i tillegg forsvinner de helt. Merk: post__in med listen over festede innlegg ville begrense spørringen til nettopp de innleggene, ikke legge dem til.
<?php
$args = array(
'category_name' => 'news',
'ignore_sticky_posts' => true, // Ignorer festede innlegg
'posts_per_page' => 10,
);
// Alternativt: Fjern festede innlegg helt fra kategorilisten
$args = array(
'category_name' => 'news',
'ignore_sticky_posts' => true,
'post__not_in' => get_option( 'sticky_posts' ),
'posts_per_page' => 10,
);
?>Problem: Paginering fungerer ikke. Dette er et svært vanlig problem som ofte skyldes feil konfigurasjon av paged-parameteren eller at WP_Query ikke brukes korrekt med hovedløkken.
<?php
// Riktig paginering i WP_Query
$paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
$args = array(
'category_name' => 'news',
'posts_per_page' => 10,
'paged' => $paged,
);
$query = new WP_Query( $args );
if ( $query->have_posts() ) :
while ( $query->have_posts() ) : $query->the_post();
// Vis innlegg
endwhile;
// Paginering
echo paginate_links( array(
'total' => $query->max_num_pages,
'current' => $paged,
) );
wp_reset_postdata();
endif;
?>Lage egen kategorimal i WordPress-temaet
WordPress lar deg opprette egendefinerte maler for spesifikke kategorier, noe som gir deg full kontroll over hvordan innlegg fra ulike kategorier vises.
Opprett en fil i temamappen din med navnet category-{slug}.php, der {slug} er kategorisluggen. For eksempel, for kategorien «nyheter», oppretter du category-nyheter.php. I denne filen kan du lage en helt tilpasset visning:
<?php
/**
* Arkivmal for kategorien med slug "nyheter",
* malhierarkiet velger den ut fra filnavnet
*/
get_header();
$category = get_category_by_slug( 'nyheter' );
?>
<div class="news-archive">
<header class="archive-header">
<h1><?php echo esc_html( $category->name ); ?></h1>
<?php if ( category_description( $category->term_id ) ) : ?>
<div class="archive-description">
<?php echo wp_kses_post( category_description( $category->term_id ) ); ?>
</div>
<?php endif; ?>
</header>
<div class="news-grid">
<?php
$news_args = array(
'cat' => $category->term_id,
'posts_per_page' => 12,
'paged' => get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1,
);
$news_query = new WP_Query( $news_args );
if ( $news_query->have_posts() ) :
while ( $news_query->have_posts() ) : $news_query->the_post();
?>
<article class="news-item">
<?php if ( has_post_thumbnail() ) : ?>
<div class="news-thumbnail">
<a href="<?php the_permalink(); ?>">
<?php the_post_thumbnail( 'medium_large', array( 'loading' => 'lazy' ) ); ?>
</a>
</div>
<?php endif; ?>
<div class="news-content">
<span class="news-date"><?php echo get_the_date(); ?></span>
<h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
<?php the_excerpt(); ?>
</div>
</article>
<?php
endwhile;
wp_reset_postdata();
else :
?>
<p class="no-news">Ingen nyheter funnet.</p>
<?php endif; ?>
</div>
<?php if ( $news_query->max_num_pages > 1 ) : ?>
<nav class="pagination">
<?php
echo paginate_links( array(
'total' => $news_query->max_num_pages,
'current' => max( 1, get_query_var( 'paged' ) ),
'format' => '?paged=%#%',
'prev_text' => '« Forrige',
'next_text' => 'Neste »',
) );
?>
</nav>
<?php endif; ?>
</div>
<?php get_footer(); ?>WP_Query med kategori og meta_query
Ofte trenger du å kombinere kategorifiltrering med andre kriterier som egendefinerte felt, søkeord, eller forfatterskap. WordPress WP_Query støtter alle disse kombinasjonene gjennom meta_query og andre parametere.
<?php
$args = array(
'post_type' => 'event',
'posts_per_page' => 10,
'category__in' => array( get_cat_ID( 'konferanser' ), get_cat_ID( 'workshops' ) ),
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'event_dato',
'value' => date( 'Y-m-d' ),
'compare' => '>=',
'type' => 'DATE',
),
array(
'key' => 'event_sted',
'value' => 'Oslo',
'compare' => '=',
),
),
'orderby' => 'meta_value',
'meta_key' => 'event_dato',
'order' => 'ASC',
);
$events = new WP_Query( $args );
if ( $events->have_posts() ) {
while ( $events->have_posts() ) {
$events->the_post();
// Vis event
}
wp_reset_postdata();
}
?>Hente innlegg fra kategori via WordPress REST API
I moderne nettapplikasjoner bygget med Astro, Next.js eller mobilapper hentes ofte innlegg direkte via det innebygde REST-grensesnittet:
- Effektiv filtrering via endepunkter: Endepunktet
/wp/v2/posts?categories=12returnerer artikler fra en bestemt kategori som JSON-data. Ved å legge til_fields=id,title,slug,date,excerptbegrenser du datamengden betraktelig, noe som gir raskere overføring og bedre mobilytelse. - Innebygde mediedata med _embed: For å slippe separate spørringer etter forfatterdata og utvalgte bilder, sørger parameteren
_embedfor at alle relaterte objekter inkluderes direkte i samme respons. - Hurtigbufring på kanten (Edge Caching): Med et CDN foran API-et og passende
Cache-Control-headere besvarer kantbufferen gjentatte forespørsler uten at WordPress kjører spørringen på nytt.
Tre detaljer fra REST-håndboken avgjør om en headless-liste blir komplett:
- Underkategorier krever objektformen.
categories=5treffer bare term 5. For å ta med underkategoriene sender ducategories[terms]=5&categories[include_children]=true. Samme objekt godtarcategories[operator]=ANDnår et innlegg må ha alle termene du lister opp. - En side gir maks 100 elementer. Pagineringsveiledningen begrenser
per_pagetil en verdi mellom 1 og 100. Les svarhodeneX-WP-TotalogX-WP-TotalPagesog hentpage=2,page=3til du har alt. _fieldsstøtter nestede nøkler. Siden WordPress 5.3 godtar parameteren_fieldsstier sommeta.arrangement_dato, så en liste kan be om én registrert metanøkkel uten hele metaobjektet. WordPress hopper da over beregningen av feltene du ikke ba om, noe som også korter ned svartiden.
Hente kategoriinnlegg med WPGraphQL
For frontender som trenger mange koblede data i ett kall, er utvidelsen WPGraphQL et alternativ til REST API-et:
- Presis datainnhenting: Med én enkelt GraphQL-spørring henter du nøyaktig de feltene du trenger - fra kategorinavn og innleggstitler til optimaliserte bilde-URL-er - uten overflødig databallast.
- Cursor-basert paginering: I stedet for sidetall sender klienten markøren til det sist lastede elementet, noe som passer for uendelig rulling (infinite scroll).
Unngå N+1-spørringer i WordPress-løkken
På travle nettsteder har utformingen av databasespørringene direkte innvirkning på stabiliteten:
- Bruk av update_post_meta_cache: Skal du vise metadata i en løkke, må
update_post_meta_cachestå påtrue, som er standard. Da forhåndslaster WordPress alle metadata i én samlet SQL-spørring, i stedet for å sende én ny spørring for hver enkelt artikkel. - Objekt-caching med Redis: Med en persistent objektbuffer som Redis besvares gjentatte taksonomispørringer fra minnet i stedet for fra MySQL-databasen.
Vise innlegg fra kategori med Query Loop-blokken
I blokktemaer setter redaktører sammen kategorilister uten PHP:
- Visuell filtrering uten PHP-koding: Den innebygde
core/query-blokken (spørringsløkke) lar redaktører hente og vise innlegg basert på kategorier, stikkord og forfattere direkte i nettsideeditoren. Utviklere kan forhåndsdefinere gjenbrukbare blokkmønstre, slik at innholdsprodusenter kan sette opp skreddersydde artikkellister uten teknisk bistand. - Malhierarki for blokktemaer: I blokktemaer styres visningen av HTML-filer som
category.htmlogarchive.html. Malene ligger som filer i temaet og kan versjonsstyres med Git på samme måte som PHP-maler.
Blokkens kategorifilter treffer bare termene du velger. Kjernen gjør det om til en tax query med include_children satt til false, så en valgt overordnet kategori tar ikke med innlegg som bare ligger i underkategoriene; legg underkategoriene til i filteret også.
Liste innlegg fra en kategori med WP-CLI
Til revisjoner, migreringer og engangseksporter kjører wp post list den samme WP_Query fra kommandolinjen. Hvert alternativ --<felt>=<verdi> sendes til WP_Query som argument, så kategorireglene fra tabellen over gjelder uendret:
# Term-ID og antall innlegg for hver kategori
wp term list category --fields=term_id,name,slug,count
# Publiserte innlegg i "nyheter" og underkategoriene, som CSV
wp post list --category_name=nyheter --post_status=publish --fields=ID,post_title,post_date --format=csv
# Bare ID-er, innlegg som ligger direkte i kategori 12 (uten underkategorier)
wp post list --category__in=12 --post_status=publish --format=ids
# Hvor mange innlegg en mal viser for kategori 12 med underkategorier
wp post list --cat=12 --post_status=publish --format=countTo standardverdier skiller seg fra en løkke i en mal. Kildekoden til kommandoen setter posts_per_page til -1 og post_status til any, så uten --post_status=publish inneholder utdataene også utkast, ventende og private innlegg. Standardkolonnene er ID, post_title, post_name, post_date og post_status, og --format godtar table, csv, ids, json, count og yaml. Sammenlign --format=count for --cat og --category__in med samme ID, så ser du raskt hvor mange innlegg som bare ligger i underkategorier.
Oppsummering og anbefalinger
Å hente og vise innlegg fra kategorier i WordPress er en grunnleggende ferdighet som alle utviklere bør mestre. De viktigste punktene å huske på er:
For enkle lister uten behov for paginering er get_posts() det beste valget på grunn av enkelheten og at den ikke påvirker hovedløkken. For komplekse visninger med paginering og avanserte filtre er WP_Query det foretrukne verktøyet. Unngå query_posts() med mindre du eksplisitt trenger å modifisere hovedløkken.
Optimalisering er kritisk for store nettsteder. Bruk 'fields' => 'ids' når du bare trenger ID-er, no_found_rows når du ikke trenger totalt antall resultater, og Transients API for å cache resultatene. For dynamiske nettsteder bør du vurdere AJAX-lastning for en bedre brukeropplevelse.
Husk alltid å tilbakestille postdata med wp_reset_postdata() etter at du har brukt WP_Query eller get_posts(), og valider og saniter alle input fra brukere for å unngå sikkerhetsproblemer.
Vanlige spørsmål
Hvordan henter jeg innlegg fra flere kategorier samtidig?
Du kan bruke category__in-parameteren med en array av kategori-IDer. For eksempel: 'category__in' => array( 12, 15, 18 ). Dette viser innlegg som tilhører minst én av de listede kategoriene. Hvis du vil ha innlegg som tilhører ALLE kategoriene, bruker du category__and i stedet.
Hvordan inkluderer jeg underkategorier i spørringen?
Med cat eller category_name skjer det automatisk, begge parameterne tar med underkategorier. category__in gjør det ikke. I REST API-et trenger du objektformen categories[terms]=5&categories[include_children]=true, og i Query Loop-blokken må du velge underkategoriene selv.
Hvordan paginerer jeg resultatene fra en tilpasset spørring?
Bruk WP_Query med paged-parameteren satt til get_query_var( 'paged' ). Deretter bruker du paginate_links()-funksjonen med max_num_pages fra spørringen. Husk at WP_Query sin paginering er uavhengig av hovedløkken.
Hvordan cacher jeg kategorispørringer for bedre ytelse?
Bruk WordPress Transients API. Lagre resultatene av spørringen med set_transient() og hent dem med get_transient(). Sett en passende utløpstid basert på hvor ofte innholdet oppdateres. Husk å invalidere cachen når nye innlegg publiseres.
Hvordan ekskluderer jeg bestemte innlegg fra kategorivisningen?
Bruk post__not_in-parameteren med en array av post-IDer du vil ekskludere. Du kan også bruke category__not_in for å ekskludere hele kategorier fra spørringen.
Feilsøke kategorispørringer med Query Monitor
Når kategorispørringer ikke returnerer de forventede artiklene:
- Kontroller publiseringsstatus og dato: Standardinnstillingen viser kun artikler med status
publish. Fremtidige eller private innlegg krever eksplisitte parametere. - Feilsøking med Query Monitor: Installer analyseverktøyet Query Monitor i utviklingsmiljøet for å inspisere de faktiske SQL-spørringene, kjøretider og eventuelle indekseringsfeil.
- Rens hurtigbufferen: Husk alltid å tømme både objektbufferen og sidebufferen etter endringer i taksonomier for å sikre at endringene vises umiddelbart for alle brukere.







