mirror of
https://github.com/WordPress/WordPress.git
synced 2025-01-03 06:57:35 +01:00
Editor: Add functionality required for theme export in the site editor
This bring across changes to theme export functionality, and related code, and tests. Relates issue in Gutenberg: https://github.com/WordPress/gutenberg/issues/39889. Props scruffian, timothyblynjacobs, oandregal, ajlende, zieleadam. See #55505. Built from https://develop.svn.wordpress.org/trunk@53129 git-svn-id: http://core.svn.wordpress.org/trunk@52718 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
5d78798b5c
commit
9e3c5a4215
@ -119,11 +119,11 @@ function get_default_block_template_types() {
|
|||||||
),
|
),
|
||||||
'home' => array(
|
'home' => array(
|
||||||
'title' => _x( 'Home', 'Template name' ),
|
'title' => _x( 'Home', 'Template name' ),
|
||||||
'description' => __( 'Displays as the site\'s home page, or as the Posts page when a static home page isn\'t set.' ),
|
'description' => __( 'Displays posts on the homepage, or on the Posts page if a static homepage is set.' ),
|
||||||
),
|
),
|
||||||
'front-page' => array(
|
'front-page' => array(
|
||||||
'title' => _x( 'Front Page', 'Template name' ),
|
'title' => _x( 'Front Page', 'Template name' ),
|
||||||
'description' => __( 'Displays as the site\'s home page.' ),
|
'description' => __( 'Displays the homepage.' ),
|
||||||
),
|
),
|
||||||
'singular' => array(
|
'singular' => array(
|
||||||
'title' => _x( 'Singular', 'Template name' ),
|
'title' => _x( 'Singular', 'Template name' ),
|
||||||
@ -162,12 +162,12 @@ function get_default_block_template_types() {
|
|||||||
'description' => __( 'Displays latest posts with a single post tag.' ),
|
'description' => __( 'Displays latest posts with a single post tag.' ),
|
||||||
),
|
),
|
||||||
'attachment' => array(
|
'attachment' => array(
|
||||||
'title' => __( 'Attachment' ),
|
'title' => __( 'Media' ),
|
||||||
'description' => __( 'Displays individual media items or attachments.' ),
|
'description' => __( 'Displays individual media items or attachments.' ),
|
||||||
),
|
),
|
||||||
'search' => array(
|
'search' => array(
|
||||||
'title' => _x( 'Search', 'Template name' ),
|
'title' => _x( 'Search', 'Template name' ),
|
||||||
'description' => __( 'Template used to display search results.' ),
|
'description' => __( 'Displays search results.' ),
|
||||||
),
|
),
|
||||||
'privacy-policy' => array(
|
'privacy-policy' => array(
|
||||||
'title' => __( 'Privacy Policy' ),
|
'title' => __( 'Privacy Policy' ),
|
||||||
@ -902,12 +902,32 @@ function block_footer_area() {
|
|||||||
block_template_part( 'footer' );
|
block_template_part( 'footer' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters theme directories that should be ignored during export.
|
||||||
|
*
|
||||||
|
* @since 6.0.0
|
||||||
|
*
|
||||||
|
* @param string $path The path of the file in the theme.
|
||||||
|
* @return Bool Whether this file is in an ignored directory.
|
||||||
|
*/
|
||||||
|
function wp_is_theme_directory_ignored( $path ) {
|
||||||
|
$directories_to_ignore = array( '.svn', '.git', '.hg', '.bzr', 'node_modules', 'vendor' );
|
||||||
|
foreach ( $directories_to_ignore as $directory ) {
|
||||||
|
if ( strpos( $path, $directory ) === 0 ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an export of the current templates and
|
* Creates an export of the current templates and
|
||||||
* template parts from the site editor at the
|
* template parts from the site editor at the
|
||||||
* specified path in a ZIP file.
|
* specified path in a ZIP file.
|
||||||
*
|
*
|
||||||
* @since 5.9.0
|
* @since 5.9.0
|
||||||
|
* @since 6.0.0 Adds the whole theme to the export archive.
|
||||||
*
|
*
|
||||||
* @return WP_Error|string Path of the ZIP file or error on failure.
|
* @return WP_Error|string Path of the ZIP file or error on failure.
|
||||||
*/
|
*/
|
||||||
@ -916,17 +936,40 @@ function wp_generate_block_templates_export_file() {
|
|||||||
return new WP_Error( 'missing_zip_package', __( 'Zip Export not supported.' ) );
|
return new WP_Error( 'missing_zip_package', __( 'Zip Export not supported.' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
$obscura = wp_generate_password( 12, false, false );
|
$obscura = wp_generate_password( 12, false, false );
|
||||||
$filename = get_temp_dir() . 'edit-site-export-' . $obscura . '.zip';
|
$theme_name = wp_get_theme()->get( 'TextDomain' );
|
||||||
|
$filename = get_temp_dir() . $theme_name . $obscura . '.zip';
|
||||||
|
|
||||||
$zip = new ZipArchive();
|
$zip = new ZipArchive();
|
||||||
if ( true !== $zip->open( $filename, ZipArchive::CREATE ) ) {
|
if ( true !== $zip->open( $filename, ZipArchive::CREATE | ZipArchive::OVERWRITE ) ) {
|
||||||
return new WP_Error( 'unable_to_create_zip', __( 'Unable to open export file (archive) for writing.' ) );
|
return new WP_Error( 'unable_to_create_zip', __( 'Unable to open export file (archive) for writing.' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
$zip->addEmptyDir( 'theme' );
|
$zip->addEmptyDir( 'templates' );
|
||||||
$zip->addEmptyDir( 'theme/templates' );
|
$zip->addEmptyDir( 'parts' );
|
||||||
$zip->addEmptyDir( 'theme/parts' );
|
|
||||||
|
// Get path of the theme.
|
||||||
|
$theme_path = wp_normalize_path( get_stylesheet_directory() );
|
||||||
|
|
||||||
|
// Create recursive directory iterator.
|
||||||
|
$theme_files = new RecursiveIteratorIterator(
|
||||||
|
new RecursiveDirectoryIterator( $theme_path ),
|
||||||
|
RecursiveIteratorIterator::LEAVES_ONLY
|
||||||
|
);
|
||||||
|
|
||||||
|
// Make a copy of the current theme.
|
||||||
|
foreach ( $theme_files as $file ) {
|
||||||
|
// Skip directories as they are added automatically.
|
||||||
|
if ( ! $file->isDir() ) {
|
||||||
|
// Get real and relative path for current file.
|
||||||
|
$file_path = wp_normalize_path( $file );
|
||||||
|
$relative_path = substr( $file_path, strlen( $theme_path ) + 1 );
|
||||||
|
|
||||||
|
if ( ! wp_is_theme_directory_ignored( $relative_path ) ) {
|
||||||
|
$zip->addFile( $file_path, $relative_path );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Load templates into the zip file.
|
// Load templates into the zip file.
|
||||||
$templates = get_block_templates();
|
$templates = get_block_templates();
|
||||||
@ -934,7 +977,7 @@ function wp_generate_block_templates_export_file() {
|
|||||||
$template->content = _remove_theme_attribute_in_block_template_content( $template->content );
|
$template->content = _remove_theme_attribute_in_block_template_content( $template->content );
|
||||||
|
|
||||||
$zip->addFromString(
|
$zip->addFromString(
|
||||||
'theme/templates/' . $template->slug . '.html',
|
'templates/' . $template->slug . '.html',
|
||||||
$template->content
|
$template->content
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -943,11 +986,37 @@ function wp_generate_block_templates_export_file() {
|
|||||||
$template_parts = get_block_templates( array(), 'wp_template_part' );
|
$template_parts = get_block_templates( array(), 'wp_template_part' );
|
||||||
foreach ( $template_parts as $template_part ) {
|
foreach ( $template_parts as $template_part ) {
|
||||||
$zip->addFromString(
|
$zip->addFromString(
|
||||||
'theme/parts/' . $template_part->slug . '.html',
|
'parts/' . $template_part->slug . '.html',
|
||||||
$template_part->content
|
$template_part->content
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load theme.json into the zip file.
|
||||||
|
$tree = WP_Theme_JSON_Resolver::get_theme_data( array(), array( 'with_supports' => false ) );
|
||||||
|
// Merge with user data.
|
||||||
|
$tree->merge( WP_Theme_JSON_Resolver::get_user_data() );
|
||||||
|
|
||||||
|
$theme_json_raw = $tree->get_data();
|
||||||
|
// If a version is defined, add a schema.
|
||||||
|
if ( $theme_json_raw['version'] ) {
|
||||||
|
global $wp_version;
|
||||||
|
$theme_json_version = 'wp/' . substr( $wp_version, 0, 3 );
|
||||||
|
$schema = array( '$schema' => 'https://schemas.wp.org/' . $theme_json_version . '/theme.json' );
|
||||||
|
$theme_json_raw = array_merge( $schema, $theme_json_raw );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to a string.
|
||||||
|
$theme_json_encoded = wp_json_encode( $theme_json_raw, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
|
||||||
|
|
||||||
|
// Replace 4 spaces with a tab.
|
||||||
|
$theme_json_tabbed = preg_replace( '~(?:^|\G)\h{4}~m', "\t", $theme_json_encoded );
|
||||||
|
|
||||||
|
// Add the theme.json file to the zip.
|
||||||
|
$zip->addFromString(
|
||||||
|
'theme.json',
|
||||||
|
$theme_json_tabbed
|
||||||
|
);
|
||||||
|
|
||||||
// Save changes to the zip file.
|
// Save changes to the zip file.
|
||||||
$zip->close();
|
$zip->close();
|
||||||
|
|
||||||
|
@ -151,14 +151,19 @@ class WP_Theme_JSON_Resolver {
|
|||||||
*
|
*
|
||||||
* @since 5.8.0
|
* @since 5.8.0
|
||||||
* @since 5.9.0 Theme supports have been inlined and the `$theme_support_data` argument removed.
|
* @since 5.9.0 Theme supports have been inlined and the `$theme_support_data` argument removed.
|
||||||
|
* @since 6.0.0 Adds a second parameter to allow the theme data to be returned without theme supports.
|
||||||
*
|
*
|
||||||
* @param array $deprecated Deprecated. Not used.
|
* @param array $deprecated Deprecated. Not used.
|
||||||
|
* @param array $options Contains a key called with_supports to determine whether to include theme supports in the data.
|
||||||
* @return WP_Theme_JSON Entity that holds theme data.
|
* @return WP_Theme_JSON Entity that holds theme data.
|
||||||
*/
|
*/
|
||||||
public static function get_theme_data( $deprecated = array() ) {
|
public static function get_theme_data( $deprecated = array(), $options = array() ) {
|
||||||
if ( ! empty( $deprecated ) ) {
|
if ( ! empty( $deprecated ) ) {
|
||||||
_deprecated_argument( __METHOD__, '5.9.0' );
|
_deprecated_argument( __METHOD__, '5.9.0' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$options = wp_parse_args( $options, array( 'with_supports' => true ) );
|
||||||
|
|
||||||
if ( null === static::$theme ) {
|
if ( null === static::$theme ) {
|
||||||
$theme_json_data = static::read_json_file( static::get_file_path_from_theme( 'theme.json' ) );
|
$theme_json_data = static::read_json_file( static::get_file_path_from_theme( 'theme.json' ) );
|
||||||
$theme_json_data = static::translate( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) );
|
$theme_json_data = static::translate( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) );
|
||||||
@ -177,6 +182,10 @@ class WP_Theme_JSON_Resolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! $options['with_supports'] ) {
|
||||||
|
return static::$theme;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We want the presets and settings declared in theme.json
|
* We want the presets and settings declared in theme.json
|
||||||
* to override the ones declared via theme supports.
|
* to override the ones declared via theme supports.
|
||||||
@ -208,6 +217,9 @@ class WP_Theme_JSON_Resolver {
|
|||||||
$default_gradients = true;
|
$default_gradients = true;
|
||||||
}
|
}
|
||||||
$theme_support_data['settings']['color']['defaultGradients'] = $default_gradients;
|
$theme_support_data['settings']['color']['defaultGradients'] = $default_gradients;
|
||||||
|
|
||||||
|
// Classic themes without a theme.json don't support global duotone.
|
||||||
|
$theme_support_data['settings']['color']['defaultDuotone'] = false;
|
||||||
}
|
}
|
||||||
$with_theme_supports = new WP_Theme_JSON( $theme_support_data );
|
$with_theme_supports = new WP_Theme_JSON( $theme_support_data );
|
||||||
$with_theme_supports->merge( static::$theme );
|
$with_theme_supports->merge( static::$theme );
|
||||||
@ -477,4 +489,5 @@ class WP_Theme_JSON_Resolver {
|
|||||||
}
|
}
|
||||||
return $variations;
|
return $variations;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -74,41 +74,49 @@ class WP_Theme_JSON {
|
|||||||
*
|
*
|
||||||
* This contains the necessary metadata to process them:
|
* This contains the necessary metadata to process them:
|
||||||
*
|
*
|
||||||
* - path => where to find the preset within the settings section
|
* - path => Where to find the preset within the settings section.
|
||||||
* - override => whether a theme preset with the same slug as a default preset
|
* - prevent_override => Disables override of default presets by theme presets.
|
||||||
* can override it
|
* The relationship between whether to override the defaults
|
||||||
|
* and whether the defaults are enabled is inverse:
|
||||||
|
* - If defaults are enabled => theme presets should not be overriden
|
||||||
|
* - If defaults are disabled => theme presets should be overriden
|
||||||
|
* For example, a theme sets defaultPalette to false,
|
||||||
|
* making the default palette hidden from the user.
|
||||||
|
* In that case, we want all the theme presets to be present,
|
||||||
|
* so they should override the defaults by setting this false.
|
||||||
* - use_default_names => whether to use the default names
|
* - use_default_names => whether to use the default names
|
||||||
* - value_key => the key that represents the value
|
* - value_key => the key that represents the value
|
||||||
* - value_func => optionally, instead of value_key, a function to generate
|
* - value_func => optionally, instead of value_key, a function to generate
|
||||||
* the value that takes a preset as an argument
|
* the value that takes a preset as an argument
|
||||||
* (either value_key or value_func should be present)
|
* (either value_key or value_func should be present)
|
||||||
* - css_vars => template string to use in generating the CSS Custom Property.
|
* - css_vars => template string to use in generating the CSS Custom Property.
|
||||||
* Example output: "--wp--preset--duotone--blue: <value>" will generate
|
* Example output: "--wp--preset--duotone--blue: <value>" will generate as many CSS Custom Properties as presets defined
|
||||||
* as many CSS Custom Properties as presets defined
|
* substituting the $slug for the slug's value for each preset value.
|
||||||
* substituting the $slug for the slug's value for each preset value.
|
* - classes => array containing a structure with the classes to
|
||||||
* - classes => array containing a structure with the classes to
|
* generate for the presets, where for each array item
|
||||||
* generate for the presets, where for each array item
|
* the key is the class name and the value the property name.
|
||||||
* the key is the class name and the value the property name.
|
* The "$slug" substring will be replaced by the slug of each preset.
|
||||||
* The "$slug" substring will be replaced by the slug of each preset.
|
* For example:
|
||||||
* For example:
|
* 'classes' => array(
|
||||||
* 'classes' => array(
|
* '.has-$slug-color' => 'color',
|
||||||
* '.has-$slug-color' => 'color',
|
* '.has-$slug-background-color' => 'background-color',
|
||||||
* '.has-$slug-background-color' => 'background-color',
|
* '.has-$slug-border-color' => 'border-color',
|
||||||
* '.has-$slug-border-color' => 'border-color',
|
* )
|
||||||
* )
|
* - properties => array of CSS properties to be used by kses to
|
||||||
* - properties => array of CSS properties to be used by kses to
|
* validate the content of each preset
|
||||||
* validate the content of each preset
|
* by means of the remove_insecure_properties method.
|
||||||
* by means of the remove_insecure_properties method.
|
|
||||||
*
|
*
|
||||||
* @since 5.8.0
|
* @since 5.8.0
|
||||||
* @since 5.9.0 Added the `color.duotone` and `typography.fontFamilies` presets,
|
* @since 5.9.0 Added the `color.duotone` and `typography.fontFamilies` presets,
|
||||||
* `use_default_names` preset key, and simplified the metadata structure.
|
* `use_default_names` preset key, and simplified the metadata structure.
|
||||||
|
* @since 6.0.0 Replaced `override` with `prevent_override` and updated the
|
||||||
|
* `prevent_overried` value for `color.duotone` to use `color.defaultDuotone`.
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
const PRESETS_METADATA = array(
|
const PRESETS_METADATA = array(
|
||||||
array(
|
array(
|
||||||
'path' => array( 'color', 'palette' ),
|
'path' => array( 'color', 'palette' ),
|
||||||
'override' => array( 'color', 'defaultPalette' ),
|
'prevent_override' => array( 'color', 'defaultPalette' ),
|
||||||
'use_default_names' => false,
|
'use_default_names' => false,
|
||||||
'value_key' => 'color',
|
'value_key' => 'color',
|
||||||
'css_vars' => '--wp--preset--color--$slug',
|
'css_vars' => '--wp--preset--color--$slug',
|
||||||
@ -121,7 +129,7 @@ class WP_Theme_JSON {
|
|||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'path' => array( 'color', 'gradients' ),
|
'path' => array( 'color', 'gradients' ),
|
||||||
'override' => array( 'color', 'defaultGradients' ),
|
'prevent_override' => array( 'color', 'defaultGradients' ),
|
||||||
'use_default_names' => false,
|
'use_default_names' => false,
|
||||||
'value_key' => 'gradient',
|
'value_key' => 'gradient',
|
||||||
'css_vars' => '--wp--preset--gradient--$slug',
|
'css_vars' => '--wp--preset--gradient--$slug',
|
||||||
@ -130,7 +138,7 @@ class WP_Theme_JSON {
|
|||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'path' => array( 'color', 'duotone' ),
|
'path' => array( 'color', 'duotone' ),
|
||||||
'override' => true,
|
'prevent_override' => array( 'color', 'defaultDuotone' ),
|
||||||
'use_default_names' => false,
|
'use_default_names' => false,
|
||||||
'value_func' => 'wp_get_duotone_filter_property',
|
'value_func' => 'wp_get_duotone_filter_property',
|
||||||
'css_vars' => '--wp--preset--duotone--$slug',
|
'css_vars' => '--wp--preset--duotone--$slug',
|
||||||
@ -139,7 +147,7 @@ class WP_Theme_JSON {
|
|||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'path' => array( 'typography', 'fontSizes' ),
|
'path' => array( 'typography', 'fontSizes' ),
|
||||||
'override' => true,
|
'prevent_override' => false,
|
||||||
'use_default_names' => true,
|
'use_default_names' => true,
|
||||||
'value_key' => 'size',
|
'value_key' => 'size',
|
||||||
'css_vars' => '--wp--preset--font-size--$slug',
|
'css_vars' => '--wp--preset--font-size--$slug',
|
||||||
@ -148,7 +156,7 @@ class WP_Theme_JSON {
|
|||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'path' => array( 'typography', 'fontFamilies' ),
|
'path' => array( 'typography', 'fontFamilies' ),
|
||||||
'override' => true,
|
'prevent_override' => false,
|
||||||
'use_default_names' => false,
|
'use_default_names' => false,
|
||||||
'value_key' => 'fontFamily',
|
'value_key' => 'fontFamily',
|
||||||
'css_vars' => '--wp--preset--font-family--$slug',
|
'css_vars' => '--wp--preset--font-family--$slug',
|
||||||
@ -229,10 +237,12 @@ class WP_Theme_JSON {
|
|||||||
*/
|
*/
|
||||||
const VALID_TOP_LEVEL_KEYS = array(
|
const VALID_TOP_LEVEL_KEYS = array(
|
||||||
'customTemplates',
|
'customTemplates',
|
||||||
|
'patterns',
|
||||||
'settings',
|
'settings',
|
||||||
'styles',
|
'styles',
|
||||||
'templateParts',
|
'templateParts',
|
||||||
'version',
|
'version',
|
||||||
|
'title',
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -242,6 +252,7 @@ class WP_Theme_JSON {
|
|||||||
* @since 5.9.0 Renamed from `ALLOWED_SETTINGS` to `VALID_SETTINGS`,
|
* @since 5.9.0 Renamed from `ALLOWED_SETTINGS` to `VALID_SETTINGS`,
|
||||||
* added new properties for `border`, `color`, `spacing`,
|
* added new properties for `border`, `color`, `spacing`,
|
||||||
* and `typography`, and renamed others according to the new schema.
|
* and `typography`, and renamed others according to the new schema.
|
||||||
|
* @since 6.0.0 Added `color.defaultDuotone`.
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
const VALID_SETTINGS = array(
|
const VALID_SETTINGS = array(
|
||||||
@ -257,6 +268,7 @@ class WP_Theme_JSON {
|
|||||||
'custom' => null,
|
'custom' => null,
|
||||||
'customDuotone' => null,
|
'customDuotone' => null,
|
||||||
'customGradient' => null,
|
'customGradient' => null,
|
||||||
|
'defaultDuotone' => null,
|
||||||
'defaultGradients' => null,
|
'defaultGradients' => null,
|
||||||
'defaultPalette' => null,
|
'defaultPalette' => null,
|
||||||
'duotone' => null,
|
'duotone' => null,
|
||||||
@ -347,6 +359,24 @@ class WP_Theme_JSON {
|
|||||||
'h6' => 'h6',
|
'h6' => 'h6',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options that settings.appearanceTools enables.
|
||||||
|
*
|
||||||
|
* @since 6.0.0
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
const APPEARANCE_TOOLS_OPT_INS = array(
|
||||||
|
array( 'border', 'color' ),
|
||||||
|
array( 'border', 'radius' ),
|
||||||
|
array( 'border', 'style' ),
|
||||||
|
array( 'border', 'width' ),
|
||||||
|
array( 'color', 'link' ),
|
||||||
|
array( 'spacing', 'blockGap' ),
|
||||||
|
array( 'spacing', 'margin' ),
|
||||||
|
array( 'spacing', 'padding' ),
|
||||||
|
array( 'typography', 'lineHeight' ),
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The latest version of the schema in use.
|
* The latest version of the schema in use.
|
||||||
*
|
*
|
||||||
@ -429,19 +459,7 @@ class WP_Theme_JSON {
|
|||||||
* @param array $context The context to which the settings belong.
|
* @param array $context The context to which the settings belong.
|
||||||
*/
|
*/
|
||||||
protected static function do_opt_in_into_settings( &$context ) {
|
protected static function do_opt_in_into_settings( &$context ) {
|
||||||
$to_opt_in = array(
|
foreach ( static::APPEARANCE_TOOLS_OPT_INS as $path ) {
|
||||||
array( 'border', 'color' ),
|
|
||||||
array( 'border', 'radius' ),
|
|
||||||
array( 'border', 'style' ),
|
|
||||||
array( 'border', 'width' ),
|
|
||||||
array( 'color', 'link' ),
|
|
||||||
array( 'spacing', 'blockGap' ),
|
|
||||||
array( 'spacing', 'margin' ),
|
|
||||||
array( 'spacing', 'padding' ),
|
|
||||||
array( 'typography', 'lineHeight' ),
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ( $to_opt_in as $path ) {
|
|
||||||
// Use "unset prop" as a marker instead of "null" because
|
// Use "unset prop" as a marker instead of "null" because
|
||||||
// "null" can be a valid value for some props (e.g. blockGap).
|
// "null" can be a valid value for some props (e.g. blockGap).
|
||||||
if ( 'unset prop' === _wp_array_get( $context, $path, 'unset prop' ) ) {
|
if ( 'unset prop' === _wp_array_get( $context, $path, 'unset prop' ) ) {
|
||||||
@ -830,8 +848,8 @@ class WP_Theme_JSON {
|
|||||||
|
|
||||||
$has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null;
|
$has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null;
|
||||||
if ( $has_block_gap_support ) {
|
if ( $has_block_gap_support ) {
|
||||||
$block_rules .= '.wp-site-blocks > * { margin-top: 0; margin-bottom: 0; }';
|
$block_rules .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }';
|
||||||
$block_rules .= '.wp-site-blocks > * + * { margin-top: var( --wp--style--block-gap ); }';
|
$block_rules .= '.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1501,6 +1519,45 @@ class WP_Theme_JSON {
|
|||||||
return $nodes;
|
return $nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For metadata values that can either be booleans or paths to booleans, gets the value.
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* $data = array(
|
||||||
|
* 'color' => array(
|
||||||
|
* 'defaultPalette' => true
|
||||||
|
* )
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
* static::get_metadata_boolean( $data, false );
|
||||||
|
* // => false
|
||||||
|
*
|
||||||
|
* static::get_metadata_boolean( $data, array( 'color', 'defaultPalette' ) );
|
||||||
|
* // => true
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @since 6.0.0
|
||||||
|
*
|
||||||
|
* @param array $data The data to inspect.
|
||||||
|
* @param bool|array $path Boolean or path to a boolean.
|
||||||
|
* @param bool $default Default value if the referenced path is missing.
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected static function get_metadata_boolean( $data, $path, $default = false ) {
|
||||||
|
if ( is_bool( $path ) ) {
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( is_array( $path ) ) {
|
||||||
|
$value = _wp_array_get( $data, $path );
|
||||||
|
if ( null !== $value ) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge new incoming data.
|
* Merge new incoming data.
|
||||||
*
|
*
|
||||||
@ -1550,7 +1607,7 @@ class WP_Theme_JSON {
|
|||||||
|
|
||||||
// Replace the presets.
|
// Replace the presets.
|
||||||
foreach ( static::PRESETS_METADATA as $preset ) {
|
foreach ( static::PRESETS_METADATA as $preset ) {
|
||||||
$override_preset = static::should_override_preset( $this->theme_json, $node['path'], $preset['override'] );
|
$override_preset = ! static::get_metadata_boolean( $this->theme_json['settings'], $preset['prevent_override'], true );
|
||||||
|
|
||||||
foreach ( static::VALID_ORIGINS as $origin ) {
|
foreach ( static::VALID_ORIGINS as $origin ) {
|
||||||
$base_path = array_merge( $node['path'], $preset['path'] );
|
$base_path = array_merge( $node['path'], $preset['path'] );
|
||||||
@ -1624,13 +1681,16 @@ class WP_Theme_JSON {
|
|||||||
* Returns whether a presets should be overridden or not.
|
* Returns whether a presets should be overridden or not.
|
||||||
*
|
*
|
||||||
* @since 5.9.0
|
* @since 5.9.0
|
||||||
|
* @deprecated 6.0.0 Use {@see 'get_metadata_boolean'} instead.
|
||||||
*
|
*
|
||||||
* @param array $theme_json The theme.json like structure to inspect.
|
* @param array $theme_json The theme.json like structure to inspect.
|
||||||
* @param array $path Path to inspect.
|
* @param array $path Path to inspect.
|
||||||
* @param bool|array $override Data to compute whether to override the preset.
|
* @param bool|array $override Data to compute whether to override the preset.
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
protected static function should_override_preset( $theme_json, $path, $override ) {
|
protected static function should_override_preset( $theme_json, $path, $override ) {
|
||||||
|
_deprecated_function( __METHOD__, '6.0.0', 'get_metadata_boolean' );
|
||||||
|
|
||||||
if ( is_bool( $override ) ) {
|
if ( is_bool( $override ) ) {
|
||||||
return $override;
|
return $override;
|
||||||
}
|
}
|
||||||
@ -2013,4 +2073,151 @@ class WP_Theme_JSON {
|
|||||||
return $theme_settings;
|
return $theme_settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current theme's wanted patterns(slugs) to be
|
||||||
|
* registered from Pattern Directory.
|
||||||
|
*
|
||||||
|
* @since 6.0.0
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function get_patterns() {
|
||||||
|
if ( isset( $this->theme_json['patterns'] ) && is_array( $this->theme_json['patterns'] ) ) {
|
||||||
|
return $this->theme_json['patterns'];
|
||||||
|
}
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a valid theme.json as provided by a theme.
|
||||||
|
*
|
||||||
|
* Unlike get_raw_data() this returns the presets flattened, as provided by a theme.
|
||||||
|
* This also uses appearanceTools instead of their opt-ins if all of them are true.
|
||||||
|
*
|
||||||
|
* @since 6.0.0
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_data() {
|
||||||
|
$output = $this->theme_json;
|
||||||
|
$nodes = static::get_setting_nodes( $output );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flatten the theme & custom origins into a single one.
|
||||||
|
*
|
||||||
|
* For example, the following:
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* "settings": {
|
||||||
|
* "color": {
|
||||||
|
* "palette": {
|
||||||
|
* "theme": [ {} ],
|
||||||
|
* "custom": [ {} ]
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* will be converted to:
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* "settings": {
|
||||||
|
* "color": {
|
||||||
|
* "palette": [ {} ]
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
foreach ( $nodes as $node ) {
|
||||||
|
foreach ( static::PRESETS_METADATA as $preset_metadata ) {
|
||||||
|
$path = array_merge( $node['path'], $preset_metadata['path'] );
|
||||||
|
$preset = _wp_array_get( $output, $path, null );
|
||||||
|
if ( null === $preset ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$items = array();
|
||||||
|
if ( isset( $preset['theme'] ) ) {
|
||||||
|
foreach ( $preset['theme'] as $item ) {
|
||||||
|
$slug = $item['slug'];
|
||||||
|
unset( $item['slug'] );
|
||||||
|
$items[ $slug ] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( isset( $preset['custom'] ) ) {
|
||||||
|
foreach ( $preset['custom'] as $item ) {
|
||||||
|
$slug = $item['slug'];
|
||||||
|
unset( $item['slug'] );
|
||||||
|
$items[ $slug ] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$flattened_preset = array();
|
||||||
|
foreach ( $items as $slug => $value ) {
|
||||||
|
$flattened_preset[] = array_merge( array( 'slug' => $slug ), $value );
|
||||||
|
}
|
||||||
|
_wp_array_set( $output, $path, $flattened_preset );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all of the static::APPEARANCE_TOOLS_OPT_INS are true,
|
||||||
|
// this code unsets them and sets 'appearanceTools' instead.
|
||||||
|
foreach ( $nodes as $node ) {
|
||||||
|
$all_opt_ins_are_set = true;
|
||||||
|
foreach ( static::APPEARANCE_TOOLS_OPT_INS as $opt_in_path ) {
|
||||||
|
$full_path = array_merge( $node['path'], $opt_in_path );
|
||||||
|
// Use "unset prop" as a marker instead of "null" because
|
||||||
|
// "null" can be a valid value for some props (e.g. blockGap).
|
||||||
|
$opt_in_value = _wp_array_get( $output, $full_path, 'unset prop' );
|
||||||
|
if ( 'unset prop' === $opt_in_value ) {
|
||||||
|
$all_opt_ins_are_set = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $all_opt_ins_are_set ) {
|
||||||
|
_wp_array_set( $output, array_merge( $node['path'], array( 'appearanceTools' ) ), true );
|
||||||
|
foreach ( static::APPEARANCE_TOOLS_OPT_INS as $opt_in_path ) {
|
||||||
|
$full_path = array_merge( $node['path'], $opt_in_path );
|
||||||
|
// Use "unset prop" as a marker instead of "null" because
|
||||||
|
// "null" can be a valid value for some props (e.g. blockGap).
|
||||||
|
$opt_in_value = _wp_array_get( $output, $full_path, 'unset prop' );
|
||||||
|
if ( true !== $opt_in_value ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following could be improved to be path independent.
|
||||||
|
// At the moment it relies on a couple of assumptions:
|
||||||
|
//
|
||||||
|
// - all opt-ins having a path of size 2.
|
||||||
|
// - there's two sources of settings: the top-level and the block-level.
|
||||||
|
if (
|
||||||
|
( 1 === count( $node['path'] ) ) &&
|
||||||
|
( 'settings' === $node['path'][0] )
|
||||||
|
) {
|
||||||
|
// Top-level settings.
|
||||||
|
unset( $output['settings'][ $opt_in_path[0] ][ $opt_in_path[1] ] );
|
||||||
|
if ( empty( $output['settings'][ $opt_in_path[0] ] ) ) {
|
||||||
|
unset( $output['settings'][ $opt_in_path[0] ] );
|
||||||
|
}
|
||||||
|
} elseif (
|
||||||
|
( 3 === count( $node['path'] ) ) &&
|
||||||
|
( 'settings' === $node['path'][0] ) &&
|
||||||
|
( 'blocks' === $node['path'][1] )
|
||||||
|
) {
|
||||||
|
// Block-level settings.
|
||||||
|
$block_name = $node['path'][2];
|
||||||
|
unset( $output['settings']['blocks'][ $block_name ][ $opt_in_path[0] ][ $opt_in_path[1] ] );
|
||||||
|
if ( empty( $output['settings']['blocks'][ $block_name ][ $opt_in_path[0] ] ) ) {
|
||||||
|
unset( $output['settings']['blocks'][ $block_name ][ $opt_in_path[0] ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_recursive_ksort( $output );
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8440,3 +8440,21 @@ function is_php_version_compatible( $required ) {
|
|||||||
function wp_fuzzy_number_match( $expected, $actual, $precision = 1 ) {
|
function wp_fuzzy_number_match( $expected, $actual, $precision = 1 ) {
|
||||||
return abs( (float) $expected - (float) $actual ) <= $precision;
|
return abs( (float) $expected - (float) $actual ) <= $precision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts the keys of an array alphabetically.
|
||||||
|
* The array is passed by reference so it doesn't get returned
|
||||||
|
* which mimics the behaviour of ksort.
|
||||||
|
*
|
||||||
|
* @since 6.0.0
|
||||||
|
*
|
||||||
|
* @param array $array The array to sort, passed by reference.
|
||||||
|
*/
|
||||||
|
function wp_recursive_ksort( &$array ) {
|
||||||
|
foreach ( $array as &$value ) {
|
||||||
|
if ( is_array( $value ) ) {
|
||||||
|
wp_recursive_ksort( $value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ksort( $array );
|
||||||
|
}
|
||||||
|
@ -53,15 +53,15 @@ class WP_REST_Edit_Site_Export_Controller extends WP_REST_Controller {
|
|||||||
* @return WP_Error|true True if the request has access, or WP_Error object.
|
* @return WP_Error|true True if the request has access, or WP_Error object.
|
||||||
*/
|
*/
|
||||||
public function permissions_check() {
|
public function permissions_check() {
|
||||||
if ( ! current_user_can( 'edit_theme_options' ) ) {
|
if ( current_user_can( 'edit_theme_options' ) ) {
|
||||||
return new WP_Error(
|
return true;
|
||||||
'rest_cannot_export_templates',
|
|
||||||
__( 'Sorry, you are not allowed to export templates and template parts.' ),
|
|
||||||
array( 'status' => rest_authorization_required_code() )
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return new WP_Error(
|
||||||
|
'rest_cannot_export_templates',
|
||||||
|
__( 'Sorry, you are not allowed to export templates and template parts.' ),
|
||||||
|
array( 'status' => rest_authorization_required_code() )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,8 +82,9 @@ class WP_REST_Edit_Site_Export_Controller extends WP_REST_Controller {
|
|||||||
return $filename;
|
return $filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$theme_name = wp_get_theme()->get( 'TextDomain' );
|
||||||
header( 'Content-Type: application/zip' );
|
header( 'Content-Type: application/zip' );
|
||||||
header( 'Content-Disposition: attachment; filename=edit-site-export.zip' );
|
header( 'Content-Disposition: attachment; filename=' . $theme_name . '.zip' );
|
||||||
header( 'Content-Length: ' . filesize( $filename ) );
|
header( 'Content-Length: ' . filesize( $filename ) );
|
||||||
flush();
|
flush();
|
||||||
readfile( $filename );
|
readfile( $filename );
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
*
|
*
|
||||||
* @global string $wp_version
|
* @global string $wp_version
|
||||||
*/
|
*/
|
||||||
$wp_version = '6.0-alpha-53128';
|
$wp_version = '6.0-alpha-53129';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||||
|
Loading…
Reference in New Issue
Block a user