
🔧 Hvordan lage en mal for en egendefinert innholdstype i WordPress
Du la til en egendefinert innholdstype på nettstedet ditt, for eksempel «Kampanjer», «Portefølje» eller «Attester». Alt fungerer: innlegg opprettes, metabokser fylles ut. Men når du åpner et av disse innleggene på forsiden, ser det ut som et vanlig blogginnlegg. Samme layout, samme sidekolonner, ingen forskjell i det hele tatt. Likevel opprettet du en egendefinert innholdstype nettopp for at innholdet skulle presenteres annerledes.
Problemet er at WordPress som standard viser ethvert egendefinert innlegg via single.php, den universelle malen for alle enkeltinnlegg. For å få en unik layout for en bestemt type, trenger du din egen malfil. Og det viser seg å være overraskende enkelt.
Nedenfor følger en trinnvis gjennomgang: fra malhierarkiet til to opprettelsesmetoder (via en temafil og via template_include-filteret), med fungerende kodeeksempler.
💡 Rask oversikt:
- Forstå hvordan WordPress leter etter en mal for en egendefinert innholdstype, og prioriteten til
single-{post_type}.php - Kopiere temaets
single.php, gi det nytt navn for din CPT og tilpasse det - Utforske en alternativ metode via
template_include-filteret (nyttig hvis du ikke vil røre temaet) - Opprette selve den egendefinerte innholdstypen ved hjelp av Custom Post Type UI-pluginen, raskt og uten kode
1. Hvordan WordPress velger en mal for en egendefinert innholdstype
WordPress-malhierarkiet er en kjede av filer som kjernen sjekker for å finne riktig mal for å vise en side. For standardinnlegg er kjeden lang: single-post.php → single.php → singular.php → index.php. For egendefinerte innholdstyper er den kortere, men logikken er den samme.
Når en besøkende åpner et egendefinert innlegg av typen aktsii, sjekker WordPress filer i denne rekkefølgen:
single-aktsii.php, malen spesifikt for denne egendefinerte innholdstypensingle.php, den generiske malen for enkeltinnleggsingular.php, malen for ethvert entallsinnhold (innlegg, side, CPT)index.php, den endelige reserveløsningen
Den første filen som blir funnet i kjeden, er den som brukes til visning. Hvis single-aktsii.php eksisterer, plukker WordPress den opp og stopper. Hvis den ikke blir funnet, går kjernen videre til single.php. Det er akkurat derfor din egendefinerte innholdstype ser ut som et vanlig innlegg: det finnes ingen single-aktsii.php-fil, så kjernen faller tilbake på den generiske single.php.
Løsningen følger direkte av dette: opprett single-{post_type}.php, så plukker WordPress den opp automatisk.
2. Opprette en malfil: kopier single.php og gi den nytt navn
Dette er den enkleste og mest pålitelige tilnærmingen. Den fungerer med ethvert klassisk tema og krever ingen pluginer eller filtre.
Trinn 1: finn temaets single.php. Den ligger i roten av temamappen: /wp-content/themes/your-theme/single.php. Hvis temaet bruker FSE (Full Site Editing) og er bygget på blokker, kan det hende denne filen ikke eksisterer, og filtermetoden (template_include) vil være mer praktisk (seksjon 4).
Trinn 2: kopier og gi nytt navn. Kopier single.php og gi den navn etter mønsteret single-{slug}.php: erstatt {slug} med slugen for din egendefinerte innholdstype (den som ble spesifisert under registrering, med latinske tegn). For eksempel, for en type med slugen aktsii:
1 single-aktsii.php
For en type med slugen portfolio vil filen hete single-portfolio.php. For testimonials blir den single-testimonials.php. Viktig: slugen må samsvare med den som er spesifisert i parameteren 'rewrite' => array('slug' => '...') under registrering.
Trinn 3: plasser filen tilbake i temamappen. WordPress vil automatisk plukke den opp for alle innlegg av denne typen. Ingen ytterligere konfigurasjon er nødvendig; malhierarkiet håndterer det automatisk.
Trinn 4: verifiser. Åpne et hvilket som helst innlegg av den egendefinerte typen på forsiden. Hvis du ser den samme siden som før, sjekk filnavnet (store/små bokstaver, bindestreker i stedet for understreker) og tøm hurtigbufferen. Hvis filen ble opprettet i et barnetema og foreldretemaet også inneholder single-{post_type}.php, har barnetemaet prioritet.
3. Tilpasse malinnholdet
Den kopierte single.php er fortsatt identisk med originalen; den viser ganske enkelt den samme generiske layouten. Nå fyller vi den med innhold spesifikt for den egendefinerte innholdstypen.
3.1. Grunnstruktur: utmating av egendefinerte felt
Anta at den egendefinerte innholdstypen aktsii har feltene aktsiya_data_start, aktsiya_data_end og aktsiya_skidka (opprettet via ACF, Meta Box eller manuelt). Her er en minimal mal som viser dem:
1 <?php 2 /** 3 * Template for custom type "Promotions" (single-aktsii.php) 4 */ 5 6 get_header(); 7 ?> 8 9 <main id="main" class="site-main" role="main"> 10 11 <?php while ( have_posts() ) : the_post(); ?> 12 13 <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> 14 15 <header class="entry-header"> 16 <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?> 17 </header> 18 19 <?php if ( has_post_thumbnail() ) : ?> 20 <div class="post-thumbnail"> 21 <?php the_post_thumbnail( 'large' ); ?> 22 </div> 23 <?php endif; ?> 24 25 <div class="entry-content"> 26 <?php the_content(); ?> 27 28 <div class="custom-fields"> 29 <?php 30 $data_start = get_post_meta( get_the_ID(), 'aktsiya_data_start', true ); 31 $data_end = get_post_meta( get_the_ID(), 'aktsiya_data_end', true ); 32 $skidka = get_post_meta( get_the_ID(), 'aktsiya_skidka', true ); 33 34 if ( $data_start ) { 35 echo '<p><strong>Start Date:</strong> ' . esc_html( $data_start ) . '</p>'; 36 } 37 if ( $data_end ) { 38 echo '<p><strong>End Date:</strong> ' . esc_html( $data_end ) . '</p>'; 39 } 40 if ( $skidka ) { 41 echo '<p><strong>Discount:</strong> ' . esc_html( $skidka ) . '%</p>'; 42 } 43 ?> 44 </div> 45 </div> 46 47 </article> 48 49 <?php 50 if ( comments_open() || get_comments_number() ) : 51 comments_template(); 52 endif; 53 ?> 54 55 <?php endwhile; ?> 56 57 </main> 58 59 <?php 60 get_sidebar(); 61 get_footer();
Dette er en fullt funksjonell mal som du kan slippe inn i temaet ditt som den er. Den viser tittelen, utvalgt bilde, innholdet og tre egendefinerte felt i en egen blokk.
3.2. Hva annet du kan gjøre med malen
Herfra er mulighetene for tilpasning praktisk talt ubegrensede:
- Fjern sidekolonnen: fjern ganske enkelt kallet til
get_sidebar(). - Endre HTML-omslaget: erstatt
<article>med en<div>som bærer klassen du trenger, legg til ditt eget rutenett. - Kall en spesifikk maldel: for eksempel
get_template_part( 'template-parts/content', 'aktsii' )og behold logikken i en separat fil. - Kø egendefinerte stiler: via
wp_enqueue_style()inne ifunctions.phpmed enis_singular( 'aktsii' )-sjekk.
En viktig merknad: hvis temaet oppdateres, kan en fil i foreldretemaet bli overskrevet. Så enten jobb i et barnetema, eller bruk filtermetoden fra neste seksjon.
4. Alternativ tilnærming: template_include-filteret
Hvis du foretrekker å ikke endre temafiler (eller temaet er blokkbasert og mangler en klassisk single.php), kan du tilordne en mal via template_include-kroken. Den utløses før WordPress inkluderer malfilen og lar deg overstyre banen.
Ulempe: du må lagre malfilen enten i en plugin eller i et barnetema, og koden må peke til riktig bane. Fordel: logikken går ikke tapt når foreldretemaet oppdateres.
4.1. Eksempel: én CPT, én mal
Legg dette til i barnetemaets functions.php (eller i en MU-plugin):
1 add_filter( 'template_include', 'techblog_cpt_template', 99 ); 2 3 function techblog_cpt_template( $template ) { 4 if ( is_singular( 'aktsii' ) ) { 5 $custom_template = get_stylesheet_directory() . '/single-aktsii.php'; 6 if ( file_exists( $custom_template ) ) { 7 return $custom_template; 8 } 9 } 10 return $template; 11 }
Koden sjekker om den gjeldende siden tilhører den egendefinerte innholdstypen aktsii. I så fall ser den etter filen single-aktsii.php i barnetemamappen (get_stylesheet_directory()) og returnerer den. Hvis filen ikke blir funnet, returnerer den den opprinnelige $template uendret.
4.2. Eksempel: flere CPT-er med én enkelt håndterer
Hvis du har flere egendefinerte innholdstyper, er det praktisk å samle logikken i ett filter:
1 add_filter( 'template_include', 'techblog_cpt_templates', 99 ); 2 3 function techblog_cpt_templates( $template ) { 4 $cpt_templates = array( 5 'aktsii' => 'single-aktsii.php', 6 'portfolio' => 'single-portfolio.php', 7 'testimonials' => 'single-testimonials.php', 8 ); 9 10 foreach ( $cpt_templates as $cpt => $template_file ) { 11 if ( is_singular( $cpt ) ) { 12 $custom_template = get_stylesheet_directory() . '/' . $template_file; 13 if ( file_exists( $custom_template ) ) { 14 return $custom_template; 15 } 16 } 17 } 18 19 return $template; 20 }
Nå får hver CPT sin egen mal, og all logikken ligger i én enkelt funksjon.
4.3. Lagre maler i en plugin
Hvis du distribuerer den egendefinerte innholdstypen som en plugin (i stedet for som en del av et tema), gir det mening å lagre malen i plugin-mappen. I så fall spesifiserer du banen via plugin_dir_path( __FILE__ ):
1 add_filter( 'template_include', 'myplugin_cpt_template', 99 ); 2 3 function myplugin_cpt_template( $template ) { 4 if ( is_singular( 'aktsii' ) ) { 5 $custom_template = plugin_dir_path( __FILE__ ) . 'templates/single-aktsii.php'; 6 if ( file_exists( $custom_template ) ) { 7 return $custom_template; 8 } 9 } 10 return $template; 11 }
Dette mønsteret brukes av mange populære pluginer (WooCommerce, Easy Digital Downloads, The Events Calendar): de leverer maler internt og inkluderer dem via filteret.
5. Opprette den egendefinerte innholdstypen
Vi har malen klar, men for fullstendighetens skyld, noen ord om hvor selve den egendefinerte innholdstypen kommer fra.
5.1. Registrering via kode
En minimal CPT-registrering i functions.php eller en MU-plugin:
1 add_action( 'init', 'techblog_register_cpt_aktsii' ); 2 3 function techblog_register_cpt_aktsii() { 4 $labels = array( 5 'name' => 'Promotions', 6 'singular_name' => 'Promotion', 7 'menu_name' => 'Promotions', 8 ); 9 10 $args = array( 11 'labels' => $labels, 12 'public' => true, 13 'has_archive' => true, 14 'supports' => array( 'title', 'editor', 'thumbnail' ), 15 'rewrite' => array( 'slug' => 'aktsii' ), 16 'show_in_rest' => true, 17 ); 18 19 register_post_type( 'aktsii', $args ); 20 }
Nøkkeldetaljen her er at parameteren 'rewrite' => array( 'slug' => 'aktsii' ) setter slugen som brukes både i URL-en og i malfilnavnet. Hvis slugen er aktsii, må malfilen hete single-aktsii.php.
5.2. Bruke Custom Post Type UI-pluginen
Hvis du heller ikke vil redigere functions.php, kan du opprette en CPT visuelt ved hjelp av den gratis Custom Post Type UI-pluginen på WordPress.org. Etter installasjon:
- I adminpanelet, gå til CPT UI → Add/Edit Post Types
- Fyll ut feltene: Post Type Slug (latinske tegn), Plural Label, Singular Label
- På Innstillinger-fanen, velg hvilke redigeringsfunksjoner du trenger (tittel, editor, miniatyrbilde)
- Klikk Add Post Type
Pluginen genererer PHP-registreringskoden, som du kan eksportere og lime inn i functions.php. Dette er praktisk hvis du senere vil fjerne plugin-avhengigheten. Slugen du spesifiserte i CPT UI, er den samme som går inn i malfilnavnet.
⁉️🤔 Ofte stilte spørsmål
Hva bør jeg gjøre hvis malen ikke blir plukket opp etter at filen er opprettet?
Tøm permalenkene: gå til Innstillinger → Permalenker og klikk «Lagre endringer» (du trenger ikke endre noe). WordPress vil bygge om sine rutingregler. Hvis det ikke hjelper, sjekk filnavnet: slugen for den egendefinerte innholdstypen og filnavnet må samsvare (store/små bokstaver, bindestreker og understreker). Som et tredje trinn, tøm hurtigbufferen til din caching-plugin, hvis en er installert. Permalenker bør tømmes etter registrering av enhver ny egendefinert innholdstype, ikke bare når du støter på malproblemer. Dette er standard praksis: gå til Innstillinger → Permalenker → Lagre, så begynner de nye URL-ene å fungere umiddelbart.
Kan jeg bruke én mal for flere egendefinerte innholdstyper?
Ja, på to måter. For det første, opprett en fysisk fil
single-aktsii.php, og for den andre typen (for eksempelportfolio) kopier den somsingle-portfolio.php. For det andre, bruktemplate_include-filteret (seksjon 4): i$cpt_templates-arrayet, pek forskjellige typer til den samme malfilen. I praksis har imidlertid forskjellige CPT-er nesten alltid forskjellige layouter; å kopiere og redigere er enklere enn å bygge betinget logikk inne i en enkelt mal. Hvis du virkelig har mange typer med identisk logikk, opprett en deltsingle-cpt.php, sjekkget_post_type()inne i den, og inkluder den tilsvarende maldelen viaget_template_part( 'template-parts/content', get_post_type() ). Dette er en ren og skalerbar tilnærming.
Trenger jeg å opprette archive-{post_type}.php** for arkivsiden?**
Det anbefales, men er ikke påkrevd. Uten den bruker WordPress
archive.phpellerindex.php. Hvis CPT-en har'has_archive' => trueog arkivet åpnes på/aktsii/, men det ikke finnes noenarchive-aktsii.php-fil, vil den generiskearchive.phpbli brukt. Å opprette en egen arkivmal gir mening når innleggsrutenettet, kolonneoppsettet eller sidekolonnen bør avvike fra bloggarkivet.
Fungerer dette med blokktemaer (FSE)?
I blokktemaer er klassiske PHP-malfiler ikke den primære tilnærmingen. Imidlertid fungerer
template_include-filteret (seksjon 4) også i FSE: du kan plasseresingle-aktsii.phpi et barnetema eller en plugin og inkludere den via filteret. Alternativt kan du i Nettstedsredigering opprette en mal for en spesifikk egendefinert innholdstype gjennom grensesnittet: Utseende → Redigering → Maler → Legg til ny mal → Enkeltelement: Aktsii. WordPress vil lagre den som en HTML-mal i databasen, og den vil fungere uten noen filer i temaet.
Hva du bør velge i 2026: fil eller filter?
En rask beslutningsmatrise for valg av tilnærming:
Scenario | Hva du bør bruke |
|---|---|
Klassisk tema, én eller to CPT-er |
|
Barnetema, du legger til CPT-en | Fil i barnetemaet, overlever oppdateringer av foreldretemaet |
Blokktema (FSE), CPT via en plugin |
|
CPT distribuert som en plugin | Filter + mal inne i plugin-mappen |
Mange CPT-er med lignende struktur | Filter + delt |
I praksis, på techblog.sdstudio.top, bruker vi oftest en kombinasjon: registrer CPT-en via kode i en MU-plugin og plasser malene som filer i et barnetema. Dette gir automatisk opphenting uten ekstra filtre, og oppdateringer av foreldretemaet ødelegger ingenting.
Hvis du akkurat har begynt å lære om egendefinerte innholdstyper, begynn med single-{post_type}.php-filen. Det tar fem minutter og gir umiddelbare resultater. Når du føler at den filbaserte tilnærmingen ikke lenger er nok (du trenger å laste maler fra en plugin eller bytte dem i farten), bytt til template_include. Begge metodene er fullt legitime og støttet av WordPress-kjernen.



