Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 92
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 / 92
0.00% covered (danger)
0.00%
0 / 9
462
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 / 30
0.00% covered (danger)
0.00%
0 / 1
20
 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        $error_message = $request->get_error_message();
101        $response = new \WP_Error(
102            'sitekits_generation_failed',
103            $error_message,
104            array( 'status' => $response_code )
105        );
106        return $response;
107    }
108
109    /**
110     * Gets the sitekit object.
111     *
112     * @param array $sitekit The sitekit.
113     * @return Sitekit The sitekit object.
114     */
115    private function get_sitekit_object( array $sitekit ): Sitekit {
116        $processed_sitekit = $this->process_sitekit_item( $sitekit );
117
118        $sitekit = new Sitekit(
119            $processed_sitekit['slug'],
120            $processed_sitekit['title'],
121            $processed_sitekit['header'],
122            $processed_sitekit['footer'],
123            $processed_sitekit['pages'],
124            $processed_sitekit['color_palette']
125        );
126
127        return $sitekit;
128    }
129
130    /**
131     * Processes and prepares a sitekit item from the response.
132     *
133     * @param array $sitekit_item The sitekit item.
134     * @return array The processed sitekit item — ready to be converted to a Sitekit object.
135     */
136    private function process_sitekit_item( array $sitekit_item ): array {
137        $result           = array();
138        $result['slug']   = $sitekit_item['slug'];
139        $result['title']  = $sitekit_item['title'];
140        $result['header'] = $this->check_custom_logo( $sitekit_item['header']['patternContent'] );
141        $result['footer'] = $this->check_custom_logo( $sitekit_item['footer']['patternContent'] );
142
143        $pages = array();
144        foreach ( $sitekit_item['pages'] as $page_slug => $page_patterns ) {
145            $page_title    = ucfirst( str_replace( '-', ' ', $page_slug ) );
146            $page_content  = $this->get_page_content_from_patterns( $page_patterns );
147            $is_front_page = $page_slug === 'home';
148            $pages[]       = new Page( $page_title, $page_slug, $page_content, $is_front_page );
149        }
150        $result['pages'] = new Pages( $pages );
151
152        // Attach a color palette to the sitekit.
153        $result['color_palette'] = SiteGenService::get_instance()->get_color_palette();
154
155        return $result;
156    }
157
158    /**
159     * Gets the page content from the response patterns array.
160     *
161     * @param array $page_patterns The page patterns.
162     * @return string The page content.
163     */
164    private function get_page_content_from_patterns( array $page_patterns ): string {
165        $page_content = '';
166        foreach ( $page_patterns as $pattern ) {
167            $page_content .= $pattern['patternContent'];
168        }
169        return $page_content;
170    }
171
172    /**
173     * Installs the pre-requisites in background.
174     *
175     * @return void
176     */
177    private function install_pre_requisites_in_background(): void {
178        if ( $this->site_type === 'ecommerce' ) {
179            EcommerceSiteTypeService::install_ecommerce_plugins();
180        }
181    }
182
183    /**
184     * Publishes the demo content.
185     *
186     * @param array $posts The posts.
187     * @return void
188     */
189    private function publish_content( array $posts = array() ): void {
190        // Publish WooCommerce products.
191        $products = $posts['products'] ?? array();
192        if ( ! empty( $products ) ) {
193            foreach ( $products as $index => $product ) {
194                EcommerceSiteTypeService::publish_woo_product(
195                    $product['name'] ?? 'Product ' . $index + 1,
196                    $product['description'] ?? 'Description for Product ' . $index + 1,
197                    $product['price'] ?? '24.99',
198                    $product['image'] ?? '',
199                    $product['categories'] ?? array()
200                );
201            }
202        }
203        $articles = $posts['articles']['posts'] ?? array();
204
205        if ( ! empty( $articles ) ) {
206            foreach ( $articles as $index => $article ) {
207                CommonSiteTypeService::publish_article(
208                    $article['title'] ?? 'Article ' . $index + 1,
209                    $article['excerpt'] ?? 'Excerpt for Article ' . $index + 1,
210                    $article['content'] ?? 'Content for Article ' . $index + 1,
211                    $article['image'] ?? '',
212                    $article['categories'] ?? array()
213                );
214            }
215        }
216    }
217
218    /**
219     * Checks if the site type supports sitekits`.
220     *
221     * @param string $site_type The site type.
222     * @return bool
223     */
224    public static function site_type_supported( string $site_type ): bool {
225        return in_array( $site_type, self::$site_types_supported );
226    }
227
228    /**
229     * Check if a custom logo exists; otherwise, replace the site logo block with the site title block.
230     *
231     * @var string $content Content to check.
232     * @return string
233     */
234    private function check_custom_logo( string $content ): string {
235        if ( function_exists('has_custom_logo') && ! has_custom_logo() ) {
236            $content = preg_replace(
237                '/<!--\s*wp:site-logo\s*\/-->/',
238                '<!-- wp:site-logo /--><!-- wp:site-title /-->',
239                $content
240            );
241        }
242
243        return $content;
244    }
245}