Come velocizzare un sito in WordPress

Qualche consiglio per evitare di avere un sito lento, rendere felici i vostri utenti e guadagnare in termini di posizionamento SEO e Web Reputation.

SHARE

Come velocizzare un sito in WordPress

Come qualcuno dei miei affezionati lettori avrà notato, da qualche settimana è online il mio nuovo sito. Oltre al restyling grafico ho cercato di focalizzarmi anche sull'aspetto performance, non solo per cercare di garantire prestazioni ottimali, ma anche per imparare nuove tecniche di ottimizzazione come esercizio personale.

Premesse

Ci sono alcuni elementi da tenere in considerazione prima di lanciarsi nell'ottimizzazione del proprio sito web. La prima premessa doverosa è che i miracoli non esistono. Quando si realizza un sito bisogna fare attenzione in primis a due fattori: gli aspetti tecnici (leggi: scelta dell'hosting) e le scelte progettuali.
Il primo punto è abbastanza ovvio: se volete un sito veloce vanno evitati come la peste gli shared hosting, soprattutto quelli a basso costo (i vari Godaddy, Aruba, ecc.), in quanto le prestazioni di questi servizi sono mediamente scadenti e possono influire seriamente sulle performance del sito. Meglio puntare su una VPS o su un server dedicato, in modo da avere risorse dedicate (quasi) esclusivamente al proprio sito e la possibilità di effettuare interventi utili ad incrementare le prestazioni, cosa solitamente impossibile su uno shared hosting. Importante anche la scelta della connettività (USA / Europa / Italia), la location fisica del server dovrebbe essere quanto più vicina possibile alla provenienza della maggioranza del vostro target di utenza.
Questo sito è hostato su Digital Ocean da diversi anni, e personalmente mi sono trovato molto bene con loro.
Il secondo punto riguarda la realizzazione vera e propria del sito: vanno evitati i template preconfezionati (leggi: Theme Forest), in quanto solitamente pieni di schifezze che appesantiscono il codice, il 90% delle quali assolutamente inutili lato utente. A livello di scelte progettuali è bene inoltre fare un'analisi su quali feature sono veramente indispensabili per il vostro sito, ed evitare fin da subito quelle che non lo sono. Riempire il sito di feature inutili e poi chiedersi come velocizzarlo è un non-sense; il noto adagio della "botte piena e la moglie ubriaca", oltre ad essere poco politically correct in epoca di indignazione facile, in informatica decisamente non funziona.
Ultima premessa doverosa: diffidate dei plugin preconfezionati che promettono mirabolanti ottimizzazioni del vostro sito. La maggior parte di essi è adatta solo per casistiche molto standard, e in ogni caso se li applicate senza avere idea di cosa stanno facendo potreste ritrovarvi con un sito ancora più lento, o peggio ancora del tutto non funzionante.

Come verificare le prestazioni

Oltre ovviamente all'aspetto empirico - se il proprio sito impiega più di 5-10 secondi a caricare una pagina è evidente che qualcosa non va - sono disponibili numerosi tool che aiutano a capire quali sono le possibili aree di intervento.
Dal mondo Google ci vengono in aiuto WEB.dev e il noto Page Speed. Il primo, più recente e basato sull'open source Lighthouse, è più severo rispetto al Page Speed, e si differenzia da quest'ultimo in quanto analizza anche aspetti non prestazionali del sito (accessibilità, ottimizzazione SEO, best practice adottate), scorporando il punteggio totale nelle diverse aree. Rispetto al Page Speed, inoltre, effettua di default il test da device mobile, simulando una connessione 3G di media velocità.

-

La verifica delle prestazioni e del rispetto delle best practice di SEO e accessibilità del proprio sito può essere effettuata attraverso il tool WEB.Dev

Altri tool utili e abbastanza famosi sono GTMetrix e Pingdom.
In locale, utilizzando il browser Chrome, è possibile sfruttare il pannello "Network" (tasto destro / Ispeziona elemento / Network) per capire quantità e tipologia di risorse caricate all'interno della pagina e definire le priorità di intervento.

