Files
claude-plugins/wordpress/skills/rank-math/SKILL.md
T
ealmeida faef9b47dc fix(project-manager): remover Dify KB das descriptions, marcar nota TODO
Dify foi removido 06-03-2026. Skills brainstorm/discover ainda referenciam-no
no corpo. Bump v1.2 + nota top-of-file. Reescrita workflow para próxima sessão.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 04:52:03 +01:00

40 KiB

name, description
name description
rank-math Gestão programática do Rank Math SEO (Free e PRO) via WP-CLI em servidores CWP. Cobre auditoria SEO, meta em massa, schema markup, redirects, sitemaps, Instant Indexing, Analytics PRO, hooks/filtros, taxonomias WooCommerce, News/Video Sitemap, validação e rollback. Usar quando "rank math", "seo cli", "schema markup", "redirects seo", "instant indexing", "indexnow", "seo bulk", "rankmath pro".

/rank-math — Gestão Programática Rank Math SEO via WP-CLI

Operações SEO WordPress completas via WP-CLI no servidor CWP. Free + PRO.

Manual completo: Hub/06-Operacoes/Documentacao/Manuais/WP-CLI/Rank-Math-WP-CLI-Manual-Definitivo.md Quick Reference: Hub/06-Operacoes/Documentacao/Quick-Reference/QR-RankMath-WP-CLI.md Pesquisa Claude: Hub/06-Operacoes/Documentacao/Manuais/WP-CLI/Rank-Math-SEO-WP-CLI-Skils-Pesquisa-Claude.md Pesquisa Gemini: Hub/06-Operacoes/Documentacao/Manuais/WP-CLI/Rank-Math-SEO-WP-CLI-Skills-Pesquisa-Gemini.md NotebookLM: WordPress Config CLI Skill relacionada: /seo-post — optimizar posts individuais com pipeline completo


Contexto NotebookLM

ANTES de executar, consultar notebooks para contexto especializado:

Notebook ID Consultar quando
WordPress e Elementor 5be0d1a6 Sempre
Marketing Digital PT 4c595973 Para contexto SEO
mcp__notebooklm__notebook_query({
  notebook_id: "5be0d1a6-00f2-4cd9-b835-978cb7721601",
  query: "<adaptar ao contexto do pedido do utilizador>"
})

Uso

/rank-math audit SITE_PATH
/rank-math update-meta SITE_PATH
/rank-math sitemap SITE_PATH
/rank-math redirects SITE_PATH
/rank-math schema post ID SITE_PATH
/rank-math indexing SITE_PATH [URL|bulk]
/rank-math analytics SITE_PATH
/rank-math taxonomy SITE_PATH
/rank-math hooks SITE_PATH
/rank-math backup SITE_PATH
/rank-math provision SITE_PATH

Contexto CWP — sempre obrigatorio

# Formato base (PHP 8.3)
/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp <comando> --allow-root --path=/home/USER/public_html

# Alias
wp83 <comando> --allow-root --path=/home/USER/public_html

Acesso via MCP SSH:

servidor: server.descomplicar.pt (176.9.3.158) | porta: 9443 | user: root

Prefixo de tabelas: Sites podem ter prefixo custom (ex: wpah_ em vez de wp_). Detectar primeiro:

PREFIX=$(wp db prefix --allow-root --path=$PATH)
# Usar $PREFIX em todas as queries SQL: ${PREFIX}posts, ${PREFIX}postmeta, etc.

Unico comando nativo Rank Math:

wp rankmath sitemap generate --allow-root --path=$PATH

Tudo o resto usa wp post meta, wp option patch, wp eval ou wp db query.

Options com defaults: Muitas sub-keys (title_separator, strip_category_base, homepage_title, knowledgegraph_type) podem nao existir na BD se nunca foram alteradas — o Rank Math usa valores por defeito internos. wp option pluck retorna exit code 1 neste caso. Nao e erro — significa valor default.


Decision tree — qual comando usar

Operacao Comando
Alterar meta de 1 post wp post meta update
Alterar sub-key em option serializada wp option patch update
Ler sub-key de option wp option pluck
Schema complexo wp eval com PHP
Redirects wp eval com \RankMath\Redirections\DB
Bulk simples shell loop com wp post list | while read
Bulk complexo wp eval-file com script PHP
SQL directo apenas auditorias (seguido de wp cache flush)
Regenerar sitemap wp rankmath sitemap generate
Instant Indexing wp eval com IndexNow API ou classes RM
Side-effects RM wp eval com update_option() (dispara hooks)

1. Auditoria SEO (/rank-math audit)

Passo 1 — diagnostico rapido

PATH=/home/USER/public_html
PREFIX=$(wp db prefix --allow-root --path=$PATH)

# Posts sem titulo SEO
wp db query "SELECT p.ID, p.post_title FROM ${PREFIX}posts p
LEFT JOIN ${PREFIX}postmeta pm ON p.ID=pm.post_id AND pm.meta_key='rank_math_title'
WHERE p.post_type='post' AND p.post_status='publish'
AND (pm.meta_value IS NULL OR pm.meta_value='');" --allow-root --path=$PATH

# Posts sem descricao SEO
wp db query "SELECT p.ID, p.post_title FROM ${PREFIX}posts p
LEFT JOIN ${PREFIX}postmeta pm ON p.ID=pm.post_id AND pm.meta_key='rank_math_description'
WHERE p.post_type='post' AND p.post_status='publish'
AND (pm.meta_value IS NULL OR pm.meta_value='');" --allow-root --path=$PATH

# Distribuicao de SEO scores
wp db query "SELECT
  CASE WHEN CAST(meta_value AS UNSIGNED) >= 80 THEN 'Bom (80-100)'
       WHEN CAST(meta_value AS UNSIGNED) >= 50 THEN 'OK (50-79)'
       ELSE 'Fraco (0-49)' END AS faixa,
  COUNT(*) AS total
