diff --git a/admin/class-create-theme.php b/admin/class-create-theme.php index d05d3a9f..c12fed72 100644 --- a/admin/class-create-theme.php +++ b/admin/class-create-theme.php @@ -13,7 +13,7 @@ require_once __DIR__ . '/create-theme/theme-readme.php'; require_once __DIR__ . '/create-theme/theme-form.php'; require_once __DIR__ . '/create-theme/form-messages.php'; - +require_once __DIR__ . '/create-theme/theme-create.php'; /** * The admin-specific functionality of the plugin. * diff --git a/admin/create-theme/theme-create.php b/admin/create-theme/theme-create.php new file mode 100644 index 00000000..6efc3cd4 --- /dev/null +++ b/admin/create-theme/theme-create.php @@ -0,0 +1,111 @@ + 'image/png', + ); + + public static function clone_current_theme( $theme ) { + + // 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 ); + + // Copy theme files. + Theme_Utils::clone_theme_to_folder( $new_theme_path, $theme['slug'], $theme['name'] ); + Theme_Utils::add_templates_to_folder( $new_theme_path, 'all', $theme['slug'] ); + + file_put_contents( $new_theme_path . DIRECTORY_SEPARATOR . 'theme.json', MY_Theme_JSON_Resolver::export_theme_data( 'all' ) ); + + 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. + $source = plugin_dir_path( __DIR__ ) . 'assets/boilerplate'; + $blank_theme_path = get_theme_root() . DIRECTORY_SEPARATOR . $theme['subfolder'] . DIRECTORY_SEPARATOR . $theme['slug']; + + if ( file_exists( $blank_theme_path ) ) { + return new WP_Error( 'theme_already_exists', __( 'Theme already exists.', 'create-block-theme' ) ); + } + + wp_mkdir_p( $blank_theme_path ); + + // Add readme.txt. + file_put_contents( + $blank_theme_path . DIRECTORY_SEPARATOR . 'readme.txt', + Theme_Readme::build_readme_txt( $theme ) + ); + + // Add new metadata. + $css_contents = Theme_Styles::build_child_style_css( $theme ); + + // Add style.css. + file_put_contents( + $blank_theme_path . DIRECTORY_SEPARATOR . 'style.css', + $css_contents + ); + + $iterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator( $source, \RecursiveDirectoryIterator::SKIP_DOTS ), + \RecursiveIteratorIterator::SELF_FIRST + ); + + foreach ( + $iterator as $item + ) { + if ( $item->isDir() ) { + wp_mkdir_p( $blank_theme_path . DIRECTORY_SEPARATOR . $iterator->getSubPathname() ); + } else { + copy( $item, $blank_theme_path . DIRECTORY_SEPARATOR . $iterator->getSubPathname() ); + } + } + + // Overwrite default screenshot if one is provided. + if ( static::is_valid_screenshot( $screenshot ) ) { + file_put_contents( + $blank_theme_path . DIRECTORY_SEPARATOR . 'screenshot.png', + file_get_contents( $screenshot['tmp_name'] ) + ); + } + + if ( ! defined( 'IS_GUTENBERG_PLUGIN' ) ) { + global $wp_version; + $theme_json_version = 'wp/' . substr( $wp_version, 0, 3 ); + $schema = '"$schema": "https://schemas.wp.org/' . $theme_json_version . '/theme.json"'; + $theme_json_path = $blank_theme_path . DIRECTORY_SEPARATOR . 'theme.json'; + $theme_json_string = file_get_contents( $theme_json_path ); + $theme_json_string = str_replace( '"$schema": "https://schemas.wp.org/trunk/theme.json"', $schema, $theme_json_string ); + file_put_contents( $theme_json_path, $theme_json_string ); + } + + if ( $theme['subfolder'] ) { + switch_theme( $theme['subfolder'] . '/' . $theme['slug'] ); + } else { + switch_theme( $theme['slug'] ); + } + } + + private static function is_valid_screenshot( $file ) { + $filetype = wp_check_filetype( $file['name'], self::ALLOWED_SCREENSHOT_TYPES ); + if ( is_uploaded_file( $file['tmp_name'] ) && in_array( $filetype['type'], self::ALLOWED_SCREENSHOT_TYPES, true ) && $file['size'] < 2097152 ) { + return 1; + } + return 0; + } +} diff --git a/admin/create-theme/theme-utils.php b/admin/create-theme/theme-utils.php index b147864f..b06bfa90 100644 --- a/admin/create-theme/theme-utils.php +++ b/admin/create-theme/theme-utils.php @@ -202,4 +202,51 @@ public static function get_readme_data() { return $readme_file_details; } + + /** + * Relocate the theme to a new folder and activate the newly relocated theme. + */ + public static function relocate_theme( $new_theme_subfolder ) { + + $current_theme_subfolder = ''; + $theme_dir = get_stylesheet(); + + $source = get_theme_root() . DIRECTORY_SEPARATOR . $theme_dir; + $destination = get_theme_root() . DIRECTORY_SEPARATOR . $theme_dir; + + if ( str_contains( get_stylesheet(), '/' ) ) { + $current_theme_subfolder = substr( get_stylesheet(), 0, strrpos( get_stylesheet(), '/' ) ); + $theme_dir = substr( get_stylesheet(), strrpos( get_stylesheet(), '/' ) + 1 ); + $source = get_theme_root() . DIRECTORY_SEPARATOR . $current_theme_subfolder . DIRECTORY_SEPARATOR . $theme_dir; + $destination = get_theme_root() . DIRECTORY_SEPARATOR . $theme_dir; + } + + if ( $new_theme_subfolder ) { + $destination = get_theme_root() . DIRECTORY_SEPARATOR . $new_theme_subfolder . DIRECTORY_SEPARATOR . $theme_dir; + wp_mkdir_p( get_theme_root() . DIRECTORY_SEPARATOR . $new_theme_subfolder ); + } + + if ( $source === $destination ) { + return; + } + + global $wp_filesystem; + if ( ! $wp_filesystem ) { + require_once ABSPATH . 'wp-admin/includes/file.php'; + WP_Filesystem(); + } + + $success = move_dir( $source, $destination, false ); + + if ( ! $success ) { + return new \WP_Error( 'problem_moving', __( 'There was a problem moving the theme', 'create-block-theme' ) ); + } + + if ( $new_theme_subfolder ) { + switch_theme( $new_theme_subfolder . '/' . $theme_dir ); + } else { + switch_theme( $theme_dir ); + } + } + } diff --git a/includes/class-create-block-theme-api.php b/includes/class-create-block-theme-api.php index ca2c4804..33e0e826 100644 --- a/includes/class-create-block-theme-api.php +++ b/includes/class-create-block-theme-api.php @@ -120,49 +120,11 @@ function rest_get_readme_data( $request ) { } function rest_clone_theme( $request ) { - $theme = $request->get_params(); - - //TODO: Handle uploading a screenshot somehow... - $screenshot = null; - $theme_slug = Theme_Utils::get_theme_slug( $theme['name'] ); - - // Sanitize inputs. - $theme['name'] = sanitize_text_field( $theme['name'] ); - $theme['description'] = sanitize_text_field( $theme['description'] ); - $theme['uri'] = sanitize_text_field( $theme['uri'] ); - $theme['author'] = sanitize_text_field( $theme['author'] ); - $theme['author_uri'] = sanitize_text_field( $theme['author_uri'] ); - $theme['tags_custom'] = sanitize_text_field( $theme['tags_custom'] ); - $theme['recommended_plugins'] = sanitize_textarea_field( $theme['recommended_plugins'] ); - $theme['template'] = ''; - $theme['slug'] = $theme_slug; - $theme['text_domain'] = $theme_slug; - - // Create theme directory. - $source = get_stylesheet_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_exists', __( 'Theme already exists.', 'create-block-theme' ) ); - } + $response = Theme_Create::clone_current_theme( $this->sanitize_theme_data( $request->get_params() ) ); - wp_mkdir_p( $new_theme_path ); - - // Copy theme files. - Theme_Utils::clone_theme_to_folder( $new_theme_path, $theme['slug'], $theme['name'] ); - Theme_Utils::add_templates_to_folder( $new_theme_path, 'all', $theme['slug'] ); - - file_put_contents( $new_theme_path . DIRECTORY_SEPARATOR . 'theme.json', MY_Theme_JSON_Resolver::export_theme_data( 'all' ) ); - - if ( $theme['subfolder'] ) { - switch_theme( $theme['subfolder'] . '/' . $theme_slug ); - } else { - switch_theme( $theme_slug ); + if ( is_wp_error( $response ) ) { + return $response; } return new WP_REST_Response( @@ -175,86 +137,14 @@ function rest_clone_theme( $request ) { function rest_create_blank_theme( $request ) { - $theme = $request->get_params(); - - //TODO: Handle uploading a screenshot somehow... + $theme = $this->sanitize_theme_data( $request->get_params() ); + //TODO: Handle screenshots $screenshot = null; - $theme_slug = Theme_Utils::get_theme_slug( $theme['name'] ); - - // Sanitize inputs. - $theme['name'] = sanitize_text_field( $theme['name'] ); - $theme['description'] = sanitize_text_field( $theme['description'] ); - $theme['uri'] = sanitize_text_field( $theme['uri'] ); - $theme['author'] = sanitize_text_field( $theme['author'] ); - $theme['author_uri'] = sanitize_text_field( $theme['author_uri'] ); - $theme['tags_custom'] = sanitize_text_field( $theme['tags_custom'] ); - $theme['template'] = ''; - $theme['slug'] = $theme_slug; - $theme['text_domain'] = $theme_slug; - - // Create theme directory. - $source = plugin_dir_path( __DIR__ ) . 'assets/boilerplate'; - $blank_theme_path = get_theme_root() . DIRECTORY_SEPARATOR . $theme['subfolder'] . DIRECTORY_SEPARATOR . $theme['slug']; - - if ( file_exists( $blank_theme_path ) ) { - return new \WP_Error( 'theme_exists', __( 'Theme already exists.', 'create-block-theme' ) ); - } - - wp_mkdir_p( $blank_theme_path ); - - // Add readme.txt. - file_put_contents( - $blank_theme_path . DIRECTORY_SEPARATOR . 'readme.txt', - Theme_Readme::build_readme_txt( $theme ) - ); - - // Add new metadata. - $css_contents = Theme_Styles::build_child_style_css( $theme ); + $response = Theme_Create::create_blank_theme( $theme, $screenshot ); - // Add style.css. - file_put_contents( - $blank_theme_path . DIRECTORY_SEPARATOR . 'style.css', - $css_contents - ); - - $iterator = new \RecursiveIteratorIterator( - new \RecursiveDirectoryIterator( $source, \RecursiveDirectoryIterator::SKIP_DOTS ), - \RecursiveIteratorIterator::SELF_FIRST - ); - - foreach ( - $iterator as $item - ) { - if ( $item->isDir() ) { - wp_mkdir_p( $blank_theme_path . DIRECTORY_SEPARATOR . $iterator->getSubPathname() ); - } else { - copy( $item, $blank_theme_path . DIRECTORY_SEPARATOR . $iterator->getSubPathname() ); - } - } - - // Overwrite default screenshot if one is provided. - if ( $this->is_valid_screenshot( $screenshot ) ) { - file_put_contents( - $blank_theme_path . DIRECTORY_SEPARATOR . 'screenshot.png', - file_get_contents( $screenshot['tmp_name'] ) - ); - } - - if ( ! defined( 'IS_GUTENBERG_PLUGIN' ) ) { - global $wp_version; - $theme_json_version = 'wp/' . substr( $wp_version, 0, 3 ); - $schema = '"$schema": "https://schemas.wp.org/' . $theme_json_version . '/theme.json"'; - $theme_json_path = $blank_theme_path . DIRECTORY_SEPARATOR . 'theme.json'; - $theme_json_string = file_get_contents( $theme_json_path ); - $theme_json_string = str_replace( '"$schema": "https://schemas.wp.org/trunk/theme.json"', $schema, $theme_json_string ); - file_put_contents( $theme_json_path, $theme_json_string ); - } - - if ( $theme['subfolder'] ) { - switch_theme( $theme['subfolder'] . '/' . $theme_slug ); - } else { - switch_theme( $theme_slug ); + if ( is_wp_error( $response ) ) { + return $response; } return new WP_REST_Response( @@ -266,22 +156,10 @@ function rest_create_blank_theme( $request ) { } function rest_export_cloned_theme( $request ) { - $theme = $request->get_params(); - $theme_slug = Theme_Utils::get_theme_slug( $theme['name'] ); - - // Sanitize inputs. - $theme['name'] = sanitize_text_field( $theme['name'] ); - $theme['description'] = sanitize_text_field( $theme['description'] ); - $theme['uri'] = sanitize_text_field( $theme['uri'] ); - $theme['author'] = sanitize_text_field( $theme['author'] ); - $theme['author_uri'] = sanitize_text_field( $theme['author_uri'] ); - $theme['tags_custom'] = sanitize_text_field( $theme['tags_custom'] ); - $theme['recommended_plugins'] = sanitize_textarea_field( $theme['recommended_plugins'] ); - $theme['slug'] = $theme_slug; - $theme['template'] = ''; - $theme['original_theme'] = wp_get_theme()->get( 'Name' ); - $theme['text_domain'] = $theme_slug; + //TODO: Handle Screenshots + $screenshot = null; + $theme = $this->sanitize_theme_data( $request->get_params() ); // Use previous theme's tags if custom tags are empty. if ( empty( $theme['tags_custom'] ) ) { @@ -364,14 +242,16 @@ function rest_update_theme( $request ) { $theme = $request->get_params(); // Update the metadata of the theme in the style.css file - $response = $this->update_theme_metadata( $theme ); - - if ( is_wp_error( $response ) ) { - return $response; - } + $style_css = file_get_contents( get_stylesheet_directory() . '/style.css' ); + $style_css = Theme_Styles::update_style_css( $style_css, $theme ); + file_put_contents( get_stylesheet_directory() . '/style.css', $style_css ); + file_put_contents( + get_stylesheet_directory() . '/readme.txt', + Theme_Readme::update_readme_txt( $theme ) + ); // Relocate the theme to a new folder - $response = $this->relocate_theme( $theme['subfolder'] ); + $response = Theme_Utils::relocate_theme( $theme['subfolder'] ); if ( is_wp_error( $response ) ) { return $response; @@ -407,75 +287,17 @@ function rest_save_theme( $request ) { ); } - /** - * Update the theme metadata in the style.css and readme.txt files. - */ - function update_theme_metadata( $theme ) { - $style_css = file_get_contents( get_stylesheet_directory() . '/style.css' ); - $style_css = Theme_Styles::update_style_css( $style_css, $theme ); - file_put_contents( get_stylesheet_directory() . '/style.css', $style_css ); - file_put_contents( - get_stylesheet_directory() . '/readme.txt', - Theme_Readme::update_readme_txt( $theme ) - ); + private function sanitize_theme_data( $theme ) { + $sanitized_theme['name'] = sanitize_text_field( $theme['name'] ); + $sanitized_theme['description'] = sanitize_text_field( $theme['description'] ); + $sanitized_theme['uri'] = sanitize_text_field( $theme['uri'] ); + $sanitized_theme['author'] = sanitize_text_field( $theme['author'] ); + $sanitized_theme['author_uri'] = sanitize_text_field( $theme['author_uri'] ); + $sanitized_theme['tags_custom'] = sanitize_text_field( $theme['tags_custom'] ); + $sanitized_theme['recommended_plugins'] = sanitize_textarea_field( $theme['recommended_plugins'] ); + $sanitized_theme['template'] = ''; + $sanitized_theme['slug'] = Theme_Utils::get_theme_slug( $theme['name'] ); + $sanitized_theme['text_domain'] = $theme['slug']; + return $sanitized_theme; } - - /** - * Relocate the theme to a new folder and activate the newly relocated theme. - */ - function relocate_theme( $new_theme_subfolder ) { - - $current_theme_subfolder = ''; - $theme_dir = get_stylesheet(); - - $source = get_theme_root() . DIRECTORY_SEPARATOR . $theme_dir; - $destination = get_theme_root() . DIRECTORY_SEPARATOR . $theme_dir; - - if ( str_contains( get_stylesheet(), '/' ) ) { - $current_theme_subfolder = substr( get_stylesheet(), 0, strrpos( get_stylesheet(), '/' ) ); - $theme_dir = substr( get_stylesheet(), strrpos( get_stylesheet(), '/' ) + 1 ); - $source = get_theme_root() . DIRECTORY_SEPARATOR . $current_theme_subfolder . DIRECTORY_SEPARATOR . $theme_dir; - $destination = get_theme_root() . DIRECTORY_SEPARATOR . $theme_dir; - } - - if ( $new_theme_subfolder ) { - $destination = get_theme_root() . DIRECTORY_SEPARATOR . $new_theme_subfolder . DIRECTORY_SEPARATOR . $theme_dir; - wp_mkdir_p( get_theme_root() . DIRECTORY_SEPARATOR . $new_theme_subfolder ); - } - - if ( $source === $destination ) { - return; - } - - global $wp_filesystem; - if ( ! $wp_filesystem ) { - require_once ABSPATH . 'wp-admin/includes/file.php'; - WP_Filesystem(); - } - - $success = move_dir( $source, $destination, false ); - - if ( ! $success ) { - return new \WP_Error( 'problem_moving', __( 'There was a problem moving the theme', 'create-block-theme' ) ); - } - - if ( $new_theme_subfolder ) { - switch_theme( $new_theme_subfolder . '/' . $theme_dir ); - } else { - switch_theme( $theme_dir ); - } - } - - const ALLOWED_SCREENSHOT_TYPES = array( - 'png' => 'image/png', - ); - - function is_valid_screenshot( $file ) { - $filetype = wp_check_filetype( $file['name'], self::ALLOWED_SCREENSHOT_TYPES ); - if ( is_uploaded_file( $file['tmp_name'] ) && in_array( $filetype['type'], self::ALLOWED_SCREENSHOT_TYPES, true ) && $file['size'] < 2097152 ) { - return 1; - } - return 0; - } - }