PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.9
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.9
1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 0.8.7 0.8.6 All 33 releases
desktop-mode / includes / plugin-notices.php

plugin-notices.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 1.1.9, at includes/plugin-notices.php

148 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * A small, opt-in allowlist of well-known *library* admin notices that render
4 * globally (so they repeat in every desktop window) and can be re-derived from
5 * authoritative state. Unlike arbitrary plugin `admin_notices` — which we
6 * deliberately leave alone — these are shared
7 * libraries bundled across many plugins, common enough to warrant a targeted
8 * case. Each entry is detached in-window and surfaced once in the shell, the
9 * same pattern as the core notices.
10 *
11 * @package OpenStation
12 */
13
14 defined( 'ABSPATH' ) || exit;
15
16 /**
17 * The allowlisted plugin/library notices for the current user, as shell
18 * descriptors (same shape as `openstation_get_core_notices()`).
19 *
20 * @return array<int,array{id:string,title:string,message:string,actionLabel:string,actionUrl:string}>
21 */
22 function openstation_get_plugin_notices() {
23 $builders = array(
24 'openstation_plugin_notice_action_scheduler',
25 );
26
27 $notices = array();
28 foreach ( $builders as $builder ) {
29 $notice = $builder();
30 if ( $notice ) {
31 $notices[] = $notice;
32 }
33 }
34
35 /**
36 * Filters the allowlisted plugin/library notices surfaced once in the
37 * desktop shell. Return an empty array to suppress them all, or unset
38 * individual entries by `id`.
39 *
40 * @param array $notices List of notice descriptors.
41 */
42 return apply_filters( 'openstation_plugin_notices', $notices );
43 }
44
45 /**
46 * Action Scheduler's "N past-due actions found" warning — bundled by
47 * WooCommerce, Jetpack, and many other plugins, and printed globally on
48 * `admin_notices` (with no throttle while past-due actions exist, so it
49 * repeats in every window). Re-derived here from Action Scheduler's own store,
50 * mirroring `ActionScheduler_AdminView::check_pastdue_actions()` including its
51 * filters, so the count matches what Action Scheduler would show.
52 *
53 * @return array|null
54 */
55 function openstation_plugin_notice_action_scheduler() {
56 // Every filter applied below is Action Scheduler's own. Mirroring its
57 // check means honouring the same extension points a site has already
58 // hooked; prefixing them would consult filters nobody implements and
59 // silently diverge from the count Action Scheduler itself shows.
60 // phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
61 if ( ! class_exists( 'ActionScheduler_Store' ) || ! function_exists( 'as_get_datetime_object' ) ) {
62 return null;
63 }
64
65 // Capability gate — mirrors `action_scheduler_check_pastdue_actions`.
66 if ( ! apply_filters( 'action_scheduler_check_pastdue_actions', current_user_can( 'manage_options' ) ) ) {
67 return null;
68 }
69
70 $threshold_seconds = (int) apply_filters( 'action_scheduler_pastdue_actions_seconds', DAY_IN_SECONDS );
71 $threshold_min = (int) apply_filters( 'action_scheduler_pastdue_actions_min', 1 );
72
73 // A third party can preempt Action Scheduler's own check; when it does the
74 // count is opaque, so mirror Action Scheduler and don't surface.
75 if ( ! is_null( apply_filters( 'action_scheduler_pastdue_actions_check_pre', null ) ) ) {
76 return null;
77 }
78
79 $query_args = array(
80 'date' => as_get_datetime_object( time() - $threshold_seconds ),
81 'status' => ActionScheduler_Store::STATUS_PENDING,
82 'per_page' => $threshold_min,
83 );
84
85 $count = (int) ActionScheduler_Store::instance()->query_actions( $query_args, 'count' );
86
87 $check = (bool) apply_filters(
88 'action_scheduler_pastdue_actions_check',
89 $count >= $threshold_min,
90 $count,
91 $threshold_seconds,
92 $threshold_min
93 );
94 if ( ! $check ) {
95 return null;
96 }
97 // phpcs:enable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
98
99 $url = add_query_arg(
100 array(
101 'page' => 'action-scheduler',
102 'status' => 'past-due',
103 'order' => 'asc',
104 ),
105 admin_url( 'tools.php' )
106 );
107
108 return array(
109 'id' => 'action-scheduler-pastdue',
110 'title' => __( 'Scheduled Actions', 'desktop-mode' ),
111 'message' => sprintf(
112 /* translators: %d: number of past-due scheduled actions. */
113 _n(
114 'Action Scheduler: %d past-due action found; something may be wrong.',
115 'Action Scheduler: %d past-due actions found; something may be wrong.',
116 $count,
117 'desktop-mode'
118 ),
119 $count
120 ),
121 'actionLabel' => __( 'View actions', 'desktop-mode' ),
122 'actionUrl' => $url,
123 );
124 }
125
126 /**
127 * Detaches the allowlisted plugin/library notices inside chromeless iframes so
128 * they don't repeat in every window — the shell surfaces each once (see
129 * `openstation_get_plugin_notices()`).
130 */
131 function openstation_chromeless_suppress_plugin_notices() {
132 if ( ! openstation_is_chromeless_request() ) {
133 return;
134 }
135
136 // Action Scheduler registers the notice as an instance method on its
137 // `ActionScheduler_AdminView` singleton (during `init`, before this runs).
138 // Detect the actual priority it registered at rather than assuming 10.
139 if ( class_exists( 'ActionScheduler_AdminView' ) ) {
140 $callback = array( ActionScheduler_AdminView::instance(), 'maybe_check_pastdue_actions' );
141 $priority = has_action( 'admin_notices', $callback );
142 if ( false !== $priority ) {
143 remove_action( 'admin_notices', $callback, $priority );
144 }
145 }
146 }
147 add_action( 'admin_init', 'openstation_chromeless_suppress_plugin_notices' );
148