Come interpretare i dati forniti?
Quando si analizzano i dati  forniti da questi tool è facile farsi prendere dalla smania di fare subito tutti gli interventi consigliati. Bisogna fare alcune considerazioni: le analisi fatte da questi tool sono frutto di algoritmi software, e non di ragionamenti umani; possono essere imprecise, o variare a seconda delle situazioni. Infine bisogna considerare quelli che possono essere i reali vantaggi percepiti dall'utente, i costi in termini di sviluppo software e le possibili complicazioni per chi dovrà gestire i contenuti del sito.
Attuare in maniera acritica tutti gli interventi suggeriti e lasciarsi prendere dalla smania di ottenere il punteggio più alto è assolutamente sbagliato, e lo è ancora di più se il vostro obiettivo è quello di rivendere al cliente un lavoro di ottimizzazione postuma, magari staccando una corposa offerta economica dedicata.

Concetti di base per l'ottimizzazione

Non è obiettivo di questa guida andare a coprire tutte le casistiche possibili, tuttavia gli interventi di ottimizzazione possono essere ricondotti ad alcuni concetti fondamentali:

  • Miglioramento dei tempi di risposta del server: scelta dell'hosting adeguata e ottimizzazioni lato server per assicurare tempi di risposta rapidi.

  • Miglioramento del tempo di rendering lato utente: per l'utente è fondamentale avere la possibilità di interagire nel tempo più rapido possibile con il vostro sito, con un FCP (First Contentful Paint) e un FMP (First Meaningful Paint) bassi. Nel concreto vuol dire caricare "in differita" tutto ciò che non è immediatamente indispensabile (Javascript aggiuntivi, immagini non visibili, ecc.).

  • Selezione delle risorse aggiuntive: la scelta di script aggiuntivi (ad es. plugin, photogallery, Javascript per effetti grafici, ecc.) deve essere quanto più oculata possibile, scegliendo script e plugin che rispondano a logiche di corretto sviluppo software, meglio se customizzabili in base alle proprie esigenze; ad esempio jQuery o Modernizr possono essere personalizzati in modo da creare delle versioni "light" che contengono solo le feature indispensabili per il vostro sito.

  • Limitazione delle parti dinamiche e caching: nel caso di Wordpress devono essere ridotte quanto più possibile le parti del sito che richiedono elaborazioni dinamiche. E' bene utilizzare soluzioni di caching (plugin o lato server) che servano all'utente contenuti statici. Vanno limitate anche eventuali aree dinamiche che vanno a interrogare il backend con una certa frequenza, ad esempio infinite scrolling, caricamento in ajax degli ultimi post, ecc.

  • Compressione dei contenuti: deve avvenire sia lato server (ad esempio GZIP) che lato applicativo, combinando e "minimizzando" le risorse CSS e Javascript servite, o utilizzando i "next generation format" per le immagini.

  • Riduzione del numero di richieste: ogni elemento che compone la pagina (immagini, Javascript, fogli di stile) costituisce una richiesta al server. Per ottimizzare le prestazioni il numero di richieste deve essere necessariamente ridotto all'osso.

  • Riduzione delle richieste esterne: font o Javascript che risiedono su siti esterni, ad esempio, ma anche tool di metriche, advertising, e altro ancora.

Interventi lato server

Relativamente alla scelta dell'hosting già citata, consiglio di privilegiare hosting con un'adeguata quantità di memoria e che utilizzino SSD per l'archiviazione dei dati. Tra le feature indispensabili da installare segnalo la compressione GZIP, che riduce sensibilmente il peso dei dati inviati all'utente e garantisce un buon incremento prestazionale. A seconda dello stack utilizzato (LAMP o LEMP), può essere utile valutare l'adozione dell'HTTP/2, evoluzione del classico protocollo HTTP che include numerosi vantaggi, tra cui una migliore compressione e la possibilità di inviare in una singola richiesta tutte le risorse che normalmente vengono richieste durante la navigazione di un sito. Va tenuta presente la non totale compatibilità con alcuni plugin di caching (ad es. W3 Total Cache non consente di sfruttare HTTP/2 su stack LEMP), e il differente comportamento che hanno alcuni browser nel gestire le richieste effettuate tramite questo protocollo.
In casi di siti ad alto traffico, può essere utile valutare l'adozione di load balancer e di soluzioni di server-caching, come Varnish, al posto dei classici plugin di caching per Wordpress.
A livello di stack è sempre consigliabile utilizzare le ultime versioni di PHP e MySql. In particolare la versione 7 di PHP consente dei notevoli vantaggi dal punto di vista delle prestazioni e del consumo di memoria, oltre ad essere altamente consigliata per le nuove feature e per una maggiore sicurezza.

