diff --git a/plugins/wme-sitebuilder/wme-sitebuilder/Container.php b/plugins/wme-sitebuilder/wme-sitebuilder/Container.php index e41fbb22..d41f1f3b 100755 --- a/plugins/wme-sitebuilder/wme-sitebuilder/Container.php +++ b/plugins/wme-sitebuilder/wme-sitebuilder/Container.php @@ -156,11 +156,18 @@ public function config() { // Services. - Services\Domain::class => null, - Services\Logger::class => null, + Services\Domain::class => null, + Services\Goals::class => null, + Services\Logger::class => null, + Services\Kadence\Templates\ApiClient::class => null, // Wizards. - Wizards\FirstTimeConfiguration::class => null, + Wizards\FirstTimeConfiguration::class => static function ( $app ) { + return new Wizards\FirstTimeConfiguration( + $app->make( Services\Kadence\Templates\ApiClient::class ), + $app->make( Services\Goals::class ) + ); + }, Wizards\GoLive::class => static function ( $app ) { return new Wizards\GoLive( $app->make( Contracts\ManagesDomain::class ) diff --git a/plugins/wme-sitebuilder/wme-sitebuilder/Exceptions/WPErrorException.php b/plugins/wme-sitebuilder/wme-sitebuilder/Exceptions/WPErrorException.php new file mode 100644 index 00000000..adbf8f44 --- /dev/null +++ b/plugins/wme-sitebuilder/wme-sitebuilder/Exceptions/WPErrorException.php @@ -0,0 +1,42 @@ +error = $wp_error; + + parent::__construct( + $wp_error->get_error_message(), + is_numeric($wp_error->get_error_code()) ? (int) $wp_error->get_error_code() : 0 + ); + } + + /** + * Get the underlying WP_Error object. + * + * @return WP_Error The underlying WP_Error object. + */ + public function getError(): WP_Error + { + return $this->error; + } +} diff --git a/plugins/wme-sitebuilder/wme-sitebuilder/Services/Goals.php b/plugins/wme-sitebuilder/wme-sitebuilder/Services/Goals.php new file mode 100644 index 00000000..8591685f --- /dev/null +++ b/plugins/wme-sitebuilder/wme-sitebuilder/Services/Goals.php @@ -0,0 +1,105 @@ + self::GOALS_BUSINESS, + 'value' => __( 'Create a home for myself, my business or organization online', 'wme-sitebuilder' ), + 'description' => __( 'A web presence that shares information about my services, and expertise and helps customers find and get in contact with me.', 'wme-sitebuilder' ), + 'icon' => 'WebAsset', + 'requiredPages' => [ + 'home' => [ + 'title' => __( 'Home', 'wme-sitebuilder' ), + ], + 'about' => [ + 'title' => __( 'About', 'wme-sitebuilder' ), + ], + 'contact' => [ + 'title' => __( 'Contact', 'wme-sitebuilder' ), + ], + ], + 'requiredPlugins' => [], + ], + [ + 'key' => self::GOALS_ECOMMERCE, + 'value' => __( 'Sell physical or digital goods online', 'wme-sitebuilder' ), + 'description' => __( 'An ecommerce store to accept payment and manage customers.', 'wme-sitebuilder' ), + 'icon' => 'ShoppingCart', + 'requiredPages' => [ + 'shop' => [ + 'title' => __( 'Shop', 'wme-sitebuilder' ), + ] + ], + 'requiredPlugins' => [ + 'woocommerce', + ], + ], + [ + 'key' => self::GOALS_BLOG, + 'value' => __( 'Share news or write blogs', 'wme-sitebuilder' ), + 'description' => __( 'Posting content is the primary goal of my organization or a core component of my website.', 'wme-sitebuilder' ), + 'icon' => 'Article', + 'requiredPages' => [ + 'blog' => [ + 'title' => __( 'News', 'wme-sitebuilder' ), + ], + ], + 'requiredPlugins' => [], + ], + [ + 'key' => self::GOALS_CAREERS, + 'value' => __( 'Share open positions to potential candidates', 'wme-sitebuilder' ), + 'description' => '', + 'icon' => 'SupervisorAccount', + 'requiredPages' => [ + 'careers' => [ + 'title' => __( 'Careers', 'wme-sitebuilder' ), + ], + ], + 'requiredPlugins' => [], + ], + [ + 'key' => self::GOALS_SERVICES, + 'value' => __( 'Promote my services', 'wme-sitebuilder' ), + 'description' => '', + 'icon' => 'ChatBubble', + 'requiredPages' => [ + 'services' => [ + 'title' => __( 'Services', 'wme-sitebuilder' ), + ], + ], + 'requiredPlugins' => [], + ], + [ + 'key' => self::GOALS_PRICING_PLANS, + 'value' => __( 'Share my pricing plans', 'wme-sitebuilder' ), + 'description' => __( 'A place to showcase each plan, with their benefits and prices.', 'wme-sitebuilder' ), + 'icon' => 'PriceChange', + 'requiredPages' => [ + 'pricing' => [ + 'title' => __( 'Plans (Pricing)', 'wme-sitebuilder' ), + ], + ], + 'requiredPlugins' => [], + ], + ]; + + return apply_filters( 'wme_sitebuilder_ftc_wizard_goals', $goals ); + } +} diff --git a/plugins/wme-sitebuilder/wme-sitebuilder/Services/Kadence/Templates/ApiClient.php b/plugins/wme-sitebuilder/wme-sitebuilder/Services/Kadence/Templates/ApiClient.php new file mode 100644 index 00000000..b0b735de --- /dev/null +++ b/plugins/wme-sitebuilder/wme-sitebuilder/Services/Kadence/Templates/ApiClient.php @@ -0,0 +1,92 @@ + An array containing all page templates sorted by type.Z + */ + public function fetch_page_patterns() + { + $pages = wp_cache_get( 'wme_ktp_pages' ); + + if (! $pages) { + $response = $this->fetch_patterns(Types::PAGES); + $body = json_decode($response['body'], true); + + foreach ( TYPES::get_page_types() as $type ) { + $pages[$type] = array_filter( $body, function ($item) use ($type) { + return in_array( $type, array_keys($item['categories'])); + }); + } + + wp_cache_set( 'wme_ktp_pages', $pages, '', 60 * 60 * 24 ); + } + + // slug => string + // name => string + // categories => array (use as is) + // keywords => array (use as is) + // pro => bool + // locked => bool + // content => string (ignore) + // html => string (ignore) + // rows_htmls => gutenberg blocks + // rows => array + // description => string + // image => url + // imageW => int + // imageH => int + return $pages; + } + + /** + * Fetch the Kadence Template Patterns Cloud API + * + * @param string $type The type of pattern to fetch. + * @param mixed[] $args Optional. WP HTTP API arguments, which will be merged with defaults. + * {@link https://developer.wordpress.org/reference/classes/WP_Http/request/#parameters}. + * + * @throws WPErrorException If an error occurs making the request. + * + * @return Array An array containing the following keys: 'headers', 'body', 'response', 'cookies', + * and 'filename'. This is the same as {@see \WP_HTTP::request()} + */ + public function fetch_patterns(string $type, array $args = []) + { + if (!Types::is_valid_type($type)) { + return new WP_Error('invalid_type', sprintf('The type %s is not valid.', $type)); + } + + $response = wp_remote_request( + esc_url_raw(sprintf('%1$s/wp-json/kadence-cloud/v1/pages/?key=%2$s', $this->url, $type)), + array_replace_recursive([ + 'user-agent' => 'StellarWP/WME/PartnerCloud', + 'timeout' => 30, + 'headers' => [ + 'Accept' => 'application/json', + ], + ], $args) + ); + + if (is_wp_error($response)) { + throw new WPErrorException($response); + } + + return $response; + } +} diff --git a/plugins/wme-sitebuilder/wme-sitebuilder/Services/Kadence/Templates/Types.php b/plugins/wme-sitebuilder/wme-sitebuilder/Services/Kadence/Templates/Types.php new file mode 100644 index 00000000..58e4c2ee --- /dev/null +++ b/plugins/wme-sitebuilder/wme-sitebuilder/Services/Kadence/Templates/Types.php @@ -0,0 +1,66 @@ +api_client = $api_client; + $this->goals = $goals; + parent::__construct(); $this->add_ajax_action( 'wizard_started', [ $this, 'telemetryWizardStarted' ] ); @@ -99,7 +105,7 @@ public function props() { 'autoLaunch' => false, 'canBeClosed' => $this->isComplete(), 'adminUrl' => admin_url(), - 'goal_choices' => $this->getGoalsChoices(), + 'goal_choices' => $this->goals->getChoices(), 'site' => [ 'siteName' => $this->getSitename(), 'tagline' => $this->getTagline(), @@ -186,7 +192,7 @@ public function finish() { $this->getData()->set( 'complete', true )->save(); - do_action( 'wme_event_wizard_ftc_completed', $this ); + do_action( 'wme_event_wizard_ftc_completed' ); do_action( 'wme_event_wizard_completed', 'ftc' ); $this->setUserCredentials(); @@ -203,98 +209,6 @@ public function isComplete() { return (bool) $this->getData()->get( 'complete', false ); } - /** - * Get the goal choices. - * - * @return array - */ - public function getGoalsChoices() { - $goals = [ - [ - 'key' => self::GOALS_BUSINESS, - 'value' => __( 'Create a home for myself, my business or organization online', 'wme-sitebuilder' ), - 'description' => __( 'A web presence that shares information about my services, and expertise and helps customers find and get in contact with me.', 'wme-sitebuilder' ), - 'icon' => 'WebAsset', - 'requiredPages' => [ - 'home' => [ - 'title' => __( 'Home', 'wme-sitebuilder' ), - ], - 'about' => [ - 'title' => __( 'About', 'wme-sitebuilder' ), - ], - 'contact' => [ - 'title' => __( 'Contact', 'wme-sitebuilder' ), - ], - ], - 'requiredPlugins' => [], - ], - [ - 'key' => self::GOALS_ECOMMERCE, - 'value' => __( 'Sell physical or digital goods online', 'wme-sitebuilder' ), - 'description' => __( 'An ecommerce store to accept payment and manage customers.', 'wme-sitebuilder' ), - 'icon' => 'ShoppingCart', - 'requiredPages' => [ - 'shop' => [ - 'title' => __( 'Shop', 'wme-sitebuilder' ), - ] - ], - 'requiredPlugins' => [ - 'woocommerce', - ], - ], - [ - 'key' => self::GOALS_BLOG, - 'value' => __( 'Share news or write blogs', 'wme-sitebuilder' ), - 'description' => __( 'Posting content is the primary goal of my organization or a core component of my website.', 'wme-sitebuilder' ), - 'icon' => 'Article', - 'requiredPages' => [ - 'news' => [ - 'title' => __( 'News', 'wme-sitebuilder' ), - ], - ], - 'requiredPlugins' => [], - ], - [ - 'key' => self::GOALS_CAREERS, - 'value' => __( 'Share open positions to potential candidates', 'wme-sitebuilder' ), - 'description' => '', - 'icon' => 'SupervisorAccount', - 'requiredPages' => [ - 'careers' => [ - 'title' => __( 'Careers', 'wme-sitebuilder' ), - ], - ], - 'requiredPlugins' => [], - ], - [ - 'key' => self::GOALS_SERVICES, - 'value' => __( 'Promote my services', 'wme-sitebuilder' ), - 'description' => '', - 'icon' => 'ChatBubble', - 'requiredPages' => [ - 'services' => [ - 'title' => __( 'Services', 'wme-sitebuilder' ), - ], - ], - 'requiredPlugins' => [], - ], - [ - 'key' => self::GOALS_PRICING_PLANS, - 'value' => __( 'Share my pricing plans', 'wme-sitebuilder' ), - 'description' => __( 'A place to showcase each plan, with their benefits and prices.', 'wme-sitebuilder' ), - 'icon' => 'PriceChange', - 'requiredPages' => [ - 'plans' => [ - 'title' => __( 'Plans (Pricing)', 'wme-sitebuilder' ), - ], - ], - 'requiredPlugins' => [], - ], - ]; - - return apply_filters( 'wme_sitebuilder_ftc_wizard_goals', $goals ); - } - /** * Auto launch the wizard. * @@ -792,7 +706,8 @@ public function actionGoalSave() { return; } - $goalChoices = $this->getGoalsChoices(); + $goalChoices = $this->goals->getChoices(); + $page_templates = $this->api_client->fetch_page_patterns(); foreach ( $goals as $selected ) { $goal = array_filter( $goalChoices, function ( $choice ) use ( $selected ) { @@ -810,6 +725,10 @@ public function actionGoalSave() { } foreach ( $goal['requiredPages'] as $slug => $args ) { + if ( ! empty( $page_templates[ $slug ] ) ) { + $key = array_rand( $page_templates[ $slug ]); + $args['content'] = implode( PHP_EOL, array_filter( wp_list_pluck($page_templates[ $slug ][$key]['rows'], 'pattern_content') ) ); + } $this->createPage( $slug, $args ); } } @@ -833,9 +752,14 @@ protected function createPage( string $slug, array $args ) { 'post_name' => $slug, 'post_type' => 'page', 'post_status' => 'publish', - 'post_content' => '', + 'post_content' => $args['content'], ]; - wp_insert_post( $page ); + $page_id = wp_insert_post( $page ); + + if ( 'home' === $slug ) { + update_option( 'show_on_front', 'page' ); + update_option( 'page_on_front', (int) $page_id ); + } } }