????

Your IP : 216.73.216.112


Current Path : /proc/self/root/home/carpe/www/space/lbrm3v/
Upload File :
Current File : //proc/self/root/home/carpe/www/space/lbrm3v/files.tar

frontend.php000064400000011550151221634660007104 0ustar00<?php

namespace Elementor\Core\Responsive\Files;

use Elementor\Core\Breakpoints\Breakpoint;
use Elementor\Core\Files\Base;
use Elementor\Core\Responsive\Responsive;
use Elementor\Plugin;
use Elementor\Utils;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}

class Frontend extends Base {

	const META_KEY = 'elementor-custom-breakpoints-files';

	private $template_file;

	/**
	 * @since 2.1.0
	 * @access public
	 */
	public function __construct( $file_name, $template_file = null ) {
		$this->template_file = $template_file;

		parent::__construct( $file_name );
	}

	/**
	 * @since 2.1.0
	 * @access public
	 */
	public function parse_content() {
		$breakpoints = Plugin::$instance->breakpoints->get_active_breakpoints();

		$breakpoints_keys = array_keys( $breakpoints );

		$file_content = Utils::file_get_contents( $this->template_file );

		// The regex pattern parses placeholders located in the frontend _templates.scss file.
		$file_content = preg_replace_callback( '/ELEMENTOR_SCREEN_([A-Z_]+)(?:_(MIN|MAX|NEXT))/', function ( $placeholder_data ) use ( $breakpoints_keys, $breakpoints ) {
			// Handle BC for legacy template files and Elementor Pro builds.
			$placeholder_data = $this->maybe_convert_placeholder_data( $placeholder_data );

			$breakpoint_index = array_search( strtolower( $placeholder_data[1] ), $breakpoints_keys, true );

			if ( 'DESKTOP' === $placeholder_data[1] ) {
				if ( 'MIN' === $placeholder_data[2] ) {
					$value = Plugin::$instance->breakpoints->get_desktop_min_point();
				} elseif ( isset( $breakpoints['widescreen'] ) ) {
					// If the 'widescreen' breakpoint is active, the Desktop's max value is the Widescreen breakpoint - 1px.
					$value = $breakpoints['widescreen']->get_value() - 1;
				} else {
					// If the 'widescreen' breakpoint is not active, the Desktop device should not have a max value.
					$value = 99999;
				}
			} elseif ( false === $breakpoint_index ) {
				// If the breakpoint in the placeholder is not active - use a -1 value for the media query, to make
				// sure the setting is printed (to avoid a PHP error) but doesn't apply.
				return -1;
			} elseif ( 'WIDESCREEN' === $placeholder_data[1] ) {
				$value = $breakpoints['widescreen']->get_value();
			} else {
				$breakpoint_index = array_search( strtolower( $placeholder_data[1] ), $breakpoints_keys, true );

				$is_max_point = 'MAX' === $placeholder_data[2];

				// If the placeholder capture is `MOBILE_NEXT` or `TABLET_NEXT`, the original breakpoint value is used.
				if ( ! $is_max_point && 'NEXT' !== $placeholder_data[2] ) {
					$breakpoint_index--;
				}

				$value = $breakpoints[ $breakpoints_keys[ $breakpoint_index ] ]->get_value();

				if ( ! $is_max_point ) {
					$value++;
				}
			}

			return $value . 'px';
		}, $file_content );

		return $file_content;
	}

	/**
	 * Load meta.
	 *
	 * Retrieve the file meta data.
	 *
	 * @since 2.1.0
	 * @access protected
	 */
	protected function load_meta() {
		$option = $this->load_meta_option();

		$file_meta_key = $this->get_file_meta_key();

		if ( empty( $option[ $file_meta_key ] ) ) {
			return [];
		}

		return $option[ $file_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 ) {
		$option = $this->load_meta_option();

		$option[ $this->get_file_meta_key() ] = $meta;

		update_option( static::META_KEY, $option );
	}

	/**
	 * Delete meta.
	 *
	 * Delete the file meta data.
	 *
	 * @since 2.1.0
	 * @access protected
	 */
	protected function delete_meta() {
		$option = $this->load_meta_option();

		$file_meta_key = $this->get_file_meta_key();

		if ( isset( $option[ $file_meta_key ] ) ) {
			unset( $option[ $file_meta_key ] );
		}

		if ( $option ) {
			update_option( static::META_KEY, $option );
		} else {
			delete_option( static::META_KEY );
		}
	}

	/**
	 * @since 2.1.0
	 * @access private
	 */
	private function get_file_meta_key() {
		return pathinfo( $this->get_file_name(), PATHINFO_FILENAME );
	}

	/**
	 * @since 2.1.0
	 * @access private
	 */
	private function load_meta_option() {
		$option = get_option( static::META_KEY );

		if ( ! $option ) {
			$option = [];
		}

		return $option;
	}

	/**
	 * Maybe Convert Placeholder Data
	 *
	 * Converts responsive placeholders in Elementor CSS template files from the legacy format into the new format.
	 * Used for backwards compatibility for old Pro versions that were built with an Elementor Core version <3.2.0.
	 *
	 * @since 3.2.3
	 *
	 * @param $placeholder_data
	 * @return mixed
	 */
	private function maybe_convert_placeholder_data( $placeholder_data ) {
		switch ( $placeholder_data[1] ) {
			case 'SM':
				$placeholder_data[1] = 'MOBILE';
				break;
			case 'MD':
				$placeholder_data[1] = 'TABLET';
				break;
			case 'LG':
				$placeholder_data[1] = 'DESKTOP';
		}

		return $placeholder_data;
	}
}
file-types/json.php000064400000001040151223464240010305 0ustar00<?php
namespace Elementor\Core\Files\File_Types;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

class Json extends Base {

	/**
	 * Get File Extension
	 *
	 * Returns the file type's file extension
	 *
	 * @since 3.3.0
	 *
	 * @return string - file extension
	 */
	public function get_file_extension() {
		return 'json';
	}

	/**
	 * Get Mime Type
	 *
	 * Returns the file type's mime type
	 *
	 * @since 3.5.0
	 *
	 * @return string mime type
	 */
	public function get_mime_type() {
		return 'application/json';
	}
}
file-types/svg.php000064400000013230151223464240010137 0ustar00<?php
namespace Elementor\Core\Files\File_Types;

use Elementor\Core\Utils\Exceptions;
use Elementor\Core\Utils\Svg\Svg_Sanitizer;
use Elementor\Utils;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

class Svg extends Base {

	/**
	 * Inline svg attachment meta key
	 */
	const META_KEY = '_elementor_inline_svg';

	const SCRIPT_REGEX = '/(?:\w+script|data):/xi';

	/**
	 * Get File Extension
	 *
	 * Returns the file type's file extension
	 *
	 * @since 3.5.0
	 * @access public
	 *
	 * @return string - file extension
	 */
	public function get_file_extension() {
		return 'svg';
	}

	/**
	 * Get Mime Type
	 *
	 * Returns the file type's mime type
	 *
	 * @since 3.5.0
	 * @access public
	 *
	 * @return string mime type
	 */
	public function get_mime_type() {
		return 'image/svg+xml';
	}

	/**
	 * Sanitize SVG
	 *
	 * @since 3.5.0
	 * @access public
	 *
	 * @param $filename
	 * @return bool
	 */
	public function sanitize_svg( $filename ) {
		return ( new SVG_Sanitizer() )->sanitize_file( $filename );
	}

