/** * Desktop Mode — Chromeless Overrides. * * CSS adjustments for legacy admin pages rendered inside desktop mode * iframes (chromeless mode). All rules are scoped to .desktop-mode-chromeless * so they never affect the classic admin or the desktop shell. * * Plugin and theme developers: to add your own chromeless overrides, * enqueue a stylesheet on the 'desktop_mode_chromeless_styles' action. * Your CSS just needs to target .desktop-mode-chromeless as the body class. * * Example: * add_action( 'desktop_mode_chromeless_styles', function() { * wp_enqueue_style( 'my-plugin-chromeless', plugin_dir_url( __FILE__ ) . 'chromeless.css' ); * } ); * * @since 0.1.0 */ /* --------------------------------------------------------------- * Hide the classic admin chrome elements. These would otherwise * reserve space (sidebar gutter, footer, admin bar) around the * chromeless page content. * --------------------------------------------------------------- */ .desktop-mode-chromeless #adminmenuwrap, .desktop-mode-chromeless #adminmenuback, .desktop-mode-chromeless #wpfooter, .desktop-mode-chromeless #wpadminbar, .desktop-mode-chromeless .wp-responsive-toggle, .desktop-mode-chromeless #collapse-menu { display: none !important; } /* * _wp_admin_html_begin() adds the `wp-toolbar` class to whenever * is_admin_bar_showing() is true — which, in admin, is unconditional. * The class carries a `padding-top: var(--wp-admin--admin-bar--height)` * that would leave a 32px (or 46px) dead gap at the top of the iframe. * Zero it out inside chromeless iframes. * * We also rebind `--wp-admin--admin-bar--height` (and the derived * `--wp-admin--admin-bar--position-offset` from block-library) to 0px * inside chromeless so plugins that position UI relative to the admin * bar resolve their math against the iframe's actual chrome state. * * WooCommerce's activity-panel wrapper, the block editor's sticky * header, and several others use `top: var(--wp-admin--admin-bar--height)` * to clear the bar. Without this override they reserve a 32px (or 46px * on small screens) gap that no longer exists, producing visible jumps * on first paint and dead space at the top of the content area. */ html.wp-toolbar:has( body.desktop-mode-chromeless ) { padding-top: 0 !important; --wp-admin--admin-bar--height: 0px; --wp-admin--admin-bar--position-offset: 0px; } /* Remove the sidebar gutter on #wpcontent and let the body fill the frame. */ .desktop-mode-chromeless #wpcontent { margin-inline-start: 0 !important; padding-inline-start: 0 !important; } /* * WooCommerce sidebar-reservation override. * * `.woocommerce-layout__header` is a `position: fixed` bar WC * mounts on every wc-admin and wc-embedded page. Its width is * compiled from the SCSS source (header/style.scss) as a literal: * * position: fixed; * top: 32px; // $adminbar-height * width: calc(100% - 160px); // reserves classic sidebar * z-index: 1001; * * The 160px subtraction is the classic admin menu width — WC bakes * it in at build time so the header doesn't overlap the sidebar * in standard admin. Inside chromeless we hide the sidebar, but * the header keeps the reservation — so the header ends 160px * short of the iframe right edge, and `.woocommerce-layout__activity-panel-wrapper` * (`position: absolute; right: 0; top: 100%; transform: translateX(100%)`, * containing block = the fixed header) translates past the * header's right edge, NOT past the iframe's right edge. The * resulting visible strip is exactly 160px wide — the size of the * sidebar gap WC reserved for nothing. * * Reclaim the reservation: pin the header to full iframe width * inside chromeless. The activity panel then translates past the * iframe edge as WC's design intended, the gray strip disappears, * and the header's content uses the full window width. No * transform / overflow / visibility tricks needed. */ .desktop-mode-chromeless .woocommerce-layout__header { width: 100% !important; } /* --------------------------------------------------------------- * Screen Meta (Screen Options / Help panels) * The toggle buttons (#screen-meta-links) are hidden because * the parent desktop shell adds its own buttons to the window * title bar. The panels themselves stay visible and functional — * they're toggled via postMessage from the parent. * * Collapse all margins on the hidden links and the panel container * so they don't leave a gap at the top of the iframe content. * --------------------------------------------------------------- */ .desktop-mode-chromeless #screen-meta-links { display: none; margin: 0; } .desktop-mode-chromeless #screen-meta { margin: 0; border: none; } /* --------------------------------------------------------------- * Wrap container * Remove the default left margin that accounts for the sidebar * which doesn't exist in chromeless mode. * --------------------------------------------------------------- */ .desktop-mode-chromeless .wrap { margin: 0; } /* --------------------------------------------------------------- * Page title & header * The window title bar already shows the page title, so the * in-page

