From b930a93fb652af05f107fe1f55757a018b6b7e16 Mon Sep 17 00:00:00 2001 From: arunshenoy99 Date: Thu, 7 Dec 2023 11:42:16 +0530 Subject: [PATCH] Add sitegen child theme generation --- composer.json | 3 +- composer.lock | 89 ++++++- includes/Data.php | 2 +- includes/Flows/Flows.php | 13 +- includes/Mustache/Mustache.php | 37 +++ .../Templates/themeStylesheet.mustache | 9 + includes/Services/SiteGenService.php | 133 ++++++++++ includes/Services/SitePagesService.php | 27 +++ includes/Services/ThemeGeneratorService.php | 228 ++++++++++++++++++ 9 files changed, 524 insertions(+), 17 deletions(-) create mode 100644 includes/Mustache/Mustache.php create mode 100644 includes/Mustache/Templates/themeStylesheet.mustache create mode 100644 includes/Services/SitePagesService.php create mode 100644 includes/Services/ThemeGeneratorService.php diff --git a/composer.json b/composer.json index 5d34375..0c401e9 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,8 @@ "newfold-labs/wp-module-installer": "^1.1", "newfold-labs/wp-module-data": "^2.4.3", "newfold-labs/wp-module-ai": "^1.0.4", - "wp-forge/wp-upgrade-handler": "^1.0" + "wp-forge/wp-upgrade-handler": "^1.0", + "mustache/mustache": "^2.14" }, "require-dev": { "newfold-labs/wp-php-standards": "^1.2" diff --git a/composer.lock b/composer.lock index e9aa764..b76c877 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,58 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6a95054ac9d3588eff6ea0cadb976939", + "content-hash": "a51d9791ffca6d77413ac5106c009021", "packages": [ + { + "name": "mustache/mustache", + "version": "v2.14.2", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/mustache.php.git", + "reference": "e62b7c3849d22ec55f3ec425507bf7968193a6cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/e62b7c3849d22ec55f3ec425507bf7968193a6cb", + "reference": "e62b7c3849d22ec55f3ec425507bf7968193a6cb", + "shasum": "" + }, + "require": { + "php": ">=5.2.4" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~1.11", + "phpunit/phpunit": "~3.7|~4.0|~5.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Mustache": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "A Mustache implementation in PHP.", + "homepage": "https://github.com/bobthecow/mustache.php", + "keywords": [ + "mustache", + "templating" + ], + "support": { + "issues": "https://github.com/bobthecow/mustache.php/issues", + "source": "https://github.com/bobthecow/mustache.php/tree/v2.14.2" + }, + "time": "2022-08-23T13:07:01+00:00" + }, { "name": "newfold-labs/wp-module-ai", "version": "1.0.4", @@ -53,16 +103,16 @@ }, { "name": "newfold-labs/wp-module-data", - "version": "2.4.11", + "version": "2.4.14", "source": { "type": "git", "url": "https://github.com/newfold-labs/wp-module-data.git", - "reference": "c244dd52e7e07bf0d890e51892e179c62f197bac" + "reference": "3bdc70e9f0784832c2955bd2f887215cd38c4425" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/newfold-labs/wp-module-data/zipball/c244dd52e7e07bf0d890e51892e179c62f197bac", - "reference": "c244dd52e7e07bf0d890e51892e179c62f197bac", + "url": "https://api.github.com/repos/newfold-labs/wp-module-data/zipball/3bdc70e9f0784832c2955bd2f887215cd38c4425", + "reference": "3bdc70e9f0784832c2955bd2f887215cd38c4425", "shasum": "" }, "require": { @@ -95,10 +145,10 @@ ], "description": "Newfold Data Module", "support": { - "source": "https://github.com/newfold-labs/wp-module-data/tree/2.4.11", + "source": "https://github.com/newfold-labs/wp-module-data/tree/2.4.14", "issues": "https://github.com/newfold-labs/wp-module-data/issues" }, - "time": "2023-11-13T19:54:44+00:00" + "time": "2023-12-04T19:34:50+00:00" }, { "name": "newfold-labs/wp-module-installer", @@ -555,16 +605,16 @@ }, { "name": "phpcsstandards/phpcsextra", - "version": "1.1.2", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", - "reference": "746c3190ba8eb2f212087c947ba75f4f5b9a58d5" + "reference": "78b2cae1e9de1c05f0416de6f9a658cbb83ac324" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/746c3190ba8eb2f212087c947ba75f4f5b9a58d5", - "reference": "746c3190ba8eb2f212087c947ba75f4f5b9a58d5", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/78b2cae1e9de1c05f0416de6f9a658cbb83ac324", + "reference": "78b2cae1e9de1c05f0416de6f9a658cbb83ac324", "shasum": "" }, "require": { @@ -612,9 +662,24 @@ ], "support": { "issues": "https://github.com/PHPCSStandards/PHPCSExtra/issues", + "security": "https://github.com/PHPCSStandards/PHPCSExtra/security/policy", "source": "https://github.com/PHPCSStandards/PHPCSExtra" }, - "time": "2023-09-20T22:06:18+00:00" + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2023-12-02T14:30:12+00:00" }, { "name": "phpcsstandards/phpcsutils", diff --git a/includes/Data.php b/includes/Data.php index 89f9e06..13c5a3d 100644 --- a/includes/Data.php +++ b/includes/Data.php @@ -120,7 +120,7 @@ public static function current_plan() { */ public static function current_flow() { $current_plan = self::current_plan(); - return $current_plan['flow']; + return 'sitegen'; } /** diff --git a/includes/Flows/Flows.php b/includes/Flows/Flows.php index 380352f..996cfc4 100644 --- a/includes/Flows/Flows.php +++ b/includes/Flows/Flows.php @@ -16,7 +16,7 @@ final class Flows { * @var array */ protected static $data = array( - 'version' => '1.0.5', + 'version' => '1.0.6', // Each time step is viewed, insert GMT timestamp to array. 'isViewed' => array(), @@ -67,8 +67,10 @@ final class Flows { // This integer will map to the attachment ID for an uploaded image to the WordPress media library 'siteLogo' => array( - 'id' => 0, - 'url' => '', + 'id' => 0, + 'url' => '', + 'fileName' => '', + 'fileSize' => 0, ), // key-value store for social media accounts @@ -153,6 +155,11 @@ final class Flows { 'currentStatus' => 0, 'totalCount' => 8, ), + 'homepages' => array( + 'active' => array(), + 'data' => array(), + ), + 'customDesign' => false, ), ); diff --git a/includes/Mustache/Mustache.php b/includes/Mustache/Mustache.php new file mode 100644 index 0000000..a16d012 --- /dev/null +++ b/includes/Mustache/Mustache.php @@ -0,0 +1,37 @@ +mustache_engine = new \Mustache_Engine( + array( + 'loader' => new \Mustache_Loader_FilesystemLoader( dirname( __FILE__ ) . '/Templates' ), + ) + ); + } + + /** + * Render respective template data. + * + * @param string $template_name Template Name + * @param array $data Data + * @return string + */ + public function render_template( $template_name, $data ) { + return $this->mustache_engine->loadTemplate( $template_name )->render( $data ); + } +} diff --git a/includes/Mustache/Templates/themeStylesheet.mustache b/includes/Mustache/Templates/themeStylesheet.mustache new file mode 100644 index 0000000..8b2a081 --- /dev/null +++ b/includes/Mustache/Templates/themeStylesheet.mustache @@ -0,0 +1,9 @@ +/* +Theme Name: {{ theme_name }} +Author: {{ site_title }} & {{ brand_name }} +Author URI: {{ site_url }} +Description: A Custom WordPress Theme built for {{ site_title }} by {{ brand_name }} +Version: 1.0.0 +Template: {{ parent_theme_slug }} +Text Domain: {{ child_theme_slug }} +*/ diff --git a/includes/Services/SiteGenService.php b/includes/Services/SiteGenService.php index 8391fc8..bc8e8e5 100644 --- a/includes/Services/SiteGenService.php +++ b/includes/Services/SiteGenService.php @@ -3,7 +3,10 @@ namespace NewfoldLabs\WP\Module\Onboarding\Data\Services; use NewfoldLabs\WP\Module\AI\SiteGen\SiteGen; +use NewfoldLabs\WP\Module\Onboarding\Data\Options; use NewfoldLabs\WP\Module\Onboarding\Data\Data; +use NewfoldLabs\WP\Module\Onboarding\Data\Mustache\Mustache; +use NewfoldLabs\WP\Module\Onboarding\Data\Themes; /** * Class SiteGenService @@ -76,4 +79,134 @@ public static function instantiate_site_meta( $site_info, $identifier, $skip_cac ); } + public static function complete( $active_homepage, $homepage_data ) { + $show_pages_on_front = \get_option( Options::get_option_name( 'show_on_front', false ) ); + + // Check if default homepage is posts + if ( 'posts' === $show_pages_on_front ) { + \update_option( Options::get_option_name( 'show_on_front', false ), 'page' ); + } + + foreach( $homepage_data as $slug => $data ) { + if ( false === $data['favorite'] ) { + continue; + } + $title = $data['title']; + $content = $data['content']; + $post_id = SitePagesService::publish_page( $title, $content, true, array( + 'nf_dc_page' => 'home', + ) ); + if ( is_wp_error( $post_id ) ) { + return $post_id; + } + if ( $active_homepage['slug'] === $slug ) { + \update_option( Options::get_option_name( 'page_on_front', false ), $post_id ); + } + + self::generate_child_theme( $data ); + + } + + + return true; + } + + public static function generate_child_theme( $data ) { + global $wp_filesystem; + ThemeGeneratorService::connect_to_filesystem(); + $parent_theme_slug = 'yith-wonder'; + $parent_theme_exists = ( \wp_get_theme( $parent_theme_slug ) )->exists(); + if ( ! $parent_theme_exists ) { + return new \WP_Error( + 'nfd_onboarding_error', + 'Parent theme is missing to generate the child theme.', + array( 'status' => 500 ) + ); + } + + /* + Activate the parent theme if it is not active. + This is necessary to register the parent theme's block patterns. + */ + $active_theme = Themes::get_active_theme(); + if ( $active_theme !== $parent_theme_slug ) { + ThemeGeneratorService::activate_theme( $parent_theme_slug ); + } + + // Generate the necessary slugs and paths. + $themes_dir = dirname( \get_stylesheet_directory() ); + $parent_theme_dir = $themes_dir . '/' . $parent_theme_slug; + $child_theme_slug = $data['slug']; + $child_theme_dir = $themes_dir . '/' . $child_theme_slug; + + $theme_json_file = $parent_theme_dir . '/theme.json'; + if ( ! $wp_filesystem->exists( $theme_json_file ) ) { + return false; + } + $theme_json = $wp_filesystem->get_contents( $theme_json_file ); + $theme_json_data = json_decode( $theme_json, true ); + + $theme_json_data['settings']['color']['palette'] = $data['color']['palette']; + + if ( ! $theme_json_data ) { + return new \WP_Error( + 'nfd_onboarding_error', + 'Could not generate theme.json', + array( 'status' => 500 ) + ); + } + + $current_brand = Data::current_brand(); + $customer = \wp_get_current_user(); + + $default_site_titles_dashed = array( 'welcome', 'wordpress-site' ); + $site_title = \get_bloginfo( 'name' ); + $site_title_dashed = \sanitize_title_with_dashes( $site_title ); + if ( empty( $site_title ) || in_array( $site_title_dashed, $default_site_titles_dashed, true ) ) { + $site_title = $current_brand['brand'] . '-' . ThemeGeneratorService::get_site_url_hash(); + } + + $theme_style_data = array( + 'current_brand' => Data::current_brand(), + 'brand' => $current_brand['brand'], + 'brand_name' => $current_brand['name'] ? $current_brand['name'] : 'Newfold Digital', + 'theme_name' => $data['title'], + 'site_title' => $site_title, + 'site_url' => \site_url(), + 'author' => $customer->user_firstname, + 'parent_theme_slug' => $parent_theme_slug, + 'child_theme_slug' => $child_theme_slug, + ); + + $mustache = new Mustache(); + $child_theme_stylesheet_comment = $mustache->render_template( 'themeStylesheet', $theme_style_data ); + + // Write the child theme to the filesystem under themes. + $child_theme_data = array( + 'parent_theme_slug' => $parent_theme_slug, + 'child_theme_slug' => $child_theme_slug, + 'parent_theme_dir' => $parent_theme_dir, + 'child_theme_dir' => $child_theme_dir, + 'child_theme_json' => \wp_json_encode( $theme_json_data ), + 'child_theme_stylesheet_comment' => $child_theme_stylesheet_comment, + ); + + $child_theme_written = ThemeGeneratorService::write_child_theme( $child_theme_data ); + if ( true !== $child_theme_written ) { + return new \WP_Error( + 'nfd_onboarding_error', + $child_theme_written, + array( 'status' => 500 ) + ); + } + + // Activate the child theme. + if ( true === $data['favorite'] ) { + ThemeGeneratorService::activate_theme( $child_theme_slug ); + } + + return true; + + } + } diff --git a/includes/Services/SitePagesService.php b/includes/Services/SitePagesService.php new file mode 100644 index 0000000..bc4edd4 --- /dev/null +++ b/includes/Services/SitePagesService.php @@ -0,0 +1,27 @@ + $title, + 'post_status' => 'publish', + 'post_content' => $content, + 'post_type' => 'page', + ); + + if ( $meta ) { + $post['meta_input'] = $meta; + } + + if ( $is_template_no_title ) { + $post['page_template'] = 'no-title'; + } + + return \wp_insert_post( $post ); + } + + +} + diff --git a/includes/Services/ThemeGeneratorService.php b/includes/Services/ThemeGeneratorService.php new file mode 100644 index 0000000..20e0d35 --- /dev/null +++ b/includes/Services/ThemeGeneratorService.php @@ -0,0 +1,228 @@ +exists( $dir ) ) { + return $wp_filesystem->mkdir( $dir ); + } + + return true; + } + + /** + * Writes $theme_json to a theme's theme.json file. + * + * @param string $theme_dir Theme Directory + * @param string $theme_json Theme json content + * + * @return boolean + */ + public static function write_theme_json( $theme_dir, $theme_json ) { + return self::write_to_filesystem( $theme_dir . '/theme.json', $theme_json ); + } + + /** + * Writes HTML template parts to the theme's parts directory. + * + * @param string $theme_dir Theme Directory + * @param array $part_patterns HTML Template Part + * + * @return boolean + */ + public static function write_template_parts( $theme_dir, $part_patterns ) { + global $wp_filesystem; + + if ( ! $wp_filesystem->exists( $theme_dir . '/parts' ) ) { + $parts_directory_created = mkdir( $theme_dir . '/parts' ); + if ( ! $parts_directory_created ) { + return false; + } + } + foreach ( $part_patterns as $part => $pattern ) { + $status = self::write_to_filesystem( $theme_dir . "/parts/{$part}.html", $pattern ); + if ( ! $status ) { + return false; + } + } + + return true; + } + + /** + * Writes style.css for the child theme. + * + * @param string $child_theme_stylesheet_comment Stylesheet comment of Child Theme + * @param string $child_theme_dir Child Theme Directory + * + * @return boolean + */ + public static function write_child_stylesheet( $child_theme_stylesheet_comment, $child_theme_dir ) { + return self::write_to_filesystem( $child_theme_dir . '/style.css', $child_theme_stylesheet_comment ); + } + + + /** + * Writes content to the specified file. + * + * @param string $file Specific File where $content is to be written + * @param string $content Content to write to the $file + * + * @return boolean + */ + public static function write_to_filesystem( $file, $content ) { + global $wp_filesystem; + + return $wp_filesystem->put_contents( + $file, + $content, + FS_CHMOD_FILE // predefined mode settings for WP files + ); + } + + /** + * Copy parent's screenshot.png to the child theme directory. + * + * [TODO] Generate the actual child theme screenshot. + * + * @param string $parent_theme_dir Parent Theme Directory + * @param string $child_theme_dir Child Theme Directory + * + * @return boolean + */ + public static function generate_screenshot( $parent_theme_dir, $child_theme_dir ) { + global $wp_filesystem; + + $screenshot_files = array( '/screenshot.png', '/screenshot.jpg' ); + foreach ( $screenshot_files as $key => $screenshot_file ) { + $child_theme_screenshot_file = $child_theme_dir . $screenshot_file; + $parent_theme_screenshot_file = $parent_theme_dir . $screenshot_file; + if ( $wp_filesystem->exists( $parent_theme_screenshot_file ) ) { + break; + } + } + + if ( $wp_filesystem->exists( $child_theme_screenshot_file ) ) { + $wp_filesystem->delete( $child_theme_screenshot_file ); + } + + return $wp_filesystem->copy( + $parent_theme_screenshot_file, + $child_theme_screenshot_file + ); + } + + /** + * Retrieve Site Url Hash Value + * + * @param integer $length hash length + * + * @return string + */ + public static function get_site_url_hash( $length = 8 ) { + return substr( hash( 'sha256', site_url() ), 0, $length ); + } + + +} \ No newline at end of file