	/**
	 * Validate File
	 *
	 * @since 3.3.0
	 * @access public
	 *
	 * @param $file
	 * @return bool|\WP_Error
	 */
	public function validate_file( $file ) {
		if ( ! $this->sanitize_svg( $file['tmp_name'] ) ) {
			return new \WP_Error( Exceptions::FORBIDDEN, esc_html__( 'This file is not allowed for security reasons.', 'elementor' ) );
		}

		return true;
	}

	/**
	 * Sanitizer
	 *
	 * @since 3.5.0
	 * @access public
	 *
	 * @param $content
	 * @return bool|string
	 */
	public function sanitizer( $content ) {
		return ( new SVG_Sanitizer() )->sanitize( $content );
	}

	/**
	 * WP Prepare Attachment For J
	 *
	 * Runs on the `wp_prepare_attachment_for_js` filter.
	 *
	 * @since 3.5.0
	 * @access public
	 *
	 * @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 Svg Meta Data
	 *
	 * Adds dimensions metadata to uploaded SVG files, since WordPress doesn't do it.
	 *
	 * @since 3.5.0
	 * @access public
	 *
	 * @return mixed
	 */
	public function set_svg_meta_data( $data, $id ) {
		$attachment = get_post( $id ); // Filter makes sure that the post is an attachment.
		$mime_type = $attachment->post_mime_type;

		// If the attachment is an svg
		if ( 'image/svg+xml' === $mime_type ) {
			// If the svg metadata are empty or the width is empty or the height is empty.
			// then get the attributes from xml.
			if ( empty( $data ) || empty( $data['width'] ) || empty( $data['height'] ) ) {
				$attachment = wp_get_attachment_url( $id );
				$xml = simplexml_load_file( $attachment );

				if ( ! empty( $xml ) ) {
					$attr = $xml->attributes();
					$view_box = explode( ' ', $attr->viewBox );// phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
					$data['width'] = isset( $attr->width ) && preg_match( '/\d+/', $attr->width, $value ) ? (int) $value[0] : ( 4 === count( $view_box ) ? (int) $view_box[2] : null );
					$data['height'] = isset( $attr->height ) && preg_match( '/\d+/', $attr->height, $value ) ? (int) $value[0] : ( 4 === count( $view_box ) ? (int) $view_box[3] : null );
				}
			}
		}

		return $data;
	}

	/**
	 * Delete Meta Cache
	 *
	 * Deletes the Inline SVG post meta entry.
	 *
	 * @since 3.5.0
	 * @access public
	 */
	public function delete_meta_cache() {
		delete_post_meta_by_key( self::META_KEY );
	}

	/**
	 * File Sanitizer Can Run
	 *
	 * Checks if the classes required for the file sanitizer are in memory.
	 *
	 * @since 3.5.0
	 * @access public
	 * @static
	 *
	 * @return bool
	 */
	public static function file_sanitizer_can_run() {
		return class_exists( 'DOMDocument' ) && class_exists( 'SimpleXMLElement' );
	}

	/**
	 * Get Inline SVG
	 *
	 * @since 3.5.0
	 * @access public
	 * @static
	 *
	 * @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 ) ) {
			$valid_svg = ( new SVG_Sanitizer() )->sanitize( $svg );

			return ( false === $valid_svg ) ? '' : $valid_svg;
		}

		$attachment_file = get_attached_file( $attachment_id );

		if ( ! file_exists( $attachment_file ) ) {
			return '';
		}

		$svg = Utils::file_get_contents( $attachment_file );

		$valid_svg = ( new SVG_Sanitizer() )->sanitize( $svg );

		if ( false === $valid_svg ) {
			return '';
		}

		if ( ! empty( $valid_svg ) ) {
			update_post_meta( $attachment_id, self::META_KEY, $valid_svg );
		}

		return $valid_svg;
	}

	public function __construct() {
		add_filter( 'wp_update_attachment_metadata', [ $this, 'set_svg_meta_data' ], 10, 2 );
		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' ] );
	}
}
file-types/zip.php000064400000011142151223464240010142 0ustar00<?php
namespace Elementor\Core\Files\File_Types;

use Elementor\Core\Base\Document;
use Elementor\Core\Utils\Exceptions;
use Elementor\Plugin;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Elementor File Types Base.
 *
 * The File Types Base class provides base methods used by all file type handler classes.
 * These methods are used in file upl
 *
 * @since 3.3.0
 */
class Zip extends Base {

	/**
	 * Get File Extension
	 *
	 * Returns the file type's file extension
	 *
	 * @since 3.3.0
	 *
	 * @return string - file extension
	 */
	public function get_file_extension() {
		return 'zip';
	}

	/**
	 * Get Mime Type
	 *
	 * Returns the file type's mime type
	 *
	 * @since 3.5.0
	 *
	 * @return string mime type
	 */
	public function get_mime_type() {
		return 'application/zip';
	}

	/**
	 * Get File Property Name
	 *
	 * Get the property name to look for in the $_FILES superglobal
	 *
	 * @since 3.3.0
	 *
	 * @return string
	 */
	public function get_file_property_name() {
		return 'zip_upload';
	}

	/**
	 * Extract
	 *
	 * Performs the extraction of the zip files to a temporary directory.
	 * Returns an error if for some reason the ZipArchive utility isn't available.
	 * Otherwise, Returns an array containing the temporary extraction directory, and the list of extracted files.
	 *
	 * @since 3.3.0
	 *
	 * @param string $file_path
	 * @param array|null $allowed_file_types
	 * @return array|\WP_Error
	 */
	public function extract( $file_path, $allowed_file_types ) {
		if ( ! class_exists( '\ZipArchive' ) ) {
			return new \WP_Error( 'zip_error', 'PHP Zip extension not loaded' );
		}

		$zip = new \ZipArchive();

		/**
		 * Zip Extraction Directory
		 *
		 * Filters the extraction directory for uploaded zip files.
		 *
		 * @since 3.6.0
		 *
		 * @param string $extraction_directory A temporary upload directory generated by Elementor's Uploads Manager
		 */
		$extraction_directory = apply_filters( 'elementor/files/zip/extraction-directory', '' );

		if ( ! $extraction_directory ) {
			$extraction_directory = Plugin::$instance->uploads_manager->create_unique_dir();
		}

		$zip->open( $file_path );

		// if an array of allowed file types is provided, get the filtered file list to extract.
		$allowed_files = $allowed_file_types ? $this->get_allowed_files( $zip, $allowed_file_types ) : null;

		$zip->extractTo( $extraction_directory, $allowed_files );

		$zip->close();

		return [
			'extraction_directory' => $extraction_directory,
			'files' => $this->find_temp_files( $extraction_directory ),
		];
	}

	/**
	 * Get Allowed Files
	 *
	 * Accepts a zipArchive instance and an array of allowed file types. Iterates over the zip archive's files and
	 * checks if their extensions are in the list of allowed file types. Returns an array containing all valid files.
	 *
	 * @since 3.3.0
	 *
	 * @param \ZipArchive $zip
	 * @param array $allowed_file_types
	 * @return array
	 */
	private function get_allowed_files( $zip, $allowed_file_types ) {
		$allowed_files = [];

		// phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
		for ( $i = 0; $i < $zip->numFiles; $i++ ) {
			$filename = $zip->getNameIndex( $i );
			$extension = pathinfo( $filename, PATHINFO_EXTENSION );

			// Skip files with transversal paths.
			if ( strpos( $filename, '..' ) !== false ) {
				continue;
			}

			if ( in_array( $extension, $allowed_file_types, true ) ) {
				$allowed_files[] = $filename;
			}
		}

		return $allowed_files;
	}

