diff --git a/composer.json b/composer.json index a9428f8..b911677 100644 --- a/composer.json +++ b/composer.json @@ -23,8 +23,11 @@ }, "require": { "newfold-labs/wp-module-installer": "^1.1", - "newfold-labs/wp-module-data": "^2.4.16", + "newfold-labs/wp-module-patterns": "^0.1.12", + "newfold-labs/wp-module-ai": "^1.0.4", "wp-forge/wp-upgrade-handler": "^1.0", + "mustache/mustache": "^2.14", + "newfold-labs/wp-module-data": "^2.4.16", "newfold-labs/wp-module-coming-soon": "^1.1.13" }, "require-dev": { @@ -35,4 +38,4 @@ "dealerdirect/phpcodesniffer-composer-installer": true } } -} \ No newline at end of file +} diff --git a/composer.lock b/composer.lock index b7741bd..49b7045 100644 --- a/composer.lock +++ b/composer.lock @@ -4,22 +4,120 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "69018fa72a38a7c24cd1445d6c6610c0", + "content-hash": "6cd9b51764420c712677a723a453dcb6", "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.9", + "source": { + "type": "git", + "url": "https://github.com/newfold-labs/wp-module-ai.git", + "reference": "17e48833284ef04113abc42fc2bb773a8124aef3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/newfold-labs/wp-module-ai/zipball/17e48833284ef04113abc42fc2bb773a8124aef3", + "reference": "17e48833284ef04113abc42fc2bb773a8124aef3", + "shasum": "" + }, + "require": { + "newfold-labs/wp-module-data": "^2.3.1" + }, + "require-dev": { + "newfold-labs/wp-php-standards": "^1.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "NewfoldLabs\\WP\\Module\\AI\\": "includes" + }, + "files": [ + "bootstrap.php" + ] + }, + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "Micah Wood", + "email": "micah@bluehost.com" + } + ], + "description": "A module for providing artificial intelligence capabilities.", + "support": { + "source": "https://github.com/newfold-labs/wp-module-ai/tree/1.0.9", + "issues": "https://github.com/newfold-labs/wp-module-ai/issues" + }, + "time": "2023-12-18T14:53:40+00:00" + }, { "name": "newfold-labs/wp-module-coming-soon", - "version": "1.1.13", + "version": "1.1.14", "source": { "type": "git", "url": "https://github.com/newfold-labs/wp-module-coming-soon.git", - "reference": "9719bae8534e6c86d389b769a1757eceed5f1dd5" + "reference": "98f13af0aeccab8b3d387c4bc731a48c6cf49668" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/newfold-labs/wp-module-coming-soon/zipball/9719bae8534e6c86d389b769a1757eceed5f1dd5", - "reference": "9719bae8534e6c86d389b769a1757eceed5f1dd5", + "url": "https://api.github.com/repos/newfold-labs/wp-module-coming-soon/zipball/98f13af0aeccab8b3d387c4bc731a48c6cf49668", + "reference": "98f13af0aeccab8b3d387c4bc731a48c6cf49668", "shasum": "" }, + "require": { + "wp-forge/wp-upgrade-handler": "^1.0" + }, "require-dev": { "newfold-labs/wp-php-standards": "^1.2" }, @@ -51,10 +149,10 @@ ], "description": "Coming Soon module for WordPress sites.", "support": { - "source": "https://github.com/newfold-labs/wp-module-coming-soon/tree/1.1.13", + "source": "https://github.com/newfold-labs/wp-module-coming-soon/tree/1.1.14", "issues": "https://github.com/newfold-labs/wp-module-coming-soon/issues" }, - "time": "2024-01-08T18:13:10+00:00" + "time": "2024-01-11T20:19:06+00:00" }, { "name": "newfold-labs/wp-module-data", @@ -147,6 +245,56 @@ }, "time": "2023-09-18T06:42:43+00:00" }, + { + "name": "newfold-labs/wp-module-patterns", + "version": "0.1.12", + "source": { + "type": "git", + "url": "https://github.com/newfold-labs/wp-module-patterns.git", + "reference": "6f4189c97a9e37f24531af8cfae986041d4b613b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/newfold-labs/wp-module-patterns/zipball/6f4189c97a9e37f24531af8cfae986041d4b613b", + "reference": "6f4189c97a9e37f24531af8cfae986041d4b613b", + "shasum": "" + }, + "require-dev": { + "newfold-labs/wp-php-standards": "^1.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "NewfoldLabs\\WP\\Module\\Patterns\\": "includes" + }, + "files": [ + "bootstrap.php" + ] + }, + "scripts": { + "lint": [ + "vendor/bin/phpcs . --ignore=*/build/* --standard=Newfold -d error_reporting=\"E_ALL&~E_DEPRECATED\"" + ], + "clean": [ + "vendor/bin/phpcbf . --ignore=*/build/* --standard=Newfold -d error_reporting=\"E_ALL&~E_DEPRECATED\"" + ] + }, + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "Hristina Conjic", + "email": "hristina.conjic@newfold.com" + } + ], + "description": "WordPress Cloud Patterns", + "support": { + "source": "https://github.com/newfold-labs/wp-module-patterns/tree/0.1.12", + "issues": "https://github.com/newfold-labs/wp-module-patterns/issues" + }, + "time": "2024-01-03T21:56:57+00:00" + }, { "name": "wp-forge/wp-query-builder", "version": "1.0.3", @@ -560,29 +708,29 @@ }, { "name": "phpcsstandards/phpcsextra", - "version": "1.1.2", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", - "reference": "746c3190ba8eb2f212087c947ba75f4f5b9a58d5" + "reference": "11d387c6642b6e4acaf0bd9bf5203b8cca1ec489" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/746c3190ba8eb2f212087c947ba75f4f5b9a58d5", - "reference": "746c3190ba8eb2f212087c947ba75f4f5b9a58d5", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/11d387c6642b6e4acaf0bd9bf5203b8cca1ec489", + "reference": "11d387c6642b6e4acaf0bd9bf5203b8cca1ec489", "shasum": "" }, "require": { "php": ">=5.4", - "phpcsstandards/phpcsutils": "^1.0.8", - "squizlabs/php_codesniffer": "^3.7.1" + "phpcsstandards/phpcsutils": "^1.0.9", + "squizlabs/php_codesniffer": "^3.8.0" }, "require-dev": { "php-parallel-lint/php-console-highlighter": "^1.0", "php-parallel-lint/php-parallel-lint": "^1.3.2", "phpcsstandards/phpcsdevcs": "^1.1.6", "phpcsstandards/phpcsdevtools": "^1.2.1", - "phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0" + "phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, "type": "phpcodesniffer-standard", "extra": { @@ -617,35 +765,50 @@ ], "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-08T16:49:07+00:00" }, { "name": "phpcsstandards/phpcsutils", - "version": "1.0.8", + "version": "1.0.9", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSUtils.git", - "reference": "69465cab9d12454e5e7767b9041af0cd8cd13be7" + "reference": "908247bc65010c7b7541a9551e002db12e9dae70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/69465cab9d12454e5e7767b9041af0cd8cd13be7", - "reference": "69465cab9d12454e5e7767b9041af0cd8cd13be7", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/908247bc65010c7b7541a9551e002db12e9dae70", + "reference": "908247bc65010c7b7541a9551e002db12e9dae70", "shasum": "" }, "require": { "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0", "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.7.1 || 4.0.x-dev@dev" + "squizlabs/php_codesniffer": "^3.8.0 || 4.0.x-dev@dev" }, "require-dev": { "ext-filter": "*", "php-parallel-lint/php-console-highlighter": "^1.0", "php-parallel-lint/php-parallel-lint": "^1.3.2", "phpcsstandards/phpcsdevcs": "^1.1.6", - "yoast/phpunit-polyfills": "^1.0.5 || ^2.0.0" + "yoast/phpunit-polyfills": "^1.1.0 || ^2.0.0" }, "type": "phpcodesniffer-standard", "extra": { @@ -690,22 +853,37 @@ "support": { "docs": "https://phpcsutils.com/", "issues": "https://github.com/PHPCSStandards/PHPCSUtils/issues", + "security": "https://github.com/PHPCSStandards/PHPCSUtils/security/policy", "source": "https://github.com/PHPCSStandards/PHPCSUtils" }, - "time": "2023-07-16T21:39:41+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-08T14:50:00+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.7.2", + "version": "3.8.1", "source": { "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879" + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "14f5fff1e64118595db5408e946f3a22c75807f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/14f5fff1e64118595db5408e946f3a22c75807f7", + "reference": "14f5fff1e64118595db5408e946f3a22c75807f7", "shasum": "" }, "require": { @@ -715,11 +893,11 @@ "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, "bin": [ - "bin/phpcs", - "bin/phpcbf" + "bin/phpcbf", + "bin/phpcs" ], "type": "library", "extra": { @@ -734,22 +912,45 @@ "authors": [ { "name": "Greg Sherwood", - "role": "lead" + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", "keywords": [ "phpcs", "standards", "static analysis" ], "support": { - "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", - "source": "https://github.com/squizlabs/PHP_CodeSniffer", - "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" }, - "time": "2023-02-22T23:07:41+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": "2024-01-11T20:47:48+00:00" }, { "name": "wp-coding-standards/wpcs", diff --git a/includes/Brands.php b/includes/Brands.php index 7050c2f..0e177d8 100644 --- a/includes/Brands.php +++ b/includes/Brands.php @@ -37,6 +37,9 @@ public static function get_default_brand() { */ public static function get_brands() { + // Checks if customer has acess to AI Sitegen + $has_ai_sitegen = Config::has_ai_sitegen(); + return array( 'bluehost' => array( 'brand' => 'bluehost', @@ -103,6 +106,7 @@ public static function get_brands() { 'enabled_flows' => array( 'ecommerce' => true, 'wp-setup' => true, + 'sitegen' => $has_ai_sitegen, ), 'wonder_blocks' => true, 'prioritization' => false, @@ -165,6 +169,7 @@ public static function get_brands() { 'enabled_flows' => array( 'ecommerce' => true, 'wp-setup' => false, + 'sitegen' => $has_ai_sitegen, ), 'wonder_blocks' => true, 'prioritization' => false, @@ -225,6 +230,7 @@ public static function get_brands() { 'enabled_flows' => array( 'ecommerce' => false, 'wp-setup' => false, + 'sitegen' => $has_ai_sitegen, ), 'wonder_blocks' => true, 'prioritization' => false, @@ -285,6 +291,7 @@ public static function get_brands() { 'enabled_flows' => array( 'ecommerce' => true, 'wp-setup' => true, + 'sitegen' => $has_ai_sitegen, ), 'wonder_blocks' => true, 'prioritization' => false, @@ -352,6 +359,7 @@ public static function get_brands() { 'enabled_flows' => array( 'ecommerce' => true, 'wp-setup' => true, + 'sitegen' => $has_ai_sitegen, ), 'wonder_blocks' => true, 'prioritization' => false, @@ -437,6 +445,7 @@ public static function get_brands() { 'enabled_flows' => array( 'ecommerce' => true, 'wp-setup' => true, + 'sitegen' => $has_ai_sitegen, ), 'wonder_blocks' => true, 'prioritization' => false, diff --git a/includes/Config.php b/includes/Config.php index f3294dd..77e9faa 100644 --- a/includes/Config.php +++ b/includes/Config.php @@ -48,4 +48,13 @@ public static function get_site_capability( $capability ) { public static function is_jarvis() { return self::get_site_capability( 'isJarvis' ); } + + /** + * Gets the current customer capability if he has access to AI Sitegen. + * + * @return boolean + */ + public static function has_ai_sitegen() { + return self::get_site_capability( 'hasAISiteGen' ); + } } diff --git a/includes/Data.php b/includes/Data.php index fbc3381..b9609f9 100644 --- a/includes/Data.php +++ b/includes/Data.php @@ -16,18 +16,23 @@ final class Data { */ public static function runtime() { return array( - 'buildUrl' => \NFD_ONBOARDING_BUILD_URL, - 'siteUrl' => \get_site_url(), - 'restUrl' => \get_home_url() . '/index.php?rest_route=', - 'adminUrl' => \admin_url(), - 'currentBrand' => self::current_brand(), - 'currentPlan' => self::current_plan(), - 'currentFlow' => self::current_flow(), - 'pluginInstallHash' => PluginInstaller::rest_get_plugin_install_hash(), - 'previewSettings' => array( + 'buildUrl' => \NFD_ONBOARDING_BUILD_URL, + 'siteUrl' => \get_site_url(), + 'restUrl' => \get_home_url() . '/index.php?rest_route=', + 'adminUrl' => \admin_url(), + 'currentBrand' => self::current_brand(), + 'currentPlan' => self::current_plan(), + 'currentFlow' => self::current_flow(), + 'pluginInstallHash' => PluginInstaller::rest_get_plugin_install_hash(), + 'previewSettings' => array( 'settings' => Preview::get_settings(), 'stepPreviewData' => Themes::step_preview_data(), ), + 'aiPreviewSettings' => array( + 'settings' => Preview::get_settings(), + 'stepPreviewData' => Themes::step_preview_data(), + ), + 'currentUserDetails' => self::wp_current_user_details(), ); } @@ -51,6 +56,15 @@ public static function current_brand() { * @return array */ public static function current_plan() { + $is_sitegen = Flows::is_sitegen(); + if ( $is_sitegen ) { + return array( + 'flow' => 'sitegen', + 'subtype' => null, + 'type' => null, + ); + } + $customer_data = self::customer_data(); $current_flow = Flows::get_flow_from_customer_data( $customer_data ); @@ -140,4 +154,25 @@ public static function coming_soon() { $coming_soon_service = container()->get( 'comingSoon' ); return $coming_soon_service->is_enabled(); } + + /** + * Get the current WordPress admin user details. + * + * @return array + */ + public static function wp_current_user_details() { + $user = wp_get_current_user(); + if ( $user->exists() ) { + return array( + 'displayName' => $user->display_name, + 'avatarUrl' => get_avatar_url( $user->ID ), + ); + } + + // If no user is found, return an empty array or default values as appropriate + return array( + 'displayName' => '', + 'avatarUrl' => '', + ); + } } diff --git a/includes/Flows/Flows.php b/includes/Flows/Flows.php index eea9af1..85898ca 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.3', + 'version' => '2.0.0', // 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 @@ -110,6 +112,8 @@ final class Flows { 'comingSoon' => false, ), + 'activeFlow' => '', + // we will store active flows (abandoned wp-setup, abandoned wp-commerce) with their identifier and use as a reference to access currentStep and data 'currentFlows' => array(), @@ -132,6 +136,37 @@ final class Flows { 'product_types' => array(), ), ), + + 'sitegen' => array( + 'siteDetails' => array( + 'name' => '', + 'type' => '', + 'style' => '', + 'prompt' => '', + 'uniqueAboutBusiness' => '', + 'mode' => 'simple', + ), + 'siteLogo' => array( + 'id' => 0, + 'url' => '', + 'fileName' => '', + 'fileSize' => 0, + ), + 'experience' => array( + 'level' => 0, + ), + 'siteGenMetaStatus' => array( + 'currentStatus' => 0, + 'totalCount' => 8, + ), + 'homepages' => array( + 'active' => array(), + 'data' => array(), + ), + 'skipCache' => true, + 'sitemapPagesGenerated' => false, + 'customDesign' => false, + ), ); /** @@ -184,6 +219,7 @@ public static function get_flows() { ? $current_brand['config']['enabled_flows'] : array( 'wp-setup' => false, 'ecommerce' => false, + 'sitegen' => false, ); } @@ -273,6 +309,25 @@ public static function get_flow_from_plan_subtype( $plan_subtype ) { } return false; } + + /** + * Determines whether SiteGen flow was ever visited. + * + * @return boolean + */ + public static function is_sitegen() { + if ( ! self::get_flows()['sitegen'] ) { + return false; + } + + $flow_data = FlowService::read_data_from_wp_option(); + if ( ! $flow_data || empty( $flow_data['activeFlow'] ) ) { + return false; + } + + return 'sitegen' === $flow_data['activeFlow']; + } + /** * Get the corresponding flow from the top priority in flow data. * diff --git a/includes/Mustache/Mustache.php b/includes/Mustache/Mustache.php new file mode 100644 index 0000000..b04e2d6 --- /dev/null +++ b/includes/Mustache/Mustache.php @@ -0,0 +1,37 @@ +mustache_engine = new \Mustache_Engine( + array( + 'loader' => new \Mustache_Loader_FilesystemLoader( __DIR__ . '/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/Options.php b/includes/Options.php index db31704..0b6825c 100644 --- a/includes/Options.php +++ b/includes/Options.php @@ -55,6 +55,7 @@ final class Options { 'wc_calc_taxes' => 'woocommerce_calc_taxes', 'wc_no_sales_tax' => 'woocommerce_no_sales_tax', 'filter_active_plugins' => 'filter_active_plugins', + 'sitegen_regenerated_homepages' => 'sitegen_regenerated_homepages', 'status' => 'status', ); diff --git a/includes/Plugins.php b/includes/Plugins.php index c3fa52f..33c41d0 100644 --- a/includes/Plugins.php +++ b/includes/Plugins.php @@ -1,6 +1,10 @@ plugin()->basename, + isset( PluginsInstaller::get_wp_slugs()['woocommerce']['path'] ) ? PluginsInstaller::get_wp_slugs()['woocommerce']['path'] : false, + ); + } } diff --git a/includes/Services/FlowService.php b/includes/Services/FlowService.php index 9132bdd..412835a 100644 --- a/includes/Services/FlowService.php +++ b/includes/Services/FlowService.php @@ -390,7 +390,7 @@ private static function update_data_for_ecommerce( $data ) { * * @return array */ - private static function update_data_in_wp_option( $data ) { + public static function update_data_in_wp_option( $data ) { return \update_option( Options::get_option_name( 'flow' ), $data ); } diff --git a/includes/Services/SiteGenService.php b/includes/Services/SiteGenService.php new file mode 100644 index 0000000..a83cefc --- /dev/null +++ b/includes/Services/SiteGenService.php @@ -0,0 +1,821 @@ + 'siteclassification', + 'target_audience' => 'targetaudience', + 'content_tones' => 'contenttones', + 'content_structure' => 'contentstructure', + 'color_palette' => 'colorpalette', + 'sitemap' => 'sitemap', + 'plugin_recommendation' => 'pluginrecommendation', + 'font_pair' => 'fontpair', + ); + + /** + * Get SiteGen identifier from an Onboarding identifier key. + * + * @param string $identifier_key Onboarding identifier key. + * @return string|false + */ + public static function get_identifier_name( $identifier_key ) { + return isset( self::$identifiers[ $identifier_key ] ) ? self::$identifiers[ $identifier_key ] : false; + } + + /** + * Gets Valid Identifiers. + * + * @return array + */ + public static function enabled_identifiers() { + return array( + 'site_classification' => true, + 'target_audience' => true, + 'content_tones' => true, + 'content_structure' => true, + 'color_palette' => true, + 'sitemap' => true, + 'plugin_recommendation' => true, + 'font_pair' => true, + ); + } + + /** + * Determines whether the given identifier is valid. + * + * @param string $key The identifier to be evaluated. + * @return boolean + */ + public static function is_identifier( $key ) { + return isset( self::enabled_identifiers()[ $key ] ); + } + + /** + * Checks if the site is eligible for SiteGen Capabilities. + * + * @return boolean + */ + public static function is_enabled() { + if ( ! ( class_exists( 'NewfoldLabs\WP\Module\AI\SiteGen\SiteGen' ) ) ) { + return false; + } + return isset( Data::current_brand()['config']['enabled_flows']['sitegen'] ) + && true === Data::current_brand()['config']['enabled_flows']['sitegen']; + } + + + /** + * Sends the data required for SiteGen Generation + * + * @param string|Object $site_info The prompt that configures the Site gen object. + * @param string $identifier The identifier for Generating Site Meta. + * @param boolean $skip_cache To override the cache and fetch the data. + * @return array + */ + public static function instantiate_site_meta( $site_info, $identifier, $skip_cache = false ) { + if ( ! self::is_identifier( $identifier ) ) { + return new \WP_Error( + 'nfd_onboarding_error', + __( 'Not a valid identifier', 'wp-module-onboarding' ), + array( + 'status' => '400', + ) + ); + } + + $identifier = self::get_identifier_name( $identifier ); + $response = SiteGen::generate_site_meta( $site_info, $identifier, $skip_cache ); + if ( isset( $response['error'] ) ) { + // Handle the error case by returning a WP_Error. + return new \WP_Error( + 'nfd_onboarding_error', + __( 'Error generating site meta: ', 'wp-module-onboarding' ), + array( 'status' => 400 ) + ); + } + + return $response; + } + + /** + * Handle completion of the sitegen flow. + * + * @param array $active_homepage The active homepage that was customized. + * @param array $homepage_data All the other generated homepage options. + * @return boolean + */ + 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' ); + } + + $title = $active_homepage['title']; + $content = $active_homepage['content']; + $post_id = SitePagesService::publish_page( + $title, + $content, + true, + array( + 'nf_dc_page' => 'home', + ) + ); + + if ( is_wp_error( $post_id ) ) { + return $post_id; + } + + \update_option( Options::get_option_name( 'page_on_front', false ), $post_id ); + + self::generate_child_theme( $active_homepage ); + + foreach ( $homepage_data as $index => $data ) { + if ( $data['isFavorite'] && $data['slug'] !== $active_homepage['slug'] ) { + self::generate_child_theme( $data ); + } + } + + ThemeGeneratorService::activate_theme( $active_homepage['slug'] ); + + return true; + } + + /** + * Generates a child theme for the sitegen flow. + * + * @param array $data Data on each homepage and it's corresponding styles. + * @return true|\WP_Error + */ + 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(); + } + + $part_patterns = array(); + if ( ! empty( $data['header'] ) ) { + $part_patterns['header'] = $data['header']; + } + + if ( ! empty( $data['footer'] ) ) { + $part_patterns['footer'] = $data['footer']; + } + + $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, + 'part_patterns' => $part_patterns, + 'theme_screenshot_dir' => realpath( __DIR__ . '/../assets/images' ), + ); + + $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 ) + ); + } + + return true; + } + + /** + * Gets the preview homepages + * + * @param string $site_description Description of the site. + * @param array $content_style Description of the content style. + * @param array $target_audience Description of the target audience. + * @return array + */ + public static function generate_homepages( $site_description, $content_style, $target_audience ) { + + $homepages = SiteGen::get_home_pages( + $site_description, + $content_style, + $target_audience, + false + ); + + if ( isset( $homepages['error'] ) ) { + return new \WP_Error( + 'nfd_onboarding_error', + __( 'Error generating homepages: ', 'wp-module-onboarding' ), + array( 'status' => 400 ) + ); + } + + $processed_homepages = self::process_homepages_response( $homepages ); + + if ( is_wp_error( $processed_homepages ) ) { + return $processed_homepages; + } + + self::update_homepages( $processed_homepages ); + + return $processed_homepages; + } + + /** + * Regenerate previews for favourited homepages + * + * @param string $slug slug of the home page to be regenerated. + * @param array $color_palette color palatte. + * @return array + */ + public static function regenerate_favorite_homepage( $slug, $color_palette ) { + $existing_homepages = self::get_homepages(); + if ( ! isset( $existing_homepages[ $slug ] ) ) { + return new \WP_Error( + 'nfd_onboarding_error', + __( 'The homepage could not be found for regeneration.', 'wp-module-onboarding' ), + array( + 'status' => 404, + ) + ); + } + $homepage = $existing_homepages[ $slug ]; + + // Fetch the color palette data from the options table. + $existing_color_palettes = self::get_color_palettes(); + + if ( is_wp_error( $existing_color_palettes ) ) { + return $existing_color_palettes; + } + + // Decode the color palettes if it's not an array (assuming it's a JSON string). + if ( ( is_string( $existing_color_palettes ) ) ) { + $existing_color_palettes = json_decode( $existing_color_palettes, true ); + } + + // Select a random palette and check against the parent's palette. + $palette_index = array_rand( $existing_color_palettes ); + $selected_palette = self::transform_palette( $existing_color_palettes[ $palette_index ], $palette_index ); + + // If regeneration is true and the selected palette matches the parent's palette, reselect. + $palette_count = count( $existing_color_palettes ); + while ( $selected_palette === $color_palette && $palette_count > 1 ) { + $palette_index = array_rand( $existing_color_palettes ); + $selected_palette = self::transform_palette( $existing_color_palettes[ $palette_index ], $palette_index ); + } + + $homepage['slug'] .= '-copy'; + $homepage['title'] .= __( ' (Copy)', 'wp-module-onboarding' ); + $homepage['color'] = $selected_palette; + + while ( isset( $existing_homepages[ $homepage['slug'] ] ) ) { + $homepage['slug'] .= '-copy'; + $homepage['title'] .= __( ' (Copy)', 'wp-module-onboarding' ); + } + + $existing_homepages[ $homepage['slug'] ] = $homepage; + self::update_homepages( $existing_homepages ); + + return $homepage; + } + + /** + * Regenerate previews homepages + * + * @param string $site_description Description of the site. + * @param array $content_style Description of the content style. + * @param array $target_audience Description of the target audience. + * @return array + */ + public static function regenerate_homepage( $site_description, $content_style, $target_audience ) { + $existing_homepages = self::get_homepages(); + $regenerated_homepages = self::get_regenerated_homepages(); + + if ( ! empty( $regenerated_homepages ) ) { + $regenerated_homepage = array_shift( $regenerated_homepages ); + $existing_homepages[ $regenerated_homepage['slug'] ] = $regenerated_homepage; + self::update_homepages( $existing_homepages ); + self::update_regenerated_homepages( $regenerated_homepages ); + return $regenerated_homepage; + } + + $regenerated_homepages = SiteGen::get_home_pages( $site_description, $content_style, $target_audience, true ); + if ( isset( $homepages['error'] ) ) { + return new \WP_Error( + 'nfd_onboarding_error', + __( 'Error re-generating homepages: ', 'wp-module-onboarding' ), + array( 'status' => 400 ) + ); + } + $processed_regenerated_homepages = self::process_homepages_response( $regenerated_homepages ); + $regenerated_homepage = array_shift( $processed_regenerated_homepages ); + $existing_homepages[ $regenerated_homepage['slug'] ] = $regenerated_homepage; + self::update_homepages( $existing_homepages ); + self::update_regenerated_homepages( $processed_regenerated_homepages ); + return $regenerated_homepage; + } + + /** + * Processes the Homepages response structure for homepages + * + * @param array $homepages array. + * @return array + */ + public static function process_homepages_response( + $homepages + ) { + $processed_homepages = array(); + // Fetch the color palette data from the options table. + $color_palettes = self::get_color_palettes(); + + if ( is_wp_error( $color_palettes ) ) { + return $color_palettes; + } + // Retrieve the existing homepages to find the last version number. + $existing_homepages = self::get_homepages(); + $last_version_number = self::get_last_version_number( $existing_homepages ); + $version_number = $last_version_number + 1; + + foreach ( $homepages as $slug => $data ) { + + // Select a random palette and check against the parent's palette. + $palette_index = array_rand( $color_palettes ); + $selected_palette = self::transform_palette( $color_palettes[ $palette_index ], $palette_index ); + + $homepage_slug = 'version-' . $version_number; + $processed_homepages[ $homepage_slug ] = array( + 'slug' => $homepage_slug, + 'title' => __( 'Version ', 'wp-module-onboarding' ) . $version_number, + 'isFavorite' => false, + 'content' => $data['content'], + 'header' => $data['header'], + 'footer' => $data['footer'], + 'color' => $selected_palette, + ); + ++$version_number; + } + + return $processed_homepages; + } + + + /** + * Get color palattes from the SiteGen meta. + * + * @return array|\WP_Error + */ + public static function get_color_palettes() { + $prompt = self::get_prompt(); + if ( ! $prompt ) { + return new \WP_Error( + 'nfd_onboarding_error', + __( 'Prompt not found.', 'wp-module-onboarding' ), + array( 'status' => 404 ) + ); + } + + $color_palette = self::instantiate_site_meta( + array( + 'site_description' => $prompt, + ), + 'color_palette' + ); + + if ( is_wp_error( $color_palette ) ) { + return new \WP_Error( + 'nfd_onboarding_error', + __( 'Cannot retrieve color palatte', 'wp-module-onboarding' ), + array( 'status' => 400 ) + ); + } + + $color_palettes = array(); + if ( is_int( array_rand( $color_palette ) ) ) { + $color_palettes = $color_palette; + } else { + $color_palettes[] = $color_palette; + } + return $color_palettes; + } + + /** + * Get the last version number to increment excluiding the (copy) versions + * + * @param array $homepages unstructured home pages from sitegen ai responses. + * @return array + */ + public static function get_last_version_number( $homepages ) { + // Initialize to zero, assuming there are no versions yet. + $last_version_number = 0; + + // Loop through the homepages to find the highest version number. + foreach ( $homepages as $slug => $data ) { + // Extract the number from the slug (assuming slug is like "version3"). + if ( preg_match( '/version-(\d+)$/', $slug ) ) { + ++$last_version_number; + } + } + + return $last_version_number; + } + + /** + * Transform the color palatte structure for response + * + * @param array $palette color platte chosen to transform. + * @param string $palette_index color palatte index. + * @return array + */ + public static function transform_palette( $palette, $palette_index ) { + $palette_name = 'palette-' . ( $palette_index + 1 ); + $transformed_palette = array( + 'slug' => $palette_name, + 'palette' => array_map( + function ( $key, $value ) { + return array( + 'slug' => $key, + 'name' => ucfirst( str_replace( '_', ' ', $key ) ), + 'color' => $value, + ); + }, + array_keys( $palette ), + $palette + ), + ); + + return $transformed_palette; + } + + /** + * Get Plugin recommendations from the SiteGen meta. + * + * @return array|\WP_Error + */ + public static function get_plugin_recommendations() { + $flow_data = \get_option( Options::get_option_name( 'flow' ), false ); + if ( ! $flow_data || empty( $flow_data['sitegen']['siteDetails']['prompt'] ) ) { + return new \WP_Error( + 'nfd_onboarding_error', + __( 'Prompt not found.', 'wp-module-onboarding' ), + array( 'status' => 404 ) + ); + } + + $prompt = $flow_data['sitegen']['siteDetails']['prompt']; + $plugin_recommendations = self::instantiate_site_meta( + array( + 'site_description' => $prompt, + ), + 'plugin_recommendation' + ); + + if ( isset( $plugin_recommendations['error'] ) || is_wp_error( $plugin_recommendations ) ) { + return new \WP_Error( + 'nfd_onboarding_error', + __( 'Cannot retrieve plugin recommendations.', 'wp-module-onboarding' ), + array( 'status' => 400 ) + ); + } + + $priority = 0; + $recommended_plugins = isset( $plugin_recommendations['recommendedPlugins'] ) ? $plugin_recommendations['recommendedPlugins'] : array(); + $final_recommended_plugins = array(); + foreach ( $recommended_plugins as $recommended_plugin ) { + $recommended_plugin['priority'] = $priority; + $priority += 20; + $recommended_plugin['activate'] = false; + array_push( $final_recommended_plugins, $recommended_plugin ); + } + + $required_plugins = isset( $plugin_recommendations['requiredPlugins'] ) ? $plugin_recommendations['requiredPlugins'] : array(); + $final_required_plugins = array(); + foreach ( $required_plugins as $required_plugin ) { + $required_plugin['priority'] = $priority; + $priority += 20; + $required_plugin['activate'] = true; + array_push( $final_required_plugins, $required_plugin ); + } + + return array_merge( $final_required_plugins, $final_recommended_plugins ); + } + + /** + * Get SiteGen customize sidebar data. + * + * @return array|\WP_Error + */ + public static function get_customize_sidebar_data() { + $flow_data = get_option( Options::get_option_name( 'flow' ), false ); + if ( ! $flow_data || empty( $flow_data['sitegen']['siteDetails']['prompt'] ) ) { + return new \WP_Error( + 'nfd_onboarding_error', + __( 'Prompt not found.', 'wp-module-onboarding' ), + array( 'status' => 404 ) + ); + } + + $prompt = $flow_data['sitegen']['siteDetails']['prompt']; + $color_palette = self::instantiate_site_meta( + array( + 'site_description' => $prompt, + ), + 'color_palette' + ); + $font_pair = self::instantiate_site_meta( + array( + 'site_description' => $prompt, + ), + 'font_pair' + ); + + if ( is_wp_error( $color_palette ) ) { + $color_palette = Colors::get_sitegen_color_palette_data(); + } + + if ( is_wp_error( $font_pair ) ) { + $font_pair = Fonts::get_sitegen_font_data(); + } + + $default_design = Fonts::get_sitegen_default_design_data(); + + return array( + 'design' => $default_design, + 'colorPalettes' => $color_palette, + 'designStyles' => $font_pair, + ); + } + + /** + * Filters Wonder Blocks transients before they are set. + * + * @return void + */ + public static function pre_set_filter_wonder_blocks_transients() { + $args = wp_parse_args( + array( + 'primary_type' => PatternsSiteClassification::get_primary_type(), + 'secondary_type' => PatternsSiteClassification::get_secondary_type(), + ) + ); + $id = md5( serialize( $args ) ); + + \add_action( "pre_set_transient_wba_templates_{$id}", array( __CLASS__, 'filter_wonder_blocks_templates_transient' ), 10, 1 ); + \add_action( 'pre_set_transient_wba_templates_categories', array( __CLASS__, 'filter_wonder_blocks_categories_transient' ), 10, 1 ); + } + + /** + * Filters the Wonder Blocks templates transient. + * + * @param array $value The original value of the transient. + * @return array + */ + public static function filter_wonder_blocks_templates_transient( $value ) { + if ( empty( $value ) || ! is_array( $value ) ) { + return $value; + } + + $homepages = self::get_homepages(); + if ( ! $homepages ) { + return $value; + } + + foreach ( $homepages as $index => $data ) { + array_push( + $value, + array( + 'id' => $data['slug'], + 'slug' => $data['slug'], + 'description' => $data['slug'], + 'content' => $data['content'], + 'categories' => array( 'home', 'featured' ), + ) + ); + } + + return $value; + } + + /** + * Filters the Wonder Blocks categories transient. + * + * @param array $value The original value of the transient. + * @return array + */ + public static function filter_wonder_blocks_categories_transient( $value ) { + if ( empty( $value ) || ! is_array( $value ) ) { + return $value; + } + + $homepages = self::get_homepages(); + if ( ! $homepages ) { + return $value; + } + + foreach ( $value as $index => $category ) { + if ( 'home' === $category['title'] ) { + $category['count'] = $category['count'] + count( $homepages ); + $value[ $index ] = $category; + } + } + + return $value; + } + + /** + * Fetches the homepages generated in the Sitegen flow. + * + * @return false|array + */ + public static function get_homepages() { + $data = FlowService::read_data_from_wp_option( false ); + return isset( $data['sitegen']['homepages']['data'] ) ? $data['sitegen']['homepages']['data'] : false; + } + + /** + * Get the prompt entered during the sitegen flow. + * + * @return string|false + */ + public static function get_prompt() { + $data = FlowService::read_data_from_wp_option( false ); + return ! empty( $data['sitegen']['siteDetails']['prompt'] ) ? $data['sitegen']['siteDetails']['prompt'] : false; + } + + /** + * Update the list of sitegen generated homepages. + * + * @param array $homepages The new list of homepages. + * @return boolean + */ + public static function update_homepages( $homepages ) { + $data = FlowService::read_data_from_wp_option( false ); + if ( ! isset( $data['sitegen']['homepages']['data'] ) ) { + return false; + } + + $data['sitegen']['homepages']['data'] = $homepages; + FlowService::update_data_in_wp_option( $data ); + return true; + } + + /** + * Get the list of regenerated homepages. + * + * @return array + */ + public static function get_regenerated_homepages() { + return \get_option( Options::get_option_name( 'sitegen_regenerated_homepages' ), array() ); + } + + /** + * Update the list of sitegen regenerated homepages. + * + * @param array $regenerated_homepages The new list of regenerated homepages. + * @return boolean + */ + public static function update_regenerated_homepages( $regenerated_homepages ) { + \update_option( Options::get_option_name( 'sitegen_regenerated_homepages' ), $regenerated_homepages ); + return true; + } + + /** + * Sets the sitemapPagesGenerated data in the flow. + * + * @param boolean $status The status of the generated sitemap pages. + * @return true + */ + public static function set_sitemap_pages_generated( $status ) { + $data = FlowService::read_data_from_wp_option( false ); + $data['sitegen']['sitemapPagesGenerated'] = $status; + FlowService::update_data_in_wp_option( $data ); + return true; + } + + /** + * Generate and publish the sitemap pages. + * + * @param string $site_description The description of the site (prompt). + * @param array $content_style The type of content style. + * @param array $target_audience The target audience meta. + * @param array $sitemap The list of site pages and their keywords. + * @return true + */ + public static function publish_sitemap_pages( $site_description, $content_style, $target_audience, $sitemap ) { + $other_pages = SiteGen::get_pages( + $site_description, + $content_style, + $target_audience, + $sitemap, + false + ); + + // TODO: Improve error handling to reliably determine if a page has been published or not instead of trying and returning true. + foreach ( $sitemap as $index => $page ) { + if ( ! isset( $other_pages[ $page['slug'] ] ) || isset( $other_pages[ $page['slug']['error'] ] ) ) { + continue; + } + + $page_content = $other_pages[ $page['slug'] ]; + SitePagesService::publish_page( + $page['title'], + $page_content, + true, + array( + 'nf_dc_page' => $page['slug'], + ) + ); + } + + self::set_sitemap_pages_generated( true ); + + return true; + } +} diff --git a/includes/Services/SitePagesService.php b/includes/Services/SitePagesService.php new file mode 100644 index 0000000..043872e --- /dev/null +++ b/includes/Services/SitePagesService.php @@ -0,0 +1,36 @@ + $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..8e3fe99 --- /dev/null +++ b/includes/Services/ThemeGeneratorService.php @@ -0,0 +1,229 @@ +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 $src_dir The Source Directory + * @param string $child_theme_dir Child Theme Directory + * + * @return boolean + */ + public static function generate_screenshot( $src_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; + $screenshot_file = $src_dir . $screenshot_file; + if ( $wp_filesystem->exists( $screenshot_file ) ) { + break; + } + } + + if ( $wp_filesystem->exists( $child_theme_screenshot_file ) ) { + $wp_filesystem->delete( $child_theme_screenshot_file ); + } + + return $wp_filesystem->copy( + $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 ); + } +} diff --git a/includes/SiteGen.php b/includes/SiteGen.php new file mode 100644 index 0000000..ccff0fc --- /dev/null +++ b/includes/SiteGen.php @@ -0,0 +1,32 @@ + array( + 'question' => __( '1. Do you have a business name or website title?', 'wp-module-onboarding' ), + 'prompt' => __( 'My business name is', 'wp-module-onboarding' ), + ), + 'websiteType' => array( + 'question' => __( '2. What type of website are you making?', 'wp-module-onboarding' ), + 'placeholder' => __( 'e.g. Graphic design portfolio', 'wp-module-onboarding' ), + 'prompt' => __( 'I am making a website type of', 'wp-module-onboarding' ), + ), + 'uniqueBusiness' => array( + 'question' => __( '3. Is there anything unique about your business or brand?', 'wp-module-onboarding' ), + 'placeholder' => __( 'e.g. Unique product, amazing customer service, customizations, etc.', 'wp-module-onboarding' ), + 'prompt' => __( 'Unique about my business is', 'wp-module-onboarding' ), + ), + ); + } +} diff --git a/includes/Themes.php b/includes/Themes.php index e786b75..9a74050 100644 --- a/includes/Themes.php +++ b/includes/Themes.php @@ -14,6 +14,7 @@ final class Themes { protected static $flow_default_theme_slugs = array( 'wp-setup' => 'yith-wonder', 'ecommerce' => 'yith-wonder', + 'sitegen' => 'yith-wonder', ); /** @@ -48,6 +49,15 @@ final class Themes { ), ), ), + 'sitegen' => array( + 'default' => array( + array( + 'slug' => 'nfd_slug_yith_wonder', + 'activate' => true, + 'priority' => 20, + ), + ), + ), ); /** diff --git a/includes/Themes/Colors.php b/includes/Themes/Colors.php index 1d84c07..f5cf1cc 100644 --- a/includes/Themes/Colors.php +++ b/includes/Themes/Colors.php @@ -166,6 +166,81 @@ protected static function get_theme_colors() { ); } + /** + * This returns default Color Palette data for Sitegen customize sidebar. + * + * @var string + */ + public static function get_sitegen_color_palette_data() { + return array( + array( + 'name' => 'Tropical Dawn', + 'base' => '#F0F0F0', + 'contrast' => '#333333', + 'primary' => '#09728C', + 'secondary' => '#C79E10', + 'tertiary' => '#F5EBB8', + 'header_background' => '#09728C', + 'header_foreground' => '#F5EBB8', + 'header_titles' => '#F5EBB8', + 'secondary_background' => '#09728C', + 'secondary_foreground' => '#F5EBB8', + ), + array( + 'name' => 'Earthy Delight', + 'base' => '#EAE2D6', + 'contrast' => '#2E2E2E', + 'primary' => '#D19858', + 'secondary' => '#A1623B', + 'tertiary' => '#704238', + 'header_background' => '#D19858', + 'header_foreground' => '#EAE2D6', + 'header_titles' => '#EAE2D6', + 'secondary_background' => '#A1623B', + 'secondary_foreground' => '#EAE2D6', + ), + array( + 'name' => 'Cool Breeze', + 'base' => '#D9E4E7', + 'contrast' => '#1B1B1B', + 'primary' => '#3C7A89', + 'secondary' => '#5E9EA4', + 'tertiary' => '#81BFC5', + 'header_background' => '#3C7A89', + 'header_foreground' => '#D9E4E7', + 'header_titles' => '#D9E4E7', + 'secondary_background' => '#5E9EA4', + 'secondary_foreground' => '#D9E4E7', + ), + array( + 'name' => 'Warm Comfort', + 'base' => '#F4E1D2', + 'contrast' => '#272727', + 'primary' => '#D83367', + 'secondary' => '#F364A2', + 'tertiary' => '#FEA5E2', + 'header_background' => '#D83367', + 'header_foreground' => '#F4E1D2', + 'header_titles' => '#F4E1D2', + 'secondary_background' => '#F364A2', + 'secondary_foreground' => '#F4E1D2', + ), + array( + 'name' => 'Classic Elegance', + 'base' => '#EDEDED', + 'contrast' => '#1C1C1C', + 'primary' => '#A239CA', + 'secondary' => '#4717F6', + 'tertiary' => '#E7DFDD', + 'header_background' => '#A239CA', + 'header_foreground' => '#EDEDED', + 'header_titles' => '#EDEDED', + 'secondary_background' => '#4717F6', + 'secondary_foreground' => '#EDEDED', + ), + ); + } + /** * Retrieves the active theme color variations. * diff --git a/includes/Themes/Fonts.php b/includes/Themes/Fonts.php index c3205ff..4aa1d74 100644 --- a/includes/Themes/Fonts.php +++ b/includes/Themes/Fonts.php @@ -213,6 +213,81 @@ protected static function get_theme_fonts() { ); } + /** + * This returns the default font data for Sitegen customize sidebar. + * + * @var string + */ + public static function get_sitegen_font_data() { + return array( + array( + 'aesthetics' => 'modern', + 'fonts_heading' => 'Arial', + 'fonts_content' => 'Times New Roman', + 'spacing' => 6, + 'radius' => 4, + ), + array( + 'aesthetics' => 'vintage', + 'fonts_heading' => 'Courier New', + 'fonts_content' => 'Georgia', + 'spacing' => 5, + 'radius' => 3, + ), + array( + 'aesthetics' => 'minimalist', + 'fonts_heading' => 'Verdana', + 'fonts_content' => 'Tahoma', + 'spacing' => 7, + 'radius' => 2, + ), + array( + 'aesthetics' => 'retro', + 'fonts_heading' => 'Lucida Console', + 'fonts_content' => 'Palatino Linotype', + 'spacing' => 6, + 'radius' => 5, + ), + array( + 'aesthetics' => 'typographic', + 'fonts_heading' => 'Impact', + 'fonts_content' => 'Comic Sans MS', + 'spacing' => 5, + 'radius' => 3, + ), + ); + } + + /** + * This returns the default design data for Sitegen customize sidebar. + * + * @var string + */ + public static function get_sitegen_default_design_data() { + return array( + 'name' => 'Modern Foodie', + 'style' => array( + 'aesthetics' => 'modern', + 'fonts_heading' => 'Arial', + 'fonts_content' => 'Times New Roman', + 'spacing' => 6, + 'radius' => 4, + ), + 'color_palette' => array( + 'base' => '#F0F0F0', + 'contrast' => '#333333', + 'primary' => '#09728C', + 'secondary' => '#C79E10', + 'tertiary' => '#F5EBB8', + 'header_background' => '#09728C', + 'header_foreground' => '#F5EBB8', + 'header_titles' => '#F5EBB8', + 'secondary_background' => '#09728C', + 'secondary_foreground' => '#F5EBB8', + ), + ); + } + /** * Retrieves the active theme font variations. * diff --git a/includes/assets/images/screenshot.png b/includes/assets/images/screenshot.png new file mode 100644 index 0000000..5a67181 Binary files /dev/null and b/includes/assets/images/screenshot.png differ