settings = SettingsManager::get_instance(); $this->init_hooks(); } private function get_setting($key, $default = '') { return $this->settings->get('menu_editor', $key, $default); } private function init_hooks() { if ($this->get_setting('enable_menu_editor')) { // Re-ordering logic add_filter('custom_menu_order', '__return_true'); add_filter('menu_order', [$this, 'apply_menu_order'], PHP_INT_MAX); // Capture menu state BEFORE modifications add_action('admin_menu', [$this, 'capture_menu'], PHP_INT_MAX - 100); // Apply modifications (Hiding/Renaming) add_action('admin_menu', [$this, 'apply_customizations'], PHP_INT_MAX); } } public function capture_menu() { global $menu; if (isset($menu) && is_array($menu)) { $this->full_menu = $menu; } } public function apply_menu_order($menu_order) { $custom_order = $this->get_setting('menu_order', []); if (empty($custom_order) || !is_array($custom_order)) { return $menu_order; } $new_order = []; // 1. Add items from custom order foreach ($custom_order as $slug) { if (in_array($slug, $menu_order)) { $new_order[] = $slug; } } // 2. Append remaining foreach ($menu_order as $slug) { if (!in_array($slug, $new_order)) { $new_order[] = $slug; } } return $new_order; } public function apply_customizations() { global $menu; // Ensure we captured the menu if for some reason capture_menu didn't run or array was empty then if (empty($this->full_menu) && !empty($menu)) { $this->full_menu = $menu; } if (empty($menu)) return; $renames = $this->get_setting('menu_renames', []); $hidden = $this->get_setting('menu_hidden', []); // 1. Hiding if (!empty($hidden)) { foreach ($hidden as $slug) { // Ensure we NEVER hide our own plugin if ($slug === 'admin-menu-optimizer') continue; remove_menu_page($slug); } } // 2. Renaming foreach ($menu as $index => $item) { if (!isset($item[2])) continue; $slug = $item[2]; if (isset($renames[$slug]) && !empty($renames[$slug])) { if (preg_match('//', $item[0], $matches)) { $menu[$index][0] = $renames[$slug] . ' ' . $matches[0]; } else { $menu[$index][0] = $renames[$slug]; } } } } public function get_current_menus() { // Use the captured full menu if available, otherwise fallback to global menu $source_menu = !empty($this->full_menu) ? $this->full_menu : $GLOBALS['menu']; $items = []; if (!empty($source_menu)) { foreach ($source_menu as $item) { if (empty($item[0])) continue; // Skip separators // Clean label: remove notification spans first, then strip tags $raw_label = $item[0]; if (strpos($raw_label, ' $label, 'slug' => $slug, 'icon' => $icon ]; } } return $items; } public function render_settings() { // We need a JS-driven UI here. // We will output the current menu list as JSON in a script tag. $current_menus = $this->get_current_menus(); $saved_order = $this->get_setting('menu_order', []); $saved_renames = $this->get_setting('menu_renames', []); $saved_hidden = $this->get_setting('menu_hidden', []); $enable_editor = $this->get_setting('enable_menu_editor'); echo '
'; echo ''; echo '
'; echo ''; echo '
'; echo '
'; echo '
'; // Pass data to JS // Note: we need to handle sort order. If saved order exists, we should respect it in display. $display_items = []; if (!empty($saved_order)) { // First added saved/ordered items foreach ($saved_order as $slug) { foreach ($current_menus as $key => $menu_item) { if ($menu_item['slug'] === $slug) { $display_items[] = $menu_item; unset($current_menus[$key]); break; } } } } // Append remaining $display_items = array_merge($display_items, $current_menus); echo '
    '; foreach ($display_items as $item) { $slug = $item['slug']; $label = $item['label']; $icon = $item['icon']; $is_hidden = in_array($slug, $saved_hidden); $rename_val = isset($saved_renames[$slug]) ? $saved_renames[$slug] : ''; $is_protected = ($slug === 'admin-menu-optimizer'); echo '
  • '; echo '
    '; echo '
    '; echo '
    '; echo '' . esc_html($label) . ''; echo ''; echo '
    '; echo '
    '; if (!$is_protected) { echo ''; } else { echo ''; } // Hidden input for order echo ''; echo '
    '; echo '
  • '; } echo '
'; echo '
'; echo '

' . esc_html( __('Drag and drop to reorder. Uncheck the eye icon to hide. Enter text to rename.', 'admin-menu-optimizer') ) . '

'; } }