A “famosa instalação de 5 minutos” é um slogan de marketing, não um padrão profissional. Uma instalação predefinida do WordPress é “faladora”, pouco otimizada e muitas vezes insegura.
Como programadores, não nos limitamos a “instalar” o WordPress. Preparamo-lo para funcionar num ambiente concreto. Este guia cobre as constantes de configuração essenciais e as técnicas de reforço de segurança que devem fazer parte da base de qualquer projeto de cliente em 2026.
Configurar o wp-config.php após instalar o WordPress
Este é o cérebro da sua instalação. Deixe de o manter nas definições predefinidas.
Definir o WP_ENVIRONMENT_TYPE no wp-config.php
Desde o WordPress 5.5, WP_ENVIRONMENT_TYPE é o padrão. Use-o para impedir que erros de desenvolvimento cheguem à produção.
// No wp-config.php
define( 'WP_ENVIRONMENT_TYPE', 'production' ); // 'local', 'development', 'staging', 'production'Depois, no seu código:
if ( wp_get_environment_type() === 'production' ) {
// Ativar cache, desativar erros
}Desativar o editor de ficheiros e forçar SSL no wp-config.php
Impeça que clientes (ou atacantes) estraguem o site através do painel de administração.
// Desativar o editor de ficheiros (editor de temas/plugins)
define( 'DISALLOW_FILE_EDIT', true );
// Bloquear a instalação/atualização de plugins (bom para implementações imutáveis)
define( 'DISALLOW_FILE_MODS', true );
// Forçar SSL na administração
define( 'FORCE_SSL_ADMIN', true );Como limitar as revisões de artigos no WordPress
O assassino da base de dados. Precisa mesmo de 100 versões da página “Sobre nós”?
define( 'WP_POST_REVISIONS', 10 ); // Manter as últimas 10
// OU
define( 'WP_POST_REVISIONS', false ); // Desativar por completo (não recomendado)Como ativar o WP_DEBUG_LOG sem mostrar erros
Nunca mostre erros no frontend. Registe-os.
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', '/tmp/wp-errors.log' ); // Mova o registo para fora da pasta pública!
define( 'WP_DEBUG_DISPLAY', false );
// Registar consultas SQL para depurar o desempenho (desative em produção!)
define( 'SAVEQUERIES', false );Como desativar os emoji e o XML-RPC no WordPress
O WordPress vem com funções de que 90% dos sites empresariais não precisam: emoji, oEmbeds e XML-RPC.
Não instale um plugin para os desligar. Crie um plugin must-use (wp-content/mu-plugins/lean-core.php).
<?php
/* Plugin Name: Lean Core */
// 1. Desativar os emoji (poupa um pedido HTTP)
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'wp_print_styles', 'print_emoji_styles' );
// 2. Desativar o XML-RPC (segurança)
add_filter( 'xmlrpc_enabled', '__return_false' );
// 3. Remover a versão do WP (security by obscurity)
remove_action( 'wp_head', 'wp_generator' );
// 4. Desativar os feeds RSS (se estiver a criar um site institucional)
// function wppoland_disable_feed() {
// wp_die( 'Não há feed, visite a nossa página inicial!' );
// }
// add_action('do_feed', 'wppoland_disable_feed', 1);Alterar as chaves salt no wp-config.php
Conhece as chaves de autenticação no wp-config.php.
define('AUTH_KEY', 'escreva aqui a sua frase única');
// ...Facto: alterá-las termina de imediato a sessão de todos os utilizadores. É a “opção nuclear” se o site for comprometido. Dica profissional: automatize a rotação com um script CLI ou com o Vault se gere sites enterprise.
O que definir no wp-config.php antes de pôr o site no ar
Antes do lançamento:
- Defina
WP_ENVIRONMENT_TYPEcomo production. - Defina
DISALLOW_FILE_EDITcomo true. - Limite
WP_POST_REVISIONS. - Mova
WP_DEBUG_LOGpara uma pasta privada. - Desative os emoji/XML-RPC por código.
Uma instância de WordPress bem configurada é silenciosa, segura e rápida.
Que ligações permanentes definir no WordPress
A estrutura de ligações permanentes ideal
Definições > Ligações permanentes > Nome do artigoPorquê:
- URLs mais curtos e legíveis
- Melhor para SEO (palavras-chave no URL)
- Mais fáceis de memorizar e partilhar
Configuração no wp-config.php:
// Forçar a estrutura de ligações permanentes (opcional)
define('WP_POST_REVISIONS', 10);Estrutura de categorias e etiquetas
- Crie as categorias base (3-7 principais)
- Defina a hierarquia (categorias superiores e subcategorias)
- Defina uma categoria predefinida (não “Sem categoria”)
- Planeie uma estratégia de etiquetas (opcional, 5-10 etiquetas por artigo)
Definições de multimédia e tamanhos de imagem no WordPress
Tamanhos de imagem
Definições > MultimédiaDefinições recomendadas:
- Miniatura: 150x150px (marque “Recortar a miniatura para as dimensões exatas”)
- Média: 300x300px
- Grande: 1024x1024px
- Tamanho completo: sempre disponível
Otimização automática de imagens
// Num mu-plugin: wp-content/mu-plugins/image-optimization.php
<?php
/* Plugin Name: Image Optimization */
// Não gerar tamanhos adicionais que não utiliza
function remove_unused_image_sizes() {
remove_image_size('1536x1536'); // WordPress 5.3+
remove_image_size('2048x2048'); // WordPress 5.3+
}
add_action('init', 'remove_unused_image_sizes');
// Ativar o lazy loading para imagens
add_filter('wp_lazy_loading_enabled', '__return_true');
// Otimizar imagens no carregamento
add_filter('wp_image_editors', function($editors) {
return ['WP_Image_Editor_Imagick', 'WP_Image_Editor_GD'];
});Como ativar o carregamento em WebP no WordPress
// Ativar WebP (requer suporte do servidor)
add_filter('wp_upload_image_mime_transforms', function($transforms) {
$transforms['image/jpeg'] = ['image/webp', 'image/jpeg'];
$transforms['image/png'] = ['image/webp', 'image/png'];
return $transforms;
});Como proteger o WordPress após a instalação
Alterar o prefixo predefinido das tabelas
Durante a instalação: Introduza um prefixo personalizado em vez de wp_ (por exemplo x7k9_, mysite_, proj23_)
Após a instalação (avançado):
-- Alterar o prefixo no phpMyAdmin (faça uma cópia de segurança!)
RENAME TABLE wp_posts TO x7k9_posts;
RENAME TABLE wp_options TO x7k9_options;
-- ... repita para todas as tabelas
-- Atualize o wp-config.php
define('DB_PREFIX', 'x7k9_');Proteger o ficheiro wp-config.php
# No .htaccess (pasta raiz do WordPress)
<files wp-config.php>
order allow,deny
deny from all
</files>
# Proteção adicional
<files ~ "^.*\.([Hh][Tt][Aa])">
order allow,deny
deny from all
</files>Bloquear o acesso a pastas
# Em wp-content/uploads/.htaccess
Options -Indexes
# Em wp-includes/.htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^wp-admin/includes/ - [F,L]
RewriteRule !^wp-includes/ - [S=3]
RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
RewriteRule ^wp-includes/theme-compat/ - [F,L]
</IfModule>Limitar as tentativas de início de sessão
// Num mu-plugin: wp-content/mu-plugins/login-security.php
<?php
/* Plugin Name: Login Security */
// Limitar as tentativas de início de sessão (sem plugin)
add_action('wp_login_failed', function($username) {
$ip = $_SERVER['REMOTE_ADDR'];
$attempts = get_transient('login_attempts_' . $ip);
if ($attempts === false) {
set_transient('login_attempts_' . $ip, 1, HOUR_IN_SECONDS);
} else {
set_transient('login_attempts_' . $ip, $attempts + 1, HOUR_IN_SECONDS);
if ($attempts >= 5) {
wp_die('Demasiadas tentativas de início de sessão. Tente novamente daqui a uma hora.');
}
}
});
// Ocultar a versão do WordPress
remove_action('wp_head', 'wp_generator');
add_filter('the_generator', '__return_empty_string');Autenticação de dois fatores (2FA)
// Exigir palavras-passe fortes
add_action('user_profile_update_errors', function($errors) {
$password = $_POST['pass1'];
if (!empty($password) && strlen($password) < 12) {
$errors->add('password_error', 'A palavra-passe tem de ter pelo menos 12 caracteres.');
}
});Como acelerar o WordPress após a instalação
Otimização básica da base de dados
// No wp-config.php
// Limitar as revisões de artigos
define('WP_POST_REVISIONS', 10);
// Esvaziar o lixo automaticamente após 7 dias
define('EMPTY_TRASH_DAYS', 7);
// Desativar o editor de ficheiros (segurança + desempenho)
define('DISALLOW_FILE_EDIT', true);Limpeza da base de dados
// Num mu-plugin: wp-content/mu-plugins/db-cleanup.php
<?php
/* Plugin Name: DB Cleanup */
// Eliminar revisões antigas (manter as últimas 10)
add_action('wp_scheduled_auto_draft_delete', function() {
global $wpdb;
$wpdb->query("DELETE FROM {$wpdb->posts} WHERE post_type = 'revision' AND post_date < DATE_SUB(NOW(), INTERVAL 30 DAY)");
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_%' AND option_value < UNIX_TIMESTAMP()");
$wpdb->query("OPTIMIZE TABLE {$wpdb->posts}, {$wpdb->options}, {$wpdb->postmeta}");
});Otimização da Heartbeat API
// Reduzir a frequência do Heartbeat
add_filter('heartbeat_settings', function($settings) {
$settings['interval'] = 60; // segundos (predefinição 15)
return $settings;
});
// Desativar o Heartbeat no frontend
add_action('init', function() {
if (!is_admin()) {
wp_deregister_script('heartbeat');
}
}, 1);Remover as ligações RSD, shortlink e REST API do wp_head
// Num mu-plugin: wp-content/mu-plugins/disable-bloat.php
<?php
/* Plugin Name: Disable Bloat */
// Desativar os emoji
remove_action('wp_head', 'print_emoji_detection_script', 7);
remove_action('wp_print_styles', 'print_emoji_styles');
// Desativar o XML-RPC
add_filter('xmlrpc_enabled', '__return_false');
// Desativar a ligação RSD
remove_action('wp_head', 'rsd_link');
// Desativar a ligação do Windows Live Writer
remove_action('wp_head', 'wlwmanifest_link');
// Desativar a ligação curta
remove_action('wp_head', 'wp_shortlink_wp_head');
// Desativar a ligação da REST API (se não a utilizar)
remove_action('wp_head', 'rest_output_link_wp_head');Definições básicas de SEO no WordPress
Título do site, descrição e visibilidade nos motores de pesquisa
Definições > Geral:
- Título do site: [A sua marca] | [Descrição curta]
- Descrição: 2-3 frases sobre o site (meta description)
- Visibilidade nos motores de pesquisa: DESMARQUE "Pedir aos motores de pesquisa para não indexarem este site"Estrutura de ligações permanentes amiga do SEO
Definições > Ligações permanentes > Nome do artigoMapa do site (XML Sitemap)
// Ativar o mapa do site predefinido do WordPress
add_filter('wp_sitemaps_enabled', '__return_true');
// Adicionar tipos de conteúdo personalizados ao mapa
add_filter('wp_sitemaps_post_types', function($post_types) {
$post_types[] = 'portfolio';
return $post_types;
});Otimização básica de imagens para SEO
// Atributos ALT automáticos (alternativa)
add_filter('wp_get_attachment_image_attributes', function($attributes, $attachment) {
if (empty($attributes['alt'])) {
$attributes['alt'] = get_the_title($attachment->ID);
}
return $attributes;
}, 10, 2);
// Títulos das imagens
add_filter('wp_insert_attachment_data', function($data, $postarr) {
if (empty($data['post_title'])) {
$filename = basename($data['guid']);
$data['post_title'] = sanitize_title($filename);
}
return $data;
}, 10, 2);Como fazer cópias de segurança do WordPress
Cópias automáticas da base de dados
// Num mu-plugin: wp-content/mu-plugins/backup-scheduler.php
<?php
/* Plugin Name: Backup Scheduler */
// Cópia diária da base de dados
add_action('daily_database_backup', function() {
$upload_dir = wp_upload_dir();
$backup_dir = $upload_dir['basedir'] . '/backups';
if (!file_exists($backup_dir)) {
wp_mkdir_p($backup_dir);
}
$filename = $backup_dir . '/db-backup-' . date('Y-m-d-H-i-s') . '.sql';
// Use o WP-CLI ou o mysqldump
exec('mysqldump --user=' . DB_USER . ' --password=' . DB_PASSWORD . ' --host=' . DB_HOST . ' ' . DB_NAME . ' > ' . $filename);
// Eliminar cópias antigas (manter as últimas 7)
$files = glob($backup_dir . '/db-backup-*.sql');
if (count($files) > 7) {
array_multisort(array_map('filemtime', $files), SORT_ASC, $files);
for ($i = 0; $i < count($files) - 7; $i++) {
unlink($files[$i]);
}
}
});
// Agendar a tarefa
if (!wp_next_scheduled('daily_database_backup')) {
wp_schedule_event(time(), 'daily', 'daily_database_backup');
}Configurar cópias externas
Soluções recomendadas:
- UpdraftPlus: a versão gratuita chega para sites pequenos
- BlogVault: pago, mas muito fiável
- WPvivid: uma boa alternativa gratuita
Configuração:
- Cópia diária (base de dados)
- Cópia semanal (completa)
- Retenção: no mínimo 30 dias
- Localização externa: Google Drive, Dropbox, S3
Configurar o SMTP no WordPress
SMTP em vez de mail()
// No wp-config.php ou num mu-plugin
define('SMTP_USER', '[email protected]');
define('SMTP_PASS', 'your-password');
define('SMTP_HOST', 'smtp.gmail.com');
define('SMTP_PORT', '587');
define('SMTP_SECURE', 'tls');
define('SMTP_FROM', '[email protected]');
define('SMTP_NAME', 'O seu site');
// No mu-plugin
add_action('phpmailer_init', function($phpmailer) {
$phpmailer->isSMTP();
$phpmailer->Host = SMTP_HOST;
$phpmailer->SMTPAuth = true;
$phpmailer->Username = SMTP_USER;
$phpmailer->Password = SMTP_PASS;
$phpmailer->SMTPSecure = SMTP_SECURE;
$phpmailer->Port = SMTP_PORT;
$phpmailer->From = SMTP_FROM;
$phpmailer->FromName = SMTP_NAME;
});Como enviar um email de teste a partir do WordPress
// Função de teste (execute uma vez)
add_action('admin_init', function() {
if (isset($_GET['test_email'])) {
wp_mail(get_option('admin_email'), 'Test Email', 'Esta é uma mensagem de teste enviada pelo WordPress.');
wp_die('Email de teste enviado!');
}
});Monitorização do WordPress e registo de erros
Registo de erros
// No wp-config.php
define('WP_DEBUG', false);
define('WP_DEBUG_LOG', '/var/log/wp-errors.log'); // Fora da pasta pública
define('WP_DEBUG_DISPLAY', false);
// Registo de consultas SQL (apenas em modo de depuração)
// define('SAVEQUERIES', true);Monitorização de uptime
Ferramentas recomendadas:
- UptimeRobot (plano gratuito: 50 monitores, intervalos de 5 minutos)
- Pingdom (pago, mas mais avançado)
- Better Uptime (alternativa moderna)
Registar inícios de sessão e atualizações de artigos
// Num mu-plugin: wp-content/mu-plugins/activity-log.php
<?php
/* Plugin Name: Activity Log */
add_action('wp_login', function($user_login, $user) {
error_log('User logged in: ' . $user_login . ' from IP: ' . $_SERVER['REMOTE_ADDR']);
}, 10, 2);
add_action('save_post', function($post_id, $post, $update) {
if ($update && $post->post_status === 'publish') {
error_log('Post updated: ' . $post->post_title . ' by user: ' . get_current_user_id());
}
}, 10, 3);O que verificar antes de lançar um site WordPress
Lista de verificação antes de pôr o site no ar
- Todas as definições de SEO corretas
- Mapa do site gerado
- Google Search Console configurado
- Google Analytics instalado
- Política de privacidade e termos adicionados
- Formulários de contacto testados
- O email funciona
- O SSL funciona (HTTPS)
- Redirecionamentos entre www e sem www configurados
- Cópia de segurança feita
- Plugins de cache configurados (opcional)
- CDN configurada (opcional)
- Testes de desempenho feitos (PageSpeed Insights)
- Testes de responsividade em dispositivos móveis
- Testes em vários navegadores
- Página 404 configurada
- Favicon adicionado
Testar checksums e acesso a ficheiros com WP-CLI e curl
# Testes WP-CLI
wp core verify-checksums
wp plugin verify-checksums --all
wp db check
# Testes de segurança
curl -I https://o-seu-site.pt/wp-admin/install.php # Deve devolver 404
curl -I https://o-seu-site.pt/wp-config.php # Deve devolver 403Resumo: a lista de verificação de 50 pontos
Segurança (1-15)
- ✅ Altere o prefixo das tabelas da base de dados
- ✅ Defina palavras-passe fortes (mín. 12 caracteres)
- ✅ Altere o nome de utilizador admin
- ✅ Desative o editor de ficheiros no painel
- ✅ Bloqueie a instalação de plugins (opcional)
- ✅ Force SSL no painel de administração
- ✅ Proteja o wp-config.php através do .htaccess
- ✅ Bloqueie o acesso a pastas (no indexes)
- ✅ Desative o XML-RPC
- ✅ Oculte a versão do WordPress
- ✅ Limite as tentativas de início de sessão
- ✅ Configure a autenticação de dois fatores (2FA)
- ✅ Faça a rotação regular das chaves de autenticação (salts)
- ✅ Instale um certificado SSL
- ✅ Configure proteções ao nível do servidor (firewall, limite de tentativas de início de sessão)
Desempenho (16-25)
- ✅ Limite as revisões de artigos (5-10)
- ✅ Desative os emoji
- ✅ Desative funções não utilizadas (XML-RPC, RSD)
- ✅ Otimize os tamanhos de imagem
- ✅ Ative o lazy loading
- ✅ Configure a cache (de objetos, de página)
- ✅ Otimize a Heartbeat API
- ✅ Ative a compressão GZIP/Brotli
- ✅ Configure uma CDN (opcional)
- ✅ Otimize a base de dados (limpeza automática)
SEO (26-35)
- ✅ Defina a estrutura de ligações permanentes “Nome do artigo”
- ✅ Configure o título e a descrição do site
- ✅ Ative o mapa do site XML
- ✅ Adicione o site ao Google Search Console
- ✅ Configure o Google Analytics / GA4
- ✅ Otimize as imagens (atributos ALT)
- ✅ Crie a estrutura de categorias
- ✅ Configure breadcrumbs
- ✅ Adicione o schema Organization
- ✅ Prepare as meta tags Open Graph
Cópias de segurança (36-42)
- ✅ Configure cópias automáticas da base de dados
- ✅ Configure cópias completas semanais
- ✅ Guarde as cópias numa localização externa
- ✅ Teste a reposição a partir de uma cópia
- ✅ Defina a retenção das cópias (mín. 30 dias)
- ✅ Documente o procedimento de reposição
- ✅ Verifique regularmente a integridade das cópias
Conteúdo e funcionalidades (43-50)
- ✅ Crie as páginas base (Sobre nós, Contacto, Política de privacidade)
- ✅ Configure os menus de navegação
- ✅ Teste todos os formulários
- ✅ Configure o SMTP para o email
- ✅ Crie uma página 404 personalizada
- ✅ Adicione o favicon e os ícones PWA
- ✅ Faça testes de desempenho
- ✅ Documente a configuração
Consulte a nossa auditoria de segurança WordPress se quiser pôr em ordem os riscos e as proteções do site.
Diferenças no wp-config.php entre staging e produção
Este guia define WP_DEBUG duas vezes com valores diferentes: true na secção sobre depuração e false na secção sobre monitorização. Ambas as versões estão corretas, cada uma para um ambiente diferente, por isso a mesma cópia do wp-config.php não deve ir sem alterações para o staging e para a produção. Antes de mover o ficheiro entre servidores, reveja estas constantes:
WP_ENVIRONMENT_TYPE:stagingna cópia de testes,productionno site em produção. Todas as condições baseadas emwp_get_environment_type()dependem deste valor.WP_DEBUG: ativado no staging, desativado na produção.WP_DEBUG_DISPLAYficafalsenos dois sítios, e o registo vai para fora da pasta pública.SAVEQUERIES: apenas enquanto procura consultas lentas, nunca em produção.DISALLOW_FILE_MODS: em produção bloqueia a instalação e a atualização de plugins a partir do painel, pelo que as atualizações passam pela implementação ou pelo WP-CLI. Combine isto com o cliente antes que ele repare que o botão de atualização desapareceu.- Chaves de autenticação: geradas aleatoriamente para cada instalação. Uma cópia da produção no staging recebe o seu próprio conjunto, e as chaves de produção não se tocam, porque alterá-las termina a sessão de todos os utilizadores.
Depois de mover o ficheiro, execute wp core verify-checksums e wp plugin verify-checksums --all da secção sobre testes antes do lançamento.