FROM ${PREFIX}postmeta WHERE meta_key = 'rank_math_seo_score' GROUP BY faixa;" --allow-root --path=$PATH

# Top 404s (ultimos 30 dias)
wp db query "SELECT uri, SUM(times_accessed) as total FROM ${PREFIX}rank_math_404_logs
GROUP BY uri ORDER BY total DESC LIMIT 20;" --allow-root --path=$PATH

# Tamanho options (detectar bloat WooCommerce)
wp db query "SELECT option_name, LENGTH(option_value) as bytes FROM ${PREFIX}options
WHERE option_name LIKE 'rank%' AND autoload='yes' ORDER BY bytes DESC;" --allow-root --path=$PATH

# Listar TODAS as meta keys Rank Math existentes
wp db query "SELECT DISTINCT meta_key FROM ${PREFIX}postmeta WHERE meta_key LIKE 'rank_math%' ORDER BY meta_key;" --allow-root --path=$PATH

Passo 2 — estado modulos

wp option pluck rank_math_modules --allow-root --path=$PATH
wp option pluck rank-math-options-general strip_category_base --allow-root --path=$PATH
wp option pluck rank-math-options-titles title_separator --allow-root --path=$PATH

# Ver tabelas custom (usa % wildcard — funciona com qualquer prefixo)
wp db query "SHOW TABLES LIKE '%rank_math%';" --allow-root --path=$PATH

2. Actualizar meta SEO (/rank-math update-meta)

Meta key individual

# Titulo SEO
wp post meta update ID rank_math_title "%title% %sep% %sitename%" --allow-root --path=$PATH

# Descricao SEO (<160 chars)
wp post meta update ID rank_math_description "Texto conciso da pagina." --allow-root --path=$PATH

# Focus keyword
wp post meta update ID rank_math_focus_keyword "keyword1,keyword2" --allow-root --path=$PATH

# Robots (ARRAY JSON — obrigatorio --format=json)
wp post meta update ID rank_math_robots '["noindex"]' --format=json --allow-root --path=$PATH

# Advanced robots
wp post meta update ID rank_math_advanced_robots '{"max-snippet":"-1","max-video-preview":"-1","max-image-preview":"large"}' --format=json --allow-root --path=$PATH

# Canonical URL
wp post meta update ID rank_math_canonical_url "https://site.pt/url/" --allow-root --path=$PATH

# Pillar content
wp post meta update ID rank_math_pillar_content "on" --allow-root --path=$PATH

# Categoria primaria
wp post meta update ID rank_math_primary_category "15" --allow-root --path=$PATH

# Breadcrumb title
wp post meta update ID rank_math_breadcrumb_title "Titulo Breadcrumb" --allow-root --path=$PATH

# OpenGraph
wp post meta update ID rank_math_facebook_title "Titulo OG" --allow-root --path=$PATH
wp post meta update ID rank_math_facebook_description "Desc OG" --allow-root --path=$PATH
wp post meta update ID rank_math_facebook_image "https://site.pt/og.jpg" --allow-root --path=$PATH
wp post meta update ID rank_math_twitter_card_type "summary_large_image" --allow-root --path=$PATH

# Redirect per-post
wp post meta update ID rank_math_redirect_url_to "/nova-url/" --allow-root --path=$PATH
wp post meta update ID rank_math_redirection_header_code "301" --allow-root --path=$PATH

Bulk update (wp eval)

# Aplicar titulo padrao a todos os posts sem titulo
wp eval '
$posts = get_posts(["numberposts"=>-1,"post_status"=>"publish"]);
$updated = 0;
foreach ($posts as $p) {
    if (!get_post_meta($p->ID, "rank_math_title", true)) {
        update_post_meta($p->ID, "rank_math_title", "%title% %sep% %sitename%");
        $updated++;
    }
}
echo "$updated posts actualizados\n";
' --allow-root --path=$PATH

# Aplicar descricao a partir do excerpt
wp eval '
$posts = get_posts(["post_type"=>"post","numberposts"=>-1,"post_status"=>"publish"]);
$updated = 0;
foreach ($posts as $p) {
    if (!get_post_meta($p->ID, "rank_math_description", true) && $p->post_excerpt) {
        $desc = wp_trim_words($p->post_excerpt, 20, "...");
        update_post_meta($p->ID, "rank_math_description", $desc);
        $updated++;
    }
}
echo "$updated posts actualizados\n";
' --allow-root --path=$PATH

Bulk via shell

# Actualizar titulo de todos os posts publicados
wp post list --post_type=post --post_status=publish --field=ID --allow-root --path=$PATH | while read id; do
  wp post meta update $id rank_math_title "%title% %sep% %sitename%" --allow-root --path=$PATH
done

# Noindex em todos os drafts
wp post list --post_type=post --post_status=draft --field=ID --allow-root --path=$PATH | while read id; do
  wp post meta update $id rank_math_robots '["noindex"]' --format=json --allow-root --path=$PATH
done

# Paralelo com xargs
wp post list --post_type=page --post_status=publish --field=ID --allow-root --path=$PATH | \
  xargs -P4 -I {} wp post meta delete {} rank_math_canonical_url --allow-root --path=$PATH

Bulk via CSV

# Formato CSV: id,descricao
while IFS=, read -r post_id desc; do
  wp post meta update "$post_id" rank_math_description "$desc" --allow-root --path=$PATH
done < descriptions.csv

3. Options globais (/rank-math options)

Regra critica: SEMPRE usar wp option patch, NUNCA wp option update em options serializadas.

# Separador de titulo
wp option patch update rank-math-options-titles title_separator "-" --allow-root --path=$PATH

# Templates por post type
wp option patch update rank-math-options-titles pt_post_title "%title% %sep% %sitename%" --allow-root --path=$PATH
wp option patch update rank-math-options-titles pt_page_title "%title% %sep% %sitename%" --allow-root --path=$PATH
wp option patch update rank-math-options-titles pt_product_title "%title% %sep% %currentyear% %sep% %sitename%" --allow-root --path=$PATH

