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 +4419 -1044 1.0.13trunk 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,175 +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 - $site_url = isset( $_POST['site_url'] ) ? esc_url_raw( wp_unslash( $_POST['site_url'] ) ) : '';
485 -
486 - $user_key = strstr( $user_email, '@', true );
487 - $response = '';
488 -
489 - delete_transient( 'wdkit_auth_' . $user_key );
490 -
491 - $get_login = get_transient( 'wdkit_auth_' . $user_key );
492 -
493 - if ( ! empty( $user_email ) && ! empty( $user_password ) && false === $get_login ) {
494 - $response = WDesignKit_Data_Query::get_data(
495 - 'login',
496 - array(
497 - 'user_email' => $user_email,
498 - 'password' => $user_password,
499 - 'site_url' => $site_url,
500 - )
501 - );
502 -
503 - if ( ! empty( $response ) && ! empty( $response['success'] ) ) {
504 - if ( ! empty( $response['message'] ) && ! empty( $response['token'] ) ) {
505 - if ( false === get_transient( 'wdkit_auth_' . $user_key ) ) {
506 - $this->wdkit_set_time_out( $user_key, $user_email, $response['token'], $login_type );
507 - }
508 - }
509 - }
510 - } elseif ( ! empty( $get_login ) && ! empty( $get_login['token'] ) ) {
511 - $response = array_merge(
512 - array(
513 - 'success' => true,
514 - 'message' => esc_html__( 'Success! Login successful.', 'wdesignkit' ),
515 - 'description' => esc_html__( 'Login successful. Keep it up!', 'wdesignkit' ),
516 - ),
517 - $get_login
518 - );
519 - }
520 -
521 - wp_send_json( $response );
522 - wp_die();
523 - }
524 -
525 - /**
526 - *
527 - * This Function is used for Login with Api (token)
528 - *
529 - * @version 1.0.0
530 - * @access public
531 - */
532 - protected function wdkit_api_login() {
533 - $user_token = isset( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '';
534 - $login_type = isset( $_POST['login_type'] ) ? sanitize_text_field( wp_unslash( $_POST['login_type'] ) ) : '';
535 -
536 - $site_url = isset( $_POST['site_url'] ) ? esc_url_raw( wp_unslash( $_POST['site_url'] ) ) : '';
537 -
538 - if ( empty( $user_token ) ) {
539 - $result = array(
540 - 'success' => false,
541 - 'token' => '',
542 - 'data' => array(
543 - 'message' => $this->e_msg_login,
544 - 'description' => $this->e_desc_login,
545 - ),
546 - );
547 -
548 - wp_send_json( $result );
549 - wp_die();
550 - }
551 -
552 - $array_data = array(
553 - 'token' => $user_token,
554 - 'site_url' => $site_url,
555 - );
556 -
557 - $response = $this->wkit_api_call( $array_data, 'login/api' );
558 -
559 - $success = ! empty( $response['success'] ) ? is_bool( $response['success'] ) : false;
560 -
561 - if ( empty( $success ) ) {
562 - $result = array(
563 - 'data' => $response,
564 - 'token' => '',
565 - 'success' => false,
566 - );
567 -
568 - wp_send_json( $result );
569 - wp_die();
570 - }
571 -
572 - $response = json_decode( wp_json_encode( $response['data'] ), true );
573 - $user_email = ! empty( $response['user']['user_email'] ) ? sanitize_email( $response['user']['user_email'] ) : '';
574 - $user_key = strstr( $user_email, '@', true );
575 -
576 - $this->wdkit_set_time_out( $user_key, $user_email, $user_token, $login_type );
577 -
578 - $result = array(
579 - 'success' => true,
580 - 'data' => $response,
581 - 'token' => $user_token,
582 - );
583 -
584 - wp_send_json( $result );
585 - wp_die();
586 - }
587 -
588 - /**
589 - *
590 - * This Function is used for social Login
591 - *
592 - * @version 1.0.0
593 - * @access public
594 - */
595 - protected function wdkit_social_login() {
596 - $user_state = isset( $_POST['state'] ) ? sanitize_text_field( wp_unslash( $_POST['state'] ) ) : '';
597 - $login_type = isset( $_POST['login_type'] ) ? sanitize_text_field( wp_unslash( $_POST['login_type'] ) ) : '';
598 -
599 - $site_url = isset( $_POST['site_url'] ) ? esc_url_raw( wp_unslash( $_POST['site_url'] ) ) : '';
600 -
601 - $array_data = array(
602 - 'state' => $user_state,
603 - 'site_url' => $site_url
604 - );
605 -
606 - $response = $this->wkit_api_call( $array_data, 'login/ip' );
607 - $success = ! empty( $response['success'] ) ? $response['success'] : false;
608 -
609 - if ( empty( $success ) ) {
610 - $result = array(
611 - 'data' => $response,
612 - 'success' => false,
613 - );
614 -
615 - wp_send_json( $result );
616 - wp_die();
617 - }
618 -
619 - $response = json_decode( wp_json_encode( $response['data'] ), true );
620 - $user_email = ! empty( $response['user']['user_email'] ) ? sanitize_email( $response['user']['user_email'] ) : '';
621 - $user_token = ! empty( $response['token'] ) ? sanitize_text_field( $response['token'] ) : '';
622 - $user_key = strstr( $user_email, '@', true );
623 -
624 - if ( ! empty( $response ) && ! empty( $user_token ) ) {
625 - $this->wdkit_set_time_out( $user_key, $user_email, $user_token, $login_type );
626 - }
627 -
628 - $result = array(
629 - 'data' => $response,
630 - 'token' => $user_token,
631 - );
632 -
633 - wp_send_json( $result );
634 - wp_die();
635 - }
636 -
637 - /**
638 - *
639 - * It is Use for get meta data for non login user
640 - *
641 - * @since 1.0.0\
642 - */
643 715 protected function wdkit_meta_data() {
644 716 $type = isset( $_POST['meta_type'] ) ? sanitize_text_field( wp_unslash( $_POST['meta_type'] ) ) : '';
645 717 $data = array( 'type' => $type );
646 718
@@ -670,9 +742,10 @@
670 742 $statuscode = array( 'HTTP_CODE' => $status );
671 743
672 744 $final = json_decode( wp_json_encode( $get_data_one ), true );
673 745
674 - $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() );
675 748
676 749 $final = array(
677 750 'data' => $final,
678 751 );
@@ -682,14 +755,49 @@
682 755 }
683 756
684 757 /**
685 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 + *
686 794 * It is Use for get all info of user.
687 795 *
688 796 * @since 1.0.0
689 - * @access public
690 797 */
691 798 protected function wdkit_get_user_info() {
799 + $token = isset( $_POST['token'] ) ? wp_unslash( $_POST['token'] ) : false;
692 800 $email = isset( $_POST['email'] ) ? strtolower( sanitize_email( wp_unslash( $_POST['email'] ) ) ) : false;
693 801 $builder = isset( $_POST['builder'] ) ? strtolower( sanitize_text_field( wp_unslash( $_POST['builder'] ) ) ) : '';
694 802
695 803 $site_url = isset( $_POST['site_url'] ) ? esc_url_raw( wp_unslash( $_POST['site_url'] ) ) : '';
@@ -695,9 +803,9 @@
695 803 $site_url = isset( $_POST['site_url'] ) ? esc_url_raw( wp_unslash( $_POST['site_url'] ) ) : '';
696 804
697 805 $response = array();
698 806
699 - if ( empty( $email ) ) {
807 + if ( empty( $token ) ) {
700 808 $response = array(
701 809 'success' => false,
702 810 'message' => $this->e_msg_login,
703 811 'description' => $this->e_desc_login,
@@ -706,26 +814,56 @@
706 814 wp_send_json( $response );
707 815 wp_die();
708 816 }
709 817
710 - $token = $this->wdkit_login_user_token( $email );
711 - $args = array(
712 - 'token' => $token,
713 - 'builder' => $builder,
818 + // $token = $this->wdkit_login_user_token( $email );
819 + $args = array(
820 + 'token' => $token,
821 + 'builder' => $builder,
714 822 'site_url' => $site_url,
715 823 );
716 824
717 825 $response = WDesignKit_Data_Query::get_data( 'get_user_info', $args );
718 - $status = ( ! empty( $response['status'] ) ) ? sanitize_text_field( $response['status'] ) : 'error';
719 - $email = isset( $_POST['email'] ) ? strtolower( sanitize_email( wp_unslash( $_POST['email'] ) ) ) : false;
720 826
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 + }
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 +
721 839 /**Condtion user for user logout & expire token*/
722 840 if ( 'Token is Expired' === $status || 'Authorization Token not found' === $status ) {
723 - 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' );
724 844 }
725 845
726 - $response['Setting'] = self::wkit_get_settings_panel();
846 + if ( empty( $response ) ) {
847 + $response['login_reset'] = 'yes';
848 + }
727 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 +
728 866 $response = array(
729 867 'data' => $response,
730 868 'success' => true,
731 869 );
@@ -734,57 +872,166 @@
734 872 wp_die();
735 873 }
736 874
737 875 /**
738 - * Browse Page Filter
739 876 *
740 - * @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.
741 881 */
742 - protected function wdkit_browse_page() {
743 - $args = $this->wdkit_parse_args( $_POST );
882 + protected function wkit_manage_widget_sequence( $response = array() ) {
744 883
745 - $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();
746 887
747 - wp_send_json( $response );
748 - 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;
749 1009 }
750 1010
751 1011 /**
1012 + * Browse Page Filter
752 1013 *
753 - * It is Use to get data for widget browse page
754 - *
755 1014 * @since 1.0.0
756 - * @access public
757 1015 */
758 - protected function wdkit_widget_browse_page() {
759 - $array_data = array(
760 - 'CurrentPage' => isset( $_POST['page'] ) ? (int) $_POST['page'] : 1,
761 - 'builder' => isset( $_POST['buildertype'] ) ? sanitize_text_field( wp_unslash( $_POST['buildertype'] ) ) : '',
762 - 'category' => isset( $_POST['category'] ) ? sanitize_text_field( wp_unslash( $_POST['category'] ) ) : '',
763 - 'ParPage' => isset( $_POST['perpage'] ) ? (int) $_POST['perpage'] : 12,
764 - 'search' => isset( $_POST['search'] ) ? sanitize_text_field( wp_unslash( $_POST['search'] ) ) : '',
765 - 'free_pro' => isset( $_POST['free_pro'] ) ? sanitize_text_field( wp_unslash( $_POST['free_pro'] ) ) : '',
766 - );
1016 + protected function wdkit_browse_page() {
1017 + $args = $this->wdkit_parse_args( $_POST );
767 1018
768 - $response = $this->wkit_api_call( $array_data, 'browse_widget' );
769 - $success = ! empty( $response['success'] ) ? $response['success'] : false;
1019 + $response = WDesignKit_Data_Query::get_data( 'browse_page', $args );
770 1020
771 - if ( empty( $success ) ) {
772 - $response = array(
773 - 'success' => false,
774 - 'message' => esc_html__( 'Data Not Found', 'wdesignkit' ),
775 - 'description' => esc_html__( 'Widget List Not Found', 'wdesignkit' ),
776 -
777 - 'widgets' => array(),
778 - 'widgetscount' => 0,
779 - 'showwidgets' => 0,
780 - );
781 -
782 - 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 + ) );
783 1026 wp_die();
784 1027 }
785 1028
786 - $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;
787 1034
788 1035 wp_send_json( $response );
789 1036 wp_die();
790 1037 }
@@ -808,9 +1055,8 @@
808 1055 *
809 1056 * It is Use for remove or delete template.
810 1057 *
811 1058 * @since 1.0.0
812 - * @access public
813 1059 */
814 1060 protected function wdkit_template_remove() {
815 1061 $args = $this->wdkit_parse_args( $_POST );
816 1062
@@ -816,15 +1062,14 @@
816 1062
817 1063 $user_email = strtolower( sanitize_email( $args['email'] ) );
818 1064 $response = '';
819 1065
1066 + // Bug D fix: response()->json() is Laravel syntax — causes PHP fatal. Use plain array.
820 1067 if ( empty( $user_email ) || empty( $args['template_id'] ) ) {
821 - $response = response()->json(
822 - array(
823 - 'message' => $this->e_msg_login,
824 - 'description' => $this->e_desc_login,
825 - 'success' => true,
826 - )
1068 + $response = array(
1069 + 'message' => $this->e_msg_login,
1070 + 'description' => $this->e_desc_login,
1071 + 'success' => false,
827 1072 );
828 1073
829 1074 wp_send_json( $response );
830 1075 wp_die();
@@ -845,9 +1090,12 @@
845 1090 *
846 1091 * @since 1.0.0
847 1092 */
848 1093 protected function wdkit_put_save_template() {
849 - $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 +
850 1098 $response = '';
851 1099
852 1100 if ( empty( $email ) ) {
853 1101 $response = array(
@@ -865,14 +1113,19 @@
865 1113 $args = $this->wdkit_parse_args( $_POST );
866 1114 $args['token'] = $this->wdkit_login_user_token( $email );
867 1115 unset( $args['email'] );
868 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 +
869 1123 global $post;
870 1124
871 - $post_id = get_the_ID();
872 1125 $custom_fields = array();
873 1126 if ( ! empty( $post_id ) ) {
874 - $meta_fields = get_post_custom( get_the_ID() );
1127 + $meta_fields = get_post_custom( $post_id );
875 1128
876 1129 foreach ( $meta_fields as $key => $value ) {
877 1130 if ( str_contains( $key, 'nxt-' ) ) {
878 1131 $custom_fields[ $key ] = $value;
@@ -887,8 +1140,24 @@
887 1140 }
888 1141
889 1142 $response = WDesignKit_Data_Query::get_data( 'save_template', $args );
890 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 +
891 1160 wp_send_json( $response );
892 1161 wp_die();
893 1162 }
894 1163
@@ -893,8 +1162,1344 @@
893 1162 }
894 1163
895 1164 /**
896 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 + *
897 2502 * It is For Find User Existing template List.
898 2503 *
899 2504 * @since 1.0.6
900 2505 */
@@ -921,16 +2526,39 @@
921 2526 * @since 1.0.6
922 2527 */
923 2528 protected function wdkit_update_template() {
924 2529 $array_data = array(
925 - 'data' => isset( $_POST['data'] ) ? wp_unslash( $_POST['data'] ) : '',
926 - 'token' => isset( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '',
927 - 'type' => isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : '',
928 - '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(),
929 2538 );
930 2539
931 - $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'];
932 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' );
933 2561 wp_send_json( $response );
934 2562 wp_die();
935 2563 }
936 2564
@@ -974,8 +2602,9 @@
974 2602 */
975 2603 protected function wdkit_check_plugins_depends() {
976 2604 $plugins = isset( $_POST['plugins'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['plugins'] ) ) ) : array();
977 2605 $update_plugin = array();
2606 + $update_theme = array();
978 2607
979 2608 if ( empty( $plugins ) || ! is_array( $plugins ) ) {
980 2609 $this->wdkit_error_msg( array( 'plugins' => 'No Plugins' ) );
981 2610 }
@@ -988,8 +2617,9 @@
988 2617
989 2618 if ( is_null( $pluginslug ) ) {
990 2619 $plugin->status = 'warning';
991 2620 $update_plugin[] = $plugin;
2621 + $update_theme[] = $plugin;
992 2622
993 2623 continue;
994 2624 }
995 2625
@@ -1010,13 +2640,13 @@
1010 2640 $plugin->status = 'active';
1011 2641 $update_plugin[] = $plugin;
1012 2642 }
1013 2643 } elseif ( 'theme' === $type ) {
1014 - $theme_array = array_keys( wp_get_themes() );
1015 - $current_themes = get_current_theme();
1016 - $theme_slug = get_stylesheet();
2644 + $theme_array = array_keys( wp_get_themes() );
2645 + $theme_slug = get_stylesheet();
2646 + $parent_theme_slug = get_template();
1017 2647
1018 - if ( $theme_slug === $plugin->original_slug ) {
2648 + if ( $theme_slug === $plugin->original_slug || $parent_theme_slug === $plugin->original_slug ) {
1019 2649
1020 2650 $plugin->status = 'active';
1021 2651 } else {
1022 2652 $theme_name = $plugin->original_slug;
@@ -1030,13 +2660,19 @@
1030 2660 $plugin->status = 'inactive';
1031 2661 }
1032 2662 }
1033 2663
1034 - $update_plugin[] = $plugin;
2664 + $update_theme[] = $plugin;
1035 2665 }
1036 2666 }
1037 2667
1038 - $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 );
1039 2675 }
1040 2676
1041 2677 /**
1042 2678 *
@@ -1047,8 +2683,9 @@
1047 2683 */
1048 2684 protected function wdkit_install_plugins_depends() {
1049 2685 $plugins = isset( $_POST['plugins'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['plugins'] ) ), true ) : array();
1050 2686 $type = ! empty( $plugins['type'] ) ? $plugins['type'] : 'plugin';
2687 + $p_id = ! empty( $plugins['p_id'] ) ? $plugins['p_id'] : 'plugin';
1051 2688
1052 2689 $responce = '';
1053 2690 if ( 'plugin' === $type ) {
1054 2691 $responce = Wdkit_Depends_Installer::get_instance()->wdkit_install_plugin( $plugins );
@@ -1055,24 +2692,46 @@
1055 2692 } elseif ( 'theme' === $type ) {
1056 2693 $theme_name = ! empty( $plugins['original_slug'] ) ? $plugins['original_slug'] : '';
1057 2694 if ( ! empty( $theme_name ) ) {
1058 2695
1059 - $activate_result = switch_theme( $theme_name );
2696 + $theme_array = array_keys( wp_get_themes() );
2697 + $theme_slug = get_stylesheet();
1060 2698
1061 - if ( ! is_wp_error( $activate_result ) ) {
1062 - $responce = array(
1063 - 'message' => esc_html__( 'Theme activated successfully', 'wdesignkit' ),
1064 - 'description' => esc_html__( 'Theme successfully activated', 'wdesignkit' ),
1065 - 'slug' => 'the-plus-addons-for-block-editor',
1066 - 'status' => 'active',
1067 - 'success' => true,
1068 - );
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 + }
1069 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 +
1070 2728 $responce = array(
1071 - 'message' => esc_html__( 'Theme Not Activated !', 'wdesignkit' ),
1072 - 'description' => $activate_result->get_error_message(),
1073 - 'status' => 'inactive',
1074 - 'success' => false,
2729 + 'message' => $message,
2730 + 'description' => $description,
2731 + 'p_id' => $p_id,
2732 + 'status' => $status,
2733 + 'success' => $success,
1075 2734 );
1076 2735 }
1077 2736 } else {
1078 2737 $responce = array(
@@ -1077,9 +2736,9 @@
1077 2736 } else {
1078 2737 $responce = array(
1079 2738 'message' => esc_html__( 'Theme Name not Found', 'wdesignkit' ),
1080 2739 'description' => esc_html__( 'Can Not Found Theme Name you Enterd.', 'wdesignkit' ),
1081 - 'success' => true,
2740 + 'success' => false,
1082 2741 );
1083 2742 }
1084 2743 }
1085 2744
@@ -1086,10 +2745,138 @@
1086 2745 wp_send_json( $responce );
1087 2746 wp_die();
1088 2747 }
1089 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 +
1090 2866 /**
1091 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 + *
1092 2879 * It is Use for get plugin list.
1093 2880 *
1094 2881 * @since 1.0.0
1095 2882 */
@@ -1105,25 +2892,118 @@
1105 2892 * Get Download Template Content
1106 2893 *
1107 2894 * @since 1.0.0
1108 2895 */
1109 - protected function wdkit_import_template() {
1110 - $args = $this->wdkit_parse_args( $_POST );
2896 + protected function wdkit_activate_container() {
1111 2897
1112 - if ( empty( $args['email'] ) ) {
1113 - $response = array(
1114 - 'content' => '',
1115 - 'message' => esc_html__( 'Invalid import', 'wdesignkit' ),
1116 - 'description' => esc_html__( 'Invalid import: Check your details and try again.', 'wdesignkit' ),
1117 - 'success' => true,
1118 - );
2898 + $option_value = get_option( 'elementor_experiment-container', false );
1119 2899
1120 - wp_send_json( $response );
1121 - wp_die();
2900 + if ( $option_value === false ) {
2901 + add_option( 'elementor_experiment-container', 'active' );
2902 + } else {
2903 + update_option( 'elementor_experiment-container', 'active' );
1122 2904 }
1123 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 +
1124 3004 $response = '';
1125 - if ( empty( $args['email'] ) || empty( $args['template_id'] ) ) {
3005 + if ( empty( $args['template_id'] ) ) {
1126 3006 $result = array(
1127 3007 'content' => '',
1128 3008 'message' => esc_html__( 'Invalid import', 'wdesignkit' ),
1129 3009 'description' => esc_html__( 'Invalid import: Check your details and try again.', 'wdesignkit' ),
@@ -1136,9 +3016,19 @@
1136 3016
1137 3017 $args['token'] = $this->wdkit_login_user_token( $args['email'] );
1138 3018
1139 3019 unset( $args['email'] );
1140 - $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 +
1141 3031 $custom_meta = isset( $_POST['custom_meta'] ) ? sanitize_text_field( wp_unslash( $_POST['custom_meta'] ) ) : false;
1142 3032
1143 3033 /** Custom meta Field */
1144 3034 if ( ! empty( $custom_meta ) && 'true' === $custom_meta && ! empty( $response ) && ! empty( $response['content'] ) ) {
@@ -1149,9 +3039,9 @@
1149 3039
1150 3040 if ( ! empty( $meta_data ) ) {
1151 3041 foreach ( $meta_data as $meta_key => $meta_val ) {
1152 3042 if ( ! empty( $meta_val[0] ) && is_serialized( $meta_val[0] ) ) {
1153 - $meta_val[0] = maybe_unserialize( $meta_val[0] );
3043 + $meta_val[0] = unserialize( $meta_val[0], array( 'allowed_classes' => false ) );
1154 3044 }
1155 3045
1156 3046 if ( get_post_meta( get_the_ID(), $meta_key, true ) === '' ) {
1157 3047 add_post_meta( get_the_ID(), $meta_key, $meta_val[0] );
@@ -1162,8 +3052,34 @@
1162 3052 }
1163 3053 }
1164 3054 }
1165 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 +
1166 3082 wp_send_json( $response );
1167 3083 wp_die();
1168 3084 }
1169 3085
@@ -1174,8 +3090,265 @@
1174 3090 *
1175 3091 * @param array $content store media content.
1176 3092 * @param string $editor it is check editor.
1177 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 +
1178 3351 public function wdkit_media_import( $content = array(), $editor = '' ) {
1179 3352
1180 3353 if ( empty( $content ) && empty( $editor ) ) {
1181 3354 $args = $this->wdkit_parse_args( $_POST );
@@ -1195,8 +3368,9 @@
1195 3368 if ( ! class_exists( 'Wdkit_Import_Images' ) ) {
1196 3369 require_once WDKIT_INCLUDES . 'admin/class-wdkit-import-images.php';
1197 3370 }
1198 3371
3372 +
1199 3373 if ( ! empty( $args['editor'] ) && 'gutenberg' === $args['editor'] && ! empty( $content ) ) {
1200 3374 $media_import = array( $content );
1201 3375 $media_import = self::blocks_import_media_copy_content( $media_import );
1202 3376 $content = $media_import[0];
@@ -1204,8 +3378,13 @@
1204 3378 $media_import = array( $content );
1205 3379 $media_import = self::widgets_elements_id_change( $media_import );
1206 3380 $media_import = self::widgets_import_media_copy_content( $media_import );
1207 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 );
1208 3387 }
1209 3388
1210 3389 return $content;
1211 3390 }
@@ -1276,9 +3455,13 @@
1276 3455 $control_type = \Elementor\Plugin::instance()->controls_manager->get_control( $get_control['type'] );
1277 3456 $control_name = $get_control['name'];
1278 3457
1279 3458 if ( ! $control_type ) {
1280 - 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;
1281 3464 }
1282 3465
1283 3466 if ( method_exists( $control_type, $tp_mi_on_fun ) ) {
1284 3467 $get_element_instance['settings'][ $control_name ] = $control_type->{$tp_mi_on_fun}( $element->get_settings( $control_name ), $get_control );
@@ -1353,57 +3536,16 @@
1353 3536 public static function blocks_data_instance( array $block_data, array $args = array(), $block_args = null ) {
1354 3537
1355 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'] ) ) ) {
1356 3539 $blocks_attr = isset( $block_data['attributes'] ) ? $block_data['attributes'] : ( isset( $block_data['attrs'] ) ? $block_data['attrs'] : array() );
1357 - foreach ( $blocks_attr as $block_key => $block_val ) {
1358 - if ( isset( $block_val['url'] ) && isset( $block_val['id'] ) && ! empty( $block_val['url'] ) ) {
1359 - $new_media = Wdkit_Import_Images::wdkit_Import_media( $block_val );
1360 - $blocks_attr[ $block_key ] = $new_media;
1361 - } elseif ( isset( $block_val['url'] ) && ! empty( $block_val['url'] ) && preg_match( '/\.(jpg|png|jpeg|gif|svg|webp)$/', $block_val['url'] ) ) {
1362 - $new_media = Wdkit_Import_Images::wdkit_Import_media( $block_val );
1363 - $blocks_attr[ $block_key ] = $new_media;
1364 - } elseif ( is_array( $block_val ) && ! empty( $block_val ) ) {
1365 - 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 ) ) {
1366 - foreach ( $block_val as $key => $val ) {
1367 - if ( is_array( $val ) && ! empty( $val ) ) {
1368 -
1369 - if ( isset( $val['url'] ) && ( isset( $val['Id'] ) || isset( $val['id'] ) ) && ! empty( $val['url'] ) ) {
1370 - $new_media = Wdkit_Import_Images::wdkit_Import_media( $val );
1371 - $blocks_attr[ $block_key ][ $key ] = $new_media;
1372 - } elseif ( isset( $val['url'] ) && ! empty( $val['url'] ) && preg_match( '/\.(jpg|png|jpeg|gif|svg|webp)$/', $val['url'] ) ) {
1373 - $new_media = Wdkit_Import_Images::wdkit_Import_media( $val );
1374 - $blocks_attr[ $block_key ][ $key ] = $new_media;
1375 - } else {
1376 - foreach ( $val as $sub_key => $sub_val ) {
1377 - if ( isset( $sub_val['url'] ) && ( isset( $sub_val['Id'] ) || isset( $sub_val['id'] ) ) && ! empty( $sub_val['url'] ) ) {
1378 - $new_media = Wdkit_Import_Images::wdkit_Import_media( $sub_val );
1379 - $blocks_attr[ $block_key ][ $key ][ $sub_key ] = $new_media;
1380 - } elseif ( isset( $sub_val['url'] ) && ! empty( $sub_val['url'] ) && preg_match( '/\.(jpg|png|jpeg|gif|svg|webp)$/', $sub_val['url'] ) ) {
1381 - $new_media = Wdkit_Import_Images::wdkit_Import_media( $sub_val );
1382 - $blocks_attr[ $block_key ][ $key ][ $sub_key ] = $new_media;
1383 - } elseif ( is_array( $sub_val ) && ! empty( $sub_val ) ) {
1384 - foreach ( $sub_val as $sub_key1 => $sub_val1 ) {
1385 - if ( isset( $sub_val1['url'] ) && ( isset( $sub_val1['Id'] ) || isset( $sub_val1['id'] ) ) && ! empty( $sub_val1['url'] ) ) {
1386 - $new_media = Wdkit_Import_Images::wdkit_Import_media( $sub_val1 );
1387 - $blocks_attr[ $block_key ][ $key ][ $sub_key ][ $sub_key1 ] = $new_media;
1388 - } elseif ( isset( $sub_val1['url'] ) && ! empty( $sub_val1['url'] ) && preg_match( '/\.(jpg|png|jpeg|gif|svg|webp)$/', $sub_val1['url'] ) ) {
1389 - $new_media = Wdkit_Import_Images::wdkit_Import_media( $sub_val1 );
1390 - $blocks_attr[ $block_key ][ $key ][ $sub_key ][ $sub_key1 ] = $new_media;
1391 - }
1392 - }
1393 - }
1394 - }
1395 - }
1396 - }
1397 - }
1398 - }
1399 - }
1400 - }
3540 + $blocks_attr = self::wdkit_import_block_media( $blocks_attr );
1401 3541 if ( isset( $block_data['attributes'] ) ) {
1402 3542 $block_data['attributes'] = $blocks_attr;
1403 3543 } elseif ( isset( $block_data['attrs'] ) ) {
1404 3544 $block_data['attrs'] = $blocks_attr;
1405 3545 }
3546 +
3547 + $block_data = self::wdkit_relink_block_markup( $block_data );
1406 3548 }
1407 3549
1408 3550 return $block_data;
1409 3551 }
@@ -1408,8 +3550,284 @@
1408 3550 return $block_data;
1409 3551 }
1410 3552
1411 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 + /**
1412 3830 * Kit Template Import Pages/Sections
1413 3831 *
1414 3832 * @since 1.0.0
1415 3833 * */
@@ -1418,8 +3836,10 @@
1418 3836 if ( ! current_user_can( 'manage_options' ) ) {
1419 3837 return false;
1420 3838 }
1421 3839
3840 + $builder = isset( $_POST['builder'] ) ? sanitize_text_field( wp_unslash( $_POST['builder'] ) ) : '';
3841 +
1422 3842 $page_section = ! empty( $_POST['page_section'] ) ? sanitize_text_field( wp_unslash( $_POST['page_section'] ) ) : '';
1423 3843
1424 3844 if ( isset( $page_section ) ) {
1425 3845 $args['page_section'] = ! empty( $page_section ) ? sanitize_text_field( wp_unslash( $page_section ) ) : '';
@@ -1424,13 +3844,16 @@
1424 3844 if ( isset( $page_section ) ) {
1425 3845 $args['page_section'] = ! empty( $page_section ) ? sanitize_text_field( wp_unslash( $page_section ) ) : '';
1426 3846 }
1427 3847
1428 - $template_ids = ! empty( $_POST['template_ids'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['template_ids'] ) ), true ) : array();
1429 - $email = ! empty( $_POST['email'] ) ? strtolower( sanitize_email( wp_unslash( $_POST['email'] ) ) ) : '';
1430 - $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;
1431 3854
1432 - if ( empty( $email ) || empty( $template_ids ) ) {
3855 + if ( empty( $template_ids ) ) {
1433 3856 $output = array(
1434 3857 'message' => esc_html__( 'Invalid import', 'wdesignkit' ),
1435 3858 'description' => esc_html__( 'Invalid import: Check your details and try again.', 'wdesignkit' ),
1436 3859 'success' => false,
@@ -1453,24 +3876,112 @@
1453 3876 $temp_args = array(
1454 3877 'token' => $token,
1455 3878 'template_id' => $template_ids['id'],
1456 3879 'editor' => $editor,
3880 + 'website_kit' => $website_kit,
3881 + 'unique_id' => get_option( 'wdkit_unique_id' ) ?? '',
1457 3882 );
1458 3883
1459 - $response = WDesignKit_Data_Query::get_data( 'import_template', $temp_args );
3884 + $response = WDesignKit_Data_Query::get_data( $api_type, $temp_args );
1460 3885 $output = array();
1461 3886
1462 - if ( 'error' === $response['content'] ) {
3887 + if ( is_wp_error( $response ) ) {
3888 +
1463 3889 wp_send_json( $response );
1464 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 + );
1465 3971 } else {
1466 - $output[ $template_ids['id'] ] = $this->import_page_section_content( $args, $template_ids['id'], $response, $template_ids );
1467 - $output['message'] = $response['message'];
1468 - $output['description'] = $response['description'];
1469 - $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 + );
1470 3981 }
1471 3982
1472 - wp_send_json( $output );
3983 + wp_send_json( $res );
1473 3984 wp_die();
1474 3985 }
1475 3986
1476 3987 /**
@@ -1476,9 +3987,10 @@
1476 3987 /**
1477 3988 * Import single template and section from plugin only
1478 3989 * */
1479 3990 protected function wdkit_import_multi_template() {
1480 - $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';
1481 3993
1482 3994 if ( ! current_user_can( 'manage_options' ) ) {
1483 3995 return false;
1484 3996 }
@@ -1507,62 +4019,199 @@
1507 4019 $args['post_type'] = ! empty( $_POST['select'] ) ? sanitize_text_field( wp_unslash( $_POST['select'] ) ) : '';
1508 4020 }
1509 4021
1510 4022 $args['custom_meta'] = isset( $_POST['custom_meta'] ) ? sanitize_text_field( wp_unslash( $_POST['custom_meta'] ) ) : false;
4023 +
1511 4024 if ( ! empty( $args['template_ids'] ) && ! empty( $args['page_section'] ) ) {
1512 4025 $output = array();
1513 - if ( is_array( $args['template_ids'] ) ) {
1514 - foreach ( $args['template_ids'] as $key => $value ) {
1515 - if ( ! empty( $value['id'] ) ) {
1516 - $token = $this->wdkit_login_user_token( $args['email'] );
1517 - $temp_args = array(
1518 - 'token' => $token,
1519 - 'template_id' => $value['id'],
1520 - 'editor' => $args['editor'],
1521 - );
4026 + if ( ! empty( $args['template_ids']['id'] ) ) {
4027 + $token = $this->wdkit_login_user_token( $args['email'] );
1522 4028
1523 - $response = WDesignKit_Data_Query::get_data( 'import_template', $temp_args );
1524 -
1525 - if ( 'error' === $response['content'] ) {
1526 - wp_send_json( $response );
1527 - wp_die();
1528 - } else {
1529 - $output[ $value['id'] ] = $this->import_page_section_content( $args, $value['id'], $response, $value );
1530 - $output['message'] = $response['message'];
1531 - $output['description'] = $response['description'];
1532 - $output['success'] = $response['success'];
1533 - }
1534 - }
1535 - }
1536 - } else {
1537 - $token = $this->wdkit_login_user_token( $args['email'] );
1538 4029 $temp_args = array(
1539 4030 'token' => $token,
1540 - 'template_id' => $args['template_ids'],
4031 + 'template_id' => $args['template_ids']['id'],
1541 4032 'editor' => $args['editor'],
4033 + 'unique_id' => get_option( 'wdkit_unique_id' ) ?? '',
1542 4034 );
1543 4035
1544 - $response = WDesignKit_Data_Query::get_data( 'import_template', $temp_args );
4036 + $response = WDesignKit_Data_Query::get_data( $api_type, $temp_args );
1545 4037
1546 - 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'] ) {
1547 4047 wp_send_json( $response );
1548 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 ] = "";
1549 4084 } else {
1550 - $output[ $args['template_ids'] ] = $this->import_page_section_content( $args, $args['template_ids'], $response );
1551 - $output['message'] = $response['message'];
1552 - $output['description'] = $response['description'];
1553 - $output['success'] = $response['success'];
4085 + $this->wdkit_content_remover( $value );
1554 4086 }
1555 4087 }
4088 + } elseif ( is_object( $data ) ) {
1556 4089
1557 - $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 + }
1558 4100
1559 - wp_send_json( $output );
1560 - 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 ) : '';
1561 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 + ]);
1562 4125 }
1563 4126
1564 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 + /**
1565 4214 * Import single template and section from plugin only
1566 4215 *
1567 4216 * @param array $args store data.
1568 4217 * @param array $template_id store data.
@@ -1568,23 +4217,88 @@
1568 4217 * @param array $template_id store data.
1569 4218 * @param array $data store data.
1570 4219 * @param array $temp_data store data.
1571 4220 * */
1572 - 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 +
1573 4266 $enqueue_instance = new Wdkit_Enqueue();
1574 4267 $get_post_type = $enqueue_instance->wdkit_get_post_type_list();
1575 4268
1576 4269 $post_type = ! empty( $temp_data['type'] ) ? sanitize_text_field( wp_unslash( $temp_data['type'] ) ) : 'page';
1577 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 +
1578 4277 if ( ! array_key_exists( $post_type, $get_post_type ) ) {
1579 4278 $post_type = 'page';
1580 4279 }
1581 4280
1582 - if ( ! empty( $data ) && ! empty( $data['content'] ) && ! empty( $template_id ) && ! empty( $post_type ) && current_user_can( 'manage_options' ) ) {
1583 - $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 +
1584 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 ) : '';
1585 4298 $file_type = isset( $post_content->file_type ) ? sanitize_text_field( $post_content->file_type ) : '';
1586 4299 $content = isset( $post_content->content ) ? wp_slash( $post_content->content ) : '';
4300 + $temp_con = '';
1587 4301
1588 4302 if ( 'gutenberg' === $args['editor'] || ( 'wdkit' === $args['editor'] && ! empty( $file_type ) && 'wp_block' === $file_type ) ) {
1589 4303 if ( empty( $content ) ) {
1590 4304 wp_send_json(
@@ -1589,24 +4303,31 @@
1589 4303 if ( empty( $content ) ) {
1590 4304 wp_send_json(
1591 4305 array(
1592 4306 'template_id' => $template_id,
1593 - 'message' => 'Content is Empty.',
4307 + 'message' => __( 'Content is Empty.', 'wdesignkit' ),
1594 4308 )
1595 4309 );
1596 4310 wp_die();
1597 4311 } elseif ( ! empty( $content ) && ! empty( $file_type ) && 'wp_block' === $file_type ) {
1598 - $parse_blocks = parse_blocks( stripslashes( $content ) );
1599 4312
1600 4313 $editor = ( 'wdkit' === $args['editor'] ) ? 'gutenberg' : $args['editor'];
1601 - $content = $this->wdkit_media_import( $parse_blocks, $editor );
1602 - $content = addslashes( serialize_blocks( $content ) );
4314 + $blocks = parse_blocks( stripslashes( $content ) );
1603 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 +
1604 4324 $inserted_post = wp_insert_post(
1605 4325 array(
1606 4326 'post_status' => 'publish',
1607 4327 'post_type' => $post_type,
1608 4328 'post_title' => $post_title,
4329 + 'post_name' => $post_slug,
1609 4330 'post_content' => $content,
1610 4331 )
1611 4332 );
1612 4333
@@ -1619,14 +4340,47 @@
1619 4340 );
1620 4341 wp_die();
1621 4342 }
1622 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 +
1623 4377 if ( ! empty( $args['custom_meta'] ) && 'true' == $args['custom_meta'] ) {
1624 4378 $custom_meta = isset( $post_content->custom_meta ) ? json_decode( wp_json_encode( $post_content->custom_meta ), true ) : '';
1625 4379 if ( ! empty( $custom_meta ) ) {
1626 4380 foreach ( $custom_meta as $meta_key => $meta_val ) {
1627 4381 if ( isset( $meta_val[0] ) && ! empty( $meta_val[0] ) && is_serialized( $meta_val[0] ) ) {
1628 - $meta_val[0] = maybe_unserialize( $meta_val[0] );
4382 + $meta_val[0] = unserialize( $meta_val[0], array( 'allowed_classes' => false ) );
1629 4383 }
1630 4384
1631 4385 if ( '' === get_post_meta( $inserted_post, $meta_key, true ) && isset( $meta_val[0] ) ) {
1632 4386 add_post_meta( $inserted_post, $meta_key, $meta_val[0] );
@@ -1634,13 +4388,49 @@
1634 4388 }
1635 4389 }
1636 4390 }
1637 4391
1638 - return array(
4392 + $temp_detail = array(
1639 4393 'title' => get_the_title( $inserted_post ),
1640 4394 'edit_link' => get_edit_post_link( $inserted_post, 'internal' ),
1641 4395 'view' => get_permalink( $inserted_post ),
4396 + 'id' => $inserted_post,
1642 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();
1643 4433 }
1644 4434 } elseif ( 'elementor' === $args['editor'] || ( 'wdkit' === $args['editor'] && ! empty( $file_type ) && 'elementor' === $file_type ) ) {
1645 4435 if ( did_action( 'elementor/loaded' ) ) {
1646 4436 if ( empty( $content ) ) {
@@ -1646,17 +4436,21 @@
1646 4436 if ( empty( $content ) ) {
1647 4437 wp_send_json(
1648 4438 array(
1649 4439 'template_id' => $template_id,
1650 - 'message' => 'Content is Empty.',
4440 + 'message' => __( 'Content is Empty.', 'wdesignkit' ),
1651 4441 )
1652 4442 );
1653 4443 wp_die();
1654 4444 } elseif ( ! empty( $content ) && ! empty( $file_type ) && 'elementor' === $file_type ) {
4445 +
4446 + $content = $this->wdkit_content_remover( $content );
4447 +
1655 4448 $post_attributes = array(
1656 4449 'post_title' => $post_title,
1657 4450 'post_type' => $post_type,
1658 4451 'post_status' => 'publish',
4452 + 'post_name' => $post_slug,
1659 4453 );
1660 4454
1661 4455 if ( 'elementor_library' === $post_type ) {
1662 4456 $el_type = ( isset( $post_content->el_type ) && ! empty( $post_content->el_type ) ) ? sanitize_text_field( $post_content->el_type ) : 'page';
@@ -1680,8 +4474,43 @@
1680 4474 );
1681 4475 wp_die();
1682 4476 }
1683 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 +
1684 4513 $settings = ( isset( $post_content->settings ) && ! empty( $post_content->settings ) ) ? json_decode( wp_json_encode( $post_content->settings ), true ) : array();
1685 4514
1686 4515 $content = wp_json_encode( $content );
1687 4516 $content = $this->wdkit_media_import( $content, $file_type );
@@ -1694,14 +4523,18 @@
1694 4523 );
1695 4524
1696 4525 $inserted_id = $new_document->get_main_id();
1697 4526
4527 + if( $temp_type == 'navigation' ){
4528 + $temp_con = $content;
4529 + }
4530 +
1698 4531 if ( ! empty( $args['custom_meta'] ) && 'true' == $args['custom_meta'] ) {
1699 4532 $custom_meta = isset( $post_content->custom_meta ) ? json_decode( wp_json_encode( $post_content->custom_meta ), true ) : '';
1700 4533 if ( ! empty( $custom_meta ) ) {
1701 4534 foreach ( $custom_meta as $meta_key => $meta_val ) {
1702 4535 if ( ! empty( $meta_val[0] ) && is_serialized( $meta_val[0] ) ) {
1703 - $meta_val[0] = maybe_unserialize( $meta_val[0] );
4536 + $meta_val[0] = unserialize( $meta_val[0], array( 'allowed_classes' => false ) );
1704 4537 }
1705 4538 if ( '' === get_post_meta( $inserted_id, $meta_key, true ) ) {
1706 4539 add_post_meta( $inserted_id, $meta_key, $meta_val[0] );
1707 4540 }
@@ -1708,13 +4541,40 @@
1708 4541 }
1709 4542 }
1710 4543 }
1711 4544
1712 - return array(
4545 + $temp_detail = array(
1713 4546 'title' => get_the_title( $inserted_id ),
1714 4547 'edit_link' => get_edit_post_link( $inserted_id, 'internal' ),
1715 4548 'view' => get_permalink( $inserted_id ),
4549 + 'id' => $inserted_id,
1716 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();
1717 4577 }
1718 4578 } else {
1719 4579 wp_send_json(
1720 4580 array(
@@ -1725,11 +4585,610 @@
1725 4585 wp_die();
1726 4586 }
1727 4587 }
1728 4588 }
4589 +
4590 + wp_send_json(
4591 + array(
4592 + 'success' => false,
4593 + 'message' => esc_html__( 'Something went wrong', 'wdesignkit' ),
4594 + )
4595 + );
4596 + wp_die();
1729 4597 }
1730 4598
1731 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 + /**
1732 5191 * Share with Me Template and widgets
1733 5192 *
1734 5193 * @since 1.0.0
1735 5194 */
@@ -1789,10 +5248,10 @@
1789 5248 *
1790 5249 * @since 1.0.0
1791 5250 */
1792 5251 protected function wdkit_manage_widget_workspace() {
1793 - $Workspace_info = isset( $_POST['workspace_info'] ) ? sanitize_text_field( wp_unslash( $_POST['workspace_info'] ) ) : array();
1794 - $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();
1795 5254
1796 5255 $array_data = array(
1797 5256 'token' => isset( $data->token ) ? sanitize_text_field( $data->token ) : '',
1798 5257 'wstype' => isset( $data->type ) ? sanitize_text_field( $data->type ) : '',
@@ -1816,9 +5275,10 @@
1816 5275 protected function wdkit_activate_key() {
1817 5276 $email = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '';
1818 5277 $response = '';
1819 5278
1820 - 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 ) ) {
1821 5281 $response = array(
1822 5282 'message' => $this->e_msg_login,
1823 5283 'description' => $this->e_desc_login,
1824 5284 'success' => false,
@@ -1852,13 +5312,13 @@
1852 5312 }
1853 5313
1854 5314 /**
1855 5315 *
1856 - * It is Use for get local widget list.
5316 + * Get list local Widget List
1857 5317 *
1858 5318 * @since 1.0.0
1859 5319 */
1860 - protected function wdkit_get_widget_list() {
5320 + protected function wdkit_get_local_widgets() {
1861 5321 $builder = array();
1862 5322 $a_c_s_d_s_c = array();
1863 5323 $j_s_o_n_array = array();
1864 5324
@@ -1873,8 +5333,12 @@
1873 5333 if ( Wdkit_Wdesignkit::wdkit_is_compatible( 'gutenberg', 'widget' ) ) {
1874 5334 array_push( $builder, 'gutenberg' );
1875 5335 }
1876 5336
5337 + if ( Wdkit_Wdesignkit::wdkit_is_compatible( 'gutenberg_core', 'widget' ) ) {
5338 + array_push( $builder, 'gutenberg_core' );
5339 + }
5340 +
1877 5341 foreach ( $builder as $key => $name ) {
1878 5342 $elementor_dir = WDKIT_BUILDER_PATH . '/' . $name;
1879 5343
1880 5344 if ( ! empty( $elementor_dir ) && is_dir( $elementor_dir ) ) {
@@ -1882,10 +5346,10 @@
1882 5346 $elementor_list = array_diff( $elementor_list, array( '.', '..' ) );
1883 5347
1884 5348 if ( ! empty( $elementor_list ) ) {
1885 5349 foreach ( $elementor_list as $key => $value ) {
1886 - $a_c_s_d_s_c[ filemtime( "{$elementor_dir}/{$value}" ) ]['data'] = $value;
1887 - $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;
1888 5352 }
1889 5353 }
1890 5354 }
1891 5355 }
@@ -1914,10 +5378,9 @@
1914 5378 }
1915 5379 }
1916 5380 }
1917 5381
1918 - wp_send_json( $j_s_o_n_array );
1919 - wp_die();
5382 + return $j_s_o_n_array;
1920 5383 }
1921 5384
1922 5385 /**
1923 5386 *
@@ -1953,521 +5416,133 @@
1953 5416 wp_send_json( get_option( 'wkit_builder' ) );
1954 5417 }
1955 5418
1956 5419 /**
5420 + * Get Workspace data
1957 5421 *
1958 - * Custom_upload_dir
1959 - *
1960 - * @since 1.0.0
1961 - *
1962 - * @param array $upload store data.
5422 + * @since 2.2.5
1963 5423 */
1964 - public function custom_upload_dir( $upload ) {
1965 - // Specify the path to your custom upload directory.
1966 - if ( isset( $this->widget_folder_u_r_l ) && ! empty( $this->widget_folder_u_r_l ) ) {
5424 + public function wdkit_get_workspace_data() {
1967 5425
1968 - // Set the custom directory as the upload path.
1969 - $upload['path'] = $this->widget_folder_u_r_l;
1970 - // Set the URL for the uploaded file.
1971 - $upload['url'] = $upload['baseurl'] . $upload['subdir'];
1972 - }
5426 + $wid = isset( $_POST['wid'] ) ? sanitize_text_field( $_POST['wid'] ) : '';
5427 + $token = isset( $_POST['token'] ) ? sanitize_text_field( $_POST['token'] ) : '';
1973 5428
1974 - return $upload;
1975 - }
1976 -
1977 - /**
1978 - *
1979 - * It is Use for create widget for local
1980 - *
1981 - * @since 1.0.0
1982 - */
1983 - protected function wdkit_create_widget() {
1984 - $image = '';
1985 - if ( isset( $_FILES ) && ! empty( $_FILES ) && isset( $_FILES['image'] ) && ! empty( $_FILES['image'] ) ) {
1986 - $image = Wdkit_Data_Hooks::get_super_global_value( $_FILES, 'image' );
1987 - }
1988 -
1989 - $icon = '';
1990 - if ( isset( $_FILES ) && ! empty( $_FILES ) && isset( $_FILES['icon'] ) && ! empty( $_FILES['icon'] ) ) {
1991 - $icon = Wdkit_Data_Hooks::get_super_global_value( $_FILES, 'icon' );
1992 - }
1993 -
1994 - $data = ! empty( $_POST['value'] ) ? $this->wdkit_sanitizer_bypass( $_POST, 'value', 'cr_widget' ) : '';
1995 - $data = ! empty( $data ) ? stripslashes( $data ) : '';
1996 - $return = ! empty( $data ) ? json_decode( $data ) : '';
1997 -
1998 - $all_val = ! empty( $return ) ? $return : '';
1999 - if ( empty( $all_val ) ) {
2000 -
2001 - $responce = array(
2002 - 'message' => esc_html__( 'Data Not Found', 'wdesignkit' ),
2003 - 'description' => esc_html__( 'something went wrong! please try again later.', 'wdesignkit' ),
5429 + if ( empty( $wid ) ) {
5430 + return array(
2004 5431 'success' => false,
5432 + 'message' => esc_html__( 'Workspace ID Not Found', 'wdesignkit' ),
5433 + 'description' => esc_html__( 'Workspace ID is required', 'wdesignkit' ),
2005 5434 );
2006 -
2007 - wp_send_json( $responce );
2008 - wp_die();
2009 5435 }
2010 5436
2011 - $file_name = ! empty( $all_val->file_name ) ? sanitize_text_field( $all_val->file_name ) : '';
2012 - $folder_name = ! empty( $all_val->folder_name ) ? sanitize_text_field( $all_val->folder_name ) : '';
2013 - $old_widget = ! empty( $all_val->old_folder ) ? sanitize_text_field( $all_val->old_folder ) : '';
2014 - $description = ! empty( $all_val->description ) ? sanitize_text_field( $all_val->description ) : '';
2015 - $json_file = ! empty( $all_val->json_file ) ? $all_val->json_file : '';
2016 - $function_call = ! empty( $all_val->call ) ? sanitize_text_field( $all_val->call ) : '';
2017 - $plugin = ! empty( $all_val->plugin ) ? $all_val->plugin : '';
2018 - $d_image = ! empty( $all_val->d_image ) ? $all_val->d_image : '';
2019 - $data = json_decode( $json_file );
2020 -
2021 - $elementor_php_file = ! empty( $all_val->elementor_php_file ) ? $all_val->elementor_php_file : '';
2022 - $elementor_js = ! empty( $all_val->elementor_js ) ? $all_val->elementor_js : '';
2023 - $elementor_css = ! empty( $all_val->elementor_css ) ? $all_val->elementor_css : '';
2024 -
2025 - $gutenberg_php_file = ! empty( $all_val->gutenberg_php_file ) ? $all_val->gutenberg_php_file : '';
2026 - $gutenberg_js = ! empty( $all_val->gutenberg_js ) ? $all_val->gutenberg_js : '';
2027 - $gutenberg_css = ! empty( $all_val->gutenberg_css ) ? $all_val->gutenberg_css : '';
2028 - $external_js_file = ! empty( $all_val->external_js_file ) ? $all_val->external_js_file : '';
2029 - $style_file = ! empty( $all_val->style_file ) ? $all_val->style_file : '';
2030 -
2031 - $bricks_php_file = ! empty( $all_val->bricks_php_file ) ? $all_val->bricks_php_file : '';
2032 - $bricks_js = ! empty( $all_val->bricks_js ) ? $all_val->bricks_js : '';
2033 - $bricks_css = ! empty( $all_val->bricks_css ) ? $all_val->bricks_css : '';
2034 -
2035 - $old_folder = ! empty( $old_widget ) ? str_replace( ' ', '-', $old_widget ) : '';
2036 - $widget_type = ! empty( $data->widget_data->widgetdata->type ) ? sanitize_text_field( $data->widget_data->widgetdata->type ) : '';
2037 -
2038 - if ( empty( $widget_type ) ) {
2039 - $responce = array(
2040 - 'message' => esc_html__( 'Builder Type not found', 'wdesignkit' ),
2041 - 'description' => esc_html__( 'something went wrong! please try again later.', 'wdesignkit' ),
5437 + if ( empty( $token ) ) {
5438 + return array(
2042 5439 'success' => false,
5440 + 'message' => esc_html__( 'Token Not Found', 'wdesignkit' ),
5441 + 'description' => esc_html__( 'Token is required', 'wdesignkit' ),
2043 5442 );
2044 -
2045 - wp_send_json( $responce );
2046 - wp_die();
2047 5443 }
2048 5444
2049 - $builder_type_path = trailingslashit( WDKIT_BUILDER_PATH ) . trailingslashit( $widget_type );
2050 - $widget_file_url = $builder_type_path . $folder_name;
5445 + $args = array(
5446 + 'token' => $token,
5447 + 'wid' => $wid,
5448 + );
2051 5449
2052 - if ( ! is_dir( $widget_file_url ) ) {
2053 - wp_mkdir_p( $widget_file_url );
2054 - }
5450 + $this->wdkit_api = $this->wdkit_api_v2;
2055 5451
2056 - include_once ABSPATH . 'wp-admin/includes/file.php';
2057 - \WP_Filesystem();
2058 - global $wp_filesystem;
2059 - $widget_folder_u_r_l = trailingslashit( $widget_file_url ) . $file_name;
2060 - $this->widget_folder_u_r_l = $widget_file_url;
5452 + $url = "workspace/{$wid}/get";
2061 5453
2062 - if ( 'elementor' === $plugin ) {
2063 - $widget_file_list = scandir( $widget_file_url );
2064 - $widget_file_list = array_diff( $widget_file_list, array( '.', '..' ) );
5454 + $response = $this->wkit_api_call( $args, $url );
2065 5455
2066 - foreach ( $widget_file_list as $sub_dir_value ) {
2067 - $file = new SplFileInfo( $sub_dir_value );
2068 - $check_ext = $file->getExtension();
2069 - $extiona = pathinfo( $sub_dir_value, PATHINFO_EXTENSION );
2070 -
2071 - if ( 'js' === $extiona || 'css' === $extiona || 'json' === $extiona || 'php' === $extiona ) {
2072 - $wp_filesystem->rmdir( "$widget_file_url/$sub_dir_value", true );
2073 - }
2074 - }
2075 -
2076 - if ( ! empty( $elementor_php_file ) ) {
2077 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.php", $elementor_php_file );
2078 - }
2079 - if ( ! empty( $json_file ) ) {
2080 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.json", $json_file );
2081 - }
2082 - if ( ! empty( $elementor_css ) ) {
2083 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.css", $elementor_css );
2084 - }
2085 - if ( ! empty( $elementor_js ) ) {
2086 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.js", $elementor_js );
2087 - }
2088 - } elseif ( 'bricks' === $plugin ) {
2089 -
2090 - $widget_file_list = scandir( $widget_file_url );
2091 - $widget_file_list = array_diff( $widget_file_list, array( '.', '..' ) );
2092 -
2093 - foreach ( $widget_file_list as $sub_dir_value ) {
2094 - $file = new SplFileInfo( $sub_dir_value );
2095 - $check_ext = $file->getExtension();
2096 - $extiona = pathinfo( $sub_dir_value, PATHINFO_EXTENSION );
2097 -
2098 - if ( 'js' === $extiona || 'css' === $extiona || 'json' === $extiona || 'php' === $extiona ) {
2099 - $wp_filesystem->rmdir( "$widget_file_url/$sub_dir_value", true );
2100 - }
2101 - }
2102 -
2103 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.php", $bricks_php_file );
2104 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.json", $json_file );
2105 -
2106 - if ( ! empty( $bricks_css ) ) {
2107 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.css", $bricks_css );
2108 - }
2109 -
2110 - if ( ! empty( $bricks_js ) ) {
2111 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.js", $bricks_js );
2112 - }
2113 - } elseif ( 'gutenberg' === $plugin ) {
2114 -
2115 - $widget_file_list = scandir( $widget_file_url );
2116 - $widget_file_list = array_diff( $widget_file_list, array( '.', '..' ) );
2117 -
2118 - foreach ( $widget_file_list as $sub_dir_value ) {
2119 - $file = new SplFileInfo( $sub_dir_value );
2120 - $check_ext = $file->getExtension();
2121 - $extiona = pathinfo( $sub_dir_value, PATHINFO_EXTENSION );
2122 -
2123 - if ( 'js' === $extiona || 'css' === $extiona || 'json' === $extiona || 'php' === $extiona ) {
2124 - $wp_filesystem->rmdir( "$widget_file_url/$sub_dir_value", true );
2125 - }
2126 - }
2127 -
2128 - if ( ! empty( $external_js_file ) ) {
2129 - $wp_filesystem->put_contents( "$widget_file_url/index.js", $external_js_file );
2130 - }
2131 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.php", $gutenberg_php_file );
2132 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.json", $json_file );
2133 - if ( ! empty( $gutenberg_css ) ) {
2134 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.css", $gutenberg_css );
2135 - }
2136 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.js", $gutenberg_js );
2137 - }
2138 -
2139 - if ( ! empty( $image ) && ! empty( $image['tmp_name'] ) ) {
2140 -
2141 - $img_type = array( 'jpg', 'png' );
2142 -
2143 - foreach ( $img_type as $imgext ) {
2144 - $wp_filesystem->rmdir( "$widget_folder_u_r_l . $imgext", true );
2145 - }
2146 -
2147 - $ext = $image['type'];
2148 - $img_ext = '';
2149 - if ( strpos( $ext, 'jpeg' ) ) {
2150 - $img_ext = 'jpg';
2151 - } elseif ( strpos( $ext, 'png' ) ) {
2152 - $img_ext = 'png';
2153 - }
2154 - if ( ! empty( $img_ext ) ) {
2155 - add_filter( 'upload_dir', array( $this, 'custom_upload_dir' ) );
2156 -
2157 - $uploaded_file = wp_handle_upload( $image, array( 'test_form' => false ) );
2158 -
2159 - rename( $uploaded_file['file'], $widget_folder_u_r_l . '.' . $img_ext );
2160 -
2161 - remove_filter( 'upload_dir', array( $this, 'custom_upload_dir' ) );
2162 -
2163 - }
2164 - } elseif ( ! empty( $old_widget ) ) {
2165 - $img_url = $data->widget_data->widgetdata->w_image;
2166 - $img_ext = ! empty( pathinfo( $img_url )['extension'] ) ? pathinfo( $img_url )['extension'] : '';
2167 -
2168 - if ( ! empty( $img_ext ) ) {
2169 - $old_widget_folder = str_replace( ' ', '-', $old_widget );
2170 - $old_widget_file = str_replace( ' ', '_', $old_widget );
2171 - $img_path = "$builder_type_path$old_widget_folder/$old_widget_file.$img_ext";
2172 - $img_path = str_replace( '\\', '/', $img_path );
2173 -
2174 - if ( file_exists( $img_path ) ) {
2175 - $get_img = $img_path;
2176 - $put_img = "$widget_folder_u_r_l.$img_ext";
2177 -
2178 - if ( ! empty( $get_img ) && ! empty( $put_img ) ) {
2179 - rename( $get_img, $put_img );
2180 - }
2181 - }
2182 - }
2183 - }
2184 -
2185 - if ( ! empty( $d_image ) ) {
2186 - $d_image = str_replace( '\\', '', $d_image );
2187 - $d_img_url = $d_image;
2188 - $img_body = wp_remote_get( $d_img_url );
2189 - $img_ext = pathinfo( $d_img_url )['extension'];
2190 - $wp_filesystem->put_contents( WDKIT_BUILDER_PATH . "/$widget_type/$folder_name/$file_name.$img_ext", $img_body['body'] );
2191 - }
2192 -
2193 - if ( ! empty( $function_call ) && 'import' !== $function_call && ! empty( $old_folder ) && strtolower( $old_folder ) !== strtolower( $folder_name ) && is_dir( $builder_type_path . $old_folder ) ) {
2194 - require_once ABSPATH . 'wp-admin/includes/file.php';
2195 - global $wp_filesystem;
2196 - WP_Filesystem();
2197 - $wp_filesystem->rmdir( $builder_type_path . $old_folder, true );
2198 - } elseif ( $old_folder !== $folder_name ) {
2199 - rename( WDKIT_BUILDER_PATH . "/$widget_type/$old_folder", WDKIT_BUILDER_PATH . "/$widget_type/$folder_name" );
2200 - }
2201 -
2202 - $responce = array(
2203 - 'message' => esc_html__( 'Update Saved Successfully', 'wdesignkit' ),
2204 - 'description' => esc_html__( 'Success! Update Saved', 'wdesignkit' ),
2205 - 'success' => true,
2206 - );
2207 -
2208 - wp_send_json( $responce );
5456 + wp_send_json( $response['data'] );
2209 5457 wp_die();
2210 5458 }
2211 5459
2212 5460 /**
2213 5461 *
2214 - * It is Use for delete widget from server
5462 + * Custom_upload_dir
2215 5463 *
2216 5464 * @since 1.0.0
5465 + *
5466 + * @param array $upload store data.
2217 5467 */
2218 - protected function wdkit_import_widget() {
2219 - $filename = '';
2220 - if ( isset( $_FILES ) && ! empty( $_FILES ) && isset( $_FILES['zipName'] ) && ! empty( $_FILES['zipName'] ) ) {
2221 - $filename = ! empty( $_FILES['zipName']['name'] ) ? sanitize_file_name( $_FILES['zipName']['name'] ) : '';
2222 - }
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 ) ) {
2223 5471
2224 - $name = rtrim( $filename, '.zip' );
2225 - $ext = WDKIT_BUILDER_PATH . '/elementor/dump/';
2226 -
2227 - if ( ! is_dir( $ext ) ) {
2228 - wp_mkdir_p( $ext );
2229 - } else {
2230 - require_once ABSPATH . 'wp-admin/includes/file.php';
2231 - global $wp_filesystem;
2232 - WP_Filesystem();
2233 - $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'];
2234 5476 }
2235 5477
2236 - $dir = WDKIT_BUILDER_PATH . '/elementor/dump';
2237 - $getall_json = array();
2238 - $zip = new ZipArchive();
2239 -
2240 - $zipname = '';
2241 - if ( ! empty( $_FILES['zipName']['tmp_name'] ) ) {
2242 - $zipname = $this->wdkit_file_sanitizer_bypass( $_FILES, 'zipName', 'name' );
2243 - }
2244 -
2245 - $res = $zip->open( $zipname );
2246 - if ( true === $res ) {
2247 - $zip->extractTo( $ext );
2248 - $zip->close();
2249 - $widget_name = $image = $json_file = '';
2250 - $list = scandir( $dir );
2251 - $list = array_diff( $list, array( '.', '..' ) );
2252 - foreach ( $list as $sub_dir_value ) {
2253 - $file = new SplFileInfo( $sub_dir_value );
2254 - $check_ext = $file->getExtension();
2255 - $extiona = pathinfo( $sub_dir_value, PATHINFO_EXTENSION );
2256 - if ( 'json' === $extiona ) {
2257 - $json_file = $sub_dir_value;
2258 - $u_r_l = wp_json_file_decode( $ext . $sub_dir_value );
2259 - if ( ! empty( $u_r_l->widget_data->widgetdata->name ) && ! empty( $u_r_l->widget_data->widgetdata->widget_id ) ) {
2260 - $widget_name = $u_r_l->widget_data->widgetdata->name;
2261 - $widget_id = $u_r_l->widget_data->widgetdata->widget_id;
2262 - $widget_type = ! empty( $u_r_l->widget_data->widgetdata->type ) ? $u_r_l->widget_data->widgetdata->type : '';
2263 - }
2264 - } elseif ( 'jpg' === $extiona || 'png' === $extiona || 'jpeg' === $extiona ) {
2265 - $img_ext = $extiona;
2266 - $image = $sub_dir_value;
2267 - }
2268 - }
2269 -
2270 - if ( ! empty( $widget_name ) && ! empty( $json_file ) ) {
2271 - $folder_name = str_replace( ' ', '-', $widget_name );
2272 - $file_name = str_replace( ' ', '_', $widget_name );
2273 - if(! is_dir(WDKIT_BUILDER_PATH . "/{$widget_type}")){
2274 - wp_mkdir_p( WDKIT_BUILDER_PATH . "/{$widget_type}" );
2275 - }
2276 - $file_path = WDKIT_BUILDER_PATH . "/{$widget_type}/{$folder_name}_{$widget_id}";
2277 - $dummy_path = WDKIT_BUILDER_PATH . '/elementor/dump';
2278 -
2279 - if ( is_dir( $dummy_path ) ) {
2280 - if ( ! rename( $dummy_path, $file_path ) ) {
2281 -
2282 - require_once ABSPATH . 'wp-admin/includes/file.php';
2283 - global $wp_filesystem;
2284 - WP_Filesystem();
2285 - $wp_filesystem->rmdir( $dummy_path, true );
2286 -
2287 - $responce = (object) array(
2288 - 'success' => false,
2289 - 'message' => esc_html__( 'Widget Not imported', 'wdesignkit' ),
2290 - 'description' => esc_html__( 'Widget alreday exist!', 'wdesignkit' ),
2291 - );
2292 -
2293 - wp_send_json( $responce );
2294 - wp_die();
2295 - }
2296 - }
2297 -
2298 - rename( "{$file_path}/{$json_file}", "{$file_path}/{$file_name}_{$widget_id}.json" );
2299 -
2300 - $get_img_file = "{$file_path}/{$image}";
2301 -
2302 - if ( file_exists( $get_img_file ) ) {
2303 - rename( $get_img_file, "{$file_path}/{$file_name}_{$widget_id}.{$img_ext}" );
2304 - }
2305 - }
2306 -
2307 - $responce = (object) array(
2308 - 'success' => true,
2309 - 'message' => esc_html__( 'Widget imported', 'wdesignkit' ),
2310 - 'description' => esc_html__( 'Widget imported successfully', 'wdesignkit' ),
2311 - 'json' => $u_r_l,
2312 - );
2313 -
2314 - wp_send_json( $responce );
2315 - wp_die();
2316 -
2317 - } else {
2318 - $responce = (object) array(
2319 - 'success' => false,
2320 - 'message' => esc_html__( 'Operation Fial!', 'wdesignkit' ),
2321 - 'description' => esc_html__( 'Widget can not imported', 'wdesignkit' ),
2322 - );
2323 -
2324 - wp_send_json( $responce );
2325 - wp_die();
2326 - }
5478 + return $upload;
2327 5479 }
2328 5480
2329 5481 /**
2330 5482 *
2331 - * Create Uniq name
2332 - *
2333 - * @since 1.0.0
2334 - */
2335 - protected function generate_unique_id() {
2336 - $now = new DateTime();
2337 - $unique_i_d = $now->format( 'YmdHis' );
2338 - $hashed_i_d = (int) $unique_i_d % 10000;
2339 - return str_pad( $hashed_i_d, 4, '0', STR_PAD_LEFT );
2340 - }
2341 -
2342 - /**
2343 - *
2344 5483 * It is Use for delete widget from server
2345 5484 *
2346 5485 * @since 1.0.0
2347 5486 */
2348 - protected function wdkit_export_widget() {
2349 - $data = isset( $_POST['info'] ) ? sanitize_text_field( wp_unslash( $_POST['info'] ) ) : '';
2350 - $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'] ) ) : '';
2351 5491
2352 - $widget_name_temp = isset( $data->widget_name ) ? sanitize_text_field( $data->widget_name ) : '';
2353 - $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 + }
2354 5499
2355 - $widget_name = str_replace( ' ', '_', $widget_name_temp );
2356 - $folder = str_replace( ' ', '-', $widget_name_temp );
2357 - $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 );
2358 5506
2359 - if ( empty( $widget_type ) ) {
2360 - $result = (object) array(
5507 + if ( false === $safe_path || '' === $safe_path['folder'] || '' === $safe_path['file'] ) {
5508 + return array(
2361 5509 'success' => false,
2362 - 'url' => '',
2363 - 'message' => esc_html__( 'Widget Type Fail', 'wdesignkit' ),
2364 - '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' ),
2365 5512 );
2366 -
2367 - wp_send_json( $result );
2368 - wp_die();
2369 5513 }
2370 5514
2371 - $downlod_path = WDKIT_BUILDER_PATH . "/{$widget_type}/";
2372 - $new_path = "{$downlod_path}/{$folder}/{$widget_name}";
5515 + $json_path = $safe_path['base'];
2373 5516
2374 - $download_url = WDKIT_SERVER_PATH . "/{$widget_type}/{$widget_name}.zip";
2375 - $zip = new ZipArchive();
2376 - $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 + }
2377 5526
2378 - $json_data = wp_json_file_decode( "$new_path.json" );
2379 - $img_ext = $json_data->widget_data->widgetdata->img_ext;
2380 -
2381 - if ( true === $zip->open( $tmp_file, ZipArchive::CREATE ) ) {
2382 - $widget_wb = str_replace( '-', '_', $folder );
2383 - $zip->addFile( "$new_path.json", "$widget_wb.json" );
2384 - if ( ! empty( $img_ext ) ) {
2385 - $zip->addFile( "$new_path.$img_ext", "$widget_wb.$img_ext" );
2386 - }
2387 - $zip->close();
2388 -
5527 + $json_data = wp_json_file_decode( "$json_path.json" );
5528 + if ( ! empty( $json_data ) ) {
2389 5529 $result = (object) array(
2390 5530 'success' => true,
2391 - 'url' => $download_url,
2392 - 'message' => esc_html__( 'Widget Exported', 'wdesignkit' ),
2393 - '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' ),
2394 5534 );
2395 -
2396 - wp_send_json( $result );
2397 - wp_die();
2398 5535 } else {
2399 5536 $result = (object) array(
2400 5537 'success' => false,
2401 - 'url' => '',
2402 - 'message' => esc_html__( 'Widget Exported Fail', 'wdesignkit' ),
2403 - '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' ),
2404 5540 );
2405 -
2406 - wp_send_json( $result );
2407 - wp_die();
2408 5541 }
2409 - }
2410 5542
2411 - /**
2412 - *
2413 - * It is Use for delete widget from server
2414 - *
2415 - * @since 1.0.0
2416 - */
2417 - protected function wdkit_delete_widget() {
2418 - $data = isset( $_POST['info'] ) ? sanitize_text_field( wp_unslash( $_POST['info'] ) ) : '';
2419 - $data = json_decode( stripslashes( $data ) );
2420 -
2421 - $delete_type = isset( $data->delete_type ) ? sanitize_text_field( $data->delete_type ) : '';
2422 -
2423 - if ( 'plugin_server' === $delete_type ) {
2424 - $array_data = array(
2425 - 'token' => isset( $data->token ) ? sanitize_text_field( $data->token ) : '',
2426 - 'type' => isset( $data->type ) ? sanitize_text_field( $data->type ) : '',
2427 - 'w_unique' => isset( $data->w_unique ) ? sanitize_text_field( $data->w_unique ) : '',
2428 - 'id' => isset( $data->id ) ? sanitize_text_field( $data->id ) : '',
2429 - );
2430 -
2431 - $response = $this->wkit_api_call( $array_data, 'save_widget' );
2432 - $success = ! empty( $response['success'] ) ? $response['success'] : false;
2433 -
2434 - if ( empty( $success ) ) {
2435 - $massage = ! empty( $response['massage'] ) ? $response['massage'] : esc_html__( 'server error', 'wdesignkit' );
2436 -
2437 - $result = (object) array(
2438 - 'success' => false,
2439 - 'message' => esc_html__( 'Widget Not Deleted', 'wdesignkit' ),
2440 - 'description' => esc_html__( 'Widget Not Deleted', 'wdesignkit' ),
2441 - );
2442 -
2443 - wp_send_json( $result );
2444 - wp_die();
2445 - }
2446 - }
2447 -
2448 - $dir_name = isset( $data->name ) ? sanitize_text_field( $data->name ) : '';
2449 - $widget_type = isset( $data->builder ) ? sanitize_text_field( $data->builder ) : '';
2450 - $dir = WDKIT_BUILDER_PATH . "/{$widget_type}/{$dir_name}";
2451 -
2452 - require_once ABSPATH . 'wp-admin/includes/file.php';
2453 - global $wp_filesystem;
2454 - WP_Filesystem();
2455 - $wp_filesystem->rmdir( $dir, true );
2456 -
2457 - if ( 'plugin_server' === $delete_type ) {
2458 - wp_send_json( $response['data'] );
2459 - wp_die();
2460 - } else {
2461 - $result = (object) array(
2462 - 'success' => true,
2463 - 'message' => esc_html__( 'widget deleted', 'wdesignkit' ),
2464 - 'description' => esc_html__( 'Widget deleted successfully', 'wdesignkit' ),
2465 - );
2466 -
2467 - wp_send_json( $result );
2468 - wp_die();
2469 - }
5543 + wp_send_json( $result );
5544 + wp_die();
2470 5545 }
2471 5546
2472 5547 /**
2473 5548 *
@@ -2475,9 +5550,9 @@
2475 5550 *
2476 5551 * @since 1.0.0
2477 5552 */
2478 5553 protected function wdkit_download_widget() {
2479 - $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' ) : '';
2480 5555 $data = json_decode( stripslashes( $data ) );
2481 5556
2482 5557 $array_data = array(
2483 5558 'token' => isset( $data->token ) ? sanitize_text_field( $data->token ) : '',
@@ -2482,8 +5557,10 @@
2482 5557 $array_data = array(
2483 5558 'token' => isset( $data->token ) ? sanitize_text_field( $data->token ) : '',
2484 5559 'type' => isset( $data->type ) ? sanitize_text_field( $data->type ) : '',
2485 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 ) : '',
2486 5563 );
2487 5564
2488 5565 $response = $this->wkit_api_call( $array_data, 'save_widget' );
2489 5566 $success = ! empty( $response['success'] ) ? $response['success'] : false;
@@ -2516,10 +5593,16 @@
2516 5593 wp_die();
2517 5594 }
2518 5595
2519 5596 $img_url = ! empty( $response['data']['image'] ) ? $response['data']['image'] : '';
2520 - $json_data = ! empty( $response['data']['json'] ) ? json_decode( $response['data']['json'] ) : '';
5597 + $json_data = ! empty( $response['data']['json'] ) ? json_decode( $response['data']['json'], true ) : '';
2521 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 +
2522 5605 if ( empty( $img_url ) && empty( $json_data ) ) {
2523 5606 $responce = (object) array(
2524 5607 'success' => false,
2525 5608 'message' => esc_html__( 'No Response Found', 'wdesignkit' ),
@@ -2533,14 +5616,38 @@
2533 5616 include_once ABSPATH . 'wp-admin/includes/file.php';
2534 5617 \WP_Filesystem();
2535 5618 global $wp_filesystem;
2536 5619
2537 - $title = ! empty( $json_data->widget_data->widgetdata->name ) ? sanitize_text_field( $json_data->widget_data->widgetdata->name ) : '';
2538 - $builder = ! empty( $json_data->widget_data->widgetdata->type ) ? sanitize_text_field( $json_data->widget_data->widgetdata->type ) : '';
2539 - $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 + }
2540 5623
2541 - $folder_name = str_replace( ' ', '-', $title ) . '_' . $w_uniq;
2542 - $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 );
2543 5650 $builder_type_path = WDKIT_BUILDER_PATH . "/{$builder}/";
2544 5651
2545 5652 if ( ! is_dir( $builder_type_path ) ) {
2546 5653 wp_mkdir_p( $builder_type_path );
@@ -2550,17 +5657,30 @@
2550 5657 wp_mkdir_p( $builder_type_path . $folder_name );
2551 5658 }
2552 5659
2553 5660 if ( ! empty( $img_url ) ) {
2554 - $img_body = wp_remote_get( $img_url );
2555 - $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'] );
2556 5668
2557 - $wp_filesystem->put_contents( WDKIT_BUILDER_PATH . "/$builder/$folder_name/$file_name.$img_ext", $img_body['body'] );
2558 - $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 + }
2559 5674 }
2560 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.
2561 5681 $result = (object) array(
2562 - 'success' => false,
5682 + 'success' => true,
2563 5683 'message' => ! empty( $response['message'] ) ? $response['message'] : esc_html__( 'no message', 'wdesignkit' ),
2564 5684 'description' => '',
2565 5685 'json' => wp_json_encode( $json_data ),
2566 5686 );
@@ -2570,94 +5690,16 @@
2570 5690 }
2571 5691
2572 5692 /**
2573 5693 *
2574 - * It is Use for download widget from browse page.
2575 - *
2576 - * @since 1.0.0
2577 - */
2578 - protected function wdkit_public_download_widget() {
2579 - $data = ! empty( $_POST['widget_info'] ) ? $this->wdkit_sanitizer_bypass( $_POST, 'widget_info', 'none' ) : '';
2580 - $data = json_decode( stripslashes( $data ) );
2581 -
2582 - $array_data = array(
2583 - 'id' => isset( $data->w_uniq ) ? sanitize_text_field( $data->w_uniq ) : '',
2584 - 'u_id' => isset( $data->u_id ) ? sanitize_text_field( $data->u_id ) : '',
2585 - 'type' => isset( $data->d_type ) ? sanitize_text_field( $data->d_type ) : '',
2586 - );
2587 -
2588 - $response = $this->wkit_api_call( $array_data, 'widget/download' );
2589 - $success = ! empty( $response['success'] ) ? $response['success'] : false;
2590 -
2591 - if ( empty( $success ) ) {
2592 - $massage = ! empty( $response['massage'] ) ? $response['massage'] : esc_html__( 'server error', 'wdesignkit' );
2593 -
2594 - $result = (object) array(
2595 - 'success' => false,
2596 - 'message' => $massage,
2597 - 'description' => esc_html__( 'Widget not Downloaded', 'wdesignkit' ),
2598 - );
2599 -
2600 - wp_send_json( $result );
2601 - wp_die();
2602 - }
2603 -
2604 - $response = json_decode( wp_json_encode( $response['data'] ), true );
2605 - if ( ! empty( $response ) && ! empty( $response['data'] ) ) {
2606 - $img_url = ! empty( $response['data']['image'] ) ? esc_url_raw( $response['data']['image'] ) : '';
2607 - $json = ! empty( $response['data']['json'] ) ? wp_json_encode( $response['data']['json'] ) : '';
2608 -
2609 - if ( ! empty( $json ) ) {
2610 - include_once ABSPATH . 'wp-admin/includes/file.php';
2611 - \WP_Filesystem();
2612 - global $wp_filesystem;
2613 -
2614 - $json_data = json_decode( $json );
2615 - $json_data = json_decode( $json_data );
2616 - $title = ! empty( $json_data->widget_data->widgetdata->name ) ? sanitize_text_field( $json_data->widget_data->widgetdata->name ) : '';
2617 - $builder = ! empty( $json_data->widget_data->widgetdata->type ) ? sanitize_text_field( $json_data->widget_data->widgetdata->type ) : '';
2618 - $widget_id = ! empty( $json_data->widget_data->widgetdata->widget_id ) ? sanitize_text_field( $json_data->widget_data->widgetdata->widget_id ) : '';
2619 -
2620 - $folder_name = str_replace( ' ', '-', $title ) . '_' . $widget_id;
2621 - $file_name = str_replace( ' ', '_', $title ) . '_' . $widget_id;
2622 -
2623 - $builder_type_path = WDKIT_BUILDER_PATH . "/{$builder}/";
2624 -
2625 - if ( ! is_dir( $builder_type_path . $folder_name ) ) {
2626 - wp_mkdir_p( $builder_type_path . $folder_name );
2627 - }
2628 -
2629 - if ( ! empty( $img_url ) ) {
2630 - $img_body = wp_remote_get( $img_url );
2631 - $img_ext = pathinfo( $img_url )['extension'];
2632 - $wp_filesystem->put_contents( WDKIT_BUILDER_PATH . "/$builder/$folder_name/$file_name.$img_ext", $img_body['body'] );
2633 -
2634 - $json_data->widget_data->widgetdata->w_image = WDKIT_SERVER_PATH . "/$builder/$folder_name/$file_name.$img_ext";
2635 - }
2636 -
2637 - $response = (object) array(
2638 - 'message' => ! empty( $response['message'] ) ? $response['message'] : '',
2639 - 'description' => ! empty( $response['description'] ) ? $response['description'] : '',
2640 - 'success' => ! empty( $response['success'] ) ? $response['success'] : false,
2641 - 'r_id' => ! empty( $response['data']['rid'] ) ? $response['data']['rid'] : 0,
2642 - 'json' => wp_json_encode( $json_data ),
2643 - );
2644 - }
2645 - }
2646 -
2647 - wp_send_json( $response );
2648 - wp_die();
2649 - }
2650 -
2651 - /**
2652 - *
2653 5694 * It is Use for sync widget to server
2654 5695 *
2655 5696 * @since 1.0.0
2656 5697 */
2657 5698 protected function wdkit_add_widget() {
2658 - $data = ! empty( $_POST['widget_info'] ) ? $this->wdkit_sanitizer_bypass( $_POST, 'widget_info', 'none' ) : '';
2659 - $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 );
2660 5702
2661 5703 $title = isset( $data->title ) ? sanitize_text_field( $data->title ) : '';
2662 5704 $builder = isset( $data->builder ) ? sanitize_text_field( $data->builder ) : '';
2663 5705 $w_uniq = isset( $data->w_uniq ) ? sanitize_text_field( $data->w_uniq ) : '';
@@ -2664,9 +5706,11 @@
2664 5706 $w_image = isset( $data->w_image ) ? esc_url_raw( $data->w_image ) : '';
2665 5707
2666 5708 if ( ! empty( $w_image ) ) {
2667 5709 $w_image = str_replace( '\\', '', $w_image );
2668 - $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 );
2669 5713 }
2670 5714
2671 5715 $array_data = array(
2672 5716 'token' => isset( $data->token ) ? sanitize_text_field( $data->token ) : '',
@@ -2680,8 +5724,9 @@
2680 5724 'w_imgext' => isset( $data->w_imgext ) ? sanitize_text_field( $data->w_imgext ) : '',
2681 5725 'w_version' => isset( $data->w_version ) ? $data->w_version : '',
2682 5726 'w_updates' => ! empty( $data->w_updates ) ? serialize( $data->w_updates ) : serialize( array() ),
2683 5727 'r_id' => isset( $data->r_id ) ? $data->r_id : 0,
5728 + 'unique_id' => get_option( 'wdkit_unique_id' ) ?? '',
2684 5729 );
2685 5730
2686 5731 $response = $this->wkit_api_call( $array_data, 'save_widget' );
2687 5732 $success = ! empty( $response['success'] ) ? $response['success'] : false;
@@ -2704,22 +5749,52 @@
2704 5749 $response = json_decode( wp_json_encode( $res ), true );
2705 5750 $img_url = ! empty( $response['data']['imgurl'] ) ? $response['data']['imgurl'] : '';
2706 5751
2707 5752 if ( ! empty( $img_url ) && 'error' !== $res ) {
2708 - $img_body = wp_remote_get( $img_url );
2709 - $img_ext = pathinfo( $img_url )['extension'];
2710 - include_once ABSPATH . 'wp-admin/includes/file.php';
2711 - \WP_Filesystem();
2712 - global $wp_filesystem;
2713 - $folder_name = str_replace( ' ', '-', $title ) . '_' . $w_uniq;
2714 - $file_name = str_replace( ' ', '_', $title ) . '_' . $w_uniq;
2715 - $file_path = WDKIT_BUILDER_PATH . "/$builder/$folder_name/$file_name";
2716 5753
2717 - $u_r_l = wp_json_file_decode( "$file_path.json" );
2718 - $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 );
2719 5768
2720 - $wp_filesystem->put_contents( "$file_path.json", wp_json_encode( $u_r_l ) );
2721 - $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 + }
2722 5797 }
2723 5798
2724 5799 wp_send_json( $response );
2725 5800 wp_die();
@@ -2786,24 +5861,135 @@
2786 5861 *
2787 5862 * @since 1.0.0
2788 5863 */
2789 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 +
2790 5890 $get_setting = get_option( 'wkit_settings_panel', false );
2791 5891
2792 - return array(
2793 - 'builder' => isset( $get_setting['builder'] ) ? $get_setting['builder'] : true,
2794 - 'template' => isset( $get_setting['template'] ) ? $get_setting['template'] : true,
2795 - 'gutenberg_builder' => isset( $get_setting['gutenberg_builder'] ) ? $get_setting['gutenberg_builder'] : true,
2796 - 'elementor_builder' => isset( $get_setting['elementor_builder'] ) ? $get_setting['elementor_builder'] : true,
2797 - 'bricks_builder' => isset( $get_setting['bricks_builder'] ) ? $get_setting['bricks_builder'] : false,
2798 - 'debugger_mode' => isset( $get_setting['debugger_mode'] ) ? $get_setting['debugger_mode'] : false,
2799 - 'gutenberg_template' => isset( $get_setting['gutenberg_template'] ) ? $get_setting['gutenberg_template'] : true,
2800 - '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,
2801 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;
2802 5918 }
2803 5919
2804 5920 /**
5921 + * Updated White Label Data.
2805 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 + *
2806 5992 * Use for Add new licence key.
2807 5993 *
2808 5994 * @since 1.0.0
2809 5995 */
@@ -2811,13 +5997,43 @@
2811 5997 $args = array(
2812 5998 'token' => ! empty( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '',
2813 5999 'licencekey' => ! empty( $_POST['licencekey'] ) ? sanitize_text_field( wp_unslash( $_POST['licencekey'] ) ) : '',
2814 6000 'licencename' => ! empty( $_POST['licencename'] ) ? sanitize_text_field( wp_unslash( $_POST['licencename'] ) ) : '',
6001 + 'uichemyid' => ! empty( $_POST['uichemyid'] ) ? sanitize_text_field( wp_unslash( $_POST['uichemyid'] ) ) : '',
2815 6002 );
2816 6003
2817 6004 $response = $this->wkit_api_call( $args, 'wkit_activate_key' );
2818 6005
2819 - 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 );
2820 6036 wp_die();
2821 6037 }
2822 6038
2823 6039 /**
@@ -2828,16 +6044,23 @@
2828 6044 */
2829 6045 protected function wdkit_delete_licence_key() {
2830 6046 $token = ! empty( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '';
2831 6047 $licencename = ! empty( $_POST['licencename'] ) ? sanitize_text_field( wp_unslash( $_POST['licencename'] ) ) : '';
6048 + $apikey = ! empty( $_POST['apikey'] ) ? sanitize_text_field( wp_unslash( $_POST['apikey'] ) ) : '';
2832 6049
2833 6050 $args = array(
2834 6051 'token' => $token,
2835 6052 'licencename' => $licencename,
6053 + 'apikey' => $apikey,
2836 6054 );
2837 6055
2838 6056 $response = $this->wkit_api_call( $args, 'licence_delete' );
2839 6057
6058 + // Remove local WDesignKit license data if deleting WDesignKit license
6059 + if ( 'wdkit' === $licencename ) {
6060 + delete_option( 'wdkit_licence_data' );
6061 + }
6062 +
2840 6063 wp_send_json( $response['data'] );
2841 6064 wp_die();
2842 6065 }
2843 6066
@@ -2849,12 +6072,16 @@
2849 6072 */
2850 6073 protected function wdkit_sync_licence_key() {
2851 6074 $token = ! empty( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '';
2852 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'] ) ) : '';
2853 6079
2854 6080 $args = array(
2855 6081 'token' => $token,
2856 6082 'licencename' => $licencename,
6083 + 'apikey' => $apikey,
2857 6084 );
2858 6085
2859 6086 $response = $this->wkit_api_call( $args, 'licence_sync' );
2860 6087
@@ -2862,15 +6089,126 @@
2862 6089 wp_die();
2863 6090 }
2864 6091
2865 6092 /**
6093 + * Rollback to Previous Versions
2866 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 + *
2867 6203 * It is Use for logout.
2868 6204 *
2869 6205 * @since 1.0.0
2870 6206 */
2871 6207 protected function wdkit_logout() {
2872 - $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 +
2873 6211 $response = '';
2874 6212
2875 6213 if ( ! empty( $email ) ) {
2876 6214 $token = $this->wdkit_login_user_token( $email );
@@ -2875,10 +6213,14 @@
2875 6213 if ( ! empty( $email ) ) {
2876 6214 $token = $this->wdkit_login_user_token( $email );
2877 6215 $args = array( 'token' => $token );
2878 6216
2879 - delete_transient( 'wdkit_auth_' . $email );
2880 - $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 + }
2881 6223 }
2882 6224
2883 6225 wp_send_json( $response );
2884 6226 wp_die();
@@ -2894,9 +6236,9 @@
2894 6236 */
2895 6237 protected function wdkit_login_user_token( $email = '' ) {
2896 6238
2897 6239 if ( ! empty( $email ) ) {
2898 - $user_key = strstr( $email, '@', true );
6240 + $user_key = wdesignkit_cloud_session_key( $email );
2899 6241 $get_login = get_transient( 'wdkit_auth_' . $user_key );
2900 6242
2901 6243 if ( ! empty( $get_login ) && ! empty( $get_login['token'] ) ) {
2902 6244 return $get_login['token'];
@@ -2914,9 +6256,9 @@
2914 6256 * @param string $data send all post data.
2915 6257 * @param string $type store text data.
2916 6258 * @param string $condition store text data.
2917 6259 */
2918 - protected function wdkit_sanitizer_bypass( $data, $type, $condition = 'none' ) {
6260 + protected function wdkit_extract_post_field( $data, $type, $condition = 'none' ) {
2919 6261
2920 6262 if ( 'none' === $condition ) {
2921 6263 return $data[ $type ];
2922 6264 } elseif ( 'cr_widget' === $condition ) {
@@ -2921,26 +6263,13 @@
2921 6263 return $data[ $type ];
2922 6264 } elseif ( 'cr_widget' === $condition ) {
2923 6265 return $data[ $type ];
2924 6266 }
6267 +
6268 + return null;
2925 6269 }
2926 6270
2927 - /**
2928 - * Parse args $_POST
2929 - *
2930 - * @since 1.0.0
2931 - *
2932 - * @param string $data send all post data.
2933 - * @param string $type store text data.
2934 - * @param string $condition store text data.
2935 - */
2936 - protected function wdkit_file_sanitizer_bypass( $data, $type, $condition = 'none' ) {
2937 6271
2938 - if ( 'name' === $condition ) {
2939 - return wp_normalize_path( $data[ $type ]['tmp_name'] );
2940 - }
2941 - }
2942 -
2943 6272 /**
2944 6273 * Parse args $_POST
2945 6274 *
2946 6275 * @since 1.0.0
@@ -2969,9 +6298,9 @@
2969 6298 $args['template_id'] = isset( $data['template_id'] ) ? intval( strtolower( sanitize_text_field( $data['template_id'] ) ) ) : '';
2970 6299 }
2971 6300
2972 6301 if ( isset( $data['builder'] ) ) {
2973 - $args['builder'] = isset( $data['builder'] ) ? sanitize_text_field( $data['builder'] ) : '';
6302 + $args['builder'] = isset( $data['builder'] ) ? wp_unslash( $data['builder'] ) : '';
2974 6303 }
2975 6304
2976 6305 if ( isset( $data['editor'] ) ) {
2977 6306 $args['editor'] = isset( $data['editor'] ) ? sanitize_text_field( $data['editor'] ) : '';
@@ -3016,8 +6345,28 @@
3016 6345 if ( isset( $data['plugin'] ) ) {
3017 6346 $args['plugin'] = isset( $data['plugin'] ) ? wp_unslash( $data['plugin'] ) : array();
3018 6347 }
3019 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 +
3020 6369 if ( isset( $data['tag'] ) ) {
3021 6370 $args['tag'] = isset( $data['tag'] ) ? wp_unslash( $data['tag'] ) : array();
3022 6371 }
3023 6372
@@ -3045,8 +6394,34 @@
3045 6394 $args['page_type'] = isset( $data['page_type'] ) ? wp_unslash( $data['page_type'] ) : array();
3046 6395 }
3047 6396
3048 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();
3049 6424 }
3050 6425 }
3051 6426
3052 6427 Wdkit_Api_Call::get_instance();