PluginProbe
Elementor Website Builder – more than just a page builder / 3.0.12
Elementor Website Builder – more than just a page builder v3.0.12
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
elementor / includes / utils.php

utils.php in Elementor Website Builder – more than just a page builder 3.0.12, at includes/utils.php

588 lines 14.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit; // Exit if accessed directly.
6 }
7
8 /**
9 * Elementor utils.
10 *
11 * Elementor utils handler class is responsible for different utility methods
12 * used by Elementor.
13 *
14 * @since 1.0.0
15 */
16 class Utils {
17
18 const DEPRECATION_RANGE = 0.4;
19
20 /**
21 * Is ajax.
22 *
23 * Whether the current request is a WordPress ajax request.
24 *
25 * @since 1.0.0
26 * @deprecated 2.6.0 Use `wp_doing_ajax()` instead.
27 * @access public
28 * @static
29 *
30 * @return bool True if it's a WordPress ajax request, false otherwise.
31 */
32 public static function is_ajax() {
33 _deprecated_function( __METHOD__, '2.6.0', 'wp_doing_ajax()' );
34
35 return wp_doing_ajax();
36 }
37
38 /**
39 * Is script debug.
40 *
41 * Whether script debug is enabled or not.
42 *
43 * @since 1.0.0
44 * @access public
45 * @static
46 *
47 * @return bool True if it's a script debug is active, false otherwise.
48 */
49 public static function is_script_debug() {
50 return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG;
51 }
52
53 /**
54 * Get pro link.
55 *
56 * Retrieve the link to Elementor Pro.
57 *
58 * @since 1.7.0
59 * @access public
60 * @static
61 *
62 * @param string $link URL to Elementor pro.
63 *
64 * @return string Elementor pro link.
65 */
66 public static function get_pro_link( $link ) {
67 static $theme_name = false;
68
69 if ( ! $theme_name ) {
70 $theme_obj = wp_get_theme();
71 if ( $theme_obj->parent() ) {
72 $theme_name = $theme_obj->parent()->get( 'Name' );
73 } else {
74 $theme_name = $theme_obj->get( 'Name' );
75 }
76
77 $theme_name = sanitize_key( $theme_name );
78 }
79
80 $link = add_query_arg( 'utm_term', $theme_name, $link );
81
82 return $link;
83 }
84
85 /**
86 * Replace URLs.
87 *
88 * Replace old URLs to new URLs. This method also updates all the Elementor data.
89 *
90 * @since 2.1.0
91 * @static
92 * @access public
93 *
94 * @param $from
95 * @param $to
96 *
97 * @return string
98 * @throws \Exception
99 */
100 public static function replace_urls( $from, $to ) {
101 $from = trim( $from );
102 $to = trim( $to );
103
104 if ( $from === $to ) {
105 throw new \Exception( __( 'The `from` and `to` URL\'s must be different', 'elementor' ) );
106 }
107
108 $is_valid_urls = ( filter_var( $from, FILTER_VALIDATE_URL ) && filter_var( $to, FILTER_VALIDATE_URL ) );
109 if ( ! $is_valid_urls ) {
110 throw new \Exception( __( 'The `from` and `to` URL\'s must be valid URL\'s', 'elementor' ) );
111 }
112
113 global $wpdb;
114
115 // @codingStandardsIgnoreStart cannot use `$wpdb->prepare` because it remove's the backslashes
116 $rows_affected = $wpdb->query(
117 "UPDATE {$wpdb->postmeta} " .
118 "SET `meta_value` = REPLACE(`meta_value`, '" . str_replace( '/', '\\\/', $from ) . "', '" . str_replace( '/', '\\\/', $to ) . "') " .
119 "WHERE `meta_key` = '_elementor_data' AND `meta_value` LIKE '[%' ;" ); // meta_value LIKE '[%' are json formatted
120 // @codingStandardsIgnoreEnd
121
122 if ( false === $rows_affected ) {
123 throw new \Exception( __( 'An error occurred', 'elementor' ) );
124 }
125
126 Plugin::$instance->files_manager->clear_cache();
127
128 return sprintf(
129 /* translators: %d: Number of rows */
130 _n( '%d row affected.', '%d rows affected.', $rows_affected, 'elementor' ),
131 $rows_affected
132 );
133 }
134
135 /**
136 * Is post supports Elementor.
137 *
138 * Whether the post supports editing with Elementor.
139 *
140 * @since 1.0.0
141 * @access public
142 * @static
143 *
144 * @param int $post_id Optional. Post ID. Default is `0`.
145 *
146 * @return string True if post supports editing with Elementor, false otherwise.
147 */
148 public static function is_post_support( $post_id = 0 ) {
149 $post_type = get_post_type( $post_id );
150
151 $is_supported = self::is_post_type_support( $post_type );
152
153 /**
154 * Is post type support.
155 *
156 * Filters whether the post type supports editing with Elementor.
157 *
158 * @since 1.0.0
159 * @deprecated 2.2.0 Use `elementor/utils/is_post_support` Instead
160 *
161 * @param bool $is_supported Whether the post type supports editing with Elementor.
162 * @param int $post_id Post ID.
163 * @param string $post_type Post type.
164 */
165 $is_supported = apply_filters( 'elementor/utils/is_post_type_support', $is_supported, $post_id, $post_type );
166
167 /**
168 * Is post support.
169 *
170 * Filters whether the post supports editing with Elementor.
171 *
172 * @since 2.2.0
173 *
174 * @param bool $is_supported Whether the post type supports editing with Elementor.
175 * @param int $post_id Post ID.
176 * @param string $post_type Post type.
177 */
178 $is_supported = apply_filters( 'elementor/utils/is_post_support', $is_supported, $post_id, $post_type );
179
180 return $is_supported;
181 }
182
183
184 /**
185 * Is post type supports Elementor.
186 *
187 * Whether the post type supports editing with Elementor.
188 *
189 * @since 2.2.0
190 * @access public
191 * @static
192 *
193 * @param string $post_type Post Type.
194 *
195 * @return string True if post type supports editing with Elementor, false otherwise.
196 */
197 public static function is_post_type_support( $post_type ) {
198 if ( ! post_type_exists( $post_type ) ) {
199 return false;
200 }
201
202 if ( ! post_type_supports( $post_type, 'elementor' ) ) {
203 return false;
204 }
205
206 return true;
207 }
208
209 /**
210 * Get placeholder image source.
211 *
212 * Retrieve the source of the placeholder image.
213 *
214 * @since 1.0.0
215 * @access public
216 * @static
217 *
218 * @return string The source of the default placeholder image used by Elementor.
219 */
220 public static function get_placeholder_image_src() {
221 $placeholder_image = ELEMENTOR_ASSETS_URL . 'images/placeholder.png';
222
223 /**
224 * Get placeholder image source.
225 *
226 * Filters the source of the default placeholder image used by Elementor.
227 *
228 * @since 1.0.0
229 *
230 * @param string $placeholder_image The source of the default placeholder image.
231 */
232 $placeholder_image = apply_filters( 'elementor/utils/get_placeholder_image_src', $placeholder_image );
233
234 return $placeholder_image;
235 }
236
237 /**
238 * Generate random string.
239 *
240 * Returns a string containing a hexadecimal representation of random number.
241 *
242 * @since 1.0.0
243 * @access public
244 * @static
245 *
246 * @return string Random string.
247 */
248 public static function generate_random_string() {
249 return dechex( rand() );
250 }
251
252 /**
253 * Do not cache.
254 *
255 * Tell WordPress cache plugins not to cache this request.
256 *
257 * @since 1.0.0
258 * @access public
259 * @static
260 */
261 public static function do_not_cache() {
262 if ( ! defined( 'DONOTCACHEPAGE' ) ) {
263 define( 'DONOTCACHEPAGE', true );
264 }
265
266 if ( ! defined( 'DONOTCACHEDB' ) ) {
267 define( 'DONOTCACHEDB', true );
268 }
269
270 if ( ! defined( 'DONOTMINIFY' ) ) {
271 define( 'DONOTMINIFY', true );
272 }
273
274 if ( ! defined( 'DONOTCDN' ) ) {
275 define( 'DONOTCDN', true );
276 }
277
278 if ( ! defined( 'DONOTCACHCEOBJECT' ) ) {
279 define( 'DONOTCACHCEOBJECT', true );
280 }
281
282 // Set the headers to prevent caching for the different browsers.
283 nocache_headers();
284 }
285
286 /**
287 * Get timezone string.
288 *
289 * Retrieve timezone string from the WordPress database.
290 *
291 * @since 1.0.0
292 * @access public
293 * @static
294 *
295 * @return string Timezone string.
296 */
297 public static function get_timezone_string() {
298 $current_offset = (float) get_option( 'gmt_offset' );
299 $timezone_string = get_option( 'timezone_string' );
300
301 // Create a UTC+- zone if no timezone string exists.
302 if ( empty( $timezone_string ) ) {
303 if ( $current_offset < 0 ) {
304 $timezone_string = 'UTC' . $current_offset;
305 } else {
306 $timezone_string = 'UTC+' . $current_offset;
307 }
308 }
309
310 return $timezone_string;
311 }
312
313 /**
314 * Get create new post URL.
315 *
316 * Retrieve a custom URL for creating a new post/page using Elementor.
317 *
318 * @since 1.9.0
319 * @access public
320 * @static
321 *
322 * @param string $post_type Optional. Post type slug. Default is 'page'.
323 *
324 * @return string A URL for creating new post using Elementor.
325 */
326 public static function get_create_new_post_url( $post_type = 'page' ) {
327 $new_post_url = add_query_arg( [
328 'action' => 'elementor_new_post',
329 'post_type' => $post_type,
330 ], admin_url( 'edit.php' ) );
331
332 $new_post_url = add_query_arg( '_wpnonce', wp_create_nonce( 'elementor_action_new_post' ), $new_post_url );
333
334 return $new_post_url;
335 }
336
337 /**
338 * Get post autosave.
339 *
340 * Retrieve an autosave for any given post.
341 *
342 * @since 1.9.2
343 * @access public
344 * @static
345 *
346 * @param int $post_id Post ID.
347 * @param int $user_id Optional. User ID. Default is `0`.
348 *
349 * @return \WP_Post|false Post autosave or false.
350 */
351 public static function get_post_autosave( $post_id, $user_id = 0 ) {
352 global $wpdb;
353
354 $post = get_post( $post_id );
355
356 $where = $wpdb->prepare( 'post_parent = %d AND post_name LIKE %s AND post_modified_gmt > %s', [ $post_id, "{$post_id}-autosave%", $post->post_modified_gmt ] );
357
358 if ( $user_id ) {
359 $where .= $wpdb->prepare( ' AND post_author = %d', $user_id );
360 }
361
362 $revision = $wpdb->get_row( "SELECT * FROM $wpdb->posts WHERE $where AND post_type = 'revision'" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
363
364 if ( $revision ) {
365 $revision = new \WP_Post( $revision );
366 } else {
367 $revision = false;
368 }
369
370 return $revision;
371 }
372
373 /**
374 * Is CPT supports custom templates.
375 *
376 * Whether the Custom Post Type supports templates.
377 *
378 * @since 2.0.0
379 * @access public
380 * @static
381 *
382 * @return bool True is templates are supported, False otherwise.
383 */
384 public static function is_cpt_custom_templates_supported() {
385 require_once ABSPATH . '/wp-admin/includes/theme.php';
386
387 return method_exists( wp_get_theme(), 'get_post_templates' );
388 }
389
390 /**
391 * @since 2.1.2
392 * @access public
393 * @static
394 */
395 public static function array_inject( $array, $key, $insert ) {
396 $length = array_search( $key, array_keys( $array ), true ) + 1;
397
398 return array_slice( $array, 0, $length, true ) +
399 $insert +
400 array_slice( $array, $length, null, true );
401 }
402
403 /**
404 * Render html attributes
405 *
406 * @access public
407 * @static
408 * @param array $attributes
409 *
410 * @return string
411 */
412 public static function render_html_attributes( array $attributes ) {
413 $rendered_attributes = [];
414
415 foreach ( $attributes as $attribute_key => $attribute_values ) {
416 if ( is_array( $attribute_values ) ) {
417 $attribute_values = implode( ' ', $attribute_values );
418 }
419
420 $rendered_attributes[] = sprintf( '%1$s="%2$s"', $attribute_key, esc_attr( $attribute_values ) );
421 }
422
423 return implode( ' ', $rendered_attributes );
424 }
425
426 public static function get_meta_viewport( $context = '' ) {
427 $meta_tag = '<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />';
428 /**
429 * Viewport meta tag.
430 *
431 * Filters the Elementor preview URL.
432 *
433 * @since 2.5.0
434 *
435 * @param string $meta_tag Viewport meta tag.
436 */
437 return apply_filters( 'elementor/template/viewport_tag', $meta_tag, $context );
438 }
439
440 /**
441 * Add Elementor Config js vars to the relevant script handle,
442 * WP will wrap it with <script> tag.
443 * To make sure this script runs thru the `script_loader_tag` hook, use a known handle value.
444 * @param string $handle
445 * @param string $js_var
446 * @param mixed $config
447 */
448 public static function print_js_config( $handle, $js_var, $config ) {
449 $config = wp_json_encode( $config );
450
451 if ( get_option( 'elementor_editor_break_lines' ) ) {
452 // Add new lines to avoid memory limits in some hosting servers that handles the buffer output according to new line characters
453 $config = str_replace( '}},"', '}},' . PHP_EOL . '"', $config );
454 }
455
456 $script_data = 'var ' . $js_var . ' = ' . $config . ';';
457
458 wp_add_inline_script( $handle, $script_data, 'before' );
459 }
460
461 public static function handle_deprecation( $item, $version, $replacement = null ) {
462 preg_match( '/^[0-9]+\.[0-9]+/', ELEMENTOR_VERSION, $current_version );
463
464 $current_version_as_float = (float) $current_version[0];
465
466 preg_match( '/^[0-9]+\.[0-9]+/', $version, $alias_version );
467
468 $alias_version_as_float = (float) $alias_version[0];
469
470 if ( round( $current_version_as_float - $alias_version_as_float, 1 ) >= self::DEPRECATION_RANGE ) {
471 _deprecated_file( $item, $version, $replacement );
472 }
473 }
474
475 /**
476 * Checks a control value for being empty, including a string of '0' not covered by PHP's empty().
477 *
478 * @param mixed $source
479 * @param bool|string $key
480 *
481 * @return bool
482 */
483 public static function is_empty( $source, $key = false ) {
484 if ( is_array( $source ) ) {
485 if ( ! isset( $source[ $key ] ) ) {
486 return true;
487 }
488
489 $source = $source[ $key ];
490 }
491
492 return '0' !== $source && empty( $source );
493 }
494
495 public static function has_pro() {
496 return defined( 'ELEMENTOR_PRO_VERSION' );
497 }
498
499 /**
500 * Convert HTMLEntities to UTF-8 characters
501 *
502 * @param $string
503 * @return string
504 */
505 public static function urlencode_html_entities( $string ) {
506 $entities_dictionary = [
507 '&#145;' => "'", // Opening single quote
508 '&#146;' => "'", // Closing single quote
509 '&#147;' => '"', // Closing double quote
510 '&#148;' => '"', // Opening double quote
511 '&#8216;' => "'", // Closing single quote
512 '&#8217;' => "'", // Opening single quote
513 '&#8218;' => "'", // Single low quote
514 '&#8220;' => '"', // Closing double quote
515 '&#8221;' => '"', // Opening double quote
516 '&#8222;' => '"', // Double low quote
517 ];
518
519 // Decode decimal entities
520 $string = str_replace( array_keys( $entities_dictionary ), array_values( $entities_dictionary ), $string );
521
522 return rawurlencode( html_entity_decode( $string, ENT_QUOTES | ENT_HTML5, 'UTF-8' ) );
523 }
524
525 /**
526 * Parse attributes that come as a string of comma-delimited key|value pairs.
527 * Removes Javascript events and unescaped `href` attributes.
528 *
529 * @param string $attributes_string
530 *
531 * @param string $delimiter Default comma `,`.
532 *
533 * @return array
534 */
535 public static function parse_custom_attributes( $attributes_string, $delimiter = ',' ) {
536 $attributes = explode( $delimiter, $attributes_string );
537 $result = [];
538
539 foreach ( $attributes as $attribute ) {
540 $attr_key_value = explode( '|', $attribute );
541
542 $attr_key = mb_strtolower( $attr_key_value[0] );
543
544 // Remove any not allowed characters.
545 preg_match( '/[-_a-z0-9]+/', $attr_key, $attr_key_matches );
546
547 if ( empty( $attr_key_matches[0] ) ) {
548 continue;
549 }
550
551 $attr_key = $attr_key_matches[0];
552
553 // Avoid Javascript events and unescaped href.
554 if ( 'href' === $attr_key || 'on' === substr( $attr_key, 0, 2 ) ) {
555 continue;
556 }
557
558 if ( isset( $attr_key_value[1] ) ) {
559 $attr_value = trim( $attr_key_value[1] );
560 } else {
561 $attr_value = '';
562 }
563
564 $result[ $attr_key ] = $attr_value;
565 }
566
567 return $result;
568 }
569
570 public static function find_element_recursive( $elements, $id ) {
571 foreach ( $elements as $element ) {
572 if ( $id === $element['id'] ) {
573 return $element;
574 }
575
576 if ( ! empty( $element['elements'] ) ) {
577 $element = self::find_element_recursive( $element['elements'], $id );
578
579 if ( $element ) {
580 return $element;
581 }
582 }
583 }
584
585 return false;
586 }
587 }
588