is_block_editor() ); } public function get_global_css() { static $printed = false; if ( $printed || ( is_admin() && ! $this->is_needed_in_admin() ) ) { return; } $printed = true; // Validate every admin-set color to a hex literal before interpolating // into the "; if ( ! is_admin() ) { $this->print_theme_font_sizes(); } // Backend (wp-admin) dark mode — gated to Academy's own admin screens only, so // the #wpcontent/#wpbody-content override below never bleeds into other // plugins' admin pages. Scoped to (not
or #academywrap): // #academywrap is a DESCENDANT of #wpcontent/#wpbody-content, not an ancestor, // so a selector on #academywrap can't restyle its own parents — and // doesn't exist yet when this runs (admin_head fires inside ), so the // bootstrap script below targets document.documentElement (, available // immediately) to avoid a flash of light mode on every page load. See // openspec/changes/backend-dashboard-dark-mode/design.md decision 2. if ( is_admin() && Helper::is_academy_admin_page() ) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- All interpolations are sanitize_hex_color()-validated above; the rest of the "; }//end if } /** * Map Academy's type scale (--academy-fs-*) onto the font-size presets a * block theme -- or the site owner in Global Styles -- defines, so the * theme controls Academy's text sizes. Only presets from the `theme` / * `custom` origins count: WordPress core's own defaults are skipped, and * any size the theme does not define keeps Academy's default from * _global.scss. * * Block themes only: there the `medium` preset is the body text size. * Classic themes that ship a theme.json (Astra copies core's 13/20/36/42px) * mean their presets for editor content, not base text, so mapping them * would blow Academy's text up to 20px. A classic theme sets the * --academy-fs-* variables in its own CSS instead. * * @return void */ private function print_theme_font_sizes() { if ( ! function_exists( 'wp_get_global_settings' ) || ! Helper::is_fse_theme() ) { return; } $sizes = wp_get_global_settings( array( 'typography', 'fontSizes' ) ); $slugs = array(); foreach ( array( 'theme', 'custom' ) as $origin ) { if ( empty( $sizes[ $origin ] ) || ! is_array( $sizes[ $origin ] ) ) { continue; } foreach ( $sizes[ $origin ] as $size ) { if ( ! empty( $size['slug'] ) ) { $slugs[ $size['slug'] ] = true; } } } // Academy token => theme preset slugs, first match wins. $map = array( 'xs' => array( 'x-small', 'small' ), 'sm' => array( 'small' ), 'md' => array( 'medium' ), 'lg' => array( 'large' ), 'xl' => array( 'x-large' ), '2xl' => array( 'xx-large' ), ); $declarations = ''; foreach ( $map as $token => $candidates ) { foreach ( $candidates as $slug ) { if ( isset( $slugs[ $slug ] ) ) { $declarations .= sprintf( '--academy-fs-%s:var(--wp--preset--font-size--%s);', $token, $slug ); break; } } } if ( '' !== $declarations ) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Built only from the fixed token/slug map above. echo ''; } } }