# desktop-mode/1.1.8/includes/plugin-notices.php

OpenStation: Desktop Windows, Dock &amp; Virtual Desktops for WP Admin, version 1.1.8. 148 lines.

- Page: https://pluginprobe.com/plugins/desktop-mode/1.1.8/code/includes/plugin-notices.php
- Raw: https://pluginprobe.com/plugins/desktop-mode/1.1.8/raw/includes/plugin-notices.php
- Modified: 2026-08-07T20:39:04+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/desktop-mode/1.1.8/code/includes/plugin-notices.php#L10-L20`.

```php
<?php
/**
 * A small, opt-in allowlist of well-known *library* admin notices that render
 * globally (so they repeat in every desktop window) and can be re-derived from
 * authoritative state. Unlike arbitrary plugin `admin_notices` — which we
 * deliberately leave alone — these are shared
 * libraries bundled across many plugins, common enough to warrant a targeted
 * case. Each entry is detached in-window and surfaced once in the shell, the
 * same pattern as the core notices.
 *
 * @package OpenStation
 */

defined( 'ABSPATH' ) || exit;

/**
 * The allowlisted plugin/library notices for the current user, as shell
 * descriptors (same shape as `openstation_get_core_notices()`).
 *
 * @return array<int,array{id:string,title:string,message:string,actionLabel:string,actionUrl:string}>
 */
function openstation_get_plugin_notices() {
	$builders = array(
		'openstation_plugin_notice_action_scheduler',
	);

	$notices = array();
	foreach ( $builders as $builder ) {
		$notice = $builder();
		if ( $notice ) {
			$notices[] = $notice;
		}
	}

	/**
	 * Filters the allowlisted plugin/library notices surfaced once in the
	 * desktop shell. Return an empty array to suppress them all, or unset
	 * individual entries by `id`.
	 *
	 * @param array $notices List of notice descriptors.
	 */
	return apply_filters( 'openstation_plugin_notices', $notices );
}

/**
 * Action Scheduler's "N past-due actions found" warning — bundled by
 * WooCommerce, Jetpack, and many other plugins, and printed globally on
 * `admin_notices` (with no throttle while past-due actions exist, so it
 * repeats in every window). Re-derived here from Action Scheduler's own store,
 * mirroring `ActionScheduler_AdminView::check_pastdue_actions()` including its
 * filters, so the count matches what Action Scheduler would show.
 *
 * @return array|null
 */
function openstation_plugin_notice_action_scheduler() {
	// Every filter applied below is Action Scheduler's own. Mirroring its
	// check means honouring the same extension points a site has already
	// hooked; prefixing them would consult filters nobody implements and
	// silently diverge from the count Action Scheduler itself shows.
	// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
	if ( ! class_exists( 'ActionScheduler_Store' ) || ! function_exists( 'as_get_datetime_object' ) ) {
		return null;
	}

	// Capability gate — mirrors `action_scheduler_check_pastdue_actions`.
	if ( ! apply_filters( 'action_scheduler_check_pastdue_actions', current_user_can( 'manage_options' ) ) ) {
		return null;
	}

	$threshold_seconds = (int) apply_filters( 'action_scheduler_pastdue_actions_seconds', DAY_IN_SECONDS );
	$threshold_min     = (int) apply_filters( 'action_scheduler_pastdue_actions_min', 1 );

	// A third party can preempt Action Scheduler's own check; when it does the
	// count is opaque, so mirror Action Scheduler and don't surface.
	if ( ! is_null( apply_filters( 'action_scheduler_pastdue_actions_check_pre', null ) ) ) {
		return null;
	}

	$query_args = array(
		'date'     => as_get_datetime_object( time() - $threshold_seconds ),
		'status'   => ActionScheduler_Store::STATUS_PENDING,
		'per_page' => $threshold_min,
	);

	$count = (int) ActionScheduler_Store::instance()->query_actions( $query_args, 'count' );

	$check = (bool) apply_filters(
		'action_scheduler_pastdue_actions_check',
		$count >= $threshold_min,
		$count,
		$threshold_seconds,
		$threshold_min
	);
	if ( ! $check ) {
		return null;
	}
	// phpcs:enable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

	$url = add_query_arg(
		array(
			'page'   => 'action-scheduler',
			'status' => 'past-due',
			'order'  => 'asc',
		),
		admin_url( 'tools.php' )
	);

	return array(
		'id'          => 'action-scheduler-pastdue',
		'title'       => __( 'Scheduled Actions', 'desktop-mode' ),
		'message'     => sprintf(
			/* translators: %d: number of past-due scheduled actions. */
			_n(
				'Action Scheduler: %d past-due action found; something may be wrong.',
				'Action Scheduler: %d past-due actions found; something may be wrong.',
				$count,
				'desktop-mode'
			),
			$count
		),
		'actionLabel' => __( 'View actions', 'desktop-mode' ),
		'actionUrl'   => $url,
	);
}

/**
 * Detaches the allowlisted plugin/library notices inside chromeless iframes so
 * they don't repeat in every window — the shell surfaces each once (see
 * `openstation_get_plugin_notices()`).
 */
function openstation_chromeless_suppress_plugin_notices() {
	if ( ! openstation_is_chromeless_request() ) {
		return;
	}

	// Action Scheduler registers the notice as an instance method on its
	// `ActionScheduler_AdminView` singleton (during `init`, before this runs).
	// Detect the actual priority it registered at rather than assuming 10.
	if ( class_exists( 'ActionScheduler_AdminView' ) ) {
		$callback = array( ActionScheduler_AdminView::instance(), 'maybe_check_pastdue_actions' );
		$priority = has_action( 'admin_notices', $callback );
		if ( false !== $priority ) {
			remove_action( 'admin_notices', $callback, $priority );
		}
	}
}
add_action( 'admin_init', 'openstation_chromeless_suppress_plugin_notices' );

```
