Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions backport-changelog/7.0/10623.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
https://github.com/WordPress/wordpress-develop/pull/10623

* https://github.com/WordPress/gutenberg/pull/73971
70 changes: 25 additions & 45 deletions lib/block-editor-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,53 +41,33 @@ function gutenberg_get_block_editor_settings( $settings ) {
}
}

if ( wp_theme_has_theme_json() ) {
$block_classes = array(
'css' => 'styles',
'__unstableType' => 'theme',
'isGlobalStyles' => true,
);
$actual_css = gutenberg_get_global_stylesheet( array( $block_classes['css'] ) );
if ( '' !== $actual_css ) {
$block_classes['css'] = $actual_css;
$global_styles[] = $block_classes;
}
$block_classes = array(
'css' => 'styles',
'__unstableType' => 'theme',
'isGlobalStyles' => true,
);
$actual_css = gutenberg_get_global_stylesheet( array( $block_classes['css'] ) );
if ( '' !== $actual_css ) {
$block_classes['css'] = $actual_css;
$global_styles[] = $block_classes;
}

// Get any additional css from the customizer and add it before global styles custom CSS.
$global_styles[] = array(
'css' => wp_get_custom_css(),
'__unstableType' => 'user',
'isGlobalStyles' => false,
);
// Get any additional css from the customizer and add it before global styles custom CSS.
$global_styles[] = array(
'css' => wp_get_custom_css(),
'__unstableType' => 'user',
'isGlobalStyles' => false,
);

/*
* Add the custom CSS as a separate stylesheet so any invalid CSS
* entered by users does not break other global styles.
*/
$global_styles[] = array(
'css' => gutenberg_get_global_stylesheet( array( 'custom-css' ) ),
'__unstableType' => 'user',
'isGlobalStyles' => true,
);
} else {
// If there is no `theme.json` file, ensure base layout styles are still available.
$block_classes = array(
'css' => 'base-layout-styles',
'__unstableType' => 'base-layout',
'isGlobalStyles' => true,
);
$actual_css = gutenberg_get_global_stylesheet( array( $block_classes['css'] ) );
if ( '' !== $actual_css ) {
$block_classes['css'] = $actual_css;
$global_styles[] = $block_classes;
}
// Get any additional css from the customizer.
$global_styles[] = array(
'css' => wp_get_custom_css(),
'__unstableType' => 'user',
'isGlobalStyles' => false,
);
}
/*
* Add the custom CSS as a separate stylesheet so any invalid CSS
* entered by users does not break other global styles.
*/
$global_styles[] = array(
'css' => gutenberg_get_global_stylesheet( array( 'custom-css' ) ),
'__unstableType' => 'user',
'isGlobalStyles' => true,
);

$settings['styles'] = array_merge( $global_styles, get_block_editor_theme_styles() );

