Joomla SEF: pagine duplicate, url inesistenti e nessun errore 404

Menù, moduli e links di Joomla: ecco le pagine duplicate

I cms tendono a 'duplicare le pagine' per un medesimo contenuto, ma di norma l'origine di questi problemi è da ricercarsi più nel comportamento di chi implementa il sito che non nel codice proprio del cms.

Spesso chi realizza il sito tende a portare in evidenza i contenuti da lui considerati più importanti, fornendo al navigatore molteplici ed alternative strade per raggiungerli. La cosa, di norma, si attua tramite il ricorso a menù (uno o più) con collegamento al contenitore dei contenuti (categorie) e collegamenti diretti al contenuto, cui si tende ad aggiungere moduli specifici dell'estensione che visualizzano i contenuti in vari modi (contenuti più importanti, più visti, più recenti...).

Per comodità focalizzeremo l'attenzione su com_content dato che la quasi totalità dei siti, che non siano e-commerce, hanno com_content, con una delle sue view, come pagina di default. Comunque, fatte salve le peculiarità, i discorsi qui sviluppati si applicano a qualsiasi componente.

 

Menù, sotto menù e link duplicati

Questo è un caso comune di duplicazione degli url. Quando si collegano più voci di menù, appartenenti a menù e/o livelli diversi, alla stessa informazione, si ottengono percorsi diversi, causati dai differenti alias da noi impostati e/o dalla presenza degli alias stessi nelle voci di menù di livello superiore. Questo è un comportamento corretto del cms, e la duplicazione dei contenuti è solamente imputabile all'utente.

In questi casi la soluzione è molto semplice: è sufficiente mantenere una sola voce che collega l'informazione ed usare gli 'Alias voce menu' (da non confondere con gli alias del percorso SEF) per tutte le altre voci, ponendo attenzione che la voce di menù 'reale', non si trovi al di sotto della 'voce alias'.

Un caso più comune si ha quando si collega una voce di menù ad una categoria di contenuti e un'altra voce ad un contenuto specifico della categoria. In questo caso il router di com_content, almeno nelle ultime versioni di Joomla!, è abbastanza evoluto da gestire correttamente la cosa. Nella visualizzazione della categoria, prima di visualizzare il link ad uno specifico contenuto, il router verifica che il contenuto medesimo non sia già collegato ad un'altra voce di menù, in tal caso utilizza questo ultimo link, evitando la duplicazione dei contenuti.

 

Menù, moduli e link duplicati

Un altro caso di duplicazione degli url, e quindi una situazione di contenuti ripetuti, e quindi pagine duplicate, si ha quando si inserisce in un menù il collegamento alla vista di una categoria o a quella di un singolo oggetto, e si usa contestualmente un modulo che visualizzi il contenuto della categoria di cui sopra, che per forza di cose incorpora anche il collegamento all'eventuale oggetto singolo.

Come nel caso precedente, e, per quanto non sembri, questo è esattamente il caso precedente, il router di com_content è in grado di gestire correttamente la situazione, l'importante è che si faccia riferimento allo stesso. I moduli inerenti a com_content, distribuiti con Joomla!, caricano un router (/helpers/route.php) avanzato del componente e lasciano a quest'ultimo il compito di completare lo URL con tutti i dati necessari ad individuare articolo e categoria, dopo di che viene chiamato, da Joomla, il router di default del componente.

 

Contenuti inesistenti, nessun errore 404 e pagine duplicate

Nei due casi precedenti, abbiamo constatato che com_content si comporta bene e non genera link duplicati.

Non sempre si può dire lo stesso di altri componenti e moduli: se il router è mancante, o non è scritto in maniera corretta, le precedenti situazioni creano link e contenuti duplicati; va però tenuto presente che l'errore non è imputabile a Joomla! e la soluzione andrà cercata nel componente di cui si trovano i contenuti duplicati

Però capita di trovare, quando si va a verificare lo stato di indicizzazione del sito, molte più pagine di quelle effettivamente ipotizzabili dal numero degli articoli presenti; ma da dove vengono queste pagine?