# Homepage
wp option patch update rank-math-options-titles homepage_title "Titulo Site" --allow-root --path=$PATH
wp option patch update rank-math-options-titles homepage_description "Descricao Site" --allow-root --path=$PATH

# Remover base de categoria do URL
wp option patch update rank-math-options-general strip_category_base "on" --allow-root --path=$PATH
wp rewrite flush --allow-root --path=$PATH  # OBRIGATORIO apos esta alteracao

# Breadcrumbs
wp option patch update rank-math-options-general breadcrumbs_separator ">" --allow-root --path=$PATH

# Nofollow links externos
wp option patch update rank-math-options-general nofollow_external_links "on" --allow-root --path=$PATH

# Knowledge Graph
wp option patch update rank-math-options-titles knowledgegraph_type "Organization" --allow-root --path=$PATH
wp option patch update rank-math-options-titles knowledgegraph_name "Descomplicar" --allow-root --path=$PATH

# Webmaster verification
wp option patch update rank-math-options-general google_verify "codigo" --allow-root --path=$PATH

# Verificar sub-key
wp option pluck rank-math-options-titles title_separator --allow-root --path=$PATH

# LER option completa (diagnostico)
wp option get rank-math-options-general --format=json --allow-root --path=$PATH

Gestao de modulos

# LER modulos activos
wp option get rank_math_modules --format=json --allow-root --path=$PATH

# ACTIVAR modulo (via wp eval — dispara hooks)
wp eval '
$modules = get_option("rank_math_modules", []);
if (!in_array("redirections", $modules)) {
    $modules[] = "redirections";
    update_option("rank_math_modules", $modules);
    echo "Modulo activado.\n";
} else { echo "Ja activo.\n"; }
' --allow-root --path=$PATH

# DESACTIVAR modulo
wp eval '
$modules = get_option("rank_math_modules", []);
$modules = array_values(array_diff($modules, ["404-monitor"]));
update_option("rank_math_modules", $modules);
echo "Modulo desactivado.\n";
' --allow-root --path=$PATH

# Modulos disponiveis:
# sitemap, rich-snippet, redirections, 404-monitor, local-seo,
# woocommerce, image-seo, link-counter, instant-indexing, content-ai,
# analytics, role-manager, acf, amp, news-sitemap (PRO), video-sitemap (PRO)

4. Schema markup (/rank-math schema)

Schema armazenado como array PHP em rank_math_schema_{Type}. Usar wp eval (nao JSON directo).

Estrutura interna

{
  "metadata": {"title": "Article", "type": "custom", "shortcode": "s-UNIQUE", "isPrimary": "1"},
  "@type": "Article",
  "headline": "%seo_title%",
  "description": "%seo_description%"
}
  • type: "template" — herda globals | type: "custom" — personalizado
  • isPrimary: "1" — schema principal do post
  • Free: 1 schema/post | PRO: ilimitados

Criar schemas

# Article
wp eval '
update_post_meta(ID, "rank_math_schema_Article", [
    "metadata" => ["title"=>"Article","type"=>"custom","shortcode"=>"s-".uniqid(),"isPrimary"=>"1"],
    "@type"=>"Article",
    "headline"=>"%seo_title%",
    "description"=>"%seo_description%",
    "keywords"=>"%keywords%",
    "articleSection"=>"%categories%",
    "image"=>["@type"=>"ImageObject","url"=>"%post_thumbnail%"],
    "author"=>["@type"=>"Person","name"=>"%name%"],
    "publisher"=>["@type"=>"Organization","name"=>"%sitename%","logo"=>""],
    "datePublished"=>"%date(Y-m-dTH:i:sP)%",
    "dateModified"=>"%modified(Y-m-dTH:i:sP)%"
]);
echo "Schema Article criado\n";
' --user=1 --allow-root --path=$PATH

# FAQ
wp eval '
update_post_meta(ID, "rank_math_schema_FAQPage", [
    "metadata" => ["title"=>"FAQ","type"=>"custom","shortcode"=>"s-".uniqid(),"isPrimary"=>"0"],
    "@type"=>"FAQPage",
    "mainEntity"=>[
        ["@type"=>"Question","name"=>"Pergunta 1","acceptedAnswer"=>["@type"=>"Answer","text"=>"Resposta 1"]],
        ["@type"=>"Question","name"=>"Pergunta 2","acceptedAnswer"=>["@type"=>"Answer","text"=>"Resposta 2"]]
    ]
]);
echo "Schema FAQ criado\n";
' --user=1 --allow-root --path=$PATH

# Product (WooCommerce)
wp eval '
update_post_meta(ID, "rank_math_schema_Product", [
    "metadata" => ["title"=>"Product","type"=>"custom","shortcode"=>"s-".uniqid(),"isPrimary"=>"1"],
    "@type"=>"Product",
    "name"=>"%title%",
    "description"=>"%excerpt%",
    "sku"=>"SKU-001",
    "brand"=>["@type"=>"Brand","name"=>"Marca"],
    "image"=>["@type"=>"ImageObject","url"=>"%post_thumbnail%"],
    "offers"=>[
        "@type"=>"Offer","price"=>"29.99","priceCurrency"=>"EUR",
        "availability"=>"https://schema.org/InStock","url"=>"%url%",
        "priceValidUntil"=>"2026-12-31"
    ]
]);
echo "Schema Product criado\n";
' --user=1 --allow-root --path=$PATH

