Un cliente aggiunge la versione spagnola a un negozio online che vende già in inglese e francese. Le traduzioni vengono inserite correttamente, il selettore funziona e ogni pagina appare a posto. Tre settimane dopo, qualcuno chiede perché Google continui a mostrare la pagina agli acquirenti di Madrid.
Questa domanda ci viene posta spesso. Il problema non è quasi mai un tag mancante. Basta guardare il codice sorgente: i tag hreflang di PrestaShop sono presenti, esattamente dove dovrebbero essere. Il problema risiede in qualcos'altro. La lingua non è stata associata correttamente a quel negozio. Qualcuno ha utilizzato un codice di regione che non corrisponde a quello previsto da Google. Forse c'è un reindirizzamento 301 alternativo che punta a una pagina di categoria invece che alla pagina localizzata corretta.
Il problema non è che il tag sia sbagliato. Il problema è che la configurazione non corrisponde. Il tag indica "Spagnolo". Il sistema continua a pensare che la versione francese sia quella principale per quella località. È questo che confonde i motori di ricerca.
A volte il codice canonico punta a una lingua completamente diversa. Ricordo in particolare un episodio in cui un aggiornamento del tema aveva eliminato l'intero blocco tre settimane prima e da allora nessuno aveva più controllato il codice sorgente.
Ecco perché è importante pensare a hreflang come a un modo in cui gli URL si connettono tra loro, piuttosto che vederlo semplicemente come un elemento aggiunto a una pagina. Gli URL, i codici lingua, i tag canonici, le traduzioni e le impostazioni del negozio devono corrispondere tutti prima che un motore di ricerca possa utilizzarli in alcun modo.
1.0 Cos'è Hreflang e perché è necessario per i negozi PrestaShop multilingue