Utilizzare una CDN?

La risposta, come spesso accade, è: dipende. Una CDN può essere molto utile se il vostro sito ha necessità di avere performance elevate in diverse parti del mondo, ad esempio se il server ha connettività italiana o europea e deve garantire prestazioni elevate in USA / Asia / Australia; del resto, oggi sono disponibili anche soluzioni gratuite o a basso costo. I side effect di questa scelta sono principalmente gli sforzi necessari per configurare la CDN e interfacciare Wordpress in maniera corretta (ad esempio alla pubblicazione di un contenuto sul sito deve corrispondere il purging di una o più pagine sulla CDN). Infine, la comprensione del funzionamento di una CDN non è sempre facile per chi deve gestire i contenuti di un sito e per l'utente finale.

Caching, contenuti statici e compressione

L'elaborazione dinamica di una pagina Wordpress può essere molto onerosa, e può portare a gravi rallentamenti o addirittura al blocco del server in caso di picchi di traffico.
Ci viene in aiuto il plugin W3 Total Cache, che si occupa di servire agli utenti versioni statiche delle nostre pagine. Non è scopo di questa guida illustrare nel dettaglio tutte le possibili opzioni di configurazione, mi limiterò a elencare le opzioni principali da attivare.

  • Page caching e Disk Caching Enhanced: è l'opzione che permette di servire contenuti statici; da preferire rispetto al Disk Basic, che prevede l'utilizzo dell'interprete PHP per servire contenuti dalla cache.

  • Database e Object Cache: da attivare, con un occhio agli eventuali consumi di memoria e CPU della macchina.

  • Minify: da attivare, sia per il codice HTML che per CSS e Javascript; a seconda degli script caricati e del loro posizionamento potete anche attivare le opzioni per il caricamento async/defer.

  • Browser Cache: da attivare, avendo cura di abilitare la compressione GZIP e gli expires header, settando i tempi di scadenza in base alla tipologia di risorse (solitamente più alti per immagini, CSS e Javascript, un po' più bassi per le pagine di contenuto) e alle funzionalità del sito (un sito di informazione, ad esempio, avrà per forza di cose necessità di expire time più ridotti).

Miglioramento del rendering lato utente

Come detto, è estremamente importante fare in modo che l'utente "veda qualcosa" il prima possibile. Una delle criticità che vengono segnalate più spesso è la presenza nell'header di elementi che bloccano il rendering della pagina. Situazioni di questo tipo:

<head>
<link rel="stylesheet" href="path/style.css">
<script type="text/javascript" src="path/script.js">
</head>

stanno ad indicare che il browser rimarrà "bloccato" finché non avrà elaborato il caricamento di queste risorse. La soluzione è caricare il maggior numero possibile di risorse in fondo alla pagina, e utilizzare il caricamento "async" o "defer" per i Javascript nel maggior numero di casi possibile.
Vediamo nel dettaglio come fare su Wordpress. Prendiamo ad esempio il seguente pezzo di codice contenuto nel file functions.php del nostro tema:

add_action('wp_enqueue_scripts', 'loadFrontendAssets');
add_action('get_footer', 'loadFrontendAssetsFooter');

//Load frontend assets
function loadFrontendAssets()
{
	//Remove WP useless stuff
	wp_dequeue_style('wp-block-library');
    wp_deregister_style('wp-block-library');
	wp_deregister_script('jquery');
	wp_deregister_script('wp-embed');
	wp_dequeue_script('wp-embed');

	//Add scripts
	wp_enqueue_script('jquery', get_bloginfo('template_url') . '/js/jquery-3.4.1.min.js','','',true);
	wp_enqueue_script('aos-js', get_bloginfo('template_url') . '/js/aos/aos.js', array('jquery'),'',true);
	wp_enqueue_script('lazy-js', get_bloginfo('template_url') . '/js/jquery.lazy-master/jquery.lazy.min.js', array('jquery'),'',true);
	wp_enqueue_script('theme-js', get_bloginfo('template_url') . '/js/core.js', array('jquery', 'aos-js', 'lazy-js'),'',true);
	wp_enqueue_script('lightgallery-js', get_bloginfo('template_url') . '/js/lightgallery/js/lightgallery-all.min.js', array('jquery'),'',true);

	//Add styles
	wp_enqueue_style('aos-stylesheet', get_bloginfo('template_url') . '/js/aos/aos.css', false, '', 'screen and (min-width : 768px)');
	wp_enqueue_style('spectre-fwk', get_bloginfo('template_url') . "/css/spectre.min.css", false);
	wp_enqueue_style('theme-stylesheet', get_stylesheet_uri(), false);

}

//Load some frontend assets in footer
function loadFrontendAssetsFooter()
{
	wp_enqueue_style('lightgallery-stylesheet', get_bloginfo('template_url') . '/js/lightgallery/css/lightgallery.min.css', false);
	wp_enqueue_style('icon-font-animation-stylesheet', get_bloginfo('template_url') . '/font/css/animation.css', false);
	wp_enqueue_style('icon-font-stylesheet', get_bloginfo('template_url') . '/font/css/pierantonioromano-icons-embedded.css', false);
}

Come potete vedere, il caricamento delle risorse è stato suddiviso in due funzioni. Questo perché il wp_enqueue_script permette di dichiarare con un parametro (il "true" finale) se si vuole caricare lo script nel footer o meno, mentre il wp_enqueue_style non ha questa funzionalità. Per questo motivo gli stili vengono caricati nella seconda funzione, che viene agganciata all'hook get_footer di Wordpress.
La scelta di cosa caricare nel footer e cosa no dipende dalla struttura del vostro sito, non esistono regole fisse. In linea generale, tutto ciò che non è immediatamente necessario nei primi istanti di caricamento della pagina può essere rimandato nel footer.
E' importante inoltre gestire l'ordine e le dipendenze. Avrete notato che ho messo tutti i Javascript insieme e tutti i CSS insieme; questo perché plugin come il W3 Total Cache vanno a comprimere e unificare gli script seguendo l'ordine in cui sono inseriti nel codice. Se mischiate Javascript e stili, vi ritroverete con più file generati, mentre in questo modo i 5 script dell'esempio sopra produrranno un unico file compresso. Le dipendenze sono altrettanto importanti, se ad esempio il Javascript del vostro tema richiede jQuery, è bene specificarlo nel parametro $deps della funzione wp_enqueue_script, in modo che venga caricato successivamente al jQuery.

 

Caricamento condizionale
Se avete delle risorse che devono essere caricate in una specifica area del sito, potete limitare da codice il loro caricamento. Ad esempio, se decidete di utilizzare uno script per la gallery solo in un'area dedicata, non ha senso caricarlo su tutte le pagine del vostro sito. Pertanto il codice potrebbe essere rivisto in questo modo:

if(is_page('photogallery'))
		wp_enqueue_script('lightgallery-js', get_bloginfo('template_url') . '/js/lightgallery/js/lightgallery-all.min.js', array('jquery'),'',true);

Risorse caricate dai plugin
Quanto detto sopra va bene nel caso del caricamento delle risorse relative al nostro tema, ma cosa succede per le risorse richieste dai plugin? La risposta è: dipende. I plugin sviluppati correttamente fanno già in modo che le proprie risorse vengano caricate nel footer, oppure offrono opzioni per il caricamento condizionale (carico stili e Javascript solo se nella pagina è stato utilizzato il mio plugin) o per la scelta della posizione di caricamento (header o footer). Se uno dei vostri plugin non offre questa opzione, purtroppo l'unica soluzione sarà intervenire manualmente modificandone il codice, oppure utilizzare il dequeue per poi ri-aggiungere le risorse all'interno del vostro tema.

 

Rimozione degli elementi inutili di Wordpress
Avrete notato nel codice sopra che sono stati rimossi alcuni elementi che Wordpress inserisce di default sulle nostre pagine. Se non prevedete di utilizzarli, potete rimuoverli tranquillamente.
Infine, ho sostituito la versione di jQuery che viene fornita in bundle con Wordpress con una versione più aggiornata, dato che il WEB.dev mi segnalava le possibili vulnerabilità di sicurezza della versione inclusa in Wordpress.

 

Riduzione delle richieste (locali ed esterne)
Analizzando tramite il pannello "Ispeziona elemento" di Chrome le risorse caricate dalla pagina (immagini, font, fogli di stile, ecc.) e ordinandole per dimensione, è facile rendersi conto di cosa è possibile eliminare, accorpare o ridurre. Nella scelta degli script e dei plugin è bene privilegiare software che hanno un'architettura modulare, meglio se compilabili e personalizzabili in base alle proprie esigenze. E' buona norma evitare di richiamare Javascript o stili da CDN esterne: la comodità di avere l'ultima versione di un pacchetto potrebbe avere come effetto spiacevole un aumento dei tempi di latenza o dei disservizi causati da problemi momentanei alla CDN stessa.

 

"Critical CSS" e possibili soluzioni
Come potete notare dal codice riportato sopra, ho scelto di mantenere lo stile principale del sito nell'head, anche se questo causa un leggero degrado delle prestazioni. Se scegliete di caricarlo nel footer, infatti, gli utenti che accederanno al vostro sito per la prima volta si troveranno per qualche frazione di secondo in una situazione del genere:

-

Gli effetti indesiderati di una mancata gestione del "Critical CSS": per qualche secondo l'utente vedrà una pagina quasi completamente priva di grafica e stili CSS.

I possibili approcci, oltre ovviamente a lasciare il CSS nell'header, sono: utilizzare un preloader o scegliere l'approccio del "Critical CSS". La prima soluzione prevede l'inserimento di un preloader grafico con stili in linea (la classica gif rotante, per intenderci), da rimuovere tramite CSS o Javascript una volta completato il caricamento della pagina. La seconda soluzione prevede invece l'inserimento nell'head - direttamente nel codice HTML - degli stili "critical", ossia della porzione di stili indispensabile per la corretta visualizzazione della prima parte visibile della pagina; il caricamento del CSS completo avviene invece a fondo pagina. Personalmente non sono molto a favore di questa soluzione; sebbene esistano dei generatori automatici che vi aiutano a capire quali sono gli stili fondamentali, la suddivisione del CSS richiede comunque un intervento manuale, da ripetere ogni qualvolta deciderete di apportare delle modifiche di layout al vostro sito.

 

Caricamento asincrono degli script
Una volta sistemato il posizionamento degli script nel footer, potete decidere di caricarli in maniera asincrona. Il W3 Total Cache permette - nei settaggi del Minify - di decidere come caricarli:

-

Impostazioni consigliate per il Minify gestito da W3 Total Cache

Il "defer" è il metodo consigliato, in quanto nell'esecuzione rispetta l'ordine con cui gli script vengono richiamati nel markup delle vostre pagine.

Gestione delle immagini

La gestione delle immagini è un aspetto di particolare importanza nell'ottimizzazione delle prestazioni. Vediamo nel dettaglio le diverse tecniche da adottare.

 

Utilizzare le image sizes di Wordpress
Quando si sviluppa un tema per Wordpress, è possibile impostare delle dimensioni personalizzate per le immagini, da utilizzare nei diversi punti del sito. Così facendo, quando caricheremo un'immagine dal pannello Media di Wordpress, verranno generate automaticamente tutte le altre versioni impostate.
Questo il codice da inserire nel file functions.php:

//Image and thumbnails
add_theme_support('post-thumbnails');
add_image_size("postLargeImage", 1680, 520, true);
add_image_size("postMediumImage", 700, 355, true);
add_image_size("gridRectangularImage", 690, 550, true);
add_image_size("gallerySquaredImage", 500, 500, true);
add_image_size("postCardImage", 240, 320, true);

Richiamiamo poi opportunamente l'immagine all'interno del tema:

echo get_the_post_thumbnail($post->ID, "postMediumImage", array('class' => 'img-responsive'));

In questo modo eviteremo di utilizzare le versioni "full" delle immagini, risparmiando in termini di peso/banda e di conseguenza guadagnando in velocità di caricamento.

 

Utilizzo di immagini responsive
Per caricare differenti versioni di un'immagine a seconda della risoluzione utilizzata o del tipo di device, è possibile sfruttare l'attributo "srcset". In questo modo sarà il browser a selezionare l'immagine giusta in base ai breakpoint impostati.

<img srcset="elva-fairy-320w.jpg 320w,
             elva-fairy-480w.jpg 480w,
             elva-fairy-800w.jpg 800w"
     sizes="(max-width: 320px) 280px,
            (max-width: 480px) 440px,
            800px"
     src="elva-fairy-800w.jpg" alt="Elva dressed as a fairy">

Nell'attributo "srcset" si impostano le varie versioni dell'immagine, separate da virgola e con accanto l'indicazione delle dimensioni. Il classico attributo "src" rimane come fallback per i browser che non supportano "srcset". Notare l'attributo "sizes", che definisce un set di condizioni e di dimensioni immagini da visualizzare, ritenuto obbligatorio in accoppiata all'srcset.
Utilizzare questa tecnica per le gallerie di immagini o per le thumbnail dei post richiede per forza un lavoro di sviluppo software, dato che non viene implementata di default da Wordpress. Personalmente ho scelto di utilizzarla per le immagini "decorative" del mio sito.

 

Utilizzo dei "Next Generation Formats"
Da qualche anno ha preso piede il WebP, formato di immagini creato da Google che promette una compressione più efficiente rispetto ai tradizionali JPEG e PNG. I vantaggi in termini di peso del file sono tangibili, in alcuni frangenti il risparmio raggiunge il 30-40%. L'adozione di questo formato viene ormai consigliata da tutti i tool di reportistica. Gli svantaggi principali sono: il mancato supporto da parte di alcuni browser e la conseguente necessità di dover creare/gestire più formati di una stessa immagine.
Personalmente ho scelto di utilizzare questo formato per le immagini di header del sito e per le altre immagini "decorative", evitando di utilizzarlo per le foto della gallery o per le immagini dei post. Per convertire le proprie immagini sono disponibili numerosi convertitori online, come questo.
Come fare per il supporto ai vari browser? Per le immagini nel testo è possibile utilizzare l'elemento <picture> specificando diverse sorgenti che vanno a coprire tutte le possibili casistiche:

<picture>
  <source srcset="img/immagineWEBP.webp" type="image/webp">
  <source srcset="img/immagineJPEG.jpg" type="image/jpeg"> 
  <img src="img/immagineJPEG.jpg" alt="Alt Text!">
</picture>

In questo modo il browser scaricherà in automatico l'immagine adatta in base al proprio supporto. E' ovviamente possibile inserire nelle <source> le immagini responsive, secondo il metodo descritto prima.
Per quanto riguarda le immagini di sfondo, invece, è indispensabile affidarsi a soluzioni ibride basate sul Javascript, in particolare utilizzando la libreria Modernizr che permette di verificare il supporto da parte del browser ad una serie di feature. Suggerimento: potete compilarla inserendo solo il test per il WebP, andando quindi a ridurre sensibilmente l'impatto sul caricamento del sito. Per le immagini di header di questo sito (caricate tramite custom field di Wordpress) ho inserito nell'html un parametro "data-nowebp-fallback":

<section class="fullHeightSection homeHero p-relative" data-nowebp-fallback="https://www.pierantonioromano.com/wp-content/uploads/2013/03/greece-home.jpg" style="background-image: url(https://www.pierantonioromano.com/wp-content/uploads/2019/06/greece-home.webp)">
</section>

Lato Javascript viene eseguita una verifica sul supporto da parte del browser:

//WebP support on header images
jQuery(".homeHero, .singleHero").each(function(){
	if(!Modernizr.webp)
		jQuery(this).css("background-image", "url(" + jQuery(this).data('nowebp-fallback') + ")");
});

In questa guida di CSS Tricks trovate altri possibili approcci, incluse alcune soluzioni per utenti che hanno il Javascript disabilitato.

Nota importante: Wordpress di default non consente l'upload di immagini WebP, pertanto dovrete inserire nel functions.php o in un vostro plugin personalizzato il seguente codice:

add_filter('upload_mimes', 'cc_mime_types');

//Allow WEBP uploads
function cc_mime_types($mimes) 
{
	$mimes['webp'] = 'image/webp';
	return $mimes;
}

Utilizzo del "lazy loading"
Una buona tecnica per risparmiare banda e velocizzare il caricamento delle pagine è quella di utilizzare il "lazy loading": in pratica, le immagini vengono caricate solo nel momento in cui l'utente effettua lo scroll e visualizza una determinata area della pagina. Sono disponibili numerosi Javascript che effettuano questo compito, potete scegliere quello che meglio risponde alle vostre esigenze. Il markup delle immagini cambierà come segue:

<img alt="text" class="img-responsive" data-src="uploads/post-image-240x320.jpg" src="img/lazy_placeholder.png">

Come vedete, il classico attributo "src" dell'immagine è stato sostituito con un placeholder (in questo caso un'immagine PNG trasparente di pochi pixel), mentre nel data-src è presente l'url reale dell'immagine. Effettuando lo scroll sarà il Javascript ad occuparsi di caricare l'immagine vera:

jQuery(".card-image img").Lazy();

Se avete scelto di utilizzare immagini responsive e formato WebP, potete combinare queste tecniche come segue:

<img class="lazy img-responsive" data-srcset="https://www.pierantonioromano.com/wp-content/themes/par2019/img/homer_rsz.webp 320w, https://www.pierantonioromano.com/wp-content/themes/par2019/img/homer.webp 768w" data-srcset-nowebp="https://www.pierantonioromano.com/wp-content/themes/par2019/img/homer_rsz.png 320w, https://www.pierantonioromano.com/wp-content/themes/par2019/img/homer.png 768w" sizes="100vw" src="https://www.pierantonioromano.com/wp-content/themes/par2019/img/lazy_placeholder.png" alt="About me - Homer" />

In questo caso sono stati utilizzati due differenti attributi, "data-srcset" per le immagini responsive in WebP e "data-srcset-nowebp" per i browser senza supporto WebP.
Il Javascript va ad estrarre l'immagine dall'attributo corretto in base al supporto del browser:

//Lazy load home images with WebP support
jQuery(".lazy").Lazy({
	visibleOnly: false,
	srcsetAttribute: (Modernizr.webp) ? 'data-srcset' : 'data-srcset-nowebp'
});

CDN per immagini
Un'altra soluzione per velocizzare il caricamento delle immagini, soprattutto per siti ad alto traffico, può essere quella di utilizzare una CDN (Content Delivery Network) esterna su cui caricare le immagini, anche per diminuire il consumo di banda e il carico del server. Alcune di esse, come Imagekit.io, si occupano anche di servire all'utente l'immagine nel formato/dimensione più opportuno, ad esempio a bassa risoluzione se si sta navigando da un device mobile o in formato WebP se il proprio browser lo supporta. Verificate attentamente le possibili modalità di integrazione con Wordpress, per non avere sgradevoli sorprese in fase di pubblicazione dei contenuti.

