first commit
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Core\Files\Assets;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
abstract class Files_Upload_Handler {
|
||||
const OPTION_KEY = 'elementor_unfiltered_files_upload';
|
||||
|
||||
public function __construct() {
|
||||
add_filter( 'upload_mimes', [ $this, 'support_unfiltered_files_upload' ] );
|
||||
add_filter( 'wp_handle_upload_prefilter', [ $this, 'handle_upload_prefilter' ] );
|
||||
add_filter( 'wp_check_filetype_and_ext', [ $this, 'check_filetype_and_ext' ], 10, 4 );
|
||||
}
|
||||
|
||||
abstract public function get_mime_type();
|
||||
|
||||
abstract public function get_file_type();
|
||||
|
||||
/**
|
||||
* is_elementor_media_upload
|
||||
* @return bool
|
||||
*/
|
||||
private function is_elementor_media_upload() {
|
||||
return isset( $_POST['uploadTypeCaller'] ) && 'elementor-editor-upload' === $_POST['uploadTypeCaller']; // phpcs:ignore
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
final public static function is_enabled() {
|
||||
$enabled = ! ! get_option( self::OPTION_KEY ) && self::file_sanitizer_can_run();
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 Use `elementor/document/urls/edit` filter instead.
|
||||
*/
|
||||
$enabled = apply_filters( 'elementor/files/svg/enabled', $enabled );
|
||||
|
||||
/**
|
||||
* Allow Unfiltered Files Upload.
|
||||
*
|
||||
* Determines whether to enable unfiltered file uploads.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param bool $enabled Weather upload is enabled or not.
|
||||
*/
|
||||
$enabled = apply_filters( 'elementor/files/allow_unfiltered_upload', $enabled );
|
||||
|
||||
return $enabled;
|
||||
}
|
||||
|
||||
final public function support_unfiltered_files_upload( $existing_mimes ) {
|
||||
$existing_mimes[ $this->get_file_type() ] = $this->get_mime_type();
|
||||
|
||||
return $existing_mimes;
|
||||
}
|
||||
|
||||
/**
|
||||
* handle_upload_prefilter
|
||||
* @param $file
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle_upload_prefilter( $file ) {
|
||||
if ( ! $this->is_file_should_handled( $file ) ) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
$ext = pathinfo( $file['name'], PATHINFO_EXTENSION );
|
||||
$file_type = $this->get_file_type();
|
||||
$display_type = strtoupper( $file_type );
|
||||
|
||||
if ( $file_type !== $ext ) {
|
||||
$file['error'] = sprintf( __( 'The uploaded %1$s file is not supported. Please upload a valid %2$s file', 'elementor' ), $ext, $display_type );
|
||||
return $file;
|
||||
}
|
||||
|
||||
if ( ! self::is_enabled() ) {
|
||||
$file['error'] = sprintf( __( '%1$s file is not allowed for security reasons', 'elementor' ), $display_type );
|
||||
return $file;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
protected function is_file_should_handled( $file ) {
|
||||
return $this->is_elementor_media_upload() && $this->get_mime_type() === $file['type'];
|
||||
}
|
||||
|
||||
/**
|
||||
* file_sanitizer_can_run
|
||||
* @return bool
|
||||
*/
|
||||
public static function file_sanitizer_can_run() {
|
||||
return class_exists( 'DOMDocument' ) && class_exists( 'SimpleXMLElement' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check filetype and ext
|
||||
*
|
||||
* A workaround for upload validation which relies on a PHP extension (fileinfo)
|
||||
* with inconsistent reporting behaviour.
|
||||
* ref: https://core.trac.wordpress.org/ticket/39550
|
||||
* ref: https://core.trac.wordpress.org/ticket/40175
|
||||
*
|
||||
* @param $data
|
||||
* @param $file
|
||||
* @param $filename
|
||||
* @param $mimes
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function check_filetype_and_ext( $data, $file, $filename, $mimes ) {
|
||||
if ( ! empty( $data['ext'] ) && ! empty( $data['type'] ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$wp_file_type = wp_check_filetype( $filename, $mimes );
|
||||
$file_type = strtolower( $this->get_file_type() );
|
||||
|
||||
if ( $file_type === $wp_file_type['ext'] ) {
|
||||
$data['ext'] = $file_type;
|
||||
$data['type'] = $this->get_mime_type();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace Elementor\Core\Files\Assets\Json;
|
||||
|
||||
use Elementor\Core\Files\Assets\Files_Upload_Handler;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Json_Handler extends Files_Upload_Handler {
|
||||
public static function get_name() {
|
||||
return 'json-handler';
|
||||
}
|
||||
|
||||
public function get_mime_type() {
|
||||
return 'application/json';
|
||||
}
|
||||
|
||||
public function get_file_type() {
|
||||
return 'json';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
namespace Elementor\Core\Files\Assets;
|
||||
|
||||
use Elementor\Core\Files\Assets\Svg\Svg_Handler;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor files manager.
|
||||
*
|
||||
* Elementor files manager handler class is responsible for creating files.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
class Manager {
|
||||
|
||||
/**
|
||||
* Holds registered asset types
|
||||
* @var array
|
||||
*/
|
||||
protected $asset_types = [];
|
||||
|
||||
/**
|
||||
* Assets manager constructor.
|
||||
*
|
||||
* Initializing the Elementor assets manager.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->register_asset_types();
|
||||
/**
|
||||
* Elementor files assets registered.
|
||||
*
|
||||
* Fires after Elementor registers assets types
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
do_action( 'elementor/core/files/assets/assets_registered', $this );
|
||||
}
|
||||
|
||||
public function get_asset( $name ) {
|
||||
return isset( $this->asset_types[ $name ] ) ? $this->asset_types[ $name ] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Asset
|
||||
* @param $instance
|
||||
*/
|
||||
public function add_asset( $instance ) {
|
||||
$this->asset_types[ $instance::get_name() ] = $instance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register Asset Types
|
||||
*
|
||||
* Registers Elementor Asset Types
|
||||
*/
|
||||
private function register_asset_types() {
|
||||
$this->add_asset( new Svg_Handler() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,704 @@
|
||||
<?php
|
||||
namespace Elementor\Core\Files\Assets\Svg;
|
||||
|
||||
use Elementor\Core\Files\Assets\Files_Upload_Handler;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Svg_Handler extends Files_Upload_Handler {
|
||||
/**
|
||||
* Inline svg attachment meta key
|
||||
*/
|
||||
const META_KEY = '_elementor_inline_svg';
|
||||
|
||||
const SCRIPT_REGEX = '/(?:\w+script|data):/xi';
|
||||
|
||||
/**
|
||||
* @var \DOMDocument
|
||||
*/
|
||||
private $svg_dom = null;
|
||||
|
||||
/**
|
||||
* Attachment ID.
|
||||
*
|
||||
* Holds the current attachment ID.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $attachment_id;
|
||||
|
||||
public static function get_name() {
|
||||
return 'svg-handler';
|
||||
}
|
||||
|
||||
/**
|
||||
* get_meta
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get_meta() {
|
||||
return get_post_meta( $this->attachment_id, self::META_KEY, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* update_meta
|
||||
* @param $meta
|
||||
*/
|
||||
protected function update_meta( $meta ) {
|
||||
update_post_meta( $this->attachment_id, self::META_KEY, $meta );
|
||||
}
|
||||
|
||||
/**
|
||||
* delete_meta
|
||||
*/
|
||||
protected function delete_meta() {
|
||||
delete_post_meta( $this->attachment_id, self::META_KEY );
|
||||
}
|
||||
|
||||
public function get_mime_type() {
|
||||
return 'image/svg+xml';
|
||||
}
|
||||
|
||||
public function get_file_type() {
|
||||
return 'svg';
|
||||
}
|
||||
|
||||
/**
|
||||
* delete_meta_cache
|
||||
*/
|
||||
public function delete_meta_cache() {
|
||||
delete_post_meta_by_key( self::META_KEY );
|
||||
}
|
||||
|
||||
/**
|
||||
* read_from_file
|
||||
* @return bool|string
|
||||
*/
|
||||
public function read_from_file() {
|
||||
return file_get_contents( get_attached_file( $this->attachment_id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* get_inline_svg
|
||||
* @param $attachment_id
|
||||
*
|
||||
* @return bool|mixed|string
|
||||
*/
|
||||
public static function get_inline_svg( $attachment_id ) {
|
||||
$svg = get_post_meta( $attachment_id, self::META_KEY, true );
|
||||
|
||||
if ( ! empty( $svg ) ) {
|
||||
return $svg;
|
||||
}
|
||||
|
||||
$attachment_file = get_attached_file( $attachment_id );
|
||||
|
||||
if ( ! $attachment_file ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$svg = file_get_contents( $attachment_file );
|
||||
|
||||
if ( ! empty( $svg ) ) {
|
||||
update_post_meta( $attachment_id, self::META_KEY, $svg );
|
||||
}
|
||||
|
||||
return $svg;
|
||||
}
|
||||
|
||||
/**
|
||||
* decode_svg
|
||||
* @param $content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function decode_svg( $content ) {
|
||||
return gzdecode( $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* encode_svg
|
||||
* @param $content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function encode_svg( $content ) {
|
||||
return gzencode( $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* sanitize_svg
|
||||
* @param $filename
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function sanitize_svg( $filename ) {
|
||||
$original_content = file_get_contents( $filename );
|
||||
$is_encoded = $this->is_encoded( $original_content );
|
||||
|
||||
if ( $is_encoded ) {
|
||||
$decoded = $this->decode_svg( $original_content );
|
||||
if ( false === $decoded ) {
|
||||
return false;
|
||||
}
|
||||
$original_content = $decoded;
|
||||
}
|
||||
|
||||
$valid_svg = $this->sanitizer( $original_content );
|
||||
|
||||
if ( false === $valid_svg ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we were gzipped, we need to re-zip
|
||||
if ( $is_encoded ) {
|
||||
$valid_svg = $this->encode_svg( $valid_svg );
|
||||
}
|
||||
file_put_contents( $filename, $valid_svg );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the contents are gzipped
|
||||
* @see http://www.gzip.org/zlib/rfc-gzip.html#member-format
|
||||
*
|
||||
* @param $contents
|
||||
* @return bool
|
||||
*/
|
||||
private function is_encoded( $contents ) {
|
||||
$needle = "\x1f\x8b\x08";
|
||||
if ( function_exists( 'mb_strpos' ) ) {
|
||||
return 0 === mb_strpos( $contents, $needle );
|
||||
} else {
|
||||
return 0 === strpos( $contents, $needle );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* is_allowed_tag
|
||||
* @param $element
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_allowed_tag( $element ) {
|
||||
static $allowed_tags = false;
|
||||
if ( false === $allowed_tags ) {
|
||||
$allowed_tags = $this->get_allowed_elements();
|
||||
}
|
||||
|
||||
$tag_name = $element->tagName; // phpcs:ignore -- php DomDocument
|
||||
|
||||
if ( ! in_array( strtolower( $tag_name ), $allowed_tags ) ) {
|
||||
$this->remove_element( $element );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function remove_element( $element ) {
|
||||
$element->parentNode->removeChild( $element ); // phpcs:ignore -- php DomDocument
|
||||
}
|
||||
|
||||
/**
|
||||
* is_a_attribute
|
||||
* @param $name
|
||||
* @param $check
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_a_attribute( $name, $check ) {
|
||||
return 0 === strpos( $name, $check . '-' );
|
||||
}
|
||||
|
||||
/**
|
||||
* is_remote_value
|
||||
* @param $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function is_remote_value( $value ) {
|
||||
$value = trim( preg_replace( '/[^ -~]/xu', '', $value ) );
|
||||
$wrapped_in_url = preg_match( '~^url\(\s*[\'"]\s*(.*)\s*[\'"]\s*\)$~xi', $value, $match );
|
||||
if ( ! $wrapped_in_url ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$value = trim( $match[1], '\'"' );
|
||||
return preg_match( '~^((https?|ftp|file):)?//~xi', $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* has_js_value
|
||||
* @param $value
|
||||
*
|
||||
* @return false|int
|
||||
*/
|
||||
private function has_js_value( $value ) {
|
||||
return preg_match( '/base64|data|(?:java)?script|alert\(|window\.|document/i', $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* get_allowed_attributes
|
||||
* @return array
|
||||
*/
|
||||
private function get_allowed_attributes() {
|
||||
$allowed_attributes = [
|
||||
'class',
|
||||
'clip-path',
|
||||
'clip-rule',
|
||||
'fill',
|
||||
'fill-opacity',
|
||||
'fill-rule',
|
||||
'filter',
|
||||
'id',
|
||||
'mask',
|
||||
'opacity',
|
||||
'stroke',
|
||||
'stroke-dasharray',
|
||||
'stroke-dashoffset',
|
||||
'stroke-linecap',
|
||||
'stroke-linejoin',
|
||||
'stroke-miterlimit',
|
||||
'stroke-opacity',
|
||||
'stroke-width',
|
||||
'style',
|
||||
'systemlanguage',
|
||||
'transform',
|
||||
'href',
|
||||
'xlink:href',
|
||||
'xlink:title',
|
||||
'cx',
|
||||
'cy',
|
||||
'r',
|
||||
'requiredfeatures',
|
||||
'clippathunits',
|
||||
'type',
|
||||
'rx',
|
||||
'ry',
|
||||
'color-interpolation-filters',
|
||||
'stddeviation',
|
||||
'filterres',
|
||||
'filterunits',
|
||||
'height',
|
||||
'primitiveunits',
|
||||
'width',
|
||||
'x',
|
||||
'y',
|
||||
'font-size',
|
||||
'display',
|
||||
'font-family',
|
||||
'font-style',
|
||||
'font-weight',
|
||||
'text-anchor',
|
||||
'marker-end',
|
||||
'marker-mid',
|
||||
'marker-start',
|
||||
'x1',
|
||||
'x2',
|
||||
'y1',
|
||||
'y2',
|
||||
'gradienttransform',
|
||||
'gradientunits',
|
||||
'spreadmethod',
|
||||
'markerheight',
|
||||
'markerunits',
|
||||
'markerwidth',
|
||||
'orient',
|
||||
'preserveaspectratio',
|
||||
'refx',
|
||||
'refy',
|
||||
'viewbox',
|
||||
'maskcontentunits',
|
||||
'maskunits',
|
||||
'd',
|
||||
'patterncontentunits',
|
||||
'patterntransform',
|
||||
'patternunits',
|
||||
'points',
|
||||
'fx',
|
||||
'fy',
|
||||
'offset',
|
||||
'stop-color',
|
||||
'stop-opacity',
|
||||
'xmlns',
|
||||
'xmlns:se',
|
||||
'xmlns:xlink',
|
||||
'xml:space',
|
||||
'method',
|
||||
'spacing',
|
||||
'startoffset',
|
||||
'dx',
|
||||
'dy',
|
||||
'rotate',
|
||||
'textlength',
|
||||
];
|
||||
|
||||
return apply_filters( 'elementor/files/svg/allowed_attributes', $allowed_attributes );
|
||||
}
|
||||
|
||||
/**
|
||||
* get_allowed_elements
|
||||
* @return array
|
||||
*/
|
||||
private function get_allowed_elements() {
|
||||
$allowed_elements = [
|
||||
'a',
|
||||
'circle',
|
||||
'clippath',
|
||||
'defs',
|
||||
'style',
|
||||
'desc',
|
||||
'ellipse',
|
||||
'fegaussianblur',
|
||||
'filter',
|
||||
'foreignobject',
|
||||
'g',
|
||||
'image',
|
||||
'line',
|
||||
'lineargradient',
|
||||
'marker',
|
||||
'mask',
|
||||
'metadata',
|
||||
'path',
|
||||
'pattern',
|
||||
'polygon',
|
||||
'polyline',
|
||||
'radialgradient',
|
||||
'rect',
|
||||
'stop',
|
||||
'svg',
|
||||
'switch',
|
||||
'symbol',
|
||||
'text',
|
||||
'textpath',
|
||||
'title',
|
||||
'tspan',
|
||||
'use',
|
||||
];
|
||||
return apply_filters( 'elementor/files/svg/allowed_elements', $allowed_elements );
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_allowed_attributes
|
||||
* @param \DOMElement $element
|
||||
*/
|
||||
private function validate_allowed_attributes( $element ) {
|
||||
static $allowed_attributes = false;
|
||||
if ( false === $allowed_attributes ) {
|
||||
$allowed_attributes = $this->get_allowed_attributes();
|
||||
}
|
||||
|
||||
for ( $index = $element->attributes->length - 1; $index >= 0; $index-- ) {
|
||||
// get attribute name
|
||||
$attr_name = $element->attributes->item( $index )->name;
|
||||
$attr_name_lowercase = strtolower( $attr_name );
|
||||
// Remove attribute if not in whitelist
|
||||
if ( ! in_array( $attr_name_lowercase, $allowed_attributes ) && ! $this->is_a_attribute( $attr_name_lowercase, 'aria' ) && ! $this->is_a_attribute( $attr_name_lowercase, 'data' ) ) {
|
||||
$element->removeAttribute( $attr_name );
|
||||
continue;
|
||||
}
|
||||
|
||||
$attr_value = $element->attributes->item( $index )->value;
|
||||
|
||||
// Remove attribute if it has a remote reference or js or data-URI/base64
|
||||
if ( ! empty( $attr_value ) && ( $this->is_remote_value( $attr_value ) || $this->has_js_value( $attr_value ) ) ) {
|
||||
$element->removeAttribute( $attr_name );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* strip_xlinks
|
||||
* @param \DOMElement $element
|
||||
*/
|
||||
private function strip_xlinks( $element ) {
|
||||
$xlinks = $element->getAttributeNS( 'http://www.w3.org/1999/xlink', 'href' );
|
||||
|
||||
if ( ! $xlinks ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$allowed_links = [
|
||||
'data:image/png', // PNG
|
||||
'data:image/gif', // GIF
|
||||
'data:image/jpg', // JPG
|
||||
'data:image/jpe', // JPEG
|
||||
'data:image/pjp', // PJPEG
|
||||
];
|
||||
if ( 1 === preg_match( self::SCRIPT_REGEX, $xlinks ) ) {
|
||||
if ( ! in_array( substr( $xlinks, 0, 14 ), $allowed_links ) ) {
|
||||
$element->removeAttributeNS( 'http://www.w3.org/1999/xlink', 'href' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_use_tag
|
||||
* @param $element
|
||||
*/
|
||||
private function validate_use_tag( $element ) {
|
||||
$xlinks = $element->getAttributeNS( 'http://www.w3.org/1999/xlink', 'href' );
|
||||
if ( $xlinks && '#' !== substr( $xlinks, 0, 1 ) ) {
|
||||
$element->parentNode->removeChild( $element ); // phpcs:ignore -- php DomNode
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* strip_docktype
|
||||
*/
|
||||
private function strip_doctype() {
|
||||
foreach ( $this->svg_dom->childNodes as $child ) {
|
||||
if ( XML_DOCUMENT_TYPE_NODE === $child->nodeType ) { // phpcs:ignore -- php DomDocument
|
||||
$child->parentNode->removeChild( $child ); // phpcs:ignore -- php DomDocument
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sanitize_elements
|
||||
*/
|
||||
private function sanitize_elements() {
|
||||
$elements = $this->svg_dom->getElementsByTagName( '*' );
|
||||
// loop through all elements
|
||||
// we do this backwards so we don't skip anything if we delete a node
|
||||
// see comments at: http://php.net/manual/en/class.domnamednodemap.php
|
||||
for ( $index = $elements->length - 1; $index >= 0; $index-- ) {
|
||||
/**
|
||||
* @var \DOMElement $current_element
|
||||
*/
|
||||
$current_element = $elements->item( $index );
|
||||
// If the tag isn't in the whitelist, remove it and continue with next iteration
|
||||
if ( ! $this->is_allowed_tag( $current_element ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//validate element attributes
|
||||
$this->validate_allowed_attributes( $current_element );
|
||||
|
||||
$this->strip_xlinks( $current_element );
|
||||
|
||||
if ( 'use' === strtolower( $current_element->tagName ) ) { // phpcs:ignore -- php DomDocument
|
||||
$this->validate_use_tag( $current_element );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sanitizer
|
||||
* @param $content
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function sanitizer( $content ) {
|
||||
// Strip php tags
|
||||
$content = $this->strip_comments( $content );
|
||||
$content = $this->strip_php_tags( $content );
|
||||
|
||||
// Find the start and end tags so we can cut out miscellaneous garbage.
|
||||
$start = strpos( $content, '<svg' );
|
||||
$end = strrpos( $content, '</svg>' );
|
||||
if ( false === $start || false === $end ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$content = substr( $content, $start, ( $end - $start + 6 ) );
|
||||
|
||||
// Make sure to Disable the ability to load external entities
|
||||
$libxml_disable_entity_loader = libxml_disable_entity_loader( true );
|
||||
// Suppress the errors
|
||||
$libxml_use_internal_errors = libxml_use_internal_errors( true );
|
||||
|
||||
// Create DomDocument instance
|
||||
$this->svg_dom = new \DOMDocument();
|
||||
$this->svg_dom->formatOutput = false;
|
||||
$this->svg_dom->preserveWhiteSpace = false;
|
||||
$this->svg_dom->strictErrorChecking = false;
|
||||
|
||||
$open_svg = $this->svg_dom->loadXML( $content );
|
||||
if ( ! $open_svg ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->strip_doctype();
|
||||
$this->sanitize_elements();
|
||||
|
||||
// Export sanitized svg to string
|
||||
// Using documentElement to strip out <?xml version="1.0" encoding="UTF-8"...
|
||||
$sanitized = $this->svg_dom->saveXML( $this->svg_dom->documentElement, LIBXML_NOEMPTYTAG );
|
||||
|
||||
// Restore defaults
|
||||
libxml_disable_entity_loader( $libxml_disable_entity_loader );
|
||||
libxml_use_internal_errors( $libxml_use_internal_errors );
|
||||
|
||||
return $sanitized;
|
||||
}
|
||||
|
||||
/**
|
||||
* strip_php_tags
|
||||
* @param $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function strip_php_tags( $string ) {
|
||||
$string = preg_replace( '/<\?(=|php)(.+?)\?>/i', '', $string );
|
||||
// Remove XML, ASP, etc.
|
||||
$string = preg_replace( '/<\?(.*)\?>/Us', '', $string );
|
||||
$string = preg_replace( '/<\%(.*)\%>/Us', '', $string );
|
||||
|
||||
if ( ( false !== strpos( $string, '<?' ) ) || ( false !== strpos( $string, '<%' ) ) ) {
|
||||
return '';
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* strip_comments
|
||||
* @param $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function strip_comments( $string ) {
|
||||
// Remove comments.
|
||||
$string = preg_replace( '/<!--(.*)-->/Us', '', $string );
|
||||
$string = preg_replace( '/\/\*(.*)\*\//Us', '', $string );
|
||||
if ( ( false !== strpos( $string, '<!--' ) ) || ( false !== strpos( $string, '/*' ) ) ) {
|
||||
return '';
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_prepare_attachment_for_js
|
||||
* @param $attachment_data
|
||||
* @param $attachment
|
||||
* @param $meta
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function wp_prepare_attachment_for_js( $attachment_data, $attachment, $meta ) {
|
||||
if ( 'image' !== $attachment_data['type'] || 'svg+xml' !== $attachment_data['subtype'] || ! class_exists( 'SimpleXMLElement' ) ) {
|
||||
return $attachment_data;
|
||||
}
|
||||
|
||||
$svg = self::get_inline_svg( $attachment->ID );
|
||||
|
||||
if ( ! $svg ) {
|
||||
return $attachment_data;
|
||||
}
|
||||
|
||||
try {
|
||||
$svg = new \SimpleXMLElement( $svg );
|
||||
} catch ( \Exception $e ) {
|
||||
return $attachment_data;
|
||||
}
|
||||
|
||||
$src = $attachment_data['url'];
|
||||
$width = (int) $svg['width'];
|
||||
$height = (int) $svg['height'];
|
||||
|
||||
// Media Gallery
|
||||
$attachment_data['image'] = compact( 'src', 'width', 'height' );
|
||||
$attachment_data['thumb'] = compact( 'src', 'width', 'height' );
|
||||
|
||||
// Single Details of Image
|
||||
$attachment_data['sizes']['full'] = [
|
||||
'height' => $height,
|
||||
'width' => $width,
|
||||
'url' => $src,
|
||||
'orientation' => $height > $width ? 'portrait' : 'landscape',
|
||||
];
|
||||
return $attachment_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* set_attachment_id
|
||||
* @param $attachment_id
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function set_attachment_id( $attachment_id ) {
|
||||
$this->attachment_id = $attachment_id;
|
||||
return $this->attachment_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_attachment_id
|
||||
* @return int
|
||||
*/
|
||||
public function get_attachment_id() {
|
||||
return $this->attachment_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* handle_upload_prefilter
|
||||
* @param $file
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle_upload_prefilter( $file ) {
|
||||
if ( ! $this->is_file_should_handled( $file ) ) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
$file = parent::handle_upload_prefilter( $file );
|
||||
|
||||
if ( ! $file['error'] && self::file_sanitizer_can_run() && ! $this->sanitize_svg( $file['tmp_name'] ) ) {
|
||||
$display_type = strtoupper( $this->get_file_type() );
|
||||
|
||||
$file['error'] = sprintf( __( 'Invalid %1$s Format, file not uploaded for security reasons', 'elementor' ), $display_type );
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0
|
||||
* @deprecated 3.0.0 Use Files_Upload_Handler::file_sanitizer_can_run() instead.
|
||||
*/
|
||||
public function svg_sanitizer_can_run() {
|
||||
_deprecated_function( __METHOD__, '3.0.0', 'Files_Upload_Handler::file_sanitizer_can_run()' );
|
||||
|
||||
return Files_Upload_Handler::file_sanitizer_can_run();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0
|
||||
* @deprecated 3.0.0
|
||||
*/
|
||||
public function upload_mimes() {
|
||||
_deprecated_function( __METHOD__, '3.0.0' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0
|
||||
* @deprecated 3.0.0
|
||||
*/
|
||||
public function wp_handle_upload_prefilter() {
|
||||
_deprecated_function( __METHOD__, '3.0.0' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0
|
||||
* @deprecated 3.0.0 Use Files_Upload_Handler::is_enabled() instead.
|
||||
* @see is_enabled()
|
||||
*/
|
||||
public function is_svg_uploads_enabled() {
|
||||
_deprecated_function( __METHOD__, '3.0.0', 'Files_Upload_Handler::is_enabled()' );
|
||||
|
||||
return Files_Upload_Handler::is_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Svg_Handler constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_filter( 'wp_prepare_attachment_for_js', [ $this, 'wp_prepare_attachment_for_js' ], 10, 3 );
|
||||
add_action( 'elementor/core/files/clear_cache', [ $this, 'delete_meta_cache' ] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
<?php
|
||||
namespace Elementor\Core\Files;
|
||||
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
abstract class Base {
|
||||
|
||||
const UPLOADS_DIR = 'elementor/';
|
||||
|
||||
const DEFAULT_FILES_DIR = 'css/';
|
||||
|
||||
const META_KEY = '';
|
||||
|
||||
private static $wp_uploads_dir = [];
|
||||
|
||||
private $files_dir;
|
||||
|
||||
private $file_name;
|
||||
|
||||
/**
|
||||
* File path.
|
||||
*
|
||||
* Holds the file path.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $path;
|
||||
|
||||
/**
|
||||
* Content.
|
||||
*
|
||||
* Holds the file content.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $content;
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function get_base_uploads_dir() {
|
||||
$wp_upload_dir = self::get_wp_uploads_dir();
|
||||
|
||||
return $wp_upload_dir['basedir'] . '/' . self::UPLOADS_DIR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function get_base_uploads_url() {
|
||||
$wp_upload_dir = self::get_wp_uploads_dir();
|
||||
|
||||
return $wp_upload_dir['baseurl'] . '/' . self::UPLOADS_DIR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a create function for PhpDoc (@return static).
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function create() {
|
||||
return Plugin::$instance->files_manager->get( get_called_class(), func_get_args() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function __construct( $file_name ) {
|
||||
/**
|
||||
* Elementor File Name
|
||||
*
|
||||
* Filters the File name
|
||||
*
|
||||
* @since 2.3.0
|
||||
*
|
||||
* @param string $file_name
|
||||
* @param object $this The file instance, which inherits Elementor\Core\Files
|
||||
*/
|
||||
$file_name = apply_filters( 'elementor/files/file_name', $file_name, $this );
|
||||
|
||||
$this->set_file_name( $file_name );
|
||||
|
||||
$this->set_files_dir( static::DEFAULT_FILES_DIR );
|
||||
|
||||
$this->set_path();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function set_files_dir( $files_dir ) {
|
||||
$this->files_dir = $files_dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function set_file_name( $file_name ) {
|
||||
$this->file_name = $file_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function get_file_name() {
|
||||
return $this->file_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function get_url() {
|
||||
$url = set_url_scheme( self::get_base_uploads_url() . $this->files_dir . $this->file_name );
|
||||
|
||||
return add_query_arg( [ 'ver' => $this->get_meta( 'time' ) ], $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function get_content() {
|
||||
if ( ! $this->content ) {
|
||||
$this->content = $this->parse_content();
|
||||
}
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function update() {
|
||||
$this->update_file();
|
||||
|
||||
$meta = $this->get_meta();
|
||||
|
||||
$meta['time'] = time();
|
||||
|
||||
$this->update_meta( $meta );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function update_file() {
|
||||
$this->content = $this->parse_content();
|
||||
|
||||
if ( $this->content ) {
|
||||
$this->write();
|
||||
} else {
|
||||
$this->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function write() {
|
||||
return file_put_contents( $this->path, $this->content );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function delete() {
|
||||
if ( file_exists( $this->path ) ) {
|
||||
unlink( $this->path );
|
||||
}
|
||||
|
||||
$this->delete_meta();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get meta data.
|
||||
*
|
||||
* Retrieve the CSS file meta data. Returns an array of all the data, or if
|
||||
* custom property is given it will return the property value, or `null` if
|
||||
* the property does not exist.
|
||||
*
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $property Optional. Custom meta data property. Default is
|
||||
* null.
|
||||
*
|
||||
* @return array|null An array of all the data, or if custom property is
|
||||
* given it will return the property value, or `null` if
|
||||
* the property does not exist.
|
||||
*/
|
||||
public function get_meta( $property = null ) {
|
||||
$meta = array_merge( $this->get_default_meta(), (array) $this->load_meta() );
|
||||
|
||||
if ( $property ) {
|
||||
return isset( $meta[ $property ] ) ? $meta[ $property ] : null;
|
||||
}
|
||||
|
||||
return $meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access protected
|
||||
* @abstract
|
||||
*/
|
||||
abstract protected function parse_content();
|
||||
|
||||
/**
|
||||
* Load meta.
|
||||
*
|
||||
* Retrieve the file meta data.
|
||||
*
|
||||
* @since 2.1.0
|
||||
* @access protected
|
||||
*/
|
||||
protected function load_meta() {
|
||||
return get_option( static::META_KEY );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update meta.
|
||||
*
|
||||
* Update the file meta data.
|
||||
*
|
||||
* @since 2.1.0
|
||||
* @access protected
|
||||
*
|
||||
* @param array $meta New meta data.
|
||||
*/
|
||||
protected function update_meta( $meta ) {
|
||||
update_option( static::META_KEY, $meta );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete meta.
|
||||
*
|
||||
* Delete the file meta data.
|
||||
*
|
||||
* @since 2.1.0
|
||||
* @access protected
|
||||
*/
|
||||
protected function delete_meta() {
|
||||
delete_option( static::META_KEY );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access protected
|
||||
*/
|
||||
protected function get_default_meta() {
|
||||
return [
|
||||
'time' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access private
|
||||
* @static
|
||||
*/
|
||||
private static function get_wp_uploads_dir() {
|
||||
global $blog_id;
|
||||
if ( empty( self::$wp_uploads_dir[ $blog_id ] ) ) {
|
||||
self::$wp_uploads_dir[ $blog_id ] = wp_upload_dir( null, false );
|
||||
}
|
||||
|
||||
return self::$wp_uploads_dir[ $blog_id ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access private
|
||||
*/
|
||||
private function set_path() {
|
||||
$dir_path = self::get_base_uploads_dir() . $this->files_dir;
|
||||
|
||||
if ( ! is_dir( $dir_path ) ) {
|
||||
wp_mkdir_p( $dir_path );
|
||||
}
|
||||
|
||||
$this->path = $dir_path . $this->file_name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,902 @@
|
||||
<?php
|
||||
namespace Elementor\Core\Files\CSS;
|
||||
|
||||
use Elementor\Base_Data_Control;
|
||||
use Elementor\Control_Repeater;
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Controls_Stack;
|
||||
use Elementor\Core\Files\Base as Base_File;
|
||||
use Elementor\Core\DynamicTags\Manager;
|
||||
use Elementor\Core\DynamicTags\Tag;
|
||||
use Elementor\Core\Kits\Documents\Tabs\Global_Typography;
|
||||
use Elementor\Element_Base;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Core\Responsive\Responsive;
|
||||
use Elementor\Stylesheet;
|
||||
use Elementor\Icons_Manager;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor CSS file.
|
||||
*
|
||||
* Elementor CSS file handler class is responsible for generating CSS files.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @abstract
|
||||
*/
|
||||
abstract class Base extends Base_File {
|
||||
|
||||
/**
|
||||
* Elementor CSS file generated status.
|
||||
*
|
||||
* The parsing result after generating CSS file.
|
||||
*/
|
||||
const CSS_STATUS_FILE = 'file';
|
||||
|
||||
/**
|
||||
* Elementor inline CSS status.
|
||||
*
|
||||
* The parsing result after generating inline CSS.
|
||||
*/
|
||||
const CSS_STATUS_INLINE = 'inline';
|
||||
|
||||
/**
|
||||
* Elementor CSS empty status.
|
||||
*
|
||||
* The parsing result when an empty CSS returned.
|
||||
*/
|
||||
const CSS_STATUS_EMPTY = 'empty';
|
||||
|
||||
/**
|
||||
* Fonts.
|
||||
*
|
||||
* Holds the list of fonts.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $fonts = [];
|
||||
|
||||
private $icons_fonts = [];
|
||||
|
||||
private $dynamic_elements_ids = [];
|
||||
|
||||
/**
|
||||
* Stylesheet object.
|
||||
*
|
||||
* Holds the CSS file stylesheet instance.
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @var Stylesheet
|
||||
*/
|
||||
protected $stylesheet_obj;
|
||||
|
||||
/**
|
||||
* Printed.
|
||||
*
|
||||
* Holds the list of printed files.
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $printed = [];
|
||||
|
||||
/**
|
||||
* Get CSS file name.
|
||||
*
|
||||
* Retrieve the CSS file name.
|
||||
*
|
||||
* @since 1.6.0
|
||||
* @access public
|
||||
* @abstract
|
||||
*/
|
||||
abstract public function get_name();
|
||||
|
||||
protected function is_global_parsing_supported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use external file.
|
||||
*
|
||||
* Whether to use external CSS file of not. When there are new schemes or settings
|
||||
* updates.
|
||||
*
|
||||
* @since 1.9.0
|
||||
* @access protected
|
||||
*
|
||||
* @return bool True if the CSS requires an update, False otherwise.
|
||||
*/
|
||||
protected function use_external_file() {
|
||||
return 'internal' !== get_option( 'elementor_css_print_method' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the CSS file.
|
||||
*
|
||||
* Delete old CSS, parse the CSS, save the new file and update the database.
|
||||
*
|
||||
* This method also sets the CSS status to be used later on in the render posses.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access public
|
||||
*/
|
||||
public function update() {
|
||||
$this->update_file();
|
||||
|
||||
$meta = $this->get_meta();
|
||||
|
||||
$meta['time'] = time();
|
||||
|
||||
$content = $this->get_content();
|
||||
|
||||
if ( empty( $content ) ) {
|
||||
$meta['status'] = self::CSS_STATUS_EMPTY;
|
||||
$meta['css'] = '';
|
||||
} else {
|
||||
$use_external_file = $this->use_external_file();
|
||||
|
||||
if ( $use_external_file ) {
|
||||
$meta['status'] = self::CSS_STATUS_FILE;
|
||||
} else {
|
||||
$meta['status'] = self::CSS_STATUS_INLINE;
|
||||
$meta['css'] = $content;
|
||||
}
|
||||
}
|
||||
|
||||
$meta['dynamic_elements_ids'] = $this->dynamic_elements_ids;
|
||||
|
||||
$this->update_meta( $meta );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
*/
|
||||
public function write() {
|
||||
if ( $this->use_external_file() ) {
|
||||
parent::write();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0
|
||||
* @access public
|
||||
*/
|
||||
public function delete() {
|
||||
if ( $this->use_external_file() ) {
|
||||
parent::delete();
|
||||
} else {
|
||||
$this->delete_meta();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue CSS.
|
||||
*
|
||||
* Either enqueue the CSS file in Elementor or add inline style.
|
||||
*
|
||||
* This method is also responsible for loading the fonts.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access public
|
||||
*/
|
||||
public function enqueue() {
|
||||
$handle_id = $this->get_file_handle_id();
|
||||
|
||||
if ( isset( self::$printed[ $handle_id ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$printed[ $handle_id ] = true;
|
||||
|
||||
$meta = $this->get_meta();
|
||||
|
||||
if ( self::CSS_STATUS_EMPTY === $meta['status'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// First time after clear cache and etc.
|
||||
if ( '' === $meta['status'] || $this->is_update_required() ) {
|
||||
$this->update();
|
||||
|
||||
$meta = $this->get_meta();
|
||||
}
|
||||
|
||||
if ( self::CSS_STATUS_INLINE === $meta['status'] ) {
|
||||
$dep = $this->get_inline_dependency();
|
||||
// If the dependency has already been printed ( like a template in footer )
|
||||
if ( wp_styles()->query( $dep, 'done' ) ) {
|
||||
printf( '<style id="%1$s">%2$s</style>', $this->get_file_handle_id(), $meta['css'] ); // XSS ok.
|
||||
} else {
|
||||
wp_add_inline_style( $dep, $meta['css'] );
|
||||
}
|
||||
} elseif ( self::CSS_STATUS_FILE === $meta['status'] ) { // Re-check if it's not empty after CSS update.
|
||||
wp_enqueue_style( $this->get_file_handle_id(), $this->get_url(), $this->get_enqueue_dependencies(), null ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion
|
||||
}
|
||||
|
||||
// Handle fonts.
|
||||
if ( ! empty( $meta['fonts'] ) ) {
|
||||
foreach ( $meta['fonts'] as $font ) {
|
||||
Plugin::$instance->frontend->enqueue_font( $font );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $meta['icons'] ) ) {
|
||||
$icons_types = Icons_Manager::get_icon_manager_tabs();
|
||||
foreach ( $meta['icons'] as $icon_font ) {
|
||||
if ( ! isset( $icons_types[ $icon_font ] ) ) {
|
||||
continue;
|
||||
}
|
||||
Plugin::$instance->frontend->enqueue_font( $icon_font );
|
||||
}
|
||||
}
|
||||
|
||||
$name = $this->get_name();
|
||||
|
||||
/**
|
||||
* Enqueue CSS file.
|
||||
*
|
||||
* Fires when CSS file is enqueued on Elementor.
|
||||
*
|
||||
* The dynamic portion of the hook name, `$name`, refers to the CSS file name.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param Base $this The current CSS file.
|
||||
*/
|
||||
do_action( "elementor/css-file/{$name}/enqueue", $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Print CSS.
|
||||
*
|
||||
* Output the final CSS inside the `<style>` tags and all the frontend fonts in
|
||||
* use.
|
||||
*
|
||||
* @since 1.9.4
|
||||
* @access public
|
||||
*/
|
||||
public function print_css() {
|
||||
echo '<style>' . $this->get_content() . '</style>'; // XSS ok.
|
||||
Plugin::$instance->frontend->print_fonts_links();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add control rules.
|
||||
*
|
||||
* Parse the CSS for all the elements inside any given control.
|
||||
*
|
||||
* This method recursively renders the CSS for all the selectors in the control.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access public
|
||||
*
|
||||
* @param array $control The controls.
|
||||
* @param array $controls_stack The controls stack.
|
||||
* @param callable $value_callback Callback function for the value.
|
||||
* @param array $placeholders Placeholders.
|
||||
* @param array $replacements Replacements.
|
||||
* @param array $values Global Values.
|
||||
*/
|
||||
public function add_control_rules( array $control, array $controls_stack, callable $value_callback, array $placeholders, array $replacements, array $values = [] ) {
|
||||
if ( empty( $control['selectors'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$control_global_key = $control['name'];
|
||||
|
||||
if ( ! empty( $control['groupType'] ) ) {
|
||||
$control_global_key = $control['groupPrefix'] . $control['groupType'];
|
||||
}
|
||||
|
||||
$global_values = [];
|
||||
$global_key = '';
|
||||
|
||||
if ( ! empty( $values['__globals__'] ) ) {
|
||||
$global_values = $values['__globals__'];
|
||||
}
|
||||
|
||||
if ( ! empty( $global_values[ $control_global_key ] ) ) {
|
||||
$global_key = $global_values[ $control_global_key ];
|
||||
}
|
||||
|
||||
if ( ! $global_key ) {
|
||||
$value = call_user_func( $value_callback, $control );
|
||||
|
||||
if ( null === $value ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$stylesheet = $this->get_stylesheet();
|
||||
|
||||
foreach ( $control['selectors'] as $selector => $css_property ) {
|
||||
$output_css_property = '';
|
||||
|
||||
if ( $global_key ) {
|
||||
$selector_global_value = $this->get_selector_global_value( $control, $global_key );
|
||||
|
||||
if ( $selector_global_value ) {
|
||||
$output_css_property = preg_replace( '/(:)[^;]+(;?)/', '$1' . $selector_global_value . '$2', $css_property );
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
$output_css_property = preg_replace_callback( '/{{(?:([^.}]+)\.)?([^}| ]*)(?: *\|\| *(?:([^.}]+)\.)?([^}| ]*) *)*}}/', function( $matches ) use ( $control, $value_callback, $controls_stack, $value, $css_property ) {
|
||||
$external_control_missing = $matches[1] && ! isset( $controls_stack[ $matches[1] ] );
|
||||
|
||||
$parsed_value = '';
|
||||
|
||||
if ( ! $external_control_missing ) {
|
||||
$parsed_value = $this->parse_property_placeholder( $control, $value, $controls_stack, $value_callback, $matches[2], $matches[1] );
|
||||
}
|
||||
|
||||
if ( '' === $parsed_value ) {
|
||||
if ( isset( $matches[4] ) ) {
|
||||
$parsed_value = $matches[4];
|
||||
|
||||
$is_string_value = preg_match( '/^([\'"])(.*)\1$/', $parsed_value, $string_matches );
|
||||
|
||||
if ( $is_string_value ) {
|
||||
$parsed_value = $string_matches[2];
|
||||
} elseif ( ! is_numeric( $parsed_value ) ) {
|
||||
if ( $matches[3] && ! isset( $controls_stack[ $matches[3] ] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$parsed_value = $this->parse_property_placeholder( $control, $value, $controls_stack, $value_callback, $matches[4], $matches[3] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( '' === $parsed_value ) {
|
||||
if ( $external_control_missing ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
throw new \Exception();
|
||||
}
|
||||
}
|
||||
|
||||
return $parsed_value;
|
||||
}, $css_property );
|
||||
} catch ( \Exception $e ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $output_css_property ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$device_pattern = '/^(?:\([^\)]+\)){1,2}/';
|
||||
|
||||
preg_match( $device_pattern, $selector, $device_rules );
|
||||
|
||||
$query = [];
|
||||
|
||||
if ( $device_rules ) {
|
||||
$selector = preg_replace( $device_pattern, '', $selector );
|
||||
|
||||
preg_match_all( '/\(([^)]+)\)/', $device_rules[0], $pure_device_rules );
|
||||
|
||||
$pure_device_rules = $pure_device_rules[1];
|
||||
|
||||
foreach ( $pure_device_rules as $device_rule ) {
|
||||
if ( Element_Base::RESPONSIVE_DESKTOP === $device_rule ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$device = preg_replace( '/\+$/', '', $device_rule );
|
||||
|
||||
$endpoint = $device === $device_rule ? 'max' : 'min';
|
||||
|
||||
$query[ $endpoint ] = $device;
|
||||
}
|
||||
}
|
||||
|
||||
$parsed_selector = str_replace( $placeholders, $replacements, $selector );
|
||||
|
||||
if ( ! $query && ! empty( $control['responsive'] ) ) {
|
||||
$query = array_intersect_key( $control['responsive'], array_flip( [ 'min', 'max' ] ) );
|
||||
|
||||
if ( ! empty( $query['max'] ) && Element_Base::RESPONSIVE_DESKTOP === $query['max'] ) {
|
||||
unset( $query['max'] );
|
||||
}
|
||||
}
|
||||
|
||||
$stylesheet->add_rules( $parsed_selector, $output_css_property, $query );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $control
|
||||
* @param mixed $value
|
||||
* @param array $controls_stack
|
||||
* @param callable $value_callback
|
||||
* @param string $placeholder
|
||||
* @param string $parser_control_name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function parse_property_placeholder( array $control, $value, array $controls_stack, $value_callback, $placeholder, $parser_control_name = null ) {
|
||||
if ( $parser_control_name ) {
|
||||
$control = $controls_stack[ $parser_control_name ];
|
||||
|
||||
$value = call_user_func( $value_callback, $control );
|
||||
}
|
||||
|
||||
if ( Controls_Manager::FONT === $control['type'] ) {
|
||||
$this->fonts[] = $value;
|
||||
}
|
||||
|
||||
/** @var Base_Data_Control $control_obj */
|
||||
$control_obj = Plugin::$instance->controls_manager->get_control( $control['type'] );
|
||||
|
||||
return (string) $control_obj->get_style_value( $placeholder, $value, $control );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fonts.
|
||||
*
|
||||
* Retrieve the list of fonts.
|
||||
*
|
||||
* @since 1.9.0
|
||||
* @access public
|
||||
*
|
||||
* @return array Fonts.
|
||||
*/
|
||||
public function get_fonts() {
|
||||
return $this->fonts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stylesheet.
|
||||
*
|
||||
* Retrieve the CSS file stylesheet instance.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access public
|
||||
*
|
||||
* @return Stylesheet The stylesheet object.
|
||||
*/
|
||||
public function get_stylesheet() {
|
||||
if ( ! $this->stylesheet_obj ) {
|
||||
$this->init_stylesheet();
|
||||
}
|
||||
|
||||
return $this->stylesheet_obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add controls stack style rules.
|
||||
*
|
||||
* Parse the CSS for all the elements inside any given controls stack.
|
||||
*
|
||||
* This method recursively renders the CSS for all the child elements in the stack.
|
||||
*
|
||||
* @since 1.6.0
|
||||
* @access public
|
||||
*
|
||||
* @param Controls_Stack $controls_stack The controls stack.
|
||||
* @param array $controls Controls array.
|
||||
* @param array $values Values array.
|
||||
* @param array $placeholders Placeholders.
|
||||
* @param array $replacements Replacements.
|
||||
* @param array $all_controls All controls.
|
||||
*/
|
||||
public function add_controls_stack_style_rules( Controls_Stack $controls_stack, array $controls, array $values, array $placeholders, array $replacements, array $all_controls = null ) {
|
||||
if ( ! $all_controls ) {
|
||||
$all_controls = $controls_stack->get_controls();
|
||||
}
|
||||
|
||||
$parsed_dynamic_settings = $controls_stack->parse_dynamic_settings( $values, $controls );
|
||||
|
||||
foreach ( $controls as $control ) {
|
||||
if ( ! empty( $control['style_fields'] ) ) {
|
||||
$this->add_repeater_control_style_rules( $controls_stack, $control, $values[ $control['name'] ], $placeholders, $replacements );
|
||||
}
|
||||
|
||||
if ( ! empty( $control[ Manager::DYNAMIC_SETTING_KEY ][ $control['name'] ] ) ) {
|
||||
$this->add_dynamic_control_style_rules( $control, $control[ Manager::DYNAMIC_SETTING_KEY ][ $control['name'] ] );
|
||||
}
|
||||
|
||||
if ( Controls_Manager::ICONS === $control['type'] ) {
|
||||
$this->icons_fonts[] = $values[ $control['name'] ]['library'];
|
||||
}
|
||||
|
||||
if ( ! empty( $parsed_dynamic_settings[ Manager::DYNAMIC_SETTING_KEY ][ $control['name'] ] ) ) {
|
||||
// Dynamic CSS should not be added to the CSS files.
|
||||
// Instead it's handled by \Elementor\Core\DynamicTags\Dynamic_CSS
|
||||
// and printed in a style tag.
|
||||
unset( $parsed_dynamic_settings[ $control['name'] ] );
|
||||
|
||||
$this->dynamic_elements_ids[] = $controls_stack->get_id();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( empty( $control['selectors'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->add_control_style_rules( $control, $parsed_dynamic_settings, $all_controls, $placeholders, $replacements );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file handle ID.
|
||||
*
|
||||
* Retrieve the file handle ID.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
* @abstract
|
||||
*
|
||||
* @return string CSS file handle ID.
|
||||
*/
|
||||
abstract protected function get_file_handle_id();
|
||||
|
||||
/**
|
||||
* Render CSS.
|
||||
*
|
||||
* Parse the CSS.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
* @abstract
|
||||
*/
|
||||
abstract protected function render_css();
|
||||
|
||||
protected function get_default_meta() {
|
||||
return array_merge( parent::get_default_meta(), [
|
||||
'fonts' => array_unique( $this->fonts ),
|
||||
'icons' => array_unique( $this->icons_fonts ),
|
||||
'dynamic_elements_ids' => [],
|
||||
'status' => '',
|
||||
] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get enqueue dependencies.
|
||||
*
|
||||
* Retrieve the name of the stylesheet used by `wp_enqueue_style()`.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
*
|
||||
* @return array Name of the stylesheet.
|
||||
*/
|
||||
protected function get_enqueue_dependencies() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get inline dependency.
|
||||
*
|
||||
* Retrieve the name of the stylesheet used by `wp_add_inline_style()`.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
*
|
||||
* @return string Name of the stylesheet.
|
||||
*/
|
||||
protected function get_inline_dependency() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Is update required.
|
||||
*
|
||||
* Whether the CSS requires an update. When there are new schemes or settings
|
||||
* updates.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
*
|
||||
* @return bool True if the CSS requires an update, False otherwise.
|
||||
*/
|
||||
protected function is_update_required() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse CSS.
|
||||
*
|
||||
* Parsing the CSS file.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
*/
|
||||
protected function parse_content() {
|
||||
$this->render_css();
|
||||
|
||||
$name = $this->get_name();
|
||||
|
||||
/**
|
||||
* Parse CSS file.
|
||||
*
|
||||
* Fires when CSS file is parsed on Elementor.
|
||||
*
|
||||
* The dynamic portion of the hook name, `$name`, refers to the CSS file name.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param Base $this The current CSS file.
|
||||
*/
|
||||
do_action( "elementor/css-file/{$name}/parse", $this );
|
||||
|
||||
return $this->get_stylesheet()->__toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add control style rules.
|
||||
*
|
||||
* Register new style rules for the control.
|
||||
*
|
||||
* @since 1.6.0
|
||||
* @access private
|
||||
*
|
||||
* @param array $control The control.
|
||||
* @param array $values Values array.
|
||||
* @param array $controls The controls stack.
|
||||
* @param array $placeholders Placeholders.
|
||||
* @param array $replacements Replacements.
|
||||
*/
|
||||
protected function add_control_style_rules( array $control, array $values, array $controls, array $placeholders, array $replacements ) {
|
||||
$this->add_control_rules(
|
||||
$control, $controls, function( $control ) use ( $values ) {
|
||||
return $this->get_style_control_value( $control, $values );
|
||||
}, $placeholders, $replacements, $values
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get style control value.
|
||||
*
|
||||
* Retrieve the value of the style control for any give control and values.
|
||||
*
|
||||
* It will retrieve the control name and return the style value.
|
||||
*
|
||||
* @since 1.6.0
|
||||
* @access private
|
||||
*
|
||||
* @param array $control The control.
|
||||
* @param array $values Values array.
|
||||
*
|
||||
* @return mixed Style control value.
|
||||
*/
|
||||
private function get_style_control_value( array $control, array $values ) {
|
||||
if ( ! empty( $values['__globals__'][ $control['name'] ] ) ) {
|
||||
// When the control itself has no global value, but it refers to another control global value
|
||||
return $this->get_selector_global_value( $control, $values['__globals__'][ $control['name'] ] );
|
||||
}
|
||||
|
||||
$value = $values[ $control['name'] ];
|
||||
|
||||
if ( isset( $control['selectors_dictionary'][ $value ] ) ) {
|
||||
$value = $control['selectors_dictionary'][ $value ];
|
||||
}
|
||||
|
||||
if ( ! is_numeric( $value ) && ! is_float( $value ) && empty( $value ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init stylesheet.
|
||||
*
|
||||
* Initialize CSS file stylesheet by creating a new `Stylesheet` object and register new
|
||||
* breakpoints for the stylesheet.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access private
|
||||
*/
|
||||
private function init_stylesheet() {
|
||||
$this->stylesheet_obj = new Stylesheet();
|
||||
|
||||
$breakpoints = Responsive::get_breakpoints();
|
||||
|
||||
$this->stylesheet_obj
|
||||
->add_device( 'mobile', 0 )
|
||||
->add_device( 'tablet', $breakpoints['md'] )
|
||||
->add_device( 'desktop', $breakpoints['lg'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add repeater control style rules.
|
||||
*
|
||||
* Register new style rules for the repeater control.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access private
|
||||
*
|
||||
* @param Controls_Stack $controls_stack The control stack.
|
||||
* @param array $repeater_control The repeater control.
|
||||
* @param array $repeater_values Repeater values array.
|
||||
* @param array $placeholders Placeholders.
|
||||
* @param array $replacements Replacements.
|
||||
*/
|
||||
protected function add_repeater_control_style_rules( Controls_Stack $controls_stack, array $repeater_control, array $repeater_values, array $placeholders, array $replacements ) {
|
||||
$placeholders = array_merge( $placeholders, [ '{{CURRENT_ITEM}}' ] );
|
||||
|
||||
foreach ( $repeater_control['style_fields'] as $index => $item ) {
|
||||
$this->add_controls_stack_style_rules(
|
||||
$controls_stack,
|
||||
$item,
|
||||
$repeater_values[ $index ],
|
||||
$placeholders,
|
||||
array_merge( $replacements, [ '.elementor-repeater-item-' . $repeater_values[ $index ]['_id'] ] ),
|
||||
$repeater_control['fields']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add dynamic control style rules.
|
||||
*
|
||||
* Register new style rules for the dynamic control.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @access private
|
||||
*
|
||||
* @param array $control The control.
|
||||
* @param string $value The value.
|
||||
*/
|
||||
protected function add_dynamic_control_style_rules( array $control, $value ) {
|
||||
Plugin::$instance->dynamic_tags->parse_tags_text( $value, $control, function( $id, $name, $settings ) {
|
||||
$tag = Plugin::$instance->dynamic_tags->create_tag( $id, $name, $settings );
|
||||
|
||||
if ( ! $tag instanceof Tag ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->add_controls_stack_style_rules( $tag, $this->get_style_controls( $tag ), $tag->get_active_settings(), [ '{{WRAPPER}}' ], [ '#elementor-tag-' . $id ] );
|
||||
} );
|
||||
}
|
||||
|
||||
private function get_selector_global_value( $control, $global_key ) {
|
||||
$data = Plugin::$instance->data_manager->run( $global_key );
|
||||
|
||||
if ( empty( $data['value'] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$global_args = explode( '?id=', $global_key );
|
||||
|
||||
$id = $global_args[1];
|
||||
|
||||
if ( ! empty( $control['groupType'] ) ) {
|
||||
$property_name = str_replace( [ $control['groupPrefix'], '_tablet', '_mobile' ], '', $control['name'] );
|
||||
|
||||
// TODO: This check won't retrieve the proper answer for array values (multiple controls).
|
||||
if ( empty( $data['value'][ Global_Typography::TYPOGRAPHY_GROUP_PREFIX . $property_name ] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$property_name = str_replace( '_', '-', $property_name );
|
||||
|
||||
$value = "var( --e-global-$control[groupType]-$id-$property_name )";
|
||||
} else {
|
||||
$value = "var( --e-global-$control[type]-$id )";
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
final protected function get_active_controls( Controls_Stack $controls_stack, array $controls = null, array $settings = null ) {
|
||||
if ( ! $controls ) {
|
||||
$controls = $controls_stack->get_controls();
|
||||
}
|
||||
|
||||
if ( ! $settings ) {
|
||||
$settings = $controls_stack->get_controls_settings();
|
||||
}
|
||||
|
||||
if ( $this->is_global_parsing_supported() ) {
|
||||
$settings = $this->parse_global_settings( $settings, $controls );
|
||||
}
|
||||
|
||||
$active_controls = array_reduce(
|
||||
array_keys( $controls ), function( $active_controls, $control_key ) use ( $controls_stack, $controls, $settings ) {
|
||||
$control = $controls[ $control_key ];
|
||||
|
||||
if ( $controls_stack->is_control_visible( $control, $settings ) ) {
|
||||
$active_controls[ $control_key ] = $control;
|
||||
}
|
||||
|
||||
return $active_controls;
|
||||
}, []
|
||||
);
|
||||
|
||||
return $active_controls;
|
||||
}
|
||||
|
||||
final public function get_style_controls( Controls_Stack $controls_stack, array $controls = null, array $settings = null ) {
|
||||
$controls = $this->get_active_controls( $controls_stack, $controls, $settings );
|
||||
|
||||
$style_controls = [];
|
||||
|
||||
foreach ( $controls as $control_name => $control ) {
|
||||
$control_obj = Plugin::$instance->controls_manager->get_control( $control['type'] );
|
||||
|
||||
if ( ! $control_obj instanceof Base_Data_Control ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$control = array_merge( $control_obj->get_settings(), $control );
|
||||
|
||||
if ( $control_obj instanceof Control_Repeater ) {
|
||||
$style_fields = [];
|
||||
|
||||
foreach ( $controls_stack->get_settings( $control_name ) as $item ) {
|
||||
$style_fields[] = $this->get_style_controls( $controls_stack, $control['fields'], $item );
|
||||
}
|
||||
|
||||
$control['style_fields'] = $style_fields;
|
||||
}
|
||||
|
||||
if ( ! empty( $control['selectors'] ) || ! empty( $control['dynamic'] ) || $this->is_global_control( $controls_stack, $control_name, $controls ) || ! empty( $control['style_fields'] ) ) {
|
||||
$style_controls[ $control_name ] = $control;
|
||||
}
|
||||
}
|
||||
|
||||
return $style_controls;
|
||||
}
|
||||
|
||||
private function parse_global_settings( array $settings, array $controls ) {
|
||||
foreach ( $controls as $control ) {
|
||||
$control_name = $control['name'];
|
||||
$control_obj = Plugin::$instance->controls_manager->get_control( $control['type'] );
|
||||
|
||||
if ( ! $control_obj instanceof Base_Data_Control ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $control_obj instanceof Control_Repeater ) {
|
||||
foreach ( $settings[ $control_name ] as & $field ) {
|
||||
$field = $this->parse_global_settings( $field, $control['fields'] );
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( empty( $control['global']['active'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( empty( $settings['__globals__'][ $control_name ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$settings[ $control_name ] = 'global';
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
private function is_global_control( Controls_Stack $controls_stack, $control_name, $controls ) {
|
||||
$control = $controls[ $control_name ];
|
||||
|
||||
$control_global_key = $control_name;
|
||||
|
||||
if ( ! empty( $control['groupType'] ) ) {
|
||||
$control_global_key = $control['groupPrefix'] . $control['groupType'];
|
||||
}
|
||||
|
||||
if ( empty( $controls[ $control_global_key ]['global']['active'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$globals = $controls_stack->get_settings( '__globals__' );
|
||||
|
||||
return ! empty( $globals[ $control_global_key ] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
namespace Elementor\Core\Files\CSS;
|
||||
|
||||
use Elementor\Core\Kits\Manager;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Settings;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor global CSS file.
|
||||
*
|
||||
* Elementor CSS file handler class is responsible for generating the global CSS
|
||||
* file.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
class Global_CSS extends Base {
|
||||
|
||||
/**
|
||||
* Elementor global CSS file handler ID.
|
||||
*/
|
||||
const FILE_HANDLER_ID = 'elementor-global';
|
||||
|
||||
const META_KEY = '_elementor_global_css';
|
||||
|
||||
/**
|
||||
* Get CSS file name.
|
||||
*
|
||||
* Retrieve the CSS file name.
|
||||
*
|
||||
* @since 1.6.0
|
||||
* @access public
|
||||
*
|
||||
* @return string CSS file name.
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'global';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file handle ID.
|
||||
*
|
||||
* Retrieve the handle ID for the global post CSS file.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
*
|
||||
* @return string CSS file handle ID.
|
||||
*/
|
||||
protected function get_file_handle_id() {
|
||||
return self::FILE_HANDLER_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render CSS.
|
||||
*
|
||||
* Parse the CSS for all the widgets and all the scheme controls.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
*/
|
||||
protected function render_css() {
|
||||
$this->render_schemes_and_globals_css();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get inline dependency.
|
||||
*
|
||||
* Retrieve the name of the stylesheet used by `wp_add_inline_style()`.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
*
|
||||
* @return string Name of the stylesheet.
|
||||
*/
|
||||
protected function get_inline_dependency() {
|
||||
return 'elementor-frontend';
|
||||
}
|
||||
|
||||
/**
|
||||
* Is update required.
|
||||
*
|
||||
* Whether the CSS requires an update. When there are new schemes or settings
|
||||
* updates.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
*
|
||||
* @return bool True if the CSS requires an update, False otherwise.
|
||||
*/
|
||||
protected function is_update_required() {
|
||||
return $this->get_meta( 'time' ) < get_option( Settings::UPDATE_TIME_FIELD );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render schemes CSS.
|
||||
*
|
||||
* Parse the CSS for all the widgets and all the scheme controls.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access private
|
||||
*/
|
||||
private function render_schemes_and_globals_css() {
|
||||
$elementor = Plugin::$instance;
|
||||
|
||||
/** @var Manager $module */
|
||||
$kits_manager = Plugin::$instance->kits_manager;
|
||||
$custom_colors_enabled = $kits_manager->is_custom_colors_enabled();
|
||||
$custom_typography_enabled = $kits_manager->is_custom_typography_enabled();
|
||||
|
||||
// If both default colors and typography are disabled, there is no need to render schemes and default global css.
|
||||
if ( ! $custom_colors_enabled && ! $custom_typography_enabled ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $elementor->widgets_manager->get_widget_types() as $widget ) {
|
||||
$controls = $widget->get_controls();
|
||||
|
||||
$global_controls = [];
|
||||
|
||||
$global_values['__globals__'] = [];
|
||||
|
||||
foreach ( $controls as $control ) {
|
||||
$is_color_control = 'color' === $control['type'];
|
||||
$is_typography_control = isset( $control['groupType'] ) && 'typography' === $control['groupType'];
|
||||
|
||||
// If it is a color/typography control and default colors/typography are disabled,
|
||||
// don't add the default CSS.
|
||||
if ( ( $is_color_control && ! $custom_colors_enabled ) || ( $is_typography_control && ! $custom_typography_enabled ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$global_control = $control;
|
||||
|
||||
// Handle group controls that don't have a default global property.
|
||||
if ( ! empty( $control['groupType'] ) ) {
|
||||
$global_control = $controls[ $control['groupPrefix'] . $control['groupType'] ];
|
||||
}
|
||||
|
||||
// If the control has a default global defined, add it to the globals array
|
||||
// that is used in add_control_rules.
|
||||
if ( ! empty( $control['global']['default'] ) ) {
|
||||
$global_values['__globals__'][ $control['name'] ] = $global_control['global']['default'];
|
||||
}
|
||||
|
||||
if ( ! empty( $global_control['global']['default'] ) ) {
|
||||
$global_controls[] = $control;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $global_controls as $control ) {
|
||||
$this->add_control_rules( $control, $controls, function( $control ) {}, [ '{{WRAPPER}}' ], [ '.elementor-widget-' . $widget->get_name() ], $global_values );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Core\Files\CSS;
|
||||
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
abstract class Post_Local_Cache extends Post {
|
||||
|
||||
/**
|
||||
* Meta cache
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $meta_cache = [];
|
||||
|
||||
abstract protected function get_post_id_for_data();
|
||||
|
||||
public function is_update_required() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function load_meta() {
|
||||
return $this->meta_cache;
|
||||
}
|
||||
|
||||
protected function delete_meta() {
|
||||
$this->meta_cache = [];
|
||||
}
|
||||
|
||||
protected function update_meta( $meta ) {
|
||||
$this->meta_cache = $meta;
|
||||
}
|
||||
|
||||
protected function get_data() {
|
||||
$document = Plugin::$instance->documents->get( $this->get_post_id_for_data() );
|
||||
|
||||
return $document ? $document->get_elements_data() : [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
namespace Elementor\Core\Files\CSS;
|
||||
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor post preview CSS file.
|
||||
*
|
||||
* Elementor CSS file handler class is responsible for generating the post
|
||||
* preview CSS file.
|
||||
*
|
||||
* @since 1.9.0
|
||||
*/
|
||||
class Post_Preview extends Post_Local_Cache {
|
||||
|
||||
/**
|
||||
* Preview ID.
|
||||
*
|
||||
* Holds the ID of the current post being previewed.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $post_id_for_data;
|
||||
|
||||
/**
|
||||
* Post preview CSS file constructor.
|
||||
*
|
||||
* Initializing the CSS file of the post preview. Set the post ID and the
|
||||
* parent ID and initiate the stylesheet.
|
||||
*
|
||||
* @since 1.9.0
|
||||
* @access public
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
*/
|
||||
public function __construct( $post_id ) {
|
||||
$this->post_id_for_data = $post_id;
|
||||
|
||||
$parent_id = wp_get_post_parent_id( $post_id );
|
||||
|
||||
parent::__construct( $parent_id );
|
||||
}
|
||||
|
||||
protected function get_post_id_for_data() {
|
||||
return $this->post_id_for_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1.0
|
||||
* @access public
|
||||
* @deprecated 3.0.0 Use `Post_Preview::get_post_id_for_data()` instead
|
||||
*/
|
||||
protected function get_preview_id() {
|
||||
_deprecated_function( __METHOD__, '3.0.0', __CLASS__ . '::get_post_id_for_data()' );
|
||||
|
||||
return $this->get_post_id_for_data();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file handle ID.
|
||||
*
|
||||
* Retrieve the handle ID for the previewed post CSS file.
|
||||
*
|
||||
* @since 1.9.0
|
||||
* @access protected
|
||||
*
|
||||
* @return string CSS file handle ID.
|
||||
*/
|
||||
protected function get_file_handle_id() {
|
||||
return 'elementor-preview-' . $this->get_post_id_for_data();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
<?php
|
||||
namespace Elementor\Core\Files\CSS;
|
||||
|
||||
use Elementor\Base_Data_Control;
|
||||
use Elementor\Control_Repeater;
|
||||
use Elementor\Controls_Stack;
|
||||
use Elementor\Element_Base;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor post CSS file.
|
||||
*
|
||||
* Elementor CSS file handler class is responsible for generating the single
|
||||
* post CSS file.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
class Post extends Base {
|
||||
|
||||
/**
|
||||
* Elementor post CSS file prefix.
|
||||
*/
|
||||
const FILE_PREFIX = 'post-';
|
||||
|
||||
const META_KEY = '_elementor_css';
|
||||
|
||||
/**
|
||||
* Post ID.
|
||||
*
|
||||
* Holds the current post ID.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $post_id;
|
||||
|
||||
protected function is_global_parsing_supported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post CSS file constructor.
|
||||
*
|
||||
* Initializing the CSS file of the post. Set the post ID and initiate the stylesheet.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access public
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
*/
|
||||
public function __construct( $post_id ) {
|
||||
$this->post_id = $post_id;
|
||||
|
||||
parent::__construct( static::FILE_PREFIX . $post_id . '.css' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get CSS file name.
|
||||
*
|
||||
* Retrieve the CSS file name.
|
||||
*
|
||||
* @since 1.6.0
|
||||
* @access public
|
||||
*
|
||||
* @return string CSS file name.
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'post';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get post ID.
|
||||
*
|
||||
* Retrieve the ID of current post.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access public
|
||||
*
|
||||
* @return int Post ID.
|
||||
*/
|
||||
public function get_post_id() {
|
||||
return $this->post_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get unique element selector.
|
||||
*
|
||||
* Retrieve the unique selector for any given element.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access public
|
||||
*
|
||||
* @param Element_Base $element The element.
|
||||
*
|
||||
* @return string Unique element selector.
|
||||
*/
|
||||
public function get_element_unique_selector( Element_Base $element ) {
|
||||
return '.elementor-' . $this->post_id . ' .elementor-element' . $element->get_unique_selector();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load meta data.
|
||||
*
|
||||
* Retrieve the post CSS file meta data.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
*
|
||||
* @return array Post CSS file meta data.
|
||||
*/
|
||||
protected function load_meta() {
|
||||
return get_post_meta( $this->post_id, static::META_KEY, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update meta data.
|
||||
*
|
||||
* Update the global CSS file meta data.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
*
|
||||
* @param array $meta New meta data.
|
||||
*/
|
||||
protected function update_meta( $meta ) {
|
||||
update_post_meta( $this->post_id, static::META_KEY, $meta );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete meta.
|
||||
*
|
||||
* Delete the file meta data.
|
||||
*
|
||||
* @since 2.1.0
|
||||
* @access protected
|
||||
*/
|
||||
protected function delete_meta() {
|
||||
delete_post_meta( $this->post_id, static::META_KEY );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get post data.
|
||||
*
|
||||
* Retrieve raw post data from the database.
|
||||
*
|
||||
* @since 1.9.0
|
||||
* @access protected
|
||||
*
|
||||
* @return array Post data.
|
||||
*/
|
||||
protected function get_data() {
|
||||
$document = Plugin::$instance->documents->get( $this->post_id );
|
||||
return $document ? $document->get_elements_data() : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Render CSS.
|
||||
*
|
||||
* Parse the CSS for all the elements.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
*/
|
||||
protected function render_css() {
|
||||
$data = $this->get_data();
|
||||
|
||||
if ( ! empty( $data ) ) {
|
||||
foreach ( $data as $element_data ) {
|
||||
$element = Plugin::$instance->elements_manager->create_element_instance( $element_data );
|
||||
|
||||
if ( ! $element ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->render_styles( $element );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue CSS.
|
||||
*
|
||||
* Enqueue the post CSS file in Elementor.
|
||||
*
|
||||
* This method ensures that the post was actually built with elementor before
|
||||
* enqueueing the post CSS file.
|
||||
*
|
||||
* @since 1.2.2
|
||||
* @access public
|
||||
*/
|
||||
public function enqueue() {
|
||||
if ( ! Plugin::$instance->db->is_built_with_elementor( $this->post_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
parent::enqueue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add controls-stack style rules.
|
||||
*
|
||||
* Parse the CSS for all the elements inside any given controls stack.
|
||||
*
|
||||
* This method recursively renders the CSS for all the child elements in the stack.
|
||||
*
|
||||
* @since 1.6.0
|
||||
* @access public
|
||||
*
|
||||
* @param Controls_Stack $controls_stack The controls stack.
|
||||
* @param array $controls Controls array.
|
||||
* @param array $values Values array.
|
||||
* @param array $placeholders Placeholders.
|
||||
* @param array $replacements Replacements.
|
||||
* @param array $all_controls All controls.
|
||||
*/
|
||||
public function add_controls_stack_style_rules( Controls_Stack $controls_stack, array $controls, array $values, array $placeholders, array $replacements, array $all_controls = null ) {
|
||||
parent::add_controls_stack_style_rules( $controls_stack, $controls, $values, $placeholders, $replacements, $all_controls );
|
||||
|
||||
if ( $controls_stack instanceof Element_Base ) {
|
||||
foreach ( $controls_stack->get_children() as $child_element ) {
|
||||
$this->render_styles( $child_element );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get enqueue dependencies.
|
||||
*
|
||||
* Retrieve the name of the stylesheet used by `wp_enqueue_style()`.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
*
|
||||
* @return array Name of the stylesheet.
|
||||
*/
|
||||
protected function get_enqueue_dependencies() {
|
||||
return [ 'elementor-frontend' ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get inline dependency.
|
||||
*
|
||||
* Retrieve the name of the stylesheet used by `wp_add_inline_style()`.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
*
|
||||
* @return string Name of the stylesheet.
|
||||
*/
|
||||
protected function get_inline_dependency() {
|
||||
return 'elementor-frontend';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file handle ID.
|
||||
*
|
||||
* Retrieve the handle ID for the post CSS file.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
*
|
||||
* @return string CSS file handle ID.
|
||||
*/
|
||||
protected function get_file_handle_id() {
|
||||
return 'elementor-post-' . $this->post_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render styles.
|
||||
*
|
||||
* Parse the CSS for any given element.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access protected
|
||||
*
|
||||
* @param Element_Base $element The element.
|
||||
*/
|
||||
protected function render_styles( Element_Base $element ) {
|
||||
/**
|
||||
* Before element parse CSS.
|
||||
*
|
||||
* Fires before the CSS of the element is parsed.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*
|
||||
* @param Post $this The post CSS file.
|
||||
* @param Element_Base $element The element.
|
||||
*/
|
||||
do_action( 'elementor/element/before_parse_css', $this, $element );
|
||||
|
||||
$element_settings = $element->get_settings();
|
||||
|
||||
$this->add_controls_stack_style_rules( $element, $this->get_style_controls( $element, null, $element->get_parsed_dynamic_settings() ), $element_settings, [ '{{ID}}', '{{WRAPPER}}' ], [ $element->get_id(), $this->get_element_unique_selector( $element ) ] );
|
||||
|
||||
/**
|
||||
* After element parse CSS.
|
||||
*
|
||||
* Fires after the CSS of the element is parsed.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*
|
||||
* @param Post $this The post CSS file.
|
||||
* @param Element_Base $element The element.
|
||||
*/
|
||||
do_action( 'elementor/element/parse_css', $this, $element );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
namespace Elementor\Core\Files;
|
||||
|
||||
use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
|
||||
use Elementor\Core\Files\Assets\Files_Upload_Handler;
|
||||
use Elementor\Core\Files\Assets\Json\Json_Handler;
|
||||
use Elementor\Core\Files\Assets\Svg\Svg_Handler;
|
||||
use Elementor\Core\Files\CSS\Global_CSS;
|
||||
use Elementor\Core\Files\CSS\Post as Post_CSS;
|
||||
use Elementor\Core\Responsive\Files\Frontend;
|
||||
use Elementor\Utils;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor files manager.
|
||||
*
|
||||
* Elementor files manager handler class is responsible for creating files.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
class Manager {
|
||||
|
||||
private $files = [];
|
||||
|
||||
/**
|
||||
* Files manager constructor.
|
||||
*
|
||||
* Initializing the Elementor files manager.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access public
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->register_actions();
|
||||
|
||||
new Svg_Handler();
|
||||
new Json_Handler();
|
||||
}
|
||||
|
||||
public function get( $class, $args ) {
|
||||
$id = $class . '-' . wp_json_encode( $args );
|
||||
|
||||
if ( ! isset( $this->files[ $id ] ) ) {
|
||||
// Create an instance from dynamic args length.
|
||||
$reflection_class = new \ReflectionClass( $class );
|
||||
$this->files[ $id ] = $reflection_class->newInstanceArgs( $args );
|
||||
}
|
||||
|
||||
return $this->files[ $id ];
|
||||
}
|
||||
|
||||
/**
|
||||
* On post delete.
|
||||
*
|
||||
* Delete post CSS immediately after a post is deleted from the database.
|
||||
*
|
||||
* Fired by `deleted_post` action.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $post_id Post ID.
|
||||
*/
|
||||
public function on_delete_post( $post_id ) {
|
||||
if ( ! Utils::is_post_support( $post_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$css_file = Post_CSS::create( $post_id );
|
||||
|
||||
$css_file->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* On export post meta.
|
||||
*
|
||||
* When exporting data using WXR, skip post CSS file meta key. This way the
|
||||
* export won't contain the post CSS file data used by Elementor.
|
||||
*
|
||||
* Fired by `wxr_export_skip_postmeta` filter.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access public
|
||||
*
|
||||
* @param bool $skip Whether to skip the current post meta.
|
||||
* @param string $meta_key Current meta key.
|
||||
*
|
||||
* @return bool Whether to skip the post CSS meta.
|
||||
*/
|
||||
public function on_export_post_meta( $skip, $meta_key ) {
|
||||
if ( Post_CSS::META_KEY === $meta_key ) {
|
||||
$skip = true;
|
||||
}
|
||||
|
||||
return $skip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear cache.
|
||||
*
|
||||
* Delete all meta containing files data. And delete the actual
|
||||
* files from the upload directory.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access public
|
||||
*/
|
||||
public function clear_cache() {
|
||||
delete_post_meta_by_key( Post_CSS::META_KEY );
|
||||
|
||||
delete_option( Global_CSS::META_KEY );
|
||||
|
||||
delete_option( Frontend::META_KEY );
|
||||
|
||||
// Delete files.
|
||||
$path = Base::get_base_uploads_dir() . Base::DEFAULT_FILES_DIR . '*';
|
||||
|
||||
foreach ( glob( $path ) as $file_path ) {
|
||||
unlink( $file_path );
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor clear files.
|
||||
*
|
||||
* Fires after Elementor clears files
|
||||
*
|
||||
* @since 2.1.0
|
||||
*/
|
||||
do_action( 'elementor/core/files/clear_cache' );
|
||||
}
|
||||
|
||||
public function register_ajax_actions( Ajax $ajax ) {
|
||||
$ajax->register_ajax_action( 'enable_unfiltered_files_upload', [ $this, 'ajax_unfiltered_files_upload' ] );
|
||||
}
|
||||
|
||||
public function ajax_unfiltered_files_upload() {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
update_option( Files_Upload_Handler::OPTION_KEY, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register actions.
|
||||
*
|
||||
* Register filters and actions for the files manager.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @access private
|
||||
*/
|
||||
private function register_actions() {
|
||||
add_action( 'deleted_post', [ $this, 'on_delete_post' ] );
|
||||
|
||||
// Ajax.
|
||||
add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_actions' ] );
|
||||
|
||||
add_filter( 'wxr_export_skip_postmeta', [ $this, 'on_export_post_meta' ], 10, 2 );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user