	/**
	 * Find temporary files.
	 *
	 * Recursively finds a list of temporary files from the extracted zip file.
	 *
	 * Example return data:
	 *
	 * [
	 *  0 => '/www/wp-content/uploads/elementor/tmp/5eb3a7a411d44/templates/block-2-col-marble-title.json',
	 *  1 => '/www/wp-content/uploads/elementor/tmp/5eb3a7a411d44/templates/block-2-col-text-and-photo.json',
	 * ]
	 *
	 * @since 2.9.8
	 * @access private
	 *
	 * @param string $temp_path - The temporary file path to scan for template files
	 *
	 * @return array An array of temporary files on the filesystem
	 */
	private function find_temp_files( $temp_path ) {
		$file_names = [];

		$possible_file_names = array_diff( scandir( $temp_path ), [ '.', '..' ] );

		// Find nested files in the unzipped path. This happens for example when the user imports a Website Kit.
		foreach ( $possible_file_names as $possible_file_name ) {
			$full_possible_file_name = $temp_path . $possible_file_name;
			if ( is_dir( $full_possible_file_name ) ) {
				$file_names = array_merge( $file_names, $this->find_temp_files( $full_possible_file_name . '/' ) );
			} else {
				$file_names[] = $full_possible_file_name;
			}
		}

		return $file_names;
	}
}
file-types/base.php000064400000002503151223464240010253 0ustar00<?php
namespace Elementor\Core\Files\File_Types;

use Elementor\Core\Base\Base_Object;
use Elementor\Core\Utils\Exceptions;
use Elementor\Plugin;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Elementor File Types Base.
 *
 * The File Types Base class provides base methods used by all file type handler classes.
 * These methods are used in file upl
 *
 * @since 3.3.0
 */
abstract class Base extends Base_Object {

	/**
	 * Get File Extension
	 *
	 * Returns the file type's file extension
	 *
	 * @since 3.3.0
	 *
	 * @return string - file extension
	 */
	abstract public function get_file_extension();

	/**
	 * Get Mime Type
	 *
	 * Returns the file type's mime type
	 *
	 * @since 3.5.0
	 *
	 * @return string - file extension
	 */
	abstract public function get_mime_type();

	/**
	 * Validate File
	 *
	 * This method give file types the chance to run file-type-specific validations before returning the file for upload.
	 *
	 * @since 3.3.0
	 *
	 * @param $file
	 * @return bool|\WP_Error
	 */
	public function validate_file( $file ) {
		return true;
	}

	/**
	 * Is Upload Allowed
	 *
	 * This method returns whether the file type is allowed to be uploaded, even if unfiltered uploads are disabled.
	 *
	 * @since 3.3.0
	 *
	 * @return bool
	 */
	public function is_upload_allowed() {
		return true;
	}
}
uploads-manager.php000064400000044242151223464240010345 0ustar00<?php
namespace Elementor\Core\Files;

use Elementor\Core\Base\Base_Object;
use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
use Elementor\Core\Files\File_Types\Base as File_Type_Base;
use Elementor\Core\Files\File_Types\Json;
use Elementor\Core\Files\File_Types\Svg;
use Elementor\Core\Files\File_Types\Zip;
use Elementor\Core\Utils\Exceptions;
use Elementor\User;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Elementor uploads manager.
 *
 * Elementor uploads manager handler class is responsible for handling file uploads that are not done with WP Media.
 *
 * @since 3.3.0
 */
class Uploads_Manager extends Base_Object {

	const UNFILTERED_FILE_UPLOADS_KEY = 'elementor_unfiltered_files_upload';
	const INVALID_FILE_CONTENT = 'Invalid Content In File';

	/**
	 * @var File_Type_Base[]
	 */
	private $file_type_handlers = [];

	private $allowed_file_extensions;

	/**
	 * @var bool
	 */
	private $is_elementor_upload = false;

	/**
	 * @var string
	 */
	private $temp_dir;

	/**
	 * Register File Types
	 *
	 * To Add a new file type to Elementor, with its own handling logic, you need to add it to the $file_types array here.
	 *
	 * @since 3.3.0
	 * @access public
	 */
	public function register_file_types() {
		// All file types that have handlers should be included here.
		$file_types = [
			'json' => new Json(),
			'zip' => new Zip(),
			'svg' => new Svg(),
		];

		foreach ( $file_types as $file_type => $file_handler ) {
			$this->file_type_handlers[ $file_type ] = $file_handler;
		}
	}

	/**
	 * Extract and Validate Zip
	 *
	 * This method accepts a $file array (which minimally should include a 'tmp_name')
	 *
	 * @since 3.3.0
	 * @access public
	 *
	 * @param string $file_path
	 * @param array $allowed_file_types
	 * @return array|\WP_Error
	 */
	public function extract_and_validate_zip( $file_path, $allowed_file_types = null ) {
		$result = [];

		/** @var Zip $zip_handler - File Type */
		$zip_handler = $this->file_type_handlers['zip'];

		// Returns an array of file paths.
		$extracted = $zip_handler->extract( $file_path, $allowed_file_types );

		if ( is_wp_error( $extracted ) ) {
			return $extracted;
		}

		// If there are no extracted file names, no files passed the extraction validation.
		if ( empty( $extracted['files'] ) ) {
			// TODO: Decide what to do if no files passed the extraction validation
			return new \WP_Error( 'file_error', self::INVALID_FILE_CONTENT );
		}

		$result['extraction_directory'] = $extracted['extraction_directory'];

		foreach ( $extracted['files'] as $extracted_file_path ) {
			// Each file is an array with a 'name' (file path) property.
			if ( ! is_wp_error( $this->validate_file( [ 'tmp_name' => $extracted_file_path ] ) ) ) {
				$result['files'][] = $extracted_file_path;
			}
		}

		return $result;
	}

	/**
	 * Handle Elementor Upload
	 *
	 * This method receives a $file array. If the received file is a Base64 string, the $file array should include a
	 * 'fileData' property containing the string, which is decoded and has its contents stored in a temporary file.
	 * If the $file parameter passed is a standard $file array, the 'name' and 'tmp_name' properties are used for
	 * validation.
	 *
	 * The file goes through validation; if it passes validation, the file is returned. Otherwise, an error is returned.
	 *
	 * @since 3.3.0
	 * @access public
	 *
	 * @param array $data
	 * @param array $allowed_file_extensions Optional. an array of file types that are allowed to pass validation for each
	 * upload.
	 * @return array|\WP_Error
	 */
	public function handle_elementor_upload( array $data, $allowed_file_extensions = null ) {
		// If $file['fileData'] is set, it signals that the passed file is a Base64 string that needs to be decoded and
		// saved to a temporary file.
		if ( isset( $data['fileData'] ) ) {
			$data = $this->save_base64_to_tmp_file( $data, $allowed_file_extensions );
		}

		if ( is_wp_error( $data ) ) {
			return $data;
		}

		$validation_result = $this->validate_file( $data, $allowed_file_extensions );

		if ( is_wp_error( $validation_result ) ) {
			return $validation_result;
		}

		return $data;
	}

