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