PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.8
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.8
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 / my-wordpress / window.php

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

240 lines 11.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * OpenStation — My WordPress: the explorer's identity + shared helpers.
4 *
5 * The app people open is `apps/my-wordpress/` — WP Explorer, rebuilt
6 * on the App Framework. This module keeps what the port shares: the
7 * name and the folder-mark icon (the app reads both from the helpers
8 * here), the capability gate, and the inert entities compatibility
9 * surface (see the note at the end of the file).
10 *
11 * **The app is called WP Explorer; the module is called my-wordpress.**
12 * The function prefix and every `openstation_my_wordpress_*` filter
13 * are names plugins already reference — the frozen-values rule in
14 * AGENTS.md keeps them put.
15 *
16 * Filterable surface:
17 *
18 * - `openstation_my_wordpress_user_can_use`
19 * - `openstation_my_wordpress_entities` (inert — see the end note)
20 *
21 * (`openstation_my_wordpress_icon_args`, `_window_args` and
22 * `_template_html` went with the legacy window they configured.)
23 *
24 * @package OpenStation
25 */
26
27 defined( 'ABSPATH' ) || exit;
28
29 /**
30 * Display name of the app, for the window title and the pinned icon.
31 *
32 * A file explorer, named after what it explores. The window used to
33 * carry the site title instead, on the reasoning that the desktop holds
34 * objects rather than a mention of the software you are already standing
35 * in — but a site title is what the *root folder* is called, not what
36 * the app is called, and the breadcrumb still says it. The two are no
37 * longer the same string.
38 *
39 * @return string
40 */
41 function openstation_my_wordpress_app_title() {
42 return __( 'WP Explorer', 'desktop-mode' );
43 }
44
45 /**
46 * The app's icon: a folder wearing the WordPress mark.
47 *
48 * The window used to wear `dashicons-wordpress`, the double-ringed
49 * wp.org mark, which said "WordPress" and nothing about what the app
50 * does — every other window here is WordPress too. A folder says
51 * "browse", and the single-ringed mark inside it says whose files.
52 *
53 * Drawn in `currentColor` so both painters mask it: the dock masks
54 * image icons to the rail's own glyph colour so a plugin's brand
55 * colours cannot break the monochrome rail, and `renderIcon()` masks it
56 * to the title bar's text colour. A literal fill would silently turn it
57 * back into a background image in one and a solid blob in the other.
58 *
59 * The folder is outlined rather than filled so the mark inside it stays
60 * a mark: on a filled folder, a same-colour mark is invisible. Hand-
61 * placed at 64×64, the established canvas for the custom icons here,
62 * and held to two shapes because it renders as small as 20px in the
63 * dock. The mark's own path is the upstream single-ringed logo, a
64 * filled disc with the W knocked out by the nonzero fill rule.
65 *
66 * On the sizing: the front panel runs `y 19.1 → 52.1` on the
67 * centreline, so at stroke 3 the clear height inside it is 30 units.
68 * The mark takes 20 of those at scale 1, centred on 35.6, which leaves
69 * five units above and below. It used to be scaled 1.15× for 23 units
70 * and barely three units of clearance, less than one stroke width, and
71 * a disc that close to the panel edge reads as crammed in rather than
72 * placed. Horizontal clearance was never the constraint: the panel is
73 * 50 units wide against the mark's 20.
74 *
75 * @return string Raw `<svg>` markup.
76 */
77 function openstation_my_wordpress_icon_svg() {
78 return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">'
79 // The folder: back tab, notch, front panel, all one outline.
80 . '<path d="M11 13h12.2a3 3 0 0 1 2.4 1.2l2.8 3.7a3 3 0 0 0 2.4 1.2H53a4 4 0 0 1 4 4v25a4 4 0 0 1-4 4H11a4 4 0 0 1-4-4V17a4 4 0 0 1 4-4z"'
81 . ' fill="none" stroke="currentColor" stroke-width="3" stroke-linejoin="round"/>'
82 // The WordPress mark, centred on the front panel at r=10.
83 . '<g transform="translate(22 25.6) scale(1)">'
84 . '<path fill="currentColor" d="M20 10c0-5.51-4.49-10-10-10C4.48 0 0 4.49 0 10c0 5.52 4.48 10 10 10 5.51 0 10-4.48 10-10zM7.78 15.37L4.37 6.22c.55-.02 1.17-.08 1.17-.08.5-.06.44-1.13-.06-1.11 0 0-1.45.11-2.37.11-.18 0-.37 0-.58-.01C4.12 2.69 6.87 1.11 10 1.11c2.33 0 4.45.87 6.05 2.34-.68-.11-1.65.39-1.65 1.58 0 .74.45 1.36.9 2.1.35.61.55 1.36.55 2.46 0 1.49-1.4 5-1.4 5l-3.03-8.37c.54-.02.82-.17.82-.17.5-.05.44-1.25-.06-1.22 0 0-1.44.12-2.38.12-.87 0-2.33-.12-2.33-.12-.5-.03-.56 1.2-.06 1.22l.92.08 1.26 3.41zM17.41 10c.24-.64.74-1.87.43-4.25.7 1.29 1.05 2.71 1.05 4.25 0 3.29-1.73 6.24-4.4 7.78.97-2.59 1.94-5.2 2.92-7.78zM6.1 18.09C3.12 16.65 1.11 13.53 1.11 10c0-1.3.23-2.48.72-3.59C3.25 10.3 4.67 14.2 6.1 18.09zm4.03-6.63l2.58 6.98c-.86.29-1.76.45-2.71.45-.79 0-1.57-.11-2.29-.33.81-2.38 1.62-4.74 2.42-7.1z"/>'
85 . '</g>'
86 . '</svg>';
87 }
88
89 /**
90 * Whether the current user should see My WordPress.
91 *
92 * Mirrors the recycle-bin gate — anyone who can edit posts can
93 * browse posts and pages.
94 *
95 * This is the module's one capability gate, and it is a **server-side
96 * authorization** gate, not just a visibility one. It decides:
97 *
98 * - The non-REST post-type bridge: whether
99 * `desktop-mode/v1/post-type/<slug>` routes register at all
100 * (`rest-post-type.php`).
101 * - The per-comment dossier route
102 * `desktop-mode/v1/comment-stats/<id>` (`comment-stats.php`).
103 * - Whether the WooCommerce integration's boot config ships, so the
104 * client can reach the order / customer / product surfaces at all
105 * — those routes still enforce their own Woo capabilities on top
106 * (`integrations/woocommerce.php`).
107 * - Whether preview-action scripts registered by plugins are
108 * enqueued (`preview-actions.php`).
109 * - Whether Station Home offers the "WP Explorer" quick action
110 * (`apps/station-home/parts/snapshot.php`).
111 *
112 * It does **not** gate the app's own window or pinned launcher: WP
113 * Explorer is an App Framework app and declares
114 * `->capabilities( 'edit_posts' )` itself (`apps/my-wordpress/`).
115 * Returning `true` here opens the surfaces above without opening the
116 * window; to move the window too, filter the app's manifest.
117 *
118 * @return bool
119 */
120 function openstation_my_wordpress_user_can_use() {
121 $can = current_user_can( 'edit_posts' );
122
123 /**
124 * Filter whether the current user can reach the My WordPress
125 * module's surfaces — its REST routes included.
126 *
127 * @param bool $can Default: edit_posts capability.
128 */
129 return (bool) apply_filters( 'openstation_my_wordpress_user_can_use', $can );
130 }
131
132 /**
133 * Build the entity list shipped to the bundle. Posts, Pages,
134 * Users, and Media. Future phases add
135 * Comments, Tags, Categories, Themes, and Plugins.
136 *
137 * The optional `kind` field tells the bundle how to render entries
138 * of this entity: `'post'` (default) renders the standard
139 * title/excerpt/featured-image tile and the rendered-HTML preview;
140 * `'user'` renders an avatar + display-name tile and routes to the
141 * user dossier preview; `'media'` renders a thumbnail-grid tile and
142 * routes to the media preview pane. Plugins extending the entity
143 * list with a post-shaped collection can omit the field; user- and
144 * media-shaped collections must set `'user'` / `'media'`.
145 * The optional `post_type` field specifies the WP post-type
146 * slug used for `os.<slug>.changed` cross-window broadcasts.
147 *
148 * @return array[] Each entry is `array( 'id', 'label', 'icon',
149 * 'restPath', 'kind', 'post_type' )`. `restPath` is appended to
150 * the `restRoot` config to derive the list URL.
151 */
152 function openstation_my_wordpress_entities() {
153 $entities = array(
154 array(
155 'id' => 'posts',
156 'label' => __( 'Posts', 'desktop-mode' ),
157 'icon' => 'dashicons-admin-post',
158 'restPath' => 'wp/v2/posts',
159 'kind' => 'post',
160 'post_type' => 'post',
161 ),
162 array(
163 'id' => 'pages',
164 'label' => __( 'Pages', 'desktop-mode' ),
165 'icon' => 'dashicons-admin-page',
166 'restPath' => 'wp/v2/pages',
167 'kind' => 'post',
168 'post_type' => 'page',
169 ),
170 array(
171 'id' => 'users',
172 'label' => __( 'Users', 'desktop-mode' ),
173 'icon' => 'dashicons-admin-users',
174 'restPath' => 'wp/v2/users',
175 'kind' => 'user',
176 ),
177 array(
178 'id' => 'media',
179 'label' => __( 'Media', 'desktop-mode' ),
180 'icon' => 'dashicons-admin-media',
181 'restPath' => 'wp/v2/media',
182 'kind' => 'media',
183 'post_type' => 'attachment',
184 ),
185 );
186
187 /**
188 * Filter the list of entity types shown inside the My WordPress
189 * window. Each entry must declare `id`, `label`, `icon`, and
190 * `restPath`. Returning a reordered or extended array shows up
191 * in the bundle on the next render.
192 *
193 * **Status: Experimental** — the entity descriptor shape may
194 * gain fields as new entity kinds land (Comments, Tags,
195 * Categories, Themes, Plugins). Stable id/label/icon/restPath
196 * fields will continue to work; new optional fields will not
197 * break existing consumers. The `kind` field is optional and
198 * defaults to `'post'` for back-compat.
199 *
200 * Optional fields:
201 * - `kind` — render strategy (`'post'` default, `'user'`, `'media'`).
202 * - `post_type` — WP post-type slug for cross-window broadcast topic `os.<slug>.changed`.
203 * - `thumbnails` — set false to keep the section icon on every tile
204 * instead of the entity's featured image.
205 * - `editAction` — who edits this section's rows. A preview-action id
206 * (see `openstation_my_wordpress_preview_actions`)
207 * replaces "Open in editor" everywhere — pane button,
208 * context-menu open entry, tile double-click. `false`
209 * removes every edit affordance (double-click falls
210 * back to the detail dossier; the bulk "Edit…" modal
211 * is suppressed). Omit for the classic editor.
212 * - `group` — folder id this section nests under at the root
213 * (null / omitted renders it loose at the root).
214 * - `groupLabel` — folder label. `groupIcon`, `groupOrder` follow.
215 *
216 * @param array[] $entities Default entities.
217 */
218 $filtered = apply_filters( 'openstation_my_wordpress_entities', $entities );
219 return is_array( $filtered ) ? array_values( $filtered ) : $entities;
220 }
221
222 /*
223 * No window, no template, no launcher. The explorer people open is
224 * the `my-wordpress` APP (`apps/my-wordpress/`), which reclaimed the
225 * "WP Explorer" name and the folder mark from this module's helpers
226 * above. The legacy native window, its bundle and its pinned icon are
227 * gone; every deep surface it used to host moved with the port — the
228 * detail dossiers and the activity footprint render inside the app,
229 * "open this object" travels through the shared stores in
230 * `src/open-targets/explorer-open.ts` / `footprint-target.ts`, and
231 * the Recycle Bin trashes dropped rows by their payload's `restPath`.
232 *
233 * `openstation_my_wordpress_entities()` and its filter remain as an
234 * inert compatibility surface: subscribers registered against them
235 * (WooCommerce's own among them) still run, and the pure helpers are
236 * still what the tests pin — but nothing consumes the list to build a
237 * window any more. The `openstation_my_wordpress_window_args` /
238 * `openstation_my_wordpress_template_html` filters no longer fire.
239 */
240