*/ private static array $hosts = []; /** * Let a screen host the notice. * * The hooks are static callbacks, so a second screen registering adds itself to the host list * without adding the actions twice — add_action() keys on the callback. * * @param string $page_slug The screen's own `page` slug, e.g. 'wpwand-bulk-new'. */ public static function register(string $page_slug): void { if ($page_slug === '') { return; } self::$hosts[$page_slug] = true; add_action('admin_init', [self::class, 'maybe_dismiss']); add_action('admin_notices', [self::class, 'maybe_render']); } /** * "Dismiss" was clicked: forget the switch and reload without the spent parameter, so a refresh * or a back button never replays it. */ public static function maybe_dismiss(): void { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- the nonce is what this reads. $nonce = isset($_GET[self::DISMISS_ARG]) ? sanitize_text_field(wp_unslash((string) $_GET[self::DISMISS_ARG])) : ''; // Not our request. This hook runs on nearly every admin page load, so leave at once. if ($nonce === '') { return; } if (!current_user_can('edit_posts') || !wp_verify_nonce($nonce, self::NONCE_ACTION)) { return; } Failover::dismiss_notice(); wp_safe_redirect(esc_url_raw(remove_query_arg(self::DISMISS_ARG))); exit; } /** Print it, if there is something to say and this is a screen that says it. */ public static function maybe_render(): void { if (!current_user_can('edit_posts') || !self::on_host_screen()) { return; } $notice = Failover::notice(); $message = isset($notice['message']) ? (string) $notice['message'] : ''; if ($message === '') { return; } // 'warning' is a key that stopped working; everything else is informational — the post still // got written, just somewhere else. $severity = (isset($notice['severity']) && $notice['severity'] === 'warning') ? 'warning' : 'info'; printf( '

%2$s

%4$s %6$s

', esc_attr($severity), esc_html($message), esc_url(admin_url('admin.php?page=wpwand')), esc_html__('Open settings', 'ai-content-generation'), esc_url(self::dismiss_url()), esc_html__('Dismiss', 'ai-content-generation') ); } /** * Is this one of the screens that asked to host the notice? * * Matched on the tail of the screen id rather than the whole thing: the id is built from the * parent menu's title, which the white-label settings can change. */ private static function on_host_screen(): bool { if (self::$hosts === [] || !function_exists('get_current_screen')) { return false; } $screen = get_current_screen(); if (!$screen || !isset($screen->id)) { return false; } $id = (string) $screen->id; foreach (array_keys(self::$hosts) as $slug) { if (substr($id, -strlen($slug)) === $slug) { return true; } } return false; } /** This same screen, plus the dismiss parameter and its nonce. */ private static function dismiss_url(): string { return wp_nonce_url( remove_query_arg(self::DISMISS_ARG), self::NONCE_ACTION, self::DISMISS_ARG ); } }