# LocalBusiness
wp eval '
update_post_meta(ID, "rank_math_schema_LocalBusiness", [
    "metadata" => ["title"=>"LocalBusiness","type"=>"custom","shortcode"=>"s-".uniqid(),"isPrimary"=>"1"],
    "@type"=>"LocalBusiness",
    "name"=>"Nome Empresa",
    "description"=>"%seo_description%",
    "url"=>"%url%",
    "email"=>"email@empresa.pt",
    "telephone"=>"+351 XXX XXX XXX",
    "address"=>["@type"=>"PostalAddress","streetAddress"=>"Rua X","addressLocality"=>"Cidade","postalCode"=>"XXXX-XXX","addressCountry"=>"PT"],
    "geo"=>["@type"=>"GeoCoordinates","latitude"=>"38.7","longitude"=>"-9.1"],
    "openingHoursSpecification"=>[
        ["@type"=>"OpeningHoursSpecification","dayOfWeek"=>["Monday","Tuesday","Wednesday","Thursday","Friday"],"opens"=>"09:00","closes"=>"18:00"]
    ],
    "image"=>"%post_thumbnail%"
]);
echo "Schema LocalBusiness criado\n";
' --user=1 --allow-root --path=$PATH

# VideoObject
wp eval '
update_post_meta(ID, "rank_math_schema_VideoObject", [
    "metadata" => ["title"=>"VideoObject","type"=>"custom","shortcode"=>"s-".uniqid(),"isPrimary"=>"0"],
    "@type"=>"VideoObject",
    "name"=>"%seo_title%",
    "description"=>"%seo_description%",
    "thumbnailUrl"=>"%post_thumbnail%",
    "uploadDate"=>"%date(Y-m-dTH:i:sP)%",
    "contentUrl"=>"https://exemplo.pt/video.mp4",
    "embedUrl"=>"https://youtube.com/embed/VIDEO_ID"
]);
echo "Schema VideoObject criado\n";
' --user=1 --allow-root --path=$PATH

Actualizar/apagar schema

# Actualizar campo especifico
wp eval '
$schema = get_post_meta(ID, "rank_math_schema_Article", true);
if ($schema) {
    $schema["headline"] = "Novo Titulo";
    update_post_meta(ID, "rank_math_schema_Article", $schema);
    echo "Actualizado.\n";
}
' --allow-root --path=$PATH

# Apagar schema corrompido
wp post meta delete ID rank_math_schema_Article --allow-root --path=$PATH

# Apagar TODOS os schemas de um post
wp eval '
global $wpdb;
$wpdb->query($wpdb->prepare(
    "DELETE FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key LIKE %s",
    ID, "rank_math_schema_%"
));
echo "Todos os schemas eliminados.\n";
' --allow-root --path=$PATH

5. Redirects (/rank-math redirects)

CRUD via API PHP (recomendado)

# Criar redirect 301
wp eval '
\RankMath\Redirections\DB::add([
    "id"=>"",
    "sources"=>[["pattern"=>"/url-antiga/","comparison"=>"exact"]],
    "url_to"=>"/url-nova/",
    "header_code"=>301,
    "status"=>"active",
]);
echo "Redirect criado\n";
' --allow-root --path=$PATH

# Redirect regex
wp eval '
\RankMath\Redirections\DB::add([
    "id"=>"",
    "sources"=>[["pattern"=>"^/blog/2023/.*$","comparison"=>"regex"]],
    "url_to"=>"/blog/",
    "header_code"=>301,
    "status"=>"active",
]);
' --allow-root --path=$PATH

# Redirect 410 (conteudo removido)
wp eval '
\RankMath\Redirections\DB::add([
    "id"=>"",
    "sources"=>[["pattern"=>"/removida/","comparison"=>"exact"]],
    "url_to"=>"",
    "header_code"=>410,
    "status"=>"active",
]);
' --allow-root --path=$PATH

# Actualizar
wp eval '
\RankMath\Redirections\DB::update([
    "id"=>42,
    "sources"=>[["pattern"=>"/url-antiga/","comparison"=>"exact"]],
    "url_to"=>"/url-nova/",
    "header_code"=>301,
    "status"=>"active",
]);
echo "Actualizado\n";
' --allow-root --path=$PATH

# Apagar
wp eval '\RankMath\Redirections\DB::delete(42); echo "Eliminado\n";' --allow-root --path=$PATH
wp eval '\RankMath\Redirections\DB::delete([42, 43, 44]); echo "Eliminados\n";' --allow-root --path=$PATH

# Bulk criar
wp eval '
$redirects = [
    ["/antiga-1/", "/nova-1/", 301],
    ["/antiga-2/", "/nova-2/", 301],
    ["/removida/", "", 410],
];
foreach ($redirects as $r) {
    $id = \RankMath\Redirections\DB::add([
        "id"=>"", "sources"=>[["pattern"=>$r[0],"comparison"=>"exact"]],
        "url_to"=>$r[1], "header_code"=>$r[2], "status"=>"active",
    ]);
    echo "#{$id}: {$r[0]} -> {$r[1]} ({$r[2]})\n";
}
' --allow-root --path=$PATH

# Validar
curl -I -s https://site.pt/url-antiga/ | grep HTTP

Tipos de comparacao

comparison Comportamento
exact Match exacto
contains URL contem pattern
start URL comeca com pattern
end URL termina com pattern
regex Expressao regular

404 Monitor

# Top 404s
wp db query "SELECT uri, SUM(times_accessed) as total FROM ${PREFIX}rank_math_404_logs
GROUP BY uri ORDER BY total DESC LIMIT 20;" --allow-root --path=$PATH

# Limpar logs antigos (>30 dias)
wp db query "DELETE FROM ${PREFIX}rank_math_404_logs WHERE accessed < DATE_SUB(NOW(), INTERVAL 30 DAY);" --allow-root --path=$PATH

# Truncar tudo
wp db query "TRUNCATE TABLE ${PREFIX}rank_math_404_logs;" --allow-root --path=$PATH

6. Sitemap (/rank-math sitemap)

# Regenerar sitemap
wp rankmath sitemap generate --allow-root --path=$PATH

# Invalidar cache de sitemap via API PHP
wp eval '\RankMath\Sitemap\Cache::invalidate_storage(); echo "Cache invalidada.\n";' --allow-root --path=$PATH