+ header separator (.wp-header-end) are redundant * inside chromeless iframes. Hide them so the window content * starts flush. * * `.page-title-action` (the "Add New" / "Add Order" button next to * the H1) stays VISIBLE by default — it's the only entry point to * the add-new flow on many plugin pages (WooCommerce Orders, custom * CPTs, plugin settings pages, etc.). Earlier versions of this CSS * hid it on the assumption that the submenu tab strip exposed the * same action — which holds for WP Core pages with a registered * "Add New" submenu (Posts, Pages, Users) but breaks every third- * party plugin page that has no submenu equivalent. A small bit of * redundancy with the submenu strip on Core pages is the better * trade-off vs. losing the primary affordance on plugin pages * entirely. * * Sites that prefer the cleaner Core-page look can hide the button * on specific pages via the `desktop_mode_chromeless_styles` * action — e.g.: * * body.edit-php .wrap > .page-title-action { display: none; } * * --------------------------------------------------------------- */ .desktop-mode-chromeless .wrap > h1, .desktop-mode-chromeless .wrap > h1.wp-heading-inline, .desktop-mode-chromeless #wpbody-content > .wrap > h1, .desktop-mode-chromeless .wrap > .wp-header-end { display: none; } /* * The H1 above it is hidden, so the button would float at the very * top of the iframe area without breathing room — give it a small * margin so it lands cleanly. inline-block matches WP Core's * computed style on this element (matters for vertical-align with * any adjacent inline content like the `.subsubsub` filter row). * * Themes.php's native "Add Theme" button lives in the submenu tab * strip via `desktop_mode_inject_appearance_tabs` * (includes/themes-tabs.php), so its in-page page-title-action is * redundant on that one screen — keep the per-page hide rule below * so we don't ship two "Add Theme" entry points. */ .desktop-mode-chromeless .wrap > .page-title-action { display: inline-block; margin-top: 12px; } .desktop-mode-chromeless.themes-php .wrap > .page-title-action { display: none; } /* --------------------------------------------------------------- * WooCommerce "embed page" header overlay — page-scoped. * * Background: WC renders TWO layouts simultaneously on "connected" * pages like `wc-orders` — the PHP-rendered legacy `.wrap` (with * the h1 + the "Add order" `.page-title-action`) AND a React-mounted * `EmbedHeader` (`client/admin/client/header/embed.tsx`) that * `position: fixed`-overlays the page from the top. References: * - `src/Internal/Admin/Loader.php::embed_page_header` * - `includes/react-admin/connect-existing-pages.php` (registers * wc-orders as a connected page when HPOS is on) * - `client/admin/client/header/shared.tsx::useUpdateBodyMargin` * (the hook that pushes `#wpbody.style.marginTop` to make * room for the fixed header) * * The conflict, narrowly: * 1. The legacy `.wrap > .page-title-action` ("Add order") at * the top of the document body — primary add-new affordance. * 2. The React `EmbedHeader` overlays the top of the iframe with * a redundant `

Orders

` and an Activity Panel toggle. * * The fixed React header OBSCURES the legacy `.page-title-action` * button when we reset `#wpbody`'s margin-top. * * Scope: ONLY the pages where the dual rendering is genuinely a * problem — `wc-orders` (Orders list, the user-reported failure * mode) and `wc-orders--shop_order` (the trash view variant). Other * WC-admin pages (Analytics, Marketing, Customers, Coupons, * Products, Reports, …) DON'T render a competing legacy `.wrap` * with a `.page-title-action` button; their primary content IS the * React app. On those pages the Activity Panel + EmbedHeader are * the only header affordance the user has, so we keep them visible. * * If new HPOS-style connected pages emerge where the same dual * layout creates the same conflict, add their per-page body class * (`.woocommerce_page_`) to the selector — don't broaden the * rule to `.woocommerce-admin-page` (that would silently strip the * Activity Panel from every WC screen). * * @since 0.8.9 */ .desktop-mode-chromeless.woocommerce_page_wc-orders .woocommerce-layout__header, .desktop-mode-chromeless.woocommerce_page_wc-orders--shop_order .woocommerce-layout__header { display: none !important; } .desktop-mode-chromeless.woocommerce_page_wc-orders #wpbody, .desktop-mode-chromeless.woocommerce_page_wc-orders--shop_order #wpbody { margin-top: 0 !important; } /* --------------------------------------------------------------- * Dashboard welcome panel * The default 16px top margin pushes the panel down and creates a * visible gap at the top of the iframe. Collapse it in chromeless * mode so the panel sits flush with the top of the window body. * --------------------------------------------------------------- */ .desktop-mode-chromeless #welcome-panel, .desktop-mode-chromeless .welcome-panel { margin-top: 0.5em; } /* --------------------------------------------------------------- * Footer * The classic footer is not rendered in chromeless mode, * but some pages have bottom padding assuming it exists. * --------------------------------------------------------------- */ .desktop-mode-chromeless #wpbody-content { margin: 0; padding: 0 8px 8px; float: none; width: auto; } /* --------------------------------------------------------------- * Block Editor — hide Gutenberg chrome that would break the window. * * The fullscreen-mode close button (the "W" logo top-left of the editor) * is an that navigates the iframe to a * non-chromeless URL — which re-renders the entire classic admin * inside our desktop window. The link interceptor in the chromeless * bridge catches it too, but hiding the button removes the visual * affordance so users never try to click "back to dashboard" inside * what looks like a self-contained window. * * The site editor's equivalent navigation affordances (site hub toggle, * "back to dashboard" link) get the same treatment. * * The welcome guide is intentionally NOT hidden anymore. Earlier * iterations both CSS-hid the dialog AND flipped `core/edit-post: * welcomeGuide` to `false` at the data layer on every chromeless * mount — but Gutenberg already persists the user's "Get started" * dismissal to user meta the moment they close it, so the override * was permanently stealing the one-time orientation tour from every * user who never got to see it. Modal's focus trap is Tab-only and * doesn't fight the shell. Let it run. (See git history for the * removed `desktop_mode_chromeless_editor_preferences` override.) * --------------------------------------------------------------- */ .desktop-mode-chromeless .edit-post-fullscreen-mode-close, .desktop-mode-chromeless .edit-post-fullscreen-mode-close__view-mode-toggle, .desktop-mode-chromeless .edit-site-navigation-link, .desktop-mode-chromeless .edit-site-site-hub, .desktop-mode-chromeless .edit-site-site-hub__toggle { display: none !important; } /* --------------------------------------------------------------- * Block Editor & Site Editor — full-bleed layouts. * Gutenberg owns its entire viewport (its own header bar, side * panels, etc.). Any padding around #wpbody-content crops the * editor and breaks its layout, so reset to zero on those pages * and let the editor render edge-to-edge. * --------------------------------------------------------------- */ .desktop-mode-chromeless.block-editor-page #wpbody-content, .desktop-mode-chromeless.site-editor-php #wpbody-content, .desktop-mode-chromeless.is-fullscreen-mode #wpbody-content { padding: 0; } /* --------------------------------------------------------------- * "Boot" SPA pages (Font Library, Options → Connectors). * * These screens mount a React app into `.boot-layout-container` and * paint `#wpwrap` a dark `#1e1e1e` via inline