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 +4410 -1042 1.0.16trunk 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,10 +814,10 @@
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(
818 + // $token = $this->wdkit_login_user_token( $email );
819 + $args = array(
712 820 'token' => $token,
713 821 'builder' => $builder,
714 822 'site_url' => $site_url,
715 823 );
@@ -714,18 +822,48 @@
714 822 'site_url' => $site_url,
715 823 );
716 824
717 825 $response = WDesignKit_Data_Query::get_data( 'get_user_info', $args );
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 +
718 836 $status = ( ! empty( $response['status'] ) ) ? sanitize_text_field( $response['status'] ) : 'error';
719 837 $email = isset( $_POST['email'] ) ? strtolower( sanitize_email( wp_unslash( $_POST['email'] ) ) ) : false;
720 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'] ) ? 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 = wp_get_theme()->get('Name');
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,14 +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'] ) ) : '';
1431 - $website_kit = isset( $_POST['website_kit'] ) ? sanitize_text_field( wp_unslash( $_POST['website_kit'] ) ) : '';
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;
1432 3854
1433 - if ( empty( $email ) || empty( $template_ids ) ) {
3855 + if ( empty( $template_ids ) ) {
1434 3856 $output = array(
1435 3857 'message' => esc_html__( 'Invalid import', 'wdesignkit' ),
1436 3858 'description' => esc_html__( 'Invalid import: Check your details and try again.', 'wdesignkit' ),
1437 3859 'success' => false,
@@ -1455,24 +3877,111 @@
1455 3877 'token' => $token,
1456 3878 'template_id' => $template_ids['id'],
1457 3879 'editor' => $editor,
1458 3880 'website_kit' => $website_kit,
3881 + 'unique_id' => get_option( 'wdkit_unique_id' ) ?? '',
1459 3882 );
1460 3883
1461 - $response = WDesignKit_Data_Query::get_data( 'import_template', $temp_args );
3884 + $response = WDesignKit_Data_Query::get_data( $api_type, $temp_args );
1462 3885 $output = array();
1463 3886
1464 - if ( 'error' === $response['content'] ) {
3887 + if ( is_wp_error( $response ) ) {
3888 +
1465 3889 wp_send_json( $response );
1466 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 + );
1467 3971 } else {
1468 - $output[ $template_ids['id'] ] = $this->import_page_section_content( $args, $template_ids['id'], $response, $template_ids );
1469 - $output['message'] = $response['message'];
1470 - $output['description'] = $response['description'];
1471 - $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 + );
1472 3981 }
1473 3982
1474 - wp_send_json( $output );
3983 + wp_send_json( $res );
1475 3984 wp_die();
1476 3985 }
1477 3986
1478 3987 /**
@@ -1478,9 +3987,10 @@
1478 3987 /**
1479 3988 * Import single template and section from plugin only
1480 3989 * */
1481 3990 protected function wdkit_import_multi_template() {
1482 - $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';
1483 3993
1484 3994 if ( ! current_user_can( 'manage_options' ) ) {
1485 3995 return false;
1486 3996 }
@@ -1509,62 +4019,199 @@
1509 4019 $args['post_type'] = ! empty( $_POST['select'] ) ? sanitize_text_field( wp_unslash( $_POST['select'] ) ) : '';
1510 4020 }
1511 4021
1512 4022 $args['custom_meta'] = isset( $_POST['custom_meta'] ) ? sanitize_text_field( wp_unslash( $_POST['custom_meta'] ) ) : false;
4023 +
1513 4024 if ( ! empty( $args['template_ids'] ) && ! empty( $args['page_section'] ) ) {
1514 4025 $output = array();
1515 - if ( is_array( $args['template_ids'] ) ) {
1516 - foreach ( $args['template_ids'] as $key => $value ) {
1517 - if ( ! empty( $value['id'] ) ) {
1518 - $token = $this->wdkit_login_user_token( $args['email'] );
1519 - $temp_args = array(
1520 - 'token' => $token,
1521 - 'template_id' => $value['id'],
1522 - 'editor' => $args['editor'],
1523 - );
4026 + if ( ! empty( $args['template_ids']['id'] ) ) {
4027 + $token = $this->wdkit_login_user_token( $args['email'] );
1524 4028
1525 - $response = WDesignKit_Data_Query::get_data( 'import_template', $temp_args );
1526 -
1527 - if ( 'error' === $response['content'] ) {
1528 - wp_send_json( $response );
1529 - wp_die();
1530 - } else {
1531 - $output[ $value['id'] ] = $this->import_page_section_content( $args, $value['id'], $response, $value );
1532 - $output['message'] = $response['message'];
1533 - $output['description'] = $response['description'];
1534 - $output['success'] = $response['success'];
1535 - }
1536 - }
1537 - }
1538 - } else {
1539 - $token = $this->wdkit_login_user_token( $args['email'] );
1540 4029 $temp_args = array(
1541 4030 'token' => $token,
1542 - 'template_id' => $args['template_ids'],
4031 + 'template_id' => $args['template_ids']['id'],
1543 4032 'editor' => $args['editor'],
4033 + 'unique_id' => get_option( 'wdkit_unique_id' ) ?? '',
1544 4034 );
1545 4035
1546 - $response = WDesignKit_Data_Query::get_data( 'import_template', $temp_args );
4036 + $response = WDesignKit_Data_Query::get_data( $api_type, $temp_args );
1547 4037
1548 - 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'] ) {
1549 4047 wp_send_json( $response );
1550 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 ] = "";
1551 4084 } else {
1552 - $output[ $args['template_ids'] ] = $this->import_page_section_content( $args, $args['template_ids'], $response );
1553 - $output['message'] = $response['message'];
1554 - $output['description'] = $response['description'];
1555 - $output['success'] = $response['success'];
4085 + $this->wdkit_content_remover( $value );
1556 4086 }
1557 4087 }
4088 + } elseif ( is_object( $data ) ) {
1558 4089
1559 - $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 + }
1560 4100
1561 - wp_send_json( $output );
1562 - 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 ) : '';
1563 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 + ]);
1564 4125 }
1565 4126
1566 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 + /**
1567 4214 * Import single template and section from plugin only
1568 4215 *
1569 4216 * @param array $args store data.
1570 4217 * @param array $template_id store data.
@@ -1570,16 +4217,62 @@
1570 4217 * @param array $template_id store data.
1571 4218 * @param array $data store data.
1572 4219 * @param array $temp_data store data.
1573 4220 * */
1574 - 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 +
1575 4266 $enqueue_instance = new Wdkit_Enqueue();
1576 4267 $get_post_type = $enqueue_instance->wdkit_get_post_type_list();
1577 4268
1578 4269 $post_type = ! empty( $temp_data['type'] ) ? sanitize_text_field( wp_unslash( $temp_data['type'] ) ) : 'page';
1579 4270
1580 - if ( 'section' == $post_type ) {
4271 + if ( 'section' === $post_type ) {
1581 4272 $post_type = $temp_data['wp_post_type'];
4273 + } else {
4274 + $post_type = $temp_data['wp_post_type'];
1582 4275 }
1583 4276
1584 4277 if ( ! array_key_exists( $post_type, $get_post_type ) ) {
1585 4278 $post_type = 'page';
@@ -1584,13 +4277,28 @@
1584 4277 if ( ! array_key_exists( $post_type, $get_post_type ) ) {
1585 4278 $post_type = 'page';
1586 4279 }
1587 4280
1588 - if ( ! empty( $data ) && ! empty( $data['content'] ) && ! empty( $template_id ) && ! empty( $post_type ) && current_user_can( 'manage_options' ) ) {
1589 - $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 +
1590 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 ) : '';
1591 4298 $file_type = isset( $post_content->file_type ) ? sanitize_text_field( $post_content->file_type ) : '';
1592 4299 $content = isset( $post_content->content ) ? wp_slash( $post_content->content ) : '';
4300 + $temp_con = '';
1593 4301
1594 4302 if ( 'gutenberg' === $args['editor'] || ( 'wdkit' === $args['editor'] && ! empty( $file_type ) && 'wp_block' === $file_type ) ) {
1595 4303 if ( empty( $content ) ) {
1596 4304 wp_send_json(
@@ -1595,24 +4303,31 @@
1595 4303 if ( empty( $content ) ) {
1596 4304 wp_send_json(
1597 4305 array(
1598 4306 'template_id' => $template_id,
1599 - 'message' => 'Content is Empty.',
4307 + 'message' => __( 'Content is Empty.', 'wdesignkit' ),
1600 4308 )
1601 4309 );
1602 4310 wp_die();
1603 4311 } elseif ( ! empty( $content ) && ! empty( $file_type ) && 'wp_block' === $file_type ) {
1604 - $parse_blocks = parse_blocks( stripslashes( $content ) );
1605 4312
1606 4313 $editor = ( 'wdkit' === $args['editor'] ) ? 'gutenberg' : $args['editor'];
1607 - $content = $this->wdkit_media_import( $parse_blocks, $editor );
1608 - $content = addslashes( serialize_blocks( $content ) );
4314 + $blocks = parse_blocks( stripslashes( $content ) );
1609 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 +
1610 4324 $inserted_post = wp_insert_post(
1611 4325 array(
1612 4326 'post_status' => 'publish',
1613 4327 'post_type' => $post_type,
1614 4328 'post_title' => $post_title,
4329 + 'post_name' => $post_slug,
1615 4330 'post_content' => $content,
1616 4331 )
1617 4332 );
1618 4333
@@ -1625,14 +4340,47 @@
1625 4340 );
1626 4341 wp_die();
1627 4342 }
1628 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 +
1629 4377 if ( ! empty( $args['custom_meta'] ) && 'true' == $args['custom_meta'] ) {
1630 4378 $custom_meta = isset( $post_content->custom_meta ) ? json_decode( wp_json_encode( $post_content->custom_meta ), true ) : '';
1631 4379 if ( ! empty( $custom_meta ) ) {
1632 4380 foreach ( $custom_meta as $meta_key => $meta_val ) {
1633 4381 if ( isset( $meta_val[0] ) && ! empty( $meta_val[0] ) && is_serialized( $meta_val[0] ) ) {
1634 - $meta_val[0] = maybe_unserialize( $meta_val[0] );
4382 + $meta_val[0] = unserialize( $meta_val[0], array( 'allowed_classes' => false ) );
1635 4383 }
1636 4384
1637 4385 if ( '' === get_post_meta( $inserted_post, $meta_key, true ) && isset( $meta_val[0] ) ) {
1638 4386 add_post_meta( $inserted_post, $meta_key, $meta_val[0] );
@@ -1640,13 +4388,49 @@
1640 4388 }
1641 4389 }
1642 4390 }
1643 4391
1644 - return array(
4392 + $temp_detail = array(
1645 4393 'title' => get_the_title( $inserted_post ),
1646 4394 'edit_link' => get_edit_post_link( $inserted_post, 'internal' ),
1647 4395 'view' => get_permalink( $inserted_post ),
4396 + 'id' => $inserted_post,
1648 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();
1649 4433 }
1650 4434 } elseif ( 'elementor' === $args['editor'] || ( 'wdkit' === $args['editor'] && ! empty( $file_type ) && 'elementor' === $file_type ) ) {
1651 4435 if ( did_action( 'elementor/loaded' ) ) {
1652 4436 if ( empty( $content ) ) {
@@ -1652,17 +4436,21 @@
1652 4436 if ( empty( $content ) ) {
1653 4437 wp_send_json(
1654 4438 array(
1655 4439 'template_id' => $template_id,
1656 - 'message' => 'Content is Empty.',
4440 + 'message' => __( 'Content is Empty.', 'wdesignkit' ),
1657 4441 )
1658 4442 );
1659 4443 wp_die();
1660 4444 } elseif ( ! empty( $content ) && ! empty( $file_type ) && 'elementor' === $file_type ) {
4445 +
4446 + $content = $this->wdkit_content_remover( $content );
4447 +
1661 4448 $post_attributes = array(
1662 4449 'post_title' => $post_title,
1663 4450 'post_type' => $post_type,
1664 4451 'post_status' => 'publish',
4452 + 'post_name' => $post_slug,
1665 4453 );
1666 4454
1667 4455 if ( 'elementor_library' === $post_type ) {
1668 4456 $el_type = ( isset( $post_content->el_type ) && ! empty( $post_content->el_type ) ) ? sanitize_text_field( $post_content->el_type ) : 'page';
@@ -1686,8 +4474,43 @@
1686 4474 );
1687 4475 wp_die();
1688 4476 }
1689 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 +
1690 4513 $settings = ( isset( $post_content->settings ) && ! empty( $post_content->settings ) ) ? json_decode( wp_json_encode( $post_content->settings ), true ) : array();
1691 4514
1692 4515 $content = wp_json_encode( $content );
1693 4516 $content = $this->wdkit_media_import( $content, $file_type );
@@ -1700,14 +4523,18 @@
1700 4523 );
1701 4524
1702 4525 $inserted_id = $new_document->get_main_id();
1703 4526
4527 + if( $temp_type == 'navigation' ){
4528 + $temp_con = $content;
4529 + }
4530 +
1704 4531 if ( ! empty( $args['custom_meta'] ) && 'true' == $args['custom_meta'] ) {
1705 4532 $custom_meta = isset( $post_content->custom_meta ) ? json_decode( wp_json_encode( $post_content->custom_meta ), true ) : '';
1706 4533 if ( ! empty( $custom_meta ) ) {
1707 4534 foreach ( $custom_meta as $meta_key => $meta_val ) {
1708 4535 if ( ! empty( $meta_val[0] ) && is_serialized( $meta_val[0] ) ) {
1709 - $meta_val[0] = maybe_unserialize( $meta_val[0] );
4536 + $meta_val[0] = unserialize( $meta_val[0], array( 'allowed_classes' => false ) );
1710 4537 }
1711 4538 if ( '' === get_post_meta( $inserted_id, $meta_key, true ) ) {
1712 4539 add_post_meta( $inserted_id, $meta_key, $meta_val[0] );
1713 4540 }
@@ -1714,13 +4541,40 @@
1714 4541 }
1715 4542 }
1716 4543 }
1717 4544
1718 - return array(
4545 + $temp_detail = array(
1719 4546 'title' => get_the_title( $inserted_id ),
1720 4547 'edit_link' => get_edit_post_link( $inserted_id, 'internal' ),
1721 4548 'view' => get_permalink( $inserted_id ),
4549 + 'id' => $inserted_id,
1722 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();
1723 4577 }
1724 4578 } else {
1725 4579 wp_send_json(
1726 4580 array(
@@ -1731,11 +4585,610 @@
1731 4585 wp_die();
1732 4586 }
1733 4587 }
1734 4588 }
4589 +
4590 + wp_send_json(
4591 + array(
4592 + 'success' => false,
4593 + 'message' => esc_html__( 'Something went wrong', 'wdesignkit' ),
4594 + )
4595 + );
4596 + wp_die();
1735 4597 }
1736 4598
1737 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 + /**
1738 5191 * Share with Me Template and widgets
1739 5192 *
1740 5193 * @since 1.0.0
1741 5194 */
@@ -1795,10 +5248,10 @@
1795 5248 *
1796 5249 * @since 1.0.0
1797 5250 */
1798 5251 protected function wdkit_manage_widget_workspace() {
1799 - $Workspace_info = isset( $_POST['workspace_info'] ) ? sanitize_text_field( wp_unslash( $_POST['workspace_info'] ) ) : array();
1800 - $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();
1801 5254
1802 5255 $array_data = array(
1803 5256 'token' => isset( $data->token ) ? sanitize_text_field( $data->token ) : '',
1804 5257 'wstype' => isset( $data->type ) ? sanitize_text_field( $data->type ) : '',
@@ -1822,9 +5275,10 @@
1822 5275 protected function wdkit_activate_key() {
1823 5276 $email = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '';
1824 5277 $response = '';
1825 5278
1826 - 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 ) ) {
1827 5281 $response = array(
1828 5282 'message' => $this->e_msg_login,
1829 5283 'description' => $this->e_desc_login,
1830 5284 'success' => false,
@@ -1858,13 +5312,13 @@
1858 5312 }
1859 5313
1860 5314 /**
1861 5315 *
1862 - * It is Use for get local widget list.
5316 + * Get list local Widget List
1863 5317 *
1864 5318 * @since 1.0.0
1865 5319 */
1866 - protected function wdkit_get_widget_list() {
5320 + protected function wdkit_get_local_widgets() {
1867 5321 $builder = array();
1868 5322 $a_c_s_d_s_c = array();
1869 5323 $j_s_o_n_array = array();
1870 5324
@@ -1879,8 +5333,12 @@
1879 5333 if ( Wdkit_Wdesignkit::wdkit_is_compatible( 'gutenberg', 'widget' ) ) {
1880 5334 array_push( $builder, 'gutenberg' );
1881 5335 }
1882 5336
5337 + if ( Wdkit_Wdesignkit::wdkit_is_compatible( 'gutenberg_core', 'widget' ) ) {
5338 + array_push( $builder, 'gutenberg_core' );
5339 + }
5340 +
1883 5341 foreach ( $builder as $key => $name ) {
1884 5342 $elementor_dir = WDKIT_BUILDER_PATH . '/' . $name;
1885 5343
1886 5344 if ( ! empty( $elementor_dir ) && is_dir( $elementor_dir ) ) {
@@ -1888,10 +5346,10 @@
1888 5346 $elementor_list = array_diff( $elementor_list, array( '.', '..' ) );
1889 5347
1890 5348 if ( ! empty( $elementor_list ) ) {
1891 5349 foreach ( $elementor_list as $key => $value ) {
1892 - $a_c_s_d_s_c[ filemtime( "{$elementor_dir}/{$value}" ) ]['data'] = $value;
1893 - $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;
1894 5352 }
1895 5353 }
1896 5354 }
1897 5355 }
@@ -1920,10 +5378,9 @@
1920 5378 }
1921 5379 }
1922 5380 }
1923 5381
1924 - wp_send_json( $j_s_o_n_array );
1925 - wp_die();
5382 + return $j_s_o_n_array;
1926 5383 }
1927 5384
1928 5385 /**
1929 5386 *
@@ -1959,521 +5416,133 @@
1959 5416 wp_send_json( get_option( 'wkit_builder' ) );
1960 5417 }
1961 5418
1962 5419 /**
5420 + * Get Workspace data
1963 5421 *
1964 - * Custom_upload_dir
1965 - *
1966 - * @since 1.0.0
1967 - *
1968 - * @param array $upload store data.
5422 + * @since 2.2.5
1969 5423 */
1970 - public function custom_upload_dir( $upload ) {
1971 - // Specify the path to your custom upload directory.
1972 - if ( isset( $this->widget_folder_u_r_l ) && ! empty( $this->widget_folder_u_r_l ) ) {
5424 + public function wdkit_get_workspace_data() {
1973 5425
1974 - // Set the custom directory as the upload path.
1975 - $upload['path'] = $this->widget_folder_u_r_l;
1976 - // Set the URL for the uploaded file.
1977 - $upload['url'] = $upload['baseurl'] . $upload['subdir'];
1978 - }
5426 + $wid = isset( $_POST['wid'] ) ? sanitize_text_field( $_POST['wid'] ) : '';
5427 + $token = isset( $_POST['token'] ) ? sanitize_text_field( $_POST['token'] ) : '';
1979 5428
1980 - return $upload;
1981 - }
1982 -
1983 - /**
1984 - *
1985 - * It is Use for create widget for local
1986 - *
1987 - * @since 1.0.0
1988 - */
1989 - protected function wdkit_create_widget() {
1990 - $image = '';
1991 - if ( isset( $_FILES ) && ! empty( $_FILES ) && isset( $_FILES['image'] ) && ! empty( $_FILES['image'] ) ) {
1992 - $image = Wdkit_Data_Hooks::get_super_global_value( $_FILES, 'image' );
1993 - }
1994 -
1995 - $icon = '';
1996 - if ( isset( $_FILES ) && ! empty( $_FILES ) && isset( $_FILES['icon'] ) && ! empty( $_FILES['icon'] ) ) {
1997 - $icon = Wdkit_Data_Hooks::get_super_global_value( $_FILES, 'icon' );
1998 - }
1999 -
2000 - $data = ! empty( $_POST['value'] ) ? $this->wdkit_sanitizer_bypass( $_POST, 'value', 'cr_widget' ) : '';
2001 - $data = ! empty( $data ) ? stripslashes( $data ) : '';
2002 - $return = ! empty( $data ) ? json_decode( $data ) : '';
2003 -
2004 - $all_val = ! empty( $return ) ? $return : '';
2005 - if ( empty( $all_val ) ) {
2006 -
2007 - $responce = array(
2008 - 'message' => esc_html__( 'Data Not Found', 'wdesignkit' ),
2009 - 'description' => esc_html__( 'something went wrong! please try again later.', 'wdesignkit' ),
5429 + if ( empty( $wid ) ) {
5430 + return array(
2010 5431 'success' => false,
5432 + 'message' => esc_html__( 'Workspace ID Not Found', 'wdesignkit' ),
5433 + 'description' => esc_html__( 'Workspace ID is required', 'wdesignkit' ),
2011 5434 );
2012 -
2013 - wp_send_json( $responce );
2014 - wp_die();
2015 5435 }
2016 5436
2017 - $file_name = ! empty( $all_val->file_name ) ? sanitize_text_field( $all_val->file_name ) : '';
2018 - $folder_name = ! empty( $all_val->folder_name ) ? sanitize_text_field( $all_val->folder_name ) : '';
2019 - $old_widget = ! empty( $all_val->old_folder ) ? sanitize_text_field( $all_val->old_folder ) : '';
2020 - $description = ! empty( $all_val->description ) ? sanitize_text_field( $all_val->description ) : '';
2021 - $json_file = ! empty( $all_val->json_file ) ? $all_val->json_file : '';
2022 - $function_call = ! empty( $all_val->call ) ? sanitize_text_field( $all_val->call ) : '';
2023 - $plugin = ! empty( $all_val->plugin ) ? $all_val->plugin : '';
2024 - $d_image = ! empty( $all_val->d_image ) ? $all_val->d_image : '';
2025 - $data = json_decode( $json_file );
2026 -
2027 - $elementor_php_file = ! empty( $all_val->elementor_php_file ) ? $all_val->elementor_php_file : '';
2028 - $elementor_js = ! empty( $all_val->elementor_js ) ? $all_val->elementor_js : '';
2029 - $elementor_css = ! empty( $all_val->elementor_css ) ? $all_val->elementor_css : '';
2030 -
2031 - $gutenberg_php_file = ! empty( $all_val->gutenberg_php_file ) ? $all_val->gutenberg_php_file : '';
2032 - $gutenberg_js = ! empty( $all_val->gutenberg_js ) ? $all_val->gutenberg_js : '';
2033 - $gutenberg_css = ! empty( $all_val->gutenberg_css ) ? $all_val->gutenberg_css : '';
2034 - $external_js_file = ! empty( $all_val->external_js_file ) ? $all_val->external_js_file : '';
2035 - $style_file = ! empty( $all_val->style_file ) ? $all_val->style_file : '';
2036 -
2037 - $bricks_php_file = ! empty( $all_val->bricks_php_file ) ? $all_val->bricks_php_file : '';
2038 - $bricks_js = ! empty( $all_val->bricks_js ) ? $all_val->bricks_js : '';
2039 - $bricks_css = ! empty( $all_val->bricks_css ) ? $all_val->bricks_css : '';
2040 -
2041 - $old_folder = ! empty( $old_widget ) ? str_replace( ' ', '-', $old_widget ) : '';
2042 - $widget_type = ! empty( $data->widget_data->widgetdata->type ) ? sanitize_text_field( $data->widget_data->widgetdata->type ) : '';
2043 -
2044 - if ( empty( $widget_type ) ) {
2045 - $responce = array(
2046 - 'message' => esc_html__( 'Builder Type not found', 'wdesignkit' ),
2047 - 'description' => esc_html__( 'something went wrong! please try again later.', 'wdesignkit' ),
5437 + if ( empty( $token ) ) {
5438 + return array(
2048 5439 'success' => false,
5440 + 'message' => esc_html__( 'Token Not Found', 'wdesignkit' ),
5441 + 'description' => esc_html__( 'Token is required', 'wdesignkit' ),
2049 5442 );
2050 -
2051 - wp_send_json( $responce );
2052 - wp_die();
2053 5443 }
2054 5444
2055 - $builder_type_path = trailingslashit( WDKIT_BUILDER_PATH ) . trailingslashit( $widget_type );
2056 - $widget_file_url = $builder_type_path . $folder_name;
5445 + $args = array(
5446 + 'token' => $token,
5447 + 'wid' => $wid,
5448 + );
2057 5449
2058 - if ( ! is_dir( $widget_file_url ) ) {
2059 - wp_mkdir_p( $widget_file_url );
2060 - }
5450 + $this->wdkit_api = $this->wdkit_api_v2;
2061 5451
2062 - include_once ABSPATH . 'wp-admin/includes/file.php';
2063 - \WP_Filesystem();
2064 - global $wp_filesystem;
2065 - $widget_folder_u_r_l = trailingslashit( $widget_file_url ) . $file_name;
2066 - $this->widget_folder_u_r_l = $widget_file_url;
5452 + $url = "workspace/{$wid}/get";
2067 5453
2068 - if ( 'elementor' === $plugin ) {
2069 - $widget_file_list = scandir( $widget_file_url );
2070 - $widget_file_list = array_diff( $widget_file_list, array( '.', '..' ) );
5454 + $response = $this->wkit_api_call( $args, $url );
2071 5455
2072 - foreach ( $widget_file_list as $sub_dir_value ) {
2073 - $file = new SplFileInfo( $sub_dir_value );
2074 - $check_ext = $file->getExtension();
2075 - $extiona = pathinfo( $sub_dir_value, PATHINFO_EXTENSION );
2076 -
2077 - if ( 'js' === $extiona || 'css' === $extiona || 'json' === $extiona || 'php' === $extiona ) {
2078 - $wp_filesystem->rmdir( "$widget_file_url/$sub_dir_value", true );
2079 - }
2080 - }
2081 -
2082 - if ( ! empty( $elementor_php_file ) ) {
2083 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.php", $elementor_php_file );
2084 - }
2085 - if ( ! empty( $json_file ) ) {
2086 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.json", $json_file );
2087 - }
2088 - if ( ! empty( $elementor_css ) ) {
2089 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.css", $elementor_css );
2090 - }
2091 - if ( ! empty( $elementor_js ) ) {
2092 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.js", $elementor_js );
2093 - }
2094 - } elseif ( 'bricks' === $plugin ) {
2095 -
2096 - $widget_file_list = scandir( $widget_file_url );
2097 - $widget_file_list = array_diff( $widget_file_list, array( '.', '..' ) );
2098 -
2099 - foreach ( $widget_file_list as $sub_dir_value ) {
2100 - $file = new SplFileInfo( $sub_dir_value );
2101 - $check_ext = $file->getExtension();
2102 - $extiona = pathinfo( $sub_dir_value, PATHINFO_EXTENSION );
2103 -
2104 - if ( 'js' === $extiona || 'css' === $extiona || 'json' === $extiona || 'php' === $extiona ) {
2105 - $wp_filesystem->rmdir( "$widget_file_url/$sub_dir_value", true );
2106 - }
2107 - }
2108 -
2109 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.php", $bricks_php_file );
2110 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.json", $json_file );
2111 -
2112 - if ( ! empty( $bricks_css ) ) {
2113 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.css", $bricks_css );
2114 - }
2115 -
2116 - if ( ! empty( $bricks_js ) ) {
2117 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.js", $bricks_js );
2118 - }
2119 - } elseif ( 'gutenberg' === $plugin ) {
2120 -
2121 - $widget_file_list = scandir( $widget_file_url );
2122 - $widget_file_list = array_diff( $widget_file_list, array( '.', '..' ) );
2123 -
2124 - foreach ( $widget_file_list as $sub_dir_value ) {
2125 - $file = new SplFileInfo( $sub_dir_value );
2126 - $check_ext = $file->getExtension();
2127 - $extiona = pathinfo( $sub_dir_value, PATHINFO_EXTENSION );
2128 -
2129 - if ( 'js' === $extiona || 'css' === $extiona || 'json' === $extiona || 'php' === $extiona ) {
2130 - $wp_filesystem->rmdir( "$widget_file_url/$sub_dir_value", true );
2131 - }
2132 - }
2133 -
2134 - if ( ! empty( $external_js_file ) ) {
2135 - $wp_filesystem->put_contents( "$widget_file_url/index.js", $external_js_file );
2136 - }
2137 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.php", $gutenberg_php_file );
2138 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.json", $json_file );
2139 - if ( ! empty( $gutenberg_css ) ) {
2140 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.css", $gutenberg_css );
2141 - }
2142 - $wp_filesystem->put_contents( "$widget_folder_u_r_l.js", $gutenberg_js );
2143 - }
2144 -
2145 - if ( ! empty( $image ) && ! empty( $image['tmp_name'] ) ) {
2146 -
2147 - $img_type = array( 'jpg', 'png' );
2148 -
2149 - foreach ( $img_type as $imgext ) {
2150 - $wp_filesystem->rmdir( "$widget_folder_u_r_l . $imgext", true );
2151 - }
2152 -
2153 - $ext = $image['type'];
2154 - $img_ext = '';
2155 - if ( strpos( $ext, 'jpeg' ) ) {
2156 - $img_ext = 'jpg';
2157 - } elseif ( strpos( $ext, 'png' ) ) {
2158 - $img_ext = 'png';
2159 - }
2160 - if ( ! empty( $img_ext ) ) {
2161 - add_filter( 'upload_dir', array( $this, 'custom_upload_dir' ) );
2162 -
2163 - $uploaded_file = wp_handle_upload( $image, array( 'test_form' => false ) );
2164 -
2165 - rename( $uploaded_file['file'], $widget_folder_u_r_l . '.' . $img_ext );
2166 -
2167 - remove_filter( 'upload_dir', array( $this, 'custom_upload_dir' ) );
2168 -
2169 - }
2170 - } elseif ( ! empty( $old_widget ) ) {
2171 - $img_url = $data->widget_data->widgetdata->w_image;
2172 - $img_ext = ! empty( pathinfo( $img_url )['extension'] ) ? pathinfo( $img_url )['extension'] : '';
2173 -
2174 - if ( ! empty( $img_ext ) ) {
2175 - $old_widget_folder = str_replace( ' ', '-', $old_widget );
2176 - $old_widget_file = str_replace( ' ', '_', $old_widget );
2177 - $img_path = "$builder_type_path$old_widget_folder/$old_widget_file.$img_ext";
2178 - $img_path = str_replace( '\\', '/', $img_path );
2179 -
2180 - if ( file_exists( $img_path ) ) {
2181 - $get_img = $img_path;
2182 - $put_img = "$widget_folder_u_r_l.$img_ext";
2183 -
2184 - if ( ! empty( $get_img ) && ! empty( $put_img ) ) {
2185 - rename( $get_img, $put_img );
2186 - }
2187 - }
2188 - }
2189 - }
2190 -
2191 - if ( ! empty( $d_image ) ) {
2192 - $d_image = str_replace( '\\', '', $d_image );
2193 - $d_img_url = $d_image;
2194 - $img_body = wp_remote_get( $d_img_url );
2195 - $img_ext = pathinfo( $d_img_url )['extension'];
2196 - $wp_filesystem->put_contents( WDKIT_BUILDER_PATH . "/$widget_type/$folder_name/$file_name.$img_ext", $img_body['body'] );
2197 - }
2198 -
2199 - if ( ! empty( $function_call ) && 'import' !== $function_call && ! empty( $old_folder ) && strtolower( $old_folder ) !== strtolower( $folder_name ) && is_dir( $builder_type_path . $old_folder ) ) {
2200 - require_once ABSPATH . 'wp-admin/includes/file.php';
2201 - global $wp_filesystem;
2202 - WP_Filesystem();
2203 - $wp_filesystem->rmdir( $builder_type_path . $old_folder, true );
2204 - } elseif ( $old_folder !== $folder_name ) {
2205 - rename( WDKIT_BUILDER_PATH . "/$widget_type/$old_folder", WDKIT_BUILDER_PATH . "/$widget_type/$folder_name" );
2206 - }
2207 -
2208 - $responce = array(
2209 - 'message' => esc_html__( 'Update Saved Successfully', 'wdesignkit' ),
2210 - 'description' => esc_html__( 'Success! Update Saved', 'wdesignkit' ),
2211 - 'success' => true,
2212 - );
2213 -
2214 - wp_send_json( $responce );
5456 + wp_send_json( $response['data'] );
2215 5457 wp_die();
2216 5458 }
2217 5459
2218 5460 /**
2219 5461 *
2220 - * It is Use for delete widget from server
5462 + * Custom_upload_dir
2221 5463 *
2222 5464 * @since 1.0.0
5465 + *
5466 + * @param array $upload store data.
2223 5467 */
2224 - protected function wdkit_import_widget() {
2225 - $filename = '';
2226 - if ( isset( $_FILES ) && ! empty( $_FILES ) && isset( $_FILES['zipName'] ) && ! empty( $_FILES['zipName'] ) ) {
2227 - $filename = ! empty( $_FILES['zipName']['name'] ) ? sanitize_file_name( $_FILES['zipName']['name'] ) : '';
2228 - }
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 ) ) {
2229 5471
2230 - $name = rtrim( $filename, '.zip' );
2231 - $ext = WDKIT_BUILDER_PATH . '/elementor/dump/';
2232 -
2233 - if ( ! is_dir( $ext ) ) {
2234 - wp_mkdir_p( $ext );
2235 - } else {
2236 - require_once ABSPATH . 'wp-admin/includes/file.php';
2237 - global $wp_filesystem;
2238 - WP_Filesystem();
2239 - $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'];
2240 5476 }
2241 5477
2242 - $dir = WDKIT_BUILDER_PATH . '/elementor/dump';
2243 - $getall_json = array();
2244 - $zip = new ZipArchive();
2245 -
2246 - $zipname = '';
2247 - if ( ! empty( $_FILES['zipName']['tmp_name'] ) ) {
2248 - $zipname = $this->wdkit_file_sanitizer_bypass( $_FILES, 'zipName', 'name' );
2249 - }
2250 -
2251 - $res = $zip->open( $zipname );
2252 - if ( true === $res ) {
2253 - $zip->extractTo( $ext );
2254 - $zip->close();
2255 - $widget_name = $image = $json_file = '';
2256 - $list = scandir( $dir );
2257 - $list = array_diff( $list, array( '.', '..' ) );
2258 - foreach ( $list as $sub_dir_value ) {
2259 - $file = new SplFileInfo( $sub_dir_value );
2260 - $check_ext = $file->getExtension();
2261 - $extiona = pathinfo( $sub_dir_value, PATHINFO_EXTENSION );
2262 - if ( 'json' === $extiona ) {
2263 - $json_file = $sub_dir_value;
2264 - $u_r_l = wp_json_file_decode( $ext . $sub_dir_value );
2265 - if ( ! empty( $u_r_l->widget_data->widgetdata->name ) && ! empty( $u_r_l->widget_data->widgetdata->widget_id ) ) {
2266 - $widget_name = $u_r_l->widget_data->widgetdata->name;
2267 - $widget_id = $u_r_l->widget_data->widgetdata->widget_id;
2268 - $widget_type = ! empty( $u_r_l->widget_data->widgetdata->type ) ? $u_r_l->widget_data->widgetdata->type : '';
2269 - }
2270 - } elseif ( 'jpg' === $extiona || 'png' === $extiona || 'jpeg' === $extiona ) {
2271 - $img_ext = $extiona;
2272 - $image = $sub_dir_value;
2273 - }
2274 - }
2275 -
2276 - if ( ! empty( $widget_name ) && ! empty( $json_file ) ) {
2277 - $folder_name = str_replace( ' ', '-', $widget_name );
2278 - $file_name = str_replace( ' ', '_', $widget_name );
2279 - if ( ! is_dir( WDKIT_BUILDER_PATH . "/{$widget_type}" ) ) {
2280 - wp_mkdir_p( WDKIT_BUILDER_PATH . "/{$widget_type}" );
2281 - }
2282 - $file_path = WDKIT_BUILDER_PATH . "/{$widget_type}/{$folder_name}_{$widget_id}";
2283 - $dummy_path = WDKIT_BUILDER_PATH . '/elementor/dump';
2284 -
2285 - if ( is_dir( $dummy_path ) ) {
2286 - if ( ! rename( $dummy_path, $file_path ) ) {
2287 -
2288 - require_once ABSPATH . 'wp-admin/includes/file.php';
2289 - global $wp_filesystem;
2290 - WP_Filesystem();
2291 - $wp_filesystem->rmdir( $dummy_path, true );
2292 -
2293 - $responce = (object) array(
2294 - 'success' => false,
2295 - 'message' => esc_html__( 'Widget Not imported', 'wdesignkit' ),
2296 - 'description' => esc_html__( 'Widget alreday exist!', 'wdesignkit' ),
2297 - );
2298 -
2299 - wp_send_json( $responce );
2300 - wp_die();
2301 - }
2302 - }
2303 -
2304 - rename( "{$file_path}/{$json_file}", "{$file_path}/{$file_name}_{$widget_id}.json" );
2305 -
2306 - $get_img_file = "{$file_path}/{$image}";
2307 -
2308 - if ( file_exists( $get_img_file ) ) {
2309 - rename( $get_img_file, "{$file_path}/{$file_name}_{$widget_id}.{$img_ext}" );
2310 - }
2311 - }
2312 -
2313 - $responce = (object) array(
2314 - 'success' => true,
2315 - 'message' => esc_html__( 'Widget imported', 'wdesignkit' ),
2316 - 'description' => esc_html__( 'Widget imported successfully', 'wdesignkit' ),
2317 - 'json' => $u_r_l,
2318 - );
2319 -
2320 - wp_send_json( $responce );
2321 - wp_die();
2322 -
2323 - } else {
2324 - $responce = (object) array(
2325 - 'success' => false,
2326 - 'message' => esc_html__( 'Operation Fial!', 'wdesignkit' ),
2327 - 'description' => esc_html__( 'Widget can not imported', 'wdesignkit' ),
2328 - );
2329 -
2330 - wp_send_json( $responce );
2331 - wp_die();
2332 - }
5478 + return $upload;
2333 5479 }
2334 5480
2335 5481 /**
2336 5482 *
2337 - * Create Uniq name
2338 - *
2339 - * @since 1.0.0
2340 - */
2341 - protected function generate_unique_id() {
2342 - $now = new DateTime();
2343 - $unique_i_d = $now->format( 'YmdHis' );
2344 - $hashed_i_d = (int) $unique_i_d % 10000;
2345 - return str_pad( $hashed_i_d, 4, '0', STR_PAD_LEFT );
2346 - }
2347 -
2348 - /**
2349 - *
2350 5483 * It is Use for delete widget from server
2351 5484 *
2352 5485 * @since 1.0.0
2353 5486 */
2354 - protected function wdkit_export_widget() {
2355 - $data = isset( $_POST['info'] ) ? sanitize_text_field( wp_unslash( $_POST['info'] ) ) : '';
2356 - $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'] ) ) : '';
2357 5491
2358 - $widget_name_temp = isset( $data->widget_name ) ? sanitize_text_field( $data->widget_name ) : '';
2359 - $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 + }
2360 5499
2361 - $widget_name = str_replace( ' ', '_', $widget_name_temp );
2362 - $folder = str_replace( ' ', '-', $widget_name_temp );
2363 - $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 );
2364 5506
2365 - if ( empty( $widget_type ) ) {
2366 - $result = (object) array(
5507 + if ( false === $safe_path || '' === $safe_path['folder'] || '' === $safe_path['file'] ) {
5508 + return array(
2367 5509 'success' => false,
2368 - 'url' => '',
2369 - 'message' => esc_html__( 'Widget Type Fail', 'wdesignkit' ),
2370 - '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' ),
2371 5512 );
2372 -
2373 - wp_send_json( $result );
2374 - wp_die();
2375 5513 }
2376 5514
2377 - $downlod_path = WDKIT_BUILDER_PATH . "/{$widget_type}/";
2378 - $new_path = "{$downlod_path}/{$folder}/{$widget_name}";
5515 + $json_path = $safe_path['base'];
2379 5516
2380 - $download_url = WDKIT_SERVER_PATH . "/{$widget_type}/{$widget_name}.zip";
2381 - $zip = new ZipArchive();
2382 - $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 + }
2383 5526
2384 - $json_data = wp_json_file_decode( "$new_path.json" );
2385 - $img_ext = $json_data->widget_data->widgetdata->img_ext;
2386 -
2387 - if ( true === $zip->open( $tmp_file, ZipArchive::CREATE ) ) {
2388 - $widget_wb = str_replace( '-', '_', $folder );
2389 - $zip->addFile( "$new_path.json", "$widget_wb.json" );
2390 - if ( ! empty( $img_ext ) ) {
2391 - $zip->addFile( "$new_path.$img_ext", "$widget_wb.$img_ext" );
2392 - }
2393 - $zip->close();
2394 -
5527 + $json_data = wp_json_file_decode( "$json_path.json" );
5528 + if ( ! empty( $json_data ) ) {
2395 5529 $result = (object) array(
2396 5530 'success' => true,
2397 - 'url' => $download_url,
2398 - 'message' => esc_html__( 'Widget Exported', 'wdesignkit' ),
2399 - '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' ),
2400 5534 );
2401 -
2402 - wp_send_json( $result );
2403 - wp_die();
2404 5535 } else {
2405 5536 $result = (object) array(
2406 5537 'success' => false,
2407 - 'url' => '',
2408 - 'message' => esc_html__( 'Widget Exported Fail', 'wdesignkit' ),
2409 - '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' ),
2410 5540 );
2411 -
2412 - wp_send_json( $result );
2413 - wp_die();
2414 5541 }
2415 - }
2416 5542
2417 - /**
2418 - *
2419 - * It is Use for delete widget from server
2420 - *
2421 - * @since 1.0.0
2422 - */
2423 - protected function wdkit_delete_widget() {
2424 - $data = isset( $_POST['info'] ) ? sanitize_text_field( wp_unslash( $_POST['info'] ) ) : '';
2425 - $data = json_decode( stripslashes( $data ) );
2426 -
2427 - $delete_type = isset( $data->delete_type ) ? sanitize_text_field( $data->delete_type ) : '';
2428 -
2429 - if ( 'plugin_server' === $delete_type ) {
2430 - $array_data = array(
2431 - 'token' => isset( $data->token ) ? sanitize_text_field( $data->token ) : '',
2432 - 'type' => isset( $data->type ) ? sanitize_text_field( $data->type ) : '',
2433 - 'w_unique' => isset( $data->w_unique ) ? sanitize_text_field( $data->w_unique ) : '',
2434 - 'id' => isset( $data->id ) ? sanitize_text_field( $data->id ) : '',
2435 - );
2436 -
2437 - $response = $this->wkit_api_call( $array_data, 'save_widget' );
2438 - $success = ! empty( $response['success'] ) ? $response['success'] : false;
2439 -
2440 - if ( empty( $success ) ) {
2441 - $massage = ! empty( $response['massage'] ) ? $response['massage'] : esc_html__( 'server error', 'wdesignkit' );
2442 -
2443 - $result = (object) array(
2444 - 'success' => false,
2445 - 'message' => esc_html__( 'Widget Not Deleted', 'wdesignkit' ),
2446 - 'description' => esc_html__( 'Widget Not Deleted', 'wdesignkit' ),
2447 - );
2448 -
2449 - wp_send_json( $result );
2450 - wp_die();
2451 - }
2452 - }
2453 -
2454 - $dir_name = isset( $data->name ) ? sanitize_text_field( $data->name ) : '';
2455 - $widget_type = isset( $data->builder ) ? sanitize_text_field( $data->builder ) : '';
2456 - $dir = WDKIT_BUILDER_PATH . "/{$widget_type}/{$dir_name}";
2457 -
2458 - require_once ABSPATH . 'wp-admin/includes/file.php';
2459 - global $wp_filesystem;
2460 - WP_Filesystem();
2461 - $wp_filesystem->rmdir( $dir, true );
2462 -
2463 - if ( 'plugin_server' === $delete_type ) {
2464 - wp_send_json( $response['data'] );
2465 - wp_die();
2466 - } else {
2467 - $result = (object) array(
2468 - 'success' => true,
2469 - 'message' => esc_html__( 'widget deleted', 'wdesignkit' ),
2470 - 'description' => esc_html__( 'Widget deleted successfully', 'wdesignkit' ),
2471 - );
2472 -
2473 - wp_send_json( $result );
2474 - wp_die();
2475 - }
5543 + wp_send_json( $result );
5544 + wp_die();
2476 5545 }
2477 5546
2478 5547 /**
2479 5548 *
@@ -2481,9 +5550,9 @@
2481 5550 *
2482 5551 * @since 1.0.0
2483 5552 */
2484 5553 protected function wdkit_download_widget() {
2485 - $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' ) : '';
2486 5555 $data = json_decode( stripslashes( $data ) );
2487 5556
2488 5557 $array_data = array(
2489 5558 'token' => isset( $data->token ) ? sanitize_text_field( $data->token ) : '',
@@ -2488,8 +5557,10 @@
2488 5557 $array_data = array(
2489 5558 'token' => isset( $data->token ) ? sanitize_text_field( $data->token ) : '',
2490 5559 'type' => isset( $data->type ) ? sanitize_text_field( $data->type ) : '',
2491 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 ) : '',
2492 5563 );
2493 5564
2494 5565 $response = $this->wkit_api_call( $array_data, 'save_widget' );
2495 5566 $success = ! empty( $response['success'] ) ? $response['success'] : false;
@@ -2522,10 +5593,16 @@
2522 5593 wp_die();
2523 5594 }
2524 5595
2525 5596 $img_url = ! empty( $response['data']['image'] ) ? $response['data']['image'] : '';
2526 - $json_data = ! empty( $response['data']['json'] ) ? json_decode( $response['data']['json'] ) : '';
5597 + $json_data = ! empty( $response['data']['json'] ) ? json_decode( $response['data']['json'], true ) : '';
2527 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 +
2528 5605 if ( empty( $img_url ) && empty( $json_data ) ) {
2529 5606 $responce = (object) array(
2530 5607 'success' => false,
2531 5608 'message' => esc_html__( 'No Response Found', 'wdesignkit' ),
@@ -2539,14 +5616,38 @@
2539 5616 include_once ABSPATH . 'wp-admin/includes/file.php';
2540 5617 \WP_Filesystem();
2541 5618 global $wp_filesystem;
2542 5619
2543 - $title = ! empty( $json_data->widget_data->widgetdata->name ) ? sanitize_text_field( $json_data->widget_data->widgetdata->name ) : '';
2544 - $builder = ! empty( $json_data->widget_data->widgetdata->type ) ? sanitize_text_field( $json_data->widget_data->widgetdata->type ) : '';
2545 - $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 + }
2546 5623
2547 - $folder_name = str_replace( ' ', '-', $title ) . '_' . $w_uniq;
2548 - $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 );
2549 5650 $builder_type_path = WDKIT_BUILDER_PATH . "/{$builder}/";
2550 5651
2551 5652 if ( ! is_dir( $builder_type_path ) ) {
2552 5653 wp_mkdir_p( $builder_type_path );
@@ -2556,17 +5657,30 @@
2556 5657 wp_mkdir_p( $builder_type_path . $folder_name );
2557 5658 }
2558 5659
2559 5660 if ( ! empty( $img_url ) ) {
2560 - $img_body = wp_remote_get( $img_url );
2561 - $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'] );
2562 5668
2563 - $wp_filesystem->put_contents( WDKIT_BUILDER_PATH . "/$builder/$folder_name/$file_name.$img_ext", $img_body['body'] );
2564 - $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 + }
2565 5674 }
2566 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.
2567 5681 $result = (object) array(
2568 - 'success' => false,
5682 + 'success' => true,
2569 5683 'message' => ! empty( $response['message'] ) ? $response['message'] : esc_html__( 'no message', 'wdesignkit' ),
2570 5684 'description' => '',
2571 5685 'json' => wp_json_encode( $json_data ),
2572 5686 );
@@ -2576,94 +5690,16 @@
2576 5690 }
2577 5691
2578 5692 /**
2579 5693 *
2580 - * It is Use for download widget from browse page.
2581 - *
2582 - * @since 1.0.0
2583 - */
2584 - protected function wdkit_public_download_widget() {
2585 - $data = ! empty( $_POST['widget_info'] ) ? $this->wdkit_sanitizer_bypass( $_POST, 'widget_info', 'none' ) : '';
2586 - $data = json_decode( stripslashes( $data ) );
2587 -
2588 - $array_data = array(
2589 - 'id' => isset( $data->w_uniq ) ? sanitize_text_field( $data->w_uniq ) : '',
2590 - 'u_id' => isset( $data->u_id ) ? sanitize_text_field( $data->u_id ) : '',
2591 - 'type' => isset( $data->d_type ) ? sanitize_text_field( $data->d_type ) : '',
2592 - );
2593 -
2594 - $response = $this->wkit_api_call( $array_data, 'widget/download' );
2595 - $success = ! empty( $response['success'] ) ? $response['success'] : false;
2596 -
2597 - if ( empty( $success ) ) {
2598 - $massage = ! empty( $response['massage'] ) ? $response['massage'] : esc_html__( 'server error', 'wdesignkit' );
2599 -
2600 - $result = (object) array(
2601 - 'success' => false,
2602 - 'message' => $massage,
2603 - 'description' => esc_html__( 'Widget not Downloaded', 'wdesignkit' ),
2604 - );
2605 -
2606 - wp_send_json( $result );
2607 - wp_die();
2608 - }
2609 -
2610 - $response = json_decode( wp_json_encode( $response['data'] ), true );
2611 - if ( ! empty( $response ) && ! empty( $response['data'] ) ) {
2612 - $img_url = ! empty( $response['data']['image'] ) ? esc_url_raw( $response['data']['image'] ) : '';
2613 - $json = ! empty( $response['data']['json'] ) ? wp_json_encode( $response['data']['json'] ) : '';
2614 -
2615 - if ( ! empty( $json ) ) {
2616 - include_once ABSPATH . 'wp-admin/includes/file.php';
2617 - \WP_Filesystem();
2618 - global $wp_filesystem;
2619 -
2620 - $json_data = json_decode( $json );
2621 - $json_data = json_decode( $json_data );
2622 - $title = ! empty( $json_data->widget_data->widgetdata->name ) ? sanitize_text_field( $json_data->widget_data->widgetdata->name ) : '';
2623 - $builder = ! empty( $json_data->widget_data->widgetdata->type ) ? sanitize_text_field( $json_data->widget_data->widgetdata->type ) : '';
2624 - $widget_id = ! empty( $json_data->widget_data->widgetdata->widget_id ) ? sanitize_text_field( $json_data->widget_data->widgetdata->widget_id ) : '';
2625 -
2626 - $folder_name = str_replace( ' ', '-', $title ) . '_' . $widget_id;
2627 - $file_name = str_replace( ' ', '_', $title ) . '_' . $widget_id;
2628 -
2629 - $builder_type_path = WDKIT_BUILDER_PATH . "/{$builder}/";
2630 -
2631 - if ( ! is_dir( $builder_type_path . $folder_name ) ) {
2632 - wp_mkdir_p( $builder_type_path . $folder_name );
2633 - }
2634 -
2635 - if ( ! empty( $img_url ) ) {
2636 - $img_body = wp_remote_get( $img_url );
2637 - $img_ext = pathinfo( $img_url )['extension'];
2638 - $wp_filesystem->put_contents( WDKIT_BUILDER_PATH . "/$builder/$folder_name/$file_name.$img_ext", $img_body['body'] );
2639 -
2640 - $json_data->widget_data->widgetdata->w_image = WDKIT_SERVER_PATH . "/$builder/$folder_name/$file_name.$img_ext";
2641 - }
2642 -
2643 - $response = (object) array(
2644 - 'message' => ! empty( $response['message'] ) ? $response['message'] : '',
2645 - 'description' => ! empty( $response['description'] ) ? $response['description'] : '',
2646 - 'success' => ! empty( $response['success'] ) ? $response['success'] : false,
2647 - 'r_id' => ! empty( $response['data']['rid'] ) ? $response['data']['rid'] : 0,
2648 - 'json' => wp_json_encode( $json_data ),
2649 - );
2650 - }
2651 - }
2652 -
2653 - wp_send_json( $response );
2654 - wp_die();
2655 - }
2656 -
2657 - /**
2658 - *
2659 5694 * It is Use for sync widget to server
2660 5695 *
2661 5696 * @since 1.0.0
2662 5697 */
2663 5698 protected function wdkit_add_widget() {
2664 - $data = ! empty( $_POST['widget_info'] ) ? $this->wdkit_sanitizer_bypass( $_POST, 'widget_info', 'none' ) : '';
2665 - $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 );
2666 5702
2667 5703 $title = isset( $data->title ) ? sanitize_text_field( $data->title ) : '';
2668 5704 $builder = isset( $data->builder ) ? sanitize_text_field( $data->builder ) : '';
2669 5705 $w_uniq = isset( $data->w_uniq ) ? sanitize_text_field( $data->w_uniq ) : '';
@@ -2670,9 +5706,11 @@
2670 5706 $w_image = isset( $data->w_image ) ? esc_url_raw( $data->w_image ) : '';
2671 5707
2672 5708 if ( ! empty( $w_image ) ) {
2673 5709 $w_image = str_replace( '\\', '', $w_image );
2674 - $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 );
2675 5713 }
2676 5714
2677 5715 $array_data = array(
2678 5716 'token' => isset( $data->token ) ? sanitize_text_field( $data->token ) : '',
@@ -2686,8 +5724,9 @@
2686 5724 'w_imgext' => isset( $data->w_imgext ) ? sanitize_text_field( $data->w_imgext ) : '',
2687 5725 'w_version' => isset( $data->w_version ) ? $data->w_version : '',
2688 5726 'w_updates' => ! empty( $data->w_updates ) ? serialize( $data->w_updates ) : serialize( array() ),
2689 5727 'r_id' => isset( $data->r_id ) ? $data->r_id : 0,
5728 + 'unique_id' => get_option( 'wdkit_unique_id' ) ?? '',
2690 5729 );
2691 5730
2692 5731 $response = $this->wkit_api_call( $array_data, 'save_widget' );
2693 5732 $success = ! empty( $response['success'] ) ? $response['success'] : false;
@@ -2710,22 +5749,52 @@
2710 5749 $response = json_decode( wp_json_encode( $res ), true );
2711 5750 $img_url = ! empty( $response['data']['imgurl'] ) ? $response['data']['imgurl'] : '';
2712 5751
2713 5752 if ( ! empty( $img_url ) && 'error' !== $res ) {
2714 - $img_body = wp_remote_get( $img_url );
2715 - $img_ext = pathinfo( $img_url )['extension'];
2716 - include_once ABSPATH . 'wp-admin/includes/file.php';
2717 - \WP_Filesystem();
2718 - global $wp_filesystem;
2719 - $folder_name = str_replace( ' ', '-', $title ) . '_' . $w_uniq;
2720 - $file_name = str_replace( ' ', '_', $title ) . '_' . $w_uniq;
2721 - $file_path = WDKIT_BUILDER_PATH . "/$builder/$folder_name/$file_name";
2722 5753
2723 - $u_r_l = wp_json_file_decode( "$file_path.json" );
2724 - $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 );
2725 5768
2726 - $wp_filesystem->put_contents( "$file_path.json", wp_json_encode( $u_r_l ) );
2727 - $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 + }
2728 5797 }
2729 5798
2730 5799 wp_send_json( $response );
2731 5800 wp_die();
@@ -2792,24 +5861,135 @@
2792 5861 *
2793 5862 * @since 1.0.0
2794 5863 */
2795 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 +
2796 5890 $get_setting = get_option( 'wkit_settings_panel', false );
2797 5891
2798 - return array(
2799 - 'builder' => isset( $get_setting['builder'] ) ? $get_setting['builder'] : true,
2800 - 'template' => isset( $get_setting['template'] ) ? $get_setting['template'] : true,
2801 - 'gutenberg_builder' => isset( $get_setting['gutenberg_builder'] ) ? $get_setting['gutenberg_builder'] : true,
2802 - 'elementor_builder' => isset( $get_setting['elementor_builder'] ) ? $get_setting['elementor_builder'] : true,
2803 - 'bricks_builder' => isset( $get_setting['bricks_builder'] ) ? $get_setting['bricks_builder'] : false,
2804 - 'debugger_mode' => isset( $get_setting['debugger_mode'] ) ? $get_setting['debugger_mode'] : false,
2805 - 'gutenberg_template' => isset( $get_setting['gutenberg_template'] ) ? $get_setting['gutenberg_template'] : true,
2806 - '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,
2807 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;
2808 5918 }
2809 5919
2810 5920 /**
5921 + * Updated White Label Data.
2811 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 + *
2812 5992 * Use for Add new licence key.
2813 5993 *
2814 5994 * @since 1.0.0
2815 5995 */
@@ -2822,9 +6002,38 @@
2822 6002 );
2823 6003
2824 6004 $response = $this->wkit_api_call( $args, 'wkit_activate_key' );
2825 6005
2826 - 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 );
2827 6036 wp_die();
2828 6037 }
2829 6038
2830 6039 /**
@@ -2835,16 +6044,23 @@
2835 6044 */
2836 6045 protected function wdkit_delete_licence_key() {
2837 6046 $token = ! empty( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '';
2838 6047 $licencename = ! empty( $_POST['licencename'] ) ? sanitize_text_field( wp_unslash( $_POST['licencename'] ) ) : '';
6048 + $apikey = ! empty( $_POST['apikey'] ) ? sanitize_text_field( wp_unslash( $_POST['apikey'] ) ) : '';
2839 6049
2840 6050 $args = array(
2841 6051 'token' => $token,
2842 6052 'licencename' => $licencename,
6053 + 'apikey' => $apikey,
2843 6054 );
2844 6055
2845 6056 $response = $this->wkit_api_call( $args, 'licence_delete' );
2846 6057
6058 + // Remove local WDesignKit license data if deleting WDesignKit license
6059 + if ( 'wdkit' === $licencename ) {
6060 + delete_option( 'wdkit_licence_data' );
6061 + }
6062 +
2847 6063 wp_send_json( $response['data'] );
2848 6064 wp_die();
2849 6065 }
2850 6066
@@ -2856,12 +6072,16 @@
2856 6072 */
2857 6073 protected function wdkit_sync_licence_key() {
2858 6074 $token = ! empty( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '';
2859 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'] ) ) : '';
2860 6079
2861 6080 $args = array(
2862 6081 'token' => $token,
2863 6082 'licencename' => $licencename,
6083 + 'apikey' => $apikey,
2864 6084 );
2865 6085
2866 6086 $response = $this->wkit_api_call( $args, 'licence_sync' );
2867 6087
@@ -2869,15 +6089,126 @@
2869 6089 wp_die();
2870 6090 }
2871 6091
2872 6092 /**
6093 + * Rollback to Previous Versions
2873 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 + *
2874 6203 * It is Use for logout.
2875 6204 *
2876 6205 * @since 1.0.0
2877 6206 */
2878 6207 protected function wdkit_logout() {
2879 - $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 +
2880 6211 $response = '';
2881 6212
2882 6213 if ( ! empty( $email ) ) {
2883 6214 $token = $this->wdkit_login_user_token( $email );
@@ -2882,10 +6213,14 @@
2882 6213 if ( ! empty( $email ) ) {
2883 6214 $token = $this->wdkit_login_user_token( $email );
2884 6215 $args = array( 'token' => $token );
2885 6216
2886 - delete_transient( 'wdkit_auth_' . $email );
2887 - $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 + }
2888 6223 }
2889 6224
2890 6225 wp_send_json( $response );
2891 6226 wp_die();
@@ -2901,9 +6236,9 @@
2901 6236 */
2902 6237 protected function wdkit_login_user_token( $email = '' ) {
2903 6238
2904 6239 if ( ! empty( $email ) ) {
2905 - $user_key = strstr( $email, '@', true );
6240 + $user_key = wdesignkit_cloud_session_key( $email );
2906 6241 $get_login = get_transient( 'wdkit_auth_' . $user_key );
2907 6242
2908 6243 if ( ! empty( $get_login ) && ! empty( $get_login['token'] ) ) {
2909 6244 return $get_login['token'];
@@ -2921,9 +6256,9 @@
2921 6256 * @param string $data send all post data.
2922 6257 * @param string $type store text data.
2923 6258 * @param string $condition store text data.
2924 6259 */
2925 - protected function wdkit_sanitizer_bypass( $data, $type, $condition = 'none' ) {
6260 + protected function wdkit_extract_post_field( $data, $type, $condition = 'none' ) {
2926 6261
2927 6262 if ( 'none' === $condition ) {
2928 6263 return $data[ $type ];
2929 6264 } elseif ( 'cr_widget' === $condition ) {
@@ -2928,26 +6263,13 @@
2928 6263 return $data[ $type ];
2929 6264 } elseif ( 'cr_widget' === $condition ) {
2930 6265 return $data[ $type ];
2931 6266 }
6267 +
6268 + return null;
2932 6269 }
2933 6270
2934 - /**
2935 - * Parse args $_POST
2936 - *
2937 - * @since 1.0.0
2938 - *
2939 - * @param string $data send all post data.
2940 - * @param string $type store text data.
2941 - * @param string $condition store text data.
2942 - */
2943 - protected function wdkit_file_sanitizer_bypass( $data, $type, $condition = 'none' ) {
2944 6271
2945 - if ( 'name' === $condition ) {
2946 - return wp_normalize_path( $data[ $type ]['tmp_name'] );
2947 - }
2948 - }
2949 -
2950 6272 /**
2951 6273 * Parse args $_POST
2952 6274 *
2953 6275 * @since 1.0.0
@@ -3023,8 +6345,28 @@
3023 6345 if ( isset( $data['plugin'] ) ) {
3024 6346 $args['plugin'] = isset( $data['plugin'] ) ? wp_unslash( $data['plugin'] ) : array();
3025 6347 }
3026 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 +
3027 6369 if ( isset( $data['tag'] ) ) {
3028 6370 $args['tag'] = isset( $data['tag'] ) ? wp_unslash( $data['tag'] ) : array();
3029 6371 }
3030 6372
@@ -3053,8 +6395,34 @@
3053 6395 }
3054 6396
3055 6397 return $args;
3056 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();
6424 + }
3057 6425 }
3058 6426
3059 6427 Wdkit_Api_Call::get_instance();
3060 -}
6428 +}