Skip to content

Allt om WordPress, webbutveckling — och mer därtill

🔧 Hur man skapar en mall för en anpassad posttyp i WordPress

🔧 Hur man skapar en mall för en anpassad posttyp i WordPress

Du har lagt till en anpassad posttyp på din webbplats, till exempel "Erbjudanden", "Portfölj" eller "Referenser". Allt fungerar: inlägg skapas, metafält fylls i. Men när du öppnar ett av dessa inlägg på frontend ser det ut som ett vanligt blogginlägg. Samma layout, samma sidopaneler, ingen skillnad alls. Ändå skapade du en anpassad posttyp just för att innehållet skulle presenteras annorlunda.

Problemet är att WordPress som standard renderar alla anpassade inlägg via single.php, den universella mallen för alla enskilda inlägg. För att få en unik layout för en specifik typ behöver du en egen mallfil. Och det visar sig vara förvånansvärt enkelt.

Nedan följer en steg-för-steg-genomgång: från mallhierarkin till två skapandemetoder (via en temafil och via template_include-filtret), med fungerande kodexempel.

💡 Snabb översikt:

  • Förstå hur WordPress letar efter en mall för en anpassad posttyp, och prioriteten för single-{post_type}.php
  • Kopiera ditt temas single.php, döp om den för din CPT och anpassa den
  • Utforska en alternativ metod via template_include-filtret (praktiskt om du inte vill röra temat)
  • Skapa själva den anpassade posttypen med hjälp av tillägget Custom Post Type UI, snabbt och utan kod

1. Hur WordPress väljer en mall för en anpassad posttyp

WordPress mallhierarki är en kedja av filer som kärnan kontrollerar för att hitta rätt mall för att rendera en sida. För standardinlägg är kedjan lång: single-post.phpsingle.phpsingular.phpindex.php. För anpassade posttyper är den kortare, men logiken är densamma.

När en besökare öppnar ett anpassat inlägg av typen aktsii kontrollerar WordPress filer i denna ordning:

  • single-aktsii.php, mallen specifikt för denna anpassade posttyp
  • single.php, den generiska mallen för enskilda inlägg
  • singular.php, mallen för allt singulärt innehåll (inlägg, sida, CPT)
  • index.php, den slutliga fallbacken

Den första filen som hittas i kedjan är den som används för rendering. Om single-aktsii.php finns, plockar WordPress upp den och stannar. Om den inte hittas går kärnan vidare till single.php. Det är precis därför din anpassade posttyp ser ut som ett vanligt inlägg: det finns ingen single-aktsii.php-fil, så kärnan faller tillbaka på den generiska single.php.

Lösningen följer direkt av detta: skapa single-{post_type}.php, så plockar WordPress upp den automatiskt.

2. Skapa en mallfil: kopiera single.php och döp om den

Detta är den enklaste och mest pålitliga metoden. Den fungerar med alla klassiska teman och kräver inga tillägg eller filter.

Steg 1: hitta ditt temas single.php. Den ligger i temamappens rot: /wp-content/themes/your-theme/single.php. Om temat använder FSE (Full Site Editing) och är byggt på block, kanske denna fil inte finns, och filtermetoden (template_include) blir smidigare (avsnitt 4).

Steg 2: kopiera och döp om. Kopiera single.php och namnge den enligt mönstret single-{slug}.php: ersätt {slug} med sluggen för din anpassade posttyp (den som angavs vid registreringen, med latinska tecken). Till exempel, för en typ med sluggen aktsii:

1single-aktsii.php

För en typ med sluggen portfolio skulle filen heta single-portfolio.php. För testimonials blir det single-testimonials.php. Viktigt: sluggen måste matcha den som angavs i parametern 'rewrite' => array('slug' => '...') vid registreringen.

Steg 3: placera filen tillbaka i temamappen. WordPress kommer automatiskt att plocka upp den för alla inlägg av denna typ. Ingen ytterligare konfiguration behövs; mallhierarkin hanterar det automatiskt.

Steg 4: verifiera. Öppna ett inlägg av den anpassade typen på frontend. Om du ser samma sida som tidigare, kontrollera filnamnet (skiftlägeskänslighet, bindestreck istället för understreck) och rensa cachen. Om filen skapades i ett barntema och föräldratemat också innehåller single-{post_type}.php, har barntemat prioritet.

3. Anpassa mallinnehållet

