<?php
namespace Elementor;
use Elementor\Core\Files\Fonts\Google_Font;
use Elementor\Core\Utils\Collection;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor utils.
*
* Elementor utils handler class is responsible for different utility methods
* used by Elementor.
*
* @since 1.0.0
*/
class Utils {
const DEPRECATION_RANGE = 0.4;
const EDITOR_BREAK_LINES_OPTION_KEY = 'elementor_editor_break_lines';
/**
* A list of safe tags for `validate_html_tag` method.
*/
const ALLOWED_HTML_WRAPPER_TAGS = [
'a',
'article',
'aside',
'button',
'div',
'footer',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'header',
'main',
'nav',
'p',
'section',
'span',
];
const EXTENDED_ALLOWED_HTML_TAGS = [
'iframe' => [
'iframe' => [
'allow' => true,
'allowfullscreen' => true,
'frameborder' => true,
'height' => true,
'loading' => true,
'name' => true,
'referrerpolicy' => true,
'sandbox' => true,
'src' => true,
'width' => true,
],
],
'svg' => [
'svg' => [
'aria-hidden' => true,
'aria-labelledby' => true,
'class' => true,
'height' => true,
'role' => true,
'viewbox' => true,
'width' => true,
'xmlns' => true,
],
'g' => [
'fill' => true,
],
'title' => [
'title' => true,
],
'path' => [
'd' => true,
'fill' => true,
],
],
'image' => [
'img' => [
'srcset' => true,
'sizes' => true,
],
],
];
/**
* Variables for free to pro upsale modal promotions
*/
const ANIMATED_HEADLINE = 'animated_headline';
const CTA = 'cta';
const VIDEO_PLAYLIST = 'video_playlist';
const TESTIMONIAL_WIDGET = 'testimonial_widget';
const IMAGE_CAROUSEL = 'image_carousel';
/**
* Whether WordPress CLI mode is enabled or not.
*
* @access public
* @static
*
* @return bool
*/
public static function is_wp_cli() {
return defined( 'WP_CLI' ) && WP_CLI;
}
/**
* Whether script debug is enabled or not.
*
* @since 1.0.0
* @access public
* @static
*
* @return bool
*/
public static function is_script_debug() {
return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG;
}
/**
* Whether Elementor debug is enabled or not.
*
* @access public
* @static
*
* @return bool
*/
public static function is_elementor_debug() {
return defined( 'ELEMENTOR_DEBUG' ) && ELEMENTOR_DEBUG;
}
/**
* Whether Elementor test mode is enabled or not.
*
* @access public
* @static
*
* @return bool
*/
public static function is_elementor_tests() {
return defined( 'ELEMENTOR_TESTS' ) && ELEMENTOR_TESTS;
}
/**
* Get pro link.
*
* Retrieve the link to Elementor Pro.
*
* @since 1.7.0
* @access public
* @static
*
* @param string $link URL to Elementor pro.
*
* @return string Elementor pro link.
*/
public static function get_pro_link( $link ) {
static $theme_name = false;
if ( ! $theme_name ) {
$theme_obj = wp_get_theme();
if ( $theme_obj->parent() ) {
$theme_name = $theme_obj->parent()->get( 'Name' );
} else {
$theme_name = $theme_obj->get( 'Name' );
}
$theme_name = sanitize_key( $theme_name );
}
$link = add_query_arg( 'utm_term', $theme_name, $link );
return $link;
}
/**
* Replace URLs.
*
* Replace old URLs to new URLs. This method also updates all the Elementor data.
*
* @since 2.1.0
* @static
* @access public
*
* @param string $from
* @param string $to
*
* @return string
* @throws \Exception Replace URL exception.
*/
public static function replace_urls( $from, $to ) {
$from = trim( $from );
$to = trim( $to );
if ( empty( $from ) ) {
throw new \Exception( 'Couldn’t replace your address because the old URL was not provided. Try again by entering the old URL.' );
}
if ( empty( $to ) ) {
throw new \Exception( 'Couldn’t replace your address because the new URL was not provided. Try again by entering the new URL.' );
}
if ( $from === $to ) {
throw new \Exception( 'Couldn’t replace your address because both of the URLs provided are identical. Try again by entering different URLs.' );
}
$is_valid_urls = ( filter_var( $from, FILTER_VALIDATE_URL ) && filter_var( $to, FILTER_VALIDATE_URL ) );
if ( ! $is_valid_urls ) {
throw new \Exception( 'Couldn’t replace your address because at least one of the URLs provided are invalid. Try again by entering valid URLs.' );
}
global $wpdb;
$escaped_from = str_replace( '/', '\\/', $from );
$escaped_to = str_replace( '/', '\\/', $to );
$meta_value_like = '[%'; // meta_value LIKE '[%' are json formatted
$rows_affected = $wpdb->query(
$wpdb->prepare(
"UPDATE {$wpdb->postmeta} " .
'SET `meta_value` = REPLACE(`meta_value`, %s, %s) ' .
"WHERE `meta_key` = '_elementor_data' AND `meta_value` LIKE %s;",
$escaped_from,
$escaped_to,
$meta_value_like
)
);
if ( false === $rows_affected ) {
throw new \Exception( 'An error occurred while replacing URL\'s.' );
}
// Allow externals to replace-urls, when they have to.
$rows_affected += (int) apply_filters( 'elementor/tools/replace-urls', 0, $from, $to );
Plugin::$instance->files_manager->clear_cache();
Google_Font::clear_cache();
return sprintf(
/* translators: %d: Number of rows. */
_n( '%d database row affected.', '%d database rows affected.', $rows_affected, 'elementor' ),
$rows_affected
);
}
/**
* Is post supports Elementor.
*
* Whether the post supports editing with Elementor.
*
* @since 1.0.0
* @access public
* @static
*
* @param int $post_id Optional. Post ID. Default is `0`.
*
* @return string True if post supports editing with Elementor, false otherwise.
*/
public static function is_post_support( $post_id = 0 ) {
$post_type = get_post_type( $post_id );
$is_supported = self::is_post_type_support( $post_type );
/**
* Is post type support.
*
* Filters whether the post type supports editing with Elementor.
*
* @since 1.0.0
* @deprecated 2.2.0 Use `elementor/utils/is_post_support` hook Instead.
*
* @param bool $is_supported Whether the post type supports editing with Elementor.
* @param int $post_id Post ID.
* @param string $post_type Post type.
*/
$is_supported = apply_filters( 'elementor/utils/is_post_type_support', $is_supported, $post_id, $post_type );
/**
* Is post support.
*
* Filters whether the post supports editing with Elementor.
*
* @since 2.2.0
*
* @param bool $is_supported Whether the post type supports editing with Elementor.
* @param int $post_id Post ID.
* @param string $post_type Post type.
*/
$is_supported = apply_filters( 'elementor/utils/is_post_support', $is_supported, $post_id, $post_type );
return $is_supported;
}
/**
* Is post type supports Elementor.
*
* Whether the post type supports editing with Elementor.
*
* @since 2.2.0
* @access public
* @static
*
* @param string $post_type Post Type.
*
* @return string True if post type supports editing with Elementor, false otherwise.
*/
public static function is_post_type_support( $post_type ) {
if ( ! post_type_exists( $post_type ) ) {
return false;
}
if ( ! post_type_supports( $post_type, 'elementor' ) ) {
return false;
}
return true;
}
/**
* Get placeholder image source.
*
* Retrieve the source of the placeholder image.
*
* @since 1.0.0
* @access public
* @static
*
* @return string The source of the default placeholder image used by Elementor.
*/
public static function get_placeholder_image_src() {
$placeholder_image = ELEMENTOR_ASSETS_URL . 'images/placeholder.png';
/**
* Get placeholder image source.
*
* Filters the source of the default placeholder image used by Elementor.
*
* @since 1.0.0
*
* @param string $placeholder_image The source of the default placeholder image.
*/
$placeholder_image = apply_filters( 'elementor/utils/get_placeholder_image_src', $placeholder_image );
return $placeholder_image;
}
/**
* Generate random string.
*
* Returns a string containing a hexadecima