WordPress函数:remove_submenu_page 移除后台子菜单

编辑文章

简介

remove_submenu_page 函数用于移除WordPress后台管理菜单中的特定子菜单项,常用于定制后台界面、按用户角色隐藏功能或创建简化的管理体验。

语法

<?php
remove_submenu_page( string $menu_slug, string $submenu_slug );

该函数位于 wp-admin/includes/plugin.php 文件,通过修改全局变量 $submenu 实现功能,是WordPress菜单系统API的一部分。

参数 类型 必填 默认值 说明
$menu_slug string 父菜单的slug(标识符)
$submenu_slug string 要移除的子菜单slug

返回值:无返回值

用法

基础用法

最常见的场景是在插件或主题中移除特定的后台菜单项。以下示例展示如何移除”设置”菜单下的”常规”子菜单:

<?php
/**
 * 移除设置菜单中的常规子菜单
 * 
 * 此代码应添加到主题的functions.php文件或插件文件中
 */
function my_custom_remove_submenu() {
    // 移除设置 -> 常规
    remove_submenu_page( 'options-general.php', 'options-general.php' );

    // 注意:'常规'子菜单的slug与父菜单相同
}
add_action( 'admin_menu', 'my_custom_remove_submenu', 999 );

为什么需要高优先级?
我们将优先级设为999确保在菜单添加完成后执行。WordPress默认的菜单添加优先级是10,许多插件使用更高的优先级(如99),因此使用999可以确保最后执行,避免被其他代码重新添加。

进阶用法

根据用户角色动态移除菜单

在实际项目中,经常需要根据不同用户角色显示不同的菜单结构:

<?php
/**
 * 根据用户角色定制后台菜单
 */
function custom_role_based_menu() {
    // 获取当前用户
    $user = wp_get_current_user();

    // 检查用户角色
    if ( in_array( 'editor', (array) $user->roles ) ) {
        // 为编辑角色移除某些管理功能
        remove_submenu_page( 'tools.php', 'tools.php' );           // 工具 -> 可用工具
        remove_submenu_page( 'options-general.php', 'options-writing.php' );  // 设置 -> 撰写
    }

    // 如果是自定义用户组
    if ( in_array( 'custom_role', (array) $user->roles ) ) {
        // 隐藏所有外观设置,只保留主题管理
        remove_submenu_page( 'themes.php', 'themes.php' );          // 外观 -> 主题
        remove_submenu_page( 'themes.php', 'customize.php' );       // 外观 -> 自定义
        remove_submenu_page( 'themes.php', 'widgets.php' );         // 外观 -> 小工具
    }
}
add_action( 'admin_menu', 'custom_role_based_menu', 999 );

创建完全自定义的管理界面

对于定制化管理面板,可能需要移除大部分默认菜单,只保留必需功能:

<?php
/**
 * 为特定客户创建简化管理界面
 */
function create_minimal_admin() {
    // 仅在特定条件下执行
    if ( ! defined( 'MINIMAL_ADMIN' ) || ! MINIMAL_ADMIN ) {
        return;
    }

    global $menu, $submenu;

    // 移除外观下的所有子菜单(除了菜单管理)
    remove_submenu_page( 'themes.php', 'themes.php' );          // 主题
    remove_submenu_page( 'themes.php', 'customize.php' );       // 自定义
    remove_submenu_page( 'themes.php', 'widgets.php' );         // 小工具
    remove_submenu_page( 'themes.php', 'theme-editor.php' );    // 主题编辑器

    // 保留菜单管理功能
    // 注意:菜单管理功能通常通过theme.php?page=nav-menus访问
    // 但它的slug是'nav-menus',属于themes.php父菜单

    // 移除插件菜单
    remove_menu_page( 'plugins.php' );

    // 移除工具菜单
    remove_menu_page( 'tools.php' );
}
add_action( 'admin_menu', 'create_minimal_admin', 999 );

为什么保留菜单管理?
即使移除外观菜单的其他功能,用户仍可能需要管理导航菜单。WordPress将菜单管理作为独立功能处理,其slug为’nav-menus’,仍属于themes.php父菜单。

易错点

错误的slug引用

