
Creare un tema WordPress da zero significa scrivere ogni riga di quello che il browser riceve. Nessuna opzione da disattivare, nessuna funzione ereditata che non userai mai, nessun page builder che ti impone il suo markup. In cambio devi scrivere PHP e devi capire come WordPress decide quale file usare per quale pagina.
Questa guida è divisa in quattro parti e ti porta da una cartella vuota a un tema completo, modulare e pronto per essere distribuito. Questa prima parte copre le fondamenta: quali file servono davvero, cosa contengono, e come arrivare al momento in cui attivi il tema e vedi i tuoi contenuti a schermo.
Prima però vale la pena rispondere a una domanda che di solito viene saltata: partire da zero è la scelta giusta per il tuo progetto? Spesso non lo è, e sbagliare strada all’inizio costa settimane. Alla sezione Da zero, child theme, starter theme o tema pronto trovi il criterio per decidere in cinque minuti.
La guida in quattro parti: cosa trovi in ciascuna
Le quattro parti sono pensate per essere lette in ordine: ognuna parte dal tema che hai lasciato alla fine della precedente. Se cerchi un argomento preciso puoi però saltare direttamente al punto giusto.
- Parte 1 — File base e struttura (questa pagina). I due file obbligatori, l’intestazione di
style.css, le prime funzioni infunctions.php, il loop inindex.php, l’attivazione e il debug dei primi errori. Alla fine hai un tema attivo che mostra i tuoi contenuti. - Parte 2 — Template file, gerarchia e layout dinamico.
header.php,footer.php,sidebar.php, la registrazione dei menu e delle sidebar, e soprattutto la template hierarchy: la regola con cui WordPress sceglie quale file caricare. È la parte che trasforma una pagina sola in un sito. Vai alla Parte 2: template file e gerarchia. - Parte 3 — single, page, archive, 404 e loop avanzato. I template specifici per articoli, pagine, archivi ed errori 404, più
WP_Queryper le query personalizzate. Vai alla Parte 3: creare template personalizzati. - Parte 4 — Modularizzazione, Gutenberg, ACF e distribuzione.
get_template_part(), il supporto all’editor a blocchi e al Full Site Editing, l’integrazione con ACF e la checklist finale prima di consegnare o pubblicare il tema. Vai alla Parte 4: tema pronto per la distribuzione.
Il tempo realistico per arrivare in fondo, se parti con le basi di PHP e CSS già solide, è tra le venti e le quaranta ore di lavoro effettivo. Non è un pomeriggio.
Da zero, child theme, starter theme o tema pronto
“Da zero” è una delle quattro strade possibili, ed è quella che costa di più. Vale la pena percorrerla solo quando le altre tre hanno un difetto che pesa sul progetto specifico. Ecco come si confrontano.
| Strada | Quando ha senso | Cosa devi saper fare | Cosa ti costa |
|---|---|---|---|
| Tema pronto | Il sito deve essere online in fretta e il design non è il fattore decisivo | Niente codice | Peso, funzioni che non userai, dipendenza dall’autore del tema |
| Child theme | Un tema esistente ti va bene al novanta per cento e devi cambiare il resto | CSS e un po’ di PHP | Resti legato al tema padre, ai suoi aggiornamenti e alle sue scelte |
| Starter theme | Vuoi un tema tuo ma non vuoi riscrivere il boilerplate | PHP, e per alcuni anche i build tool | Erediti convenzioni scritte da altri, che devi comunque capire |
| Da zero | Il progetto durerà anni e il markup, il peso e la manutenibilità sono un requisito | PHP, HTML, CSS, template hierarchy | Tempo, molto più di quanto sembri all’inizio |
Il criterio pratico è uno solo: chi manterrà questo tema tra due anni? Se la risposta è “io, e ci lavorerò spesso”, partire da zero si ripaga, perché ogni riga la conosci e ogni modifica è immediata. Se la risposta è “il cliente da solo” oppure “nessuno”, un tema pronto ben scelto è la decisione più onesta. C’è poi una quinta strada che non compare nella tabella perché non produce un tema tuo: all’estremo opposto, un sito generato dall’AI risolve la domanda saltandola, e ha senso esattamente quando la risposta alla domanda è “nessuno”.
Due precisazioni che evitano di perdere tempo. Se sei arrivato qui perché devi modificare un tema che stai già usando, la strada corretta è creare un child theme del tema che stai usando, non questa guida: un tema da zero non risolve quel problema, lo sostituisce con un problema più grande. E se vuoi un tema tuo ma preferisci partire da una base già impostata, la scorciatoia ragionevole è uno starter theme come WP Rig, Sage o Air-light — l’ho raccontata in come creare un tema WordPress custom partendo da uno starter theme.
Se invece sei ancora nella fase di valutazione e stai confrontando temi esistenti, i criteri per non sbagliare acquisto sono in come scegliere un tema WordPress professionale. C’è infine una quinta strada, fuori scala rispetto alle altre: staccare del tutto il frontend da WordPress con un’architettura headless con Next.js.
Cosa serve prima di iniziare
Non servono competenze da guru, ma tre cose sì, e senza quelle il resto della guida diventa copia e incolla senza comprensione.
Le conoscenze minime
- HTML semantico: sapere quando si usa
<header>,<main>,<article>e<nav>, e perché non sono<div>con un nome diverso. Il markup che scrivi qui è quello su cui poi lavorano Google e gli screen reader. - CSS: selettori, specificità, box model, Flexbox e Grid. Le media query servono dal primo giorno, non alla fine.
- PHP di base: variabili, funzioni, cicli, condizioni e array. WordPress è scritto in PHP e un tema è codice PHP che genera HTML.
Aggiungo una quarta voce che non è una competenza ma un’abitudine: imparare a consultare il WordPress Developer Handbook e il Code Reference ufficiali. Ogni funzione che incontrerai ha una pagina che ne spiega parametri, valori di ritorno e versione di introduzione. Cercare lì prima che su un forum fa la differenza tra sapere e indovinare.
Gli strumenti
- Un ambiente locale. LocalWP è il più immediato: crea un sito WordPress completo in un clic, con PHP, MySQL e web server già configurati. Alternative valide sono DevKinsta, DDEV o wp-env. Il punto non è quale scegli, è non sviluppare un tema direttamente in produzione.
- Un editor con supporto PHP. Visual Studio Code con PHP Intelephense per autocompletamento e linting, e WordPress Snippets per hook e funzioni. Il linting ti segnala l’errore di sintassi prima che sia il sito a farlo.
- Git. Anche se lavori da solo. Un tema in sviluppo si rompe spesso, e la differenza tra “torno al commit di ieri” e “ricostruisco a memoria” è di ore.
- I DevTools del browser. Per ispezionare il DOM generato, provare il CSS a caldo e vedere cosa viene caricato davvero e in quale ordine.
I file che compongono un tema WordPress
Un tema classico può contenere decine di file, ma perché WordPress lo riconosca e lo attivi ne bastano due. Tutto il resto è opzionale in senso tecnico e indispensabile in senso pratico.
| File | Obbligatorio | A cosa serve |
|---|---|---|
style.css | Sì | Contiene l’intestazione con i metadati del tema. Senza, WordPress non lo elenca nemmeno in Aspetto > Temi. Può contenere anche il CSS. |
index.php | Sì | Il template di fallback universale: WordPress lo usa quando non trova un file più specifico per la richiesta in corso. |
functions.php | No | Il punto in cui il tema dichiara cosa sa fare: caricamento di CSS e JS, supporti nativi, menu, sidebar, funzioni proprie. |
screenshot.png | No | L’anteprima visiva mostrata nella dashboard. Formato PNG, 1200 × 900 pixel. |
Una precisazione che risparmia confusione: quei due file obbligatori valgono per i temi classici, quelli basati su PHP, che è ciò che costruiamo in questa guida. Un block theme per il Full Site Editing ha requisiti diversi — servono style.css, templates/index.html e, di fatto, theme.json. Il supporto ai blocchi e il passaggio a FSE li affrontiamo nella Parte 4.
Dove creare la cartella del tema
Tutti i temi vivono in wp-content/themes/. Crea lì una cartella con un nome tutto minuscolo, separato da trattini, senza accenti, senza spazi e senza numeri iniziali. Evita tema1 o mytheme: il nome della cartella diventa parte di percorsi e riferimenti, e cambiarlo dopo significa ricollegare tutto.
wp-content/
└── themes/
├── twentytwentyfive/
└── nome-tema/ <-- la tua cartellaScegli il nome pensando già al text domain: la convenzione è che coincidano. Se la cartella si chiama nome-tema, il text domain sarà nome-tema e le stringhe traducibili useranno quello. Tenerli allineati evita che le traduzioni smettano di caricarsi senza un motivo apparente.
style.css: l’intestazione che fa riconoscere il tema
La prima cosa che WordPress legge non è CSS: è un commento. L’intestazione va all’inizio del file, prima di qualsiasi regola di stile, e deve essere un commento CSS regolare.
/* Theme Name: Nome Tema Theme URI: https://esempio.it/nome-tema Author: Alessandro Aili Author URI: https://www.alessandroaili.it/ Description: Tema custom sviluppato su misura, senza dipendenze da framework esterni. Version: 1.0.0 Requires at least: 6.0 Tested up to: 6.8 Requires PHP: 7.4 License: GNU General Public License v2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html Text Domain: nome-tema Tags: custom, responsive, accessibility-ready */
L’unico campo davvero obbligatorio è Theme Name: basta quello perché il tema compaia nella dashboard. Gli altri diventano importanti appena il tema esce dal tuo computer.
- Version non è decorativa: la useremo più avanti per il versioning dei file CSS, ed è ciò che impedisce ai browser di servire un foglio di stile vecchio dopo un aggiornamento.
- Requires at least e Requires PHP impediscono a WordPress di attivare il tema su un ambiente troppo vecchio. Su un tema consegnato a un cliente valgono più di qualsiasi nota nella documentazione.
- Text Domain deve coincidere con il nome della cartella, come dicevamo sopra.
Sotto l’intestazione puoi già mettere qualche regola minima — un reset, la tipografia di base, un colore di sfondo — solo per avere un riscontro visivo immediato all’attivazione. La struttura definitiva del CSS la organizzeremo nella cartella assets/.
functions.php: caricare il CSS e attivare i supporti
functions.php viene eseguito a ogni caricamento di pagina, sia sul frontend sia nel backend. È il file in cui il tema dichiara le proprie capacità, e le due operazioni da fare subito sono caricare il foglio di stile e attivare i supporti nativi.
<?php
/**
* Funzioni e definizioni del tema.
*/
function nometema_setup() {
add_theme_support( 'title-tag' );
add_theme_support( 'post-thumbnails' );
add_theme_support( 'html5', array(
'search-form',
'comment-form',
'comment-list',
'gallery',
'caption',
'style',
'script',
) );
register_nav_menus( array(
'primary' => __( 'Menu principale', 'nome-tema' ),
) );
}
add_action( 'after_setup_theme', 'nometema_setup' );
function nometema_assets() {
$theme = wp_get_theme();
wp_enqueue_style(
'nometema-style',
get_stylesheet_uri(),
array(),
$theme->get( 'Version' )
);
}
add_action( 'wp_enqueue_scripts', 'nometema_assets' );Tre dettagli fanno la differenza tra questo codice e la versione che si trova nella maggior parte dei tutorial.
- Il prefisso su ogni nome di funzione.
nometema_setup(), nonsetup(). Le funzioni di un tema vivono nello stesso spazio dei nomi globale di WordPress e di tutti i plugin attivi: una funzione chiamatasetup()prima o poi collide con qualcosa e produce un errore fatale. - I supporti vanno dichiarati dentro
after_setup_theme. Scriverli fuori da un hook può funzionare per caso, ma li esegue nel momento sbagliato del ciclo di vita di WordPress. - La versione del CSS presa da
style.css. Passando$theme->get( 'Version' )come quarto parametro, ogni volta che alziVersionnell’intestazione tutti i browser scaricano il foglio aggiornato. Con una stringa scritta a mano ti dimenticherai di cambiarla, e passerai un pomeriggio a chiederti perché il CSS “non si aggiorna”.
Sul cosa attivano quelle tre righe: title-tag lascia gestire a WordPress il contenuto del tag <title>, cosa che i plugin SEO si aspettano per poterlo riscrivere; post-thumbnails abilita le immagini in evidenza; html5 sostituisce il markup datato che WordPress genererebbe per moduli, gallerie e didascalie. Su un tema classico vanno dichiarati esplicitamente: non sono attivi per default.
index.php e il loop: il minimo per vedere qualcosa a schermo
index.php è il fondo della gerarchia dei template: se WordPress non trova un file più specifico — single.php per un articolo, page.php per una pagina, archive.php per un archivio — usa questo. Finché è l’unico template che hai, gestisce tutto il sito.
Dentro ci va il loop, il meccanismo con cui WordPress scorre i contenuti che corrispondono alla richiesta corrente e li stampa uno a uno. Non è una funzione che chiami: è un ciclo while costruito su due funzioni, have_posts() e the_post().
<?php get_header(); ?>
<main id="primary" class="site-main">
<?php if ( have_posts() ) : ?>
<?php while ( have_posts() ) : the_post(); ?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<h2 class="entry-title">
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
</h2>
<div class="entry-summary">
<?php the_excerpt(); ?>
</div>
</article>
<?php endwhile; ?>
<?php the_posts_pagination(); ?>
<?php else : ?>
<p><?php esc_html_e( 'Nessun contenuto trovato.', 'nome-tema' ); ?></p>
<?php endif; ?>
</main>
<?php get_footer(); ?>Alcune scelte in questo codice meritano una nota. the_post() non stampa nulla: prepara il post corrente, ed è la ragione per cui tutte le funzioni che seguono — the_title(), the_permalink(), the_excerpt() — sanno di quale contenuto stanno parlando. post_class() stampa un elenco di classi CSS generate da WordPress in base al tipo, alla categoria e allo stato del post: è gratis e ti servirà appena inizierai a differenziare i layout. Il ramo else non è formalità: senza, una ricerca senza risultati restituisce una pagina bianca.
Se header.php e footer.php non esistono ancora, get_header() e get_footer() non generano errori: WordPress ricade sui propri file di default. Puoi lasciarli lì e crearli nella Parte 2, oppure sostituirli temporaneamente con HTML statico.
screenshot.png e attivazione del tema
screenshot.png è l’unico file di questa guida che non ha alcun effetto tecnico e che comunque va fatto bene: è l’anteprima in Aspetto > Temi, e su un tema consegnato a un cliente è il primo contatto visivo con il tuo lavoro.
- Formato PNG, con esattamente questo nome, nella root della cartella del tema.
- 1200 × 900 pixel: è la dimensione consigliata per i display ad alta densità. WordPress la mostra ridotta, ma parte da quella.
- Contenuto: una schermata reale del tema con contenuti demo, oppure un mockup pulito con header, contenuto e footer riconoscibili. Non immagini generiche, non loghi, non sfocature.
A questo punto la cartella contiene i quattro file e il tema è attivabile. Vai in Aspetto > Temi, verifica che compaia con nome e anteprima corretti, attivalo e apri la homepage. Se vedi i titoli dei tuoi articoli, senza stile ma al loro posto, la Parte 1 ha raggiunto il suo obiettivo.
Per avere contenuti su cui provare davvero il layout, importa il Theme Unit Test: è il set di dati ufficiale usato per validare i temi, e contiene apposta i casi limite — titoli lunghissimi, immagini di ogni allineamento, commenti annidati, liste dentro le citazioni. Sono gli stessi casi che rompono il tema una settimana dopo la consegna.
Gli errori che rompono il tema al primo avvio
Quattro problemi coprono quasi tutti i fallimenti di un primo tema, e hanno sintomi abbastanza diversi da essere riconoscibili.
- Il tema non compare in dashboard. Manca l’intestazione in
style.css, oppure non è il primo contenuto del file, oppure la cartella non è direttamente sottowp-content/themes/. Un livello di annidamento in più è sufficiente perché WordPress non la veda. - Pagina bianca dopo l’attivazione. Quasi sempre un errore fatale di PHP con la visualizzazione degli errori disattivata. Si risolve leggendo il log, non provando modifiche a caso.
- Errore di sintassi in
functions.php. È il caso peggiore, perché il file viene caricato anche nel backend: un punto e virgola mancante può bloccare anche/wp-admin. Da WordPress 5.2 esiste la recovery mode: WordPress rileva l’errore fatale, disattiva il tema e manda all’indirizzo dell’amministratore un link per entrare in modalità di ripristino. Se non ricevi l’email — e in locale succede spesso — rinomina la cartella del tema via file system: WordPress torna automaticamente a un tema di default e ti restituisce l’accesso. - Caratteri strani a schermo. File salvato con la codifica sbagliata. Sempre UTF-8 senza BOM: il BOM inserisce byte invisibili prima del tag
<?phpe genera l’errore “headers already sent”.
Attivare il debug nel modo giusto
In wp-config.php, prima della riga /* That's all, stop editing! */:
define( 'WP_DEBUG', true ); define( 'WP_DEBUG_LOG', true ); define( 'WP_DEBUG_DISPLAY', false );
Con questa combinazione gli errori finiscono in wp-content/debug.log invece di essere stampati nella pagina. È preferibile anche in locale: gli errori stampati a schermo si mescolano all’HTML, rompono il layout e a volte spariscono dietro il CSS. Su un sito in produzione WP_DEBUG_DISPLAY a false non è una preferenza ma una misura di sicurezza, perché i messaggi di errore rivelano percorsi assoluti e struttura del filesystem.
Accanto al log, un plugin vale l’installazione fin dal primo giorno: Query Monitor. Mostra in una barra quale template WordPress ha effettivamente caricato per la pagina che stai guardando, quali hook sono scattati, quali query sono state eseguite e quali sono lente. Nella Parte 2, quando la gerarchia dei template inizierà a decidere le cose al posto tuo, quell’informazione sarà la più utile che hai.
Organizzare le cartelle prima che il tema cresca
Con quattro file l’organizzazione sembra un problema che non esiste. Con quaranta è troppo tardi per affrontarlo. Questa struttura regge fino alla fine della guida e oltre.
nome-tema/ ├── style.css ├── index.php ├── functions.php ├── screenshot.png ├── assets/ │ ├── css/ │ ├── js/ │ └── img/ ├── inc/ ├── parts/ └── templates/
assets/— file statici: CSS compilato, JavaScript, immagini e font del tema.inc/— codice PHP separato per area (registrazione dei menu, personalizzazioni, funzioni di supporto), incluso dafunctions.php. È così che si evita ilfunctions.phpda millecinquecento righe che nessuno riesce più a leggere.parts/— porzioni riutilizzabili di markup richiamate conget_template_part(): la card di un articolo, un blocco autore, un box CTA. Le vediamo nella Parte 4.templates/— i template di pagina personalizzati, quelli selezionabili dall’editor.
Sulle convenzioni di nome vale la stessa regola dei prefissi vista prima: nometema_enqueue_scripts() e non enqueue_scripts(). E un commento per ogni funzione che spieghi perché esiste, non cosa fa — cosa fa si legge dal codice, perché esiste no.
Il passo successivo: la Parte 2
A questo punto hai un tema tuo, attivo, che carica il proprio CSS e mostra i contenuti del sito. È un tema di una pagina sola: qualunque URL apri, risponde sempre index.php.
Nella Parte 2 — template file, gerarchia e layout dinamico si separa il layout in header.php, footer.php e sidebar.php, si registrano menu e aree widget, e soprattutto si entra nella template hierarchy: la regola con cui WordPress sceglie il file da usare per ogni tipo di richiesta. È il passaggio che trasforma quello che hai adesso in un sito vero.
Domande frequenti
Serve saper programmare per creare un tema WordPress da zero?
Sì, e non è una risposta scoraggiante ma una precisazione utile: servono HTML, CSS e PHP di base — variabili, funzioni, cicli, condizioni. Non serve conoscere la programmazione a oggetti, né JavaScript avanzato, né i build tool, almeno per un tema classico come quello di questa guida. Se PHP ti è del tutto estraneo, il percorso sensato è partire da un child theme: si lavora quasi solo in CSS e si impara la struttura di WordPress dall’interno, senza doverla costruire.
Quanto tempo serve per completare tutte e quattro le parti?
Tra le venti e le quaranta ore di lavoro effettivo, se le basi ci sono. Questa prima parte si chiude in due o tre ore. La distribuzione della fatica non è uniforme: le Parti 1 e 2 sono le più lunghe da capire, la Parte 3 è ripetitiva una volta afferrata la gerarchia, la Parte 4 dipende molto da quanto vuoi spingere sull’integrazione con l’editor a blocchi.
Meglio un tema classico in PHP o un block theme per il Full Site Editing?
Dipende da chi gestirà il sito. Un block theme permette a chi non scrive codice di modificare header, footer e template dall’editor, ed è la direzione in cui WordPress sta andando. Un tema classico dà controllo totale sul markup e sulla logica PHP, ed è ancora la scelta più solida quando il tema deve integrarsi con funzionalità custom, campi avanzati o sistemi esterni. Imparare il tema classico non è tempo perso in nessuno dei due casi: la template hierarchy, gli hook e il loop restano gli stessi anche sotto un block theme.
Posso sviluppare il tema direttamente su un sito già online?
Tecnicamente sì, praticamente no. Un errore in functions.php mette offline l’intero sito, backend compreso, e lo fa mentre ci sono visitatori. Si sviluppa in locale e si trasferisce a lavoro finito. Se il sito è già pubblico e il tema deve sostituirne un altro, il passaggio va fatto su una copia di staging, verificando prima che tutti i contenuti — non solo la homepage — vengano resi correttamente.
Un tema fatto da zero è davvero più veloce di uno commerciale?
Parte avvantaggiato, perché carica solo quello che serve, ma non è garantito: un tema custom scritto male è lento quanto un tema commerciale pieno di funzioni inutilizzate. Il vantaggio reale è un altro — quando il sito è lento, sai esattamente dove guardare e puoi intervenire, cosa che con un tema di terze parti spesso non puoi fare. Sulle cause concrete della lentezza, e su quanto pesi davvero il tema rispetto ad altri fattori, ho scritto sito WordPress lento: 6 cause reali e come risolverle.
Prima di andare avanti
Due cose che conviene sistemare mentre il tema è ancora piccolo, perché rifarle dopo costa molto di più. La prima è la struttura semantica del markup: gerarchia dei titoli coerente, un solo <h1> per pagina, attributi alt sulle immagini. Sono le stesse voci della checklist SEO on-page per WordPress, e in un tema custom dipendono interamente da te. La seconda è l’escaping dell’output: esc_html(), esc_url(), esc_attr() vanno usati da subito, perché un tema custom è codice che gira sul sito con tutti i privilegi — il contesto è quello della checklist sicurezza WordPress.
Se il tema ti serve per un progetto reale e preferisci non partire da zero da solo, sviluppo temi e plugin WordPress su misura: posso occuparmene io, oppure affiancarti sulla parte che ti sta bloccando.

Lascia un commento