settings_page = $settings_page; $this->status_page = $status_page; $this->files_page = $files_page; $this->about_page = $about_page; $this->first_run_page = $first_run_page; $this->help_page = $help_page; } public function init() { add_action('admin_menu', [$this, 'register_menus']); } public function register_menus() { // 1. Create Top-Level Menu // Slug: Using 'active-twist-seo-status' to ensure Status is the default landing page. // Label: Active Twist SEO add_menu_page( esc_html__('Active Twist SEO', 'active-twist-seo-json-ld'), esc_html__('Active Twist SEO', 'active-twist-seo-json-ld'), 'manage_options', 'active-twist-seo-status', [$this->status_page, 'render_page'], 'dashicons-chart-area', 80 ); // Check First Run State $first_run_complete = Options::get('first_run_complete'); if (!$first_run_complete) { // Add First Run Submenu (Top Priority) add_submenu_page( 'active-twist-seo-status', esc_html__('First Run', 'active-twist-seo-json-ld'), esc_html__('First Run', 'active-twist-seo-json-ld'), 'manage_options', 'active-twist-seo-first-run', [$this->first_run_page, 'render_page'] ); } // 2. Add Status Submenu // Parent: active-twist-seo-status // Slug: active-twist-seo-status (Same as parent) // Label: Status // This will override the first submenu item (Active Twist SEO) to be "Status" // IF First Run is present, this actually becomes the second item, and First Run becomes the default slightly awkwardly // unless we change the parent slug logic. // Actually, if we want First Run to be the default when active, we should probably change the main menu callback or slug order. // But simply adding it as a submenu is enough for visibility per the requirement "appears at the top of the plugin menu". add_submenu_page( 'active-twist-seo-status', esc_html__('Active Twist SEO Status', 'active-twist-seo-json-ld'), esc_html__('Status', 'active-twist-seo-json-ld'), 'manage_options', 'active-twist-seo-status', [$this->status_page, 'render_page'] ); // 3. Add Files Submenu // Parent: active-twist-seo-status // Slug: active-twist-seo-files // Label: Files add_submenu_page( 'active-twist-seo-status', esc_html__('Active Twist SEO Files', 'active-twist-seo-json-ld'), esc_html__('Files', 'active-twist-seo-json-ld'), 'manage_options', 'active-twist-seo-files', [$this->files_page, 'render_page'] ); // 4. Add Settings Submenu // Parent: active-twist-seo-status // Slug: active-twist-seo (Legacy compatibility) // Label: Settings add_submenu_page( 'active-twist-seo-status', esc_html__('Active Twist SEO Settings', 'active-twist-seo-json-ld'), esc_html__('Settings', 'active-twist-seo-json-ld'), 'manage_options', 'active-twist-seo', [$this->settings_page, 'render_page'] ); // 5. Add Help Submenu // Parent: active-twist-seo-status // Slug: active-twist-seo-help // Label: Help add_submenu_page( 'active-twist-seo-status', esc_html__('Active Twist SEO Help', 'active-twist-seo-json-ld'), esc_html__('Help', 'active-twist-seo-json-ld'), 'manage_options', 'active-twist-seo-help', [$this->help_page, 'render_page'] ); // 5. Add About Submenu // Parent: active-twist-seo-status // Slug: active-twist-seo-about // Label: About // Rule: Must always be last in the plugin menu. add_submenu_page( 'active-twist-seo-status', esc_html__('About Active Twist SEO', 'active-twist-seo-json-ld'), esc_html__('About', 'active-twist-seo-json-ld'), 'manage_options', 'active-twist-seo-about', [$this->about_page, 'render_page'] ); } }