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