
🔧 Come creare un template per un custom post type in WordPress
Hai aggiunto un custom post type al tuo sito, ad esempio «Promozioni», «Portfolio» o «Testimonianze». Tutto funziona: i post vengono creati, i meta field sono compilati. Ma quando apri uno di questi post nel front end, ha l’aspetto di un normale articolo del blog. Stesso layout, stesse sidebar, nessuna differenza. Eppure hai creato un custom post type proprio perché il contenuto venisse presentato in modo diverso.
Il problema è che WordPress renderizza qualsiasi custom post attraverso single.php in modo predefinito, il template universale per tutti i post singoli. Per ottenere un layout unico per un tipo specifico, ti serve un tuo file template. E la soluzione è sorprendentemente semplice.
Di seguito trovi una guida passo passo: dalla gerarchia dei template a due metodi di creazione (tramite file del tema e tramite il filtro template_include), con esempi di codice funzionanti.
💡 Panoramica rapida:
- Capire come WordPress cerca un template per un custom post type e la priorità di
single-{post_type}.php - Copiare il
single.phpdel tuo tema, rinominarlo per il tuo CPT e personalizzarlo - Esplorare un metodo alternativo tramite il filtro
template_include(utile se non vuoi toccare il tema) - Creare il custom post type stesso usando il plugin Custom Post Type UI, in modo rapido e senza codice
1. Come WordPress sceglie un template per un custom post type
La gerarchia dei template di WordPress è una catena di file che il core controlla per trovare il template giusto per renderizzare una pagina. Per i post standard la catena è lunga: single-post.php → single.php → singular.php → index.php. Per i custom post type è più corta, ma la logica è la stessa.
Quando un visitatore apre un custom post di tipo aktsii, WordPress controlla i file in questo ordine:
single-aktsii.php, il template specifico per questo custom post typesingle.php, il template generico per post singolisingular.php, il template per qualsiasi contenuto singolare (post, pagina, CPT)index.php, il fallback finale
Il primo file trovato nella catena è quello usato per la renderizzazione. Se single-aktsii.php esiste, WordPress lo prende e si ferma. Se non viene trovato, il core passa a single.php. È esattamente per questo che il tuo custom post type ha l’aspetto di un post normale: non esiste un file single-aktsii.php, quindi il core ripiega sul generico single.php.
La soluzione deriva direttamente da questo: crea single-{post_type}.php e WordPress lo rileverà automaticamente.
2. Creare un file template: copia single.php e rinominalo
Questo è l’approccio più semplice e affidabile. Funziona con qualsiasi tema classico e non richiede plugin o filtri.
Passo 1: trova il single.php del tuo tema. Si trova nella root della cartella del tema: /wp-content/themes/your-theme/single.php. Se il tema usa FSE (Full Site Editing) ed è basato su blocchi, questo file potrebbe non esistere e il metodo del filtro (template_include) sarà più comodo (sezione 4).
Passo 2: copia e rinomina. Copia single.php e nominalo seguendo lo schema single-{slug}.php: sostituisci {slug} con lo slug del tuo custom post type (quello specificato durante la registrazione, in caratteri latini). Ad esempio, per un tipo con lo slug aktsii:
1 single-aktsii.php
Per un tipo con lo slug portfolio il file si chiamerà single-portfolio.php. Per testimonials diventerà single-testimonials.php. Importante: lo slug deve corrispondere a quello specificato nel parametro 'rewrite' => array('slug' => '...') durante la registrazione.
Passo 3: rimetti il file nella cartella del tema. WordPress lo rileverà automaticamente per tutti i post di questo tipo. Non serve alcuna configurazione aggiuntiva; la gerarchia dei template lo gestisce in automatico.
Passo 4: verifica. Apri un qualsiasi post del custom post type nel front end. Se vedi la stessa pagina di prima, controlla il nome del file (distingue tra maiuscole e minuscole, trattini invece di underscore) e svuota la cache. Se il file è stato creato in un tema child e anche il tema parent contiene single-{post_type}.php, il tema child ha la priorità.
3. Personalizzare il contenuto del template
Il single.php copiato è ancora identico all’originale; si limita a renderizzare lo stesso layout generico. Ora lo riempiamo con contenuti specifici per il custom post type.
3.1. Struttura di base: output dei campi personalizzati
Supponiamo che il custom post type aktsii abbia i campi aktsiya_data_start, aktsiya_data_end e aktsiya_skidka (creati tramite ACF, Meta Box o manualmente). Ecco un template minimo che li mostra in output:
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();
Questo è un template completamente funzionante che puoi inserire nel tuo tema così com’è. Mostra il titolo, l’immagine in evidenza, il contenuto e tre campi personalizzati in un blocco separato.
3.2. Cos’altro puoi fare con il template
Da qui, le possibilità di personalizzazione sono virtualmente illimitate:
- Rimuovere la sidebar: basta rimuovere la chiamata a
get_sidebar(). - Cambiare il wrapper HTML: sostituisci
<article>con un<div>che porta la classe che ti serve, aggiungi la tua griglia. - Chiamare una template part specifica: ad esempio,
get_template_part( 'template-parts/content', 'aktsii' )e tieni la logica in un file separato. - Caricare stili personalizzati: tramite
wp_enqueue_style()dentrofunctions.phpcon un controllois_singular( 'aktsii' ).
Una nota importante: se il tema viene aggiornato, un file nel tema parent può essere sovrascritto. Quindi o lavori in un tema child, oppure usi il metodo del filtro della prossima sezione.
4. Approccio alternativo: il filtro template_include
Se preferisci non modificare i file del tema (o il tema è basato su blocchi e manca di un classico single.php), puoi assegnare un template tramite l’hook template_include. Viene eseguito prima che WordPress includa il file template e ti permette di sovrascrivere il percorso.
Svantaggio: dovrai conservare il file template o in un plugin o in un tema child, e il codice deve puntare al percorso corretto. Vantaggio: la logica non va persa quando il tema parent viene aggiornato.
4.1. Esempio: un CPT, un template
Aggiungi questo al functions.php del tema child (o a un 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 }
Il codice controlla se la pagina corrente appartiene al custom post type aktsii. In caso affermativo, cerca il file single-aktsii.php nella cartella del tema child (get_stylesheet_directory()) e lo restituisce. Se il file non viene trovato, restituisce il $template predefinito invariato.
4.2. Esempio: CPT multipli con un unico gestore
Se hai diversi custom post type, è comodo consolidare la logica in un unico filtro:
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 }
Ora ogni CPT ottiene il proprio template e tutta la logica risiede in una singola funzione.
4.3. Conservare i template in un plugin
Se distribuisci il custom post type come plugin (anziché come parte di un tema), ha senso conservare il template nella cartella del plugin. In tal caso, specifica il percorso tramite 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 }
Questo schema è usato da molti plugin popolari (WooCommerce, Easy Digital Downloads, The Events Calendar): distribuiscono i template al loro interno e li includono tramite il filtro.
5. Creare il custom post type
Abbiamo il template pronto, ma per completezza, qualche parola su da dove proviene il custom post type stesso.
5.1. Registrazione tramite codice
Una registrazione CPT minima in functions.php o in un 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 }
Il dettaglio chiave qui è che il parametro 'rewrite' => array( 'slug' => 'aktsii' ) imposta lo slug usato sia nell’URL sia nel nome del file template. Se lo slug è aktsii, il file template deve chiamarsi single-aktsii.php.
5.2. Usare il plugin Custom Post Type UI
Se preferisci non modificare functions.php, puoi creare un CPT in modo visuale usando il plugin gratuito Custom Post Type UI su WordPress.org. Dopo l’installazione:
- Nel pannello di amministrazione, vai su CPT UI → Add/Edit Post Types
- Compila i campi: Post Type Slug (caratteri latini), Plural Label, Singular Label
- Nella scheda Settings, seleziona quali funzionalità dell’editor ti servono (titolo, editor, thumbnail)
- Clicca Add Post Type
Il plugin genera il codice PHP di registrazione, che puoi esportare e incollare in functions.php. Questo è comodo se in seguito vuoi rimuovere la dipendenza dal plugin. Lo slug che hai specificato in CPT UI è lo stesso che va nel nome del file template.
⁉️🤔 Domande frequenti
Cosa devo fare se il template non viene rilevato dopo aver creato il file?
Rigenera i permalink: vai su Impostazioni → Permalink e clicca «Salva modifiche» (non devi cambiare nulla). WordPress ricostruirà le sue regole di routing. Se non aiuta, controlla il nome del file: lo slug del custom post type e il nome del file devono corrispondere (maiuscole/minuscole, trattini e underscore). Come terzo passo, svuota la cache del tuo plugin di caching, se ne hai uno installato. I permalink andrebbero rigenerati dopo aver registrato qualsiasi nuovo custom post type, non solo quando hai problemi di template. È una prassi standard: vai su Impostazioni → Permalink → Salva, e i nuovi URL iniziano a funzionare immediatamente.
Posso usare un template per più custom post type?
Sì, in due modi. Primo, crea un file fisico
single-aktsii.phpe per il secondo tipo (ad esempio,portfolio) copialo comesingle-portfolio.php. Secondo, usa il filtrotemplate_include(sezione 4): nell’array$cpt_templates, punta tipi diversi allo stesso file template. In pratica, però, CPT diversi hanno quasi sempre layout diversi; copiare e modificare è più semplice che costruire logica condizionale dentro un unico template. Se hai davvero molti tipi con logica identica, crea unsingle-cpt.phpcondiviso, controllaget_post_type()al suo interno e includi la template part corrispondente tramiteget_template_part( 'template-parts/content', get_post_type() ). Questo è un approccio pulito e scalabile.
Devo creare archive-{post_type}.php** per la pagina archivio?**
È consigliato ma non obbligatorio. Senza, WordPress usa
archive.phpoindex.php. Se il CPT ha'has_archive' => truee l’archivio si apre su/aktsii/ma non esiste un filearchive-aktsii.php, verrà usato il genericoarchive.php. Creare un template archivio separato ha senso quando la griglia dei post, il layout a colonne o la sidebar devono differire dall’archivio del blog.
Funziona con i temi a blocchi (FSE)?
Nei temi a blocchi, i file template PHP classici non sono l’approccio principale. Tuttavia, il filtro
template_include(sezione 4) funziona anche in FSE: puoi posizionaresingle-aktsii.phpin un tema child o in un plugin e includerlo tramite il filtro. In alternativa, nell’Editor del sito puoi creare un template per uno specifico custom post type tramite l’interfaccia: Aspetto → Editor → Template → Aggiungi nuovo template → Elemento singolo: Aktsii. WordPress lo salverà come template HTML nel database e funzionerà senza alcun file nel tema.
Cosa scegliere nel 2026: file o filtro?
Una rapida matrice decisionale per scegliere l’approccio:
Scenario | Cosa usare |
|---|---|
Tema classico, uno o due CPT | File |
Tema child, stai aggiungendo il CPT | File nel tema child, sopravvive agli aggiornamenti del tema parent |
Tema a blocchi (FSE), CPT tramite plugin | Filtro |
CPT distribuito come plugin | Filtro + template dentro la cartella del plugin |
Molti CPT con struttura simile | Filtro + |
In pratica, su techblog.sdstudio.top usiamo più spesso una combinazione: registriamo il CPT tramite codice in un MU-plugin e posizioniamo i template come file in un tema child. Questo dà un rilevamento automatico senza filtri extra e gli aggiornamenti del tema parent non rompono nulla.
Se stai appena iniziando a studiare i custom post type, comincia con il file single-{post_type}.php. Richiede cinque minuti e dà risultati immediati. Quando senti che l’approccio basato su file non è più sufficiente (devi caricare template da un plugin o scambiarli al volo), passa a template_include. Entrambi i metodi sono pienamente legittimi e supportati dal core di WordPress.



