JezK
Edit File: custom-menu-manager.php
<?php /** * Plugin Name: Custom Menu Manager * Plugin URI: https://www.advaxe.com * Description: Hide any WordPress admin menus and submenus, and restrict direct link access. * Version: 1.0.0 * Author: Advaxe * Author URI: https://www.advaxe.com * Text Domain: advaxe-menu-manager */ if ( ! defined( 'ABSPATH' ) ) { exit; } class Advaxe_Custom_Menu_Manager { private $option_name = 'advaxe_menu_manager_settings'; public function __construct() { // Hooks for adding the settings page and saving data add_action( 'admin_menu', [ $this, 'add_plugin_page' ] ); add_action( 'admin_init', [ $this, 'save_settings' ] ); // Hooks for hiding menus and blocking access (priority 999 to run after other plugins) add_action( 'admin_menu', [ $this, 'hide_selected_menus' ], 999 ); add_action( 'admin_init', [ $this, 'check_page_access' ], 999 ); } // 1. Create the Menu public function add_plugin_page() { add_options_page( 'Menu Manager', 'Menu Manager', 'manage_options', 'advaxe-menu-manager', [ $this, 'create_admin_page' ] ); } // Save Settings Data public function save_settings() { if ( isset( $_POST['advaxe_menu_manager_nonce'] ) && wp_verify_nonce( $_POST['advaxe_menu_manager_nonce'], 'advaxe_save_menus' ) ) { $menus_data = isset( $_POST['advaxe_menus'] ) ? (array) $_POST['advaxe_menus'] : []; update_option( $this->option_name, $menus_data ); add_settings_error( 'advaxe_menu_messages', 'advaxe_menu_message', 'Settings saved successfully!', 'updated' ); } } // Hide Selected Menus (Hide Option) public function hide_selected_menus() { $settings = get_option( $this->option_name, [] ); if ( empty( $settings ) ) return; foreach ( $settings as $item ) { if ( ! isset( $item['hide'] ) || $item['hide'] != '1' ) continue; $menu_slug = htmlspecialchars_decode( $item['slug'] ); $parent_slug = htmlspecialchars_decode( $item['parent'] ); // Prevent hiding the plugin's own settings page if ( $menu_slug === 'advaxe-menu-manager' ) continue; if ( $parent_slug === $menu_slug ) { remove_menu_page( $menu_slug ); } else { remove_submenu_page( $parent_slug, $menu_slug ); } } } // Block Direct Access (Block Access Option) public function check_page_access() { if ( wp_doing_ajax() ) return; // Allow Ajax requests $settings = get_option( $this->option_name, [] ); if ( empty( $settings ) ) return; global $pagenow, $plugin_page, $typenow; // Logic to determine the current page slug $current_slug = $pagenow; if ( ! empty( $plugin_page ) ) { $current_slug = $plugin_page; } elseif ( ! empty( $_GET['page'] ) ) { $current_slug = sanitize_text_field( $_GET['page'] ); } elseif ( ! empty( $typenow ) && $pagenow === 'edit.php' ) { $current_slug = 'edit.php?post_type=' . $typenow; } elseif ( ! empty( $typenow ) && $pagenow === 'post-new.php' ) { $current_slug = 'post-new.php?post_type=' . $typenow; } foreach ( $settings as $item ) { if ( isset( $item['block'] ) && $item['block'] == '1' ) { $menu_slug = htmlspecialchars_decode( $item['slug'] ); // Prevent blocking the plugin's own settings page if ( $menu_slug === 'advaxe-menu-manager' ) continue; if ( $current_slug === $menu_slug ) { wp_die( '<h1>Access Denied</h1><p>Sorry, you do not have permission to access this page.</p>', 'Access Denied', [ 'response' => 403 ] ); } } } } // 2 & 3. Menu Manager Dashboard and Accordion UI public function create_admin_page() { global $menu, $submenu; $settings = get_option( $this->option_name, [] ); ?> <div class="wrap"> <h1>Custom Menu Manager</h1> <p><strong>Developed by:</strong> <a href="https://www.advaxe.com" target="_blank">Advaxe</a></p> <?php settings_errors( 'advaxe_menu_messages' ); ?> <form method="post" action=""> <?php wp_nonce_field( 'advaxe_save_menus', 'advaxe_menu_manager_nonce' ); ?> <div style="margin-top: 20px; background: #fff; padding: 20px; border: 1px solid #ccd0d4; border-radius: 5px;"> <p style="margin-bottom: 20px; font-size: 14px;"> <strong>Hide:</strong> Only hides the menu from the admin sidebar.<br> <strong>Block:</strong> In addition to hiding, if someone visits the direct link, they will see an <em>Access Denied</em> message. </p> <ul style="margin: 0; padding: 0; list-style: none;"> <?php $index = 0; if( ! empty( $menu ) ) { foreach ( $menu as $m ) { if ( empty( $m[0] ) ) continue; // Skip separators $menu_title = strip_tags( $m[0] ); $menu_slug = $m[2]; $has_submenu = isset( $submenu[$menu_slug] ) && ! empty( $submenu[$menu_slug] ); // Check if previously saved $is_hidden = false; $is_blocked = false; foreach( $settings as $s ) { if( htmlspecialchars_decode( $s['slug'] ) === $menu_slug && htmlspecialchars_decode( $s['parent'] ) === $menu_slug ) { $is_hidden = isset( $s['hide'] ) ? true : false; $is_blocked = isset( $s['block'] ) ? true : false; break; } } ?> <li style="border: 1px solid #ddd; margin-bottom: 10px; border-radius: 4px;"> <!-- Parent Menu Header --> <div class="advaxe-menu-header" style="background: #f9f9f9; padding: 10px 15px; display: flex; justify-content: space-between; align-items: center; cursor: pointer;"> <strong style="font-size: 14px;"> <?php echo esc_html( $menu_title ); ?> <span style="color:#aaa; font-weight:normal; font-size:12px;">(<?php echo esc_html($menu_slug); ?>)</span> </strong> <div onclick="event.stopPropagation();"> <label style="margin-right: 15px; cursor: pointer;"> <input type="checkbox" name="advaxe_menus[<?php echo $index; ?>][hide]" value="1" <?php checked( $is_hidden, true ); ?>> Hide </label> <label style="cursor: pointer;"> <input type="checkbox" name="advaxe_menus[<?php echo $index; ?>][block]" value="1" <?php checked( $is_blocked, true ); ?>> Block </label> <input type="hidden" name="advaxe_menus[<?php echo $index; ?>][slug]" value="<?php echo esc_attr( $menu_slug ); ?>"> <input type="hidden" name="advaxe_menus[<?php echo $index; ?>][parent]" value="<?php echo esc_attr( $menu_slug ); ?>"> <?php if ( $has_submenu ) : ?> <span class="dashicons dashicons-arrow-down-alt2" style="margin-left: 10px; color: #555; vertical-align: middle;"></span> <?php endif; ?> </div> </div> <!-- Submenu Accordion --> <?php if ( $has_submenu ) : ?> <div class="advaxe-submenu-container" style="display: none; padding: 10px 15px 10px 40px; border-top: 1px solid #ddd; background: #fff;"> <ul style="margin: 0; padding: 0; list-style: none;"> <?php foreach ( $submenu[$menu_slug] as $sub ) { $index++; $sub_title = strip_tags( $sub[0] ); $sub_slug = $sub[2]; // Disable options for the plugin's own settings page $is_disabled = ( $sub_slug === 'advaxe-menu-manager' ) ? 'disabled' : ''; $sub_hidden = false; $sub_blocked = false; foreach( $settings as $s ) { if( htmlspecialchars_decode( $s['slug'] ) === $sub_slug && htmlspecialchars_decode( $s['parent'] ) === $menu_slug ) { $sub_hidden = isset( $s['hide'] ) ? true : false; $sub_blocked = isset( $s['block'] ) ? true : false; break; } } ?> <li style="padding: 8px 0; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center;"> <span>- <?php echo esc_html( $sub_title ); ?></span> <div> <label style="margin-right: 15px; cursor: pointer;"> <input type="checkbox" name="advaxe_menus[<?php echo $index; ?>][hide]" value="1" <?php checked( $sub_hidden, true ); ?> <?php echo $is_disabled; ?>> Hide </label> <label style="cursor: pointer;"> <input type="checkbox" name="advaxe_menus[<?php echo $index; ?>][block]" value="1" <?php checked( $sub_blocked, true ); ?> <?php echo $is_disabled; ?>> Block </label> <input type="hidden" name="advaxe_menus[<?php echo $index; ?>][slug]" value="<?php echo esc_attr( $sub_slug ); ?>"> <input type="hidden" name="advaxe_menus[<?php echo $index; ?>][parent]" value="<?php echo esc_attr( $menu_slug ); ?>"> </div> </li> <?php } ?> </ul> </div> <?php endif; ?> </li> <?php $index++; } } ?> </ul> <p class="submit"> <button type="submit" class="button button-primary button-hero">Save Menu Settings</button> </p> </div> </form> </div> <!-- Accordion JS Script --> <script> document.addEventListener("DOMContentLoaded", function() { const headers = document.querySelectorAll(".advaxe-menu-header"); headers.forEach(header => { header.addEventListener("click", function() { const submenu = this.nextElementSibling; if (submenu && submenu.classList.contains("advaxe-submenu-container")) { if (submenu.style.display === "none" || submenu.style.display === "") { submenu.style.display = "block"; } else { submenu.style.display = "none"; } } }); }); }); </script> <?php } } new Advaxe_Custom_Menu_Manager();