PluginProbe ʕ •ᴥ•ʔ
JetFormBuilder — Dynamic Blocks Form Builder / trunk
JetFormBuilder — Dynamic Blocks Form Builder vtrunk
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 weeks ago
tools.php
850 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 * Returns editable roles and ensures the core helper is loaded.
277 *
278 * @return array
279 */
280 public static function get_editable_roles_safe(): array {
281 if ( ! function_exists( 'get_editable_roles' ) ) {
282 require_once ABSPATH . 'wp-admin/includes/user.php';
283 }
284
285 if ( ! function_exists( 'get_editable_roles' ) ) {
286 return array();
287 }
288
289 return get_editable_roles();
290 }
291
292 /**
293 * Returns all registered roles without filtering by the current user's capabilities.
294 *
295 * @return array
296 */
297 public static function get_registered_roles_safe(): array {
298 $wp_roles = wp_roles();
299
300 if ( ! is_a( $wp_roles, \WP_Roles::class ) ) {
301 return array();
302 }
303
304 return $wp_roles->roles ?? array();
305 }
306
307 /**
308 * Returns auto-detected low-privilege roles that can be used as
309 * a starting point for self-service role transitions.
310 *
311 * @return string[]
312 */
313 public static function get_default_self_promotable_roles(): array {
314 $editable_roles = self::get_registered_roles_safe();
315
316 if ( empty( $editable_roles ) ) {
317 return array();
318 }
319
320 $roles = array();
321
322 foreach ( array_keys( $editable_roles ) as $role ) {
323 if ( self::is_safe_self_promotable_role( $role ) ) {
324 $roles[] = $role;
325 }
326 }
327
328 return array_values( array_unique( $roles ) );
329 }
330
331 public static function is_safe_self_promotable_role( string $role ): bool {
332 if ( 'administrator' === $role ) {
333 return false;
334 }
335
336 $wp_roles = wp_roles();
337
338 if ( ! isset( $wp_roles->roles[ $role ] ) ) {
339 return false;
340 }
341
342 $caps = array_filter( $wp_roles->roles[ $role ]['capabilities'] ?? array() );
343
344 $dangerous_caps = array(
345 'activate_plugins',
346 'create_users',
347 'delete_users',
348 'edit_users',
349 'list_users',
350 'promote_users',
351 'remove_users',
352 'manage_options',
353 'edit_theme_options',
354 'switch_themes',
355 'install_plugins',
356 'update_plugins',
357 'delete_plugins',
358 'install_themes',
359 'update_themes',
360 'delete_themes',
361 'unfiltered_html',
362 'edit_others_posts',
363 'delete_others_posts',
364 'publish_posts',
365 'manage_categories',
366 );
367
368 foreach ( $dangerous_caps as $cap ) {
369 if ( ! empty( $caps[ $cap ] ) ) {
370 return false;
371 }
372 }
373
374 return true;
375 }
376
377 /**
378 * Prepare passed array for using in JS options
379 *
380 * @param array $array
381 * @param null $value_key
382 * @param null $label_key
383 * @param bool $for_elementor
384 *
385 * Only if $for_elementor === false
386 * @param array $additional_attrs
387 *
388 * @return array [type] [description]
389 */
390 public static function prepare_list_for_js(
391 $collection = array(),
392 $value_key = null,
393 $label_key = null,
394 $for_elementor = false,
395 $additional_attrs = array()
396 ) {
397
398 $result = array();
399
400 if ( ! is_array( $collection ) || empty( $collection ) ) {
401 return $result;
402 }
403
404 foreach ( $collection as $key => $item ) {
405
406 $value = null;
407 $label = null;
408
409 if ( is_scalar( $item ) ) {
410 $value = $key;
411 $label = $item;
412 } else {
413 $value = self::get_property( $item, $value_key );
414 $label = self::get_property( $item, $label_key );
415 }
416
417 if ( $for_elementor ) {
418 $result[ $value ] = $label;
419 } else {
420 $prepared = array(
421 'value' => $value,
422 'label' => $label,
423 );
424 foreach ( $additional_attrs as $attr ) {
425 $prepared[ $attr ] = self::get_property( $item, $attr );
426 }
427
428 $result[] = $prepared;
429 }
430 }
431
432 return $result;
433 }
434
435 /**
436 * @param array $collection
437 * @param string $label
438 *
439 * @return array
440 */
441 public static function with_placeholder( array $collection, string $label = '--' ): array {
442 return array_merge(
443 array(
444 array( 'label' => $label, 'value' => '' ),
445 ),
446 $collection
447 );
448 }
449
450 /**
451 * Check if is valid timestamp
452 *
453 * @param mixed $timestamp
454 *
455 * @return boolean
456 */
457 public static function is_valid_timestamp( $timestamp ): bool {
458 return ( (string) (int) $timestamp === $timestamp || (int) $timestamp === $timestamp )
459 && ( $timestamp <= PHP_INT_MAX )
460 && ( $timestamp >= ~PHP_INT_MAX );
461 }
462
463 public static function array_merge_intersect_key( $source, $arrays ) {
464 foreach ( $source as $index => $path ) {
465 $name = $path['path'] ?? $index;
466
467 $deep_value = self::getDeepValue( $name, $arrays );
468
469 if ( self::EMPTY_DEEP_VALUE === $deep_value ) {
470 unset( $source[ $index ] );
471 } else {
472 $source[ $index ] = $deep_value;
473 }
474 }
475
476 return $source;
477 }
478
479 // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
480 public static function getDeepValue( $key, $source ) {
481 $keys = explode( '/', $key );
482 $last = end( $keys );
483 reset( $keys );
484
485 return self::deep( $keys, current( $keys ), $last, $source );
486 }
487
488 private static function deep( $collection, $key, $last, $source ) {
489
490 if ( isset( $source[ $key ] ) ) {
491 if ( $last !== $key ) {
492 return self::deep( $collection, next( $collection ), $last, $source[ $key ] );
493 }
494
495 return $source[ $key ];
496 }
497
498 return self::EMPTY_DEEP_VALUE;
499 }
500
501 public static function call( $callback, ...$params ) {
502 if ( ! is_callable( $callback ) ) {
503 return;
504 }
505
506 call_user_func( $callback, ...$params );
507 }
508
509 public static function decode_unserializable( $value ) {
510 $data = self::decode_json( $value );
511
512 // phpcs:ignore Universal.Operators.DisallowShortTernary.Found
513 return $data ?: maybe_unserialize( $value );
514 }
515
516 public static function decode_json( $json ) {
517 if ( is_array( $json ) ) {
518 foreach ( $json as $key => $row ) {
519 $json[ $key ] = static::decode_json( $row );
520 }
521
522 return $json;
523 }
524 if ( defined( 'JSON_INVALID_UTF8_IGNORE' ) ) {
525 // phpcs:ignore PHPCompatibility.Constants.NewConstants
526 return json_decode( $json, true, 512, JSON_INVALID_UTF8_IGNORE );
527 }
528
529 return json_decode( $json, true );
530 }
531
532 public static function encode_json( $json ) {
533 return wp_json_encode( $json, JSON_UNESCAPED_UNICODE );
534 }
535
536 public static function sanitize_recursive( $source = null ) {
537 if ( ! is_array( $source ) ) {
538 return self::sanitize( $source );
539 }
540
541 $result = array();
542
543 foreach ( $source as $key => $value ) {
544 $result[ $key ] = self::sanitize_recursive( $value );
545 }
546
547 return $result;
548 }
549
550 public static function maybe_recursive_sanitize( $source = null ) {
551 return self::sanitize_recursive( $source );
552 }
553
554 public static function sanitize( $source ) {
555 if ( self::is_url( $source ) ) {
556 return esc_url_raw( $source );
557 }
558
559 return self::sanitize_text_field( $source );
560 }
561
562 public static function is_url( $url ) {
563 return wp_http_validate_url( $url );
564 }
565
566 public static function sanitize_text_field( $source, $replace_enqueue = true ) {
567 $str = (string) $source;
568
569 $filtered = wp_check_invalid_utf8( $str );
570 $sanitize_callback = apply_filters( 'jet-form-builder/sanitize-string/callback', false );
571
572 if ( $sanitize_callback && is_callable( $sanitize_callback ) ) {
573 $filtered = call_user_func( $sanitize_callback, $filtered );
574 } elseif ( $replace_enqueue && false !== strpos( $filtered, '<' ) ) {
575 $filtered = wp_kses_post( $filtered );
576 }
577
578 return trim( $filtered );
579 }
580
581 /**
582 * @param $type
583 * @param mixed ...$values
584 *
585 * @return mixed
586 */
587 private static function call_escape_func( $type, ...$values ) {
588 return call_user_func( self::get_escape_func( $type ), ...$values );
589 }
590
591 public static function recursive_wp_kses( $source, $allowed_html = 'strip' ) {
592 if ( ! is_array( $source ) ) {
593 return wp_kses( $source, $allowed_html );
594 }
595
596 $result = array();
597 foreach ( $source as $key => $value ) {
598 $result[ $key ] = self::sanitize_recursive( $value );
599 }
600
601 return $result;
602 }
603
604 public static function sanitize_files( $source ) {
605 if ( ! is_array( $source ) ) {
606 return false;
607 }
608
609 $response = array();
610
611 foreach ( $source as $index => $item ) {
612 foreach ( $item as $key => $value ) {
613 switch ( $key ) {
614 case 'error':
615 case 'size':
616 $response[ $index ][ $key ] = absint( $value );
617 break;
618 case 'name':
619 $response[ $index ][ $key ] = sanitize_file_name( $value );
620 break;
621 case 'type':
622 $response[ $index ][ $key ] = sanitize_mime_type( $value );
623 break;
624 case 'tmp_name':
625 $response[ $index ][ $key ] = sanitize_text_field( $value );
626 break;
627 }
628 }
629 }
630
631 return $response;
632 }
633
634 /**
635 * @param $source
636 * @param bool $replace_enqueue
637 *
638 * @return string
639 */
640 private static function esc_template( $source, $replace_enqueue = true ): string {
641 return self::sanitize_text_field( $source, $replace_enqueue );
642 }
643
644 public static function get_jet_engine_version() {
645 return function_exists( 'jet_engine' )
646 ? jet_engine()->get_version()
647 : false;
648 }
649
650 public static function is_readable( string $filename ) {
651 // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
652 return strlen( $filename ) <= PHP_MAXPATHLEN && @is_readable( $filename );
653 }
654
655 /**
656 * Returns template path
657 *
658 * @param [type] $path [description]
659 *
660 * @return [type] [description]
661 */
662 public static function get_global_template( $path = '' ) {
663 return JET_FORM_BUILDER_PATH . 'templates/' . $path;
664 }
665
666 public static function get_property( $source, $name, $if_not_exist = '' ) {
667 if ( is_object( $source ) ) {
668 return $source->{$name} ?? $if_not_exist;
669 }
670
671 return $source[ $name ] ?? $if_not_exist;
672 }
673
674 public static function esc_template_string( $source, $replace_enqueue = true ) {
675 return self::call_escape_func( 'template', $source, $replace_enqueue );
676 }
677
678 public static function is_repeater_val( $value ): bool {
679 if ( is_array( $value ) && ! empty( $value ) ) {
680 foreach ( $value as $item ) {
681 return is_array( $item );
682 }
683 }
684
685 return false;
686 }
687
688 public static function set_current_post( $post_id ) {
689 global $post;
690
691 // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
692 $post = get_post( absint( $post_id ) );
693 }
694
695 public static function prepare_repeater_value( $value, $fields_map ): array {
696 $prepared_value = array();
697
698 foreach ( $value as $index => $row ) {
699 $prepared_row = array();
700
701 foreach ( $row as $item_key => $item_value ) {
702 $item_key = ! empty( $fields_map[ $item_key ] ) ? self::sanitize_text_field( $fields_map[ $item_key ] ) : $item_key;
703 $prepared_row[ $item_key ] = $item_value;
704 }
705
706 $prepared_value[ 'item-' . $index ] = $prepared_row;
707 }
708
709 return $prepared_value;
710 }
711
712 public static function is_webhook(): bool {
713 return (
714 defined( 'JET_FB_REST_WEBHOOK' ) &&
715 JET_FB_REST_WEBHOOK
716 );
717 }
718
719 public static function esc_attr( $value ) {
720 if ( ! is_scalar( $value ) ) {
721 return esc_attr( self::encode_json( $value ) );
722 }
723
724 return esc_attr( $value );
725 }
726
727 public static function get_suffix(): string {
728 return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
729 }
730
731 /**
732 * Get from function below
733 *
734 * @return string
735 * @see \retrieve_password
736 */
737 public static function get_site_name(): string {
738 if ( is_multisite() ) {
739 return get_network()->site_name;
740 }
741
742 /*
743 * The blogname option is escaped with esc_html on the way into the database
744 * in sanitize_option. We want to reverse this for the plain text arena of emails.
745 */
746
747 return wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
748 }
749
750 /**
751 * @param mixed $value
752 */
753 public static function to_string( $value ): string {
754 if ( is_array( $value ) ) {
755 return implode(
756 ',',
757 array_map( array( self::class, 'to_string' ), $value )
758 );
759 }
760
761 if ( is_object( $value ) && ! method_exists( $value, '__toString' ) ) {
762 return '';
763 }
764
765 return (string) $value;
766 }
767
768 public static function is_empty( $value ): bool {
769 return '0' !== $value && 0 !== $value && empty( $value );
770 }
771
772 public static function contains_registered_shortcode( $string ) {
773 global $shortcode_tags;
774
775 foreach ( array_keys( $shortcode_tags ) as $shortcode ) {
776 if ( strpos( $string, "[$shortcode" ) !== false ) {
777 return true;
778 }
779 }
780
781 return false;
782 }
783
784 /**
785 * Check if string is a WordPress password hash
786 * Supports all WordPress hash formats:
787 * - Old Portable Hash: $P$...
788 * - Bcrypt: $2a$, $2y$...
789 *
790 * @param string $hash Password hash to check
791 * @return bool
792 */
793 public static function is_wp_password_hash( $hash ) {
794 if ( ! is_string( $hash ) || empty( $hash ) ) {
795 return false;
796 }
797
798 // Old Portable Hash format: $P$[A-Za-z0-9./]{31}
799 if ( preg_match( '/^\$P\$[A-Za-z0-9\.\/]{31}$/', $hash ) ) {
800 return true;
801 }
802
803 // Bcrypt format: $2a$, $2x$, $2y$ followed by cost and hash
804 if ( preg_match( '/^\$2[axy]\$\d{2}\$[A-Za-z0-9\.\/]{53}$/', $hash ) ) {
805 return true;
806 }
807
808 return false;
809 }
810
811 public static function get_array_of_user_roles( $settings ) {
812 if ( is_string( $settings ) ) {
813 return '' === $settings ? array() : array( $settings );
814 }
815
816 if ( ! is_array( $settings ) ) {
817 return array();
818 }
819
820 return $settings;
821 }
822
823 public static function get_main_user_role_by_priority( $roles ): string {
824 if ( is_string( $roles ) ) {
825 $roles = array( $roles );
826 }
827 $wp_roles_priority = array(
828 'editor' => 4,
829 'author' => 3,
830 'contributor' => 2,
831 'subscriber' => 1,
832 );
833
834 $wp_roles = array_intersect( $roles, array_keys( $wp_roles_priority ) );
835 $custom_roles = array_diff( $roles, array_keys( $wp_roles_priority ) );
836
837 usort(
838 $wp_roles,
839 function ( $a, $b ) use ( $wp_roles_priority ) {
840 return ( $wp_roles_priority[ $b ] ?? 0 ) <=> ( $wp_roles_priority[ $a ] ?? 0 );
841 }
842 );
843
844 return $wp_roles[0] ?? $custom_roles[0] ?? '';
845 }
846
847
848
849 }
850