diff --git a/lib/compat/wordpress-6.0/class-wp-theme-json-gutenberg.php b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php similarity index 99% rename from lib/compat/wordpress-6.0/class-wp-theme-json-gutenberg.php rename to lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php index 668082863114f..1a0945b175422 100644 --- a/lib/compat/wordpress-6.0/class-wp-theme-json-gutenberg.php +++ b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php @@ -14,7 +14,7 @@ * * @access private */ -class WP_Theme_JSON_Gutenberg extends WP_Theme_JSON_5_9 { +class WP_Theme_JSON_6_0 extends WP_Theme_JSON_5_9 { /** * Metadata for style properties. * diff --git a/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php b/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php new file mode 100644 index 0000000000000..3a53117593d1e --- /dev/null +++ b/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php @@ -0,0 +1,200 @@ +theme_json, $blocks_metadata, $separate_block_assets ); + $setting_nodes = static::get_setting_nodes( $this->theme_json, $blocks_metadata ); + + $stylesheet = ''; + + if ( in_array( 'variables', $types, true ) ) { + $stylesheet .= $this->get_css_variables( $setting_nodes, $origins ); + } + + if ( in_array( 'styles', $types, true ) ) { + $stylesheet .= $this->get_block_classes( $style_nodes_without_blocks ); + } + + if ( in_array( 'presets', $types, true ) ) { + $stylesheet .= $this->get_preset_classes( $setting_nodes, $origins ); + } + + return $stylesheet; + } + + /** + * Builds metadata for the style nodes, which returns in the form of: + * + * [ + * [ + * 'path' => [ 'path', 'to', 'some', 'node' ], + * 'selector' => 'CSS selector for some node', + * 'duotone' => 'CSS selector for duotone for some node' + * ], + * [ + * 'path' => ['path', 'to', 'other', 'node' ], + * 'selector' => 'CSS selector for other node', + * 'duotone' => null + * ], + * ] + * + * @since 5.8.0 + * + * @param array $theme_json The tree to extract style nodes from. + * @param array $selectors List of selectors per block. + * @param array $exclude_blocks Exclude blocks from the style nodes. + * @return array + */ + protected static function get_style_nodes( $theme_json, $selectors = array(), $exclude_blocks = false ) { + $nodes = array(); + if ( ! isset( $theme_json['styles'] ) ) { + return $nodes; + } + + // Top-level. + $nodes[] = array( + 'path' => array( 'styles' ), + 'selector' => static::ROOT_BLOCK_SELECTOR, + ); + + if ( isset( $theme_json['styles']['elements'] ) ) { + foreach ( $theme_json['styles']['elements'] as $element => $node ) { + $nodes[] = array( + 'path' => array( 'styles', 'elements', $element ), + 'selector' => static::ELEMENTS[ $element ], + ); + } + } + + if ( $exclude_blocks ) { + return $nodes; + } + + // Blocks. + if ( ! isset( $theme_json['styles']['blocks'] ) ) { + return $nodes; + } + + $nodes = array_merge( $nodes, static::get_block_nodes_private( $theme_json ) ); + + return $nodes; + } + + /** + * A public helper to get the block nodes from a theme.json file. + * + * @return array The block nodes in theme.json. + */ + public function get_block_nodes() { + return static::get_block_nodes_private( $this->theme_json ); + } + + /** + * An internal method to get the block nodes from a theme.json file. + * + * @param array $theme_json The theme.json converted to an array. + * + * @return array The block nodes in theme.json. + */ + private static function get_block_nodes_private( $theme_json ) { + $selectors = static::get_blocks_metadata(); + $nodes = array(); + if ( ! isset( $theme_json['styles'] ) ) { + return $nodes; + } + + // Blocks. + if ( ! isset( $theme_json['styles']['blocks'] ) ) { + return $nodes; + } + + foreach ( $theme_json['styles']['blocks'] as $name => $node ) { + $selector = null; + if ( isset( $selectors[ $name ]['selector'] ) ) { + $selector = $selectors[ $name ]['selector']; + } + + $duotone_selector = null; + if ( isset( $selectors[ $name ]['duotone'] ) ) { + $duotone_selector = $selectors[ $name ]['duotone']; + } + + $nodes[] = array( + 'name' => $name, + 'path' => array( 'styles', 'blocks', $name ), + 'selector' => $selector, + 'duotone' => $duotone_selector, + ); + + if ( isset( $theme_json['styles']['blocks'][ $name ]['elements'] ) ) { + foreach ( $theme_json['styles']['blocks'][ $name ]['elements'] as $element => $node ) { + $nodes[] = array( + 'path' => array( 'styles', 'blocks', $name, 'elements', $element ), + 'selector' => $selectors[ $name ]['elements'][ $element ], + ); + } + } + } + + return $nodes; + } + + /** + * Gets the CSS rules for a particular block from theme.json. + * + * @param array $block_metadata Meta data about the block to get styles for. + * + * @return array Styles for the block. + */ + public function get_styles_for_block( $block_metadata ) { + $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() ); + $selector = $block_metadata['selector']; + $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); + $declarations = static::compute_style_properties( $node, $settings ); + $block_rules = static::to_ruleset( $selector, $declarations ); + return $block_rules; + } +} diff --git a/lib/compat/wordpress-6.1/get-global-styles-and-settings.php b/lib/compat/wordpress-6.1/get-global-styles-and-settings.php new file mode 100644 index 0000000000000..c15fb46c8f66d --- /dev/null +++ b/lib/compat/wordpress-6.1/get-global-styles-and-settings.php @@ -0,0 +1,101 @@ +get_stylesheet( array( 'variables' ) ); + $types = array_diff( $types, array( 'variables' ) ); + } + + /* + * For the remaining types (presets, styles), we do consider origins: + * + * - themes without theme.json: only the classes for the presets defined by core + * - themes with theme.json: the presets and styles classes, both from core and the theme + */ + $styles_rest = ''; + if ( ! empty( $types ) ) { + $origins = array( 'default', 'theme', 'custom' ); + if ( ! $supports_theme_json ) { + $origins = array( 'default' ); + } + $styles_rest = $tree->get_stylesheet( $types, $origins ); + } + + $stylesheet = $styles_variables . $styles_rest; + + if ( $can_use_cached ) { + // Cache for a minute. + // This cache doesn't need to be any longer, we only want to avoid spikes on high-traffic sites. + set_transient( $transient_name, $stylesheet, MINUTE_IN_SECONDS ); + } + + return $stylesheet; +} + +/** + * Adds global style rules to the inline style for each block. + */ +function wp_add_global_styles_for_blocks() { + $tree = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data(); + // TODO some nodes dont have a name... + $block_nodes = $tree->get_block_nodes(); + + foreach ( $block_nodes as $metadata ) { + $block_css = $tree->get_styles_for_block( $metadata ); + $block_name = str_replace( 'core/', '', $metadata['name'] ); + wp_add_inline_style( 'wp-block-' . $block_name, $block_css ); + } + +} diff --git a/lib/compat/wordpress-6.1/script-loader.php b/lib/compat/wordpress-6.1/script-loader.php new file mode 100644 index 0000000000000..82548cf7f2d48 --- /dev/null +++ b/lib/compat/wordpress-6.1/script-loader.php @@ -0,0 +1,54 @@ +