Files
claude-plugins/wordpress/skills/branda-menu/SKILL.md
Emanuel Almeida 9404af7ac9 feat: sync all plugins, skills, agents updates
New plugins: core-tools
New skills: auto-expense, ticket-triage, design, security-check,
  aiktop-tasks, daily-digest, imap-triage, index-update, mindmap,
  notebooklm, proc-creator, tasks-overview, validate-component,
  perfex-module, report, calendar-manager
New agents: design-critic, design-generator, design-lead,
  design-prompt-architect, design-researcher, compliance-auditor,
  metabase-analyst, gitea-integration-specialist
Updated: all plugin configs, knowledge datasets, existing skills

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:16:32 +00:00

20 KiB

name, description, author, version, quality_score, user_invocable, category, tags, desk_project, allowed-tools, mcps, dependencies, triggers
name description author version quality_score user_invocable category tags desk_project allowed-tools mcps dependencies triggers
branda-menu Organiza o menu admin WordPress via Branda (branda-white-labeling) em seccoes Descomplicar standard. Computa Branda IDs a partir de slugs WP, constroi menu custom com itens nativos reordenados + section headers, e guarda programaticamente via WP-CLI. Use when "branda menu", "organizar menu admin", "menu wordpress", "admin sidebar", "reorganizar admin". Descomplicar Crescimento Digital 1.0.0 85 true wordpress
branda
wordpress
admin-menu
white-labeling
wip
69 Read, Write, Edit, Bash, mcp__ssh-unified, mcp__memory-supabase ssh-unified, memory-supabase
mcps plugins
ssh-unified
branda-white-labeling
User mentions 'branda menu', 'organizar menu', 'admin sidebar'
User asks to reorganize WordPress admin menu
Setting up new WiP site admin customization

/branda-menu - Organizar Menu Admin WordPress

Skill para organizar o menu admin sidebar de qualquer site WordPress WiP usando o Branda (branda-white-labeling).


Arquitectura Branda (Referencia Interna)

Como o Branda gere menus

O Branda usa um modulo admin/menu.php que intercepta o render do menu admin WordPress e substitui pela configuracao custom.

Options wp_options envolvidas:

Option Funcao
ultimatebranding_activated_modules Modulos activos (precisa ter admin/menu.php)
ub_custom_admin_menu Configuracao do menu custom por role
ub_saved_admin_menus Captura do menu nativo WP (so para UI Branda, nao para render)

Algoritmo de ID (critico)

O Branda mapeia slugs WordPress para IDs internos usando:

function branda_id($slug) {
    return "menu_item_" . substr(base_convert(md5($slug), 16, 32), 0, 12);
}

Exemplo: index.php -> menu_item_42ho017e7jo0

Este algoritmo e determinista. O mesmo slug gera sempre o mesmo ID, independente do site.

Tipos de itens no menu

Tipo Campos chave Uso
Section header link_type: "none", css_classes: "menu-highlight" Separador visual com titulo
Custom link link_type: "custom", custom_url: "..." Link manual (ex: Descomplicar)
Native item was_native: 1, campos vazios Item WP real, nome preenchido dinamicamente
Hidden item is_hidden: "1", was_native: 1 Item WP escondido do menu

Mecanismo de merge (parse_args_deep)

Na renderizacao, o Branda faz merge do menu configurado com o menu WP real:

  • Itens nativos no config: aparecem na posicao configurada
  • Itens nativos nao no config: inseridos na posicao default (aparecem misturados!)
  • Itens custom: aparecem na posicao configurada
  • Submenus vazios []: auto-preenchidos com submenus reais do WP

Regra critica: Incluir todos os itens nativos no config (visiveis na posicao desejada OU hidden). Se faltar algum, aparece na posicao default e quebra a organizacao.


Seccoes Standard Descomplicar (9)

Todo site WiP deve ter o menu organizado nestas 9 seccoes, nesta ordem:

# Seccao Dashicon Conteudo tipico
1 Suporte dashicons-admin-tools Link Descomplicar (desk.descomplicar.pt)
2 Admin dashicons-admin-generic Painel, Utilizadores, Opcoes, Plugins, Ferramentas
3 Conteudo dashicons-admin-page Paginas, CPTs do projecto, Artigos, Multimedia, ACF
4 Design dashicons-admin-appearance Elementor, Modelos, Jeg Kit, Apresentacao
5 Marketing dashicons-megaphone FluentCRM, Fluent Forms, Rank Math, WhatsApp, etc.
6 Idiomas dashicons-translation Polylang/WPML, Loco Translate (se multilingue)
7 Performance dashicons-performance WP Fastest Cache, WebP Express
8 Seguranca dashicons-shield Wordfence, Complianz
9 WebMaster dashicons-admin-settings Branda, Code Snippets, Activity Log

