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