Den kopierade single.php är fortfarande identisk med originalet; den renderar helt enkelt samma generiska layout. Nu fyller vi den med innehåll specifikt för den anpassade posttypen.

3.1. Grundstruktur: skriva ut anpassade fält

Anta att den anpassade posttypen aktsii har fälten aktsiya_data_start, aktsiya_data_end och aktsiya_skidka (skapade via ACF, Meta Box eller manuellt). Här är en minimal mall som skriver ut dem:

1<?php
2/**
3 * Template for custom type "Promotions" (single-aktsii.php)
4 */
5
6get_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
60get_sidebar();
61get_footer();

Detta är en fullt fungerande mall som du kan släppa in i ditt tema som den är. Den skriver ut titeln, den utvalda bilden, innehållet och tre anpassade fält i ett separat block.

3.2. Vad mer du kan göra med mallen

Härifrån är möjligheterna till anpassning praktiskt taget obegränsade:

  • Ta bort sidopanelen: ta helt enkelt bort anropet get_sidebar().
  • Ändra HTML-omslaget: ersätt <article> med en <div> som bär den klass du behöver, lägg till ditt eget grid.
  • Anropa en specifik malldel: till exempel get_template_part( 'template-parts/content', 'aktsii' ) och håll logiken i en separat fil.
  • Köa anpassade stilar: via wp_enqueue_style() inuti functions.php med en is_singular( 'aktsii' )-kontroll.

En viktig notering: om temat uppdateras kan en fil i föräldratemat skrivas över. Så arbeta antingen i ett barntema, eller använd filtermetoden från nästa avsnitt.

4. Alternativ metod: filtret template_include

Om du föredrar att inte modifiera temafiler (eller om temat är blockbaserat och saknar en klassisk single.php), kan du tilldela en mall via hooken template_include. Den körs innan WordPress inkluderar mallfilen och låter dig åsidosätta sökvägen.

Nackdel: du måste lagra mallfilen antingen i ett tillägg eller i ett barntema, och koden måste peka på rätt sökväg. Fördel: logiken går inte förlorad när föräldratemat uppdateras.

4.1. Exempel: en CPT, en mall

Lägg till detta i barntemats functions.php (eller i ett MU-plugin):

1add_filter( 'template_include', 'techblog_cpt_template', 99 );
2
3function 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 kontrollerar om den aktuella sidan tillhör den anpassade posttypen aktsii. Om så är fallet letar den efter filen single-aktsii.php i barntemats mapp (get_stylesheet_directory()) och returnerar den. Om filen inte hittas returneras den förvalda $template oförändrad.

4.2. Exempel: flera CPT:er med en enda hanterare

Om du har flera anpassade posttyper är det praktiskt att konsolidera logiken i ett filter:

1add_filter( 'template_include', 'techblog_cpt_templates', 99 );
2
3function 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}

Nu får varje CPT sin egen mall, och all logik finns i en enda funktion.

4.3. Lagra mallar i ett tillägg

Om du distribuerar den anpassade posttypen som ett tillägg (snarare än som en del av ett tema), är det vettigt att lagra mallen i tilläggets mapp. I så fall anger du sökvägen via plugin_dir_path( __FILE__ ):

1add_filter( 'template_include', 'myplugin_cpt_template', 99 );
2
3function 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}

Detta mönster används av många populära tillägg (WooCommerce, Easy Digital Downloads, The Events Calendar): de levererar mallar internt och inkluderar dem via filtret.

5. Skapa den anpassade posttypen

Vi har mallen redo, men för fullständighetens skull, några ord om var själva den anpassade posttypen kommer ifrån.

5.1. Registrering via kod

En minimal CPT-registrering i functions.php eller ett MU-plugin:

1add_action( 'init', 'techblog_register_cpt_aktsii' );
2
3function 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}

Nyckeldetaljen här är att parametern 'rewrite' => array( 'slug' => 'aktsii' ) sätter sluggen som används både i URL:en och i mallfilens namn. Om sluggen är aktsii måste mallfilen heta single-aktsii.php.

5.2. Använda tillägget Custom Post Type UI

Om du hellre inte vill redigera functions.php kan du skapa en CPT visuellt med det kostnadsfria tillägget Custom Post Type UI på WordPress.org. Efter installation:

  • Gå i adminpanelen till CPT UI → Add/Edit Post Types
  • Fyll i fälten: Post Type Slug (latinska tecken), Plural Label, Singular Label
  • På fliken Settings väljer du vilka redigeringsfunktioner du behöver (titel, editor, utvald bild)
  • Klicka på Add Post Type

