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/themes-tabs.php +101 -23 0.9.31.1.10 View file →
@@ -1,7 +1,7 @@
1 1 <?php
2 2 /**
3 - * Desktop Mode — Appearance window tab adaptations.
3 + * OpenStation — Appearance window tab adaptations.
4 4 *
5 5 * The Appearance dock item opens an iframe of `themes.php` and uses
6 6 * the in-window submenu strip (built from the WP `$submenu` global)
7 7 * as its tab bar. WP Core does not register `theme-install.php` as a
@@ -11,15 +11,14 @@
11 11 * Inside chromeless we hide that button (it scrolled out of the
12 12 * iframe's visible area on first paint, leaving no entry point to
13 13 * the install flow — see assets/css/chromeless.css). This file
14 14 * compensates by injecting an "Add Theme" tab at the front of the
15 - * Appearance window's submenu strip via the `desktop_mode_dock_item`
15 + * Appearance window's submenu strip via the `openstation_dock_item`
16 16 * filter.
17 17 *
18 18 * Resulting tab order: Appearance | Add Theme | Editor | Fonts | …
19 19 *
20 - * @package Desktop_Mode
21 - * @since 0.8.2
20 + * @package OpenStation
22 21 */
23 22
24 23 defined( 'ABSPATH' ) || exit;
25 24
@@ -25,21 +24,19 @@
25 24
26 25 /**
27 26 * Prepends an "Add Theme" entry to the Appearance dock item's submenu.
28 27 *
29 - * Called once per dock item via {@see desktop_mode_build_dock_items()}.
28 + * Called once per dock item via {@see openstation_build_dock_items()}.
30 29 * Skipped for every menu other than `themes.php` and for users who
31 30 * lack the `install_themes` capability — matching what classic
32 31 * admin's "Add Theme" page-title-action enforces.
33 32 *
34 - * @since 0.8.2
35 - *
36 33 * @param array $dock_item The dock item data (id, title, icon, url,
37 34 * badge, submenu, multi, placement, isCore).
38 35 * @param string $menu_slug The menu slug — e.g. `themes.php`.
39 36 * @return array Filtered dock item.
40 37 */
41 -function desktop_mode_inject_appearance_tabs( $dock_item, $menu_slug ) {
38 +function openstation_inject_appearance_tabs( $dock_item, $menu_slug ) {
42 39 if ( 'themes.php' !== $menu_slug ) {
43 40 return $dock_item;
44 41 }
45 42
@@ -74,11 +71,88 @@
74 71 array_unshift( $dock_item['submenu'], $add_theme );
75 72
76 73 return $dock_item;
77 74 }
78 -add_filter( 'desktop_mode_dock_item', 'desktop_mode_inject_appearance_tabs', 10, 2 );
75 +add_filter( 'openstation_dock_item', 'openstation_inject_appearance_tabs', 10, 2 );
79 76
80 77 /**
78 + * Renders the orientation header for the chromeless Themes workspace.
79 + *
80 + * Core's page heading is intentionally hidden inside OpenStation because the
81 + * window chrome already names the screen. The Themes page still needs a little
82 + * more context than a generic list screen, though: a theme changes the public
83 + * face of the site, and Core's single-theme state otherwise opens directly on
84 + * an unexplained details panel.
85 + *
86 + * The markup is emitted through `admin_notices`, which places it immediately
87 + * before the page's `.wrap`. Core continues to own the theme cards, details
88 + * overlay, actions, AJAX updates, and keyboard behavior.
89 + *
90 + * The screen is identified by `get_current_screen()`, not `$pagenow`. Every
91 + * page registered with `add_theme_page()` also reports `themes.php` as its
92 + * `$pagenow`, but its body class comes from the hook suffix
93 + * (`appearance_page_<slug>`) and so matches none of the workspace CSS, which
94 + * is scoped to `.themes-php`. Gating on `$pagenow` would emit this header
95 + * unstyled on top of unrelated Appearance screens. The screen ID also keeps
96 + * network admin (`themes-network`, a different list table entirely) out.
97 + */
98 +function openstation_render_themes_workspace_intro() {
99 + if ( ! openstation_is_chromeless_request() ) {
100 + return;
101 + }
102 +
103 + $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
104 + if ( ! $screen || 'themes' !== $screen->id ) {
105 + return;
106 + }
107 +
108 + /*
109 + * Mirrors how `wp_prepare_themes_for_js()` builds its own list, without
110 + * paying for the preparation itself. Core already called that function
111 + * on this request before `admin-header.php` ran, and calling it again
112 + * would re-resolve every screenshot, tag and author URL and fire
113 + * `pre_prepare_themes_for_js` / `wp_prepare_themes_for_js` a second
114 + * time — so any third-party callback hanging off them would run twice
115 + * per page load. `wp_get_themes()` is cached, so this is a lookup.
116 + */
117 + if ( current_user_can( 'switch_themes' ) ) {
118 + $themes = wp_get_themes( array( 'allowed' => true ) );
119 + $stylesheet = get_stylesheet();
120 + if ( ! isset( $themes[ $stylesheet ] ) ) {
121 + $themes[ $stylesheet ] = wp_get_theme();
122 + }
123 + $theme_count = count( $themes );
124 + } else {
125 + $theme_count = 1;
126 + }
127 + ?>
128 + <section class="openstation-themes-intro" aria-labelledby="openstation-themes-intro-title">
129 + <div class="openstation-themes-intro__copy">
130 + <p class="openstation-themes-intro__eyebrow"><?php esc_html_e( 'Site appearance', 'desktop-mode' ); ?></p>
131 + <h1 id="openstation-themes-intro-title"><?php esc_html_e( 'Choose how your site greets the world.', 'desktop-mode' ); ?></h1>
132 + <p><?php esc_html_e( 'Themes shape your site’s look. Switching keeps your posts and pages in place.', 'desktop-mode' ); ?></p>
133 + </div>
134 + <?php
135 + /*
136 + * Left readable rather than labelled: `aria-label` is ignored on a
137 + * `<p>` (the paragraph role prohibits an author-supplied name), so
138 + * pairing it with `aria-hidden` children hid the count from
139 + * assistive tech entirely — and Core's own `.title-count` inside
140 + * the page `<h1>` is display:none in chromeless mode, making this
141 + * the only count on the screen. Read in DOM order the two spans
142 + * announce as "3 Themes installed" on their own.
143 + */
144 + ?>
145 + <p class="openstation-themes-intro__count">
146 + <strong><?php echo esc_html( number_format_i18n( $theme_count ) ); ?></strong>
147 + <span><?php echo esc_html( _n( 'Theme installed', 'Themes installed', $theme_count, 'desktop-mode' ) ); ?></span>
148 + </p>
149 + </section>
150 + <?php
151 +}
152 +add_action( 'admin_notices', 'openstation_render_themes_workspace_intro', 0 );
153 +
154 +/**
81 155 * Fixes the visible "active tab" state inside chromeless
82 156 * theme-install.php iframes.
83 157 *
84 158 * Background: WP's installer JS uses a Backbone router whose pattern
@@ -83,10 +157,10 @@
83 157 *
84 158 * Background: WP's installer JS uses a Backbone router whose pattern
85 159 * `theme-install.php?browse=:sort` greedy-captures everything past
86 160 * `browse=` ([^/?]+ matches `&` too). Inside chromeless the URL also
87 - * carries `desktop_mode_chromeless=1`, so `:sort` ends up as
88 - * `popular&desktop_mode_chromeless=1`. WP's `view.sort()` then runs
161 + * carries `openstation_chromeless=1`, so `:sort` ends up as
162 + * `popular&openstation_chromeless=1`. WP's `view.sort()` then runs
89 163 * with that polluted value and the `[data-sort]` selector finds
90 164 * nothing — leaving every tab in the unselected state even though
91 165 * the popular themes ARE the rendered listing.
92 166 *
@@ -96,18 +170,16 @@
96 170 * chromeless flag (which would re-render the iframe with full admin
97 171 * chrome on next paint).
98 172 *
99 173 * The minimum-viable shim: inline JS that reads the real `browse`
100 - * value via URLSearchParams, finds the matching `[data-sort]` tab,
101 - * and sets `current` + `aria-current` on it. A MutationObserver on
102 - * `.filter-links` keeps the tab synced if WP's router fires again
103 - * (e.g. the user picks Latest, then comes back to Popular via the
104 - * route's pushState).
105 - *
106 - * @since 0.8.2
174 + * value dynamically via URLSearchParams on every check, finds the
175 + * matching `[data-sort]` tab, and sets `current` + `aria-current` on it.
176 + * A MutationObserver on `.filter-links` keeps the tab synced when WP's
177 + * router fires or state changes (e.g. switching tabs to Latest or
178 + * returning via pushState).
107 179 */
108 -function desktop_mode_theme_install_active_tab_script() {
109 - if ( ! desktop_mode_is_chromeless_request() ) {
180 +function openstation_theme_install_active_tab_script() {
181 + if ( ! openstation_is_chromeless_request() ) {
110 182 return;
111 183 }
112 184 if ( ! isset( $GLOBALS['pagenow'] ) || 'theme-install.php' !== $GLOBALS['pagenow'] ) {
113 185 return;
@@ -114,13 +186,19 @@
114 186 }
115 187
116 188 $js = <<<'JS'
117 189 ( function () {
118 - var browseParam = new URLSearchParams( window.location.search ).get( 'browse' );
119 - if ( ! browseParam ) {
190 + function getBrowseParam() {
191 + return new URLSearchParams( window.location.search ).get( 'browse' );
192 + }
193 + if ( ! getBrowseParam() ) {
120 194 return;
121 195 }
122 196 function applyActiveTab() {
197 + var browseParam = getBrowseParam();
198 + if ( ! browseParam ) {
199 + return true;
200 + }
123 201 var match = document.querySelector(
124 202 '.filter-links li > a[data-sort="' + browseParam + '"]'
125 203 );
126 204 if ( ! match ) {
@@ -178,5 +256,5 @@
178 256 JS;
179 257
180 258 wp_print_inline_script_tag( $js );
181 259 }
182 -add_action( 'admin_footer', 'desktop_mode_theme_install_active_tab_script', 100 );
260 +add_action( 'admin_footer', 'openstation_theme_install_active_tab_script', 100 );