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/picsoutemplates/): funciona, mas o próximogit pullou 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ça | Chave de config | Mecanismo no GLPI 11 | Armadilha comum |
|---|---|---|---|
| Favicon | favicon_picture | <link rel="icon"> reescrito via JS | A cache agressiva do navegador retém o ícone antigo |
| Título do separador | page_title | document.title | Ecrãs que definem o próprio título revertem-no |
| Logótipo do login | login_picture | span.glpi-logo via content: url(...) | Apontar a .login-logo, que não existe no 11 |
| Fundo do login | login_background | body.welcome-anonymous / .page-anonymous | Apontar a body.login-page, que não existe no 11 |
| Logótipo do cabeçalho | internal_picture | Cabeçalho interno via add_javascript | Confundi-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 interface | color_* | 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
- Ative o módulo Branding no catálogo de módulos do NexTool.
- 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). - Carregue o fundo do ecrã de início de sessão e ajuste o título do separador do navegador.
- Escolha o comportamento do rodapé: manter o original, ocultar ou substituir por texto (HTML limitado a etiquetas seguras).
- 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: containjustamente 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.