Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
In questo articolo daremo una definizione quanto più chiara possibile di cosa sia un plugin di WordPress. Si tratta di una
precisazione importante per poter affrontare in modo completo il tema generale dei plugin per il noto Blog engine/CMS
Open Source.
Un plugin di WordPress è un componente che viene aggiunto a WordPress per modificarne o estenderne le funzionalità.
Un plugin viene spesso chiamato modulo in altre applicazioni simili, ma la definizione rimane nello specifico la medesima.
Lo scopo di un plugin è infatti quello di permettere agli utilizzatori di eseguire delle operazioni in modo diverso rispetto a
quello previsto da WordPress o di aggiungere nuove operazioni a quelle predefinite.
Un esempio del primo tipo di plugin è quello che aggiunge dei ruoli utente a WordPress oltre a quelli tradizionali, in tal caso
viene quindi migliorata una funzionalità già disponibile. Nello stesso modo un plugin che gestisce gli slideshow appartiene
al secondo tipo, poiché per il momento WordPress non consente nativamente tale operazione, viene quindi integrata una
nuova funzionalità.
I plugin vengono attivati o disattivati nella sezione amministrativa di WordPress. Quando un plugin viene attivato,
WordPress include tutto il suo codice nel suo intero flusso di esecuzione consentendo al plugin di operare sia nel frontend
che nel backend del sito (a meno che l’autore del plugin non opti per operare solo in uno di questi due contesti).
Al contrario, quando un plugin viene disattivato, WordPress lo rimuove dal suo flusso di esecuzione e si comporta come se
il plugin non esistesse, ossia il codice del plugin non viene più eseguito.
WordPress non assegna privilegi di esecuzione inferiori ai plugin: ciò significa che un plugin può di fatto apportare
qualsiasi tipo di modifica a WordPress. Da qui sorge il problema dei bug e delle vulnerabilità nei plugin: se un plugin ha
un problema, anche WordPress ha lo stesso problema e non di rado quest’ultimo riguarda la sicurezza.
Per questo motivo una delle procedure di risoluzione dei problemi in WordPress prevede appunto la disabilitazione dei
plugin al fine di individuare quello che è all’origine del problema (una falla, un malfunzionamento, un calo di prestazioni..).
Nonostante i plugin, secondo le intenzioni della community di WordPress, debbano essere rilasciati in modo libero e aperto
(seguendo i termini contenuti nella licenza GPL per le applicazioni Open Source), una cospicua fetta dei plugin presenti sul
mercato sono disponibili a pagamento.
Esiste una differenza di fondo tra i plugin a pagamento e quelli liberi e gratuiti presenti nella repository ufficiale di
WordPress, esso risiede sostanzialmente nel modo in cui i plugin vengono aggiornati.
Mentre i plugin della repository ufficiale di WordPress sono tutti aggiornabili in automatico (ovviamente se l’autore rilascia
con regolarità gli aggiornamenti), quelli a pagamento non sempre lo sono e quindi spesso si è costretti ad installare la nuova
versione manualmente.
Installare un plugin manualmente è un’operazione molto semplice: è sufficiente uploadare la catella del plugin con i suoi
file (dopo averli decompressi) nella directory /wp-content/plugins e quindi attivarlo nel backend di WordPress.
Come abbiamo appena sottolineato, l’aggiornamento di un plugin è un requisito essenziale per gestire al meglio WordPress.
Un plugin che non viene mai aggiornato non solo può causare problemi con gli aggiornamenti delle versioni di WordPress,
ma rappresentare esso stesso un potenziale problema di sicurezza.
Se infatti un plugin viene disattivato ma i suoi file non vengono cancellati, questi possono essere usati per attacchi remoti se
sono vulnerabili. Il problema della sicurezza, insieme a quello dell’usabilità, è una questione di primaria importanza per i
plugin di WordPress. Questi aspetti non vanno mai trascurati sia che si voglia scegliere un plugin e sia che si desideri
svilupparlo in modo autonomo.
Nella prossima lezione esamineremo la struttura del codice di un plugin di WordPress.
Prima di iniziare è bene ricordare che un plugin per essere attivato con successo non deve contenere errori di sintassi PHP.
In caso contrario il plugin non verrà attivato e WordPress mostrerà un messaggio contenente i dettagli dell’errore. Inoltre
quando si lavora con i plugin è sempre consigliabile abilitare la modalità di debug di WordPress nel file wp-config.php
impostando la costante WP_DEBUG su true.
La pratica comunemente seguita e raccomandata è quella di dare al file principale del plugin lo stesso nome della directory
in cui sono contenuti i file del plugin. Quindi se la directory viene chiamata myplugin, il file principale del plugin verrà
nominato myplugin.php. Tuttavia, come vedremo in seguito, questo non basta ancora affinché WordPress includa un
plugin nell’elenco della sezione Plugin nel backend.
I plugin vanno inseriti nella directory wp-content/plugins. WordPress analizza il contenuto di questa directory ad
ogni sua inizializzazione. Quindi il percorso del nostro ipotetico plugin sarà wp-
content/plugins/myplugin/myplugin.php (come vedremo WordPress dispone di diverse funzioni e costanti
per far riferimento sia all’URL assoluto che al percorso dei plugin ).
Il file principale del plugin può di fatto contenere l’intero codice del plugin. Tuttavia questa soluzione si applica solo nel
caso di plugin molto semplici. Nel caso invece di plugin più complessi, il file principale del plugin servirà semplicemente a
caricare il codice del plugin che risiederà in file esterni che si troveranno sempre all’interno della directory principale del
plugin stesso.
Un plugin di solito non contiene solo file PHP, ma anche file CSS, JavaScript ed immagini. Queste risorse possono essere
utilizzate sia nel frontend che nel backend del sito, come ad esempio nel pannello di controllo del plugin (per le sue
impostazioni). La struttura delle directory aggiuntive e dei nomi dei file ausiliari di fatto non segue alcuno schema
predefinito, anche se la community di WordPress incoraggia gli autori di plugin ad usare una strutturazione coerente.
Di fatto l’unico punto saldo nella struttura di un plugin è il suo file principale. WordPress riconosce un plugin come valido
se all’inizio di questo file è contenuto un blocco di commenti che ha la seguente struttura:
/*
Plugin Name: My Plugin
Version: 1.0
Description: Descrizione del plugin
Author: Nome Cognome
Author URI: http://sito.com
*/
Questi sono i metadati del plugin che verranno usati da WordPress per identificarlo nel backend. La prima riga dichiara il
nome del plugin, la seconda il numero di versione, la terza la descrizione, la quarta mostra l’autore del plugin e la quinta
l’URL del sito dell’autore del plugin. Quando il plugin viene attivato le informazioni contenute in questi metadati vengono
salvate nel database aggiungendole alla stringa contenuta nel campo active_plugins della tabella wp_options (si
tratta di una stringa serializzata).
Dopo questo blocco iniziale l’autore del plugin può inserire il suo codice che, come abbiamo anticipato, può essere
interamente contenuto nel file principale o basato su file esterni richiamati tramite le funzioni PHP require() o
require_once(). Una volta attivato, il codice del plugin è disponibile globalmente nel flusso di WordPress. Quindi se il
plugin definisce una funzione chiamata my_func() questa sarà disponibile nella nostra installazione di WordPress,
ovviamente nel contesto che le è proprio (frontend o backend) secondo le scelte di design dell’autore del plugin. Quando il
plugin viene disattivato o non è presente, la nostra funzione my_func() non sarà più disponibile.
C’è una differenza sostanziale tra percorsi ed URL quando si parla di plugin e più in generale di tutto ciò che ha a che fare
con WordPress. Un "percorso" (path) fa riferimento al file system del server che ospita WordPress, mentre un "URL" fa
riferimento al protocollo HTTP e al dominio su cui risiedono i file.
I percorsi vengono usati per includere i file PHP, mentre gli URL per includere i file CSS, JavaScript e le immagini.
WordPress gestisce i percorsi tramite la funzione plugin_dir_path() che restituisce il percorso alla directory del plugin
compreso lo slash finale. Quindi nel file principale del plugin possiamo scrivere:
Al contrario la funzione plugin_dir_url() restituisce l’URL assoluto alla directory principale del plugin compreso lo slash
finale. Quindi nel file principale del plugin possiamo scrivere:
Da segnalare anche la funzione plugins_url() che ha uno scopo identico anche se con parametri diversi.
Tutte queste funzioni si basano sul file o sulla directory passata come parametro per restituire il percorso o l’URL corretto.
In PHP __FILE__ fa riferimento al file corrente in cui viene invocato. Quindi usarlo in my_plugin/my_plugin.php
e in my_plugin/framework/MyClass.php restituirà due valori distinti poiché i file non si trovano nella stessa
directory.
Ora che abbiamo chiara la struttura di un plugin dal punto di vista dell’organizzazione del codice, possiamo entrare nel
merito dello sviluppo del codice di un plugin di WordPress.
WordPress dispone di numerose action che vengono invocate ogni qualvolta si accede ad una sezione del backend. Esistono
action generiche che vengono invocate su più sezioni ed action specifiche che vengono invocate solo su determinate sezioni.
Una buona pratica è quella di limitare al massimo il codice collegato ad action generiche ed usare invece le action più
specifiche attraverso filtri ed hook. La action a cui non si dovrebbero mai associare troppe routine è init. Come suggerisce
il suo nome, questa action è la radice di tutto il flusso del codice di WordPress ed è sempre invocata. WordPress, quindi,
eseguirà sempre il nostro codice, anche dove non ce ne sarebbe bisogno. Su questa action non andrebbe mai legato del
sorgente che comporti operazioni intensive, come query ripetute al database.
Un altro aspetto da tenere presente sin dall’inizio consiste nel verificare cosa accade nel backend una volta attivato il nostro
plugin impostando in wp-config.php la costante WP_DEBUG su true. Anche se questa opzione non serve a monitorare
la performance di un plugin, è tuttavia importante per escludere l’eventualità che i rallentamenti siano causati da codice
errato.
Se un plugin utilizza il database con tabelle personalizzate (come ad esempio un’estensione che gestisce le prenotazioni
online per un sito) tramite la classe wpdb, una buona regola è quella di mettere in cache quelle query per cui non è sempre
necessario avere un refresh immediato.
Il caching delle query può essere implementato con le Transients API di WordPress:
global
$wpdb;
$results
= get_transient( ‘prenotazioni’ );
if( $results
) {
// loop sui risultati
} else
{
$res
= $wpdb->get_results( “SELECT * FROM prenotazioni” );
set_transient( ‘prenotazioni’, $res, HOUR_IN_SECONDS );
}
In questo caso abbiamo messo in cache i risultati della query per 1 ora. Quando il tempo è scaduto, il valore della chiave
prenotazioni torna ad essere false ed il processo si ripete con dei nuovi risultati.
In generale queste API possono essere usate per memorizzare qualsiasi tipo di dato, quindi sono molto indicate per
velocizzare alcune operazioni ripetute (come ad esempio la generazione e la visualizzazione di stringhe HTML o CSS).
Un altro aspetto, stavolta più controverso, sono i task programmati usando le API Cron. PHP infatti non ha la capacità di
attivarsi in un determinato momento in modo autonomo: c’è sempre bisogno di una richiesta GET su un file specifico che
eseguirà il codice. Nello specifico, WordPress usa il file wp-cron.php per i suoi cron jobs.
Il problema è che questi cron si attivano quando si visualizza una qualsiasi sezione di un sito Web, sia nel backend che nel
frontend. In pratica la routine di verifica avviene sempre, e questo ha un impatto sulla performance.
Quindi se si vogliono utilizzare i cron nei plugin si dovrebbe sempre tenere presente questa particolarità per evitare di
sovraccaricare inutilmente WordPress.
Il frontend
Nel frontend bisogna applicare un modello specifico di ottimizzazione che parte sempre dalle condizioni peggiori per poi
scalare verso condizioni migliori. Le condizioni peggiori sono quelle rappresentate da un sito poco performante e lento a
rispondere. Se sviluppiamo in locale abbiamo bisogno di un applicativo come Sloppy per emulare le condizioni peggiori,
come per esempio connessioni molto lente che aiutano a capire dove intervenire per migliorare la situazione.
Il codice CSS e JavaScript va fornito in due formati: uno compresso e minimizzato da usare effettivamente sul sito Internet
ed un formato non compresso per le eventuali modifiche da parte dell’utente (se si segue la licenza GPL).
Le immagini da usare con i CSS devono essere ottimizzate. Se usate le icone, è preferibile impiegare le sprite CSS per
ridurre al minimo le richieste GET.
Se si utilizzano invece dei Web font per generare le icone, il peso complessivo dei file dovrà essere limitato. Si tenga
presente che un Web font viene rilasciato in diversi formati (TTF, SVG, EOT ecc.).
In questo caso la regola da seguire è semplice: inserire il codice CSS e JavaScript solo dove è richiesto e non in tutto il sito
Internet. Se sappiamo ad esempio che il nostro codice verrà usato solo nei custom post type di tipo prenotazioni
possiamo scrivere:
Gli script JavaScript andrebbero sempre inseriti prima della chiusura dell’elemento <body> per velocizzare il caricamento
delle pagine. Ecco perché usiamo l’ultimo parametro della funzione wp_register_script() impostato su true.
Inoltre, se non possiamo limitare l’uso del codice a sezioni specifiche, è sempre buona norma creare un namespace per il
codice CSS e JavaScript usando i prefissi per evitare conflitti, ad esempio:
#my-plugin-booking-form {
}
In JavaScript:
(function( $ ) {
$.MyPluginBooking = {};
//…
})( jQuery );
Le ambiguità generano rallentamenti, perché i browser devono comunque risolverle, mentre la specificità implica velocità.
Conclusione
Con dei semplici accorgimenti possiamo creare plugin snelli che non hanno un grande impatto sulle prestazioni complessive
di WordPress; Nel prossimo capitolo verrà affrontato il discorso relativo a plugin e sicurezza.
Analisi di una procedura per l’attacco contro un sito basato su WordPress
Anche se esistono plugin che affermano di nascondere un’installazione di WordPress, esistono tuttavia tool automatici per
la scansione dei siti che possono letteralmente eseguire una radiografia di un sito. Non solo un malintenzionato sa che
usiamo WordPress, ma sa anche che plugin stiamo utilizzando, quali sono i temi installati e molto altro ancora. Questo è il
prezzo da pagare per aver pubblicato un sito pubblico.
Una volta effettuata la scansione, un malintenzionato di solito passa alla ricerca di vulnerabilità nei temi e nei plugin e, se
WordPress non è aggiornato, anche nel Core di WordPress stesso. Trovata la vulnerabilità, l’attaccante può usare un exploit
già disponibile in rete o scriverne uno (questo nel caso in cui il malintenzionato sia molto esperto).
All’exploit, eseguito da remoto su un file specifico dell’installazione di WordPress, segue il payload, ossia il codice
malevolo che verrà eseguito. A questo punto se PHP viene eseguito con i vincoli dell’utenza corrente, i danni causati
interesseranno lo spazio Web dell’utente stesso. Se questi vincoli non dovessero esistere, il codice malevolo potrà
propagarsi su più utenze e quindi su più siti Internet.
A questo punto il danno sarà ormai fatto. L’unica soluzione valida rimane come al solito è la prevenzione.
PHP gestisce i metodi HTTP GET e POST e i file con array superglobali. Quando dobbiamo manipolare un input esterno,
dobbiamo sempre validare e filtrare i dati in ingresso. In altre parole dobbiamo considerare qualsiasi forma di input come
potenzialmente pericoloso ed agire di conseguenza.
• filtrare
le
query
SQL
con
il
metodo
prepare()
della
classe
wpdb;
• filtrare
ogni
variabile
veicolata
tramite
GET
o
POST
da
inserire
nel
flusso
di
output
con
le
funzioni
di
escape
(con
prefisso
esc_)
di
WordPress;
• validare
i
dati
inseriti
dagli
utenti
secondo
il
formato
dati
richiesto
(numero,
stringa,
indirizzo
e-‐mail..
);
• se
si
gestiscono
file
(upload,
manipolazione,
inclusione..)
verificare
sempre
che
il
file
sia
del
tipo
corretto
e
che
l’operazione
che
l’utente
vuole
eseguire
sia
consentita;
• se
si
usano
le
sessioni
di
PHP,
validare
sempre
la
sessione
corrente
tramite
token
o
autenticazione
utente.
global
$wpdb;
$reservation_id
= $_GET[‘res_id’];
$reservation
= $wpdb->get_results( “SELECT * FROM reservations WHERE id =
$reservation_id” );
Tendenzialmente la variabile GET potrebbe contenere qualsiasi valore ed è una porta spalancata per un tentativo di SQL
injection. Sappiamo che ci dobbiamo aspettare un valore numerico intero. Quindi come validazione preliminare e
grossolana potremmo scrivere:
$sane_res_id
= 0;
if( is_numeric( $reservation_id
) ) {
$r_id
= intval( $reservation_id
);
if( filter_var( $r_id, FILTER_VALIDATE_INT ) ) {
$sane_res_id
= $r_id;
}
}
Tale accorgimento è sufficiente ai fini della sicurezza? Assolutamente no. Quindi usiamo wpdb::prepare():
$title
= $_GET[‘title’];
echo
‘<h1>’ . $title
. ‘</h1>’;
Questo è un esempio tipico in cui può verificarsi un attacco di tipo XSS (Cross-site scripting), ossia l’inserimento nella
pagina di codice JavaScript malevolo. Per prevenirlo dobbiamo fare in modo che la stringa passata non contenga appunto
tale codice:
Qui abbiamo semplicemente combinato le funzioni di WordPress wp_kses() ed esc_html() per essere sicuri che la stringa
non contenga nessun tag HTML.
Abbiamo visto come i malintenzionati cerchino di eseguire il codice dei file da remoto. Per impedire questa pratica
possiamo utilizzare una costante PHP globale nei nostri plugin:
In questo modo il nostro codice potrà essere eseguito solo all’interno del contesto del plugin.
Una variabile GET contiene il nome di un file PDF da scaricare. I PDF nel nostro esempio sono stati uploadati tramite FTP
perché troppo pesanti per la Media Library. Nell’esempio abbiamo verificato che il nome del file sia valido in prima istanza.
Quindi abbiamo controllato che il file richiesto sia effettivamente un file PDF verificando il suo MIME Type. Se non
avessimo eseguito questa operazione, si sarebbe potuto scaricare qualsiasi tipo di file.
La verifica del MIME Type si rivela fondamentale anche nella gestione degli upload. In questo caso è inutile implementare
un sistema di upload personalizzato, sarebbe meglio invece cercare di utilizzare sempre la Media Library e le sue API per la
gestione degli allegati e dei file.
Ora, si ipotizzi il caso di un carrello per un e-commerce. Quando l’utente sceglie un prodotto, questo viene aggiunto
all’array superglobale $_SESSION. Ma come facciamo a sapere che sia sempre lo stesso utente ad effettuare tali
operazioni?
Alla fine della procedura d’acquisto la sessione dovrà essere distrutta e con essa il token di sessione.
Conclusione
Questa introduzione alla sicurezza dei plugin di WordPress è da ricollegarsi direttamente al tema più generale della
sicurezza in PHP. Essere a conoscenza dei rischi è il primo passo per evitarli.
Un aneddoto molto in voga che si racconta a proposito degli utenti finali è quello del “Press any key” e dell’avvertenza che
recita “Non esiste il tasto Any”. L’aneddoto vuole ricordare che non è possibile conoscere in anticipo il livello tecnico degli
utenti, quindi occorre adottare una strategia di tipo “difensivo”.
• i
nostri
utenti
potrebbero
avere
una
laurea
in
informatica
o
essere
degli
“analfabeti”
informatici;
• quello
che
per
noi
è
scontato
ed
intuitivo,
per
un
utente
potrebbe
essere
contorto
e
complesso;
• gli
utenti
vogliono
usare
il
plugin
da
subito.
Stiamo quindi parlando degli utenti reali e non di quelli “ideali”. Sulla base di tali osservazioni, quello che possiamo fare in
concreto è:
• creare
un’interfaccia
semplice
ed
intuitiva
basandosi
sull’approccio
“Less
is
more“;
• usare
delle
etichette
chiare
ed
autoesplicative;
• spiegare
brevemente
in
ogni
sezione
delle
opzioni
a
cosa
serve
quella
pagina;
• fornire
una
o
più
pagine
di
documentazione;
• fornire
una
o
più
pagine
con
le
risposte
alle
domande
frequenti
(FAQ);
• fornire
un
form
di
contatti
per
inoltrare
una
richiesta
di
supporto.
Molti plugin forniscono un pannello di controllo che non ha nulla a che fare con il backend di WordPress a livello di
interfaccia visuale. Questa scelta di design rende le cose più complicate per gli utenti perché essi vengono costretti ad
abituarsi di colpo a qualcosa di radicalmente diverso rispetto all’impostazione precedente. Per limitare l’insorgere di tali
problematiche è quindi consigliabile usare:
Quando “etichettiamo” una sezione o un elemento interattivo non dobbiamo lasciare spazio a dubbi: se una sezione contiene
i dettagli dell’account Twitter di un utente, la chiameremo “Impostazioni Twitter” e sui campi della sezione useremo
etichette come “Nome utente” e “Password”.
In altre parole dobbiamo sempre puntare alla massima chiarezza e descrittività possibile, quando generiamo dubbi creiamo
problemi per gli utilizzatori.
Spiegare, sempre!
“Cosa devo fare ora?” o “A cosa serve questo?” o anche “Dove mi trovo?” sono domande che si pongono spesso gli utenti.
Noi non dobbiamo lasciare che questi ultimi si pongano tali domande, dobbiamo invece anticiparle e fornire già le risposte.
Come? Usando brevi descrizioni nelle sezioni e nei componenti delle opzioni.
La documentazione di un plugin dovrebbe essere sempre divisa in due sezioni ben distinte: una per gli utenti ed una per gli
sviluppatori. Mai e poi mai dovremmo mischiare insieme le due cose. Ciò che è utile per un developer è spesso inutile (o
semplicemente troppo complicato) per un utente e ciò che è utile per un utente spesso è scontato per un developer.
Le FAQ sono un work in progress: queste vanno aggiornate man mano che riceviamo il feedback dagli utenti. Non
dovrebbero mai rimanere le stesse, ma andrebbero aggiornate man mano che gli utenti ci segnalano dubbi o problemi.
Il supporto è invece molto più complesso da gestire: la frase ricorrente “non funziona” può voler dire tutto e niente ed in
effetti non è di alcuna utilità per uno sviluppatore. Quindi nel form di supporto o sul forum di WordPress dovremmo
chiedere o raccogliere dati tecnici precisi come:
Solo avendo a disposizione questi dati possiamo realmente intervenire per aiutare gli utenti che ce ne fanno richiesta.
Funzionalità
Se creo un plugin per Twitter che pubblichi su Twitter i nuovi post dovrò avere almeno queste funzionalità che forniscano la
capacità di:
Visualizzare la timeline dell’utente, effettuare ricerche o altro sono caratteristiche utili ma non indispensabili al nostro
plugin: dobbiamo sempre attenerci allo scopo per cui esso è stato creato. Se gli utenti ce ne faranno richiesta, possiamo
certamente aggiungere nuove caratteristiche ma senza mai esagerare.
Un mito comune riguardante WordPress è quello secondo cui il codice sorgente di questo CMS sia interamente procedurale
nel suo design. Nulla di più falso: la scelta di design di WordPress è stata quella di costruire le fondamenta del CMS
usando le classi e di esporre i metodi e le proprietà di tali classi tramite funzioni e variabili globali. Ad esempio tutti noi
sappiamo che il Loop principale di WordPress – ossia il ciclo attraverso cui vengono reperiti i contenuti – può di solito
presentarsi come segue:
if( have_posts() ) {
while( have_posts() ) {
the_post();
}
}
Apparentemente tale codice è interamente procedurale, in realtà tutte le funzioni che abbiamo utilizzato non sono altro che
una scorciatoia per il seguente codice OOP:
Lo stesso concetto vale per le funzioni get_posts() e query_posts(), esse sono tutte basate sulla classe WP_Query; più
precisamente, tutto ciò che in WordPress ha a che fare con il Loop – ossia con il reperimento dei contenuti dal database
(post, pagine, allegati) – dipende direttamente da tale classe e non può in alcun modo prescindervi.
Ma non basta: anche la temporizzazione degli eventi, la gestione degli errori, delle richieste AJAX, delle query dirette al
database, degli utenti e dei loro ruoli, dei menu di navigazione, i widget e altro ancora, sono tutte funzionalità affidate alle
classi.
In definitiva, noi usiamo quasi sempre funzioni in WordPress, ma in realtà stiamo adottando le sue classi che restano
nascoste dietro le quinte.
Abbiamo detto che in WordPress le funzioni svolgono egregiamente il loro compito, quindi, per aggiungere una funzionalità
al tema utilizzato è solitamente sufficiente modificare il file “functions.php” (il nome è significativo) con il nostro codice e
ottenere così l’effetto desiderato. Se per esempio volessimo creare uno shortcode per visualizzare una citazione di blocco,
dovremmo semplicemente aggiungere il seguente codice:
Ma cosa succederebbe se avessimo più di uno shortcode da aggiungere? A livello di gestione e manutenibilità del codice ci
ritroveremmo con un file “functions.php” letteralmente traboccante di funzioni, per cui ogni volta che dovessimo modificare
una funzionalità saremmo costretti a ricordarci in quale funzione l’abbiamo definita. Si tratta di uno scenario davvero
difficile da gestire. Le classi ci permettono invece di raggruppare il codice in moduli separati, ciascuno con una propria
logica ed una propria struttura; quindi, per gli shortcode potremmo definire una classe apposita:
class
MyThemeShortcodes {
}
Al suo interno saranno i metodi della classe a definire le azioni legate a ciascuno shortcode:
class
MyThemeShortcodes {
public
function
__construct() {
add_shortcode( 'my-pullquote', array( &$this, 'createPullQuote'
) );
}
public
function
createPullQuote( $content
) {
return
'<blockquote class="pullquote">'
. $content
.
'</blockquote>';
}
}
$myThemeShortcodes
= new
MyThemeShortcodes();
Nel caso specifico l’istanza della classe richiama direttamente la funzione di WordPress add_shortcode() che crea lo
shortcode. Quindi in “functions.php” richiameremo i moduli desiderati:
Si potrebbe obiettare che questo tipo di classi in WordPress non sono altro che dei wrapper per metodi pubblici, ma in realtà
non è così; si supponga ad esempio di voler eliminare la marcatura aggiuntiva inserita da WordPress nel contenuto degli
shortcode:
Come si può notare, viene applicata la stessa distinzione alla base della logica OOP di PHP: un metodo privato opera
all’interno della sua classe di appartenenza secondo il principio dell’incapsulamento.
Il metodo è privato perché al di fuori della classe che gestisce gli shortcode non sarebbe di alcuna utilità. Infatti il problema
della marcatura extra è peculiare degli shortcode di WordPress. Lo stesso principio si applica alle proprietà di queste classi,
ad esempio potremmo volere che sia l’utente a scegliere di rimuovere la marcatura dagli shortcode o mantenerla:
class
MyThemeShortcodes {
public
$removeAutop
= false;
public
function
__construct() {
if(get_option('my-no-autop')) {
$this->removeAutop = (bool) get_option('my-no-autop');
}
//...
}
public
function
createPullQuote( $content
) {
if($this->removeAutop) {
// rimuove la marcatura
} else
{
// non la rimuove
}
}
}
In questo caso usiamo una proprietà pubblica in modo da poter comunicare lo status della classe alle altre classi che
andremo a definire, ossia la scelta di non intervenire sul contenuto degli shortcode.
Buone pratiche nella scrittura del codice in
WordPress
Nel precedente articolo abbiamo introdotto alcuni concetti fondamentali della programmazione OO in WordPress. In
questo articolo tratteremo invece delle convenzioni stilistiche per la scrittura del codice OO nel noto Blog engine.
Sebbene WordPress consenta di fatto la scrittura del nostro intero codice nel file functions.php di un tema o nel file
principale di un plugin, l’OOP prevede invece la creazione di una gerarchia di directory contenente i file delle nostre classi;
tale gerarchia va sempre creata al di sotto della directory principale del tema o del plugin. Una buona pratica è quella di
raggruppare insieme le classi che svolgono compiti analoghi. Ecco un esempio di questa gerarchia:
• /framework/
o /shortcodes/
o /post-‐types/
o /widgets/
o /theme-‐settings/
I nomi delle directory dovranno essere autoesplicativi nel senso che assegnare nomi abbreviati o quantomeno criptici alle
directory renderà la manutenzione futura molto più difficile, inoltre, se avete intenzione di rivendere il vostro lavoro sul
mercato, tenete presente che una struttura chiara delle directory vi eviterà spesso di dover rispondere alle classiche richieste
di supporto del tipo “dove trovo il codice X?”.
Per quanto riguarda invece i nomi delle classi, la pratica corrente è quella di creare un file PHP per ciascuna classe.
Solitamente la struttura del nome di questi file è così composta:
PrefissoTemaOPluginNomeClasse.php
Come si può notare viene utilizzata la notazione camel-case. Il prefisso del tema o del plugin viene preposto al nome della
classe allo scopo di creare sia un riferimento visivo alle classi sia un contesto di applicazione per esse. Se volete invece
creare un framework da riutilizzare su più temi o plugin, allora il prefisso sarà quello del vostro framework.
Se utilizzate lo standard Zend, allora il nome della classe avrà come primo componente il nome della directory seguito dal
nome della classe. Ciascuna parte del nome sarà separata da un underscore:
Prefisso_Directory_Nome_Classe.php
Una pratica comune in WordPress è quella di evitare che le classi interagiscano direttamente con i temi nel frontend, per
questo motivo vengono create delle funzioni ad hoc che potranno essere usate nel frontend semplicemente richiamando i
metodi delle classi.
Queste funzioni dovranno essere raggruppate in file specifici, come ad esempio frontend-funcs.php e quindi
richiamate nel loop principale di WordPress.
WordPress dispone di uno standard ben definito per la scrittura del codice PHP, questo standard, tuttavia, si applica per
quegli sviluppatori che intendono contribuire al Core del CMS. Ad un’attenta lettura, come del resto accade anche per molti
altri CMS, solo alcune di queste pratiche raccomandate trova un riscontro universale nell’ambito generale di PHP. Per
esempio l’uso delle virgolette è una pratica condivisa, mentre l’uso dei tab al posto degli spazi non lo è.
Sicuramente una pratica molto utile è la spaziatura intorno alle parentesi tonde dei blocchi. Quindi:
foreach($foo
as
$bar) {
...
}
è sconsigliato, mentre:
Lo stesso principio, secondo gli sviluppatori di WordPress, dovrebbe applicarsi anche ai nomi delle classi:
Tuttavia questa pratica non è universalmente accettata, quindi le seguenti alternative sono valide:
class
PrefixMyClass {
//...
}
class
Prefix_Dir_My_Class
{
// Zend
}
Per quanto riguarda i nomi dei metodi e delle proprietà si segue in genere la notazione camel-case, usando un underscore
come prefisso per i metodi e le proprietà con visibilità protected o private:
class
PrefixMyClass {
protected
$_testProperty;
private
function
_sampleMethod() { }
}
Una pratica assolutamente sconsigliata è quella che riguarda l’uso dell’operatore di scope su metodi non statici. Anche se in
PHP funziona ugualmente, tuttavia una pratica come:
class
PrefixMyClass {
public
function
method() { }
}
PrefixMyClass::method();
è errata perché dovrebbe essere utilizzata solo se il metodo di cui sopra fosse stato dichiarato come static.
I nomi delle costanti, sia quelle definite in modo globale sia quelle definite in una classe, andrebbero sempre in lettere
maiuscole, separate da un underscore:
class
PrefixMyClass {
const
MY_VALUE = 'OK';
}
Se i vostri file contengono soltanto codice PHP, allora potrete omettere il delimitatore PHP di chiusura, stando bene attenti
che il vostro file non contenga spazi alla fine. Questa pratica ci permette di evitare il tristemente noto errore Headers
already sent quando includiamo il nostro codice nel flusso di WordPress.
Conclusioni
In questo articolo abbiamo definito alcune semplici linee guida da seguire nella scrittura e nella gestione del nostro codice
OO in WordPress, tali linee guida si riveleranno fondamentali quando dovremo affrontare progetti complessi. Nella
prossima lezione presenteremo un’introduzione alla programmazione per oggetti nei plugin di WordPress
Il celebre plugin multilingua WPML a prima vista potrebbe sembrare come un’implementazione monolitica che lascia ben
poco spazio all’interazione con il codice esterno dei temi.
In realtà questo plugin, come altri, dispone di API specifiche che permettono agli autori di temi di poter interagire con esso,
ad esempio creando un selettore di lingua personalizzato o ottenendo la traduzione di alcune stringhe.
Se osserviamo la pagina dedicata alle API di WPML noteremo che tali interfacce sono state implementate usando due
tecniche già utilizzate da WordPress, ossia:
1. action
personalizzate;
2. funzioni
globali;
3. costanti.
WPML adotta lo stesso approccio di WordPress nella gestione del codice: l’OOP viene usato per gestire tramite classi il
funzionamento core del plugin ma non deve essere direttamente invocato nei temi. Al contrario i temi dovranno utilizzare le
API pubbliche, ossia le action e le funzioni globali.
Vediamo ora come implementare le nostre API partendo dalle basi, ossia dalle funzioni.
Le funzioni
Le funzioni possono avere o non avere argomenti. Usare funzioni senza argomenti può avere senso se stiamo inserendo del
contenuto che non necessita di essere modificato, ma se vogliamo permettere agli autori di temi di gestire il nostro codice
con maggiore facilità, allora creare funzioni con argomenti è la scelta consigliata.
Ipotizziamo di avere implementato un plugin che gestisce degli slideshow tramite custom post type e tassonomie. Nella
nostra classe core avremo:
class
My_Slideshow {
//...
public
function
render( $slideshow
) {
$args
= array(
'post_type'
=> 'slides',
'slideshow'
=> $slideshow,
'posts_per_page'
=> -1
);
$loop
= new
WP_Query( $args
);
if( $loop->have_posts() ) {
// Crea lo slideshow
}
}
}
$mySlideshow
= new
My_Slideshow();
Possiamo creare una funzione specifica globale che, dato lo slug di una tassonomia, visualizzi uno slideshow specifico nel
tema:
Quindi un autore potrà usare la nostra funzione nel modo seguente all’interno del suo tema:
Quella che abbiamo appena creato è una funzione che agisce direttamente sul tema modificandolo. Possiamo anche creare
funzioni che restituiscano un valore impostato nel plugin, ad esempio attraverso le sue opzioni o i suoi custom field
(funzioni getter):
function
my_slideshow_get_animation_type() {
$type
= get_option( 'my_slideshow_animation_type'
);
return
$type;
}
In questo caso l’autore del tema potrà usare il valore restituito per gestire alcune scelte a livello di codice CSS o JavaScript:
$anim_type
= my_slideshow_get_animation_type();
if( $anim_type
== 'fade'
):
// Codice
else:
// Codice
endif;
Le costanti
Il nostro plugin può anche operare tenendo presente le preferenze espresse dall’autore del tema sotto forma di costanti PHP
definite nel file functions.php del tema. Dato che le costanti PHP sono immutabili e non possono essere ridefinite,
pena un “errore fatale”, dobbiamo prima verificare che l’autore del tema le abbia dichiarate:
In questo caso se la costante MY_SLIDESHOW_NO_PLUGIN_CSS è stata impostata su true non andremo a caricare i
nostri stili CSS ma lasceremo all’autore il compito di definire il layout dello slideshow.
Le action
1. add_action();
2. do_action().
Leggendo la documentazione appare chiaro il motivo per cui abbiamo affrontato le funzioni come primo argomento di
questo capitolo: le action personalizzate non sono altro che funzioni che vengono registrate in WordPress tramite
add_action() e che poi possono essere eseguite nei temi con la funzione do_action().
Ritornando all’esempio della nostra funzione che visualizza uno slideshow, possiamo quindi ridefinirla come action:
La funzione accetta come sappiamo un argomento che però verrà delegato alla funzione do_action():
In questo modo l’autore del tema ha a disposizione uno strumento ancora più flessibile per interagire con il nostro plugin.
WordPress opera una distinzione tra il codice lato client inserito nel backend e quello inserito nel frontend, ossia nella
sezione amministrativa e nel sito. Sono quindi presenti due action distinte:
1. admin_enqueue_scripts
2. wp_enqueue_scripts
La prima action è per il backend, la seconda per il frontend. Anche se i loro nomi potrebbero trarre in inganno, queste due
action servono per includere i file JavaScript e CSS, come nell’esempio seguente:
function
add_js() {
wp_register_script( ‘my’, plugins_url() . ‘/plugin/js/my.js’ );
wp_enqueue_script( ‘my’ );
}
add_action( ‘wp_enqueue_scripts’, ‘add_js’ );
1. wp_register_script()
2. wp_enqueue_script()
3. wp_register_style()
4. wp_enqueue_style()
5. wp_script_is()
6. wp_style_is()
Per gli autori di plugin, anche se può sembrare strano, le funzioni più importanti per scrivere plugin flessibili sono le ultime
due: servono infatti a verificare che uno script o un file CSS non sia già stato incluso. A questo proposito immaginiamo il
caso in cui un tema usi il framework JavaScript jQuery, scenario molto comune. Il seguente codice ci eviterà di
compromettere il frontend:
WordPress dispone di molti script preinstallati, tra cui il già citato jQuery; in questo caso, dato che il nostro plugin usa
jQuery, prima di includerlo dobbiamo verificare che non sia già presente.
Se non avessimo effettuato questa verifica avremmo avuto due copie di jQuery sullo stesso sito, il che avrebbe generato
errori fatali a cascata. Lo stesso principio si applica per i file CSS.
WordPress, specialmente con jQuery, spinge gli autori ad usare un namespace per il proprio codice JavaScript; a tal
proposito avrete sicuramente osservato questo modo di usare jQuery in WordPress:
(function( $ ) {
// codice
})( jQuery );
jQuery
.
In
questo
modo
possiamo
usare
jQuery
direttamente
con
il
suo
alias.
In JavaScript quando usiamo questo pattern creiamo una sandbox in cui il nostro sorgente può sì operare sulle pagine ma
resta isolato dal resto del codice JavaScript presente nel sito Web.
Questo fattore è fondamentale, dato che noi non possiamo sapere se i nomi delle nostre variabili, delle funzioni e degli
oggetti siano stati già usati da qualche altro script, in un plugin o dal tema.
A differenza di PHP, JavaScript non interrompe l’esecuzione del codice se una variabile viene ad esempio ridefinita. Molto
semplicemente, la variabile creata dopo la prima ne sovrascrive il valore. La stessa cosa, purtroppo, vale anche per le
funzioni e per gli oggetti.
Oltre che con la sandbox che abbiamo già analizzato, possiamo rafforzare ulteriormente il nostro codice usando un prefisso
da usare con funzioni e oggetti. Un altro accorgimento fondamentale è quello di evitare ad ogni costo le variabili globali ed
affidarci invece al contesto (scope) creato dal nostro codice.
Il principio della creazione di un namespace per il nostro codice si applica anche ai CSS con una fondamentale differenza:
nei CSS i prefissi sono l’unico sistema. Possiamo aggiungere un prefisso ai selettori di classe e di ID in questo modo:
#mioplugin-container { … }
.mioplugin-item { … }
mioplugin è il nostro prefisso che non solo ci mette al riparo da possibili conflitti, ma permette anche agli autori ed agli
utenti di modificare i nostri stili con maggiore facilità.
Una volta creato un namespace possiamo sfruttare il contesto creato dai selettori per definire regole più specifiche:
#mioplugin-container .mioplugin-item a { … }
Sfruttando la cascata possiamo indirizzare le nostre regole con maggiore precisione. Se vi state chiedendo come altri utenti
possano sfruttare il nostro namespace creato dai prefissi, ecco un esempio:
[class^=“mioplugin”] * {
font-family: Arial, sans-serif
!important;
}
In questo caso gli utenti possono effettuare un reset globale sui nostri elementi senza dover conoscere necessariamente il
nome dell’elemento. Un notevole vantaggio.
API
Le API (Application Programming Interface) di WordPress si suddividono in diverse sezioni. Ogni sezione comprende in
genere due tipi di argomenti associati:
1. classi
2. funzioni
Le classi sono una scelta obbligatoria solo in alcuni casi, perché il principio chiave di WordPress è quello di permettere agli
autori di temi e plugin di utilizzare le funzioni. Tutte le funzioni di WordPress fanno riferimento ad una classe del Core. Di
fatto le funzioni nascondono la logica della classe secondo il principio della modularità. Quando si usa una funzione
bisogna leggere nella documentazione tre parti fondamentali:
1. parametri
2. valori
di
ritorno
3. casi
d’uso
WordPress in genere usa gli array associativi per assegnare alle funzioni dei parametri predefiniti. A differenza del
tradizionale modo con cui i parametri predefiniti vengono passati alle funzioni in PHP, in questo caso l’ordine dei parametri
non è rilevante. Al contrario, se la funzione utilizza il modo tradizionale di passare gli argomenti, in questo caso invece
l’ordine dei parametri è rilevante.
Ciò a cui bisogna prestare un’attenzione particolare sono i valori di ritorno. Questi ultimi si differenziano a seconda che la
funzione restituisca il valore atteso o meno. Se la funzione ha successo, WordPress restituirà un valore (ad esempio un array
di oggetti), altrimenti può restituire un tipo di dati PHP (false, null ecc.) oppure un’istanza della classe WP_Error. Ad
esempio, prendiamo la funzione wp_remote_get():
$attachment_id
= 8;
$image
= wp_get_attachment_image_src( $attachment_id
);
if( $image
) {
// Successo!
}
Questa funzione restituisce un array, quindi in questo caso la verifica da effettuare è diversa. Si consiglia quindi di leggere
sempre con attenzione gli esempi forniti nella documentazione. Si tratta di codice che illustra perfettamente i casi d’uso
delle funzioni o delle classi trattate.
Filtri e hook
1. action
2. filtri
Le action vengono invocate durante un evento di WordPress, mentre i filtri servono a modificare l’output restituito dai
componenti dell’applicazione.
Questi hook hanno bisogno di una funzione o di un metodo di una classe che andremo a definire per poter operare. La
differenza tra i due sta nel fatto che un filtro ha bisogno di un input da modificare, mentre una action non presenta questa
necessità.
Ad esempio, se dovessimo applicare un nofollow a tutti i link di un post, dovremmo modificare l’output della funzione
the_content(). Il filtro corrispondente si chiama appunto the_content, quindi scriveremo:
La nostra funzione in questo caso accetta un solo parametro, ossia il contenuto del post. Bisogna sempre leggere sulla
documentazione delle API quali parametri sono richiesti dalla funzione usata come filtro. Attenzione: se non usiamo i
parametri nel modo e nell’ordine corretto verrà restituito un errore. E molto spesso è solo un parametro quello che andremo
a modificare.
Le action, al contrario dei filtri, eseguono semplicemente del codice durante un evento di WordPress. Ad esempio, se
volessimo inserire il codice di Google Analytics nella sezione dei nostri documenti, dovremo usare l’action wp_head che è
direttamente collegata alla funzione wp_head(). Quindi scriveremo:
function
add_ga() {
$ga_code
= ‘codice Analytics';
echo
$ga_code;
}
add_action( ‘wp_head', ‘add_ga'
);
WordPress aggiunge il nostro codice alla serie di routine da eseguire in modo seriale e semplicemente lo esegue. Quello che
i filtri e le action hanno in comune, oltre al modo di associarli, è che possiamo spostare il sorgente avanti o indietro nella
coda di esecuzione di WordPress.
La documentazione:
• add_filter()
• add_action()
Lower
numbers
correspond
with
earlier
execution,
and
functions
with
the
same
priority
are
executed
in
the
order
in
which
they
were
added(…).
I numeri con un basso valore vengono eseguiti prima e le funzioni con la stessa priorità vengono eseguite nell’ordine in cui
sono state aggiunte.
Quindi, tornando al nostro filtro sul contenuto dei post, possiamo coordinare più routine in sequenza. La funzione che
avevamo definito viene eseguita con priorità 10, motivo per il quale se volessimo eseguire un’altra routine prima di questa:
avremo che in questo caso la priorità è 5, quindi tale routine viene eseguita prima dell’altra. Come si può notare, leggere la
documentazione è il modo migliore di lavorare con WordPress.
Per descrivere il nostro progetto si può cominciare dal sito ufficiale per gli sviluppatori di Twitter. Quello che bisogna
capire da subito è che le API di Twitter funzionano solo tramite autenticazione. Occorre infatti creare un’app e ottenere
così le credenziali di accesso per poter usare le API (sezione “Keys and Access Tokens” di ogni app).
Un’app può avere diversi permessi: lettura, scrittura o entrambi. Un’app in sola lettura potrà leggere i tweet di un utente,
effettuare ricerche, visualizzare i trend del giorno ma non postare un tweet mentre, al contrario, un’app con permessi di
scrittura potrà effettuare anche quest’ultima operazione.
Ovviamente la pubblicazione dei tweet potrà avvenire unicamente tramite l’account Twitter che possiede l’app creata
attraverso di esso. Per gli esempi mostrati in questo capitolo sarà sufficiente un’app in sola lettura.
L’approccio migliore per lavorare con le API è quello di utilizzare una libreria PHP esistente che andrà poi ad integrare
nella nostra implementazione.
Per Twitter possiamo usare la libreria TwitterOauth di Ricardo Pereira. Questa libreria supporta sia il metodo GET che
POST, quindi è adatta sia per app in lettura che in scrittura.
Per reperire i tweet di un account Twitter dobbiamo utilizzare l’endpoint statuses/user_timeline delle API.
Creiamo una classe per questo scopo e per prima cosa includiamo la libreria TwitterOauth:
class
My_Twitter {
private
$_connection;
public
function
__construct() {
$settings
= array(
'oauth_token'
=> 'tuotoken',
'oauth_token_secret'
=> 'tuotokensecret',
'consumer_key'
=> 'tuaconsumerkey',
'consumer_secret'
=> 'tuoconsumersecret',
'output_format'
=> 'text'
);
$this->_connection = new
TwitterOauth( $settings
);
}
//…
}
Ora la proprietà privata _connection contiene un’istanza della classe TwitterOauth. A questo punto ci servono due
metodi privati per altrettanti compiti specifici:
Ora dobbiamo definire il metodo principale, stavolta pubblico, per reperire i tweet utilizzando il metodo
TwitterOauth::get():
Seguendo il design di WordPress, concluderemo la nostra implementazione definendo una funzione che utilizzerà la classe
appena creata, impedendo così che una classe venga usata direttamente.
C’è un potenziale problema di performance nel nostro codice: troppe richieste GET potrebbero rappresentare un bottleneck
per un sito. Fortunatamente WordPress dispone delle Transients API che ci permettono di creare un sistema di caching di
durata personalizzabile. Quindi scriveremo:
Nel caso specifico dell’esempio proposto il codice metterà in cache per 5 minuti i risultati ottenuti da Twitter, solo dopo
questo intervallo di tempo verrà effettuata nuovamente una richiesta GET.
Un Web service funziona mediante un’architettura client-server. L’utente effettua una richiesta lato client e il server remoto
esegue un’azione restituendo solitamente un output che informa sull’esito dell’azione oppure fornisce dei dati che sono stati
richiesti.
Solitamente i metodi HTTP utilizzati in questi casi sono GET e POST. Un Web service può anche scegliere di far eseguire
le sue azioni solo tramite POST se il suo design è concepito in tale modo.
Per esempio, per inserire un file su Amazon S3 effettueremo una richiesta e il Web service ci comunicherà se il
trasferimento ha avuto successo. Come avviene tutto questo? Tramite le API, interfacce per la programmazione messe a
disposizione dal Web service di cui dovremmo studiare esempi e documentazione ed eventualmente scaricare un SDK per
lo sviluppo in PHP.
Quando si usa un Software Development Kit occorre verificare la compatibilità con la versione di PHP in uso sul server,
infatti, alcune feature potrebbero funzionare solo da una determinata versione del linguaggio in poi, come accade per i
namespace introdotti soltanto con la release 5.3 di PHP.
Usare le API di Amazon per reperire informazioni sui prodotti
Possiamo usare le API AWS (Amazon Advertising API) per reperire informazioni relative ai prodotti presenti nel catalogo
del noto sito Web per il commercio elettronico; per far questo occorrono però le credenziali di accesso alle API.
Quindi, per prima cosa definiamo una funzione per effettuare la richiesta. Ci serviranno anche i dati relativi al codice ASIN
(Amazon Standard Identification Number) del prodotto e alla regione di riferimento.
Amazon restituisce una risposta in formato XML, dobbiamo quindi effettuare il parsing del documento XML restituito:
Abbiamo così ottenuto il titolo del prodotto, l’URL della sua pagina, l’URL della sua immagine, il prezzo, la valuta e la
quantità; la funzione scritta potrà essere utilizzata in questo modo:
Lo scopo di ACF, che è possibile scaricare ed installare facilmente con la procedura standard adottata della stragrande
maggioranza dei plugin, è quella di rendere disponibile un’interfaccia grafica chiara e flessibile nel backend del CMS per
gestire campi personalizzati per tutte le tipologie di custom post type, di tassonomie, di file multimediali e di utenti.
Una
volta
scaricato
ed
attivato,
il
plugin
(in
gran
parte
tradotto
in
italiano)
inserisce
una
nuova
voce
nel
menu
amministrativo
che
comprende
la
pagina
per
la
gestione
dei
campi,
una
pagina
dedicata
all’esportazione
e
un’altra
per
l’installazione
dei
componenti
aggiuntivi.
Creare i campi
Creare un nuovo campo è molto semplice: i campi sono raccolti per gruppi che si creano tramite la familiare interfaccia di
WordPress. Creato un gruppo, al suo interno possono essere inseriti tutti i campi desiderati. La reale forza del plugin risulta
evidente proprio in questa fase: le tipologie di campo disponibili sono molte, dalle più semplici come i campi di testo, ai
campi con validazione per numeri e indirizzi email, fino a elementi con GUI più complesse quali caricamento di immagini,
relazione fra post type tramite AJAX, date picker e color picker.
Ad esempio, per l’inserimento di un menu a tendina dovremo elencare le coppie valore/etichetta e il valore di default; per
campi di relazione dovremo specificare quale tipologia di elemento deve essere possibile relazionare, mentre per le
immagini dovremo specificare la grandezza delle anteprime e, soprattutto, se desideriamo come valore restituito la ID
dell’immagine, la sua URL o un oggetto PHP con le sue proprietà.
Il secondo passo è quello di indicare a quali tipologie di oggetti di WordPress va allegato questo gruppo di campi. È
possibile combinare più regole che indicano il post type, le pagine (anche per un singolo template), il ruolo dell’utente, il
tipo di tassonomia, o i media files. Questo semplifica di molto il lavoro dello sviluppatore, che non dovrà più preoccuparsi
di inserire tutto il codice necessario per aggiungere i campi per ciascuna delle diverse tipologie di contenuti.
La parte amministrativa dei campi può essere personalizzata facilmente stabilendone l’ordine con un immediato drag and
drop e raggruppandoli tramite un capo specifico denominato tab. Nel backend verrano inclusi tutti i campi con i relativi file
JavaScript e CSS necessari alla loro GUI.
In questo esempio abbiamo creato 7 campi, di cui due in realtà semplici tab che non restituiscono un valore, ma che aiutano
a personalizzare l’area amministrativa.
Fino a questo punto il plugin è utilizzabile via interfaccia grafica, ma per richiamare in un tema i valori dei campi
personalizzati, a meno di non appoggiarsi ad altri plugin, dobbiamo lavorare sul codice.
L’esempio base è molto semplice: i due metodi fondamentali sono the_field() e get_field(). Il primo stampa a
schermo il valore del campo, il secondo lo legge e lo rende disponibile per successive elaborazioni. La sintassi è la
seguente:
<?php
if( get_field( "nome_campo"
) ) { ?>
<p><?php the_field( "nome_campo"
); ?></p>
<?php } ?>
Nella prima riga controlliamo l’esistenza del campo e che il valore non sia nullo, nella seconda riga lo stampiamo a
schermo. Per entrambi i metodi l’unico parametro obbligatorio è lo slug del campo; se siamo all’interno di un loop di
WordPress il metodo si riferirà automaticamente al post che viene elaborato, diversamente possiamo passare come secondo
parametro l’id del post che ci interessa, oppure della tassonomia o dell’utente tramite le diciture: category_1 e user_1,
dove nella prima parte della stringa indichiamo lo slug della tassonomia (o “user” per gli utenti) e subito dopo l’underscore
l’id vero e proprio.
Nel caso delle immagini o dei file caricati, il codice cambia a seconda dell’opzione da noi selezionata sul valore restituito.
Sicuramente scegliere l’oggetto PHP ci dà una maggiore flessibilità. Ecco un esempio:
<?php
$immagine
= get_field('immagine');
/*La variabile immagine ha questo valore:
Array
(
[id] => 540
[alt] => Testo alternativo
[title] => Titolo dell’immagine
=> Didascalia dell’immagine
[description] => Descrizione dell’immagine
[url] => http://localhost:8888/acf/wp-
content/uploads/2013/09/imm.jpg
[sizes] => Array
(
[thumbnail] => http://localhost:8888/acf/wp-
content/uploads/2013/09/imm-150x150.jpg
[medium] => http://localhost:8888/acf/wp-
content/uploads/2013/09/imm-300x119.jpg
[large] => http://localhost:8888/acf/wp-
content/uploads/2013/09/imm.jpg
)
)
Stampa dell’immagine alla dimensione "large" */
?>
<img src="<?php echo $immagine['sizes']['large']; ?>"
alt="<?php echo
$immagine['alt']; ?>"
/>
In tutti quei campi nei quali sono previsti più valori viene restituito un array. Nel caso si tratti del tipo di campo di tipo
“relazione” si posso ottenere come valori di ritorno gli id dei post, oppure direttamente dei post object che possono
inizializzare la funzione setup_postdata() per generare dei loop, come in questo esempio, nel quale viene creato un elenco di
post con permalink e titolo.
<?php
$post_objects
= get_field('relazione');
if( $post_objects
): ?
<ul>
<?php foreach( $post_objects
as
$post): /*La variabile deve essere chiamata
$post */
?>
<?php setup_postdata($post); ?>
<li>
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
</li>
<?php endforeach; ?>
</ul>
<?php wp_reset_postdata(); /*Questo reset è obbligatorio per la corretta
esecuzione dei loop successivi */
?>
<?php endif; ?>
Con queste operazioni di base si possono ottenere rapidamente interfacce complesse dotate di funzionalità decisamente più
avanzate di un’installazione standard di WordPress, ma ACF può offrire molto di più.
Dal punto di vista dello sviluppo il componente offre numerosi hook e filter e dà la possibilità agli sviluppatori di creare i
propri campi aggiuntivi che possono essere installati come normali plugin di WordPress. Campi per form, per mappe, per
orari e per sistemi di pagamento sono solo alcuni esempi presentati nel sito ufficiale, dal quale si possono anche acquistare
componenti aggiuntivi a pagamento (con licenza multisite) per le gallerie di immagini, pagine di impostazioni
personalizzate, campi ripetibili e layout personalizzabili. Lo sviluppatore mette a disposizione su GitHub un template di
partenza per costruire i propri campi.
Allo stesso tempo avere a disposizione le API del componente rende possibile costruire un form con i campi personalizzati,
comprensivi di interfaccia utente, anche nel frontend, come mostra questo template:
<?php
/**
* Template Name: Pagina con form per campi personalizzati
* Un page template personalizzato con i campi creati da ACF
*/
acf_form_head(); /* Questa funzione include tutti i file CSS e JavaScript necessari
all’interfaccia dei campi personalizzati. Deve essere inclusa prima di
get_header(). */
get_header();
?>
<?php the_post(); ?>
<?php
//Opzioni per l’inclusione del form
$options
= array(
'post_id'
=> $post->ID, /* post id del post type cui sono assegnati i
campi*/
'field_groups'
=> array(), /* id del gruppo di campi. Se vuoto inserirà
tutti quelli realivi a quel post id*/
'form'
=> true, // Aggunge il tag "form"
'form_attributes'
=> array( // Attributi del form
'id'
=> 'post',
'class'
=> '',
'action'
=> '',
'method'
=> 'post',
),
'return'
=> add_query_arg( 'updated', 'true', get_permalink() ), /* url di
ritorno. L'argomento "updated" fa visualizzare il messaggio di conferma*/
'html_before_fields'
=> '', /* html da inserire prima dei campi*/
'html_after_fields'
=> '', /* html da inserire dopo i campi */
'submit_value'
=> 'Aggiorna', /* valore del pulsante di submit */
'updated_message'
=> 'Post aggiornato.', /* Messaggio di conferma */
); ?
<?php acf_form( $options
); // Questa è la funzione che genera il form ?>
<?php get_sidebar(); ?>
<?php get_footer(); ?>
In sintesi, la funzione acf_form() genera il form con tutti i campi compresi nel gruppo specificato tramite il suo id (ogni
gruppo di campi è in realtà un custom post type); è suffciente che nella head della pagina siano stati caricati tutti i file
necessari tramite la funzione acf_form_head().
Conclusioni
Sicuramente Advanced Custom Fields, è uno degli strumenti più completi per la gestione dei campi personalizzati in
WordPress e può rendere molto più rapido lo sviluppo in tutti quei casi nei quali è prevista l’implementazione di diversi
campi personalizzati anche complessi, che da soli richiederebbero una programmazione aggiuntiva piuttosto impegnativa
per la gestione dell’ di interfaccia utente.
Creare un sito WordPress multilingua permette di ampliare la tua attività, di attirare un volume di traffico decisamente
più corpulento e naturalmente di aumentare i guadagni. Che si tratti di un sito vetrina o di un ecommerce i vantaggi sono
tantissimi.
Per farla breve: si tratta di una scelta con un potenziale inimmaginabile che potrebbe aprire nuove porte al tuo
business. Grazie ad un sito WordPress multilingua puoi cominciare a ricevere traffico in diverse lingue e da diversi paesi
del mondo e riuscire così ad aumentare le tue vendite ed i tuoi guadagni online.
Abbiamo capito che creare e gestire uno spazio online multilingua su WordPress è un’ottima idea, ma come succede sempre
in questi casi, dopo il primo entusiasmo subentra il panico da “e ora da dove comincio?”.
Di seguito puoi leggere la mia guida dettagliata. Sono circa 5000 parole, quindi preparati perché abbiamo un bel po di cose
da vedere.
WPML è il plugin WordPress multilingua che ti aiuta a creare un sito web traducibile in diverse lingue. Più
precisamente, permette di generare copie delle pagine, degli articoli, dei menu e di tutti gli altri contenuti testuali del tuo sito
web in altre lingue a tua scelta. E non si ferma qui. WPML offre anche un ampio ventaglio di impostazioni di
configurazione per decidere come visualizzare le opzioni di lingua sul sito web interessato.
Quello che lo rende davvero raccomandabile è la sua straordinaria compatibilità con WordPress e tutto ciò che ruota
attorno a questa piattaforma: dai temi agli altri plugin. Non per niente WPML è generalmente considerato lo standard per
creare siti web WordPress multilingua.
Sebbene WPML renda questo processo decisamente più semplice rispetto ad altre strade, un aiuto extra non fa mai male,
soprattutto perché non tutto il manuale di WPML è disponibile in italiano (ironico, lo so). Ecco perché ti spiegherò passo
per passo come fare a installarlo e ad utilizzarlo per rendere il tuo sito multilingua.
L’obiettivo di questa guida è rendere il più chiaro possibile come creare e gestire un sito web multilingua su WordPress con
WPML. Non vogliamo dunque fare di tutta l’erba un fascio. Per questo e per tua comodità, analizzeremo separatamente
come creare un sito vetrina multilingua e come creare un ecommerce multilingua usando WPML.
Per creare una piattaforma multilingua su WordPress la prima cosa da fare è installare WPML come un normalissimo
plugin. Ciò significa che devi andare sulla pagina dei plugin di WordPress, scaricare e avviare l’installazione di WPML.
Come avrai notato WPML è un plugin a pagamento e ha un prezzo che varia a seconda delle opzioni e della durata del
contratto. In particolare puoi acquistare tre pacchetti di WPML:
• 29
$
licenza
per
un
anno
e
siti
illimitati:
è
l’offerta
studiata
per
i
blog
multilingua.
• 79
$
licenza
per
un
anno
e
siti
illimitati:
per
creare
uno
sito
web
multilingua,
ovvero
con
la
possibilità
di
tradurre
anche
temi
e
plugin
(quello
che
interessa
a
noi).
• 195
$
per
sempre
e
siti
illimitati:
in
questo
modo
non
dovrai
più
preoccuparti
del
rinnovamento.
Fidati: di tutti i plugin e le funzionalità per il tuo sito web che puoi trovare free, la funzione multilingua è l’ultima su cui
puoi fare economia. Non solo perché quelli di WPML sono soldi ben spesi, ma anche (e soprattutto) perché quando devi
creare un sito multilingua su WordPress la qualità è fondamentale. Pensa a che disastro succederebbe nel caso che le
traduzioni dei tuoi testi e dei tuoi menu fossero sbagliate o imprecise.
Configurare WPML e scegliere le lingue in cui tradurre il tuo sito web
Una volta scaricato e installato il plugin, nella tua bacheca di WordPress clicca a sinistra su WPML per entrare nel Setup
(ovvero le impostazioni generali del plugin).
Innanzitutto è necessario impostare la lingua sorgente del tuo sito web, ovvero la lingua in cui sono scritti attualmente i
tuoi contenuti. Nel tuo caso verosimilmente sarà Italiano, ma puoi decidere in ogni momento di aggiungere o togliere una
lingua, o invertire il loro ordine.
Nella pagina successiva trovi un elenco di lingue “flaggabili” tra cui scegliere. Si tratta del cuore del plugin, ovvero, dove
succede tutta la “magia” della traduzione istantanea dei tuoi contenuti. Qui devi selezionare le lingue in cui hai intenzione di
tradurre i testi, ovvero le altre lingue in cui il tuo sito web sarà leggibile e visualizzabile.
La scelta è vastissima e puoi optare per le lingue più disparate, dal cinese allo spagnolo. Questo è un altro punto di forza di
WPML quando si tratta di creare un ambiente web multilingua su WordPress.
L’ultima pagina delle impostazioni permette di gestire le funzionalità di WPML. Puoi scegliere:
• l’ordine
delle
lingue
scelte,
che
funziona
con
un
semplice
drag
and
drop.
• in
che
modo
organizzare
le
opzioni
di
lingua
tra
menu
a
tendina,
pulsante
classico
o
elenco.
Per
aiutarti
a
scegliere
è
persino
disponibile
un’anteprima
sulla
destra.
• come
visualizzare
le
lingue
(bandiera
o
parola).
• qui
ti
è
data
la
possibilità
di
decidere
anche
come
WPML
deve
comportarsi
con
le
pagine
o
i
contenuti
che
non
può
tradurre.
Quando hai finito di scegliere e sistemare le voci delle impostazioni che ti interessano, salva.
Adesso nella bacheca, sotto la voce WPML appaiono nuove voci. Tra le nuove impostazioni più importanti, puoi per
esempio scegliere il formato URL delle pagine tradotte.
Iniziamo a vedere come creare un sito vetrina multilingua con WPML. Così tutti i tuoi contenuti saranno disponibili
anche in altre lingue, risultando comprensibili – e invitanti – anche per gli utenti stranieri.
Con sito vetrina si intende un normale portale web costituito da pagine, contenuti testuali, immagini e video. Per esempio, il
sito web di un’azienda, con la classica gerarchia pagine del “chi siamo”, “prodotti”, “blog” e “contatti”.
Il tuo sito vetrina può contenere dei plugin e widget, ma non la funzione ecommerce. Come già anticipato, questo è un caso
a parte che merita di essere analizzato più avanti.
Riprendiamo da dove avevamo lasciato, ovvero dalla configurazione di WPML. Una volta confermate le impostazioni,
possiamo iniziare a creare una piattaforma web multilingua su WordPress.
Partiamo dal contenuto vero e proprio: gli articoli. Clicca su Articoli dalla tua bacheca WordPress.
Noterai che adesso appare un nuovo menu in alto che mostra le lingue che hai scelto nelle impostazioni di WPML. Non
solo, per ogni opzione indica gli articoli pubblicati in ciascuna delle lingue scelte nelle impostazioni, come in questa
immagine sotto:
Cliccando su ogni lingua appare l’elenco dei post tradotti. Lateralmente ai titoli compare una nuova colonna, con una
bandiera in cima e delle icone di un più. La bandiera indica quella che hai scelto come prima lingua straniera di default. Il
simbolo “+” serve per creare la copia di ciascun articolo direttamente nella lingua di default (appunto quella indicata dalla
bandiera). Ma vediamo nel dettaglio come.
Per tradurre un articolo di WordPress in un’altra lingua con WPML ci sono due modi.
1. Se
vuoi
creare
una
copia
dell’articolo
nella
lingua
impostata
come
default
clicca
sul
più
(+).
A
questo
punto
si
aprirà
una
pagina
in
cui
puoi
inserire
manualmente
il
contenuto
tradotto.
Puoi
anche
scegliere
di
duplicare
quello
già
esistente
nella
lingua
sorgente,
così
da
poter
conservare
elementi
come
immagini
e
video,
sovrascrivendo
solo
la
parte
testuale.
2. Altrimenti,
modifica
l’articolo
desiderato.
Sulla
destra
puoi
scegliere
in
che
lingua
tradurre
l’articolo
e
decidere
se
duplicare
il
contenuto
della
lingua
originaria
(vedi
sopra).
Fatto questo, nel menu degli articoli vedrai l’icona di una matita dove prima c’era il più. Questo indica quali articoli sono
stati già tradotti.
Il procedimento per creare delle pagine multilingua su WordPress è pressoché lo stesso usato per gli articoli. Anche in
questo caso possiamo cliccare sull’icona del “+” oppure su Modifica.
Importante: nel pannello di modifica noterai come l’URL della pagina è diverso a seconda della lingua, di cui contiene la
sigla. Per modificare il formato URL delle pagine multilingua basta andare nelle impostazioni Lingue di WPML dalla
bacheca, come spiegato precedentemente.
Senza saperlo sei già riuscito ad ottenere un sito tradotto con WPML, almeno parzialmente.
Visualizza il tuo sito web per renderti conto di quanto fatto. Nelle pagine che hai tradotto puoi vedere il menu con le lingue
disponibili tra cui scegliere per visionare la rispettiva pagina appena creata.
Cliccando invece su un articolo, alla fine del testo viene segnalato automaticamente in quali altre lingue tale contenuto è
disponibile, con la possibilità anche in questo caso di cliccare su quella desiderata.
Scegliendo una lingua dall’elenco, il sito web cambia automaticamente, caricando le copie multilingue che hai creato, sia
delle pagine che degli articoli.
Infine, noterai che alcuni elementi della pagina sono stati tradotti automaticamente nella lingua selezionata, come ad
esempio le categorie e il nome stesso delle lingue.
Tradurre il menu di un sito web WordPress con WPML
Quello che invece non è cambiato pur selezionando un’altra lingua è il menu di navigazione. Non preoccuparti, è normale.
Infatti per creare un menu di navigazione multilingua occorre seguire un procedimento a sé. Vediamo come.
Ti ritrovi nella classica pagina di gestione dei tuoi menu di navigazione. Con una piccola differenza, perché anche qui
adesso compare l’opzione lingua.
A destra scegli il menu che vuoi tradurre e seleziona la lingua di destinazione. Ora puoi creare la versione in un’altra lingua
del tuo menu, conservando tutte le caratteristiche del menu originario (gerarchia pagine e così via).
Come puoi vedere WPML rende questo processo molto intuitivo e bastano pochi passaggi per familiarizzare con l’intero
funzionamento del plugin. Lavorare con WPML infatti è facile persino per i principianti.
A questo punto hai tradotto tutto il contenuto del tuo sito web. Dagli articoli alle pagine, fino al menu di navigazione. Tutti
questi elementi cambiano lingua nel momento in cui i visitatori ne selezionano una diversa dal menu che appare su ciascuna
pagina web tradotta.
Eppure come ben sai un sito web è fatto anche da altri elementi, primi fra tutti i plugin e i widget. Ebbene, è possibile
tradurre plugin e widget usando WPML, così da creare un sito multilingua su WordPress a 360 gradi. Abbi solo ancora
un po’ di pazienza, ci arriviamo subito.
Creare
un
“sito
e-‐Commerce
Multilingua”
con
WPML
Questa parte della guida è rivolta ai lettori che vogliono creare un sito e-commerce multilingua su WordPress con
WPML per vendere dei prodotti.
Capita spesso – per nostra grande fortuna – che l’amatissimo Made in Italy spopoli all’estero. Infatti, in alcuni casi è
proprio il mercato internazionale a fare la fortuna di un brand. Aziende italiane, medie e persino piccole, si trovano così a
doversi equipaggiare per vendere anche fuori del nostro paese.
WPML ti permette di realizzare anche questo compito in modo facile. Vediamo subito come.
Il primo requisito fondamentale per creare un ecommerce su WordPress è munirsi di un plugin che svolga questa funzione.
Ne esistono diversi, ecco una lista dei migliori plugin ecommerce gratuiti per WordPress. Nel nostro caso ipotizziamo di
aver installato il popolare plugin ecommerce per WordPress WooCommerce.
Hai installato un plugin ecommerce per WordPress e il plugin multilingua WPML (se non l’hai fatto, è il caso che tu faccia
qualche passo indietro in questa guida). Adesso è il momento di creare il tuo ecommerce multilingua su WordPress con
WPML.
Per quanto riguarda creare pagine e articoli multilingue, il processo è lo stesso spiegato qui sopra, nella parte relativa alla
creazione di un sito web vetrina multilingua. Ora però vogliamo vedere come tradurre i componenti e le pagine tipiche di un
ecommerce, prime fra tutti le schede prodotto.
Tradurre
i
prodotti
Regola numero 1 per un ecommerce multilingua di successo: tradurre i prodotti correttamente. In fin dei conti è questo il
fulcro di un ecommerce e quindi merita un trattamento speciale.
I clienti che visitano il tuo sito web devono essere in grado di:
Ogni volta che un utente compra un tuo prodotto stai stipulando un contratto. Essere chiaro nella descrizione, nelle
condizioni di vendita e nelle modalità di pagamento è fondamentale per evitare una lunga serie di richieste di rimborso,
oltre naturalmente per salvaguardare la tua reputazione.
Per tua fortuna tradurre i prodotti di un ecommerce multilingua con WPML è molto semplice.
Nel caso di un ecommerce è importante tradurre tutte le pagine non solo del sito web stesso, ma anche del processo di
acquisto, incluse le schermate del carrello e del checkout.
Non devi fare altro che andare in Pagine sulla bacheca di WordPress e creare la copia multilingua di tutte le pagine
dell’ecommerce, come già visto sopra con una normalissima pagina web. Grazie a WPML puoi tradurre ogni aspetto o
definizione legata al tuo commercio, come ad esempio il termine “size” o “color” riferito ai prodotti in vendita.
Una volta installato un plugin ecommerce per WordPress (nel nostro caso WooCommerce) tra le voci a sinistra della
bacheca compare infatti anche la voce Prodotti.
Clicca qui. Si aprirà la lista di tutti i prodotti pubblicati sul tuo sito web, proprio come succede con gli articoli di un blog. In
alto a questa pagina puoi vedere l’elenco delle lingue selezionate nelle impostazioni di WPML.
Seleziona il prodotto che vuoi tradurre e a destra delle pagina di modifica clicca su Duplica.
Adesso che hai la copia multilingua della pagina del prodotto, a destra sotto Lingue puoi vedere la lingua in cui è
visualizzato il prodotto sul sito web e la lingua della traduzione. Clicca sull’icona della matita per modificare il contenuto.
Scrivi o incolla il testo nella nuova lingua, ricordandoti di sostituire correttamente tutti gli elementi testuali della
pagina: dal titolo alla descrizione.
In questa pagina (sempre a destra) puoi anche caricare una nuova immagine, in caso quella originaria contenga del testo
in italiano. Basta cliccare e scegliere l’immagine. Molto importante: in questa sezione ricorda di tradurre il titolo e la
descrizione dell’immagine.
Salva.
Finalmente puoi cambiare lingua anche nella pagina del prodotto. Visualizza il sito web in un’altra lingua e apri un prodotto
per vedere la pagina tradotta. Noterai che WPML traduce automaticamente i pulsanti di acquisto (come “aggiungi al
carrello”). Decisamente una bella sorpresa.
Convertire la valuta su un ecommerce multilingua di WordPress con WPML
Certo, i tuoi clienti devono capire cosa vendi, ma anche quanto costa. Per questo nel creare un ecommerce multilingua su
WordPress con WPML devi anche inserire tutte le valute straniere che ti interessano, in relazione alle lingue previste.
Nel caso di WooCommerce, è possibile impostare una valuta di default per ciascuna lingua specifica. In questo modo,
quando un visitatore cambia lingua (per esempio Giapponese) il sito web cambia automaticamente valuta (Yen).
• manualmente: sei tu a inserire il prezzo di un prodotto nella valuta straniera.
• automaticamente:
quando
viene
selezionata
una
valuta
diversa
da
quella
di
default,
il
plugin
cambia
automaticamente
i
prezzi,
aggiornandoli
in
base
ai
tassi
di
cambio
impostati.
Puoi scegliere una delle due opzioni dalle impostazioni del plugin. Vediamo bene come.
Innanzitutto devi attivare il plugin WPML Translation Management. Si tratta di un altro strumento importante per
ottimizzare la procedura delle traduzioni.
Dalla tua bacheca di WordPress vai con il cursore su WPML per fare apparire un elenco di opzioni del plugin. Clicca su
WooComerce Multilingual.
Qui puoi attivare la multi valuta e scegliere se impostare la valuta del tuo ecommerce multilingua automaticamente o
manualmente.
Dopo avere salvato la tua scelta compare l’opzione per aggiungere una valuta straniera. Qui devi scegliere la lingua da
attribuire alla valuta, il codice (o abbreviazione, per esempio EUR nel caso di euro, USD per il dollaro, ecc.) e il tasso di
cambio attuale.
NB: Nel caso di un sito italiano, creando la valuta euro bisogna impostare 0 come tasso di cambio.
Se invece decidi di impostare i prezzi manualmente, dovrai inserirli per ciascun prodotto. Si tratta di una scelta più
scomoda, che ha senso solo in circostanze particolari.
Ce l’abbiamo fatta. Siamo riusciti a creare un sito ecommerce multilingua su WordPress con WPML. Visita il tuo sito web e
apri una scheda prodotto. Adesso puoi cambiare lingua e valuta.
Adesso è arrivato il momento di tradurre anche tutti quegli elementi del sito web che fanno da contorno ai contenuti: i
widget, i plugin e naturalmente il tema in uso.
Su WordPress l’uso di widget è pratica comune. Molti di questi contribuiscono in modo diretto alla qualità dell’esperienza
degli utenti sul sito web. Tuttavia quando si decide di creare un sito web multilingue su WordPress con WPML, i widget
installati non vengono tradotti in automatico (come succede per altri aspetti come le categorie).
Ne risulta l’effetto opposto: quello che prima era un aiuto si trasforma in un fattore disturbante. Per fortuna il nostro plugin
multilingua per WordPress WPML non ci delude nemmeno questa volta.
Se stai usando i widget di default di WordPress oppure widget non di default ma comunque codificati correttamente,
WPML permette di tradurre sia il titolo che il contenuto del widget.
WPML permette di gestire in Traduzione stringhe la traduzione dei titoli di widget, delle stringhe (per esempio la barra di
ricerca del sito web) e di tutti i testi che non appartengono a un articolo, a una pagina o al menu.
Nella pagina che si apre cerca la stringa o il widget che vuoi tradurre. Per aiutarti puoi usare la funzione di ricerca in alto a
destra.
Individuata la stringa clicca sul rispettivo pulsante Traduzioni a destra. Appariranno le stringhe in tutte le lingue create.
Sostituisci il testo che vuoi tradurre, spunta la casella “traduzione completata” e salva.
Adesso puoi vedere che cambiando lingua vengono tradotte anche le stringhe e i titoli di widget che hai aggiornato.
Dunque WPML permette di tradurre i titoli e il testo di widget. Tuttavia possono emergere ulteriori necessità, come
mostrare widget diversi a seconda della lingua. È possibile, ma in questo caso serve un altro plugin: Widget Logic.
Installato Widget Logic vai nella tua bacheca di WordPress. Sotto Aspetto clicca su Widget.
Si apre la pagina con tutti i widget: ciascuno di essi è attivo solo in una lingua, per averli in più lingue è quindi necessario
creare delle copie. Una volta fatto, devi specificare in che lingua attivare i singoli widget.
Come? Clicca sul widget desiderato e aggiorna le impostazioni di lingua nel campo Widget Logic. Qui inserisci il codice:
ICL_LANGUAGE_CODE == ‘LINGUA’
Dove al posto di LINGUA si inserisce il codice della lingua in cui vuoi fare apparire il widget (per esempio
ICL_LANGUAGE_CODE == ‘en’ per l’inglese). In questa area puoi anche modificare il titolo e il testo del widget.
Salva.
Adesso se visiti il sito web e selezioni una lingua diversa, puoi vedere come cambiano anche i widget.
Creare siti web multilingua su WordPress significa anche dover fare i conti (ovvero tradurre) anche con i testi generati dai
plugin e con i testi statici del tema utilizzato. Il plugin multilingua WPML permette di rimediare anche a questo
problema.
In questo caso serve la versione CMS di WPML, in modo da poter trovare questi testi e sostituirli con la traduzione.
Adesso dalla Bacheca di WordPress vai in WPML -> Localizzazione del tema e dei plugin. Qui alla voce Stringhe del Tema
clicca sul pulsante Scansiona.
Adesso da WPML vai in Traduzione stringhe e cerca “testo da tradurre”. Clicca su Traduzione e sostituisci i testi tradotti.
Conferma e salva.
Finalmente i testi dei plugin e i testi statici del tema cambiano lingua insieme al resto del sito web.
Parlando di temi per siti web multilingua su WordPress, è molto importante scegliere quello giusto. Ovvero verificare la
compatibilità del tema di WordPress installato con il plugin multilingua WPML.
• Enfold
• Centum
• Rounder
• Eunoia
• Nevada
• MetroCorp
• Rework
• MetroStyle
Sei riuscito a tradurre tutto il contenuto testuale del tuo sito web multilingua (vetrina o ecommerce), dagli articoli ai testi
statici del tema. Mi spiace rovinare già il momento, ma non abbiamo ancora finito.
Avere uno spazio online in più lingue non significa fare un semplice copia-incolla di testi tradotti. Occorre prendersi cura e
rendere il più efficace possibile ciascuna versione del sito web. Questo include l’ottimizzazione del contenuto tradotto.
Stiamo entrando nel territorio della SEO multilingua, ovvero dell’ottimizzazione del sito web in tutte le lingue che hai
creato.
Il concetto SEO spaventa già di suo, dunque mi rendo conto come il termine SEO multilingua possa suonare un po’ ostico.
Non preoccuparti, in questa guida ti spiego come ottimizzare un sito web multilingua su WordPress in modo semplice.
Partiamo innanzitutto da alcuni consigli utilissimi e facili da applicare. Sette, per l’esattezza.
Per noi motore di ricerca è sinonimo di Google, ma non per il resto del mondo. A seconda della lingua, informati su quale
sia il motore di ricerca più utilizzato nello specifico paese e quali consigli di SEO offre. Per esempio, se includi la lingua
cinese sulla tua piattaforma, ti conviene ottimizzare il sito in cinese per Baidu. Oppure per Yandex in russo e così via.
Si tratta di una regola d’oro: i motori di ricerca non amano indicizzare un calderone di lingue diverse. Utilizza una sola
lingua alla volta nella ottimizzazione delle parole chiave, nei testi e nei titoli/descrizioni delle immagini. Questo aiuta molto
l’ottimizzazione SEO multilingua.
Anche per i link vale la stessa regola del punto #2. Se vuoi ottimizzare un sito web multilingua su WordPress, devi inserire
collegamenti esterni con siti nella stessa lingua. Nella versione spagnola del tuo sito web inserirai dunque solo link a siti in
spagnolo.
4. Traduci
i
breadcrumb
e
i
rich
snippet
Per la SEO multilingua quello che si nasconde dietro a un sito web è importante tanto quanto quello che i visitatori leggono
sulle pagine. Traduci tutti quei contenuti nascosti tanto amati dai motori di ricerca.
La gerarchia tra le pagine è un elemento fondamentale ai fini di ottimazione SEO. Tutte le pagine devono essere collegate
fra di loro e facilmente accessibili (con il minor numero di click possibili). Tuttavia, devi tenere presente anche la relazione
tra pagine in lingue diverse. Anziché avere un collegamento comune, collega le pagine corrispondenti nelle varie lingue. Per
capire meglio: collega la pagina Contatti in italiano con la pagina Contatti in inglese.
Come già detto prima, una piattaforma multilingua non vuole dire una copia approssimativa degli stessi testi in più lingue.
La tua attività o brand deve essere presente tanto globalmente quanto localmente. Oltre a tradurre i tuoi contenuti
internazionali, cerca di pubblicare contenuti originali nella lingua locale. Il giusto equilibrio fra i due metodi è la chiave
per il successo.
Qui ci addentriamo in un territorio controverso. Ai fini di ottimizzare un sito web multilingua su WordPress è possibile
acquistare domini con estensione diversa (e specifica) per ciascuna lingua. Ad esempio www.miosito.it per l’italiano,
www.miosito.en per l’inglese, www.miosito.de per il tedesco e così via. È un argomento che merita un approfondimento,
per questo ne parliamo nel dettaglio più avanti.
Chiusa questa utile parentesi, torniamo al nostro plugin multilingua per WordPress preferito. La buona notizia è che WPML
ha pensato proprio a tutto, anche all’ottimizzazione SEO multilingua.
Non solo WPML è compatibile con il plugin WordPress SEO, ma contribuisce direttamente all’ottimizzazione del tuo
sito web multilingua.
Vuoi ottimizzare al massimo i tuoi contenuti lato SEO? Ecco la guida all’eccellente plugin SEO by Yoast.
Leggi
Vediamo come.
Partiamo dalla homepage. WordPress SEO permette di aggiungere del testo (titolo e descrizione) per facilitare
l’indicizzazione del sito web. Per tradurre il titolo e la meta descrizione della home di un sito web multilingua su
WordPress con WPML, dalla tua Bacheca vai in WPML-> Traduzione stringhe.
Trovi tutti i testi di WordPress SEO sotto la voce ‘admin_texts_plugin_wordpress-seo‘. Individua quello che vuoi tradurre e
clicca su Traduzioni. Sostituisci il testo con la lingua giusta, conferma di aver completato e salva.
Per tradurre il titolo, la meta descrizione e le parole chiave delle altre pagine web del sito, una volta create le copie
della pagine nella altre lingue, basta accedere attraverso WordPress SEO by Yoast e ottimizzarle nella lingua corretta.
Un
dominio
VS
domini
multipli
Come ho anticipato sopra, utilizzando WPML si può optare per aprire dei domini o sottodomini multipli. Ovvero creare un
sito web diverso per ciascuna lingua. Esistono due modi per farlo.
La prima strada consiste nel creare domini di primo livello nazionali separati su cui caricare i contenuti web in una
singola lingua. Questo significa avere un sito web specifico per ogni lingua, utilizzando l’estensione di riferimento al paese
in cui la lingua è parlata. .it per l’Italia, .de per la Germania, .es per la Spagna, .fr per la Francia.
Altrimenti, puoi optare per creare dei siti web individuali ricorrendo a dei sottodomini del dominio principale che hai
acquistato. In questo caso disporrai un dominio generico di primo livello condiviso dai diversi sottodomini. Così avrai
un’estensione finale comune (per esempio .com) e dei suffissi nazionali. Ecco come: it.miosito.com per l’Italia,
es.miosito.com per la Spagna e così via.
Nel caso di un ecommerce multilingua, oltre all’estensione e alla lingua, andrai a inserire direttamente anche la valuta di
riferimento della nazione.
Anche in questo scenario entra in gioco il plugin multilingua WPML. Infatti questo “gioiellino” è in grado di gestire diverse
lingue su domini o sottodomini differenti. Come? Sono necessarie alcune impostazioni specifiche. E per niente facili.
Insomma, non di certo ciò che consiglierei a principianti e a chi non mastica molto linguaggio informatico.
Tuttavia è possibile. Per farlo (e farlo bene) puoi leggere un utilissimo articolo di aiuto pubblicato dal sito di WPML.
Ti suggerisco inoltre di contattare il supporto WPML per chiedere assistenza passo per passo con questo complicato
processo. Infine, non fa mai male rivolgersi al proprio hosting provider (il sito su cui hai acquistato i domini con le
diverse estensioni) e chiedere alla sua assistenza clienti come configurare esattamente le impostazioni del tuo server per
creare un sito web multilingua su WordPress con WPML.
Se hai deciso di creare un dominio o sottodominio diverso per ciascuna lingua, puoi tradurre la sitemap. Si tratta di
un’altra tecnica di SEO multilingua volta all’ottimizzazione del tuo sito web
Per tradurre la sitemap, devi installare WordPress SEO by Yoast e abilitare l’opzione ‘Un dominio differente per lingua’
in WPML-> Lingue. In questo modo avrai un file XML per ogni lingua, che puoi trovare in SEO -> XML Sitemap ->
WPML.
Se vuoi ottenere un sito multilingua autorevole e ben indicizzato, l’aspetto più importante è la qualità delle traduzioni.
Perché il tuo sito web abbia successo tanto in altre lingue quanto in italiano, devi assicurarti che i contenuti siano tradotti
alla perfezione.
Diffida dai traduttori automatici. L’errore più grande che tu possa commettere è utilizzare Google Translator e strumenti
similari. Si tratta di software approssimativi e letterali, che non tengono in considerazione le dinamiche di scrittura web.
Non ci credi? Prendi un qualsiasi sito straniero, copia una parte di contenuto e traducilo con Google. Osserva il risultato e
chiediti se ti fideresti di un sito web scritto in questo modo.
I testi tradotti richiedono la medesima cura di quelli originali. Per questo ti consiglio di affidarti a professionisti o
madrelingua.
WPML include un altro utile plugin di nome Translation Management. Lo abbiamo già citato ma senza vederne una delle
sue applicazioni principali: determinare “chi traduce cosa”. In altre parole permette di trasformare qualsiasi utente di
WordPress in un traduttore a cui affidare i tuoi testi.
Clicca su “locale” e scegli l’utente che vuoi rendere traduttore. Sopra invece scegli la combinazione linguistica (lingua di
origine e lingua di destinazione) da assegnare all’utente.
Per tradurre i contenuti assegnati, l’utente non modificherà l’articolo o le pagine, ma utilizzerà direttamente l’editor di
traduzione di WPML.
Non finisce qui. Può succedere che tu non abbia utenti in grado di tradurre i tuoi testi oppure che non ti fidi completamente
della loro capacità. In tal caso WPML dà la possibilità di trovare dei traduttori professionisti prequalificati. Basta usare
l’opzione ICanLocalize.
Per selezionare e personalizzare i tipi di contenuto da tradurre devi andare in WPML->Translation Management->
Configurazione contenuto multilingue.
Invece, per inviare i contenuti da tradurre vai in WPML->Translation Management-> Bacheca traduzioni.
Qui puoi selezionare quali testi inviare e da chi farli tradurre. Per confermare clicca su Traduci documenti.
A questo punto i tuoi utenti-traduttori riceveranno un’email di notifica e potranno iniziare a lavorare con l’editor di
traduzione di WPML. Se invece hai scelto l’opzione ICanLocalize, WPML invierà il contenuto a dei traduttori
professionisti scelti.
Puoi visualizzare lo stato delle traduzioni sempre nella Bacheca traduzioni di WPML. Vedrai i documenti passare da “non
tradotto” a “traduzione in corso” e infine come già tradotti.
Oltre agli strumenti forniti da WPML, puoi affidare la traduzione dei contenuti a dei traduttori freelance.
Esistono diverse aziende e siti web specializzati nella traduzione in tutte le lingue immaginabili. Uno strumento che io trovo
molto utile per assumere traduttori freelance è Elance. Qui puoi scegliere utenti specializzati nelle diverse lingue, aiutandoti
con la loro reputazione e feedback.
Creare un Sito Web Vetrina Multilingua WordPress con WPML: in conclusione
Abbiamo coperto anche l’ultimo aspetto di come creare un sito web multilingua su WordPress con WPML. Adesso non
resta altro che mettersi al lavoro.
WordPress, WPML, Translation Management, WooCommerce e WordPress SEO by Yoast sono tutto ciò di cui hai
bisogno per creare il tuo sito vetrina o il tuo ecommerce multilingua, otre naturalmente a questa guida che spero ti sarà
davvero utile per lo sviluppo della tuo sito web multilingua.
Cos’è un tema di WordPress
In questa guida esamineremo le procedura necessaria per creare da zero un tema di WordPress, se ne analizzerà la struttura,
si descriveranno le principali funzioni del framework, si cercherà di capire cosa si possa chiedere ad un tema e come
ottenerlo. Il percorso della trattazione seguirà un percorso precisa e condurrà allo sviluppo di un tema completo,
perfettamente funzionante, che sarà scaricabile come allegato dalle pagine della guida e successivamente pubblicato su
Github per eventuali sviluppi futuri.
Un tema svolge due macro-funzioni: genera il layout e la componente grafica del sito, e aggiunge funzionalità al core di
WordPress. Un tema, quindi, non fornisce solo la veste grafica, ma è anche uno strumento utile a sviluppare la dimensione
"comportamentale" di un sito Web, ciò nello stesso modo dei plugin.
Di regola, un tema dovrebbe essere abbastanza generico da poter essere utilizzato per finalità differenti, ma dovrebbe anche
offrire alcune funzionalità uniche, cosicché l’utente (o acquirente) possa distinguerlo nella miriade di temi disponibili.
Dal punto di vista strutturale, WordPress si presenta con una directory principale, contenente file di valenza globale, come il
file di configurazione wp-config.php e il file .htaccess, e le tre sub-directory wp-admin, wp-content e wp-
includes. Di queste ultime, la prima contiene i file che generano il pannello di amministrazione; la seconda ospita i temi,
i plugin, i file lingua e gli allegati ai contenuti del sito; infine, wp-includes contiene una serie corposa di script che
aggiungono funzionalità all’istallazione, sia dal lato admin che dal lato front-end.
I temi sono collocati nella directory /wp-content/themes e, nel caso specifico di WordPress, "installare un tema"
significa semplicemente caricarlo all’interno di questa directory. Una volta istallato, l’anteprima del tema sarà visualizzata
nella pagina denominata "Gestione Temi" del pannello di amministrazione, alla quale si potrà accedere attraverso il
percorso di menu "Aspetto > Temi".
Gli unici file indispensabili perché un tema funzioni sono i file style.css e index.php; di questi il primo non è solo
un foglio di stile, ma anche il file in cui vengono memorizzati i metadati necessari al corretto funzionamento del tema
stesso. Quella che segue è una parte dell’intestazione del file style.css del magazine theme denominato Twenty
Fourteen, il tema predefinito di WordPress per il 2014:
/*
Theme Name: Twenty Fourteen
Theme URI: http://wordpress.org/themes/twentyfourteen
Author: the WordPress team
Author URI: http://wordpress.org/
...
*/
Come anticipato, il secondo file indispensabile per un tema è index.php, questo fornisce il template della pagina iniziale
del sito e viene normalmente strutturato in quattro diverse sezioni:
1. intestazione;
2. contenuti;
3. sidebar;
4. fondo
pagina.
È prassi incorporare il codice che compone le diverse sezioni in file esterni, si avranno così i file header.php,
sidebar.php e footer.php. Anche i contenuti della pagina possono essere generati sia all’interno del file
index.php, che in template esterni, dipendenti dal formato dell’articolo.
WordPress permette anche di creare template pagina, ossia particolari template destinati alle pagine statiche. Sempre
all’interno della directory del tema, potranno essere collocati una cartella destinata ai file di lingua, nonché tutti gli script e i
fogli di stile necessari allo sviluppo del sito.
È buona norma progettare un tema avendo come obiettivo la sua distribuzione. Un tema può essere distribuito
gratuitamente, al fine di accrescere la reputazione dello sviluppatore o per promuovere una versione a pagamento; oppure
può essere distribuito commercialmente e diventare fonte diretta di guadagno. In entrambi i casi, bisogna tener presente che
WordPress è rilasciato sotto licenza GPL, la quale prevede che ogni opera derivata venga rilasciata sotto le stesse
condizioni.
I temi (e i plugin), quindi, utilizzando le funzioni PHP del framework, vanno considerati come opere derivate, da distribuire
secondo la stessa licenza GPL. Se ciò è vero per il codice PHP, non può dirsi altrettanto per il codice CSS e per i file
immagine, che non dipendono da WordPress. Questi ultimi tipi di file devono quindi essere considerati opere separate e non
derivate.
In conclusione, la licenza GPL non si applica al tema nel suo complesso, ma solo ai file PHP.
Terminata la fase relativa alla presentazione dei temi di WordPress, dedicheremo le prossime pagine della guida ad
esaminare le diverse componenti che costituiscono un tema.
In WordPress una pagina si struttura in quattro blocchi: intestazione (header), corpo della pagina (content), una o più aree
dedicate ai widget (sidebar), fondo pagina (footer). Nel caso delle pagine dedicate a singoli articoli, va prevista un’area
aggiuntiva destinata ai commenti.
In PHP, la funzione include() incorpora all’interno di uno script il contenuto di un file esterno; quando si sviluppa un
tema di WordPress, però, al posto di include() è opportuno utilizzare funzioni specifiche del framework che permettono
di inserire con maggior sicurezza e semplicità i template che costituiscono le parti della pagina. L’immagine che segue
mostra il file index.php del Blank Theme di HTML5 Reset, cui si farà spesso riferimento in questa guida:
All’interno del Loop vengono invocati altri template tags, tramite i quali si accede al database e si manda l’output a video.
Il template tag get_header() include il template header.php. Se esiste un template più specifico per il tipo di pagina,
questo andrà nominato header-{name}.php, e alla funzione andrà passata la stringa name come argomento:
get_header( 'name' ). La home page del sito, ad esempio, potrebbe avere un’intestazione specifica nel template
header-home.php, che andrebbe inclusa con get_header( 'home' ).
Il file header.php contiene l’intestazione del documento HTML, con i vari tag meta, link e script. È il file che
genera la parte superiore della pagina con il menu di navigazione. Quello che segue è il codice di un header.php
notevolmente semplificato:
La sidebar è un contenitore di blocchi di codice HTML – definiti widget – che contengono informazioni correlate ai
contenuti del sito Web. In una pagina possono essere inserite diverse sidebar, ognuna collocata in un’area diversa. La
sidebar viene generata dal file sidebar.php, o da più specifici file sidebar-{name}.php, e incorporata nei template
del sito grazie al template tag get_sidebar() (maggiori info nel Codex). Nel caso di template specifici, alla funzione
andrà passata la stringa 'name'. Ecco un generico sidebar.php:
Footer
Il footer è la parte inferiore della pagina del sito. Questa spesso contiene informazioni aggiuntive, note di copyright, form di
ricerca. Vista l’eterogeneità delle informazioni, spesso nel footer trova posto un’ulteriore sidebar, sempre incorporata dal
template tag get_sidebar().
Il Codex è il riferimento ufficiale e imprescindibile per chiunque voglia sviluppare su WordPress, e al Codex si farà
frequente rinvio in questa guida. Qui si troverà l’elenco completo dei template tags e l’indice delle risorse relative ai
template. Altra risorsa indispensabile è l’articolo Stepping into templates.
Il Loop: introduzione
Sebbene non esistano regole generali sulla struttura che deve avere un template file, generalmente questo non manca dei tag
get_header(), get_sidebar() e get_footer(), che includono le parti della pagina e del ciclo iterativo (Loop)
che accede al database e lancia a video i contenuti:
Il Loop genera quindi un elenco di articoli, il cui markup dipende dalle decisioni di chi sviluppa il tema. Per ogni articolo
potrà essere visualizzato un estratto del contenuto principale o un testo alternativo (excerpt); potrà essere visualizzata o
meno un’immagine di anteprima (post thumbnail); potranno essere visualizzate le categorie, i tag, la data di pubblicazione,
l’autore e tutti i possibili metadati. Tutte queste opzioni devono essere attentamente vagliate quando si progetta un tema.
Figura 1. Il Loop del file archive.php del Blank Theme di HTML5 Reset
Quelli che seguono sono i principali template da tenere in considerazione quando si progetta un tema.
Il file index.php
index.php costituisce il template principale di un tema, sebbene sia allo stesso tempo quel template cui WordPress
ricorre solo come soluzione di fallback, ossia quando mancano template specifici per il tipo di richiesta del client.
Proprio per questa sua caratteristica, il file index.php deve essere adatto a generare ogni tipo di pagina, dagli archivi di
notizie, agli articoli singoli fino alle pagine statiche.
Per WordPress un archivio è un elenco di post. L’utente può chiedere i post pubblicati in un dato periodo, creati da un
determinato autore, appartenenti ad una certa categoria, o etichettati con uno specifico tag. In tutti questi casi viene richiesta
una pagina d’archivio. Qualora non esista un template più specifico per il tipo di pagina richiesta, WordPress cercherà il
generico file di archivio archive.php (in mancanza del quale tornerà al file index.php).
Normalmente il template archive.php è simile al file index.php, avendo anch’esso lo scopo di fornire un elenco di
articoli.
I
template
specifici:
categorie,
tag,
autori
Esistono numerosi tipi di archivi, e WordPress permette di creare una pagina specifica per ognuna delle varie tipologie. Si
avranno, quindi, i seguenti template:
• author.php
• category.php
• date.php
• tag.php
• taxonomy.php
La specificità può essere ancora maggiore: è possibile creare, infatti, template diversi per ogni
categoria/autore/tag/tassonomia, aggiungendo un suffisso al nome del file. Così, ad esempio, per le categorie si avranno i
seguenti template:
• category.php
• category-$id.php
• category-$slug.php
Allo stesso modo, per i tag si avrà:
• tag.php
• tag-$id.php
• tag-$slug.php
L’elenco dei template è lungo, e si rinvia ancora al Codex per ogni utile approfondimento.
Oltre che per gli archivi, è possibile creare template adatti alla visualizzazione di singoli contenuti, che possono essere
articoli del blog, pagine statiche, attachment, e post personalizzati.
In questo caso la struttura del template sarà sensibilmente diversa dai file di archivio, sebbene in entrambi i casi saranno
presenti i tag get_header(), get_sidebar() e get_footer(), oltre che, ovviamente, il Loop, che in questo caso
manderà a video un solo elemento.
Per i singoli contenuti, WordPress dispone dei seguenti template:
• attachment.php
• page.php
• single.php
• custom.php
Anche questa volta è possibile creare template più specifici. Nel caso dei post, avremo:
• single.php
• single-$post.php
• single-$posttype.php
Altri template
WordPress dispone di altri template, che vanno a completare il mosaico permettendo un controllo assoluto dell’aspetto del
sito.
• I
template
front-page.php
e
home.php
sono
utilizzati
per
la
visualizzazione
della
pagina
iniziale:
il
primo
nel
caso
di
una
pagina
statica,
il
secondo
nel
caso
in
cui
si
voglia
un
template
più
specifico
del
file
index.php;
• Il
template
404.php
è
destinato
alle
pagine
di
errore;
• search.php
mostra
i
risultati
di
una
ricerca
interna
al
sito;
• comments-popup.php
genera
una
finestra
di
popup
per
i
commenti.
Conclusioni e riferimenti
In questo capitolo si è voluta offrire una panoramica dei template file di WordPress e si è fatto riferimento ai seguenti
articoli del Codex:
Nel prossimo capitolo si presenteranno le funzioni del framework che permettono di creare la struttura HTML dei template
file.
Il file style.css
È molto di più di un foglio di stile. Il file, infatti, fornisce a WordPress tutte le informazioni necessarie a gestire il tema:
nome, autore, descrizione, licenza, e molto altro. L’immagine seguente mostra l’intestazione del file style.css del tema
Twenty Fourteen:
Figura 1. Intestazione del file style.css di Twenty Fourteen
I metadati che compongono l’intestazione del file style.css devono essere forniti all’interno di un commento.
Particolare attenzione va posta al nome del tema, che deve sempre essere univoco. Nel caso dovessero essere istallati due
temi con lo stesso nome, infatti, WordPress non potrebbe gestirli correttamente.
Quello che segue è l’elenco degli Header-Names che possono essere utilizzati nel foglio di stile:
• Author
• Author URI
• Description
• Domain Path
• Status
• Tags
• Template
• Text Domain
• Theme Name
• Theme URI
• Version
Le intestazioni possono essere estese con l’aggiunta di altri nomi alla lista appena vista, come ad esempio Licence e
License URI (a tal proposito si veda come esempio il tema Twenty Fourteen). Non tutti gli Header-Names sono
indispensabili; per la corretta gestione del tema, però, è necessario prevedere almeno i nomi che consentano di individuarlo
e descriverlo.
È importante ricordare che ogni coppia nome/valore va collocata su un rigo singolo e viene separata dal simbolo dei due
punti (":"), maggiori informazioni sulle regole da seguire per l’intestazione del foglio di stile sono disponibili nel Codex.
Nel caso si stia sviluppando un Child Theme, cioè un tema derivato da un tema principale (Parent Theme), il foglio di
stile deve contenere anche un riferimento al tema principale, individuato dal nome Template. Nell’immagine che segue,
si riporta, a titolo di esempio, l’intestazione del foglio di stile di un Child Theme basato su Twenty Fourteen.
Figura 2. Intestazione dello style.css di un Child Theme basato su Twenty Fourteen
Il
file
functions.php
Sebbene, come anticipato, non sia strettamente necessario, il file functions.php è presente nella quasi totalità dei temi.
Questo permette di estendere il core di WordPress con quelle funzionalità che spesso vengono aggiunte tramite plugin. Ciò
avviene sia attraverso la definizione di nuove funzioni, sia utilizzando le funzioni del framework. Il file consente, inoltre, di
attivare tutte quelle funzionalità che sono specifiche dei temi, come i post thumbnail, i menu personalizzati, le aree destinate
ai widget. La figura proposta di seguito mostra un estratto del codice del file functions.php del tema twenty Fourteen:
La funzione del file rimane la stessa, sia che si sviluppi un tema, sia che si lavori su un Child Theme. In quest’ultimo caso è
opportuno precisare che il functions.php è l’unico file del tema derivato che non sovrascrive il corrispondente file del
tema originale, ma viene caricato in aggiunta al suo corrispondente. Più precisamente, il functions.php del Child
Theme viene caricato prima del file presente nella directory del parent.
Riferimenti online
Molti template tag generano informazioni relative a post e pagine, come il titolo, l’autore, la data di pubblicazione, etc.
Questi tag vanno utilizzati all’interno del Loop. Altri tag generano informazioni di carattere generale e possono essere
utilizzati al di fuori del Loop.
Tra i tag di utilizzo più frequente, bloginfo() fornisce un semplice esempio di come restituire a video informazioni sul
sito Web corrente:
L’argomento individua il tipo di informazione richiesta e la funzione invia direttamente l’output al browser. Il codice
precedentemente proposto manda a video il seguente testo:
Spesso l’output restituito a video non è costituito da una semplice stringa di testo, ma da un frammento di codice HTML:
the_ID() restituisce l’ID del post corrente in forma di stringa; post_class(), invece, restituisce un frammento di
codice HTML, sicché l’output a video sarà:
Tra le molte decine di tag, è possibile individuare due sottogruppi che si presentano con caratteristiche omogenee: i tag con
prefisso the_ e i tag con prefisso get_.
I
tag
the_
Il prefisso the_ individua un tag che manda a video un output. the_title() e the_permalink(), ad esempio,
restituisce a video il titolo e il permalink di un post (o di una pagina) e deve necessariamente essere utilizzato all’interno del
Loop. Si consideri questo esempio:
Con questa istruzione vengono stampati a video il permalink e il titolo di un post all’interno di un titolo delimitato da h2.
Altri tag the_ di impiego comune sono:
Tag Descrizione
the_author() Produce
una
stringa
con
il
nome
dell’autore
di
un
post.
the_author_meta() Mostra
ogni
altro
tipo
di
informazione
sull’autore
del
post.
the_time()
e
the_date() Mostrano
ora
e
data
di
pubblicazione.
the_excerpt()
e
the_content() Mandano
a
video
il
riassunto
e
il
contenuto
principale
del
post.
the_category()
e
the_tags() Generano
l’elenco
delle
categorie
e
dei
tag
post.
I tag get_
Se i tag the_ stampano un output a video, i tag get_ restituiscono una stringa da gestire via PHP. Il framework dispone,
per molti tag the_, di un corrispondente tag get_. Così i tag get_permalink() e get_the_title() permettono
di ottenere lo stesso risultato dell’esempio precedente:
get_permalink() e get_the_title() possono essere utilizzati al di fuori del Loop, e quindi si prestano ad una
molteplicità di impieghi. Altri tag di uso comune sono get_bloginfo(), get_the_author(),
get_the_author_meta(), get_the_time(), get_the_date(), get_the_excerpt() e
get_the_content() i cui nomi rendono facilmente intuibile la funzione svolta.
Tag condizionali
Sono funzioni che permettono di testare una condizione. Grazie a questi tag, è possibile generare un output alternativo a
seconda del valore TRUE o FALSE restituito. is_single(), ad esempio, restituisce TRUE al caricamento di una pagina
singola:
if
( is_single() ) :
the_title( '<h1 class="entry-title">', '</h1>'
);
else
:
the_title( '<h1 class="entry-title"><a href="'
. esc_url( get_permalink() ) .
'" rel="bookmark">', '</a></h1>'
);
endif;
Altri tag condizionali di uso corrente sono is_home() e is_front_page(), che testano se la pagina corrente sia la
Home Page del sito Web corrente (blog o pagina statica); is_page(), che verifica che l’utente si trovi in una pagina
statica; is_category(), che verifica la categoria del post corrente.
Include
tags
Gli
Include
Tags,
di
cui
si
è
già
parlato
nei
capitoli
precedenti,
sono
funzioni
che
includono
il
contenuto
di
specifici
template.
Si
tratta
dei
seguenti
template
tags:
• get_header()
• get_footer()
• get_sidebar()
• get_template_part()
• get_search_form()
• comments_template()
Anche in questo caso i nomi dei tags rendono facilmente intuibile la funzione svolta
I parametri
Come tutte le funzioni PHP, i template tag possono accettare o meno argomenti. bloginfo(), ad esempio, accetta una
stringa che individua il tipo di dato da mandare a video. Nel caso non venisse passato alcun argomento, bloginfo()
stamperà il nome del sito Web corrente. Alcuni tag accettano argomenti come ogni funzione PHP; a tal proposito si
consideri la seguente istruzione:
Qui il primo argomento è un testo da visualizzare prima dell’output, il secondo stabilisce se la funzione deve mandare a
video il testo, o restituirlo in una variabile PHP. Infine, alcuni tag accettano argomenti nella forma di array o di querystring:
L’argomento passato alla funzione consiste in una querystring che imposta i valori di quattro parametri: orderby,
exclude, title_li e taxonomy. In alternativa alla querystring, gli stessi parametri avrebbero potuto essere trasmessi
come elementi di un array.
Riferimenti online
In questo capitolo si è fatto ampio riferimento al Codex di WordPress, e in particolare ai seguenti articoli:
• Template
Tags
• Stepping
into
Template
Tags
• Anatomy
of
a
Template
Tag
• How
to
pass
tag
parameters
• Conditional
Tags
• Include
Tags
Nel prossimo capitolo si parlerà nel dettaglio della gerarchia dei template.
Tra tutti i template file, l’unico indispensabile è il file index.php, utilizzato da WordPress qualora manchino template più
specifici per la pagina richiesta dall’utente.
La pagina iniziale
Per restituire la pagina iniziale di un sito Web basato su WordPress sono previsti due template: home.php e front-
page.php. Il primo viene utilizzato quando la pagina iniziale mostra gli ultimi articoli del blog; il secondo quando viene
impostata una pagina statica nel menu “Impostazioni lettura” del pannello di amministrazione.
In mancanza del file home.php, viene caricato il file index.php, in mancanza del file front-page.php, invece,
WordPress cercherà il template page.php, nel caso in cui la pagina iniziale sia una pagina statica; in alternativa, qualora
la pagina iniziale sia un elenco di articoli, WordPress cercherà di nuovo il template home.php.
Pagine
singole
Per rendere singoli post e pagine statiche sono disponibili due template generali: single.php per gli articoli e
page.php per le pagine statiche. Prima di questi due template, però, WordPress ne cercherà di più specifici. Quella che
segue è la gerarchia prevista per articoli, tipi di post personalizzati e allegati:
• single-post.php
• single.php
• single-$posttype.php
• single.php
• $mimetype.php
• $subtype.php
• $mimetype_$subtype.php
• attachment.php
• single.php
• $custom.php
• page.php
• page-$slug.php
• page-$id.php
• page.php
Come sempre, ogni qual volta manchino tutti i template della gerarchia, WordPress cercherà il file index.php.
Pagine
di
archivio
Una pagina di archivio è una pagina che ospita un elenco di notizie. Può trattarsi delle notizie di una specifica categoria,
etichettate con un certo tag o con una determinata tassonomia, appartenenti ad un tipo di post personalizzato, create da un
certo autore, o, infine, pubblicate in una certa data.
In tutti questi casi, WordPress cercherà template specifici per il tipo di archivio, secondo il seguente schema:
Commenti,
404
e
risultati
di
ricerca
Gli ultimi template generano il pop-up dei commenti (comments-popup.php), la pagina di errore 404 (404.php) e la
pagina che mostra i risultati di una ricerca interna al sito (search.php).
Per ogni approfondimento degli argomenti trattati in questo capitolo, si rinvia alle seguenti risorse:
• Template
Hierarchy
• WordPress
Template
Hierarchy
La seconda parte del file contiene le dichiarazioni CSS che permettono di creare la veste grafica del sito. WordPress genera
numerosissimi nomi di classi CSS che vengono assegnati automaticamente agli elementi che compongono le pagine del
front-end. Una volta noti i nomi delle classi, sarà agevole definire con precisione le caratteristiche grafiche di ogni elemento
della pagina.
Quelli che seguono sono i metadati che possono comporre l’intestazione del file style.css:
Chiave Descrizione
Name il
nome
del
tema
ThemeURI la
URI
della
home
page
del
tema
Description la
descrizione
del
tema
Author l’autore
del
tema
AuthorURI il
sito
web
dell’autore
Version la
versione
corrente
Template previsto
solo
per
i
child
themes,
indica
la
directory
del
parent
theme
(obbligatorio)
Status indica
se
il
tema
è
pubblicato
Tags etichette
utilizzate
per
descrivere
il
tema
TextDomain il
text
domain
utilizzato
per
la
localizzazione
DomainPath il
percorso
ai
file
contenenti
le
traduzioni
La lista proposta non è tassativa e altre coppie chiave/valore possono essere aggiunte all’elenco. Quello che segue è invece
un esempio di intestazione:
/*
Theme Name: Seventy One Theme
Theme URI: http://example.com
Description: A basic theme for HTML.it readers
Author: Carlo Daniele
Author URI: https://www.linkedin.com/in/carlodaniele
Version: 0.1
*/
Queste stesse informazioni saranno visibili nel pannello di amministrazione, nella scheda "Dettagli Tema" della pagina
"Aspetto > Temi".
Dopo aver azzerato gli stili predefiniti, si passa alla progettazione della presentazione del sito, con la creazione del layout.
Si vedrà più avanti come generare il markup, ma già da ora si può definire il seguente schema:
La div#page esterna costituisce il contenitore generale. I blocchi interni sono costituiti dall’elemento header,
contenente il titolo del sito e il menu principale di navigazione, dalla div#main-content, che ospita i contenuti,
dall’elemento aside, che ospita la sidebar principale e, infine, dall’elemento footer, che ospiterà una diversa sidebar e
le informazioni di copyright.
Definita la struttura, si può procedere alla creazione del layout. Nel foglio di stile andranno aggiunte le seguenti istruzioni:
#page {
margin: 0
auto;
width: 90%;
max-width: 960px;
}
#site-header {
margin: 0
1.0416667%;
padding-top: 2.7659574%;
width: 97.9166667%;
}
#primary-navigation {
margin-top: 2.7659574%;
margin-bottom: 2.7659574%;
width: 100%;
}
#main-content {
margin-right: 1.0416667%;
float: right;
width: 72.7083333%;
}
#sidebar {
border-right: 2px
solid
#e8e8e8;
margin-right: 1.0416667%;
margin-left: 1.0416667%;
padding-right: 1.0416667%;
float: left;
width: 22.7083333%;
}
#site-footer {
float: left;
margin: 2.7659574%
1.0416667%
1.0416667%
0;
clear: both;
width: 97.9166667%;
}
Come è possibile notare, sono state utilizzate unità di misura relative per fare in modo che il layout sia flessibile e si adatti
alla dimensione dello schermo. Il blocco #main-content occupa il 72% circa dell’area disponibile, mentre la barra
laterale occupa il 22%. Le proporzioni vanno ora adattate agli schermi di dimensioni inferiori:
Riferimenti e conclusioni
Come in precedenza, anche in questo capitolo si è ampiamente fatto riferimento al Codex di WordPress, in particolare sono
state seguite le linee guida delle seguenti risorse:
• File
Header
• L’oggetto
WP_Theme
• CSS
Coding
Standard
Da qui in avanti si vedrà, quindi, come definire l’aspetto dei singoli elementi.
WordPress assegna all’elemento body un numero variabile di classi a seconda della pagina richiesta dall’utente. Nessuna di
queste è strettamente necessaria, ma ognuna consente di personalizzare la pagina a seconda che essa contenga un post, un
archivio, o una pagina di errore. Le classi vengono assegnate grazie al tag body_class():
.home {}
.blog {}
.page {}
.archive {}
.search {}
.error404 {}
.category {}
.tag {}
.tax-{taxonomy} {}
.term-{term} {}
.post-type-archive {}
.author {}
.date
{}
.single {}
.single-post {}
.single-author {}
Nel file qui allegato è disponibile l’elenco completo delle classi generate dal tag body_class().
La testata della pagina viene racchiusa in un elemento header, generalmente inserito nel file header.php. Nel tema che
ci si propone di sviluppare, l’header è strutturato come segue:
L’header contiene il titolo, la descrizione del sito e il menu di navigazione, racchiuso in un elemento nav. Di seguito gli
stili degli elementi:
.site-header {}
.site-header a {
color: #555;
text-decoration: none;
}
.site-header a:hover {
color: #222;
}
.site-title {
margin-top: 0;
margin-bottom: 0;
}
.site-description {
font-size: 1.2em;
}
All’interno dell’header, particolare importanza riveste il menu di navigazione. Questo viene generato dal seguente
template tag:
Essp dispone di diverse decine di classi che vengono assegnate agli elementi del menu di navigazione a seconda del
contesto. Il menu a cui si farà riferimento presenta la seguente struttura:
<nav
id="primary-navigation"
class="site-navigation primary-navigation"
role="navigation">
<div
class="menu-main-menu-container">
<ul
id="menu-main-menu"
class="nav-menu">
<li
id="menu-item-79"
class="menu-item menu-item-type-custom menu-item-
object-custom current-menu-ancestor menu-item-has-children menu-item-79">
<a
href=" ... ">CMS</a>
<ul
class="sub-menu"> ... </ul>
</li>
Per il tema che si sta sviluppando, si è pensato di utilizzare un menu Suckerfish nella sua versione originale, in puro CSS:
Un menu a scomparsa, come il menu appena creato, non si adatta agli schermi touch dei dispositivi mobili, per questo sono
necessarie una o più media queries:
@media screen
and (max-width: 640px) {
.primary-navigation ul {
margin: 0;
padding: 0;
overflow: hidden;
}
.primary-navigation li {
width: 100%;
padding: 0;
margin: 0;
}
.primary-navigation ul ul {
display: block;
}
.primary-navigation ul ul ul {
display: block;
top: auto;
left: auto;
}
.primary-navigation li ul {
display: block;
position: relative;
}
.primary-navigation .current_page_item > a,
.primary-navigation .current-menu-item > a {
}
.primary-navigation .current_page_item > a:before,
.primary-navigation .current-menu-item > a:before {
content: " \27AF ";
margin-right: .2em;
}
}
Gli elementi che vengono nascosti con la proprietà display: none, vengono resi sempre visibili sugli schermi di
larghezza superiore a 800px. Inoltre sono state adattate le dimensioni degli elementi delle liste, che andranno ad occupare
tutta la larghezza disponibile (width: 100%). Per rendere più chiara la navigazione, infine, si è aggiunta una freccia
verso destra alla voce corrente del menu (content: " \27AF "). L’immagine che segue mostra l’effetto a video.
Si è, così, iniziato a progettare l’aspetto delle pagine. Va evidenziato che sono possibili molte alternative al menu
presentato, il cui scopo è, quindi, solo quello di fornire uno spunto per ulteriori analisi.
Per approfondire gli argomenti trattati in questo capitolo, si rinvia alle seguenti risorse:
• Funzione
body_class()
• Funzione
wp_nav_menu()
Il file style.css: i contenuti delle pagine
Terzo capitolo dedicato al file style.css. Nei precedenti si è definito il layout e si è analizzata nel dettaglio
l’intestazione delle pagine. Si è creato, inoltre, il menu di navigazione nello stile Suckerfish. In questo capitolo si vedrà
come assegnare gli stili alle pagine e ai post, per la parte che riguarda i testi e le immagini che costituiscono i contenuti,
nonché per la parte che riguarda i commenti dei lettori ed il form di risposta.
Così come il tag body_class() manda a video le classi del body, il tag post_class() stampa le classi dei singoli
post. Alcune di queste hanno valenza generale, come post o page. Altre sono più specifiche, come category-
{category-name} e tag-{tag-name}. Nel file allegato è disponibile l’elenco delle classi generate dalla funzione
post_class().
Nel tema che si sta sviluppando, i post sono racchiusi all’interno di un elemento article, che quindi sarà generato dalla
seguente stringa:
Strutturalmente, un articolo si scompone in un’intestazione contenente il titolo, in un riassunto (se previsto), nel contenuto
principale e in un footer contenente meta-tag e commenti:
<article>
<header
class="entry-header">
<h1
class="entry-title">...</h1>
</header>
<div
class="entry-summary">...</div> <!-- conditional -->
<div
class="entry-content">...</div>
<footer
class="entry-meta">...</footer>
</article>
In questa struttura, le classi non sono generate da WordPress, ma vengono aggiunte in fase di sviluppo nel template file.
Quelle che seguono sono alcune dichiarazioni che permettono di dar forma agli articoli:
.content-area article {
margin-bottom: 4.2em;
}
.entry-header {
margin-bottom: 1em;
}
.entry-title {
font-size: 2.2em;
margin-bottom: .5em;
}
.edit-link {
display: inline-block;
float: right;
text-transform: uppercase;
}
.edit-link a {
text-decoration: none;
padding: 0
.6em;
}
.edit-link a {
color: #397249;
background-color: #ececec;
}
.edit-link a:hover {
color: #9cb770;
}
.entry-summary {}
.entry-content {}
.entry-content a {
text-decoration: underline;
}
.entry-meta {
margin-top: 1.4em;
}
Ovviamente queste dichiarazioni sono solo quelle essenziali, e in fase di sviluppo si dovranno definire con maggior
dettaglio gli stili degli elementi. Tuttavia bastano già a dare alla pagina un aspetto accettabile, come evidenziato
dall’immagine che segue.
Una funzionalità dei temi ad alto valore aggiunto è costituita dalle immagini in evidenza. Se il tema supporta i post
thumbnails, questi possono essere inseriti all’interno di vari template per dar risalto ai singoli post, con un’immagine di
dimensioni prestabilite. Nei prossimi capitoli si vedrà come attivare questa funzionalità, per ora si imposteranno solo gli stili
per le classi predefinite, che sono le seguenti:
.attachment-{size} {}
.wp-post-image {}
size sta ad indicare le dimensioni impostate per l’immagine, che potrà essere post-thumbnail (nessuna dimensione
specificata), thumbnail, medium, large, full. Nel tema che si sta sviluppando, lo stile dell’immagine di anteprima
sarà il seguente:
.post-thumbnail img[class^=attachment] {
float: left;
margin: 0
1.2em
1.2em
0;
}
A beneficio degli schermi di dimensioni inferiori sarà integrata la media query dichiarata nei precedenti capitoli:
Gli
stili
dell’editor
WYSIWYG
Alcune classi vengono generate al momento della creazione dei contenuti nell’editor WYSIWYG. Queste classi permettono
di definire agevolmente l’allineamento degli elementi, la dimensione delle immagini, lo stile delle didascalie, e gran parte
del markup generato dall’editor.
Nel tema che si sta sviluppando vengono subito dichiarati i seguenti stili, necessari ad allineare gli elementi:
.wp-caption
{
margin-bottom: 2em;
}
.wp-caption
img[class*="wp-image-"] {
display: block;
margin: 0;
}
.wp-caption
{
color: #397249;
border: 2px
solid
#ececec;
margin: 0
.4em;
}
.wp-caption-text {
font-size: .8em;
font-style: italic;
line-height: 1.2em;
margin: .6em
0
0;
padding: .4em;
text-align: center;
background-color: #ececec;
}
.wp-smiley {
margin: 0
!important;
max-height: 1em;
}
Queste poche dichiarazioni non completano l’aspetto degli articoli, eppure danno a post e pagine un look già ben definito.
blockquote {
background: rgba(199, 225, 186, 0.6);
border: 1px
solid
rgba(57, 114, 73, 0.6);
color: rgb(57, 114, 73);
padding-left: .5em;
quotes: "«"
"»";
}
blockquote::before {
color: rgb(57, 114, 73);
content: open-quote;
font-size: 4em;
line-height: 0.1em;
margin-right: 0.25em;
vertical-align: -0.4em;
}
blockquote p {
margin: -1em
0
0
2em;
padding: 0.5em
.7em
1em;
}
Il risultato è nella figura che segue.
Le
gallerie
Sono molteplici le classi associate da WordPress agli elementi che compongono le gallerie di immagini. Queste vengono
ospitate da una div di classe gallery, mentre le singole immagini saranno inserite in elementi figure o dl, a seconda
che il tema supporti o meno le gallerie in HTML5.
In precedenza sono stati dichiarati alcuni stili per le immagini; gli stessi stili valgono per le gallerie, il cui markup si
presenta genericamente come segue:
Come si vede, l’elemento img è assegnato da WordPress alla classe attachment-thumbnail, mentre l’elemento dd
viene assegnato alla classe wp-caption-text. Gli stessi stili dichiarati sopra per le immagini di anteprima, vengono
applicati, quindi, alle immagini organizzate in gallerie.
L’elenco completo delle classi generate da WordPress per le gallerie di immagini, come per tutti gli elementi generati
dall’editor WYSIWYG, è disponibile nel file in allegato al capitolo .
Commenti
Se i commenti sono abilitati, al di sotto di ogni post o pagina viene visualizzato l’output del template comments.php. Il
markup generato rispetta la seguente struttura generale:
All’interno del form possono trovar posto un numero variabile di campi, a seconda che l’utente sia autenticato o meno.
Come si vede dal codice riportato, anche in questo caso gli elementi generati da WordPress vengono assegnati a classi
specifiche che ne permettono una facile selezione.
Tre soli blocchi di dichiarazioni e i commenti si distinguono nettamente dal resto della pagina:
.comment {
padding: .4em;
padding-left: 1em;
font-size: .9rem;
}
.thread-even {
background-color: #e9e9e9;
}
.comment-list .children {
margin-left: 1em;
}
Nel file CSS qui disponibile è riportato l’elenco completo dei selettori degli elementi che generano la struttura della
div.comments-area.
I form
Un lavoro più attento va svolto sui form, che potrebbero essere composti da un corposo set di elementi, tra cui i numerosi
input introdotti da HTML5. Nello sviluppo del tema di questa guida, si è fatto riferimento al foglio di stile dello starter
theme Underscore di Automattic. Il codice CSS che regola l’aspetto dei form è, dunque, il seguente:
button,
input,
select,
textarea {
font-size: 100%;
margin: 0;
vertical-align: baseline;
}
button,
input[type="button"],
input[type="reset"],
input[type="submit"] {
border: 1px
solid;
border-color: #ccc
#ccc
#bbb;
border-radius: 3px;
background: #e6e6e6;
box-shadow: inset
0
1px
0
rgba(255, 255, 255, 0.5), inset
0
15px
17px
rgba(255,
255, 255, 0.5), inset
0
-5px
12px
rgba(0, 0, 0, 0.05);
color: rgba(0, 0, 0, .8);
cursor: pointer;
-webkit-appearance: button;
font-size: 12px;
font-size: 1.2rem;
line-height: 1;
padding: .6em
1em
.4em;
text-shadow: 0
1px
0
rgba(255, 255, 255, 0.8);
}
button:hover,
input[type="button"]:hover,
input[type="reset"]:hover,
input[type="submit"]:hover {
border-color: #ccc
#bbb
#aaa;
box-shadow: inset
0
1px
0
rgba(255, 255, 255, 0.8), inset
0
15px
17px
rgba(255,
255, 255, 0.8), inset
0
-5px
12px
rgba(0, 0, 0, 0.02);
}
button:focus,
input[type="button"]:focus,
input[type="reset"]:focus,
input[type="submit"]:focus,
button:active,
input[type="button"]:active,
input[type="reset"]:active,
input[type="submit"]:active {
border-color: #aaa
#bbb
#bbb;
box-shadow: inset
0
-1px
0
rgba(255, 255, 255, 0.5), inset
0
2px
5px
rgba(0, 0, 0,
0.15);
}
input[type="checkbox"],
input[type="radio"] {
padding: 0; /* Addresses excess padding in IE8/9 */
}
input[type="search"] {
-webkit-appearance: textfield;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
input[type="text"],
input[type="email"],
input[type="url"],
input[type="password"],
input[type="search"],
textarea {
color: #666;
border: 1px
solid
#ccc;
border-radius: 3px;
}
input[type="text"]:focus,
input[type="email"]:focus,
input[type="url"]:focus,
input[type="password"]:focus,
input[type="search"]:focus,
textarea:focus {
color: #111;
}
input[type="text"],
input[type="email"],
input[type="url"],
input[type="password"],
input[type="search"] {
padding: 3px;
}
textarea {
overflow: auto;
padding-left: 3px;
vertical-align: top;
width: 100%;
}
Il lavoro sul foglio di stile non è ancora concluso, ma non manca molto. Nel prossimo capitolo si darà forma al sistema di
navigazione tra i post, alle sidebar con i rispettivi widget, e, infine, al footer delle pagine. In ultimo, si fornirà il foglio di
stile del tema in via di sviluppo ed un riferimento definitivo (e quasi completo) alle classi generate da WordPress.
• L’oggetto
WP_Theme
• CSS
Coding
Standard
• Funzione
post_class()
• Post
formats
• Post
Thumbnails
• TinyMCE
• Progetto
Underscores,
disponibile
su
Github
Le funzioni di WordPress che producono mark-up sono diverse, alcune delle quali assegnano una o più classi agli elementi
generati. Tra queste, wp_page_menu genera una div di classe menu contenente la lista non ordinata delle pagine:
wp_page_menu( 'show_home=1&exclude=56&menu_class=page-navi&sort_column=menu_order'
);
Tra i parametri passati alla funzione, menu_class permette di sovrascrivere la classe menu, assegnata di default al
container. L’output inviato al browser è strutturato come segue:
<div
class="page-navi">
<ul>
<li><a
href="http://example.com/">Home</a></li>
<li
class="page_item page-item-2">
<a
href="http://example.com/pagina-‐di-‐esempio/">Pagina di esempio</a>
</li>
<li
class="page_item page-item-4 current_page_item">
<li
class="page_item page-item-4 page_item_has_children current_page_item">
<a
href="http://example.com/nuova-‐pagina/">Nuova Pagina</a>
<ul
class="children">
<li
class="page_item page-item-56">
<a
href="http://example.com/nuova-‐pagina/pagina-‐figlio/">Pagina
figlio</a>
</li>
</ul>
</li>
</ul>
</div>
La funzione wp_list_pages genera una lista pressoché identica alla precedente, con la sola differenza che gli elementi
dell’elenco non vengono inseriti in una div, ma in un elemento li di classe pagenav:
<li
class="pagenav">
Pagine
<ul>
...
</ul>
</li>
Seguendo lo stesso schema degli elenchi di pagine, la funzione wp_list_categories genera un list item contenente
una o più liste annidate, i cui elementi individuano le categorie o qualsiasi tassonomia registrata. Queste le classi generate
dal framework:
Se alla funzione wp_list_categories viene richiesta una tassonomia, al list item esterno sarà assegnato un nome di
classe corrispondente al nome della tassonomia.
Le sidebar e i widget
Per WordPress una sidebar non è letteralmente una barra laterale, ma un’area destinata ad accogliere widget, ossia
blocchi di codice HTML generati dinamicamente. WordPress dispone di una dozzina di widget predefiniti, i quali generano
elenchi di categorie, articoli recenti, tag, pagine, menu personalizzati, ed altro ancora. Una sidebar viene inserita nel tema
grazie alla seguente funzione:
La funzione dynamic_sidebar() manda a video la sidebar-primary, che sarà definita più avanti nel file
functions.php. La sidebar così generata viene popolata di widget dalla pagina di amministrazione "Aspetto > Widget".
Ognuno di questi ha una precisa struttura HTML, e ai rispettivi elementi vengono assegnati classi e id che permettono di
selezionarli agevolmente.
Figura 1. I widget vengono aggiunti alla sidebar con una semplice operazione di drag & drop.
Due nomi di classe sono comuni a tutti i widget:
La prima classe viene assegnata alla div esterna, mentre la seconda all’elemento h2 che racchiude il titolo. Si deve
sottolineare che sia le classi widget e widgettitle, che l’elemento h2, possono essere sostituiti con nomi di classe ed
elementi HTML personalizzati, come si vedrà più avanti in questa guida. Alla div esterna, oltre alla classe widget, viene
assegnata una classe specifica per il tipo di widget:
.widget_categories {}
.widget_recent_comments {}
.widget_calendar {}
.widget_recent_entries {}
.widget_archive {}
.widget_nav_menu {}
.widget_pages {}
.widget_text {}
.widget_tag_cloud {}
.widget_rss {}
.widget_meta {}
.widget_search {}
I contenuti dei widget vengono generalmente visualizzati all’interno di liste non ordinate, a meno che non si tratti di
elementi specifici, come il calendario e il box di ricerca. Per il tema "seventyone", che si sta sviluppando in questa guida,
sono state impostate le dimensioni generali dei widget con la seguente dichiarazione:
.widget {
line-height: 2;
margin-bottom: 2em;
width: 100%;
}
.widget_calendar table {
width: 100%;
line-height: 2;
margin: 0;
}
.widget_calendar caption
{
color: #fff;
font-weight: 700;
line-height: 1.7142857142;
margin-bottom: 18px;
text-align: left;
text-transform: uppercase;
}
.widget_calendar tbody {
border-bottom: 1px
solid
rgba(57, 114, 73, 0.6);
border-top: 1px
solid
rgba(57, 114, 73, 0.6);
}
.widget_calendar tbody td,
.widget_calendar thead th {
text-align: center;
}
.widget_calendar tbody a {
background-color: rgba(199, 225, 186, 0.6);
display: block;
}
.widget_calendar tbody a:hover {
background-color: #c7e1ba;
color: #000;
}
.widget_calendar #prev {
padding-left: 5px;
}
.widget_calendar #next {
padding-right: 5px;
text-align: right;
}
Nel box di ricerca viene, infine, nascosto il pulsante di invio:
/* Search Widget*/
.widget_search input[type="submit"] {
visibility: hidden;
display: none;
}
Potrebbe sembrare che la progettazione delle sidebar, e soprattutto dei widget, comporti un gran lavoro di codifica CSS.
Eppure, a ben guardare, dal punto di vista strutturale i widget non si differenziano molto l’uno dall’altro. Il numero
consistente di classi potrà essere un utile strumento per rifinire e differenziare, ma l’aspetto base potrà essere definito con
dichiarazioni di carattere generale:
Nello “zip” allegato è disponibile l’elenco completo dei selettori degli elementi che compongono i widget predefiniti.
Il footer
Il piè di pagina può ospitare diverse informazioni: un menu di navigazione alternativo, disclaimer e informazioni di
copyright, collegamenti a social network ed anche un form per un contatto rapido. Grazie ai widget, è possibile inserire e
modificare queste informazioni direttamente dal pannello di amministrazione. Chi sviluppa il tema potrà, quindi, prevedere
una nuova sidebar.
#footer-sidebar {
border-bottom: 1px
solid
black;
border-top: 1px
solid
black;
overflow: hidden;
width: 100%
}
#footer-sidebar .widget {
margin-right: 0.52083335%;
margin-left: 0.52083335%;
padding: 0.52083335%;
width: 22.9166666%;
float: left;
background-color: #eee;
}
Gli elementi div.widget sono affiancati a sinistra con la proprietà float. Un problema dei layout basati sui float è che
i contenitori collassano su se stessi se non opportunamente progettati. In questo caso si è fatto ricorso ad una tecnica poco
nota, ma perfettamente cross-browser. Il primo blocco di dichiarazioni, quindi, permetterà al contenitore #footer-
sidebar di non collassare, e i blocchi interni ed esterni saranno resi correttamente. Il secondo blocco assegna le
dimensioni ai widget e li affianca l’uno all’altro.
L’ultimo task consiste nel rendere responsive la sidebar del footer. Se nel layout generale si è voluto dare ai singoli widget
una larghezza pari a circa il 25% dell’area disponibile, su schermi di dimensioni inferiori sarà opportuno ridimensionarli.
Ad esempio, se la finestra del browser ha una larghezza in pixel compresa tra i 640 e gli 800, i widget potrebbero occupare
ognuno la metà (circa) della larghezza del contenitore:
• wp_page_menu
• wp_list_pages
• wp_list_categories
• register_sidebar
• Clearing
floats
Lo scopo del file index.php è quello di generare dinamicamente il mark-up delle pagine. In un tema estremamente
semplice, si può affidare questo compito al solo index.php; in un tema più complesso sarà necessario creare template ad-
hoc. Alcuni di questi generano la struttura generale della pagina (blog, archivio, pagina singola, ecc.), altri, invece, generano
il codice di specifiche parti.
Così i template header.php, sidebar.php e footer.php, saranno inclusi nel file index.php, e produrranno
rispettivamente il mark-up dell’intestazione, della sidebar e del fondo della pagina. Si supponga, quindi, che la struttura
della pagina sia così articolata:
Anche se non è indispensabile, spesso il codice PHP del file index viene preceduto da meta-dati che forniscono alcune
informazioni generali sul template, come il nome del CMS, il nome e la versione del tema:
/**
* @package WordPress
* @subpackage Seventy-One-WordPress-Theme
* @since Seventy One 1.0
*/
Subito dopo aver incluso l’header, il file index.php provvede a generare la parte principale della pagina, dove vengono
visualizzati i contenuti archiviati nella tabella wp_posts del database. In questa parte del documento, oltre ai contenuti,
vengono spesso inserite le categorie e le tassonomie associate agli articoli (tag e custom taxonomies). Quello che segue è lo
script completo del file index.php del tema “Seventyone”:
La prima istruzione del file include il template header.php. Invece delle consuete funzioni include() e require(),
è consigliato utilizzare una funzione propria del framework di WordPress: get_header():
Il file header.php genera i tag di apertura del documento, <doctype> e <html>, il tag di apertura <head> e tutti i
meta tag; incorpora gli script e i fogli di stile e, infine, genera la parte superiore della pagina, ossia header e menu di
navigazione. Tale file header.php sarà analizzato dettagliatamente nel prossimo capitolo.
Il contenuto viene racchiuso nelle due div, #main-content e #content. Il blocco condizionale verifica l’esistenza di
post che corrispondono alla richiesta dell’utente e, in caso positivo, avvia un ciclo iterativo, definito Loop, che recupera dal
database gli articoli.
Le istruzioni interne al Loop dovranno generare l’output HTML. Queste istruzioni possono essere inserite direttamente nel
file index.php, oppure inserite in template specifici, incorporati nel file dalla funzione get_template_part. Nel
tema Seventyone è stato previsto di creare un template specifico per ogni formato di post.
get_template_part incorpora quindi un template individuato dai due argomenti accettati dalla funzione:
Per quanto detto, sarà necessario creare un template generico e tanti template specifici per quanti sono i formati di post
supportati dal tema. Pertanto bisognerà creare i seguenti file:
• content.php
• content-aside.php
• content-audio.php
• content-gallery.php
• content-image.php
• content-link.php
• content-none.php
• content-quote.php
• content-video.php
Oltre al template generico content.php e ai template specifici per ogni formato, è stato previsto il template content-
none.php, che sarà incorporato nel file index.php nel caso in cui non siano presenti articoli corrispondenti alla
richiesta dell’utente. Quello che segue è il codice del file content.php del tema Seventyone:
Tag, attributi e contenuti vengono generati dinamicamente, grazie ai template tags. Per sintetizzare l’analisi, lo stesso codice
sarà inserito in tutti i template content-{postformat}.php.
Il discorso sul file index.php è ampio e sarà esaurito nel proseguio della guida, quando esamineremo la prima versione
del tema “Seventyone”.
Nello script appena visto si è più volte fatto ricorso alla funzione _e(): questa genera un testo corrispondente alla
traduzione della stringa passata come primo argomento (il secondo argomento definisce il textdomain dove recuperare la
traduzione). La funzione posted_on() non fa parte del framework, ma viene definita nel file functions.php come
segue:
Oltre alle due funzioni riportate qui sopra, si è fatto ricorso a svariati tag del framework:
Tag Descrizione
Manda
a
video
una
stringa
con
l’ID
del
post
corrente;
va
utilizzata
the_ID()
all’interno
del
Loop.
Manda
a
video
le
classi
associate
al
post
corrente;
questo
tag
può
post_class()
essere
utilizzato
all’interno
o
all’esterno
del
Loop.
E’
un
conditional
tag
che
testa
se
la
pagina
corrente
sia
una
pagina
is_single()
singola
(tipo
di
post,
pagina
o
allegato),
o
una
pagina
di
archivio.
Manda
a
video
o
restituisce
una
stringa
con
il
titolo
del
post
corrente;
the_title()
va
utilizzata
all’interno
del
Loop.
Manda
a
video
un
link
alla
pagina
di
modifica
del
post
corrente;
può
edit_post_link()
essere
utilizzata
all’interno
o
all’esterno
del
Loop.
E’
un
conditional
tag
che
testa
se
la
pagina
corrente
mostra
i
risultati
is_search()
di
una
ricerca.
Testa
se
la
pagina
corrente
è
una
home
page
strutturata
come
blog
di
is_home()
notizie.
Testa
se
il
post
corrente
dispone
di
un’immagine
di
anteprima;
va
has_post_thumbnail()
utilizzata
all’interno
del
Loop.
Genera
il
codice
HTML
dell’immagine
di
anteprima;
va
utilizzata
nel
the_post_thumbnail()
Loop.
the_excerpt() Mostra
il
riassunto
del
post
corrente;
va
utilizzata
nel
Loop.
the_content() Mostra
il
contenuto
del
post
corrente;
va
utilizzata
nel
Loop.
Genera
il
codice
HTML
dei
link
agli
archivi
dei
tag
associati
al
post
the_tags()
corrente;
deve
essere
utilizzato
all’interno
del
Loop.
the_category() Genera
il
codice
HTML
dei
link
agli
archivi
delle
categorie
del
post
corrente;
deve
essere
utilizzato
all’interno
del
Loop.
comments_open() Testa
se
per
il
post
o
per
la
pagina
corrente
i
commenti
sono
aperti.
Genera
un
link
alla
finestra
di
pop-‐up
dei
commenti;
se
questa
non
è
comments_popup_link()
attiva,
genera
un
normale
link
alla
lista
dei
commenti.
Nel caso in cui non esistano articoli corrispondenti alla richiesta dell’utente, viene incluso nel documento il template
content-none.php:
Nella tabella che segue sono elencati i tag cui si è fatto ricorso:
Tag Descrizione
Testa
se
la
pagina
corrente
è
una
home
page
strutturata
come
blog
di
is_home()
notizie.
current_user_can() Testa
se
l’utente
collegato
ha
i
privilegi
per
accedere
alla
risorsa
corrente.
Genera
un
link
al
pannello
di
amministrazione;
i
parametri
passati
come
admin_url()
argomento
permettono
di
stabilire
la
pagina
specifica.
is_search() Testa
se
la
pagina
corrente
mostra
i
risultati
di
una
ricerca.
get_search_form() Manda
a
video
il
form
di
ricerca
generato
dal
template
file
searchform.php.
Anche qui, per la corretta localizzazione dei testi, si è fatto ricorso alla funzione _e().
I commenti
Qualora il blog/sito Web sia aperto ai commenti degli utenti, subito dopo la generazione del contenuto dell’articolo, sarà
necessario predisporre un’area dedicata in cui inserire il form e la lista dei commenti. Nel file index.php di
“Seventyone”, si è utilizzato il seguente blocco condizionale:
Il conditional tag is_single() restituisce true qualora l’utente abbia richiesto un articolo o una pagina singola. Nel
caso in cui la condizione sia verificata, il template tag comments_template() incorpora nel documento il template file
comments.php, che sarà analizzato nel dettaglio nei prossimi capitoli.
La
navigazione
Nel file index.php va predisposto anche un sistema di navigazione tra gli articoli del sito Web. Al di fuori del Loop
bisognerà inserire il codice che genera i link che puntano alle pagine precedenti e successive. Nel file index.php di
“Seventyone” viene invocata la funzione post_navigation():
Seguendo la stessa logica del tag get_header(), queste ultime due funzioni includono nel documento i template
sidebar.php e footer.php. Il primo genera un’area widget; il secondo genera il fondo della pagina. I due template
saranno analizzati dettagliatamente nei prossimi capitoli.
Il file index.php non è costituito da uno script indipendente, ma da frammenti di codice distribuiti in diversi template
file, ognuno destinato a generare una parte specifica del documento. Nei prosimi capitoli si analizzeranno nel dettaglio i
template file che qui sono stati solo presentati, a cominciare dal file header.php.
Si rinvia al Codex per ogni informazione sui template tag e sulle altre funzioni del framework qui riportate. È utile
approfondire gli argomenti trattati tramite le seguenti risorse:
• The
Loop
• I18n
for
WordPress
Developers
La struttura dell’intestazione
Lo script genera l’intestazione del documento HTML e la parte superiore della pagina. L’output comprenderà, quindi, il
doctype, i tag di apertura degli elementi html e body, nonché l’elemento head con i relativi meta tag, gli script e i
fogli di stile. Questi, naturalmente, possono essere inseriti direttamente nel documento o inclusi con gli elementi link e
script. Quello che segue è un esempio dell’intestazione generato dal file header.php:
<!doctype html>
<html
class="no-js">
<head>
<meta
charset="UTF-8">
<meta
name="viewport"
content="width=device-width, initial-scale=1">
...
<title>Seventyone | Un nuovo sito targato WordPress</title>
<link
rel="stylesheet"
href="style.css"
/>
<script
src="/js/vendor/modernizr-2.8.3.min.js"></script>
</head>
Lo script provvede anche a generare la parte superiore della pagina e il menu di navigazione principale. La struttura su cui si
svilupperà l’intestazione del tema Seventyone è la seguente:
Una volta definita la struttura, si può procedere alla progettazione dello script. Esattamente come per il file index.php, le
istruzioni PHP e il codice HTML del file header.php sono precedute dai meta-dati che identificano il tema:
<?php
/**
* @package WordPress
* @subpackage Seventy-One-WordPress-Theme
* @since Seventy One 1.0
*/
?>
Subito dopo vanno generati il doctype e l’apertura dei tag <html> e <head>:
<!doctype html>
<!--[if lt IE 7]><html class="no-js lt-ie9 lt-ie8 lt-ie7" <?php
language_attributes(); ?>> <![endif]-->
<!--[if IE 7]><html class="no-js lt-ie9 lt-ie8" <?php language_attributes(); ?>>
<![endif]-->
<!--[if IE 8]><html class="no-js lt-ie9" <?php language_attributes(); ?>>
<![endif]-->
<!--[if gt IE 8]><!--><html
class="no-js"
<?php language_attributes(); ?>> <!--
<![endif]-->
<!-- the "no-js" class is for Modernizr. -->
<head>
I tag condizionali permettono di definire un elemento html specifico per ogni versione di Internet Explorer. In questo
blocco di codice, l’unica istruzione PHP è data dalla funzione language_attributes(), che genera gli attributi
specifici per la lingua del sito.La classe no-js è, infine, richiesta dalla libreria Modernizr.
Si prosegue, quindi, con l’elemento head. Questo conterrà tutti i meta-tag del documento:
<head>
<meta charset="<?php bloginfo('charset'); ?>">
<meta name="viewport"
content="width=device-width, initial-scale=1">
<meta name="title"
content="<?php wp_title( '|', true, 'right' ); ?>">
<meta name="description"
content="<?php bloginfo('description'); ?>"
/>
...
Del template tag bloginfo()si è già detto nei capitoli precedenti: qui i parametri charset e description
forniscono la codifica e la descrizione del sito, come memorizzati nelle impostazioni generali e di lettura del pannello di
amministrazione. La funzione wp_title(), invece, genera il titolo del sito. Si passa, quindi, agli elementi title, link
e script:
<head>
...
<title><?php wp_title( '|', true, 'right'
); ?></title>
<link rel="profile"
href="http://gmpg.org/xfn/11">
<link rel="pingback"
href="<?php bloginfo( 'pingback_url' ); ?>">
<!-- <link rel="stylesheet"
href="<?php echo get_template_directory_uri();
?>/css/normalize.css"> -->
<link rel="stylesheet"
href="<?php echo get_stylesheet_uri(); ?>"
/>
<!-- Lea Verou's Prefix Free, lets you use
only un-prefixed properties in yuor
CSS files -->
<script src="<?php echo get_template_directory_uri();
?>/js/vendor/prefixfree.min.js"></script>
<script src="<?php echo get_template_directory_uri(); ?>/js/vendor/modernizr-
2.8.3.min.js"></script>
Ancora una volta si è fatto ricorso alla funzione bloginfo(), cui è stato passato, questa volta, il parametro
pingback_url. Le funzioni get_template_directory_uri() e get_stylesheet_uri() forniscono due
dati diversi: la directory del tema corrente e l’URL del foglio di stile. Come si vede, nel tema Seventyone si fa ricorso al
foglio di stile normalize.css, allo script -prefix-free e alla libreria Modernizr.
Infine, subito prima del tag di chiusura </head>, va invocata la funzione wp_head(), che completa l’intestazione del
documento:
<head>
...
<?php wp_head(); ?>
</head>
Chiuso il tag <head>, si va a generare la parte superiore della pagina. Viene aperto il tag <body> e creata l’a testata con il
menu di navigazione:
Il primo elemento discendente è un header, che contiene il titolo e la descrizione del sito in h1 e h3. L’header, inoltre,
contiene il menu di navigazione principale, racchiuso in un elemento nav. All’interno vengono invocate le funzioni
wp_nav_menu e get_search_form. La prima genera il menu di navigazione, strutturato come lista non ordinata di
elementi. Qualora siano presenti dei sottomenu, questi vengono strutturati nella forma di liste annidate, sicché un elemento
li di un menu sovraordinato diventa il parent di un sottomenu. La seconda funzione, infine, genera un form di ricerca.
Nella tabella che segue vengono elencate le funzioni del framework cui si è fatto riferimento nella progettazione del file
header.php del tema Seventyone.
Funzione Descrizione
language_attributes() Mostra
gli
attributi
specifici
della
lingua
del
sito.
Filtra
le
URL
codificando
i
caratteri
speciali,
elimina
caratteri
esc_url() non
validi
o
pericolosi,
rimuove
le
URL
che
non
appartengono
a
protocolli
noti.
wp_title() Mostra
o
recupera
il
titolo
del
sito.
bloginfo()
Mostra
a
video
informazioni
sul
sito
in
base
ai
parametri
passati
come
argomenti.
get_bloginfo()
Restituisce
informazioni
sul
sito
in
base
ai
parametri
passati
come
argomenti.
get_template_directory_uri() Restituisce
la
directory
in
cui
è
istallato
il
tema
corrente.
get_stylesheet_uri() Restituisce
l’URL
del
foglio
di
stile
del
tema
corrente.
wp_head() Genera
le
intestazioni
del
documento.
language_attributes() Manda
a
video
le
classi
associate
al
body.
wp_nav_menu()
Mostra
un
menu
di
navigazione
creato
nella
scheda
“Menus”
del
pannello
di
amministrazione.
get_search_form() Mostra
un
form
di
ricerca.
Il tag get_header
Si è detto che il file header.php viene incluso nel file index.php grazie all’include tag get_header(). Se al tag
non viene passato alcun argomento, la funzione include l’header.php generico; tuttavia è possibile creare un header
diverso per ogni tipo di pagina. Questo dovrà avere un nome composto dal prefisso header e da un suffisso che
individua il template: header-{slug}.php. Ad esempio, l’istruzione
Lo script includerà nel template corrente il file header-home.php. Predisponendo, quindi, template specifici, si
potranno differenziare gli header a seconda della pagina richiesta dall’utente. Come si vedrà nei prossimi capitoli, la stessa
logica può essere applicata ai template che generano le sidebar e il footer delle pagine.
WordPress permette di creare più aree widget all’interno della stessa pagina, come anche di creare aree widget specifiche
per i diversi tipi di pagine disponibili in un tema. Prima di essere inserita nelle pagine, una sidebar va registrata nel file
functions.php, grazie alla funzione register_sidebar:
if
( function_exists('register_sidebar'
)) {
function
seventyone_widgets_init() {
register_sidebar( array(
'name'
=> __( 'Sidebar Widgets', 'seventyone'
),
'id'
=> 'sidebar-primary',
'before_widget'
=> '<div id="%1$s" class="widget %2$s">',
'after_widget'
=> '</div>',
'before_title'
=> '<h3 class="widget-title">',
'after_title'
=> '</h3>',
) );
register_sidebar( array(
'name'
=> __( 'Sidebar Footer', 'seventyone'
),
'id'
=> 'sidebar-footer',
'before_widget'
=> '<div id="%1$s" class="widget %2$s">',
'after_widget'
=> '</div>',
'before_title'
=> '<h3 class="widget-title">',
'after_title'
=> '</h3>',
) );
}
add_action( 'widgets_init', 'seventyone_widgets_init'
);
}
Una
volta
registrate,
le
sidebar
appaiono
nel
menu
“Aspetto
→
Widget”
del
pannello
di
amministrazione.
Nel capitolo dedicato al file index.php, si è visto che sidebar.php viene incluso nel template principale dal tag
get_sidebar():
L’argomento $name è facoltativo ed è costituito da una stringa che rappresenta il nome di un template specifico
sidebar-{$name}.php. Se non viene passato alcun argomento, la funzione include il template sidebar.php
principale, che nel tema Seventyone contiene il seguente script:
<aside id="sidebar">
<?php if
( is_active_sidebar( 'sidebar-primary'
) ) : ?>
<div id="primary-sidebar"
class="primary-sidebar widget-area"
role="complementary">
<?php dynamic_sidebar( 'sidebar-primary'
); ?>
</div><!-- #primary-sidebar -->
<?php endif; ?>
</aside>
Il conditional tag is_active_sidebar() verifica se una data sidebar sia attiva, ossia contenga widget. L’argomento
individua la sidebar da verificare, che nell’esempio, è la sidebar principale. Nel caso in cui sia presente almeno un widget,
viene generata la div#primary-sidebar e, quindi, invocata la funzione dynamic_sidebar(), che avvia le varie
callback che generano i widget. Anche quest’ultima funzione aspetta come argomento l’identificativo della sidebar.
Risulterà il seguente markup:
<aside id="sidebar">
<div id="primary-sidebar"
class="primary-sidebar widget-area"
role="complementary">
<!-- widget -->
<!-- widget -->
<!-- widget -->
</div><!-- #primary-sidebar -->
</aside>
Il template footer.php
footer.php, oltre a generare la parte inferiore della pagina, chiude i tag aperti nel file header.php. Anche questo file
viene incluso nel template principale da un tag specifico:
L’argomento $name, come già visto per le funzioni get_header() e get_sidebar(), individua il nome del template
specifico footer-{$name}.php. In mancanza dell’argomento, get_footer() include il template generico. Il
footer.php del tema Seventyone contiene il seguente codice:
Il conditional tag is_active_sidebar verifica che la sidebar-footer sia registrata e contenga widget: in caso
positivo, viene generato il markup della seconda sidebar. Al di fuori del blocco condizionale, la div#site-info ospiterà
le informazioni di copyright.
Un ultimo tag, wp_footer(), va inserito "sempre" prima della chiusura del tag <body>. Questa funzione, tra l’altro,
genera gli script che molti plugin prevedono di includere nella parte inferiore del documento. Pertanto, per evitare che
alcuni plugin non funzionino correttamente, andrebbe sempre inserito.
Si torni ancora una volta al file index.php per individuare le seguenti tre righe di codice:
if( is_single() ) :
comments_template();
endif;
Il conditional tag is_single() verifica che l’utente abbia richiesto una pagina singola (post, pagina o custom post type).
Nel caso in cui la condizione sia verificata, il tag comments_template() include nella pagina lo script del file
comments.php. Questo genera la lista dei commenti, il sistema di navigazione e il form di trasmissione.
if
( post_password_required() ) {
return;
}
?>
Qualora il tag post_password_required() restituisse false, lo script sarebbe interrotto. Si apre quindi il container e
si genera il titolo dell’area dei commenti:
Una volta verificato che esistano commenti (have_comments()), viene mandato a video un titolo h2. La funzione _n()
restituisce una stringa diversa a seconda che il valore di get_comments_number() sia o meno maggiore di uno;
number_format_i18n() formatta un numero in base alle impostazioni locali; infine, get_the_title() restituisce
il titolo del post. Il codice HTML generato è il seguente:
Nella scheda di amministrazione “Impostazioni > Discussione” è possibile stabilire un numero massimo di commenti per
pagina. Bisognerà, per questo, prevedere un sistema di navigazione:
La funzione get_comment_pages_count() restituisce il numero di pagine in cui sono suddivisi i commenti, mentre
get_option( 'page_comments' ) restituisce 1 nel caso in cui i commenti sono suddivisi in pagine, 0 in caso
contrario. Il test, quindi, verifica che sia stata impostata la paginazione dei commenti. Viene, quindi, generato un elemento
nav destinato ad ospitare i link alla pagina precedente e alla pagina successiva.
<ol class="comment-list">
<?php
wp_list_comments( array(
'style'
=> 'ol',
'short_ping'
=> true,
'avatar_size'=> 34,
) );
?>
</ol><!-- .comment-list -->
La funzione wp_list_comments() genera il codice HTML della lista, che sarà strutturata in base ai parametri
dell’array argomento:
Dopo la lista, può essere opportuno riproporre il sistema di navigazione, per evitare che l’utente ritorni alla parte superiore
della pagina per sfogliare le pagine dei commenti.
Il tag comment_form() genera il markup necessario. La tabella che segue offre un riepilogo delle funzioni del
framework utilizzate.
Funzione Descrizione
comments_open() Verifica
se
i
commenti
sono
ammessi
comment_form() Genera
il
form
dei
commenti
have_comments() Verifica
se
esistono
per
il
post
corrente
Restituisce
una
stringa
corrispondente
al
primo
o
al
secondo
_n()
argomento,
a
seconda
che
il
terzo
sia
uguale
o
superiore
a
1
get_comments_number() Restituisce
il
numero
dei
commenti
ad
un
dato
articolo
get_comment_pages_count() Calcola
il
numero
di
pagine
in
cui
sono
suddivisi
i
commenti
Preleva
il
valore
di
un’opzione
dal
database,
in
base
al
parametro
get_option()
passato
come
argomento
Restituisce
il
titolo
di
un
articolo;
se
utilizzata
all’esterno
del
Loop
get_the_title()
prevede
come
argomento
l’id
dell’articolo
Converte
un
numero
intero
in
un
formato
basato
sulle
number_format_i18n()
impostazioni
locali
next_comments_link() Genera
il
link
alla
successiva
pagina
dei
commenti
previous_comments_link() Genera
il
link
alla
precedente
pagina
dei
commenti
wp_list_comments() Genera
la
lista
dei
commenti
in
base
ai
parametri
passati
Riferimenti
Come sempre, si raccomanda un’attenta lettura delle risorse del Codex, con particolare attenzione alle funzioni presentate in
questo capitolo. Oltre a quelle già segnalate, si aggiungono due utili risorse per chi sviluppa temi:
• Sidebars
• Option
Reference
Nel caso del file index.php, vengono generalmente richiesti i post più recenti, indipendentemente dalla categoria o dalle
etichette (tag) associate. Un archivio categoria, invece, è più specifico e mostrerà solo i post appartenenti alla categoria.
Il template single.php funziona esattamente allo stesso modo, con la sola particolarità che la query restituirà un result
set di un solo elemento. I post recuperati dal database sono disponibili nell’oggetto $posts e vengono gestiti tramite un
ciclo iterativo definito Loop. All’interno del ciclo, template tag, conditional tag e include tag permettono di accedere in
sicurezza ad ogni singola informazione associata ai post.
The
Loop
if
(have_posts()) :
while
(have_posts()) : the_post();
...
endwhile;
else:
...
endif;
All’interno del Loop andranno inserite le istruzioni che permettono di visualizzare le informazioni recuperate dal database.
A questo scopo, come illustrato in precedenza, WordPress fornisce un gran numero di template tag. Quello che segue è un
Loop che genera le informazioni essenziali di ogni post:
<?php
if
(have_posts()) :
while
(have_posts()) : the_post(); ?>
<article id="post-<?php the_ID(); ?>"
<?php post_class(); ?>>
<header class="entry-header">
<?php the_title( '<h1 class="entry-title"><a href="'
. esc_url(
get_permalink() ) . '" rel="bookmark">', '</a></h1>'
); ?>
</header>
<div class="entry-content">
<?php the_content(); ?>
</div>
<footer class="entry-meta">
<?php the_tags(__('Tags: ','seventyone'), ', ', '<br />'); ?>
<?php _e('Posted in','seventyone'); ?> <?php the_category(', ') ?> |
<?php
if
( comments_open() ) :
comments_popup_link(__('No Comments »','seventyone'), __('1
Comment »','seventyone'), __('% Comments »','seventyone'));
endif; ?>
</footer>
<?php endwhile;
else: ?>
<header class="page-header">
<h1 class="page-title"><?php _e( 'Nothing Found', 'seventyone'
); ?></h1>
</header>
<?php endif; ?>
Il Loop appena visto non è ancora completo, ma è sufficiente per comprendere come utilizzare i template tag. Quelli che
seguono sono i tag di uso più comune all’interno del Loop:
Funzione Descrizione
the_permalink() Mostra
la
URL
del
post
corrente
the_title() Mostra
il
titolo
del
post
the_author() Mostra
il
display
name
dell’autore
the_time()
e
the_date() Mostrano
la
data
del
post
the_excerpt()
e
the_content() Mostrano
il
riassunto
e
il
contenuto
del
post
the_meta() Genera
una
lista
non
ordinata
dei
custom
field
associati
al
post
the_category()
e
the_tags() Generano
le
liste
delle
categorie
e
dei
tag
del
post
Queste funzioni non fanno altro che mandare a video i dati già disponibili nell’oggetto $post. Per una gestione più
avanzata del dati, può essere opportuno manipolarli via PHP prima che venga generato l’output HTML. A tal fine, come si
ricorderà, WordPress fornisce i tag get_, che restituiscono i dati come valori di variabili. Al posto del tag
the_category, ad esempio, si può ricorrere al tag get_the_category(), che restituisce l’elenco delle categorie del
post sotto forma di array:
Nell’elenco che segue sono riportati alcuni dei tag get_ di uso più comune:
• get_permalink
• get_the_title
• get_the_author
• get_the_time
• get_the_date
• get_the_content
• get_post_meta
• get_metadata
• get_the_category
• get_the_tags
Spesso è necessario testare una condizione prima di visualizzare i dati. Ciò avviene, ad esempio, quando l’utente stesso
richieda un post singolo invece di un archivio di articoli, oppure quando bisogna verificare che l’utente sia autenticato. I
conditional tag sono quelle funzioni del framework che, appunto, permettono di verificare specifiche condizioni, restituendo
true in caso di successo, false in caso contrario. Quello che segue è un elenco dei tag condizionali a cui probabilmente
si farà maggior ricorso:
Funzione Descrizione
is_home() Verifica
se
l’utente
ha
richiesto
la
home
page
del
sito
is_front_page() Verifica
se
la
pagina
iniziale
sia
un
post
o
una
pagina
statica
is_single() Verifica
se
la
richiesta
corrisponde
ad
un
post
o
una
pagina
singola
is_sticky()
Verifica
se
il
post
corrente
sia
stato
contrassegnato
come
post
in
evidenza
is_category()
e
Verificano
se
la
richiesta
corrisponde
ad
una
pagina
d’archivio
di
una
is_tag() categoria
o
di
un
tag
is_archive() Verifica
se
la
richiesta
corrisponde
ad
una
qualsiasi
pagina
di
archivio
is_search() Verifica
se
la
richiesta
corrisponde
al
risultato
di
una
ricerca
comments_open() Verifica
che
sul
post
corrente
siano
abilitati
i
commenti
is_user_logged_in() Verifica
che
l’utente
corrente
sia
autenticato
A questo punto dell’analisi, sarà ben chiaro il Loop del file index.php di Seventyone:
<?php
if
(have_posts()) :
// The Loop.
while
(have_posts()) : the_post(); ?>
<article id="post-<?php the_ID(); ?>"
<?php post_class(); ?>>
<header class="entry-header">
<?php
if
( is_single() ) :
the_title( '<h1 class="entry-title">', '</h1>'
);
else
:
the_title( '<h1 class="entry-title"><a href="'
. esc_url(
get_permalink() ) . '" rel="bookmark">', '</a></h1>'
);
endif;
?>
<?php posted_on(); ?>
<?php edit_post_link( __( 'Edit', 'seventyone'
), '<span
class="edit-link">', '</span>'
); ?>
</header>
<?php if
( is_search() || is_home() ) : ?>
<div class="entry-summary">
<?php
if
( has_post_thumbnail() ){
?>
<div class="post-thumbnail"><?php the_post_thumbnail(
'thumbnail'
); ?></div>
<?php
}
?>
<?php the_excerpt(); ?>
</div><!-- .entry-summary -->
<?php else
: ?>
<div class="entry-content">
<?php the_content(); ?>
</div>
<footer class="entry-meta">
<?php the_tags(__('Tags: ','seventyone'), ', ', '<br />'); ?>
<?php _e('Posted in','seventyone'); ?> <?php the_category(', ') ?>
|
<?php
if
( comments_open() ) :
comments_popup_link(__('No Comments »','seventyone'), __('1
Comment »','seventyone'), __('% Comments »','seventyone'));
endif;
?>
</footer>
<?php endif; ?>
</article>
<?php
if( is_single() ) :
comments_template();
endif;
endwhile;
?>
La funzione posted_on() non fa parte del framework di WordPress, ma è stata definita nel file functions.php come
segue:
function
posted_on() {
printf( __( '<span class="sep">Posted </span><a href="%1$s" title="%2$s"
rel="bookmark"><time class="entry-date" datetime="%3$s" pubdate>%4$s</time></a> by
<span class="byline author vcard">%5$s</span>', ''
),
esc_url( get_permalink() ),
esc_attr( get_the_time() ),
esc_attr( get_the_date( 'c'
) ),
esc_html( get_the_date() ),
esc_attr( get_the_author() )
);
}
In questo modo viene mandato a video uno span con il permalink del post, la data di pubblicazione e il nome a video
dell’autore.
Più avanti in questa guida, si vedrà che i template file possono diventare sempre più complessi, man mano che si
aggiungono funzionalità al tema o aumenta il numero di opzioni di configurazione. Per tenere in ordine il codice, può essere
quindi opportuno creare file che contengono parti di template.
Seguendo lo schema del tema "Twentyfourteen", in "Seventyone" si è creato un template per ogni formato di post
disponibile. Il codice PHP e HTML compreso all’interno del Loop viene quindi inserito nei template content-
{post_format}.php, mentre nel file index.php rimane il codice che segue:
<?php
if
(have_posts()) :
// The Loop.
while
(have_posts()) : the_post();
get_template_part( 'content', get_post_format() );
if( is_single() ) :
comments_template();
endif;
endwhile;
?>
<?php
post_navigation();
else
:
get_template_part( 'content', 'none'
);
endif;
?>
La
paginazione
In un blog è sempre necessario offrire agli utenti la possibilità di scorrere tra le pagine del sito prevedendo un sistema di
paginazione. Il tag posts_nav_link() genera i link alla pagina precedente e alla pagina successiva di un archivio o di
una pagina singola. Per gestire l’output in modo preciso, il framework fornisce i tag previous_posts_link() e
next_posts_link(). I corrispondenti tag get_ restituiscono i link come valori gestibili via PHP. Quello che segue è il
sistema di paginazione di Seventyone:
function
post_navigation() {
echo
'<div class="navigation">';
echo
'<div class="next-posts">'
. get_next_posts_link( '« Older Entries'
)
. '</div>';
echo
'<div class="prev-posts">'
. get_previous_posts_link( 'Newer Entries
»'
) . '</div>';
echo
'</div>';
}
Anche nel caso della paginazione, si può decidere di scrivere il codice in un file a parte. Invece di utilizzare un "include
ta"g, in questo caso si è preferito definire la funzione post_navigation() nel file functions.php. Nel file
index.php e in ognuno dei template file del tema, al di sotto del Loop si inserirà la seguente istruzione:
In questo capitolo si è visto come operare con le query predefinite. WordPress, però, permette di impostare query
personalizzate e creare Loop multipli, funzionalità queste che, per complessità e conoscenze necessarie, richiedono
maggiore spazio e che, quindi, analizzeremo approfonditamente in un capitolo successivo. Per introdurre il Loop si è fatto
riferimento alle seguenti risorse:
Per visualizzare singoli articoli, WordPress sceglie il template secondo il seguente ordine:
single-{$post_type}.php
single.php
index.php
Lo script
<?php
/**
* @package WordPress
* @subpackage Seventy-One-WordPress-Theme
* @since Seventy One 1.0
*/
get_header(); ?>
<div id="main-content"
class="main-content">
<div id="content"
class="content-area"
role="main">
<?php
if
(have_posts()) :
// Start the Loop.
while
(have_posts()) : the_post();
get_template_part( 'content', get_post_format() );
if
( comments_open() || get_comments_number() ) {
comments_template();
}
endwhile;
?>
<?php post_navigation(); ?>
<?php
else
:
get_template_part( 'content', 'none'
);
endif;
?>
</div><!-- #content -->
</div><!-- #main-content -->
<?php get_sidebar(); ?>
<?php get_footer(); ?>
La struttura di base è esattamente la stessa del template index.php. Trattandosi di un articolo specifico, però, potrebbe
essere interessante aggiungere meta-informazioni che riguardano il post o l’argomento trattato.
Soprattutto quando partecipano più utenti alla creazione dei contenuti, potrebbe essere una buona idea quella di aggiungere
alle pagine dei singoli articoli un box con una serie di informazioni sull’autore. Si supponga di voler dare al box la seguente
struttura:
<aside
class="author-box">
<img
alt=""
src="...">
<h4>About carlo</h4>
<p>...<br
/>
<a
href="...">View all posts by ... (...)</a>
</p>
</aside>
Trattandosi di informazioni a margine del contenuto principale, per generare il box si ricorre ad un elemento aside.
All’interno sarà collocata l’icona del profilo utente, il nome dell’autore, la descrizione, il link all’archivio personale e il
numero di articoli pubblicati. Tutte queste informazioni saranno recuperate dal database grazie alle funzioni del framework
di WordPress. Data la struttura, si può progettare l’aspetto del box, aggiungendo le seguenti dichiarazioni al file
style.css:
/*
5.5 – Other stuff
*/
.author-box{
margin-top: 2.08334%;
padding: 1.04167%;
width: 100%;
overflow: hidden;
border: 2px
solid
#e8e8e8;
background-color: #eee;
}
.author-box .avatar {
float: left;
margin-right: 1.04167%;
}
In precedenza si è già presentato il codice del file single.php e a questo non si apporterà alcuna modifica. Si supponga
ora di voler aggiungere il box autore solo agli articoli di formato standard. L’unico template da modificare sarà il file
content.php. Si apra, quindi, il file e si vada direttamente alla chiusura dell’elemento article:
La condizione è necessaria in quanto il template content.php viene caricato per generare il contenuto sia delle pagine
singole che delle pagine di archivio. Quindi, qualora l’utente si trovi in una pagina singola, sarà caricato il template parziale
template-author.php, che si collocherà in una directory ad-hoc che può essere nominata template_parts.
Quello che segue è il codice del template.
<?php
/**
* @package WordPress
* @subpackage Seventy-One-WordPress-Theme
* @since Seventy One 1.0
*/
?>
<aside class="author-box">
<?php echo
get_avatar( get_the_author_meta( 'ID'
) ); ?>
<h4><?php echo
__('About ') . get_the_author_meta( 'display_name'
); ?></h4>
<p>
<?php the_author_meta( 'description'
); ?><br />
<a href="<?php echo get_author_posts_url( get_the_author_meta( 'ID' ) );
?>">
<?php echo
__('View all posts by ') . get_the_author() . ' ('
.
get_the_author_posts() .')'; ?>
</a>
</p>
</aside>
L’elemento img dell’icona viene generato grazie alla funzione del framework get_avatar(). Questa recupera l’avatar
dell’utente a partire dall’ID o dall’indirizzo email. All’interno del Loop, l’ID viene recuperato grazie alla funzione
get_the_author_meta(). Questa stessa funzione viene invocata più volte: la prima volta viene passato come
argomento il parametro ID, la seconda volta il parametro display_name, infine ancora l’ID. Ogni volta la funzione
restituisce l’informazione corrispondente.
get_the_author_meta restituisce una stringa gestibile via PHP. Gli stessi dati possono essere mandati a video grazie
al corrispondente tag the_author_meta, qui invocato per stampare la descrizione dell’autore. L’URL del successivo
link viene generata dalla funzione get_author_posts_url, alla quale viene passato l’ID dell’autore.
Il testo del link, infine, viene generato dalla funzione get_the_author, che restituisce il display_name dell’autore
allo stesso modo di get_the_author_meta( 'display_name' ), e da get_the_author_posts, che
restituisce il numero degli articoli pubblicati dallo stesso autore. Nell’immagine che segue, il risultato a video.
Funzione Descrizione
get_the_author() Restituisce
il
display_name
dell’autore
del
post
corrente
get_author_posts_url() Restituisce
la
URL
della
pagina
d’archivio
dell’autore
the_author_posts_link() Manda
a
video
un
link
che
punta
all’archivio
dell’autore
get_avatar()
Restituisce
una
stringa
in
cui
è
rappresentato
l’elemento
img
che
genera
l’icona
di
un
utente
the_author_meta()
Manda
a
video
i
dati
riferiti
all’autore
in
base
ai
parametri
passati
come
argomenti
get_the_author_meta()
Restituisce
i
dati
riferiti
all’autore
in
base
ai
parametri
passati
come
argomenti
the_author_posts() Manda
a
video
il
numero
di
post
dell’autore
get_the_author_posts() Restituisce
il
numero
di
post
dell’autore
Si è visto che il template parziale template-author.php è stato collocato in una directory specifica, cui è stato
assegnato il nome di template_parts. Ciò non sarebbe necessario se il tema mantenesse nel tempo una struttura
semplice e composta di pochi file. Può capitare, però, che un tema inizialmente semplice, aumenti via via di complessità. In
questo caso, si corre il rischio di ritrovarsi con una struttura disordinata e difficile da gestire. Si consiglia, quindi, di
strutturare in modo rigoroso il tema anche nel caso in cui si componga di pochi file essenziali. Quella che segue è la
struttura attuale del tema Seventyone.
Conclusioni
e
riferimenti
Quando si modifica il file style.css, potrebbe succedere che le modifiche non siano visibili. Dato che in questo capitolo
sono state aggiunte alcune dichiarazioni al foglio di stile, è opportuno disabilitare la cache del browser per verificare i
risultati a video.