diff --git a/wp-includes/block-editor.php b/wp-includes/block-editor.php index f1ec5d2d1acf..814433f27867 100644 --- a/wp-includes/block-editor.php +++ b/wp-includes/block-editor.php @@ -243,6 +243,50 @@ function get_block_editor_settings( $editor_name, $custom_settings = array() ) { $custom_settings ); + $editor_settings['__experimentalFeatures'] = WP_Theme_JSON_Resolver::get_merged_data( $editor_settings )->get_settings(); + + // These settings may need to be updated based on data coming from theme.json sources. + if ( isset( $editor_settings['__experimentalFeatures']['color']['palette'] ) ) { + $editor_settings['colors'] = $editor_settings['__experimentalFeatures']['color']['palette']; + unset( $editor_settings['__experimentalFeatures']['color']['palette'] ); + } + if ( isset( $editor_settings['__experimentalFeatures']['color']['gradients'] ) ) { + $editor_settings['gradients'] = $editor_settings['__experimentalFeatures']['color']['gradients']; + unset( $editor_settings['__experimentalFeatures']['color']['gradients'] ); + } + if ( isset( $editor_settings['__experimentalFeatures']['color']['custom'] ) ) { + $editor_settings['disableCustomColors'] = $editor_settings['__experimentalFeatures']['color']['custom']; + unset( $editor_settings['__experimentalFeatures']['color']['custom'] ); + } + if ( isset( $editor_settings['__experimentalFeatures']['color']['customGradient'] ) ) { + $editor_settings['disableCustomGradients'] = $editor_settings['__experimentalFeatures']['color']['customGradient']; + unset( $editor_settings['__experimentalFeatures']['color']['customGradient'] ); + } + if ( isset( $editor_settings['__experimentalFeatures']['typography']['fontSizes'] ) ) { + $editor_settings['fontSizes'] = $editor_settings['__experimentalFeatures']['typography']['fontSizes']; + unset( $editor_settings['__experimentalFeatures']['typography']['fontSizes'] ); + } + if ( isset( $editor_settings['__experimentalFeatures']['typography']['customFontSize'] ) ) { + $editor_settings['disableCustomFontSizes'] = $editor_settings['__experimentalFeatures']['typography']['customFontSize']; + unset( $editor_settings['__experimentalFeatures']['typography']['customFontSize'] ); + } + if ( isset( $editor_settings['__experimentalFeatures']['typography']['customLineHeight'] ) ) { + $editor_settings['enableCustomLineHeight'] = $editor_settings['__experimentalFeatures']['typography']['customLineHeight']; + unset( $editor_settings['__experimentalFeatures']['typography']['customLineHeight'] ); + } + if ( isset( $editor_settings['__experimentalFeatures']['spacing']['units'] ) ) { + if ( ! is_array( $editor_settings['__experimentalFeatures']['spacing']['units'] ) ) { + $editor_settings['enableCustomUnits'] = false; + } else { + $editor_settings['enableCustomUnits'] = count( $editor_settings['__experimentalFeatures']['spacing']['units'] ) > 0; + } + unset( $editor_settings['__experimentalFeatures']['spacing']['units'] ); + } + if ( isset( $editor_settings['__experimentalFeatures']['spacing']['customPadding'] ) ) { + $editor_settings['enableCustomSpacing'] = $editor_settings['__experimentalFeatures']['spacing']['customPadding']; + unset( $editor_settings['__experimentalFeatures']['spacing']['customPadding'] ); + } + /** * Filters the settings to pass to the block editor for all editor type. * diff --git a/wp-includes/class-wp-theme-json-resolver.php b/wp-includes/class-wp-theme-json-resolver.php new file mode 100644 index 000000000000..87e2fa4bf150 --- /dev/null +++ b/wp-includes/class-wp-theme-json-resolver.php @@ -0,0 +1,362 @@ + [ + * 'path' => [ 'settings', '*', 'typography', 'fontSizes' ], + * 'key' => 'name', + * 'context' => 'Font size name' + * ], + * 1 => [ + * 'path' => [ 'settings', '*', 'typography', 'fontStyles' ], + * 'key' => 'name', + * 'context' => 'Font style name' + * ] + * ] + * + * @param array $i18n_partial A tree that follows the format of i18n-theme.json. + * @param array $current_path Keeps track of the path as we walk down the given tree. + * + * @return array A linear array containing the paths to translate. + */ + private static function extract_paths_to_translate( $i18n_partial, $current_path = array() ) { + $result = array(); + foreach ( $i18n_partial as $property => $partial_child ) { + if ( is_numeric( $property ) ) { + foreach ( $partial_child as $key => $context ) { + return array( + array( + 'path' => $current_path, + 'key' => $key, + 'context' => $context, + ), + ); + } + } + $result = array_merge( + $result, + self::extract_paths_to_translate( $partial_child, array_merge( $current_path, array( $property ) ) ) + ); + } + return $result; + } + + /** + * Returns a data structure used in theme.json translation. + * + * @return array An array of theme.json fields that are translatable and the keys that are translatable + */ + public static function get_fields_to_translate() { + if ( null === self::$theme_json_i18n ) { + $file_structure = self::read_json_file( __DIR__ . '/theme-i18n.json' ); + self::$theme_json_i18n = self::extract_paths_to_translate( $file_structure ); + } + return self::$theme_json_i18n; + } + + /** + * Translates a chunk of the loaded theme.json structure. + * + * @param array $array_to_translate The chunk of theme.json to translate. + * @param string $key The key of the field that contains the string to translate. + * @param string $context The context to apply in the translation call. + * @param string $domain Text domain. Unique identifier for retrieving translated strings. + * + * @return array Returns the modified $theme_json chunk. + */ + private static function translate_theme_json_chunk( array $array_to_translate, $key, $context, $domain ) { + foreach ( $array_to_translate as $item_key => $item_to_translate ) { + if ( empty( $item_to_translate[ $key ] ) ) { + continue; + } + + // phpcs:ignore WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralContext,WordPress.WP.I18n.NonSingularStringLiteralDomain + $array_to_translate[ $item_key ][ $key ] = translate_with_gettext_context( $array_to_translate[ $item_key ][ $key ], $context, $domain ); + } + + return $array_to_translate; + } + + /** + * Given a theme.json structure modifies it in place + * to update certain values by its translated strings + * according to the language set by the user. + * + * @param array $theme_json The theme.json to translate. + * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. + * Default 'default'. + * + * @return array Returns the modified $theme_json_structure. + */ + private static function translate( $theme_json, $domain = 'default' ) { + $fields = self::get_fields_to_translate(); + foreach ( $fields as $field ) { + $path = $field['path']; + $key = $field['key']; + $context = $field['context']; + + /* + * We need to process the paths that include '*' separately. + * One example of such a path would be: + * [ 'settings', 'blocks', '*', 'color', 'palette' ] + */ + $nodes_to_iterate = array_keys( $path, '*', true ); + if ( ! empty( $nodes_to_iterate ) ) { + /* + * At the moment, we only need to support one '*' in the path, so take it directly. + * - base will be [ 'settings', 'blocks' ] + * - data will be [ 'color', 'palette' ] + */ + $base_path = array_slice( $path, 0, $nodes_to_iterate[0] ); + $data_path = array_slice( $path, $nodes_to_iterate[0] + 1 ); + $base_tree = _wp_array_get( $theme_json, $base_path, array() ); + foreach ( $base_tree as $node_name => $node_data ) { + $array_to_translate = _wp_array_get( $node_data, $data_path, null ); + if ( is_null( $array_to_translate ) ) { + continue; + } + + // Whole path will be [ 'settings', 'blocks', 'core/paragraph', 'color', 'palette' ]. + $whole_path = array_merge( $base_path, array( $node_name ), $data_path ); + $translated_array = self::translate_theme_json_chunk( $array_to_translate, $key, $context, $domain ); + _wp_array_set( $theme_json, $whole_path, $translated_array ); + } + } else { + $array_to_translate = _wp_array_get( $theme_json, $path, null ); + if ( is_null( $array_to_translate ) ) { + continue; + } + + $translated_array = self::translate_theme_json_chunk( $array_to_translate, $key, $context, $domain ); + _wp_array_set( $theme_json, $path, $translated_array ); + } + } + + return $theme_json; + } + + /** + * Return core's origin config. + * + * @return WP_Theme_JSON Entity that holds core data. + */ + public static function get_core_data() { + if ( null !== self::$core ) { + return self::$core; + } + + $config = self::read_json_file( __DIR__ . '/theme.json' ); + $config = self::translate( $config ); + self::$core = new WP_Theme_JSON( $config ); + + return self::$core; + } + + /** + * Returns the theme's data. + * + * Data from theme.json can be augmented via the + * $theme_support_data variable. This is useful, for example, + * to backfill the gaps in theme.json that a theme has declared + * via add_theme_supports. + * + * Note that if the same data is present in theme.json + * and in $theme_support_data, the theme.json's is not overwritten. + * + * @param array $theme_support_data Theme support data in theme.json format. + * + * @return WP_Theme_JSON Entity that holds theme data. + */ + public static function get_theme_data( $theme_support_data = array() ) { + if ( null === self::$theme ) { + $theme_json_data = self::read_json_file( self::get_file_path_from_theme( 'theme.json' ) ); + $theme_json_data = self::translate( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) ); + self::$theme = new WP_Theme_JSON( $theme_json_data ); + } + + if ( empty( $theme_support_data ) ) { + return self::$theme; + } + + /* + * We want the presets and settings declared in theme.json + * to override the ones declared via add_theme_support. + */ + $with_theme_supports = new WP_Theme_JSON( $theme_support_data ); + $with_theme_supports->merge( self::$theme ); + + return $with_theme_supports; + } + + /** + * There are different sources of data for a site: + * core and theme. + * + * While the getters {@link get_core_data}, + * {@link get_theme_data} return the raw data + * from the respective origins, this method merges them + * all together. + * + * If the same piece of data is declared in different origins (core and theme), + * the last origin overrides the previous. For example, + * if core disables custom colors but a theme enables them, + * the theme config wins. + * + * @param array $settings Existing block editor settings. + * Empty array by default. + * + * @return WP_Theme_JSON + */ + public static function get_merged_data( $settings = array() ) { + $theme_support_data = WP_Theme_JSON::get_from_editor_settings( $settings ); + + $result = new WP_Theme_JSON(); + $result->merge( self::get_core_data() ); + $result->merge( self::get_theme_data( $theme_support_data ) ); + + return $result; + } + + /** + * Whether the current theme has a theme.json file. + * + * @return boolean + */ + public static function theme_has_support() { + if ( ! isset( self::$theme_has_support ) ) { + self::$theme_has_support = (bool) self::get_file_path_from_theme( 'theme.json' ); + } + + return self::$theme_has_support; + } + + /** + * Builds the path to the given file + * and checks that it is readable. + * + * If it isn't, returns an empty string, + * otherwise returns the whole file path. + * + * @param string $file_name Name of the file. + * @return string The whole file path or empty if the file doesn't exist. + */ + private static function get_file_path_from_theme( $file_name ) { + // This used to be a locate_template call. + // However, that method proved problematic + // due to its use of constants (STYLESHEETPATH) + // that threw errors in some scenarios. + // + // When the theme.json merge algorithm properly supports + // child themes, this should also fallback + // to the template path, as locate_template did. + $located = ''; + $candidate = get_stylesheet_directory() . '/' . $file_name; + if ( is_readable( $candidate ) ) { + $located = $candidate; + } + return $located; + } + + /** + * Cleans the cached data so it can be recalculated. + */ + public static function clean_cached_data() { + self::$core = null; + self::$theme = null; + self::$theme_has_support = null; + self::$theme_json_i18n = null; + } + +} + +add_action( 'switch_theme', array( 'WP_Theme_JSON_Resolver', 'clean_cached_data' ) ); diff --git a/wp-includes/class-wp-theme-json.php b/wp-includes/class-wp-theme-json.php new file mode 100644 index 000000000000..b78f7c9be41f --- /dev/null +++ b/wp-includes/class-wp-theme-json.php @@ -0,0 +1,389 @@ + array( + 'custom' => null, + 'customGradient' => null, + 'duotone' => null, + 'gradients' => null, + 'link' => null, + 'palette' => null, + ), + 'custom' => null, + 'layout' => null, + 'spacing' => array( + 'customMargin' => null, + 'customPadding' => null, + 'units' => null, + ), + 'typography' => array( + 'customFontSize' => null, + 'customLineHeight' => null, + 'dropCap' => null, + 'fontSizes' => null, + ), + ); + + const LATEST_SCHEMA = 1; + + /** + * Constructor. + * + * @param array $theme_json A structure that follows the theme.json schema. + */ + public function __construct( $theme_json = array() ) { + if ( ! isset( $theme_json['version'] ) || self::LATEST_SCHEMA !== $theme_json['version'] ) { + $this->theme_json = array(); + return; + } + + $this->theme_json = self::sanitize( $theme_json ); + } + + /** + * Returns the allowed block names. + * + * @return array + */ + private static function get_allowed_block_names() { + if ( null !== self::$allowed_block_names ) { + return self::$allowed_block_names; + } + + self::$allowed_block_names = array_keys( WP_Block_Type_Registry::get_instance()->get_all_registered() ); + + return self::$allowed_block_names; + } + + /** + * Sanitizes the input according to the schemas. + * + * @param array $input Structure to sanitize. + * + * @return array The sanitized output. + */ + private static function sanitize( $input ) { + $output = array(); + + if ( ! is_array( $input ) ) { + return $output; + } + + $allowed_blocks = self::get_allowed_block_names(); + + $output = array_intersect_key( $input, array_flip( self::ALLOWED_TOP_LEVEL_KEYS ) ); + + // Build the schema. + $schema = array(); + $schema_settings_blocks = array(); + foreach ( $allowed_blocks as $block ) { + $schema_settings_blocks[ $block ] = self::ALLOWED_SETTINGS; + } + $schema['settings'] = self::ALLOWED_SETTINGS; + $schema['settings']['blocks'] = $schema_settings_blocks; + + // Remove anything that's not present in the schema. + foreach ( array( 'settings' ) as $subtree ) { + if ( ! isset( $input[ $subtree ] ) ) { + continue; + } + + if ( ! is_array( $input[ $subtree ] ) ) { + unset( $output[ $subtree ] ); + continue; + } + + $result = self::remove_keys_not_in_schema( $input[ $subtree ], $schema[ $subtree ] ); + + if ( empty( $result ) ) { + unset( $output[ $subtree ] ); + } else { + $output[ $subtree ] = $result; + } + } + + return $output; + } + + /** + * Given a tree, removes the keys that are not present in the schema. + * + * It is recursive and modifies the input in-place. + * + * @param array $tree Input to process. + * @param array $schema Schema to adhere to. + * + * @return array Returns the modified $tree. + */ + private static function remove_keys_not_in_schema( $tree, $schema ) { + $tree = array_intersect_key( $tree, $schema ); + + foreach ( $schema as $key => $data ) { + if ( ! isset( $tree[ $key ] ) ) { + continue; + } + + if ( is_array( $schema[ $key ] ) && is_array( $tree[ $key ] ) ) { + $tree[ $key ] = self::remove_keys_not_in_schema( $tree[ $key ], $schema[ $key ] ); + + if ( empty( $tree[ $key ] ) ) { + unset( $tree[ $key ] ); + } + } elseif ( is_array( $schema[ $key ] ) && ! is_array( $tree[ $key ] ) ) { + unset( $tree[ $key ] ); + } + } + + return $tree; + } + + /** + * Returns the existing settings for each block. + * + * Example: + * + * { + * 'root': { + * 'color': { + * 'custom': true + * } + * }, + * 'core/paragraph': { + * 'spacing': { + * 'customPadding': true + * } + * } + * } + * + * @return array Settings per block. + */ + public function get_settings() { + if ( ! isset( $this->theme_json['settings'] ) ) { + return array(); + } else { + return $this->theme_json['settings']; + } + } + + /** + * Builds metadata for the setting nodes, which returns in the form of: + * + * [ + * [ + * 'path' => ['path', 'to', 'some', 'node' ] + * ], + * [ + * 'path' => [ 'path', 'to', 'other', 'node' ] + * ], + * ] + * + * @param array $theme_json The tree to extract setting nodes from. + * + * @return array + */ + private static function get_setting_nodes( $theme_json ) { + $nodes = array(); + if ( ! isset( $theme_json['settings'] ) ) { + return $nodes; + } + + // Top-level. + $nodes[] = array( + 'path' => array( 'settings' ), + ); + + // Calculate paths for blocks. + if ( ! isset( $theme_json['settings']['blocks'] ) ) { + return $nodes; + } + + foreach ( $theme_json['settings']['blocks'] as $name => $node ) { + $nodes[] = array( + 'path' => array( 'settings', 'blocks', $name ), + ); + } + + return $nodes; + } + + /** + * Merge new incoming data. + * + * @param WP_Theme_JSON $incoming Data to merge. + */ + public function merge( $incoming ) { + $incoming_data = $incoming->get_raw_data(); + $this->theme_json = array_replace_recursive( $this->theme_json, $incoming_data ); + + // The array_replace_recursive algorithm merges at the leaf level. + // For leaf values that are arrays it will use the numeric indexes for replacement. + // In those cases, what we want is to use the incoming value, if it exists. + // + // These are the cases that have array values at the leaf levels. + $properties = array(); + $properties[] = array( 'color', 'palette' ); + $properties[] = array( 'color', 'gradients' ); + $properties[] = array( 'custom' ); + $properties[] = array( 'spacing', 'units' ); + $properties[] = array( 'typography', 'fontSizes' ); + $properties[] = array( 'typography', 'fontFamilies' ); + + $nodes = self::get_setting_nodes( $this->theme_json ); + foreach ( $nodes as $metadata ) { + foreach ( $properties as $property_path ) { + $path = array_merge( $metadata['path'], $property_path ); + $node = _wp_array_get( $incoming_data, $path, array() ); + if ( ! empty( $node ) ) { + _wp_array_set( $this->theme_json, $path, $node ); + } + } + } + + } + + /** + * Returns the raw data. + * + * @return array Raw data. + */ + public function get_raw_data() { + return $this->theme_json; + } + + /** + * + * Transforms the given editor settings according the + * add_theme_support format to the theme.json format. + * + * @param array $settings Existing editor settings. + * + * @return array Config that adheres to the theme.json schema. + */ + public static function get_from_editor_settings( $settings ) { + $theme_settings = array( + 'version' => self::LATEST_SCHEMA, + 'settings' => array(), + ); + + // Deprecated theme supports. + if ( isset( $settings['disableCustomColors'] ) ) { + if ( ! isset( $theme_settings['settings']['color'] ) ) { + $theme_settings['settings']['color'] = array(); + } + $theme_settings['settings']['color']['custom'] = ! $settings['disableCustomColors']; + } + + if ( isset( $settings['disableCustomGradients'] ) ) { + if ( ! isset( $theme_settings['settings']['color'] ) ) { + $theme_settings['settings']['color'] = array(); + } + $theme_settings['settings']['color']['customGradient'] = ! $settings['disableCustomGradients']; + } + + if ( isset( $settings['disableCustomFontSizes'] ) ) { + if ( ! isset( $theme_settings['settings']['typography'] ) ) { + $theme_settings['settings']['typography'] = array(); + } + $theme_settings['settings']['typography']['customFontSize'] = ! $settings['disableCustomFontSizes']; + } + + if ( isset( $settings['enableCustomLineHeight'] ) ) { + if ( ! isset( $theme_settings['settings']['typography'] ) ) { + $theme_settings['settings']['typography'] = array(); + } + $theme_settings['settings']['typography']['customLineHeight'] = $settings['enableCustomLineHeight']; + } + + if ( isset( $settings['enableCustomUnits'] ) ) { + if ( ! isset( $theme_settings['settings']['spacing'] ) ) { + $theme_settings['settings']['spacing'] = array(); + } + $theme_settings['settings']['spacing']['units'] = ( true === $settings['enableCustomUnits'] ) ? + array( 'px', 'em', 'rem', 'vh', 'vw' ) : + $settings['enableCustomUnits']; + } + + if ( isset( $settings['colors'] ) ) { + if ( ! isset( $theme_settings['settings']['color'] ) ) { + $theme_settings['settings']['color'] = array(); + } + $theme_settings['settings']['color']['palette'] = $settings['colors']; + } + + if ( isset( $settings['gradients'] ) ) { + if ( ! isset( $theme_settings['settings']['color'] ) ) { + $theme_settings['settings']['color'] = array(); + } + $theme_settings['settings']['color']['gradients'] = $settings['gradients']; + } + + if ( isset( $settings['fontSizes'] ) ) { + $font_sizes = $settings['fontSizes']; + // Back-compatibility for presets without units. + foreach ( $font_sizes as $key => $font_size ) { + if ( is_numeric( $font_size['size'] ) ) { + $font_sizes[ $key ]['size'] = $font_size['size'] . 'px'; + } + } + if ( ! isset( $theme_settings['settings']['typography'] ) ) { + $theme_settings['settings']['typography'] = array(); + } + $theme_settings['settings']['typography']['fontSizes'] = $font_sizes; + } + + // This allows to make the plugin work with WordPress 5.7 beta + // as well as lower versions. The second check can be removed + // as soon as the minimum WordPress version for the plugin + // is bumped to 5.7. + if ( isset( $settings['enableCustomSpacing'] ) ) { + if ( ! isset( $theme_settings['settings']['spacing'] ) ) { + $theme_settings['settings']['spacing'] = array(); + } + $theme_settings['settings']['spacing']['customPadding'] = $settings['enableCustomSpacing']; + } + + // Things that didn't land in core yet, so didn't have a setting assigned. + if ( current( (array) get_theme_support( 'experimental-link-color' ) ) ) { + if ( ! isset( $theme_settings['settings']['color'] ) ) { + $theme_settings['settings']['color'] = array(); + } + $theme_settings['settings']['color']['link'] = true; + } + + return $theme_settings; + } + +} diff --git a/wp-includes/theme-i18n.json b/wp-includes/theme-i18n.json new file mode 100644 index 000000000000..a01a5aa566b4 --- /dev/null +++ b/wp-includes/theme-i18n.json @@ -0,0 +1,51 @@ +{ + "settings": { + "typography": { + "fontSizes": [ + { + "name": "Font size name" + } + ] + }, + "color": { + "palette": [ + { + "name": "Color name" + } + ], + "gradients": [ + { + "name": "Gradient name" + } + ], + "duotone": [ + { + "name": "Duotone name" + } + ] + }, + "blocks": { + "*": { + "typography": { + "fontSizes": [ + { + "name": "Font size name" + } + ] + }, + "color": { + "palette": [ + { + "name": "Color name" + } + ], + "gradients": [ + { + "name": "Gradient name" + } + ] + } + } + } + } +} diff --git a/wp-includes/theme.json b/wp-includes/theme.json new file mode 100644 index 000000000000..eafaf0d69b37 --- /dev/null +++ b/wp-includes/theme.json @@ -0,0 +1,213 @@ +{ + "version": 1, + "settings": { + "color": { + "custom": true, + "customGradient": true, + "duotone": [ + { + "name": "Dark grayscale" , + "colors": [ "#000000", "#7f7f7f" ], + "slug": "dark-grayscale" + }, + { + "name": "Grayscale" , + "colors": [ "#000000", "#ffffff" ], + "slug": "grayscale" + }, + { + "name": "Purple and yellow" , + "colors": [ "#8c00b7", "#fcff41" ], + "slug": "purple-yellow" + }, + { + "name": "Blue and red" , + "colors": [ "#000097", "#ff4747" ], + "slug": "blue-red" + }, + { + "name": "Midnight" , + "colors": [ "#000000", "#00a5ff" ], + "slug": "midnight" + }, + { + "name": "Magenta and yellow" , + "colors": [ "#c7005a", "#fff278" ], + "slug": "magenta-yellow" + }, + { + "name": "Purple and green" , + "colors": [ "#a60072", "#67ff66" ], + "slug": "purple-green" + }, + { + "name": "Blue and orange" , + "colors": [ "#1900d8", "#ffa96b" ], + "slug": "blue-orange" + } + ], + "gradients": [ + { + "name": "Vivid cyan blue to vivid purple", + "gradient": "linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)", + "slug": "vivid-cyan-blue-to-vivid-purple" + }, + { + "name": "Light green cyan to vivid green cyan", + "gradient": "linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%)", + "slug": "light-green-cyan-to-vivid-green-cyan" + }, + { + "name": "Luminous vivid amber to luminous vivid orange", + "gradient": "linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%)", + "slug": "luminous-vivid-amber-to-luminous-vivid-orange" + }, + { + "name": "Luminous vivid orange to vivid red", + "gradient": "linear-gradient(135deg,rgba(255,105,0,1) 0%,rgb(207,46,46) 100%)", + "slug": "luminous-vivid-orange-to-vivid-red" + }, + { + "name": "Very light gray to cyan bluish gray", + "gradient": "linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%)", + "slug": "very-light-gray-to-cyan-bluish-gray" + }, + { + "name": "Cool to warm spectrum", + "gradient": "linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%)", + "slug": "cool-to-warm-spectrum" + }, + { + "name": "Blush light purple", + "gradient": "linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%)", + "slug": "blush-light-purple" + }, + { + "name": "Blush bordeaux", + "gradient": "linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%)", + "slug": "blush-bordeaux" + }, + { + "name": "Luminous dusk", + "gradient": "linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%)", + "slug": "luminous-dusk" + }, + { + "name": "Pale ocean", + "gradient": "linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%)", + "slug": "pale-ocean" + }, + { + "name": "Electric grass", + "gradient": "linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%)", + "slug": "electric-grass" + }, + { + "name": "Midnight", + "gradient": "linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%)", + "slug": "midnight" + } + ], + "link": false, + "palette": [ + { + "name": "Black", + "slug": "black", + "color": "#000000" + }, + { + "name": "Cyan bluish gray", + "slug": "cyan-bluish-gray", + "color": "#abb8c3" + }, + { + "name": "White", + "slug": "white", + "color": "#ffffff" + }, + { + "name": "Pale pink", + "slug": "pale-pink", + "color": "#f78da7" + }, + { + "name": "Vivid red", + "slug": "vivid-red", + "color": "#cf2e2e" + }, + { + "name": "Luminous vivid orange", + "slug": "luminous-vivid-orange", + "color": "#ff6900" + }, + { + "name": "Luminous vivid amber", + "slug": "luminous-vivid-amber", + "color": "#fcb900" + }, + { + "name": "Light green cyan", + "slug": "light-green-cyan", + "color": "#7bdcb5" + }, + { + "name": "Vivid green cyan", + "slug": "vivid-green-cyan", + "color": "#00d084" + }, + { + "name": "Pale cyan blue", + "slug": "pale-cyan-blue", + "color": "#8ed1fc" + }, + { + "name": "Vivid cyan blue", + "slug": "vivid-cyan-blue", + "color": "#0693e3" + }, + { + "name": "Vivid purple", + "slug": "vivid-purple", + "color": "#9b51e0" + } + ] + }, + "spacing": { + "customMargin": false, + "customPadding": false, + "units": [ "px", "em", "rem", "vh", "vw" ] + }, + "typography": { + "customFontSize": true, + "customLineHeight": false, + "dropCap": true, + "fontSizes": [ + { + "name": "Small", + "slug": "small", + "size": "13px" + }, + { + "name": "Normal", + "slug": "normal", + "size": "16px" + }, + { + "name": "Medium", + "slug": "medium", + "size": "20px" + }, + { + "name": "Large", + "slug": "large", + "size": "36px" + }, + { + "name": "Huge", + "slug": "huge", + "size": "42px" + } + ] + } + } +} diff --git a/wp-includes/version.php b/wp-includes/version.php index d69f7755f5e7..4eb0e3750688 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -13,7 +13,7 @@ * * @global string $wp_version */ -$wp_version = '5.8-alpha-50958'; +$wp_version = '5.8-alpha-50959'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. diff --git a/wp-settings.php b/wp-settings.php index 79574e4b2fb0..45949fda9119 100644 --- a/wp-settings.php +++ b/wp-settings.php @@ -295,6 +295,8 @@ require ABSPATH . WPINC . '/class-wp-block-parser.php'; require ABSPATH . WPINC . '/blocks.php'; require ABSPATH . WPINC . '/blocks/index.php'; +require ABSPATH . WPINC . '/class-wp-theme-json.php'; +require ABSPATH . WPINC . '/class-wp-theme-json-resolver.php'; require ABSPATH . WPINC . '/block-editor.php'; require ABSPATH . WPINC . '/block-patterns.php'; require ABSPATH . WPINC . '/class-wp-block-supports.php';