PluginProbe
Elementor Website Builder – more than just a page builder / 3.3.0
Elementor Website Builder – more than just a page builder v3.3.0
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
← All changes | includes/utils.php +59 -443 4.3.0-beta23.3.0 View file →
@@ -1,10 +1,7 @@
1 1 <?php
2 2 namespace Elementor;
3 3
4 -use Elementor\Core\Files\Fonts\Google_Font;
5 -use Elementor\Core\Utils\Collection;
6 -
7 4 if ( ! defined( 'ABSPATH' ) ) {
8 5 exit; // Exit if accessed directly.
9 6 }
10 7
@@ -19,19 +16,15 @@
19 16 class Utils {
20 17
21 18 const DEPRECATION_RANGE = 0.4;
22 19
23 - const EDITOR_BREAK_LINES_OPTION_KEY = 'elementor_editor_break_lines';
24 -
25 20 /**
26 - * A list of safe tags for `validate_html_tag` method.
21 + * A list of safe tage for `validate_html_tag` method.
27 22 */
28 23 const ALLOWED_HTML_WRAPPER_TAGS = [
29 24 'a',
30 25 'article',
31 26 'aside',
32 - 'button',
33 - 'form',
34 27 'div',
35 28 'footer',
36 29 'h1',
37 30 'h2',
@@ -47,93 +40,28 @@
47 40 'span',
48 41 ];
49 42
50 43 /**
51 - * Tags that must never be usable as an HTML wrapper tag, regardless of what
52 - * `elementor/allowed_html_wrapper_tags` filters return. These are the classic
53 - * script-execution / markup-injection vectors (XSS), so they're enforced as a
54 - * hard denylist rather than left to filter authors to avoid re-adding them.
44 + * Is ajax.
45 + *
46 + * Whether the current request is a WordPress ajax request.
47 + *
48 + * @since 1.0.0
49 + * @deprecated 2.6.0 Use `wp_doing_ajax()` instead.
50 + * @access public
51 + * @static
52 + *
53 + * @return bool True if it's a WordPress ajax request, false otherwise.
55 54 */
56 - const FORBIDDEN_HTML_WRAPPER_TAGS = [
57 - 'script',
58 - 'iframe',
59 - 'object',
60 - 'embed',
61 - 'style',
62 - 'link',
63 - 'meta',
64 - 'base',
65 - 'noscript',
66 - 'template',
67 - 'svg',
68 - 'math',
69 - ];
55 + public static function is_ajax() {
56 + _deprecated_function( __METHOD__, '2.6.0', 'wp_doing_ajax()' );
70 57
71 - const EXTENDED_ALLOWED_HTML_TAGS = [
72 - 'iframe' => [
73 - 'iframe' => [
74 - 'allow' => true,
75 - 'allowfullscreen' => true,
76 - 'frameborder' => true,
77 - 'height' => true,
78 - 'loading' => true,
79 - 'name' => true,
80 - 'referrerpolicy' => true,
81 - 'sandbox' => true,
82 - 'src' => true,
83 - 'width' => true,
84 - ],
85 - ],
86 - 'svg' => [
87 - 'svg' => [
88 - 'aria-hidden' => true,
89 - 'aria-labelledby' => true,
90 - 'class' => true,
91 - 'height' => true,
92 - 'role' => true,
93 - 'viewbox' => true,
94 - 'width' => true,
95 - 'xmlns' => true,
96 - ],
97 - 'g' => [
98 - 'fill' => true,
99 - ],
100 - 'title' => [
101 - 'title' => true,
102 - ],
103 - 'path' => [
104 - 'd' => true,
105 - 'fill' => true,
106 - ],
107 - ],
108 - 'image' => [
109 - 'img' => [
110 - 'srcset' => true,
111 - 'sizes' => true,
112 - ],
113 - ],
114 - ];
58 + return wp_doing_ajax();
59 + }
115 60
116 61 /**
117 - * Variables for free to pro upsale modal promotions
118 - */
119 -
120 - const ANIMATED_HEADLINE = 'animated_headline';
121 -
122 - const CTA = 'cta';
123 -
124 - const VIDEO_PLAYLIST = 'video_playlist';
125 -
126 - const TESTIMONIAL_WIDGET = 'testimonial_widget';
127 -
128 - const IMAGE_CAROUSEL = 'image_carousel';
129 -
130 - /**
131 - * Whether WordPress CLI mode is enabled or not.
62 + * Is WP CLI.
132 63 *
133 - * @access public
134 - * @static
135 - *
136 64 * @return bool
137 65 */
138 66 public static function is_wp_cli() {
139 67 return defined( 'WP_CLI' ) && WP_CLI;
@@ -139,8 +67,10 @@
139 67 return defined( 'WP_CLI' ) && WP_CLI;
140 68 }
141 69
142 70 /**
71 + * Is script debug.
72 + *
143 73 * Whether script debug is enabled or not.
144 74 *
145 75 * @since 1.0.0
146 76 * @access public
@@ -145,9 +75,9 @@
145 75 * @since 1.0.0
146 76 * @access public
147 77 * @static
148 78 *
149 - * @return bool
79 + * @return bool True if it's a script debug is active, false otherwise.
150 80 */
151 81 public static function is_script_debug() {
152 82 return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG;
153 83 }
@@ -152,32 +82,8 @@
152 82 return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG;
153 83 }
154 84
155 85 /**
156 - * Whether Elementor debug is enabled or not.
157 - *
158 - * @access public
159 - * @static
160 - *
161 - * @return bool
162 - */
163 - public static function is_elementor_debug() {
164 - return defined( 'ELEMENTOR_DEBUG' ) && ELEMENTOR_DEBUG;
165 - }
166 -
167 - /**
168 - * Whether Elementor test mode is enabled or not.
169 - *
170 - * @access public
171 - * @static
172 - *
173 - * @return bool
174 - */
175 - public static function is_elementor_tests() {
176 - return defined( 'ELEMENTOR_TESTS' ) && ELEMENTOR_TESTS;
177 - }
178 -
179 - /**
180 86 * Get pro link.
181 87 *
182 88 * Retrieve the link to Elementor Pro.
183 89 *
@@ -216,54 +122,38 @@
216 122 * @since 2.1.0
217 123 * @static
218 124 * @access public
219 125 *
220 - * @param string $from
221 - * @param string $to
126 + * @param $from
127 + * @param $to
222 128 *
223 129 * @return string
224 - * @throws \Exception If URLs are missing or invalid URLs provided.
130 + * @throws \Exception
225 131 */
226 132 public static function replace_urls( $from, $to ) {
227 133 $from = trim( $from );
228 134 $to = trim( $to );
229 135
230 - if ( empty( $from ) ) {
231 - throw new \Exception( 'Couldn’t replace your address because the old URL was not provided. Try again by entering the old URL.' );
232 - }
233 -
234 - if ( empty( $to ) ) {
235 - throw new \Exception( 'Couldn’t replace your address because the new URL was not provided. Try again by entering the new URL.' );
236 - }
237 -
238 136 if ( $from === $to ) {
239 - throw new \Exception( 'Couldn’t replace your address because both of the URLs provided are identical. Try again by entering different URLs.' );
137 + throw new \Exception( __( 'The `from` and `to` URL\'s must be different', 'elementor' ) );
240 138 }
241 139
242 140 $is_valid_urls = ( filter_var( $from, FILTER_VALIDATE_URL ) && filter_var( $to, FILTER_VALIDATE_URL ) );
243 -
244 141 if ( ! $is_valid_urls ) {
245 - throw new \Exception( 'Couldn’t replace your address because at least one of the URLs provided are invalid. Try again by entering valid URLs.' );
142 + throw new \Exception( __( 'The `from` and `to` URL\'s must be valid URL\'s', 'elementor' ) );
246 143 }
247 144
248 145 global $wpdb;
249 - $escaped_from = str_replace( '/', '\\/', $from );
250 - $escaped_to = str_replace( '/', '\\/', $to );
251 - $meta_value_like = '[%'; // meta_value LIKE '[%' are json formatted
252 146
147 + // @codingStandardsIgnoreStart cannot use `$wpdb->prepare` because it remove's the backslashes
253 148 $rows_affected = $wpdb->query(
254 - $wpdb->prepare(
255 - "UPDATE {$wpdb->postmeta} " .
256 - 'SET `meta_value` = REPLACE(`meta_value`, %s, %s) ' .
257 - "WHERE `meta_key` = '_elementor_data' AND `meta_value` LIKE %s;",
258 - $escaped_from,
259 - $escaped_to,
260 - $meta_value_like
261 - )
262 - );
149 + "UPDATE {$wpdb->postmeta} " .
150 + "SET `meta_value` = REPLACE(`meta_value`, '" . str_replace( '/', '\\\/', $from ) . "', '" . str_replace( '/', '\\\/', $to ) . "') " .
151 + "WHERE `meta_key` = '_elementor_data' AND `meta_value` LIKE '[%' ;" ); // meta_value LIKE '[%' are json formatted
152 + // @codingStandardsIgnoreEnd
263 153
264 154 if ( false === $rows_affected ) {
265 - throw new \Exception( 'An error occurred while replacing URL\'s.' );
155 + throw new \Exception( __( 'An error occurred', 'elementor' ) );
266 156 }
267 157
268 158 // Allow externals to replace-urls, when they have to.
269 159 $rows_affected += (int) apply_filters( 'elementor/tools/replace-urls', 0, $from, $to );
@@ -268,13 +158,12 @@
268 158 // Allow externals to replace-urls, when they have to.
269 159 $rows_affected += (int) apply_filters( 'elementor/tools/replace-urls', 0, $from, $to );
270 160
271 161 Plugin::$instance->files_manager->clear_cache();
272 - Google_Font::clear_cache();
273 162
274 163 return sprintf(
275 - /* translators: %d: Number of rows. */
276 - _n( '%d database row affected.', '%d database rows affected.', $rows_affected, 'elementor' ),
164 + /* translators: %d: Number of rows */
165 + _n( '%d row affected.', '%d rows affected.', $rows_affected, 'elementor' ),
277 166 $rows_affected
278 167 );
279 168 }
280 169
@@ -301,9 +190,9 @@
301 190 *
302 191 * Filters whether the post type supports editing with Elementor.
303 192 *
304 193 * @since 1.0.0
305 - * @deprecated 2.2.0 Use `elementor/utils/is_post_support` hook Instead.
194 + * @deprecated 2.2.0 Use `elementor/utils/is_post_support` Instead
306 195 *
307 196 * @param bool $is_supported Whether the post type supports editing with Elementor.
308 197 * @param int $post_id Post ID.
309 198 * @param string $post_type Post type.
@@ -420,10 +309,10 @@
420 309 if ( ! defined( 'DONOTCDN' ) ) {
421 310 define( 'DONOTCDN', true );
422 311 }
423 312
424 - if ( ! defined( 'DONOTCACHEOBJECT' ) ) {
425 - define( 'DONOTCACHEOBJECT', true );
313 + if ( ! defined( 'DONOTCACHCEOBJECT' ) ) {
314 + define( 'DONOTCACHCEOBJECT', true );
426 315 }
427 316
428 317 // Set the headers to prevent caching for the different browsers.
429 318 nocache_headers();
@@ -462,12 +351,11 @@
462 351 * Retrieve a custom URL for creating a new post/page using Elementor.
463 352 *
464 353 * @since 1.9.0
465 354 * @access public
466 - * @deprecated 3.3.0 Use `Plugin::$instance->documents->get_create_new_post_url()` instead.
467 355 * @static
468 356 *
469 - * @param string $post_type Optional. Post type slug. Default is 'page'.
357 + * @param string $post_type Optional. Post type slug. Default is 'page'.
470 358 * @param string|null $template_type Optional. Query arg 'template_type'. Default is null.
471 359 *
472 360 * @return string A URL for creating new post using Elementor.
473 361 */
@@ -534,14 +422,14 @@
534 422 * @since 2.1.2
535 423 * @access public
536 424 * @static
537 425 */
538 - public static function array_inject( $base_array, $key, $insert ) {
539 - $length = array_search( $key, array_keys( $base_array ), true ) + 1;
426 + public static function array_inject( $array, $key, $insert ) {
427 + $length = array_search( $key, array_keys( $array ), true ) + 1;
540 428
541 - return array_slice( $base_array, 0, $length, true ) +
429 + return array_slice( $array, 0, $length, true ) +
542 430 $insert +
543 - array_slice( $base_array, $length, null, true );
431 + array_slice( $array, $length, null, true );
544 432 }
545 433
546 434 /**
547 435 * Render html attributes
@@ -579,25 +467,18 @@
579 467 }
580 468
581 469 public static function get_meta_viewport( $context = '' ) {
582 470 $meta_tag = '<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />';
583 -
584 471 /**
585 472 * Viewport meta tag.
586 473 *
587 - * Filters the meta tag containing the viewport information.
474 + * Filters the Elementor preview URL.
588 475 *
589 - * This hook can be used to change the initial viewport meta tag set by Elementor
590 - * and replace it with a different viewport tag.
591 - *
592 476 * @since 2.5.0
593 477 *
594 478 * @param string $meta_tag Viewport meta tag.
595 - * @param string $context Page context.
596 479 */
597 - $meta_tag = apply_filters( 'elementor/template/viewport_tag', $meta_tag, $context );
598 -
599 - return $meta_tag;
480 + return apply_filters( 'elementor/template/viewport_tag', $meta_tag, $context );
600 481 }
601 482
602 483 /**
603 484 * Add Elementor Config js vars to the relevant script handle,
@@ -602,17 +483,16 @@
602 483 /**
603 484 * Add Elementor Config js vars to the relevant script handle,
604 485 * WP will wrap it with <script> tag.
605 486 * To make sure this script runs thru the `script_loader_tag` hook, use a known handle value.
606 - *
607 487 * @param string $handle
608 488 * @param string $js_var
609 - * @param mixed $config
489 + * @param mixed $config
610 490 */
611 491 public static function print_js_config( $handle, $js_var, $config ) {
612 492 $config = wp_json_encode( $config );
613 493
614 - if ( get_option( self::EDITOR_BREAK_LINES_OPTION_KEY ) ) {
494 + if ( get_option( 'elementor_editor_break_lines' ) ) {
615 495 // Add new lines to avoid memory limits in some hosting servers that handles the buffer output according to new line characters
616 496 $config = str_replace( '}},"', '}},' . PHP_EOL . '"', $config );
617 497 }
618 498
@@ -630,9 +510,9 @@
630 510
631 511 $alias_version_as_float = (float) $alias_version[0];
632 512
633 513 if ( round( $current_version_as_float - $alias_version_as_float, 1 ) >= self::DEPRECATION_RANGE ) {
634 - _deprecated_file( $item, $version, $replacement ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
514 + _deprecated_file( $item, $version, $replacement );
635 515 }
636 516 }
637 517
638 518 /**
@@ -637,9 +517,9 @@
637 517
638 518 /**
639 519 * Checks a control value for being empty, including a string of '0' not covered by PHP's empty().
640 520 *
641 - * @param mixed $source
521 + * @param mixed $source
642 522 * @param bool|string $key
643 523 *
644 524 * @return bool
645 525 */
@@ -658,34 +538,15 @@
658 538 public static function has_pro() {
659 539 return defined( 'ELEMENTOR_PRO_VERSION' );
660 540 }
661 541
662 - public static function is_license_active(): bool {
663 - return class_exists( '\ElementorPro\License\API' ) && \ElementorPro\License\API::is_license_active();
664 - }
665 -
666 - public static function is_pro_installed_and_not_active(): bool {
667 - if ( ! function_exists( 'get_plugins' ) ) {
668 - require_once ABSPATH . 'wp-admin/includes/plugin.php';
669 - }
670 -
671 - $file_path = self::get_elementor_pro_file_path();
672 - $installed_plugins = get_plugins();
673 -
674 - return isset( $installed_plugins[ $file_path ] );
675 - }
676 -
677 - private static function get_elementor_pro_file_path(): string {
678 - return 'elementor-pro/elementor-pro.php';
679 - }
680 -
681 542 /**
682 543 * Convert HTMLEntities to UTF-8 characters
683 544 *
684 - * @param string $html_string
545 + * @param $string
685 546 * @return string
686 547 */
687 - public static function urlencode_html_entities( $html_string ) {
548 + public static function urlencode_html_entities( $string ) {
688 549 $entities_dictionary = [
689 550 '&#145;' => "'", // Opening single quote
690 551 '&#146;' => "'", // Closing single quote
691 552 '&#147;' => '"', // Closing double quote
@@ -698,11 +559,11 @@
698 559 '&#8222;' => '"', // Double low quote
699 560 ];
700 561
701 562 // Decode decimal entities
702 - $html_string = str_replace( array_keys( $entities_dictionary ), array_values( $entities_dictionary ), $html_string );
563 + $string = str_replace( array_keys( $entities_dictionary ), array_values( $entities_dictionary ), $string );
703 564
704 - return rawurlencode( html_entity_decode( $html_string, ENT_QUOTES | ENT_HTML5, 'UTF-8' ) );
565 + return rawurlencode( html_entity_decode( $string, ENT_QUOTES | ENT_HTML5, 'UTF-8' ) );
705 566 }
706 567
707 568 /**
708 569 * Parse attributes that come as a string of comma-delimited key|value pairs.
@@ -754,19 +615,13 @@
754 615 if ( $id === $element['id'] ) {
755 616 return $element;
756 617 }
757 618
758 - $inner_elements = apply_filters(
759 - 'elementor/utils/find_element_recursive/inner_elements',
760 - $element['elements'] ?? [],
761 - $element
762 - );
619 + if ( ! empty( $element['elements'] ) ) {
620 + $element = self::find_element_recursive( $element['elements'], $id );
763 621
764 - if ( ! empty( $inner_elements ) ) {
765 - $found = self::find_element_recursive( $inner_elements, $id );
766 -
767 - if ( $found ) {
768 - return $found;
622 + if ( $element ) {
623 + return $element;
769 624 }
770 625 }
771 626 }
772 627
@@ -781,10 +636,10 @@
781 636 * Fired by `admin_menu` action.
782 637 *
783 638 * @since 3.1.0
784 639 *
785 - * @param string $menu_slug
786 - * @param string $new_label
640 + * @param $menu_slug
641 + * @param $new_label
787 642 * @access public
788 643 */
789 644 public static function change_submenu_first_item_label( $menu_slug, $new_label ) {
790 645 global $submenu;
@@ -796,45 +651,8 @@
796 651 }
797 652 }
798 653
799 654 /**
800 - * @var string[]|null
801 - */
802 - private static $resolved_allowed_html_wrapper_tags;
803 -
804 - /**
805 - * Get allowed HTML wrapper tags.
806 - *
807 - * @since 4.4.0
808 - *
809 - * @return string[]
810 - */
811 - public static function get_allowed_html_wrapper_tags(): array {
812 - if ( null !== self::$resolved_allowed_html_wrapper_tags ) {
813 - return self::$resolved_allowed_html_wrapper_tags;
814 - }
815 -
816 - /**
817 - * Allowed HTML wrapper tags.
818 - *
819 - * Filters the list of allowed HTML tag names used by `validate_html_tag()`.
820 - *
821 - * Note: tags in `Utils::FORBIDDEN_HTML_WRAPPER_TAGS` (e.g. `script`, `iframe`,
822 - * `object`) are always stripped after this filter runs and cannot be re-added,
823 - * to prevent XSS via a wrapper tag that executes script or embeds external content.
824 - *
825 - * @since 4.4.0
826 - *
827 - * @param string[] $tags A list of lowercase HTML tag name strings.
828 - */
829 - $tags = apply_filters( 'elementor/allowed_html_wrapper_tags', self::ALLOWED_HTML_WRAPPER_TAGS );
830 -
831 - self::$resolved_allowed_html_wrapper_tags = self::normalize_allowed_html_wrapper_tags( $tags );
832 -
833 - return self::$resolved_allowed_html_wrapper_tags;
834 - }
835 -
836 - /**
837 655 * Validate an HTML tag against a safe allowed list.
838 656 *
839 657 * @param string $tag
840 658 *
@@ -840,37 +658,12 @@
840 658 *
841 659 * @return string
842 660 */
843 661 public static function validate_html_tag( $tag ) {
844 - return $tag && in_array( strtolower( $tag ), self::get_allowed_html_wrapper_tags(), true ) ? $tag : 'div';
662 + return in_array( strtolower( $tag ), self::ALLOWED_HTML_WRAPPER_TAGS ) ? $tag : 'div';
845 663 }
846 664
847 665 /**
848 - * @param array $tags
849 - *
850 - * @return string[]
851 - */
852 - private static function normalize_allowed_html_wrapper_tags( array $tags ): array {
853 - $normalized_tags = [];
854 -
855 - foreach ( $tags as $tag ) {
856 - if ( ! is_string( $tag ) ) {
857 - continue;
858 - }
859 -
860 - $tag = strtolower( $tag );
861 -
862 - if ( in_array( $tag, self::FORBIDDEN_HTML_WRAPPER_TAGS, true ) ) {
863 - continue;
864 - }
865 -
866 - $normalized_tags[] = $tag;
867 - }
868 -
869 - return array_values( array_unique( $normalized_tags ) );
870 - }
871 -
872 - /**
873 666 * Safe print a validated HTML tag.
874 667 *
875 668 * @param string $tag
876 669 */
@@ -881,10 +674,10 @@
881 674
882 675 /**
883 676 * Print internal content (not user input) without escaping.
884 677 */
885 - public static function print_unescaped_internal_string( $internal_string ) {
886 - echo $internal_string; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
678 + public static function print_unescaped_internal_string( $string ) {
679 + echo $string; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
887 680 }
888 681
889 682 /**
890 683 * Get recently edited posts query.
@@ -897,9 +690,8 @@
897 690 * @return \WP_Query
898 691 */
899 692 public static function get_recently_edited_posts_query( $args = [] ) {
900 693 $args = wp_parse_args( $args, [
901 - 'no_found_rows' => true,
902 694 'post_type' => 'any',
903 695 'post_status' => [ 'publish', 'draft' ],
904 696 'posts_per_page' => '3',
905 697 'meta_key' => '_elementor_edit_mode',
@@ -907,182 +699,6 @@
907 699 'orderby' => 'modified',
908 700 ] );
909 701
910 702 return new \WP_Query( $args );
911 - }
912 -
913 - public static function print_wp_kses_extended( $text, array $tags ) {
914 - $allowed_html = wp_kses_allowed_html( 'post' );
915 -
916 - foreach ( $tags as $tag ) {
917 - if ( isset( self::EXTENDED_ALLOWED_HTML_TAGS[ $tag ] ) ) {
918 - $extended_tags = apply_filters( "elementor/extended_allowed_html_tags/{$tag}", self::EXTENDED_ALLOWED_HTML_TAGS[ $tag ] );
919 - $allowed_html = array_replace_recursive( $allowed_html, $extended_tags );
920 - }
921 - }
922 -
923 - echo wp_kses( $text, $allowed_html );
924 - }
925 -
926 - public static function kses_post_deep( $data ) {
927 - return map_deep( $data, function ( $value ) {
928 - return is_string( $value ) ? wp_kses_post( $value ) : $value;
929 - } );
930 - }
931 -
932 - public static function is_elementor_path( $path ) {
933 - $path = wp_normalize_path( $path );
934 -
935 - /**
936 - * Elementor related paths.
937 - *
938 - * Filters Elementor related paths.
939 - *
940 - * @param string[] $available_paths
941 - */
942 - $available_paths = apply_filters( 'elementor/utils/elementor_related_paths', [ ELEMENTOR_PATH ] );
943 -
944 - return (bool) ( new Collection( $available_paths ) )
945 - ->map( function ( $p ) {
946 - // `untrailingslashit` in order to include other plugins prefixed with elementor.
947 - return untrailingslashit( wp_normalize_path( $p ) );
948 - } )
949 - ->find(function ( $p ) use ( $path ) {
950 - return false !== strpos( $path, $p );
951 - } );
952 - }
953 -
954 - /**
955 - * @param string $file
956 - * @param mixed ...$args
957 - * @return false|string
958 - */
959 - public static function file_get_contents( $file, ...$args ) {
960 - if ( ! is_file( $file ) || ! is_readable( $file ) ) {
961 - return false;
962 - }
963 - return file_get_contents( $file, ...$args );
964 - }
965 -
966 - public static function get_super_global_value( $super_global, $key ) {
967 - if ( ! isset( $super_global[ $key ] ) ) {
968 - return null;
969 - }
970 -
971 - if ( $_FILES === $super_global ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
972 - return isset( $super_global[ $key ]['name'] ) ?
973 - self::sanitize_file_name( $super_global[ $key ] ) :
974 - self::sanitize_multi_upload( $super_global[ $key ] );
975 - }
976 -
977 - return wp_kses_post_deep( wp_unslash( $super_global[ $key ] ) );
978 - }
979 -
980 - private static function sanitize_multi_upload( $fields ) {
981 - return array_map( function( $field ) {
982 - return array_map( 'self::sanitize_file_name', $field );
983 - }, $fields );
984 - }
985 -
986 - private static function sanitize_file_name( $file ) {
987 - $file['name'] = sanitize_file_name( $file['name'] );
988 -
989 - return $file;
990 - }
991 -
992 - /**
993 - * Return specific object property value if exist from array of keys.
994 - *
995 - * @param array $base_array
996 - * @param array $keys
997 - * @return mixed|null
998 - */
999 - public static function get_array_value_by_keys( $base_array, $keys ) {
1000 - $keys = (array) $keys;
1001 - foreach ( $keys as $key ) {
1002 - if ( ! isset( $base_array[ $key ] ) ) {
1003 - return null;
1004 - }
1005 - $base_array = $base_array[ $key ];
1006 - }
1007 - return $base_array;
1008 - }
1009 -
1010 - public static function get_cached_callback( $callback, $cache_key, $cache_time = 24 * HOUR_IN_SECONDS ) {
1011 - $cache = get_site_transient( $cache_key );
1012 -
1013 - if ( ! $cache ) {
1014 - $cache = call_user_func( $callback );
1015 -
1016 - if ( ! is_wp_error( $cache ) ) {
1017 - set_site_transient( $cache_key, $cache, $cache_time );
1018 - }
1019 - }
1020 -
1021 - return $cache;
1022 - }
1023 -
1024 - public static function is_sale_time(): bool {
1025 - $sale_start_time = gmmktime( 10, 0, 0, 6, 15, 2026 );
1026 - $sale_end_time = gmmktime( 3, 59, 0, 6, 17, 2026 );
1027 -
1028 - $now_time = gmdate( 'U' );
1029 -
1030 - return $now_time >= $sale_start_time && $now_time <= $sale_end_time;
1031 - }
1032 -
1033 - public static function safe_throw( string $message ) {
1034 - if ( ! static::is_elementor_debug() ) {
1035 - return;
1036 - }
1037 -
1038 - throw new \Exception( esc_html( $message ) );
1039 - }
1040 -
1041 - public static function has_invalid_post_permissions( $post ): bool {
1042 - $is_image_attachment = 'attachment' === $post->post_type && strpos( $post->post_mime_type, 'image/' ) === 0;
1043 -
1044 - if ( $is_image_attachment ) {
1045 - return false;
1046 - }
1047 -
1048 - $is_private = 'private' === $post->post_status
1049 - && ! current_user_can( 'read_private_posts', $post->ID );
1050 -
1051 - $not_allowed = 'publish' !== $post->post_status
1052 - && ! current_user_can( 'edit_post', $post->ID );
1053 -
1054 - $password_required = post_password_required( $post->ID )
1055 - && ! current_user_can( 'edit_post', $post->ID );
1056 -
1057 - return $is_private || $not_allowed || $password_required;
1058 - }
1059 -
1060 - public static function is_custom_kit_applied() {
1061 - return (bool) Plugin::$instance->kits_manager->get_previous_id();
1062 - }
1063 -
1064 - public static function decode_string( string $encoded_string, ?string $fallback = '' ) {
1065 - try {
1066 - return base64_decode( $encoded_string, true ) ?? $fallback;
1067 - } catch ( \Exception $e ) {
1068 - return $fallback;
1069 - }
1070 - }
1071 -
1072 - public static function encode_string( string $decoded_string ): string {
1073 - return base64_encode( $decoded_string );
1074 - }
1075 -
1076 - public static function html_to_plain_text( string $html ): string {
1077 - if ( empty( $html ) ) {
1078 - return '';
1079 - }
1080 -
1081 - $text = preg_replace( '#<br\s*/?\s*>#i', ' ', $html );
1082 - $text = preg_replace( '#</?[a-z][^>]*>#i', ' ', $text );
1083 - $text = html_entity_decode( $text, ENT_QUOTES, 'UTF-8' );
1084 - $text = str_replace( "\xE2\x80\x8B", '', $text );
1085 -
1086 - return trim( preg_replace( '/\s+/', ' ', $text ) );
1087 703 }
1088 704 }