Sunday, August 21, 2011

TagCloud and SEO in Plone: problem solved and lesson learned

This article is an analysis of how a minor bug in a Plone product we are maintaining give us some problems on a production site, how fixing it was not enough to revert problems, and what lesson I learned.

The environment
The Plone site I'm talking about is an old Plone 3.3 installation with an old hardware. It worked without problems for years then suddenly it started to be slow (sometimes really slow).
In front of this Plone installation there's also a Varnish installation that cache also HTML for anonymous users (a standard for us).

So what's can be turned wrong?!

After started checking the problem I also find that it wasn't a memory consumption problem (a lot of free memory, thanks to the use of also on this Plone 3.3 installation), but only a CPU usage (unluckily we have only a single core for the Plone site).

Next step was checking what the site was doing to keep the CPU so busy. Before installing products like zope.healthwatcher, I spent some minutes simply checking the HTTP log and I found that the site is... "really popular". I mean it is very often visited by web crawlers, mainly Googlebot. This is not strange: the site is the main site of a well know public agency, and update really often.

The Vaporisation problem found
Is this enough to make a Plone site "slow"? Obviously no! The problem was not Plone but the TagCloud portlet.

One of the best features of collective.vaporisation (maybe the main feature that convinced us to takeover the project and maintain it) is the joint navigation.
When activating it, clicking on one of the links inside the cloud will not simply display a search result, but a search result where you can also navigate through found items using related additional terms (something like a faceted navigation).

The first problem was that customer site use a lot of different keyword, using them widely in a lot of site contents.
In this way the joint navigation became complex. Imagine a web crawler that starts to scan the tag cloud results page: it's able to follow a lot of additional link that create a great permutation of different search results (let call this big number N).

The second problem (the real one) was a bug in the way Vaporisation was creating links from the cloud to the result page (note that version 1.2.0 of the TagCloud fixed this problem so recent releases will not give you such behavior): older releases were calling the cloud_search template on the context.
This mean that when the visitor was checking the cloud links from the home page, it will call Plone as, but when visiting another page, the URL will became

This is a disaster for the cache that Varnish is trying to produce for our site: the two URL are different from the cache point of view, but in facts on Plone they are generating the same result. This is really bad (also for page rank).

This also raise the number of possible cloud search pages from N to NxM (where M is the number of documents in the site). Terrible!

The fix was simple: change the way the URL to the cloud is created, always give to users the version.

Google: the elephant
When I released this fix I make another mistake (not very lucky...).
Always remember that in Plone the context can be important. If you created a site view that must be called onto the site root is better to define it callable only on this context. An common error can be define this view callable everywhere (like old CMF skins templates).

So even if all URL were always generated in the right way, the view was defined still as follow:


In this way calling (manually) again the will still be valid.

Why this is still a problem? Haven't you fixed all possible wrong links?
Because of Google long memory.

Even if we removed all links to the useless cloud_search call, Google already indexed them so it continue to call all those URLs and make the Varnish cache useless.
Maybe with the time those kind of call could decrease (as the search engines will find no links to this page anymore), but after applied the fix we get no benefits.

Version 1.2.2 fixed this, defining also the right context for the view:


After this change all calls to something that isn't will simply generate a NotFound error page. This is good: Plone is very fast to generate this page, and this kind of pages (if no link lead to them) will rapidly disappear from the index.

Some SEO enhancement can help
Version 1.2.2 helped a lot, but in the meantime I was also reading a book about SEO and talked with coworkers (real SEO expert) of those kind of problems.

Must Google be aware of the cloud_search page? Is a good thing that this page will be indexed?Also, the site still use the joint navigation, so a major number of pages are still called, but in any case are those pages giving some good feedback to Web users that performs searches?

I think that there isn't an universal answer (I've doubt also related to simple Plone SERP... must be indexed by Google? Maybe Plone itself must think about this) but in this case no: let search engines index results page of search performed by tag cloud is useless.

Version 1.2.3 make the Vaporisation product more "SEO friendly".

First of all we can suggest search engines to not follow a link when scanning our site putting a rel='nofollow' attribute on it.

The new version of Vaporisation will put this rel nofollow value on every tag cloud link. I read recently that this attribute is only a suggestion, but can help.

The second and last change of this version is the use of a tag meta in the cloud SERP:

