Cambiare il logo di GLPI sembra una modifica da cinque minuti - finché il prossimo aggiornamento non cancella tutto. Personalizzare l'identità visiva modificando il CSS del core o il template di login funziona oggi, ma è un debito che scade da solo: sparisce all'aggiornamento e, nel salto da GLPI 10 a 11, il DOM della schermata di login è stato rinominato, quindi il vecchio hack smette di applicarsi senza lanciare alcun errore. Questa guida mostra come fare branding che sopravvive agli aggiornamenti, dove vive ogni pezzo in GLPI 11 e le insidie che compaiono solo in ambiente cliente.
Il branding in GLPI non è solo estetica
Un GLPI con il volto dell'organizzazione riduce l'attrito: l'utente finale riconosce che è il Service Desk dell'azienda, e non un sistema strano che chiede il login. Ma il costo nascosto non sta nello scegliere il colore giusto - sta in come viene applicata la personalizzazione. Ci sono tre strade, e due di esse si pagano care dopo.
- Modificare il core (CSS, immagini o template dentro
glpi/css,glpi/picsotemplates/): funziona, ma il prossimogit pullo l'estrazione della release sovrascrive i file. La personalizzazione evapora e nessuno ricorda perché. - Tema/CSS iniettato dall'esterno: sopravvive all'aggiornamento dei file, ma resta legato ai selettori di quella versione. Quando GLPI cambia la struttura HTML - come ha fatto dal 10 all'11 - il selettore non esiste più e il CSS diventa lettera morta, in silenzio.
- Hook di plugin: GLPI espone punti di iniezione ufficiali (
display_login,add_css,add_javascript). Il modulo applica il marchio tramite questi hook, senza toccare un solo file del core. È l'unica strada che sopravvive agli aggiornamenti per progettazione.
Cosa si può personalizzare - e dove vive ogni pezzo
Ogni elemento visivo di GLPI vive in un punto diverso del DOM, e cambiarlo senza conoscere il bersaglio giusto è ciò che genera la maggior parte dei ticket "l'ho cambiato e non è successo nulla". La matrice qui sotto mappa ogni pezzo alla sua chiave di configurazione e al meccanismo reale in GLPI 11:
| Pezzo | Chiave di config | Meccanismo in GLPI 11 | Insidia comune |
|---|---|---|---|
| Favicon | favicon_picture | <link rel="icon"> riscritto via JS | La cache aggressiva del browser trattiene la vecchia icona |
| Titolo della scheda | page_title | document.title | Le schermate che impostano il proprio titolo lo ripristinano |
| Logo del login | login_picture | span.glpi-logo via content: url(...) | Mirare a .login-logo, che non esiste nell'11 |
| Sfondo del login | login_background | Solo body.welcome-anonymous (.page-anonymous resta trasparente) | Mirare a body.login-page, che non esiste nell'11 |
| Logo dell'intestazione | internal_picture | CSS nel <head> via add_css | Confonderlo con il logo di login (bersagli distinti) |
| Piè di pagina | footer_mode / footer_text | .copyright (tema predefinito dell'11) | Incollare HTML non sanitizzato nel testo personalizzato |
| Colori dell'interfaccia | color_* | Variabili CSS Tabler (--tblr-*) | Passare un valore non hex e iniettare CSS rotto |
L'insidia di GLPI 11: il logo di login non è uno sfondo
Nella manutenzione di ambienti cliente, il ticket classico è: "abbiamo aggiornato GLPI e la schermata di login è tornata allo standard". La causa è quasi sempre una personalizzazione fatta direttamente nel core o in un CSS che puntava ai selettori di GLPI 10. Nel salto all'11, il template della schermata di login (page_card_notlogged.html.twig) è stato riscritto: il <body> è diventato body.welcome-anonymous, il contenitore è diventato .page-anonymous e il logo ha smesso di essere un'immagine di sfondo - ora è uno <span class="glpi-logo"> reso da content: var(--logo). L'abbiamo scoperto sul campo il 2026-06-10, indagando perché lo sfondo di login di un cliente semplicemente non si applicava dopo l'upgrade: il vecchio selettore body.login-page non esisteva più nel DOM. Nessun errore nel log - il CSS era corretto per una versione che non girava più. Per questo ora emettiamo i selettori giusti tramite hook, versionati insieme al modulo. Questo è il CSS reale che il modulo inietta - e i selettori morti che spiegano la scomparsa:
/* GLPI 11 - selettori REALI della schermata di login (page_card_notlogged.html.twig) */
/* Il logo NON e uno sfondo: e uno <span class="glpi-logo"> con content: var(--logo) */
.page-anonymous .glpi-logo {
content: url("/plugins/nextool/ajax/module_ajax.php?module=branding&file=branding.picture.send.php&path=...") !important;
width: 240px !important;
height: 130px !important;
object-fit: contain !important; /* preserva le proporzioni dell'immagine */
}
/* Lo sfondo va SOLO su body.welcome-anonymous - MAI su body.login-page.
Dipingere anche .page-anonymous (figlio diretto) duplicava la grafica sui bordi. */
body.welcome-anonymous {
background-image: url("...") !important;
background-size: cover !important; /* oppure contain, o 100% 100% (allungare) */
background-position: center center !important;
background-repeat: no-repeat !important;
background-attachment: fixed !important; /* misurato sulla finestra, non sulla pagina */
}
.page-anonymous { background-image: none !important; background-color: transparent !important; }
/* Selettori di GLPI 10 che NON esistono piu nell'11 (perche il vecchio hack sparisce senza errore):
.login-logo -> ora e span.glpi-logo
body.login-page -> ora e body.welcome-anonymous */
Come il modulo applica senza toccare il core
Nella schermata di login non c'è sessione, quindi il modulo si aggancia all'hook display_login e inietta un blocco <style>/<script> in linea. Le immagini (favicon, logo, sfondo) sono servite da un endpoint stateless che non richiede login, con tre protezioni che vale la pena nominare perché sono esattamente il punto in cui i plugin disattenti perdono dati: l'estensione passa per una whitelist (png, jpg, jpeg, gif, ico, webp; l'SVG è stato escluso nella versione 1.4.0) e il tipo reale del file viene verificato dal contenuto, il percorso è risolto con realpath() e verificato contro il prefisso della cartella di upload (blocco del path traversal), e il file è salvato con un nome casuale generato dal server, senza riutilizzare il nome inviato, per non collidere né sovrascrivere. Nelle pagine interne, già autenticate, i colori, il logo dell'intestazione e il footer nascosto entrano come CSS nel <head> tramite l'hook add_css, mentre favicon, titolo e footer personalizzato entrano tramite l'hook add_javascript.
Un dettaglio di prestazioni che compare solo misurando: il JS interno viaggia con Cache-Control: private, max-age=86400 e le immagini con public, max-age=31536000, immutable (un anno: ogni upload crea un file con un nome nuovo), ma senza ETag. Il motivo è concreto - con ETag e max-age insieme, Chrome rivalidava (HTTP 304) a ogni caricamento di pagina, e ogni 304 pagava ancora il bootstrap completo di GLPI sul server. Un hash della configurazione entra nel parametro fv= dell'URL, quindi salvare la config cambia l'URL e invalida la cache all'istante, senza rivalidazione.
Configurazione in cinque passi
- Attivi il modulo Branding nel catalogo dei moduli NexTool.
- Nella scheda Configurazione, carichi il favicon, il logo di login e il logo dell'intestazione; imposti larghezza e altezza di ogni logo (accetta
px,em,rem,%,vw,vh). - Carichi lo sfondo della schermata di login e regoli il titolo della scheda del browser.
- Scelga il comportamento del piè di pagina: mantenere l'originale, nasconderlo o sostituirlo con del testo (HTML limitato a tag sicuri).
- Opzionale: imposti i colori dell'interfaccia tramite variabili CSS (il modulo valida ogni valore come hex prima di emetterlo, prevenendo la CSS injection). Ricarichi GLPI per vedere il risultato.
Audit: chi ha cambiato cosa
Ogni azione - attivare, disattivare, salvare config, caricare o eliminare un'immagine - viene registrata in una tabella di log del modulo. In un ambiente con più di un amministratore, questa traccia risponde a "chi ha cambiato il logo venerdì sera" senza dipendere dalla memoria. La query di diagnostica:
-- Traccia di audit del modulo Branding: chi ha cambiato l'identita visiva e quando
SELECT l.date_creation AS quando,
u.name AS utente,
l.action AS azione, -- save_config (upload ed eliminazione di immagini nel dettaglio), toggle_enable/disable
l.detail AS dettaglio
FROM glpi_plugin_nextool_branding_log l
LEFT JOIN glpi_users u ON u.id = l.users_id
ORDER BY l.date_creation DESC
LIMIT 20;
Insidie sul campo
- Favicon che non cambia - il browser mette in cache il favicon in modo aggressivo, per scheda e per sessione. Dopo aver caricato la nuova icona, un hard refresh (Ctrl+Shift+R) o chiudere e riaprire la scheda risolve; non è un bug del modulo.
- L'SVG non è accettato - dalla versione 1.4.0 il modulo rifiuta l'SVG per il logo e la favicon, perché il formato può portare script incorporato e le immagini del modulo sono servite senza login. Per il logo va bene il PNG con sfondo trasparente (o il WEBP), per la favicon PNG o ICO; il server verifica il contenuto reale del file, quindi anche un SVG rinominato in .png viene rifiutato.
- Piè di pagina con HTML incollato - il testo personalizzato del piè passa per una sanitizzazione che consente solo una manciata di tag (
a, b, strong, i, em, span, br). Incollare un intero blocco di HTML di marketing semplicemente non renderà ciò che si aspetta. - Proporzioni del logo - impostare larghezza e altezza fisse senza rispettare la proporzione originale distorce l'immagine. Il modulo applica
object-fit: containproprio per non stirare, ma lo verifichi a schermo. - Upgrade dal 10 all'11 - se il cliente aveva già un branding manuale su GLPI 10, sparisce nell'11 a causa dei selettori cambiati. Tratti il branding come parte del piano di upgrade, non come una sorpresa post-migrazione.
Vuole standardizzare l'identità visiva di GLPI su tutti gli ambienti che amministra, senza riaprire l'argomento a ogni aggiornamento? Il modulo Branding è gratuito e applica il marchio tramite hook nativi. E se preferisce esternalizzare l'implementazione e la manutenzione di GLPI, NexTool mantiene ambienti cliente con branding versionato e a prova di aggiornamento.
Revisionato dal team NexTool Solutions.