[MU] Admin Menu Editor

Aula: Editor de Menu Administrativo com MU-Plugin – Substituindo o Admin Menu Editor

Objetivo: Substituir o plugin admin-menu-editor por um MU-Plugin enxuto, que permite reorganizar, renomear, ocultar e adicionar itens personalizados no menu lateral do WordPress (admin).

Contexto: O plugin original oferece uma interface drag-and-drop, mas muitas vezes precisamos apenas de ajustes simples: esconder um menu para certos perfis, renomear um rótulo, reordenar itens, ou adicionar um link externo. Tudo isso pode ser feito com poucas linhas de PHP, sem peso adicional.

Funcionalidades implementadas no nosso MU-Plugin

  • Reordenar itens do menu (ex: levar “Posts” para o topo)
  • Renomear rótulos de menus (ex: “Posts” → “Artigos”)
  • Ocultar menus por papel do usuário (Administrador, Editor, Autor, etc.) ou por capacidade
  • Adicionar separadores visuais no menu
  • Adicionar links personalizados (URLs internas ou externas) com ícones
  • Remover submenus específicos
  • Totalmente configurável via array no próprio MU-Plugin

Código do MU-Plugin

Crie a pasta wp-content/mu-plugins/neodoor-admin-menu-editor/ e dentro dela o arquivo neodoor-admin-menu-editor.php com o conteúdo abaixo:

<?php
/**
 * Plugin Name:  Neodoor Admin Menu Editor
 * Description:  Reorganize, renomeie, oculte ou adicione itens no menu administrativo do WordPress.
 * Version:      1.0
 * Author:       Reinaldo (Neodoor.neo)
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

class Neodoor_Admin_Menu_Editor {

    private static $instance = null;

    // Configuração do menu – edite este array conforme sua necessidade
    private $menu_config = [
        // Ordem personalizada (os slugs dos itens principais)
        'order' => [
            'index.php',                  // Dashboard
            'edit.php',                   // Posts
            'edit.php?post_type=page',    // Páginas
            'upload.php',                 // Mídia
            'separator1',                 // Separador (opcional)
            'themes.php',                 // Aparência
            'plugins.php',                // Plugins
            'users.php',                  // Usuários
            'tools.php',                  // Ferramentas
            'options-general.php',        // Configurações
        ],
        
        // Renomear títulos de menus (slug => novo título)
        'rename' => [
            'edit.php'         => 'Artigos',
            'edit.php?post_type=page' => 'Páginas do Site',
            'upload.php'       => 'Biblioteca',
        ],
        
        // Ocultar menus para determinados papéis (ou capacidades)
        'hide_for_roles' => [
            'plugins.php' => [ 'editor', 'author' ],   // Esconde Plugins para Editores e Autores
            'tools.php'   => [ 'editor', 'author', 'contributor' ],
        ],
        
        // Ocultar para capacidade específica (ex: só quem pode 'manage_options' vê)
        'hide_by_capability' => [
            'edit.php?post_type=acf-field-group' => 'manage_options', // Esconde ACF se não for admin
        ],
        
        // Remover submenus específicos (menu_slug => array de slugs de submenu)
        'remove_submenus' => [
            'themes.php' => [ 'theme-editor.php', 'customize.php' ], // Remove editor de temas e customizer
            'plugins.php' => [ 'plugin-editor.php' ],                // Remove editor de plugins
        ],
        
        // Adicionar links personalizados
        'custom_links' => [
            [
                'title'      => 'Documentação WP',
                'url'        => 'https://wordpress.org/documentation/',
                'capability' => 'read',
                'icon'       => 'dashicons-media-document',
                'position'   => 99, // ordem (quanto maior, mais abaixo)
            ],
            [
                'title'      => 'Suporte Neodoor',
                'url'        => '/suporte', // URL interna
                'capability' => 'read',
                'icon'       => 'dashicons-sos',
                'position'   => 100,
            ],
        ],
    ];

    public static function get_instance() {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        add_action( 'admin_menu', [ $this, 'reorder_menu' ], 999 );
        add_action( 'admin_menu', [ $this, 'rename_menu_items' ], 999 );
        add_action( 'admin_menu', [ $this, 'hide_menu_items' ], 999 );
        add_action( 'admin_menu', [ $this, 'remove_submenus' ], 999 );
        add_action( 'admin_menu', [ $this, 'add_custom_links' ], 999 );
    }

    /**
     * Reordena o menu principal baseado na configuração 'order'
     */
    public function reorder_menu() {
        global $menu, $submenu;

        if ( empty( $this->menu_config['order'] ) ) {
            return;
        }

        $ordered_menu = [];
        $remaining = [];

        // Mapeia menus existentes por slug
        $menu_by_slug = [];
        foreach ( $menu as $item ) {
            if ( isset( $item[2] ) ) {
                $menu_by_slug[ $item[2] ] = $item;
            } else {
                $remaining[] = $item;
            }
        }

        // Adiciona na ordem especificada
        foreach ( $this->menu_config['order'] as $slug ) {
            if ( $slug === 'separator1' || $slug === 'separator2' ) {
                // Cria separador
                $ordered_menu[] = [ '', 'read', $slug, '', 'wp-menu-separator', '' ];
            } elseif ( isset( $menu_by_slug[ $slug ] ) ) {
                $ordered_menu[] = $menu_by_slug[ $slug ];
                unset( $menu_by_slug[ $slug ] );
            }
        }

        // Adiciona os itens que sobraram no final
        $menu = array_merge( $ordered_menu, array_values( $menu_by_slug ), $remaining );
    }

    /**
     * Renomeia títulos de menus
     */
    public function rename_menu_items() {
        global $menu;

        if ( empty( $this->menu_config['rename'] ) ) {
            return;
        }

        foreach ( $menu as &$item ) {
            if ( isset( $item[2] ) && isset( $this->menu_config['rename'][ $item[2] ] ) ) {
                $item[0] = $this->menu_config['rename'][ $item[2] ];
            }
        }
    }

    /**
     * Oculta menus baseado em papel do usuário ou capacidade
     */
    public function hide_menu_items() {
        global $menu, $submenu;

        $user = wp_get_current_user();
        $user_roles = (array) $user->roles;

        // Oculta por papel
        foreach ( $this->menu_config['hide_for_roles'] as $slug => $roles_to_hide ) {
            if ( array_intersect( $user_roles, $roles_to_hide ) ) {
                remove_menu_page( $slug );
            }
        }

        // Oculta por capacidade
        foreach ( $this->menu_config['hide_by_capability'] as $slug => $cap ) {
            if ( ! current_user_can( $cap ) ) {
                remove_menu_page( $slug );
            }
        }
    }

    /**
     * Remove submenus específicos
     */
    public function remove_submenus() {
        global $submenu;

        if ( empty( $this->menu_config['remove_submenus'] ) ) {
            return;
        }

        foreach ( $this->menu_config['remove_submenus'] as $parent_slug => $submenu_slugs ) {
            if ( isset( $submenu[ $parent_slug ] ) ) {
                foreach ( $submenu[ $parent_slug ] as $key => $item ) {
                    if ( isset( $item[2] ) && in_array( $item[2], $submenu_slugs ) ) {
                        unset( $submenu[ $parent_slug ][ $key ] );
                    }
                }
                // Reindexa
                $submenu[ $parent_slug ] = array_values( $submenu[ $parent_slug ] );
            }
        }
    }

    /**
     * Adiciona links personalizados ao menu
     */
    public function add_custom_links() {
        if ( empty( $this->menu_config['custom_links'] ) ) {
            return;
        }

        foreach ( $this->menu_config['custom_links'] as $link ) {
            if ( ! current_user_can( $link['capability'] ) ) {
                continue;
            }
            add_menu_page(
                $link['title'],
                $link['title'],
                $link['capability'],
                $link['url'],
                '',
                $link['icon'],
                $link['position']
            );
        }
    }
}

Neodoor_Admin_Menu_Editor::get_instance();