Expand Down
64 changes: 19 additions & 45 deletions lib/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -1390,14 +1390,14 @@ public function get_settings() {
* - `variables`: only the CSS Custom Properties for presets & custom ones.
* - `styles`: only the styles section in theme.json.
* - `presets`: only the classes for the presets.
* - `base-layout-styles`: only the base layout styles.
* - `custom-css`: only the custom CSS.
* @param array $origins A list of origins to include. By default it includes VALID_ORIGINS.
* @param array $options An array of options for now used for internal purposes only (may change without notice).
* The options currently supported are:
* - 'scope' that makes sure all style are scoped to a given selector
* - `root_selector` which overwrites and forces a given selector to be used on the root node
* - `skip_root_layout_styles` which omits root layout styles from the generated stylesheet.
* - `base_layout_styles` which when true generates only base layout styles without alignment rules. Defaults to false.
* - `include_block_style_variations` which includes CSS for block style variations.
* @return string The resulting stylesheet.
*/
Expand Down Expand Up @@ -1452,43 +1452,9 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets'

if ( in_array( 'styles', $types, true ) ) {
if ( false !== $root_style_key && empty( $options['skip_root_layout_styles'] ) ) {
$stylesheet .= $this->get_root_layout_rules( $style_nodes[ $root_style_key ]['selector'], $style_nodes[ $root_style_key ] );
$stylesheet .= $this->get_root_layout_rules( $style_nodes[ $root_style_key ]['selector'], $style_nodes[ $root_style_key ], $options );
}
$stylesheet .= $this->get_block_classes( $style_nodes );
} elseif ( in_array( 'base-layout-styles', $types, true ) ) {
$root_selector = static::ROOT_BLOCK_SELECTOR;
$columns_selector = '.wp-block-columns';
$post_template_selector = '.wp-block-post-template';
if ( ! empty( $options['scope'] ) ) {
$root_selector = static::scope_selector( $options['scope'], $root_selector );
$columns_selector = static::scope_selector( $options['scope'], $columns_selector );
$post_template_selector = static::scope_selector( $options['scope'], $post_template_selector );
}
if ( ! empty( $options['root_selector'] ) ) {
$root_selector = $options['root_selector'];
}
// Base layout styles are provided as part of `styles`, so only output separately if explicitly requested.
// For backwards compatibility, the Columns block is explicitly included, to support a different default gap value.
$base_styles_nodes = array(
array(
'path' => array( 'styles' ),
'selector' => $root_selector,
),
array(
'path' => array( 'styles', 'blocks', 'core/columns' ),
'selector' => $columns_selector,
'name' => 'core/columns',
),
array(
'path' => array( 'styles', 'blocks', 'core/post-template' ),
'selector' => $post_template_selector,
'name' => 'core/post-template',
),
);

foreach ( $base_styles_nodes as $base_style_node ) {
$stylesheet .= $this->get_layout_styles( $base_style_node, $types );
}
}

if ( in_array( 'presets', $types, true ) ) {
Expand Down Expand Up @@ -1723,9 +1689,10 @@ protected function get_block_classes( $style_nodes ) {
* @since 6.1.0
*
* @param array $block_metadata Metadata about the block to get styles for.
* @param array $options Optional. An array of options for now used for internal purposes only.
* @return string Layout styles for the block.
*/
protected function get_layout_styles( $block_metadata, $types = array() ) {
protected function get_layout_styles( $block_metadata, $options = array() ) {
$block_rules = '';
$block_type = null;

Expand Down Expand Up @@ -1871,8 +1838,9 @@ protected function get_layout_styles( $block_metadata, $types = array() ) {
foreach ( $base_style_rules as $base_style_rule ) {
$declarations = array();

// Skip outputting base styles for flow and constrained layout types if theme doesn't support theme.json. The 'base-layout-styles' type flags this.
if ( in_array( 'base-layout-styles', $types, true ) && ( 'default' === $layout_definition['name'] || 'constrained' === $layout_definition['name'] ) ) {
// Skip outputting base styles for flow and constrained layout types when base_layout_styles is enabled.
// These themes don't use .wp-site-blocks wrapper, so these layout-specific alignment styles aren't needed.
if ( ! empty( $options['base_layout_styles'] ) && ( 'default' === $layout_definition['name'] || 'constrained' === $layout_definition['name'] ) ) {
continue;
}

Expand Down Expand Up @@ -3200,11 +3168,12 @@ static function ( $pseudo_selector ) use ( $selector ) {
* @since 6.1.0
* @since 6.6.0 Use `ROOT_CSS_PROPERTIES_SELECTOR` for CSS custom properties.
*
* @param string $selector The root node selector.
* @param string $selector The root node selector.
* @param array $block_metadata The metadata for the root block.
* @param array $options Optional. An array of options. Default empty array.
* @return string The additional root rules CSS.
*/
public function get_root_layout_rules( $selector, $block_metadata ) {
public function get_root_layout_rules( $selector, $block_metadata, $options = array() ) {
$css = '';
$settings = $this->theme_json['settings'] ?? array();
$use_root_padding = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments'];
Expand Down Expand Up @@ -3245,9 +3214,14 @@ public function get_root_layout_rules( $selector, $block_metadata ) {
$css .= '.has-global-padding :where(:not(.alignfull.is-layout-flow) > .has-global-padding:not(.wp-block-block, .alignfull)) > .alignfull { margin-left: 0; margin-right: 0; }';
}

$css .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }';
$css .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }';
$css .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
// Skip outputting alignment styles when base_layout_styles is enabled.
// These styles target .wp-site-blocks which is only used by block themes.
if ( empty( $options['base_layout_styles'] ) ) {
$css .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }';
$css .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }';
$css .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
}

// Block gap styles will be output unless explicitly set to `null`. See static::PROTECTED_PROPERTIES.
if ( isset( $this->theme_json['settings']['spacing']['blockGap'] ) ) {
$block_gap_value = static::get_property_value( $this->theme_json, array( 'styles', 'spacing', 'blockGap' ) );
Expand All @@ -3258,7 +3232,7 @@ public function get_root_layout_rules( $selector, $block_metadata ) {
// For backwards compatibility, ensure the legacy block gap CSS variable is still available.
$css .= static::ROOT_CSS_PROPERTIES_SELECTOR . " { --wp--style--block-gap: $block_gap_value; }";
}
$css .= $this->get_layout_styles( $block_metadata );
$css .= $this->get_layout_styles( $block_metadata, $options );

return $css;
}
Expand Down
11 changes: 0 additions & 11 deletions lib/class-wp-theme-json-resolver-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -459,17 +459,6 @@ public static function get_user_data_from_wp_global_styles( $theme, $create_post
$theme = wp_get_theme();
}

/*
* Bail early if the theme does not support a theme.json.
*
* Since wp_theme_has_theme_json only supports the active
* theme, the extra condition for whether $theme is the active theme is
* present here.
*/
if ( $theme->get_stylesheet() === get_stylesheet() && ! wp_theme_has_theme_json() ) {
return array();
}

$user_cpt = array();
$post_type_filter = 'wp_global_styles';
$stylesheet = $theme->get_stylesheet();
Expand Down
144 changes: 144 additions & 0 deletions lib/compat/wordpress-7.0/global-styles.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?php
/**

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole file is only here to override the Core behavior, but in reality there's no really change here from core behavior outside calling the overridden Gutenberg theme.json functions...

* WordPress 7.0 compatibility functions for Global Styles.
*
* Overrides WordPress Core functions to enable full global styles support
* (including fonts) for classic themes without theme.json.
*
* @package gutenberg
*/

// Remove WordPress Core's wp_print_font_faces action.
remove_action( 'wp_head', 'wp_print_font_faces', 50 );

/**
* Gets font-face styles CSS for fonts from Gutenberg's global styles.
*
* WordPress Core's wp_print_font_faces() relies on wp_get_global_settings()
* which excludes custom origin for classic themes. This function uses
* Gutenberg's settings resolver to include user-customized fonts.
*
* @since Gutenberg 20.0.0
* @return string Font-face CSS.
*/
function gutenberg_get_font_face_styles() {
// Get settings using Gutenberg's resolver with custom origin.
$settings = gutenberg_get_global_settings();

// Bail out early if there are no font settings.
if ( empty( $settings['typography']['fontFamilies'] ) ) {
return '';
}

// Parse fonts from settings.
$fonts = array();
foreach ( $settings['typography']['fontFamilies'] as $font_families ) {
foreach ( $font_families as $definition ) {
// Skip if "fontFace" is not defined, meaning there are no variations.
if ( empty( $definition['fontFace'] ) ) {
Comment thread
youknowriad marked this conversation as resolved.
continue;
}

// Skip if "fontFamily" is not defined.
if ( empty( $definition['fontFamily'] ) ) {
continue;
}

$font_family_name = $definition['fontFamily'];
Comment thread
youknowriad marked this conversation as resolved.
// Parse font-family name from comma-separated lists.
if ( str_contains( $font_family_name, ',' ) ) {
$font_family_name = explode( ',', $font_family_name )[0];
}
$font_family_name = trim( $font_family_name, "\"'" );

// Skip if no font family is defined.
if ( empty( $font_family_name ) ) {
continue;
}
Comment on lines +49 to +57

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get this section.
If the $font_family_name happens to be a string with comma separated font names, it will convert it into an array

But after conversion to array, it executes a trim? Maybe you were looking for an array_map('trim', ...)? I'm have not dug too much into the format of the fontFamily, but finally it checks again if it's empty. Is there any chance of having a fontFamily like this , ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not able to reply the full question here but I suggest that we keep the code as is. This code is copied as is exactly from Core, it's only in Gutenberg because it's not filtrable so we need to override/copy the full function.

@SirLouen SirLouen Dec 15, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@youknowriad ok, I'm still trying to figure out how Gutenberg integrates with Core not as straightforward, as I thought.

I'm assuming you took the parse_settings from src/wp-includes/fonts/class-wp-font-face-resolver.php for this section and removed some elements for convenience, and then when 7.0 is released, this file will be ignored and changes will be manually merged into Core?

In this case, I'm going to send a PR in core to fix this part 👍

PS: I have tested and its not problematic as is returning just the first font family not the whole list so this section is technically correct.


// Convert font face properties.
$converted_font_faces = array();
foreach ( $definition['fontFace'] as $font_face ) {
Comment thread
youknowriad marked this conversation as resolved.
// Add the font-family property to the font-face.
$font_face['font-family'] = $font_family_name;

// Convert camelCase to kebab-case.
$converted_face = array();
foreach ( $font_face as $key => $value ) {
$kebab_case = _wp_to_kebab_case( $key );
$converted_face[ $kebab_case ] = $value;
}

$converted_font_faces[] = $converted_face;
}

$fonts[] = $converted_font_faces;
}
}

if ( empty( $fonts ) ) {
return '';
}

// Use WordPress Core's WP_Font_Face class to generate the CSS.
if ( ! class_exists( 'WP_Font_Face' ) ) {
return '';
}

// WP_Font_Face only has generate_and_print(), so use output buffering to capture.
ob_start();
$wp_font_face = new WP_Font_Face();
$wp_font_face->generate_and_print( $fonts );
$css = ob_get_clean();

// Remove the wrapping <style> tags if present, we'll add our own.
$css = preg_replace( '/<\/?style[^>]*>/', '', $css );

return trim( $css );
}

/**
* Prints font-face styles for fonts on the frontend.
*
* @since Gutenberg 20.0.0
*/
function gutenberg_print_font_faces() {
$font_face_styles = gutenberg_get_font_face_styles();
if ( ! empty( $font_face_styles ) ) {
printf( "<style id='wp-fonts-local'>\n%s\n</style>\n", $font_face_styles );
}
}
add_action( 'wp_head', 'gutenberg_print_font_faces', 50 );

/**
* Adds font-face styles to block editor settings.
*
* @since Gutenberg 20.0.0
*
* @param array $settings Block editor settings.
* @return array Modified settings.
*/
function gutenberg_add_font_face_styles_to_editor( $settings ) {
$font_face_styles = gutenberg_get_font_face_styles();

if ( ! empty( $font_face_styles ) ) {
// Add font faces as a style entry in the editor settings.
if ( ! isset( $settings['styles'] ) ) {
$settings['styles'] = array();
}

// Insert font faces at the beginning so they load before other styles.
array_unshift(
$settings['styles'],
array(
'css' => $font_face_styles,
'__unstableType' => 'font-faces',
'isGlobalStyles' => false,
)
);
}

return $settings;
}
// Run after gutenberg_get_block_editor_settings() which runs at priority 0.
add_filter( 'block_editor_settings_all', 'gutenberg_add_font_face_styles_to_editor', 5 );
Loading
Loading