Cambiar el logo de GLPI parece un ajuste de cinco minutos - hasta que la próxima actualización lo borra todo. Personalizar la identidad visual editando el CSS del core o la plantilla de login funciona hoy, pero es una deuda que vence sola: desaparece en la actualización y, en el salto de GLPI 10 a 11, el DOM de la pantalla de login cambió de nombre, así que el hack antiguo deja de aplicarse sin lanzar ningún error. Esta guía muestra cómo hacer branding que sobrevive a las actualizaciones, dónde vive cada pieza en GLPI 11 y las trampas que solo aparecen en un entorno de cliente.
El branding en GLPI no es solo estética
Un GLPI con la cara de la organización reduce la fricción: el usuario final reconoce que es el Service Desk de la empresa, y no un sistema extraño pidiendo login. Pero el coste oculto no está en elegir el color correcto - está en cómo se aplica la personalización. Hay tres caminos, y dos de ellos cobran caro después.
- Editar el core (CSS, imágenes o plantillas dentro de
glpi/css,glpi/picsotemplates/): funciona, pero el próximogit pullo la extracción del release sobrescribe los archivos. La personalización se evapora y nadie recuerda por qué. - Tema/CSS inyectado por fuera: sobrevive a la actualización de archivos, pero queda atado a los selectores de esa versión. Cuando GLPI cambia la estructura HTML - como hizo del 10 al 11 - el selector deja de existir y el CSS se vuelve letra muerta, en silencio.
- Hook de plugin: GLPI expone puntos de inyección oficiales (
display_login,add_javascript). El módulo aplica la marca por esos hooks, sin tocar un solo archivo del core. Es el único camino que sobrevive a las actualizaciones por diseño.
Qué se puede personalizar - y dónde vive cada pieza
Cada elemento visual de GLPI vive en un lugar distinto del DOM, y cambiarlo sin saber el objetivo correcto es lo que genera la mayoría de los tickets de "lo cambié y no apareció". La matriz siguiente asigna cada pieza a su clave de configuración y al mecanismo real en GLPI 11:
| Pieza | Clave de config | Mecanismo en GLPI 11 | Trampa común |
|---|---|---|---|
| Favicon | favicon_picture | <link rel="icon"> reescrito vía JS | La caché agresiva del navegador retiene el icono antiguo |
| Título de la pestaña | page_title | document.title | Pantallas que fijan su propio título lo revierten |
| Logo del login | login_picture | span.glpi-logo vía content: url(...) | Apuntar a .login-logo, que no existe en el 11 |
| Fondo del login | login_background | body.welcome-anonymous / .page-anonymous | Apuntar a body.login-page, que no existe en el 11 |
| Logo del encabezado | internal_picture | Encabezado interno vía add_javascript | Confundirlo con el logo de login (objetivos distintos) |
| Pie de página | footer_mode / footer_text | .copyright (tema por defecto del 11) | Pegar HTML sin sanitizar en el texto personalizado |
| Colores de la interfaz | color_* | Variables CSS Tabler (--tblr-*) | Pasar un valor que no es hex e inyectar CSS roto |
La trampa de GLPI 11: el logo de login no es un fondo
En el mantenimiento de entornos de clientes, el ticket clásico es: "actualizamos GLPI y la pantalla de login volvió al estándar". La causa casi siempre es una personalización hecha directamente en el core o en un CSS que apuntaba a los selectores de GLPI 10. En el salto al 11, la plantilla de la pantalla de login (page_card_notlogged.html.twig) fue reescrita: el <body> pasó a ser body.welcome-anonymous, el contenedor pasó a ser .page-anonymous y el logo dejó de ser una imagen de fondo - ahora es un <span class="glpi-logo"> renderizado por content: var(--logo). Lo descubrimos en la práctica el 2026-06-10, depurando por qué el fondo de login de un cliente simplemente no se aplicaba tras el upgrade: el selector antiguo body.login-page ya no existía en el DOM. No había error en el log - el CSS era correcto para una versión que ya no corría. Por eso ahora emitimos los selectores correctos por hook, versionados junto al módulo. Este es el CSS real que el módulo inyecta - y los selectores muertos que explican la desaparición:
/* GLPI 11 - selectores REALES de la pantalla de login (page_card_notlogged.html.twig) */
/* El logo NO es un fondo: es un <span class="glpi-logo"> con content: var(--logo) */
.page-anonymous .glpi-logo {
content: url("/plugins/nextool/front/module_assets.php?module=branding&file=...") !important;
width: 240px !important;
height: 130px !important;
object-fit: contain !important; /* preserva la proporcion de la imagen */
}
/* El fondo va en body.welcome-anonymous / .page-anonymous - NUNCA en body.login-page */
body.welcome-anonymous,
.page-anonymous {
background-image: url("...") !important;
background-size: cover !important;
background-position: center center !important;
}
/* Selectores de GLPI 10 que YA NO existen en el 11 (por eso el hack antiguo desaparece sin error):
.login-logo -> ahora es span.glpi-logo
body.login-page -> ahora es body.welcome-anonymous */
Cómo el módulo aplica sin tocar el core
En la pantalla de login no hay sesión, así que el módulo se cuelga del hook display_login e inyecta un bloque <style>/<script> en línea. Las imágenes (favicon, logo, fondo) se sirven por un endpoint stateless que no exige login, con tres protecciones que vale nombrar porque son justo donde los plugins descuidados filtran: la extensión pasa por una whitelist (png, jpg, jpeg, gif, ico, svg, webp), la ruta se resuelve con realpath() y se comprueba contra el prefijo del directorio de subida (bloqueo de path traversal), y el archivo se guarda con nombre único vía uniqid() para que no colisione ni sobrescriba. En las páginas internas, ya autenticadas, la personalización entra por el hook add_javascript.
Un detalle de rendimiento que solo aparece midiendo: el JS interno va con Cache-Control: private, max-age=86400 y las imágenes con public, max-age=604800 (una semana), pero sin ETag. La razón es concreta - con ETag y max-age juntos, Chrome revalidaba (HTTP 304) en cada carga de página, y cada 304 aún pagaba el bootstrap completo de GLPI en el servidor. Un hash de la configuración entra en el parámetro fv= de la URL, así que guardar la config cambia la URL e invalida la caché al instante, sin revalidación.
Configuración en cinco pasos
- Activa el módulo Branding en el catálogo de módulos de NexTool.
- En la pestaña Configuración, sube el favicon, el logo de login y el logo del encabezado; define ancho y alto de cada logo (acepta
px,em,rem,%,vw,vh). - Sube el fondo de la pantalla de login y ajusta el título de la pestaña del navegador.
- Elige el comportamiento del pie de página: mantener el original, ocultarlo o sustituirlo por texto (HTML limitado a etiquetas seguras).
- Opcional: define los colores de la interfaz por variables CSS (el módulo valida cada valor como hex antes de emitirlo, evitando CSS injection). Recarga GLPI para ver el resultado.
Auditoría: quién cambió qué
Toda acción - activar, desactivar, guardar config, subir o borrar imagen - se registra en una tabla de log del módulo. En un entorno con más de un administrador, esa traza responde "quién cambió el logo el viernes por la noche" sin depender de la memoria. La consulta de diagnóstico:
-- Traza de auditoria del modulo Branding: quien cambio la identidad visual y cuando
SELECT l.date_creation AS cuando,
u.name AS usuario,
l.action AS accion, -- save_config, upload_picture, delete_picture, toggle_enable/disable
l.detail AS detalle
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;
Trampas de campo
- Favicon que no cambia - el navegador cachea el favicon de forma agresiva, por pestaña y por sesión. Después de subir el nuevo icono, un hard refresh (Ctrl+Shift+R) o cerrar y reabrir la pestaña lo resuelve; no es un bug del módulo.
- SVG de fuente confiable - el SVG es ideal para un logo (escala sin perder nitidez), pero puede llevar script embebido. Usa SVG solo de arte que generaste tú; el endpoint sirve el archivo con el Content-Type correcto, pero la higiene empieza en la subida.
- Pie con HTML pegado - el texto personalizado del pie pasa por una sanitización que solo permite un puñado de etiquetas (
a, b, strong, i, em, span, br). Pegar un bloque entero de HTML de marketing simplemente no renderiza lo que esperas. - Proporción del logo - definir ancho y alto fijos sin respetar la proporción original distorsiona la imagen. El módulo aplica
object-fit: containjusto para no estirar, pero conviene comprobarlo en pantalla. - Upgrade del 10 al 11 - si el cliente ya tenía branding manual en GLPI 10, desaparecerá en el 11 por los selectores cambiados. Trata el branding como parte del plan de upgrade, no como una sorpresa posterior a la migración.
¿Quieres estandarizar la identidad visual de GLPI en todos los entornos que administras, sin reabrir el tema en cada actualización? El módulo Branding es gratuito y aplica la marca por hooks nativos. Y si prefieres externalizar la implantación y el mantenimiento de GLPI, NexTool mantiene entornos de clientes con branding versionado y a prueba de actualizaciones.
Este conteúdo foi produzido com auxílio de inteligência artificial e revisado pela equipe Nextool Solutions.