最常见的错误是使用错误的菜单slug。WordPress核心菜单的slug是特定的,不能随意猜测:

<?php
// 错误示例:使用页面标题而不是slug
remove_submenu_page( 'Settings', 'General' ); // 错误!应该使用slug

// 正确示例:使用正确的slug
remove_submenu_page( 'options-general.php', 'options-general.php' );

如何查找正确的slug?
可以在浏览器开发者工具中检查管理页面URL,如/wp-admin/options-general.php,其slug就是options-general.php

执行时机过早

在菜单被添加之前尝试移除会导致操作无效:

<?php
// 错误示例:在admin_menu之前执行
remove_submenu_page( 'options-general.php', 'options-general.php' );

// 错误示例:优先级太低
function wrong_timing() {
    remove_submenu_page( 'options-general.php', 'options-general.php' );
}
add_action( 'admin_menu', 'wrong_timing', 1 ); // 优先级1可能太早

解决方案:总是使用admin_menu钩子,并设置足够高的优先级(如999)。

忽略用户权限检查

未检查用户权限可能导致所有用户都看到相同的菜单结构,包括没有权限访问对应功能的用户:

<?php
// 不完善的示例:未检查用户权限
function no_permission_check() {
    if ( some_condition() ) {
        remove_submenu_page( 'themes.php', 'theme-editor.php' );
    }
}

正确做法:结合current_user_can()检查用户能力。

对自定义菜单位置的误解

自定义插件创建的菜单可能有不同的结构:

<?php
// 假设插件这样添加菜单
add_menu_page( 'My Plugin', 'My Plugin', 'manage_options', 'my-plugin', 'callback' );
add_submenu_page( 'my-plugin', 'Settings', 'Settings', 'manage_options', 'my-plugin-settings', 'settings_callback' );

// 要移除"设置"子菜单,需要知道:
// 父菜单slug: 'my-plugin'
// 子菜单slug: 'my-plugin-settings'(不是'settings')
remove_submenu_page( 'my-plugin', 'my-plugin-settings' );

最佳实践

安全性考虑

始终验证用户权限,确保只有授权用户能看到特定的菜单结构:

<?php
/**
 * 安全地移除菜单项
 */
function secure_menu_removal() {
    // 检查用户权限
    if ( ! current_user_can( 'manage_options' ) ) {
        return; // 非管理员,不进行菜单定制
    }

    // 只有管理员可以移除这些菜单
    if ( current_user_can( 'administrator' ) && is_super_admin() ) {
        // 移除主题编辑器(安全考虑)
        remove_submenu_page( 'themes.php', 'theme-editor.php' );

        // 移除插件编辑器
        remove_submenu_page( 'plugins.php', 'plugin-editor.php' );
    }
}
add_action( 'admin_menu', 'secure_menu_removal', 999 );

可维护的代码组织

将菜单管理逻辑组织成易于维护的结构:

<?php
/**
 * 菜单管理类
 */
class Menu_Manager {

    private $user_roles;

    public function __construct() {
        $this->user_roles = wp_get_current_user()->roles;
        add_action( 'admin_menu', array( $this, 'manage_menus' ), 999 );
    }

    public function manage_menus() {
        $this->remove_unsafe_features();
        $this->customize_by_role();
        $this->add_custom_items();
    }

    private function remove_unsafe_features() {
        // 移除所有用户都不应访问的危险功能
        remove_submenu_page( 'themes.php', 'theme-editor.php' );
        remove_submenu_page( 'plugins.php', 'plugin-editor.php' );
    }

    private function customize_by_role() {
        if ( in_array( 'editor', $this->user_roles ) ) {
            $this->setup_editor_menus();
        }

        if ( in_array( 'author', $this->user_roles ) ) {
            $this->setup_author_menus();
        }
    }

    private function setup_editor_menus() {
        // 编辑角色的特定菜单配置
        remove_submenu_page( 'tools.php', 'import.php' );
    }

    private function add_custom_items() {
        // 添加自定义菜单项的逻辑
    }
}

// 初始化
new Menu_Manager();

与用户设置集成

将菜单配置保存为用户选项,允许用户自定义界面:

<?php
/**
 * 用户可定制的菜单系统
 */