<meta name="robots" content="noindex, nofollow" />

This says to the search engine to not index this page (noindex value) but also don't follow any links from this page (nofollow value, less important there).

In this way Google quickly stopped to index also the big number of possible joint navigation results pages.

Damn Google Reader!
After every fix I applied, the site quickly became faster.
After all those fixes I still saw an heavy Google access to the site on a lot of different pages: this time to the search_rss page (used by Plone to generate RSS feeds from search result), commonly called with an URL like
The site now was not so slow, but I liked to continue the investigation.

The problem was still the first one I analyzed above: the search_rss URL was available from the cloud_search page and so, when using older releases, was created on the context and not on the portal root.
So while a version lower than 1.2.0 was active, Google indexed a lot of cloud_search versions but for each one also a useless search_rss page.

Again, have fixed the problem for the "master" cloud_search page will not stop Google from indexing all the RSS calls.

This time we can't rely onto a well-done meta tag, as the RSS isn't HTML! Where I can put the tag?!

We have two alternative ways.

The quicker one is to block every web crawler access to the search_rss page, using simply a robots.txt file on the site root (but this will works with query parameters?):

User-agent: *
    Disallow: /search_rss

The other way, that also leave the search_rss page indexable by services like Google Reader, is to make also the search_rss template callable only from the site root.

This need some simple Plone customization (outside the Vaporisation product itself). Maybe Plone 5 (or 6?) will not use anymore CMF templates, but right now we have a lot of them all around Plone.
One of the problem of old-style template is that they can be called on every possible context. And obviously search_rss template is a very old template...

So the fix is not elegant as the cloud_search ones. We can:
  • configure Apache to disallow any search_rss call outside the site root
  • manually check if the site context is the site root; if not, we manually raise a NotFound error.

I found the resolution of this someway "funny".

Other Plone sites that installed directly the 1.2.0 version of Vaporisation didn't suffer all problems that are here described because the cloud_search page was always called in the "most correct way": on the site root.
So in this case Google did not indexed all other useless alternative way to call the same page (this mean also no need to fix the Plone basic search_rss)

Last thing: if you create a Plone template planned to be called on a context be sure to register it only on this context. If this template is an old CMF ones keep an eye on how you create links to this template.

Saturday, August 6, 2011

Data di Scadenza/Pubblicazione in Plone: la guida definitiva

E' una delle funzionalità da sempre presente nel CMS, eppure rimane ancora oggi poco capita dagli utenti e spesso provoca effetti imprevisti.

Stiamo parlando della data di scadenza e della data di pubblicazione di Plone.

Il caso peggiore che può capitare
Mi torna in mente un affascinante concetto letto in un libro sulla storia della crittografia ("Codici e Segreti", ve lo consiglio). Più o meno recitava così:
La sola cosa peggiore di non avere segretezza è credere di averla
Torno subito coi piedi per terra.
Plone ha un potente sistema per rendere i nostri dati segreti e sicuri: il workflow. Quando il workflow è ben configurato e i documenti o le cartelle sono nel giusto stato di revisione, possiamo dormire sonni tranquilli.

La cosa più difficile da capire per un redattore Plone è che le date di scadenza e pubblicazione non influiscono sul workflow!

Dopo tutti questi anni ho spiegato e visto spiegare questo concetto ai redattori molte volte eppure tante volte ho visto questa stessa caratteristica di Plone non essere capita.

