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 / content-graph / window.php

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

248 lines 9.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * OpenStation — Content Graph: window + desktop icon registration.
4 *
5 * Filterable surface (mirrors the my-wordpress module shape):
6 *
7 * - `openstation_content_graph_window_args`
8 * - `openstation_content_graph_icon_args`
9 * - `openstation_content_graph_user_can_use`
10 * - `openstation_content_graph_post_types`
11 * - `openstation_content_graph_template_html`
12 *
13 * @package OpenStation
14 */
15
16 defined( 'ABSPATH' ) || exit;
17
18 /**
19 * The Corkboard SVG, shared by the window icon and the desktop icon.
20 *
21 * The thread is the window's actual subject: the links between pieces
22 * of content. That reading is unchanged and is why this icon exists at
23 * all. What changed is everything drawn around it.
24 *
25 * The previous version framed two pinned notes with the thread arcing
26 * over them. On a 64-unit grid the arc closed the top of the
27 * silhouette, and a closed top over two rectangles is a bag: at 40px
28 * and below the icon read as a shopping bag rather than a board. The
29 * frame was also spending most of the 20px budget on an outline that
30 * carried no meaning, leaving the notes too small to be notes.
31 *
32 * So the board and the paper are gone and the graph is the whole mark:
33 * one focused post with related ones fanned around it, which is what
34 * the window itself draws now that nodes are discs rather than post-
35 * type glyphs (see `src/content-graph/satellites.ts`). Sizes are
36 * deliberately unequal, so the hierarchy reads without a caption.
37 *
38 * Pin-led marks are deliberately avoided: `assets/images/pushpin.svg`
39 * belongs to pinned notes, and an icon led by a pin would point at
40 * that feature instead of this one.
41 *
42 * Drawn in `currentColor`, which makes it a silhouette: `renderIcon()`
43 * paints it as a CSS mask rather than a background-image, so it takes
44 * whatever colour the surface is already using for text. That keeps it
45 * legible on the dark dock, on a light title bar, and under a desktop
46 * theme's icon tint, with nothing to configure.
47 *
48 * Hand-placed at 64×64 like the Games icon, the established shape for
49 * custom icons here, and held to five elements because it renders as
50 * small as 20px in the dock.
51 *
52 * @return string Raw `<svg>` markup.
53 */
54 function openstation_content_graph_icon_svg() {
55 return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">'
56 // Threads first: the discs below are drawn over their ends, so
57 // the joins stay round instead of showing a stroke cap.
58 . '<path d="M14 16 32 32 52 18M32 32 40 49" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round"/>'
59 // The focused post.
60 . '<circle cx="32" cy="32" r="9" fill="currentColor"/>'
61 // Its satellites, sized just under the hub so the eye lands on
62 // the middle first.
63 . '<circle cx="14" cy="16" r="5.5" fill="currentColor"/>'
64 . '<circle cx="52" cy="18" r="5.5" fill="currentColor"/>'
65 . '<circle cx="40" cy="49" r="5" fill="currentColor"/>'
66 . '</svg>';
67 }
68
69 /**
70 * Whether the current user should see Content Graph.
71 *
72 * Mirrors the my-wordpress gate, anyone who can edit posts can view
73 * the link map of the content they author and maintain.
74 *
75 * @return bool
76 */
77 function openstation_content_graph_user_can_use() {
78 $can = current_user_can( 'edit_posts' );
79
80 /**
81 * Filter whether the current user can see the Content Graph
82 * desktop icon and window.
83 *
84 * @param bool $can Default: edit_posts capability.
85 */
86 return (bool) apply_filters( 'openstation_content_graph_user_can_use', $can );
87 }
88
89 /**
90 * Build the descriptor list of post types eligible for the graph.
91 * Defaults to every public post type (so CPTs participate by
92 * default), matching the user-facing filter bar that ships ON for all
93 * of them.
94 *
95 * @return array[] Each entry: `array( 'slug', 'label', 'icon', 'taxonomies' )`.
96 */
97 function openstation_content_graph_post_types() {
98 $types = get_post_types( array( 'public' => true ), 'objects' );
99 $result = array();
100 foreach ( $types as $type ) {
101 // `attachment` is public but participates in the graph as media
102 // (rendered in the side panel) rather than as a node — skip it
103 // on the node-type axis to avoid every image becoming a node.
104 if ( 'attachment' === $type->name ) {
105 continue;
106 }
107 $result[] = array(
108 'slug' => (string) $type->name,
109 'label' => (string) $type->labels->name,
110 'icon' => (string) ( ! empty( $type->menu_icon ) ? $type->menu_icon : 'dashicons-admin-post' ),
111 'taxonomies' => array(
112 'category' => is_object_in_taxonomy( $type->name, 'category' ),
113 'post_tag' => is_object_in_taxonomy( $type->name, 'post_tag' ),
114 ),
115 );
116 }
117
118 /**
119 * Filter the list of post types shown in the Content Graph filter
120 * bar. Each entry declares `slug`, `label`, `icon`, and optionally
121 * `taxonomies` (`array( 'category' => bool, 'post_tag' => bool )`);
122 * entries missing `taxonomies` get it derived from
123 * `is_object_in_taxonomy()` after filtering. Removing
124 * an entry hides it from the filter bar AND excludes it from the
125 * graph entirely.
126 *
127 * @param array[] $result Default: every public post type except attachment.
128 */
129 $filtered = apply_filters( 'openstation_content_graph_post_types', $result );
130 $filtered = is_array( $filtered ) ? array_values( $filtered ) : $result;
131
132 foreach ( $filtered as $i => $entry ) {
133 $slug = isset( $entry['slug'] ) ? (string) $entry['slug'] : '';
134 $filtered[ $i ]['taxonomies'] = array(
135 'category' => isset( $entry['taxonomies'] ) ? ! empty( $entry['taxonomies']['category'] ) : is_object_in_taxonomy( $slug, 'category' ),
136 'post_tag' => isset( $entry['taxonomies'] ) ? ! empty( $entry['taxonomies']['post_tag'] ) : is_object_in_taxonomy( $slug, 'post_tag' ),
137 );
138 }
139
140 return $filtered;
141 }
142
143 /**
144 * Render the Content Graph window's static template body. The bundle
145 * mounts its UI into `[data-os-content-graph-root]`.
146 */
147 function openstation_content_graph_render_template() {
148 ob_start();
149 ?>
150 <div class="desktop-mode-content-graph" data-os-content-graph-root>
151 <header class="os-content-graph__toolbar" data-os-content-graph-toolbar></header>
152 <div class="os-content-graph__body">
153 <div class="os-content-graph__stage" data-os-content-graph-stage>
154 <div class="os-content-graph__loading" data-os-content-graph-loading>
155 <os-spinner></os-spinner>
156 </div>
157 </div>
158 <aside class="os-content-graph__panel" data-os-content-graph-panel hidden></aside>
159 </div>
160 </div>
161 <?php
162 $html = (string) ob_get_clean();
163
164 /**
165 * Filter the Content Graph window's template HTML.
166 *
167 * @param string $html Default template HTML.
168 */
169 $filtered = (string) apply_filters( 'openstation_content_graph_template_html', $html );
170
171 $allowed_html = function_exists( 'openstation_native_window_allowed_html' )
172 ? openstation_native_window_allowed_html()
173 : wp_kses_allowed_html( 'post' );
174
175 echo wp_kses( $filtered, $allowed_html );
176 }
177
178 /**
179 * Register the native window + the desktop icon on `init` priority 20,
180 * matching the my-wordpress + recycle-bin modules.
181 */
182 function openstation_content_graph_register_window() {
183 if ( ! openstation_content_graph_user_can_use() ) {
184 return;
185 }
186
187 $icon_uri = 'data:image/svg+xml;base64,' . base64_encode( openstation_content_graph_icon_svg() );
188
189 $window_args = array(
190 'title' => __( 'Corkboard', 'desktop-mode' ),
191 'icon' => $icon_uri,
192 'template' => 'openstation_content_graph_render_template',
193 'script' => 'desktop-mode-content-graph',
194 'styles' => array( 'desktop-mode-content-graph' ),
195 'width' => 1080,
196 'height' => 720,
197 'min_width' => 720,
198 'min_height' => 480,
199 'placement' => 'none',
200 'config' => array(
201 'restRoot' => esc_url_raw( rest_url() ),
202 'restNonce' => wp_create_nonce( 'wp_rest' ),
203 'apiBase' => esc_url_raw( rest_url( 'desktop-mode/v1/content-graph' ) ),
204 'editPostUrl' => esc_url_raw( admin_url( 'post.php' ) ),
205 'editTermUrl' => esc_url_raw( admin_url( 'term.php' ) ),
206 'editUserUrl' => esc_url_raw( admin_url( 'user-edit.php' ) ),
207 'editCommentUrl' => esc_url_raw( admin_url( 'comment.php' ) ),
208 'mediaUrl' => esc_url_raw( admin_url( 'upload.php' ) ),
209 // Labels the "Open in <site>" action on the detail panel,
210 // which hands off to the WP Explorer window.
211 'siteName' => openstation_site_title(),
212 'postTypes' => openstation_content_graph_post_types(),
213 ),
214 );
215
216 /**
217 * Filter the args used to register the Content Graph native window.
218 *
219 * @param array $window_args Args passed to `openstation_register_window()`.
220 */
221 $window_args = (array) apply_filters( 'openstation_content_graph_window_args', $window_args );
222
223 $registered = openstation_register_window( 'desktop-mode-content-graph', $window_args );
224 if ( is_wp_error( $registered ) ) {
225 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
226 error_log( '[openstation] Content Graph window registration failed: ' . $registered->get_error_message() );
227 return;
228 }
229
230 $icon_args = array(
231 'title' => __( 'Corkboard', 'desktop-mode' ),
232 'icon_svg' => openstation_content_graph_icon_svg(),
233 'window' => 'desktop-mode-content-graph',
234 'pinned' => false,
235 'position' => 20,
236 );
237
238 /**
239 * Filter the args used to register the Content Graph desktop icon.
240 *
241 * @param array $icon_args Args passed to `openstation_register_icon()`.
242 */
243 $icon_args = (array) apply_filters( 'openstation_content_graph_icon_args', $icon_args );
244
245 openstation_register_icon( 'desktop-mode-content-graph', $icon_args );
246 }
247 add_action( 'init', 'openstation_content_graph_register_window', 20 );
248