Difficile dare una risposta senza valutare il singolo caso; potrebbe essere una configurazione particolare di vari elementi (menù, sotto menù, moduli, plugins, ...) che il router non riesce a gestire, un bug in una precedente versione del codice o dei links che, seppur sicuramente esistenti una volta, ora non sono più presenti.

La prima cosa da fare è esaminare menù e contenuti alla ricerca dei links e dei percorsi incriminati.

La modalità più rapida per effettuare questo controllo è quella di scaricare il dump del database e cercare i percorsi in questione all'interno del file sql: è sicuramente più veloce che usare l'interfaccia web per 'spulciare' i singoli elementi e presenta il vantaggio di mostrare anche dati ad uso interno di Joomla che non sono accessibili dall'interfaccia del cms; esempio di quest'ultima asserzione è il campo `#__menu`.`path` ('The computed path of the menu item based on the alias field') che tanti mal di testa ha causato, in caso avesse avuto a contenere dati errati, a chi non ne conosceva l'esistenza o l'uso.

La seconda cosa da fare è verificare il sito e cercare nello stesso i collegamenti duplicati (ci si può aiutare con un crawler/parser) generati dinamicamente da componenti, moduli o plugins.

E se non troviamo questi link? forse in questo caso vale la pena di soffermarsi non tanto sulla ricerca di che cosa abbia dato origine a questi collegamenti, ma sul motivo per cui questi collegamenti inesistenti siano gestiti come fossero corretti e sia visualizzato del contenuto piuttosto che sia correttamente restituito un http status code 404 (not found).

Passo ad un esempio specifico che ci sarà utile trattazione. Il sito in questione disponeva di una photo gallery, che era stata collegata al menù principale del sito tramite l'alias 'galleria-immagini'. A questo indirizzo corrispondeva la view 'categories' del componente; tale view visualizzava le categorie contenute e ciascuna categoria visualizzava le singole immagini. Dopo poco tempo, sui vari motori di ricerca erano presenti una serie di links come 'http://example.com/galleria-immagini/2-inverno/18-monte-alben', fin qui tutto bene, almeno finché non si è deciso di cambiare l'alias della voce di menù che permette di accedere alla galleria. Ora, accedendo al link sopra indicato, appare un articolo invece della foto.

Il problema è che quasi tutti i links come quello sopra indicato portano ora ad contenuto differente da quello originale e, non restituendo un errore 404 (not found), creano contenuti duplicati.

Ma perché succede ciò? Per rispondere alla domanda serve un'analisi del funzionamento del sistema SEF di Joomla.

 

Analisi del routing SEF di Jooma

Due documenti sono utili per capire da dove partire per l'analisi cui ci accingiamo:

Per il resto analizzeremo un po' di files php alla ricerca del codice di interesse. Massima parte del processo avviene all'interno di una istanza della classe JRouterSite, che è estensione di JRouter.

In questa trattazione limiteremo la nostra attenzione solo agli url SEF, ed al routing degli stessi.

Subito dopo l'inizializzazione del sito, come si può vedere dalla documentazione citata e dal file /index.php nella root di Joomla, viene richiamato, tramite la classe factory JSite (deriva da JApplication), il metodo JRouterSite->parse() che si occupa di individuare la parte SEF dell'url, ovvero di rimuovere dall'url il protocollo, il dominio, l'eventuale path in caso di installazione in una sottodirectory e l'eventuale estensione del file, se inserita nella configurazione SEF, nonché l'eventuale index.php se non si è potuta attivare la riscrittura completa dell'url SEF.

Questo metodo è un override dell'omologo presente in JRouter, ed alla fine richiama il metodo sovrascritto. JRouter->parse() riceve la stringa SEF e richiama l'opportuno metodo di analisi della stessa, metodo che, per altro, deve essere definito nella classe derivata JRouterSite.

Arriviamo ora a JRouterSite->_parseSefRoute(), ed è qui che viene svolto il 'vero' lavoro SEF. L'url SEF, qui indicato dalla variabile $route, viene diviso, al carattere '/', in segmenti. Se il primo segmento non equivale a 'component', allora il componente di riferimento deve essere cercato nel menù.