Hreflang aiuta un motore di ricerca a capire che diversi URL sono versioni linguistiche o regionali della stessa pagina. Supponiamo che il tuo catalogo ne abbia tre:
- Italiano: https://example.com/en/running-shoes
- Francese: https://example.com/fr/chaussures-running
- Spagnolo: https://example.com/es/zapatillas-running
Il markup che li collega ha questo aspetto:
Google ha tre regole sulle versioni che mettono in difficoltà la maggior parte dei negozi, e la seconda è la più costosa. Ogni versione localizzata deve elencare se stessa insieme a tutte le altre versioni localizzate. All'inizio sembra illogico: perché una pagina dovrebbe collegarsi a se stessa? Ma questa è la regola. Oltre a ciò, le pagine devono fare riferimento l'una all'altra in entrambe le direzioni: la pagina X si collega alla pagina Y, la pagina Y si collega a X. Se si salta questo passaggio in qualsiasi punto della catena, Google è noto per ignorare l'intero set di annotazioni. E non dimentichiamo che gli URL alternativi non possono essere relativi: niente abbreviazioni come /foo, deve essere l'URL completo. https://example.com/fooQuel requisito intermedio è davvero il punto cruciale: se si guarda una sola pagina, non si può sapere con certezza se la configurazione funziona. Valutare un'implementazione di hreflang significa analizzare l'intero processo.
2.0 Come PrestaShop genera Hreflang e quando non lo fa silenziosamente
Quattro lingue elencate nella pagina Lingue non significano quattro alternative nel codice sorgente, e presumere il contrario comporta una notevole perdita di tempo per il debug. Il core assembla l'insieme in FrontController::getAlternativeLangsUrl(), un metodo sufficientemente breve da poter essere letto in una sola volta:
$languages = Language::getLanguages(true, $this->context->shop->id); if (count($languages) < 2) { return $alternativeLangs; // meno di due lingue, niente emesso } foreach ($languages as $lang) { $alternativeLangs[$lang['language_code']] = $this->context->link->getLanguageLink($lang['id_lang']); }
Da queste poche righe emergono tre cose. Viene passato l'ID del negozio, quindi una lingua abilitata a livello globale ma mai associata a questo negozio semplicemente non verrà visualizzata. Meno di due lingue attive producono un array vuoto e nessun tag. Inoltre, la chiave dell'array proviene da language_code, che non è lo stesso campo di iso_code, una distinzione su cui torneremo in seguito.
Il tema classico quindi renderizza qualsiasi cosa gli sia stata passata tramite il blocco head_hreflang in _partials/head.tpl. Una cosa da sapere prima di iniziare la ricerca: il core non emette mai x-default, quindi se la tua strategia lo richiede, deve provenire da un override del tema o da un modulo.
Ci siamo imbattuti in un caso multi-negozio in cui l'inglese e il francese erano associati al Negozio A, lo spagnolo era presente nell'installazione, ma non era mai stato associato a quel negozio. Nessun errore PHP, nessun avviso nel back office, nessun sintomo visibile. Il Negozio A semplicemente non aveva mai pubblicizzato un'alternativa in spagnolo.
2.1 Controlla il codice HTML grezzo prima di modificare qualsiasi cosa
curl -s https://example.com/fr/product-name | grep -i hreflang
L'output vuoto restringe rapidamente le possibilità. Verifica se una seconda lingua è effettivamente abilitata, se è associata a questo negozio, se il tema visualizza ancora il blocco, se ti viene servita una pagina memorizzata nella cache e se qualche altro componente sta riscrivendo il .
3.0 Il codice ISO e il codice linguistico sono campi diversi
Questo genera bug davvero sconcertanti, perché entrambi i campi sembrano corretti nel back office e nessuno dei due è chiaramente quello che alimenta i tag.
PrestaShop memorizza un codice ISO e un codice lingua, e l'attributo hreflang viene creato a partire dal secondo. Un negozio potrebbe avere "es" come codice ISO, mentre il codice lingua potrebbe essere "es-MX", che si riferisce specificamente al Messico anziché allo spagnolo in generale. Il problema sta nel valore predefinito. Il metodo `Language::getFields()` copia il codice ISO nel campo `Language_code` ogni volta che quest'ultimo è vuoto, e `getFields()` viene eseguito a ogni aggiunta e aggiornamento, quindi una lingua salvata con quel campo vuoto eredita silenziosamente il valore ISO. Ecco perché molti negozi emettono codici di due lettere quando in realtà intendevano indirizzare le lingue a specifiche regioni, e perché la soluzione di solito consiste nella modifica di un campo nel back office piuttosto che in una modifica al codice.
C'è un limite che può creare problemi durante le implementazioni in Asia e America Latina. La colonna language_code è composta da cinque caratteri, convalidati da Validate::isLanguageCode(), la cui espressione regolare è:
preg_match('/^[a-zA-Z]{2}(-[a-zA-Z]{2})?$/', $s)
Quella grammatica accetta pt-BR senza problemi, ma rifiuta zh-Hans, dove il sottotag è composto da quattro lettere, e anche es-419, poiché le cifre non corrispondono mai. Qualsiasi strategia SEO basata su sottotag di tipo script o numeric-region si scontra quindi con una tabella delle lingue che non può memorizzarli, e i tag devono essere inseriti in qualche altro modo.
Anche l'aspetto permissivo della stessa espressione regolare merita attenzione. Due lettere, un trattino e altre due lettere vengono accettate indipendentemente dal fatto che la regione esista o meno, quindi PrestaShop memorizza senza problemi en-UK nonostante il codice ISO 3166-1 per il Regno Unito sia GB. Il validatore controlla solo la forma. Non esprime un'opinione sul significato e non rileverà una regione non valida.
4.0 Hreflang e Canonical sono segnali separati
Confondere questi due elementi è uno degli errori più comuni che riscontriamo, e onestamente, rispondono a domande completamente diverse. Un tag canonico indica ai motori di ricerca quale URL deve rappresentare una pagina. Hreflang, invece, sceglie quale URL servire in base alla lingua o alla regione del visitatore.
Una pagina francese coerente afferma:
Ora immaginate la stessa pagina in francese: il tag canonical punta all'URL in inglese, ma il tag hreflang indica ancora la versione francese. La pagina si presenta come francese e allo stesso tempo indica un URL in inglese come quello corretto. I motori di ricerca risolvono questa contraddizione in modi che non vi piaceranno, ed è per questo che i tag canonical e hreflang devono essere controllati insieme, non uno dopo l'altro.
5.0 La trappola Multistore Hreflang
Multistore rende la SEO internazionale considerevolmente più interessante. Immagina shop-fr.example.com, shop-de.example.com e shop-es.example.com come negozi separati, ognuno con il proprio contesto, senza che nessuno di essi abbia una conoscenza intrinseca del contenuto degli altri. Il negozio francese non sa che il negozio tedesco contiene la versione tedesca di una determinata pagina, quindi il risultato è che entrambi i negozi funzionano, entrambi visualizzano hreflang, ma non dichiarano mai la relazione tra di loro.
Il meccanismo spiega il perché. getAlternativeLangsUrl() passa $this->context->shop->id a Language::getLanguages(), quindi l'insieme che viene creato può contenere solo le lingue associate al negozio attualmente in esecuzione. Un negozio che esegue una sola lingua per dominio, quindi, incontra il limite di due lingue e non emette alcun segnale, che è esattamente la configurazione scelta da molti lanci internazionali. Il negozio appare corretto in ogni browser e non pubblica alcun segnale internazionale.
Due configurazioni si comportano in modo molto diverso in questo caso, ed è importante sapere quale si possiede. Un negozio che offre servizi in diverse lingue con i prefissi /fr/ e /de/ ottiene automaticamente l'attributo hreflang dal core. Diversi negozi monolingue su domini separati non ottengono nulla automaticamente e le relazioni devono essere gestite da un modulo che comprende la mappatura dei domini, oppure da un override del tema che crea l'insieme in base alla configurazione personalizzata.
La presenza di un tag non dimostra nulla in questo caso. Ciò che è necessario verificare è la reciprocità.
6.0 Reciprocità: la regola che manda in tilt la maggior parte delle implementazioni
Se la pagina francese dichiara un link alternativo in tedesco, anche la pagina tedesca deve dichiararne uno in francese. Laddove manchi tale link di ritorno, la documentazione di Google afferma che le annotazioni possono essere ignorate, il che in pratica significa tenerne conto. La spiegazione solitamente fornita per questa regola è di natura difensiva: senza link di ritorno, chiunque potrebbe indicare la tua pagina come alternativa alla propria, sebbene la pagina attuale di Google si limiti a elencare il requisito anziché la motivazione.
Controllare un singolo URL, quindi, fornisce una falsa sicurezza. Su un catalogo di qualsiasi dimensione, questo è lavoro da crawler, perché le relazioni interrotte si concentrano proprio sui prodotti che nessuno si è preso la briga di controllare a campione.
Per una rapida verifica manuale, staccate le alternative da una pagina e seguitele una per una a ritroso:
curl -s https://example.com/fr/chaussures-running \ | grep -o ' ]*>'
PrestaShop scrive href prima di hreflang in quel tag, quindi corrisponde all'intero elemento. Un modello che inizia con hreflang= non restituirà nulla silenziosamente e verrà letto come tag mancanti.
Ripeti quindi la procedura per ogni URL restituito e verifica che la pagina in francese appaia in ogni risultato. Se una lingua risulta presente in uscita ma non in uscita, quell'abbinamento viene scartato e nessuna correzione del markup sul lato francese potrà cambiare la situazione. Per un numero di pagine superiore a poche, un crawler che segnala i link di ritorno hreflang troverà in pochi minuti ciò che un controllo manuale non riesce a individuare.
7.0 Slug non tradotti e URL alternativi che non si risolvono
Due fallimenti che vale la pena distinguere, perché dall'esterno sembrano molto simili.
Primo problema: riscritture non tradotte. Prendiamo un prodotto francese che si trova all'indirizzo /fr/chaussures-running; la versione inglese dovrebbe essere /en/running-shoes, ma se si omette di inserire quella riscrittura, si ottiene /en/chaussures-running, ovvero parole francesi sotto un URL inglese. Il meccanismo alla base di questo problema viene spesso descritto in modo errato, quindi vale la pena spiegarlo. Le pagine prodotto passano da getLanguageLink() a getProductLink(), che recupera link_rewrite per la lingua di destinazione da ps_product_lang tramite ObjectModel::getFieldByLang(), e non esiste alcun fallback in questo percorso. Ciò che si trova nella riga di quella lingua è ciò che viene visualizzato. In pratica, la riga di solito contiene una copia dello slug nella lingua di origine, perché nessuno l'ha tradotto. Se la riga è effettivamente vuota, si ottiene un URL non valido, che il dispatcher potrebbe non instradare affatto. In entrambi i casi la pagina restituisce 200 risultati, il contenuto viene visualizzato in inglese, il cliente non si accorge di nulla e la selezione di sei prodotti non fornisce alcuna informazione sugli altri quattromila.
Il secondo caso riguarda l'URL alternativo che non atterra dove ci si aspetterebbe. Ogni URL in un set hreflang dovrebbe restituire un codice 200, nella lingua corretta, con un tag canonical appropriato, senza reindirizzamenti inattesi e senza un noindex superfluo. Un URL alternativo che restituisce un 301 da /es/product a /es/category appare comunque perfettamente valido nel codice sorgente. Verificate dove atterra l'URL, poi preoccupatevi di come è scritto il tag.
8.0 Dove si collocano i moduli SEO
I negozi reali raramente hanno un unico componente che controlla l'output SEO. La gestione canonica, i meta titoli, le direttive robots, i dati strutturati, la riscrittura degli URL, le sitemap e l'hreflang sono distribuiti tra il core, il tema e due o tre moduli, con la cache che si trova al di sopra di tutto. Abbiamo analizzato a fondo molti negozi in cui ogni singolo elemento era tecnicamente valido e l'output combinato non era comunque quello che il commerciante si aspettava. Quando diversi sistemi scrivono allo stesso , eseguire il debug dell'HTML finale piuttosto che ragionare su chi dovrebbe esserne responsabile.
La cache merita particolare sospetto durante questo tipo di lavoro. La compilazione Smarty di PrestaShop e la cache a pagina intera possono entrambe continuare a servire un creato prima della tua modifica, il che fa sembrare una correzione corretta un fallimento e costringe gli utenti a tornare a modificare modelli che erano già corretti. Svuota la cache e recupera nuovamente i dati con curl prima di trarre conclusioni sull'efficacia di una modifica.
Stabilire prima un punto di riferimento è altrettanto utile. Uno strumento come Knowband SEO Audit Manager valuta le pagine in base a segnali on-page come titoli, meta descrizioni, intestazioni, testo alternativo e struttura dei link, e gestisce i reindirizzamenti, la sitemap e il file robots.txt. Non gestisce l'attributo hreflang, quindi va considerato come uno strumento che indica se una pagina è sufficientemente valida da meritare un link alternativo, piuttosto che come una soluzione per correggere l'attributo hreflang.
9.0 Un flusso di lavoro pratico per il debug di Hreflang
Quando un cliente segnala che hreflang non funziona, resisti alla tentazione di aprire un template. Spesso il problema risiede nella configurazione piuttosto che nel markup, e i sette passaggi seguenti seguono un approccio "il più economico prima di procedere", quindi lo scoprirai prima di apportare qualsiasi modifica.
9.1 Partire da un URL di prodotto reale
Le homepage nascondono i problemi. Le pagine prodotto, invece, includono contemporaneamente nomi tradotti, riscritture tradotte, disponibilità e logica canonica.
9.2 Leggi cosa ha effettivamente inviato il server
curl -s https://example.com/fr/product-name | grep -Ei "hreflang|canonical|robots"
Gli strumenti per sviluppatori del browser mostrano il DOM dopo che JavaScript lo ha modificato. Per il lavoro di SEO, invece, è necessaria la risposta grezza.
9.3 Contare le lingue, per negozio
Quanti sono attivi, quali appartengono a questo negozio e si tratta di un'installazione multi-store? Ricorda che il core non emette alcun contenuto al di sotto di due lingue.
9.4 Leggete i codici lingua, non i codici ISO.
Verificate che il targeting regionale corrisponda alla strategia effettiva e che nessuno abbia memorizzato un codice regionale inesistente.
9.5 Aprire a giorni alterni
Qualsiasi numero diverso da 200 è un dato anomalo, che si tratti di un 301, 302, 404 o qualcosa nella gamma 5xx.
curl -I https://example.com/es/product-name
9.6 Verificare insieme la reciprocità e la canonicità
Percorri il circuito in entrambe le direzioni, quindi verifica i punti canonici di ciascuna versione linguistica in relazione a se stessa, piuttosto che confrontandoli tra le diverse lingue.
9.7 Verifica cosa è cambiato
Se il problema è iniziato dopo un aggiornamento del tema, controlla il file themes/yourtheme/templates/_partials/head.tpl e verifica che il blocco hreflang sia rimasto intatto. Se un modulo è stato installato, aggiornato o riconfigurato nello stesso periodo, isolalo nell'ambiente di staging anziché in quello di produzione e procedi senza aver già formulato un giudizio. Sia il modulo che il core sono possibili cause, e ciò che può chiarire la situazione è confrontare l'HTML previsto con l'HTML effettivo, modificando una variabile alla volta. Questo metodo fornisce prove concrete anziché ipotesi, ed è più rapido che discutere su quale componente sia più probabilmente responsabile del problema.
10.0 Un esempio prima e dopo
Ecco l'output con diversi problemi:
Ogni riga di quel blocco presenta degli errori. L'alternativa spagnola è relativa laddove Google richiede un URL completo, e il codice di regione en-UK dovrebbe essere en-GB, cosa che, come abbiamo visto, il validatore non contesterà mai. L'URL inglese conserva ancora lo slug francese, quindi quella riscrittura non è mai stata tradotta. Inoltre, non è presente alcuna indicazione di un x-default, lasciando i visitatori che non corrispondono a nessuna delle lingue elencate a ciò che Google decide.
Pulito:
Non incollare quel codice in ogni negozio. Il punto è che lingua, regione, URL e canonical siano tutti coerenti tra loro.
11.0 Robot, Noindex e il livello Sitemap
Abbiamo visto sviluppatori passare una giornata a perfezionare hreflang solo per scoprire che la pagina spagnola contiene oppure che il file robots.txt blocchi il percorso. Una relazione alternativa non risolverà il problema di una pagina che non può essere indicizzata fin dall'inizio.
Esegui un audit su tre livelli anziché uno. L'HTML della pagina ti fornisce i tag canonical, hreflang e robots. Gli URL stessi ti forniscono i codici di stato, la lingua corretta e i reindirizzamenti indesiderati. La sitemap ti dice se gli URL che stai inviando corrispondono a quelli che hai dichiarato canonical e alternative. Quando questi tre elementi non coincidono, ti trovi di fronte a un'architettura incoerente piuttosto che a un singolo tag errato.
12.0 Hreflang per PrestaShop 1.7, 8 e 9
Il meccanismo si è dimostrato sostanzialmente stabile, con due eccezioni degne di nota. getAlternativeLangsUrl() e il blocco head_hreflang funzionano allo stesso modo nelle versioni 1.7.7.8 e 9.1.3, e la protezione contro le due lingue è identica in entrambe.
La prima eccezione riguarda le prime versioni della 1.7. Nella 1.7.5.0 la condizione di controllo è "if ($languages < 2)", che confronta un array con un numero intero invece di contarlo, quindi non si attiva mai e un negozio monolingue emette un'alternativa autoreferenziale invece di nessuna. Dalla 1.7.7.8 la condizione è "count($languages) < 2". Se stai utilizzando una versione precedente della 1.7.x, controlla la tua copia prima di fidarti della regola.
La seconda differenza è che le versioni 8.2.4 e 9.1.3 passano ogni URL generato attraverso un metodo sanitizeUrl() che esegue l'escape dei valori della stringa di query prima che raggiungano il tag. Questo metodo non esiste nella versione 1.7.7.8. Modifica il modo in cui vengono scritti i valori, non quali parametri vengono mantenuti.
Ciò che varia maggiormente tra le installazioni, tuttavia, è tutto ciò che ruota attorno al nucleo del sistema: implementazione del tema, override, moduli personalizzati, configurazione multi-store, caching e qualsiasi altra modifica introdotta silenziosamente da un aggiornamento.
Pertanto, dopo ogni aggiornamento, ricontrollate gli URL dei prodotti, delle categorie e del CMS. Il fatto che un negozio funzionasse correttamente prima di un aggiornamento non significa che la sua ottimizzazione SEO sia rimasta invariata.
13.0 La checklist di PrestaShop Hreflang
[ ] Almeno due lingue abilitate e abilitate per QUESTO negozio
[ ] language_code impostato deliberatamente, non lasciato ripiegare su iso_code
[ ] I codici regionali sono valori ISO 3166-1 reali (GB, non UK)
[ ] Nessuna lingua necessita di un sottotag più lungo della colonna di 5 caratteri
[ ] Ogni URL alternativo è assoluto
[ ] Ogni alternativa restituisce 200, nessun reindirizzamento, lingua corretta
[ ] Ogni pagina elenca se stessa e le altre
[ ] Le relazioni sono reciproche in entrambe le direzioni
[ ] Punti canonici all'interno della stessa versione linguistica
[ ] Nessuna alternativa è noindexata o bloccata in robots.txt
[ ] Le riscritture URL tradotte esistono laddove la strategia lo richiede
[ ] Il tema continua a visualizzare il blocco head_hreflang
[ ] x-default aggiunto deliberatamente se necessario (il core non lo emetterà)
[ ] Domini multistore mappati correttamente
[ ] Cache svuotata dopo le modifiche di configurazione
14.0 Considerazioni finali: Eseguire il debug dell'intera relazione
Un negozio può avere un hreflang="es" perfettamente formato e comunque presentare un'implementazione errata, perché il target reindirizza, restituisce un errore 404, serve la lingua sbagliata, contraddice il proprio canonical, si trova dietro un noindex o appartiene a un negozio completamente diverso. Allo stesso modo, una strategia canonical impeccabile non fornisce alcuna informazione sulla completezza dell'insieme alternativo.
Impostare correttamente l'attributo hreflang di PrestaShop ha ben poco a che fare con l'aggiunta di tag. Si tratta piuttosto di far sì che l'intera catena sia coerente al suo interno, dalla configurazione della lingua alla generazione degli URL, passando per i contenuti, gli attributi canonici, l'indicizzazione e, infine, la sitemap.
Quando questi segnali si allineano, i motori di ricerca capiscono il tuo negozio multilingue. Quando non lo fanno, un altro modulo o un altro Raramente è d'aiuto. Inizia con l'HTML grezzo, controlla la configurazione della lingua rispetto al negozio, apri ogni alternativa, percorri il ciclo in entrambe le direzioni, confronta canonical con hreflang e solo allora passa a esaminare le modifiche al tema e ai moduli.
Per un catalogo di grandi dimensioni, questo cambiamento è più importante di qualsiasi singola correzione, perché trasforma la risoluzione dei problemi SEO in qualcosa di ripetibile anziché in una serie di soluzioni isolate.
Se hai domande o hai bisogno di assistenza per le prestazioni o la migrazione del tuo sito web, i nostri esperti sono qui per aiutarti. Contatta il team di Knowband all'indirizzo [email protected] Oggi stesso potrete usufruire di plugin per eCommerce affidabili e personalizzati in base alle vostre esigenze.