# Invalidar sitemap de tipo especifico
wp eval '\RankMath\Sitemap\Cache::invalidate_storage("post"); echo "Sitemap posts invalidado.\n";' --allow-root --path=$PATH

# Incluir/excluir post-types
wp option patch update rank-math-options-sitemap pt_post_sitemap "on" --allow-root --path=$PATH
wp option patch update rank-math-options-sitemap pt_attachment_sitemap "off" --allow-root --path=$PATH

# Excluir posts especificos
wp eval '
$opts = get_option("rank-math-options-sitemap");
$opts["exclude_posts"] = "123,456,789";
update_option("rank-math-options-sitemap", $opts);
' --allow-root --path=$PATH

# Itens por pagina (reduzir em sites grandes)
wp option patch update rank-math-options-sitemap items_per_page "200" --allow-root --path=$PATH

# Verificar setting
wp option pluck rank-math-options-sitemap pt_post_sitemap --allow-root --path=$PATH

Nginx rewrite rules (obrigatorio em Nginx puro):

rewrite ^/sitemap_index.xml$ /index.php?sitemap=1 last;
rewrite ^/([^/]+?)-sitemap([0-9]+)?.xml$ /index.php?sitemap=$1&sitemap_n=$2 last;
rewrite ^/([a-z]+)?-sitemap\.xsl$ /index.php?xsl=$1 last;

7. Instant Indexing (/rank-math indexing) — PRO

IndexNow (integrado no Rank Math)

# Submeter URL individual
wp eval '
$url = "https://site.pt/novo-artigo/";
$api_key = get_option("rank-math-options-instant-indexing")["indexnow_api_key"] ?? "";
$response = wp_remote_post("https://api.indexnow.org/indexnow", [
    "headers" => ["Content-Type" => "application/json"],
    "body" => json_encode([
        "host" => parse_url(home_url(), PHP_URL_HOST),
        "key" => $api_key,
        "urlList" => [$url],
    ]),
]);
echo "Codigo: " . wp_remote_retrieve_response_code($response) . "\n";
' --allow-root --path=$PATH

# Submeter URLs em bulk
wp eval '
$urls = ["https://site.pt/post-1/", "https://site.pt/post-2/", "https://site.pt/post-3/"];
$api_key = get_option("rank-math-options-instant-indexing")["indexnow_api_key"] ?? "";
$response = wp_remote_post("https://api.indexnow.org/indexnow", [
    "headers" => ["Content-Type" => "application/json"],
    "body" => json_encode([
        "host" => parse_url(home_url(), PHP_URL_HOST),
        "key" => $api_key,
        "urlList" => $urls,
    ]),
]);
echo "Codigo: " . wp_remote_retrieve_response_code($response) . "\n";
' --allow-root --path=$PATH

# Submeter todos os posts publicados nos ultimos 7 dias
wp eval '
$posts = get_posts(["numberposts"=>-1,"post_status"=>"publish","date_query"=>[["after"=>"7 days ago"]]]);
$urls = array_map(function($p) { return get_permalink($p->ID); }, $posts);
$api_key = get_option("rank-math-options-instant-indexing")["indexnow_api_key"] ?? "";
$chunks = array_chunk($urls, 10000); // IndexNow max 10k por pedido
foreach ($chunks as $chunk) {
    $response = wp_remote_post("https://api.indexnow.org/indexnow", [
        "headers" => ["Content-Type" => "application/json"],
        "body" => json_encode([
            "host" => parse_url(home_url(), PHP_URL_HOST),
            "key" => $api_key,
            "urlList" => $chunk,
        ]),
    ]);
    echo count($chunk) . " URLs submetidos. Codigo: " . wp_remote_retrieve_response_code($response) . "\n";
}
' --allow-root --path=$PATH

# Verificar API key
wp eval 'echo get_option("rank-math-options-instant-indexing")["indexnow_api_key"] ?? "nao definida"; echo "\n";' --allow-root --path=$PATH

# Configurar post types para IndexNow
wp option patch update rank-math-options-instant-indexing bing_post_types '["post","page","product"]' --format=json --allow-root --path=$PATH

Codigos resposta IndexNow: 200=sucesso, 202=aceite (pendente), 400=invalido, 403=key invalida, 429=rate limit.

Google Indexing API (via classes RM PRO)

# Submeter URL via API interna RM
wp eval '
$target = get_permalink(99);
\RankMath\Instant_Indexing\Api::submit($target, "URL_UPDATED");
echo "Submetido: $target\n";
' --allow-root --path=$PATH

Limites: Google Indexing API quota ~200 pedidos/dia. Nao submeter URLs voláteis (parametrizados, facturacao).


8. Analytics PRO (/rank-math analytics)

Tabelas de analytics (apenas com modulo analytics activo + PRO)

# Dados Google Search Console armazenados
wp db query "SELECT page, SUM(clicks) as clicks, SUM(impressions) as impressions,
AVG(position) as avg_pos, AVG(ctr) as avg_ctr
FROM ${PREFIX}rank_math_analytics_gsc
WHERE created >= DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY page ORDER BY clicks DESC LIMIT 20;" --allow-root --path=$PATH

# Top queries
wp db query "SELECT query, SUM(clicks) as clicks, SUM(impressions) as impressions,
AVG(position) as avg_pos
FROM ${PREFIX}rank_math_analytics_gsc
WHERE created >= DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY query ORDER BY clicks DESC LIMIT 30;" --allow-root --path=$PATH

# Objectos rastreados (seo score, indexabilidade)
wp db query "SELECT page, seo_score, is_indexable, object_type
FROM ${PREFIX}rank_math_analytics_objects
ORDER BY seo_score ASC LIMIT 20;" --allow-root --path=$PATH

# Posts com pior ranking
wp db query "SELECT gsc.page, gsc.query, AVG(gsc.position) as avg_pos, ao.seo_score
FROM ${PREFIX}rank_math_analytics_gsc gsc
LEFT JOIN ${PREFIX}rank_math_analytics_objects ao ON gsc.page = ao.page
WHERE gsc.created >= DATE_SUB(NOW(), INTERVAL 7 DAY)
GROUP BY gsc.page, gsc.query
HAVING avg_pos > 10
ORDER BY gsc.impressions DESC LIMIT 20;" --allow-root --path=$PATH