La procedura analizza, una per una, tutte le voci di tutti i menù, alla ricerca di una voce di menù il cui alias sia l'inizio della route presente nell'url. Se questa è trovata allora vengono recuperati il componente e la voce di menù associata, viene eliminata la parte iniziale della route (quella presente nella voce di menù) e, se presente, viene richiamato il router del componente perché effettui il riconoscimento ed il parsing della rimanente parte dell'url SEF a beneficio del componente stesso. A questo punto la normale esecuzione di Joomla prosegue con il caricamento del componente individuato e le altre operazioni necessarie.

Ma se, come nel nostro caso, non viene trovata nessuna corrispondenza tra l'alias presente nel menù e l'url SEF che succede? Il seguente frammento di codice risponde alla domanda:

 
if (!$found) {
  $found = $menu->getDefault($lang_tag);
}
...
$vars['Itemid'] = $found->id;
$vars['option'] = $found->component;
 
 

$menu è una istanza di JMenuSite, ma penso che la cosa fosse intuibile. Se non viene trovata una voce di menù con le caratteristiche sopra spiegate ($found) allora si considera il percorso SEF come facente capo alla voce di default del sito per la lingua in uso ($lang_tag), ovvero si rimanda il tutto alla home page ed al componente che la gestisce.

Come accennato nelle premesse a questo articolo, nella massima parte dei siti, la home page è gestita da com_content, e qui abbiamo già un indizio sul perché ora, al posto della foto, appaia un articolo.

A questo punto il codice di JRouteSite, sulla base del componente individuato, sia o meno la voce di default, verifica l'esistenza di un router specifico e, come detto sopra, lo richiama perché questo effettui l'analisi della route.

A questo punto dobbiamo dunque spostare la nostra attenzione sull'analisi della funzione ContentParseRoute() contenuta nel router specifico di com_content (/components/com_content/router.php)

La funzione verifica se vi è più di un segmento (vedi sopra) e ha procedimenti diversi nell'uno e nell'altro caso, comunque considera sempre l'ultimo elemento come riferimento all'articolo o alla categoria. Sulla base dei commenti al codice, l'intenzione era quella di considerare un segmento che che avesse il formato numero:stringa come il riferimento ad un articolo, mentre solo una stringa sarebbe dovuto essere il riferimento ad una categoria. Dato che però si verifica solo se vi sono i due punti e che il sef traduce il primo '-' in due punti, e visto che il '-' è il sostituto degli spazi negli url SEF, il comportamento non è sempre coerente!

Il problema si verifica, però, quando l'ultimo segmento inizia con un numero, come nel nostro caso, o è composto solo da un numero, e la sfortuna vuole che questo numero coincida con l'id di un articolo presente nel sistema. Si noti che il verificarsi delle due situazioni non è un eventualità tanto remota, dato che tutti gli id PK partono da uno!

da quanto sopra, e dall'analisi del codice del router di com_content, possiamo anche derivare che:

  • /galleria-immagini/2-inverno/18-monte-alben
  • /galleria-immagini/18-monte-alben
  • /galleria-immagini/18

ma anche:

  • /18-monte-alben
  • /18

sono tutti url validi che visualizzeranno l'articolo con id=18 quando la home page è gestita da com_content, e ciò porta inevitabilmente a pagine duplicate sui motori di ricerca.

SEF e contenuti duplicatiÈ un bug del router di com_content? Una attenta riflessione ci porta ad escludere questa eventualità; certo alcuni aspetti potevano essere curati meglio, ad esempio si sarebbe potuto effettuare un pattern matching con una regex, al posto di vedere se vi è un due punti nella stringa, ma di sicuro non si sarebbe intaccata la radice del problema.

