From 277b398de717808cac779e58bd1f8e5c8a67ee1a Mon Sep 17 00:00:00 2001 From: Jason Crist Date: Wed, 27 Mar 2024 10:48:50 -0400 Subject: [PATCH 1/2] Add Child Theme Creation to Site Editor --- admin/create-theme/theme-create.php | 51 +++++++++++++++++++++++ admin/create-theme/theme-styles.php | 8 ++-- admin/create-theme/theme-templates.php | 21 ++++++---- includes/class-create-block-theme-api.php | 31 ++++++++++++++ src/editor-sidebar/create-panel.js | 47 +++++++++++++++++++++ 5 files changed, 146 insertions(+), 12 deletions(-) diff --git a/admin/create-theme/theme-create.php b/admin/create-theme/theme-create.php index 9cbefd7b..2852e075 100644 --- a/admin/create-theme/theme-create.php +++ b/admin/create-theme/theme-create.php @@ -33,6 +33,57 @@ public static function clone_current_theme( $theme ) { } } + public static function create_child_theme( $theme, $screenshot ) { + + // Create theme directory. + $new_theme_path = get_theme_root() . DIRECTORY_SEPARATOR . $theme['slug']; + + if ( $theme['subfolder'] ) { + $new_theme_path = get_theme_root() . DIRECTORY_SEPARATOR . $theme['subfolder'] . DIRECTORY_SEPARATOR . $theme['slug']; + } + + if ( file_exists( $new_theme_path ) ) { + return new WP_Error( 'theme_already_exists', __( 'Theme already exists.', 'create-block-theme' ) ); + } + + wp_mkdir_p( $new_theme_path ); + + // Add readme.txt. + file_put_contents( + $new_theme_path . DIRECTORY_SEPARATOR . 'readme.txt', + Theme_Readme::build_readme_txt( $theme ) + ); + + // Add style.css. + $theme['template'] = wp_get_theme()->get( 'TextDomain' ); + $css_contents = Theme_Styles::build_style_css( $theme ); + file_put_contents( + $new_theme_path . DIRECTORY_SEPARATOR . 'style.css', + $css_contents + ); + + // Add theme.json + Theme_Templates::add_templates_to_local( 'user', $new_theme_path, $theme['slug'] ); + file_put_contents( $new_theme_path . DIRECTORY_SEPARATOR . 'theme.json', MY_Theme_JSON_Resolver::export_theme_data( 'variation' ) ); + + // Add Screenshot + if ( static::is_valid_screenshot( $screenshot ) ) { + file_put_contents( + $new_theme_path . DIRECTORY_SEPARATOR . 'screenshot.png', + file_get_contents( $screenshot['tmp_name'] ) + ); + } else { + $source = plugin_dir_path( __DIR__ ) . '../assets/boilerplate/screenshot.png'; + copy( $source, $new_theme_path . DIRECTORY_SEPARATOR . 'screenshot.png' ); + } + + if ( $theme['subfolder'] ) { + switch_theme( $theme['subfolder'] . '/' . $theme['slug'] ); + } else { + switch_theme( $theme['slug'] ); + } + } + public static function create_blank_theme( $theme, $screenshot ) { // Create theme directory. diff --git a/admin/create-theme/theme-styles.php b/admin/create-theme/theme-styles.php index ee8cdf39..609514f6 100644 --- a/admin/create-theme/theme-styles.php +++ b/admin/create-theme/theme-styles.php @@ -62,10 +62,12 @@ public static function build_style_css( $theme ) { $author = stripslashes( $theme['author'] ); $author_uri = $theme['author_uri']; $wp_version = get_bloginfo( 'version' ); - $template = $theme['template']; $text_domain = sanitize_title( $name ); - $version = '1.0.0'; - $tags = Theme_Tags::theme_tags_list( $theme ); + if ( isset( $theme['template'] ) ) { + $template = $theme['template']; + } + $version = '1.0.0'; + $tags = Theme_Tags::theme_tags_list( $theme ); if ( isset( $theme['version'] ) ) { $version = $theme['version']; diff --git a/admin/create-theme/theme-templates.php b/admin/create-theme/theme-templates.php index 5ed59134..a2ab7727 100644 --- a/admin/create-theme/theme-templates.php +++ b/admin/create-theme/theme-templates.php @@ -186,21 +186,16 @@ public static function add_templates_to_local( $export_type, $path = null, $slug $template_part_dir = $base_dir . DIRECTORY_SEPARATOR . $template_folders['wp_template_part']; $patterns_dir = $base_dir . DIRECTORY_SEPARATOR . 'patterns'; - // If there is no templates folder, create it. - if ( ! is_dir( $template_dir ) ) { + // If there is no templates folder, and it is needed, create it. + if ( ! is_dir( $template_dir ) && count( $theme_templates->templates ) > 0 ) { wp_mkdir_p( $template_dir ); } - // If there is no parts folder, create it. - if ( ! is_dir( $template_part_dir ) ) { + // If there is no parts folder, and it is needed, create it. + if ( ! is_dir( $template_part_dir ) && count( $theme_templates->parts ) > 0 ) { wp_mkdir_p( $template_part_dir ); } - // If there is no patterns folder, create it. - if ( ! is_dir( $patterns_dir ) ) { - wp_mkdir_p( $patterns_dir ); - } - foreach ( $theme_templates->templates as $template ) { $template = self::prepare_template_for_export( $template, $slug ); @@ -218,6 +213,10 @@ public static function add_templates_to_local( $export_type, $path = null, $slug // Write the pattern if it exists if ( isset( $template->pattern ) ) { + // If there is no patterns folder, create it. + if ( ! is_dir( $patterns_dir ) ) { + wp_mkdir_p( $patterns_dir ); + } file_put_contents( $patterns_dir . DIRECTORY_SEPARATOR . $template->slug . '.php', $template->pattern @@ -242,6 +241,10 @@ public static function add_templates_to_local( $export_type, $path = null, $slug // Write the pattern if it exists if ( isset( $template->pattern ) ) { + // If there is no patterns folder, create it. + if ( ! is_dir( $patterns_dir ) ) { + wp_mkdir_p( $patterns_dir ); + } file_put_contents( $patterns_dir . DIRECTORY_SEPARATOR . $template->slug . '.php', $template->pattern diff --git a/includes/class-create-block-theme-api.php b/includes/class-create-block-theme-api.php index 0ed2e4a5..f033cc3b 100644 --- a/includes/class-create-block-theme-api.php +++ b/includes/class-create-block-theme-api.php @@ -75,6 +75,17 @@ public function register_rest_routes() { }, ) ); + register_rest_route( + 'create-block-theme/v1', + '/create-child', + array( + 'methods' => 'POST', + 'callback' => array( $this, 'rest_create_child_theme' ), + 'permission_callback' => function () { + return current_user_can( 'edit_theme_options' ); + }, + ) + ); register_rest_route( 'create-block-theme/v1', '/export-clone', @@ -135,6 +146,26 @@ function rest_clone_theme( $request ) { ); } + function rest_create_child_theme( $request ) { + + $theme = $this->sanitize_theme_data( $request->get_params() ); + //TODO: Handle screenshots + $screenshot = null; + + $response = Theme_Create::create_child_theme( $theme, $screenshot ); + + if ( is_wp_error( $response ) ) { + return $response; + } + + return new WP_REST_Response( + array( + 'status' => 'SUCCESS', + 'message' => __( 'Child Theme Created.', 'create-block-theme' ), + ) + ); + } + function rest_create_blank_theme( $request ) { $theme = $this->sanitize_theme_data( $request->get_params() ); diff --git a/src/editor-sidebar/create-panel.js b/src/editor-sidebar/create-panel.js index e6600f70..85ebcdce 100644 --- a/src/editor-sidebar/create-panel.js +++ b/src/editor-sidebar/create-panel.js @@ -142,6 +142,36 @@ export const CreateThemePanel = () => { } ); }; + const handleCreateChildClick = () => { + apiFetch( { + path: '/create-block-theme/v1/create-child', + method: 'POST', + data: theme, + headers: { + 'Content-Type': 'application/json', + }, + } ) + .then( () => { + // eslint-disable-next-line + alert( + __( + 'Child theme created successfully. The editor will now reload.', + 'create-block-theme' + ) + ); + window.location.reload(); + } ) + .catch( ( error ) => { + const errorMessage = + error.message || + __( + 'An error occurred while attempting to create the theme.', + 'create-block-theme' + ); + createErrorNotice( errorMessage, { type: 'snackbar' } ); + } ); + }; + return ( @@ -234,6 +264,23 @@ export const CreateThemePanel = () => { 'create-block-theme' ) } +
+ + + + + { __( + 'Create a child theme on the server and activate it. The user changes will be preserved in the new theme.', + 'create-block-theme' + ) } + +
+ + + { __( + 'Export a child of this theme as a .zip file. The user changes will be preserved in the new theme.', + 'create-block-theme' + ) } + +
+