Skip to content

Commit

Permalink
Editor: Add functionality required for theme export in the site editor
Browse files Browse the repository at this point in the history
This bring across changes to theme export functionality, and related code, and tests. Relates issue in Gutenberg: WordPress/gutenberg#39889.

Props scruffian, timothyblynjacobs, oandregal, ajlende, zieleadam.
See #55505.



git-svn-id: https://develop.svn.wordpress.org/trunk@53129 602fd350-edb4-49c9-b593-d223f7449a82
  • Loading branch information
gziolo committed Apr 11, 2022
1 parent 43aba3b commit a5a6d0d
Show file tree
Hide file tree
Showing 8 changed files with 712 additions and 80 deletions.
93 changes: 81 additions & 12 deletions src/wp-includes/block-template-utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,11 @@ function get_default_block_template_types() {
),
'home' => array(
'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(
'title' => _x( 'Front Page', 'Template name' ),
'description' => __( 'Displays as the site\'s home page.' ),
'description' => __( 'Displays the homepage.' ),
),
'singular' => array(
'title' => _x( 'Singular', 'Template name' ),
Expand Down Expand Up @@ -162,12 +162,12 @@ function get_default_block_template_types() {
'description' => __( 'Displays latest posts with a single post tag.' ),
),
'attachment' => array(
'title' => __( 'Attachment' ),
'title' => __( 'Media' ),
'description' => __( 'Displays individual media items or attachments.' ),
),
'search' => array(
'title' => _x( 'Search', 'Template name' ),
'description' => __( 'Template used to display search results.' ),
'description' => __( 'Displays search results.' ),
),
'privacy-policy' => array(
'title' => __( 'Privacy Policy' ),
Expand Down Expand Up @@ -902,12 +902,32 @@ function block_footer_area() {
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
* template parts from the site editor at the
* specified path in a ZIP file.
*
* @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.
*/
Expand All @@ -916,25 +936,48 @@ function wp_generate_block_templates_export_file() {
return new WP_Error( 'missing_zip_package', __( 'Zip Export not supported.' ) );
}

$obscura = wp_generate_password( 12, false, false );
$filename = get_temp_dir() . 'edit-site-export-' . $obscura . '.zip';
$obscura = wp_generate_password( 12, false, false );
$theme_name = wp_get_theme()->get( 'TextDomain' );
$filename = get_temp_dir() . $theme_name . $obscura . '.zip';

$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.' ) );
}

$zip->addEmptyDir( 'theme' );
$zip->addEmptyDir( 'theme/templates' );
$zip->addEmptyDir( 'theme/parts' );
$zip->addEmptyDir( 'templates' );
$zip->addEmptyDir( '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.
$templates = get_block_templates();
foreach ( $templates as $template ) {
$template->content = _remove_theme_attribute_in_block_template_content( $template->content );

$zip->addFromString(
'theme/templates/' . $template->slug . '.html',
'templates/' . $template->slug . '.html',
$template->content
);
}
Expand All @@ -943,11 +986,37 @@ function wp_generate_block_templates_export_file() {
$template_parts = get_block_templates( array(), 'wp_template_part' );
foreach ( $template_parts as $template_part ) {
$zip->addFromString(
'theme/parts/' . $template_part->slug . '.html',
'parts/' . $template_part->slug . '.html',
$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.
$zip->close();

Expand Down
15 changes: 14 additions & 1 deletion src/wp-includes/class-wp-theme-json-resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,19 @@ public static function get_core_data() {
*
* @since 5.8.0
* @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 $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.
*/
public static function get_theme_data( $deprecated = array() ) {
public static function get_theme_data( $deprecated = array(), $options = array() ) {
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __METHOD__, '5.9.0' );
}

$options = wp_parse_args( $options, array( 'with_supports' => true ) );

if ( null === static::$theme ) {
$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' ) );
Expand All @@ -177,6 +182,10 @@ public static function get_theme_data( $deprecated = array() ) {
}
}

if ( ! $options['with_supports'] ) {
return static::$theme;
}

/*
* We want the presets and settings declared in theme.json
* to override the ones declared via theme supports.
Expand Down Expand Up @@ -208,6 +217,9 @@ public static function get_theme_data( $deprecated = array() ) {
$default_gradients = true;
}
$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->merge( static::$theme );
Expand Down Expand Up @@ -477,4 +489,5 @@ public static function get_style_variations() {
}
return $variations;
}

}
Loading

0 comments on commit a5a6d0d

Please sign in to comment.