Gestione dei font

Un altro capitolo dolente è spesso costituito dai font utilizzati nel sito. In un layout moderno è ormai consuetudine scegliere webfont che non sono quelli classici di sistema. Per utilizzarli si fa spesso uso di "kit" Javascript che si occupano di importare i font da servizi esterni, oppure di import via HTML/CSS. Di seguito troverete alcuni aspetti da tenere in considerazione.

 

Utilizzo di font in locale
Come per tutti gli altri servizi, è sempre preferibile hostare i font sul proprio server, piuttosto che fare affidamento su servizi di terze parti come Typekit o Google Fonts. Questo permette di tenere sotto controllo tempi di caricamento e performance, di evitare ritardi dovuti a disservizi della terza parte, e di evitare situazioni in cui il font esterno viene modificato/rimosso dal fornitore.
Per i Google Fonts, è possibile utilizzare questo servizio che si occupa di fornirvi file e CSS da caricare sul vostro sito.
Suggerimento: selezionate attentamente i diversi stili di font da importare, scegliendo solo quelli che effettivamente prevedete di utilizzare.

 

Impostare sempre un'alternativa per i font
Quando impostate il font all'interno del vostro CSS, è indispensabile impostare un'alternativa, preferibilmente tra i font di sistema. In questo modo, in caso di difficoltà nel caricare il font aggiuntivo, o semplicemente in caso di navigazione lenta, l'utente vedrà comunque il font di default:

body{ font: 400 21px 'Barlow', 'Segoe UI', Helvetica, Arial; line-height: 32px; }

Utilizzare correttamente le proprietà "font-display"
Strettamente collegata al punto precedente è la proprietà "font-display". Di default, in caso di caricamento di un font esterno, il testo risulta non visibile fin quando non è avvenuto il caricamento. Settando la proprietà "font-display" su "swap", l'utente potrà vedere, nel frattempo, il testo con il font alternativo impostato nel punto precedente.

/* barlow-regular - latin */
@font-face {
	font-family: 'Barlow';
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: local('Barlow Regular'), local('Barlow-Regular'),
		 url('font/google/barlow-v3-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
		 url('font/google/barlow-v3-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}

Font Awesome e Icon Fonts in generale
E' ormai uso comune utilizzare i Font Awesome e gli icon fonts per l'iconografia del proprio sito.
Purtroppo con il passare del tempo il pacchetto Font Awesome si è arricchito di centinaia di icone, e lo stesso accade per altri icon fonts famosi. Il risultato è che il caricamento di tali risorse, anche se effettuato in maniera asincrona, diventa particolarmente oneroso, facendo salire non di poco il tempo di caricamento e la quantità di richieste/dati scaricati.
Ecco un esempio pratico:

-

Per ovviare a questo inconveniente, l'ideale è evitare i kit preconfezionati creando il proprio icon font personalizzato, anche alla luce del fatto che non userete mai tutte le centinaia di icone incluse. I servizi che permettono questa operazione sono numerosi; personalmente ho utilizzato Fontello, che permette di selezionare le icone desiderate scegliendo tra una serie di icon font famosi. Una volta completata la selezione potrete scaricare file e CSS da includere sul vostro sito.

 

Font e supporto ai vari browser
Quando si importano web font tramite CSS, solitamente si va a caricare tutte le versioni per garantire il supporto anche ai browser più vecchi:

@font-face {
  font-family: 'MyWebFont';
  src: url('webfont.eot'); /* IE9 Compat Modes */
  src: url('webfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
       url('webfont.woff2') format('woff2'), /* Super Modern Browsers */
       url('webfont.woff') format('woff'), /* Pretty Modern Browsers */
       url('webfont.ttf')  format('truetype'), /* Safari, Android, iOS */
       url('webfont.svg#svgFontName') format('svg'); /* Legacy iOS */
}

Oggi, data la graduale (e graditissima) scomparsa di Internet Explorer, se non siete obbligati al supporto di questo browser potete serenamente rimuovere le righe inerenti.
Per avere un supporto abbastanza esteso potete richiamare il formato .woff; il .woff2 è più efficiente ma non è ancora pienamente supportato da tutti i browser.

Altri consigli

Se dovete mantenere alcune aree dinamiche del sito, consiglio di disabilitare l'esecuzione automatica del WP-Cron, inserendo questa riga nel file wp-config.php:

define('DISABLE_WP_CRON', 'true');

Si eviterà così di mandare in esecuzione il wp-cron.php ad ogni caricamento di pagina, causando rallentamenti o blocchi del sito.
Il WP-Cron può essere eseguito periodicamente impostando un cron job:

wget -q -O - https://domain.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1

Attenti al marketing :)

Uno dei momenti più difficili nella vita lavorativa di qualunque sviluppatore consiste nel dover fronteggiare gli assalti dell'area marketing, che, dopo la messa online del sito, non vede l'ora di riempirlo di widget social, script per il tracking degli eventi, script per il tracking delle conversioni, script per il tracking delle chiamate al customer service, script per tracciare i movimenti del mouse dell'utente, script di A/B testing e qualunque altra cosa del genere, con l'unico scopo di riempire le giornate dei vari digital che dovranno compilare noiosissimi e inutilissimi report da consegnare al cliente.
Inutile dire - ma al termine di questa guida dovrebbe essere abbastanza chiaro - che è necessaria una valutazione molto attenta di tali aggiunte, per evitare di rovinare un sito già ottimizzato.
Mi permetto di aggiungere una considerazione personale: a meno che non stiate lavorando sul sito Apple o su Amazon, dove una semplice modifica di una call to action o del colore del pulsante "Acquista" può portarvi milioni di fatturato in più, il riempimento di un sito con ammenicoli del genere avrà un effetto pressoché nullo.

 

Conclusioni

In questa guida ho volutamente selezionato alcuni degli aspetti più importanti da tenere in considerazione nell'ottimizzazione di un sito web. Ovviamente le casistiche possibili sono quasi infinite, e a seconda della tipologia di sito e di contenuti potrà essere necessario implementare ulteriori soluzioni. Fatemi conoscere le vostre opinioni ed esperienze nei commenti! ;)

Hai trovato interessante questo post?

Condividilo sui Social, o contattami per farmi qualche domanda o discuterne insieme!
Oppure, se ti va, puoi offrirmi un caffè o una pizza! :)