PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.9.8
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.9.8
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.8, at includes/plugins-window/window.php

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