E qui ci ricolleghiamo alla frase che ho citato sopra. Assai spesso l'utente crede (sebbene nessuno lo abbia mai spiegato in questi termini) che quando un documento di Plone scade, questo magicamente diventi privato.
Ho visto casi dove, a volte anche dopo anni di utilizzo di un sito in produzione, un redattore scopre che qualche altro utente riesce ad accedere ad un contenuto che non dovrebbe vedere e la loro prima impressione è che sia un baco di Plone (o peggio, un baco dell'installazione data dal fornitore).

Vi siete mai sentiti dire "Ma è scaduto! Perché si vede?!", oppure: "Credevo che diventassero privati!". Ed ecco che entriamo nel caso peggiore... per tutto questo tempo il redattore ha creduto che i suoi contenuti fossero al sicuro, ma non era così!

Per certi versi questo caso è particolarmente sentito per la scadenza dei contenuti, mentre raramente lo è per la data di pubblicazione (o visibilità effettiva). Nel seguito del documento mi riferirò quindi maggiormente al concetto di scadenza ma sia chiaro che quanto verrà spiegato vale anche per i documenti non ancora giunti alla data di pubblicazione.

Badate bene: se c'è una colpa non è dei redattori. Il funzionamento del meccanismo di scadenza/pubblicazione è in effetti difficile da assimilare (e la lunghezza che assumerà questo articolo è quantomai sospetta per poterlo negare... elefantiasi letteraria a parte!  :-)).

In più, come vedremo poi, è un meccanismo ibrido... in parte usa i permessi (il cuore della sicurezza Plone) ma in modo assai diverso da come i permessi funzionano per tante altre situazioni. Quindi anche gli sviluppatori Plone meno esperti, che magari si sentono già padroni dell'uso del workflow, possono commettere errori.

Prima cosa da capire: scaduto non significa privato
Questo semplice concetto a volte basta agli utenti per poter dire "quindi questo meccanismo non mi serve" perché avrebbero preferito che la scadenza portasse automaticamente all'archiviazione o alla "spubblicazione" del documento.
Consiglio a questi utenti di non abbandonare così precipitosamente questa funzionalità, perché rimane nonostante tutto molto interessante e utile se la si capisce fino in fondo.

Ammettiamo di essere in presenza di un semplice workflow a due stati: privato e pubblicato. Il contenuto privato non è visibile da nessun utente se non il redattore stesso (o il suo team) ma comunque non ai semplici ed anonimi visitatori del sito.
Il contenuto pubblicato è invece di pubblico dominio. Tutti lo vedono, tutti lo trovano (compreso Google).

Poi abbiamo la data di scadenza (o pubblicazione).

Queste due entità (stato di revisione del documento e data di pubblicazione) viaggiano in modo completamente disaccoppiato e non si influenzano in nessun modo. Posso avere tutte e quattro le possibili combinazioni:
  • documento privato e ancora valido
  • documento privato a scaduto
  • documento pubblicato e ancora valido
  • documento pubblicato e scaduto
La sicurezza (il workflow) è l'unica cosa certa. Se un contenuto è privato è sicuro. Qualunque sia la data di scadenza poco importa, il documento privato non può essere acceduto direttamente, o tramite ricerche da Google o nel sito. Non ci sono problemi relativamente a scarsa sicurezza in questi casi.

I problemi che potete riscontrare iniziano quando i documenti diventano pubblicati e per questo da ora in poi ci concentriamo su questi casi. Se un documento è pubblicato è accessibile al mondo. Le date di scadenza/pubblicazione servono solo a limitare alcuni tipi di accesso al contenuto.

La prima lezione da imparare è quindi non confondere la sicurezza del contenuto con la sua validità.

Contenuto scaduto significa "non è ricercabile"
Questa è la mia Legge Zero sull'uso della scadenza/pubblicazione in Plone. E' la prima cosa che dico agli utenti quando parlo di questa funzionalità, che sia ad un corso o ad un nuovo redattore (o purtroppo ad uno vecchio che magari non aveva capito).
Ovviamente questa frase non basta... va argomentata! Ma intanto vi fa iniziare la discussione in modo diverso dal più vago "quando un contenuto è scaduto, non è più visibile", che ricorda troppo quello che capita col passaggio allo stato di revisione privato.

Il funzionamento della data di scadenza/pubblicazione è in realtà davvero tutto qui: il contenuto non può essere trovato dal catalogo di Plone.
Questo significa quindi che il contenuto è escluso automaticamente:
  • dalla ricerca del sito (base, istantanea, avanzata)
  • dal navigatore
  • dai risultati delle collezioni
  • dalle viste applicabili alle cartelle
Come dicevo, il funzionamento va argomentato un po': l'utente deve capire che Plone usa la ricerca per quasi qualunque cosa venga mostrata nella sua interfaccia. Se è ovvio comprendere questa regola per quello che riguarda la ricerca del sito, è bene accennare al fatto che anche:
  • che il navigatore è frutto di una serie di utilizzi del catalogo di Plone
  • che le varie viste applicabili alle cartelle eseguono delle ricerche nel catalogo (questo in realtà dovrebbe essere cambiato da Plone 4.0 ma non è cambiato il risultato quindi non complichiamo le cose!)
  • che le collezioni non sono altro che "ricerche salvate" e quindi usano il catalogo
Il risultato di questa regola è che il contenuto scaduto, se non per il Manager del sito (il perché lo vedremo poi) risulta sparito.
L'effetto primario per l'utente finale è che in effetti (ad una prima occhiata che spesso confonde i redattori) subisce lo stesso effetto del cambio di stato quando si revoca il contenuto e lo si porta a privato: il contenuto non viene più trovato dalla ricerca, sparisce dai navigatori e dalle viste...

Ma la differenza quindi qual'è?

Google e cronologia hanno la memoria lunga
La differenza è semplice: un contenuto che non può essere trovato non significa sia inaccessibile mentre con l'uso del workflow abbiamo entrambe le cose.

Partiamo da Google, che ha indicizzato il vostro contenuto (in quanto c'è stato un momento nella sua storia dove probabilmente questo era pubblicato e non era scaduto). E' vero che anche i crawler dei motori di ricerca, visitando il sito come utenti anonimi, improvvisamente smetteranno di trovare link al documento in quanto il contenuto è sparito dai navigatori e dalle varie viste.

Ma questo basta per dire a Google di smettere di indicizzare quella pagina e farla sparire dagli archivi?
Ovviamente no! I motori di ricerca (e gli utenti, tramite questi) continueranno ad arrivare alla pagina. Google conosceva l'indirizzo e continuerà ad indicizzare quella pagina a meno che non decida spontaneamente di rimuoverla dall'indice. L'unico effetto certo è vederne calare il page rank, visto che i link a questa pagina saranno meno (o addirittura spariti completamente). Niente più.

A dire la verità forse Plone potrebbe esplicitamente avvertire i motori di ricerca di smettere di indicizzare le pagine scadute (basterebbe un tag META ben scritto... che sia un'ottimizzazione SEO da considerare)?

Senza andare a disturbare Big G, ricordate poi che gli utenti usano browser che sono sempre più avanzati. Oltre ai bookmarks (preferiti o segnalibri), possono contare sulla cronologia delle ricerche, l'autocompletamento, ... E' quindi comunque possibile che gli utenti raggiungano la vostra pagina semplicemente perché ci sono già stati (loro direttamente, o un altro utilizzatore dello stesso browser).

Infine: siete certi al 100% che nel resto del sito, o in un altro sito che non è sotto il controllo vostro o dei vostri redattori, qualcuno non abbia inserito un link alla pagina scaduta? Non l'avete per caso inviata per posta? Ad una mailing list? In un forum?

Capire questo vi eviterà di trovarvi nella situazione di credere che i vostri contenuti, i quali non dovrebbero essere più accessibili, siano spiacevolmente ancora pubblici.

Vorrei che i contenuti scaduti venissero archiviati
Questo è possibile? Certamente, ma va sviluppato qualcosa... a Plone va aggiunto qualche componente.
Un paio di idee:
  • un processo esterno chiama Plone ogni ora (o una volta al giorno, magari la notte) e scatena un'operazione che porta i contenuti scaduti allo stato privato
  • come sopra, ma li sposta in una cartella privata
  • aggiungere a tutti i contenuti del sito un controllo (una viewlet andrebbe bene ma probabilmente non sarebbe troppo elegante...) che controlli se l'utente corrente ha poteri per vedere i contenuti scaduti e in caso contrario lanci l'errore di "Non Autorizzato"
Tutte queste soluzioni sono praticabili ed hanno pro e contro.

Mi serve davvero farlo scadere?
La scadenza di News ed Eventi a mio avviso è nella natura stessa di questi contenuti, quindi sì, probabilmente dovete farli scadere.
Altre volte invece ho visto utenti che volevano fondamentalmente archiviare un documento, mettere una data di scadenza a quello vecchio e pubblicare quello nuovo, per poter avere sempre disponibile la vecchia versione.

A questi utenti ricordo che Plone ha un sistema di versionamento integrato. In questo caso non vi serve assolutamente giocare con la data di scadenza. Semplicemente modificando il contenuto e sostituendo le sue informazioni con quelle aggiornate fa sì che i vecchi dati vengano salvati come "vecchia versione".

Imparare ad usare le date di scadenza e pubblicazione
Ora che abbiamo capito come non intendere il funzionamento delle date di scadenza e pubblicazione e come evitare che il loro uso improprio provochi problemi al nostro sito, non ci rimane che tirare le somme e riassumere come vanno usate.

I documenti scaduti, per la loro natura, perdono grandissima visibilità nel sito e questo è un bene. Come dicevo sopra anche Google viene influenzato dalla sparizione di link che portano a quella pagina, quindi anche la ricerca della stessa risulterà più difficile.

Ma nella mente dei vostri redattori questa deve rimanere una pagina pubblica. Dovete chiarir loro questo concetto in modo definitivo. Il documento ha perso importanza, contiene informazioni non più aggiornate, ma se un utente particolare volesse accedervi potrebbe ancora farlo.
Dovete vedere questa caratteristica come un pregio... se il visitatore vuole leggere una news scaduta, relativa ad un evento dell'anno scorso sul vostro sito, perché impedirglielo?

Purtroppo, nella pratica di Plone questo non è un ragionamento che torna completamente. Plone non permette completamente nemmeno questo (a meno di modificare i permessi, come spiegato sotto): come dicevo sopra, non potete cercare il documento scaduto.

Siamo quindi in presenza di una situazione un po' "a mezza via". Se infatti la vostra scelta è consapevole e sapete come Plone si comporterà col vostro contenuto scaduto (e lo accettate), non è quindi facile per il visitatore del sito tornare a quel documento.

L'assurdità della situazione è che Google può ancora guidare i vostri utenti alla pagina scaduta, la ricerca integrata nel sito no.

Come funziona la "magia" dei documenti scaduti?
Questa sezione diventa un po' più tecnica ma servirà a capire perché succede tutto questo.

Nei fatti non appena il comportamento di Plone diventa chiaro mi sono sentito chiedere varie volte "ma non si può correggere"?
Come dicevo all'inizio, questo comportamento è percepito con un bug. Ma è bene chiarire che non è un bug... forse potrà essere definito un limite del sistema, ma è un comportamento che ha una precisa spiegazione.

Quando eseguiamo qualcosa che scatena una ricerca nel catalogo di Plone (e questo capita decine di volte per ogni click che provoca il caricamento di una pagina), per sapere se quel contenuto può essere trovato dall'utente corrente, viene analizzato uno speciale indice del catalogo dal nome allowedRolesAndUsers. Questo indice ha un comportamento complesso che non voglio approfondire; diciamo solo che contiene, per ogni contenuto, tutte le informazioni necessarie per capire se l'utente corrente (anche il visitatore anonimo), con i suoi ruoli e i ruoli dei gruppi di cui fa parte, può vedere un documento.

Lasciando momentaneamente perdere le ricerche nel catalogo, chiediamoci invece come funziona la sicurezza di Plone: come fa Plone a sapere se un certo utente può vedere un contenuto?

Viene verificato ogni ruolo dell'utente corrente per capire se ad uno di questi è associato il permesso View, che identifica proprio il permesso di vedere il contenuto. Questo (e tutti gli altri permessi che di solito interessano) sono gestiti dal workflow di Plone. Avere questo permesso significa vedere, non averlo significa non poter accedere e ottenere quindi la pagina di errore per accesso non autorizzato (nel caso si tenti comunque di visitarne l'URL).

Stato privato del workflow

Lo spostamento del contenuto da stato pubblicato a privato non fa altro che modificare quel valore.

Stato pubblicato del workflow

Il numero di ruoli (e anche l'essere Anonimo è visto come un ruolo) che può vedere il contenuto cambia.
Come già detto, la verifica della sicurezza di un oggetto è perfetta e non da problemi, ma le ricerche non funzionano in questo modo.

Le ricerche di Plone non accedono al contenuto vero e proprio per verificarne lo stato di revisione, ma usano l'indice allowedRolesAndUsers di cui parlavamo sopra.
Questo viene fatto per questioni di velocità: accedere al contenuto è una pratica decine di volte più lenta (e più costosa in termini di memoria) che non usare il catalogo. Quell'indice è una traduzione dello stato di visibilità corrente del contenuto (permesso di View) e viene aggiornato ad ogni modifica del contenuto stesso che ne provochi un cambio.

Non esiste quindi un permesso che si occupi dei contenuti scaduti?
Certo! Il permesso è "Access inactive portal content" (letteralmente: "accesso al contenuto inattivo") ma a differenza dello stato di revisione e del permesso di View, questo risente anche di un'altra variabile non controllata da Plone: il tempo.

Per questo non è possibile avere un ulteriore indice (o modificare il comportamento di allowedRolesAndUser) che memorizzi in qualche modo questa informazione perché l'informazione cambia con lo scorrere del tempo.
Non è nemmeno è possibile verificare il permesso direttamente sul contenuto: questa verifica comporterebbe il caricamento del contenuto stesso (e come detto poco fa è un procedimento che rallenterebbe troppo Plone, se immaginato ripetuto per centinaia o migliaia di documenti).

Quindi come viene usato? Nella pratica se l'utente corrente non ha questo permesso, ai criteri di ricerca viene letteralmente iniettato un nuovo criterio basato sull'indice effectiveRange, quindi l'intervallo di tempo in cui il contenuto è valido.
Ma come viene fatta quindi la verifica del permesso? La modifica di questo permesso non ha effetto sui singoli contenuti (e non va quindi usato nel workflow a meno di non introdurre la viewlet poco elegante ipotizzata sopra) ma può essere gestita a livello di sito.
Questo apre nuovi scenari e possibilità... e purtroppo qualche altra incomprensione.

Modifiche di "Access inactive portal content" da valutare
Abbiamo quindi imparato come questo permesso possa essere usato, ed in effetti influenzi la ricerca, sul sito Plone. Ecco infatti il motivo per cui il Manager del sito vede i documenti scaduti.

Ragionando un attimo, potrete arrivare a capire come questo porti anche ad un altro comportamento di Plone poco amichevole. Vi è mai capitato che l'autore di un contenuto (ruolo Owner) non veda più i propri documenti una volta che sono scaduti?
Ebbene... capita. L'utente è Owner sul contenuto, ma non lo è a livello di sito (l'Owner del sito è ovviamente il suo creatore, quindi l'utente Manager principale che di solito ha id "admin").

Questo ci porta in fretta a valutare le uniche due modifiche al permesso "Access inactive portal content" che vi consiglio di valutare.

Chi ha un account nel sito può vedere documenti scaduti
Nella maggior parte dei siti chi ha un account (di qualunque tipo) è un redattore o un revisore di contenuti. Ha quindi senso valutare se dare al ruolo "Member" (il Collaboratore) il permesso per trovare i contenuti scaduti.
Il Redattore A potrà vedere i contenuti scaduti, suoi e anche del Redattore B... ma questo è un problema? Dopo tutto sarebbero comunque accessibili conoscendone l'URL!

In questo modo evitate lo spiacevole caso del "non vedo i miei contenuti".

Tutti vedono i contenuti scaduti
L'interfaccia di Plone evidenzierebbe comunque l'accesso ad un contenuto che è scaduto, mostrando una scritta "scaduto".

Vista di un contenuto scaduto

Se vi sembra poco, la modifica di questo testo con qualcosa di più "acceso" è semplice.

Dunque perché non valutare se dare questo permesso anche agli anonimi? Otterreste che la ricerca nel sito funzionerà alla pari di Google, trovando di nuovo tutti i contenti pubblici, ma visitandone il dettaglio il visitatore potrà comunque accorgersi che sta accedendo a dati non più aggiornati.
Nota bene: purtroppo perché l'utente anonimo sia in grado di visualizzare quella scritta, come nell'immagine sopra, è anche necessario andare nel pannello di controllo di Plone (sezione "Sicurezza") e selezionare "Consenti a chiunque di vedere le informazioni personali".

Altre combinazioni?
Ci sono in effetti altri casi possibili che potete valutare ma li trovo meno comuni.
Esempio: se la squadra di revisione dei contenuti è unica nel sito (e quindi avete un gruppo di persone che hanno ruolo Reviewer ovunque) allora potreste dare il permesso "Access inactive portal content" a questo ruolo.
Stessa cosa per i contributori (Contributor) e gli Editor... dipende molto dalla dimensione e dalla struttura della vostra redazione, e del vostro sito.