Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 91 |
|
0.00% |
0 / 10 |
CRAP | |
0.00% |
0 / 1 |
SiteGenService | |
0.00% |
0 / 91 |
|
0.00% |
0 / 10 |
1056 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
get_instance | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
get_sitekits | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
20 | |||
publish_homepage | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
56 | |||
get_sitemap_page_title | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
56 | |||
get_site_classification | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
6 | |||
get_color_palette | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
12 | |||
get_prompt | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
get_site_type | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
get_locale | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | |
3 | namespace NewfoldLabs\WP\Module\Onboarding\Services; |
4 | |
5 | use NewfoldLabs\WP\Module\Onboarding\Data\Services\SitePagesService; |
6 | use NewfoldLabs\WP\Module\Onboarding\Data\Services\SiteGenService as LegacySiteGenService; |
7 | use NewfoldLabs\WP\Module\Onboarding\Services\Ai\ContentGeneration\ContentGenerationPrompt; |
8 | use NewfoldLabs\WP\Module\Onboarding\Services\Ai\ContentGeneration\SitekitsContentGeneration; |
9 | use NewfoldLabs\WP\Module\Onboarding\Types\Color; |
10 | use NewfoldLabs\WP\Module\Onboarding\Types\ColorPalette; |
11 | use NewfoldLabs\WP\Module\Onboarding\Types\SiteClassification; |
12 | use NewfoldLabs\WP\Module\Onboarding\Services\SiteGenImageService; |
13 | use NewfoldLabs\WP\Module\Onboarding\Services\ReduxStateService; |
14 | |
15 | /** |
16 | * Class SiteGenService |
17 | * |
18 | * Handles the onboarding SiteGen flow for generating, publishing, and managing AI-generated homepages and related content. |
19 | * |
20 | * This service is designed to work with the onboarding module's Redux state and integrates with other onboarding services. |
21 | * |
22 | * @package NewfoldLabs\WP\Module\Onboarding\Services |
23 | */ |
24 | class SiteGenService { |
25 | |
26 | /** |
27 | * The singleton instance. |
28 | * |
29 | * @var SiteGenService|null |
30 | */ |
31 | private static $instance = null; |
32 | |
33 | /** |
34 | * The Redux input object. |
35 | * |
36 | * @var array|null |
37 | */ |
38 | private $input_data = null; |
39 | |
40 | /** |
41 | * The Redux sitegen object. |
42 | * |
43 | * @var array|null |
44 | */ |
45 | private $sitegen_data = null; |
46 | |
47 | /** |
48 | * SiteGenService constructor. |
49 | * |
50 | * Initializes the service by loading the Redux input and sitegen data from the ReduxStateService. |
51 | */ |
52 | public function __construct() { |
53 | $this->input_data = ReduxStateService::get( 'input' ); |
54 | $this->sitegen_data = ReduxStateService::get( 'sitegen' ); |
55 | } |
56 | |
57 | /** |
58 | * Get the singleton instance. |
59 | * |
60 | * @return SiteGenService |
61 | */ |
62 | public static function get_instance(): SiteGenService { |
63 | if ( null === self::$instance ) { |
64 | self::$instance = new self(); |
65 | } |
66 | return self::$instance; |
67 | } |
68 | |
69 | /** |
70 | * Generate the sitekits. |
71 | * |
72 | * @param string $site_description The site description. |
73 | * @param string $site_type The site type. |
74 | * @param string $locale The locale. |
75 | * @param bool $for_onboarding_preview Whether to return the sitekits as array for onboarding preview. |
76 | * @return array|\WP_Error Array of Sitekit objects, array of sitekits for onboarding preview, or WP_Error if there is an error. |
77 | */ |
78 | public function get_sitekits( string $site_description, string $site_type, string $locale = 'en_US', bool $for_onboarding_preview = false ) { |
79 | $prompt = new ContentGenerationPrompt( $site_description, $site_type, $locale ); |
80 | $site_classification = $this->get_site_classification(); |
81 | |
82 | $sitekits = new SitekitsContentGeneration( $site_type, $locale, $prompt, $site_classification ); |
83 | $sitekits = $sitekits->generate_sitekits(); |
84 | |
85 | // If there is an error, return it. |
86 | if ( is_wp_error( $sitekits ) ) { |
87 | return $sitekits; |
88 | } |
89 | |
90 | // If we are generating sitekits for onboarding preview, return the sitekits as array. |
91 | if ( $for_onboarding_preview ) { |
92 | $previews = array(); |
93 | foreach ( $sitekits as $sitekit ) { |
94 | $previews[ $sitekit->get_slug() ] = $sitekit->onboarding_preview_data(); |
95 | } |
96 | $sitekits = $previews; |
97 | } |
98 | |
99 | return $sitekits; |
100 | } |
101 | |
102 | /** |
103 | * Publish the selected sitegen homepage. |
104 | * |
105 | * @param string $selected_sitegen_homepage The selected sitegen homepage to publish. |
106 | * @return int|\WP_Error |
107 | */ |
108 | public function publish_homepage( string $selected_sitegen_homepage ) { |
109 | // Validate we have the selected homepage. |
110 | if ( |
111 | ! $this->sitegen_data || |
112 | ! is_array( $this->sitegen_data['homepages'] ) || |
113 | ! isset( $this->sitegen_data['homepages'][ $selected_sitegen_homepage ] ) |
114 | ) { |
115 | return new \WP_Error( |
116 | 'sitegen_homepage_publish_validation_error', |
117 | 'Error validating selected homepage.', |
118 | ); |
119 | } |
120 | |
121 | $selected_homepage = $this->sitegen_data['homepages'][ $selected_sitegen_homepage ]; |
122 | $content = $selected_homepage['content']; |
123 | $title = __( 'Home', 'wp-module-onboarding' ); |
124 | |
125 | $post_id = SitePagesService::publish_page( |
126 | $title, |
127 | $content, |
128 | true, |
129 | array( |
130 | 'nf_dc_page' => 'home', |
131 | ) |
132 | ); |
133 | if ( 0 === $post_id || is_wp_error( $post_id ) ) { |
134 | return new \WP_Error( |
135 | 'sitegen_homepage_publish_error', |
136 | 'Error publishing homepage.', |
137 | ); |
138 | } |
139 | |
140 | // Process images immediately in background (non-blocking) |
141 | SiteGenImageService::process_homepage_images_immediate_async( $post_id, $content ); |
142 | |
143 | // Change WordPress reading options to show static page as homepage. |
144 | $wp_reading_homepage_option = get_option( 'show_on_front' ); |
145 | if ( 'page' !== $wp_reading_homepage_option ) { |
146 | update_option( 'show_on_front', 'page' ); |
147 | } |
148 | // Set the homepage as the front page. |
149 | update_option( 'page_on_front', $post_id ); |
150 | |
151 | return $post_id; |
152 | } |
153 | |
154 | /** |
155 | * Get AI generated page title for a given slug (if found in sitemap). |
156 | * |
157 | * @param string $slug The slug of the page to get the title for. |
158 | * @return string|false The page title, or false if not found. |
159 | */ |
160 | public function get_sitemap_page_title( string $slug ) { |
161 | $prompt = $this->get_prompt(); |
162 | $locale = $this->get_locale(); |
163 | $site_type = $this->get_site_type(); |
164 | if ( ! $prompt || ! $locale || ! $site_type ) { |
165 | return false; |
166 | } |
167 | |
168 | $sitemap = LegacySiteGenService::instantiate_site_meta( $prompt, 'sitemap', $site_type, $locale ); |
169 | if ( ! is_wp_error( $sitemap ) ) { |
170 | foreach ( $sitemap as $page ) { |
171 | if ( $slug === $page['slug'] ) { |
172 | $title = $page['title']; |
173 | return $title; |
174 | } |
175 | } |
176 | } |
177 | |
178 | return false; |
179 | } |
180 | |
181 | /** |
182 | * Get the site classification. |
183 | * |
184 | * @return SiteClassification |
185 | */ |
186 | public function get_site_classification(): SiteClassification { |
187 | $primary_type = 'other'; |
188 | $secondary_type = 'other'; |
189 | $site_classification = LegacySiteGenService::instantiate_site_meta( |
190 | $this->get_prompt(), |
191 | 'site_classification', |
192 | $this->get_site_type(), |
193 | $this->get_locale() |
194 | ); |
195 | |
196 | if ( is_array( $site_classification ) ) { |
197 | $primary_type = $site_classification['primaryType'] ?? $primary_type; |
198 | $secondary_type = $site_classification['slug'] ?? $secondary_type; |
199 | } |
200 | |
201 | return new SiteClassification( $primary_type, $secondary_type ); |
202 | } |
203 | |
204 | /** |
205 | * Get a palette from the color palettes generated during the sitemeta calls. |
206 | * |
207 | * @return ColorPalette|null The color palette, or null on error. |
208 | */ |
209 | public function get_color_palette() { |
210 | $color_palettes = LegacySiteGenService::instantiate_site_meta( |
211 | $this->get_prompt(), |
212 | 'color_palette', |
213 | $this->get_site_type(), |
214 | $this->get_locale() |
215 | ); |
216 | |
217 | if ( ! is_array( $color_palettes ) ) { |
218 | return null; |
219 | } |
220 | |
221 | // Select a random color palette from the sitemeta. |
222 | $selected_color_palette_index = array_rand( $color_palettes ); |
223 | $selected_color_palette = $color_palettes[ $selected_color_palette_index ]; |
224 | |
225 | $palette_slug = 'palette_' . ( $selected_color_palette_index + 1 ); |
226 | $palette_colors = array(); |
227 | |
228 | // Create a Color object for each color in the selected color palette. |
229 | foreach ( $selected_color_palette as $key => $value ) { |
230 | $slug = $key; |
231 | $name = ucfirst( str_replace( '_', ' ', $slug ) ); |
232 | $color = $value; |
233 | |
234 | $palette_colors[] = new Color( $name, $slug, $color ); |
235 | } |
236 | |
237 | return new ColorPalette( $palette_slug, $palette_colors ); |
238 | } |
239 | |
240 | /** |
241 | * Get the prompt entered during Onboarding. |
242 | * |
243 | * @return string|false |
244 | */ |
245 | public function get_prompt() { |
246 | return ! empty( $this->input_data['prompt'] ) ? $this->input_data['prompt'] : false; |
247 | } |
248 | |
249 | /** |
250 | * Get the site type entered during Onboarding. |
251 | * |
252 | * @return string |
253 | */ |
254 | public function get_site_type() { |
255 | return ! empty( $this->input_data['siteType'] ) ? $this->input_data['siteType'] : 'business'; |
256 | } |
257 | |
258 | /** |
259 | * Get the locale entered during Onboarding. |
260 | * |
261 | * @return string |
262 | */ |
263 | public function get_locale() { |
264 | return ! empty( $this->input_data['locale'] ) ? $this->input_data['locale'] : 'en_US'; |
265 | } |
266 | } |