Standard WordPress-funksjonen the_category() er praktisk i klassiske temaer, men den har en hard grense: den skriver alltid ut HTML-ankere (<a href="...">...</a>) til kategoriarkivet. Det funker på en enkeltinnleggsside der leseren skal kunne klikke videre. Det funker dårlig på et porteføljekort, en slider, en meta-rad i et headless-oppsett eller en badge der kategorien bare skal være etikett.
Løsningen er get_the_category(), som returnerer en array av term-objekter i stedet for ferdig markup. Offisiell referanse: get_the_category(), the_category() og get_the_terms().
På WordUp Oslo og WordCamp Norge dukker dette opp ofte når noen bygger et kortbasert arkiv for norske medlemsbedrifter eller et konferanseprogram: de vil ha «Nyheter», «Case» eller «Arrangører» som tekst, ikke som klikkbare arkivlenker inne i kortet. Samme krav dukker opp i medlemsportaler der kortet allerede er hele lenkemålet - en ekstra anker inne i badge-en skaper nestede <a>-tagger, som er ugyldig HTML og rotete for tastaturnavigasjon.
Målet med denne veiledningen er praktisk: velg riktig API, escape i riktig kontekst, håndter flere termer, egne taksonomier, SEO-primary og FSE, og unngå snarveier som ser smarte ut i et gist men feiler i produksjon.
Hvorfor the_category() alltid skriver ut anker
the_category() er en template tag i WordPress-forstand: den er laget for å vise noe, ikke for å returnere data du kan forme videre. Under panseret bygger den på get_the_category_list(), som setter sammen en liste med lenker, separator og valgfri overordnet kontekst.
Parametere styrer separator, foreldre og post-ID. De styrer ikke en «kun tekst»-modus. Hvis du trenger navnet uten markup, er feil verktøy valgt. Bytt API, ikke lim på strip_tags() etterpå.
Et konkret scenario: du har en forsiderad med åtte arrangementskort etter WordCamp Norge. Hvert kort linker allerede til single. Hvis badge-en også er en kategoriarkiv-lenke, får mobilbrukere to treffområder oppå hverandre, og analytics blander «kortklikk» med «kategoriklikk». Ren tekst i badge-en gjør målingen ærlig.
<?php
// Dette skriver alltid ut <a>-tagger.
the_category( ', ' );
?>Hva returnerer get_the_category() i WordPress
<?php
$categories = get_the_category();
// Array av WP_Term-objekter for taksonomien «category».
?>get_the_category( $post_id = false ) uten argument bruker gjeldende post fra den globale $post (inne i loopen). Returverdien er en array av term-objekter. Feltene du bruker mest:
name- synlig etikett («Nyheter»)slug- URL- og CSS-vennlig streng (nyheter)term_id- stabil ID for spørringer og metadescription- kategoriens beskrivelsesfeltcount- antall innlegg i kategorienparent- overordnet term-ID (0 hvis toppnivå)
Tom array er lovlig: et innlegg uten kategorier (eller et custom post type uten category) gir array(). Sjekk alltid ! empty( $categories ) før du leser indeks 0. Ellers får du notices i WP_DEBUG og blanke badges i produksjon når redaksjonen glemmer å tilordne kategori på et hastig publisert innlegg.
Rekkefølgen i arrayen er ikke en kontrakt du bør bygge forretningslogikk på. Den følger hvordan termene er tilordnet og sortert internt, ikke nødvendigvis den redaksjonelle «hovedkategorien». Trenger du den, les plugin-meta for primary (se egen seksjon under).
Utenfor hovedloopen (widget, REST-callback, cron) send eksplisitt post-ID:
<?php
$categories = get_the_category( $post_id );
?>Hvordan escape kategorinavn med esc_html og esc_attr
Kategorinavn kommer fra databasen og kan i teorien inneholde tegn som ødelegger markup. Bruk kontekst riktig:
- Tekstinnhold i HTML:
esc_html( $category->name ) - Attributter (
class,data-*,title):esc_attr( $category->slug ) - URL-er (hvis du velger å lenke selv):
esc_url( get_category_link( $category->term_id ) )
<?php
$cats = get_the_category();
$first_cat = ! empty( $cats ) ? $cats[0] : null;
if ( $first_cat ) : ?>
<span class="badge badge-<?php echo esc_attr( $first_cat->slug ); ?>">
<?php echo esc_html( $first_cat->name ); ?>
</span>
<?php endif; ?>Da får «Nyheter» klassen .badge-nyheter uten at du mister kontroll over markup. the_category() gir deg ikke den friheten.
Hvordan vise flere kategorier uten lenke med implode
Mange innlegg har mer enn én kategori. Samle navnene først, slå dem sammen etterpå. Da styrer du separator, mellomrom og rekkefølge uten å røre anker-HTML.
<?php
$categories = get_the_category();
$output = array();
if ( ! empty( $categories ) ) {
foreach ( $categories as $category ) {
$output[] = esc_html( $category->name );
}
echo implode( ', ', $output );
}
?>Tips fra praksis på norske nettredaksjoner: bruk en midterprikk (·) eller skråstrek når komma konkurrerer med tusenskiller i talltunge case-studier. implode() bryr seg ikke - du velger strengen.
Hvis du trenger både navn og slug i samme pass (for eksempel JSON-LD articleSection pluss CSS), bygg to arrays eller ett assosiativt kart i loopen, ikke kall get_the_category() to ganger i samme request uten grunn.
Hvorfor strip_tags på kategorilisten er feil
Dette dukker fortsatt opp i gamle child themes og i «raske» snippets fra forum:
<?php
// Unngå dette.
echo strip_tags( get_the_category_list( ', ' ) );
?>Hvorfor det er dårlig:
- Du ber WordPress bygge full HTML bare for å kaste den.
strip_tags()fjerner ikke attributter før den stripper tagger i alle versjoner/kontekster like forutsigbart som du tror når noe annet filtrerer listen.- Du mister tilgang til
slug,term_idogparent. - Filtre på
the_category/get_the_category_listkan fortsatt kjøre og endre output før strip.
Riktig retning: hent data med get_the_category() eller get_the_terms(), escape ved utskrift. Bygg markup selv hvis du trenger den.
Hente termnavn fra egen taksonomi med get_the_terms
get_the_category() er spesialisert for innebygd category. Har du produktlinje, fagfelt eller wordcamp-spor, bruk get_the_terms():
<?php
$terms = get_the_terms( get_the_ID(), 'fagfelt' );
if ( empty( $terms ) || is_wp_error( $terms ) ) {
return;
}
$names = array();
foreach ( $terms as $term ) {
$names[] = esc_html( $term->name );
}
echo implode( ', ', $names );
?>Merk forskjellen: get_the_terms() kan returnere false eller WP_Error. get_the_category() returnerer vanligvis en (muligens tom) array. Kode som kopieres mellom kategori og custom taxonomy må håndtere begge returformer.
Til WordCamp Norge-programmet er det vanlig å ha både category (innholdstype) og en egen taksonomi for spor (utvikling, innhold, business). Da trenger du to kall, ikke én «superliste».
Hente primærkategori fra Yoast og Rank Math
Yoast, Rank Math og flere lagrer en «primary category». get_the_category()[0] er ikke garantert den samme. Rekkefølgen fra get_the_category() følger term-rekkefølge / tilordning, ikke nødvendigvis SEO-pluginens valg.
Typisk mønster (Yoast-meta som eksempel - sjekk alltid nøkkelen for din plugin-versjon):
<?php
$post_id = get_the_ID();
$primary = (int) get_post_meta( $post_id, '_yoast_wpseo_primary_category', true );
$categories = get_the_category( $post_id );
$chosen = null;
if ( $primary && ! empty( $categories ) ) {
foreach ( $categories as $category ) {
if ( (int) $category->term_id === $primary ) {
$chosen = $category;
break;
}
}
}
if ( ! $chosen && ! empty( $categories ) ) {
$chosen = $categories[0];
}
if ( $chosen ) {
echo esc_html( $chosen->name );
}
?>Fallback til første element er viktig: eldre innlegg mangler ofte primary-meta. På et medlemsmagasin etter WordUp Bergen så vi badges som hoppet mellom «Medlemsnytt» og «Arrangement» fra side til side fordi noen kort leste [0] og andre leste Yoast-primary uten fallback.
Kategorinavn uten lenke i blokktema og FSE
I Full Site Editing får du Query Loop og Post Terms-blokker. De er fine når du vil ha standard term-lenker i et arkiv. De er svake når:
- badge-markup må matche et designsystem med faste BEM-klasser
- du trenger bare én term (primær) uten lenke
- headless / App Router-frontends leser REST og forventer rene strenger
- du mapper term-slug til Tailwind- eller token-klasser i PHP-delen av et hybridtema
Da beholder du en liten template-part eller et blokkvariasjonsmønster med PHP, eller du eksponerer feltene via REST (register_rest_field) basert på samme get_the_category() / get_the_terms()-logikk. Poenget er det samme: les term-objektet, ikke strip ferdig HTML.
Et hybridtema vi så etter WordUp Trondheim brukte FSE til layout og en render_callback på en egen «Post badge»-blokk. Callback-en kalte get_the_category( $block->context['postId'] ), escapet name/slug, og returnerte span-markup. Redaktørene flyttet blokken i Site Editor; utviklerne beholdt kontroll på klassenavn. Det er et bedre kompromiss enn å låse hele arkivet til klassisk PHP, eller å tvinge Post Terms til å late som den er et designsystem.
Når bør du bruke the_category() med lenke?
Noen ganger er ankeret riktig: brødsmuler, term-sky, enkeltinnlegg der meta-raden skal lede til arkivet. Da er the_category() eller en bevisst bygget <a href="<?php echo esc_url( get_category_link( $id ) ); ?>"> greit. Poenget er ikke «aldri lenke». Poenget er å ikke la template-taggen bestemme markup når UI-et ditt allerede har bestemt noe annet.
Hvordan cache kategorinavn i innleggskort og meta
På forsider med 24 kort er 24 kall til get_the_category() billige sammenlignet med remote HTTP, men de summerer seg under objektcache-miss og tung term-meta. Noen mønstre som holder i produksjon:
- Les inne i loopen, skriv én gang. Ikke kall funksjonen i header, i kortet og i schema for samme post uten å cache lokalt i en variabel.
- Transient per post bare når du aggregérer tungt. For eksempel en «topp kategorier denne uken»-widget. Ikke transient for enkeltnavn på single - det er overkill.
- Object cache / Redis: WordPress cacher allerede mange term-oppslag. Unngå å invalidere hele term-cachen unødig etter hver lagring i admin.
- Fragment cache for HTML-kort: hvis kortet er dyrt (bilde + ACF + term), cache hele kort-HTML med post-ID som nøkkel og tøm ved
save_post.
<?php
function wppoland_post_category_label( $post_id = 0 ) {
$post_id = $post_id ? (int) $post_id : get_the_ID();
$cats = get_the_category( $post_id );
if ( empty( $cats ) ) {
return '';
}
return esc_html( $cats[0]->name );
}
?>En liten helper hindrer at fem template-filer hver finner opp sin egen variant med eller uten escaping.
Kategorinavn uten lenke i single.php og innleggskort
Minimal utgave til single eller content.php:
<?php
$categories = get_the_category();
if ( ! empty( $categories ) ) {
echo esc_html( $categories[0]->name );
}
?>Liste uten lenker:
<?php
$categories = get_the_category();
$output = array();
if ( ! empty( $categories ) ) {
foreach ( $categories as $category ) {
$output[] = esc_html( $category->name );
}
echo implode( ', ', $output );
}
?>Trenger du samme kontroll gjennom hele temaet, er det typisk slik vi strukturerer merkelapper i skreddersydd WordPress-utvikling.
Sjekkliste for kategorinavn uten lenke i temaet
- Bytt
the_category()der du faktisk ikke vil ha anker. - Bruk
get_the_category()forcategory,get_the_terms()for resten. - Escape med
esc_html/esc_attretter kontekst. - Bygg lister med
foreach+implode, ikkestrip_tags( get_the_category_list() ). - Avklar om «første kategori» eller SEO-primary er kravet.
- Test et innlegg uten kategori (tom array) og et CPT uten
category. - I FSE: beholde PHP bare der blokken ikke kan levere etiketten din.
Oppsummering
the_category() printer lenker. get_the_category() gir deg term-objekter. Derfra bygger du tekst, badges, schema og REST-felt uten å strippe HTML i etterkant. Samme idé gjelder egne taksonomier via get_the_terms(). Primærkategori er plugin-meta, ikke magisk indeks null.
Ta med dette videre i code review:
- Ingen
strip_tagsrundt kategorilister. - Escape ved utskrift, ikke «senere».
- Tom array og
WP_Errorer testet. - Primary vs
[0]er avklart med redaksjonen. - FSE-blokker får PHP der designet krever det.
På WordCamp Norge- og WordUp-oppsett er det forskjellen mellom et kort som ser ut som designet og et kort som lekker arkivlenker inn i UI-et. Hold API-valget eksplisitt, så slipper neste utvikler å gjette hvorfor badge-en plutselig ble klikkbar igjen etter en theme-oppdatering.