	/**
	 * are Unfiltered Uploads Enabled
	 *
	 * @since 3.5.0
	 * @access public
	 *
	 * @return bool
	 */
	final public static function are_unfiltered_uploads_enabled() {
		$enabled = ! ! get_option( self::UNFILTERED_FILE_UPLOADS_KEY )
			&& Svg::file_sanitizer_can_run()
			&& User::is_current_user_can_upload_json();

		/**
		 * Allow Unfiltered Files Upload.
		 *
		 * Determines whether to enable unfiltered file uploads.
		 *
		 * @since 3.0.0
		 *
		 * @param bool $enabled Whether upload is enabled or not.
		 */
		$enabled = apply_filters( 'elementor/files/allow_unfiltered_upload', $enabled );

		return $enabled;
	}

	/**
	 * Handle Elementor WP Media Upload
	 *
	 * Runs on the 'wp_handle_upload_prefilter' filter.
	 *
	 * @since 3.2.0
	 * @access public
	 *
	 * @param $file
	 * @return mixed
	 */
	public function handle_elementor_wp_media_upload( $file ) {
		// If it isn't a file uploaded by Elementor, we do not intervene.
		if ( ! $this->is_elementor_wp_media_upload() ) {
			return $file;
		}

		$result = $this->validate_file( $file );

		if ( is_wp_error( $result ) ) {
			$file['error'] = $result->get_error_message();
		}

		return $file;
	}

	/**
	 * Get File Type Handler
	 *
	 * Initialize the proper file type handler according to the file extension
	 * and assign it to the file type handlers array.
	 *
	 * @since 3.3.0
	 * @access public
	 *
	 * @param string|null $file_extension - file extension
	 * @return File_Type_Base[]|File_Type_Base
	 */
	public function get_file_type_handlers( $file_extension = null ) {
		return self::get_items( $this->file_type_handlers, $file_extension );
	}

	/**
	 * 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
	 *
	 * @since 3.5.0
	 * @access public
	 *
	 * @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_handlers = $this->get_file_type_handlers();

		if ( isset( $file_type_handlers[ $wp_file_type['ext'] ] ) ) {
			$file_type_handler = $file_type_handlers[ $wp_file_type['ext'] ];

			$data['ext'] = $file_type_handler->get_file_extension();
			$data['type'] = $file_type_handler->get_mime_type();
		}

		return $data;
	}

	/**
	 * Remove File Or Directory
	 *
	 * Directory is deleted recursively with all of its contents (subdirectories and files).
	 *
	 * @since 3.3.0
	 * @access public
	 *
	 * @param string $path
	 */
	public function remove_file_or_dir( $path ) {
		if ( is_dir( $path ) ) {
			$this->remove_directory_with_files( $path );
		} elseif ( is_file( $path ) ) {
			unlink( $path );
		}
	}

	/**
	 * Create Temp File
	 *
	 * Create a random temporary file.
	 *
	 * @since 3.3.0
	 * @access public
	 *
	 * @param string $file_content
	 * @param string $file_name
	 * @return string|\WP_Error
	 */
	public function create_temp_file( $file_content, $file_name ) {
		$file_name = str_replace( ' ', '', sanitize_file_name( $file_name ) );

		if ( empty( $file_name ) ) {
			return new \WP_Error( 'invalid_file_name', esc_html__( 'Invalid file name.', 'elementor' ) );
		}

		$temp_filename = $this->create_unique_dir() . $file_name;

		/**
		 * Temp File Path
		 *
		 * Allows modifying the full path of the temporary file.
		 *
		 * @since 3.7.0
		 *
		 * @param string full path to file
		 */
		$temp_filename = apply_filters( 'elementor/files/temp-file-path', $temp_filename );

		file_put_contents( $temp_filename, $file_content ); // phpcs:ignore

		return $temp_filename;
	}

	/**
	 * Get Temp Directory
	 *
	 * Get the temporary files directory path. If the directory does not exist, this method creates it.
	 *
	 * @since 3.3.0
	 * @access public
	 *
	 * @return string $temp_dir
	 */
	public function get_temp_dir() {
		if ( ! $this->temp_dir ) {
			$wp_upload_dir = wp_upload_dir();

			$temp_dir = implode( DIRECTORY_SEPARATOR, [ $wp_upload_dir['basedir'], 'elementor', 'tmp' ] ) . DIRECTORY_SEPARATOR;

			/**
			 * Temp File Path
			 *
			 * Allows modifying the full path of the temporary file.
			 *
			 * @since 3.7.0
			 *
			 * @param string temporary directory
			 */
			$this->temp_dir = apply_filters( 'elementor/files/temp-dir', $temp_dir );

			if ( ! is_dir( $this->temp_dir ) ) {
				wp_mkdir_p( $this->temp_dir );
			}
		}

		return $this->temp_dir;
	}

	/**
	 * Create Unique Temp Dir
	 *
	 * Create a unique temporary directory
	 *
	 * @since 3.3.0
	 * @access public
	 *
	 * @return string the new directory path
	 */
	public function create_unique_dir() {
		$unique_dir_path = $this->get_temp_dir() . uniqid() . DIRECTORY_SEPARATOR;

		wp_mkdir_p( $unique_dir_path );

		return $unique_dir_path;
	}

	/**
	 * Register Ajax Actions
	 *
	 * Runs on the 'elementor/ajax/register_actions' hook. Receives the AJAX module as a parameter and registers
	 * callbacks for specified action IDs.
	 *
	 * @since 3.5.0
	 * @access public
	 *
	 * @param Ajax $ajax
	 */
	public function register_ajax_actions( Ajax $ajax ) {
		$ajax->register_ajax_action( 'enable_unfiltered_files_upload', [ $this, 'enable_unfiltered_files_upload' ] );
	}

	/**
	 * Set Unfiltered Files Upload
	 *
	 * @since 3.5.0
	 * @access public
	 */
	public function enable_unfiltered_files_upload() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		update_option( self::UNFILTERED_FILE_UPLOADS_KEY, 1 );
	}

	/**
	 * Support Unfiltered File Uploads
	 *
	 * When uploading a file within Elementor, this method adds the registered
	 * file types to WordPress' allowed mimes list. This will only happen if the user allowed unfiltered file uploads
	 * in Elementor's settings in the admin dashboard.
	 *
	 * @since 3.5.0
	 * @access public
	 *
	 * @param array $allowed_mimes
	 * @return array allowed mime types
	 */
	final public function support_unfiltered_elementor_file_uploads( $allowed_mimes ) {
		if ( $this->is_elementor_upload() && $this->are_unfiltered_uploads_enabled() ) {
			foreach ( $this->file_type_handlers as $file_type_handler ) {
				$allowed_mimes[ $file_type_handler->get_file_extension() ] = $file_type_handler->get_mime_type();
			}
		}

		return $allowed_mimes;
	}

	/**
	 * Set Elementor Upload State
	 *
	 * @since 3.5.0
	 * @access public
	 *
	 * @param $state
	 */
	public function set_elementor_upload_state( $state ) {
		$this->is_elementor_upload = $state;
	}

	/**
	 * Is Elementor Upload
	 *
	 * This method checks if the current session includes a request to upload files made via Elementor.
	 *
	 * @since 3.5.0
	 * @access private
	 *
	 * @return bool
	 */
	private function is_elementor_upload() {
		return $this->is_elementor_upload || $this->is_elementor_media_upload() || $this->is_elementor_wp_media_upload();
	}

