PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.9.0
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.9.0
1.1.10 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 All 34 releases
desktop-mode / includes / plugins-window / window.php

window.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 0.9.0, at includes/plugins-window/window.php

200 lines 8.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Desktop Mode — Native Plugins Window: registration + template.
4 *
5 * Native window registered with `placement: 'none'` — the entry
6 * point is the existing Plugins dock tile (built from WordPress's
7 * `$menu`), which the JS-side URL remap rewrites to open this window
8 * when `nativePluginsEnabled` is on.
9 *
10 * The shell wraps the template echoed by
11 * `desktop_mode_plugins_window_render_template()` in
12 * `<template id="desktop-mode-native-window-desktop-mode-plugins">`
13 * and clones it into the window body BEFORE the JS render callback
14 * fires. The `data-desktop-mode-plugins-*` hooks below are the
15 * contract the JS relies on — keep them intact (or rename via the
16 * filter) when customizing the layout.
17 *
18 * @package WPDesktopMode
19 * @since 0.9.0
20 */
21
22 defined( 'ABSPATH' ) || exit;
23
24 /**
25 * Echoes the native Plugins window's template body.
26 *
27 * @since 0.9.0
28 */
29 function desktop_mode_plugins_window_render_template() {
30 $caps = desktop_mode_plugins_window_caps();
31
32 ob_start();
33 ?>
34 <div class="desktop-mode-plugins" data-desktop-mode-plugins-root>
35 <wpd-tabs value="installed" class="desktop-mode-plugins__tabs" data-desktop-mode-plugins-tabs>
36 <wpd-tab value="installed"><?php esc_html_e( 'Installed', 'desktop-mode' ); ?></wpd-tab>
37 <?php if ( ! empty( $caps['install'] ) ) : ?>
38 <wpd-tab value="browse"><?php esc_html_e( 'Add Plugin', 'desktop-mode' ); ?></wpd-tab>
39 <wpd-tab value="featured"><?php esc_html_e( 'Desktop Mode plugins', 'desktop-mode' ); ?></wpd-tab>
40 <?php endif; ?>
41 </wpd-tabs>
42
43 <wpd-tabpanel for="installed" class="desktop-mode-plugins__panel">
44 <div class="desktop-mode-plugins__installed" data-desktop-mode-plugins-installed-host>
45 <?php /* JS bundle paints the toolbar + <wpd-table> here.
46 Empty host — first-frame shows the table's own
47 loading skeleton. */ ?>
48 </div>
49 </wpd-tabpanel>
50
51 <?php if ( ! empty( $caps['install'] ) ) : ?>
52 <wpd-tabpanel for="browse" class="desktop-mode-plugins__panel">
53 <div class="desktop-mode-plugins__browse" data-desktop-mode-plugins-browse-host>
54 <?php /* JS bundle paints the search + segmented filter
55 + Upload button + <wpd-grid> of cards here. */ ?>
56 </div>
57 </wpd-tabpanel>
58 <wpd-tabpanel for="featured" class="desktop-mode-plugins__panel">
59 <div class="desktop-mode-plugins__featured" data-desktop-mode-plugins-featured-host>
60 <?php /* JS bundle paints an intro blurb + gallery of
61 plugins that integrate with Desktop Mode here. */ ?>
62 </div>
63 </wpd-tabpanel>
64 <?php endif; ?>
65
66 <?php /* Detail flyout — populated lazily when a card is clicked.
67 Lives at the root of the template so it can slide over the
68 full window body, not just one tab panel. */ ?>
69 <wpd-flyout
70 placement="end"
71 data-desktop-mode-plugins-flyout
72 aria-label="<?php esc_attr_e( 'Plugin details', 'desktop-mode' ); ?>"
73 ></wpd-flyout>
74 </div>
75 <?php
76 $html = (string) ob_get_clean();
77
78 /**
79 * Filter the native Plugins window's template HTML.
80 *
81 * Keep the `data-desktop-mode-plugins-*` hooks intact so the JS
82 * render callback can find its mount points, or rename them and
83 * update the matching constants in `src/plugins-window/index.ts`.
84 *
85 * @since 0.9.0
86 *
87 * @param string $html Default template HTML.
88 */
89 $filtered = (string) apply_filters( 'desktop_mode_plugins_window_template_html', $html );
90
91 if ( function_exists( 'desktop_mode_kses_native_window_template' ) ) {
92 echo desktop_mode_kses_native_window_template( $filtered ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- helper kses-escapes.
93 } else {
94 echo wp_kses( $filtered, wp_kses_allowed_html( 'post' ) );
95 }
96 }
97
98 /**
99 * Register the native Plugins window on `init` (priority 20, after
100 * `components.php` has bootstrapped the registry).
101 *
102 * Cap-only gate so that flipping the opt-in mid-session doesn't
103 * require an F5. The opt-in is a runtime check on the JS-side remap
104 * (`enabled: ( s ) => s.nativePluginsEnabled === true` in
105 * `src/desktop.ts`).
106 *
107 * @since 0.9.0
108 */
109 function desktop_mode_plugins_window_register_window() {
110 if ( ! desktop_mode_plugins_window_user_can_register() ) {
111 return;
112 }
113
114 $caps = desktop_mode_plugins_window_caps();
115
116 $window_args = array(
117 'title' => __( 'Plugins', 'desktop-mode' ),
118 'icon' => 'dashicons-admin-plugins',
119 'template' => 'desktop_mode_plugins_window_render_template',
120 'script' => 'desktop-mode-plugins-window',
121 'style' => 'desktop-mode-plugins-window',
122 'width' => 1180,
123 'height' => 760,
124 'min_width' => 760,
125 'min_height' => 480,
126 // `'none'` — no dock or wallpaper tile from this registration.
127 // The Plugins dock tile lives in WordPress's `$menu` and the
128 // JS-side URL remap routes its click to `openById` here when
129 // the opt-in is on. A separate tile would be a duplicate
130 // entry point.
131 'placement' => 'none',
132 'config' => array(
133 'restRoot' => esc_url_raw( rest_url() ),
134 'restNonce' => wp_create_nonce( 'wp_rest' ),
135 // Core's REST controller for installed plugins.
136 'pluginsUrl' => esc_url_raw( rest_url( 'wp/v2/plugins' ) ),
137 // `admin-ajax.php` is the canonical home for our
138 // install/upload/browse/info/reviews handlers — Plugin Check
139 // rejects calls to admin-only classes from REST callbacks.
140 'ajaxUrl' => esc_url_raw( admin_url( 'admin-ajax.php' ) ),
141 'ajaxNonce' => wp_create_nonce( 'desktop-mode-plugins' ),
142 // Core's `wp_ajax_install_plugin` (and friends) verify
143 // against the `'updates'` nonce action — same string Core's
144 // wp.updates client passes. We reuse it verbatim so we go
145 // through Core's existing handler, no reimplementation.
146 'updatesNonce' => wp_create_nonce( 'updates' ),
147 'caps' => $caps,
148 // Global "Automatic Updates" column gate — same shape Core's
149 // `WP_Plugins_List_Table::$show_autoupdates` uses (true only
150 // when the auto-update subsystem is enabled AND the viewer
151 // can update plugins). Per-row state still lives on the REST
152 // field `desktop_mode_auto_update` so the JS knows whether
153 // each individual row is enabled / forced / supported.
154 'autoUpdatesEnabled' => desktop_mode_plugins_window_auto_updates_enabled(),
155 'currentUserId' => (int) get_current_user_id(),
156 'introSeen' => function_exists( 'desktop_mode_has_seen_intro' )
157 ? desktop_mode_has_seen_intro( get_current_user_id(), 'plugins' )
158 : true,
159 'introUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/intros/seen' ) ),
160 // The plugin file path WordPress uses to identify the
161 // Desktop Mode plugin itself in REST mutations
162 // (`/wp/v2/plugins/{plugin}`). The JS uses this to detect
163 // "user just deactivated/deleted us" and reload the page
164 // out of the now-stale desktop shell before they hit any
165 // dead UI.
166 //
167 // Stripped of `.php` to match Core's REST representation —
168 // the `/wp/v2/plugins` controller returns `plugin` as
169 // `substr( $file, 0, -4 )` (see
170 // `wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php`).
171 // Comparing the raw `plugin_basename()` against the REST
172 // field always missed by exactly four characters, which
173 // silently skipped the self-deactivate reload.
174 'selfPluginFile' => substr( plugin_basename( DESKTOP_MODE_FILE ), 0, -4 ),
175 // The wp-admin root URL — the JS navigates here after a
176 // self-deactivate so the user lands on the classic
177 // Dashboard rather than reloading their current URL
178 // (which might be a deactivated plugin's `?page=…` route
179 // that now 403s).
180 'adminUrl' => esc_url_raw( admin_url() ),
181 ),
182 );
183
184 /**
185 * Filter the args used to register the native Plugins window.
186 *
187 * @since 0.9.0
188 *
189 * @param array $window_args Args passed to `desktop_mode_register_window()`.
190 */
191 $window_args = (array) apply_filters( 'desktop_mode_plugins_window_args', $window_args );
192
193 $registered = desktop_mode_register_window( 'desktop-mode-plugins', $window_args );
194 if ( is_wp_error( $registered ) ) {
195 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
196 error_log( '[desktop-mode] Native Plugins window registration failed: ' . $registered->get_error_message() );
197 }
198 }
199 add_action( 'init', 'desktop_mode_plugins_window_register_window', 20 );
200