# Google Analytics pageviews (se integrado)
wp db query "SELECT page, SUM(pageviews) as views, SUM(visitors) as visitors
FROM ${PREFIX}rank_math_analytics_ga
GROUP BY page ORDER BY views DESC LIMIT 20;" --allow-root --path=$PATH

# Links internos
wp db query "SELECT post_id, internal_link_count, external_link_count, incoming_link_count
FROM ${PREFIX}rank_math_internal_meta
ORDER BY incoming_link_count ASC LIMIT 20;" --allow-root --path=$PATH

9. Taxonomias e WooCommerce (/rank-math taxonomy)

Terms (categorias, tags, taxonomias custom)

# LER titulo SEO de categoria
wp term meta get 15 rank_math_title --allow-root --path=$PATH

# DEFINIR description SEO
wp term meta update 23 rank_math_description "Descricao SEO da tag." --allow-root --path=$PATH

# DEFINIR noindex numa taxonomia
wp term meta update 23 rank_math_robots '["noindex"]' --format=json --allow-root --path=$PATH
# CUIDADO: noindex numa categoria remove do indice TODAS as paginas arquivo dessa cat

WooCommerce bulk

# Titulo SEO para todas as categorias de produto sem titulo
wp eval '
$terms = get_terms(["taxonomy"=>"product_cat","hide_empty"=>false]);
$updated = 0;
foreach ($terms as $t) {
    if (!get_term_meta($t->term_id, "rank_math_title", true)) {
        update_term_meta($t->term_id, "rank_math_title", "%term% %sep% %sitename%");
        $updated++;
    }
}
echo "$updated categorias actualizadas\n";
' --allow-root --path=$PATH

# Descricao SEO para categorias de produto a partir da descricao da categoria
wp eval '
$terms = get_terms(["taxonomy"=>"product_cat","hide_empty"=>false]);
$updated = 0;
foreach ($terms as $t) {
    if (!get_term_meta($t->term_id, "rank_math_description", true) && $t->description) {
        $desc = wp_trim_words($t->description, 25, "...");
        update_term_meta($t->term_id, "rank_math_description", $desc);
        $updated++;
    }
}
echo "$updated categorias actualizadas\n";
' --allow-root --path=$PATH

# Noindex em taxonomias de atributos vazias (cor, tamanho, etc.)
wp eval '
$taxonomies = wc_get_attribute_taxonomy_names();
$noindexed = 0;
foreach ($taxonomies as $tax) {
    $terms = get_terms(["taxonomy"=>$tax,"hide_empty"=>true]);
    foreach ($terms as $t) {
        if (!get_term_meta($t->term_id, "rank_math_robots", true)) {
            update_term_meta($t->term_id, "rank_math_robots", ["noindex"]);
            $noindexed++;
        }
    }
}
echo "$noindexed atributos noindexados\n";
' --allow-root --path=$PATH

User meta (arquivo de autor)

wp user meta update 1 rank_math_title "Nome Autor — Especialista WordPress" --allow-root --path=$PATH
wp user meta update 1 rank_math_description "Artigos sobre WordPress e SEO." --allow-root --path=$PATH

10. News Sitemap PRO (/rank-math news)

# Activar modulo
wp eval '
$modules = get_option("rank_math_modules", []);
if (!in_array("news-sitemap", $modules)) { $modules[] = "news-sitemap"; update_option("rank_math_modules", $modules); }
echo "News Sitemap activo\n";
' --allow-root --path=$PATH

# Definir meta por post
wp post meta update ID rank_math_news_sitemap_robots "index" --allow-root --path=$PATH
wp post meta update ID rank_math_news_sitemap_genres "PressRelease" --allow-root --path=$PATH
# Generos: Blog, PressRelease, Satire, OpEd
wp post meta update ID rank_math_news_sitemap_keywords "ia,automacao,marketing" --allow-root --path=$PATH
wp post meta update ID rank_math_news_sitemap_stock_tickers "GOOG,MSFT" --allow-root --path=$PATH

# Configurar post types para news sitemap
wp eval '
$opts = get_option("rank-math-options-sitemap");
$opts["news_sitemap_post_type"] = ["post"];
update_option("rank-math-options-sitemap", $opts);
' --allow-root --path=$PATH

11. Hooks e filtros (/rank-math hooks)

Frontend

# Modificar titulo via filtro (persistente via rank-math.php)
wp eval '
file_put_contents(get_stylesheet_directory() . "/rank-math.php",
"<?php\n// Filtros custom Rank Math\n" .
"add_filter(\"rank_math/frontend/show_keywords\", \"__return_true\");\n"
);
echo "Filtro adicionado.\n";
' --allow-root --path=$PATH

Hooks uteis (para rank-math.php ou mu-plugin)

// rank_math/frontend/robots — modificar robots programaticamente
add_filter('rank_math/frontend/robots', function($robots) {
    if (is_tax('product_cat')) { $robots['noindex'] = 'noindex'; }
    return $robots;
});

// rank_math/json_ld — modificar todo o output JSON-LD
add_filter('rank_math/json_ld', function($data, $jsonld) { return $data; }, 10, 2);

// rank_math/snippet/rich_snippet_article_entity — modificar schema Article
add_filter('rank_math/snippet/rich_snippet_article_entity', function($entity) {
    $entity['headline'] = 'Titulo Custom';
    return $entity;
});

// rank_math/sitemap/enable_caching — desactivar cache sitemap
add_filter('rank_math/sitemap/enable_caching', '__return_false');

// rank_math/focus_keyword/maxtags — alterar limite keywords (Free: 5)
add_filter('rank_math/focus_keyword/maxtags', function() { return 10; });

