Como personalizar a identidade visual do GLPI com o módulo Branding

Branding no GLPI que sobrevive às atualizações: porque editar o core apaga a marca no update, o DOM real do ecrã de início de sessão no GLPI 11 (span.glpi-logo, body.welcome-anonymous), o CSS que o módulo injeta por hook, SQL de auditoria e as armadilhas de campo.

Trocar o logótipo do GLPI parece um ajuste de cinco minutos - até a próxima atualização apagar tudo. Personalizar a identidade visual editando o CSS do core ou o template de início de sessão funciona no dia, mas é uma dívida que vence sozinha: desaparece na atualização e, no salto do GLPI 10 para o 11, o DOM do ecrã de início de sessão mudou de nome, por isso o hack antigo deixa de aplicar sem lançar qualquer erro. Este guia mostra como fazer branding que sobrevive às atualizações, onde vive cada peça no GLPI 11 e as armadilhas que só aparecem em ambiente de cliente.

Branding no GLPI não é só estética

Um GLPI com a cara da organização reduz o atrito: o utilizador final reconhece que aquilo é o Service Desk da empresa, e não um sistema estranho a pedir credenciais. Mas o custo escondido não está em escolher a cor certa - está na forma como a personalização é aplicada. Há três caminhos, e dois deles cobram caro depois.

  • Editar o core (CSS, imagens ou templates dentro de glpi/css, glpi/pics ou templates/): funciona, mas o próximo git pull ou a extração do release sobrescreve os ficheiros. A personalização evapora-se e ninguém se lembra porquê.
  • Tema/CSS injetado por fora: sobrevive à atualização dos ficheiros, mas fica preso aos seletores dessa versão. Quando o GLPI muda a estrutura HTML - como fez do 10 para o 11 - o seletor deixa de existir e o CSS torna-se letra morta, silenciosamente.
  • Hook de plugin: o GLPI expõe pontos de injeção oficiais (display_login, add_javascript). O módulo aplica a marca por esses hooks, sem tocar num único ficheiro do core. É o único caminho que sobrevive às atualizações por conceção.

O que se pode personalizar - e onde vive cada peça

Cada elemento visual do GLPI vive num sítio diferente do DOM, e trocá-lo sem saber o alvo certo é o que gera a maioria dos pedidos de "mudei e não apareceu". A matriz abaixo mapeia cada peça à sua chave de configuração e ao mecanismo real no GLPI 11:

PeçaChave de configMecanismo no GLPI 11Armadilha comum
Faviconfavicon_picture<link rel="icon"> reescrito via JSA cache agressiva do navegador retém o ícone antigo
Título do separadorpage_titledocument.titleEcrãs que definem o próprio título revertem-no
Logótipo do loginlogin_picturespan.glpi-logo via content: url(...)Apontar a .login-logo, que não existe no 11
Fundo do loginlogin_backgroundbody.welcome-anonymous / .page-anonymousApontar a body.login-page, que não existe no 11
Logótipo do cabeçalhointernal_pictureCabeçalho interno via add_javascriptConfundi-lo com o logótipo de login (alvos distintos)
Rodapéfooter_mode / footer_text.copyright (tema predefinido do 11)Colar HTML não sanitizado no texto personalizado
Cores da interfacecolor_*Variáveis CSS Tabler (--tblr-*)Passar um valor que não é hex e injetar CSS partido

A armadilha do GLPI 11: o logótipo de login não é fundo

Na sustentação de ambientes de clientes, o pedido clássico é: "atualizámos o GLPI e o ecrã de início de sessão voltou ao predefinido". A causa é quase sempre uma personalização feita diretamente no core ou num CSS que apontava aos seletores do GLPI 10. No salto para o 11, o template do ecrã de início de sessão (page_card_notlogged.html.twig) foi reescrito: o <body> passou a body.welcome-anonymous, o contentor passou a .page-anonymous e o logótipo deixou de ser uma imagem de fundo - agora é um <span class="glpi-logo"> renderizado por content: var(--logo). Descobrimos isto na prática a 2026-06-10, a depurar porque o fundo de login de um cliente simplesmente não aplicava após o upgrade: o seletor antigo body.login-page já não existia no DOM. Não havia erro no log - o CSS estava correto para uma versão que já não corria. Por isso passámos a emitir os seletores certos por hook, versionados junto do módulo. Este é o CSS real que o módulo injeta - e os seletores mortos que explicam o desaparecimento:

/* GLPI 11 - seletores REAIS do ecra de inicio de sessao (page_card_notlogged.html.twig) */
/* O logotipo NAO e fundo: e um <span class="glpi-logo"> com 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 a proporcao da imagem */
}

/* O fundo vai no body.welcome-anonymous / .page-anonymous - NUNCA em body.login-page */
body.welcome-anonymous,
.page-anonymous {
  background-image: url("...") !important;
  background-size: cover !important;
  background-position: center center !important;
}

/* Seletores do GLPI 10 que JA NAO existem no 11 (por isso o hack antigo desaparece sem erro):
   .login-logo      -> agora e span.glpi-logo
   body.login-page  -> agora e body.welcome-anonymous  */

Como o módulo aplica sem tocar no core

No ecrã de início de sessão não há sessão, por isso o módulo pendura-se no hook display_login e injeta um bloco <style>/<script> em linha. As imagens (favicon, logótipo, fundo) são servidas por um endpoint stateless que não exige início de sessão, com três proteções que vale a pena nomear porque são precisamente onde plugins descuidados deixam fugir dados: a extensão passa por uma whitelist (png, jpg, jpeg, gif, ico, svg, webp), o caminho é resolvido com realpath() e verificado contra o prefixo da pasta de carregamento (bloqueio de path traversal), e o ficheiro é gravado com nome único via uniqid() para não colidir nem sobrescrever. Nas páginas internas, já autenticadas, a personalização entra pelo hook add_javascript.

