PluginProbe ʕ •ᴥ•ʔ
Kirki – Freeform Page Builder, Website Builder & Customizer / 6.1.1
Kirki – Freeform Page Builder, Website Builder & Customizer v6.1.1
6.1.1 6.1.0 6.0.14 6.0.13 6.0.12 6.0.11 6.0.10 6.0.9 6.0.8 6.0.7 6.0.6 6.0.5 6.0.4 6.0.3 6.0.2 6.0.1 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 4.0.19 4.0.20 4.0.21 4.0.22 4.0.23 4.0.24 4.1 4.2.0 5.0.0 5.1.0 5.1.1 5.2.0 5.2.1 5.2.2 5.2.3 6.0.0 trunk 3.0.40 3.0.41 3.0.42 3.0.43 3.0.44 3.0.45 3.1.0 3.1.1 3.1.2
kirki / includes / Ajax / UserData.php
kirki / includes / Ajax Last commit date
Collaboration 2 weeks ago Apps.php 2 weeks ago Collection.php 1 month ago Comments.php 2 months ago DynamicContent.php 1 month ago ExportImport.php 2 days ago Form.php 2 weeks ago Media.php 2 days ago Page.php 2 days ago PageSettings.php 2 weeks ago RBAC.php 2 weeks ago Symbol.php 2 weeks ago Taxonomy.php 2 months ago TemplateExportImport.php 2 months ago UserData.php 2 weeks ago Users.php 2 months ago Walkthrough.php 2 months ago WordpressData.php 2 months ago WpAdmin.php 2 days ago
UserData.php
741 lines
1 <?php
2 /**
3 * Manager User data
4 *
5 * @package kirki
6 */
7
8 namespace Kirki\Ajax;
9
10 use Exception;
11 use Kirki\HelperFunctions;
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit; // Exit if accessed directly.
15 }
16
17 /**
18 * UserData API Class
19 * @deprecated
20 */
21 class UserData {
22
23 /**
24 * Save user controller data
25 *
26 * @return void wp_send_json
27 *
28 * @deprecated
29 * @see \Kirki\App\Managers\GlobalDataManager::update_global_ui_controller()
30 */
31 public static function save_user_controller() {
32 $user_id = get_current_user_id();
33 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
34 $data = isset( $_POST['data'] ) ? $_POST['data'] : null;
35 $data = json_decode( stripslashes( $data ), true );
36 if ( ! empty( $user_id ) ) {
37 HelperFunctions::update_global_data_using_key( KIRKI_USER_CONTROLLER_META_KEY, $data );
38 wp_send_json( array( 'status' => 'User controller data saved' ) );
39 }
40 die();
41 }
42
43 /**
44 * Save user saved data
45 *
46 * @return void wp_send_json
47 *
48 * @deprecated
49 * @see \Kirki\App\Managers\GlobalDataManager::update_global_ui_saved_data()
50 */
51 public static function save_user_saved_data() {
52 $user_id = get_current_user_id();
53 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
54 $data = isset( $_POST['data'] ) ? $_POST['data'] : null;
55 $data = json_decode( stripslashes( $data ), true );
56 if ( ! empty( $user_id ) ) {
57 HelperFunctions::update_global_data_using_key( KIRKI_USER_SAVED_DATA_META_KEY, $data );
58 wp_send_json( array( 'status' => 'User saved data saved' ) );
59 }
60 die();
61 }
62
63 /**
64 * Save user custom fonts data
65 *
66 * @return void wp_send_json
67 *
68 * @deprecated
69 * @see \Kirki\App\Managers\GlobalDataManager::update_global_custom_fonts()
70 */
71 public static function save_user_custom_fonts_data() {
72 $user_id = get_current_user_id();
73 //phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
74 $data = isset( $_POST['data'] ) ? $_POST['data'] : null;
75 $data = json_decode( stripslashes( $data ), true );
76 if ( ! empty( $user_id ) ) {
77 HelperFunctions::update_global_data_using_key( KIRKI_USER_CUSTOM_FONTS_META_KEY, $data );
78 wp_send_json( array( 'status' => 'User custom fonts data saved' ) );
79 }
80 die();
81 }
82
83 /**
84 * Save the updated font data in global data
85 *
86 * @param object $font Font data.
87 *
88 * @deprecated
89 * @see \Kirki\App\Services\FontService::save_google_font_into_global_custom_fonts()
90 */
91 public static function save_the_font_global_data( $font ) {
92 // first get the font data
93 $custom_fonts = HelperFunctions::get_global_data_using_key( KIRKI_USER_CUSTOM_FONTS_META_KEY );
94
95 if ( empty( $custom_fonts ) ) {
96 $custom_fonts = array();
97 }
98
99 if ( isset( $font['family'] ) ) {
100 // update the font data
101 $custom_fonts[ $font['family'] ] = $font;
102
103 // save the font data
104 HelperFunctions::update_global_data_using_key( KIRKI_USER_CUSTOM_FONTS_META_KEY, $custom_fonts );
105 }
106 }
107
108 /**
109 * Download google font in local
110 *
111 * Requirements => must be a google font
112 *
113 * @param object $font Font data.
114 *
115 * @return object
116 * @deprecated
117 * @see \Kirki\App\Services\FontService::download_google_font()
118 */
119 public static function make_google_font_offline() {
120 $font = isset( $_POST['font'] ) ? $_POST['font'] : null;
121 $font = json_decode( stripslashes( $font ), true );
122
123 $data = self::download_font_offline( $font );
124
125 if ( $data['status'] ) {
126 // save the font data in global data
127 self::save_the_font_global_data( $data['font'] );
128 }
129
130 // return the response
131 wp_send_json( $data );
132 }
133
134 /**
135 * Download fonts
136 * @deprecated
137 * @see \Kirki\App\Services\FontService::download_google_font()
138 */
139 private static function download_font_offline( &$font ) {
140 if ( empty( $font['family'] ) || empty( $font['fontUrl'] ) || strpos( $font['fontUrl'], 'fonts.googleapis.com' ) === false ) {
141 return array(
142 'font' => $font,
143 'status' => false,
144 'message' => "It's not a valid Google Font",
145 );
146 }
147
148 $font_family_slug = sanitize_title_with_dashes( $font['family'] );
149 // Extra security: keep only a-z, 0-9, and hyphens
150 $font_family_slug = preg_replace( '/[^a-z0-9\-]/i', '', $font_family_slug );
151
152 // Prevent empty value
153 if ( empty( $font_family_slug ) ) {
154 return array(
155 'font' => $font,
156 'status' => false,
157 'message' => 'Not valid font family',
158 );
159 }
160 // Prevent path traversal (..), though whitelist already blocks it
161 if ( strpos( $font_family_slug, '..' ) !== false ) {
162 return array(
163 'font' => $font,
164 'status' => false,
165 'message' => 'Not valid font family',
166 );
167 }
168
169 $font_dir = WP_CONTENT_DIR . "/uploads/kirki-fonts/{$font_family_slug}";
170
171 $has_write_permission = HelperFunctions::get_upload_dir_has_write_permission();
172
173 // Check if the directory has upload or write permission
174 if ( ! $has_write_permission ) {
175 return array(
176 'font' => $font,
177 'status' => false,
178 'message' => 'Font directory is not writable',
179 );
180 }
181
182 try {
183 if ( ! is_dir( $font_dir ) ) {
184 wp_mkdir_p( $font_dir );
185 }
186
187 $css_file_path = $font_dir . "/{$font_family_slug}.css";
188
189 // Already downloaded
190 if ( file_exists( $css_file_path ) ) {
191 return array(
192 'font' => $font,
193 'status' => false,
194 'message' => 'Font already downloaded',
195 );
196 }
197
198 $css = HelperFunctions::http_get( $font['fontUrl'] );
199
200 if ( ! $css ) {
201 throw new Exception( 'Failed to fetch Google Fonts CSS' );
202 }
203
204 if ( empty( $font['files'] ) || ! is_array( $font['files'] ) ) {
205 throw new Exception( 'No font files provided.' );
206 }
207 // update font-weight to 400 from regular
208 if ( isset( $font['files']['regular'] ) ) {
209 $font['files']['400'] = $font['files']['regular'];
210 unset( $font['files']['regular'] );
211 }
212
213 $local_css = '';
214 $formats = array(
215 'woff2' => 'woff2',
216 'woff' => 'woff',
217 'ttf' => 'truetype',
218 'otf' => 'opentype',
219 );
220
221 foreach ( $font['files'] as $weight => $url ) {
222 $allowed_ext = array( 'woff2', 'woff', 'ttf', 'otf' );
223 $extension = strtolower( pathinfo( $url, PATHINFO_EXTENSION ) );
224 if ( ! in_array( $extension, $allowed_ext, true ) ) {
225 throw new Exception( "Invalid or unsafe file extension: {$extension}" );
226 }
227
228 $file_name = "{$weight}.{$extension}";
229 $file_path = $font_dir . '/' . $file_name;
230
231 $font_data = HelperFunctions::http_get( $url );
232 if ( ! $font_data ) {
233 throw new Exception( 'Failed to fetch font file' );
234 }
235 file_put_contents( $file_path, $font_data );
236
237 $format = $formats[ $extension ] ?? 'truetype';
238 $local_css .= "@font-face {
239 font-family: '{$font['family']}';
240 font-style: normal;
241 font-weight: {$weight};
242 font-display: swap;
243 src: url('{$file_name}') format('{$format}');
244 }\n";
245 }
246
247 if ( empty( $local_css ) ) {
248 throw new Exception( 'No usable font files were downloaded.' );
249 }
250
251 file_put_contents( $css_file_path, $local_css );
252 $font['localUrl'] = content_url( "/uploads/kirki-fonts/{$font_family_slug}/{$font_family_slug}.css" );
253
254 return array(
255 'font' => $font,
256 'status' => true,
257 'message' => 'Font downloaded successfully',
258 );
259 } catch ( Exception $e ) {
260 // Clean up on failure
261 if ( is_dir( $font_dir ) ) {
262 HelperFunctions::delete_directory( $font_dir );
263 }
264
265 return array(
266 'font' => $font,
267 'status' => false,
268 'message' => 'Error: ' . $e->getMessage(),
269 );
270 }
271 }
272
273 /**
274 * Delete google font from local
275 *
276 * @param object $font Font data.
277 *
278 * @return object
279 *
280 * @deprecated
281 * @see \Kirki\App\Services\FontService::remove_google_font()
282 */
283 public static function remove_google_font_offline() {
284 $font = isset( $_POST['font'] ) ? $_POST['font'] : null;
285 $font = json_decode( stripslashes( $font ), true );
286
287 $font_family_slug = sanitize_title_with_dashes( basename( $font['family'] ) );
288 $font_dir = WP_CONTENT_DIR . "/uploads/kirki-fonts/{$font_family_slug}";
289
290 if ( is_dir( $font_dir ) ) {
291 HelperFunctions::delete_directory( $font_dir );
292 }
293
294 // remove the localUrl from font object and update the
295 unset( $font['localUrl'] );
296
297 // save the font data in global data
298 self::save_the_font_global_data( $font );
299
300 wp_send_json(
301 array(
302 'font' => $font,
303 'status' => true,
304 'message' => 'Font removed successfully',
305 )
306 );
307
308 die();
309 }
310
311 /**
312 * Get user controller data
313 *
314 * @return void wp_send_json
315 *
316 * @deprecated
317 * @see \Kirki\App\Managers\GlobalDataManager::get_global_ui_controller()
318 */
319 public static function get_user_controller() {
320 $control = HelperFunctions::get_global_data_using_key( KIRKI_USER_CONTROLLER_META_KEY );
321 if ( $control ) {
322 wp_send_json( $control );
323 } else {
324 wp_send_json( json_decode( '{}' ) );
325 }
326 }
327
328
329 /**
330 * Get User Saved data
331 *
332 * @return void wp_send_json
333 *
334 * @deprecated
335 * @see \Kirki\App\Managers\GlobalDataManager::get_global_ui_saved_data()
336 */
337 public static function get_user_saved_data() {
338 $saved_data = HelperFunctions::get_global_data_using_key( KIRKI_USER_SAVED_DATA_META_KEY );
339 if ( ! $saved_data ) {
340 $saved_data = array();
341 }
342
343 $saved_data['variableData'] = self::get_kirki_variable_data();
344
345 wp_send_json( $saved_data );
346 }
347
348 /**
349 * Get User login status
350 *
351 * @return void wp_send_json
352 * @deprecated
353 * @see \Kirki\Framework\Wordpress\User::is_logged_in()
354 */
355 public static function check_user_login() {
356 wp_send_json( is_user_logged_in() );
357 die();
358 }
359
360 /**
361 * @deprecated
362 * @see \Kirki\App\Managers\GlobalDataManager::normalize_variable_data()
363 */
364 public static function normalize_variable_data( $raw_data ) {
365
366 if(isset( $raw_data['data'] ) && is_array( $raw_data['data'] ) && count($raw_data['data']) > 0 && isset($raw_data['data'][0]['key']) ) {
367 return $raw_data; // thats means already normalized.
368 }
369 // Start from clean base
370 $organized = self::initial_variable_data();
371
372 // Index groups by key for fast access
373 $groups = [];
374 foreach ( $organized['data'] as $index => $group ) {
375 $groups[ $group['key'] ] = &$organized['data'][ $index ];
376 }
377
378 foreach ( $raw_data['data'] as $section ) {
379
380 /* ---------------------------------
381 * Merge modes (unique by key)
382 * --------------------------------- */
383 if ( ! empty( $section['modes'] ) ) {
384
385 foreach ( $groups as &$group ) {
386
387 $mode_index = [];
388
389 foreach ( $group['modes'] as $existing_mode ) {
390 if ( isset( $existing_mode['key'] ) ) {
391 $mode_index[ $existing_mode['key'] ] = true;
392 }
393 }
394
395 foreach ( $section['modes'] as $mode ) {
396 if (
397 isset( $mode['key'] ) &&
398 ! isset( $mode_index[ $mode['key'] ] )
399 ) {
400 $group['modes'][] = $mode;
401 $mode_index[ $mode['key'] ] = true;
402 }
403 }
404 }
405 }
406
407 /* ---------------------------------
408 * Organize variables
409 * --------------------------------- */
410 if ( empty( $section['variables'] ) ) {
411 continue;
412 }
413
414 foreach ( $section['variables'] as $variable ) {
415
416 if ( empty( $variable['type'] ) ) {
417 continue;
418 }
419
420 $group_key = $variable['type'];
421
422 if ( ! isset( $groups[ $group_key ] ) ) {
423 continue;
424 }
425
426 $found = false;
427
428 foreach ( $groups[ $group_key ]['variables'] as &$existing ) {
429
430 if ( isset( $existing['id'], $variable['id'] ) && $existing['id'] === $variable['id'] ) {
431
432 // Merge values by mode
433 $existing['value'] = array_merge(
434 $existing['value'] ?? [],
435 $variable['value'] ?? []
436 );
437
438 $found = true;
439 break;
440 }
441 }
442
443 if ( ! $found ) {
444 $groups[ $group_key ]['variables'][] = $variable;
445 }
446 }
447 }
448
449 return $organized;
450 }
451
452 /**
453 * @deprecated
454 * @see \Kirki\App\Managers\GlobalDataManager::sort_variable_data()
455 */
456 public static function sort_variable_data( $data ) {
457 // Enforce deterministic group order: Color, Number, Text style, Font family
458 $order_map = array(
459 'color' => 0,
460 'size' => 1,
461 'text-style' => 2,
462 'font-family' => 3,
463 );
464
465 usort(
466 $data['data'],
467 function ( $a, $b ) use ( $order_map ) {
468 $a_order = isset( $order_map[ $a['key'] ] ) ? $order_map[ $a['key'] ] : 99;
469 $b_order = isset( $order_map[ $b['key'] ] ) ? $order_map[ $b['key'] ] : 99;
470 return $a_order - $b_order;
471 }
472 );
473
474 return $data;
475 }
476
477
478 /**
479 * @deprecated
480 * @see \Kirki\App\Managers\GlobalDataManager::initial_variable_data()
481 */
482 public static function initial_variable_data() {
483 // return json_decode( '{"data":[]}', true );
484 return array(
485 'data' => array(
486 array(
487 'title' => 'Colors',
488 'key' => 'color',
489 'modes' => array(
490 array(
491 'title' => 'Default',
492 'key' => 'default',
493 ),
494 ),
495 'variables' => array(),
496 ),
497 array(
498 'title' => 'Numbers',
499 'key' => 'size',
500 'modes' => array(
501 array(
502 'title' => 'Default',
503 'key' => 'default',
504 ),
505 ),
506 'variables' => array(),
507 ),
508 array(
509 'title' => 'Text Styles',
510 'key' => 'text-style',
511 'modes' => array(
512 array(
513 'title' => 'Default',
514 'key' => 'default',
515 ),
516 ),
517 'variables' => array(),
518 ),
519 array(
520 'title' => 'Font Family',
521 'key' => 'font-family',
522 'modes' => array(
523 array(
524 'title' => 'Default',
525 'key' => 'default',
526 ),
527 ),
528 'variables' => array(),
529 ),
530 ),
531
532 );
533 }
534
535 /**
536 * @deprecated
537 * @see Kirki\App\Managers\GlobalDataManager::get_variable_data()
538 */
539 public static function get_kirki_variable_data() {
540 $saved_data = HelperFunctions::get_global_data_using_key( KIRKI_USER_SAVED_DATA_META_KEY );
541
542 if ( $saved_data && ! empty( $saved_data['variableData']['data'] ) ) {
543 $variables = self::normalize_variable_data( $saved_data['variableData'] );
544 } else {
545 $variables = self::initial_variable_data();
546 }
547
548 $variables = self::normalize_old_variable_data( $variables );
549
550 // sort variable data
551 $variables = self::sort_variable_data( $variables );
552
553 return $variables;
554 }
555
556 /**
557 * @deprecated
558 * @see Kirki\App\Managers\GlobalDataManager::normalize_old_variable_data()
559 */
560 private static function normalize_old_variable_data( $variables ) {
561 // Check if data needs normalization
562 if ( ! isset( $variables['data'] ) || ! is_array( $variables['data'] ) ) {
563 return $variables;
564 }
565
566 // Check if already normalized (has the 4 standard groups with correct keys)
567 $expected_keys = array( 'color', 'size', 'text-style', 'font-family' );
568 $actual_keys = array_column( $variables['data'], 'key' );
569
570 if ( count( $actual_keys ) === 4 && empty( array_diff( $expected_keys, $actual_keys ) ) ) {
571 // Already normalized, return as-is
572 return $variables;
573 }
574
575 // Create fresh groups
576 $normalized = array(
577 'data' => array(
578 array(
579 'title' => 'Colors',
580 'key' => 'color',
581 'modes' => array(),
582 'variables' => array(),
583 ),
584 array(
585 'title' => 'Numbers',
586 'key' => 'size',
587 'modes' => array(),
588 'variables' => array(),
589 ),
590 array(
591 'title' => 'Text Styles',
592 'key' => 'text-style',
593 'modes' => array(),
594 'variables' => array(),
595 ),
596 array(
597 'title' => 'Font Family',
598 'key' => 'font-family',
599 'modes' => array(),
600 'variables' => array(),
601 ),
602 ),
603 );
604
605 // Index for quick access
606 $groups = array();
607 foreach ( $normalized['data'] as $index => &$group ) {
608 $groups[ $group['key'] ] = &$normalized['data'][ $index ];
609 }
610
611 // Track modes per type
612 $modes_per_type = array(
613 'color' => array(),
614 'size' => array(),
615 'text-style' => array(),
616 'font-family' => array(),
617 );
618
619 // Single pass: process all variables
620 foreach ( $variables['data'] as $section ) {
621 if ( empty( $section['variables'] ) ) {
622 continue;
623 }
624
625 foreach ( $section['variables'] as $variable ) {
626 // Determine correct group based on variable's type
627 $var_type = isset( $variable['type'] ) ? $variable['type'] : null;
628
629 if ( ! $var_type || ! isset( $groups[ $var_type ] ) ) {
630 continue;
631 }
632
633 // Add variable to correct group (move if in wrong section)
634 $groups[ $var_type ]['variables'][] = $variable;
635
636 // Collect modes for this type
637 if ( isset( $variable['value'] ) && is_array( $variable['value'] ) ) {
638 foreach ( array_keys( $variable['value'] ) as $mode_key ) {
639 if ( ! isset( $modes_per_type[ $var_type ][ $mode_key ] ) ) {
640 $modes_per_type[ $var_type ][ $mode_key ] = array(
641 'key' => $mode_key,
642 'title' => ucfirst( $mode_key ),
643 );
644 }
645 }
646 }
647 }
648 }
649
650 // Assign collected modes to groups
651 foreach ( $modes_per_type as $type => $modes ) {
652 if ( isset( $groups[ $type ] ) ) {
653 $groups[ $type ]['modes'] = array_values( $modes );
654 // Ensure default mode exists
655 if ( empty( $groups[ $type ]['modes'] ) ) {
656 $groups[ $type ]['modes'][] = array(
657 'key' => 'default',
658 'title' => 'Default',
659 );
660 }
661 }
662 }
663
664 return $normalized;
665 }
666
667 /**
668 * Get user custom fonts data
669 *
670 * @return void wp_send_json
671 *
672 * @deprecated
673 * @see \Kirki\App\Managers\GlobalDataManager::get_global_custom_fonts()
674 */
675 public static function get_user_custom_fonts_data() {
676 $custom_fonts = HelperFunctions::get_global_data_using_key( KIRKI_USER_CUSTOM_FONTS_META_KEY );
677 if ( $custom_fonts ) {
678 wp_send_json( $custom_fonts );
679 } else {
680 wp_send_json( json_decode( '{}' ) );
681 }
682 }
683
684 /**
685 * Get View port list.
686 * this method only for front end. not for editor. cause list data not completed data.
687 *
688 * @return array
689 *
690 * @deprecated
691 * @see \Kirki\App\Managers\GlobalDataManager::get_view_port_list()
692 */
693 public static function get_view_port_list() {
694 $control = HelperFunctions::get_global_data_using_key( KIRKI_USER_CONTROLLER_META_KEY );
695 if ( ! $control || ! isset( $control['viewport'], $control['viewport']['list'] ) ) {
696 return self::sort_viewport_list( HelperFunctions::get_initial_view_ports()['list'] );
697 }
698 return self::sort_viewport_list( $control['viewport']['list'] );
699 }
700
701 /**
702 * Sort view port list
703 *
704 * @param array $arr list of view port list.
705 * @return array
706 *
707 * @deprecated
708 * @see \Kirki\App\Managers\GlobalDataManager::sort_viewport_list()
709 */
710 private static function sort_viewport_list( $arr ) {
711 $arr = (array) $arr;
712 $list = array();
713 array_multisort( array_column( $arr, 'minWidth' ), SORT_ASC, SORT_NUMERIC, $arr );
714 $flag = false;
715 foreach ( $arr as $key => $value ) {
716 if ( $flag ) {
717 $list[ $key ] = $value;
718 $list[ $key ]['type'] = 'min';
719 $list[ $key ]['id'] = $key;
720 }
721 if ( $key === 'md' ) {
722 $flag = true;
723 $list[ $key ] = $value;
724 $list[ $key ]['id'] = $key;
725 $list[ $key ]['type'] = 'max';
726 }
727 }
728 $flag = false;
729 foreach ( array_reverse( $arr ) as $key => $value ) {
730 if ( $flag ) {
731 $list[ $key ] = $value;
732 $list[ $key ]['type'] = 'max';
733 $list[ $key ]['id'] = $key;
734 }
735 if ( $key === 'md' ) {
736 $flag = true;
737 }
738 }
739 return $list;
740 }
741 }