first commit
This commit is contained in:
64
wp-content/plugins/elementor/core/base/app.php
Normal file
64
wp-content/plugins/elementor/core/base/app.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Core\Base;
|
||||
|
||||
use Elementor\Utils;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
/**
|
||||
* Base App
|
||||
*
|
||||
* Base app utility class that provides shared functionality of apps.
|
||||
*
|
||||
* @since 2.3.0
|
||||
*/
|
||||
abstract class App extends Module {
|
||||
|
||||
/**
|
||||
* Print config.
|
||||
*
|
||||
* Used to print the app and its components settings as a JavaScript object.
|
||||
*
|
||||
* @param string $handle Optional
|
||||
*
|
||||
* @since 2.3.0
|
||||
* @since 2.6.0 added the `$handle` parameter
|
||||
* @access protected
|
||||
*/
|
||||
final protected function print_config( $handle = null ) {
|
||||
$name = $this->get_name();
|
||||
|
||||
$js_var = 'elementor' . str_replace( ' ', '', ucwords( str_replace( '-', ' ', $name ) ) ) . 'Config';
|
||||
|
||||
$config = $this->get_settings() + $this->get_components_config();
|
||||
|
||||
if ( ! $handle ) {
|
||||
$handle = 'elementor-' . $name;
|
||||
}
|
||||
|
||||
Utils::print_js_config( $handle, $js_var, $config );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get components config.
|
||||
*
|
||||
* Retrieves the app components settings.
|
||||
*
|
||||
* @since 2.3.0
|
||||
* @access private
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_components_config() {
|
||||
$settings = [];
|
||||
|
||||
foreach ( $this->get_components() as $id => $instance ) {
|
||||
$settings[ $id ] = $instance->get_settings();
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
namespace Elementor\Core\Base\BackgroundProcess;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* https://github.com/A5hleyRich/wp-background-processing GPL v2.0
|
||||
*
|
||||
* WP Async Request
|
||||
*
|
||||
* @package WP-Background-Processing
|
||||
*/
|
||||
|
||||
/**
|
||||
* Abstract WP_Async_Request class.
|
||||
*
|
||||
* @abstract
|
||||
*/
|
||||
abstract class WP_Async_Request {
|
||||
|
||||
/**
|
||||
* Prefix
|
||||
*
|
||||
* (default value: 'wp')
|
||||
*
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
protected $prefix = 'wp';
|
||||
|
||||
/**
|
||||
* Action
|
||||
*
|
||||
* (default value: 'async_request')
|
||||
*
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
protected $action = 'async_request';
|
||||
|
||||
/**
|
||||
* Identifier
|
||||
*
|
||||
* @var mixed
|
||||
* @access protected
|
||||
*/
|
||||
protected $identifier;
|
||||
|
||||
/**
|
||||
* Data
|
||||
*
|
||||
* (default value: array())
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
protected $data = array();
|
||||
|
||||
/**
|
||||
* Initiate new async request
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->identifier = $this->prefix . '_' . $this->action;
|
||||
|
||||
add_action( 'wp_ajax_' . $this->identifier, array( $this, 'maybe_handle' ) );
|
||||
add_action( 'wp_ajax_nopriv_' . $this->identifier, array( $this, 'maybe_handle' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set data used during the request
|
||||
*
|
||||
* @param array $data Data.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function data( $data ) {
|
||||
$this->data = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch the async request
|
||||
*
|
||||
* @return array|\WP_Error
|
||||
*/
|
||||
public function dispatch() {
|
||||
$url = add_query_arg( $this->get_query_args(), $this->get_query_url() );
|
||||
$args = $this->get_post_args();
|
||||
|
||||
return wp_remote_post( esc_url_raw( $url ), $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_query_args() {
|
||||
if ( property_exists( $this, 'query_args' ) ) {
|
||||
return $this->query_args;
|
||||
}
|
||||
|
||||
return array(
|
||||
'action' => $this->identifier,
|
||||
'nonce' => wp_create_nonce( $this->identifier ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query URL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_query_url() {
|
||||
if ( property_exists( $this, 'query_url' ) ) {
|
||||
return $this->query_url;
|
||||
}
|
||||
|
||||
return admin_url( 'admin-ajax.php' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get post args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_post_args() {
|
||||
if ( property_exists( $this, 'post_args' ) ) {
|
||||
return $this->post_args;
|
||||
}
|
||||
|
||||
return array(
|
||||
'timeout' => 0.01,
|
||||
'blocking' => false,
|
||||
'body' => $this->data,
|
||||
'cookies' => $_COOKIE,
|
||||
/** This filter is documented in wp-includes/class-wp-http-streams.php */
|
||||
'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe handle
|
||||
*
|
||||
* Check for correct nonce and pass to handler.
|
||||
*/
|
||||
public function maybe_handle() {
|
||||
// Don't lock up other requests while processing
|
||||
session_write_close();
|
||||
|
||||
check_ajax_referer( $this->identifier, 'nonce' );
|
||||
|
||||
$this->handle();
|
||||
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle
|
||||
*
|
||||
* Override this method to perform any actions required
|
||||
* during the async request.
|
||||
*/
|
||||
abstract protected function handle();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,521 @@
|
||||
<?php
|
||||
namespace Elementor\Core\Base\BackgroundProcess;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* https://github.com/A5hleyRich/wp-background-processing GPL v2.0
|
||||
*
|
||||
* WP Background Process
|
||||
*
|
||||
* @package WP-Background-Processing
|
||||
*/
|
||||
|
||||
/**
|
||||
* Abstract WP_Background_Process class.
|
||||
*
|
||||
* @abstract
|
||||
* @extends WP_Async_Request
|
||||
*/
|
||||
abstract class WP_Background_Process extends WP_Async_Request {
|
||||
|
||||
/**
|
||||
* Action
|
||||
*
|
||||
* (default value: 'background_process')
|
||||
*
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
protected $action = 'background_process';
|
||||
|
||||
/**
|
||||
* Start time of current process.
|
||||
*
|
||||
* (default value: 0)
|
||||
*
|
||||
* @var int
|
||||
* @access protected
|
||||
*/
|
||||
protected $start_time = 0;
|
||||
|
||||
/**
|
||||
* Cron_hook_identifier
|
||||
*
|
||||
* @var mixed
|
||||
* @access protected
|
||||
*/
|
||||
protected $cron_hook_identifier;
|
||||
|
||||
/**
|
||||
* Cron_interval_identifier
|
||||
*
|
||||
* @var mixed
|
||||
* @access protected
|
||||
*/
|
||||
protected $cron_interval_identifier;
|
||||
|
||||
/**
|
||||
* Initiate new background process
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->cron_hook_identifier = $this->identifier . '_cron';
|
||||
$this->cron_interval_identifier = $this->identifier . '_cron_interval';
|
||||
|
||||
add_action( $this->cron_hook_identifier, array( $this, 'handle_cron_healthcheck' ) );
|
||||
add_filter( 'cron_schedules', array( $this, 'schedule_cron_healthcheck' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch
|
||||
*
|
||||
* @access public
|
||||
* @return array|\WP_Error
|
||||
*/
|
||||
public function dispatch() {
|
||||
// Schedule the cron healthcheck.
|
||||
$this->schedule_event();
|
||||
|
||||
// Perform remote post.
|
||||
return parent::dispatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Push to queue
|
||||
*
|
||||
* @param mixed $data Data.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function push_to_queue( $data ) {
|
||||
$this->data[] = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save queue
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function save() {
|
||||
$key = $this->generate_key();
|
||||
|
||||
if ( ! empty( $this->data ) ) {
|
||||
update_site_option( $key, $this->data );
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update queue
|
||||
*
|
||||
* @param string $key Key.
|
||||
* @param array $data Data.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function update( $key, $data ) {
|
||||
if ( ! empty( $data ) ) {
|
||||
update_site_option( $key, $data );
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete queue
|
||||
*
|
||||
* @param string $key Key.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function delete( $key ) {
|
||||
delete_site_option( $key );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate key
|
||||
*
|
||||
* Generates a unique key based on microtime. Queue items are
|
||||
* given a unique key so that they can be merged upon save.
|
||||
*
|
||||
* @param int $length Length.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generate_key( $length = 64 ) {
|
||||
$unique = md5( microtime() . rand() );
|
||||
$prepend = $this->identifier . '_batch_';
|
||||
|
||||
return substr( $prepend . $unique, 0, $length );
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe process queue
|
||||
*
|
||||
* Checks whether data exists within the queue and that
|
||||
* the process is not already running.
|
||||
*/
|
||||
public function maybe_handle() {
|
||||
// Don't lock up other requests while processing
|
||||
session_write_close();
|
||||
|
||||
if ( $this->is_process_running() ) {
|
||||
// Background process already running.
|
||||
wp_die();
|
||||
}
|
||||
|
||||
if ( $this->is_queue_empty() ) {
|
||||
// No data to process.
|
||||
wp_die();
|
||||
}
|
||||
|
||||
check_ajax_referer( $this->identifier, 'nonce' );
|
||||
|
||||
$this->handle();
|
||||
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is queue empty
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_queue_empty() {
|
||||
global $wpdb;
|
||||
|
||||
$table = $wpdb->options;
|
||||
$column = 'option_name';
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$table = $wpdb->sitemeta;
|
||||
$column = 'meta_key';
|
||||
}
|
||||
|
||||
$key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
|
||||
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
// Can't use placeholders for table/column names, it will be wrapped by a single quote (') instead of a backquote (`).
|
||||
$count = $wpdb->get_var( $wpdb->prepare( "
|
||||
SELECT COUNT(*)
|
||||
FROM {$table}
|
||||
WHERE {$column} LIKE %s
|
||||
", $key ) );
|
||||
// phpcs:enable
|
||||
|
||||
return ( $count > 0 ) ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is process running
|
||||
*
|
||||
* Check whether the current process is already running
|
||||
* in a background process.
|
||||
*/
|
||||
protected function is_process_running() {
|
||||
if ( get_site_transient( $this->identifier . '_process_lock' ) ) {
|
||||
// Process already running.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock process
|
||||
*
|
||||
* Lock the process so that multiple instances can't run simultaneously.
|
||||
* Override if applicable, but the duration should be greater than that
|
||||
* defined in the time_exceeded() method.
|
||||
*/
|
||||
protected function lock_process() {
|
||||
$this->start_time = time(); // Set start time of current process.
|
||||
|
||||
$lock_duration = ( property_exists( $this, 'queue_lock_time' ) ) ? $this->queue_lock_time : 60; // 1 minute
|
||||
$lock_duration = apply_filters( $this->identifier . '_queue_lock_time', $lock_duration );
|
||||
|
||||
set_site_transient( $this->identifier . '_process_lock', microtime(), $lock_duration );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock process
|
||||
*
|
||||
* Unlock the process so that other instances can spawn.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function unlock_process() {
|
||||
delete_site_transient( $this->identifier . '_process_lock' );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get batch
|
||||
*
|
||||
* @return \stdClass Return the first batch from the queue
|
||||
*/
|
||||
protected function get_batch() {
|
||||
global $wpdb;
|
||||
|
||||
$table = $wpdb->options;
|
||||
$column = 'option_name';
|
||||
$key_column = 'option_id';
|
||||
$value_column = 'option_value';
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$table = $wpdb->sitemeta;
|
||||
$column = 'meta_key';
|
||||
$key_column = 'meta_id';
|
||||
$value_column = 'meta_value';
|
||||
}
|
||||
|
||||
$key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
|
||||
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
// Can't use placeholders for table/column names, it will be wrapped by a single quote (') instead of a backquote (`).
|
||||
$query = $wpdb->get_row( $wpdb->prepare( "
|
||||
SELECT *
|
||||
FROM {$table}
|
||||
WHERE {$column} LIKE %s
|
||||
ORDER BY {$key_column} ASC
|
||||
LIMIT 1
|
||||
", $key ) );
|
||||
// phpcs:enable
|
||||
|
||||
$batch = new \stdClass();
|
||||
$batch->key = $query->$column;
|
||||
$batch->data = maybe_unserialize( $query->$value_column );
|
||||
|
||||
return $batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle
|
||||
*
|
||||
* Pass each queue item to the task handler, while remaining
|
||||
* within server memory and time limit constraints.
|
||||
*/
|
||||
protected function handle() {
|
||||
$this->lock_process();
|
||||
|
||||
do {
|
||||
$batch = $this->get_batch();
|
||||
|
||||
foreach ( $batch->data as $key => $value ) {
|
||||
$task = $this->task( $value );
|
||||
|
||||
if ( false !== $task ) {
|
||||
$batch->data[ $key ] = $task;
|
||||
} else {
|
||||
unset( $batch->data[ $key ] );
|
||||
}
|
||||
|
||||
if ( $this->time_exceeded() || $this->memory_exceeded() ) {
|
||||
// Batch limits reached.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Update or delete current batch.
|
||||
if ( ! empty( $batch->data ) ) {
|
||||
$this->update( $batch->key, $batch->data );
|
||||
} else {
|
||||
$this->delete( $batch->key );
|
||||
}
|
||||
} while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() );
|
||||
|
||||
$this->unlock_process();
|
||||
|
||||
// Start next batch or complete process.
|
||||
if ( ! $this->is_queue_empty() ) {
|
||||
$this->dispatch();
|
||||
} else {
|
||||
$this->complete();
|
||||
}
|
||||
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Memory exceeded
|
||||
*
|
||||
* Ensures the batch process never exceeds 90%
|
||||
* of the maximum WordPress memory.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function memory_exceeded() {
|
||||
$memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory
|
||||
$current_memory = memory_get_usage( true );
|
||||
$return = false;
|
||||
|
||||
if ( $current_memory >= $memory_limit ) {
|
||||
$return = true;
|
||||
}
|
||||
|
||||
return apply_filters( $this->identifier . '_memory_exceeded', $return );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get memory limit
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function get_memory_limit() {
|
||||
if ( function_exists( 'ini_get' ) ) {
|
||||
$memory_limit = ini_get( 'memory_limit' );
|
||||
} else {
|
||||
// Sensible default.
|
||||
$memory_limit = '128M';
|
||||
}
|
||||
|
||||
if ( ! $memory_limit || -1 === intval( $memory_limit ) ) {
|
||||
// Unlimited, set to 32GB.
|
||||
$memory_limit = '32000M';
|
||||
}
|
||||
|
||||
return intval( $memory_limit ) * 1024 * 1024;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time exceeded.
|
||||
*
|
||||
* Ensures the batch never exceeds a sensible time limit.
|
||||
* A timeout limit of 30s is common on shared hosting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function time_exceeded() {
|
||||
$finish = $this->start_time + apply_filters( $this->identifier . '_default_time_limit', 20 ); // 20 seconds
|
||||
$return = false;
|
||||
|
||||
if ( time() >= $finish ) {
|
||||
$return = true;
|
||||
}
|
||||
|
||||
return apply_filters( $this->identifier . '_time_exceeded', $return );
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete.
|
||||
*
|
||||
* Override if applicable, but ensure that the below actions are
|
||||
* performed, or, call parent::complete().
|
||||
*/
|
||||
protected function complete() {
|
||||
// Unschedule the cron healthcheck.
|
||||
$this->clear_scheduled_event();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule cron healthcheck
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $schedules Schedules.
|
||||
* @return mixed
|
||||
*/
|
||||
public function schedule_cron_healthcheck( $schedules ) {
|
||||
$interval = apply_filters( $this->identifier . '_cron_interval', 5 );
|
||||
|
||||
if ( property_exists( $this, 'cron_interval' ) ) {
|
||||
$interval = apply_filters( $this->identifier . '_cron_interval', $this->cron_interval );
|
||||
}
|
||||
|
||||
// Adds every 5 minutes to the existing schedules.
|
||||
$schedules[ $this->identifier . '_cron_interval' ] = array(
|
||||
'interval' => MINUTE_IN_SECONDS * $interval,
|
||||
'display' => sprintf(
|
||||
/* translators: %d: Interval in minutes. */
|
||||
esc_html__( 'Every %d minutes', 'elementor' ),
|
||||
$interval,
|
||||
),
|
||||
);
|
||||
|
||||
return $schedules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle cron healthcheck
|
||||
*
|
||||
* Restart the background process if not already running
|
||||
* and data exists in the queue.
|
||||
*/
|
||||
public function handle_cron_healthcheck() {
|
||||
if ( $this->is_process_running() ) {
|
||||
// Background process already running.
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( $this->is_queue_empty() ) {
|
||||
// No data to process.
|
||||
$this->clear_scheduled_event();
|
||||
exit;
|
||||
}
|
||||
|
||||
$this->handle();
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule event
|
||||
*/
|
||||
protected function schedule_event() {
|
||||
if ( ! wp_next_scheduled( $this->cron_hook_identifier ) ) {
|
||||
wp_schedule_event( time(), $this->cron_interval_identifier, $this->cron_hook_identifier );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear scheduled event
|
||||
*/
|
||||
protected function clear_scheduled_event() {
|
||||
$timestamp = wp_next_scheduled( $this->cron_hook_identifier );
|
||||
|
||||
if ( $timestamp ) {
|
||||
wp_unschedule_event( $timestamp, $this->cron_hook_identifier );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel Process
|
||||
*
|
||||
* Stop processing queue items, clear cronjob and delete batch.
|
||||
*
|
||||
*/
|
||||
public function cancel_process() {
|
||||
if ( ! $this->is_queue_empty() ) {
|
||||
$batch = $this->get_batch();
|
||||
|
||||
$this->delete( $batch->key );
|
||||
|
||||
wp_clear_scheduled_hook( $this->cron_hook_identifier );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Task
|
||||
*
|
||||
* Override this method to perform any actions required on each
|
||||
* queue item. Return the modified item for further processing
|
||||
* in the next pass through. Or, return false to remove the
|
||||
* item from the queue.
|
||||
*
|
||||
* @param mixed $item Queue item to iterate over.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function task( $item );
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Core\Base;
|
||||
|
||||
use Elementor\Core\Base\Module as BaseModule;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
abstract class Background_Task_Manager extends BaseModule {
|
||||
/**
|
||||
* @var Background_Task
|
||||
*/
|
||||
protected $task_runner;
|
||||
|
||||
abstract public function get_action();
|
||||
abstract public function get_plugin_name();
|
||||
abstract public function get_plugin_label();
|
||||
abstract public function get_task_runner_class();
|
||||
abstract public function get_query_limit();
|
||||
|
||||
abstract protected function start_run();
|
||||
|
||||
public function on_runner_start() {
|
||||
$logger = Plugin::$instance->logger->get_logger();
|
||||
$logger->info( $this->get_plugin_name() . '::' . $this->get_action() . ' Started' );
|
||||
}
|
||||
|
||||
public function on_runner_complete( $did_tasks = false ) {
|
||||
$logger = Plugin::$instance->logger->get_logger();
|
||||
$logger->info( $this->get_plugin_name() . '::' . $this->get_action() . ' Completed' );
|
||||
}
|
||||
|
||||
public function get_task_runner() {
|
||||
if ( empty( $this->task_runner ) ) {
|
||||
$class_name = $this->get_task_runner_class();
|
||||
$this->task_runner = new $class_name( $this );
|
||||
}
|
||||
|
||||
return $this->task_runner;
|
||||
}
|
||||
|
||||
// TODO: Replace with a db settings system.
|
||||
protected function add_flag( $flag ) {
|
||||
add_option( $this->get_plugin_name() . '_' . $this->get_action() . '_' . $flag, 1 );
|
||||
}
|
||||
|
||||
protected function get_flag( $flag ) {
|
||||
return get_option( $this->get_plugin_name() . '_' . $this->get_action() . '_' . $flag );
|
||||
}
|
||||
|
||||
protected function delete_flag( $flag ) {
|
||||
delete_option( $this->get_plugin_name() . '_' . $this->get_action() . '_' . $flag );
|
||||
}
|
||||
|
||||
protected function get_start_action_url() {
|
||||
return wp_nonce_url( add_query_arg( $this->get_action(), 'run' ), $this->get_action() . 'run' );
|
||||
}
|
||||
|
||||
protected function get_continue_action_url() {
|
||||
return wp_nonce_url( add_query_arg( $this->get_action(), 'continue' ), $this->get_action() . 'continue' );
|
||||
}
|
||||
|
||||
private function continue_run() {
|
||||
$runner = $this->get_task_runner();
|
||||
$runner->continue_run();
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
if ( empty( $_GET[ $this->get_action() ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Plugin::$instance->init_common();
|
||||
|
||||
if ( 'run' === $_GET[ $this->get_action() ] && check_admin_referer( $this->get_action() . 'run' ) ) {
|
||||
$this->start_run();
|
||||
}
|
||||
|
||||
if ( 'continue' === $_GET[ $this->get_action() ] && check_admin_referer( $this->get_action() . 'continue' ) ) {
|
||||
$this->continue_run();
|
||||
}
|
||||
|
||||
wp_safe_redirect( remove_query_arg( [ $this->get_action(), '_wpnonce' ] ) );
|
||||
die;
|
||||
}
|
||||
}
|
||||
385
wp-content/plugins/elementor/core/base/background-task.php
Normal file
385
wp-content/plugins/elementor/core/base/background-task.php
Normal file
@@ -0,0 +1,385 @@
|
||||
<?php
|
||||
namespace Elementor\Core\Base;
|
||||
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Core\Base\BackgroundProcess\WP_Background_Process;
|
||||
|
||||
/**
|
||||
* Based on https://github.com/woocommerce/woocommerce/blob/master/includes/abstracts/class-wc-background-process.php
|
||||
* & https://github.com/woocommerce/woocommerce/blob/master/includes/class-wc-background-updater.php
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* WC_Background_Process class.
|
||||
*/
|
||||
abstract class Background_Task extends WP_Background_Process {
|
||||
protected $current_item;
|
||||
|
||||
/**
|
||||
* Dispatch updater.
|
||||
*
|
||||
* Updater will still run via cron job if this fails for any reason.
|
||||
*/
|
||||
public function dispatch() {
|
||||
$dispatched = parent::dispatch();
|
||||
|
||||
if ( is_wp_error( $dispatched ) ) {
|
||||
wp_die( esc_html( $dispatched ) );
|
||||
}
|
||||
}
|
||||
|
||||
public function query_col( $sql ) {
|
||||
global $wpdb;
|
||||
|
||||
// Add Calc.
|
||||
$item = $this->get_current_item();
|
||||
if ( empty( $item['total'] ) ) {
|
||||
$sql = preg_replace( '/^SELECT/', 'SELECT SQL_CALC_FOUND_ROWS', $sql );
|
||||
}
|
||||
|
||||
// Add offset & limit.
|
||||
$sql = preg_replace( '/;$/', '', $sql );
|
||||
$sql .= ' LIMIT %d, %d;';
|
||||
|
||||
$results = $wpdb->get_col( $wpdb->prepare( $sql, $this->get_current_offset(), $this->get_limit() ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
|
||||
if ( ! empty( $results ) ) {
|
||||
$this->set_total();
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
public function should_run_again( $updated_rows ) {
|
||||
return count( $updated_rows ) === $this->get_limit();
|
||||
}
|
||||
|
||||
public function get_current_offset() {
|
||||
$limit = $this->get_limit();
|
||||
return ( $this->current_item['iterate_num'] - 1 ) * $limit;
|
||||
}
|
||||
|
||||
public function get_limit() {
|
||||
return $this->manager->get_query_limit();
|
||||
}
|
||||
|
||||
public function set_total() {
|
||||
global $wpdb;
|
||||
|
||||
if ( empty( $this->current_item['total'] ) ) {
|
||||
$total_rows = $wpdb->get_var( 'SELECT FOUND_ROWS();' );
|
||||
$total_iterates = ceil( $total_rows / $this->get_limit() );
|
||||
$this->current_item['total'] = $total_iterates;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete
|
||||
*
|
||||
* Override if applicable, but ensure that the below actions are
|
||||
* performed, or, call parent::complete().
|
||||
*/
|
||||
protected function complete() {
|
||||
$this->manager->on_runner_complete( true );
|
||||
|
||||
parent::complete();
|
||||
}
|
||||
|
||||
public function continue_run() {
|
||||
// Used to fire an action added in WP_Background_Process::_construct() that calls WP_Background_Process::handle_cron_healthcheck().
|
||||
// This method will make sure the database updates are executed even if cron is disabled. Nothing will happen if the updates are already running.
|
||||
do_action( $this->cron_hook_identifier );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_current_item() {
|
||||
return $this->current_item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get batch.
|
||||
*
|
||||
* @return \stdClass Return the first batch from the queue.
|
||||
*/
|
||||
protected function get_batch() {
|
||||
$batch = parent::get_batch();
|
||||
$batch->data = array_filter( (array) $batch->data );
|
||||
|
||||
return $batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle cron healthcheck
|
||||
*
|
||||
* Restart the background process if not already running
|
||||
* and data exists in the queue.
|
||||
*/
|
||||
public function handle_cron_healthcheck() {
|
||||
if ( $this->is_process_running() ) {
|
||||
// Background process already running.
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->is_queue_empty() ) {
|
||||
// No data to process.
|
||||
$this->clear_scheduled_event();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->handle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule fallback event.
|
||||
*/
|
||||
protected function schedule_event() {
|
||||
if ( ! wp_next_scheduled( $this->cron_hook_identifier ) ) {
|
||||
wp_schedule_event( time() + 10, $this->cron_interval_identifier, $this->cron_hook_identifier );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the updater running?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_running() {
|
||||
return false === $this->is_queue_empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* See if the batch limit has been exceeded.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function batch_limit_exceeded() {
|
||||
return $this->time_exceeded() || $this->memory_exceeded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle.
|
||||
*
|
||||
* Pass each queue item to the task handler, while remaining
|
||||
* within server memory and time limit constraints.
|
||||
*/
|
||||
protected function handle() {
|
||||
$this->manager->on_runner_start();
|
||||
|
||||
$this->lock_process();
|
||||
|
||||
do {
|
||||
$batch = $this->get_batch();
|
||||
|
||||
foreach ( $batch->data as $key => $value ) {
|
||||
$task = $this->task( $value );
|
||||
|
||||
if ( false !== $task ) {
|
||||
$batch->data[ $key ] = $task;
|
||||
} else {
|
||||
unset( $batch->data[ $key ] );
|
||||
}
|
||||
|
||||
if ( $this->batch_limit_exceeded() ) {
|
||||
// Batch limits reached.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Update or delete current batch.
|
||||
if ( ! empty( $batch->data ) ) {
|
||||
$this->update( $batch->key, $batch->data );
|
||||
} else {
|
||||
$this->delete( $batch->key );
|
||||
}
|
||||
} while ( ! $this->batch_limit_exceeded() && ! $this->is_queue_empty() );
|
||||
|
||||
$this->unlock_process();
|
||||
|
||||
// Start next batch or complete process.
|
||||
if ( ! $this->is_queue_empty() ) {
|
||||
$this->dispatch();
|
||||
} else {
|
||||
$this->complete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the protected `is_process_running` method as a public method.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_process_locked() {
|
||||
return $this->is_process_running();
|
||||
}
|
||||
|
||||
public function handle_immediately( $callbacks ) {
|
||||
$this->manager->on_runner_start();
|
||||
|
||||
$this->lock_process();
|
||||
|
||||
foreach ( $callbacks as $callback ) {
|
||||
$item = [
|
||||
'callback' => $callback,
|
||||
];
|
||||
|
||||
do {
|
||||
$item = $this->task( $item );
|
||||
} while ( $item );
|
||||
}
|
||||
|
||||
$this->unlock_process();
|
||||
}
|
||||
|
||||
/**
|
||||
* Task
|
||||
*
|
||||
* Override this method to perform any actions required on each
|
||||
* queue item. Return the modified item for further processing
|
||||
* in the next pass through. Or, return false to remove the
|
||||
* item from the queue.
|
||||
*
|
||||
* @param array $item
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
protected function task( $item ) {
|
||||
$result = false;
|
||||
|
||||
if ( ! isset( $item['iterate_num'] ) ) {
|
||||
$item['iterate_num'] = 1;
|
||||
}
|
||||
|
||||
$logger = Plugin::$instance->logger->get_logger();
|
||||
$callback = $this->format_callback_log( $item );
|
||||
|
||||
if ( is_callable( $item['callback'] ) ) {
|
||||
$progress = '';
|
||||
|
||||
if ( 1 < $item['iterate_num'] ) {
|
||||
if ( empty( $item['total'] ) ) {
|
||||
$progress = sprintf( '(x%s)', $item['iterate_num'] );
|
||||
} else {
|
||||
$percent = ceil( $item['iterate_num'] / ( $item['total'] / 100 ) );
|
||||
$progress = sprintf( '(%s of %s, %s%%)', $item['iterate_num'], $item['total'], $percent );
|
||||
}
|
||||
}
|
||||
|
||||
$logger->info( sprintf( '%s Start %s', $callback, $progress ) );
|
||||
|
||||
$this->current_item = $item;
|
||||
|
||||
$result = (bool) call_user_func( $item['callback'], $this );
|
||||
|
||||
// get back the updated item.
|
||||
$item = $this->current_item;
|
||||
$this->current_item = null;
|
||||
|
||||
if ( $result ) {
|
||||
if ( empty( $item['total'] ) ) {
|
||||
$logger->info( sprintf( '%s callback needs to run again', $callback ) );
|
||||
} elseif ( 1 === $item['iterate_num'] ) {
|
||||
$logger->info( sprintf( '%s callback needs to run more %d times', $callback, $item['total'] - $item['iterate_num'] ) );
|
||||
}
|
||||
|
||||
$item['iterate_num']++;
|
||||
} else {
|
||||
$logger->info( sprintf( '%s Finished', $callback ) );
|
||||
}
|
||||
} else {
|
||||
$logger->notice( sprintf( 'Could not find %s callback', $callback ) );
|
||||
}
|
||||
|
||||
return $result ? $item : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule cron healthcheck.
|
||||
*
|
||||
* @param array $schedules Schedules.
|
||||
* @return array
|
||||
*/
|
||||
public function schedule_cron_healthcheck( $schedules ) {
|
||||
$interval = apply_filters( $this->identifier . '_cron_interval', 5 );
|
||||
|
||||
// Adds every 5 minutes to the existing schedules.
|
||||
$schedules[ $this->identifier . '_cron_interval' ] = array(
|
||||
'interval' => MINUTE_IN_SECONDS * $interval,
|
||||
'display' => sprintf(
|
||||
/* translators: %d: Interval in minutes. */
|
||||
esc_html__( 'Every %d minutes', 'elementor' ),
|
||||
$interval
|
||||
),
|
||||
);
|
||||
|
||||
return $schedules;
|
||||
}
|
||||
|
||||
/**
|
||||
* See if the batch limit has been exceeded.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_memory_exceeded() {
|
||||
return $this->memory_exceeded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all batches.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function delete_all_batches() {
|
||||
global $wpdb;
|
||||
|
||||
$table = $wpdb->options;
|
||||
$column = 'option_name';
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$table = $wpdb->sitemeta;
|
||||
$column = 'meta_key';
|
||||
}
|
||||
|
||||
$key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
|
||||
|
||||
$wpdb->query( $wpdb->prepare( "DELETE FROM {$table} WHERE {$column} LIKE %s", $key ) ); // @codingStandardsIgnoreLine.
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill process.
|
||||
*
|
||||
* Stop processing queue items, clear cronjob and delete all batches.
|
||||
*/
|
||||
public function kill_process() {
|
||||
if ( ! $this->is_queue_empty() ) {
|
||||
$this->delete_all_batches();
|
||||
wp_clear_scheduled_hook( $this->cron_hook_identifier );
|
||||
}
|
||||
}
|
||||
|
||||
public function set_current_item( $item ) {
|
||||
$this->current_item = $item;
|
||||
}
|
||||
|
||||
protected function format_callback_log( $item ) {
|
||||
return implode( '::', (array) $item['callback'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @var \Elementor\Core\Base\Background_Task_Manager
|
||||
*/
|
||||
protected $manager;
|
||||
|
||||
public function __construct( $manager ) {
|
||||
$this->manager = $manager;
|
||||
// Uses unique prefix per blog so each blog has separate queue.
|
||||
$this->prefix = 'elementor_' . get_current_blog_id();
|
||||
$this->action = $this->manager->get_action();
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
}
|
||||
193
wp-content/plugins/elementor/core/base/base-object.php
Normal file
193
wp-content/plugins/elementor/core/base/base-object.php
Normal file
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Core\Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
/**
|
||||
* Base Object
|
||||
*
|
||||
* Base class that provides basic settings handling functionality.
|
||||
*
|
||||
* @since 2.3.0
|
||||
*/
|
||||
class Base_Object {
|
||||
|
||||
/**
|
||||
* Settings.
|
||||
*
|
||||
* Holds the object settings.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* Get Settings.
|
||||
*
|
||||
* @since 2.3.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $setting Optional. The key of the requested setting. Default is null.
|
||||
*
|
||||
* @return mixed An array of all settings, or a single value if `$setting` was specified.
|
||||
*/
|
||||
final public function get_settings( $setting = null ) {
|
||||
$this->ensure_settings();
|
||||
|
||||
return self::get_items( $this->settings, $setting );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set settings.
|
||||
*
|
||||
* @since 2.3.0
|
||||
* @access public
|
||||
*
|
||||
* @param array|string $key If key is an array, the settings are overwritten by that array. Otherwise, the
|
||||
* settings of the key will be set to the given `$value` param.
|
||||
*
|
||||
* @param mixed $value Optional. Default is null.
|
||||
*/
|
||||
final public function set_settings( $key, $value = null ) {
|
||||
$this->ensure_settings();
|
||||
|
||||
if ( is_array( $key ) ) {
|
||||
$this->settings = $key;
|
||||
} else {
|
||||
$this->settings[ $key ] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete setting.
|
||||
*
|
||||
* Deletes the settings array or a specific key of the settings array if `$key` is specified.
|
||||
* @since 2.3.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $key Optional. Default is null.
|
||||
*/
|
||||
public function delete_setting( $key = null ) {
|
||||
if ( $key ) {
|
||||
unset( $this->settings[ $key ] );
|
||||
} else {
|
||||
$this->settings = [];
|
||||
}
|
||||
}
|
||||
|
||||
final public function merge_properties( array $default_props, array $custom_props, array $allowed_props_keys = [] ) {
|
||||
$props = array_replace_recursive( $default_props, $custom_props );
|
||||
|
||||
if ( $allowed_props_keys ) {
|
||||
$props = array_intersect_key( $props, array_flip( $allowed_props_keys ) );
|
||||
}
|
||||
|
||||
return $props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get items.
|
||||
*
|
||||
* Utility method that receives an array with a needle and returns all the
|
||||
* items that match the needle. If needle is not defined the entire haystack
|
||||
* will be returned.
|
||||
*
|
||||
* @since 2.3.0
|
||||
* @access protected
|
||||
* @static
|
||||
*
|
||||
* @param array $haystack An array of items.
|
||||
* @param string $needle Optional. Needle. Default is null.
|
||||
*
|
||||
* @return mixed The whole haystack or the needle from the haystack when requested.
|
||||
*/
|
||||
final protected static function get_items( array $haystack, $needle = null ) {
|
||||
if ( $needle ) {
|
||||
return isset( $haystack[ $needle ] ) ? $haystack[ $needle ] : null;
|
||||
}
|
||||
|
||||
return $haystack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get init settings.
|
||||
*
|
||||
* Used to define the default/initial settings of the object. Inheriting classes may implement this method to define
|
||||
* their own default/initial settings.
|
||||
*
|
||||
* @since 2.3.0
|
||||
* @access protected
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_init_settings() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure settings.
|
||||
*
|
||||
* Ensures that the `$settings` member is initialized
|
||||
*
|
||||
* @since 2.3.0
|
||||
* @access private
|
||||
*/
|
||||
private function ensure_settings() {
|
||||
if ( null === $this->settings ) {
|
||||
$this->settings = $this->get_init_settings();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Has Own Method
|
||||
*
|
||||
* Used for check whether the method passed as a parameter was declared in the current instance or inherited.
|
||||
* If a base_class_name is passed, it checks whether the method was declared in that class. If the method's
|
||||
* declaring class is the class passed as $base_class_name, it returns false. Otherwise (method was NOT declared
|
||||
* in $base_class_name), it returns true.
|
||||
*
|
||||
* Example #1 - only $method_name is passed:
|
||||
* The initial declaration of `register_controls()` happens in the `Controls_Stack` class. However, all
|
||||
* widgets which have their own controls declare this function as well, overriding the original
|
||||
* declaration. If `has_own_method()` would be called by a Widget's class which implements `register_controls()`,
|
||||
* with 'register_controls' passed as the first parameter - `has_own_method()` will return true. If the Widget
|
||||
* does not declare `register_controls()`, `has_own_method()` will return false.
|
||||
*
|
||||
* Example #2 - both $method_name and $base_class_name are passed
|
||||
* In this example, the widget class inherits from a base class `Widget_Base`, and the base implements
|
||||
* `register_controls()` to add certain controls to all widgets inheriting from it. `has_own_method()` is called by
|
||||
* the widget, with the string 'register_controls' passed as the first parameter, and 'Elementor\Widget_Base' (its full name
|
||||
* including the namespace) passed as the second parameter. If the widget class implements `register_controls()`,
|
||||
* `has_own_method` will return true. If the widget class DOESN'T implement `register_controls()`, it will return
|
||||
* false (because `Widget_Base` is the declaring class for `register_controls()`, and not the class that called
|
||||
* `has_own_method()`).
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param string $method_name
|
||||
* @param string $base_class_name
|
||||
*
|
||||
* @return bool True if the method was declared by the current instance, False if it was inherited.
|
||||
*/
|
||||
public function has_own_method( $method_name, $base_class_name = null ) {
|
||||
try {
|
||||
$reflection_method = new \ReflectionMethod( $this, $method_name );
|
||||
|
||||
// If a ReflectionMethod is successfully created, get its declaring class.
|
||||
$declaring_class = $reflection_method->getDeclaringClass();
|
||||
} catch ( \Exception $e ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $base_class_name ) {
|
||||
return $base_class_name !== $declaring_class->name;
|
||||
}
|
||||
|
||||
return get_called_class() === $declaring_class->name;
|
||||
}
|
||||
}
|
||||
242
wp-content/plugins/elementor/core/base/db-upgrades-manager.php
Normal file
242
wp-content/plugins/elementor/core/base/db-upgrades-manager.php
Normal file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Core\Base;
|
||||
|
||||
use Elementor\Core\Admin\Admin_Notices;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
abstract class DB_Upgrades_Manager extends Background_Task_Manager {
|
||||
protected $current_version = null;
|
||||
protected $query_limit = 100;
|
||||
|
||||
abstract public function get_new_version();
|
||||
abstract public function get_version_option_name();
|
||||
abstract public function get_upgrades_class();
|
||||
abstract public function get_updater_label();
|
||||
|
||||
public function get_task_runner_class() {
|
||||
return 'Elementor\Core\Upgrade\Updater';
|
||||
}
|
||||
|
||||
public function get_query_limit() {
|
||||
return $this->query_limit;
|
||||
}
|
||||
|
||||
public function set_query_limit( $limit ) {
|
||||
$this->query_limit = $limit;
|
||||
}
|
||||
|
||||
public function get_current_version() {
|
||||
if ( null === $this->current_version ) {
|
||||
$this->current_version = get_option( $this->get_version_option_name() );
|
||||
}
|
||||
|
||||
return $this->current_version;
|
||||
}
|
||||
|
||||
public function should_upgrade() {
|
||||
$current_version = $this->get_current_version();
|
||||
|
||||
// It's a new install.
|
||||
if ( ! $current_version ) {
|
||||
$this->update_db_version();
|
||||
return false;
|
||||
}
|
||||
|
||||
return version_compare( $this->get_new_version(), $current_version, '>' );
|
||||
}
|
||||
|
||||
public function on_runner_start() {
|
||||
parent::on_runner_start();
|
||||
|
||||
if ( ! defined( 'IS_ELEMENTOR_UPGRADE' ) ) {
|
||||
define( 'IS_ELEMENTOR_UPGRADE', true );
|
||||
}
|
||||
}
|
||||
|
||||
public function on_runner_complete( $did_tasks = false ) {
|
||||
$logger = Plugin::$instance->logger->get_logger();
|
||||
|
||||
$logger->info( 'Elementor data updater process has been completed.', [
|
||||
'meta' => [
|
||||
'plugin' => $this->get_plugin_label(),
|
||||
'from' => $this->current_version,
|
||||
'to' => $this->get_new_version(),
|
||||
],
|
||||
] );
|
||||
|
||||
$this->clear_cache();
|
||||
|
||||
$this->update_db_version();
|
||||
|
||||
if ( $did_tasks ) {
|
||||
$this->add_flag( 'completed' );
|
||||
}
|
||||
}
|
||||
|
||||
protected function clear_cache() {
|
||||
Plugin::$instance->files_manager->clear_cache();
|
||||
}
|
||||
|
||||
public function admin_notice_start_upgrade() {
|
||||
/**
|
||||
* @var Admin_Notices $admin_notices
|
||||
*/
|
||||
$admin_notices = Plugin::$instance->admin->get_component( 'admin-notices' );
|
||||
|
||||
$options = [
|
||||
'title' => $this->get_updater_label(),
|
||||
'description' => esc_html__( 'Your site database needs to be updated to the latest version.', 'elementor' ),
|
||||
'type' => 'error',
|
||||
'icon' => false,
|
||||
'button' => [
|
||||
'text' => esc_html__( 'Update Now', 'elementor' ),
|
||||
'url' => $this->get_start_action_url(),
|
||||
'class' => 'e-button e-button--cta',
|
||||
],
|
||||
];
|
||||
|
||||
$admin_notices->print_admin_notice( $options );
|
||||
}
|
||||
|
||||
public function admin_notice_upgrade_is_running() {
|
||||
/**
|
||||
* @var Admin_Notices $admin_notices
|
||||
*/
|
||||
$admin_notices = Plugin::$instance->admin->get_component( 'admin-notices' );
|
||||
|
||||
$options = [
|
||||
'title' => $this->get_updater_label(),
|
||||
'description' => esc_html__( 'Database update process is running in the background. Taking a while?', 'elementor' ),
|
||||
'type' => 'warning',
|
||||
'icon' => false,
|
||||
'button' => [
|
||||
'text' => esc_html__( 'Click here to run it now', 'elementor' ),
|
||||
'url' => $this->get_continue_action_url(),
|
||||
'class' => 'e-button e-button--primary',
|
||||
],
|
||||
];
|
||||
|
||||
$admin_notices->print_admin_notice( $options );
|
||||
}
|
||||
|
||||
public function admin_notice_upgrade_is_completed() {
|
||||
$this->delete_flag( 'completed' );
|
||||
|
||||
$message = esc_html__( 'The database update process is now complete. Thank you for updating to the latest version!', 'elementor' );
|
||||
|
||||
/**
|
||||
* @var Admin_Notices $admin_notices
|
||||
*/
|
||||
$admin_notices = Plugin::$instance->admin->get_component( 'admin-notices' );
|
||||
|
||||
$options = [
|
||||
'description' => '<b>' . $this->get_updater_label() . '</b> - ' . $message,
|
||||
'type' => 'success',
|
||||
'icon' => false,
|
||||
];
|
||||
|
||||
$admin_notices->print_admin_notice( $options );
|
||||
}
|
||||
|
||||
/**
|
||||
* @access protected
|
||||
*/
|
||||
protected function start_run() {
|
||||
$updater = $this->get_task_runner();
|
||||
|
||||
if ( $updater->is_running() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$upgrade_callbacks = $this->get_upgrade_callbacks();
|
||||
|
||||
if ( empty( $upgrade_callbacks ) ) {
|
||||
$this->on_runner_complete();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->clear_cache();
|
||||
|
||||
foreach ( $upgrade_callbacks as $callback ) {
|
||||
$updater->push_to_queue( [
|
||||
'callback' => $callback,
|
||||
] );
|
||||
}
|
||||
|
||||
$updater->save()->dispatch();
|
||||
|
||||
Plugin::$instance->logger->get_logger()->info( 'Elementor data updater process has been queued.', [
|
||||
'meta' => [
|
||||
'plugin' => $this->get_plugin_label(),
|
||||
'from' => $this->current_version,
|
||||
'to' => $this->get_new_version(),
|
||||
],
|
||||
] );
|
||||
}
|
||||
|
||||
protected function update_db_version() {
|
||||
update_option( $this->get_version_option_name(), $this->get_new_version() );
|
||||
}
|
||||
|
||||
public function get_upgrade_callbacks() {
|
||||
$prefix = '_v_';
|
||||
$upgrades_class = $this->get_upgrades_class();
|
||||
$upgrades_reflection = new \ReflectionClass( $upgrades_class );
|
||||
|
||||
$callbacks = [];
|
||||
|
||||
foreach ( $upgrades_reflection->getMethods() as $method ) {
|
||||
$method_name = $method->getName();
|
||||
|
||||
if ( '_on_each_version' === $method_name ) {
|
||||
$callbacks[] = [ $upgrades_class, $method_name ];
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( false === strpos( $method_name, $prefix ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! preg_match_all( "/$prefix(\d+_\d+_\d+)/", $method_name, $matches ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$method_version = str_replace( '_', '.', $matches[1][0] );
|
||||
|
||||
if ( ! version_compare( $method_version, $this->current_version, '>' ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$callbacks[] = [ $upgrades_class, $method_name ];
|
||||
}
|
||||
|
||||
return $callbacks;
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
// If upgrade is completed - show the notice only for admins.
|
||||
// Note: in this case `should_upgrade` returns false, because it's already upgraded.
|
||||
if ( is_admin() && current_user_can( 'update_plugins' ) && $this->get_flag( 'completed' ) ) {
|
||||
add_action( 'admin_notices', [ $this, 'admin_notice_upgrade_is_completed' ] );
|
||||
}
|
||||
|
||||
if ( ! $this->should_upgrade() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$updater = $this->get_task_runner();
|
||||
|
||||
$this->start_run();
|
||||
|
||||
if ( $updater->is_running() && current_user_can( 'update_plugins' ) ) {
|
||||
add_action( 'admin_notices', [ $this, 'admin_notice_upgrade_is_running' ] );
|
||||
}
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
}
|
||||
1932
wp-content/plugins/elementor/core/base/document.php
Normal file
1932
wp-content/plugins/elementor/core/base/document.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
namespace Elementor\Core\Base\Elements_Iteration_Actions;
|
||||
|
||||
use Elementor\Conditions;
|
||||
use Elementor\Element_Base;
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Assets extends Base {
|
||||
const ASSETS_META_KEY = '_elementor_page_assets';
|
||||
|
||||
// Default value must be empty.
|
||||
private $page_assets;
|
||||
|
||||
// Default value must be empty.
|
||||
private $saved_page_assets;
|
||||
|
||||
public function element_action( Element_Base $element_data ) {
|
||||
$settings = $element_data->get_active_settings();
|
||||
$controls = $element_data->get_controls();
|
||||
|
||||
$element_assets = $this->get_assets( $settings, $controls );
|
||||
|
||||
if ( $element_assets ) {
|
||||
$this->update_page_assets( $element_assets );
|
||||
}
|
||||
}
|
||||
|
||||
public function is_action_needed() {
|
||||
// No need to evaluate in preview mode, will be made in the saving process.
|
||||
if ( Plugin::$instance->preview->is_preview_mode() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$page_assets = $this->get_saved_page_assets();
|
||||
|
||||
// When $page_assets is array it means that the assets registration has already been made at least once.
|
||||
if ( is_array( $page_assets ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function after_elements_iteration() {
|
||||
// In case that the page assets value is empty, it should still be saved as an empty array as an indication that at lease one iteration has occurred.
|
||||
if ( ! is_array( $this->page_assets ) ) {
|
||||
$this->page_assets = [];
|
||||
}
|
||||
|
||||
$this->get_document_assets();
|
||||
|
||||
// Saving the page assets data.
|
||||
$this->document->update_meta( self::ASSETS_META_KEY, $this->page_assets );
|
||||
|
||||
if ( 'render' === $this->mode && $this->page_assets ) {
|
||||
Plugin::$instance->assets_loader->enable_assets( $this->page_assets );
|
||||
}
|
||||
}
|
||||
|
||||
private function get_saved_page_assets( $force_meta_fetch = false ) {
|
||||
if ( ! is_array( $this->saved_page_assets ) || $force_meta_fetch ) {
|
||||
$this->saved_page_assets = $this->document->get_meta( self::ASSETS_META_KEY );
|
||||
}
|
||||
|
||||
return $this->saved_page_assets;
|
||||
}
|
||||
|
||||
private function update_page_assets( $new_assets ) {
|
||||
if ( ! is_array( $this->page_assets ) ) {
|
||||
$this->page_assets = [];
|
||||
}
|
||||
|
||||
foreach ( $new_assets as $assets_type => $assets_type_data ) {
|
||||
if ( ! isset( $this->page_assets[ $assets_type ] ) ) {
|
||||
$this->page_assets[ $assets_type ] = [];
|
||||
}
|
||||
|
||||
foreach ( $assets_type_data as $asset_name ) {
|
||||
if ( ! in_array( $asset_name, $this->page_assets[ $assets_type ], true ) ) {
|
||||
$this->page_assets[ $assets_type ][] = $asset_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function get_assets( $settings, $controls ) {
|
||||
$assets = [];
|
||||
|
||||
foreach ( $settings as $setting_key => $setting ) {
|
||||
if ( ! isset( $controls[ $setting_key ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$control = $controls[ $setting_key ];
|
||||
|
||||
// Enabling assets loading from the registered control fields.
|
||||
if ( ! empty( $control['assets'] ) ) {
|
||||
foreach ( $control['assets'] as $assets_type => $dependencies ) {
|
||||
foreach ( $dependencies as $dependency ) {
|
||||
if ( ! empty( $dependency['conditions'] ) ) {
|
||||
$is_condition_fulfilled = Conditions::check( $dependency['conditions'], $settings );
|
||||
|
||||
if ( ! $is_condition_fulfilled ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! isset( $assets[ $assets_type ] ) ) {
|
||||
$assets[ $assets_type ] = [];
|
||||
}
|
||||
|
||||
$assets[ $assets_type ][] = $dependency['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enabling assets loading from the control object.
|
||||
$control_obj = Plugin::$instance->controls_manager->get_control( $control['type'] );
|
||||
|
||||
$control_conditional_assets = $control_obj::get_assets( $setting );
|
||||
|
||||
if ( $control_conditional_assets ) {
|
||||
foreach ( $control_conditional_assets as $assets_type => $dependencies ) {
|
||||
foreach ( $dependencies as $dependency ) {
|
||||
if ( ! isset( $assets[ $assets_type ] ) ) {
|
||||
$assets[ $assets_type ] = [];
|
||||
}
|
||||
|
||||
$assets[ $assets_type ][] = $dependency;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $assets;
|
||||
}
|
||||
|
||||
private function get_document_assets() {
|
||||
$document_id = $this->document->get_post()->ID;
|
||||
|
||||
// Getting the document instance in order to get the most updated settings.
|
||||
$updated_document = Plugin::$instance->documents->get( $document_id, false );
|
||||
|
||||
$document_settings = $updated_document->get_settings();
|
||||
|
||||
$document_controls = $this->document->get_controls();
|
||||
|
||||
$document_assets = $this->get_assets( $document_settings, $document_controls );
|
||||
|
||||
if ( $document_assets ) {
|
||||
$this->update_page_assets( $document_assets );
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct( $document ) {
|
||||
parent::__construct( $document );
|
||||
|
||||
// No need to enable assets in preview mode, all assets will be loaded by default by the assets loader.
|
||||
if ( Plugin::$instance->preview->is_preview_mode() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$page_assets = $this->get_saved_page_assets();
|
||||
|
||||
// If $page_assets is not empty then enabling the assets for loading.
|
||||
if ( $page_assets ) {
|
||||
Plugin::$instance->assets_loader->enable_assets( $page_assets );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
namespace Elementor\Core\Base\Elements_Iteration_Actions;
|
||||
|
||||
use Elementor\Element_Base;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
abstract class Base {
|
||||
/**
|
||||
* The current document that the Base class instance was created from.
|
||||
*/
|
||||
protected $document;
|
||||
|
||||
/**
|
||||
* Indicates if the methods are being triggered on page save or at render time (value will be either 'save' or 'render').
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $mode = '';
|
||||
|
||||
/**
|
||||
* Is Action Needed.
|
||||
*
|
||||
* Runs only at runtime and used as a flag to determine if all methods should run on page render.
|
||||
* If returns false, all methods will run only on page save.
|
||||
* If returns true, all methods will run on both page render and on save.
|
||||
*
|
||||
* @since 3.3.0
|
||||
* @access public
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function is_action_needed();
|
||||
|
||||
/**
|
||||
* Unique Element Action.
|
||||
*
|
||||
* Will be triggered for each unique page element - section / column / widget unique type (heading, icon etc.).
|
||||
*
|
||||
* @since 3.3.0
|
||||
* @access public
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unique_element_action( Element_Base $element_data ) {}
|
||||
|
||||
/**
|
||||
* Element Action.
|
||||
*
|
||||
* Will be triggered for each page element - section / column / widget.
|
||||
*
|
||||
* @since 3.3.0
|
||||
* @access public
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function element_action( Element_Base $element_data ) {}
|
||||
|
||||
/**
|
||||
* After Elements Iteration.
|
||||
*
|
||||
* Will be triggered after all page elements iteration has ended.
|
||||
*
|
||||
* @since 3.3.0
|
||||
* @access public
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function after_elements_iteration() {}
|
||||
|
||||
public function set_mode( $mode ) {
|
||||
$this->mode = $mode;
|
||||
}
|
||||
|
||||
public function __construct( $document ) {
|
||||
$this->document = $document;
|
||||
}
|
||||
}
|
||||
338
wp-content/plugins/elementor/core/base/module.php
Normal file
338
wp-content/plugins/elementor/core/base/module.php
Normal file
@@ -0,0 +1,338 @@
|
||||
<?php
|
||||
namespace Elementor\Core\Base;
|
||||
|
||||
use Elementor\Plugin;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Elementor module.
|
||||
*
|
||||
* An abstract class that provides the needed properties and methods to
|
||||
* manage and handle modules in inheriting classes.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @abstract
|
||||
*/
|
||||
abstract class Module extends Base_Object {
|
||||
|
||||
/**
|
||||
* Module class reflection.
|
||||
*
|
||||
* Holds the information about a class.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @access private
|
||||
*
|
||||
* @var \ReflectionClass
|
||||
*/
|
||||
private $reflection;
|
||||
|
||||
/**
|
||||
* Module components.
|
||||
*
|
||||
* Holds the module components.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @access private
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $components = [];
|
||||
|
||||
/**
|
||||
* Module instance.
|
||||
*
|
||||
* Holds the module instance.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @access protected
|
||||
*
|
||||
* @var Module
|
||||
*/
|
||||
protected static $_instances = [];
|
||||
|
||||
/**
|
||||
* Get module name.
|
||||
*
|
||||
* Retrieve the module name.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
* @abstract
|
||||
*
|
||||
* @return string Module name.
|
||||
*/
|
||||
abstract public function get_name();
|
||||
|
||||
/**
|
||||
* Instance.
|
||||
*
|
||||
* Ensures only one instance of the module class is loaded or can be loaded.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @return Module An instance of the class.
|
||||
*/
|
||||
public static function instance() {
|
||||
$class_name = static::class_name();
|
||||
|
||||
if ( empty( static::$_instances[ $class_name ] ) ) {
|
||||
static::$_instances[ $class_name ] = new static();
|
||||
}
|
||||
|
||||
return static::$_instances[ $class_name ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function is_active() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class name.
|
||||
*
|
||||
* Retrieve the name of the class.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function class_name() {
|
||||
return get_called_class();
|
||||
}
|
||||
|
||||
public static function get_experimental_data() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone.
|
||||
*
|
||||
* Disable class cloning and throw an error on object clone.
|
||||
*
|
||||
* The whole idea of the singleton design pattern is that there is a single
|
||||
* object. Therefore, we don't want the object to be cloned.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
*/
|
||||
public function __clone() {
|
||||
_doing_it_wrong(
|
||||
__FUNCTION__,
|
||||
sprintf( 'Cloning instances of the singleton "%s" class is forbidden.', get_class( $this ) ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
'1.0.0'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wakeup.
|
||||
*
|
||||
* Disable unserializing of the class.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
*/
|
||||
public function __wakeup() {
|
||||
_doing_it_wrong(
|
||||
__FUNCTION__,
|
||||
sprintf( 'Unserializing instances of the singleton "%s" class is forbidden.', get_class( $this ) ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
'1.0.0'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0.0
|
||||
* @access public
|
||||
*/
|
||||
public function get_reflection() {
|
||||
if ( null === $this->reflection ) {
|
||||
$this->reflection = new \ReflectionClass( $this );
|
||||
}
|
||||
|
||||
return $this->reflection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add module component.
|
||||
*
|
||||
* Add new component to the current module.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $id Component ID.
|
||||
* @param mixed $instance An instance of the component.
|
||||
*/
|
||||
public function add_component( $id, $instance ) {
|
||||
$this->components[ $id ] = $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.3.0
|
||||
* @access public
|
||||
* @return Module[]
|
||||
*/
|
||||
public function get_components() {
|
||||
return $this->components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get module component.
|
||||
*
|
||||
* Retrieve the module component.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $id Component ID.
|
||||
*
|
||||
* @return mixed An instance of the component, or `false` if the component
|
||||
* doesn't exist.
|
||||
*/
|
||||
public function get_component( $id ) {
|
||||
if ( isset( $this->components[ $id ] ) ) {
|
||||
return $this->components[ $id ];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get assets url.
|
||||
*
|
||||
* @since 2.3.0
|
||||
* @access protected
|
||||
*
|
||||
* @param string $file_name
|
||||
* @param string $file_extension
|
||||
* @param string $relative_url Optional. Default is null.
|
||||
* @param string $add_min_suffix Optional. Default is 'default'.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
final protected function get_assets_url( $file_name, $file_extension, $relative_url = null, $add_min_suffix = 'default' ) {
|
||||
static $is_test_mode = null;
|
||||
|
||||
if ( null === $is_test_mode ) {
|
||||
$is_test_mode = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || defined( 'ELEMENTOR_TESTS' ) && ELEMENTOR_TESTS;
|
||||
}
|
||||
|
||||
if ( ! $relative_url ) {
|
||||
$relative_url = $this->get_assets_relative_url() . $file_extension . '/';
|
||||
}
|
||||
|
||||
$url = $this->get_assets_base_url() . $relative_url . $file_name;
|
||||
|
||||
if ( 'default' === $add_min_suffix ) {
|
||||
$add_min_suffix = ! $is_test_mode;
|
||||
}
|
||||
|
||||
if ( $add_min_suffix ) {
|
||||
$url .= '.min';
|
||||
}
|
||||
|
||||
return $url . '.' . $file_extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get js assets url
|
||||
*
|
||||
* @since 2.3.0
|
||||
* @access protected
|
||||
*
|
||||
* @param string $file_name
|
||||
* @param string $relative_url Optional. Default is null.
|
||||
* @param string $add_min_suffix Optional. Default is 'default'.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
final protected function get_js_assets_url( $file_name, $relative_url = null, $add_min_suffix = 'default' ) {
|
||||
return $this->get_assets_url( $file_name, 'js', $relative_url, $add_min_suffix );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get css assets url
|
||||
*
|
||||
* @since 2.3.0
|
||||
* @access protected
|
||||
*
|
||||
* @param string $file_name
|
||||
* @param string $relative_url Optional. Default is null.
|
||||
* @param string $add_min_suffix Optional. Default is 'default'.
|
||||
* @param bool $add_direction_suffix Optional. Default is `false`
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
final protected function get_css_assets_url( $file_name, $relative_url = null, $add_min_suffix = 'default', $add_direction_suffix = false ) {
|
||||
static $direction_suffix = null;
|
||||
|
||||
if ( ! $direction_suffix ) {
|
||||
$direction_suffix = is_rtl() ? '-rtl' : '';
|
||||
}
|
||||
|
||||
if ( $add_direction_suffix ) {
|
||||
$file_name .= $direction_suffix;
|
||||
}
|
||||
|
||||
return $this->get_assets_url( $file_name, 'css', $relative_url, $add_min_suffix );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get assets base url
|
||||
*
|
||||
* @since 2.6.0
|
||||
* @access protected
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_assets_base_url() {
|
||||
return ELEMENTOR_URL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get assets relative url
|
||||
*
|
||||
* @since 2.3.0
|
||||
* @access protected
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_assets_relative_url() {
|
||||
return 'assets/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the module's associated widgets.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function get_widgets() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the module related widgets.
|
||||
*/
|
||||
public function init_widgets() {
|
||||
$widget_manager = Plugin::instance()->widgets_manager;
|
||||
|
||||
foreach ( $this->get_widgets() as $widget ) {
|
||||
$class_name = $this->get_reflection()->getNamespaceName() . '\Widgets\\' . $widget;
|
||||
|
||||
$widget_manager->register( new $class_name() );
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'elementor/widgets/register', [ $this, 'init_widgets' ] );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user