Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 242 |
|
0.00% |
0 / 11 |
CRAP | |
0.00% |
0 / 1 |
DesignController | |
0.00% |
0 / 242 |
|
0.00% |
0 / 11 |
2652 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
register_routes | |
0.00% |
0 / 54 |
|
0.00% |
0 / 1 |
56 | |||
get_color_palettes | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
72 | |||
get_font_pairs | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
12 | |||
get_color_palettes_from_options | |
0.00% |
0 / 43 |
|
0.00% |
0 / 1 |
20 | |||
get_font_pairs_from_options | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
get_color_palettes_from_hiive | |
0.00% |
0 / 28 |
|
0.00% |
0 / 1 |
42 | |||
get_font_pairs_from_hiive | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 | |||
fetch_from_hiive | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
20 | |||
get_color_palettes_from_theme_json | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
110 | |||
paginate_response | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * Design Controller for handling color palettes and font pairings. |
4 | * |
5 | * @package NewfoldLabs\WP\Module\Onboarding\RestApi |
6 | */ |
7 | |
8 | namespace NewfoldLabs\WP\Module\Onboarding\RestApi; |
9 | |
10 | use NewfoldLabs\WP\Module\Onboarding\Permissions; |
11 | use WP_REST_Controller; |
12 | use WP_REST_Server; |
13 | use WP_REST_Response; |
14 | use WP_Error; |
15 | |
16 | /** |
17 | * Class DesignController |
18 | */ |
19 | class DesignController extends WP_REST_Controller { |
20 | |
21 | /** |
22 | * The namespace of this controller's route. |
23 | * |
24 | * @var string |
25 | */ |
26 | protected $namespace = 'newfold-onboarding/v1'; |
27 | |
28 | /** |
29 | * The base of this controller's route. |
30 | * |
31 | * @var string |
32 | */ |
33 | protected $rest_base = 'design'; |
34 | |
35 | /** |
36 | * Hiive API base endpoint |
37 | * |
38 | * @var string |
39 | */ |
40 | protected $hiive_api_base; |
41 | |
42 | /** |
43 | * Constructor. |
44 | */ |
45 | public function __construct() { |
46 | $this->hiive_api_base = defined( 'NFD_DATA_WB_DEV_MODE' ) && NFD_DATA_WB_DEV_MODE |
47 | ? 'http://patterns-platform.test/api/v1' |
48 | : 'https://paterns.hiive.cloud/api/v1'; |
49 | } |
50 | |
51 | /** |
52 | * Register the routes for this controller |
53 | */ |
54 | public function register_routes() { |
55 | // Add route for paginated color palettes |
56 | register_rest_route( |
57 | $this->namespace, |
58 | '/' . $this->rest_base . '/color-palettes', |
59 | array( |
60 | array( |
61 | 'methods' => WP_REST_Server::READABLE, |
62 | 'callback' => array( $this, 'get_color_palettes' ), |
63 | 'permission_callback' => array( Permissions::class, 'rest_is_authorized_admin' ), |
64 | 'args' => array( |
65 | 'page' => array( |
66 | 'default' => 1, |
67 | 'sanitize_callback' => 'absint', |
68 | 'validate_callback' => function ( $param ) { |
69 | return is_numeric( $param ) && $param > 0; |
70 | }, |
71 | ), |
72 | 'per_page' => array( |
73 | 'default' => 10, |
74 | 'sanitize_callback' => 'absint', |
75 | 'validate_callback' => function ( $param ) { |
76 | return is_numeric( $param ) && $param > 0 && $param <= 100; |
77 | }, |
78 | ), |
79 | ), |
80 | ), |
81 | ) |
82 | ); |
83 | |
84 | // Add route for paginated font pairs |
85 | register_rest_route( |
86 | $this->namespace, |
87 | '/' . $this->rest_base . '/font-pairs', |
88 | array( |
89 | array( |
90 | 'methods' => WP_REST_Server::READABLE, |
91 | 'callback' => array( $this, 'get_font_pairs' ), |
92 | 'permission_callback' => array( Permissions::class, 'rest_is_authorized_admin' ), |
93 | 'args' => array( |
94 | 'page' => array( |
95 | 'default' => 1, |
96 | 'sanitize_callback' => 'absint', |
97 | 'validate_callback' => function ( $param ) { |
98 | return is_numeric( $param ) && $param > 0; |
99 | }, |
100 | ), |
101 | 'per_page' => array( |
102 | 'default' => 10, |
103 | 'sanitize_callback' => 'absint', |
104 | 'validate_callback' => function ( $param ) { |
105 | return is_numeric( $param ) && $param > 0 && $param <= 100; |
106 | }, |
107 | ), |
108 | ), |
109 | ), |
110 | ) |
111 | ); |
112 | } |
113 | |
114 | /** |
115 | * Get paginated color palettes |
116 | * |
117 | * @param \WP_REST_Request $request Full data about the request. |
118 | * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
119 | */ |
120 | public function get_color_palettes( $request ) { |
121 | $referer = $request->get_header( 'Referer' ); |
122 | $page = $request->get_param( 'page' ); |
123 | $per_page = $request->get_param( 'per_page' ); |
124 | |
125 | if ( ! $referer ) { |
126 | return new WP_Error( |
127 | 'invalid_referer', |
128 | 'Invalid referer provided.', |
129 | array( 'status' => 400 ) |
130 | ); |
131 | } |
132 | |
133 | // Check if referer contains nfd-onboarding |
134 | if ( strpos( $referer, 'nfd-onboarding' ) !== false ) { |
135 | $result = $this->get_color_palettes_from_options( $page, $per_page ); |
136 | // If no palettes found in options, fallback to theme.json palettes |
137 | if ( is_wp_error( $result ) && $result->get_error_code() === 'no_color_palettes' ) { |
138 | return $this->get_color_palettes_from_theme_json( $page, $per_page ); |
139 | } |
140 | return $result; |
141 | } |
142 | |
143 | // For all other referers (including nfd-plugin), fetch from Hiive |
144 | $result = $this->get_color_palettes_from_hiive( $page, $per_page ); |
145 | // If hiive palettes are empty, fallback to theme.json palettes |
146 | if ( is_wp_error( $result ) || ( isset( $result->data['data'] ) && empty( $result->data['data'] ) ) ) { |
147 | return $this->get_color_palettes_from_theme_json( $page, $per_page ); |
148 | } |
149 | return $result; |
150 | } |
151 | |
152 | /** |
153 | * Get paginated font pairs |
154 | * |
155 | * @param \WP_REST_Request $request Full data about the request. |
156 | * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
157 | */ |
158 | public function get_font_pairs( $request ) { |
159 | $referer = $request->get_header( 'Referer' ); |
160 | $page = $request->get_param( 'page' ); |
161 | $per_page = $request->get_param( 'per_page' ); |
162 | |
163 | if ( ! $referer ) { |
164 | return new WP_Error( |
165 | 'invalid_referer', |
166 | 'Invalid referer provided.', |
167 | array( 'status' => 400 ) |
168 | ); |
169 | } |
170 | |
171 | // Check if referer contains nfd-onboarding |
172 | if ( strpos( $referer, 'nfd-onboarding' ) !== false ) { |
173 | return $this->get_font_pairs_from_options( $page, $per_page ); |
174 | } |
175 | |
176 | // For all other referers (including nfd-plugin), fetch from Hiive |
177 | return $this->get_font_pairs_from_hiive( $page, $per_page ); |
178 | } |
179 | |
180 | /** |
181 | * Get color palettes from WordPress options table with pagination |
182 | * |
183 | * @param int $page The current page number |
184 | * @param int $per_page Number of items per page |
185 | * @return WP_REST_Response|WP_Error |
186 | */ |
187 | protected function get_color_palettes_from_options( $page, $per_page ) { |
188 | $color_palettes = get_option( 'nfd_module_onboarding_editor_colorpalette' ); |
189 | |
190 | if ( false === $color_palettes ) { |
191 | return new WP_Error( |
192 | 'no_color_palettes', |
193 | 'No color palettes found in options.', |
194 | array( 'status' => 404 ) |
195 | ); |
196 | } |
197 | |
198 | $formatted_palettes = array(); |
199 | foreach ( $color_palettes as $index => $palette ) { |
200 | $formatted_palette = array(); |
201 | |
202 | foreach ( $palette as $key => $value ) { |
203 | $formatted_palette[] = array( |
204 | 'name' => $key, |
205 | 'slug' => $key, |
206 | 'color' => $value, |
207 | ); |
208 | } |
209 | |
210 | $formatted_palettes[] = array( |
211 | // translators: %d is the index of the palette |
212 | 'name' => sprintf( __( 'Palette %d', 'wp-module-onboarding' ), $index + 1 ), |
213 | 'displayColors' => array( |
214 | array( |
215 | 'color' => $palette['base'], |
216 | 'name' => 'Base', |
217 | 'slug' => 'base', |
218 | ), |
219 | array( |
220 | 'color' => $palette['contrast'], |
221 | 'name' => 'Contrast', |
222 | 'slug' => 'contrast', |
223 | ), |
224 | array( |
225 | 'color' => $palette['accent_2'], |
226 | 'name' => 'Primary', |
227 | 'slug' => 'accent-2', |
228 | ), |
229 | array( |
230 | 'color' => $palette['accent_5'], |
231 | 'name' => 'Secondary', |
232 | 'slug' => 'accent-5', |
233 | ), |
234 | ), |
235 | 'palette' => $formatted_palette, |
236 | ); |
237 | } |
238 | |
239 | return $this->paginate_response( $formatted_palettes, $page, $per_page ); |
240 | } |
241 | |
242 | /** |
243 | * Get font pairs from WordPress options table with pagination |
244 | * |
245 | * @param int $page The current page number |
246 | * @param int $per_page Number of items per page |
247 | * @return WP_REST_Response|WP_Error |
248 | */ |
249 | protected function get_font_pairs_from_options( $page, $per_page ) { |
250 | $font_pairs = get_option( 'nfd_module_onboarding_editor_fontpair' ); |
251 | |
252 | if ( false === $font_pairs ) { |
253 | return new WP_Error( |
254 | 'no_font_pairs', |
255 | 'No font pairs found in options.', |
256 | array( 'status' => 404 ) |
257 | ); |
258 | } |
259 | |
260 | return $this->paginate_response( $font_pairs, $page, $per_page ); |
261 | } |
262 | |
263 | /** |
264 | * Get color palettes from Hiive API with pagination |
265 | * |
266 | * @param int $page The current page number |
267 | * @param int $per_page Number of items per page |
268 | * @return WP_REST_Response|WP_Error |
269 | */ |
270 | protected function get_color_palettes_from_hiive( $page, $per_page ) { |
271 | // Try to get cached data first |
272 | $cached_data = get_transient( 'nfd_hiive_color_palettes' ); |
273 | if ( false !== $cached_data ) { |
274 | return $this->paginate_response( $cached_data, $page, $per_page ); |
275 | } |
276 | |
277 | $color_palettes = $this->fetch_from_hiive( '/colors' ); |
278 | if ( is_wp_error( $color_palettes ) ) { |
279 | return $color_palettes; |
280 | } |
281 | |
282 | // Filter out invalid palettes and add displayColors |
283 | $formatted_palettes = array_filter( |
284 | array_map( |
285 | function ( $palette ) { |
286 | // Skip if required properties are missing |
287 | if ( ! isset( $palette['name'] ) || ! isset( $palette['palette'] ) || count( $palette['palette'] ) < 4 ) { |
288 | return null; |
289 | } |
290 | |
291 | // Create standardized displayColors with specific slugs |
292 | $palette['displayColors'] = array( |
293 | $palette['palette'][0], |
294 | $palette['palette'][1], |
295 | $palette['palette'][2], |
296 | $palette['palette'][3], |
297 | ); |
298 | return $palette; |
299 | }, |
300 | $color_palettes['data'] |
301 | ), |
302 | function ( $palette ) { |
303 | return null !== $palette; |
304 | } |
305 | ); |
306 | |
307 | // Re-index array to ensure sequential keys |
308 | $formatted_palettes = array_values( $formatted_palettes ); |
309 | |
310 | // Cache the formatted palettes for 24 hours |
311 | set_transient( 'nfd_hiive_color_palettes', $formatted_palettes, DAY_IN_SECONDS ); |
312 | |
313 | return $this->paginate_response( $formatted_palettes, $page, $per_page ); |
314 | } |
315 | |
316 | /** |
317 | * Get font pairs from Hiive API with pagination |
318 | * |
319 | * @param int $page The current page number |
320 | * @param int $per_page Number of items per page |
321 | * @return WP_REST_Response|WP_Error |
322 | */ |
323 | protected function get_font_pairs_from_hiive( $page, $per_page ) { |
324 | // Try to get cached data first |
325 | $cached_data = get_transient( 'nfd_hiive_font_pairs' ); |
326 | if ( false !== $cached_data ) { |
327 | return $this->paginate_response( $cached_data, $page, $per_page ); |
328 | } |
329 | |
330 | $font_pairs = $this->fetch_from_hiive( '/fonts' ); |
331 | if ( is_wp_error( $font_pairs ) ) { |
332 | return $font_pairs; |
333 | } |
334 | |
335 | // Cache the font pairs for 24 hours |
336 | set_transient( 'nfd_hiive_font_pairs', $font_pairs['data'], DAY_IN_SECONDS ); |
337 | |
338 | return $this->paginate_response( $font_pairs['data'], $page, $per_page ); |
339 | } |
340 | |
341 | /** |
342 | * Helper function to fetch data from Hiive API |
343 | * |
344 | * @param string $endpoint The endpoint to fetch from |
345 | * @return array|WP_Error The decoded response data or WP_Error on failure |
346 | */ |
347 | protected function fetch_from_hiive( $endpoint ) { |
348 | // Try to get cached endpoint data first |
349 | $cache_key = 'nfd_hiive_' . sanitize_key( $endpoint ); |
350 | $cached_data = get_transient( $cache_key ); |
351 | if ( false !== $cached_data ) { |
352 | return $cached_data; |
353 | } |
354 | |
355 | $response = wp_remote_get( |
356 | $this->hiive_api_base . $endpoint, |
357 | array( |
358 | 'timeout' => 15, |
359 | 'headers' => array( |
360 | 'Accept' => 'application/json', |
361 | ), |
362 | ) |
363 | ); |
364 | |
365 | if ( is_wp_error( $response ) ) { |
366 | return new WP_Error( |
367 | 'hiive_api_error', |
368 | 'Error fetching data from Hiive: ' . $response->get_error_message(), |
369 | array( 'status' => 502 ) |
370 | ); |
371 | } |
372 | |
373 | $body = wp_remote_retrieve_body( $response ); |
374 | $data = json_decode( $body, true ); |
375 | |
376 | if ( json_last_error() !== JSON_ERROR_NONE ) { |
377 | return new WP_Error( |
378 | 'json_parse_error', |
379 | 'Error parsing Hiive API response', |
380 | array( 'status' => 502 ) |
381 | ); |
382 | } |
383 | |
384 | // Cache the endpoint data for 24 hours |
385 | set_transient( $cache_key, $data, DAY_IN_SECONDS ); |
386 | |
387 | return $data; |
388 | } |
389 | |
390 | /** |
391 | * Get color palettes from theme.json |
392 | * |
393 | * @param int $page The current page number |
394 | * @param int $per_page Number of items per page |
395 | * @return WP_REST_Response|WP_Error |
396 | */ |
397 | protected function get_color_palettes_from_theme_json( $page, $per_page ) { |
398 | $theme_palettes = array(); |
399 | |
400 | // Method 1: Using WP_Theme_JSON_Resolver to get style variations (includes styles/colors folder) |
401 | if ( class_exists( 'WP_Theme_JSON_Resolver' ) ) { |
402 | // Get all style variations from styles/ folder (includes colors/ subfolder) |
403 | $style_variations = \WP_Theme_JSON_Resolver::get_style_variations(); |
404 | |
405 | // Process each style variation (from styles/colors folder) |
406 | foreach ( $style_variations as $variation ) { |
407 | $variation_data = $variation['settings'] ?? array(); |
408 | |
409 | // Check if this variation has color palette |
410 | if ( isset( $variation_data['color']['palette'] ) && is_array( $variation_data['color']['palette'] ) ) { |
411 | $all_palette_sources = $variation['settings']['color']['palette']; |
412 | |
413 | foreach ( $all_palette_sources as $source_name => $colors ) { |
414 | if ( is_array( $colors ) && ! empty( $colors ) ) { |
415 | $formatted_colors = array(); |
416 | $display_colors = array(); |
417 | |
418 | foreach ( $colors as $index => $color ) { |
419 | $formatted_colors[] = $color; |
420 | |
421 | if ( in_array( $color['slug'], array( 'base', 'contrast', 'accent-2', 'accent-5' ), true ) ) { |
422 | $display_colors[] = $color; |
423 | } |
424 | } |
425 | |
426 | $theme_palettes[] = array( |
427 | 'name' => $variation['title'], |
428 | 'displayColors' => $display_colors, |
429 | 'palette' => $formatted_colors, |
430 | ); |
431 | } |
432 | } |
433 | } |
434 | } |
435 | } |
436 | |
437 | return $this->paginate_response( $theme_palettes, $page, $per_page ); |
438 | } |
439 | |
440 | /** |
441 | * Helper function to paginate response data |
442 | * |
443 | * @param array $items The array of items to paginate |
444 | * @param int $page The current page number |
445 | * @param int $per_page Number of items per page |
446 | * @return WP_REST_Response |
447 | */ |
448 | protected function paginate_response( $items, $page, $per_page ) { |
449 | $total_items = count( $items ); |
450 | $total_pages = ceil( $total_items / $per_page ); |
451 | $offset = ( $page - 1 ) * $per_page; |
452 | |
453 | $paginated_items = array_slice( $items, $offset, $per_page ); |
454 | |
455 | $response = new WP_REST_Response( |
456 | array( |
457 | 'data' => $paginated_items, |
458 | 'pagination' => array( |
459 | 'total_items' => $total_items, |
460 | 'total_pages' => $total_pages, |
461 | 'current_page' => $page, |
462 | 'per_page' => $per_page, |
463 | ), |
464 | ) |
465 | ); |
466 | |
467 | // Add pagination headers |
468 | $response->header( 'X-WP-Total', $total_items ); |
469 | $response->header( 'X-WP-TotalPages', $total_pages ); |
470 | |
471 | return $response; |
472 | } |
473 | } |