PluginProbe
WDesignKit – AI Templates, Widget Builder & MCP Workflow / 2.6.4
WDesignKit – AI Templates, Widget Builder & MCP Workflow v2.6.4
2.6.6 2.6.5 2.6.4 2.6.3 2.6.2 2.6.1 2.6.0 2.5.5 2.5.4 2.5.3 2.5.2 2.5.1 2.5.0 2.4.0 2.3.3 2.3.2 2.3.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 All 128 releases
wdesignkit / includes / admin / class-api.php

class-api.php in WDesignKit – AI Templates, Widget Builder & MCP Workflow 2.6.4, at includes/admin/class-api.php

6,312 lines 202.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The file that defines the core plugin class
4 *
5 * @link https://posimyth.com/
6 * @since 1.0.0
7 *
8 * @package Wdesignkit
9 * @subpackage Wdesignkit/includes
10 */
11
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit;
14 }
15
16 use wdkit\Wdkit_Wdesignkit;
17 use wdkit\WdKit_enqueue\Wdkit_Enqueue;
18 use wdkit\wdkit_datahooks\Wdkit_Data_Hooks;
19
20 if ( ! class_exists( 'Wdkit_Api_Call' ) ) {
21
22 /**
23 * Main classs call for all api
24 *
25 * @link https://posimyth.com/
26 * @since 1.0.0
27 */
28 class Wdkit_Api_Call {
29
30 /**
31 * Member Variable
32 *
33 * @var instance
34 */
35 private static $instance;
36
37 /**
38 * Member Variable
39 *
40 * @var staring widgets_with_post_category
41 */
42 public $widgets_with_post_category = array(
43 'post_category', 'include_products',
44 );
45
46 /**
47 * Member Variable
48 *
49 * @var staring $wdkit_api
50 */
51 public $wdkit_api = WDKIT_SERVER_API_URL . 'api/wp/';
52
53 /**
54 * Member Variable
55 *
56 * @var staring $wdkit_api_v2
57 */
58 public $wdkit_api_v2 = WDKIT_SERVER_API_URL . 'api/v2/wp/';
59
60 /**
61 * Member Variable
62 *
63 * @var staring $widget_folder_u_r_l
64 */
65 public $widget_folder_u_r_l = '';
66
67 /**
68 * Member Variable
69 *
70 * @var staring $e_msg_login
71 */
72 public $e_msg_login = 'Login Error: Check your details and try again.';
73
74 /**
75 * Member Variable
76 *
77 * @var staring $e_desc_login
78 */
79 public $e_desc_login = 'Invalid Login Details';
80
81 /**
82 * Member Variable
83 *
84 * @var staring wdkit_onbording_api
85 */
86 public $wdkit_onbording_api = 'https://api.posimyth.com/wp-json/wdkit/v2/wdkit_store_user_data';
87
88 /**
89 * Member Variable
90 *
91 * @var staring wdkit_onbording_end
92 */
93 public $wdkit_onbording_end = 'wkit_onbording_end';
94
95 /**
96 * Initiator
97 */
98 public static function get_instance() {
99 if ( ! isset( self::$instance ) ) {
100 self::$instance = new self();
101 }
102
103 return self::$instance;
104 }
105
106 /**
107 * Define the core functionality of the plugin.
108 */
109 public function __construct() {
110 add_action( 'wp_ajax_get_wdesignkit', array( $this, 'wdkit_api_call' ) );
111 }
112
113 /**
114 * Error JSON message
115 *
116 * @param array $data give array.
117 * @param string $status api code number.
118 *
119 * @since 1.0.0
120 * */
121 public function wdkit_error_msg( $data = null, $status = null ) {
122 wp_send_json_error( $data );
123 wp_die();
124 }
125
126 /**
127 * Success JSON message
128 *
129 * @param array $data give array.
130 * @param string $status api code number.
131 *
132 * @since 1.0.0
133 * */
134 public function wdkit_success_msg( $data = null, $status = null ) {
135 wp_send_json_success( $data, $status );
136 wp_die();
137 }
138
139
140 /**
141 * Memory headroom left for image work, in bytes. 0 means unlimited.
142 */
143 private static function wdkit_available_image_memory() {
144 $limit = wp_convert_hr_to_bytes( ini_get( 'memory_limit' ) );
145
146 if ( $limit <= 0 ) {
147 return 0;
148 }
149
150 return max( 0, $limit - memory_get_usage( true ) );
151 }
152
153 /**
154 * Stop WordPress decoding images that cannot fit in the memory available.
155 *
156 * Both filters are consulted by wp_create_image_subsizes() *before* it loads an image
157 * editor, so refusing here means the oversized image is never decoded:
158 *
159 * big_image_size_threshold -> falsy skips the "-scaled" copy (needs a full decode)
160 * intermediate_image_sizes_advanced -> empty makes _wp_make_subsizes() return early,
161 * ahead of its wp_get_image_editor() call
162 *
163 * The original file is still attached and usable; only the derived sizes are skipped.
164 * That trades ideal thumbnails for an import that completes, instead of a fatal that
165 * takes the whole page down and repeats on every retry.
166 *
167 * @since 2.6.2
168 */
169 private static function wdkit_guard_oversized_images() {
170 static $registered = false;
171
172 // Registering twice would stack duplicate closures on both filters.
173 if ( $registered ) {
174 return;
175 }
176
177 $registered = true;
178
179 if ( ! class_exists( 'Wdkit_Image_Guard' ) ) {
180 require_once WDKIT_INCLUDES . 'admin/class-wdkit-image-guard.php';
181 }
182
183 add_filter(
184 'big_image_size_threshold',
185 function ( $threshold, $imagesize = array(), $file = '', $attachment_id = 0 ) {
186 if ( ! empty( $imagesize[0] ) && ! empty( $imagesize[1] )
187 && ! Wdkit_Image_Guard::decode_fits( $imagesize[0], $imagesize[1], self::wdkit_available_image_memory() )
188 ) {
189 return false;
190 }
191
192 return $threshold;
193 },
194 99,
195 4
196 );
197
198 add_filter(
199 'intermediate_image_sizes_advanced',
200 function ( $sizes, $image_meta = array(), $attachment_id = 0 ) {
201 if ( ! empty( $image_meta['width'] ) && ! empty( $image_meta['height'] )
202 && ! Wdkit_Image_Guard::decode_fits( $image_meta['width'], $image_meta['height'], self::wdkit_available_image_memory() )
203 ) {
204 return array();
205 }
206
207 return $sizes;
208 },
209 99,
210 3
211 );
212 }
213
214 /**
215 * Get Wdkit Api Call Ajax.
216 */
217 public function wdkit_api_call() {
218
219 check_ajax_referer( 'wdkit_nonce', 'kit_nonce' );
220
221 if ( ! is_user_logged_in() || ! current_user_can( 'manage_options' ) ) {
222 wp_send_json_error( array( 'content' => __( 'Insufficient permissions.', 'wdesignkit' ) ) );
223 }
224
225 $type = isset( $_POST['type'] ) ? strtolower( sanitize_text_field( wp_unslash( $_POST['type'] ) ) ) : false;
226 if ( ! $type ) {
227 $this->wdkit_error_msg( __( 'Something went wrong.', 'wdesignkit' ) );
228 }
229
230 switch ( $type ) {
231 case 'onboarding_handler':
232 $data = $this->wdkit_onboarding_handler();
233 break;
234 case 'wkit_login':
235 $data = apply_filters( 'wp_wdkit_login_ajax', 'wkit_login' );
236 break;
237 case 'api_login':
238 $data = apply_filters( 'wp_wdkit_login_ajax', 'api_login' );
239 break;
240 case 'social_login':
241 $data = apply_filters( 'wp_wdkit_login_ajax', 'social_login' );
242 break;
243 case 'forgot_password':
244 $data = apply_filters( 'wp_wdkit_login_ajax', 'forgot_password' );
245 break;
246 case 'wdkit_user_signup':
247 $data = apply_filters( 'wp_wdkit_login_ajax', 'wdkit_user_signup' );
248 break;
249 case 'wkit_meta_data':
250 $data = $this->wdkit_meta_data();
251 break;
252 case 'get_user_info':
253 $data = $this->wdkit_get_user_info();
254 break;
255 case 'browse_page':
256 $data = $this->wdkit_browse_page();
257 break;
258 case 'kit_template':
259 $data = $this->wdkit_template();
260 break;
261 case 'wkit_preset_template':
262 $data = apply_filters( 'wp_wdkit_preset_ajax', 'wdkit_preset_template' );
263 break;
264 case 'wdkit_preset_dwnld_template':
265 $data = apply_filters( 'wp_wdkit_preset_ajax', 'wdkit_preset_dwnld_template' );
266 break;
267 case 'template_remove':
268 $data = $this->wdkit_template_remove();
269 break;
270 case 'save_template':
271 $data = $this->wdkit_put_save_template();
272 break;
273 case 'update_save_temp_image':
274 $data = $this->wdkit_update_save_temp_image();
275 break;
276 case 'save_wp_images':
277 $data = $this->wdkit_save_wp_images();
278 break;
279 case 'get_global_val':
280 $data = $this->wdkit_get_global_val();
281 break;
282 case 'update_global_val':
283 $data = $this->wdkit_update_global_val();
284 break;
285 case 'wdkit_get_site_setting':
286 $data = $this->wdkit_get_site_setting();
287 break;
288 case 'wdkit_update_site_setting':
289 $data = $this->wdkit_update_site_setting();
290 break;
291 case 'update_preset_setting':
292 $data = $this->wdkit_update_preset();
293 break;
294 case 'find_template':
295 $data = $this->wdkit_find_existing_template();
296 break;
297 case 'update_template':
298 $data = $this->wdkit_update_template();
299 break;
300 case 'manage_favorite':
301 $data = $this->wdkit_manage_favorite();
302 break;
303 case 'check_plugins_depends':
304 $data = $this->wdkit_check_plugins_depends();
305 break;
306 case 'install_plugins_depends':
307 $data = $this->wdkit_install_plugins_depends();
308 break;
309 case 'generate_site_logo':
310 $data = $this->wkit_generate_site_logo();
311 break;
312 case 'generate_ai_content':
313 $data = apply_filters( 'wp_wdkit_import_temp_ajax', 'generate_ai_content' );
314 break;
315 case 'generate_ai_content_batch':
316 $data = apply_filters( 'wp_wdkit_import_temp_ajax', 'generate_ai_content_batch' );
317 break;
318 case 'reset_site':
319 $data = apply_filters( 'wp_wdkit_import_temp_ajax', 'reset_site' );
320 break;
321 case 'wdkit_nxt_thembuilder_reset':
322 $data = $this->wdkit_nxt_thembuilder_reset();
323 break;
324 case 'wdkit_check_user_credit':
325 $data = $this->wdkit_check_user_credit();
326 break;
327 case 'wdkit_remove_header_footer':
328 $data = apply_filters( 'wp_wdkit_import_temp_ajax', 'wdkit_remove_header_footer' );
329 break;
330 case 'check_post_count':
331 $data = apply_filters( 'wp_wdkit_import_temp_ajax', 'check_post_count' );
332 break;
333 case 'wkit_check_product_count':
334 $data = apply_filters( 'wp_wdkit_import_temp_ajax', 'wkit_check_product_count' );
335 break;
336 case 'select_team_img':
337 $data = apply_filters( 'wp_wdkit_import_temp_ajax', 'select_team_img' );
338 break;
339 case 'wkit_ai_desc_keyword':
340 $data = apply_filters( 'wp_wdkit_import_temp_ajax', 'wkit_ai_desc_keyword' );
341 break;
342 case 'wkit_ai_credit_update':
343 $data = apply_filters( 'wp_wdkit_import_temp_ajax', 'wkit_ai_credit_update' );
344 break;
345 case 'wkit_generate_post_data':
346 $data = apply_filters( 'wp_wdkit_import_temp_ajax', 'wkit_generate_post_data' );
347 break;
348 case 'wkit_generate_product_data':
349 $data = apply_filters( 'wp_wdkit_import_temp_ajax', 'wkit_generate_product_data' );
350 break;
351 case 'wkit_cteate_product':
352 $data = apply_filters( 'wp_wdkit_import_temp_ajax', 'wkit_cteate_product' );
353 break;
354 case 'wkit_remove_dummy_post':
355 $data = apply_filters( 'wp_wdkit_import_temp_ajax', 'wkit_remove_dummy_post' );
356 break;
357 case 'update_latest_plugin':
358 $data = $this->wdkit_update_latest_plugin();
359 break;
360 case 'activate_container':
361 $data = $this->wdkit_activate_container();
362 break;
363 case 'import_taxonomy':
364 $data = $this->wdkit_import_taxonomy();
365 break;
366 case 'import_template':
367 $data = $this->wdkit_import_template();
368 break;
369 case 'import_multi_template':
370 $data = $this->wdkit_import_multi_template();
371 break;
372 case 'import_page_section':
373 $data = $this->import_page_section_content();
374 break;
375 case 'wkit_update_elementor_template':
376 $data = $this->wkit_update_elementor_template();
377 break;
378 case 'wdkit_update_page_content':
379 $data = $this->wdkit_update_page_content();
380 break;
381 case 'update_plugin_setting':
382 $data = $this->update_plugin_setting();
383 break;
384 case 'update_theme_setting':
385 $data = $this->update_theme_setting();
386 break;
387 case 'update_site_setting':
388 $data = $this->update_site_setting();
389 break;
390 case 'import_kit_template':
391 $data = $this->wdkit_import_kit_template();
392 break;
393 case 'enable_template_widgets':
394 $data = $this->wdkit_enable_template_widgets();
395 break;
396 case 'scan_nexter_widgets':
397 if ( ! empty( $_POST['blockNames'] ) && has_filter( 'nexter_block_list_merge' ) ) {
398
399 $posted_blocks = json_decode( stripslashes( $_POST['blockNames'] ), true );
400
401 if ( is_array( $posted_blocks ) ) {
402 $blockList = array_map( 'sanitize_text_field', $posted_blocks );
403
404 // �
405 filter call करो
406 $result = apply_filters( 'nexter_block_list_merge', $blockList );
407
408 wp_send_json( $result );
409 wp_die();
410 }
411 }
412
413 wp_send_json(
414 array(
415 'success' => false,
416 'message' => __( 'No block names received or filter not found.', 'wdesignkit' ),
417 'description' => 'Ensure blockNames are posted and the filter is attached.',
418 )
419 );
420 wp_die();
421 $data = '';
422 break;
423 case 'shared_with_me':
424 $data = $this->wdkit_shared_with_me();
425 break;
426 case 'manage_workspace':
427 $data = $this->wdkit_manage_workspace();
428 break;
429 case 'widget_browse_page':
430 $data = apply_filters( 'wp_wdkit_widget_ajax', 'widget_browse_page' );
431 break;
432 case 'wkit_create_widget':
433 $data = apply_filters( 'wp_wdkit_widget_ajax', 'wkit_create_widget' );
434 break;
435 case 'wkit_import_widget':
436 $data = apply_filters( 'wp_wdkit_widget_ajax', 'wkit_import_widget' );
437 break;
438 case 'wkit_export_widget':
439 $data = apply_filters( 'wp_wdkit_widget_ajax', 'wkit_export_widget' );
440 break;
441 case 'wkit_delete_widget':
442 $data = apply_filters( 'wp_wdkit_widget_ajax', 'wkit_delete_widget' );
443 break;
444 case 'wkit_widget_preview':
445 $data = apply_filters( 'wp_wdkit_widget_ajax', 'wkit_widget_preview' );
446 break;
447 case 'wkit_check_widget_versions':
448 $data = apply_filters( 'wp_wdkit_widget_ajax', 'wkit_check_widget_versions' );
449 break;
450 case 'wkit_plugin_download_get':
451 $data = apply_filters( 'wp_wdkit_widget_ajax', 'wkit_plugin_download_get' );
452 break;
453 case 'wkit_manage_widget_workspace':
454 $data = $this->wdkit_manage_widget_workspace();
455 break;
456 case 'wkit_activate_key':
457 $data = $this->wdkit_activate_key();
458 break;
459 case 'wkit_manage_widget_category':
460 $data = $this->wdkit_manage_widget_category();
461 break;
462 case 'wkit_widget_json':
463 $data = $this->wkit_widget_json();
464 break;
465 case 'wkit_download_widget':
466 $data = $this->wdkit_download_widget();
467 break;
468 case 'wkit_public_download_widget':
469 $data = apply_filters( 'wp_wdkit_widget_ajax', 'wkit_public_download_widget' );
470 break;
471 case 'wkit_add_widget':
472 $data = $this->wdkit_add_widget();
473 break;
474 case 'wkit_favourite_widget':
475 $data = $this->wdkit_favourite_widget();
476 break;
477 case 'wkit_setting_panel':
478 $data = $this->wdkit_setting_panel();
479 break;
480 case 'media_import':
481 $data = $this->wdkit_media_import();
482 break;
483 case 'active_licence':
484 $data = $this->wdkit_activate_licence();
485 break;
486 case 'delete_licence':
487 $data = $this->wdkit_delete_licence_key();
488 break;
489 case 'sync_licence':
490 $data = $this->wdkit_sync_licence_key();
491 break;
492 case 'get_wkit_version':
493 $data = $this->wdkit_prev_version();
494 break;
495 case 'rollback_wdkit':
496 $data = $this->wdkit_rollback_check();
497 break;
498 case 'wkit_logout':
499 $data = $this->wdkit_logout();
500 break;
501 case 'wkit_white_label':
502 $this->wkit_white_label();
503 break;
504 case 'wkit_reset_wl':
505 $data = $this->wkit_reset_wl();
506 break;
507 case 'wdkit_dark_mode':
508 $data = $this->wdkit_dark_mode();
509 break;
510 case 'wdkit_get_workspace_data':
511 $data = $this->wdkit_get_workspace_data();
512 break;
513 default:
514 $this->wdkit_error_msg( __( 'Unknown request type.', 'wdesignkit' ) );
515 return;
516 }
517
518 $this->wdkit_success_msg( $data );
519 // wp_die();
520 }
521
522 /**
523 *
524 * This Function is used for API call
525 *
526 * @since 1.0.0
527 *
528 * @param array $data give array.
529 * @param array $name store data.
530 * @param int $timeout optional HTTP timeout in seconds. Default 100.
531 */
532 protected function wkit_api_call( $data, $name, $timeout = 100 ) {
533 $u_r_l = $this->wdkit_api;
534
535 if ( empty( $u_r_l ) ) {
536 return array(
537 'massage' => esc_html__( 'API Not Found', 'wdesignkit' ),
538 'success' => false,
539 );
540 }
541
542 $args = array(
543 'method' => 'POST',
544 'body' => $data,
545 'timeout' => $timeout,
546 );
547 $response = wp_remote_post( $u_r_l . $name, $args );
548
549 if ( is_wp_error( $response ) ) {
550 $error_message = $response->get_error_message();
551
552 /* Translators: %s is a placeholder for the error message */
553 $error_message = sprintf( esc_html__( 'API request error: %s', 'wdesignkit' ), esc_html( $error_message ) );
554
555 return array(
556 'massage' => $error_message,
557 'success' => false,
558 );
559 }
560
561 $status_code = wp_remote_retrieve_response_code( $response );
562 if ( 200 === $status_code ) {
563
564 return array(
565 'data' => json_decode( wp_remote_retrieve_body( $response ) ),
566 'massage' => esc_html__( 'Success', 'wdesignkit' ),
567 'status' => $status_code,
568 'success' => true,
569 );
570 }
571
572 $error_message = sprintf( 'Server error: %d', esc_html( $status_code ) );
573
574 if ( isset( $error_data->message ) ) {
575 $error_message .= ' (' . $error_data->message . ')';
576 }
577
578 return array(
579 'massage' => $error_message,
580 'status' => $status_code,
581 'success' => false,
582 );
583 }
584
585 /**
586 *
587 * It is Use for handle onboarding data.
588 *
589 * @since 1.0.9
590 */
591 public function wdkit_onboarding_handler() {
592 $page_template = isset( $_POST['page_template'] ) ? json_decode( wp_unslash( $_POST['page_template'] ), true ) : '';
593 $page_builder = isset( $_POST['page_builder'] ) ? json_decode( wp_unslash( $_POST['page_builder'] ), true ) : '';
594
595 $elementor_plugin = isset( $_POST['elementor_plugin'] ) ? (int) sanitize_text_field( wp_unslash( $_POST['elementor_plugin'] ) ) : 0;
596 $tpag_plugin = isset( $_POST['tpag_plugin'] ) ? (int) sanitize_text_field( wp_unslash( $_POST['tpag_plugin'] ) ) : 0;
597 $bricks_theme = isset( $_POST['bricks_theme'] ) ? (int) sanitize_text_field( wp_unslash( $_POST['bricks_theme'] ) ) : 0;
598 $site_info = isset( $_POST['info'] ) ? sanitize_text_field( wp_unslash( $_POST['info'] ) ) : false;
599
600 $server_software = ! empty( $_SERVER['SERVER_SOFTWARE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) : '';
601
602 $web_server = $server_software;
603 $memory_limit = ini_get( 'memory_limit' );
604 $max_execution_time = ini_get( 'max_execution_time' );
605 $php_version = phpversion();
606 $wp_version = get_bloginfo( 'version' );
607 $email = get_option( 'admin_email' );
608 $siteurl = get_option( 'siteurl' );
609 $language = get_bloginfo( 'language' );
610
611 // Active Plugin Name.
612 $act_plugin = array();
613 $actplu = get_option( 'active_plugins' );
614 if ( ! function_exists( 'get_plugins' ) ) {
615 require_once ABSPATH . 'wp-admin/includes/plugin.php';
616 }
617
618 $plugins = get_plugins();
619 foreach ( $actplu as $p ) {
620 if ( isset( $plugins[ $p ] ) ) {
621 $act_plugin[] = $plugins[ $p ]['Name'];
622 }
623 }
624
625 $plugin = wp_json_encode( $act_plugin );
626
627 $theme = '';
628 $acthemeobj = wp_get_theme();
629 if ( $acthemeobj->get( 'Name' ) !== null && ! empty( $acthemeobj->get( 'Name' ) ) ) {
630 $theme = $acthemeobj->get( 'Name' );
631 }
632
633 $basic_requirements = array(
634 'elementor_install' => $elementor_plugin,
635 'tpag_install' => $tpag_plugin,
636 'bricks_install' => $bricks_theme,
637 );
638
639 if ( ! empty( $site_info ) ) {
640 $final = array(
641 'web_server' => $web_server,
642 'memory_limit' => $memory_limit,
643 'max_execution_time' => $max_execution_time,
644 'php_version' => $php_version,
645 'wp_version' => $wp_version,
646 'email' => $email,
647 'site_url' => $siteurl,
648 'site_language' => $language,
649 'theme' => $theme,
650 'plugins' => $act_plugin,
651 'basic_requirements' => $basic_requirements,
652 'page_template' => $page_template,
653 'page_builder' => $page_builder,
654 );
655 } else {
656 $final = array();
657 }
658
659 $response = wp_remote_post(
660 $this->wdkit_onbording_api,
661 array(
662 'method' => 'POST',
663 'body' => wp_json_encode( $final ),
664 )
665 );
666
667 $existing_value = get_option( $this->wdkit_onbording_end );
668 if ( false === $existing_value ) {
669 add_option( $this->wdkit_onbording_end, true );
670 }
671
672 if ( is_wp_error( $response ) ) {
673 $result = array(
674 'success' => false,
675 'messages' => 'Oops',
676 'description' => 'Description',
677 );
678
679 wp_send_json( $result );
680 } else {
681 $status_one = wp_remote_retrieve_response_code( $response );
682
683 if ( 200 === $status_one ) {
684 $get_data_one = wp_remote_retrieve_body( $response );
685
686 $get_res = json_decode( json_decode( $get_data_one, true ), true );
687
688 $result = array(
689 'success' => ! empty( $get_res['success'] ) ? $get_res['success'] : false,
690 'messages' => ! empty( $get_res['messages'] ) ? $get_res['messages'] : 'success',
691 'description' => ! empty( $get_res['description'] ) ? $get_res['description'] : 'Description',
692 );
693
694 wp_send_json( $result );
695 } else {
696
697 $result = array(
698 'success' => false,
699 'messages' => 'Oops',
700 'description' => 'description',
701 );
702
703 wp_send_json( $result );
704 }
705 }
706
707 wp_die();
708 }
709
710 /**
711 *
712 * It is Use for get meta data for non login user
713 *
714 * @since 1.0.0
715 */
716 protected function wdkit_meta_data() {
717 $type = isset( $_POST['meta_type'] ) ? sanitize_text_field( wp_unslash( $_POST['meta_type'] ) ) : '';
718 $data = array( 'type' => $type );
719
720 $response = $this->wkit_api_call( $data, 'meta' );
721 $success = ! empty( $response['success'] ) ? $response['success'] : false;
722 $status = ! empty( $response['status'] ) ? (int) $response['status'] : 400;
723
724 if ( empty( $success ) ) {
725 $result = array(
726 'plugin' => array(),
727 'builder' => array(),
728 'category' => array(),
729 'widgetscategory' => array(),
730 'tags' => array(),
731 'widgetbuilder' => array(),
732
733 'message' => esc_html__( 'Server Error', 'wdesignkit' ),
734 'description' => esc_html__( 'Server Error, Data Not Found', 'wdesignkit' ),
735 'success' => false,
736 );
737
738 wp_send_json( $result );
739 wp_die();
740 }
741
742 $get_data_one = ! empty( $response['data'] ) ? $response['data'] : array();
743 $statuscode = array( 'HTTP_CODE' => $status );
744
745 $final = json_decode( wp_json_encode( $get_data_one ), true );
746
747 $final['Setting'] = self::wkit_get_settings_panel();
748 $final['widget_list'] = $this->wkit_manage_widget_sequence( array() );
749
750 $final = array(
751 'data' => $final,
752 );
753
754 wp_send_json( $final );
755 wp_die();
756 }
757
758 /**
759 *
760 * It is Use for get activate license key data from tpae and nexter blocks.
761 *
762 * @since 1.1.6
763 */
764 protected function wkit_manage_license_data() {
765 $manage_licence = array();
766 $theplus_active_check = is_plugin_active( 'the-plus-addons-for-elementor-page-builder/theplus_elementor_addon.php' );
767 $nexter_active_check = is_plugin_active( 'the-plus-addons-for-block-editor/the-plus-addons-for-block-editor.php' );
768
769 $theplus_licence = get_option( 'tpaep_licence_data', array() );
770
771 // Also require the TPAE Pro plugin to be active (Pro defines THEPLUS_VERSION;
772 // the free plugin defines L_THEPLUS_VERSION). This hides the "found active
773 // key" notice when the Pro plugin is removed even though its licence option
774 // still lingers in the database.
775 if ( ! empty( $theplus_active_check ) && defined( 'THEPLUS_VERSION' ) && ! empty( $theplus_licence ) ) {
776 $manage_licence['tpae'] = $theplus_licence;
777 }
778
779 $nexter_licence = get_option( 'tpgb_activate', array() );
780
781 // Also require the Nexter Blocks Pro plugin to be active (Pro defines
782 // TPGBP_VERSION; the free plugin defines TPGB_VERSION), so the notice hides
783 // when the Pro plugin is removed but its licence option persists.
784 if ( ! empty( $nexter_active_check ) && defined( 'TPGBP_VERSION' ) && ! empty( $nexter_licence ) && ! empty( $nexter_licence['tpgb_activate_key'] ) ) {
785 $tpgb_license_status = get_option( 'tpgbp_license_status', array() );
786 $tpgb_license_status['license_key'] = $nexter_licence['tpgb_activate_key'];
787 $manage_licence['tpag'] = $tpgb_license_status;
788 }
789
790 return $manage_licence;
791 }
792
793 /**
794 *
795 * It is Use for get all info of user.
796 *
797 * @since 1.0.0
798 */
799 protected function wdkit_get_user_info() {
800 $token = isset( $_POST['token'] ) ? wp_unslash( $_POST['token'] ) : false;
801 $email = isset( $_POST['email'] ) ? strtolower( sanitize_email( wp_unslash( $_POST['email'] ) ) ) : false;
802 $builder = isset( $_POST['builder'] ) ? strtolower( sanitize_text_field( wp_unslash( $_POST['builder'] ) ) ) : '';
803
804 $site_url = isset( $_POST['site_url'] ) ? esc_url_raw( wp_unslash( $_POST['site_url'] ) ) : '';
805
806 $response = array();
807
808 if ( empty( $token ) ) {
809 $response = array(
810 'success' => false,
811 'message' => $this->e_msg_login,
812 'description' => $this->e_desc_login,
813 );
814
815 wp_send_json( $response );
816 wp_die();
817 }
818
819 // $token = $this->wdkit_login_user_token( $email );
820 $args = array(
821 'token' => $token,
822 'builder' => $builder,
823 'site_url' => $site_url,
824 );
825
826 $response = WDesignKit_Data_Query::get_data( 'get_user_info', $args );
827
828 if ( is_wp_error( $response ) ) {
829 wp_send_json( array(
830 'success' => false,
831 'message' => $response->get_error_message(),
832 'description' => $response->get_error_message(),
833 ) );
834 wp_die();
835 }
836
837 $status = ( ! empty( $response['status'] ) ) ? sanitize_text_field( $response['status'] ) : 'error';
838 $email = isset( $_POST['email'] ) ? strtolower( sanitize_email( wp_unslash( $_POST['email'] ) ) ) : false;
839
840 /**Condtion user for user logout & expire token*/
841 if ( 'Token is Expired' === $status || 'Authorization Token not found' === $status ) {
842 delete_transient( 'wdkit_auth_' . wdesignkit_cloud_session_key( $email ) );
843 // Clear stored license data when token expires so banner shows again
844 delete_option( 'wdkit_licence_data' );
845 }
846
847 if ( empty( $response ) ) {
848 $response['login_reset'] = 'yes';
849 }
850
851 // Store WDesignKit license data locally if present in response
852 if ( ! empty( $response['credits']['wdkit_licence'] ) && is_array( $response['credits']['wdkit_licence'] ) ) {
853 $wdkit_licence = $response['credits']['wdkit_licence'];
854 // Handle serialized data
855 if ( is_string( $wdkit_licence ) && is_serialized( $wdkit_licence ) ) {
856 $wdkit_licence = unserialize( $wdkit_licence, array( 'allowed_classes' => false ) );
857 }
858 if ( ! empty( $wdkit_licence ) && is_array( $wdkit_licence ) ) {
859 update_option( 'wdkit_licence_data', $wdkit_licence );
860 }
861 }
862
863 $response['Setting'] = $this->wkit_get_settings_panel();
864 $response['widget_list'] = $this->wkit_manage_widget_sequence( $response );
865 $response['manage_licence'] = $this->wkit_manage_license_data();
866
867 $response = array(
868 'data' => $response,
869 'success' => true,
870 );
871
872 wp_send_json( $response );
873 wp_die();
874 }
875
876 /**
877 *
878 * It is Use for get all widgets local and server.
879 *
880 * @since 1.0.19
881 * @param string $response userinfo store.
882 */
883 protected function wkit_manage_widget_sequence( $response = array() ) {
884
885 $credits = ! empty( $response['credits']['widget_limit']['meta_value'] ) ? $response['credits']['widget_limit']['meta_value'] : 10;
886 $server_list = ! empty( $response['widgettemplate'] ) ? $response['widgettemplate'] : array();
887 $db_builder_list = ! empty( $response['widgetbuilder'] ) ? $response['widgetbuilder'] : array();
888
889 // Whether this call actually carried the server widget list that activation state is
890 // derived from. Captured before the loops below, which unset() matched $server_list
891 // entries as they go. wdkit_meta_data() calls this method with array(), and without
892 // this flag that call rebuilt $db_widget from local widgets only — every one of which
893 // is forced 'active' further down — and then wrote the empty result over
894 // wkit_deactivate_widgets, erasing every deactivation the user had made.
895 $has_server_widgets = ! empty( $server_list );
896
897 $placeholderimg = WDKIT_URL . 'assets/images/placeholder.jpg';
898
899 $local_list = $this->wdkit_get_local_widgets();
900
901 $server_w_unique = array_column( $server_list, 'w_unique' );
902
903 $idx_builder = array();
904 foreach ( $db_builder_list as $index => $value ) {
905 $builder_name = ! empty( $value['builder_slug'] ) ? $value['builder_slug'] : '';
906 $w_id = ! empty( $value['w_id'] ) ? $value['w_id'] : '';
907
908 if ( ! empty( $builder_name ) ) {
909 $idx_builder[ $w_id ] = strtolower( str_replace( ' ', '_', trim( $builder_name ) ) );
910 }
911 }
912
913 foreach ( $server_list as $index => $value ) {
914 $get_id = $server_list[ $index ]['builder'] ? $server_list[ $index ]['builder'] : '';
915
916 $server_list[ $index ]['type'] = 'server';
917 $server_list[ $index ]['builder'] = ! empty( $idx_builder[ $get_id ] ) ? $idx_builder[ $get_id ] : '';
918 }
919
920 $count = 0;
921
922 foreach ( $local_list as $key => $value ) {
923 $widget_id = ! empty( $value['widgetdata']['widget_id'] ) ? $value['widgetdata']['widget_id'] : '';
924 $allow_push = isset( $value['widgetdata']['allow_push'] ) ? $value['widgetdata']['allow_push'] : true;
925
926 if ( in_array( $widget_id, $server_w_unique ) ) {
927
928 $index = array_search( $widget_id, $server_w_unique );
929
930 $server_list[ $index ]['title'] = $local_list[ $key ]['widgetdata']['name'];
931 $server_list[ $index ]['w_version'] = $local_list[ $key ]['widgetdata']['widget_version'];
932 $server_list[ $index ]['allow_push'] = $allow_push;
933 $server_list[ $index ]['builder'] = $local_list[ $key ]['widgetdata']['type'];
934 $server_list[ $index ]['w_unique'] = $local_list[ $key ]['widgetdata']['widget_id'];
935 $server_list[ $index ]['image'] = ! empty( $local_list[ $key ]['widgetdata']['w_image'] ) ? $local_list[ $key ]['widgetdata']['w_image'] : $placeholderimg;
936
937 $local_list[ $key ] = $server_list[ $index ];
938
939 $local_list[ $key ]['type'] = 'done';
940
941 unset( $server_list[ $index ] );
942 } else {
943 $local_list[ $key ]['widgetdata']['builder'] = $local_list[ $key ]['widgetdata']['type'];
944 $local_list[ $key ]['widgetdata']['w_unique'] = $local_list[ $key ]['widgetdata']['widget_id'];
945 $local_list[ $key ]['widgetdata']['allow_push'] = $allow_push;
946 $local_list[ $key ]['widgetdata']['image'] = ! empty( $local_list[ $key ]['widgetdata']['w_image'] ) ? $local_list[ $key ]['widgetdata']['w_image'] : $placeholderimg;
947 $local_list[ $key ]['widgetdata']['is_activated'] = 'active';
948
949 $local_list[ $key ]['widgetdata']['type'] = 'plugin';
950
951 $local_list[ $key ]['widgetdata']['title'] = $local_list[ $key ]['widgetdata']['name'];
952 unset( $local_list[ $key ]['widgetdata']['name'] );
953 unset( $local_list[ $key ]['widgetdata']['widget_id'] );
954
955 $local_list[ $key ] = $local_list[ $key ]['widgetdata'];
956 }
957 }
958
959 $final = array_merge( $local_list, $server_list );
960
961 $db_widget = array();
962
963 foreach ( $final as $key => $self ) {
964 $is_activated = ! empty( $final[ $key ]['is_activated'] ) ? $final[ $key ]['is_activated'] : 'active';
965
966 if ( 'active' === $is_activated ) {
967 ++$count;
968 }
969
970 if ( ( $count > $credits ) && ( 'unlimited' !== $credits ) ) {
971 $final[ $key ]['is_activated'] = 'deactive';
972 }
973
974 if ( ! empty( $self['is_activated'] ) && 'active' !== $self['is_activated'] ) {
975 $db_widget[] = array(
976 'w_unique' => $self['w_unique'],
977 'builder' => $self['builder'],
978 'title' => $self['title'],
979 'is_activated' => $self['is_activated'],
980 );
981 }
982 }
983
984 // Only persist activation state when the server list it is derived from was actually
985 // supplied. See $has_server_widgets above.
986 if ( $has_server_widgets ) {
987 // update_option() creates the row when it is missing, so it covers both cases.
988 // The previous add_option()/update_option() split was chosen on empty( $option ),
989 // but wdkit_db_widgetlist() creates this row as an empty array on every install —
990 // so the empty branch ran while the row already existed, and add_option() is a
991 // no-op for an existing option. Deactivating from the My Widgets screen was
992 // therefore silently discarded on effectively every site. Autoload stays 'yes',
993 // matching the original add_option() call and wdkit_db_widgetlist().
994 update_option( 'wkit_deactivate_widgets', $db_widget, 'yes' );
995
996 // The cached widget registry bakes in wkit_deactivate_widgets membership and is
997 // stored as a no-expiry transient, so it never self-heals. Without this the
998 // loaders kept registering a widget the user had just switched off (and kept
999 // hiding one they had switched back on) until the transient was flushed by hand.
1000 // The write above is not per-builder — one save can change any builder's set, and
1001 // a widget can move between builders — so clear all four.
1002 if ( function_exists( 'wdesignkit_invalidate_widget_registry' ) ) {
1003 foreach ( array( 'elementor', 'gutenberg', 'gutenberg_core', 'bricks' ) as $builder_slug ) {
1004 wdesignkit_invalidate_widget_registry( $builder_slug );
1005 }
1006 }
1007 }
1008
1009 return $final;
1010 }
1011
1012 /**
1013 * Browse Page Filter
1014 *
1015 * @since 1.0.0
1016 */
1017 protected function wdkit_browse_page() {
1018 $args = $this->wdkit_parse_args( $_POST );
1019
1020 $response = WDesignKit_Data_Query::get_data( 'browse_page', $args );
1021
1022 if ( is_wp_error( $response ) ) {
1023 wp_send_json( array(
1024 'success' => false,
1025 'message' => $response->get_error_message(),
1026 ) );
1027 wp_die();
1028 }
1029
1030 $manage_licence = array();
1031 $manage_licence['theplus_elementor_addon'] = ! empty( defined( 'THEPLUS_VERSION' ) ) ? true : false;
1032 $manage_licence['tpag'] = ! empty( defined( 'TPGBP_VERSION' ) ) ? true : false;
1033 $manage_licence['elementor-pro'] = ! empty( defined( 'ELEMENTOR_PRO_VERSION' ) ) ? true : false;
1034 $response['manage_licence'] = $manage_licence;
1035
1036 wp_send_json( $response );
1037 wp_die();
1038 }
1039
1040 /**
1041 *
1042 * It is Use for get template from kit.
1043 *
1044 * @since 1.0.0
1045 */
1046 protected function wdkit_template() {
1047 $args = $this->wdkit_parse_args( $_POST );
1048
1049 $response = WDesignKit_Data_Query::get_data( 'kit_template', $args );
1050
1051 wp_send_json( $response );
1052 wp_die();
1053 }
1054
1055 /**
1056 *
1057 * It is Use for remove or delete template.
1058 *
1059 * @since 1.0.0
1060 */
1061 protected function wdkit_template_remove() {
1062 $args = $this->wdkit_parse_args( $_POST );
1063
1064 $user_email = strtolower( sanitize_email( $args['email'] ) );
1065 $response = '';
1066
1067 // Bug D fix: response()->json() is Laravel syntax — causes PHP fatal. Use plain array.
1068 if ( empty( $user_email ) || empty( $args['template_id'] ) ) {
1069 $response = array(
1070 'message' => $this->e_msg_login,
1071 'description' => $this->e_desc_login,
1072 'success' => false,
1073 );
1074
1075 wp_send_json( $response );
1076 wp_die();
1077 }
1078
1079 $args['token'] = $this->wdkit_login_user_token( $user_email );
1080
1081 unset( $user_email );
1082 $response = WDesignKit_Data_Query::get_data( 'template_remove', $args );
1083
1084 wp_send_json( $response );
1085 wp_die();
1086 }
1087
1088 /**
1089 *
1090 * It is Use for save template from page builder.
1091 *
1092 * @since 1.0.0
1093 */
1094 protected function wdkit_put_save_template() {
1095 $email = isset( $_POST['email'] ) ? strtolower( sanitize_email( wp_unslash( $_POST['email'] ) ) ) : false;
1096 $post_id = isset( $_POST['post_id'] ) ? sanitize_text_field( wp_unslash( $_POST['post_id'] ) ) : '';
1097 $builder = isset( $_POST['builder'] ) ? sanitize_text_field( wp_unslash( $_POST['builder'] ) ) : '';
1098
1099 $response = '';
1100
1101 if ( empty( $email ) ) {
1102 $response = array(
1103 'id' => 0,
1104 'editpage' => '',
1105 'message' => $this->e_msg_login,
1106 'description' => $this->e_desc_login,
1107 'success' => false,
1108 );
1109
1110 wp_send_json( $response );
1111 wp_die();
1112 }
1113
1114 $args = $this->wdkit_parse_args( $_POST );
1115 $args['token'] = $this->wdkit_login_user_token( $email );
1116 unset( $args['email'] );
1117
1118 if( 'elementor' === $builder ){
1119 $args['data'] = base64_decode( $args['data'] );
1120 } else if ( 'gutenberg' === $builder ) {
1121 $args['data'] = base64_decode( $args['data'] );
1122 }
1123
1124 global $post;
1125
1126 $custom_fields = array();
1127 if ( ! empty( $post_id ) ) {
1128 $meta_fields = get_post_custom( $post_id );
1129
1130 foreach ( $meta_fields as $key => $value ) {
1131 if ( str_contains( $key, 'nxt-' ) ) {
1132 $custom_fields[ $key ] = $value;
1133 }
1134 }
1135
1136 if ( ! empty( $custom_fields ) ) {
1137 $data = json_decode( $args['data'], true );
1138 $data['custom_meta'] = $custom_fields;
1139 $args['data'] = wp_json_encode( $data );
1140 }
1141 }
1142
1143 $response = WDesignKit_Data_Query::get_data( 'save_template', $args );
1144
1145 /**
1146 * The cloud call can come back as a WP_Error (timeout, DNS, refused) or with an
1147 * empty / unparsable body, which json_decode()s to null. Forwarding that as-is
1148 * makes admin-ajax answer with a literal `null` that the editor then reads
1149 * `.id` off, killing the whole app. Normalise it to the failure shape used above.
1150 */
1151 if ( is_wp_error( $response ) || ! is_array( $response ) ) {
1152 $response = array(
1153 'id' => 0,
1154 'editpage' => '',
1155 'message' => esc_html__( 'Template Not Saved !', 'wdesignkit' ),
1156 'description' => is_wp_error( $response ) ? $response->get_error_message() : esc_html__( 'Could not reach the WDesignKit server. Please try again.', 'wdesignkit' ),
1157 'success' => false,
1158 );
1159 }
1160
1161 wp_send_json( $response );
1162 wp_die();
1163 }
1164
1165 /**
1166 *
1167 * It is Use for update save template image.
1168 *
1169 * @since 2.0.6
1170 */
1171 protected function wdkit_update_save_temp_image() {
1172 $temp_content = isset( $_POST['temp_content'] ) ? esc_url_raw( $_POST['temp_content'] ) : '';
1173 $content_name = isset( $_POST['content_name'] ) ? sanitize_text_field( $_POST['content_name'] ) : '';
1174 $token = isset( $_POST['token'] ) ? sanitize_text_field( $_POST['token'] ) : '';
1175 $user_type = isset( $_POST['user_type'] ) ? sanitize_text_field( $_POST['user_type'] ) : '';
1176 $type = isset( $_POST['content_type'] ) ? sanitize_text_field( $_POST['content_type'] ) : '';
1177 $id = isset( $_POST['id'] ) ? sanitize_text_field( $_POST['id'] ) : '';
1178 if ( empty( $temp_content ) || empty( $user_type ) || empty( $id ) || empty( $token ) ) {
1179 $response = array(
1180 'message' => __( 'Data not found', 'wdesignkit' ),
1181 'description' => __( 'Data not found', 'wdesignkit' ),
1182 'success' => false,
1183 );
1184 } else {
1185 $temp_content = str_replace( '\\', '', $temp_content );
1186 // SSRF guard (CWE-918): validate the resolved host before fetching a caller-supplied URL.
1187 $fetched = wdesignkit_safe_remote_get( $temp_content );
1188 $temp_content = is_wp_error( $fetched ) ? '' : wp_remote_retrieve_body( $fetched );
1189 $temp_content = base64_encode( $temp_content );
1190
1191 $args = array(
1192 'token' => $token,
1193 'template_id' => $id,
1194 'name' => $content_name,
1195 'content' => $temp_content,
1196 'type' => $type,
1197 );
1198
1199 $response = $this->wkit_api_call( $args, 'save_images' );
1200 $success = ! empty( $response['success'] ) ? $response['success'] : false;
1201
1202 if ( $success ) {
1203 $response = array(
1204 'data' => $response['data'],
1205 'success' => true,
1206 );
1207 } else {
1208 $response = array(
1209 'message' => __( 'API Error', 'wdesignkit' ),
1210 'description' => __( 'API Error', 'wdesignkit' ),
1211 'data' => $response['data'],
1212 'success' => false,
1213 );
1214 }
1215 }
1216
1217 wp_send_json( $response );
1218 wp_die();
1219 }
1220
1221 /**
1222 *
1223 * It is Use for save image to WordPress Media Library.
1224 *
1225 * @since 2.3.3
1226 */
1227 protected function wdkit_save_wp_images() {
1228
1229 // media_sideload_image() generates every registered thumbnail size, which decodes
1230 // the full source bitmap. Same guard as the page import.
1231 $this->wdkit_guard_oversized_images();
1232
1233 $image_url = isset( $_POST['image'] ) ? sanitize_text_field( $_POST['image'] ) : '';
1234
1235 if ( empty( $image_url ) ) {
1236 $response = array(
1237 'message' => __( 'No Image Provided', 'wdesignkit' ),
1238 'description' => __( 'No Image URL provided for save.', 'wdesignkit' ),
1239 'success' => false,
1240 );
1241 } else {
1242
1243 $attachment_id = media_sideload_image( $image_url, 0, null, 'id' );
1244
1245 if ( is_wp_error( $attachment_id ) ) {
1246 $response = array(
1247 'message' => __( 'Upload Failed', 'wdesignkit' ),
1248 'description' => $attachment_id->get_error_message(),
1249 'success' => false,
1250 );
1251 } else {
1252 $saved_url = wp_get_attachment_url( $attachment_id );
1253
1254 // Elementor's importer skips an image only when it finds
1255 // _elementor_source_image_hash matching sha1 of the URL it is given. The
1256 // content we hand it now carries this local URL, so stamp the hash of that
1257 // URL too - without it Elementor re-downloads a file already on disk and
1258 // leaves a "-1" duplicate behind for every image on every page that uses it.
1259 if ( $saved_url ) {
1260 update_post_meta( $attachment_id, '_elementor_source_image_hash', sha1( $saved_url ) );
1261
1262 // Same purpose for the block importer, which keys off its own meta.
1263 update_post_meta( $attachment_id, 'tpgb_source_image_key', sha1( $saved_url ) );
1264 }
1265
1266 $response = array(
1267 'message' => __( 'Image Saved', 'wdesignkit' ),
1268 'description' => __( 'Image successfully saved to Media Library.', 'wdesignkit' ),
1269 'success' => true,
1270 'url' => $saved_url,
1271 );
1272 }
1273
1274 }
1275
1276 wp_send_json( $response );
1277 wp_die();
1278 }
1279
1280 /**
1281 *
1282 * Get Elementor Global color and Typography.
1283 *
1284 * @since 1.1.16
1285 */
1286 /**
1287 * Kit settings holding The Plus Addons' own globals.
1288 *
1289 * These sit in the Elementor kit's `_elementor_page_settings` alongside Elementor's
1290 * system_colors / system_typography, but the save flow only ever collected the four
1291 * Elementor keys. Widgets reference an entry in these lists by its `_id` through a
1292 * `tp_global_preset` setting, so a template saved without them travels with the
1293 * reference but not the definition - which is why imported sections come in missing
1294 * their button styling, radii and shadows.
1295 *
1296 * @since 2.6.4
1297 *
1298 * @return array Kit setting keys.
1299 */
1300 private function wdkit_tp_global_kit_keys() {
1301 return array(
1302 'tp_global_button_style_list',
1303 'tp_global_dimensions_list',
1304 'tp_global_box_shadow_list',
1305 'tp_global_gradient_list',
1306 'tp_global_gsap_list',
1307 'tp_global_scroll_animation_list',
1308 'tp_text_global_gsap_list',
1309 'tp_image_global_gsap_list',
1310 );
1311 }
1312
1313 /**
1314 * Merge incoming Plus globals into the active kit, keyed by `_id`.
1315 *
1316 * Entries are matched on their `_id`, never on position: an existing entry is always
1317 * left as it is, and only genuinely new ones are appended. That matters because
1318 * widgets - and the entries themselves, a button style points at dimension and shadow
1319 * entries - resolve by `_id`. Renumbering or overwriting would repoint references on
1320 * the destination site's own content.
1321 *
1322 * @since 2.6.4
1323 *
1324 * @param array $incoming Lists captured with the template.
1325 * @return bool True when the kit was changed.
1326 */
1327 /**
1328 * Global colour / typography ids this site already defines.
1329 *
1330 * @since 2.6.4
1331 *
1332 * @param array $kit_meta Kit `_elementor_page_settings`.
1333 * @return array{color:array<string,bool>,typography:array<string,bool>}
1334 */
1335 private function wdkit_known_global_ids( $kit_meta ) {
1336 $known = array(
1337 'color' => array(),
1338 'typography' => array(),
1339 );
1340
1341 $sources = array(
1342 'color' => array( 'system_colors', 'custom_colors' ),
1343 'typography' => array( 'system_typography', 'custom_typography' ),
1344 );
1345
1346 foreach ( $sources as $kind => $keys ) {
1347 foreach ( $keys as $key ) {
1348 if ( empty( $kit_meta[ $key ] ) || ! is_array( $kit_meta[ $key ] ) ) {
1349 continue;
1350 }
1351
1352 foreach ( $kit_meta[ $key ] as $entry ) {
1353 if ( ! empty( $entry['_id'] ) ) {
1354 $known[ $kind ][ $entry['_id'] ] = true;
1355 }
1356 }
1357 }
1358 }
1359
1360 return $known;
1361 }
1362
1363 /**
1364 * Make one incoming Plus global's colour / font references resolvable here.
1365 *
1366 * A Plus global can point at an Elementor global: the "Primary Button" entry holds
1367 * `__globals__: { text_color: "globals/colors?id=72e09b4", … }`, which The Plus Addons
1368 * turns into `var(--e-global-color-72e09b4)`. Elementor only emits that variable for ids
1369 * present in the kit, so on a site without `72e09b4` the button renders with no colour.
1370 *
1371 * Two cases, and the difference is deliberate:
1372 *
1373 * - The site ALREADY defines that id — leave the reference alone. The button then picks
1374 * up the destination's own colour, which is the point of a global. Their palette is
1375 * never read from or written to beyond this check.
1376 * - The site does NOT define it — write the captured value straight into the entry and
1377 * drop the reference, so it renders as designed.
1378 *
1379 * Nothing is ever added to the user's global colours or fonts. An earlier version injected
1380 * the missing definitions into their palette, which made the reference resolve but grew
1381 * their Site Settings by every colour an imported template happened to use.
1382 *
1383 * @since 2.6.4
1384 *
1385 * @param array $entry One repeater entry.
1386 * @param array $refs Definitions captured with the template.
1387 * @param array $known Ids this site defines, from wdkit_known_global_ids().
1388 * @return array Entry, with unresolvable references replaced by their values.
1389 */
1390 private function wdkit_resolve_entry_globals( $entry, $refs, $known ) {
1391 if ( empty( $entry['__globals__'] ) || ! is_array( $entry['__globals__'] ) ) {
1392 return $entry;
1393 }
1394
1395 foreach ( $entry['__globals__'] as $control => $ref ) {
1396 if ( ! is_string( $ref ) || false === strpos( $ref, 'id=' ) ) {
1397 continue;
1398 }
1399
1400 if ( false !== strpos( $ref, 'globals/colors' ) ) {
1401 $kind = 'color';
1402 } elseif ( false !== strpos( $ref, 'globals/typography' ) ) {
1403 $kind = 'typography';
1404 } else {
1405 continue;
1406 }
1407
1408 $id = substr( $ref, strpos( $ref, 'id=' ) + 3 );
1409 if ( '' === $id || isset( $known[ $kind ][ $id ] ) ) {
1410 // Defined here already — their value wins.
1411 continue;
1412 }
1413
1414 $definition = null;
1415 foreach ( ( $refs[ $kind ] ?? array() ) as $candidate ) {
1416 if ( is_array( $candidate ) && ( $candidate['_id'] ?? '' ) === $id ) {
1417 $definition = $candidate;
1418 break;
1419 }
1420 }
1421
1422 if ( null === $definition ) {
1423 // Nothing captured for it, so leave the reference rather than blank the field.
1424 continue;
1425 }
1426
1427 if ( 'color' === $kind ) {
1428 if ( empty( $definition['color'] ) ) {
1429 continue;
1430 }
1431
1432 $entry[ $control ] = $definition['color'];
1433 } else {
1434 // A typography global expands into its own set of controls: the reference is
1435 // held under e.g. `typography_typography`, and each definition key replaces
1436 // that suffix — `typography_font_family`, `typography_font_weight`, and so on.
1437 foreach ( $definition as $def_key => $def_value ) {
1438 if ( '_id' === $def_key || 'title' === $def_key ) {
1439 continue;
1440 }
1441
1442 $entry[ str_replace( 'typography_typography', $def_key, $control ) ] = $def_value;
1443 }
1444 }
1445
1446 unset( $entry['__globals__'][ $control ] );
1447 }
1448
1449 return $entry;
1450 }
1451
1452 private function wdkit_merge_tp_globals( $incoming, $refs = array() ) {
1453 if ( empty( $incoming ) || ! is_array( $incoming ) ) {
1454 return false;
1455 }
1456
1457 $kit_id = get_option( 'elementor_active_kit' );
1458 if ( empty( $kit_id ) ) {
1459 return false;
1460 }
1461
1462 $kit_meta = get_post_meta( $kit_id, '_elementor_page_settings', true );
1463 if ( ! is_array( $kit_meta ) ) {
1464 $kit_meta = array();
1465 }
1466
1467 // Which global ids this site already defines. The Plus Addons turns a reference into
1468 // var(--e-global-color-<_id>), and Elementor only emits that variable for ids in the
1469 // kit — so a reference the destination does not define resolves to nothing at all.
1470 $known = $this->wdkit_known_global_ids( $kit_meta );
1471
1472 $changed = false;
1473
1474 foreach ( $this->wdkit_tp_global_kit_keys() as $key ) {
1475 if ( empty( $incoming[ $key ] ) || ! is_array( $incoming[ $key ] ) ) {
1476 continue;
1477 }
1478
1479 $existing = ( ! empty( $kit_meta[ $key ] ) && is_array( $kit_meta[ $key ] ) ) ? $kit_meta[ $key ] : array();
1480
1481 $seen = array();
1482 foreach ( $existing as $entry ) {
1483 if ( ! empty( $entry['_id'] ) ) {
1484 $seen[ $entry['_id'] ] = true;
1485 }
1486 }
1487
1488 foreach ( $incoming[ $key ] as $entry ) {
1489 if ( ! is_array( $entry ) || empty( $entry['_id'] ) || isset( $seen[ $entry['_id'] ] ) ) {
1490 continue;
1491 }
1492
1493 // Only ever rewrite the entry being added — never one already in the kit.
1494 $existing[] = $this->wdkit_resolve_entry_globals( $entry, $refs, $known );
1495 $seen[ $entry['_id'] ] = true;
1496 $changed = true;
1497 }
1498
1499 $kit_meta[ $key ] = array_values( $existing );
1500 }
1501
1502 if ( $changed ) {
1503 update_post_meta( $kit_id, '_elementor_page_settings', $kit_meta );
1504
1505 // Writing kit meta directly does not rebuild the kit stylesheet, so the
1506 // merged globals would never reach the frontend.
1507 $this->wdkit_regenerate_elementor_kit_css();
1508 }
1509
1510 return $changed;
1511 }
1512
1513 protected function wdkit_get_global_val() {
1514
1515 $builder = isset( $_POST['builder'] ) ? strtolower( sanitize_text_field( $_POST['builder'] ) ) : '';
1516
1517 if ( 'elementor' === $builder ) {
1518 $kit_id = get_option( 'elementor_active_kit' );
1519 if ( empty( $kit_id ) ) {
1520 $response = array(
1521 'message' => __( 'Elementor kit not found', 'wdesignkit' ),
1522 'description' => __( 'No active Elementor kit found', 'wdesignkit' ),
1523 'success' => false,
1524 );
1525
1526 wp_send_json( $response );
1527 wp_die();
1528 }
1529
1530 $kit_meta = get_post_meta( $kit_id, '_elementor_page_settings', true );
1531 if ( empty( $kit_meta['system_colors'] ) ) {
1532 $static_meta = array(
1533 'system_colors' => array(
1534 0 => array(
1535 '_id' => 'primary',
1536 'title' => 'Primary',
1537 'color' => '#6EC1E4',
1538 ),
1539 1 => array(
1540 '_id' => 'secondary',
1541 'title' => 'Secondary',
1542 'color' => '#54595F',
1543 ),
1544 2 => array(
1545 '_id' => 'text',
1546 'title' => 'Text',
1547 'color' => '#7A7A7A',
1548 ),
1549 3 => array(
1550 '_id' => 'accent',
1551 'title' => 'Accent',
1552 'color' => '#61CE70',
1553 ),
1554 ),
1555 'custom_colors' => array(),
1556 'system_typography' => array(
1557 0 => array(
1558 '_id' => 'primary',
1559 'title' => 'Primary',
1560 'typography_typography' => 'custom',
1561 'typography_font_family' => 'Roboto',
1562 'typography_font_weight' => '600',
1563 ),
1564 1 => array(
1565 '_id' => 'secondary',
1566 'title' => 'Secondary',
1567 'typography_typography' => 'custom',
1568 'typography_font_family' => 'Roboto Slab',
1569 'typography_font_weight' => '400',
1570 ),
1571 2 => array(
1572 '_id' => 'text',
1573 'title' => 'Text',
1574 'typography_typography' => 'custom',
1575 'typography_font_family' => 'Roboto',
1576 'typography_font_weight' => '400',
1577 ),
1578 3 => array(
1579 '_id' => 'accent',
1580 'title' => 'Accent',
1581 'typography_typography' => 'custom',
1582 'typography_font_family' => 'Roboto',
1583 'typography_font_weight' => '500',
1584 ),
1585 ),
1586 'custom_typography' => array(),
1587 'default_generic_fonts' => 'Sans-serif',
1588 'site_name' => ! empty( get_bloginfo( 'name' ) ) ? get_bloginfo( 'name' ) : '',
1589 'page_title_selector' => 'h1.entry-title',
1590 'activeItemIndex' => 1,
1591 'viewport_md' => 768,
1592 'viewport_lg' => 1025,
1593 );
1594
1595 $kit_meta = $static_meta;
1596 update_post_meta( $kit_id, '_elementor_page_settings', $kit_meta );
1597 }
1598
1599 $system_colors = ! empty( $kit_meta['system_colors'] ) ? $kit_meta['system_colors'] : array();
1600 $custom_colors = ! empty( $kit_meta['custom_colors'] ) ? $kit_meta['custom_colors'] : array();
1601 $system_typography = ! empty( $kit_meta['system_typography'] ) ? $kit_meta['system_typography'] : array();
1602 $custom_typography = ! empty( $kit_meta['custom_typography'] ) ? $kit_meta['custom_typography'] : array();
1603
1604 $color_array = array_merge( $system_colors, $custom_colors );
1605 $typo_array = array_merge( $system_typography, $custom_typography );
1606
1607 $global_data = array(
1608 'color' => $color_array,
1609 'typography' => $typo_array,
1610 );
1611
1612 $response = array(
1613 'message' => __( 'Global data Found', 'wdesignkit' ),
1614 'description' => __( 'Global Color and Typography found', 'wdesignkit' ),
1615 'data' => $global_data,
1616 'success' => true,
1617 );
1618
1619 } elseif ( 'gutenberg' === $builder ) {
1620
1621 $plus_settings = get_option( 'tpgb_global_options', false );
1622 $plus_settings = ! empty( $plus_settings ) ? json_decode( $plus_settings, true ) : json_decode( '[]' );
1623
1624 if ( empty( $plus_settings ) ) {
1625
1626 $static_meta = array(
1627 'active' => 'preset1',
1628 'darkMode' => 'none',
1629 'presets' => array(
1630 'preset1' => array(
1631 'name' => 'Preset 1',
1632 'key' => 'preset1',
1633 'colors' => array(
1634 array(
1635 'label' => 'Primary',
1636 'value' => '#8072FC',
1637 ),
1638 array(
1639 'label' => 'Secondary',
1640 'value' => '#6FC784',
1641 ),
1642 array(
1643 'label' => 'Tertiary',
1644 'value' => '#FF5A6E',
1645 ),
1646 array(
1647 'label' => 'Accent',
1648 'value' => '#F3F3F3',
1649 ),
1650 array(
1651 'label' => 'Background',
1652 'value' => '#888888',
1653 ),
1654 ),
1655 'gradient' => array(
1656 array(
1657 'label' => 'Primary',
1658 'value' => 'linear-gradient(135deg,rgb(8,148,229) 0%,rgb(155,81,224) 100%)',
1659 ),
1660
1661 array(
1662 'label' => 'Secondary',
1663 'value' => 'linear-gradient(135deg,rgb(8,148,229) 0%,rgb(155,81,224) 100%)',
1664 ),
1665
1666 array(
1667 'label' => 'Tertiary',
1668 'value' => 'linear-gradient(135deg,rgb(8,148,229) 0%,rgb(155,81,224) 100%)',
1669 ),
1670
1671 array(
1672 'label' => 'Accent',
1673 'value' => 'linear-gradient(135deg,rgb(8,148,229) 0%,rgb(155,81,224) 100%)',
1674 ),
1675
1676 array(
1677 'label' => 'Background',
1678 'value' => 'linear-gradient(135deg,rgb(8,148,229) 0%,rgb(155,81,224) 100%)',
1679 ),
1680 ),
1681 'spacing' => array(
1682 array(
1683 'label' => 'Large',
1684 'value' => array(
1685 'md' => 70,
1686 'unit' => 'px',
1687 ),
1688 ),
1689 array(
1690 'label' => 'Medium',
1691 'value' => array(
1692 'md' => 40,
1693 'unit' => 'px',
1694 ),
1695 ),
1696 array(
1697 'label' => 'Small',
1698 'value' => array(
1699 'md' => 20,
1700 'unit' => 'px',
1701 ),
1702
1703 ),
1704 ),
1705 'typography' => array(
1706 array(
1707 'label' => 'Display Text',
1708 'value' => array(
1709 'openTypography' => 1,
1710 'size' => array(
1711 'md' => 65,
1712 'unit' => 'px',
1713 ),
1714 'height' => array(
1715 'md' => 75,
1716 'unit' => 'px',
1717 ),
1718 'fontFamily' => array(
1719 'family' => 'Roboto',
1720 'type' => 'sans-serif',
1721 'fontWeight' => 700,
1722 ),
1723 'spacing' => array(
1724 'md' => 0,
1725 'unit' => 'px',
1726 ),
1727 ),
1728 ),
1729 array(
1730 'label' => 'Headline',
1731 'value' => array(
1732 'openTypography' => 1,
1733 'size' => array(
1734 'md' => 45,
1735 'unit' => 'px',
1736 ),
1737 'height' => array(
1738 'md' => 60,
1739 'unit' => 'px',
1740 ),
1741 'fontFamily' => array(
1742 'family' => 'Roboto',
1743 'type' => 'sans-serif',
1744 'fontWeight' => 700,
1745 ),
1746 'spacing' => array(
1747 'md' => 0,
1748 'unit' => 'px',
1749 ),
1750 ),
1751 ),
1752 array(
1753 'label' => 'Sub Headline',
1754 'value' => array(
1755 'openTypography' => 1,
1756 'size' => array(
1757 'md' => 38,
1758 'unit' => 'px',
1759 ),
1760 'height' => array(
1761 'md' => 45,
1762 'unit' => 'px',
1763 ),
1764 'fontFamily' => array(
1765 'family' => 'Roboto',
1766 'type' => 'sans-serif',
1767 'fontWeight' => 500,
1768 ),
1769 'spacing' => array(
1770 'md' => 0,
1771 'unit' => 'px',
1772 ),
1773 ),
1774 ),
1775 array(
1776 'label' => 'Title 1',
1777 'value' => array(
1778 'openTypography' => 1,
1779 'size' => array(
1780 'md' => 30,
1781 'unit' => 'px',
1782 ),
1783 'height' => array(
1784 'md' => 40,
1785 'unit' => 'px',
1786 ),
1787 'fontFamily' => array(
1788 'family' => 'Roboto',
1789 'type' => 'sans-serif',
1790 'fontWeight' => 500,
1791 ),
1792 'spacing' => array(
1793 'md' => 0,
1794 'unit' => 'px',
1795 ),
1796 ),
1797 ),
1798 array(
1799 'label' => 'Title 2',
1800 'value' => array(
1801 'openTypography' => 1,
1802 'size' => array(
1803 'md' => 25,
1804 'unit' => 'px',
1805 ),
1806 'height' => array(
1807 'md' => 30,
1808 'unit' => 'px',
1809 ),
1810 'fontFamily' => array(
1811 'family' => 'Roboto',
1812 'type' => 'sans-serif',
1813 'fontWeight' => 400,
1814 ),
1815 'spacing' => array(
1816 'md' => 0,
1817 'unit' => 'px',
1818 ),
1819 ),
1820 ),
1821 array(
1822 'label' => 'Body',
1823 'value' => array(
1824 'openTypography' => 1,
1825 'size' => array(
1826 'md' => 17,
1827 'unit' => 'px',
1828 ),
1829 'height' => array(
1830 'md' => 22,
1831 'unit' => 'px',
1832 ),
1833 'fontFamily' => array(
1834 'family' => 'Roboto',
1835 'type' => 'sans-serif',
1836 'fontWeight' => 400,
1837 ),
1838 'spacing' => array(
1839 'md' => 0,
1840 'unit' => 'px',
1841 ),
1842 ),
1843 ),
1844 array(
1845 'label' => 'Captions',
1846 'value' => array(
1847 'openTypography' => 1,
1848 'size' => array(
1849 'md' => 13,
1850 'unit' => 'px',
1851 ),
1852 'height' => array(
1853 'md' => 16,
1854 'unit' => 'px',
1855 ),
1856 'fontFamily' => array(
1857 'family' => 'Roboto',
1858 'type' => 'sans-serif',
1859 'fontWeight' => 400,
1860 ),
1861 'spacing' => array(
1862 'md' => 0,
1863 'unit' => 'px',
1864 ),
1865 ),
1866 ),
1867 ),
1868 'boxshadow' => array(
1869 array(
1870 'label' => 'Normal Shadow',
1871 'value' => array(
1872 'openShadow' => 1,
1873 'inset' => 0,
1874 'horizontal' => 2,
1875 'vertical' => 6,
1876 'blur' => 10,
1877 'spread' => 0,
1878 'color' => 'rgba(0,0,0,0.15)',
1879 ),
1880 ),
1881 array(
1882 'label' => 'Hover Shadow',
1883 'value' => array(
1884 'openShadow' => 1,
1885 'inset' => 0,
1886 'horizontal' => 2,
1887 'vertical' => 5,
1888 'blur' => 14,
1889 'spread' => 3,
1890 'color' => 'rgba(0,0,0,0.2)',
1891 ),
1892 ),
1893 ),
1894 ),
1895 'preset2' => array(
1896 'name' => 'Preset 2',
1897 'key' => 'preset2',
1898 'colors' => array(
1899 array(
1900 'label' => 'Primary',
1901 'value' => '#8072FC',
1902 ),
1903 array(
1904 'label' => 'Secondary',
1905 'value' => '#6FC784',
1906 ),
1907 array(
1908 'label' => 'Tertiary',
1909 'value' => '#FF5A6E',
1910 ),
1911 array(
1912 'label' => 'Accent',
1913 'value' => '#F3F3F3',
1914 ),
1915 array(
1916 'label' => 'Background',
1917 'value' => '#888888',
1918 ),
1919 ),
1920 'gradient' => array(
1921 array(
1922 'label' => 'Primary',
1923 'value' => 'linear-gradient(135deg,rgb(8,148,229) 0%,rgb(155,81,224) 100%)',
1924 ),
1925
1926 array(
1927 'label' => 'Secondary',
1928 'value' => 'linear-gradient(135deg,rgb(8,148,229) 0%,rgb(155,81,224) 100%)',
1929 ),
1930
1931 array(
1932 'label' => 'Tertiary',
1933 'value' => 'linear-gradient(135deg,rgb(8,148,229) 0%,rgb(155,81,224) 100%)',
1934 ),
1935
1936 array(
1937 'label' => 'Accent',
1938 'value' => 'linear-gradient(135deg,rgb(8,148,229) 0%,rgb(155,81,224) 100%)',
1939 ),
1940
1941 array(
1942 'label' => 'Background',
1943 'value' => 'linear-gradient(135deg,rgb(8,148,229) 0%,rgb(155,81,224) 100%)',
1944 ),
1945 ),
1946 'spacing' => array(
1947 array(
1948 'label' => 'Large',
1949 'value' => array(
1950 'md' => 70,
1951 'unit' => 'px',
1952 ),
1953 ),
1954 array(
1955 'label' => 'Medium',
1956 'value' => array(
1957 'md' => 40,
1958 'unit' => 'px',
1959 ),
1960 ),
1961 array(
1962 'label' => 'Small',
1963 'value' => array(
1964 'md' => 20,
1965 'unit' => 'px',
1966 ),
1967
1968 ),
1969 ),
1970 'typography' => array(
1971 array(
1972 'label' => 'Display Text',
1973 'value' => array(
1974 'openTypography' => 1,
1975 'size' => array(
1976 'md' => 65,
1977 'unit' => 'px',
1978 ),
1979 'height' => array(
1980 'md' => 75,
1981 'unit' => 'px',
1982 ),
1983 'fontFamily' => array(
1984 'family' => 'Roboto',
1985 'type' => 'sans-serif',
1986 'fontWeight' => 700,
1987 ),
1988 'spacing' => array(
1989 'md' => 0,
1990 'unit' => 'px',
1991 ),
1992 ),
1993 ),
1994 array(
1995 'label' => 'Headline',
1996 'value' => array(
1997 'openTypography' => 1,
1998 'size' => array(
1999 'md' => 45,
2000 'unit' => 'px',
2001 ),
2002 'height' => array(
2003 'md' => 60,
2004 'unit' => 'px',
2005 ),
2006 'fontFamily' => array(
2007 'family' => 'Roboto',
2008 'type' => 'sans-serif',
2009 'fontWeight' => 700,
2010 ),
2011 'spacing' => array(
2012 'md' => 0,
2013 'unit' => 'px',
2014 ),
2015 ),
2016 ),
2017 array(
2018 'label' => 'Sub Headline',
2019 'value' => array(
2020 'openTypography' => 1,
2021 'size' => array(
2022 'md' => 38,
2023 'unit' => 'px',
2024 ),
2025 'height' => array(
2026 'md' => 45,
2027 'unit' => 'px',
2028 ),
2029 'fontFamily' => array(
2030 'family' => 'Roboto',
2031 'type' => 'sans-serif',
2032 'fontWeight' => 500,
2033 ),
2034 'spacing' => array(
2035 'md' => 0,
2036 'unit' => 'px',
2037 ),
2038 ),
2039 ),
2040 array(
2041 'label' => 'Title 1',
2042 'value' => array(
2043 'openTypography' => 1,
2044 'size' => array(
2045 'md' => 30,
2046 'unit' => 'px',
2047 ),
2048 'height' => array(
2049 'md' => 40,
2050 'unit' => 'px',
2051 ),
2052 'fontFamily' => array(
2053 'family' => 'Roboto',
2054 'type' => 'sans-serif',
2055 'fontWeight' => 500,
2056 ),
2057 'spacing' => array(
2058 'md' => 0,
2059 'unit' => 'px',
2060 ),
2061 ),
2062 ),
2063 array(
2064 'label' => 'Title 2',
2065 'value' => array(
2066 'openTypography' => 1,
2067 'size' => array(
2068 'md' => 25,
2069 'unit' => 'px',
2070 ),
2071 'height' => array(
2072 'md' => 30,
2073 'unit' => 'px',
2074 ),
2075 'fontFamily' => array(
2076 'family' => 'Roboto',
2077 'type' => 'sans-serif',
2078 'fontWeight' => 400,
2079 ),
2080 'spacing' => array(
2081 'md' => 0,
2082 'unit' => 'px',
2083 ),
2084 ),
2085 ),
2086 array(
2087 'label' => 'Body',
2088 'value' => array(
2089 'openTypography' => 1,
2090 'size' => array(
2091 'md' => 17,
2092 'unit' => 'px',
2093 ),
2094 'height' => array(
2095 'md' => 22,
2096 'unit' => 'px',
2097 ),
2098 'fontFamily' => array(
2099 'family' => 'Roboto',
2100 'type' => 'sans-serif',
2101 'fontWeight' => 400,
2102 ),
2103 'spacing' => array(
2104 'md' => 0,
2105 'unit' => 'px',
2106 ),
2107 ),
2108 ),
2109 array(
2110 'label' => 'Captions',
2111 'value' => array(
2112 'openTypography' => 1,
2113 'size' => array(
2114 'md' => 13,
2115 'unit' => 'px',
2116 ),
2117 'height' => array(
2118 'md' => 16,
2119 'unit' => 'px',
2120 ),
2121 'fontFamily' => array(
2122 'family' => 'Roboto',
2123 'type' => 'sans-serif',
2124 'fontWeight' => 400,
2125 ),
2126 'spacing' => array(
2127 'md' => 0,
2128 'unit' => 'px',
2129 ),
2130 ),
2131 ),
2132 ),
2133 'boxshadow' => array(
2134 array(
2135 'label' => 'Normal Shadow',
2136 'value' => array(
2137 'openShadow' => 1,
2138 'inset' => 0,
2139 'horizontal' => 2,
2140 'vertical' => 6,
2141 'blur' => 10,
2142 'spread' => 0,
2143 'color' => 'rgba(0,0,0,0.15)',
2144 ),
2145 ),
2146 array(
2147 'label' => 'Hover Shadow',
2148 'value' => array(
2149 'openShadow' => 1,
2150 'inset' => 0,
2151 'horizontal' => 2,
2152 'vertical' => 5,
2153 'blur' => 14,
2154 'spread' => 3,
2155 'color' => 'rgba(0,0,0,0.2)',
2156 ),
2157 ),
2158 ),
2159 ),
2160 ),
2161 'globalContainer' => array(
2162 'md' => '',
2163 'unit' => 'px',
2164 ),
2165 );
2166
2167 update_option( 'tpgb_global_options', json_encode( $static_meta ) );
2168 $plus_settings = $static_meta;
2169 }
2170
2171 $active_id = ! empty( $plus_settings['active'] ) ? $plus_settings['active'] : '';
2172 $preset_array = ! empty( $plus_settings['presets'] ) ? $plus_settings['presets'] : array();
2173 $act_preset = ! empty( $plus_settings['presets'][ $active_id ] ) ? $plus_settings['presets'][ $active_id ] : array();
2174
2175 foreach ( $act_preset['colors'] as $index => &$item ) {
2176 $item['id'] = $index + 1;
2177 }
2178 unset( $item );
2179
2180 foreach ( $act_preset['typography'] as $index => &$item ) {
2181 $item['id'] = $index + 1;
2182 }
2183 unset( $item );
2184
2185 $act_preset['color'] = $act_preset['colors'];
2186 unset( $act_preset['colors'] );
2187
2188 $response = array(
2189 'message' => __( 'Global data Found', 'wdesignkit' ),
2190 'description' => __( 'Global Color and Typography found', 'wdesignkit' ),
2191 'data' => $act_preset,
2192 'success' => true,
2193 );
2194 }
2195
2196 wp_send_json( $response );
2197 wp_die();
2198 }
2199
2200 /**
2201 *
2202 * Get site settings.
2203 *
2204 * @since 2.1.3
2205 */
2206 protected function wdkit_get_site_setting() {
2207
2208 $kit_id = get_option( 'elementor_active_kit' );
2209 if ( empty( $kit_id ) ) {
2210 $response = array(
2211 'message' => __( 'Elementor kit not found', 'wdesignkit' ),
2212 'description' => __( 'No active Elementor kit found', 'wdesignkit' ),
2213 'success' => false,
2214 );
2215
2216 wp_send_json( $response );
2217 wp_die();
2218 }
2219
2220 $kit_meta = get_post_meta( $kit_id, '_elementor_page_settings', true );
2221
2222 $container_width = ! empty( $kit_meta['container_width'] ) ? $kit_meta['container_width'] : array();
2223 $globals = ! empty( $kit_meta['__globals__'] ) ? $kit_meta['__globals__'] : array();
2224 $body_background_color = ! empty( $kit_meta['body_background_color'] ) ? $kit_meta['body_background_color'] : array();
2225
2226 $site_globals = array(
2227 'body_background_color' => $body_background_color,
2228 'container_width' => $container_width,
2229 'globals' => $globals,
2230 );
2231
2232 $response = array(
2233 'message' => __( 'Global data Found', 'wdesignkit' ),
2234 'description' => __( 'Global Color and Typography found', 'wdesignkit' ),
2235 'data' => $site_globals,
2236 'success' => true,
2237 );
2238
2239 wp_send_json( $response );
2240 wp_die();
2241 }
2242
2243 /**
2244 *
2245 * update site settings.
2246 *
2247 * @since 2.1.3
2248 */
2249 protected function wdkit_update_site_setting() {
2250
2251 $builder = ! empty( $_POST['builder'] ) ? sanitize_text_field( $_POST['builder'] ) : '';
2252 $site_data = ! empty( $_POST['site_data'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['site_data'] ) ), true ) : array();
2253
2254 if ( 'elementor' == $builder ) {
2255 $kit_id = get_option( 'elementor_active_kit' );
2256 if ( ! $kit_id && did_action( 'elementor/loaded' ) && class_exists( '\Elementor\Core\Kits\Manager' ) ) {
2257 \Elementor\Core\Kits\Manager::create_default_kit();
2258 $kit_id = get_option( 'elementor_active_kit' );
2259 }
2260
2261 if ( ! $kit_id ) {
2262 $response = array(
2263 'message' => __( 'Elementor kit not found', 'wdesignkit' ),
2264 'description' => __( 'No active Elementor kit found', 'wdesignkit' ),
2265 'success' => false,
2266 );
2267
2268 wp_send_json( $response );
2269 wp_die();
2270 }
2271
2272 // A freshly created kit has no `_elementor_page_settings` meta yet,
2273 // so an empty result here is a valid starting point, not an error.
2274 $kit_meta = get_post_meta( $kit_id, '_elementor_page_settings', true );
2275 if ( ! is_array( $kit_meta ) ) {
2276 $kit_meta = array();
2277 }
2278
2279 $kit_meta['container_width'] = ! empty( $site_data['container_width'] ) ? $site_data['container_width'] : array();
2280 $kit_meta['__globals__'] = ! empty( $site_data['globals'] ) ? $site_data['globals'] : array();
2281 $kit_meta['body_background_color'] = ! empty( $site_data['body_background_color'] ) ? $site_data['body_background_color'] : array();
2282
2283 update_post_meta( $kit_id, '_elementor_page_settings', $kit_meta );
2284
2285 // Regenerate Elementor's cached CSS. Writing the kit meta directly does
2286 // not rebuild the kit stylesheet, so the imported body background colour
2287 // and container width would otherwise never render on the frontend.
2288 $this->wdkit_regenerate_elementor_kit_css();
2289
2290 $response = array(
2291 'message' => __( 'Site data Updated', 'wdesignkit' ),
2292 'description' => __( 'Site Globals Updated', 'wdesignkit' ),
2293 'success' => true,
2294 );
2295
2296 } elseif ( 'gutenberg' == $builder ) {
2297 $plus_settings = get_option( 'tpgb_global_options' );
2298
2299 $site_preset = json_decode( $plus_settings, true );
2300 $site_preset['globalContainer'] = $site_data;
2301
2302 update_option( 'tpgb_global_options', json_encode( $site_preset ) );
2303
2304 $response = array(
2305 'message' => __( 'Site data Updated', 'wdesignkit' ),
2306 'description' => __( 'Site Globals Updated', 'wdesignkit' ),
2307 'success' => true,
2308 );
2309
2310 } else {
2311 $response = array(
2312 'message' => __( 'Builder Not Found !', 'wdesignkit' ),
2313 'description' => __( 'Template Builder not Found', 'wdesignkit' ),
2314 'success' => true,
2315 );
2316 }
2317
2318 wp_send_json( $response );
2319 wp_die();
2320 }
2321
2322 /**
2323 *
2324 * Update Elementor Global color and Typography.
2325 *
2326 * @since 1.1.20
2327 */
2328 protected function wdkit_update_global_val() {
2329
2330 $builder = ! empty( $_POST['builder'] ) ? sanitize_text_field( $_POST['builder'] ) : '';
2331
2332 if ( 'elementor' == $builder ) {
2333
2334 $g_color = ! empty( $_POST['g_color'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['g_color'] ) ), true ) : array();
2335 $g_typo = ! empty( $_POST['g_typography'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['g_typography'] ) ), true ) : array();
2336
2337 // Get colors from Elementor Site Kit
2338 $kit_id = get_option( 'elementor_active_kit' );
2339 if ( ! $kit_id && did_action( 'elementor/loaded' ) && class_exists( '\Elementor\Core\Kits\Manager' ) ) {
2340 // No kit has ever been created on this site (the option is only
2341 // ever populated by Elementor's own activation hook). Create one
2342 // via Elementor's own helper so the import has somewhere to write.
2343 \Elementor\Core\Kits\Manager::create_default_kit();
2344 $kit_id = get_option( 'elementor_active_kit' );
2345 }
2346
2347 if ( ! $kit_id ) {
2348 $response = array(
2349 'message' => __( 'Elementor kit not found', 'wdesignkit' ),
2350 'description' => __( 'No active Elementor kit found', 'wdesignkit' ),
2351 'success' => false,
2352 );
2353
2354 wp_send_json( $response );
2355 wp_die();
2356 }
2357
2358 // A freshly created kit has no `_elementor_page_settings` meta yet,
2359 // so an empty result here is a valid starting point, not an error.
2360 $kit_meta = get_post_meta( $kit_id, '_elementor_page_settings', true );
2361 if ( ! is_array( $kit_meta ) ) {
2362 $kit_meta = array();
2363 }
2364
2365 $kit_meta['custom_colors'] = array_merge( $g_color, $kit_meta['custom_colors'] ?? array() );
2366 $kit_meta['custom_typography'] = array_merge( $g_typo, $kit_meta['custom_typography'] ?? array() );
2367
2368 update_post_meta( $kit_id, '_elementor_page_settings', $kit_meta );
2369
2370 // Regenerate Elementor's cached CSS. Writing the kit meta directly does
2371 // not rebuild the kit stylesheet, so the imported global colours and
2372 // fonts would otherwise never render on the frontend.
2373 $this->wdkit_regenerate_elementor_kit_css();
2374
2375 $response = array(
2376 'message' => __( 'Global data Updated', 'wdesignkit' ),
2377 'description' => __( 'Global Color and Typography Updated', 'wdesignkit' ),
2378 'success' => true,
2379 );
2380
2381 } elseif ( 'gutenberg' == $builder ) {
2382 $new_preset = ! empty( $_POST['new_preset'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['new_preset'] ) ), true ) : array();
2383 $new_preset_id = ! empty( $new_preset['key'] ) ? $new_preset['key'] : '';
2384 $plus_settings = get_option( 'tpgb_global_options' );
2385 $site_preset = json_decode( $plus_settings, true );
2386
2387 $site_preset['presets'][ $new_preset_id ] = $new_preset;
2388 $site_preset['active'] = $new_preset_id;
2389
2390 update_option( 'tpgb_global_options', json_encode( $site_preset ) );
2391
2392 $response = array(
2393 'message' => __( 'Global data Updated', 'wdesignkit' ),
2394 'description' => __( 'Global Color and Typography Updated', 'wdesignkit' ),
2395 'success' => true,
2396 );
2397
2398 } else {
2399 $response = array(
2400 'message' => __( 'Builder Not Found !', 'wdesignkit' ),
2401 'description' => __( 'Template Builder not Found', 'wdesignkit' ),
2402 'success' => true,
2403 );
2404 }
2405
2406 wp_send_json( $response );
2407 wp_die();
2408 }
2409
2410 /**
2411 * Regenerate Elementor's cached CSS files after the active kit's
2412 * `_elementor_page_settings` meta has been changed directly.
2413 *
2414 * Elementor renders global colours, global fonts and the body background
2415 * colour into a cached kit stylesheet. Updating the meta via
2416 * update_post_meta() does not rebuild that stylesheet, so imported site
2417 * settings never reach the frontend until the cache is cleared. This
2418 * mirrors the clear_cache() call already used by the page/section import.
2419 *
2420 * @since 2.3.2
2421 *
2422 * @return void
2423 */
2424 protected function wdkit_regenerate_elementor_kit_css() {
2425 if ( did_action( 'elementor/loaded' ) && class_exists( '\Elementor\Plugin' ) ) {
2426 \Elementor\Plugin::$instance->files_manager->clear_cache();
2427 }
2428 }
2429
2430 /**
2431 *
2432 * Create Gutenberg page and save for re-generate css file.
2433 *
2434 * @since 1.2.3
2435 */
2436 protected function wdkit_update_preset() {
2437
2438 $act_type = ! empty( $_POST['act_type'] ) ? sanitize_text_field( $_POST['act_type'] ) : '';
2439 $post_id = ! empty( $_POST['post_id'] ) ? sanitize_text_field( $_POST['post_id'] ) : '';
2440
2441 if ( 'create' == $act_type ) {
2442
2443 $page_id = wp_insert_post(
2444 array(
2445 'post_title' => 'WDesignKit Gutenberg',
2446 'post_status' => 'publish',
2447 'post_type' => 'post',
2448 'post_name' => sanitize_title( 'wdesignkit' ),
2449 'post_content' => '<!-- wp:heading --><h2 class="wp-block-heading">Add Your Heading Text Here<h2><!-- /wp:heading -->',
2450 'meta_input' => array(
2451 'gutenberg_preview' => true,
2452 '_wp_page_template' => 'default',
2453 ),
2454 )
2455 );
2456
2457 if ( is_wp_error( $page_id ) || ! $page_id ) {
2458 $response = array(
2459 'success' => true,
2460 'message' => esc_html__( 'Page Not Found!', 'wdesignkit' ),
2461 'description' => esc_html__( 'Page Not Found!', 'wdesignkit' ),
2462 );
2463
2464 wp_send_json( $response );
2465 wp_die();
2466 }
2467
2468 update_post_meta( $page_id, '_edit_lock', time() . ':1' );
2469 update_post_meta( $page_id, '_edit_last', get_current_user_id() );
2470
2471 $preview_url = admin_url( 'post.php?post=' . $page_id . '&action=edit' );
2472
2473 $response = array(
2474 'success' => true,
2475 'post_id' => $page_id,
2476 'preview_url' => $preview_url,
2477 'message' => esc_html__( 'Page Created', 'wdesignkit' ),
2478 'description' => esc_html__( 'Page Created', 'wdesignkit' ),
2479 );
2480
2481 wp_send_json( $response );
2482 wp_die();
2483
2484 }
2485
2486 if ( ! empty( $post_id ) && ( $act_type == 'remove' ) ) {
2487
2488 wp_delete_post( $post_id, true );
2489
2490 $response = array(
2491 'success' => true,
2492 'message' => esc_html__( 'post deleted', 'wdesignkit' ),
2493 'description' => esc_html__( 'post deleted', 'wdesignkit' ),
2494 );
2495
2496 wp_send_json( $response );
2497 wp_die();
2498 }
2499 }
2500
2501 /**
2502 *
2503 * It is For Find User Existing template List.
2504 *
2505 * @since 1.0.6
2506 */
2507 protected function wdkit_find_existing_template() {
2508 $array_data = array(
2509 'search' => isset( $_POST['search'] ) ? sanitize_text_field( wp_unslash( $_POST['search'] ) ) : '',
2510 'token' => isset( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '',
2511 'type' => isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : '',
2512 'u_id' => isset( $_POST['u_id'] ) ? sanitize_text_field( wp_unslash( $_POST['u_id'] ) ) : '',
2513 'builder' => isset( $_POST['builder'] ) ? sanitize_text_field( wp_unslash( $_POST['builder'] ) ) : '',
2514 'parpage' => isset( $_POST['parpage'] ) ? sanitize_text_field( wp_unslash( $_POST['parpage'] ) ) : 12,
2515 );
2516
2517 $response = $this->wkit_api_call( $array_data, 'existing_template' );
2518
2519 wp_send_json( $response );
2520 wp_die();
2521 }
2522
2523 /**
2524 *
2525 * It is For Update User Existing template List.
2526 *
2527 * @since 1.0.6
2528 */
2529 protected function wdkit_update_template() {
2530 $array_data = array(
2531 'data' => isset( $_POST['data'] ) ? wp_unslash( $_POST['data'] ) : '',
2532 'post_id' => isset( $_POST['post_id'] ) ? sanitize_text_field( wp_unslash( $_POST['post_id'] ) ) : '',
2533 'token' => isset( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '',
2534 'type' => isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : '',
2535 'id' => isset( $_POST['id'] ) ? sanitize_text_field( wp_unslash( $_POST['id'] ) ) : '',
2536 'global_data' => isset( $_POST['global_data'] ) ? wp_unslash( $_POST['global_data'] ) : array(),
2537 // 'global_font_family' => isset( $_POST['global_font_family'] ) ? wp_unslash( $_POST['global_font_family'] ) : array(),
2538 // 'global_color' => isset( $_POST['global_color'] ) ? wp_unslash( $_POST['global_color'] ) : array(),
2539 );
2540
2541 if ( ! empty( $array_data['post_id'] ) ) {
2542 $custom_fields = array();
2543 $post_id = $array_data['post_id'];
2544
2545 $meta_fields = get_post_custom( $post_id );
2546
2547 foreach ( $meta_fields as $key => $value ) {
2548 if ( str_contains( $key, 'nxt-' ) ) {
2549 $custom_fields[ $key ] = $value;
2550 }
2551 }
2552
2553 if ( ! empty( $custom_fields ) ) {
2554 $data = json_decode( $array_data['data'], true );
2555 $data['custom_meta'] = $custom_fields;
2556 $array_data['data'] = wp_json_encode( $data );
2557 }
2558 }
2559
2560 $array_data['remove'] = 'yes';
2561 $response = $this->wkit_api_call( $array_data, 'existing_template' );
2562 wp_send_json( $response );
2563 wp_die();
2564 }
2565
2566 /**
2567 *
2568 * It is Use for manage favourite template.
2569 *
2570 * @since 1.0.0
2571 */
2572 protected function wdkit_manage_favorite() {
2573 $template_id = isset( $_POST['template_id'] ) ? strtolower( sanitize_text_field( wp_unslash( $_POST['template_id'] ) ) ) : 0;
2574 $email = isset( $_POST['email'] ) ? strtolower( sanitize_email( wp_unslash( $_POST['email'] ) ) ) : false;
2575
2576 if ( empty( $email ) || empty( $template_id ) ) {
2577 $response = array(
2578 'message' => $this->e_msg_login,
2579 'description' => $this->e_desc_login,
2580 'success' => false,
2581 );
2582
2583 wp_send_json( $response );
2584 wp_die();
2585 }
2586
2587 $args = $this->wdkit_parse_args( $_POST );
2588 $args['token'] = $this->wdkit_login_user_token( $email );
2589
2590 unset( $args['email'] );
2591 $response = WDesignKit_Data_Query::get_data( 'manage_favorite', $args );
2592
2593 wp_send_json( $response );
2594 wp_die();
2595 }
2596
2597 /**
2598 *
2599 * It is Use for Check Plugin Dependency of template.
2600 *
2601 * @since 1.0.0
2602 * @version 1.0.9
2603 */
2604 protected function wdkit_check_plugins_depends() {
2605 $plugins = isset( $_POST['plugins'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['plugins'] ) ) ) : array();
2606 $update_plugin = array();
2607 $update_theme = array();
2608
2609 if ( empty( $plugins ) || ! is_array( $plugins ) ) {
2610 $this->wdkit_error_msg( array( 'plugins' => 'No Plugins' ) );
2611 }
2612
2613 $all_plugins = $this->get_plugins();
2614 foreach ( $plugins as $plugin ) {
2615 $pluginslug = ! empty( $plugin->plugin_slug ) ? sanitize_text_field( wp_unslash( $plugin->plugin_slug ) ) : '';
2616 $free_pro = ! empty( $plugin->freepro ) ? sanitize_text_field( wp_unslash( $plugin->freepro ) ) : '0';
2617 $type = ! empty( $plugin->type ) ? sanitize_text_field( wp_unslash( $plugin->type ) ) : 'plugin';
2618
2619 if ( is_null( $pluginslug ) ) {
2620 $plugin->status = 'warning';
2621 $update_plugin[] = $plugin;
2622 $update_theme[] = $plugin;
2623
2624 continue;
2625 }
2626
2627 if ( 'plugin' === $type ) {
2628 if ( ! is_plugin_active( $pluginslug ) ) {
2629 if ( ! isset( $all_plugins[ $pluginslug ] ) ) {
2630 if ( isset( $free_pro ) && '1' === $free_pro ) {
2631 $plugin->status = 'manually';
2632 } else {
2633 $plugin->status = 'unavailable';
2634 }
2635 } else {
2636 $plugin->status = 'inactive';
2637 }
2638
2639 $update_plugin[] = $plugin;
2640 } elseif ( is_plugin_active( $pluginslug ) ) {
2641 $plugin->status = 'active';
2642 $update_plugin[] = $plugin;
2643 }
2644 } elseif ( 'theme' === $type ) {
2645 $theme_array = array_keys( wp_get_themes() );
2646 $theme_slug = get_stylesheet();
2647 $parent_theme_slug = get_template();
2648
2649 if ( $theme_slug === $plugin->original_slug || $parent_theme_slug === $plugin->original_slug ) {
2650
2651 $plugin->status = 'active';
2652 } else {
2653 $theme_name = $plugin->original_slug;
2654 if ( ! in_array( $theme_name, $theme_array ) ) {
2655 if ( isset( $free_pro ) && '1' === $free_pro ) {
2656 $plugin->status = 'manually';
2657 } else {
2658 $plugin->status = 'unavailable';
2659 }
2660 } else {
2661 $plugin->status = 'inactive';
2662 }
2663 }
2664
2665 $update_theme[] = $plugin;
2666 }
2667 }
2668
2669 $response = array(
2670 'plugins' => $update_plugin,
2671 'theme' => $update_theme,
2672 'ele_container' => get_option( 'elementor_experiment-container', false ),
2673 );
2674
2675 $this->wdkit_success_msg( $response );
2676 }
2677
2678 /**
2679 *
2680 * It is Use for Install dependent plugin.
2681 *
2682 * @since 1.0.0
2683 * @version 1.0.9
2684 */
2685 protected function wdkit_install_plugins_depends() {
2686 $plugins = isset( $_POST['plugins'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['plugins'] ) ), true ) : array();
2687 $type = ! empty( $plugins['type'] ) ? $plugins['type'] : 'plugin';
2688 $p_id = ! empty( $plugins['p_id'] ) ? $plugins['p_id'] : 'plugin';
2689
2690 $responce = '';
2691 if ( 'plugin' === $type ) {
2692 $responce = Wdkit_Depends_Installer::get_instance()->wdkit_install_plugin( $plugins );
2693 } elseif ( 'theme' === $type ) {
2694 $theme_name = ! empty( $plugins['original_slug'] ) ? $plugins['original_slug'] : '';
2695 if ( ! empty( $theme_name ) ) {
2696
2697 $theme_array = array_keys( wp_get_themes() );
2698 $theme_slug = get_stylesheet();
2699
2700 if ( in_array( $theme_name, $theme_array ) ) {
2701 $activate_result = switch_theme( $theme_name );
2702
2703 if ( ! is_wp_error( $activate_result ) ) {
2704 $responce = array(
2705 'message' => esc_html__( 'Theme activated successfully', 'wdesignkit' ),
2706 'description' => esc_html__( 'Theme successfully activated', 'wdesignkit' ),
2707 'slug' => 'nexter',
2708 'p_id' => $p_id,
2709 'status' => 'active',
2710 'success' => true,
2711 );
2712 } else {
2713 $responce = array(
2714 'message' => esc_html__( 'Theme Not Activated !', 'wdesignkit' ),
2715 'description' => $activate_result->get_error_message(),
2716 'status' => 'inactive',
2717 'p_id' => $p_id,
2718 'success' => false,
2719 );
2720 }
2721 } else {
2722 $result = $this->wdkit_install_theme_depends( $theme_name );
2723
2724 $message = ! empty( $result['message'] ) ? $result['message'] : esc_html__( 'Somthing Wrong', 'wdesignkit' );
2725 $description = ! empty( $result['description'] ) ? $result['description'] : esc_html__( 'Error Somthing Wrong', 'wdesignkit' );
2726 $status = ! empty( $result['status'] ) ? $result['status'] : esc_html__( 'inactive', 'wdesignkit' );
2727 $success = ! empty( $result['success'] ) ? $result['success'] : false;
2728
2729 $responce = array(
2730 'message' => $message,
2731 'description' => $description,
2732 'p_id' => $p_id,
2733 'status' => $status,
2734 'success' => $success,
2735 );
2736 }
2737 } else {
2738 $responce = array(
2739 'message' => esc_html__( 'Theme Name not Found', 'wdesignkit' ),
2740 'description' => esc_html__( 'Can Not Found Theme Name you Enterd.', 'wdesignkit' ),
2741 'success' => false,
2742 );
2743 }
2744 }
2745
2746 wp_send_json( $responce );
2747 wp_die();
2748 }
2749
2750 protected function wdkit_install_theme_depends( $name = 'nexter' ) {
2751
2752 if ( ! current_user_can( 'install_themes' ) ) {
2753 $response = $this->tpae_set_response( false, 'Invalid nonce.', 'The security check failed. Please refresh the page and try again.' );
2754 return $response;
2755 }
2756
2757 $theme_slug = $name;
2758 $theme_api_url = 'https://api.wordpress.org/themes/info/1.0/';
2759
2760 // Parameters for the request
2761 $args = array(
2762 'body' => array(
2763 'action' => 'theme_information',
2764 'request' => serialize(
2765 (object) array(
2766 'slug' => $name,
2767 'fields' => array(
2768 'description' => false,
2769 'sections' => false,
2770 'rating' => true,
2771 'ratings' => false,
2772 'downloaded' => true,
2773 'download_link' => true,
2774 'last_updated' => true,
2775 'homepage' => true,
2776 'tags' => true,
2777 'template' => true,
2778 'active_installs' => false,
2779 'parent' => false,
2780 'versions' => false,
2781 'screenshot_url' => true,
2782 'active_installs' => false,
2783 ),
2784 )
2785 ),
2786 ),
2787 );
2788
2789 // Make the request
2790 $response = wp_remote_post( $theme_api_url, $args );
2791 // Check for errors
2792 if ( is_wp_error( $response ) ) {
2793 $error_message = $response->get_error_message();
2794
2795 $result = $this->tpae_set_response( false, 'oops', 'oops', '' );
2796 } else {
2797 // api.wordpress.org's theme_information response is a serialized stdClass
2798 // (accessed below via ->name / ->download_link). allowed_classes => false
2799 // blocks stdClass too, turning it into an __PHP_Incomplete_Class whose
2800 // properties silently don't exist — allow only stdClass, still refusing any
2801 // other (potentially dangerous) class the payload might reference.
2802 $theme_info = unserialize( $response['body'], array( 'allowed_classes' => array( 'stdClass' ) ) );
2803 $theme_name = $theme_info->name;
2804 $theme_zip_url = $theme_info->download_link;
2805
2806 // SSRF guard (CWE-918): validate the resolved host before fetching the ZIP
2807 // referenced by the external theme_info response.
2808 if ( ! wdesignkit_validate_external_url( $theme_zip_url ) ) {
2809 return array(
2810 'message' => esc_html__( 'Theme Not Activated !', 'wdesignkit' ),
2811 'description' => esc_html__( 'The theme package URL is not allowed.', 'wdesignkit' ),
2812 'status' => 'inactive',
2813 'success' => false,
2814 );
2815 }
2816
2817 if ( ! function_exists( 'WP_Filesystem' ) ) {
2818 require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/file.php' );
2819 }
2820
2821 require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/class-wp-upgrader.php' );
2822 require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/theme.php' );
2823
2824 WP_Filesystem();
2825
2826 $active_theme = wp_get_theme();
2827 $theme_name = $active_theme->get( 'Name' );
2828
2829 // Install via WordPress core's Theme_Upgrader instead of manually fetching and
2830 // ZipArchive::extractTo()'ing the remote package: core already performs the
2831 // standard download -> unpack -> validate-package-structure -> move-into-place
2832 // flow (including cleanup on failure) used for every trusted theme install.
2833 $upgrader = new Theme_Upgrader( new Automatic_Upgrader_Skin() );
2834 $install = $upgrader->install( $theme_zip_url );
2835
2836 if ( is_wp_error( $install ) || ! $install ) {
2837 return array(
2838 'message' => esc_html__( 'Theme Not Activated !', 'wdesignkit' ),
2839 'description' => is_wp_error( $install ) ? $install->get_error_message() : esc_html__( 'Theme could not be installed.', 'wdesignkit' ),
2840 'status' => 'inactive',
2841 'success' => false,
2842 );
2843 }
2844
2845 $activate_result = switch_theme( $name );
2846
2847 if ( ! is_wp_error( $activate_result ) ) {
2848 $response = array(
2849 'message' => esc_html__( 'Theme activated successfully', 'wdesignkit' ),
2850 'description' => esc_html__( 'Theme successfully activated', 'wdesignkit' ),
2851 'status' => 'active',
2852 'success' => true,
2853 );
2854 } else {
2855 $response = array(
2856 'message' => esc_html__( 'Theme Not Activated !', 'wdesignkit' ),
2857 'description' => $activate_result->get_error_message(),
2858 'status' => 'inactive',
2859 'success' => false,
2860 );
2861 }
2862 }
2863
2864 return $response;
2865 }
2866
2867 /**
2868 *
2869 * It is Use Update WDesignKit plugin latest version.
2870 *
2871 * @since 1.0.17
2872 */
2873 protected function wdkit_update_latest_plugin() {
2874
2875 return Wdkit_Depends_Installer::get_instance()->wdkit_update_plugin();
2876 }
2877
2878 /**
2879 *
2880 * It is Use for get plugin list.
2881 *
2882 * @since 1.0.0
2883 */
2884 private function get_plugins() {
2885 if ( ! function_exists( 'get_plugins' ) ) {
2886 require_once \ABSPATH . 'wp-admin/includes/plugin.php';
2887 }
2888
2889 return get_plugins();
2890 }
2891
2892 /**
2893 * Get Download Template Content
2894 *
2895 * @since 1.0.0
2896 */
2897 protected function wdkit_activate_container() {
2898
2899 $option_value = get_option( 'elementor_experiment-container', false );
2900
2901 if ( $option_value === false ) {
2902 add_option( 'elementor_experiment-container', 'active' );
2903 } else {
2904 update_option( 'elementor_experiment-container', 'active' );
2905 }
2906
2907 $result = array(
2908 'message' => esc_html__( 'Container Activated Successfully', 'wdesignkit' ),
2909 'description' => esc_html__( 'Elementor Container Activated Successfully.', 'wdesignkit' ),
2910 'success' => true,
2911 );
2912
2913 wp_send_json( $response );
2914 wp_die();
2915 }
2916
2917 /**
2918 * import category and tags for post
2919 *
2920 * @since 2.0.0
2921 */
2922 protected function wdkit_import_taxonomy() {
2923 $category = isset( $_POST['category'] ) ? json_decode( wp_unslash( $_POST['category'] ) ) : array();
2924 $tags = isset( $_POST['tags'] ) ? json_decode( wp_unslash( $_POST['tags'] ) ) : array();
2925
2926 $response = array(
2927 'success' => false,
2928 'categories' => array(),
2929 'tags' => array(),
2930 );
2931
2932 if ( ! empty( $category ) && count( $category ) > 0 ) {
2933 foreach ( $category as $category_name ) {
2934 $category_name = sanitize_text_field( $category_name );
2935
2936 $term_exists = term_exists( $category_name, 'category' );
2937 if ( ! $term_exists ) {
2938 $result = wp_insert_term( $category_name, 'category' );
2939 if ( ! is_wp_error( $result ) ) {
2940 $response['categories'][] = array(
2941 'name' => $category_name,
2942 'term_id' => $result['term_id'],
2943 );
2944 } else {
2945 $response['categories'][] = array(
2946 'name' => $category_name,
2947 'error' => $result->get_error_message(),
2948 );
2949 }
2950 } else {
2951 $term_id = is_array( $term_exists ) ? $term_exists['term_id'] : $term_exists;
2952 $response['categories'][] = array(
2953 'name' => $category_name,
2954 'term_id' => $term_id,
2955 );
2956 }
2957 }
2958
2959 $response['success'] = true;
2960 }
2961
2962 if ( ! empty( $tags ) && count( $tags ) > 0 ) {
2963 foreach ( $tags as $tags_name ) {
2964 $tags_name = sanitize_text_field( $tags_name );
2965
2966 $term_exists = term_exists( $tags_name, 'post_tag' );
2967 if ( ! $term_exists ) {
2968 $result = wp_insert_term( $tags_name, 'post_tag' );
2969 if ( ! is_wp_error( $result ) ) {
2970 $response['tags'][] = array(
2971 'name' => $tags_name,
2972 'term_id' => $result['term_id'],
2973 );
2974 } else {
2975 $response['tags'][] = array(
2976 'name' => $tags_name,
2977 'error' => $result->get_error_message(),
2978 );
2979 }
2980 } else {
2981 $term_id = is_array( $term_exists ) ? $term_exists['term_id'] : $term_exists;
2982 $response['tags'][] = array(
2983 'name' => $tags_name,
2984 'term_id' => $term_id,
2985 );
2986 }
2987 }
2988
2989 $response['success'] = true;
2990 }
2991
2992 wp_send_json( $response );
2993 wp_die();
2994 }
2995
2996 /**
2997 * Get Download Template Content
2998 *
2999 * @since 1.0.0
3000 */
3001 protected function wdkit_import_template() {
3002 $args = $this->wdkit_parse_args( $_POST );
3003 $api_type = isset( $_POST['api_type'] ) ? sanitize_text_field( wp_unslash( $_POST['api_type'] ) ) : 'import_template';
3004
3005 $response = '';
3006 if ( empty( $args['template_id'] ) ) {
3007 $result = array(
3008 'content' => '',
3009 'message' => esc_html__( 'Invalid import', 'wdesignkit' ),
3010 'description' => esc_html__( 'Invalid import: Check your details and try again.', 'wdesignkit' ),
3011 'success' => false,
3012 );
3013
3014 wp_send_json( $response );
3015 wp_die();
3016 }
3017
3018 $args['token'] = $this->wdkit_login_user_token( $args['email'] );
3019
3020 unset( $args['email'] );
3021 $args['unique_id'] = get_option( 'wdkit_unique_id' ) ?? '';
3022 $response = WDesignKit_Data_Query::get_data( $api_type, $args );
3023
3024 if ( is_wp_error( $response ) ) {
3025 wp_send_json( array(
3026 'success' => false,
3027 'message' => $response->get_error_message(),
3028 ) );
3029 wp_die();
3030 }
3031
3032 $custom_meta = isset( $_POST['custom_meta'] ) ? sanitize_text_field( wp_unslash( $_POST['custom_meta'] ) ) : false;
3033
3034 /** Custom meta Field */
3035 if ( ! empty( $custom_meta ) && 'true' === $custom_meta && ! empty( $response ) && ! empty( $response['content'] ) ) {
3036
3037 $res_content = json_decode( $response['content'], true );
3038 if ( isset( $res_content['custom_meta'] ) && ! empty( $res_content['custom_meta'] ) ) {
3039 $meta_data = $res_content['custom_meta'];
3040
3041 if ( ! empty( $meta_data ) ) {
3042 foreach ( $meta_data as $meta_key => $meta_val ) {
3043 if ( ! empty( $meta_val[0] ) && is_serialized( $meta_val[0] ) ) {
3044 $meta_val[0] = unserialize( $meta_val[0], array( 'allowed_classes' => false ) );
3045 }
3046
3047 if ( get_post_meta( get_the_ID(), $meta_key, true ) === '' ) {
3048 add_post_meta( get_the_ID(), $meta_key, $meta_val[0] );
3049 } else {
3050 update_post_meta( get_the_ID(), $meta_key, $meta_val[0] );
3051 }
3052 }
3053 }
3054 }
3055 }
3056
3057 wp_send_json( $response );
3058 wp_die();
3059 }
3060
3061 /**
3062 * This Function is Use For Media Import
3063 *
3064 * @since 1.0.0
3065 *
3066 * @param array $content store media content.
3067 * @param string $editor it is check editor.
3068 */
3069 /**
3070 * Resolve a local upload URL back to its attachment ID.
3071 *
3072 * Handles the "-scaled" copy WordPress makes for large originals and any
3073 * "-1920x1280" size suffix, both of which attachment_url_to_postid() misses because
3074 * they are not the value stored in _wp_attached_file.
3075 *
3076 * @since 2.6.2
3077 *
3078 * @param string $url Local upload URL.
3079 * @return int Attachment ID, or 0.
3080 */
3081 private static function wdkit_attachment_id_from_url( $url ) {
3082 static $cache = array();
3083
3084 if ( isset( $cache[ $url ] ) ) {
3085 return $cache[ $url ];
3086 }
3087
3088 $id = (int) attachment_url_to_postid( $url );
3089
3090 if ( ! $id ) {
3091 // Try the original file behind a -scaled or -WxH derivative.
3092 $stripped = preg_replace( '/-scaled(\.[a-z0-9]+)$/i', '$1', $url );
3093 $stripped = preg_replace( '/-\d+x\d+(\.[a-z0-9]+)$/i', '$1', (string) $stripped );
3094
3095 if ( $stripped && $stripped !== $url ) {
3096 $id = (int) attachment_url_to_postid( $stripped );
3097 }
3098 }
3099
3100 // Only remember hits. Page imports run concurrently, so an attachment created by a
3101 // sibling request may not exist yet when this is first asked — caching that miss
3102 // would keep every later control in this request pointing at nothing.
3103 if ( $id ) {
3104 $cache[ $url ] = $id;
3105 }
3106
3107 return $id;
3108 }
3109
3110 /**
3111 * Is this media reference still pointing off-site?
3112 *
3113 * Template content arrives holding the URLs of wherever the media lived before. Those
3114 * carry that site's attachment IDs, which have no meaning here - and can collide with
3115 * unrelated local posts.
3116 *
3117 * @since 2.6.2
3118 *
3119 * @param string $url URL from a media control.
3120 * @return bool True when the URL points at another site's uploads.
3121 */
3122 private static function wdkit_is_foreign_media_url( $url ) {
3123
3124 if ( ! class_exists( 'Wdkit_Image_Guard' ) ) {
3125 require_once WDKIT_INCLUDES . 'admin/class-wdkit-image-guard.php';
3126 }
3127
3128 $uploads = wp_get_upload_dir();
3129
3130 return Wdkit_Image_Guard::is_foreign_media( $url, isset( $uploads['baseurl'] ) ? $uploads['baseurl'] : '' );
3131 }
3132
3133 /**
3134 * Find - or make - the local attachment behind a source-site media URL.
3135 *
3136 * Elementor stamps every image it imports with `_elementor_source_image_hash`
3137 * (sha1 of the URL it came from), and its importer consults that before doing any
3138 * network work. Delegating here means a URL already imported at create time resolves
3139 * from the database, and one that never made it is fetched exactly once.
3140 *
3141 * Only ever called for foreign URLs. Handing it a local URL would re-download the
3142 * file and leave a duplicate, because the stored hash is of the *remote* URL and so
3143 * would never match.
3144 *
3145 * @since 2.6.2
3146 *
3147 * @param string $url Source-site media URL.
3148 * @param int $source_id The source site's attachment ID, used as Elementor's cache key.
3149 * @return array Local `id` and `url`, or an empty array when it cannot be resolved.
3150 */
3151 private static function wdkit_localise_media_url( $url, $source_id = 0 ) {
3152 static $cache = array();
3153
3154 if ( isset( $cache[ $url ] ) ) {
3155 return $cache[ $url ];
3156 }
3157
3158 if ( ! did_action( 'elementor/loaded' ) || ! class_exists( '\\Elementor\\Plugin' ) ) {
3159 return array();
3160 }
3161
3162 $images = \Elementor\Plugin::$instance->templates_manager->get_import_images_instance();
3163
3164 if ( ! $images ) {
3165 return array();
3166 }
3167
3168 // A download may happen, so keep the oversized-image guard in force.
3169 self::wdkit_guard_oversized_images();
3170
3171 $imported = $images->import(
3172 array(
3173 // Elementor only checks its hash table when an id is present.
3174 'id' => $source_id ? $source_id : 1,
3175 'url' => $url,
3176 )
3177 );
3178
3179 $local = ( ! empty( $imported['id'] ) && ! empty( $imported['url'] ) )
3180 ? array(
3181 'id' => (int) $imported['id'],
3182 'url' => $imported['url'],
3183 )
3184 : array();
3185
3186 // Remember hits only: a sibling request importing concurrently may simply not have
3187 // finished yet, and caching that miss would strand every later control on this page.
3188 if ( $local ) {
3189 $cache[ $url ] = $local;
3190 }
3191
3192 return $local;
3193 }
3194
3195 /**
3196 * Repair dangling attachment IDs across every page of a finished import.
3197 *
3198 * The create-time repair in wdkit_media_import() can only see attachments that already
3199 * exist. Pages import concurrently and share images — an icon first imported by one
3200 * page is referenced by several others — so a page that runs early legitimately cannot
3201 * resolve an image a sibling request has not created yet.
3202 *
3203 * This runs at the finalize step, once every page and attachment exists, and fixes
3204 * whatever the per-page pass had to leave behind.
3205 *
3206 * @since 2.6.2
3207 *
3208 * @param array $page_ids Imported post IDs.
3209 * @return int Number of pages actually rewritten.
3210 */
3211 private function wdkit_sweep_attachment_ids( $page_ids ) {
3212
3213 if ( empty( $page_ids ) || ! did_action( 'elementor/loaded' ) ) {
3214 return 0;
3215 }
3216
3217 $fixed = 0;
3218 $ids = array_unique( array_map( 'intval', $page_ids ) );
3219
3220 // Primes the meta cache for the whole batch in one query, so the
3221 // get_post_meta() call below hits the cache instead of issuing one query
3222 // per imported page.
3223 update_meta_cache( 'post', $ids );
3224
3225 foreach ( $ids as $post_id ) {
3226
3227 if ( ! $post_id ) {
3228 continue;
3229 }
3230
3231 $raw = get_post_meta( $post_id, '_elementor_data', true );
3232
3233 if ( empty( $raw ) ) {
3234 continue;
3235 }
3236
3237 $data = is_array( $raw ) ? $raw : json_decode( $raw, true );
3238
3239 if ( ! is_array( $data ) ) {
3240 continue;
3241 }
3242
3243 $repaired = self::wdkit_repair_attachment_ids( $data );
3244
3245 if ( wp_json_encode( $repaired ) === wp_json_encode( $data ) ) {
3246 continue;
3247 }
3248
3249 // Save through the document API so Elementor regenerates the page CSS — the
3250 // background-image rules are only emitted once the IDs resolve.
3251 $document = \Elementor\Plugin::$instance->documents->get( $post_id );
3252
3253 // Count only a save that actually happened. Document::save() returns false
3254 // without saving when the current user cannot edit the post, and reporting
3255 // those as repaired hides the fact that nothing changed.
3256 if ( $document && $document->save( array( 'elements' => $repaired ) ) ) {
3257 ++$fixed;
3258 }
3259 }
3260
3261 if ( $fixed ) {
3262 \Elementor\Plugin::$instance->files_manager->clear_cache();
3263 }
3264
3265 return $fixed;
3266 }
3267
3268 /**
3269 * Repair media controls whose attachment ID does not resolve.
3270 *
3271 * Elementor media controls store `{ url, id }`. Controls flagged `has_sizes` — the
3272 * container/section **background image** among them — do not render from `url` at all:
3273 * CSS generation resolves the image through the attachment ID, so a dangling ID
3274 * produces no `background-image` rule and the section renders with no image even
3275 * though its URL is perfectly correct.
3276 *
3277 * IDs arrive dangling whenever Elementor's own importer does not rewrite a control —
3278 * it carries the source site's ID, which means nothing locally. Now that the URL is
3279 * already a local upload before import, the ID can simply be looked up from it.
3280 *
3281 * @since 2.6.2
3282 *
3283 * @param mixed $node Elementor data, walked recursively.
3284 * @return mixed Data with resolvable attachment IDs.
3285 */
3286 private static function wdkit_repair_attachment_ids( $node ) {
3287
3288 if ( ! is_array( $node ) ) {
3289 return $node;
3290 }
3291
3292 // A media control value: has a url, and an id slot to correct.
3293 if ( isset( $node['url'] ) && is_string( $node['url'] ) && array_key_exists( 'id', $node ) ) {
3294
3295 $current = (int) $node['id'];
3296 $is_live = $current && 'attachment' === get_post_type( $current );
3297
3298 if ( self::wdkit_is_foreign_media_url( $node['url'] ) ) {
3299 // Still pointing at the source site. Ask Elementor for the local copy: its
3300 // _elementor_source_image_hash lookup returns the attachment the create-time
3301 // import already made, so this normally costs a single query and no download.
3302 $local = self::wdkit_localise_media_url( $node['url'], $current );
3303
3304 if ( ! empty( $local['id'] ) && ! empty( $local['url'] ) ) {
3305 $node['id'] = $local['id'];
3306 $node['url'] = $local['url'];
3307 }
3308 } elseif ( ! $is_live && false !== strpos( $node['url'], '/wp-content/uploads/' ) ) {
3309 $resolved = self::wdkit_attachment_id_from_url( $node['url'] );
3310
3311 if ( $resolved ) {
3312 $node['id'] = $resolved;
3313 }
3314 }
3315 }
3316
3317 foreach ( $node as $key => $value ) {
3318 if ( is_array( $value ) ) {
3319 $node[ $key ] = self::wdkit_repair_attachment_ids( $value );
3320 }
3321 }
3322
3323 return $node;
3324 }
3325
3326 public function wdkit_media_import( $content = array(), $editor = '' ) {
3327
3328 if ( empty( $content ) && empty( $editor ) ) {
3329 $args = $this->wdkit_parse_args( $_POST );
3330 $content = ! empty( $args['content'] ) ? json_decode( $args['content'], true ) : array();
3331 } else {
3332 $args = array(
3333 'content' => $content,
3334 'editor' => $editor,
3335 );
3336 $content = ! empty( $args['content'] ) ? $args['content'] : array();
3337
3338 if ( 'elementor' === $args['editor'] ) {
3339 $content = json_decode( $content, true );
3340 }
3341 }
3342
3343 if ( ! class_exists( 'Wdkit_Import_Images' ) ) {
3344 require_once WDKIT_INCLUDES . 'admin/class-wdkit-import-images.php';
3345 }
3346
3347
3348 if ( ! empty( $args['editor'] ) && 'gutenberg' === $args['editor'] && ! empty( $content ) ) {
3349 $media_import = array( $content );
3350 $media_import = self::blocks_import_media_copy_content( $media_import );
3351 $content = $media_import[0];
3352 } elseif ( ! empty( $args['editor'] ) && 'elementor' === $args['editor'] && ! empty( $content ) ) {
3353 $media_import = array( $content );
3354 $media_import = self::widgets_elements_id_change( $media_import );
3355 $media_import = self::widgets_import_media_copy_content( $media_import );
3356 $content = $media_import[0];
3357
3358 // Last: point any control Elementor left holding a foreign attachment ID at the
3359 // local attachment its URL already refers to. Without this, has_sizes controls
3360 // such as container background images resolve to nothing and render empty.
3361 $content = self::wdkit_repair_attachment_ids( $content );
3362 }
3363
3364 return $content;
3365 }
3366
3367 /**
3368 * Widgets elements data
3369 *
3370 * @since 1.0.0
3371 * @param string $media_import it is store media data.
3372 */
3373 protected static function widgets_elements_id_change( $media_import ) {
3374 if ( did_action( 'elementor/loaded' ) ) {
3375 return \Elementor\Plugin::instance()->db->iterate_data(
3376 $media_import,
3377 function ( $element ) {
3378 $element['id'] = \Elementor\Utils::generate_random_string();
3379 return $element;
3380 }
3381 );
3382 } else {
3383 return $media_import;
3384 }
3385 }
3386
3387 /**
3388 * Widgets Media import copy content.
3389 *
3390 * @since 1.0.0
3391 *
3392 * @param string $media_import it is store media data.
3393 */
3394 protected static function widgets_import_media_copy_content( $media_import ) {
3395 if ( did_action( 'elementor/loaded' ) ) {
3396
3397 return \Elementor\Plugin::instance()->db->iterate_data(
3398 $media_import,
3399 function ( $element_data ) {
3400 $elements = \Elementor\Plugin::instance()->elements_manager->create_element_instance( $element_data );
3401
3402 if ( ! $elements ) {
3403 return null;
3404 }
3405
3406 return self::widgets_element_import_start( $elements );
3407 }
3408 );
3409 } else {
3410 return $media_import;
3411 }
3412 }
3413
3414 /**
3415 * Start element copy content for media import.
3416 *
3417 * @since 1.0.0
3418 *
3419 * @param string \Elementor\Controls_Stack $element it is store elementor data.
3420 */
3421 protected static function widgets_element_import_start( \Elementor\Controls_Stack $element ) {
3422 $get_element_instance = $element->get_data();
3423 $tp_mi_on_fun = 'on_import';
3424
3425 if ( method_exists( $element, $tp_mi_on_fun ) ) {
3426 $get_element_instance = $element->{$tp_mi_on_fun}( $get_element_instance );
3427 }
3428
3429 foreach ( $element->get_controls() as $get_control ) {
3430 $control_type = \Elementor\Plugin::instance()->controls_manager->get_control( $get_control['type'] );
3431 $control_name = $get_control['name'];
3432
3433 if ( ! $control_type ) {
3434 // Skip just this control. Returning here would abandon every control after
3435 // it, so a single unregistered type - routine when a kit uses an addon that
3436 // is not fully active yet - would silently leave the rest of the element's
3437 // media pointing at the source site.
3438 continue;
3439 }
3440
3441 if ( method_exists( $control_type, $tp_mi_on_fun ) ) {
3442 $get_element_instance['settings'][ $control_name ] = $control_type->{$tp_mi_on_fun}( $element->get_settings( $control_name ), $get_control );
3443 }
3444 }
3445
3446 return $get_element_instance;
3447 }
3448
3449 /**
3450 * Blocks Recursively data
3451 *
3452 * @param string $data_import gutenber data import.
3453 */
3454 public static function blocks_import_media_copy_content( $data_import ) {
3455 if ( ! empty( $data_import ) ) {
3456 foreach ( $data_import[0] as $key => $val ) {
3457 if ( array_key_exists( 'blockName', $val ) && ( empty( $val['blockName'] ) || null === $val['blockName'] || empty( $val['blockName'] ) || ' ' === $val['blockName'] ) ) {
3458 unset( $data_import[0][ $key ] );
3459 }
3460 }
3461 }
3462
3463 return self::blocks_array_recursively_data(
3464 $data_import,
3465 function ( $block_data ) {
3466 $elements = self::blocks_data_instance( $block_data );
3467 return $elements;
3468 }
3469 );
3470 }
3471
3472 /**
3473 * Blocks Recursively data
3474 *
3475 * @param array $data store data.
3476 * @param string $callback store data.
3477 * @param string $args store data.
3478 */
3479 public static function blocks_array_recursively_data( $data, $callback, $args = array() ) {
3480 if ( ( isset( $data['name'] ) && ! empty( $data['name'] ) ) || ( isset( $data['blockName'] ) && ! empty( $data['blockName'] ) ) ) {
3481 if ( ! empty( $data['innerBlocks'] ) ) {
3482 $data['innerBlocks'] = self::blocks_array_recursively_data( $data['innerBlocks'], $callback, $args );
3483 }
3484
3485 return call_user_func( $callback, $data, $args );
3486 }
3487
3488 if ( ! empty( $data ) ) {
3489 $data = (array) $data;
3490 foreach ( $data as $block_key => $block_value ) {
3491 $block_data = self::blocks_array_recursively_data( $data[ $block_key ], $callback, $args );
3492
3493 if ( null === $block_data ) {
3494 continue;
3495 }
3496
3497 $data[ $block_key ] = $block_data;
3498 }
3499 }
3500
3501 return $data;
3502 }
3503
3504 /**
3505 * Check Blocks data media Url
3506 *
3507 * @param array $block_data store data.
3508 * @param array $args store data.
3509 * @param array $block_args store data.
3510 */
3511 public static function blocks_data_instance( array $block_data, array $args = array(), $block_args = null ) {
3512
3513 if ( ( isset( $block_data['name'] ) && isset( $block_data['clientId'] ) && isset( $block_data['attributes'] ) ) || ( isset( $block_data['blockName'] ) && isset( $block_data['attrs'] ) && ! empty( $block_data['attrs'] ) ) ) {
3514 $blocks_attr = isset( $block_data['attributes'] ) ? $block_data['attributes'] : ( isset( $block_data['attrs'] ) ? $block_data['attrs'] : array() );
3515 $blocks_attr = self::wdkit_import_block_media( $blocks_attr );
3516 if ( isset( $block_data['attributes'] ) ) {
3517 $block_data['attributes'] = $blocks_attr;
3518 } elseif ( isset( $block_data['attrs'] ) ) {
3519 $block_data['attrs'] = $blocks_attr;
3520 }
3521
3522 $block_data = self::wdkit_relink_block_markup( $block_data );
3523 }
3524
3525 return $block_data;
3526 }
3527
3528 /**
3529 * Run block markup through the media import, the way the create path does.
3530 *
3531 * Used wherever block content is written from the browser: media import, then the Nexter
3532 * block processor so each block's rendered copy matches its attributes, then serialise.
3533 *
3534 * @since 2.6.2
3535 *
3536 * @param string $content Block markup.
3537 * @return string Block markup with local media.
3538 */
3539 private function wdkit_relink_gutenberg_content( $content ) {
3540
3541 if ( ! is_string( $content ) || false === strpos( $content, '<!-- wp:' ) ) {
3542 return $content;
3543 }
3544
3545 // wdkit_media_import() loads this itself, but it is referenced before that below.
3546 if ( ! class_exists( 'Wdkit_Import_Images' ) ) {
3547 require_once WDKIT_INCLUDES . 'admin/class-wdkit-import-images.php';
3548 }
3549
3550 // Thumbnail generation decodes each image, so keep the oversized-image guard in force.
3551 self::wdkit_guard_oversized_images();
3552
3553
3554 // Block attributes are JSON inside the block delimiters, so they only survive a parse
3555 // when the string carries exactly one level of escaping. Arrive with an extra level and
3556 // parse_blocks() reads no attributes at all - serialising that back out writes every
3557 // block bare, throwing away titles, body text, icons and styling.
3558 $parsable = self::wdkit_parsable_block_content( $content );
3559
3560 if ( null === $parsable ) {
3561
3562 return $content;
3563 }
3564
3565 $blocks = parse_blocks( $parsable );
3566 $blocks = $this->wdkit_media_import( $blocks, 'gutenberg' );
3567
3568 if ( empty( $blocks ) || ! is_array( $blocks ) ) {
3569 return $content;
3570 }
3571
3572 if ( class_exists( 'WDKIT_Nexter_Block_Processor' ) ) {
3573 $processor = new WDKIT_Nexter_Block_Processor();
3574 $blocks = $processor->run( $blocks );
3575 }
3576
3577 $serialised = serialize_blocks( $blocks );
3578
3579 // Last line of defence. This function exists to repoint media, so a result carrying
3580 // fewer block attributes than it started with is a broken round trip, not a rewrite.
3581 // Leaving the media wrong is recoverable; saving gutted content is not.
3582 $before = self::wdkit_block_attr_count( $parsable );
3583 $after = self::wdkit_block_attr_count( $serialised );
3584
3585 if ( $after < $before ) {
3586
3587 return $content;
3588 }
3589
3590 // Never hand back nothing: an empty result would blank the page.
3591 return ! empty( $serialised ) ? $serialised : $content;
3592 }
3593
3594 /**
3595 * Rebuild the block stylesheet for a page whose content we just rewrote.
3596 *
3597 * The addon keeps each block's styling in a generated per-page stylesheet, and every rule
3598 * is keyed to the block id it was written for. That file is produced when the page is
3599 * saved through the editor - not by wp_update_post() from an AJAX handler - so rewriting
3600 * content here leaves the page pointing at a stylesheet built for the previous markup.
3601 * Blocks whose ids are not in that file get no rules at all and render unstyled.
3602 *
3603 * @since 2.6.2
3604 *
3605 * @param int $post_id Page whose content changed.
3606 * @return bool True when a rebuild was triggered.
3607 */
3608 private static function wdkit_rebuild_block_css( $post_id ) {
3609
3610 if ( ! $post_id ) {
3611 return false;
3612 }
3613
3614 foreach ( get_declared_classes() as $class ) {
3615 if ( ! method_exists( $class, 'make_block_css_by_post_id' ) ) {
3616 continue;
3617 }
3618
3619 try {
3620 if ( method_exists( $class, 'instance' ) ) {
3621 $instance = $class::instance();
3622 } elseif ( method_exists( $class, 'get_instance' ) ) {
3623 $instance = $class::get_instance();
3624 } else {
3625 $instance = new $class();
3626 }
3627
3628 $instance->make_block_css_by_post_id( $post_id );
3629
3630
3631 return true;
3632 } catch ( \Throwable $e ) {
3633 // Styling is best-effort: a failure here must not fail the import.
3634
3635 return false;
3636 }
3637 }
3638
3639 return false;
3640 }
3641
3642 /**
3643 * How many block attributes does this markup actually yield when parsed?
3644 *
3645 * Used as a before/after measure: block attributes are the part of block markup a round
3646 * trip can silently drop, so counting them is how we tell a rewrite from a mangling.
3647 *
3648 * @since 2.6.2
3649 *
3650 * @param string $content Block markup.
3651 * @return int Total attributes across every block.
3652 */
3653 private static function wdkit_block_attr_count( $content ) {
3654 $total = 0;
3655
3656 $walk = function ( $blocks ) use ( &$walk, &$total ) {
3657 foreach ( $blocks as $block ) {
3658 if ( ! empty( $block['attrs'] ) && is_array( $block['attrs'] ) ) {
3659 $total += count( $block['attrs'] );
3660 }
3661
3662 if ( ! empty( $block['innerBlocks'] ) ) {
3663 $walk( $block['innerBlocks'] );
3664 }
3665 }
3666 };
3667
3668 $walk( parse_blocks( (string) $content ) );
3669
3670 return $total;
3671 }
3672
3673 /**
3674 * Return this content in a form whose block attributes actually parse.
3675 *
3676 * Content written straight to post_content never had to parse, so an extra level of
3677 * escaping on the way in did no harm. Parsing it - which repointing media requires - makes
3678 * that escaping fatal: `{\"Title\":\"…\"}` is not JSON, so every attribute is discarded.
3679 *
3680 * Rather than assume a slash depth, this measures: if stripping one level yields more
3681 * attributes, the content was over-escaped and the stripped form is the real one.
3682 *
3683 * @since 2.6.2
3684 *
3685 * @param string $content Block markup as received.
3686 * @return string|null Markup safe to parse, or null when no form of it parses.
3687 */
3688 private static function wdkit_parsable_block_content( $content ) {
3689
3690 $as_is = self::wdkit_block_attr_count( $content );
3691
3692 // Nothing claims to carry attributes, so there is nothing to lose either.
3693 if ( false === strpos( $content, '{' ) ) {
3694 return $content;
3695 }
3696
3697 $stripped = wp_unslash( $content );
3698 $stripped_attrs = self::wdkit_block_attr_count( $stripped );
3699
3700 if ( $stripped_attrs > $as_is ) {
3701 return $stripped;
3702 }
3703
3704 if ( $as_is > 0 ) {
3705 return $content;
3706 }
3707
3708 // Neither form parses into attributes even though the markup contains JSON: better to
3709 // leave the content exactly as it arrived than to rewrite it into something bare.
3710 return null;
3711 }
3712
3713 /**
3714 * Point a block's saved markup at the media that was just localised.
3715 *
3716 * A block stores a rendered copy of itself in `innerHTML` / `innerContent`, and for many
3717 * blocks that copy is what the front end actually outputs. Importing the attributes alone
3718 * therefore fixes the editor while leaving the page still loading from the site the
3719 * template came from - and those hosts answer 403, so the image renders broken.
3720 *
3721 * @since 2.6.2
3722 *
3723 * @param array $block_data One parsed block.
3724 * @return array The block with its markup repointed.
3725 */
3726 private static function wdkit_relink_block_markup( $block_data ) {
3727
3728 $map = Wdkit_Import_Images::get_url_map();
3729
3730 if ( empty( $map ) ) {
3731 return $block_data;
3732 }
3733
3734 $from = array_keys( $map );
3735 $to = array_values( $map );
3736
3737 if ( ! empty( $block_data['innerHTML'] ) && is_string( $block_data['innerHTML'] ) ) {
3738 $block_data['innerHTML'] = str_replace( $from, $to, $block_data['innerHTML'] );
3739 }
3740
3741 if ( ! empty( $block_data['innerContent'] ) && is_array( $block_data['innerContent'] ) ) {
3742 foreach ( $block_data['innerContent'] as $index => $chunk ) {
3743 if ( is_string( $chunk ) ) {
3744 $block_data['innerContent'][ $index ] = str_replace( $from, $to, $chunk );
3745 }
3746 }
3747 }
3748
3749 return $block_data;
3750 }
3751
3752 /**
3753 * Import every media reference held in a block's attributes.
3754 *
3755 * Block attributes nest arbitrarily - a repeater of cards each with an image, responsive
3756 * variants, nested inner settings - so this recurses rather than reaching a fixed number
3757 * of levels down. The previous version was unrolled exactly four levels deep and also
3758 * skipped any subtree carrying an `md` key, which meant anything below that simply kept
3759 * the source site's URL and attachment ID and rendered as an empty placeholder.
3760 *
3761 * A node counts as media when it has a non-empty string `url` and either an id slot or a
3762 * URL that names an image file. That pairing is what distinguishes a media control from
3763 * a link, which also carries a `url`.
3764 *
3765 * @since 2.6.2
3766 *
3767 * @param mixed $node Block attributes, walked recursively.
3768 * @return mixed Attributes with local media.
3769 */
3770 private static function wdkit_import_block_media( $node ) {
3771
3772 if ( ! is_array( $node ) ) {
3773 return $node;
3774 }
3775
3776 $url = isset( $node['url'] ) && is_string( $node['url'] ) ? $node['url'] : '';
3777
3778 if ( '' !== $url
3779 && ( array_key_exists( 'id', $node ) || array_key_exists( 'Id', $node )
3780 || preg_match( '/\.(?:jpe?g|png|gif|svg|webp|avif|bmp)$/i', (string) wp_parse_url( $url, PHP_URL_PATH ) ) )
3781 ) {
3782 $imported = Wdkit_Import_Images::wdkit_Import_media( $node );
3783
3784 // Only accept a real result. The importer returns the node untouched when it
3785 // cannot localise the file, and anything falsy here would wipe out the URL and
3786 // leave the block with no image at all.
3787 if ( ! empty( $imported['url'] ) ) {
3788 $node = array_merge( $node, $imported );
3789 }
3790 }
3791
3792 // Keep walking even after importing this node. A media value carries its own `sizes`
3793 // map of per-size URLs, and returning here left every one of those pointing at the
3794 // site the template came from - which is what the widgets actually render from.
3795 foreach ( $node as $key => $value ) {
3796 if ( is_array( $value ) ) {
3797 $node[ $key ] = self::wdkit_import_block_media( $value );
3798 }
3799 }
3800
3801 return $node;
3802 }
3803
3804 /**
3805 * Kit Template Import Pages/Sections
3806 *
3807 * @since 1.0.0
3808 * */
3809 protected function wdkit_import_kit_template() {
3810
3811 if ( ! current_user_can( 'manage_options' ) ) {
3812 return false;
3813 }
3814
3815 $builder = isset( $_POST['builder'] ) ? sanitize_text_field( wp_unslash( $_POST['builder'] ) ) : '';
3816
3817 $page_section = ! empty( $_POST['page_section'] ) ? sanitize_text_field( wp_unslash( $_POST['page_section'] ) ) : '';
3818
3819 if ( isset( $page_section ) ) {
3820 $args['page_section'] = ! empty( $page_section ) ? sanitize_text_field( wp_unslash( $page_section ) ) : '';
3821 }
3822
3823 $template_ids = ! empty( $_POST['template_ids'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['template_ids'] ) ), true ) : array();
3824 $email = ! empty( $_POST['email'] ) ? strtolower( sanitize_email( wp_unslash( $_POST['email'] ) ) ) : '';
3825 $editor = isset( $_POST['editor'] ) ? sanitize_text_field( wp_unslash( $_POST['editor'] ) ) : '';
3826 $website_kit = isset( $_POST['website_kit'] ) ? sanitize_text_field( wp_unslash( $_POST['website_kit'] ) ) : '';
3827 $api_type = isset( $_POST['api_type'] ) ? sanitize_text_field( wp_unslash( $_POST['api_type'] ) ) : 'import_template';
3828 $ai_compitible = isset( $_POST['ai_compitible'] ) ? sanitize_text_field( wp_unslash( $_POST['ai_compitible'] ) ) : false;
3829
3830 if ( empty( $template_ids ) ) {
3831 $output = array(
3832 'message' => esc_html__( 'Invalid import', 'wdesignkit' ),
3833 'description' => esc_html__( 'Invalid import: Check your details and try again.', 'wdesignkit' ),
3834 'success' => false,
3835 );
3836
3837 wp_send_json( $output );
3838 wp_die();
3839 }
3840
3841 /**Not Usefull*/
3842 if ( isset( $_POST['select'] ) ) {
3843 $args['post_type'] = ! empty( $_POST['select'] ) ? sanitize_text_field( wp_unslash( $_POST['select'] ) ) : '';
3844 }
3845
3846 $args['custom_meta'] = isset( $_POST['custom_meta'] ) ? sanitize_text_field( wp_unslash( $_POST['custom_meta'] ) ) : false;
3847 $args['editor'] = $editor;
3848
3849 $token = $this->wdkit_login_user_token( $email );
3850
3851 $temp_args = array(
3852 'token' => $token,
3853 'template_id' => $template_ids['id'],
3854 'editor' => $editor,
3855 'website_kit' => $website_kit,
3856 'unique_id' => get_option( 'wdkit_unique_id' ) ?? '',
3857 );
3858
3859 $response = WDesignKit_Data_Query::get_data( $api_type, $temp_args );
3860 $output = array();
3861
3862 if ( is_wp_error( $response ) ) {
3863
3864 wp_send_json( $response );
3865 wp_die();
3866 }
3867
3868 if ( isset( $response['content'] ) && 'error' === $response['content'] ) {
3869 wp_send_json( $response );
3870 wp_die();
3871 }
3872
3873 $result = array(
3874 'response' => $response,
3875 'args' => $args,
3876 'id' => $template_ids['id'],
3877 'temp_data' => $template_ids,
3878 );
3879
3880 $output['message'] = $response['message'];
3881 $output['description'] = $response['description'];
3882 $output['data'] = $result;
3883 $output['success'] = $response['success'];
3884
3885 wp_send_json( $output );
3886 wp_die();
3887 }
3888
3889 public function wdkit_enable_template_widgets() {
3890 $widget_list = ! empty( $_POST['widget_list'] ) ? json_decode( wp_unslash( $_POST['widget_list'] ), true ) : array();
3891 $extensions_list = ! empty( $_POST['extensions_list'] ) ? json_decode( wp_unslash( $_POST['extensions_list'] ), true ) : array();
3892
3893 if ( empty( $widget_list ) && empty( $extensions_list ) ) {
3894 $res = array(
3895 'massage' => __( 'Widget array not found', 'wdesignkit' ),
3896 'description' => __( 'Widget array not found', 'wdesignkit' ),
3897 'success' => false,
3898 );
3899 wp_send_json( $res );
3900 wp_die();
3901 }
3902
3903 if ( ! has_filter( 'tpae_enable_selected_widgets' ) ) {
3904 $res = array(
3905 'massage' => __( 'Relevant Plugin not Activated', 'wdesignkit' ),
3906 'description' => __( 'Relevant Plugin not Installed / Activated', 'wdesignkit' ),
3907 'success' => false,
3908 );
3909 wp_send_json( $res );
3910 wp_die();
3911 }
3912
3913 $w_list = array(
3914 'widgets' => $widget_list,
3915 'extensions' => $extensions_list,
3916 );
3917
3918 $result = apply_filters( 'tpae_enable_selected_widgets', $w_list );
3919
3920 if ( ! empty( $result['success'] ) ) {
3921 $res = array(
3922 'massage' => __( 'Enabled widgets successfully', 'wdesignkit' ),
3923 'description' => __( 'Used widgets have been enabled successfully', 'wdesignkit' ),
3924 'success' => true,
3925 );
3926 } else {
3927
3928 $message = isset( $result['message'] ) ? $result['message'] : __( 'Failed to enable widgets', 'wdesignkit' );
3929 $description = isset( $result['description'] ) ? $result['description'] : __( 'Failed to enable widgets', 'wdesignkit' );
3930
3931 $res = array(
3932 'massage' => $message,
3933 'description' => $description,
3934 'success' => false,
3935 );
3936 }
3937
3938 wp_send_json( $res );
3939 wp_die();
3940 }
3941
3942 /**
3943 * Import single template and section from plugin only
3944 * */
3945 protected function wdkit_import_multi_template() {
3946 $args = $this->wdkit_parse_args( $_POST );
3947 $api_type = isset( $_POST['api_type'] ) ? sanitize_text_field( wp_unslash( $_POST['api_type'] ) ) : 'import_template';
3948
3949 if ( ! current_user_can( 'manage_options' ) ) {
3950 return false;
3951 }
3952
3953 if ( empty( $_POST['template_ids'] ) ) {
3954 $output = array(
3955 'data' => array(),
3956 'message' => esc_html__( 'Invalid import', 'wdesignkit' ),
3957 'description' => esc_html__( 'Invalid import: Check your details and try again.', 'wdesignkit' ),
3958 'success' => false,
3959 );
3960
3961 wp_send_json( $output );
3962 wp_die();
3963 }
3964
3965 if ( isset( $_POST['template_ids'] ) ) {
3966 $args['template_ids'] = ! empty( $_POST['template_ids'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['template_ids'] ) ), true ) : array();
3967 }
3968
3969 if ( isset( $_POST['page_section'] ) ) {
3970 $args['page_section'] = ! empty( $_POST['page_section'] ) ? sanitize_text_field( wp_unslash( $_POST['page_section'] ) ) : '';
3971 }
3972
3973 if ( isset( $_POST['select'] ) ) {
3974 $args['post_type'] = ! empty( $_POST['select'] ) ? sanitize_text_field( wp_unslash( $_POST['select'] ) ) : '';
3975 }
3976
3977 $args['custom_meta'] = isset( $_POST['custom_meta'] ) ? sanitize_text_field( wp_unslash( $_POST['custom_meta'] ) ) : false;
3978
3979 if ( ! empty( $args['template_ids'] ) && ! empty( $args['page_section'] ) ) {
3980 $output = array();
3981 if ( ! empty( $args['template_ids']['id'] ) ) {
3982 $token = $this->wdkit_login_user_token( $args['email'] );
3983
3984 $temp_args = array(
3985 'token' => $token,
3986 'template_id' => $args['template_ids']['id'],
3987 'editor' => $args['editor'],
3988 'unique_id' => get_option( 'wdkit_unique_id' ) ?? '',
3989 );
3990
3991 $response = WDesignKit_Data_Query::get_data( $api_type, $temp_args );
3992
3993 if ( is_wp_error( $response ) ) {
3994 wp_send_json( array(
3995 'success' => false,
3996 'message' => $response->get_error_message(),
3997 ) );
3998 wp_die();
3999 }
4000
4001 if ( isset( $response['content'] ) && 'error' === $response['content'] ) {
4002 wp_send_json( $response );
4003 wp_die();
4004 }
4005
4006 $result = array(
4007 'response' => $response,
4008 'args' => $args,
4009 'id' => $args['template_ids'],
4010 'value' => $args['template_ids'],
4011 );
4012
4013 $output['message'] = $response['message'];
4014 $output['description'] = $response['description'];
4015 $output['data'] = $result;
4016 $output['success'] = true;
4017
4018 }
4019
4020 wp_send_json( $output );
4021 wp_die();
4022 }
4023 }
4024
4025 /**
4026 * It is Use for remove selected category from content.
4027 *
4028 * @since 2.0.5
4029 */
4030 public function wdkit_content_remover( &$data ) {
4031
4032 if ( is_array( $data ) ) {
4033
4034 foreach ( $data as $key => &$value ) {
4035 if ( $key === 'post_category' ) {
4036 $data[ $key ] = array();
4037 } else if ($key === 'include_products'){
4038 $data[ $key ] = "";
4039 } else {
4040 $this->wdkit_content_remover( $value );
4041 }
4042 }
4043 } elseif ( is_object( $data ) ) {
4044
4045 foreach ( $data as $key => &$value ) {
4046 if ( $key === 'post_category' ) {
4047 $data->$key = array();
4048 } else if ($key === 'include_products'){
4049 $data->$key = "";
4050 } else {
4051 $this->wdkit_content_remover( $value );
4052 }
4053 }
4054 }
4055
4056 return $data;
4057 }
4058
4059 protected function wkit_update_elementor_template(){
4060
4061 if ( isset( $_POST['data'] ) ) {
4062 $content = ! empty( $_POST['data'] ) ? json_decode( wp_unslash( $_POST['data'] ), true ) : '';
4063 }
4064
4065 if ( isset( $_POST['template_id'] ) ) {
4066 $template_id = ! empty( $_POST['template_id'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['template_id'] ), true ) ) : '';
4067 }
4068
4069 $document = \Elementor\Plugin::$instance->documents->get($template_id);
4070
4071 // This saves content posted straight from the browser, which carries local image
4072 // URLs but still the source template's attachment IDs. Without repairing them the
4073 // save undoes what wdkit_media_import() fixed on create, and has_sizes controls —
4074 // container background images especially — resolve to nothing and render empty.
4075 $content = self::wdkit_repair_attachment_ids( $content );
4076
4077 $document->save([
4078 'elements' => $content
4079 ]);
4080 }
4081
4082 /**
4083 * Update the content of an already-created page.
4084 *
4085 * Used by the async ("Site Ready first") import path: pages are created up front with
4086 * their un-rewritten template content, then this writes the AI-rewritten content into
4087 * each page in the background. Elementor saves via the document API (same as
4088 * wkit_update_elementor_template); Gutenberg writes post_content directly.
4089 *
4090 * @since 2.6.2
4091 */
4092 protected function wdkit_update_page_content() {
4093 $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0;
4094 $builder = isset( $_POST['builder'] ) ? sanitize_text_field( wp_unslash( $_POST['builder'] ) ) : '';
4095
4096 if ( ! $post_id || ! current_user_can( 'edit_post', $post_id ) ) {
4097 return array(
4098 'success' => false,
4099 'message' => esc_html__( 'Invalid page or insufficient permission', 'wdesignkit' ),
4100 );
4101 }
4102
4103 if ( 'gutenberg' === $builder ) {
4104 // Do NOT run kses here: Gutenberg block delimiters are HTML comments
4105 // (<!-- wp:... -->) which kses strips. Mirror the create path, which stores
4106 // the block markup slashed and unfiltered (endpoint is manage_options-gated
4107 // and the content is plugin-generated).
4108 $content = isset( $_POST['content'] ) ? wp_unslash( $_POST['content'] ) : '';
4109
4110 // This content comes straight from the browser and still carries the template
4111 // site's media URLs and attachment IDs, so it has to go through the same pipeline
4112 // the create path uses. Without this the save simply undid the import: the files
4113 // were fetched, then overwritten by a copy still pointing at the source site.
4114 //
4115 // Re-running is cheap. Every URL already handled resolves from the source-hash
4116 // lookup, and media that is already local resolves straight from its URL, so no
4117 // image is fetched or stored twice.
4118 $content = $this->wdkit_relink_gutenberg_content( $content );
4119
4120 $result = wp_update_post(
4121 array(
4122 'ID' => $post_id,
4123 'post_content' => wp_slash( $content ),
4124 ),
4125 true
4126 );
4127
4128 if ( is_wp_error( $result ) ) {
4129 return array(
4130 'success' => false,
4131 'message' => $result->get_error_message(),
4132 );
4133 }
4134
4135 self::wdkit_rebuild_block_css( $post_id );
4136 } else {
4137 $elements = isset( $_POST['content'] ) ? json_decode( wp_unslash( $_POST['content'] ), true ) : array();
4138
4139 if ( ! class_exists( '\\Elementor\\Plugin' ) ) {
4140 return array(
4141 'success' => false,
4142 'message' => esc_html__( 'Elementor not available', 'wdesignkit' ),
4143 );
4144 }
4145
4146 $document = \Elementor\Plugin::$instance->documents->get( $post_id );
4147 if ( ! $document ) {
4148 return array(
4149 'success' => false,
4150 'message' => esc_html__( 'Elementor document not found', 'wdesignkit' ),
4151 );
4152 }
4153
4154 // Same as wkit_update_elementor_template(): browser-posted content keeps the
4155 // source template's attachment IDs, so repair them or this save undoes the
4156 // create-time fix and background images stop rendering.
4157 $elements = self::wdkit_repair_attachment_ids( $elements );
4158
4159 $document->save( array( 'elements' => $elements ) );
4160 }
4161
4162 return array(
4163 'success' => true,
4164 'message' => esc_html__( 'Page content updated', 'wdesignkit' ),
4165 );
4166 }
4167
4168 /**
4169 * Import single template and section from plugin only
4170 *
4171 * @param array $args store data.
4172 * @param array $template_id store data.
4173 * @param array $data store data.
4174 * @param array $temp_data store data.
4175 * */
4176 protected function import_page_section_content() {
4177
4178 // Elementor sideloads every image referenced by the page from inside this request.
4179 // A single oversized source image decodes to more than the whole memory limit, so
4180 // guard before any of that starts.
4181 $this->wdkit_guard_oversized_images();
4182
4183 // Sideloading images for image-heavy pages (wdkit_media_import → Imagick
4184 // thumbnail generation per image) can exceed the default 30s execution
4185 // limit and fatal the request mid-import. Give this single page import
4186 // more headroom; harmless no-op where set_time_limit() is disabled.
4187 if ( function_exists( 'set_time_limit' ) ) {
4188 @set_time_limit( 120 );
4189 }
4190
4191 if ( isset( $_POST['args'] ) ) {
4192 $args = ! empty( $_POST['args'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['args'] ) ), true ) : array();
4193 }
4194
4195 if ( isset( $_POST['temp_data'] ) ) {
4196 $temp_data = ! empty( $_POST['temp_data'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['temp_data'] ) ), true ) : array();
4197 }
4198
4199 if ( isset( $_POST['category_list'] ) ) {
4200 $category_list = ! empty( $_POST['category_list'] ) ? json_decode( wp_unslash( $_POST['category_list'] ), true ) : '';
4201 }
4202
4203 if ( isset( $_POST['tag_list'] ) ) {
4204 $tag_list = ! empty( $_POST['tag_list'] ) ? json_decode( wp_unslash( $_POST['tag_list'] ), true ) : '';
4205 }
4206
4207 if ( isset( $_POST['thumb_image'] ) ) {
4208 $thumb_image = ! empty( $_POST['thumb_image'] ) ? esc_url_raw( $_POST['thumb_image'] ) : '';
4209 }
4210
4211 if ( isset( $_POST['template_id'] ) ) {
4212 $template_id = ! empty( $_POST['template_id'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['template_id'] ), true ) ) : '';
4213 }
4214
4215 $temp_type = isset( $_POST['temp_type'] ) ? sanitize_text_field( wp_unslash( $_POST['temp_type'] ) ) : 'normal';
4216
4217 if ( isset( $_POST['data'] ) ) {
4218 $data = ! empty( $_POST['data'] ) ? json_decode( wp_unslash( $_POST['data'] ) ) : '';
4219 }
4220
4221 $enqueue_instance = new Wdkit_Enqueue();
4222 $get_post_type = $enqueue_instance->wdkit_get_post_type_list();
4223
4224 $post_type = ! empty( $temp_data['type'] ) ? sanitize_text_field( wp_unslash( $temp_data['type'] ) ) : 'page';
4225
4226 if ( 'section' === $post_type ) {
4227 $post_type = $temp_data['wp_post_type'];
4228 } else {
4229 $post_type = $temp_data['wp_post_type'];
4230 }
4231
4232 if ( ! array_key_exists( $post_type, $get_post_type ) ) {
4233 $post_type = 'page';
4234 }
4235
4236 if ( ! empty( $data ) && ! empty( $template_id ) && ! empty( $post_type ) && current_user_can( 'manage_options' ) ) {
4237 $post_content = $data;
4238 // Restore The Plus Addons' globals before the page is built, so the widgets'
4239 // tp_global_preset references resolve as soon as it renders. Done here rather
4240 // than in the save-template UI's confirmation dialog so that every import path
4241 // - the library, the abilities, the theme builder - gets it.
4242 if ( isset( $post_content->tp_globals ) && ! empty( $post_content->tp_globals ) ) {
4243 $this->wdkit_merge_tp_globals(
4244 json_decode( wp_json_encode( $post_content->tp_globals ), true ),
4245 isset( $post_content->tp_global_refs )
4246 ? json_decode( wp_json_encode( $post_content->tp_global_refs ), true )
4247 : array()
4248 );
4249 }
4250
4251 $post_title = isset( $post_content->title ) ? sanitize_text_field( $post_content->title ) : '';
4252 $post_slug = isset( $post_content->slug ) ? sanitize_text_field( $post_content->slug ) : '';
4253 $file_type = isset( $post_content->file_type ) ? sanitize_text_field( $post_content->file_type ) : '';
4254 $content = isset( $post_content->content ) ? wp_slash( $post_content->content ) : '';
4255 $temp_con = '';
4256
4257 if ( 'gutenberg' === $args['editor'] || ( 'wdkit' === $args['editor'] && ! empty( $file_type ) && 'wp_block' === $file_type ) ) {
4258 if ( empty( $content ) ) {
4259 wp_send_json(
4260 array(
4261 'template_id' => $template_id,
4262 'message' => __( 'Content is Empty.', 'wdesignkit' ),
4263 )
4264 );
4265 wp_die();
4266 } elseif ( ! empty( $content ) && ! empty( $file_type ) && 'wp_block' === $file_type ) {
4267
4268 $editor = ( 'wdkit' === $args['editor'] ) ? 'gutenberg' : $args['editor'];
4269 $blocks = parse_blocks( stripslashes( $content ) );
4270
4271 $blocks = $this->wdkit_media_import( $blocks, $editor );
4272
4273 $processor = new WDKIT_Nexter_Block_Processor();
4274 $blocks = $processor->run( $blocks );
4275 $content = serialize_blocks( $blocks );
4276
4277 $content = $this->replace_unicode_glitch( serialize_blocks( $blocks ) );
4278
4279 $inserted_post = wp_insert_post(
4280 array(
4281 'post_status' => 'publish',
4282 'post_type' => $post_type,
4283 'post_title' => $post_title,
4284 'post_name' => $post_slug,
4285 'post_content' => $content,
4286 )
4287 );
4288
4289 if ( is_wp_error( $inserted_post ) ) {
4290 wp_send_json(
4291 array(
4292 'import_failed' => $inserted_post->get_error_message(),
4293 'code' => $inserted_post->get_error_code(),
4294 )
4295 );
4296 wp_die();
4297 }
4298
4299 if ( ! empty( $thumb_image ) && wdesignkit_validate_external_url( $thumb_image ) ) {
4300 // $featured_image_url = esc_url_raw( $thumb_image );
4301 $tmp = download_url( $thumb_image );
4302 if ( is_wp_error( $tmp ) ) {
4303 error_log( 'Image download failed: ' . esc_html( $tmp->get_error_message() ) );
4304 } else {
4305 $file_array = array(
4306 'name' => wp_basename( $thumb_image ),
4307 'tmp_name' => $tmp,
4308 );
4309
4310 $image_id = media_handle_sideload( $file_array, $inserted_post );
4311
4312 if ( is_wp_error( $image_id ) ) {
4313 error_log( 'Image sideload failed: ' . esc_html( $image_id->get_error_message() ) );
4314 } else {
4315 set_post_thumbnail( $inserted_post, $image_id );
4316 }
4317
4318 @unlink( $tmp );
4319 }
4320 }
4321
4322 if ( ! empty( $category_list ) && is_array( $category_list ) ) {
4323 $category_ids = array_map( 'intval', $category_list );
4324 wp_set_post_terms( $inserted_post, $category_ids, 'category' );
4325 }
4326
4327 if ( ! empty( $tag_list ) && is_array( $tag_list ) ) {
4328 $tag_ids = array_map( 'intval', $tag_list );
4329 wp_set_post_terms( $inserted_post, $tag_ids, 'post_tag' );
4330 }
4331
4332 if ( ! empty( $args['custom_meta'] ) && 'true' == $args['custom_meta'] ) {
4333 $custom_meta = isset( $post_content->custom_meta ) ? json_decode( wp_json_encode( $post_content->custom_meta ), true ) : '';
4334 if ( ! empty( $custom_meta ) ) {
4335 foreach ( $custom_meta as $meta_key => $meta_val ) {
4336 if ( isset( $meta_val[0] ) && ! empty( $meta_val[0] ) && is_serialized( $meta_val[0] ) ) {
4337 $meta_val[0] = unserialize( $meta_val[0], array( 'allowed_classes' => false ) );
4338 }
4339
4340 if ( '' === get_post_meta( $inserted_post, $meta_key, true ) && isset( $meta_val[0] ) ) {
4341 add_post_meta( $inserted_post, $meta_key, $meta_val[0] );
4342 }
4343 }
4344 }
4345 }
4346
4347 $temp_detail = array(
4348 'title' => get_the_title( $inserted_post ),
4349 'edit_link' => get_edit_post_link( $inserted_post, 'internal' ),
4350 'view' => get_permalink( $inserted_post ),
4351 'id' => $inserted_post,
4352 );
4353
4354 if ( ! empty( $template_id->id ) ) {
4355 $temp_id = $template_id->id;
4356 } elseif ( ! empty( $template_id ) ) {
4357 $temp_id = $template_id;
4358 } else {
4359 $temp_id = '';
4360 }
4361
4362 wp_update_post([
4363 'ID' => $inserted_post,
4364 ]);
4365
4366 if (class_exists('Tpgb_Library') && method_exists('Tpgb_Library', 'remove_backend_dir_files')) {
4367 Tpgb_Library()->remove_backend_dir_files();
4368 }
4369
4370 clean_post_cache( $inserted_post );
4371 wp_send_json(
4372 array(
4373 $temp_id => $temp_detail,
4374 'description' => 'Yay! Your Section has been Successfully Imported.',
4375 'message' => __( 'Successfully Imported.', 'wdesignkit' ),
4376 'inserted_id' => $inserted_post,
4377 'success' => true,
4378 )
4379 );
4380 wp_die();
4381 }
4382 } elseif ( 'elementor' === $args['editor'] || ( 'wdkit' === $args['editor'] && ! empty( $file_type ) && 'elementor' === $file_type ) ) {
4383 if ( did_action( 'elementor/loaded' ) ) {
4384 if ( empty( $content ) ) {
4385 wp_send_json(
4386 array(
4387 'template_id' => $template_id,
4388 'message' => __( 'Content is Empty.', 'wdesignkit' ),
4389 )
4390 );
4391 wp_die();
4392 } elseif ( ! empty( $content ) && ! empty( $file_type ) && 'elementor' === $file_type ) {
4393
4394 $content = $this->wdkit_content_remover( $content );
4395
4396 $post_attributes = array(
4397 'post_title' => $post_title,
4398 'post_type' => $post_type,
4399 'post_status' => 'publish',
4400 'post_name' => $post_slug,
4401 );
4402
4403 if ( 'elementor_library' === $post_type ) {
4404 $el_type = ( isset( $post_content->el_type ) && ! empty( $post_content->el_type ) ) ? sanitize_text_field( $post_content->el_type ) : 'page';
4405 $new_document = \Elementor\Plugin::$instance->documents->create(
4406 $el_type,
4407 $post_attributes
4408 );
4409 } else {
4410 $new_document = \Elementor\Plugin::$instance->documents->create(
4411 $post_attributes['post_type'],
4412 $post_attributes
4413 );
4414 }
4415
4416 if ( is_wp_error( $new_document ) ) {
4417 wp_send_json(
4418 array(
4419 'import_failed' => $new_document->get_error_message(),
4420 'code' => $new_document->get_error_code(),
4421 )
4422 );
4423 wp_die();
4424 }
4425
4426 $inserted_id = $new_document->get_main_id();
4427
4428 if ( ! empty( $thumb_image ) && wdesignkit_validate_external_url( $thumb_image ) ) {
4429 // $featured_image_url = esc_url_raw( $thumb_image );
4430 $tmp = download_url( $thumb_image );
4431 if ( is_wp_error( $tmp ) ) {
4432 error_log( 'Image download failed: ' . esc_html( $tmp->get_error_message() ) );
4433 } else {
4434 $file_array = array(
4435 'name' => wp_basename( $thumb_image ),
4436 'tmp_name' => $tmp,
4437 );
4438
4439 $image_id = media_handle_sideload( $file_array, $inserted_id );
4440
4441 if ( is_wp_error( $image_id ) ) {
4442 error_log( 'Image sideload failed: ' . esc_html( $image_id->get_error_message() ) );
4443 } else {
4444 set_post_thumbnail( $inserted_id, $image_id );
4445 }
4446
4447 @unlink( $tmp );
4448 }
4449 }
4450
4451 if ( ! empty( $category_list ) && is_array( $category_list ) ) {
4452 $category_ids = array_map( 'intval', $category_list );
4453 wp_set_post_terms( $inserted_id, $category_ids, 'category' );
4454 }
4455
4456 if ( ! empty( $tag_list ) && is_array( $tag_list ) ) {
4457 $tag_ids = array_map( 'intval', $tag_list );
4458 wp_set_post_terms( $inserted_id, $tag_ids, 'post_tag' );
4459 }
4460
4461 $settings = ( isset( $post_content->settings ) && ! empty( $post_content->settings ) ) ? json_decode( wp_json_encode( $post_content->settings ), true ) : array();
4462
4463 $content = wp_json_encode( $content );
4464 $content = $this->wdkit_media_import( $content, $file_type );
4465
4466 $new_document->save(
4467 array(
4468 'elements' => $content,
4469 'settings' => ! empty( $settings ) ? $settings : array(),
4470 )
4471 );
4472
4473 $inserted_id = $new_document->get_main_id();
4474
4475 if( $temp_type == 'navigation' ){
4476 $temp_con = $content;
4477 }
4478
4479 if ( ! empty( $args['custom_meta'] ) && 'true' == $args['custom_meta'] ) {
4480 $custom_meta = isset( $post_content->custom_meta ) ? json_decode( wp_json_encode( $post_content->custom_meta ), true ) : '';
4481 if ( ! empty( $custom_meta ) ) {
4482 foreach ( $custom_meta as $meta_key => $meta_val ) {
4483 if ( ! empty( $meta_val[0] ) && is_serialized( $meta_val[0] ) ) {
4484 $meta_val[0] = unserialize( $meta_val[0], array( 'allowed_classes' => false ) );
4485 }
4486 if ( '' === get_post_meta( $inserted_id, $meta_key, true ) ) {
4487 add_post_meta( $inserted_id, $meta_key, $meta_val[0] );
4488 }
4489 }
4490 }
4491 }
4492
4493 $temp_detail = array(
4494 'title' => get_the_title( $inserted_id ),
4495 'edit_link' => get_edit_post_link( $inserted_id, 'internal' ),
4496 'view' => get_permalink( $inserted_id ),
4497 'id' => $inserted_id,
4498 );
4499
4500 if ( ! empty( $template_id->id ) ) {
4501 $temp_id = $template_id->id;
4502 } elseif ( ! empty( $template_id ) ) {
4503 $temp_id = $template_id;
4504 } else {
4505 $temp_id = '';
4506 }
4507
4508 \Elementor\Plugin::$instance->files_manager->clear_cache();
4509
4510 wp_send_json(
4511 array(
4512 $temp_id => $temp_detail,
4513 'content' => $temp_con,
4514 'description' => 'Yay! Your Section has been Successfully Imported.',
4515 'message' => __( 'Successfully Imported.', 'wdesignkit' ),
4516 'inserted_id' => $inserted_id,
4517 'success' => true,
4518 )
4519 );
4520 wp_die();
4521 }
4522 } else {
4523 wp_send_json(
4524 array(
4525 'template_id' => $template_id,
4526 'message' => esc_html__( 'Relevant Page Builder not installed or activated', 'wdesignkit' ),
4527 )
4528 );
4529 wp_die();
4530 }
4531 }
4532 }
4533
4534 wp_send_json(
4535 array(
4536 'success' => false,
4537 'message' => esc_html__( 'Something went wrong', 'wdesignkit' ),
4538 )
4539 );
4540 wp_die();
4541 }
4542
4543 /**
4544 * Replace unicode glitch
4545 *
4546 * @since 2.0.0
4547 */
4548 private function replace_unicode_glitch( $content ) {
4549
4550 // Fix escaped unicode like \u003c → <
4551 $content = preg_replace_callback(
4552 '/\\\\u([0-9a-fA-F]{4})/',
4553 function ( $match ) {
4554 return html_entity_decode(
4555 mb_convert_encoding(
4556 pack('H*', $match[1]),
4557 'UTF-8',
4558 'UCS-2BE'
4559 ),
4560 ENT_QUOTES,
4561 'UTF-8'
4562 );
4563 },
4564 $content
4565 );
4566
4567 return $content;
4568 }
4569
4570
4571 /**
4572 * change plugins setting for import kit
4573 *
4574 * @since 2.0.0
4575 */
4576 protected function update_plugin_setting() {
4577 $temp_id = isset( $_POST['plugin_type'] ) ? sanitize_text_field( $_POST['plugin_type'] ) : '';
4578
4579 if ( $temp_id == 'elementor' ) {
4580 $unfiltered_files = get_option( 'elementor_unfiltered_files_upload', false );
4581 $load_fa4 = get_option( 'elementor_load_fa4_shim', false );
4582 $Inline_font_icons = get_option( 'elementor_experiment-e_font_icon_svg', false );
4583 $container = get_option( 'elementor_experiment-container', false );
4584
4585 if ( isset( $unfiltered_files ) ) {
4586 update_option( 'elementor_unfiltered_files_upload', 1 );
4587 } else {
4588 add_option( 'elementor_unfiltered_files_upload', 1 );
4589 }
4590
4591 if ( isset( $load_fa4 ) ) {
4592 update_option( 'elementor_load_fa4_shim', 'yes' );
4593 } else {
4594 add_option( 'elementor_load_fa4_shim', 'yes' );
4595 }
4596
4597 if ( isset( $container ) ) {
4598 update_option( 'elementor_experiment-container', 'active' );
4599 } else {
4600 add_option( 'elementor_experiment-container', 'active' );
4601 }
4602
4603 if ( isset( $Inline_font_icons ) ) {
4604 update_option( 'elementor_experiment-e_font_icon_svg', 'inactive' );
4605 } else {
4606 add_option( 'elementor_experiment-e_font_icon_svg', 'inactive' );
4607 }
4608
4609 $response = array(
4610 'message' => esc_html__( 'Plugin Setting updated', 'wdesignkit' ),
4611 'description' => esc_html__( 'Plugin Setting updated', 'wdesignkit' ),
4612 'success' => true,
4613 );
4614 } else {
4615 $response = array(
4616 'message' => esc_html__( 'Plugin not found', 'wdesignkit' ),
4617 'description' => esc_html__( 'Plugin not found', 'wdesignkit' ),
4618 'success' => false,
4619 );
4620 }
4621
4622 wp_send_json( $response );
4623 wp_die();
4624 }
4625
4626 /**
4627 * generate different color logo
4628 *
4629 * @since 2.0.0
4630 */
4631 protected function wkit_generate_site_logo() {
4632
4633 if ( empty( $_POST['image_url'] ) ) {
4634 wp_send_json_error( 'Image URL not provided.' );
4635 }
4636
4637 if ( isset( $_POST['colors'] ) ) {
4638 $img_colors = ! empty( $_POST['colors'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['colors'] ) ), true ) : array();
4639 }
4640
4641 if ( empty( $img_colors ) ) {
4642 wp_send_json_error( 'Image color not provided.' );
4643 }
4644
4645 $image_url = esc_url_raw( $_POST['image_url'] );
4646
4647 if ( ! wdesignkit_validate_external_url( $image_url ) ) {
4648 wp_send_json_error( 'Image could not be downloaded.' );
4649 }
4650
4651 $tmp_file = download_url( $image_url );
4652 if ( is_wp_error( $tmp_file ) ) {
4653 wp_send_json_error( 'Image could not be downloaded.' );
4654 }
4655
4656 if ( mime_content_type( $tmp_file ) !== 'image/png' ) {
4657 unlink( $tmp_file );
4658 wp_send_json_error( 'Not a PNG file.' );
4659 }
4660
4661 $src = imagecreatefrompng( $tmp_file );
4662 imagesavealpha( $src, true );
4663
4664 $width = imagesx( $src );
4665 $height = imagesy( $src );
4666
4667 $hasTransparency = false;
4668 for ( $x = 0; $x < $width; $x++ ) {
4669 for ( $y = 0; $y < $height; $y++ ) {
4670 $rgba = imagecolorat( $src, $x, $y );
4671 $alpha = ( $rgba & 0x7F000000 ) >> 24;
4672
4673 if ( $alpha > 0 ) {
4674 $hasTransparency = true;
4675 break 2;
4676 }
4677 }
4678 }
4679
4680 if ( ! $hasTransparency ) {
4681 unlink( $tmp_file );
4682 wp_send_json_error( 'PNG has no transparent pixels.' );
4683 }
4684
4685 $upload_dir = wp_upload_dir();
4686 $result_urls = array();
4687
4688 $colour_index = 0;
4689 foreach ( $img_colors as $name => $rgb ) {
4690 // $name is a key from the posted colours payload and went straight into the output
4691 // filename, so traversal sequences in it steered imagepng() outside the upload
4692 // directory (CWE-22, ClickUp 86d41ced6). sanitize_file_name() flattens it to one
4693 // path segment; a key made only of dots/separators sanitizes to empty, so fall back
4694 // to a positional index rather than writing to a bare "colored--<time>.png".
4695 ++$colour_index;
4696 $safe_name = sanitize_file_name( (string) $name );
4697 if ( '' === $safe_name ) {
4698 $safe_name = 'colour-' . $colour_index;
4699 }
4700
4701 $new = imagecreatetruecolor( $width, $height );
4702 imagesavealpha( $new, true );
4703 imagealphablending( $new, false );
4704
4705 $transparent = imagecolorallocatealpha( $new, 0, 0, 0, 127 );
4706 imagefill( $new, 0, 0, $transparent );
4707
4708 for ( $x = 0; $x < $width; $x++ ) {
4709 for ( $y = 0; $y < $height; $y++ ) {
4710 $rgba = imagecolorat( $src, $x, $y );
4711 $alpha = ( $rgba & 0x7F000000 ) >> 24;
4712
4713 // Skip fully transparent pixels
4714 if ( $alpha === 127 ) {
4715 continue;
4716 }
4717
4718 // Replace pixel color directly
4719 $new_r = $rgb[0];
4720 $new_g = $rgb[1];
4721 $new_b = $rgb[2];
4722
4723 $color = imagecolorallocatealpha( $new, $new_r, $new_g, $new_b, $alpha );
4724 imagesetpixel( $new, $x, $y, $color );
4725 }
4726 }
4727
4728 $filename = 'colored-' . $safe_name . '-' . time() . '.png';
4729 $filepath = $upload_dir['path'] . '/' . $filename;
4730
4731 imagepng( $new, $filepath );
4732 imagedestroy( $new );
4733
4734 $attachment = array(
4735 'post_mime_type' => 'image/png',
4736 'post_title' => sanitize_file_name( $filename ),
4737 'post_content' => '',
4738 'post_status' => 'inherit',
4739 );
4740
4741 $attach_id = wp_insert_attachment( $attachment, $filepath );
4742 require_once ABSPATH . 'wp-admin/includes/image.php';
4743 $attach_data = wp_generate_attachment_metadata( $attach_id, $filepath );
4744 wp_update_attachment_metadata( $attach_id, $attach_data );
4745
4746 $result_urls[ $name ] = wp_get_attachment_url( $attach_id );
4747 }
4748
4749 imagedestroy( $src );
4750 unlink( $tmp_file );
4751
4752 wp_send_json_success( $result_urls );
4753 }
4754
4755 /**
4756 * change theme setting for import kit
4757 *
4758 * @since 2.0.0
4759 */
4760 protected function update_theme_setting() {
4761 $theme_db = get_option( 'nxt-theme-options', false );
4762
4763 $container_type = 'container-fluid';
4764 $fluid_spacing = array(
4765 'md' => array(
4766 'left' => '0',
4767 'right' => '0',
4768 ),
4769 'sm' => array(
4770 'left' => '',
4771 'right' => '',
4772 ),
4773 'xs' => array(
4774 'left' => '',
4775 'right' => '',
4776 ),
4777 'md-unit' => 'px',
4778 'sm-unit' => 'px',
4779 'xs-unit' => 'px',
4780 );
4781
4782 if ( isset( $theme_db ) ) {
4783 $nexter_setting = $theme_db;
4784 $nexter_setting['site-header-container'] = $container_type;
4785 $nexter_setting['site-footer-container'] = $container_type;
4786 $nexter_setting['site-layout-container'] = $container_type;
4787 $nexter_setting['site-page-container'] = $container_type;
4788
4789 $nexter_setting['header-fluid-spacing'] = $fluid_spacing;
4790 $nexter_setting['footer-fluid-spacing'] = $fluid_spacing;
4791 $nexter_setting['site-fluid-spacing'] = $fluid_spacing;
4792 $nexter_setting['page-fluid-spacing'] = $fluid_spacing;
4793
4794 update_option( 'nxt-theme-options', $nexter_setting );
4795 } else {
4796 $nexter_setting = array(
4797 'site-header-container' => 'container-fluid',
4798 'header-fluid-spacing' => array(
4799 'md' => array(
4800 'left' => '0',
4801 'right' => '0',
4802 ),
4803 'sm' => array(
4804 'left' => '',
4805 'right' => '',
4806 ),
4807 'xs' => array(
4808 'left' => '',
4809 'right' => '',
4810 ),
4811 'md-unit' => 'px',
4812 'sm-unit' => 'px',
4813 'xs-unit' => 'px',
4814 ),
4815 'site-footer-container' => 'container-fluid',
4816 'footer-fluid-spacing' => array(
4817 'md' => array(
4818 'left' => '0',
4819 'right' => '0',
4820 ),
4821 'sm' => array(
4822 'left' => '',
4823 'right' => '',
4824 ),
4825 'xs' => array(
4826 'left' => '',
4827 'right' => '',
4828 ),
4829 'md-unit' => 'px',
4830 'sm-unit' => 'px',
4831 'xs-unit' => 'px',
4832 ),
4833 'site-layout-container' => 'container-fluid',
4834 'site-fluid-spacing' => array(
4835 'md' => array(
4836 'left' => '0',
4837 'right' => '0',
4838 ),
4839 'sm' => array(
4840 'left' => '',
4841 'right' => '',
4842 ),
4843 'xs' => array(
4844 'left' => '',
4845 'right' => '',
4846 ),
4847 'md-unit' => 'px',
4848 'sm-unit' => 'px',
4849 'xs-unit' => 'px',
4850 ),
4851 'site-page-container' => 'container-fluid',
4852 'page-fluid-spacing' => array(
4853 'md' => array(
4854 'left' => '0',
4855 'right' => '0',
4856 ),
4857 'sm' => array(
4858 'left' => '',
4859 'right' => '',
4860 ),
4861 'xs' => array(
4862 'left' => '',
4863 'right' => '',
4864 ),
4865 'md-unit' => 'px',
4866 'sm-unit' => 'px',
4867 'xs-unit' => 'px',
4868 ),
4869 'site-page-container' => '',
4870 'site-posts-container' => '',
4871 'site-archive-container' => '',
4872 );
4873
4874 add_option( 'nxt-theme-options', $nexter_setting );
4875 }
4876
4877 $response = array(
4878 'message' => esc_html__( 'Theme Setting updated', 'wdesignkit' ),
4879 'description' => esc_html__( 'Theme Setting updated', 'wdesignkit' ),
4880 'success' => true,
4881 );
4882
4883 wp_send_json( $response );
4884 wp_die();
4885 }
4886
4887 /**
4888 * change site setting for import kit
4889 *
4890 * @since 2.0.0
4891 */
4892 protected function update_site_setting() {
4893 $temp_id = isset( $_POST['id'] ) ? sanitize_text_field( wp_unslash( $_POST['id'] ) ) : '';
4894 $shop_id = isset( $_POST['shop_id'] ) ? sanitize_text_field( wp_unslash( $_POST['shop_id'] ) ) : '';
4895 $temp_type = isset( $_POST['temp_type'] ) ? sanitize_text_field( wp_unslash( $_POST['temp_type'] ) ) : 'page';
4896 $site_name = isset( $_POST['site_name'] ) ? sanitize_text_field( wp_unslash( $_POST['site_name'] ) ) : '';
4897 $site_tagline = isset( $_POST['site_tagline'] ) ? sanitize_text_field( wp_unslash( $_POST['site_tagline'] ) ) : '';
4898
4899 $this->wdkit_nxt_thembuilder_update();
4900
4901 if ( ! empty( $shop_id ) ) {
4902 update_option( 'woocommerce_shop_page_id', $shop_id );
4903 }
4904
4905 if ( $temp_id ) {
4906 update_option( 'show_on_front', $temp_type );
4907 update_option( 'page_on_front', $temp_id );
4908
4909 if ( ! empty( $site_name ) ) {
4910 update_option( 'blogname', $site_name );
4911 }
4912
4913 if ( ! empty( $site_tagline ) ) {
4914 update_option( 'blogdescription', $site_tagline );
4915 }
4916
4917 $response = array(
4918 'message' => esc_html__( 'Site link updated', 'wdesignkit' ),
4919 'description' => esc_html__( 'Site link updated', 'wdesignkit' ),
4920 'site_link' => get_site_url(),
4921 'success' => true,
4922 );
4923 } else {
4924 $response = array(
4925 'message' => esc_html__( 'Site not found', 'wdesignkit' ),
4926 'description' => esc_html__( 'Site not found', 'wdesignkit' ),
4927 'success' => false,
4928 );
4929 }
4930
4931 wp_send_json( $response );
4932 wp_die();
4933 }
4934
4935 /**
4936 * update theme builder
4937 *
4938 * @since 2.0.4
4939 */
4940 public function wdkit_nxt_thembuilder_update() {
4941
4942 $page_information = isset( $_POST['page_information'] ) ? sanitize_text_field( wp_unslash( $_POST['page_information'] ) ) : '';
4943 $page_information = json_decode( $page_information, true );
4944
4945 if ( ! empty( $page_information ) && is_array( $page_information ) ) {
4946
4947 // Every page and attachment now exists, so resolve any image ID the per-page
4948 // pass could not (siblings import concurrently and share icons).
4949 $this->wdkit_sweep_attachment_ids( wp_list_pluck( $page_information, 'inserted_id' ) );
4950
4951 // Step 1: banavo mapping [ old_id => new_id ]
4952 $id_mapping = array();
4953 foreach ( $page_information as $page_info ) {
4954 if ( ! empty( $page_info['old_page_id'] ) ) {
4955 $id_mapping[ $page_info['old_page_id'] ] = $page_info['inserted_id'];
4956 }
4957 }
4958
4959 // Step 2: loop karo and update exclude
4960 foreach ( $page_information as $page_info ) {
4961
4962 $post_id = $page_info['inserted_id'] ?? '';
4963 $old_post_id = $page_info['old_page_id'] ?? '';
4964 $post_type = $page_info['post_type'] ?? '';
4965
4966 if ( empty( $old_post_id ) ) {
4967 continue; // only update where old id exists
4968 }
4969
4970 if ( $post_type != 'nxt_builder' ) {
4971 continue;
4972 }
4973
4974 $include_specific = get_post_meta( $post_id, 'nxt-hooks-layout-specific', true );
4975 if ( ! empty( $include_specific ) && is_array( $include_specific ) ) {
4976
4977 foreach ( $include_specific as $key => $val ) {
4978
4979 // check karo ke koi old_id ka post match kare che ke nahi
4980 foreach ( $id_mapping as $old_id => $new_id ) {
4981 $search = 'post-' . $old_id;
4982 $replace = 'post-' . $new_id;
4983
4984 if ( $val === $search ) {
4985 $include_specific[ $key ] = $replace;
4986 }
4987 }
4988 }
4989
4990 // save back updated array
4991 update_post_meta( $post_id, 'nxt-hooks-layout-specific', $include_specific );
4992 }
4993
4994 // Get exclude meta
4995 $exclude_specific = get_post_meta( $post_id, 'nxt-hooks-layout-exclude-specific', true );
4996 if ( ! empty( $exclude_specific ) && is_array( $exclude_specific ) ) {
4997
4998 foreach ( $exclude_specific as $key => $val ) {
4999
5000 // check karo ke koi old_id ka post match kare che ke nahi
5001 foreach ( $id_mapping as $old_id => $new_id ) {
5002 $search = 'post-' . $old_id;
5003 $replace = 'post-' . $new_id;
5004
5005 if ( $val === $search ) {
5006 $exclude_specific[ $key ] = $replace;
5007 }
5008 }
5009 }
5010
5011 // save back updated array
5012 update_post_meta( $post_id, 'nxt-hooks-layout-exclude-specific', $exclude_specific );
5013 }
5014 }
5015 }
5016 }
5017
5018 /**
5019 *
5020 * select team image for import kit
5021 *
5022 * @since 2.2.2
5023 */
5024 public function wdkit_check_user_credit() {
5025 $array_data = array(
5026 'token' => isset( $_POST['token'] ) ? sanitize_text_field( $_POST['token'] ) : '',
5027 );
5028
5029 $response = $this->wkit_api_call( $array_data, 'ai/credits/get' );
5030 $success = ! empty( $response['success'] ) ? $response['success'] : false;
5031
5032 if ( empty( $success ) ) {
5033 $response = array(
5034 'success' => false,
5035 'message' => esc_html__( 'Data Not Found', 'wdesignkit' ),
5036 'description' => esc_html__( 'Data not found', 'wdesignkit' ),
5037 );
5038
5039 wp_send_json( $response );
5040 wp_die();
5041 }
5042
5043 $response = json_decode( wp_json_encode( $response['data'] ), true );
5044
5045 wp_send_json( $response );
5046 wp_die();
5047 }
5048
5049 public function wdkit_nxt_thembuilder_reset() {
5050 $post_id = isset( $_POST['post_id'] ) ? sanitize_text_field( $_POST['post_id'] ) : '';
5051 $sections_layout = get_post_meta( $post_id, 'nxt-hooks-layout-sections', true );
5052
5053 if ( ( ! empty( $sections_layout ) && ( $sections_layout == 'header' || $sections_layout == 'footer' || $sections_layout == 'breadcrumb' || $sections_layout == 'hooks' ) ) ) {
5054 if ( get_post_meta( $post_id, 'nxt-add-display-rule' ) ) {
5055 delete_post_meta( $post_id, 'nxt-add-display-rule' );
5056 }
5057
5058 if ( get_post_meta( $post_id, 'nxt-hooks-layout-specific' ) ) {
5059 update_post_meta( $post_id, 'nxt-hooks-layout-specific', '' );
5060 }
5061
5062 if ( get_post_meta( $post_id, 'nxt-exclude-display-rule' ) ) {
5063 update_post_meta( $post_id, 'nxt-exclude-display-rule', '' );
5064 }
5065
5066 if ( get_post_meta( $post_id, 'nxt-hooks-layout-exclude-specific' ) ) {
5067 update_post_meta( $post_id, 'nxt-hooks-layout-exclude-specific', '' );
5068 }
5069 }
5070 }
5071
5072
5073 /**
5074 * Share with Me Template and widgets
5075 *
5076 * @since 1.0.0
5077 */
5078 protected function wdkit_shared_with_me() {
5079 $data = isset( $_POST['api_info'] ) ? json_decode( stripslashes( sanitize_text_field( wp_unslash( $_POST['api_info'] ) ) ) ) : '';
5080
5081 $array_data = array(
5082 'token' => isset( $data->token ) ? sanitize_text_field( $data->token ) : '',
5083 'type' => isset( $data->type ) ? sanitize_text_field( wp_unslash( $data->type ) ) : '',
5084 'ParPage' => isset( $data->par_page ) ? (int) $data->par_page : 12,
5085 'CurrentPage' => isset( $data->current_page ) ? (int) $data->current_page : 1,
5086 'builder' => isset( $data->builder ) ? sanitize_text_field( wp_unslash( $data->builder ) ) : '',
5087 );
5088
5089 $response = $this->wkit_api_call( $array_data, 'shared_with_me' );
5090 $success = ! empty( $response['success'] ) ? $response['success'] : false;
5091
5092 wp_send_json( $response );
5093 wp_die();
5094 }
5095
5096 /**
5097 * Add new WorkSpace
5098 *
5099 * @since 1.0.0
5100 */
5101 protected function wdkit_manage_workspace() {
5102 $args = $this->wdkit_parse_args( $_POST );
5103
5104 $user_email = ! empty( $args['email'] ) ? strtolower( sanitize_email( $args['email'] ) ) : '';
5105 $current_wid = ! empty( $_POST['current_wid'] ) ? strtolower( sanitize_text_field( $_POST['current_wid'] ) ) : '';
5106
5107 $args['current_wid'] = $current_wid;
5108
5109 if ( empty( $user_email ) ) {
5110 $response = array(
5111 'message' => $this->e_msg_login,
5112 'description' => $this->e_desc_login,
5113 'success' => false,
5114 );
5115
5116 wp_send_json( $response );
5117 wp_die();
5118 }
5119
5120 $args['token'] = $this->wdkit_login_user_token( $user_email );
5121 unset( $user_email );
5122
5123 $response = WDesignKit_Data_Query::get_data( 'manage_workspace', $args );
5124
5125 return $response;
5126 }
5127
5128 /**
5129 *
5130 * It is Use for manage workspace
5131 *
5132 * @since 1.0.0
5133 */
5134 protected function wdkit_manage_widget_workspace() {
5135 $workspace_info = isset( $_POST['workspace_info'] ) ? sanitize_text_field( wp_unslash( $_POST['workspace_info'] ) ) : array();
5136 $data = isset( $workspace_info ) ? json_decode( stripslashes( $workspace_info ) ) : array();
5137
5138 $array_data = array(
5139 'token' => isset( $data->token ) ? sanitize_text_field( $data->token ) : '',
5140 'wstype' => isset( $data->type ) ? sanitize_text_field( $data->type ) : '',
5141 'widget_id' => isset( $data->widget_id ) ? (int) $data->widget_id : '',
5142 'wid' => isset( $data->wid ) ? (int) $data->wid : '',
5143 'current_wid' => isset( $data->current_wid ) ? (int) $data->current_wid : '',
5144 );
5145
5146 $response = $this->wkit_api_call( $array_data, 'manage_workspace' );
5147
5148 wp_send_json( $response['data'] );
5149 wp_die();
5150 }
5151
5152 /**
5153 *
5154 * It is Use for manage api key page
5155 *
5156 * @since 1.0.0
5157 */
5158 protected function wdkit_activate_key() {
5159 $email = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '';
5160 $response = '';
5161
5162 // Bug C fix: variable was $user_email but only $email is set above — always triggered empty() guard.
5163 if ( empty( $email ) ) {
5164 $response = array(
5165 'message' => $this->e_msg_login,
5166 'description' => $this->e_desc_login,
5167 'success' => false,
5168 );
5169
5170 wp_send_json( $response );
5171 wp_die();
5172 }
5173
5174 $token = $this->wdkit_login_user_token( $email );
5175 $apikey = isset( $_POST['apikey'] ) ? sanitize_key( wp_unslash( $_POST['apikey'] ) ) : '';
5176 $product = isset( $_POST['product'] ) ? sanitize_text_field( wp_unslash( $_POST['product'] ) ) : '';
5177 $product_action = isset( $_POST['product_action'] ) ? sanitize_text_field( wp_unslash( $_POST['product_action'] ) ) : 'activate';
5178 if ( ! empty( $token ) && ! empty( $product ) && ! empty( $product_action ) ) {
5179 $args = array(
5180 'token' => $token,
5181 'product' => $product,
5182 'product_action' => $product_action,
5183 );
5184
5185 if ( 'activate' === $product_action ) {
5186 $args['apikey'] = $apikey;
5187 $args['site_url'] = home_url();
5188 }
5189
5190 $response = Wdkit_Data_Hooks::get_data( 'wkit_activate_key', $args );
5191 }
5192
5193 wp_send_json( $response );
5194 wp_die();
5195 }
5196
5197 /**
5198 *
5199 * Get list local Widget List
5200 *
5201 * @since 1.0.0
5202 */
5203 protected function wdkit_get_local_widgets() {
5204 $builder = array();
5205 $a_c_s_d_s_c = array();
5206 $j_s_o_n_array = array();
5207
5208 if ( Wdkit_Wdesignkit::wdkit_is_compatible( 'bricks', 'widget' ) ) {
5209 array_push( $builder, 'bricks' );
5210 }
5211
5212 if ( Wdkit_Wdesignkit::wdkit_is_compatible( 'elementor', 'widget' ) ) {
5213 array_push( $builder, 'elementor' );
5214 }
5215
5216 if ( Wdkit_Wdesignkit::wdkit_is_compatible( 'gutenberg', 'widget' ) ) {
5217 array_push( $builder, 'gutenberg' );
5218 }
5219
5220 if ( Wdkit_Wdesignkit::wdkit_is_compatible( 'gutenberg_core', 'widget' ) ) {
5221 array_push( $builder, 'gutenberg_core' );
5222 }
5223
5224 foreach ( $builder as $key => $name ) {
5225 $elementor_dir = WDKIT_BUILDER_PATH . '/' . $name;
5226
5227 if ( ! empty( $elementor_dir ) && is_dir( $elementor_dir ) ) {
5228 $elementor_list = scandir( $elementor_dir );
5229 $elementor_list = array_diff( $elementor_list, array( '.', '..' ) );
5230
5231 if ( ! empty( $elementor_list ) ) {
5232 foreach ( $elementor_list as $key => $value ) {
5233 $a_c_s_d_s_c[ filemtime( "{$elementor_dir}/{$value}" ) . $key ]['data'] = $value;
5234 $a_c_s_d_s_c[ filemtime( "{$elementor_dir}/{$value}" ) . $key ]['builder'] = $name;
5235 }
5236 }
5237 }
5238 }
5239
5240 ksort( $a_c_s_d_s_c );
5241 $a_c_s_d_s_c = array_reverse( $a_c_s_d_s_c );
5242
5243 foreach ( $a_c_s_d_s_c as $key => $value ) {
5244 $elementor_dir = WDKIT_BUILDER_PATH . '/' . $value['builder'];
5245
5246 if ( file_exists( "{$elementor_dir}/{$value['data']}" ) && is_dir( "{$elementor_dir}/{$value['data']}" ) ) {
5247 $sub_dir = scandir( "{$elementor_dir}/{$value['data']}" );
5248 $sub = array_diff( $sub_dir, array( '.', '..' ) );
5249
5250 foreach ( $sub as $sub_dir_value ) {
5251 $file = new SplFileInfo( $sub_dir_value );
5252 $check_ext = $file->getExtension();
5253 $ext = pathinfo( $sub_dir_value, PATHINFO_EXTENSION );
5254
5255 if ( 'json' === $ext ) {
5256 $widget1 = WDKIT_BUILDER_PATH . "/{$value['builder']}/{$value['data']}/{$sub_dir_value}";
5257 $filedata = wp_json_file_decode( $widget1 );
5258 $decode_data = json_decode( wp_json_encode( $filedata ), true );
5259 array_push( $j_s_o_n_array, $decode_data['widget_data'] );
5260 }
5261 }
5262 }
5263 }
5264
5265 return $j_s_o_n_array;
5266 }
5267
5268 /**
5269 *
5270 * It is Use for manage widget category.
5271 *
5272 * @since 1.0.0
5273 */
5274 protected function wdkit_manage_widget_category() {
5275 $data = isset( $_POST['info'] ) ? sanitize_text_field( wp_unslash( $_POST['info'] ) ) : '';
5276 $data = json_decode( stripslashes( $data ) );
5277
5278 $type = isset( $data->manage_type ) ? sanitize_text_field( wp_unslash( $data->manage_type ) ) : '';
5279 $wkit_builder_option = get_option( 'wkit_builder' );
5280
5281 if ( empty( $wkit_builder_option ) ) {
5282 add_option( 'wkit_builder', array( 'WDesignKit' ), '', 'yes' );
5283 }
5284
5285 if ( 'get' === $type ) {
5286 if ( ! in_array( 'WDesignKit', $wkit_builder_option ) ) {
5287 update_option( 'wkit_builder', array( 'WDesignKit' ) );
5288 }
5289 } elseif ( 'update' === $type ) {
5290 $list = isset( $data->category_list ) ? $data->category_list : array();
5291 $list = array_unique( $list );
5292 $list = array_values( $list );
5293
5294 if ( ! empty( $list ) ) {
5295 update_option( 'wkit_builder', $list );
5296 }
5297 }
5298
5299 wp_send_json( get_option( 'wkit_builder' ) );
5300 }
5301
5302 /**
5303 * Get Workspace data
5304 *
5305 * @since 2.2.5
5306 */
5307 public function wdkit_get_workspace_data() {
5308
5309 $wid = isset( $_POST['wid'] ) ? sanitize_text_field( $_POST['wid'] ) : '';
5310 $token = isset( $_POST['token'] ) ? sanitize_text_field( $_POST['token'] ) : '';
5311
5312 if ( empty( $wid ) ) {
5313 return array(
5314 'success' => false,
5315 'message' => esc_html__( 'Workspace ID Not Found', 'wdesignkit' ),
5316 'description' => esc_html__( 'Workspace ID is required', 'wdesignkit' ),
5317 );
5318 }
5319
5320 if ( empty( $token ) ) {
5321 return array(
5322 'success' => false,
5323 'message' => esc_html__( 'Token Not Found', 'wdesignkit' ),
5324 'description' => esc_html__( 'Token is required', 'wdesignkit' ),
5325 );
5326 }
5327
5328 $args = array(
5329 'token' => $token,
5330 'wid' => $wid,
5331 );
5332
5333 $this->wdkit_api = $this->wdkit_api_v2;
5334
5335 $url = "workspace/{$wid}/get";
5336
5337 $response = $this->wkit_api_call( $args, $url );
5338
5339 wp_send_json( $response['data'] );
5340 wp_die();
5341 }
5342
5343 /**
5344 *
5345 * Custom_upload_dir
5346 *
5347 * @since 1.0.0
5348 *
5349 * @param array $upload store data.
5350 */
5351 public function custom_upload_dir( $upload ) {
5352 // Specify the path to your custom upload directory.
5353 if ( isset( $this->widget_folder_u_r_l ) && ! empty( $this->widget_folder_u_r_l ) ) {
5354
5355 // Set the custom directory as the upload path.
5356 $upload['path'] = $this->widget_folder_u_r_l;
5357 // Set the URL for the uploaded file.
5358 $upload['url'] = $upload['baseurl'] . $upload['subdir'];
5359 }
5360
5361 return $upload;
5362 }
5363
5364 /**
5365 *
5366 * It is Use for delete widget from server
5367 *
5368 * @since 1.0.0
5369 */
5370 protected function wkit_widget_json() {
5371 $widget_type = ! empty( $_POST['widget_type'] ) ? wp_unslash( $_POST['widget_type'] ) : '';
5372 $folder_name = ! empty( $_POST['folder_name'] ) ? wp_unslash( $_POST['folder_name'] ) : '';
5373 $file_name = ! empty( $_POST['file_name'] ) ? ( wp_unslash( $_POST['file_name'] ) ) : '';
5374
5375 if ( empty( $widget_type ) || empty( $folder_name ) || empty( $file_name ) ) {
5376 return array(
5377 'success' => false,
5378 'message' => esc_html__( 'Widget JSON not found', 'wdesignkit' ),
5379 'description' => esc_html__( 'widget JSON file not found.', 'wdesignkit' ),
5380 );
5381 }
5382
5383 // Read-side twin of the write and delete traversals fixed in 86d41cckh / 86d41ccz2: all
5384 // three segments arrive from $_POST with only wp_unslash() applied — which strips
5385 // nothing path-relevant — so "../" in any of them walked out of the builder directory
5386 // and this handler returned the decoded contents of any .json file the web server user
5387 // could read (CWE-22, ClickUp 86d41zaun).
5388 $safe_path = wdesignkit_widget_path_guard( $widget_type, $folder_name, $file_name );
5389
5390 if ( false === $safe_path || '' === $safe_path['folder'] || '' === $safe_path['file'] ) {
5391 return array(
5392 'success' => false,
5393 'message' => esc_html__( 'Widget JSON not found', 'wdesignkit' ),
5394 'description' => esc_html__( 'Invalid widget path.', 'wdesignkit' ),
5395 );
5396 }
5397
5398 $json_path = $safe_path['base'];
5399
5400 // Re-check the resolved file: the component guard above cannot see a symlink. Returns
5401 // false for a path that does not exist, which is the same answer we want anyway.
5402 if ( ! wdesignkit_path_inside_builder_dir( "$json_path.json" ) ) {
5403 return array(
5404 'success' => false,
5405 'message' => esc_html__( 'Widget JSON not found', 'wdesignkit' ),
5406 'description' => esc_html__( 'widget JSON file not found.', 'wdesignkit' ),
5407 );
5408 }
5409
5410 $json_data = wp_json_file_decode( "$json_path.json" );
5411 if ( ! empty( $json_data ) ) {
5412 $result = (object) array(
5413 'success' => true,
5414 'data' => $json_data,
5415 'message' => esc_html__( 'Widget get Successfully', 'wdesignkit' ),
5416 'description' => esc_html__( 'Widget JSON get Successfully', 'wdesignkit' ),
5417 );
5418 } else {
5419 $result = (object) array(
5420 'success' => false,
5421 'message' => esc_html__( 'Widget not get', 'wdesignkit' ),
5422 'description' => esc_html__( 'Widget JSON not get', 'wdesignkit' ),
5423 );
5424 }
5425
5426 wp_send_json( $result );
5427 wp_die();
5428 }
5429
5430 /**
5431 *
5432 * It is Use for download widget from widget listing.
5433 *
5434 * @since 1.0.0
5435 */
5436 protected function wdkit_download_widget() {
5437 $data = ! empty( $_POST['widget_info'] ) ? $this->wdkit_extract_post_field( $_POST, 'widget_info', 'none' ) : '';
5438 $data = json_decode( stripslashes( $data ) );
5439
5440 $array_data = array(
5441 'token' => isset( $data->token ) ? sanitize_text_field( $data->token ) : '',
5442 'type' => isset( $data->type ) ? sanitize_text_field( $data->type ) : '',
5443 'w_unique' => isset( $data->w_uniq ) ? sanitize_text_field( $data->w_uniq ) : '',
5444 // Bug F fix: u_id (widget owner's user ID) was missing — cloud cannot locate the widget without it.
5445 'u_id' => isset( $data->u_id ) ? sanitize_text_field( $data->u_id ) : '',
5446 );
5447
5448 $response = $this->wkit_api_call( $array_data, 'save_widget' );
5449 $success = ! empty( $response['success'] ) ? $response['success'] : false;
5450
5451 if ( empty( $success ) ) {
5452 $massage = ! empty( $response['massage'] ) ? $response['massage'] : esc_html__( 'server error', 'wdesignkit' );
5453 $result = (object) array(
5454 'success' => false,
5455 'message' => $massage,
5456 'description' => esc_html__( ' Widget not Downloaded', 'wdesignkit' ),
5457 );
5458
5459 wp_send_json( $result );
5460 wp_die();
5461 }
5462
5463 $response = json_decode( wp_json_encode( $response['data'] ), true );
5464
5465 if ( empty( $response ) || empty( $response['data'] ) ) {
5466 $message = ! empty( $response['message'] ) ? $response['message'] : 'No Response Found';
5467 $description = ! empty( $response['description'] ) ? $response['description'] : 'Widget not Downloaded';
5468
5469 $result = (object) array(
5470 'success' => false,
5471 'message' => esc_html( $message ),
5472 'description' => esc_html( $description ),
5473 );
5474
5475 wp_send_json( $result );
5476 wp_die();
5477 }
5478
5479 $img_url = ! empty( $response['data']['image'] ) ? $response['data']['image'] : '';
5480 $json_data = ! empty( $response['data']['json'] ) ? json_decode( $response['data']['json'], true ) : '';
5481
5482 // Bug E fix (part 1): $responce was a typo of $response — sent undefined variable (null) to frontend.
5483 if ( empty( $response['success'] ) ) {
5484 wp_send_json( $response );
5485 wp_die();
5486 }
5487
5488 if ( empty( $img_url ) && empty( $json_data ) ) {
5489 $responce = (object) array(
5490 'success' => false,
5491 'message' => esc_html__( 'No Response Found', 'wdesignkit' ),
5492 'description' => esc_html__( 'Widget not Downloaded', 'wdesignkit' ),
5493 );
5494
5495 wp_send_json( $responce );
5496 wp_die();
5497 }
5498
5499 include_once ABSPATH . 'wp-admin/includes/file.php';
5500 \WP_Filesystem();
5501 global $wp_filesystem;
5502
5503 if ( ! is_array( $json_data ) ) {
5504 $json_data = json_decode( $json_data, true );
5505 }
5506
5507 // Sanitize as filenames before use in the widget path (CWE-22): sanitize_file_name()
5508 // on name/id and sanitize_key() + allowlist on the builder strip path separators and
5509 // dots so a crafted cloud response cannot escape WDKIT_BUILDER_PATH.
5510 $title = ! empty( $json_data['widget_data']['widgetdata']['name'] ) ? sanitize_file_name( $json_data['widget_data']['widgetdata']['name'] ) : '';
5511 $builder = ! empty( $json_data['widget_data']['widgetdata']['type'] ) ? sanitize_key( $json_data['widget_data']['widgetdata']['type'] ) : '';
5512 $w_uniq = ! empty( $json_data['widget_data']['widgetdata']['widget_id'] ) ? sanitize_file_name( $json_data['widget_data']['widgetdata']['widget_id'] ) : '';
5513
5514 $allowed_builders = array( 'elementor', 'gutenberg', 'gutenberg_core', 'bricks' );
5515 if ( '' === $title || '' === $w_uniq || ! in_array( $builder, $allowed_builders, true ) ) {
5516 $responce = (object) array(
5517 'success' => false,
5518 'message' => esc_html__( 'Operation Failed!', 'wdesignkit' ),
5519 'description' => esc_html__( 'Invalid widget path.', 'wdesignkit' ),
5520 );
5521
5522 wp_send_json( $responce );
5523 wp_die();
5524 }
5525
5526 // Canonical helpers replace spaces BEFORE sanitize_file_name(). $title above is
5527 // already sanitized, which collapsed spaces to hyphens and left the underscore pass
5528 // with nothing to do — a multi-word title wrote "My-Widget_id.json" next to the
5529 // "My_Widget_id.php" the builder's save path writes. The loader pairs the two by
5530 // swapping .php for .json, so the widget was silently dropped (ClickUp 86d41cck5).
5531 $folder_name = wdesignkit_widget_folder_name( $title, $w_uniq );
5532 $file_name = wdesignkit_widget_file_name( $title, $w_uniq );
5533 $builder_type_path = WDKIT_BUILDER_PATH . "/{$builder}/";
5534
5535 if ( ! is_dir( $builder_type_path ) ) {
5536 wp_mkdir_p( $builder_type_path );
5537 }
5538
5539 if ( ! is_dir( $builder_type_path . $folder_name ) ) {
5540 wp_mkdir_p( $builder_type_path . $folder_name );
5541 }
5542
5543 if ( ! empty( $img_url ) ) {
5544 // SSRF guard (CWE-918): validate the resolved host before fetching.
5545 $img_body = wdesignkit_safe_remote_get( $img_url );
5546 if ( ! is_wp_error( $img_body ) ) {
5547 // The remote extension was written verbatim here, so a cloud response naming a
5548 // ".php" image put executable PHP in the builder directory (CWE-434,
5549 // ClickUp 86d41cczd). An empty return means the bytes are not an image.
5550 $img_ext = wdesignkit_safe_image_extension( $img_url, $img_body['body'] );
5551
5552 if ( '' !== $img_ext ) {
5553 $wp_filesystem->put_contents( WDKIT_BUILDER_PATH . "/$builder/$folder_name/$file_name.$img_ext", $img_body['body'] );
5554 $json_data['widget_data']['widgetdata']['w_image'] = WDKIT_SERVER_PATH . "/$builder/$folder_name/$file_name.$img_ext";
5555 }
5556 }
5557 }
5558
5559 if ( function_exists( 'wdesignkit_invalidate_widget_registry' ) ) {
5560 wdesignkit_invalidate_widget_registry( $builder );
5561 }
5562
5563 // Bug E fix (part 2): success was hardcoded false on the successful download path — always reported failure.
5564 $result = (object) array(
5565 'success' => true,
5566 'message' => ! empty( $response['message'] ) ? $response['message'] : esc_html__( 'no message', 'wdesignkit' ),
5567 'description' => '',
5568 'json' => wp_json_encode( $json_data ),
5569 );
5570
5571 wp_send_json( $result );
5572 wp_die();
5573 }
5574
5575 /**
5576 *
5577 * It is Use for sync widget to server
5578 *
5579 * @since 1.0.0
5580 */
5581 protected function wdkit_add_widget() {
5582 $data = ! empty( $_POST['widget_info'] ) ? $this->wdkit_extract_post_field( $_POST, 'widget_info', 'none' ) : '';
5583 $data = base64_decode( $data );
5584 $data = json_decode( $data );
5585
5586 $title = isset( $data->title ) ? sanitize_text_field( $data->title ) : '';
5587 $builder = isset( $data->builder ) ? sanitize_text_field( $data->builder ) : '';
5588 $w_uniq = isset( $data->w_uniq ) ? sanitize_text_field( $data->w_uniq ) : '';
5589 $w_image = isset( $data->w_image ) ? esc_url_raw( $data->w_image ) : '';
5590
5591 if ( ! empty( $w_image ) ) {
5592 $w_image = str_replace( '\\', '', $w_image );
5593 // SSRF guard (CWE-918): validate the resolved host before fetching.
5594 $fetched = wdesignkit_safe_remote_get( $w_image );
5595 $w_image = is_wp_error( $fetched ) ? '' : wp_remote_retrieve_body( $fetched );
5596 }
5597
5598 $array_data = array(
5599 'token' => isset( $data->token ) ? sanitize_text_field( $data->token ) : '',
5600 'type' => isset( $data->type ) ? sanitize_text_field( $data->type ) : '',
5601 'title' => isset( $data->title ) ? sanitize_text_field( $data->title ) : '',
5602 'content' => isset( $data->content ) ? sanitize_text_field( $data->content ) : '',
5603 'builder' => isset( $data->builder ) ? sanitize_text_field( $data->builder ) : '',
5604 'w_data' => isset( $data->w_data ) ? $data->w_data : '',
5605 'w_unique' => isset( $data->w_uniq ) ? sanitize_text_field( $data->w_uniq ) : '',
5606 'w_image' => $w_image,
5607 'w_imgext' => isset( $data->w_imgext ) ? sanitize_text_field( $data->w_imgext ) : '',
5608 'w_version' => isset( $data->w_version ) ? $data->w_version : '',
5609 'w_updates' => ! empty( $data->w_updates ) ? serialize( $data->w_updates ) : serialize( array() ),
5610 'r_id' => isset( $data->r_id ) ? $data->r_id : 0,
5611 'unique_id' => get_option( 'wdkit_unique_id' ) ?? '',
5612 );
5613
5614 $response = $this->wkit_api_call( $array_data, 'save_widget' );
5615 $success = ! empty( $response['success'] ) ? $response['success'] : false;
5616
5617 if ( empty( $success ) ) {
5618 $massage = ! empty( $response['massage'] ) ? $response['massage'] : esc_html__( 'server error', 'wdesignkit' );
5619
5620 $result = (object) array(
5621 'success' => false,
5622 'message' => $massage,
5623 'description' => esc_html__( 'Widget Not Added', 'wdesignkit' ),
5624 );
5625
5626 wp_send_json( $result );
5627 wp_die();
5628 }
5629
5630 $res = ! empty( $response['data'] ) ? $response['data'] : array();
5631
5632 $response = json_decode( wp_json_encode( $res ), true );
5633 $img_url = ! empty( $response['data']['imgurl'] ) ? $response['data']['imgurl'] : '';
5634
5635 if ( ! empty( $img_url ) && 'error' !== $res ) {
5636
5637 // SSRF guard (CWE-918): validate the resolved host before fetching.
5638 $img_body = wdesignkit_safe_remote_get( $img_url );
5639 if ( ! is_wp_error( $img_body ) ) {
5640 // Verified against the payload rather than trusted from the URL (CWE-434,
5641 // ClickUp 86d41cczd); '' means the bytes are not an image we accept.
5642 $img_ext = wdesignkit_safe_image_extension( $img_url, $img_body['body'] );
5643 include_once ABSPATH . 'wp-admin/includes/file.php';
5644 \WP_Filesystem();
5645 global $wp_filesystem;
5646 // Canonical helpers, so the JSON read and the image write here address the same
5647 // base name every other writer uses (ClickUp 86d41cck5). They also apply
5648 // sanitize_file_name(), which $title and $w_uniq had not been through.
5649 $folder_name = wdesignkit_widget_folder_name( $title, $w_uniq );
5650 $file_name = wdesignkit_widget_file_name( $title, $w_uniq );
5651
5652 // $builder reaches here with only sanitize_text_field() applied and no
5653 // allowlist, so it was a live traversal segment in this path (CWE-22,
5654 // ClickUp 86d41cckh). Unlike the download handler earlier in this file, this
5655 // one had neither the builder allowlist nor a containment check.
5656 $safe_path = wdesignkit_widget_path_guard( $builder, $folder_name, $file_name );
5657 if ( false === $safe_path || ! wdesignkit_path_inside_builder_dir( $safe_path['dir'] ) ) {
5658 wp_send_json(
5659 (object) array(
5660 'success' => false,
5661 'message' => esc_html__( 'Operation Failed!', 'wdesignkit' ),
5662 'description' => esc_html__( 'Invalid widget path.', 'wdesignkit' ),
5663 )
5664 );
5665 wp_die();
5666 }
5667
5668 $builder = $safe_path['builder'];
5669 $file_path = $safe_path['base'];
5670
5671 $u_r_l = wp_json_file_decode( "$file_path.json" );
5672
5673 if ( '' !== $img_ext ) {
5674 $u_r_l->widget_data->widgetdata->w_image = WDKIT_SERVER_PATH . "/$builder/$folder_name/$file_name.$img_ext";
5675 $wp_filesystem->put_contents( "$file_path.$img_ext", $img_body['body'] );
5676 }
5677
5678 $wp_filesystem->put_contents( "$file_path.json", wp_json_encode( $u_r_l ) );
5679 }
5680 }
5681
5682 wp_send_json( $response );
5683 wp_die();
5684 }
5685
5686 /**
5687 *
5688 * It is Use for manage favourite widget
5689 *
5690 * @since 1.0.0
5691 */
5692 protected function wdkit_favourite_widget() {
5693 $data = isset( $_POST['widget_info'] ) ? json_decode( stripslashes( sanitize_text_field( wp_unslash( $_POST['widget_info'] ) ) ) ) : '';
5694 $array_data = array(
5695 'token' => isset( $data->token ) ? sanitize_text_field( $data->token ) : '',
5696 'type' => isset( $data->type ) ? sanitize_text_field( $data->type ) : '',
5697 'w_unique' => isset( $data->w_uniq ) ? sanitize_text_field( $data->w_uniq ) : '',
5698 );
5699
5700 $response = $this->wkit_api_call( $array_data, 'save_widget' );
5701 $success = ! empty( $response['success'] ) ? $response['success'] : false;
5702
5703 if ( empty( $success ) ) {
5704 $massage = ! empty( $response['massage'] ) ? $response['massage'] : esc_html__( 'server error', 'wdesignkit' );
5705
5706 $result = (object) array(
5707 'success' => false,
5708 'message' => $massage,
5709 'description' => '',
5710 );
5711
5712 wp_send_json( $result );
5713 wp_die();
5714 }
5715
5716 wp_send_json( $response );
5717 wp_die();
5718 }
5719
5720 /**
5721 * It is Used Setting Panel Defalut Data Get.
5722 *
5723 * @since 1.0.0
5724 */
5725 protected function wdkit_setting_panel() {
5726 $event = ! empty( $_POST['event'] ) ? sanitize_text_field( wp_unslash( $_POST['event'] ) ) : 'get';
5727
5728 if ( 'get' === $event ) {
5729 return self::wkit_get_settings_panel();
5730 } elseif ( 'set' === $event ) {
5731 $data = ! empty( $_POST['data'] ) ? stripslashes( sanitize_text_field( wp_unslash( $_POST['data'] ) ) ) : array();
5732
5733 $data = json_decode( $data, true );
5734
5735 update_option( 'wkit_settings_panel', $data );
5736 return self::wkit_get_settings_panel();
5737 } else {
5738 return false;
5739 }
5740 }
5741
5742 /**
5743 * Get Setting Panal Data
5744 *
5745 * @since 1.0.0
5746 */
5747 protected static function wkit_get_settings_panel() {
5748 $new_version = '';
5749 $current_version = WDKIT_VERSION;
5750 $response = wp_remote_get( 'https://api.wordpress.org/plugins/info/1.0/wdesignkit.json' );
5751
5752 if ( is_wp_error( $response ) ) {
5753 return false;
5754 }
5755
5756 $body = wp_remote_retrieve_body( $response );
5757 $data = json_decode( $body );
5758
5759 if ( isset( $data->version ) ) {
5760 $new_version = $data->version;
5761 }
5762
5763 $version_check = array();
5764
5765 if ( $new_version && version_compare( $current_version, $new_version, '<' ) ) {
5766 $version_check['success'] = true;
5767 $version_check['version'] = $new_version;
5768 } else {
5769 $version_check['success'] = false;
5770 $version_check['version'] = $new_version;
5771 }
5772
5773 $get_setting = get_option( 'wkit_settings_panel', false );
5774
5775 $setting_data = array(
5776 'builder' => isset( $get_setting['builder'] ) ? $get_setting['builder'] : true,
5777 'template' => isset( $get_setting['template'] ) ? $get_setting['template'] : true,
5778 'gutenberg_builder' => isset( $get_setting['gutenberg_builder'] ) ? $get_setting['gutenberg_builder'] : true,
5779 'gutenberg_core_builder' => isset( $get_setting['gutenberg_core_builder'] ) ? $get_setting['gutenberg_core_builder'] : false,
5780 'elementor_builder' => isset( $get_setting['elementor_builder'] ) ? $get_setting['elementor_builder'] : true,
5781 'bricks_builder' => isset( $get_setting['bricks_builder'] ) ? $get_setting['bricks_builder'] : false,
5782 'gutenberg_template' => isset( $get_setting['gutenberg_template'] ) ? $get_setting['gutenberg_template'] : true,
5783 'elementor_template' => isset( $get_setting['elementor_template'] ) ? $get_setting['elementor_template'] : true,
5784 'code_snippet' => isset( $get_setting['code_snippet'] ) ? $get_setting['code_snippet'] : true,
5785 'cross_copy_paste' => isset( $get_setting['cross_copy_paste'] ) ? $get_setting['cross_copy_paste'] : false,
5786 'cross_copy_paste_elementor' => isset( $get_setting['cross_copy_paste_elementor'] ) ? $get_setting['cross_copy_paste_elementor'] : false,
5787 'cross_copy_paste_gutenberg' => isset( $get_setting['cross_copy_paste_gutenberg'] ) ? $get_setting['cross_copy_paste_gutenberg'] : false,
5788 'cross_copy_paste_bricks' => isset( $get_setting['cross_copy_paste_bricks'] ) ? $get_setting['cross_copy_paste_bricks'] : false,
5789 'plugin_version' => $version_check,
5790 );
5791
5792 if ( isset( $get_setting['remove_db'] ) ) {
5793 $setting_data['remove_db'] = $get_setting['remove_db'];
5794 }
5795
5796 if ( isset( $get_setting['debugger_mode'] ) ) {
5797 $setting_data['debugger_mode'] = $get_setting['debugger_mode'];
5798 }
5799
5800 return $setting_data;
5801 }
5802
5803 /**
5804 * Updated White Label Data.
5805 *
5806 * @since 1.1.8
5807 */
5808 protected function wkit_white_label() {
5809
5810 $get_wl_data = ! empty( $_POST['WhiteLabelData'] ) ? wp_unslash( $_POST['WhiteLabelData'] ) : array();
5811
5812 if ( ! empty( $get_wl_data ) ) {
5813 $white_label_data = json_decode( $get_wl_data, true );
5814 $plugin_name = $white_label_data['plugin_name'];
5815 } else {
5816 $result = array(
5817 'success' => false,
5818 'message' => esc_html__( 'Data Not Found', 'wdesignkit' ),
5819 );
5820
5821 wp_send_json( $result );
5822 wp_die();
5823 }
5824
5825 if ( ! empty( $plugin_name ) ) {
5826 $get_white_label = get_option( 'wkit_white_label', false );
5827 if ( ! empty( $get_white_label ) ) {
5828 update_option( 'wkit_white_label', $white_label_data );
5829 } else {
5830 add_option( 'wkit_white_label', $white_label_data );
5831 }
5832 } else {
5833 $result = array(
5834 'success' => false,
5835 'message' => esc_html__( 'Plugin Name Not Found', 'wdesignkit' ),
5836 );
5837
5838 wp_send_json( $result );
5839 wp_die();
5840 }
5841
5842 $get_updated_data = get_option( 'wkit_white_label', false );
5843 $response = array(
5844 'message' => __( 'Data Added successfully', 'wdesignkit' ),
5845 'success' => true,
5846 'data' => $get_updated_data,
5847 );
5848
5849 wp_send_json( $response );
5850 }
5851
5852 /**
5853 * Reset White Label Data.
5854 *
5855 * @since 1.1.8
5856 */
5857 public function wkit_reset_wl() {
5858 $wl_data = get_option( 'wkit_white_label' );
5859
5860 if ( ! empty( $wl_data ) ) {
5861 delete_option( 'wkit_white_label' );
5862
5863 $result = array(
5864 'success' => true,
5865 'message' => esc_html__( 'Reset White Label Successfully', 'wdesignkit' ),
5866 );
5867
5868 wp_send_json( $result );
5869 wp_die();
5870 }
5871 }
5872
5873 /**
5874 *
5875 * Use for Add new licence key.
5876 *
5877 * @since 1.0.0
5878 */
5879 protected function wdkit_activate_licence() {
5880 $args = array(
5881 'token' => ! empty( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '',
5882 'licencekey' => ! empty( $_POST['licencekey'] ) ? sanitize_text_field( wp_unslash( $_POST['licencekey'] ) ) : '',
5883 'licencename' => ! empty( $_POST['licencename'] ) ? sanitize_text_field( wp_unslash( $_POST['licencename'] ) ) : '',
5884 'uichemyid' => ! empty( $_POST['uichemyid'] ) ? sanitize_text_field( wp_unslash( $_POST['uichemyid'] ) ) : '',
5885 );
5886
5887 $response = $this->wkit_api_call( $args, 'wkit_activate_key' );
5888
5889 if ( ! empty( $response['data'] ) ) {
5890 $response = json_decode( wp_json_encode( $response['data'] ), true );
5891
5892 if ( ! empty( $response['data']['tpae_licence'] ) && is_serialized( $response['data']['tpae_licence'] ) ) {
5893 $response['data']['tpae_licence'] = unserialize( $response['data']['tpae_licence'], array( 'allowed_classes' => false ) );
5894 }
5895
5896 if ( ! empty( $response['data']['tpag_licence'] ) && is_serialized( $response['data']['tpag_licence'] ) ) {
5897 $response['data']['tpag_licence'] = unserialize( $response['data']['tpag_licence'], array( 'allowed_classes' => false ) );
5898 }
5899
5900 if ( ! empty( $response['data']['uichemy_licence'] ) && is_serialized( $response['data']['uichemy_licence'] ) ) {
5901 $response['data']['uichemy_licence'] = unserialize( $response['data']['uichemy_licence'], array( 'allowed_classes' => false ) );
5902 }
5903
5904 if ( ! empty( $response['data']['wdkit_licence'] ) && is_serialized( $response['data']['wdkit_licence'] ) ) {
5905 $response['data']['wdkit_licence'] = unserialize( $response['data']['wdkit_licence'], array( 'allowed_classes' => false ) );
5906
5907 // Store WDesignKit license status locally for quick access
5908 if ( ! empty( $response['data']['wdkit_licence'] ) && is_array( $response['data']['wdkit_licence'] ) ) {
5909 update_option( 'wdkit_licence_data', $response['data']['wdkit_licence'] );
5910 }
5911 }
5912
5913 if ( ! empty( $response['data']['wdkit_licence_extra'] ) && is_serialized( $response['data']['wdkit_licence_extra'] ) ) {
5914 $response['data']['wdkit_licence_extra'] = unserialize( $response['data']['wdkit_licence_extra'], array( 'allowed_classes' => false ) );
5915 }
5916 }
5917
5918 wp_send_json( $response );
5919 wp_die();
5920 }
5921
5922 /**
5923 *
5924 * Use for Delete licence key.
5925 *
5926 * @since 1.0.0
5927 */
5928 protected function wdkit_delete_licence_key() {
5929 $token = ! empty( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '';
5930 $licencename = ! empty( $_POST['licencename'] ) ? sanitize_text_field( wp_unslash( $_POST['licencename'] ) ) : '';
5931 $apikey = ! empty( $_POST['apikey'] ) ? sanitize_text_field( wp_unslash( $_POST['apikey'] ) ) : '';
5932
5933 $args = array(
5934 'token' => $token,
5935 'licencename' => $licencename,
5936 'apikey' => $apikey,
5937 );
5938
5939 $response = $this->wkit_api_call( $args, 'licence_delete' );
5940
5941 // Remove local WDesignKit license data if deleting WDesignKit license
5942 if ( 'wdkit' === $licencename ) {
5943 delete_option( 'wdkit_licence_data' );
5944 }
5945
5946 wp_send_json( $response['data'] );
5947 wp_die();
5948 }
5949
5950 /**
5951 *
5952 * Use for Sync licence key.
5953 *
5954 * @since 1.0.0
5955 */
5956 protected function wdkit_sync_licence_key() {
5957 $token = ! empty( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '';
5958 $licencename = ! empty( $_POST['licencename'] ) ? sanitize_text_field( wp_unslash( $_POST['licencename'] ) ) : '';
5959 // Needed to identify which extra-credit key to sync (wdkit_extra / wdkit_ai_extra
5960 // are arrays matched by the api key's last digits on the server).
5961 $apikey = ! empty( $_POST['apikey'] ) ? sanitize_text_field( wp_unslash( $_POST['apikey'] ) ) : '';
5962
5963 $args = array(
5964 'token' => $token,
5965 'licencename' => $licencename,
5966 'apikey' => $apikey,
5967 );
5968
5969 $response = $this->wkit_api_call( $args, 'licence_sync' );
5970
5971 wp_send_json( $response['data'] );
5972 wp_die();
5973 }
5974
5975 /**
5976 * Rollback to Previous Versions
5977 *
5978 * @since 1.1.0
5979 */
5980 protected function wdkit_prev_version() {
5981
5982 require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
5983
5984 $plugin_info = plugins_api(
5985 'plugin_information',
5986 array(
5987 'slug' => 'wdesignkit',
5988 )
5989 );
5990
5991 if ( empty( $plugin_info->versions ) || ! is_array( $plugin_info->versions ) ) {
5992 return array();
5993 }
5994
5995 krsort( $plugin_info->versions );
5996
5997 $versions_list = array();
5998 $index = 0;
5999
6000 foreach ( $plugin_info->versions as $version => $download_link ) {
6001
6002 $lowercase_version = strtolower( $version );
6003
6004 $is_valid_version = ! preg_match( '/(beta|rc|trunk|dev)/i', $lowercase_version );
6005
6006 $is_valid_version = apply_filters( 'wdkit_check_rollback_version', $is_valid_version, $lowercase_version );
6007
6008 if ( ! $is_valid_version || version_compare( $version, WDKIT_VERSION, '>=' ) ) {
6009 continue;
6010 }
6011
6012 $versions_list[] = $version;
6013 ++$index;
6014 }
6015
6016 // set_transient( 'wdkit_rollback_version_' . WDKIT_VERSION, $versions_list, WEEK_IN_SECONDS );
6017
6018 return $versions_list;
6019 }
6020
6021 /**
6022 * Rollback to Previous Versions
6023 *
6024 * @since 1.1.0
6025 */
6026 protected function wdkit_rollback_check() {
6027
6028 $current_ver = isset( $_POST['version'] ) ? sanitize_text_field( wp_unslash( $_POST['version'] ) ) : '';
6029 $rv = $this->wdkit_prev_version();
6030
6031 if ( empty( $current_ver ) || ! in_array( $current_ver, $rv ) ) {
6032 return array(
6033 'message' => esc_html__( 'Invalid Nonce or version not found', 'wdesignkit' ),
6034 'status' => 'error',
6035 'success' => false,
6036 );
6037 }
6038
6039 $plugin_slug = basename( WDKIT_PBNAME, '.php' );
6040
6041 $this_version = $current_ver;
6042 $this_pluginname = WDKIT_PBNAME;
6043 $this_plugin_u_r_l = sprintf( 'https://downloads.wordpress.org/plugin/%s.%s.zip', $plugin_slug, $this_version );
6044
6045 $plugin_info = new \stdClass();
6046 $plugin_info->new_version = $this_version;
6047 $plugin_info->slug = $plugin_slug;
6048 $plugin_info->package = $this_plugin_u_r_l;
6049 $plugin_info->url = 'https://wdesignkit.com/';
6050
6051 $update_plugins_data = get_site_transient( 'update_plugins' );
6052
6053 if ( ! is_object( $update_plugins_data ) ) {
6054 $update_plugins_data = new \stdClass();
6055 }
6056
6057 $update_plugins_data->response[ $this_pluginname ] = $plugin_info;
6058
6059 set_site_transient( 'update_plugins', $update_plugins_data );
6060
6061 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
6062
6063 $logo_url = WDKIT_URL . 'assets/images/jpg/Wdesignkit-logo.png';
6064
6065 $args = array(
6066 'url' => 'update.php?action=upgrade-plugin&plugin=' . rawurlencode( $this_pluginname ),
6067 'plugin' => $this_pluginname,
6068 'nonce' => 'upgrade-plugin_' . $this_pluginname,
6069 'title' => '<img src="' . esc_url( $logo_url ) . '" alt="wdesignkit-logo"><div class="theplus-rb-subtitle">' . esc_html__( 'Rollback to Previous Version', 'wdesignkit' ) . '</div>',
6070 );
6071
6072 $upgrader_plugin = new \Plugin_Upgrader( new \Plugin_Upgrader_Skin( $args ) );
6073 $upgrader_plugin->upgrade( $this_pluginname );
6074
6075 activate_plugin( $this_pluginname );
6076
6077 return array(
6078 'message' => esc_html__( 'Rollback Successful, Plugin Re-activated', 'wdesignkit' ),
6079 'status' => 'Success',
6080 'success' => true,
6081 );
6082 }
6083
6084 /**
6085 *
6086 * It is Use for logout.
6087 *
6088 * @since 1.0.0
6089 */
6090 protected function wdkit_logout() {
6091 $email = isset( $_POST['email'] ) ? strtolower( sanitize_email( wp_unslash( $_POST['email'] ) ) ) : false;
6092 $logout_type = isset( $_POST['logout_type'] ) ? strtolower( sanitize_text_field( wp_unslash( $_POST['logout_type'] ) ) ) : '';
6093
6094 $response = '';
6095
6096 if ( ! empty( $email ) ) {
6097 $token = $this->wdkit_login_user_token( $email );
6098 $args = array( 'token' => $token );
6099
6100 if ( 'session' !== $logout_type ) {
6101 delete_transient( 'wdkit_auth_' . wdesignkit_cloud_session_key( $email ) );
6102 // Clear stored license data on logout so banner shows again
6103 delete_option( 'wdkit_licence_data' );
6104 $response = WDesignKit_Data_Query::get_data( 'logout', $args );
6105 }
6106 }
6107
6108 wp_send_json( $response );
6109 wp_die();
6110 }
6111
6112 /**
6113 *
6114 * It is Use for get token of login user.
6115 *
6116 * @since 1.0.0
6117 *
6118 * @param string $email check user email.
6119 */
6120 protected function wdkit_login_user_token( $email = '' ) {
6121
6122 if ( ! empty( $email ) ) {
6123 $user_key = wdesignkit_cloud_session_key( $email );
6124 $get_login = get_transient( 'wdkit_auth_' . $user_key );
6125
6126 if ( ! empty( $get_login ) && ! empty( $get_login['token'] ) ) {
6127 return $get_login['token'];
6128 }
6129 }
6130
6131 return false;
6132 }
6133
6134 /**
6135 * Parse args $_POST
6136 *
6137 * @since 1.0.0
6138 *
6139 * @param string $data send all post data.
6140 * @param string $type store text data.
6141 * @param string $condition store text data.
6142 */
6143 protected function wdkit_extract_post_field( $data, $type, $condition = 'none' ) {
6144
6145 if ( 'none' === $condition ) {
6146 return $data[ $type ];
6147 } elseif ( 'cr_widget' === $condition ) {
6148 return $data[ $type ];
6149 }
6150
6151 return null;
6152 }
6153
6154
6155 /**
6156 * Parse args $_POST
6157 *
6158 * @since 1.0.0
6159 *
6160 * @param string $data send all post data.
6161 */
6162 protected function wdkit_parse_args( $data = array() ) {
6163 if ( empty( $data ) ) {
6164 return array();
6165 }
6166
6167 $args = array();
6168 if ( isset( $data['email'] ) ) {
6169 $args['email'] = isset( $data['email'] ) ? sanitize_email( $data['email'] ) : '';
6170 }
6171
6172 if ( isset( $data['data'] ) ) {
6173 $args['data'] = isset( $data['data'] ) ? wp_unslash( $data['data'] ) : array();
6174 }
6175
6176 if ( isset( $data['plugins'] ) ) {
6177 $args['plugins'] = isset( $data['plugins'] ) ? wp_unslash( $data['plugins'] ) : array();
6178 }
6179
6180 if ( isset( $data['template_id'] ) ) {
6181 $args['template_id'] = isset( $data['template_id'] ) ? intval( strtolower( sanitize_text_field( $data['template_id'] ) ) ) : '';
6182 }
6183
6184 if ( isset( $data['builder'] ) ) {
6185 $args['builder'] = isset( $data['builder'] ) ? wp_unslash( $data['builder'] ) : '';
6186 }
6187
6188 if ( isset( $data['editor'] ) ) {
6189 $args['editor'] = isset( $data['editor'] ) ? sanitize_text_field( $data['editor'] ) : '';
6190 }
6191
6192 if ( isset( $data['type_upload'] ) ) {
6193 $args['type_upload'] = isset( $data['type_upload'] ) ? sanitize_text_field( $data['type_upload'] ) : '';
6194 }
6195
6196 if ( isset( $data['title'] ) ) {
6197 $args['title'] = isset( $data['title'] ) ? wp_strip_all_tags( $data['title'] ) : '';
6198 }
6199
6200 if ( isset( $data['template_type'] ) ) {
6201 $args['template_type'] = isset( $data['template_type'] ) ? sanitize_text_field( $data['template_type'] ) : '';
6202 }
6203
6204 if ( isset( $data['wstype'] ) ) {
6205 $args['wstype'] = isset( $data['wstype'] ) ? wp_strip_all_tags( $data['wstype'] ) : '';
6206 }
6207
6208 if ( isset( $data['wid'] ) ) {
6209 $args['wid'] = isset( $data['wid'] ) ? intval( strtolower( sanitize_text_field( $data['wid'] ) ) ) : '';
6210 }
6211
6212 if ( isset( $data['perpage'] ) ) {
6213 $args['perpage'] = isset( $data['perpage'] ) ? intval( strtolower( sanitize_text_field( $data['perpage'] ) ) ) : 12;
6214 }
6215
6216 if ( isset( $data['page'] ) ) {
6217 $args['page'] = isset( $data['page'] ) ? intval( strtolower( sanitize_text_field( $data['page'] ) ) ) : 1;
6218 }
6219
6220 if ( isset( $data['buildertype'] ) ) {
6221 $args['buildertype'] = isset( $data['buildertype'] ) ? sanitize_text_field( $data['buildertype'] ) : '';
6222 }
6223
6224 if ( isset( $data['search'] ) ) {
6225 $args['search'] = isset( $data['search'] ) ? sanitize_text_field( $data['search'] ) : '';
6226 }
6227
6228 if ( isset( $data['plugin'] ) ) {
6229 $args['plugin'] = isset( $data['plugin'] ) ? wp_unslash( $data['plugin'] ) : array();
6230 }
6231
6232 if ( isset( $data['plugin_exclude'] ) ) {
6233 $args['plugin_exclude'] = isset( $data['plugin_exclude'] ) ? wp_unslash( $data['plugin_exclude'] ) : array();
6234 }
6235
6236 if ( isset( $data['ai_compatibility'] ) ) {
6237 $args['ai_compatibility'] = isset( $data['ai_compatibility'] ) ? wp_unslash( $data['ai_compatibility'] ) : array();
6238 }
6239
6240 // if ( isset( $data['global_color'] ) ) {
6241 // $args['global_color'] = isset( $data['global_color'] ) ? wp_unslash( $data['global_color'] ) : array();
6242 // }
6243
6244 // if ( isset( $data['global_font_family'] ) ) {
6245 // $args['global_font_family'] = isset( $data['global_font_family'] ) ? wp_unslash( $data['global_font_family'] ) : array();
6246 // }
6247
6248 if ( isset( $data['global_data'] ) ) {
6249 $args['global_data'] = isset( $data['global_data'] ) ? wp_unslash( $data['global_data'] ) : array();
6250 }
6251
6252 if ( isset( $data['tag'] ) ) {
6253 $args['tag'] = isset( $data['tag'] ) ? wp_unslash( $data['tag'] ) : array();
6254 }
6255
6256 if ( isset( $data['category'] ) ) {
6257 $args['category'] = isset( $data['category'] ) ? wp_unslash( $data['category'] ) : array();
6258 }
6259
6260 if ( isset( $data['free_pro'] ) ) {
6261 $args['free_pro'] = isset( $data['free_pro'] ) ? sanitize_text_field( wp_unslash( $data['free_pro'] ) ) : '';
6262 }
6263
6264 if ( isset( $data['wp_post_type'] ) ) {
6265 $args['wp_post_type'] = isset( $data['wp_post_type'] ) ? sanitize_text_field( wp_unslash( $data['wp_post_type'] ) ) : '';
6266 }
6267
6268 if ( isset( $data['favorite'] ) ) {
6269 $args['favorite'] = isset( $data['favorite'] ) ? sanitize_text_field( wp_unslash( $data['favorite'] ) ) : '';
6270 }
6271
6272 if ( isset( $data['content'] ) ) {
6273 $args['content'] = isset( $data['content'] ) ? wp_unslash( $data['content'] ) : '';
6274 }
6275
6276 if ( isset( $data['page_type'] ) ) {
6277 $args['page_type'] = isset( $data['page_type'] ) ? wp_unslash( $data['page_type'] ) : array();
6278 }
6279
6280 return $args;
6281 }
6282
6283 /**
6284 * Dark Mode
6285 *
6286 * @since 2.0.0
6287 *
6288 * @param string store darkmode value in database.
6289 */
6290 protected function wdkit_dark_mode() {
6291 $dark_mode = ! empty( $_POST['dark_mode'] ) ? sanitize_text_field( $_POST['dark_mode'] ) : 'light';
6292
6293 if ( get_option( 'wdkit_dark_mode' ) ) {
6294 update_option( 'wdkit_dark_mode', $dark_mode );
6295 } else {
6296 add_option( 'wdkit_dark_mode', $dark_mode );
6297 }
6298
6299 $response = array(
6300 'message' => esc_html__( 'Dark Mode Updated', 'wdesignkit' ),
6301 'status' => 'Success',
6302 'success' => true,
6303 );
6304
6305 wp_send_json( $response );
6306 wp_die();
6307 }
6308 }
6309
6310 Wdkit_Api_Call::get_instance();
6311 }
6312