// rank_math/metabox/priority — baixar prioridade do metabox
add_filter('rank_math/metabox/priority', function() { return 'low'; });

// rank_math/sitemap/remove_credit
add_filter('rank_math/sitemap/remove_credit', '__return_true');

Ficheiro auto-incluido: O Rank Math carrega automaticamente /wp-content/themes/{tema-activo}/rank-math.php quando o plugin esta activo. Colocar filtros persistentes aqui.


12. Backup e rollback (/rank-math backup)

Backup antes de operacoes em massa

# Exportar options Rank Math
wp eval '
$options = ["rank-math-options-general","rank-math-options-titles","rank-math-options-sitemap","rank_math_modules","rank-math-options-instant-indexing"];
$backup = [];
foreach ($options as $opt) { $backup[$opt] = get_option($opt); }
file_put_contents("/tmp/rankmath-options-backup.json", json_encode($backup, JSON_PRETTY_PRINT));
echo "Options exportadas para /tmp/rankmath-options-backup.json\n";
' --allow-root --path=$PATH

# Exportar todos os post meta Rank Math
wp eval '
global $wpdb;
$results = $wpdb->get_results("SELECT post_id, meta_key, meta_value FROM {$wpdb->postmeta} WHERE meta_key LIKE \"rank_math_%\"", ARRAY_A);
file_put_contents("/tmp/rankmath-postmeta-backup.json", json_encode($results));
echo count($results) . " meta entries exportadas\n";
' --allow-root --path=$PATH

# Exportar redirects
wp db query "SELECT * FROM ${PREFIX}rank_math_redirections;" --allow-root --path=$PATH > /tmp/rankmath-redirections-backup.tsv

# Exportar dados SEO para CSV
wp eval '
$posts = get_posts(["post_type"=>"post","post_status"=>"publish","numberposts"=>-1]);
$fp = fopen("/tmp/rankmath-seo-export.csv", "w");
fputcsv($fp, ["ID","Titulo","SEO_Title","Description","Focus_KW","Score","Canonical"]);
foreach ($posts as $p) {
    fputcsv($fp, [
        $p->ID, $p->post_title,
        get_post_meta($p->ID, "rank_math_title", true),
        get_post_meta($p->ID, "rank_math_description", true),
        get_post_meta($p->ID, "rank_math_focus_keyword", true),
        get_post_meta($p->ID, "rank_math_seo_score", true),
        get_post_meta($p->ID, "rank_math_canonical_url", true),
    ]);
}
fclose($fp);
echo count($posts) . " posts exportados\n";
' --allow-root --path=$PATH

Rollback

# Restaurar options de backup
wp eval '
$backup = json_decode(file_get_contents("/tmp/rankmath-options-backup.json"), true);
foreach ($backup as $key => $value) {
    update_option($key, $value);
    echo "Restaurado: $key\n";
}
' --allow-root --path=$PATH

# Restaurar post meta de backup
wp eval '
$entries = json_decode(file_get_contents("/tmp/rankmath-postmeta-backup.json"), true);
$restored = 0;
foreach ($entries as $e) {
    update_post_meta($e["post_id"], $e["meta_key"], maybe_unserialize($e["meta_value"]));
    $restored++;
}
echo "$restored meta entries restauradas\n";
' --allow-root --path=$PATH

13. Provisioning (/rank-math provision)

Configuracao completa de um site novo.

# 1. Activar modulos essenciais
wp eval '
update_option("rank_math_modules", ["sitemap","rich-snippet","redirections","404-monitor","seo-analysis","link-counter","instant-indexing","image-seo"]);
echo "Modulos configurados\n";
' --allow-root --path=$PATH

# 2. Configuracoes globais
wp option patch update rank-math-options-titles title_separator "-" --allow-root --path=$PATH
wp option patch update rank-math-options-titles knowledgegraph_type "Organization" --allow-root --path=$PATH
wp option patch update rank-math-options-titles knowledgegraph_name "Nome Empresa" --allow-root --path=$PATH
wp option patch update rank-math-options-general strip_category_base "on" --allow-root --path=$PATH
wp option patch update rank-math-options-general nofollow_external_links "on" --allow-root --path=$PATH
wp option patch update rank-math-options-general attachment_redirect_urls "on" --allow-root --path=$PATH
wp option patch update rank-math-options-sitemap pt_attachment_sitemap "off" --allow-root --path=$PATH

# 3. Templates por post type
wp option patch update rank-math-options-titles pt_post_title "%title% %sep% %sitename%" --allow-root --path=$PATH
wp option patch update rank-math-options-titles pt_page_title "%title% %sep% %sitename%" --allow-root --path=$PATH
wp option patch update rank-math-options-titles pt_post_description "%excerpt%" --allow-root --path=$PATH

# 4. Flush e regenerar
wp rewrite flush --allow-root --path=$PATH
wp rankmath sitemap generate --allow-root --path=$PATH

echo "Provisioning concluido"

14. Validacao pos-aplicacao

Verificar schema no HTML

# Verificar JSON-LD no frontend
curl -s "https://site.pt/post/" | grep -o '"@type":"[^"]*"' | sort -u

# Extrair JSON-LD completo
curl -s "https://site.pt/post/" | grep -oP '<script type="application/ld\+json">\K[^<]+'

# Verificar meta robots
curl -s "https://site.pt/post/" | grep -i 'meta name="robots"'

# Verificar OG tags
curl -s "https://site.pt/post/" | grep -i 'property="og:'

# Verificar canonical
curl -s "https://site.pt/post/" | grep -i 'rel="canonical"'

Confirmar meta na BD

wp post meta list ID --format=table --allow-root --path=$PATH | grep rank_math
wp post meta get ID rank_math_robots --format=json --allow-root --path=$PATH

Sequencia de cache (sempre apos alteracoes)