Il problema è che in un sistema SEF il router deve agire sotto molteplici condizioni (articolo con link diretto nel menu, link ad una categoria che deve quindi proporre i collegamenti ai propri contenuti con l'alias SEF della voce di menù e non non il proprio, ...) e spesso queste condizioni presentano esigenze tra loro in contrasto. Progettare il routing non è semplice, e chi ha seguito le vicende del SEF in VirtueMart lo sa bene.

Un'attenta pianificazione, basata su una competenza reale del funzionamento del cms, aiuta ad evitare di commettere errori, ma in casi come questi la soluzione è tutt'altro che semplice.

I cms ci aiutano, pensando di correggere i nostri errori di disegno e risolvendo url che non dovrebbero risolvere; i motori di ricerca ci aiutano, pensando di correggere i nostri errori di indicizzazione, continuando ad indicizzare contenuti che non sono più raggiungibili da menù. Tutto bene, se poi non ci segnalassero che il nostro sito presenta contenuti duplicati! magari se provassero ad aiutarci un poco meno (o a considerarci meno incompetenti) avremmo tutti una vita più semplice.

 

La soluzione ai contenuti duplicati di Joomla esiste?

Purtroppo non esiste una soluzione generale, esistono naturalmente tante soluzioni particolari che si adattano a ciascun caso particolare, e di conseguenza richiedono un'analisi specifica del problema in essere.

Nel nostro caso ricorrono queste condizioni:

  • i links non portano traffico, dato che non avevano alcun interesse generale,
  • gli oggetti puntati dai link sono stati rimossi,
  • i links sono analizzati solo dai crawler dei motori che segnalano pi i contenuti duplicati.

In questo caso la soluzione migliore è impedire l'accesso alle pagine ai vari motori di ricerca; pertanto agiremo a livello di .htaccess inserendo il seguente codice:

RewriteCond %{REQUEST_URI}  ^(/\w{2})?/galleria-immagini/  
RewriteRule .* - [L,R=404]

L'espressione regolare (\w{2})? serve ad includere l'eventuale codice di lingua, che non fa parte del routing del componente, ma è presente nell'url della pagina. Se l'url SEF, che può avere o meno il codice di lingua, inizia con  'galleria-immagini' viene interrotta l'esecuzione di .htaccess [L] e restituito il codice di status 404 (not found) [R=404].

Ad essere pignoli, lo status code da restituire sarebbe 410 Gone, ma, alla data attuale (agosto 2014), Google ed altri trattano i codici 410 esattamente come fossero 404 (in altri termini non si arrendono e continuano a richiedere la pagina per un certo periodo di tempo).

In caso però che i contenuti esistano, e siano solamente stati indicizzati con il percorso sbagliato è più opportuno ricorrere ad una redirezione all'indirizzo corretto, personalmente, sebbene da alcuni sia suggerito, non ritengo che il ricorso alla meta istruzione rel="canonical" sia appropriata in questo caso. 

Attenzione alla psicosi da pagine duplicate!
Qualche pagina duplicata non farà certo sì che il vostro sito sia escluso da tutti i motori di ricerca del pianeta. Se non siete ben indicizzati il problema sta probabilmente da un'altra parte.

 

Che cosa  possiamo derivare da quanto qui esposto? La conclusione è che non esiste una formula magica per risolvere il problema. La soluzione è la conoscenza del funzionamento del sistema e la corretta progettazione che può derivare solo dalla competenza. Qualora voleste avvalervi della nostra consulenza vi invitiamo a contattarci, anche questo è uno dei nostri servizi.

Buon lavoro a tutti,

marco maria leoni

 

 

Commenti   

0 #1 Davide 2018-02-23 08:41
Buongiorno Marco, avrei una domanda in merito alle pagine inesistenti, se gli URL sono molto complessi, non può essere più semplice includere gli stessi nel robots.txt in modo da far rimuovere le pagine dall'indicizzaz ione? Il mio problema infatti è che ho fatto l'upgrade di un vecchio sito scritto in php utilizzando Joomla come cms, purtroppo alcune sezioni del nuovo menu corrispondono ad alcune cartelle del vecchio sito e l'unica parte che cambia degli url è l'estensione php e il nome delle pagine che adesso sono HTML, ho provato a mettere in atto la tua strategia ma senza successo. Se l'inclusione nel robots non è consigliabile potresti darmi qualche suggerimento su come scrivere la rewritecond per filtrare le request php? Grazie in anticipo
Citazione

Aggiungi commento

Please note: URL in text are not linked and user's site address is only for internal use and is not published.

Comments are human checked. All spam will be removed, so don't waste your time and, especially, mine!

Codice di sicurezza
Aggiorna