Um detalhe de desempenho que só aparece a medir: o JS interno vai com Cache-Control: private, max-age=86400 e as imagens com public, max-age=604800 (uma semana), mas sem ETag. A razão é concreta - com ETag e max-age juntos, o Chrome revalidava (HTTP 304) em cada carregamento de página, e cada 304 ainda pagava o bootstrap completo do GLPI no servidor. Um hash da configuração entra no parâmetro fv= do URL, por isso guardar a config muda o URL e invalida a cache de imediato, sem revalidação.

Configuração em cinco passos

  1. Ative o módulo Branding no catálogo de módulos do NexTool.
  2. No separador Configurações, carregue o favicon, o logótipo de login e o logótipo do cabeçalho; defina a largura e a altura de cada logótipo (aceita px, em, rem, %, vw, vh).
  3. Carregue o fundo do ecrã de início de sessão e ajuste o título do separador do navegador.
  4. Escolha o comportamento do rodapé: manter o original, ocultar ou substituir por texto (HTML limitado a etiquetas seguras).
  5. Opcional: defina as cores da interface por variáveis CSS (o módulo valida cada valor como hex antes de emitir, evitando CSS injection). Recarregue o GLPI para ver o resultado.

Auditoria: quem mudou o quê

Toda a ação - ativar, desativar, guardar config, carregar ou apagar imagem - é registada numa tabela de log do módulo. Num ambiente com mais do que um administrador, esse rasto responde a "quem trocou o logótipo na sexta à noite" sem depender da memória. A consulta de diagnóstico:

-- Rasto de auditoria do modulo Branding: quem mudou a identidade visual e quando
SELECT l.date_creation  AS quando,
       u.name           AS utilizador,
       l.action         AS acao,      -- save_config, upload_picture, delete_picture, toggle_enable/disable
       l.detail         AS detalhe
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;

Armadilhas de campo

  • Favicon que não muda - o navegador guarda o favicon em cache de forma agressiva, por separador e por sessão. Depois de carregar o novo ícone, um hard refresh (Ctrl+Shift+R) ou fechar e reabrir o separador resolve; não é bug do módulo.
  • SVG de fonte fiável - o SVG é ótimo para um logótipo (escala sem perder nitidez), mas pode transportar script embutido. Use SVG apenas de arte que você mesmo gerou; o endpoint serve o ficheiro com o Content-Type correto, mas a higiene começa no carregamento.
  • Rodapé com HTML colado - o texto personalizado do rodapé passa por sanitização que só permite um punhado de etiquetas (a, b, strong, i, em, span, br). Colar um bloco inteiro de HTML de marketing simplesmente não renderiza o que espera.
  • Proporção do logótipo - definir largura e altura fixas sem respeitar a proporção original distorce a imagem. O módulo aplica object-fit: contain justamente para não esticar, mas convém confirmar no ecrã.
  • Upgrade do 10 para o 11 - se o cliente já tinha branding manual no GLPI 10, ele vai desaparecer no 11 pelos seletores trocados. Trate o branding como parte do plano de upgrade, não como surpresa pós-migração.

Quer padronizar a identidade visual do GLPI em todos os ambientes que administra, sem reabrir o assunto a cada atualização? O módulo Branding é gratuito e aplica a marca por hooks nativos. E, se preferir externalizar a implementação e a sustentação do GLPI, a NexTool mantém ambientes de clientes com branding versionado e à prova de atualização.


Este conteúdo foi produzido com auxílio de inteligência artificial e revisado pela equipe Nextool Solutions.

Perguntas Frequentes

Porque a personalização foi feita diretamente no core (ficheiros de CSS, imagens ou templates), e a atualização do GLPI sobrescreve esses ficheiros. A forma de sobreviver às atualizações é aplicar a marca por hooks de plugin (display_login, add_javascript), sem tocar no core - foi para isso que o módulo Branding existe.

No GLPI 11 o template do ecrã de início de sessão foi reescrito. O logótipo deixou de ser imagem de fundo e passou a um <span class="glpi-logo"> com content: var(--logo); o body passou a body.welcome-anonymous e o contentor a .page-anonymous. Se o CSS aponta aos seletores do GLPI 10 (.login-logo, body.login-page), estes já não existem no DOM e a regra não aplica, sem lançar erro.

Não. O módulo Branding aplica favicon, logótipos, fundo de login, rodapé e cores pela interface, via hooks nativos. As alterações não ficam em ficheiros do core, por isso sobrevivem às atualizações do GLPI.

No separador Configurações do módulo, carregue a imagem do favicon e escreva o título pretendido. O módulo reescreve o <link rel="icon"> e o document.title por JavaScript. Se o ícone novo não aparecer, é cache do navegador: um hard refresh (Ctrl+Shift+R) ou reabrir o separador resolve.

Sim, o SVG é aceite e escala sem perder nitidez. O carregamento passa por whitelist de extensão e o serviço protege contra path traversal. Como o SVG pode conter script embutido, use apenas arte de fonte fiável (idealmente gerada por si), não ficheiros de origem desconhecida.

Sim. O Branding é gratuito, faz parte do NexTool e é compatível com GLPI 10 e 11. Atenção no upgrade: se havia branding manual no 10, ele não migra sozinho para o 11 (os seletores do ecrã de início de sessão mudaram); reaplique pelo módulo após a migração.

Precisa de ajuda?