Tillägget genererar PHP-registreringskoden, som du kan exportera och klistra in i functions.php. Detta är praktiskt om du senare vill ta bort beroendet av tillägget. Sluggen du angav i CPT UI är densamma som går in i mallfilens namn.

⁉️🤔 Vanliga frågor

Vad ska jag göra om mallen inte plockas upp efter att filen skapats?

Spola permalänkarna: gå till Inställningar → Permalänkar och klicka på "Spara ändringar" (du behöver inte ändra något). WordPress bygger om sina routingregler. Om det inte hjälper, kontrollera filnamnet: den anpassade posttypens slug och filnamnet måste matcha (skiftläge, bindestreck och understreck). Som ett tredje steg, rensa cachen i ditt cachingtillägg, om ett sådant är installerat. Permalänkar bör spolas efter registrering av varje ny anpassad posttyp, inte bara när du stöter på mallproblem. Detta är standardpraxis: gå till Inställningar → Permalänkar → Spara, så börjar de nya URL:erna fungera omedelbart.

Kan jag använda en mall för flera anpassade posttyper?

Ja, på två sätt. För det första, skapa en fysisk fil single-aktsii.php, och för den andra typen (säg portfolio) kopiera den som single-portfolio.php. För det andra, använd template_include-filtret (avsnitt 4): i arrayen $cpt_templates, peka olika typer till samma mallfil. I praktiken har dock olika CPT:er nästan alltid olika layouter; att kopiera och redigera är enklare än att bygga villkorlig logik inuti en enda mall. Om du verkligen har många typer med identisk logik, skapa en delad single-cpt.php, kontrollera get_post_type() inuti den och inkludera motsvarande malldel via get_template_part( 'template-parts/content', get_post_type() ). Detta är en ren och skalbar metod.

Behöver jag skapa archive-{post_type}.php** för arkivsidan?**

Det rekommenderas men krävs inte. Utan den använder WordPress archive.php eller index.php. Om CPT:n har 'has_archive' => true och arkivet öppnas på /aktsii/ men det inte finns någon archive-aktsii.php-fil, kommer den generiska archive.php att användas. Att skapa en separat arkivmall är vettigt när inläggsgriden, kolumnlayouten eller sidopanelen ska skilja sig från bloggarkivet.

Fungerar detta med blockteman (FSE)?

I blockteman är klassiska PHP-mallfiler inte den primära metoden. Men template_include-filtret (avsnitt 4) fungerar även i FSE: du kan placera single-aktsii.php i ett barntema eller tillägg och inkludera den via filtret. Alternativt kan du i Webbplatsredigeraren skapa en mall för en specifik anpassad posttyp via gränssnittet: Utseende → Redigerare → Mallar → Lägg till ny mall → Enskilt objekt: Aktsii. WordPress sparar den som en HTML-mall i databasen, och den fungerar utan några filer i temat.

Vad ska man välja 2026: fil eller filter?

En snabb beslutsmatris för att välja metod:

Scenario

Vad du ska använda

Klassiskt tema, en eller två CPT:er

single-{post_type}.php-fil, minimal kod, automatisk upphämtning

Barntema, du lägger till CPT:n

Fil i barntemat, överlever uppdateringar av föräldratemat

Blocktema (FSE), CPT via ett tillägg

template_include-filter, oberoende av temastruktur

CPT distribuerad som ett tillägg

Filter + mall inuti tilläggets mapp

Många CPT:er med liknande struktur

Filter + delad single-cpt.php + malldelar

I praktiken använder vi på techblog.sdstudio.top oftast en kombination: registrera CPT:n via kod i ett MU-plugin och placera mallarna som filer i ett barntema. Detta ger automatisk upphämtning utan extra filter, och uppdateringar av föräldratemat förstör ingenting.

Om du precis har börjat lära dig om anpassade posttyper, börja med filen single-{post_type}.php. Det tar fem minuter och ger omedelbara resultat. När du känner att den filbaserade metoden inte längre räcker till (du behöver ladda mallar från ett tillägg eller byta dem i farten), byt till template_include. Båda metoderna är fullt legitima och stöds av WordPress kärna.