Cómo personalizar la identidad visual de GLPI con el módulo Branding

Branding en GLPI que sobrevive a las actualizaciones: por qué editar el core borra la marca en el update, el DOM real de la pantalla de login en GLPI 11 (span.glpi-logo, body.welcome-anonymous), el CSS que el módulo inyecta por hook, SQL de auditoría y las trampas de campo.

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/pics o templates/): funciona, pero el próximo git pull o 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:

PiezaClave de configMecanismo en GLPI 11Trampa común
Faviconfavicon_picture<link rel="icon"> reescrito vía JSLa caché agresiva del navegador retiene el icono antiguo
Título de la pestañapage_titledocument.titlePantallas que fijan su propio título lo revierten
Logo del loginlogin_picturespan.glpi-logo vía content: url(...)Apuntar a .login-logo, que no existe en el 11
Fondo del loginlogin_backgroundbody.welcome-anonymous / .page-anonymousApuntar a body.login-page, que no existe en el 11
Logo del encabezadointernal_pictureEncabezado interno vía add_javascriptConfundirlo con el logo de login (objetivos distintos)
Pie de páginafooter_mode / footer_text.copyright (tema por defecto del 11)Pegar HTML sin sanitizar en el texto personalizado
Colores de la interfazcolor_*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

  1. Activa el módulo Branding en el catálogo de módulos de NexTool.
  2. 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).
  3. Sube el fondo de la pantalla de login y ajusta el título de la pestaña del navegador.
  4. Elige el comportamiento del pie de página: mantener el original, ocultarlo o sustituirlo por texto (HTML limitado a etiquetas seguras).
  5. 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: contain justo 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.

Preguntas Frecuentes

Porque la personalización se hizo directamente en el core (archivos de CSS, imágenes o plantillas), y la actualización de GLPI sobrescribe esos archivos. La forma de sobrevivir a las actualizaciones es aplicar la marca por hooks de plugin (display_login, add_javascript), sin tocar el core - para eso existe el módulo Branding.

En GLPI 11 la plantilla de la pantalla de login fue reescrita. El logo dejó de ser imagen de fondo y pasó a ser un <span class="glpi-logo"> con content: var(--logo); el body pasó a ser body.welcome-anonymous y el contenedor .page-anonymous. Si el CSS apunta a los selectores de GLPI 10 (.login-logo, body.login-page), ya no existen en el DOM y la regla no aplica, sin lanzar error.

No. El módulo Branding aplica favicon, logos, fondo de login, pie de página y colores por la interfaz, vía hooks nativos. Los cambios no viven en archivos del core, así que sobreviven a las actualizaciones de GLPI.

En la pestaña Configuración del módulo, sube la imagen del favicon y escribe el título deseado. El módulo reescribe el <link rel="icon"> y el document.title por JavaScript. Si el icono nuevo no aparece, es caché del navegador: un hard refresh (Ctrl+Shift+R) o reabrir la pestaña lo resuelve.

Sí, el SVG se acepta y escala sin perder nitidez. La subida pasa por una whitelist de extensión y el servicio protege contra path traversal. Como el SVG puede contener script embebido, usa solo arte de fuente confiable (idealmente generada por ti), no archivos de origen desconocido.

Sí. Branding es gratuito, forma parte de NexTool y es compatible con GLPI 10 y 11. Atención en el upgrade: si había branding manual en el 10, no migra solo al 11 (los selectores de la pantalla de login cambiaron); vuelve a aplicarlo por el módulo tras la migración.

?Necesitas ayuda?