Notas:

  • Seccao Idiomas so aparece se site for multilingue
  • CPTs especificos do projecto (Tours, Servicos, etc.) vao em Conteudo
  • Plugins sectoriais (KiviCare, WooCommerce, etc.) podem ter seccao propria entre Marketing e Idiomas

Itens tipicamente hidden

Estes itens nativos devem ser incluidos no config com is_hidden: "1":

Slug Motivo
separator1, separator2, separator-last Separadores nativos substituidos por section headers
edit-comments.php Comentarios raramente usados
hello-elementor Pagina tema redundante com themes.php
elementor Menu Elementor duplicado (ja existe elementor-home)

Procedimento

Passo 1: Verificar pre-requisitos

# Via MCP SSH - verificar Branda activo e modulo menu activo
mcp__ssh-unified__ssh_execute server:"server" command:"wp plugin is-active branda-white-labeling --allow-root --path=/home/USER/SITE && echo ACTIVE || echo INACTIVE"

# Verificar modulo menu activo
mcp__ssh-unified__ssh_execute server:"server" command:"wp eval '
\$m = get_option(\"ultimatebranding_activated_modules\", array());
echo isset(\$m[\"admin/menu.php\"]) ? \"MENU MODULE ACTIVE\" : \"MENU MODULE INACTIVE\";
' --allow-root --path=/home/USER/SITE"

Se modulo inactivo, activar:

mcp__ssh-unified__ssh_execute server:"server" command:"wp eval '
\$m = get_option(\"ultimatebranding_activated_modules\", array());
\$m[\"admin/menu.php\"] = \"yes\";
update_option(\"ultimatebranding_activated_modules\", \$m);
echo \"Activado\";
' --allow-root --path=/home/USER/SITE"

Passo 2: Extrair menu nativo

Obter lista de plugins activos e menu WP via WP-CLI. Como WP-CLI nao carrega todos os menus admin, usar este metodo combinado:

Opcao A (preferida): mu-plugin temporario

# Criar mu-plugin que captura menu no proximo page load
mcp__ssh-unified__ssh_execute server:"server" command:"cat > /home/USER/SITE/wp-content/mu-plugins/capture-menu.php << 'PHPEOF'
<?php
/**
 * Temporary mu-plugin to capture native admin menu for Branda
 * Auto-removes after capture
 */
add_action('admin_menu', function() {
    if (!current_user_can('manage_options')) return;
    if (get_option('_branda_menu_captured')) return;

    global \$menu, \$submenu;

    // Save raw menu data
    update_option('_branda_menu_capture', array(
        'menu' => \$menu,
        'submenu' => \$submenu,
        'captured_at' => time()
    ));
    update_option('_branda_menu_captured', true);

    // Self-destruct
    @unlink(__FILE__);
}, 999999);
PHPEOF
echo 'mu-plugin criado'
"

Depois, gerar cookie de auth e disparar um page load admin:

# Gerar cookie auth via WP-CLI
mcp__ssh-unified__ssh_execute server:"server" command:"wp eval '
\$expiration = time() + 300;
\$cookie = wp_generate_auth_cookie(1, \$expiration, \"logged_in\");
echo \$cookie;
' --allow-root --path=/home/USER/SITE"

# Disparar page load admin com curl (substituir COOKIE e HASH)
mcp__ssh-unified__ssh_execute server:"server" command:"curl -s -o /dev/null -w '%{http_code}' -b 'wordpress_logged_in_HASH=COOKIE' https://SITE/wp-admin/"

Depois ler a captura:

mcp__ssh-unified__ssh_execute server:"server" command:"wp eval '
\$cap = get_option(\"_branda_menu_capture\");
if (\$cap) {
    foreach (\$cap[\"menu\"] as \$pos => \$item) {
        if (count(\$item) >= 3) {
            \$slug = \$item[2];
            \$title = strip_tags(\$item[0]);
            echo \"\$pos. \$title => \$slug\n\";
        }
    }
}
' --allow-root --path=/home/USER/SITE"

Opcao B (alternativa): Chrome DevTools

Se tiver acesso ao browser, navegar ao wp-admin e executar JS:

Array.from(document.querySelectorAll('#adminmenu > li')).forEach((li, i) => {
    const a = li.querySelector('a');
    if (a) {
        const name = a.querySelector('.wp-menu-name')?.textContent?.trim() || a.textContent?.trim();
        const href = a.getAttribute('href') || '';
        console.log(i + '. ' + name + ' => ' + href);
    }
});

Passo 3: Mapear itens para seccoes

Com a lista de itens nativos, mapear cada um para a seccao correcta.

Mapeamento standard por slug:

# Admin
index.php -> Admin
users.php -> Admin
options-general.php -> Admin
plugins.php -> Admin
tools.php -> Admin

# Conteudo
edit.php -> Conteudo (Artigos)
edit.php?post_type=page -> Conteudo (Paginas)
upload.php -> Conteudo (Multimedia)
edit.php?post_type=acf-field-group -> Conteudo (ACF)
edit.php?post_type=* -> Conteudo (CPTs)

# Design
elementor-home -> Design (Elementor)
edit.php?post_type=elementor_library -> Design (Modelos)
jkit -> Design (Jeg Kit)
themes.php -> Design (Apresentacao)

# Marketing
fluentcrm-admin -> Marketing
fluent_forms -> Marketing
rank-math -> Marketing
click-to-chat -> Marketing

# Idiomas (se multilingue)
mlang -> Idiomas (Polylang)
loco -> Idiomas (Loco Translate)

# Performance
wpfastestcacheoptions -> Performance

# Seguranca
Wordfence -> Seguranca
complianz -> Seguranca

# WebMaster
branding -> WebMaster (Branda)
wpcode -> WebMaster (Code Snippets)

# Hidden
separator1, separator2, separator-last -> Hidden
edit-comments.php -> Hidden
hello-elementor -> Hidden
elementor -> Hidden (duplicado de elementor-home)

Itens que nao encaixam no standard: Perguntar ao utilizador em que seccao colocar. Exemplos: WooCommerce, KiviCare, FareHarbor.

Passo 4: Construir e guardar o menu

Criar um PHP script no servidor e executar com wp eval-file:

mcp__ssh-unified__ssh_execute server:"server" command:"cat > /tmp/branda-menu-SITE.php << 'PHPEOF'
<?php
/**
 * Branda menu builder for SITENAME
 * Generated by /branda-menu skill
 */

function branda_id(\$slug) {
    return 'menu_item_' . substr(base_convert(md5(\$slug), 16, 32), 0, 12);
}

function native_item(\$subs = array()) {
    return array(
        'title' => '', 'id_attribute' => '', 'css_classes' => '',
        'icon_svg' => '', 'icon_url' => '', 'icon_image_id' => '',
        'dashicon' => '', 'icon_type' => '', 'custom_url' => '',
        'link_type' => '', 'link_target' => '', 'is_invisible' => '',
        'is_hidden' => '', 'was_native' => 1, 'submenu' => \$subs
    );
}

function hidden_item() {
    \$item = native_item();
    \$item['is_hidden'] = '1';
    return \$item;
}

function section_header(\$title, \$dashicon) {
    return array(
        'icon_type' => 'dashicon', 'link_type' => 'none',
        'submenu' => array(), 'title' => \$title,
        'css_classes' => 'menu-highlight', 'dashicon' => \$dashicon
    );
}

function custom_link(\$title, \$url, \$dashicon, \$target = '') {
    return array(
        'icon_type' => 'dashicon', 'link_type' => 'custom',
        'submenu' => array(), 'title' => \$title,
        'dashicon' => \$dashicon, 'link_target' => \$target,
        'custom_url' => \$url
    );
}

// === BUILD MENU ===
\$menu = array();

// 1. SUPORTE
\$menu['menu_item_sec_suporte'] = section_header('Suporte', 'dashicons-admin-tools');
\$menu['menu_item_desk_link'] = custom_link('Descomplicar', 'https://desk.descomplicar.pt/', 'dashicons-admin-comments', '_blank');

// 2. ADMIN
\$menu['menu_item_sec_admin'] = section_header('Admin', 'dashicons-admin-generic');
\$menu[branda_id('index.php')] = native_item();
\$menu[branda_id('users.php')] = native_item();
\$menu[branda_id('options-general.php')] = native_item();
\$menu[branda_id('plugins.php')] = native_item();
\$menu[branda_id('tools.php')] = native_item();

// 3. CONTEUDO
\$menu['menu_item_sec_conteudo'] = section_header('Conteudo', 'dashicons-admin-page');
\$menu[branda_id('edit.php?post_type=page')] = native_item();
// [INSERIR CPTs DO PROJECTO AQUI]
\$menu[branda_id('edit.php')] = native_item();
\$menu[branda_id('upload.php')] = native_item();
\$menu[branda_id('edit.php?post_type=acf-field-group')] = native_item();

// 4. DESIGN
\$menu['menu_item_sec_design'] = section_header('Design', 'dashicons-admin-appearance');
\$menu[branda_id('elementor-home')] = native_item();
\$menu[branda_id('edit.php?post_type=elementor_library')] = native_item();
// \$menu[branda_id('jkit')] = native_item(); // Se Jeg Kit activo
\$menu[branda_id('themes.php')] = native_item();

// 5. MARKETING
\$menu['menu_item_sec_marketing'] = section_header('Marketing', 'dashicons-megaphone');
\$menu[branda_id('fluentcrm-admin')] = native_item();
\$menu[branda_id('fluent_forms')] = native_item();
\$menu[branda_id('rank-math')] = native_item();
\$menu[branda_id('click-to-chat')] = native_item();

// 6. IDIOMAS (se multilingue)
// \$menu['menu_item_sec_idiomas'] = section_header('Idiomas', 'dashicons-translation');
// \$menu[branda_id('mlang')] = native_item();
// \$menu[branda_id('loco')] = native_item();

// 7. PERFORMANCE
\$menu['menu_item_sec_performance'] = section_header('Performance', 'dashicons-performance');
\$menu[branda_id('wpfastestcacheoptions')] = native_item();

// 8. SEGURANCA
\$menu['menu_item_sec_seguranca'] = section_header('Seguranca', 'dashicons-shield');
\$menu[branda_id('Wordfence')] = native_item();
\$menu[branda_id('complianz')] = native_item();

// 9. WEBMASTER
\$menu['menu_item_sec_webmaster'] = section_header('WebMaster', 'dashicons-admin-settings');
\$menu[branda_id('branding')] = native_item();
\$menu[branda_id('wpcode')] = native_item();

// HIDDEN
\$menu[branda_id('separator1')] = hidden_item();
\$menu[branda_id('separator2')] = hidden_item();
\$menu[branda_id('separator-last')] = hidden_item();
\$menu[branda_id('edit-comments.php')] = hidden_item();
\$menu[branda_id('hello-elementor')] = hidden_item();
\$menu[branda_id('elementor')] = hidden_item();

// SAVE
update_option('ub_custom_admin_menu', array('administrator' => \$menu));
wp_cache_flush();

\$visible = count(array_filter(\$menu, function(\$i) { return empty(\$i['is_hidden']); }));
\$hidden = count(\$menu) - \$visible;
echo \"Menu guardado: \$visible visiveis + \$hidden hidden = \" . count(\$menu) . \" total\n\";
PHPEOF
echo 'Script criado'
"

# Executar
mcp__ssh-unified__ssh_execute server:"server" command:"wp eval-file /tmp/branda-menu-SITE.php --allow-root --path=/home/USER/SITE"

Passo 5: Verificar

# Contar itens no config
mcp__ssh-unified__ssh_execute server:"server" command:"wp eval '
\$m = get_option(\"ub_custom_admin_menu\");
\$items = \$m[\"administrator\"];
echo \"Total: \" . count(\$items) . \"\n\";
foreach (\$items as \$key => \$item) {
    \$hidden = !empty(\$item[\"is_hidden\"]) ? \" [HIDDEN]\" : \"\";
    \$type = !empty(\$item[\"was_native\"]) ? \"native\" : (!empty(\$item[\"link_type\"]) && \$item[\"link_type\"] == \"none\" ? \"header\" : \"custom\");
    \$title = !empty(\$item[\"title\"]) ? \$item[\"title\"] : \"(native)\";
    echo \"\$key => \$type: \$title\$hidden\n\";
}
' --allow-root --path=/home/USER/SITE"

Verificar visualmente no browser: navegar ao wp-admin e confirmar que o menu esta organizado nas 9 seccoes.

Passo 6: Limpar

# Remover script temporario
mcp__ssh-unified__ssh_execute server:"server" command:"rm -f /tmp/branda-menu-SITE.php"

# Limpar captura temporaria (se usou mu-plugin)
mcp__ssh-unified__ssh_execute server:"server" command:"wp eval '
delete_option(\"_branda_menu_capture\");
delete_option(\"_branda_menu_captured\");
echo \"Limpo\";
' --allow-root --path=/home/USER/SITE"

# Garantir mu-plugin removido
mcp__ssh-unified__ssh_execute server:"server" command:"rm -f /home/USER/SITE/wp-content/mu-plugins/capture-menu.php 2>/dev/null; echo ok"

Adaptar para sites especificos

Sites multilingue (Polylang/WPML)

Descomentar seccao Idiomas no script. Adicionar:

$menu['menu_item_sec_idiomas'] = section_header('Idiomas', 'dashicons-translation');
$menu[branda_id('mlang')] = native_item(); // Polylang
$menu[branda_id('loco')] = native_item(); // Loco Translate

Sites WooCommerce

Adicionar seccao e-Commerce entre Marketing e Idiomas:

$menu['menu_item_sec_ecommerce'] = section_header('e-Commerce', 'dashicons-cart');
$menu[branda_id('woocommerce')] = native_item();
// $menu[branda_id('wc-admin&path=/analytics/overview')] = native_item(); // Analytics WC

Sites Care (KiviCare)

Adicionar seccao Clinica entre Marketing e Idiomas:

$menu['menu_item_sec_clinica'] = section_header('Clinica', 'dashicons-heart');
$menu[branda_id('kivicare-...')] = native_item(); // Verificar slug exacto

CPTs customizados

Adicionar na seccao Conteudo, antes de Artigos:

$menu[branda_id('edit.php?post_type=SLUG_CPT')] = native_item();

Itens desconhecidos

Se o menu nativo tiver itens que nao encaixam no mapeamento standard:

  1. Perguntar ao utilizador onde colocar
  2. Se plugin temporario/teste: adicionar ao Hidden
  3. Se plugin permanente: criar seccao propria ou adicionar a seccao existente

Troubleshooting

Menu nao muda apos guardar

  1. Limpar cache: wp cache flush --allow-root
  2. Verificar modulo activo: admin/menu.php em ultimatebranding_activated_modules
  3. Verificar role: config usa key administrator (nao admin)

Itens nativos aparecem fora das seccoes

Causa: item nativo nao incluido no config (inserido na posicao default pelo parse_args_deep). Fix: Identificar o slug do item, computar o Branda ID, adicionar ao config (visivel ou hidden).

Separadores nativos aparecem

Causa: separadores com slugs diferentes dos standard (separator1, separator2, separator-last). Fix: Verificar slugs via captura do menu nativo, adicionar como hidden.

Menu items custom aparecem em duplicado

Causa: o mesmo item existe como custom link E como native item. Fix: Remover o custom link, manter apenas o native item na posicao correcta.

CSS para esconder separadores em falta

Adicionar ao CSS custom do Branda (ub_admin_css) como fallback:

#adminmenu li.wp-menu-separator { display: none !important; }

IDs de slugs comuns (referencia rapida)

Slug Branda ID
index.php menu_item_42ho017e7jo0
edit.php menu_item_6lk5pbiakha0
upload.php menu_item_1jkdde99dfd0
edit.php?post_type=page menu_item_774p5endtlu0
themes.php menu_item_7jgmlsspgv60
plugins.php menu_item_5g2kqk93qi30
users.php menu_item_gajld83c8es0
tools.php menu_item_3t0no8pv5bfg
options-general.php menu_item_d1a8rsor9700
edit-comments.php menu_item_252pn6seih20
separator1 menu_item_3u7nva84d1i0
separator2 menu_item_6lm7mo14a4r0
separator-last menu_item_74g99t5jejn0
elementor-home menu_item_2kehh8g6nop0
elementor menu_item_27qkhd7iqao0
edit.php?post_type=elementor_library menu_item_3rubghs8krfg
hello-elementor menu_item_3q7v6ask7gpg
fluentcrm-admin menu_item_4a7t8bi9mt30
fluent_forms menu_item_ebai6etubd00
rank-math menu_item_148bl1t91os0
click-to-chat menu_item_1b65lubbpnd8
Wordfence menu_item_1077vi8mf9b0
complianz menu_item_5etmjgu9lnk0
wpfastestcacheoptions menu_item_4hqsn1kbum10
branding menu_item_7qde2b2f7670
wpcode menu_item_69igp9fj4tl0
loco menu_item_2c34vb7r1csg
mlang menu_item_24um676vv08g
woocommerce Computar: branda_id('woocommerce')
edit.php?post_type=acf-field-group menu_item_70ga2p32mc70

Para slugs nao listados, computar com:

wp eval 'echo "menu_item_" . substr(base_convert(md5("SLUG"), 16, 32), 0, 12);' --allow-root --path=/home/USER/SITE

Checklist

  • Branda activo e modulo admin/menu.php activo
  • Menu nativo extraido (todos os itens identificados)
  • Todos os itens nativos incluidos no config (visiveis ou hidden)
  • 9 seccoes criadas na ordem standard
  • CPTs do projecto na seccao Conteudo
  • Verificado visualmente no browser
  • Script temporario e capturas removidos
  • Permissoes corrigidas: chown -R USER:USER /home/USER/SITE/

Skill v1.0.0 | 26-02-2026 | Descomplicar