dashboard_page = new DashboardPage( $store, $density_store ); $this->crawler_log_page = new CrawlerLogPage( $store ); $this->robots_audit_page = new RobotsAuditPage( $robots ); $this->schema_page = new SchemaPage(); $this->answer_density_page = new AnswerDensityPage( $density_store ); $this->conflict_detector_page = new ConflictDetectorPage(); $this->settings = new Settings(); } /** * Attaches the admin hooks. * * Both hooks only ever fire on an admin request, so this is safe to call * unconditionally from the bootstrap and keeps the composition in one place * rather than behind an `is_admin()` branch that would have to be repeated. * * @since 1.1.0 * * @return void */ public function register_hooks() { add_action( 'admin_menu', array( $this, 'register_pages' ) ); add_action( 'admin_init', array( $this->settings, 'register_settings' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'maybe_enqueue_answer_density_assets' ) ); } /** * Registers the menu parent and its screens. * * The capability passed to each registration controls who sees the menu * entry. Each page callback re-checks it, because a callback is reachable by * URL whether or not its menu entry was rendered. * * @since 1.1.0 * * @return void */ public function register_pages() { add_menu_page( __( 'SummitCite', 'summitcite' ), __( 'SummitCite', 'summitcite' ), self::CAPABILITY, DashboardPage::PAGE_SLUG, array( $this->dashboard_page, 'render' ), 'dashicons-chart-line' ); /* * Registered against the parent's own slug so the submenu reads * "Dashboard" instead of repeating the parent's title, which is what * WordPress shows for a parent with no matching submenu entry. */ add_submenu_page( DashboardPage::PAGE_SLUG, __( 'SummitCite Dashboard', 'summitcite' ), __( 'Dashboard', 'summitcite' ), self::CAPABILITY, DashboardPage::PAGE_SLUG, array( $this->dashboard_page, 'render' ) ); add_submenu_page( DashboardPage::PAGE_SLUG, __( 'AI Crawler Log', 'summitcite' ), __( 'Crawler Log', 'summitcite' ), self::CAPABILITY, CrawlerLogPage::PAGE_SLUG, array( $this->crawler_log_page, 'render' ) ); add_submenu_page( DashboardPage::PAGE_SLUG, __( 'SummitCite Robots Audit', 'summitcite' ), __( 'Robots Audit', 'summitcite' ), self::CAPABILITY, RobotsAuditPage::PAGE_SLUG, array( $this->robots_audit_page, 'render' ) ); add_submenu_page( DashboardPage::PAGE_SLUG, __( 'SummitCite Schema', 'summitcite' ), __( 'Schema', 'summitcite' ), self::CAPABILITY, SchemaPage::PAGE_SLUG, array( $this->schema_page, 'render' ) ); $this->answer_density_hook = add_submenu_page( DashboardPage::PAGE_SLUG, __( 'SummitCite Answer Density', 'summitcite' ), __( 'Answer Density', 'summitcite' ), self::CAPABILITY, AnswerDensityPage::PAGE_SLUG, array( $this->answer_density_page, 'render' ) ); /* * Gated on the module's own enable setting, unlike every other screen * in this tree: the product contract requires that disabling the * Conflict Detector removes its menu entry entirely, not merely show a * "switched off" notice on an otherwise reachable screen. */ if ( Helpers::is_module_enabled( ConflictDetector::SLUG ) ) { add_submenu_page( DashboardPage::PAGE_SLUG, __( 'SummitCite Conflict Detector', 'summitcite' ), __( 'Conflict Detector', 'summitcite' ), self::CAPABILITY, ConflictDetectorPage::PAGE_SLUG, array( $this->conflict_detector_page, 'render' ) ); } add_submenu_page( DashboardPage::PAGE_SLUG, __( 'SummitCite Settings', 'summitcite' ), __( 'Settings', 'summitcite' ), self::CAPABILITY, Settings::PAGE_SLUG, array( $this->settings, 'render' ) ); } /** * Enqueues the Answer Density screen's own script, on that screen only. * * The increment adds zero frontend JavaScript; this is the one admin * script it adds, and the hook suffix check is what keeps it off every * other admin screen. * * @since 1.5.0 * * @param string|mixed $hook_suffix Current admin page's hook suffix. * @return void */ public function maybe_enqueue_answer_density_assets( $hook_suffix ) { if ( false === $this->answer_density_hook || $hook_suffix !== $this->answer_density_hook ) { return; } $this->answer_density_page->enqueue_assets(); } /** * Returns the Dashboard screen. * * @since 1.7.0 * * @return DashboardPage Dashboard screen. */ public function dashboard_page() { return $this->dashboard_page; } /** * Returns the Crawler Log screen. * * @since 1.1.0 * * @return CrawlerLogPage Crawler Log screen. */ public function crawler_log_page() { return $this->crawler_log_page; } /** * Returns the Robots Audit screen. * * @since 1.2.0 * * @return RobotsAuditPage Robots Audit screen. */ public function robots_audit_page() { return $this->robots_audit_page; } /** * Returns the Schema screen. * * @since 1.3.0 * * @return SchemaPage Schema screen. */ public function schema_page() { return $this->schema_page; } /** * Returns the Answer Density screen. * * @since 1.5.0 * * @return AnswerDensityPage Answer Density screen. */ public function answer_density_page() { return $this->answer_density_page; } /** * Returns the Conflict Detector screen. * * @since 1.6.0 * * @return ConflictDetectorPage Conflict Detector screen. */ public function conflict_detector_page() { return $this->conflict_detector_page; } /** * Returns the settings screen. * * @since 1.1.0 * * @return Settings Settings screen. */ public function settings() { return $this->settings; } }