loader->addAction('admin_menu', $this, 'addMenuPage', 99); } /** * Concrete subclasses call add_menu_page / add_submenu_page here. */ abstract public function addMenuPage(): void; /** * WordPress safe redirect helper. * * @param string $menuSlug * * @return void */ protected function safeRedirect(string $menuSlug): void { // Mirrors FormGenerator::safeRedirect()'s CLI guard: under PHPUnit (CLI // SAPI), redirecting via exit() would kill the test process before any // assertion runs. In CLI mode this is a no-op instead, so a handler's // side effects (or lack thereof) up to this point remain assertable. if (php_sapi_name() === 'cli') { return; } wp_safe_redirect( esc_url( site_url('/wp-admin/admin.php?page=' . $menuSlug) ) ); exit(); } }