Il tema del sito è stato personalizzato anni fa: un colore nel CSS, un campo in più nella pagina del prodotto, un blocco di codice in functions.php per un’integrazione. Le modifiche sono state fatte direttamente nei file del tema, perché era più veloce. Poi arriva la necessità di passare a PHP 8, il tema va aggiornato, e dopo l’aggiornamento il sito ha di nuovo l’aspetto di serie e l’integrazione non funziona più. Le modifiche sono state sovrascritte, e spesso nessuno ha una copia di cosa era stato cambiato.
In questo articolo vediamo come funziona un child theme in WordPress, come crearlo correttamente, cosa cambia con i temi a blocchi e l’Editor del sito, come recuperare le modifiche già fatte nel tema principale e dove mettere ogni tipo di personalizzazione perché sopravviva agli aggiornamenti di WordPress, del tema e di PHP.
Perché le modifiche si perdono
Quando WordPress aggiorna un tema, sostituisce l’intera cartella del tema con quella della nuova versione. Non fa confronti e non conserva i file modificati: tutto ciò che era stato scritto nei file del tema scompare. Lo stesso succede con i plugin. È il comportamento corretto, perché garantisce che il codice installato sia esattamente quello rilasciato dall’autore, con le sue correzioni di sicurezza.
Chi ha modificato il tema principale finisce davanti a una scelta sbagliata in entrambi i casi: aggiornare e perdere le modifiche, oppure non aggiornare e restare con un tema vecchio, che spesso è proprio ciò che impedisce di passare a PHP 8. Il child theme esiste per evitare questa scelta.
Come funziona un child theme
Un child theme, o tema figlio, è un tema che eredita tutto da un altro tema, il tema principale, e contiene solo le differenze. Il manuale dei temi di WordPress descrive le regole, che sono poche:
- l’unico file obbligatorio è
style.css, con le intestazioni standard e il campoTemplate, che deve corrispondere esattamente al nome della cartella del tema principale; - un file di template presente nel tema figlio con lo stesso nome di uno del tema principale lo sostituisce; vale anche per le parti di template e per i pattern, che devono avere lo stesso slug;
- il
functions.phpdel tema figlio non sostituisce quello del principale: vengono caricati entrambi, prima quello del figlio e subito dopo quello del principale; - i file aggiunti nel tema figlio, come nuovi template o fogli di stile, si sommano a quelli del principale.
Una conseguenza importante: non bisogna copiare nel figlio il functions.php del principale. Le funzioni verrebbero dichiarate due volte e il sito si fermerebbe con un errore fatale. Nel figlio si scrive solo il codice nuovo, e per cambiare il comportamento del principale si usano gli hook che mette a disposizione.
Gli strumenti sono tre. I filtri e le azioni del tema principale permettono di cambiare un valore o aggiungere un contenuto senza toccare il suo codice. Un’azione registrata dal principale si toglie con remove_action(), chiamata dal figlio dopo che il principale l’ha aggiunta, di solito sull’hook after_setup_theme. Infine molti temi dichiarano le proprie funzioni dentro un controllo function_exists(): dato che il figlio viene caricato prima, una funzione con lo stesso nome scritta nel figlio prende il posto di quella del principale.
Creare il child theme
Per un tema classico servono due file nella cartella wp-content/themes/. L’esempio usa un tema principale nella cartella temaprincipale: va sostituito con il nome reale.
/* wp-content/themes/temaprincipale-figlio/style.css */
/*
Theme Name: Tema principale, personalizzazioni
Template: temaprincipale
Version: 1.0.0
*/
<?php
// wp-content/themes/temaprincipale-figlio/functions.php
// Se il tema principale carica solo il foglio di stile del tema attivo,
// carica prima il suo style.css e poi quello del figlio.
add_action( 'wp_enqueue_scripts', function () {
wp_enqueue_style( 'principale', get_parent_theme_file_uri( 'style.css' ) );
wp_enqueue_style( 'figlio', get_stylesheet_uri(), array( 'principale' ) );
} );
Molti temi recenti caricano già da soli sia il proprio foglio di stile sia quello del figlio: in quel caso il secondo file può restare vuoto, e il manuale lo indica esplicitamente. Conviene controllare la documentazione del tema principale, perché caricare due volte lo stesso CSS rallenta le pagine. Molti produttori di temi commerciali, inoltre, distribuiscono un child theme già pronto, da usare come punto di partenza.
Temi a blocchi ed Editor del sito
Con i temi a blocchi, come i temi predefiniti da Twenty Twenty-Two in poi, gli stili sono descritti nel file theme.json e si sommano a livelli: quello predefinito di WordPress, quello del tema principale, quello del tema figlio e infine le personalizzazioni fatte dall’utente nell’Editor del sito. Un tema figlio può contenere solo un theme.json con le differenze, senza alcun foglio di stile.
Le personalizzazioni fatte nell’Editor del sito non finiscono nei file del tema: sono salvate nel database e hanno la precedenza su theme.json, template e pattern del tema. Sopravvivono agli aggiornamenti, ma con un effetto collaterale: un template modificato nell’Editor è una copia ferma alla versione del momento, e non riceve più i miglioramenti che il tema principale porta in quel template. Per i siti che contano conviene riportare le modifiche importanti nei file di un tema figlio, sotto controllo di versione, e usare l’Editor per gli aggiustamenti di contenuto.
Recuperare le modifiche già fatte nel tema principale
Se il tema principale è già stato modificato, il primo lavoro è ricostruire cosa è stato cambiato. Il metodo è un confronto tra i file installati e quelli originali della stessa versione, sempre su una copia del sito.
# Versione installata del tema (dal campo Version di style.css)
wp theme get temaprincipale --field=version
# Pacchetto originale della stessa versione: dalla directory di wordpress.org
# per i temi gratuiti, dall'area clienti del produttore per quelli commerciali
mkdir -p /tmp/originale && cd /tmp/originale
curl -sO https://downloads.wordpress.org/theme/temaprincipale.2.3.1.zip
unzip -q temaprincipale.2.3.1.zip
# Elenco dei file modificati o aggiunti, poi il dettaglio delle differenze
diff -rq /tmp/originale/temaprincipale /var/www/sito/wp-content/themes/temaprincipale
diff -ru /tmp/originale/temaprincipale /var/www/sito/wp-content/themes/temaprincipale > modifiche.diff
Il file delle differenze diventa l’elenco di lavoro. Ogni modifica si sposta nel posto giusto: le regole CSS nel style.css del figlio, i template modificati come copie nel figlio, il codice di functions.php nel functions.php del figlio o in un plugin. A quel punto il tema principale si può aggiornare all’ultima versione, e i template copiati nel figlio vanno confrontati con quelli nuovi per riportare le eventuali correzioni dell’autore.
Cosa va nel child theme e cosa no
Il tema figlio è il posto giusto per tutto ciò che riguarda l’aspetto del sito. Le funzioni che devono restare attive anche cambiando tema hanno un posto diverso.
- Nel tema figlio: CSS, template modificati, colori e caratteri in
theme.json, e gli override dei template di WooCommerce nella cartellawoocommercedel figlio, che vanno riallineati a ogni versione principale come spieghiamo nell’articolo su WooCommerce e PHP 8. - In un plugin di funzionalità: tipi di contenuto, tassonomie, shortcode, integrazioni con servizi esterni. Se domani si cambia tema, i contenuti e le integrazioni restano.
- Nei mu-plugin: i file nella cartella
wp-content/mu-pluginsvengono caricati sempre e non si possono disattivare dalla bacheca. Sono adatti a regole che non devono mai saltare, come un’impostazione di sicurezza. - Mai nei file di terzi: tema principale, plugin e core vengono sostituiti a ogni aggiornamento.
Il codice spostato va anche reso compatibile con PHP 8. Un blocco copiato da un vecchio functions.php può contenere le stesse funzioni rimosse che bloccano i plugin abbandonati, di cui parliamo nell’articolo sui plugin WordPress abbandonati.
Attivare il child theme senza sorprese
WordPress salva alcune impostazioni per singolo tema. Le opzioni del Personalizza, come logo, colori e intestazione, sono memorizzate con il nome del tema attivo, e passando al tema figlio ripartono vuote. Lo stesso può succedere con il CSS aggiuntivo, le posizioni dei menu e i widget. Prima di attivare il figlio in produzione conviene quindi:
- attivarlo su una copia del sito e confrontare le pagine principali con quelle originali;
- copiare le impostazioni del Personalizza dal tema principale al figlio, per esempio collegando con una pipe
wp option get theme_mods_temaprincipale --format=jsonewp option update theme_mods_temaprincipale-figlio --format=json, che legge il valore dallo standard input; - riassegnare menu e widget e ricopiare il CSS aggiuntivo, se necessario;
- attivare il figlio in produzione in un momento di poco traffico e ricontrollare le pagine.
Da quel momento il tema principale si aggiorna come qualsiasi altro componente, e il percorso verso PHP 8 descritto nell’articolo su WordPress su PHP vecchio non incontra più l’ostacolo delle modifiche da salvare.
Conclusioni
Gli aggiornamenti di WordPress sostituiscono l’intera cartella del tema, quindi le modifiche fatte nei file del tema principale si perdono. Un child theme contiene solo le differenze: un style.css con il campo Template, i template da sostituire e un functions.php che si carica prima di quello del principale senza sostituirlo. Con i temi a blocchi gli stili si sommano a livelli in theme.json, e le modifiche fatte nell’Editor del sito restano nel database come copie ferme nel tempo. Se il tema principale è già stato modificato, un confronto con il pacchetto originale della stessa versione ricostruisce cosa spostare. L’aspetto va nel tema figlio, le funzioni in un plugin o in un mu-plugin, nulla nei file che vengono aggiornati, e prima dell’attivazione vanno copiate le impostazioni salvate per tema.