	/**
	 * Is Elementor Media Upload
	 *
	 * Checks whether the current request includes uploading files via Elementor which are not destined for the Media
	 * Library.
	 *
	 * @since 3.5.0
	 * @access public
	 *
	 * @return bool
	 */
	public function is_elementor_media_upload() {
		// Sometimes `uploadTypeCaller` passed as a GET parameter when using the WP Media Library REST API, where the
		// whole request body is occupied by the uploaded file.
		return isset( $_REQUEST['uploadTypeCaller'] ) && 'elementor-media-upload' === $_REQUEST['uploadTypeCaller']; // phpcs:ignore
	}

	/**
	 * Is Elementor WP Media Upload
	 *
	 * Checks whether the current request is a request to upload files into the WP Media Library via Elementor.
	 *
	 * @since 3.3.0
	 * @access private
	 *
	 * @return bool
	 */
	private function is_elementor_wp_media_upload() {
		return isset( $_REQUEST['uploadTypeCaller'] ) && 'elementor-wp-media-upload' === $_REQUEST['uploadTypeCaller']; // phpcs:ignore
	}

	/**
	 * Add File Extension To Allowed Extensions List
	 *
	 * @since 3.3.0
	 * @access private
	 *
	 * @param string $file_type
	 */
	private function add_file_extension_to_allowed_extensions_list( $file_type ) {
		$file_handler = $this->file_type_handlers[ $file_type ];

		$file_extension = $file_handler->get_file_extension();

		// Only add the file extension to the list if it doesn't already exist in it.
		if ( ! in_array( $file_extension, $this->allowed_file_extensions, true ) ) {
			$this->allowed_file_extensions[] = $file_extension;
		}
	}

	/**
	 * Save Base64 as File
	 *
	 * Saves a Base64 string as a .tmp file in Elementor's temporary files directory.
	 *
	 * @since 3.3.0
	 * @access private
	 *
	 * @param $file
	 * @param array|null $allowed_file_extensions
	 *
	 * @return array|\WP_Error
	 */
	private function save_base64_to_tmp_file( $file, $allowed_file_extensions = null ) {
		if ( empty( $file['fileName'] ) || empty( $file['fileData'] ) ) {
			return new \WP_Error( 'file_error', self::INVALID_FILE_CONTENT );
		}

		$file_extension = pathinfo( $file['fileName'], PATHINFO_EXTENSION );
		$is_file_type_allowed = $this->is_file_type_allowed( $file_extension, $allowed_file_extensions );

		if ( is_wp_error( $is_file_type_allowed ) ) {
			return $is_file_type_allowed;
		}

		$file_content = base64_decode( $file['fileData'] ); // phpcs:ignore

		// If the decode fails
		if ( ! $file_content ) {
			return new \WP_Error( 'file_error', self::INVALID_FILE_CONTENT );
		}

		$temp_filename = $this->create_temp_file( $file_content, $file['fileName'] );

		if ( is_wp_error( $temp_filename ) ) {
			return $temp_filename;
		}

		return [
			// the original uploaded file name
			'name' => $file['fileName'],
			// The path to the temporary file
			'tmp_name' => $temp_filename,
		];
	}

	/**
	 * Validate File
	 *
	 * @since 3.3.0
	 * @access private
	 *
	 * @param array $file
	 * @param array $file_extensions Optional
	 * @return bool|\WP_Error
	 */
	private function validate_file( array $file, $file_extensions = [] ) {
		$uploaded_file_name = isset( $file['name'] ) ? $file['name'] : $file['tmp_name'];

		$file_extension = pathinfo( $uploaded_file_name, PATHINFO_EXTENSION );

		if ( ! $this->is_elementor_wp_media_upload() ) {
			$is_file_type_allowed = $this->is_file_type_allowed( $file_extension, $file_extensions );

			if ( is_wp_error( $is_file_type_allowed ) ) {
				return $is_file_type_allowed;
			}
		}

		$file_type_handler = $this->get_file_type_handlers( $file_extension );

		// If Elementor does not have a handler for this file type, don't block it.
		if ( ! $file_type_handler ) {
			return true;
		}

		// If there is a File Type Handler for the uploaded file, it means it is a non-standard file type. In this case,
		// we check if unfiltered file uploads are enabled or not before allowing it.
		if ( ! self::are_unfiltered_uploads_enabled() ) {
			$error = 'json' === $file_extension
				? esc_html__( 'You do not have permission to upload JSON files.', 'elementor' )
				: esc_html__( 'This file is not allowed for security reasons.', 'elementor' );
			return new \WP_Error( Exceptions::FORBIDDEN, $error );
		}

		// Here is each file type handler's chance to run its own specific validations
		return $file_type_handler->validate_file( $file );
	}

	/**
	 * Is File Type Allowed
	 *
	 * Checks whether the passed file extension is allowed for upload.
	 *
	 * @since 3.5.0
	 * @access private
	 *
	 * @param $file_extension
	 * @param $filtered_file_extensions
	 * @return bool|\WP_Error
	 */
	private function is_file_type_allowed( $file_extension, $filtered_file_extensions ) {
		$allowed_file_extensions = $this->get_allowed_file_extensions();

		if ( $filtered_file_extensions ) {
			$allowed_file_extensions = array_intersect( $allowed_file_extensions, $filtered_file_extensions );
		}

		$is_allowed = false;

		// Check if the file type (extension) is in the allowed extensions list. If it is a non-standard file type (not
		// enabled by default in WordPress) and unfiltered file uploads are not enabled, it will not be in the allowed
		// file extensions list.
		foreach ( $allowed_file_extensions as $allowed_extension ) {
			if ( preg_match( '/' . $allowed_extension . '/', $file_extension ) ) {
				$is_allowed = true;

				break;
			}
		}

		if ( ! $is_allowed ) {
			$is_allowed = new \WP_Error( Exceptions::FORBIDDEN, 'Uploading this file type is not allowed.' );
		}

		/**
		 * Elementor File Type Allowed
		 *
		 * Allows setting file types
		 *
		 * @since 3.5.0
		 *
		 * @param bool|\WP_Error $is_allowed
		 */
		return apply_filters( 'elementor/files/allow-file-type/' . $file_extension, $is_allowed );
	}

	/**
	 * Remove Directory with Files
	 *
	 * @since 3.3.0
	 * @access private
	 *
	 * @param string $dir
	 * @return bool
	 */
	private function remove_directory_with_files( $dir ) {
		$dir_iterator = new \RecursiveDirectoryIterator( $dir, \RecursiveDirectoryIterator::SKIP_DOTS );

		foreach ( new \RecursiveIteratorIterator( $dir_iterator, \RecursiveIteratorIterator::CHILD_FIRST ) as $name => $item ) {
			if ( is_dir( $name ) ) {
				rmdir( $name );
			} elseif ( is_file( $name ) ) {
				unlink( $name );
			}
		}

		return rmdir( $dir );
	}

	/**
	 * Get Allowed File Extensions
	 *
	 * Retrieve an array containing the list of file extensions allowed for upload.
	 *
	 * @since 3.3.0
	 * @access private
	 *
	 * @return array file extension/s
	 */
	private function get_allowed_file_extensions() {
		if ( ! $this->allowed_file_extensions ) {
			$this->allowed_file_extensions = array_keys( get_allowed_mime_types() );

			foreach ( $this->get_file_type_handlers() as $file_type => $handler ) {
				if ( $handler->is_upload_allowed() ) {
					// Add the file extension to the allowed extensions list only if unfiltered files upload is enabled.
					$this->add_file_extension_to_allowed_extensions_list( $file_type );
				}
			}
		}

		return $this->allowed_file_extensions;
	}

