Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 93
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
SitekitsContentGeneration
0.00% covered (danger)
0.00%
0 / 93
0.00% covered (danger)
0.00%
0 / 9
552
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 generate_sitekits
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
42
 get_sitekit_object
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 process_sitekit_item
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
6
 get_page_content_from_patterns
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 install_pre_requisites_in_background
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 publish_content
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
30
 site_type_supported
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 check_custom_logo
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace NewfoldLabs\WP\Module\Onboarding\Services\Ai\ContentGeneration;
4
5use NewfoldLabs\WP\Module\Onboarding\Services\LanguageService;
6use NewfoldLabs\WP\Module\Onboarding\Services\SiteGenService;
7use NewfoldLabs\WP\Module\Onboarding\Services\SiteTypes\EcommerceSiteTypeService;
8use NewfoldLabs\WP\Module\Onboarding\Services\SiteTypes\CommonSiteTypeService;
9use NewfoldLabs\WP\Module\Onboarding\Types\Page;
10use NewfoldLabs\WP\Module\Onboarding\Types\Pages;
11use NewfoldLabs\WP\Module\Onboarding\Types\SiteClassification;
12use NewfoldLabs\WP\Module\Onboarding\Types\Sitekit;
13
14class SitekitsContentGeneration {
15
16    private static $site_types_supported = [
17        'ecommerce', 'personal', 'business', 'linkinbio'
18    ];
19
20    /**
21     * The site type.
22     *
23     * @var string
24     */
25    private $site_type;
26
27    /**
28     * The prompt.
29     *
30     * @var ContentGenerationPrompt
31     */
32    private $prompt;
33
34    /**
35     * The site classification.
36     *
37     * @var SiteClassification
38     */
39    private $site_classification;
40
41    /**
42     * Constructor.
43     *
44     * @param string $site_type The site type.
45     * @param ContentGenerationPrompt $prompt The prompt.
46     * @param SiteClassification $site_classification The site classification.
47     */
48    public function __construct( string $site_type, ContentGenerationPrompt $prompt, SiteClassification $site_classification ) {
49        $this->site_type           = $site_type;
50        $this->prompt              = $prompt;
51        $this->site_classification = $site_classification;
52    }
53
54    /**
55     * Generates the sitekits.
56     *
57     * @param int $count The number of sitekits to generate.
58     * @return array|\WP_Error The sitekits - array of Sitekit objects or WP_Error on failure.
59     */
60    public function generate_sitekits( int $count = 3 ) {
61        $prompt = $this->prompt->get_prompt();
62        $request_body = array(
63            'siteType'      => $this->site_type,
64            'count'         => $count,
65            'prompt'        => $prompt,
66            'locale'        => LanguageService::get_site_locale(),
67            'primaryType'   => $this->site_classification->get_primary_type(),
68            'secondaryType' => $this->site_classification->get_secondary_type(),
69        );
70
71        // Install sitekits pre-requisites plugins in background.
72        $this->install_pre_requisites_in_background();
73
74        // Generate sitekits.
75        $request = new ContentGenerationServiceRequest( 'sitekits/generate', $request_body );
76        $request->send();
77        // Success.
78        if (
79            $request->is_successful() &&
80            isset( $request->get_response_body()['sitekits'] )
81        ) {
82            $response = array();
83
84            // Process the sitekits.
85            $sitekits = $request->get_response_body()['sitekits'];
86            foreach ( $sitekits as $sitekit ) {
87                $sitekit_object = $this->get_sitekit_object( $sitekit );
88                $response[]     = $sitekit_object;
89            }
90
91            // Publish site content.
92            $posts = $request->get_response_body()['posts'] ?? array();
93            $this->publish_content( $posts );
94
95            return $response;
96        }
97
98        // Error.
99        $response_code = $request->get_response_code();
100        $response_body = $request->get_error_response_body();
101        $error_message = ( $response_body && isset( $response_body['message'] ) ) ? $response_body['message'] : __( 'An unknown error occurred', 'wp-module-onboarding' );
102        $response = new \WP_Error(
103            'sitekits_generation_failed',
104            $error_message,
105            array( 'status' => $response_code )
106        );
107        return $response;
108    }
109
110    /**
111     * Gets the sitekit object.
112     *
113     * @param array $sitekit The sitekit.
114     * @return Sitekit The sitekit object.
115     */
116    private function get_sitekit_object( array $sitekit ): Sitekit {
117        $processed_sitekit = $this->process_sitekit_item( $sitekit );
118
119        $sitekit = new Sitekit(
120            $processed_sitekit['slug'],
121            $processed_sitekit['title'],
122            $processed_sitekit['header'],
123            $processed_sitekit['footer'],
124            $processed_sitekit['pages'],
125            $processed_sitekit['color_palette']
126        );
127
128        return $sitekit;
129    }
130
131    /**
132     * Processes and prepares a sitekit item from the response.
133     *
134     * @param array $sitekit_item The sitekit item.
135     * @return array The processed sitekit item — ready to be converted to a Sitekit object.
136     */
137    private function process_sitekit_item( array $sitekit_item ): array {
138        $result           = array();
139        $result['slug']   = $sitekit_item['slug'];
140        $result['title']  = $sitekit_item['title'];
141        $result['header'] = $this->check_custom_logo( $sitekit_item['header']['patternContent'] );
142        $result['footer'] = $this->check_custom_logo( $sitekit_item['footer']['patternContent'] );
143
144        $pages = array();
145        foreach ( $sitekit_item['pages'] as $page_slug => $page_patterns ) {
146            $page_title    = ucfirst( str_replace( '-', ' ', $page_slug ) );
147            $page_content  = $this->get_page_content_from_patterns( $page_patterns );
148            $is_front_page = $page_slug === 'home';
149            $pages[]       = new Page( $page_title, $page_slug, $page_content, $is_front_page );
150        }
151        $result['pages'] = new Pages( $pages );
152
153        // Attach a color palette to the sitekit.
154        $result['color_palette'] = SiteGenService::get_instance()->get_color_palette();
155
156        return $result;
157    }
158
159    /**
160     * Gets the page content from the response patterns array.
161     *
162     * @param array $page_patterns The page patterns.
163     * @return string The page content.
164     */
165    private function get_page_content_from_patterns( array $page_patterns ): string {
166        $page_content = '';
167        foreach ( $page_patterns as $pattern ) {
168            $page_content .= $pattern['patternContent'];
169        }
170        return $page_content;
171    }
172
173    /**
174     * Installs the pre-requisites in background.
175     *
176     * @return void
177     */
178    private function install_pre_requisites_in_background(): void {
179        if ( $this->site_type === 'ecommerce' ) {
180            EcommerceSiteTypeService::install_ecommerce_plugins();
181        }
182    }
183
184    /**
185     * Publishes the demo content.
186     *
187     * @param array $posts The posts.
188     * @return void
189     */
190    private function publish_content( array $posts = array() ): void {
191        // Publish WooCommerce products.
192        $products = $posts['products'] ?? array();
193        if ( ! empty( $products ) ) {
194            foreach ( $products as $index => $product ) {
195                EcommerceSiteTypeService::publish_woo_product(
196                    $product['name'] ?? 'Product ' . $index + 1,
197                    $product['description'] ?? 'Description for Product ' . $index + 1,
198                    $product['price'] ?? '24.99',
199                    $product['image'] ?? '',
200                    $product['categories'] ?? array()
201                );
202            }
203        }
204        $articles = $posts['articles']['posts'] ?? array();
205
206        if ( ! empty( $articles ) ) {
207            foreach ( $articles as $index => $article ) {
208                CommonSiteTypeService::publish_article(
209                    $article['title'] ?? 'Article ' . $index + 1,
210                    $article['excerpt'] ?? 'Excerpt for Article ' . $index + 1,
211                    $article['content'] ?? 'Content for Article ' . $index + 1,
212                    $article['image'] ?? '',
213                    $article['categories'] ?? array()
214                );
215            }
216        }
217    }
218
219    /**
220     * Checks if the site type supports sitekits`.
221     *
222     * @param string $site_type The site type.
223     * @return bool
224     */
225    public static function site_type_supported( string $site_type ): bool {
226        return in_array( $site_type, self::$site_types_supported );
227    }
228
229    /**
230     * Check if a custom logo exists; otherwise, replace the site logo block with the site title block.
231     *
232     * @var string $content Content to check.
233     * @return string
234     */
235    private function check_custom_logo( string $content ): string {
236        if ( function_exists('has_custom_logo') && ! has_custom_logo() ) {
237            $content = preg_replace(
238                '/<!--\s*wp:site-logo\s*\/-->/',
239                '<!-- wp:site-logo /--><!-- wp:site-title /-->',
240                $content
241            );
242        }
243
244        return $content;
245    }
246}