O ecrã de login padrão do WordPress (wp-login.php) reconhece-se em três segundos: fundo cinzento, logótipo do WordPress, formulário genérico. Para um blog pessoal serve. Para uma loja, um portal de clientes ou um projeto de agência com a marca do cliente, é uma falha de branding. Os editores entram todos os dias, e a primeira impressão não é a página inicial, é este ecrã.
Este guia mostra como adaptar o login à marca apenas com hooks do WordPress: login_enqueue_scripts, os filtros do logótipo login_headerurl e login_headertext, login_message, mensagens de erro genéricas e a escolha entre plugin must-use e tema filho. Todos os hooks e versões foram verificados no código-fonte do WordPress 7.1. Para reforço que vai além do aspeto visual, veja os nossos serviços de segurança WordPress.
O que o WordPress carrega no wp-login.php
Antes de trocar o logótipo, convém saber o que o núcleo faz quando alguém pede wp-login.php:
- Carrega
wp-admin/css/login.csse os estilos do painel de que depende (botões, formulários). - Dispara
login_enqueue_scripts, onde adiciona o seu CSS e JS, tal comowp_enqueue_scriptsno front-end. - Desenha o cabeçalho com a ligação do logótipo (por defeito para wordpress.org), o formulário, as ligações de palavra-passe esquecida e de registo, e o rodapé.
- Num erro de validação, acrescenta o script de abanar e mostra a mensagem do filtro
login_errors. - Os filtros
login_messageelogin_messagespermitem colocar HTML por cima do formulário (aviso depois de terminar sessão, nota de manutenção, banner de SSO).
A consequência principal: a página de login não passa pelo pipeline do tema do front-end. header.php, os modelos de um tema de blocos e a maioria dos callbacks de wp_enqueue_scripts não correm ali. Por isso existe uma ação de enqueue própria e por isso os estilos do login precisam de um ficheiro próprio. Regras que só estão no style.css do tema nunca chegam ao wp-login.php.
A segunda consequência: uma atualização do WordPress pode mudar seletores, a ordem dos scripts ou o markup do formulário (campos extra de um plugin de 2FA, por exemplo). Branding construído com hooks sobrevive à atualização; um wp-login.php alterado no núcleo não.
Como carregar um CSS próprio na página de login do WordPress
O fundo cinzento padrão (#f0f0f1 no login.css atual) raramente combina com a marca. Crie um ficheiro style-login.css no tema e carregue-o só na página de login, com número de versão para que o navegador não use a cópia antiga em cache depois de um deploy:
function wppoland_login_stylesheet() {
wp_enqueue_style(
'wppoland-login',
get_stylesheet_directory_uri() . '/style-login.css',
array(),
wp_get_theme()->get( 'Version' )
);
}
add_action( 'login_enqueue_scripts', 'wppoland_login_stylesheet' );Exemplo style-login.css:
body.login {
background-color: #0d1117;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.login form {
background: #161b22;
border: 1px solid #30363d;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
border-radius: 12px;
padding: 40px;
}
.login label {
color: #c9d1d9;
font-size: 14px;
font-weight: 500;
}
.login input[type="text"],
.login input[type="password"] {
background: #0d1117;
border: 1px solid #30363d;
border-radius: 6px;
color: #c9d1d9;
padding: 12px 16px;
font-size: 14px;
}
.login input[type="text"]:focus,
.login input[type="password"]:focus {
border-color: #58a6ff;
box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.4);
}
.wp-core-ui .button-primary {
background: #238636;
border-color: rgba(27, 31, 35, 0.15);
border-radius: 6px;
padding: 12px 24px;
font-size: 14px;
font-weight: 600;
text-shadow: none;
box-shadow: none;
}
.wp-core-ui .button-primary:hover,
.wp-core-ui .button-primary:focus {
background: #2ea043;
}
.login #nav,
.login #backtoblog {
text-align: center;
}
.login #nav a,
.login #backtoblog a {
color: #8b949e;
}
.login #nav a:hover,
.login #backtoblog a:hover {
color: #58a6ff;
}Regras práticas para o CSS do login:
- Aponte para classes que o WordPress realmente emite:
body.login,#login,.login form,.wp-core-ui .button-primary,#login_error,.message. - Não esconda
#nave#backtoblogsem acordo com o cliente. Os editores perdem o caminho de volta ao site e a recuperação da palavra-passe parece avariada. - Evite
display: noneem campos do formulário. Um plugin de 2FA ou de passkeys acrescenta campos próprios, e escondidos por CSS parecem um login avariado. - Teste o contraste (WCAG) das mensagens de erro e das etiquetas. Fundo escuro com texto cinzento chumba muitas vezes em auditorias de acessibilidade. Não retire o contorno de foco sem substituto: no exemplo acima, um
box-shadowbem visível faz esse papel.
Se precisar das fontes do cliente, carregue-as aqui ou aloje-as localmente no tema. Um terceiro domínio no ecrã de login é um pedido a mais e mais um ponto de falha de DNS.
Como mudar o logótipo da página de login do WordPress
O WordPress não tem um filtro que troque o ficheiro do logótipo. O padrão habitual é CSS em #login h1 a como imagem de fundo, mais dois filtros para os atributos da ligação.
function wppoland_login_logo() {
$logo = get_stylesheet_directory_uri() . '/images/logotipo-cliente.svg';
?>
<style type="text/css">
#login h1 a,
.login h1 a {
background-image: url(<?php echo esc_url( $logo ); ?>);
height: 65px;
width: 100%;
max-width: 320px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
padding-bottom: 30px;
}
@media (max-width: 768px) {
#login h1 a,
.login h1 a {
height: 50px;
max-width: 280px;
}
}
</style>
<?php
}
add_action( 'login_enqueue_scripts', 'wppoland_login_logo' );esc_url() no caminho é obrigatório, mesmo quando o URL vem de get_stylesheet_directory_uri(). Use SVG ou PNG com transparência. Um JPEG com margem branca parece um autocolante num formulário escuro. A media query reduz o logótipo em ecrãs estreitos para não empurrar o formulário para baixo.
A ligação padrão do logótipo vai para wordpress.org. Aponte-a para a página inicial e defina o texto acessível da ligação com o nome do site:
function wppoland_login_logo_url() {
return home_url( '/' );
}
add_filter( 'login_headerurl', 'wppoland_login_logo_url' );
function wppoland_login_logo_url_title() {
return get_bloginfo( 'name' );
}
add_filter( 'login_headertext', 'wppoland_login_logo_url_title' );login_headertext substituiu login_headertitle, marcado como obsoleto desde o WordPress 5.2. Snippets antigos ainda o usam.
Em instalações com um domínio próprio para o painel (cms.cliente.pt ao lado de www.cliente.pt), home_url() continua a apontar para o site público, o que costuma ser o pretendido. Se o logótipo deve levar a documentação interna ou ao fornecedor de identidade, devolva um URL HTTPS completo e teste numa janela privada.
Como mostrar uma mensagem por cima do formulário de login do WordPress
O filtro login_message coloca HTML por cima do formulário. Usos comuns em produção:
- Um aviso de manutenção («Esta noite não é possível entrar fora da VPN»).
- Uma indicação para editores («Use a conta da empresa, não uma pessoal»).
- Um banner depois de terminar sessão ou de repor a palavra-passe (o núcleo também acrescenta ali as suas próprias classes de mensagem).
- Uma ligação para SSO quando o fornecedor de identidade convive com as palavras-passe clássicas.
/**
* Mensagem por cima do formulário de login.
*
* @param string $message HTML existente.
* @return string
*/
function wppoland_login_message( $message ) {
$notice = '<p class="message">' . esc_html__(
'Contas apenas para a equipa editorial. Em caso de suspeita de fuga de palavra-passe, avise a equipa de TI.',
'wppoland'
) . '</p>';
return $notice . $message;
}
add_filter( 'login_message', 'wppoland_login_message' );Notas de implementação:
- Escape o texto (
esc_html__), ou construa o markup comwp_kses_postse precisar de uma ligação. - Não substitua
$messageàs cegas. O núcleo coloca ali os seus próprios avisos (depois deloggedout=true, por exemplo). Acrescente o seu texto antes, ou filtre conforme o pedido. - A classe
.messagejá tem estilo nologin.css. O seustyle-login.cssdeve respeitá-la (cor do texto, margem esquerda), ou o banner desaparece no fundo.
Para textos que dependem da ação (login, lostpassword, rp), verifique $_GET['action'] em vez de mostrar a mesma nota na recuperação da palavra-passe e no passo de 2FA.
Como adicionar conteúdo abaixo do formulário de login
Para uma nota de suporte por baixo do formulário, use a ação login_footer:
function wppoland_login_footer_content() {
?>
<div class="login-footer-content">
<p><?php echo esc_html__( 'Problemas a entrar? Contacte o suporte da sua agência.', 'wppoland' ); ?></p>
<p>© <?php echo esc_html( wp_date( 'Y' ) . ' ' . get_bloginfo( 'name' ) ); ?></p>
</div>
<?php
}
add_action( 'login_footer', 'wppoland_login_footer_content' );O estilo de .login-footer-content pertence ao style-login.css, não a um bloco <style> embutido. Assim todas as regras do login ficam num só ficheiro com controlo de versões.
Como aplicar as cores da marca do cliente com variáveis CSS
Agências que usam o mesmo modelo de login para vários clientes ganham em manter as cores como variáveis CSS num só sítio:
function wppoland_agency_branding() {
$primary = sanitize_hex_color( '#0073aa' ); // Cor primária do cliente
$secondary = sanitize_hex_color( '#005177' ); // Cor secundária
?>
<style type="text/css">
:root {
--brand-primary: <?php echo esc_attr( $primary ); ?>;
--brand-secondary: <?php echo esc_attr( $secondary ); ?>;
}
body.login {
background: linear-gradient(135deg, var(--brand-primary) 0%, var(--brand-secondary) 100%);
}
.wp-core-ui .button-primary {
background: var(--brand-primary);
border-color: var(--brand-primary);
}
.wp-core-ui .button-primary:hover {
background: var(--brand-secondary);
border-color: var(--brand-secondary);
}
</style>
<?php
}
add_action( 'login_enqueue_scripts', 'wppoland_agency_branding' );Se as cores passarem a vir de uma opção ou do Personalizador, sanitize_hex_color() (no formatting.php desde o WordPress 3.4, por isso disponível também na página de login) garante que só valores hexadecimais válidos chegam ao CSS.
Como tornar genéricas as mensagens de erro do login
A mensagem padrão para uma palavra-passe errada pode revelar que existe um utilizador com aquele nome. Isso facilita a enumeração de contas antes de um ataque de força bruta. O filtro login_errors devolve um texto genérico:
function wppoland_login_errors() {
return __( 'Não foi possível iniciar sessão. Verifique os seus dados e tente novamente.', 'wppoland' );
}
add_filter( 'login_errors', 'wppoland_login_errors' );Isto dificulta o reconhecimento por parte de atacantes. Não é uma firewall, nem limitação de tentativas, nem 2FA. Continua a precisar de:
- limitação de tentativas no servidor, na WAF ou com um plugin mantido,
- palavras-passe fortes e, de preferência, um segundo fator (aplicação TOTP, chave física),
- WordPress, temas e plugins atualizados,
- restrição de acesso a
wp-admine XML-RPC onde a política da empresa o permita (VPN, lista de IP, autenticação HTTP no staging).
Muitos tutoriais mostram bloqueios de login próprios com transients em login_init e verificações de nonce no filtro authenticate. Não as recomendamos. login_init corre em cada pedido a wp-login.php, incluindo a reposição da palavra-passe, e um wp_die() ali bloqueia precisamente esse caminho. O filtro authenticate também verifica entradas por XML-RPC, palavras-passe de aplicação (wp_authenticate_application_password está ligado a este filtro com prioridade 20, segundo o default-filters.php) e wp_signon() de plugins como o WooCommerce, que não enviam esse campo de nonce. Uma verificação de nonce com prioridade 30 parte esses caminhos de entrada.
Outro pedido frequente: «escondemos o login e fica seguro». Porque não funciona:
- Segurança por obscuridade: bots e scanners conhecem os caminhos padrão. Um URL diferente sem controlo de acesso real estraga sobretudo os marcadores dos editores.
- CSS não esconde nada no servidor:
display: nonenuma ligação de login no menu não remove o endpoint.wp-login.phpewp-admincontinuam a responder. - O filtro
login_urlmuda só as ligações que o WordPress gera, não o endpoint. Mudar o login a sério exige configuração no servidor ou um plugin mantido, e depois testes à reposição da palavra-passe, à conta do WooCommerce, à REST e ao cron. - Respostas REST e XML-RPC podem revelar utilizadores independentemente do branding do ecrã.
Branding do login e segurança são dois trabalhos distintos. O white-label melhora a experiência e a confiança. A proteção das contas vem de permissões, limites de tentativas, 2FA e atualizações.
Como estilizar os campos Two Factor na página de login
Construir 2FA no functions.php é o projeto errado. Use um plugin mantido, por exemplo o Two Factor do diretório WordPress.org (versão 0.17.0, mais de 100 000 instalações ativas segundo a API do diretório em outubro de 2026), e adapte os seus campos ao branding.
Classes que este plugin emite de facto no segundo passo do login (verificadas no código da versão 0.17.0):
.two-factor-promptpara o parágrafo de instruções,input.authcode(comid="authcode") para o código TOTP, o código por email e o código de reserva; o campo teminputmode="numeric"eautocomplete="one-time-code", por isso não substitua esses atributos com um script, ou o telemóvel deixa de sugerir o código do SMS ou do gestor de palavras-passe,.backup-methods-wrappara as ligações aos métodos alternativos,.two-factor-email-resendpara o botão que reenvia o código por email.
.login .two-factor-prompt {
color: #c9d1d9;
}
.login input.authcode {
background: #0d1117;
border: 1px solid #30363d;
color: #c9d1d9;
letter-spacing: 0.2em;
text-align: center;
}
.login .backup-methods-wrap a {
color: #c9d1d9;
}Seletores como .two-factor-methods ou .passkey-button, que circulam em tutoriais antigos, não existem no código atual do plugin, e regras para eles nunca se aplicam. Outros plugins de 2FA e passkeys têm markup próprio: leia os seletores no código de cada um.
Se os administradores sem 2FA configurado devem ir diretamente para a configuração depois do login, use o filtro login_redirect com o método público do plugin:
function wppoland_2fa_setup_redirect( $redirect_to, $requested_redirect_to, $user ) {
if ( ! $user instanceof WP_User || ! class_exists( 'Two_Factor_Core' ) ) {
return $redirect_to;
}
if ( user_can( $user, 'manage_options' ) && ! Two_Factor_Core::is_user_using_two_factor( $user->ID ) ) {
return admin_url( 'profile.php#two-factor-options' );
}
return $redirect_to;
}
add_filter( 'login_redirect', 'wppoland_2fa_setup_redirect', 10, 3 );Two_Factor_Core::is_user_using_two_factor() e a âncora #two-factor-options no perfil vêm do código do plugin. user_can() verifica o utilizador recebido; current_user_can() estaria errado aqui, porque o utilizador atual ainda não está definido durante o filtro. Isto não obriga ninguém a usar 2FA, apenas encaminha para a configuração no momento do login.
Como remover o efeito shake no login do WordPress
Quando o login falha, o formulário abana. Alguns clientes acham isto pouco profissional.
O snippet que a maioria dos tutoriais ainda copia, remove_action( 'login_head', 'wp_shake_js', 12 ), não faz nada desde o WordPress 5.4. O núcleo liga agora wp_shake_js a login_footer, e só de forma condicional, dentro de login_header(). Vê-se no wp-login.php do repositório wordpress-develop; o ramo 5.3 ainda usava login_head. O método estável é o filtro shake_error_codes, disponível desde a 3.0: uma lista vazia de códigos de erro significa nenhuma animação.
add_filter( 'shake_error_codes', '__return_empty_array' );O filtro é API pública e não depende da prioridade nem do hook em que o núcleo imprime o script.
Como comparar plugins de login personalizado
Quem não quer manter o login em código encontra vários plugins no diretório WordPress.org. Dados da API de plugins do WordPress.org a 14 de outubro de 2026:
| Plugin | Versão | Instalações ativas | Foco |
|---|---|---|---|
| LoginPress | 6.2.5 | 200 000+ | Editor visual para o wp-login.php |
| Custom Login Page Customizer | 2.5.4 | 90 000+ | Desenho no Personalizador |
| Theme My Login | 7.3.1 | 50 000+ | Páginas de login no front-end |
O plugin Login Designer, muito citado antes, está agora fechado no diretório e não deve ser instalado de novo. Não junte um plugin aos hooks deste guia: duas fontes a estilizar #login h1 a sobrepõem-se. Escolha código ou plugin.
Plugin must-use ou tema filho para o código do login
Onde guardar o código? Há dois sítios sensatos e um errado.
Tema filho (functions.php e style-login.css)
- Vantagens: logótipo e cores acompanham o design do front-end; o designer altera ficheiros num só repositório; versão controlada pelo campo
Versiondostyle.css. - Desvantagens: uma troca de tema (avaria, teste A/B, migração para um tema de blocos) desliga o branding do login. Num multisite com temas diferentes por site, o código tem de ser duplicado ou subir de nível, veja a nossa arquitetura multisite.
Plugin must-use (wp-content/mu-plugins/wppoland-login-branding.php)
- Vantagens: funciona independentemente do tema ativo, ideal para redes de agência e instalações cujo tema muda; difícil de desativar por acidente no painel.
- Desvantagens: os ficheiros (logótipo, CSS) carregam-se a partir da pasta do plugin (
plugin_dir_url( __FILE__ )); o deploy de plugins must-use costuma ficar esquecido em fluxos que só publicam o tema.
O sítio errado: alterações em wp-admin/ ou um patch ao wp-login.php do núcleo. Ambos desaparecem na atualização seguinte. Evite também plugins de snippets que guardam PHP na base de dados sem controlo de versões: na migração de staging para produção os snippets perdem-se ou duplicam-se.
<?php
/**
* Plugin Name: WPPoland Login Branding
* Description: White-label do wp-login.php independente do tema.
* Author: wppoland.com
*/
defined( 'ABSPATH' ) || exit;
add_action( 'login_enqueue_scripts', function () {
wp_enqueue_style(
'wppoland-login',
plugin_dir_url( __FILE__ ) . 'assets/style-login.css',
array(),
'2026.10.14'
);
} );
add_filter( 'login_headerurl', function () {
return home_url( '/' );
} );
add_filter( 'login_headertext', function () {
return get_bloginfo( 'name' );
} );Regra de decisão para o briefing: se o branding do login faz parte do produto do cliente (cores da marca, logótipo de campanha), vai para o tema filho. Se é um padrão da agência em muitas instalações (o mesmo logótipo da agência em todos os staging, erros genéricos, sem abanar), vai para um plugin must-use ou para um pacote Composer partilhado publicado em todos os ambientes.
Como personalizar o login do WooCommerce e de plugins de membros
As páginas de conta do WooCommerce e os blocos de login no checkout usam um markup diferente do wp-login.php. O CSS do ecrã de login não altera os formulários em my-account. Ou aceita os formulários padrão do Woo, ou carrega uma folha de estilos própria nesses templates. Misturar as duas coisas em style-login.css deixa regras mortas e confunde o próximo programador.
A mesma separação vale para o LearnDash, o MemberPress e produtos semelhantes: primeiro identifique o endereço por onde os clientes entram de facto, depois aplique a marca a essa superfície. Um erro típico de agência é afinar o wp-login.php enquanto os clientes só veem um modal no front-end que, dentro de um iframe, continua a mostrar o logótipo do WordPress.
Como verificar a página de login depois de atualizar o núcleo do WordPress
As versões maiores do WordPress alteram de vez em quando o markup ou o CSS por omissão do login. Depois de atualizar o núcleo no staging:
- Se algo parecer estranho, compare o HTML do login com a versão anterior à atualização.
- Volte a verificar o tamanho do logótipo; novas alturas por omissão podem cortar SVGs.
- Se desativou o efeito shake, confirme que o filtro
shake_error_codescontinua a aplicar-se. - Volte a testar os campos de 2FA se esse plugin foi atualizado na mesma altura.
Associe a versão da folha de estilos à versão do tema ou do plugin, para que os browsers não guardem um style-login.css antigo depois de corrigir um problema de contraste.
Que hooks de login o WordPress oferece e desde que versão
A tabela vem das etiquetas @since em src/wp-login.php no repositório wordpress-develop (outubro de 2026, versão atual WordPress 7.1.3). Ajuda quando um cliente mantém uma instalação antiga ou quando um snippet de fórum usa um hook que ainda não existe ou que já está obsoleto.
| Hook | Tipo | Desde | Para que serve |
|---|---|---|---|
login_headerurl | filtro | 2.1.0 | URL da ligação do logótipo |
login_message | filtro | 2.1.0 | HTML por cima do formulário |
login_errors | filtro | 2.1.0 | texto dos erros |
login_messages | filtro | 2.5.0 | avisos informativos |
login_redirect | filtro | 3.0.0 | destino do redirecionamento após o login |
shake_error_codes | filtro | 3.0.0 | códigos de erro que fazem abanar o formulário |
login_enqueue_scripts | ação | 3.1.0 | CSS e JS do ecrã de login |
login_footer | ação | 3.1.0 | conteúdo no rodapé |
login_init | ação | 3.2.0 | início do processamento do pedido |
login_body_class | filtro | 3.5.0 | classes do elemento body |
login_header | ação | 4.6.0 | conteúdo logo após a abertura do body |
login_title | filtro | 4.9.0 | conteúdo da etiqueta title |
login_link_separator | filtro | 4.9.0 | separador das ligações sob o formulário |
login_headertext | filtro | 5.2.0 | texto da ligação do logótipo |
login_site_html_link | filtro | 5.7.0 | ligação de regresso ao site no rodapé |
login_display_language_dropdown | filtro | 5.9.0 | se o seletor de idioma aparece |
login_language_dropdown_args | filtro | 5.9.0 | argumentos da lista de idiomas |
login_headertitle (desde 2.1.0) está obsoleto desde a 5.2.0 e passa por apply_filters_deprecated, por isso com WP_DEBUG ativo deixa um aviso no registo. Se o tema de um cliente ainda o usa, mude para login_headertext.
Como mudar o título, a classe do body e o seletor de idioma no wp-login.php
Quatro filtros da tabela resolvem pedidos pequenos do briefing sem tocar no CSS:
// Título do separador mais curto: nome do ecrã e nome do site.
add_filter( 'login_title', function ( $login_title, $title ) {
return $title . ' | ' . get_bloginfo( 'name', 'display' );
}, 10, 2 );
// Classe própria no body para as regras do login não colidirem com outras folhas de estilo.
add_filter( 'login_body_class', function ( $classes ) {
$classes[] = 'wppoland-login';
return $classes;
} );
// A ligação do rodapé leva a uma página de ajuda em vez da página inicial.
add_filter( 'login_site_html_link', function () {
return sprintf(
'<a href="%s">%s</a>',
esc_url( home_url( '/ajuda/' ) ),
esc_html__( 'Ajuda para editores', 'wppoland' )
);
} );
// Sem lista de idiomas por baixo do formulário.
add_filter( 'login_display_language_dropdown', '__return_false' );Pormenores que só aparecem no código do núcleo:
- O título padrão junta o nome do ecrã, o nome do site e a palavra WordPress no fim. No modo de recuperação, o núcleo acrescenta um prefixo antes de chamar o filtro. Um callback que constrói o título só a partir de
$titleperde esse prefixo, e o administrador deixa de ver no separador que o site está em modo de recuperação. Se isso importa, altere$login_titleem vez de o substituir. - A lista de idiomas só aparece quando existe pelo menos um pacote de idioma adicional instalado, e nunca na janela de novo login do painel. Escondê-la não muda o idioma da conta: depois do login aplica-se a definição do perfil.
login_site_html_linksubstitui o elemento<a>inteiro, por isso o escape do URL e do texto fica a seu cargo.- A ligação para a política de privacidade por baixo do formulário vem de
the_privacy_policy_link()e aparece quando há uma página de privacidade definida. Não a esconda com CSS em sites que recolhem dados através de um formulário de registo.
Que cabeçalhos de segurança o WordPress envia no wp-login.php
Antes de acrescentar cabeçalhos ou meta tags próprios ao ecrã de login, veja o que o núcleo já faz. Segundo o default-filters.php e o wp-login.php:
send_frame_options_header()emlogin_init(desde 3.1.3) enviaX-Frame-Options: SAMEORIGIN, e desde o WordPress 6.9 a mesma função acrescentaContent-Security-Policy: frame-ancestors 'self'. O ecrã de login não pode ser incorporado numa moldura de outro domínio.wp_admin_headers()emlogin_init(desde 4.9) enviaReferrer-Policy: strict-origin-when-cross-origin; o filtroadmin_referrer_policymuda o valor.wp_robots_sensitive_page()(desde 5.7) acrescentanoindexenoarchiveà meta robots, impressa porwp_robotsemlogin_head.wp_strict_cross_origin_referrer()(desde 5.7) acrescenta uma meta tag referrer com a mesma política.wp_site_iconemlogin_headimprime o favicon definido em Ícone do site.
Na prática, um snippet que imprime uma meta robots noindex ou uma ligação de favicon em login_head só duplica etiquetas. Não acrescente X-XSS-Protection. A MDN descreve este cabeçalho como não normalizado e obsoleto, avisa que pode criar vulnerabilidades XSS em sites de outro modo seguros e recomenda Content-Security-Policy. Cabeçalhos para todo o site (HSTS, CSP) pertencem à configuração do servidor ou da CDN, não a PHP em login_init, para cobrirem também wp-admin e a REST.
Como resolver problemas comuns no login personalizado
CSS não está a ser aplicado
- Verificar o caminho do ficheiro CSS (o nome no código e no tema tem de coincidir)
- Subir o número de versão no enqueue ou limpar a cache do navegador
- Verificar a prioridade dos hooks
Logótipo não aparece
- Verificar as permissões do ficheiro
- Em SVG, confirmar que o servidor envia o tipo MIME
image/svg+xml - Verificar o caminho com
get_stylesheet_directory_uri()
Redirecionamentos em loop
- Desativar todos os plugins de login (guia de recuperação do acesso)
- Verificar as definições de 2FA
- Rever os callbacks em
login_redirect
Conflitos com plugins de segurança
- Testar um plugin de cada vez
- Verificar a ordem de carregamento dos hooks
- Consultar a documentação do plugin
Como testar o branding do login no staging
Numa cópia da produção, siga esta ordem:
- Carregue o CSS e o logótipo; abra
wp-login.phpsem cache (janela privada). - Clique no logótipo: chega ao site do cliente, não a wordpress.org.
- Entre com uma conta válida, termine sessão, entre com a palavra-passe errada: a mensagem é genérica.
- Teste a recuperação da palavra-passe e o email de reposição num ambiente com SMTP configurado.
- Se houver 2FA, percorra o fluxo completo uma vez no computador e outra no telemóvel.
- Mude temporariamente para um tema padrão: se o branding desaparece e devia ser global, passe o código para um plugin must-use.
- Registe no README do projeto os caminhos dos ficheiros e a lista de filtros, para que o próximo programador não procure a lógica em cinco plugins de snippets.
Depois da aprovação do cliente, repita o mesmo teste rápido em produção logo após o deploy.
Resumo
Uma página de login personalizada é pouco código com grande efeito na impressão que um projeto deixa.
Pontos-chave:
- Marca: logótipo, ligação para a página inicial, texto da ligação via
login_headertext - Estilo:
style-login.csspróprio e com versão, vialogin_enqueue_scripts - Segurança: mensagens de erro genéricas, 2FA para administradores, limitação de tentativas no servidor ou na WAF
- Abanar:
shake_error_codesem vez doremove_actiondesatualizado - Localização: tema filho ou plugin must-use, nunca ficheiros do núcleo
Entregue ao cliente uma nota de uma página: onde está o código, como se troca o logótipo e qual é o URL de login da equipa. Veja os nossos serviços de segurança WordPress.







