PluginProbe ʕ •ᴥ•ʔ
JetFormBuilder — Dynamic Blocks Form Builder / 3.6.1
JetFormBuilder — Dynamic Blocks Form Builder v3.6.1
3.6.3.1 3.6.3 3.6.2.2 3.6.2.1 3.6.2 3.6.1.1 3.6.1 3.6.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.1.0 2.1.1 2.1.10 2.1.11 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 3.0.0 3.0.0.1 3.0.0.2 3.0.0.3 3.0.1 3.0.1.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.0.1 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.3.2 3.3.3 3.3.3.1 3.3.4 3.3.4.1 3.3.4.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.5.1 3.4.5.2 3.4.6 3.4.7 3.4.7.1 3.5.0 3.5.1 3.5.1.1 3.5.1.2 3.5.2 3.5.2.1 3.5.3 3.5.4 3.5.5 3.5.6 3.5.6.1 3.5.6.2 3.5.6.3 3.6.0
jetformbuilder / includes / classes / tools.php
jetformbuilder / includes / classes Last commit date
arguments 1 year ago arrayable 2 years ago filters 1 year ago http 2 years ago macro-constants 2 years ago post 1 year ago resources 2 months ago theme 2 years ago value-normalizers 1 month ago attributes-trait.php 2 years ago base-attributes-trait.php 2 years ago builder-helper.php 1 year ago compatibility.php 2 years ago date-tools.php 2 years ago gallery.php 2 years ago get-icon-trait.php 2 years ago get-template-trait.php 2 years ago html-attributes-trait.php 2 years ago instance-trait.php 2 years ago regexp-tools.php 2 years ago tools.php 2 months ago
tools.php
746 lines
1 <?php
2
3 namespace Jet_Form_Builder\Classes;
4
5 use Jet_Form_Builder\Plugin;
6 use Jet_Form_Builder\Generators\Registry as GeneratorRegistry;
7
8 // If this file is called directly, abort.
9 if ( ! defined( 'WPINC' ) ) {
10 die;
11 }
12
13 class Tools {
14
15 const EMPTY_DEEP_VALUE = self::class;
16
17 public static function is_editor() {
18 return self::is_block_editor() || self::is_elementor_editor() || self::is_bricks_editor();
19 }
20
21 public static function is_block_editor() {
22 $allowed_actions = array( 'add', 'edit' );
23
24 return (
25 in_array( self::sanitize_get_param( 'context' ), $allowed_actions, true )
26 || in_array( self::sanitize_get_param( 'action' ), $allowed_actions, true )
27 );
28 }
29
30 public static function sanitize_get_param( $param_name ) {
31 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
32 return ! empty( $_GET[ $param_name ] ) ? sanitize_key( $_GET[ $param_name ] ) : '';
33 }
34
35 public static function is_elementor_editor() {
36 if ( ! defined( 'ELEMENTOR_VERSION' ) ) {
37 return false;
38 }
39
40 return ( \Elementor\Plugin::instance()->editor->is_edit_mode() );
41 }
42
43 public static function is_bricks_editor() {
44 if ( ! defined( 'BRICKS_VERSION' ) ) {
45 return false;
46 }
47
48 return ( bricks_is_builder() );
49 }
50
51 /**
52 * Returns all post types list to use in JS components
53 *
54 * @param bool $placeholder
55 *
56 * @param array $args
57 * @param string $operator
58 *
59 * @return array [type] [description]
60 */
61 public static function get_post_types_for_js( $placeholder = false, $args = array(), $operator = 'and' ) {
62
63 $post_types = get_post_types( $args, 'objects', $operator );
64
65 $post_types_list = array();
66
67 if ( $placeholder && is_array( $placeholder ) ) {
68 $placeholder['value'] = isset( $placeholder['value'] ) ? $placeholder['value'] : '';
69 $post_types_list[] = $placeholder;
70 }
71
72 foreach ( $post_types as $post_type ) {
73 if ( Plugin::instance()->post_type->slug() !== $post_type->name ) {
74 $post_types_list[] = array(
75 'value' => $post_type->name,
76 'label' => $post_type->label,
77 );
78 }
79 }
80
81 return self::with_placeholder( $post_types_list );
82 }
83
84 /**
85 * Get post types list for options.
86 *
87 * @return array
88 */
89 public static function get_post_types_for_options(): array {
90 return self::get_post_types_for_js( false, array( 'public' => true ) );
91 }
92
93 private static function get_escape_func( $type ) {
94 switch ( $type ) {
95 case 'template':
96 default:
97 return array( self::class, 'esc_template' );
98 }
99 }
100
101 /**
102 * Sanitize WYSIWYG field
103 *
104 * @param $input
105 *
106 * @return string
107 */
108 public static function sanitize_wysiwyg( $input ): string {
109 $input = wp_kses_post( $input );
110
111 return wp_specialchars_decode( stripslashes( $input ), ENT_COMPAT );
112 }
113
114 /**
115 * Return all taxonomies list to use in JS components
116 *
117 * @param array $args
118 *
119 * @return array
120 */
121 public static function get_taxonomies_for_js( $args = array() ): array {
122 $taxonomies = get_taxonomies( $args, 'objects' );
123
124 return self::with_placeholder( self::prepare_list_for_js( $taxonomies, 'name', 'label' ) );
125 }
126
127 public static function get_taxonomies_for_modify( array $args = array() ): array {
128 $taxonomies = get_taxonomies( $args, 'objects' );
129 $response = array();
130
131 /** @var \WP_Taxonomy $taxonomy */
132 foreach ( $taxonomies as $taxonomy ) {
133 $response[] = array(
134 'label' => $taxonomy->label,
135 'value' => "jet_tax__{$taxonomy->name}",
136 );
137 }
138
139 return self::with_placeholder( $response );
140 }
141
142 public static function get_generators_list_for_js(): array {
143 $generators = Plugin::instance()->form->get_generators_list();
144
145 return self::prepare_list_for_js( $generators );
146 }
147
148 /**
149 * Get generator schemas for JS localization.
150 *
151 * @return array
152 */
153 public static function get_generator_schemas_for_js(): array {
154 if ( ! class_exists( GeneratorRegistry::class ) ) {
155 return array();
156 }
157
158 try {
159 $registry = GeneratorRegistry::instance();
160 return $registry->get_schemas_for_js();
161 } catch ( \Exception $e ) {
162 return array();
163 }
164 }
165
166 public static function get_allowed_mimes_list_for_js(): array {
167 return array_values( get_allowed_mime_types() );
168 }
169
170 /**
171 * Returns all registeredroles for JS
172 */
173 public static function get_user_roles_for_js( $exclude = array( 'administrator' ) ) {
174
175 $roles = self::get_user_roles( $exclude );
176 $result = array();
177
178 foreach ( $roles as $role => $label ) {
179 $result[] = array(
180 'value' => $role,
181 'label' => $label,
182 );
183 }
184
185 return self::with_placeholder( $result );
186 }
187
188 public static function get_options_pages_for_js() {
189 $pages = array();
190
191 if ( function_exists( 'jet_engine' ) ) {
192 $pages = jet_engine()->options_pages->get_options_pages_for_select();
193 }
194
195 return self::prepare_list_for_js( $pages );
196 }
197
198 /**
199 * Returns pages list
200 *
201 * @return [type] [description]
202 */
203 public static function get_pages_list_for_js() {
204 $pages = get_pages();
205
206 return self::prepare_list_for_js( $pages, 'ID', 'post_title' );
207 }
208
209 /**
210 * Returns pages list
211 *
212 * @param bool $for_elementor
213 *
214 * @param array $args
215 *
216 * @return array [description]
217 */
218 public static function get_forms_list_for_js( $for_elementor = false, $args = array() ) {
219 $posts = get_posts(
220 array_merge(
221 array(
222 'post_status' => 'publish',
223 'posts_per_page' => - 1,
224 'post_type' => jet_form_builder()->post_type->slug(),
225 ),
226 $args
227 )
228 );
229
230 $prepared_list_for_js = self::prepare_list_for_js( $posts, 'ID', 'post_title', $for_elementor );
231
232 if ( true === $for_elementor ) {
233 $manual_form_option = array(
234 'manual_form_id' => __( 'Enter Form ID Manually / Dynamically', 'jet-form-builder' ),
235 );
236
237 $prepared_list_for_js = array_replace( $manual_form_option, $prepared_list_for_js );
238 } else {
239 $manual_form_option[] = array(
240 'value' => -1,
241 'label' => __( 'Enter Form ID Manually / Dynamically', 'jet-form-builder' ),
242 );
243
244 $prepared_list_for_js = array_merge( $manual_form_option, $prepared_list_for_js );
245 }
246
247 return $prepared_list_for_js;
248 }
249
250 /**
251 * Returns all registered user roles
252 *
253 * @param string[] $exclude
254 *
255 * @return array [type] [description]
256 */
257 public static function get_user_roles( $exclude = array( 'administrator' ) ) {
258
259 if ( ! function_exists( 'get_editable_roles' ) ) {
260 return array();
261 } else {
262 $roles = get_editable_roles();
263 $result = array();
264
265 foreach ( $roles as $role => $data ) {
266 if ( ! in_array( $role, $exclude, true ) ) {
267 $result[ $role ] = $data['name'];
268 }
269 }
270
271 return $result;
272 }
273 }
274
275 /**
276 * Prepare passed array for using in JS options
277 *
278 * @param array $array
279 * @param null $value_key
280 * @param null $label_key
281 * @param bool $for_elementor
282 *
283 * Only if $for_elementor === false
284 * @param array $additional_attrs
285 *
286 * @return array [type] [description]
287 */
288 public static function prepare_list_for_js(
289 $collection = array(),
290 $value_key = null,
291 $label_key = null,
292 $for_elementor = false,
293 $additional_attrs = array()
294 ) {
295
296 $result = array();
297
298 if ( ! is_array( $collection ) || empty( $collection ) ) {
299 return $result;
300 }
301
302 foreach ( $collection as $key => $item ) {
303
304 $value = null;
305 $label = null;
306
307 if ( is_scalar( $item ) ) {
308 $value = $key;
309 $label = $item;
310 } else {
311 $value = self::get_property( $item, $value_key );
312 $label = self::get_property( $item, $label_key );
313 }
314
315 if ( $for_elementor ) {
316 $result[ $value ] = $label;
317 } else {
318 $prepared = array(
319 'value' => $value,
320 'label' => $label,
321 );
322 foreach ( $additional_attrs as $attr ) {
323 $prepared[ $attr ] = self::get_property( $item, $attr );
324 }
325
326 $result[] = $prepared;
327 }
328 }
329
330 return $result;
331 }
332
333 /**
334 * @param array $collection
335 * @param string $label
336 *
337 * @return array
338 */
339 public static function with_placeholder( array $collection, string $label = '--' ): array {
340 return array_merge(
341 array(
342 array( 'label' => $label, 'value' => '' ),
343 ),
344 $collection
345 );
346 }
347
348 /**
349 * Check if is valid timestamp
350 *
351 * @param mixed $timestamp
352 *
353 * @return boolean
354 */
355 public static function is_valid_timestamp( $timestamp ): bool {
356 return ( (string) (int) $timestamp === $timestamp || (int) $timestamp === $timestamp )
357 && ( $timestamp <= PHP_INT_MAX )
358 && ( $timestamp >= ~PHP_INT_MAX );
359 }
360
361 public static function array_merge_intersect_key( $source, $arrays ) {
362 foreach ( $source as $index => $path ) {
363 $name = $path['path'] ?? $index;
364
365 $deep_value = self::getDeepValue( $name, $arrays );
366
367 if ( self::EMPTY_DEEP_VALUE === $deep_value ) {
368 unset( $source[ $index ] );
369 } else {
370 $source[ $index ] = $deep_value;
371 }
372 }
373
374 return $source;
375 }
376
377 // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
378 public static function getDeepValue( $key, $source ) {
379 $keys = explode( '/', $key );
380 $last = end( $keys );
381 reset( $keys );
382
383 return self::deep( $keys, current( $keys ), $last, $source );
384 }
385
386 private static function deep( $collection, $key, $last, $source ) {
387
388 if ( isset( $source[ $key ] ) ) {
389 if ( $last !== $key ) {
390 return self::deep( $collection, next( $collection ), $last, $source[ $key ] );
391 }
392
393 return $source[ $key ];
394 }
395
396 return self::EMPTY_DEEP_VALUE;
397 }
398
399 public static function call( $callback, ...$params ) {
400 if ( ! is_callable( $callback ) ) {
401 return;
402 }
403
404 call_user_func( $callback, ...$params );
405 }
406
407 public static function decode_unserializable( $value ) {
408 $data = self::decode_json( $value );
409
410 // phpcs:ignore Universal.Operators.DisallowShortTernary.Found
411 return $data ?: maybe_unserialize( $value );
412 }
413
414 public static function decode_json( $json ) {
415 if ( is_array( $json ) ) {
416 foreach ( $json as $key => $row ) {
417 $json[ $key ] = static::decode_json( $row );
418 }
419
420 return $json;
421 }
422 if ( defined( 'JSON_INVALID_UTF8_IGNORE' ) ) {
423 // phpcs:ignore PHPCompatibility.Constants.NewConstants
424 return json_decode( $json, true, 512, JSON_INVALID_UTF8_IGNORE );
425 }
426
427 return json_decode( $json, true );
428 }
429
430 public static function encode_json( $json ) {
431 return wp_json_encode( $json, JSON_UNESCAPED_UNICODE );
432 }
433
434 public static function sanitize_recursive( $source = null ) {
435 if ( ! is_array( $source ) ) {
436 return self::sanitize( $source );
437 }
438
439 $result = array();
440
441 foreach ( $source as $key => $value ) {
442 $result[ $key ] = self::sanitize_recursive( $value );
443 }
444
445 return $result;
446 }
447
448 public static function maybe_recursive_sanitize( $source = null ) {
449 return self::sanitize_recursive( $source );
450 }
451
452 public static function sanitize( $source ) {
453 if ( self::is_url( $source ) ) {
454 return esc_url_raw( $source );
455 }
456
457 return self::sanitize_text_field( $source );
458 }
459
460 public static function is_url( $url ) {
461 return wp_http_validate_url( $url );
462 }
463
464 public static function sanitize_text_field( $source, $replace_enqueue = true ) {
465 $str = (string) $source;
466
467 $filtered = wp_check_invalid_utf8( $str );
468 $sanitize_callback = apply_filters( 'jet-form-builder/sanitize-string/callback', false );
469
470 if ( $sanitize_callback && is_callable( $sanitize_callback ) ) {
471 $filtered = call_user_func( $sanitize_callback, $filtered );
472 } elseif ( $replace_enqueue && false !== strpos( $filtered, '<' ) ) {
473 $filtered = wp_kses_post( $filtered );
474 }
475
476 return trim( $filtered );
477 }
478
479 /**
480 * @param $type
481 * @param mixed ...$values
482 *
483 * @return mixed
484 */
485 private static function call_escape_func( $type, ...$values ) {
486 return call_user_func( self::get_escape_func( $type ), ...$values );
487 }
488
489 public static function recursive_wp_kses( $source, $allowed_html = 'strip' ) {
490 if ( ! is_array( $source ) ) {
491 return wp_kses( $source, $allowed_html );
492 }
493
494 $result = array();
495 foreach ( $source as $key => $value ) {
496 $result[ $key ] = self::sanitize_recursive( $value );
497 }
498
499 return $result;
500 }
501
502 public static function sanitize_files( $source ) {
503 if ( ! is_array( $source ) ) {
504 return false;
505 }
506
507 $response = array();
508
509 foreach ( $source as $index => $item ) {
510 foreach ( $item as $key => $value ) {
511 switch ( $key ) {
512 case 'error':
513 case 'size':
514 $response[ $index ][ $key ] = absint( $value );
515 break;
516 case 'name':
517 $response[ $index ][ $key ] = sanitize_file_name( $value );
518 break;
519 case 'type':
520 $response[ $index ][ $key ] = sanitize_mime_type( $value );
521 break;
522 case 'tmp_name':
523 $response[ $index ][ $key ] = sanitize_text_field( $value );
524 break;
525 }
526 }
527 }
528
529 return $response;
530 }
531
532 /**
533 * @param $source
534 * @param bool $replace_enqueue
535 *
536 * @return string
537 */
538 private static function esc_template( $source, $replace_enqueue = true ): string {
539 return self::sanitize_text_field( $source, $replace_enqueue );
540 }
541
542 public static function get_jet_engine_version() {
543 return function_exists( 'jet_engine' )
544 ? jet_engine()->get_version()
545 : false;
546 }
547
548 public static function is_readable( string $filename ) {
549 // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
550 return strlen( $filename ) <= PHP_MAXPATHLEN && @is_readable( $filename );
551 }
552
553 /**
554 * Returns template path
555 *
556 * @param [type] $path [description]
557 *
558 * @return [type] [description]
559 */
560 public static function get_global_template( $path = '' ) {
561 return JET_FORM_BUILDER_PATH . 'templates/' . $path;
562 }
563
564 public static function get_property( $source, $name, $if_not_exist = '' ) {
565 if ( is_object( $source ) ) {
566 return $source->{$name} ?? $if_not_exist;
567 }
568
569 return $source[ $name ] ?? $if_not_exist;
570 }
571
572 public static function esc_template_string( $source, $replace_enqueue = true ) {
573 return self::call_escape_func( 'template', $source, $replace_enqueue );
574 }
575
576 public static function is_repeater_val( $value ): bool {
577 if ( is_array( $value ) && ! empty( $value ) ) {
578 foreach ( $value as $item ) {
579 return is_array( $item );
580 }
581 }
582
583 return false;
584 }
585
586 public static function set_current_post( $post_id ) {
587 global $post;
588
589 // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
590 $post = get_post( absint( $post_id ) );
591 }
592
593 public static function prepare_repeater_value( $value, $fields_map ): array {
594 $prepared_value = array();
595
596 foreach ( $value as $index => $row ) {
597 $prepared_row = array();
598
599 foreach ( $row as $item_key => $item_value ) {
600 $item_key = ! empty( $fields_map[ $item_key ] ) ? self::sanitize_text_field( $fields_map[ $item_key ] ) : $item_key;
601 $prepared_row[ $item_key ] = $item_value;
602 }
603
604 $prepared_value[ 'item-' . $index ] = $prepared_row;
605 }
606
607 return $prepared_value;
608 }
609
610 public static function is_webhook(): bool {
611 return (
612 defined( 'JET_FB_REST_WEBHOOK' ) &&
613 JET_FB_REST_WEBHOOK
614 );
615 }
616
617 public static function esc_attr( $value ) {
618 if ( ! is_scalar( $value ) ) {
619 return esc_attr( self::encode_json( $value ) );
620 }
621
622 return esc_attr( $value );
623 }
624
625 public static function get_suffix(): string {
626 return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
627 }
628
629 /**
630 * Get from function below
631 *
632 * @return string
633 * @see \retrieve_password
634 */
635 public static function get_site_name(): string {
636 if ( is_multisite() ) {
637 return get_network()->site_name;
638 }
639
640 /*
641 * The blogname option is escaped with esc_html on the way into the database
642 * in sanitize_option. We want to reverse this for the plain text arena of emails.
643 */
644
645 return wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
646 }
647
648 /**
649 * @param mixed $value
650 */
651 public static function to_string( $value ): string {
652 if ( is_array( $value ) ) {
653 return implode(
654 ',',
655 array_map( array( self::class, 'to_string' ), $value )
656 );
657 }
658
659 if ( is_object( $value ) && ! method_exists( $value, '__toString' ) ) {
660 return '';
661 }
662
663 return (string) $value;
664 }
665
666 public static function is_empty( $value ): bool {
667 return '0' !== $value && 0 !== $value && empty( $value );
668 }
669
670 public static function contains_registered_shortcode( $string ) {
671 global $shortcode_tags;
672
673 foreach ( array_keys( $shortcode_tags ) as $shortcode ) {
674 if ( strpos( $string, "[$shortcode" ) !== false ) {
675 return true;
676 }
677 }
678
679 return false;
680 }
681
682 /**
683 * Check if string is a WordPress password hash
684 * Supports all WordPress hash formats:
685 * - Old Portable Hash: $P$...
686 * - Bcrypt: $2a$, $2y$...
687 *
688 * @param string $hash Password hash to check
689 * @return bool
690 */
691 public static function is_wp_password_hash( $hash ) {
692 if ( ! is_string( $hash ) || empty( $hash ) ) {
693 return false;
694 }
695
696 // Old Portable Hash format: $P$[A-Za-z0-9./]{31}
697 if ( preg_match( '/^\$P\$[A-Za-z0-9\.\/]{31}$/', $hash ) ) {
698 return true;
699 }
700
701 // Bcrypt format: $2a$, $2x$, $2y$ followed by cost and hash
702 if ( preg_match( '/^\$2[axy]\$\d{2}\$[A-Za-z0-9\.\/]{53}$/', $hash ) ) {
703 return true;
704 }
705
706 return false;
707 }
708
709 public static function get_array_of_user_roles( $settings ) {
710 $user_roles = $settings ?? array();
711 if ( ! empty( $user_roles ) ) {
712 if ( is_string( $user_roles ) ) {
713 $user_roles = array( $user_roles );
714 }
715 }
716 return $user_roles;
717 }
718
719 public static function get_main_user_role_by_priority( $roles ): string {
720 if ( is_string( $roles ) ) {
721 $roles = array( $roles );
722 }
723 $wp_roles_priority = array(
724 'editor' => 4,
725 'author' => 3,
726 'contributor' => 2,
727 'subscriber' => 1,
728 );
729
730 $wp_roles = array_intersect( $roles, array_keys( $wp_roles_priority ) );
731 $custom_roles = array_diff( $roles, array_keys( $wp_roles_priority ) );
732
733 usort(
734 $wp_roles,
735 function ( $a, $b ) use ( $wp_roles_priority ) {
736 return ( $wp_roles_priority[ $b ] ?? 0 ) <=> ( $wp_roles_priority[ $a ] ?? 0 );
737 }
738 );
739
740 return $wp_roles[0] ?? $custom_roles[0] ?? '';
741 }
742
743
744
745 }
746