wp cache flush --allow-root --path=$PATH
wp transient delete --all --allow-root --path=$PATH
wp rewrite flush --allow-root --path=$PATH
wp rankmath sitemap generate --allow-root --path=$PATH
# Limpar page cache (adaptar ao plugin):
# wp wp-rocket clean --confirm     # WP Rocket
# wp litespeed-purge all           # LiteSpeed

Alteracoes via wp db query nao invalidam Redis/Memcached. Sempre executar wp cache flush.


Variaveis dinamicas

Post: %title% %excerpt% %seo_title% %seo_description% %url% %post_thumbnail% %id% %focuskw% %keywords% Data: %date(Y-m-d)% %modified(Y-m-d)% %currentyear% %currentmonth% Taxonomia: %category% %categories% %tag% %tags% %term% %term_description% %customterm(taxonomy)% Site: %sep% %sitename% %sitedesc% %org_name% %org_logo% %org_url% Autor: %name% %userid% %user_description% Avancado: %customfield(field-name)% %search_query% %page% %pagenumber% WooCommerce: %wc_price% %wc_sku% %wc_shortdesc% %wc_brand% PRO: %randomword(a|b|c)% %imagealt% %imagetitle%


Gotchas criticos

Problema Causa Solucao
Robots nao aplicam String em vez de array '["noindex"]' --format=json
Options corrompidas wp option update em serializada Sempre wp option patch
Alteracao nao visivel Object cache (Redis) wp cache flush
Schema quebra editor JSON invalido em schema_* wp post meta delete ID rank_math_schema_*
Sitemap 404 no Nginx Faltam rewrite rules Adicionar regras ao server block
SEO score nao actualiza Calculado no Gutenberg Apagar rank_math_seo_score para recalcular
Bloat WooCommerce options-titles por atributo Redis + reduzir atributos
Titulo ignorado Cache de pagina Limpar plugin de cache
Permissoes bloqueiam Sem contexto user --user=1 em todos os wp eval
Double serialization wp option update com JSON Usar wp option patch ou wp eval
Serialization corrupta Search-replace directo Usar wp search-replace (serialization-aware)
wp option patch sem hooks patch nao dispara hooks wp eval com update_option() para side-effects

Capabilities Rank Math

rank_math_general rank_math_sitemap rank_math_404_monitor rank_math_redirections rank_math_role_manager rank_math_analytics rank_math_onpage_general rank_math_onpage_advanced rank_math_onpage_snippet rank_math_onpage_social rank_math_content_ai


Free vs PRO — funcionalidades WP-CLI

Funcionalidade Free PRO
wp rankmath sitemap generate sim sim
Meta por post/term/user sim sim
Options globais sim sim
Schema markup (1/post) sim sim
Schemas multiplos/post nao sim
Custom Schema Builder (840+ tipos) nao sim
Redirections sim sim
404 Monitor sim sim
Instant Indexing (IndexNow) sim sim
Google Indexing API nao sim
Analytics GSC/GA basico avancado
News Sitemap nao sim
Video Sitemap nao sim
Content AI limitado sim
CSV import/export SEO nao sim
Focus keywords ilimitadas 5 max ilimitado

Migracao Yoast -> Rank Math

# BACKUP OBRIGATORIO
wp db export backup-pre-migracao-$(date +%Y%m%d).sql --allow-root --path=$PATH

# Detectar prefixo
PREFIX=$(wp db prefix --allow-root --path=$PATH)

# Migrar titulo SEO
wp db query "INSERT INTO ${PREFIX}postmeta (post_id, meta_key, meta_value)
SELECT post_id, 'rank_math_title', meta_value FROM ${PREFIX}postmeta
WHERE meta_key = '_yoast_wpseo_title' AND meta_value != ''
AND post_id NOT IN (SELECT post_id FROM ${PREFIX}postmeta WHERE meta_key = 'rank_math_title');" --allow-root --path=$PATH

# Migrar meta description
wp db query "INSERT INTO ${PREFIX}postmeta (post_id, meta_key, meta_value)
SELECT post_id, 'rank_math_description', meta_value FROM ${PREFIX}postmeta
WHERE meta_key = '_yoast_wpseo_metadesc' AND meta_value != ''
AND post_id NOT IN (SELECT post_id FROM ${PREFIX}postmeta WHERE meta_key = 'rank_math_description');" --allow-root --path=$PATH

# Migrar focus keyword
wp db query "INSERT INTO ${PREFIX}postmeta (post_id, meta_key, meta_value)
SELECT post_id, 'rank_math_focus_keyword', meta_value FROM ${PREFIX}postmeta
WHERE meta_key = '_yoast_wpseo_focuskw' AND meta_value != ''
AND post_id NOT IN (SELECT post_id FROM ${PREFIX}postmeta WHERE meta_key = 'rank_math_focus_keyword');" --allow-root --path=$PATH

# Sempre seguido de:
wp cache flush --allow-root --path=$PATH

Recursos

Referencias

  • references/commands.md — Referencia completa de meta keys, options e modulos

Documentacao Hub

  • Manual: Hub/06-Operacoes/Documentacao/Manuais/WP-CLI/Rank-Math-WP-CLI-Manual-Definitivo.md (17 seccoes)
  • QR: Hub/06-Operacoes/Documentacao/Quick-Reference/QR-RankMath-WP-CLI.md
  • Pesquisa Claude: Hub/06-Operacoes/Documentacao/Manuais/WP-CLI/Rank-Math-SEO-WP-CLI-Skils-Pesquisa-Claude.md
  • Pesquisa Gemini: Hub/06-Operacoes/Documentacao/Manuais/WP-CLI/Rank-Math-SEO-WP-CLI-Skills-Pesquisa-Gemini.md
  • NotebookLM: WordPress Config CLI (4 fontes)

Rank Math SEO via WP-CLI | Descomplicar | v2.0.0 | 29-03-2026


Healing Log

Registo de erros conhecidos e como evitá-los. Lido automaticamente antes de executar.

{"date":"","issue":"","fix":"","source":"user|auto"}

Adicionar nova linha após cada erro corrigido.