	public function __construct() {
		$this->register_file_types();

		add_filter( 'upload_mimes', [ $this, 'support_unfiltered_elementor_file_uploads' ] );
		add_filter( 'wp_handle_upload_prefilter', [ $this, 'handle_elementor_wp_media_upload' ] );
		add_filter( 'wp_check_filetype_and_ext', [ $this, 'check_filetype_and_ext' ], 10, 4 );

		// Ajax.
		add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_actions' ] );
	}
}
css/global-css.php000064400000007670151223464240010110 0ustar00<?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 );
			}
		}
	}
}
css/post-local-cache.php000064400000001366151223464240011174 0ustar00<?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() : [];
	}
}
css/post-preview.php000064400000002375151223464240010523 0ustar00<?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;
	}

	/**
	 * 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();
	}
}
css/post.php000064400000015341151223464240007041 0ustar00<?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() {
		$document = Plugin::$instance->documents->get( $this->post_id );

		if ( ! $document || ! $document->is_built_with_elementor() ) {
			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 );
	}
}
css/base.php000064400000066175151223464240007001 0ustar00<?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\Breakpoints\Manager as Breakpoints_Manager;
use Elementor\Core\Files\Base as Base_File;
use Elementor\Core\DynamicTags\Manager;
use Elementor\Core\DynamicTags\Tag;
use Elementor\Core\Frontend\Performance;
use Elementor\Core\Kits\Documents\Tabs\Global_Typography;
use Elementor\Plugin;
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();
		}
	}

	/**
	 * Get Responsive Control Duplication Mode
	 *
	 * @since 3.4.0
	 *
	 * @return string
	 */
	protected function get_responsive_control_duplication_mode() {
		return 'on';
	}

	/**
	 * 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;
		}

		/**
		 * Enqueue CSS file.
		 *
		 * Fires before enqueuing a CSS file.
		 *
		 * @param Base $this The current CSS file.
		 */
		do_action( 'elementor/css-file/before_enqueue', $this );

		// 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 );

		/**
		 * Enqueue CSS file.
		 *
		 * Fires after enqueuing a CSS file.
		 *
		 * @param Base $this The current CSS file.
		 */
		do_action( 'elementor/css-file/after_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();

		$control = apply_filters( 'elementor/files/css/selectors', $control, $value ?? [], $this );

		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 {
					if ( $this->unit_has_custom_selector( $control, $value ) ) {
						$css_property = $control['unit_selectors_dictionary'][ $value['unit'] ];
					}

					$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 = '';

						$value = apply_filters( 'elementor/files/css/property', $value, $css_property, $matches, $control );

						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();
							}
						}

						if ( '__EMPTY__' === $parsed_value ) {
							$parsed_value = '';
						}

						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 ( Breakpoints_Manager::BREAKPOINT_KEY_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'] ) && Breakpoints_Manager::BREAKPOINT_KEY_DESKTOP === $query['max'] ) {
					unset( $query['max'] );
				}
			}

			$stylesheet->add_rules( $parsed_selector, $output_css_property, $query );
		}
	}

	protected function unit_has_custom_selector( $control, $value ) {
		return isset( $control['unit_selectors_dictionary'] ) && isset( $control['unit_selectors_dictionary'][ $value['unit'] ] );
	}

	/**
	 * @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 ) {
			// If both the processed control and the control name found in the placeholder are responsive
			if ( ! empty( $control['responsive'] ) && ! empty( $controls_stack[ $parser_control_name ]['responsive'] ) ) {
				$device_suffix = Controls_Manager::get_responsive_control_device_suffix( $control );

				$control = $controls_stack[ $parser_control_name . $device_suffix ] ?? $controls_stack[ $parser_control_name ];
			} else {
				$control = $controls_stack[ $parser_control_name ];
			}

			$value = call_user_func( $value_callback, $control );
		}

		// If the control value is empty, check for global default. `0` (integer, string) are falsy but are valid values.
		if ( empty( $value ) && '0' !== $value && 0 !== $value ) {
			$value = $this->get_control_global_default_value( $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() {
		Performance::set_use_style_controls( true );

		$initial_responsive_controls_duplication_mode = Plugin::$instance->breakpoints->get_responsive_control_duplication_mode();

		Plugin::$instance->breakpoints->set_responsive_control_duplication_mode( $this->get_responsive_control_duplication_mode() );

		$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 );

		Plugin::$instance->breakpoints->set_responsive_control_duplication_mode( $initial_responsive_controls_duplication_mode );

		Performance::set_use_style_controls( false );

		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 Control Global Default Value
	 *
	 * If the control has a global default value, and the corresponding global default setting is enabled, this method
	 * fetches and returns the global default value. Otherwise, it returns null.
	 *
	 * @since 3.7.0
	 * @access private
	 *
	 * @param $control
	 * @return string|null
	 */
	private function get_control_global_default_value( $control ) {
		if ( empty( $control['global']['default'] ) ) {
			return null;
		}

		// If the control value is empty, and the control has a global default set, fetch the global value and use it.
		$global_enabled = false;

		if ( 'color' === $control['type'] ) {
			$global_enabled = Plugin::$instance->kits_manager->is_custom_colors_enabled();
		} elseif ( isset( $control['groupType'] ) && 'typography' === $control['groupType'] ) {
			$global_enabled = Plugin::$instance->kits_manager->is_custom_typography_enabled();
		}

		$value = null;

		// Only apply the global default if Global Colors are enabled.
		if ( $global_enabled ) {
			$value = $this->get_selector_global_value( $control, $control['global']['default'] );
		}

		return $value;
	}

	/**
	 * 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();

		$active_breakpoints = Plugin::$instance->breakpoints->get_active_breakpoints();

		foreach ( $active_breakpoints as $breakpoint_name => $breakpoint ) {
			$this->stylesheet_obj->add_device( $breakpoint_name, $breakpoint->get_value() );
		}
	}

	/**
	 * 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_v2->run( $global_key );

		if ( empty( $data['value'] ) ) {
			return null;
		}

		$global_args = explode( '?id=', $global_key );

		$id = $global_args[1];

		if ( ! empty( $control['groupType'] ) ) {
			$strings_to_replace = [ $control['groupPrefix'] ];

			$active_breakpoint_keys = array_keys( Plugin::$instance->breakpoints->get_active_breakpoints() );

			foreach ( $active_breakpoint_keys as $breakpoint ) {
				$strings_to_replace[] = '_' . $breakpoint;
			}

			$property_name = str_replace( $strings_to_replace, '', $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 )";

			if ( $control['groupPrefix'] . 'font_family' === $control['name'] ) {
				$default_generic_fonts = Plugin::$instance->kits_manager->get_current_settings( 'default_generic_fonts' );

				if ( $default_generic_fonts ) {
					$value  .= ", $default_generic_fonts";
				}
			}
		} 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, $controls ) ) {
					$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 ] );
	}
}
manager.php000064400000011133151223464240006671 0ustar00<?php
namespace Elementor\Core\Files;

use Elementor\Core\Base\Document as Document_Base;
use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
use Elementor\Core\Files\CSS\Global_CSS;
use Elementor\Core\Files\CSS\Post as Post_CSS;
use Elementor\Core\Page_Assets\Data_Managers\Base as Page_Assets_Data_Manager;
use Elementor\Core\Responsive\Files\Frontend;
use Elementor\Plugin;
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();
	}

	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 files.
		$path = Base::get_base_uploads_dir() . Base::DEFAULT_FILES_DIR . '*';

		foreach ( glob( $path ) as $file_path ) {
			unlink( $file_path );
		}

		delete_post_meta_by_key( Post_CSS::META_KEY );
		delete_post_meta_by_key( Document_Base::CACHE_META_KEY );

		delete_option( Global_CSS::META_KEY );
		delete_option( Frontend::META_KEY );

		$this->reset_assets_data();

		/**
		 * Elementor clear files.
		 *
		 * Fires after Elementor clears files
		 *
		 * @since 2.1.0
		 */
		do_action( 'elementor/core/files/clear_cache' );
	}

	public function clear_custom_image_sizes() {
		$upload_info = wp_upload_dir();
		$upload_dir = $upload_info['basedir'] . '/' . BFITHUMB_UPLOAD_DIR;

		$path = $upload_dir . '/*';

		foreach ( glob( $path ) as $file_path ) {
			unlink( $file_path );
		}
	}

	/**
	 * Register Ajax Actions
	 *
	 * Deprecated - use the Uploads Manager instead.
	 *
	 * @deprecated 3.5.0
	 *
	 * @param Ajax $ajax
	 */
	public function register_ajax_actions( Ajax $ajax ) {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0' );

		Plugin::$instance->uploads_manager->register_ajax_actions( $ajax );
	}

	/**
	 * Ajax Unfiltered Files Upload
	 *
	 * Deprecated - use the Uploads Manager instead.
	 *
	 * @deprecated 3.5.0
	 */
	public function ajax_unfiltered_files_upload() {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0' );

		Plugin::$instance->uploads_manager->enable_unfiltered_files_upload();
	}

	/**
	 * 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' ] );

		add_filter( 'wxr_export_skip_postmeta', [ $this, 'on_export_post_meta' ], 10, 2 );

		add_action( 'update_option_home', function () {
			$this->reset_assets_data();
		} );

		add_action( 'update_option_siteurl', function () {
			$this->reset_assets_data();
		} );
	}

	/**
	 * Reset Assets Data.
	 *
	 * Reset the page assets data.
	 *
	 * @since 3.3.0
	 * @access private
	 */
	private function reset_assets_data() {
		delete_option( Page_Assets_Data_Manager::ASSETS_DATA_KEY );
	}
}
assets/json/json-handler.php000064400000001302151223464240012113 0ustar00<?php
namespace Elementor\Core\Files\Assets\Json;

