
⚙️ WordPress: hvordan sette en standardmal for en egendefinert innholdstype
Du overleverte en side på WordPress med en portefølje til kunden, og de ringer tilbake dagen etter: «Jeg legger til en ny oppføring, men malen går stadig tilbake til standardmalen med sidestolpe. Hvordan låser jeg den?» Situasjonen er smertelig velkjent: du klikker «Legg til ny» i en egendefinert innholdstype, og i stedet for fullbredde-layouten du bygde, dukker det opp en bloggkolonne med sidestolpe. Å velge mal manuelt for hvert innlegg er meningsløst ekstraarbeid som frustrerer både deg og kunden. Særlig når «Full bredde» uten sidestolpe er det du trenger nesten hver gang.
Som standard bruker WordPress single.php fra temaet for egendefinerte innholdstyper (CPT-er). Og single.php er vanligvis skreddersydd for en blogg: tittel, innhold, sidestolpe med widgeter. For porteføljer, case-studier, attester eller produkter er den layouten dårlig egnet. Den gode nyheten: WordPress tilbyr fire måter å tilordne en mal til en CPT på, fra den enkleste (en fil i temaet, ingen kode i det hele tatt) til fullstendig programmatisk via hooks og blokktemaer. Hver metode får jobben gjort pålitelig; den eneste forskjellen er graden av kontroll og hvor enkelt det er å vedlikeholde.
💡 Rask oversikt:
- Opprett en
single-{post_type}.php-fil i temaroten, så plukker WordPress den opp automatisk via malhierarkiet - Huk deg på
template_include-filteret ifunctions.phpfor å tilordne en mal programmatisk uten å plassere en fysisk fil i temaet - For blokktemaer, opprett
single-{post_type}.htmlitemplates/-mappen; den kan redigeres gjennom Nettstedsredigering uten kode - Etter enhver endring, tøm permalenkene: «Innstillinger → Permalenker → Lagre endringer», ellers vil ikke WordPress se den nye malen
Metode 1: malfil via WordPress-hierarkiet
Den mest pålitelige og enkle metoden. Siden versjon 3.0 har WordPress støttet egendefinerte maler for CPT-er gjennom det vanlige malhierarkiet. Slik fungerer det: når en besøkende åpner en oppføring av typen portfolio, ser WordPress etter en mal i en streng rekkefølge, ovenfra og ned, og bruker den første filen den finner:
single-portfolio.php → single.php → singular.php → index.php
Du må opprette en fil med navnet single-{post_type}.php, der {post_type} er slug-en til din egendefinerte type. Plasser den i roten av det aktive temaet:
1 /* File: /wp-content/themes/your-theme/single-portfolio.php */ 2 3 <?php get_header(); ?> 4 5 <div class="full-width-content"> 6 <?php while ( have_posts() ) : the_post(); ?> 7 <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> 8 <h1><?php the_title(); ?></h1> 9 <div class="entry-content"> 10 <?php the_content(); ?> 11 </div> 12 </article> 13 <?php endwhile; ?> 14 </div> 15 16 <?php get_footer(); ?> 17
Den raskeste måten å starte på: kopier innholdet i page.php eller template-fullwidth.php fra temaet ditt og tilpass layouten for den spesifikke CPT-en. Hvis det ikke finnes noen single-{post_type}.php-fil, faller WordPress stille tilbake til single.php, og kunden ender opp med en sidestolpe.
Fordelen med denne metoden: ingen kode i functions.php; filen ligger bare i temaet og virker. Ulempen: malen er tett knyttet til temaet. Hvis du bytter tema, blir filen liggende i den gamle mappen og slutter å virke.
Metode 2: programmatisk via template_include-filteret
Den filbaserte metoden fungerer så lenge du kontrollerer temaet. Men hvis du utvikler en plugin eller et child theme som ikke skal være avhengig av at en fil finnes i roten, trenger du template_include-hooken.
Filteret fyres av før malen lastes og lar deg peke til en PHP-fil fra en hvilken som helst plassering:
1 /* File: functions.php (theme) or main plugin file */ 2 3 add_filter( 'template_include', 'sd_cpt_default_template', 99 ); 4 5 function sd_cpt_default_template( $template ) { 6 if ( is_singular( 'portfolio' ) ) { 7 $custom_template = plugin_dir_path( __FILE__ ) . 'templates/single-portfolio.php'; 8 if ( file_exists( $custom_template ) ) { 9 return $custom_template; 10 } 11 } 12 return $template; 13 }
Hva som skjer her:
is_singular('portfolio')sjekker om vi er på en enkeltoppføringsside av typenportfolio- Hvis betingelsen er sann, laster WordPress malen fra plugin-mappen og omgår temahierarkiet
- Prioritet 99 sikrer at filteret fyres av sist og ikke overstyres av temaet
Denne tilnærmingen er praktisk når malen må leve inne i en plugin og overleve temabytter. Filen templates/single-portfolio.php inne i pluginen kan bruke get_header() og get_footer() fra det aktive temaet, slik at alt visuelt forblir konsistent med nettstedets design.
Metode 3: {$type}_template-filteret
WordPress tilbyr en dynamisk hook {$type}_template, der $type er single, archive eller page. For en CPT tar den formen single-portfolio_template og lar deg overstyre malen presist, uten ekstra sjekker inne i callbacken:
1 add_filter( 'single_template', 'sd_cpt_template_by_type' ); 2 3 function sd_cpt_template_by_type( $single_template ) { 4 global $post; 5 6 if ( 'portfolio' === $post->post_type ) { 7 $custom_template = get_stylesheet_directory() . '/single-portfolio.php'; 8 if ( file_exists( $custom_template ) ) { 9 return $custom_template; 10 } 11 } 12 return $single_template; 13 }
Forskjellen fra Metode 2 er semantisk: du sier eksplisitt «endre malen for enkeltoppføringer» i stedet for «avskjær alle maler». Koden er litt renere, men funksjonelt løser begge hookene problemet på samme måte.
Metode 4: mal i et blokktema (Fullstendig nettstedsredigering)
Fra og med WordPress 5.9 og overgangen til blokktemaer endres tilnærmingen. I FSE-temaer er maler HTML-filer i templates/-mappen, ikke PHP. For en egendefinert innholdstype, opprett:
1 /wp-content/themes/your-fse-theme/templates/single-portfolio.html
Innvendig bruker du en blokkbasert struktur. Et minimalt eksempel:
1 <!-- wp:template-part {"slug":"header","theme":"your-fse-theme"} /--> 2 3 <!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} --> 4 <main class="wp-block-group"> 5 <!-- wp:post-title {"level":1} /--> 6 <!-- wp:post-featured-image /--> 7 <!-- wp:post-content {"layout":{"type":"constrained"}} /--> 8 </main> 9 <!-- /wp:group --> 10 11 <!-- wp:template-part {"slug":"footer","theme":"your-fse-theme"} /-->
Du kan redigere denne malen direkte i Nettstedsredigering (Utseende → Redigering) uten å røre noe kode. Hvis du bytter blokktema, blir filen liggende i den gamle mappen, samme sårbarhet som Metode 1.
Hvilken metode du bør velge
En rask beslutningsmatrise for ditt scenario:
Scenario | Metode |
|---|---|
Ett tema, én CPT, ingen plugins | Metode 1: |
Plugin med egen mal | Metode 2: |
Child theme, trenger å overstyre foreldremalen | Metode 1 eller 3 |
FSE / blokktema (Twenty Twenty-Four og nyere) | Metode 4: |
Etter å ha implementert noen av metodene, husk å gå til «Innstillinger → Permalenker» og klikk «Lagre endringer». Dette tømmer hurtigbufferen for omskrivingsregler, og WordPress begynner å gjenkjenne den nye malen.
⁉️🤔 Ofte stilte spørsmål
Malen blir ikke plukket opp. Hva bør jeg gjøre?
Først, tøm permalenkene («Innstillinger → Permalenker → Lagre»). For det andre, bekreft at CPT-slug-en i filnavnet samsvarer med slug-en fra
register_post_type(). For det tredje, hvis en caching-plugin er aktiv, tøm hurtigbufferen. I praksis handler problemet oftest om å tømme omskrivingsregler etter registrering av CPT-en, ikke om selve mal-koden.
Kan jeg tilordne én mal til flere CPT-er samtidig?
Ja. I Metode 2, bruk en array i
is_singular():is_singular( array( 'portfolio', 'testimonials', 'team' ) ). Eller sjekkin_array( $post->post_type, array('portfolio', 'team') )inne i callbacken. Malfilen er én, og layouten vil bli delt på tvers av alle listede typer.
Malen fungerer, men layouten er ødelagt (mangler sidestolpe-/topptekststiler).
Du arvet malen fra
page.php, men temaets stiler avhenger av CSS-klasser påbody. Legg til etbody_class-filter ifunctions.phpslik at WordPress legger til enpost-type-{slug}-klasse på<body>, så vil stilene tre i kraft:
1 add_filter( 'body_class', function( $classes ) { 2 if ( is_singular( 'portfolio' ) ) { 3 $classes[] = 'single-portfolio'; 4 } 5 return $classes; 6 } );
Hva skjer når jeg bytter tema? Malen forsvinner.
Ja,
single-portfolio.php-filen blir liggende i det gamle temaets mappe. Dine alternativer: flytt filen til det nye temaet manuelt, bruk et child theme (filen overlever oppdateringer av foreldretemaet), eller flytt malen inn i en plugin via Metode 2, som ikke avhenger av det aktive temaet.
Hva om jeg trenger at ALLE CPT-er åpnes uten sidestolpe som standard?
Bruk et universelt filter med
is_singular()uten å spesifisere en bestemt post_type, men ekskluder standardpostogpage:
1 add_filter( 'template_include', function( $template ) { 2 if ( is_singular() && ! is_singular( array( 'post', 'page' ) ) ) { 3 $fullwidth = get_stylesheet_directory() . '/template-fullwidth.php'; 4 if ( file_exists( $fullwidth ) ) { 5 return $fullwidth; 6 } 7 } 8 return $template; 9 }, 99 );
Denne løsningen bruker en enkelt fullbredde-mal på alle egendefinerte innholdstyper samtidig: porteføljer, attester, teammedlemmer, case-studier. Standard innlegg og sider påvirkes ikke.
Er det verdt å bry seg med template_include når du bare kan opprette en fil?
Hvis du har ett nettsted, ett tema og én CPT, opprett single-{post_type}.php og glem det. Dette er en løsning som varer i årevis: den knekker ikke ved WordPress-oppdateringer, avhenger ikke av PHP-versjonen, og er umiddelbart forståelig for enhver utvikler som åpner temamappen. Vedlikehold koker ned til én enkelt fil du kan fikse på null komma niks.
Programmatiske metoder via hooks er berettiget i to tilfeller. For det første: malen er en del av en distribuert plugin, og du ønsker ikke å kreve at brukere kopierer filer inn i temaet. For det andre: CPT-er registreres dynamisk gjennom ACF, Toolset eller en lignende plugin, og det er upraktisk å spre et dusin single-*.php-filer i temaet. For alt annet er WordPress malhierarki den enkleste og mest pålitelige veien, bevist over mange år.



