FAZ Cookie Manager 1.30.0 è online. È una release che ho passato quasi per intero a rimettere in fila cose che sembravano funzionare, e che funzionavano davvero — solo non per la ragione che credevo. Il changelog dice cosa è cambiato; qui provo a raccontare perché, che è la metà che un diff non produce.
Una funzione chiamata come qualcosa che non era
Il JavaScript dell’area di amministrazione aveva da sempre un helper di traduzione chiamato __(). Non è mai stato gettext: cerca una chiave puntata dentro una mappa che il PHP passa al browser, fazConfig.i18n. Il nome però è quello che in tutto l’ecosistema WordPress significa una cosa sola, e l’estrattore di stringhe di translate.wordpress.org non guarda cosa fa una funzione — guarda come si chiama.
Il risultato è che 285 chiavi come cookies.jarOnlyToggle sono state raccolte come se fossero testo inglese da tradurre. Nessuno se n’era accorto perché non rompeva nulla di visibile: il plugin continuava a funzionare, le traduzioni reali continuavano ad arrivare. Rompeva un’altra cosa, silenziosamente. Quelle 285 voci fantasma entravano nel conteggio del catalogo, e siccome nessun traduttore poteva tradurle in qualcosa di sensato, la percentuale di completamento di ogni lingua restava inchiodata all’84,8% — sotto la soglia che WordPress richiede per generare i pacchetti lingua. Nessuna lingua poteva essere distribuita.
La correzione è un rinominare: fazI18n(). Le chiavi, i fallback inglesi e la logica di ricerca sono identici, non cambia una virgola a runtime. È il tipo di bug che mi piace meno trovare, perché non c’è stato niente da diagnosticare: c’era solo da leggere il nome con gli occhi di uno strumento che non legge il codice.
Una funzione già scritta al 90% e invisibile
Da mesi c’era una richiesta per poter arrotondare gli angoli dei pulsanti del banner. Andando a guardare, i pulsanti leggevano già una variabile CSS, --faz-btn-border-radius. Era lì, funzionante, documentata nel foglio di stile. Semplicemente nessuno la scriveva mai: non esisteva alcun punto dell’interfaccia che la impostasse, quindi l’unico modo per cambiare quel valore era iniettare CSS a mano.
Aggiungere il campo in Banner → Colori ha richiesto poche righe. Il valore viene controllato nella forma quando si salva, perché finisce dentro una dichiarazione di proprietà personalizzata CSS e un valore malformato lì non dà errore: rompe la regola in silenzio. Lasciare il campo vuoto mantiene i 2px di sempre, quindi i banner esistenti si disegnano identici a prima.
Un documento legale nella lingua sbagliata, senza dirlo
Il generatore di cookie policy sceglie un modello in base alla giurisdizione e alla lingua. Olandese e croato erano selezionabili come lingua della policy — l’interfaccia era tradotta, la lingua compariva nel menu — ma per quelle due non era mai stato spedito alcun modello. Il generatore faceva quello che fa un fallback: ripiegava sull’inglese e produceva il documento.
Il punto non è la lingua mancante, è il silenzio. Chi genera una cookie policy in olandese e riceve un testo inglese può accorgersene; chi la genera, la incolla e non la rilegge, no. Un fallback che non si dichiara è peggio di un errore, perché produce qualcosa che sembra il risultato giusto. Ora i modelli ci sono per tutte e quattro le giurisdizioni, e le caselle di sovrascrittura mostrano il testo olandese e croato come segnaposto.
Un numero plausibile e sbagliato
La dashboard mostrava un totale di visualizzazioni di pagina che non era il numero di visualizzazioni di pagina: sommava le visualizzazioni del banner e le azioni di consenso. Il valore che ne usciva era sempre credibile — cresceva, era dello stesso ordine di grandezza, non faceva mai una cosa strana — e per questo poteva restare lì a lungo. I numeri sbagliati che si notano sono quelli assurdi; quelli plausibili restano.
Nella stessa area, quando il tracciamento delle visualizzazioni è disattivato le metriche ora mostrano -- e spiegano perché, invece di mostrare zero. Zero e “non lo so” sono due affermazioni diverse, e una dashboard che le confonde insegna a diffidare di tutto il resto.
Due scansioni che partono insieme
L’avvio di una scansione del browser ora prende un lock sul database prima di leggere la sessione attiva. Due avvii concorrenti per lo stesso sito e lo stesso amministratore — due schede, un doppio clic, un ricaricamento impaziente — potevano intrecciarsi e lasciare due sessioni che si sovrascrivevano a vicenda. Adesso il secondo riceve un 409 esplicito, i tentativi successivi riusano il token già emesso, e il lock viene rilasciato in ogni uscita: successo, conflitto, eccezione, e anche se la connessione cade a metà.
Traduzioni che si fondono invece di sostituirsi
Il catalogo dei testi del banner viene scaricato per lingua. Prima, un catalogo scaricato sostituiva in blocco quello incluso nel plugin: se il download copriva solo una parte dei campi, tutto il resto tornava all’inglese. Ora la fusione avviene campo per campo, e una stringa inglese non tradotta dentro un catalogo scaricato non può sovrascrivere una traduzione inclusa. Il testo di riferimento mostrato nell’editor del banner viene risolto dalla stessa fusione, così non può più dire una cosa diversa da quella che vede il visitatore.
Sono arrivate anche le traduzioni di categorie e testi del banner in russo e ucraino, e il catalogo incluso viene ora consultato per ogni lingua invece che per le 41 di un elenco scritto a mano.
Un solo paio d’occhi, e non sono quelli del visitatore
La scansione del browser gira dentro la sessione di un amministratore collegato. È strutturale — lo scanner è una schermata di amministrazione che pilota un iframe — ma significa che il sito viene guardato attraverso un paio d’occhi molto poco rappresentativo, e la dichiarazione dei cookie viene costruita da quello che quegli occhi hanno visto.
Il caso che me l’ha fatto notare è _lscache_vary, il cookie con cui LiteSpeed differenzia la cache. Su un blog normale un visitatore anonimo non lo riceve mai, e tenerlo fuori dalla dichiarazione è corretto. Su un sito WooCommerce lo riceve chiunque abbia un carrello, e tenerlo fuori è sbagliato. Stesso cookie, stesso plugin, correttezza opposta, decisa da una configurazione che nessuna scansione può osservare.
Lo scanner riportava già i nomi che metteva da parte, invitando ad aggiungerli a mano — cioè a ridigitare un dominio e una durata che la scansione aveva già misurato e poi buttato via. Ridigitare le prove è il modo in cui un giudizio non viene mai dato. Ora quelle righe vengono conservate con gli attributi misurati e offerte nella schermata Cookie con un pulsante che le dichiara in un clic.
La parte che mi ha fatto quasi consegnare una funzione decorativa è un’altra. Rendere visibile un cookie nel banner lo fa entrare nella lista che il codice JavaScript percorre per cancellare i cookie di una categoria rifiutata. Avevo verificato le protezioni lato server e mi ero fermato lì: dichiarare _lscache_vary avrebbe potuto cancellarlo, insieme ai cookie di chi commenta e ai nonce di sicurezza di altri plugin. Ora il payload porta un contrassegno esplicito che vieta la cancellazione, calcolato sul server dalla lista originale, e vale anche contro un rifiuto per singolo servizio. Dichiarare aggiunge trasparenza e non può mai armare una cancellazione — questa volta davvero, e ci sono i test che diventano rossi se qualcuno toglie quella metà.
I cookie di autenticazione di WordPress restano fuori discussione: un visitatore non collegato non li riceve mai, quindi non sono dichiarabili e la richiesta viene rifiutata anche chiamando direttamente l’endpoint.
Il resto
I link di consenso nel footer, con . Le scelte esplicite di categoria che ora governano tutti i 47 profili di giurisdizione supportati. Gli embed Vimeo e YouTube accettabili anche dopo un blocco dinamico. La trappola del focus del banner che parte quando il banner diventa visibile e non prima. I nomi e le descrizioni delle categorie modificabili in ogni lingua attiva. E lo Stato del sistema che spiega il cron gestito dall’hosting e produce il comando cPanel già compilato per il sito, senza pretendere WP-CLI.
L’aggiornamento è disponibile dalla bacheca di WordPress. Come sempre, le segnalazioni sono benvenute su GitHub.