use Elementor\Core\Files\Assets\Files_Upload_Handler;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Json Handler
 *
 * @deprecated 3.5.0 Use `Elementor\Core\Files\File_Types\Svg` instead, accessed by calling `Plugin::$instance->uploads_manager->get_file_type_handlers( 'svg' );`
 */
class Json_Handler extends Files_Upload_Handler {

	/**
	 * @deprecated 3.5.0
	 */
	public static function get_name() {
		return 'json-handler';
	}

	/**
	 * @deprecated 3.5.0
	 */
	public function get_mime_type() {
		return 'application/json';
	}

	/**
	 * @deprecated 3.5.0
	 */
	public function get_file_type() {
		return 'json';
	}
}
assets/svg/svg-handler.php000064400000015541151223464240011601 0ustar00<?php
namespace Elementor\Core\Files\Assets\Svg;

use Elementor\Core\Files\Assets\Files_Upload_Handler;
use Elementor\Core\Files\File_Types\Svg;
use Elementor\Core\Files\Uploads_Manager;
use Elementor\Plugin;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * SVG Handler
 *
 * @deprecated 3.5.0 Use `Elementor\Core\Files\File_Types\Svg` instead, accessed by calling: `Plugin::$instance->uploads_manager->get_file_type_handlers( 'svg' );`
 */
class Svg_Handler extends Files_Upload_Handler {

	/**
	 * Inline svg attachment meta key
	 *
	 * @deprecated 3.5.0
	 */
	const META_KEY = '_elementor_inline_svg';

	/**
	 * @deprecated 3.5.0
	 */
	const SCRIPT_REGEX = '/(?:\w+script|data):/xi';

	/**
	 * Attachment ID.
	 *
	 * Holds the current attachment ID.
	 *
	 * @deprecated 3.5.0
	 *
	 * @var int
	 */
	private $attachment_id;

	/**
	 * @deprecated 3.5.0
	 */
	public static function get_name() {
		return 'svg-handler';
	}

	/**
	 * get_meta
	 *
	 * @deprecated 3.5.0
	 *
	 * @return mixed
	 */
	protected function get_meta() {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0' );

		return get_post_meta( $this->attachment_id, self::META_KEY, true );
	}

	/**
	 * update_meta
	 *
	 * @deprecated 3.5.0
	 *
	 * @param $meta
	 */
	protected function update_meta( $meta ) {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0' );

		update_post_meta( $this->attachment_id, self::META_KEY, $meta );
	}

	/**
	 * delete_meta
	 *
	 * @deprecated 3.5.0
	 */
	protected function delete_meta() {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0' );

		delete_post_meta( $this->attachment_id, self::META_KEY );
	}

	/**
	 * @deprecated 3.5.0
	 */
	public function get_mime_type() {
		return 'image/svg+xml';
	}

	/**
	 * @deprecated 3.5.0
	 */
	public function get_file_type() {
		return 'svg';
	}

	/**
	 * delete_meta_cache
	 *
	 * @deprecated 3.5.0 Use `Plugin::$instance->uploads_manager->get_file_type_handlers( 'svg' )->delete_meta_cache()` instead.
	 */
	public function delete_meta_cache() {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0', 'Plugin::$instance->uploads_manager->get_file_type_handlers( \'svg\' )->delete_meta_cache()' );

		/** @var Svg $svg_handler */
		$svg_handler = Plugin::$instance->uploads_manager->get_file_type_handlers( 'svg' );

		$svg_handler->delete_meta_cache();
	}

	/**
	 * get_inline_svg
	 *
	 * @deprecated 3.5.0 Use `Elementor\Core\Files\File_Types\Svg::get_inline_svg()` instead.
	 *
	 * @param $attachment_id
	 *
	 * @return bool|mixed|string
	 */
	public static function get_inline_svg( $attachment_id ) {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0', 'Elementor\Core\Files\File_Types\Svg::get_inline_svg()' );

		return Svg::get_inline_svg( $attachment_id );
	}

	/**
	 * sanitize_svg
	 *
	 * @deprecated 3.5.0 Use `Plugin::$instance->uploads_manager->get_file_type_handlers( 'svg' )->delete_meta_cache()->sanitize_svg()` instead.
	 *
	 * @param $filename
	 *
	 * @return bool
	 */
	public function sanitize_svg( $filename ) {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0', 'Plugin::$instance->uploads_manager->get_file_type_handlers( \'svg\' )->delete_meta_cache()->sanitize_svg()' );

		/** @var Svg $svg_handler */
		$svg_handler = Plugin::$instance->uploads_manager->get_file_type_handlers( 'svg' );

		return $svg_handler->sanitize_svg( $filename );
	}

	/**
	 * sanitizer
	 *
	 * @deprecated 3.5.0 Use `Plugin::$instance->uploads_manager->get_file_type_handlers( 'svg' )->sanitizer()` instead.
	 *
	 * @param $content
	 *
	 * @return bool|string
	 */
	public function sanitizer( $content ) {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0', 'Plugin::$instance->uploads_manager->get_file_type_handlers( \'svg\' )->sanitizer()' );

		/** @var Svg $svg_handler */
		$svg_handler = Plugin::$instance->uploads_manager->get_file_type_handlers( 'svg' );

		return $svg_handler->sanitizer( $content );
	}

