PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.13
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.13
1.1.13 1.1.12 1.1.11 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 All 37 releases
← All changes | includes/widgets/widget-drafts.php +139 -66 0.9.8 → 1.1.13 View file →
@@ -1,7 +1,7 @@
1 1 <?php
2 2 /**
3 - * Desktop Mode — Drafts Widget.
3 + * OpenStation — Drafts Widget.
4 4 *
5 5 * A quick list of the current user's most recently edited draft posts,
6 6 * each a click away from reopening in the editor (the shell's admin-link
7 7 * interceptor turns the row into a native window).
@@ -9,12 +9,13 @@
9 9 * Data source: WordPress REST API /wp/v2/posts?status=draft (edit
10 10 * context, scoped to the viewer with `author` — without it an editor
11 11 * or admin would see every draft on the site, not their own).
12 12 * Refresh: every 60 seconds while the tab is visible, plus an
13 - * immediate refresh when a window closes or blurs.
14 - * Requires: Desktop Mode 0.18.0+ (desktop_mode_register_widget).
13 + * immediate refresh on every `os.post.changed` broadcast (a block-editor
14 + * save, a relayed content change) and when a window closes or blurs.
15 + * Requires: OpenStation 0.18.0+ (openstation_register_widget).
15 16 *
16 - * @package WPDesktopMode
17 + * @package OpenStation
17 18 */
18 19
19 20 defined( 'ABSPATH' ) || exit;
20 21
@@ -20,46 +21,46 @@
20 21
21 22 /**
22 23 * Register the JS + CSS assets.
23 24 */
24 -function desktop_mode_register_drafts_widget_assets() {
25 - $suffix = desktop_mode_asset_suffix();
26 - $version = defined( 'DESKTOP_MODE_VERSION' ) ? DESKTOP_MODE_VERSION : '0';
25 +function openstation_register_drafts_widget_assets() {
26 + $suffix = openstation_asset_suffix();
27 + $version = defined( 'OPENSTATION_VERSION' ) ? OPENSTATION_VERSION : '0';
27 28
28 - $js_path = DESKTOP_MODE_DIR . 'assets/js/widget-drafts' . $suffix . '.js';
29 - $css_path = DESKTOP_MODE_DIR . 'assets/js/widget-drafts' . $suffix . '.css';
29 + $js_path = OPENSTATION_DIR . 'assets/js/widget-drafts' . $suffix . '.js';
30 + $css_path = OPENSTATION_DIR . 'assets/js/widget-drafts' . $suffix . '.css';
30 31
31 32 wp_register_style(
32 - 'desktop-mode-drafts-widget',
33 - DESKTOP_MODE_URL . 'assets/js/widget-drafts' . $suffix . '.css',
33 + 'os-drafts-widget',
34 + OPENSTATION_URL . 'assets/js/widget-drafts' . $suffix . '.css',
34 35 array(),
35 36 file_exists( $css_path ) ? (string) filemtime( $css_path ) : $version
36 37 );
37 38
38 39 wp_register_script(
39 - 'desktop-mode-drafts-widget',
40 - DESKTOP_MODE_URL . 'assets/js/widget-drafts' . $suffix . '.js',
40 + 'os-drafts-widget',
41 + OPENSTATION_URL . 'assets/js/widget-drafts' . $suffix . '.js',
41 42 array( 'wp-api-fetch' ),
42 43 file_exists( $js_path ) ? (string) filemtime( $js_path ) : $version,
43 44 true
44 45 );
45 46 }
46 -add_action( 'init', 'desktop_mode_register_drafts_widget_assets', 5 );
47 +add_action( 'init', 'openstation_register_drafts_widget_assets', 5 );
47 48
48 49 /**
49 50 * Eagerly enqueue the CSS on shell pages so there is no flash of
50 51 * unstyled content while the lazy JS bundle loads.
51 52 */
52 -function desktop_mode_enqueue_drafts_widget_styles() {
53 - if ( function_exists( 'desktop_mode_is_enabled' ) && ! desktop_mode_is_enabled() ) {
53 +function openstation_enqueue_drafts_widget_styles() {
54 + if ( function_exists( 'openstation_is_enabled' ) && ! openstation_is_enabled() ) {
54 55 return;
55 56 }
56 - if ( function_exists( 'desktop_mode_is_chromeless_request' ) && desktop_mode_is_chromeless_request() ) {
57 + if ( function_exists( 'openstation_is_chromeless_request' ) && openstation_is_chromeless_request() ) {
57 58 return;
58 59 }
59 - wp_enqueue_style( 'desktop-mode-drafts-widget' );
60 + wp_enqueue_style( 'os-drafts-widget' );
60 61 }
61 -add_action( 'admin_enqueue_scripts', 'desktop_mode_enqueue_drafts_widget_styles', 20 );
62 +add_action( 'admin_enqueue_scripts', 'openstation_enqueue_drafts_widget_styles', 20 );
62 63
63 64 /**
64 65 * Register the widget definition.
65 66 *
@@ -66,19 +67,19 @@
66 67 * @return true|WP_Error True on success, `WP_Error` when the registry
67 68 * rejects the entry (e.g. the viewer lacks
68 69 * `edit_posts`), false if the registry is absent.
69 70 */
70 -function desktop_mode_register_drafts_widget() {
71 - if ( ! function_exists( 'desktop_mode_register_widget' ) ) {
71 +function openstation_register_drafts_widget() {
72 + if ( ! function_exists( 'openstation_register_widget' ) ) {
72 73 return false;
73 74 }
74 - return desktop_mode_register_widget(
75 + return openstation_register_widget(
75 76 'desktop-mode/drafts',
76 77 array(
77 78 'label' => __( 'Drafts', 'desktop-mode' ),
78 79 'description' => __( 'Your unfinished posts — click to reopen in the editor.', 'desktop-mode' ),
79 80 'icon' => 'dashicons-edit',
80 - 'script' => 'desktop-mode-drafts-widget',
81 + 'script' => 'os-drafts-widget',
81 82 'movable' => true,
82 83 'resizable' => true,
83 84 'min_width' => 240,
84 85 'min_height' => 180,
@@ -90,9 +91,9 @@
90 91 'capabilities' => array( 'edit_posts' ),
91 92 )
92 93 );
93 94 }
94 -add_action( 'init', 'desktop_mode_register_drafts_widget', 6 );
95 +add_action( 'init', 'openstation_register_drafts_widget', 6 );
95 96
96 97
97 98 /**
98 99 * Register the AI writing-suggestions REST route.
@@ -111,16 +112,16 @@
111 112 * gate here is defence in depth.
112 113 *
113 114 * @return void
114 115 */
115 -function desktop_mode_register_drafts_ai_routes() {
116 +function openstation_register_drafts_ai_routes() {
116 117 register_rest_route(
117 118 'desktop-mode/v1',
118 119 '/draft-suggestions',
119 120 array(
120 121 'methods' => WP_REST_Server::CREATABLE,
121 - 'callback' => 'desktop_mode_rest_draft_suggestions',
122 - 'permission_callback' => 'desktop_mode_rest_draft_suggestions_permission',
122 + 'callback' => 'openstation_rest_draft_suggestions',
123 + 'permission_callback' => 'openstation_rest_draft_suggestions_permission',
123 124 'args' => array(
124 125 'post_id' => array(
125 126 'required' => true,
126 127 'type' => 'integer',
@@ -129,9 +130,9 @@
129 130 ),
130 131 )
131 132 );
132 133 }
133 -add_action( 'rest_api_init', 'desktop_mode_register_drafts_ai_routes' );
134 +add_action( 'rest_api_init', 'openstation_register_drafts_ai_routes' );
134 135
135 136 /**
136 137 * Permission gate: the user can edit the target post, and AI is configured.
137 138 *
@@ -141,9 +142,9 @@
141 142 *
142 143 * @param WP_REST_Request $request Request.
143 144 * @return true|WP_Error
144 145 */
145 -function desktop_mode_rest_draft_suggestions_permission( WP_REST_Request $request ) {
146 +function openstation_rest_draft_suggestions_permission( WP_REST_Request $request ) {
146 147 $post_id = absint( $request['post_id'] );
147 148 if ( ! $post_id || ! current_user_can( 'edit_post', $post_id ) ) {
148 149 return new WP_Error(
149 150 'rest_forbidden',
@@ -150,11 +151,11 @@
150 151 __( 'You are not allowed to edit this post.', 'desktop-mode' ),
151 152 array( 'status' => rest_authorization_required_code() )
152 153 );
153 154 }
154 - if ( ! function_exists( 'desktop_mode_ai_provider_configured' ) || ! desktop_mode_ai_provider_configured() ) {
155 + if ( ! function_exists( 'openstation_ai_provider_configured' ) || ! openstation_ai_provider_configured() ) {
155 156 return new WP_Error(
156 - 'desktop_mode_ai_unavailable',
157 + 'openstation_ai_unavailable',
157 158 __( 'No AI provider is configured.', 'desktop-mode' ),
158 159 array( 'status' => 503 )
159 160 );
160 161 }
@@ -168,12 +169,12 @@
168 169 *
169 170 * @param WP_Post $post The draft being described.
170 171 * @return string
171 172 */
172 -function desktop_mode_drafts_ai_instructions( WP_Post $post ) {
173 - $instructions = 'You are a writing assistant for a WordPress author. Given a draft post\'s current title and content, help them finish and file it. Provide: exactly 3 concise, compelling title options (about 70 characters max each); one 1-2 sentence excerpt suitable as the post summary; 3 to 6 lowercase topical tags; 1 to 2 categories (strongly prefer the site\'s existing categories listed above — only propose a new concise name if none fit); and a readiness check.
173 +function openstation_drafts_ai_instructions( WP_Post $post ) {
174 + $instructions = 'You are a writing assistant for a WordPress author. Given a draft post\'s current title and content, help them finish and file it. Provide: exactly 3 concise, compelling title options (about 70 characters max each); one 1-2 sentence excerpt suitable as the post summary; 3 to 6 lowercase topical tags; 1 to 2 categories (prefer the site\'s existing categories, listed in the message; propose a new concise name only if none fit); and a readiness check.
174 175
175 -The readiness check MUST be strict and evidence-based. Judge only STRUCTURE and COMPLETENESS: does the draft have a clear introduction, enough substance/depth, at least one concrete example or detail, and a conclusion? The "missing" array lists only what is GENUINELY ABSENT from the text you were given. CRITICAL: never invent, guess, or hallucinate problems. Do NOT claim there are typos, misspellings, or cut-off/incomplete sentences unless you can quote the exact offending text verbatim from the draft — if you are not quoting real text, do not mention it. If the draft already has an intro, body with a concrete detail, and a conclusion and reads as complete, return an EMPTY "missing" array and say it looks ready in the summary.
176 +The readiness check judges structure and completeness only: does the draft have a clear introduction, enough substance, at least one concrete example or detail, and a conclusion? The "missing" array lists only what is absent from the text you were given. Mention a typo, misspelling or cut-off sentence only together with the exact text, quoted from the draft. When the draft has an introduction, a body with a concrete detail and a conclusion, return an empty "missing" array and say in the summary that it looks ready.
176 177
177 178 Write everything in the same language as the draft. Do not invent facts that are not supported by the content.';
178 179
179 180 /**
@@ -181,9 +182,9 @@
181 182 *
182 183 * @param string $instructions System instruction text.
183 184 * @param WP_Post $post The draft being described.
184 185 */
185 - return (string) apply_filters( 'desktop_mode_drafts_ai_instructions', $instructions, $post );
186 + return (string) apply_filters( 'openstation_drafts_ai_instructions', $instructions, $post );
186 187 }
187 188
188 189 /**
189 190 * JSON schema the model must answer in for draft suggestions.
@@ -190,9 +191,9 @@
190 191 *
191 192 * @param WP_Post $post The draft being described.
192 193 * @return array
193 194 */
194 -function desktop_mode_drafts_ai_schema( WP_Post $post ) {
195 +function openstation_drafts_ai_schema( WP_Post $post ) {
195 196 $schema = array(
196 197 'type' => 'object',
197 198 'additionalProperties' => false,
198 199 'required' => array( 'titles', 'excerpt', 'tags', 'categories', 'readiness' ),
@@ -243,9 +244,9 @@
243 244 *
244 245 * @param array $schema JSON schema.
245 246 * @param WP_Post $post The draft being described.
246 247 */
247 - return (array) apply_filters( 'desktop_mode_drafts_ai_schema', $schema, $post );
248 + return (array) apply_filters( 'openstation_drafts_ai_schema', $schema, $post );
248 249 }
249 250
250 251 /**
251 252 * Build the user-facing prompt body: title, trimmed content, existing terms.
@@ -252,9 +253,9 @@
252 253 *
253 254 * @param WP_Post $post The draft being described.
254 255 * @return string
255 256 */
256 -function desktop_mode_drafts_ai_prompt_text( WP_Post $post ) {
257 +function openstation_drafts_ai_prompt_text( WP_Post $post ) {
257 258 $title = (string) $post->post_title;
258 259 $content = trim( (string) preg_replace( '/\s+/', ' ', wp_strip_all_tags( (string) $post->post_content ) ) );
259 260
260 261 /**
@@ -262,9 +263,9 @@
262 263 *
263 264 * @param int $limit Character limit.
264 265 * @param WP_Post $post The draft being described.
265 266 */
266 - $limit = (int) apply_filters( 'desktop_mode_drafts_ai_content_limit', 4000, $post );
267 + $limit = (int) apply_filters( 'openstation_drafts_ai_content_limit', 4000, $post );
267 268
268 269 // mb_substr so a long draft isn't cut mid-multibyte-character.
269 270 if ( $limit > 0 && mb_strlen( $content ) > $limit ) {
270 271 $content = mb_substr( $content, 0, $limit ) . '…';
@@ -295,12 +296,12 @@
295 296 *
296 297 * @param WP_REST_Request $request Request.
297 298 * @return WP_REST_Response|WP_Error
298 299 */
299 -function desktop_mode_rest_draft_suggestions( WP_REST_Request $request ) {
300 +function openstation_rest_draft_suggestions( WP_REST_Request $request ) {
300 301 if ( ! function_exists( 'wp_ai_client_prompt' ) ) {
301 302 return new WP_Error(
302 - 'desktop_mode_ai_unavailable',
303 + 'openstation_ai_unavailable',
303 304 __( 'AI is not available on this site.', 'desktop-mode' ),
304 305 array( 'status' => 503 )
305 306 );
306 307 }
@@ -317,28 +318,32 @@
317 318 // `generate_text()` with a JSON schema — same call shape the comment
318 319 // scorer uses. The SDK can throw as well as return a WP_Error, so both
319 320 // paths land on the same 502.
320 321 try {
321 - $json = wp_ai_client_prompt( desktop_mode_drafts_ai_prompt_text( $post ) )
322 - ->using_system_instruction( desktop_mode_drafts_ai_instructions( $post ) )
323 - ->as_json_response( desktop_mode_ai_normalize_response_schema( desktop_mode_drafts_ai_schema( $post ) ) )
324 - ->generate_text();
322 + $builder = wp_ai_client_prompt( openstation_drafts_ai_prompt_text( $post ) )
323 + ->using_system_instruction( openstation_drafts_ai_instructions( $post ) )
324 + ->as_json_response( openstation_ai_normalize_response_schema( openstation_drafts_ai_schema( $post ) ) );
325 +
326 + $json = openstation_ai_apply_model_config(
327 + $builder,
328 + array(
329 + 'user_id' => get_current_user_id(),
330 + 'source' => 'widgets/drafts-suggestions',
331 + 'has_schema' => true,
332 + )
333 + )->generate_text();
325 334 } catch ( \Throwable $e ) {
326 - $json = new WP_Error( 'desktop_mode_ai_failed', $e->getMessage() );
335 + $json = new WP_Error( 'openstation_ai_failed', $e->getMessage() );
327 336 }
328 337
329 338 if ( is_wp_error( $json ) ) {
330 - return new WP_Error(
331 - 'desktop_mode_ai_failed',
332 - $json->get_error_message(),
333 - array( 'status' => 502 )
334 - );
339 + return openstation_drafts_ai_failure( $json );
335 340 }
336 341
337 342 $data = json_decode( (string) $json, true );
338 343 if ( ! is_array( $data ) ) {
339 344 return new WP_Error(
340 - 'desktop_mode_ai_parse',
345 + 'openstation_ai_parse',
341 346 __( 'The AI response could not be parsed.', 'desktop-mode' ),
342 347 array( 'status' => 502 )
343 348 );
344 349 }
@@ -345,15 +350,15 @@
345 350
346 351 $readiness = isset( $data['readiness'] ) && is_array( $data['readiness'] ) ? $data['readiness'] : array();
347 352
348 353 $suggestions = array(
349 - 'titles' => desktop_mode_drafts_clean_list( isset( $data['titles'] ) ? $data['titles'] : array(), 5 ),
354 + 'titles' => openstation_drafts_clean_list( isset( $data['titles'] ) ? $data['titles'] : array(), 5 ),
350 355 'excerpt' => trim( wp_strip_all_tags( (string) ( isset( $data['excerpt'] ) ? $data['excerpt'] : '' ) ) ),
351 - 'tags' => desktop_mode_drafts_clean_list( isset( $data['tags'] ) ? $data['tags'] : array(), 8 ),
352 - 'categories' => desktop_mode_drafts_clean_list( isset( $data['categories'] ) ? $data['categories'] : array(), 5 ),
356 + 'tags' => openstation_drafts_clean_list( isset( $data['tags'] ) ? $data['tags'] : array(), 8 ),
357 + 'categories' => openstation_drafts_clean_list( isset( $data['categories'] ) ? $data['categories'] : array(), 5 ),
353 358 'readiness' => array(
354 359 'summary' => trim( wp_strip_all_tags( (string) ( isset( $readiness['summary'] ) ? $readiness['summary'] : '' ) ) ),
355 - 'missing' => desktop_mode_drafts_clean_list( isset( $readiness['missing'] ) ? $readiness['missing'] : array(), 5 ),
360 + 'missing' => openstation_drafts_clean_list( isset( $readiness['missing'] ) ? $readiness['missing'] : array(), 5 ),
356 361 ),
357 362 );
358 363
359 364 /**
@@ -364,14 +369,82 @@
364 369 *
365 370 * @param array $suggestions { titles, excerpt, tags, categories, readiness }.
366 371 * @param WP_Post $post The draft the suggestions describe.
367 372 */
368 - $suggestions = (array) apply_filters( 'desktop_mode_drafts_ai_suggestions', $suggestions, $post );
373 + $suggestions = (array) apply_filters( 'openstation_drafts_ai_suggestions', $suggestions, $post );
369 374
370 375 return new WP_REST_Response( $suggestions, 200 );
371 376 }
372 377
373 378 /**
379 + * Turn a failed generation into the route's error.
380 + *
381 + * The route answers 502 for every provider failure: the failure is the
382 + * upstream's, not the caller's, and a provider's own 401 or 403 passed
383 + * through as the REST status would read as "your WordPress session is
384 + * invalid" to every client on the page. What the caller needs in order to
385 + * say something useful goes into the error data instead:
386 + *
387 + * - `reason`: `quota` (out of credits or rate limited), `auth` (the site's
388 + * key was rejected), `unavailable` (the provider could not be reached or
389 + * answered 5xx) or `other`.
390 + * - `provider_status`: the provider's own HTTP status, or null when the
391 + * failure never reached the provider.
392 + * - `detail`: the provider's message, verbatim, for the console and logs.
393 + *
394 + * The top-level message says what happened in plain words. The Core AI
395 + * Client reports a rejected request as `prompt_client_error` /
396 + * `prompt_upstream_server_error` with the provider's status in
397 + * `data.status` and a message of the shape "Too Many Requests (429) -
398 + * <provider text>", which is why the provider text never reached the
399 + * widget as anything but that string.
400 + *
401 + * @param WP_Error $error Failed generation.
402 + * @return WP_Error
403 + */
404 +function openstation_drafts_ai_failure( WP_Error $error ) {
405 + $code = (string) $error->get_error_code();
406 + $data = $error->get_error_data();
407 + $detail = (string) $error->get_error_message();
408 +
409 + $provider_status = null;
410 + if ( in_array( $code, array( 'prompt_client_error', 'prompt_upstream_server_error' ), true )
411 + && is_array( $data ) && isset( $data['status'] ) ) {
412 + $provider_status = (int) $data['status'];
413 + }
414 +
415 + if ( 'prompt_network_error' === $code || ( null !== $provider_status && $provider_status >= 500 ) ) {
416 + $reason = 'unavailable';
417 + $message = __( 'The AI provider could not be reached. Try again in a moment.', 'desktop-mode' );
418 + } elseif ( in_array( $provider_status, array( 402, 429 ), true ) ) {
419 + $reason = 'quota';
420 + $message = __( 'The AI provider has no credits left or is rate limiting this site. Check its plan and billing, or try again later.', 'desktop-mode' );
421 + } elseif ( in_array( $provider_status, array( 401, 403 ), true ) ) {
422 + $reason = 'auth';
423 + $message = __( 'The AI provider rejected this site’s API key. Check the key in Settings → Connectors.', 'desktop-mode' );
424 + } elseif ( null === $provider_status && preg_match( '/quota|credits?\b|billing|rate limit/i', $detail ) ) {
425 + // A provider that failed without a status (the SDK threw instead of
426 + // answering) can still say it was the account, not the request.
427 + $reason = 'quota';
428 + $message = __( 'The AI provider has no credits left or is rate limiting this site. Check its plan and billing, or try again later.', 'desktop-mode' );
429 + } else {
430 + $reason = 'other';
431 + $message = __( 'The AI provider could not produce suggestions.', 'desktop-mode' );
432 + }
433 +
434 + return new WP_Error(
435 + 'openstation_ai_failed',
436 + $message,
437 + array(
438 + 'status' => 502,
439 + 'reason' => $reason,
440 + 'provider_status' => $provider_status,
441 + 'detail' => $detail,
442 + )
443 + );
444 +}
445 +
446 +/**
374 447 * Trim, tag-strip and cap a list of model-supplied strings.
375 448 *
376 449 * @param mixed $list Raw list from the model.
377 450 * @param int $max Maximum entries to keep.
@@ -376,9 +449,9 @@
376 449 * @param mixed $list Raw list from the model.
377 450 * @param int $max Maximum entries to keep.
378 451 * @return string[]
379 452 */
380 -function desktop_mode_drafts_clean_list( $list, $max ) {
453 +function openstation_drafts_clean_list( $list, $max ) {
381 454 $out = array();
382 455 foreach ( (array) $list as $item ) {
383 456 if ( ! is_scalar( $item ) ) {
384 457 continue;
@@ -402,16 +475,16 @@
402 475 * AI-gated — this is a plain edit of the user's own draft.
403 476 *
404 477 * @return void
405 478 */
406 -function desktop_mode_register_drafts_apply_route() {
479 +function openstation_register_drafts_apply_route() {
407 480 register_rest_route(
408 481 'desktop-mode/v1',
409 482 '/draft-apply',
410 483 array(
411 484 'methods' => WP_REST_Server::CREATABLE,
412 - 'callback' => 'desktop_mode_rest_draft_apply',
413 - 'permission_callback' => 'desktop_mode_rest_draft_apply_permission',
485 + 'callback' => 'openstation_rest_draft_apply',
486 + 'permission_callback' => 'openstation_rest_draft_apply_permission',
414 487 'args' => array(
415 488 'post_id' => array(
416 489 'required' => true,
417 490 'type' => 'integer',
@@ -430,9 +503,9 @@
430 503 ),
431 504 )
432 505 );
433 506 }
434 -add_action( 'rest_api_init', 'desktop_mode_register_drafts_apply_route' );
507 +add_action( 'rest_api_init', 'openstation_register_drafts_apply_route' );
435 508
436 509 /**
437 510 * Permission gate: the user can edit the target post.
438 511 *
@@ -438,9 +511,9 @@
438 511 *
439 512 * @param WP_REST_Request $request Request.
440 513 * @return true|WP_Error
441 514 */
442 -function desktop_mode_rest_draft_apply_permission( WP_REST_Request $request ) {
515 +function openstation_rest_draft_apply_permission( WP_REST_Request $request ) {
443 516 $post_id = absint( $request['post_id'] );
444 517 if ( ! $post_id || ! current_user_can( 'edit_post', $post_id ) ) {
445 518 return new WP_Error(
446 519 'rest_forbidden',
@@ -456,9 +529,9 @@
456 529 *
457 530 * @param WP_REST_Request $request Request.
458 531 * @return WP_REST_Response|WP_Error
459 532 */
460 -function desktop_mode_rest_draft_apply( WP_REST_Request $request ) {
533 +function openstation_rest_draft_apply( WP_REST_Request $request ) {
461 534 $post_id = absint( $request['post_id'] );
462 535 $post = get_post( $post_id );
463 536 if ( ! $post instanceof WP_Post ) {
464 537 return new WP_Error(
@@ -487,9 +560,9 @@
487 560 if ( count( $update ) > 1 ) {
488 561 $result = wp_update_post( $update, true );
489 562 if ( is_wp_error( $result ) ) {
490 563 return new WP_Error(
491 - 'desktop_mode_apply_failed',
564 + 'openstation_apply_failed',
492 565 $result->get_error_message(),
493 566 array( 'status' => 500 )
494 567 );
495 568 }
@@ -554,8 +627,8 @@
554 627 * @param int $post_id Post that was updated.
555 628 * @param array $applied Fields written: { title?, excerpt?, tags?, categories? }.
556 629 * @param WP_Post $post The post as it was before the update.
557 630 */
558 - do_action( 'desktop_mode_drafts_suggestion_applied', $post_id, $applied, $post );
631 + do_action( 'openstation_drafts_suggestion_applied', $post_id, $applied, $post );
559 632
560 633 return new WP_REST_Response( array( 'applied' => $applied ), 200 );
561 634 }