class User_Customizable_Menus {

    public function __construct() {
        add_action( 'admin_menu', array( $this, 'apply_user_preferences' ), 999 );
        add_action( 'admin_init', array( $this, 'register_settings' ) );
    }

    public function register_settings() {
        // 注册设置字段,允许用户选择隐藏的菜单
        register_setting( 'menu_preferences', 'hidden_menu_items' );
    }

    public function apply_user_preferences() {
        $user_id = get_current_user_id();
        $hidden_items = get_user_meta( $user_id, 'hidden_menu_items', true );

        if ( ! empty( $hidden_items ) && is_array( $hidden_items ) ) {
            foreach ( $hidden_items as $item ) {
                list( $parent, $child ) = explode( '|', $item );
                remove_submenu_page( $parent, $child );
            }
        }
    }
}

性能优化

避免在每次页面加载时执行不必要的操作:

<?php
/**
 * 高效管理菜单
 */
function efficient_menu_management() {
    // 只在管理界面执行
    if ( ! is_admin() ) {
        return;
    }

    // 缓存用户角色查询结果
    $user_roles = wp_cache_get( 'user_roles_' . get_current_user_id(), 'menu_management' );

    if ( false === $user_roles ) {
        $user_roles = wp_get_current_user()->roles;
        wp_cache_set( 'user_roles_' . get_current_user_id(), $user_roles, 'menu_management', HOUR_IN_SECONDS );
    }

    // 只在需要时执行菜单操作
    if ( in_array( 'subscriber', $user_roles ) ) {
        // 订阅者不需要看到复杂的菜单
        remove_submenu_page( 'index.php', 'update-core.php' ); // 移除更新通知
    }
}
add_action( 'admin_menu', 'efficient_menu_management', 999 );

与现代WordPress功能结合

考虑与站点健康、REST API等现代功能的集成:

<?php
/**
 * 整合站点健康检查结果定制菜单
 */
function health_based_menu_management() {
    // 如果站点健康状态不佳,突出显示相关设置
    $health_status = get_transient( 'health-check-site-status-result' );

    if ( 'good' !== $health_status ) {
        // 不健康时,确保某些菜单不被隐藏
        // 这里可以添加逻辑确保特定设置菜单可见
    } else {
        // 健康状态下可以移除一些调试菜单
        remove_submenu_page( 'tools.php', 'site-health.php' );
    }
}
add_action( 'admin_menu', 'health_based_menu_management', 999 );

提供恢复选项

对于关键功能的移除,总是提供恢复方法:

<?php
/**
 * 提供菜单管理恢复选项
 */
class Recoverable_Menu_Management {

    const DISABLE_KEY = 'disable_menu_management';

    public function __construct() {
        // 检查是否有恢复请求
        if ( isset( $_GET['recover_menus'] ) && check_admin_referer( 'recover_menus' ) ) {
            update_option( self::DISABLE_KEY, true );
            wp_redirect( admin_url() );
            exit;
        }

        if ( ! get_option( self::DISABLE_KEY, false ) ) {
            add_action( 'admin_menu', array( $this, 'manage_menus' ), 999 );
        }

        // 在管理员工具栏添加恢复链接
        add_action( 'admin_bar_menu', array( $this, 'add_recovery_link' ), 999 );
    }

    public function manage_menus() {
        // 正常的菜单管理逻辑
        remove_submenu_page( 'themes.php', 'theme-editor.php' );
    }

    public function add_recovery_link( $wp_admin_bar ) {
        if ( current_user_can( 'manage_options' ) ) {
            $wp_admin_bar->add_node( array(
                'id'    => 'recover-menus',
                'title' => '恢复默认菜单',
                'href'  => wp_nonce_url( admin_url( '?recover_menus=1' ), 'recover_menus' ),
                'meta'  => array(
                    'title' => '点击恢复所有默认菜单项',
                ),
            ) );
        }
    }
}

new Recoverable_Menu_Management();

通过遵循这些最佳实践,您可以创建既安全又易于维护的菜单管理系统,同时确保最终用户获得最佳体验。记住,菜单定制应该始终以改善用户体验和工作流程为目标,而不是随意移除功能。