Instruções de instalação

  1. Certifique-se de que o autoloader loader.php esteja presente em /wp-content/mu-plugins/ (conforme aula anterior).
  2. Crie a pasta neodoor-admin-menu-editor dentro de /mu-plugins/.
  3. Dentro dela, crie o arquivo neodoor-admin-menu-editor.php e cole o código acima.
  4. Edite o array $menu_config conforme sua necessidade (ordem, renomeações, ocultações, etc.).
  5. Desative e remova o plugin admin-menu-editor da lista de plugins.

Configuração explicada (exemplos)

O coração do plugin é o array $menu_config. Veja como usá-lo:

  • order: lista de slugs dos menus na ordem desejada. Você pode usar slugs como 'index.php', 'edit.php', 'upload.php', 'separator1' para adicionar um separador.
  • rename: associe um slug ao novo título que aparecerá no menu.
  • hide_for_roles: esconde um menu (slug) para determinados papéis (array de strings: ‘administrator’, ‘editor’, ‘author’, ‘contributor’, ‘subscriber’).
  • hide_by_capability: esconde um menu se o usuário não tiver uma capacidade específica (ex: ‘manage_options’).
  • remove_submenus: remove submenus indesejados. A chave é o slug do menu pai, o valor é um array com os slugs dos submenus a remover.
  • custom_links: adiciona novos itens ao menu. Cada item pode ter: title (texto), url (link absoluto ou relativo), capability, icon (classe dashicons, ex: ‘dashicons-admin-links’), position (número para ordenação).

Exemplos práticos de configuração

// Reordenar: Dashboard, Posts, Separador, Mídia, Configurações
'order' => [
    'index.php',
    'edit.php',
    'separator1',
    'upload.php',
    'options-general.php',
],

// Renomear "Mídia" para "Arquivos"
'rename' => [
    'upload.php' => 'Arquivos',
],

// Ocultar "Plugins" para qualquer usuário que não seja administrador
'hide_by_capability' => [
    'plugins.php' => 'manage_options',
],

// Remover o editor de temas dentro de Aparência
'remove_submenus' => [
    'themes.php' => [ 'theme-editor.php' ],
],

Teste e verificação

  • Faça login como Administrador: veja se a ordem e renomeações estão aplicadas.
  • Faça login como Editor (ou crie um usuário de teste): itens ocultos devem desaparecer.
  • Os links personalizados devem aparecer na posição definida.
  • Submenus removidos não devem mais estar acessíveis via URL direta (o WordPress os bloqueia).

Limitações e observações

  • Alguns plugins adicionam menus dinamicamente com slugs que podem variar. Para descobrir o slug de um menu, use o inspetor de código ou o plugin Query Monitor.
  • A reordenação pode conflitar com outros plugins que também tentam reordenar o menu (ex: Jetpack, WooCommerce). Nesse caso, aumente a prioridade no hook admin_menu (o nosso já está em 999).
  • Separadores não são suportados em todas as versões do WordPress, mas funcionam bem.
  • Se você quiser ocultar um menu apenas para um papel específico, mas permitir para administradores, use hide_for_roles sem incluir ‘administrator’.

Dica extra: descubra slugs de menu rapidamente

Adicione este snippet temporariamente em um MU-Plugin ou no tema para listar todos os slugs na tela de admin (lembre-se de remover depois):

add_action( 'admin_head', function() {
    global $menu;
    echo '<pre style="position:absolute;z-index:9999;background:#fff;border:1px solid #ccc;">';
    foreach ( $menu as $item ) {
        if ( isset( $item[2] ) && ! empty( $item[0] ) ) {
            echo $item[0] . ' → ' . $item[2] . '<br>';
        }
    }
    echo '</pre>';
} );

Registro no caderno

Data:

Funcionalidade: Editor de menu administrativo (reordenar, renomear, ocultar, adicionar links)

Plugins substituídos: admin-menu-editor

Complexidade: Baixa a média (configuração via array)

Observação: Sempre teste em ambiente local antes de usar em produção.

⚠️ Você já votou neste conteúdo.

Média: 2.8 (22 votos)