	/**
	 * wp_prepare_attachment_for_js
	 *
	 * @deprecated 3.5.0 Use `Plugin::$instance->uploads_manager->get_file_type_handlers( 'svg' )->wp_prepare_attachment_for_js()` instead.
	 *
	 * @param $attachment_data
	 * @param $attachment
	 * @param $meta
	 *
	 * @return mixed
	 */
	public function wp_prepare_attachment_for_js( $attachment_data, $attachment, $meta ) {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0', 'Plugin::$instance->uploads_manager->get_file_type_handlers( \'svg\' )->wp_prepare_attachment_for_js()' );

		/** @var Svg $svg_handler */
		$svg_handler = Plugin::$instance->uploads_manager->get_file_type_handlers( 'svg' );

		return $svg_handler->wp_prepare_attachment_for_js( $attachment_data, $attachment, $meta );
	}

	/**
	 * set_attachment_id
	 *
	 * @deprecated 3.5.0
	 *
	 * @param $attachment_id
	 *
	 * @return int
	 */
	public function set_attachment_id( $attachment_id ) {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0' );

		$this->attachment_id = $attachment_id;
		return $this->attachment_id;
	}

	/**
	 * get_attachment_id
	 *
	 * @deprecated 3.5.0
	 *
	 * @return int
	 */
	public function get_attachment_id() {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0' );

		return $this->attachment_id;
	}

	/**
	 * set_svg_meta_data
	 *
	 * @deprecated 3.5.0 Use `Plugin::$instance->uploads_manager->get_file_type_handlers( 'svg' )->set_svg_meta_data()` instead.
	 *
	 * @return mixed
	 */
	public function set_svg_meta_data( $data, $id ) {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0', 'Plugin::$instance->uploads_manager->get_file_type_handlers( \'svg\' )->set_svg_meta_data()' );

		/** @var Svg $svg_handler */
		$svg_handler = Plugin::$instance->uploads_manager->get_file_type_handlers( 'svg' );

		return $svg_handler->set_svg_meta_data( $data, $id );
	}

	/**
	 * handle_upload_prefilter
	 *
	 * @deprecated 3.5.0 Use `Elementor\Plugin::$instance->uploads_manager->handle_elementor_wp_media_upload()` instead.
	 *
	 * @param $file
	 *
	 * @return mixed
	 */
	public function handle_upload_prefilter( $file ) {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0', 'Elementor\Plugin::$instance->uploads_manager->handle_elementor_wp_media_upload()' );

		return Plugin::$instance->uploads_manager->handle_elementor_wp_media_upload( $file );
	}
}
assets/manager.php000064400000002325151223464240010176 0ustar00<?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() );
	}
}
assets/files-upload-handler.php000064400000010527151223464240012566 0ustar00<?php

namespace Elementor\Core\Files\Assets;

use Elementor\Core\Files\File_Types\Svg;
use Elementor\Core\Files\Uploads_Manager;
use Elementor\Plugin;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Files Upload Handler
 *
 * @deprecated 3.5.0 Use `Elementor\Core\Files\Uploads_Manager` class instead.
 */
abstract class Files_Upload_Handler {

	/**
	 * @deprecated 3.5.0
	 */
	const OPTION_KEY = 'elementor_unfiltered_files_upload';

	/**
	 * @deprecated 3.5.0
	 */
	abstract public function get_mime_type();

	/**
	 * @deprecated 3.5.0
	 */
	abstract public function get_file_type();

	/**
	 * Is Elementor Media Upload
	 *
	 * @deprecated 3.5.0 Use `Elementor\Plugin::$instance->uploads_manager->are_unfiltered_uploads_enabled()` instead.
	 *
	 * @return bool
	 */
	private function is_elementor_media_upload() {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0', 'Elementor\Plugin::$instance->uploads_manager->are_unfiltered_uploads_enabled()' );

		return Plugin::$instance->uploads_manager->is_elementor_media_upload();
	}

	/**
	 * Is Enabled
	 *
	 * @deprecated 3.5.0 Use `Elementor\Plugin::$instance->uploads_manager->are_unfiltered_uploads_enabled()` instead.
	 *
	 * @return bool
	 */
	final public static function is_enabled() {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0', 'Elementor\Plugin::$instance->uploads_manager->are_unfiltered_uploads_enabled()' );

		return Plugin::$instance->uploads_manager->are_unfiltered_uploads_enabled();
	}

	/**
	 * @deprecated 3.5.0 Use `Elementor\Plugin::$instance->uploads_manager->are_unfiltered_uploads_enabled()` instead.
	 */
	final public function support_unfiltered_files_upload( $existing_mimes ) {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0', 'Elementor\Plugin::$instance->uploads_manager->support_unfiltered_file_uploads()' );

		return Plugin::$instance->uploads_manager->support_unfiltered_elementor_file_uploads( $existing_mimes );
	}

	/**
	 * handle_upload_prefilter
	 *
	 * @deprecated 3.5.0 Use `Elementor\Plugin::$instance->uploads_manager->handle_elementor_wp_media_upload()` instead.
	 *
	 * @param $file
	 *
	 * @return mixed
	 */
	public function handle_upload_prefilter( $file ) {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0', 'Elementor\Plugin::$instance->uploads_manager->handle_elementor_wp_media_upload()' );

		return Plugin::$instance->uploads_manager->handle_elementor_wp_media_upload( $file );
	}

	/**
	 * is_file_should_handled
	 *
	 * @deprecated 3.5.0
	 *
	 * @param $file
	 *
	 * @return bool
	 */
	protected function is_file_should_handled( $file ) {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0' );

		$ext = pathinfo( $file['name'], PATHINFO_EXTENSION );

		return $this->is_elementor_media_upload() && $this->get_file_type() === $ext;
	}

	/**
	 * file_sanitizer_can_run
	 *
	 * @deprecated 3.5.0 Use `Elementor\Core\Files\File_Types\Svg::file_sanitizer_can_run()` instead.
	 *
	 * @return bool
	 */
	public static function file_sanitizer_can_run() {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0', 'Elementor\Core\Files\File_Types\Svg::file_sanitizer_can_run()' );

		return Svg::file_sanitizer_can_run();
	}

	/**
	 * 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
	 *
	 * @deprecated 3.5.0 Use `Elementor\Plugin::$instance->uploads_manager->check_filetype_and_ext()` instead.
	 *
	 * @param $data
	 * @param $file
	 * @param $filename
	 * @param $mimes
	 *
	 * @return mixed
	 */
	public function check_filetype_and_ext( $data, $file, $filename, $mimes ) {
		Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0', 'Elementor\Plugin::$instance->uploads_manager->check_filetype_and_ext()' );

		Plugin::$instance->uploads_manager->check_filetype_and_ext( $data, $file, $filename, $mimes );
	}
}
base.php000064400000013135151223464240006175 0ustar00<?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 );
	}

	/**
	 * Get Path
	 *
	 * Returns the local path of the generated file.
	 *
	 * @since 3.5.0
	 * @access public
	 *
	 * @return string
	 */
	public function get_path() {
		return set_url_scheme( self::get_base_uploads_dir() . $this->files_dir . $this->file_name );
	}

	/**
	 * @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;
	}
}