PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.10
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.10
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
← All changes | includes/compat/divi.php +39 -53 0.9.21.1.10 View file →
@@ -29,10 +29,9 @@
29 29 *
30 30 * Reported to Elegant Themes. Remove this file when Divi ships
31 31 * the fix upstream.
32 32 *
33 - * @since 0.18.x
34 - * @package WP_Desktop_Mode\Compat
33 + * @package OpenStation\Compat
35 34 */
36 35
37 36 defined( 'ABSPATH' ) || exit;
38 37
@@ -82,13 +81,11 @@
82 81 *
83 82 * Reported to Elegant Themes. Remove this file when Divi ships
84 83 * the fix upstream.
85 84 *
86 - * @since 0.18.x
87 - *
88 85 * @return void
89 86 */
90 -function desktop_mode_compat_divi_fix_gutenberg_deps() {
87 +function openstation_compat_divi_fix_gutenberg_deps() {
91 88 global $wp_scripts;
92 89
93 90 if ( ! ( $wp_scripts instanceof WP_Scripts ) ) {
94 91 return;
@@ -106,9 +103,9 @@
106 103 $registration->deps[] = $dep;
107 104 }
108 105 }
109 106
110 - if ( desktop_mode_is_chromeless_request() ) {
107 + if ( openstation_is_chromeless_request() ) {
111 108 wp_add_inline_script(
112 109 'et-builder-gutenberg',
113 110 'window.et_gb = window;',
114 111 'before'
@@ -114,9 +111,9 @@
114 111 'before'
115 112 );
116 113 }
117 114 }
118 -add_action( 'enqueue_block_editor_assets', 'desktop_mode_compat_divi_fix_gutenberg_deps', 999 );
115 +add_action( 'enqueue_block_editor_assets', 'openstation_compat_divi_fix_gutenberg_deps', 999 );
119 116
120 117 /**
121 118 * Signal Divi's Visual Builder frame-helpers that the iframe context
122 119 * is "top-level-equivalent" so its `top_window` export resolves to
@@ -151,9 +148,9 @@
151 148 * — exactly the classic-admin behavior. The flag costs nothing
152 149 * outside Divi (no other code in the WP stack reads `__Cypress__`)
153 150 * and is idempotent (we OR with the existing value).
154 151 *
155 - * Scope: only when the current user has desktop mode enabled AND
152 + * Scope: only when the current user has OpenStation enabled AND
156 153 * the rendered document is loaded inside an iframe (`window.top !==
157 154 * window`). The inline script is a few-byte no-op everywhere else.
158 155 * Front-end only — admin pages use `et_gb` (see above) and route
159 156 * through a different compat path.
@@ -160,24 +157,22 @@
160 157 *
161 158 * Reported to Elegant Themes. Remove this hook when Divi makes
162 159 * `top_window` iframe-aware upstream.
163 160 *
164 - * @since 0.18.x
165 - *
166 161 * @return void
167 162 */
168 -function desktop_mode_compat_divi_vb_iframe_signal() {
163 +function openstation_compat_divi_vb_iframe_signal() {
169 164 if ( is_admin() ) {
170 165 return;
171 166 }
172 - if ( ! desktop_mode_is_enabled() ) {
167 + if ( ! openstation_is_enabled() ) {
173 168 return;
174 169 }
175 170 // Bail when Divi isn't active — the inline script below is
176 171 // shaped entirely around Divi's frame-helpers and VB preloader.
177 172 // Other handlers in this file already gate on
178 - // `desktop_mode_compat_divi_is_active()`; this one was missed.
179 - if ( ! desktop_mode_compat_divi_is_active() ) {
173 + // `openstation_compat_divi_is_active()`; this one was missed.
174 + if ( ! openstation_compat_divi_is_active() ) {
180 175 return;
181 176 }
182 177 // `app_window=1` flags the inner VB iframe Divi spawns inside the
183 178 // `/?p=N&et_fb=1` page. The outer ("VB-top") frame is what hosts
@@ -186,9 +181,9 @@
186 181 // VB-top — the inner frame's `__Cypress__` signal is enough.
187 182 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only flag set by Divi itself when constructing the inner iframe.
188 183 $is_app_frame = isset( $_GET['app_window'] ) && '1' === sanitize_text_field( wp_unslash( $_GET['app_window'] ) );
189 184 ?>
190 -<script id="desktop-mode-compat-divi-vb">
185 +<script id="os-compat-divi-vb">
191 186 ( function () {
192 187 if ( window.top === window ) { return; }
193 188 <?php if ( $is_app_frame ) : ?>
194 189 // Inside Divi's own inner builder iframe. We only want to
@@ -215,9 +210,9 @@
215 210 * `window.top.document`. The intent is "and also clear it on the
216 211 * outer VB-top frame I'm rendered into." In classic admin
217 212 * `window.top` IS the VB-top, so that works.
218 213 *
219 - * In a Desktop Mode chromeless iframe, the nesting is one deeper
214 + * In a OpenStation chromeless iframe, the nesting is one deeper
220 215 * — the inner React app's `window.top` is the desktop shell,
221 216 * which has no Divi elements. Root.js cleans its own doc and
222 217 * no-ops on the shell, leaving THIS document's preloader stuck
223 218 * forever.
@@ -277,9 +272,9 @@
277 272 } )();
278 273 </script>
279 274 <?php
280 275 }
281 -add_action( 'wp_head', 'desktop_mode_compat_divi_vb_iframe_signal', 1 );
276 +add_action( 'wp_head', 'openstation_compat_divi_vb_iframe_signal', 1 );
282 277
283 278 /**
284 279 * Iframe-side: hijack clicks on Divi's "Use Divi Builder" /
285 280 * "Edit With The Divi Builder" buttons and links, and hand the
@@ -288,9 +283,9 @@
288 283 *
289 284 * Why we hijack instead of letting Divi navigate:
290 285 *
291 286 * Divi's Visual Builder fundamentally doesn't behave well inside
292 - * Desktop Mode's nested iframe chain (shell -> chromeless iframe
287 + * OpenStation's nested iframe chain (shell -> chromeless iframe
293 288 * -> Divi's inner app-frame). Earlier attempts to transparently
294 289 * eject mid-navigation hit a chain of subtle race conditions —
295 290 * Divi captures `Location.prototype` references early, makes its
296 291 * REST save through a path our `fetch`/`XHR` wraps don't reach,
@@ -295,9 +290,9 @@
295 290 * Divi captures `Location.prototype` references early, makes its
296 291 * REST save through a path our `fetch`/`XHR` wraps don't reach,
297 292 * and the page-leave tears down our console before any diagnostic
298 293 * we add survives the navigation. The honest fix is to ask the
299 - * user, explicitly, whether they want to leave Desktop Mode for
294 + * user, explicitly, whether they want to leave OpenStation for
300 295 * this edit session.
301 296 *
302 297 * Detection is by visible text content on the clicked element
303 298 * rather than by selector — Divi changes the button class across
@@ -311,21 +306,19 @@
311 306 * The handler also walks every same-origin nested iframe so the
312 307 * Gutenberg editor canvas (when Gutenberg keeps it for non-Divi
313 308 * blocks) is covered.
314 309 *
315 - * @since 0.18.x
316 - *
317 310 * @return void
318 311 */
319 -function desktop_mode_compat_divi_eject_iframe_patch() {
320 - if ( ! desktop_mode_is_chromeless_request() ) {
312 +function openstation_compat_divi_eject_iframe_patch() {
313 + if ( ! openstation_is_chromeless_request() ) {
321 314 return;
322 315 }
323 - if ( ! desktop_mode_compat_divi_is_active() ) {
316 + if ( ! openstation_compat_divi_is_active() ) {
324 317 return;
325 318 }
326 319 ?>
327 -<script id="desktop-mode-compat-divi-vb-handoff">
320 +<script id="os-compat-divi-vb-handoff">
328 321 ( function () {
329 322 var BTN_TEXTS = [
330 323 'use divi builder',
331 324 'use the divi builder',
@@ -342,9 +335,9 @@
342 335 }
343 336 function postHandoff( currentUrl ) {
344 337 try {
345 338 window.top.postMessage(
346 - { type: 'desktop-mode-divi-vb-handoff', url: String( currentUrl ) },
339 + { type: 'os-divi-vb-handoff', url: String( currentUrl ) },
347 340 window.location.origin
348 341 );
349 342 } catch ( e ) {}
350 343 }
@@ -366,10 +359,10 @@
366 359 postHandoff( window.location.href );
367 360 }
368 361 function attachClickListener( doc ) {
369 362 try {
370 - if ( doc.__desktopModeDiviHandoffAttached ) { return; }
371 - doc.__desktopModeDiviHandoffAttached = true;
363 + if ( doc.__openStationDiviHandoffAttached ) { return; }
364 + doc.__openStationDiviHandoffAttached = true;
372 365 doc.addEventListener( 'click', onClick, true );
373 366 } catch ( e ) {}
374 367 }
375 368 function walkAndAttach( root ) {
@@ -380,10 +373,10 @@
380 373 frames.forEach( function ( iframe ) {
381 374 try {
382 375 if ( iframe.contentDocument ) { walkAndAttach( iframe.contentDocument ); }
383 376 } catch ( e ) {}
384 - if ( iframe.__desktopModeDiviHandoffHooked ) { return; }
385 - iframe.__desktopModeDiviHandoffHooked = true;
377 + if ( iframe.__openStationDiviHandoffHooked ) { return; }
378 + iframe.__openStationDiviHandoffHooked = true;
386 379 iframe.addEventListener( 'load', function () {
387 380 try { if ( iframe.contentDocument ) { walkAndAttach( iframe.contentDocument ); } } catch ( e ) {}
388 381 } );
389 382 } );
@@ -401,13 +394,13 @@
401 394 } )();
402 395 </script>
403 396 <?php
404 397 }
405 -add_action( 'admin_head', 'desktop_mode_compat_divi_eject_iframe_patch', 0 );
398 +add_action( 'admin_head', 'openstation_compat_divi_eject_iframe_patch', 0 );
406 399
407 400 /**
408 401 * Parent-shell side: receive the handoff message, ask the user
409 - * to confirm via `wp.desktop.confirm()`, and on accept navigate
402 + * to confirm via `wp.os.confirm()`, and on accept navigate
410 403 * `window.top.location.href` to the iframe's current URL — which
411 404 * is the post-edit page. The user lands at top level on the same
412 405 * post they were editing, clicks "Use Divi Builder" again with a
413 406 * single browser tab, and Divi runs in its native single-frame
@@ -419,38 +412,33 @@
419 412 * Same-origin guards: the message event must originate from our
420 413 * own origin AND the URL we navigate to must parse back to the
421 414 * same origin. Foreign frames can't trigger the handoff.
422 415 *
423 - * @since 0.18.x
424 - *
425 416 * @return void
426 417 */
427 -function desktop_mode_compat_divi_eject_parent_listener() {
428 - if ( ! desktop_mode_is_enabled() ) {
418 +function openstation_compat_divi_eject_parent_listener() {
419 + if ( ! openstation_is_shell_request() ) {
429 420 return;
430 421 }
431 - if ( desktop_mode_is_chromeless_request() || desktop_mode_is_classic_request() ) {
422 + if ( ! openstation_compat_divi_is_active() ) {
432 423 return;
433 424 }
434 - if ( ! desktop_mode_compat_divi_is_active() ) {
435 - return;
436 - }
437 425 ?>
438 -<script id="desktop-mode-compat-divi-vb-handoff-parent">
426 +<script id="os-compat-divi-vb-handoff-parent">
439 427 ( function () {
440 428 // Reshape the iframe's URL into a top-level classic-admin URL.
441 - // The iframe carries `desktop_mode_chromeless=1`, which would
429 + // The iframe carries `openstation_chromeless=1`, which would
442 430 // keep the chromeless render alive even at top level — leaving
443 431 // the user on what looks like the same headless Gutenberg they
444 432 // already had inside the window. We want a normal wp-admin page
445 433 // instead, so strip that flag and add `desktop_mode_classic=1`
446 - // so our own `desktop_mode_redirect_plain_admin_to_portal()` in
434 + // so our own `openstation_redirect_plain_admin_to_portal()` in
447 435 // `includes/portal.php` skips its portal-bounce for this load.
448 436 function handoffUrl( raw ) {
449 437 try {
450 438 var parsed = new URL( String( raw || '' ), window.location.href );
451 439 if ( parsed.origin !== window.location.origin ) { return null; }
452 - parsed.searchParams.delete( 'desktop_mode_chromeless' );
440 + parsed.searchParams.delete( 'openstation_chromeless' );
453 441 parsed.searchParams.set( 'desktop_mode_classic', '1' );
454 442 return parsed.toString();
455 443 } catch ( e ) { return null; }
456 444 }
@@ -455,22 +443,22 @@
455 443 } catch ( e ) { return null; }
456 444 }
457 445 window.addEventListener( 'message', function ( ev ) {
458 446 if ( ev.origin !== window.location.origin ) { return; }
459 - if ( ! ev.data || ev.data.type !== 'desktop-mode-divi-vb-handoff' ) { return; }
447 + if ( ! ev.data || ev.data.type !== 'os-divi-vb-handoff' ) { return; }
460 448 var url = handoffUrl( ev.data.url );
461 449 if ( ! url ) { return; }
462 450 var promptUser;
463 - if ( window.wp && window.wp.desktop && typeof window.wp.desktop.confirm === 'function' ) {
464 - promptUser = window.wp.desktop.confirm( {
451 + if ( window.wp && window.wp.os && typeof window.wp.os.confirm === 'function' ) {
452 + promptUser = window.wp.os.confirm( {
465 453 title: 'Divi needs its own browser tab',
466 - message: 'Divi\u2019s Visual Builder cannot run inside a Desktop Mode window \u2014 it needs the full browser tab to render and save correctly. There is no workaround on our side; Divi simply doesn\u2019t support being nested.',
454 + message: 'Divi\u2019s Visual Builder cannot run inside a OpenStation window \u2014 it needs the full browser tab to render and save correctly. There is no workaround on our side; Divi simply doesn\u2019t support being nested.',
467 455 confirmLabel: 'Open Divi in this tab',
468 456 hideCancel: true,
469 457 dismissable: true,
470 458 } );
471 459 } else {
472 - // Defense-in-depth no-op. `wp.desktop.confirm` is
460 + // Defense-in-depth no-op. `wp.os.confirm` is
473 461 // reliably present on every shell page where this
474 462 // listener emits, so this branch is unreachable in
475 463 // practice. A `window.confirm` here would violate the
476 464 // codebase-wide "no native dialogs" rule (see CLAUDE.md);
@@ -484,9 +472,9 @@
484 472 } )();
485 473 </script>
486 474 <?php
487 475 }
488 -add_action( 'admin_footer', 'desktop_mode_compat_divi_eject_parent_listener', 1 );
476 +add_action( 'admin_footer', 'openstation_compat_divi_eject_parent_listener', 1 );
489 477
490 478
491 479 /**
492 480 * Detect whether Divi (theme or standalone Divi Builder plugin)
@@ -492,14 +480,12 @@
492 480 * Detect whether Divi (theme or standalone Divi Builder plugin)
493 481 * is active. Used to gate both the iframe-side patcher and the
494 482 * parent-side listener — both no-ops on non-Divi sites.
495 483 *
496 - * @since 0.18.x
497 - *
498 484 * @return bool True when the Divi theme is active OR the Divi
499 485 * Builder plugin is active.
500 486 */
501 -function desktop_mode_compat_divi_is_active() {
487 +function openstation_compat_divi_is_active() {
502 488 $theme = wp_get_theme();
503 489 if ( $theme instanceof WP_Theme ) {
504 490 $name = (string) $theme->get( 'Name' );
505 491 $template = (string) $theme->get_template();