D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
home
/
everqlsh
/
public_html
/
wp-admin
/
user
/
577040
/
Filename :
common.tar
back
Copy
modules/ajax/module.php 0000644 00000016235 15162355075 0011155 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Ajax; use Elementor\Core\Base\Module as BaseModule; use Elementor\Core\Utils\Exceptions; use Elementor\Plugin; use Elementor\Utils; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Elementor ajax manager. * * Elementor ajax manager handler class is responsible for handling Elementor * ajax requests, ajax responses and registering actions applied on them. * * @since 2.0.0 */ class Module extends BaseModule { const NONCE_KEY = 'elementor_ajax'; /** * Ajax actions. * * Holds all the register ajax action. * * @since 2.0.0 * @access private * * @var array */ private $ajax_actions = []; /** * Ajax requests. * * Holds all the register ajax requests. * * @since 2.0.0 * @access private * * @var array */ private $requests = []; /** * Ajax response data. * * Holds all the response data for all the ajax requests. * * @since 2.0.0 * @access private * * @var array */ private $response_data = []; /** * Current ajax action ID. * * Holds all the ID for the current ajax action. * * @since 2.0.0 * @access private * * @var string|null */ private $current_action_id = null; /** * Ajax manager constructor. * * Initializing Elementor ajax manager. * * @since 2.0.0 * @access public */ public function __construct() { add_action( 'wp_ajax_elementor_ajax', [ $this, 'handle_ajax_request' ] ); } /** * Get module name. * * Retrieve the module name. * * @since 1.7.0 * @access public * * @return string Module name. */ public function get_name() { return 'ajax'; } /** * Register ajax action. * * Add new actions for a specific ajax request and the callback function to * be handle the response. * * @since 2.0.0 * @access public * * @param string $tag Ajax request name/tag. * @param callable $callback The callback function. */ public function register_ajax_action( $tag, $callback ) { if ( ! did_action( 'elementor/ajax/register_actions' ) ) { _doing_it_wrong( __METHOD__, esc_html( sprintf( 'Use `%s` hook to register ajax action.', 'elementor/ajax/register_actions' ) ), '2.0.0' ); } $this->ajax_actions[ $tag ] = compact( 'tag', 'callback' ); } /** * Handle ajax request. * * Verify ajax nonce, and run all the registered actions for this request. * * Fired by `wp_ajax_elementor_ajax` action. * * @since 2.0.0 * @access public */ public function handle_ajax_request() { if ( ! $this->verify_request_nonce() ) { $this->add_response_data( false, esc_html__( 'Token Expired.', 'elementor' ) ) ->send_error( Exceptions::UNAUTHORIZED ); } $editor_post_id = 0; if ( ! empty( $_REQUEST['editor_post_id'] ) ) { $editor_post_id = absint( $_REQUEST['editor_post_id'] ); Plugin::$instance->db->switch_to_post( $editor_post_id ); } /** * Register ajax actions. * * Fires when an ajax request is received and verified. * * Used to register new ajax action handles. * * @since 2.0.0 * * @param self $this An instance of ajax manager. */ do_action( 'elementor/ajax/register_actions', $this ); if ( ! empty( $_REQUEST['actions'] ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, each action should sanitize its own data. $this->requests = json_decode( wp_unslash( $_REQUEST['actions'] ), true ); } foreach ( $this->requests as $id => $action_data ) { $this->current_action_id = $id; if ( ! isset( $this->ajax_actions[ $action_data['action'] ] ) ) { $this->add_response_data( false, esc_html__( 'Action not found.', 'elementor' ), Exceptions::BAD_REQUEST ); continue; } if ( $editor_post_id ) { $action_data['data']['editor_post_id'] = $editor_post_id; } try { $data = $action_data['data'] ?? []; $results = call_user_func( $this->ajax_actions[ $action_data['action'] ]['callback'], $data, $this ); if ( false === $results ) { $this->add_response_data( false ); } else { $this->add_response_data( true, $results ); } } catch ( \Exception $e ) { $this->add_response_data( false, $e->getMessage(), $e->getCode() ); } } $this->current_action_id = null; $this->send_success(); } /** * Get current action data. * * Retrieve the data for the current ajax request. * * @since 2.0.1 * @access public * * @return bool|mixed Ajax request data if action exist, False otherwise. */ public function get_current_action_data() { if ( ! $this->current_action_id ) { return false; } return $this->requests[ $this->current_action_id ]; } /** * Create nonce. * * Creates a cryptographic token to * give the user an access to Elementor ajax actions. * * @since 2.3.0 * @access public * * @return string The nonce token. */ public function create_nonce() { return wp_create_nonce( self::NONCE_KEY ); } /** * Verify request nonce. * * Whether the request nonce verified or not. * * @since 2.3.0 * @access public * * @return bool True if request nonce verified, False otherwise. */ public function verify_request_nonce() { return wp_verify_nonce( Utils::get_super_global_value( $_REQUEST, '_nonce' ), self::NONCE_KEY ); } protected function get_init_settings() { return [ 'url' => admin_url( 'admin-ajax.php' ), 'nonce' => $this->create_nonce(), ]; } /** * Ajax success response. * * Send a JSON response data back to the ajax request, indicating success. * * @since 2.0.0 * @access protected */ private function send_success() { $response = [ 'success' => true, 'data' => [ 'responses' => $this->response_data, ], ]; $json = wp_json_encode( $response ); while ( ob_get_status() ) { ob_end_clean(); } if ( function_exists( 'gzencode' ) ) { $response = gzencode( $json ); header( 'Content-Type: application/json; charset=utf-8' ); header( 'Content-Encoding: gzip' ); header( 'Content-Length: ' . strlen( $response ) ); echo $response; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } else { echo $json; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } wp_die( '', '', [ 'response' => null ] ); } /** * Ajax failure response. * * Send a JSON response data back to the ajax request, indicating failure. * * @since 2.0.0 * @access protected * * @param null $code */ private function send_error( $code = null ) { wp_send_json_error( [ 'responses' => $this->response_data, ], $code ); } /** * Add response data. * * Add new response data to the array of all the ajax requests. * * @since 2.0.0 * @access protected * * @param bool $success True if the requests returned successfully, False * otherwise. * @param mixed $data Optional. Response data. Default is null. * * @param int $code Optional. Response code. Default is 200. * * @return Module An instance of ajax manager. */ private function add_response_data( $success, $data = null, $code = 200 ) { $this->response_data[ $this->current_action_id ] = [ 'success' => $success, 'code' => $code, 'data' => $data, ]; return $this; } } modules/connect/admin.php 0000644 00000004613 15162355075 0011463 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Connect; use Elementor\Core\Admin\Menu\Admin_Menu_Manager; use Elementor\Plugin; use Elementor\Settings; use Elementor\Utils; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Admin { const PAGE_ID = 'elementor-connect'; public static $url = ''; /** * @since 2.3.0 * @access public */ public function register_admin_menu( Admin_Menu_Manager $admin_menu ) { $admin_menu->register( static::PAGE_ID, new Connect_Menu_Item() ); } /** * @since 2.3.0 * @access public */ public function on_load_page() { if ( ! $this->user_has_enough_permissions() ) { wp_die( 'You do not have sufficient permissions to access this page.', 'You do not have sufficient permissions to access this page.', [ 'back_link' => true, ] ); } if ( isset( $_GET['action'], $_GET['app'] ) ) { $manager = Plugin::$instance->common->get_component( 'connect' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $app_slug = Utils::get_super_global_value( $_GET, 'app' ); $app = $manager->get_app( $app_slug ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $action = Utils::get_super_global_value( $_GET, 'action' ); $nonce_action = $app_slug . $action; if ( ! $app ) { wp_die( 'Unknown app: ' . esc_attr( $app_slug ) ); } if ( ! wp_verify_nonce( Utils::get_super_global_value( $_GET, 'nonce' ), $nonce_action ) ) { wp_die( 'Invalid Nonce', 'Invalid Nonce', [ 'back_link' => true, ] ); } $method = 'action_' . $action; if ( method_exists( $app, $method ) ) { call_user_func( [ $app, $method ] ); } } } private function user_has_enough_permissions() { if ( current_user_can( 'manage_options' ) ) { return true; } if ( 'library' === Utils::get_super_global_value( $_GET, 'app' ) ) { return current_user_can( 'edit_posts' ); } return false; } /** * @since 2.3.0 * @access public */ public function __construct() { self::$url = admin_url( 'admin.php?page=' . self::PAGE_ID ); add_action( 'elementor/admin/menu/register', [ $this, 'register_admin_menu' ] ); add_action( 'elementor/admin/menu/after_register', function ( Admin_Menu_Manager $admin_menu, array $hooks ) { if ( ! empty( $hooks[ static::PAGE_ID ] ) ) { add_action( 'load-' . $hooks[ static::PAGE_ID ], [ $this, 'on_load_page' ] ); } }, 10, 2 ); } } modules/connect/connect-menu-item.php 0000644 00000002237 15162355076 0013723 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Connect; use Elementor\Core\Admin\Menu\Interfaces\Admin_Menu_Item_With_Page; use Elementor\Core\Common\Modules\Connect\Apps\Base_App; use Elementor\Plugin; use Elementor\Settings; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Connect_Menu_Item implements Admin_Menu_Item_With_Page { public function is_visible() { return false; } public function get_parent_slug() { return Settings::PAGE_ID; } public function get_label() { return esc_html__( 'Connect', 'elementor' ); } public function get_page_title() { return esc_html__( 'Connect', 'elementor' ); } public function get_capability() { return 'edit_posts'; } public function render() { $apps = Plugin::$instance->common->get_component( 'connect' )->get_apps(); ?> <style> .elementor-connect-app-wrapper{ margin-bottom: 50px; overflow: hidden; } </style> <div class="wrap"> <?php /** @var Base_App $app */ foreach ( $apps as $app ) { echo '<div class="elementor-connect-app-wrapper">'; $app->render_admin_widget(); echo '</div>'; } ?> </div><!-- /.wrap --> <?php } } modules/connect/module.php 0000644 00000013252 15162355076 0011660 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Connect; use Elementor\Core\Base\Module as BaseModule; use Elementor\Core\Common\Modules\Connect\Apps\Base_App; use Elementor\Core\Common\Modules\Connect\Apps\Common_App; use Elementor\Core\Common\Modules\Connect\Apps\Connect; use Elementor\Core\Common\Modules\Connect\Apps\Library; use Elementor\Plugin; use Elementor\Utils; use WP_User_Query; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Module extends BaseModule { const ACCESS_LEVEL_CORE = 0; const ACCESS_LEVEL_PRO = 1; const ACCESS_LEVEL_EXPERT = 20; const ACCESS_TIER_FREE = 'free'; const ACCESS_TIER_ESSENTIAL = 'essential'; const ACCESS_TIER_ESSENTIAL_OCT_2023 = 'essential-oct2023'; const ACCESS_TIER_ADVANCED = 'advanced'; const ACCESS_TIER_EXPERT = 'expert'; const ACCESS_TIER_AGENCY = 'agency'; const ACCESS_TIER_PRO_LEGACY = 'pro'; /** * @since 2.3.0 * @access public */ public function get_name() { return 'connect'; } /** * @var array */ protected $registered_apps = []; /** * Apps Instances. * * Holds the list of all the apps instances. * * @since 2.3.0 * @access protected * * @var Base_App[] */ protected $apps = []; /** * Registered apps categories. * * Holds the list of all the registered apps categories. * * @since 2.3.0 * @access protected * * @var array */ protected $categories = []; protected $admin_page; /** * @since 2.3.0 * @access public */ public function __construct() { $this->registered_apps = [ 'connect' => Connect::get_class_name(), 'library' => Library::get_class_name(), ]; // When using REST API the parent module is construct after the action 'elementor/init' // so this part of code make sure to register the module "apps". if ( did_action( 'elementor/init' ) ) { $this->init(); } else { // Note: The priority 11 is for allowing plugins to add their register callback on elementor init. add_action( 'elementor/init', [ $this, 'init' ], 11 ); } add_filter( 'elementor/tracker/send_tracking_data_params', function ( $params ) { return $this->add_tracking_data( $params ); } ); } /** * Register default apps. * * Registers the default apps. * * @since 2.3.0 * @access public */ public function init() { if ( is_admin() ) { $this->admin_page = new Admin(); } /** * Register Elementor apps. * * Fires after Elementor registers the default apps. * * @since 2.3.0 * * @param self $this The apps manager instance. */ do_action( 'elementor/connect/apps/register', $this ); foreach ( $this->registered_apps as $slug => $class ) { $this->apps[ $slug ] = new $class(); } } /** * Register app. * * Registers an app. * * @since 2.3.0 * @access public * * @param string $slug App slug. * @param string $class App full class name. * * @return self The updated apps manager instance. */ public function register_app( $slug, $class ) { $this->registered_apps[ $slug ] = $class; return $this; } /** * Get app instance. * * Retrieve the app instance. * * @since 2.3.0 * @access public * * @param $slug * * @return Base_App|null */ public function get_app( $slug ) { if ( isset( $this->apps[ $slug ] ) ) { return $this->apps[ $slug ]; } return null; } /** * @since 2.3.0 * @access public * @return Base_App[] */ public function get_apps() { return $this->apps; } /** * @since 2.3.0 * @access public */ public function register_category( $slug, $args ) { $this->categories[ $slug ] = $args; return $this; } /** * @since 2.3.0 * @access public */ public function get_categories() { return $this->categories; } /** * @param string $context Where this subscription plan should be shown. * * @return array */ public function get_subscription_plans( $context = '' ) { $base_url = Utils::has_pro() ? 'https://my.elementor.com/upgrade-subscription' : 'https://elementor.com/pro'; $promotion_url = $base_url . '/?utm_source=' . $context . '&utm_medium=wp-dash&utm_campaign=gopro'; return [ static::ACCESS_TIER_FREE => [ 'label' => null, 'promotion_url' => null, 'color' => null, ], static::ACCESS_TIER_ESSENTIAL => [ 'label' => 'Pro', 'promotion_url' => $promotion_url, 'color' => '#92003B', ], static::ACCESS_TIER_ESSENTIAL_OCT_2023 => [ 'label' => 'Advanced', // Should be the same label as "Advanced". 'promotion_url' => $promotion_url, 'color' => '#92003B', ], static::ACCESS_TIER_ADVANCED => [ 'label' => 'Advanced', 'promotion_url' => $promotion_url, 'color' => '#92003B', ], static::ACCESS_TIER_EXPERT => [ 'label' => 'Expert', 'promotion_url' => $promotion_url, 'color' => '#92003B', ], static::ACCESS_TIER_AGENCY => [ 'label' => 'Agency', 'promotion_url' => $promotion_url, 'color' => '#92003B', ], ]; } private function add_tracking_data( $params ) { $users = []; $users_query = new WP_User_Query( [ 'count_total' => false, // Disable SQL_CALC_FOUND_ROWS. 'meta_query' => [ 'key' => Common_App::OPTION_CONNECT_COMMON_DATA_KEY, 'compare' => 'EXISTS', ], ] ); foreach ( $users_query->get_results() as $user ) { $connect_common_data = get_user_option( Common_App::OPTION_CONNECT_COMMON_DATA_KEY, $user->ID ); if ( $connect_common_data ) { $users [] = [ 'id' => $user->ID, 'email' => $connect_common_data['user']->email, 'roles' => implode( ', ', $user->roles ), ]; } } $params['usages'][ $this->get_name() ] = [ 'site_key' => get_option( Base_App::OPTION_CONNECT_SITE_KEY ), 'count' => count( $users ), 'users' => $users, ]; return $params; } } modules/connect/apps/connect.php 0000644 00000000674 15162355076 0012773 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Connect\Apps; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Connect extends Common_App { public function get_title() { return esc_html__( 'Connect', 'elementor' ); } /** * @since 2.3.0 * @access public */ protected function get_slug() { return 'connect'; } /** * @since 2.3.0 * @access public */ public function render_admin_widget() {} } modules/connect/apps/base-app.php 0000644 00000050313 15162355076 0013025 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Connect\Apps; use Elementor\Core\Admin\Admin_Notices; use Elementor\Core\Common\Modules\Connect\Admin; use Elementor\Core\Utils\Collection; use Elementor\Core\Utils\Http; use Elementor\Core\Utils\Str; use Elementor\Plugin; use Elementor\Tracker; use Elementor\Utils; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } abstract class Base_App { const OPTION_NAME_PREFIX = 'elementor_connect_'; const OPTION_CONNECT_SITE_KEY = self::OPTION_NAME_PREFIX . 'site_key'; const SITE_URL = 'https://my.elementor.com/connect/v1'; const API_URL = 'https://my.elementor.com/api/connect/v1'; const HTTP_RETURN_TYPE_OBJECT = 'object'; const HTTP_RETURN_TYPE_ARRAY = 'array'; protected $data = []; protected $auth_mode = ''; /** * @var Http */ protected $http; /** * @since 2.3.0 * @access protected * @abstract * TODO: make it public. */ abstract protected function get_slug(); /** * @since 2.8.0 * @access public * TODO: make it abstract. */ public function get_title() { return $this->get_slug(); } /** * @since 2.3.0 * @access protected * @abstract */ abstract protected function update_settings(); /** * @since 2.3.0 * @access public * @static */ public static function get_class_name() { return get_called_class(); } /** * @access public * @abstract */ public function render_admin_widget() { // PHPCS - the method get_title return a plain string. echo '<h2>' . $this->get_title() . '</h2>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped if ( $this->is_connected() ) { $remote_user = $this->get( 'user' ); $title = sprintf( /* translators: %s: Remote user. */ esc_html__( 'Connected as %s', 'elementor' ), '<strong>' . esc_html( $remote_user->email ) . '</strong>' ); $label = esc_html__( 'Disconnect', 'elementor' ); $url = $this->get_admin_url( 'disconnect' ); $attr = ''; printf( '%s <a %s href="%s">%s</a>', // PHPCS - the variable $title is already escaped above. $title, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped // PHPCS - the variable $attr is a plain string. $attr, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped esc_attr( $url ), esc_html( $label ) ); } else { echo 'Not Connected'; } echo '<hr>'; $this->print_app_info(); if ( current_user_can( 'manage_options' ) ) { printf( '<div><a href="%s">%s</a></div>', esc_url( $this->get_admin_url( 'reset' ) ), esc_html__( 'Reset Data', 'elementor' ) ); } echo '<hr>'; } /** * @since 2.3.0 * @access protected */ protected function get_option_name() { return static::OPTION_NAME_PREFIX . $this->get_slug(); } /** * @since 2.3.0 * @access public */ public function admin_notice() { $notices = $this->get( 'notices' ); if ( ! $notices ) { return; } $this->print_notices( $notices ); $this->delete( 'notices' ); } public function get_app_token_from_cli_token( $cli_token ) { $response = $this->request( 'get_app_token_from_cli_token', [ 'cli_token' => $cli_token, ] ); if ( is_wp_error( $response ) ) { // PHPCS - the variable $response does not contain a user input value. wp_die( $response, $response->get_error_message() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } // Use state as usual. $_REQUEST['state'] = $this->get( 'state' ); $_REQUEST['code'] = $response->code; } /** * @since 2.3.0 * @access public */ public function action_authorize() { if ( $this->is_connected() ) { $this->add_notice( esc_html__( 'Already connected.', 'elementor' ), 'info' ); $this->redirect_to_admin_page(); return; } $this->set_client_id(); $this->set_request_state(); $this->redirect_to_remote_authorize_url(); } public function action_reset() { if ( current_user_can( 'manage_options' ) ) { delete_option( 'elementor_remote_info_library' ); } $this->redirect_to_admin_page(); } /** * @since 2.3.0 * @access public */ public function action_get_token() { if ( $this->is_connected() ) { $this->redirect_to_admin_page(); } //phpcs:ignore WordPress.Security.NonceVerification.Recommended - The user as been authorized before in 'connect'. $state = Utils::get_super_global_value( $_REQUEST, 'state' ); if ( $state !== $this->get( 'state' ) ) { $this->add_notice( 'Get Token: Invalid Request.', 'error' ); $this->redirect_to_admin_page(); } $response = $this->request( 'get_token', [ 'grant_type' => 'authorization_code', 'code' => Utils::get_super_global_value( $_REQUEST, 'code' ), //phpcs:ignore WordPress.Security.NonceVerification.Recommended 'redirect_uri' => rawurlencode( $this->get_admin_url( 'get_token' ) ), 'client_id' => $this->get( 'client_id' ), ] ); if ( is_wp_error( $response ) ) { $notice = 'Cannot Get Token:' . $response->get_error_message(); $this->add_notice( $notice, 'error' ); $this->redirect_to_admin_page(); } $this->delete( 'state' ); $this->set( (array) $response ); if ( ! empty( $response->data_share_opted_in ) && current_user_can( 'manage_options' ) ) { Tracker::set_opt_in( true ); } $this->after_connect(); // Add the notice *after* the method `after_connect`, so an app can redirect without the notice. $this->add_notice( esc_html__( 'Connected successfully.', 'elementor' ) ); $this->redirect_to_admin_page(); } /** * @since 2.3.0 * @access public */ public function action_disconnect() { if ( $this->is_connected() ) { $this->disconnect(); $this->add_notice( esc_html__( 'Disconnected successfully.', 'elementor' ) ); } $this->redirect_to_admin_page(); } /** * @since 2.8.0 * @access public */ public function action_reconnect() { $this->disconnect(); $this->action_authorize(); } /** * @since 2.3.0 * @access public */ public function get_admin_url( $action, $params = [] ) { $params = [ 'app' => $this->get_slug(), 'action' => $action, 'nonce' => wp_create_nonce( $this->get_slug() . $action ), ] + $params; $admin_url = Str::encode_idn_url( get_admin_url() ); $admin_url .= 'admin.php?page=' . Admin::PAGE_ID; return add_query_arg( $params, $admin_url ); } /** * @since 2.3.0 * @access public */ public function is_connected() { return (bool) $this->get( 'access_token' ); } /** * @since 2.3.0 * @access protected */ protected function init() {} /** * @since 2.3.0 * @access protected */ protected function init_data() {} /** * @since 2.3.0 * @access protected */ protected function after_connect() {} /** * @since 2.3.0 * @access public */ public function get( $key, $default = null ) { $this->init_data(); return isset( $this->data[ $key ] ) ? $this->data[ $key ] : $default; } /** * @since 2.3.0 * @access protected */ protected function set( $key, $value = null ) { $this->init_data(); if ( is_array( $key ) ) { $this->data = array_replace_recursive( $this->data, $key ); } else { $this->data[ $key ] = $value; } $this->update_settings(); } /** * @since 2.3.0 * @access protected */ protected function delete( $key = null ) { $this->init_data(); if ( $key ) { unset( $this->data[ $key ] ); } else { $this->data = []; } $this->update_settings(); } /** * @since 2.3.0 * @access protected */ protected function add( $key, $value, $default = '' ) { $new_value = $this->get( $key, $default ); if ( is_array( $new_value ) ) { $new_value[] = $value; } elseif ( is_string( $new_value ) ) { $new_value .= $value; } elseif ( is_numeric( $new_value ) ) { $new_value += $value; } $this->set( $key, $new_value ); } /** * @since 2.3.0 * @access protected */ protected function add_notice( $content, $type = 'success' ) { $this->add( 'notices', compact( 'content', 'type' ), [] ); } /** * @param $action * @param array $request_body * @param false $as_array * * @return mixed|\WP_Error */ protected function request( $action, $request_body = [], $as_array = false ) { $request_body = $this->get_connect_info() + $request_body; return $this->http_request( 'POST', $action, [ 'timeout' => 25, 'body' => $request_body, 'headers' => $this->is_connected() ? [ 'X-Elementor-Signature' => $this->generate_signature( $request_body ) ] : [], ], [ 'return_type' => $as_array ? static::HTTP_RETURN_TYPE_ARRAY : static::HTTP_RETURN_TYPE_OBJECT, ] ); } /** * Get Base Connect Info * * Returns an array of connect info. * * @return array */ protected function get_base_connect_info() { return [ 'app' => $this->get_slug(), 'access_token' => $this->get( 'access_token' ), 'client_id' => $this->get( 'client_id' ), 'local_id' => get_current_user_id(), 'site_key' => $this->get_site_key(), 'home_url' => trailingslashit( home_url() ), ]; } /** * Get all the connect information * * @return array */ protected function get_connect_info() { $connect_info = $this->get_base_connect_info(); $additional_info = []; /** * Additional connect info. * * Filters the connection information when connecting to Elementor servers. * This hook can be used to add more information or add more data. * * @param array $additional_info Additional connecting information array. * @param Base_App $this The base app instance. */ $additional_info = apply_filters( 'elementor/connect/additional-connect-info', $additional_info, $this ); return array_merge( $connect_info, $additional_info ); } /** * @param $endpoint * * @return array */ protected function generate_authentication_headers( $endpoint ) { $connect_info = ( new Collection( $this->get_connect_info() ) ) ->map_with_keys( function ( $value, $key ) { // For bc `get_connect_info` returns the connect info with underscore, // headers with underscore are not valid, so all the keys with underscore will be replaced to hyphen. return [ str_replace( '_', '-', $key ) => $value ]; } ) ->replace_recursive( [ 'endpoint' => $endpoint ] ) ->sort_keys(); return $connect_info ->merge( [ 'X-Elementor-Signature' => $this->generate_signature( $connect_info->all() ) ] ) ->all(); } /** * Send an http request * * @param $method * @param $endpoint * @param array $args * @param array $options * * @return mixed|\WP_Error */ protected function http_request( $method, $endpoint, $args = [], $options = [] ) { $options = wp_parse_args( $options, [ 'return_type' => static::HTTP_RETURN_TYPE_OBJECT, ] ); $args = array_replace_recursive( [ 'headers' => $this->is_connected() ? $this->generate_authentication_headers( $endpoint ) : [], 'method' => $method, 'timeout' => 10, ], $args ); $response = $this->http->request_with_fallback( $this->get_generated_urls( $endpoint ), $args ); if ( is_wp_error( $response ) && empty( $options['with_error_data'] ) ) { // PHPCS - the variable $response does not contain a user input value. wp_die( $response, [ 'back_link' => true ] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } $body = wp_remote_retrieve_body( $response ); $response_code = (int) wp_remote_retrieve_response_code( $response ); if ( ! $response_code ) { return new \WP_Error( 500, 'No Response' ); } // Server sent a success message without content. if ( 'null' === $body ) { $body = true; } $body = json_decode( $body, static::HTTP_RETURN_TYPE_ARRAY === $options['return_type'] ); if ( false === $body ) { return new \WP_Error( 422, 'Wrong Server Response' ); } if ( 201 === $response_code ) { return $body; } if ( 200 !== $response_code ) { // In case $as_array = true. $body = (object) $body; $message = isset( $body->message ) ? $body->message : wp_remote_retrieve_response_message( $response ); $code = (int) ( isset( $body->code ) ? $body->code : $response_code ); if ( ! $code ) { $code = $response_code; } if ( 401 === $code ) { $this->delete(); $should_retry = ! in_array( $this->auth_mode, [ 'xhr', 'cli' ], true ); if ( $should_retry ) { $this->action_authorize(); } } if ( isset( $options['with_error_data'] ) && true === $options['with_error_data'] ) { return new \WP_Error( $code, $message, $body ); } return new \WP_Error( $code, $message ); } return $body; } /** * Create a signature for the http request * * @param array $payload * * @return false|string */ private function generate_signature( $payload = [] ) { return hash_hmac( 'sha256', wp_json_encode( $payload, JSON_NUMERIC_CHECK ), $this->get( 'access_token_secret' ) ); } /** * @since 2.3.0 * @access protected */ protected function get_api_url() { return static::API_URL . '/' . $this->get_slug(); } /** * @since 2.3.0 * @access protected */ protected function get_remote_site_url() { return static::SITE_URL . '/' . $this->get_slug(); } /** * @since 2.3.0 * @access protected */ protected function get_remote_authorize_url() { $redirect_uri = $this->get_auth_redirect_uri(); $allowed_query_params_to_propagate = [ 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'source', 'screen_hint', ]; $query_params = ( new Collection( $_GET ) ) // phpcs:ignore ->only( $allowed_query_params_to_propagate ) ->merge( [ 'action' => 'authorize', 'response_type' => 'code', 'client_id' => $this->get( 'client_id' ), 'auth_secret' => $this->get( 'auth_secret' ), 'state' => $this->get( 'state' ), 'redirect_uri' => rawurlencode( $redirect_uri ), 'may_share_data' => current_user_can( 'manage_options' ) && ! Tracker::is_allow_track(), 'reconnect_nonce' => wp_create_nonce( $this->get_slug() . 'reconnect' ), ] ); $utm_campaign = get_transient( 'elementor_core_campaign' ); if ( ! empty( $utm_campaign ) ) { foreach ( [ 'source', 'medium', 'campaign' ] as $key ) { if ( ! empty( $utm_campaign[ $key ] ) ) { $query_params->offsetSet( 'utm_' . $key, $utm_campaign[ $key ] ); } } } return add_query_arg( $query_params->all(), $this->get_remote_site_url() ); } /** * @since 2.3.0 * @access protected */ protected function redirect_to_admin_page( $url = '' ) { if ( ! $url ) { $url = Admin::$url; } switch ( $this->auth_mode ) { case 'popup': $this->print_popup_close_script( $url ); break; case 'cli': $this->admin_notice(); die; default: wp_safe_redirect( $url ); die; } } /** * @since 2.3.0 * @access protected */ protected function set_client_id() { $source = Utils::get_super_global_value( $_REQUEST, 'source' ) ?? ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here. $response = $this->request( 'get_client_id', [ 'source' => esc_attr( $source ), ] ); if ( is_wp_error( $response ) ) { // PHPCS - the variable $response does not contain a user input value. wp_die( $response, $response->get_error_message() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } $this->set( 'client_id', $response->client_id ); $this->set( 'auth_secret', $response->auth_secret ); } /** * @since 2.3.0 * @access protected */ protected function set_request_state() { $this->set( 'state', wp_generate_password( 12, false ) ); } protected function get_popup_success_event_data() { return []; } /** * @since 2.3.0 * @access protected */ protected function print_popup_close_script( $url ) { $data = $this->get_popup_success_event_data(); ?> <script> if ( opener && opener !== window ) { opener.jQuery( 'body' ).trigger( 'elementor/connect/success/<?php echo esc_attr( Utils::get_super_global_value( $_REQUEST, 'callback_id' ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here. ?>', <?php echo wp_json_encode( $data ); ?> ); opener.dispatchEvent( new CustomEvent( 'elementor/connect/success' ), <?php echo wp_json_encode( $data ); ?> ); window.close(); opener.focus(); } else { location = '<?php echo esc_url( $url ); ?>'; } </script> <?php die; } /** * @since 2.3.0 * @access protected */ protected function disconnect() { if ( $this->is_connected() ) { // Try update the server, but not needed to handle errors. $this->request( 'disconnect' ); } $this->delete(); } /** * @since 2.3.0 * @access protected */ public function get_site_key() { $site_key = get_option( static::OPTION_CONNECT_SITE_KEY ); if ( ! $site_key ) { $site_key = md5( uniqid( wp_generate_password() ) ); update_option( static::OPTION_CONNECT_SITE_KEY, $site_key ); } return $site_key; } protected function redirect_to_remote_authorize_url() { switch ( $this->auth_mode ) { case 'cli': $this->get_app_token_from_cli_token( Utils::get_super_global_value( $_REQUEST, 'token' ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here. return; default: wp_redirect( $this->get_remote_authorize_url() ); //phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- Safe redirect is used here. die; } } protected function get_auth_redirect_uri() { $redirect_uri = $this->get_admin_url( 'get_token' ); switch ( $this->auth_mode ) { case 'popup': $redirect_uri = add_query_arg( [ 'mode' => 'popup', 'callback_id' => esc_attr( Utils::get_super_global_value( $_REQUEST, 'callback_id' ) ), //phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here. ], $redirect_uri ); break; } return $redirect_uri; } protected function print_notices( $notices ) { switch ( $this->auth_mode ) { case 'cli': foreach ( $notices as $notice ) { printf( '[%s] %s', wp_kses_post( $notice['type'] ), wp_kses_post( $notice['content'] ) ); } break; default: /** * @var Admin_Notices $admin_notices */ $admin_notices = Plugin::$instance->admin->get_component( 'admin-notices' ); foreach ( $notices as $notice ) { $options = [ 'description' => wp_kses_post( wpautop( $notice['content'] ) ), 'type' => $notice['type'], 'icon' => false, ]; $admin_notices->print_admin_notice( $options ); } } } protected function get_app_info() { return []; } protected function print_app_info() { $app_info = $this->get_app_info(); foreach ( $app_info as $key => $item ) { if ( $item['value'] ) { $status = 'Exist'; $color = 'green'; } else { $status = 'Empty'; $color = 'red'; } // PHPCS - the values of $item['label'], $color, $status are plain strings. printf( '%s: <strong style="color:%s">%s</strong><br>', $item['label'], $color, $status ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } } private function get_generated_urls( $endpoint ) { $base_urls = $this->get_api_url(); if ( ! is_array( $base_urls ) ) { $base_urls = [ $base_urls ]; } return array_map( function ( $base_url ) use ( $endpoint ) { return trailingslashit( $base_url ) . $endpoint; }, $base_urls ); } private function init_auth_mode() { $is_rest = defined( 'REST_REQUEST' ) && REST_REQUEST; $is_ajax = wp_doing_ajax(); if ( $is_rest || $is_ajax ) { // Set default to 'xhr' if rest or ajax request. $this->set_auth_mode( 'xhr' ); } $mode = Utils::get_super_global_value( $_REQUEST, 'mode' ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here. if ( $mode ) { $allowed_auth_modes = [ 'popup', ]; if ( defined( 'WP_CLI' ) && WP_CLI ) { $allowed_auth_modes[] = 'cli'; } if ( in_array( $mode, $allowed_auth_modes, true ) ) { $this->set_auth_mode( $mode ); } } } public function set_auth_mode( $mode ) { $this->auth_mode = $mode; } /** * @since 2.3.0 * @access public */ public function __construct() { add_action( 'admin_notices', [ $this, 'admin_notice' ] ); $this->init_auth_mode(); $this->http = new Http(); /** * Allow extended apps to customize the __construct without call parent::__construct. */ $this->init(); } } modules/connect/apps/base-user-app.php 0000644 00000001061 15162355076 0013775 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Connect\Apps; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } abstract class Base_User_App extends Base_App { /** * @since 2.3.0 * @access protected */ protected function update_settings() { update_user_option( get_current_user_id(), $this->get_option_name(), $this->data ); } /** * @since 2.3.0 * @access protected */ protected function init_data() { $this->data = get_user_option( $this->get_option_name() ); if ( ! $this->data ) { $this->data = []; } } } modules/connect/apps/common-app.php 0000644 00000001615 15162355076 0013404 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Connect\Apps; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } abstract class Common_App extends Base_User_App { const OPTION_CONNECT_COMMON_DATA_KEY = self::OPTION_NAME_PREFIX . 'common_data'; protected static $common_data = null; /** * @since 2.3.0 * @access public */ public function get_option_name() { return static::OPTION_NAME_PREFIX . 'common_data'; } /** * @since 2.3.0 * @access protected */ protected function init_data() { if ( is_null( self::$common_data ) ) { self::$common_data = get_user_option( static::get_option_name() ); if ( ! self::$common_data ) { self::$common_data = []; }; } $this->data = & self::$common_data; } public function action_reset() { delete_user_option( get_current_user_id(), static::OPTION_CONNECT_COMMON_DATA_KEY ); parent::action_reset(); } } modules/connect/apps/library.php 0000644 00000010767 15162355076 0013012 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Connect\Apps; use Elementor\Api; use Elementor\User; use Elementor\Plugin; use Elementor\Core\Common\Modules\Connect\Module as ConnectModule; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Library extends Common_App { public function get_title() { return esc_html__( 'Library', 'elementor' ); } /** * @since 2.3.0 * @access protected */ protected function get_slug() { return 'library'; } public function get_template_content( $id ) { if ( ! $this->is_connected() ) { return new \WP_Error( '401', esc_html__( 'Connecting to the Library failed. Please try reloading the page and try again', 'elementor' ) ); } $body_args = [ 'id' => $id, // Which API version is used. 'api_version' => ELEMENTOR_VERSION, // Which language to return. 'site_lang' => get_bloginfo( 'language' ), ]; /** * API: Template body args. * * Filters the body arguments send with the GET request when fetching the content. * * @since 1.0.0 * * @param array $body_args Body arguments. */ $body_args = apply_filters( 'elementor/api/get_templates/body_args', $body_args ); $template_content = $this->request( 'get_template_content', $body_args, true ); if ( is_wp_error( $template_content ) && 401 === $template_content->get_error_code() ) { // Normalize 401 message return new \WP_Error( 401, esc_html__( 'Connecting to the Library failed. Please try reloading the page and try again', 'elementor' ) ); } return $template_content; } public function localize_settings( $settings ) { $is_connected = $this->is_connected(); /** @var ConnectModule $connect */ $connect = Plugin::$instance->common->get_component( 'connect' ); $user_id = $this->get_user_id(); return array_replace_recursive( $settings, [ 'library_connect' => [ 'is_connected' => $is_connected, 'user_id' => $user_id, 'subscription_plans' => $connect->get_subscription_plans( 'template-library' ), // TODO: Remove `base_access_level`. 'base_access_level' => ConnectModule::ACCESS_LEVEL_CORE, 'base_access_tier' => ConnectModule::ACCESS_TIER_FREE, 'current_access_level' => ConnectModule::ACCESS_LEVEL_CORE, 'current_access_tier' => ConnectModule::ACCESS_TIER_FREE, ], ] ); } public function library_connect_popup_seen() { User::set_introduction_viewed( [ 'introductionKey' => 'library_connect', ] ); } /** * @param \Elementor\Core\Common\Modules\Ajax\Module $ajax_manager */ public function register_ajax_actions( $ajax_manager ) { $ajax_manager->register_ajax_action( 'library_connect_popup_seen', [ $this, 'library_connect_popup_seen' ] ); } private function get_user_id() { $token = $this->get( 'access_token' ); if ( ! is_string( $token ) ) { return null; } $parts = explode( '.', $token ); if ( count( $parts ) !== 3 ) { return null; } try { $payload_encoded = $parts[1]; $payload_encoded = str_pad( $payload_encoded, strlen( $payload_encoded ) + ( 4 - strlen( $payload_encoded ) % 4 ) % 4, '=' ); $payload_json = base64_decode( strtr( $payload_encoded, '-_', '+/' ), true ); $payload = json_decode( $payload_json, true ); if ( ! isset( $payload['sub'] ) ) { return null; } return $payload['sub']; } catch ( Exception $e ) { error_log( 'JWT Decoding Error: ' . $e->getMessage() ); return null; } } /** * After Connect * * After Connecting to the library, re-fetch the library data to get it up to date. * * @since 3.7.0 */ protected function after_connect() { Api::get_library_data( true ); } protected function get_app_info() { return [ 'user_common_data' => [ 'label' => 'User Common Data', 'value' => get_user_option( $this->get_option_name(), get_current_user_id() ), ], 'connect_site_key' => [ 'label' => 'Site Key', 'value' => get_option( self::OPTION_CONNECT_SITE_KEY ), ], 'remote_info_library' => [ 'label' => 'Remote Library Info', 'value' => get_option( 'elementor_remote_info_library' ), ], ]; } protected function get_popup_success_event_data() { return [ 'access_level' => ConnectModule::ACCESS_LEVEL_CORE, 'access_tier' => ConnectModule::ACCESS_TIER_FREE, ]; } protected function init() { add_filter( 'elementor/editor/localize_settings', [ $this, 'localize_settings' ] ); add_filter( 'elementor/common/localize_settings', [ $this, 'localize_settings' ] ); add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_actions' ] ); } } modules/event-tracker/personal-data.php 0000644 00000003711 15162355076 0014245 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\EventTracker; use Elementor\Core\Base\Base_Object; use Elementor\Core\Common\Modules\EventTracker\DB as Events_DB_Manager; use Elementor\Plugin; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Personal_Data extends Base_Object { const WP_KEY = 'elementor-event-tracker'; /** * Get Title * * @since 3.6.0 * * @return string */ private function get_title() { return esc_html__( 'Elementor Event Tracker', 'elementor' ); } /** * Erase all the submissions related to specific email. * * Since event data is saved globally per site and not per user, we remove all saved events from the DB upon a * user's data deletion request. * * @return array */ private function erase_data() { // Get number of events saved in the DB. /** @var Events_DB_Manager $event_tracker_db_manager */ $event_tracker_db_manager = Plugin::$instance->common ->get_component( 'event-tracker' ) ->get_component( 'events-db' ); $events = $event_tracker_db_manager->get_event_ids_from_db(); $events_count = count( $events ); DB::reset_table(); // Validate table deleted $updated_events = $event_tracker_db_manager->get_event_ids_from_db(); $updated_events_count = count( $updated_events ); return [ 'items_removed' => $events_count - $updated_events_count, 'items_retained' => 0, 'messages' => [], 'done' => 0 === $updated_events_count, ]; } /** * Add eraser to the list of erasers. * * @param $erasers * * @return array[] */ private function add_eraser( $erasers ) { return $erasers + [ self::WP_KEY => [ 'eraser_friendly_name' => $this->get_title(), 'callback' => function () { return $this->erase_data(); }, ], ]; } /** * Personal_Data constructor. */ public function __construct() { add_filter( 'wp_privacy_personal_data_erasers', function ( $exporters ) { return $this->add_eraser( $exporters ); } ); } } modules/event-tracker/module.php 0000644 00000001642 15162355076 0013001 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\EventTracker; use Elementor\Core\Base\Module as BaseModule; use Elementor\Core\Common\Modules\EventTracker\Data\Controller; use Elementor\Plugin; use Elementor\Tracker; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Event Tracker Module Class * * @since 3.6.0 */ class Module extends BaseModule { public function get_name() { return 'event-tracker'; } /** * Get init settings. * * @since 3.6.0 * @access protected * * @return array */ protected function get_init_settings() { return [ 'isUserDataShared' => Tracker::is_allow_track(), ]; } public function __construct() { // Initialize Events Database Table $this->add_component( 'events-db', new DB() ); // Handle User Data Deletion/Export requests. new Personal_Data(); Plugin::$instance->data_manager_v2->register_controller( new Controller() ); } } modules/event-tracker/data/controller.php 0000644 00000003513 15162355076 0014607 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\EventTracker\Data; use Elementor\Core\Common\Modules\EventTracker\DB as Events_DB_Manager; use Elementor\Plugin; use WP_REST_Server; use Elementor\Data\V2\Base\Controller as Controller_Base; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Controller extends Controller_Base { public function get_name() { return 'send-event'; } public function register_endpoints() { $this->index_endpoint->register_items_route( \WP_REST_Server::CREATABLE, [ 'event_data' => [ 'description' => 'All the recorded event data in JSON format', 'type' => 'object', 'required' => true, ], ] ); } /** * Get Permissions Callback * * This endpoint should only accept POST requests, and currently we only track site administrator actions. * * @since 3.6.0 * * @param \WP_REST_Request $request * @return bool */ public function get_permission_callback( $request ) { if ( WP_REST_Server::CREATABLE !== $request->get_method() ) { return false; } return current_user_can( 'manage_options' ); } /** * Create Items * * Receives a request for adding an event data entry into the database. If the request contains event data, this * method initiates creation of a database entry with the event data in the Events DB table. * * @since 3.6.0 * * @param \WP_REST_Request $request * @return bool */ public function create_items( $request ) { $request_body = $request->get_json_params(); if ( empty( $request_body['event_data'] ) ) { return false; } /** @var Events_DB_Manager $event_tracker_db_manager */ $event_tracker_db_manager = Plugin::$instance->common ->get_component( 'event-tracker' ) ->get_component( 'events-db' ); $event_tracker_db_manager->create_entry( $request_body['event_data'] ); return true; } } modules/event-tracker/db.php 0000644 00000011410 15162355077 0012074 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\EventTracker; use Elementor\Core\Base\Base_Object; use Elementor\Core\Common\Modules\Connect\Apps\Common_App; use Elementor\Core\Common\Modules\Connect\Apps\Library; use Elementor\Plugin; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class DB extends Base_Object { /** * @var \wpdb */ private $wpdb; const TABLE_NAME = 'e_events'; const DB_VERSION_OPTION_KEY = 'elementor_events_db_version'; const CURRENT_DB_VERSION = '1.0.0'; /** * Get Table Name * * Returns the Events database table's name with the `wpdb` prefix. * * @since 3.6.0 * * @return string */ public function get_table_name() { return $this->wpdb->prefix . self::TABLE_NAME; } /** * Prepare Database for Entry * * The events database should have a limit of up to 1000 event entries stored daily. * Before adding a new entry to the database, we make sure that the limit of 1000 events is not reached. * If there are 1000 or more entries in the DB, we delete the earliest-inserted entry before inserting a new one. * * @since 3.6.0 */ public function prepare_db_for_entry() { $events = $this->get_event_ids_from_db(); if ( 1000 <= count( $events ) ) { $event_ids = []; foreach ( $events as $event ) { $event_ids[] = $event->id; } // Sort the array by entry ID array_multisort( $event_ids, SORT_ASC, $events ); // Delete the smallest ID (which is the earliest DB entry) $this->wpdb->delete( $this->get_table_name(), [ 'ID' => $events[0]->id ] ); } } /** * Create Entry * * Adds an event entry to the database. * * @since 3.6.0 */ public function create_entry( $event_data ) { $this->prepare_db_for_entry(); $connect = Plugin::$instance->common->get_component( 'connect' ); /** @var Library $library */ $library = $connect->get_apps()['library']; if ( ! isset( $event_data['details'] ) ) { $event_data['details'] = []; } if ( $library->is_connected() ) { $user_connect_data = get_user_option( Common_App::OPTION_CONNECT_COMMON_DATA_KEY ); // Add the user's client ID to the event. $event_data['details']['client_id'] = $user_connect_data['client_id']; } $event_data['details'] = wp_json_encode( $event_data['details'] ); $entry = [ 'event_data' => wp_json_encode( $event_data ), 'created_at' => $event_data['ts'], ]; $this->wpdb->insert( $this->get_table_name(), $entry ); } /** * Get Event IDs From DB * * Fetches the IDs of all events saved in the database. * * @since 3.6.0 * * @return array|object|null */ public function get_event_ids_from_db() { // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared return $this->wpdb->get_results( "SELECT id FROM {$this->get_table_name()}" ); } /** * Reset Table * * Empties the contents of the Events DB table. * * @since 3.6.0 */ public static function reset_table() { global $wpdb; $table_name = $wpdb->prefix . self::TABLE_NAME; // Delete all content of the table. // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared $wpdb->query( "TRUNCATE TABLE {$table_name}" ); } /** * Create Table * * Creates the `wp_e_events` database table. * * @since 3.6.0 * * @param string $query to that looks for the Events table in the DB. Used for checking if table was created. */ private function create_table( $query ) { require_once ABSPATH . 'wp-admin/includes/upgrade.php'; $table_name = $this->get_table_name(); $charset_collate = $this->wpdb->get_charset_collate(); $e_events_table = "CREATE TABLE `{$table_name}` ( id bigint(20) unsigned auto_increment primary key, event_data text null, created_at datetime not null ) {$charset_collate};"; // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared $this->wpdb->query( $e_events_table ); // Check if table was created successfully. // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared if ( $this->wpdb->get_var( $query ) === $table_name ) { update_option( self::DB_VERSION_OPTION_KEY, self::CURRENT_DB_VERSION, false ); } } /** * Add Indexes * * Adds an index to the events table for the creation date column. * * @since 3.6.0 */ private function add_indexes() { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $this->wpdb->query( 'ALTER TABLE ' . $this->get_table_name() . ' ADD INDEX `created_at_index` (`created_at`) ' ); } public function __construct() { global $wpdb; $this->wpdb = $wpdb; // Check if table exists. If not, create it. $query = $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $this->get_table_name() ) ); // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared if ( $wpdb->get_var( $query ) !== $this->get_table_name() ) { $this->create_table( $query ); $this->add_indexes(); } } } modules/finder/module.php 0000644 00000005064 15162355077 0011501 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Finder; use Elementor\Core\Base\Module as BaseModule; use Elementor\Core\Common\Modules\Ajax\Module as Ajax; use Elementor\Plugin; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Finder Module * * Responsible for initializing Elementor Finder functionality */ class Module extends BaseModule { /** * Categories manager. * * @access private * * @var Categories_Manager */ private $categories_manager; /** * Module constructor. * * @since 2.3.0 * @access public */ public function __construct() { $this->categories_manager = new Categories_Manager(); $this->add_template(); add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_actions' ] ); } /** * Get name. * * @since 2.3.0 * @access public * * @return string */ public function get_name() { return 'finder'; } /** * Add template. * * @since 2.3.0 * @access public */ public function add_template() { Plugin::$instance->common->add_template( __DIR__ . '/template.php' ); } /** * Register ajax actions. * * @since 2.3.0 * @access public * * @param Ajax $ajax */ public function register_ajax_actions( Ajax $ajax ) { $ajax->register_ajax_action( 'finder_get_category_items', [ $this, 'ajax_get_category_items' ] ); } /** * Ajax get category items. * * @since 2.3.0 * @access public * * @param array $data * * @return array */ public function ajax_get_category_items( array $data ) { if ( ! current_user_can( 'manage_options' ) ) { throw new \Exception( 'Access denied.' ); } $category = $this->categories_manager->get_categories( $data['category'] ); return $category->get_category_items( $data ); } /** * Get init settings. * * @since 2.3.0 * @access protected * * @return array */ protected function get_init_settings() { $categories = $this->categories_manager->get_categories(); $categories_data = []; foreach ( $categories as $category_name => $category ) { $categories_data[ $category_name ] = array_merge( $category->get_settings(), [ 'name' => $category_name ] ); } /** * Finder categories. * * Filters the list of finder categories. This hook is used to manage Finder * categories - to add new categories, remove and edit existing categories. * * @since 2.3.0 * * @param array $categories_data A list of finder categories. */ $categories_data = apply_filters( 'elementor/finder/categories', $categories_data ); return [ 'data' => $categories_data, ]; } } modules/finder/categories/site.php 0000644 00000004047 15162355077 0013305 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Finder\Categories; use Elementor\Core\Common\Modules\Finder\Base_Category; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Site Category * * Provides general site items. */ class Site extends Base_Category { /** * Get title. * * @since 2.3.0 * @access public * * @return string */ public function get_title() { return esc_html__( 'Site', 'elementor' ); } public function get_id() { return 'site'; } /** * Get category items. * * @since 2.3.0 * @access public * * @param array $options * * @return array */ public function get_category_items( array $options = [] ) { return [ 'homepage' => [ 'title' => esc_html__( 'Homepage', 'elementor' ), 'url' => home_url(), 'icon' => 'home-heart', 'keywords' => [ 'home', 'page' ], ], 'wordpress-dashboard' => [ 'title' => esc_html__( 'Dashboard', 'elementor' ), 'icon' => 'dashboard', 'url' => admin_url(), 'keywords' => [ 'dashboard', 'wordpress' ], ], 'wordpress-menus' => [ 'title' => esc_html__( 'Menus', 'elementor' ), 'icon' => 'wordpress', 'url' => admin_url( 'nav-menus.php' ), 'keywords' => [ 'menu', 'wordpress' ], ], 'wordpress-themes' => [ 'title' => esc_html__( 'Themes', 'elementor' ), 'icon' => 'wordpress', 'url' => admin_url( 'themes.php' ), 'keywords' => [ 'themes', 'wordpress' ], ], 'wordpress-customizer' => [ 'title' => esc_html__( 'Customizer', 'elementor' ), 'icon' => 'wordpress', 'url' => admin_url( 'customize.php' ), 'keywords' => [ 'customizer', 'wordpress' ], ], 'wordpress-plugins' => [ 'title' => esc_html__( 'Plugins', 'elementor' ), 'icon' => 'wordpress', 'url' => admin_url( 'plugins.php' ), 'keywords' => [ 'plugins', 'wordpress' ], ], 'wordpress-users' => [ 'title' => esc_html__( 'Users', 'elementor' ), 'icon' => 'wordpress', 'url' => admin_url( 'users.php' ), 'keywords' => [ 'users', 'profile', 'wordpress' ], ], ]; } } modules/finder/categories/create.php 0000644 00000005536 15162355077 0013610 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Finder\Categories; use Elementor\Core\Common\Modules\Finder\Base_Category; use Elementor\Plugin; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Create Category * * Provides items related to creation of new posts/pages/templates etc. */ class Create extends Base_Category { /** * Get title. * * @since 2.3.0 * @access public * * @return string */ public function get_title() { return esc_html__( 'Create', 'elementor' ); } public function get_id() { return 'create'; } /** * Get category items. * * @since 2.3.0 * @access public * * @param array $options * * @return array */ public function get_category_items( array $options = [] ) { $result = []; $registered_document_types = Plugin::$instance->documents->get_document_types(); // TODO: Remove - Support 'post' backwards compatibility - See `Documents_Manager::register_default_types()`. unset( $registered_document_types['post'] ); $elementor_supported_post_types = array_flip( get_post_types_by_support( 'elementor' ) ); foreach ( $registered_document_types as $document_name => $document_class ) { $document_properties = $document_class::get_properties(); if ( empty( $document_properties['show_in_finder'] ) ) { continue; } if ( ! empty( $document_properties['cpt'] ) ) { foreach ( $document_properties['cpt'] as $cpt ) { unset( $elementor_supported_post_types[ $cpt ] ); } } $result[ $document_name ] = $this->create_item_url_by_document_class( $document_class ); } foreach ( $elementor_supported_post_types as $post_type => $val ) { $result[ $post_type ] = $this->create_item_url_by_post_type( $post_type ); } return $result; } private function create_item_url_by_post_type( $post_type ) { $post_type_object = get_post_type_object( $post_type ); // If there is an old post type from inactive plugins. if ( ! $post_type_object ) { return false; } return $this->get_create_new_template( sprintf( __( 'Add New %s', 'elementor' ), $post_type_object->labels->singular_name ), Plugin::$instance->documents->get_create_new_post_url( $post_type ) ); } private function create_item_url_by_document_class( $document_class ) { $result = $this->get_create_new_template( $document_class::get_add_new_title(), $document_class::get_create_url() ); $lock_behavior = $document_class::get_lock_behavior_v2(); $is_locked = ! empty( $lock_behavior ) && $lock_behavior->is_locked(); if ( $is_locked ) { $result['lock'] = $lock_behavior->get_config(); } return $result; } private function get_create_new_template( $add_new_title, $url ) { return [ 'title' => $add_new_title, 'icon' => 'plus-circle-o', 'url' => $url, 'keywords' => [ $add_new_title, 'post', 'page', 'template', 'new', 'create' ], ]; } } modules/finder/categories/settings.php 0000644 00000004534 15162355077 0014202 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Finder\Categories; use Elementor\Core\Common\Modules\Finder\Base_Category; use Elementor\Modules\ElementManager\Module as ElementManagerModule; use Elementor\Settings as ElementorSettings; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Settings Category * * Provides items related to Elementor's settings. */ class Settings extends Base_Category { /** * Get title. * * @since 2.3.0 * @access public * * @return string */ public function get_title() { return esc_html__( 'Settings', 'elementor' ); } public function get_id() { return 'settings'; } /** * Get category items. * * @since 2.3.0 * @access public * * @param array $options * * @return array */ public function get_category_items( array $options = [] ) { return [ 'general-settings' => [ 'title' => esc_html__( 'General Settings', 'elementor' ), 'url' => ElementorSettings::get_settings_tab_url( 'general' ), 'keywords' => [ 'general', 'settings', 'elementor' ], ], 'integrations' => [ 'title' => esc_html__( 'Integrations', 'elementor' ), 'url' => ElementorSettings::get_settings_tab_url( 'integrations' ), 'keywords' => [ 'integrations', 'settings', 'elementor' ], ], 'advanced' => [ 'title' => esc_html__( 'Advanced', 'elementor' ), 'url' => ElementorSettings::get_settings_tab_url( 'advanced' ), 'keywords' => [ 'advanced', 'settings', 'elementor' ], ], 'performance' => [ 'title' => esc_html__( 'Performance', 'elementor' ), 'url' => ElementorSettings::get_settings_tab_url( 'performance' ), 'keywords' => [ 'performance', 'settings', 'elementor' ], ], 'experiments' => [ 'title' => esc_html__( 'Experiments', 'elementor' ), 'url' => ElementorSettings::get_settings_tab_url( 'experiments' ), 'keywords' => [ 'settings', 'elementor', 'experiments' ], ], 'features' => [ 'title' => esc_html__( 'Features', 'elementor' ), 'url' => ElementorSettings::get_settings_tab_url( 'experiments' ), 'keywords' => [ 'settings', 'elementor', 'features' ], ], 'element-manager' => [ 'title' => esc_html__( 'Element Manager', 'elementor' ), 'url' => admin_url( 'admin.php?page=' . ElementManagerModule::PAGE_ID ), 'keywords' => [ 'settings', 'elements', 'widgets', 'manager' ], ], ]; } } modules/finder/categories/edit.php 0000644 00000005271 15162355077 0013266 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Finder\Categories; use Elementor\Core\Base\Document; use Elementor\Core\Common\Modules\Finder\Base_Category; use Elementor\Plugin; use Elementor\TemplateLibrary\Source_Local; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Edit Category * * Provides items related to editing of posts/pages/templates etc. */ class Edit extends Base_Category { /** * Get title. * * @since 2.3.0 * @access public * * @return string */ public function get_title() { return esc_html__( 'Edit', 'elementor' ); } public function get_id() { return 'edit'; } /** * Is dynamic. * * Determine if the category is dynamic. * * @since 2.3.0 * @access public * * @return bool */ public function is_dynamic() { return true; } /** * Get category items. * * @since 2.3.0 * @access public * * @param array $options * * @return array */ public function get_category_items( array $options = [] ) { $post_types = get_post_types( [ 'exclude_from_search' => false, ] ); $post_types[] = Source_Local::CPT; $document_types = Plugin::$instance->documents->get_document_types( [ 'is_editable' => true, 'show_in_finder' => true, ] ); $recently_edited_query_args = [ 'no_found_rows' => true, 'post_type' => $post_types, 'post_status' => [ 'publish', 'draft', 'private', 'pending', 'future' ], 'posts_per_page' => '10', 'meta_query' => [ [ 'key' => '_elementor_edit_mode', 'value' => 'builder', ], [ 'relation' => 'or', [ 'key' => Document::TYPE_META_KEY, 'compare' => 'NOT EXISTS', ], [ 'key' => Document::TYPE_META_KEY, 'value' => array_keys( $document_types ), ], ], ], 'orderby' => 'modified', 's' => $options['filter'], ]; $recently_edited_query = new \WP_Query( $recently_edited_query_args ); $items = []; /** @var \WP_Post $post */ foreach ( $recently_edited_query->posts as $post ) { $document = Plugin::$instance->documents->get( $post->ID ); if ( ! $document ) { continue; } $is_template = Source_Local::CPT === $post->post_type; $description = $document->get_title(); $icon = 'document-file'; if ( $is_template ) { $description = esc_html__( 'Template', 'elementor' ) . ' / ' . $description; $icon = 'post-title'; } $items[] = [ 'icon' => $icon, 'title' => esc_html( $post->post_title ), 'description' => $description, 'url' => $document->get_edit_url(), 'actions' => [ [ 'name' => 'view', 'url' => $document->get_permalink(), 'icon' => 'preview-medium', ], ], ]; } return $items; } } modules/finder/categories/general.php 0000644 00000004451 15162355077 0013755 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Finder\Categories; use Elementor\Core\Common\Modules\Finder\Base_Category; use Elementor\Core\RoleManager\Role_Manager; use Elementor\Plugin; use Elementor\TemplateLibrary\Source_Local; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * General Category * * Provides general items related to Elementor Admin. */ class General extends Base_Category { /** * Get title. * * @since 2.3.0 * @access public * * @return string */ public function get_title() { return esc_html__( 'General', 'elementor' ); } public function get_id() { return 'general'; } /** * Get category items. * * @since 2.3.0 * @access public * * @param array $options * * @return array */ public function get_category_items( array $options = [] ) { return [ 'saved-templates' => [ 'title' => esc_html__( 'Saved Templates', 'elementor' ), 'icon' => 'library-save', 'url' => Source_Local::get_admin_url(), 'keywords' => [ 'template', 'section', 'page', 'library' ], ], 'system-info' => [ 'title' => esc_html__( 'System Info', 'elementor' ), 'icon' => 'info-circle-o', 'url' => admin_url( 'admin.php?page=elementor-system-info' ), 'keywords' => [ 'system', 'info', 'environment', 'elementor' ], ], 'role-manager' => [ 'title' => esc_html__( 'Role Manager', 'elementor' ), 'icon' => 'person', 'url' => Role_Manager::get_url(), 'keywords' => [ 'role', 'manager', 'user', 'elementor' ], ], 'knowledge-base' => [ 'title' => esc_html__( 'Knowledge Base', 'elementor' ), 'url' => admin_url( 'admin.php?page=go_knowledge_base_site' ), 'keywords' => [ 'help', 'knowledge', 'docs', 'elementor' ], ], 'theme-builder' => [ 'title' => esc_html__( 'Theme Builder', 'elementor' ), 'icon' => 'library-save', 'url' => Plugin::$instance->app->get_settings( 'menu_url' ), 'keywords' => [ 'template', 'header', 'footer', 'single', 'archive', 'search', '404', 'library' ], ], 'kit-library' => [ 'title' => esc_html__( 'Kit Library', 'elementor' ), 'icon' => 'kit-parts', 'url' => Plugin::$instance->app->get_base_url() . '#/kit-library', 'keywords' => [ 'kit library', 'kit', 'library', 'site parts', 'parts', 'assets', 'templates' ], ], ]; } } modules/finder/categories/tools.php 0000644 00000004055 15162355077 0013500 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Finder\Categories; use Elementor\Core\Common\Modules\Finder\Base_Category; use Elementor\Tools as ElementorTools; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Tools Category * * Provides items related to Elementor's tools. */ class Tools extends Base_Category { /** * Get title. * * @since 2.3.0 * @access public * * @return string */ public function get_title() { return esc_html__( 'Tools', 'elementor' ); } public function get_id() { return 'tools'; } /** * Get category items. * * @since 2.3.0 * @access public * * @param array $options * * @return array */ public function get_category_items( array $options = [] ) { $tools_url = ElementorTools::get_url(); $items = [ 'tools' => [ 'title' => esc_html__( 'Tools', 'elementor' ), 'icon' => 'tools', 'url' => $tools_url, 'keywords' => [ 'tools', 'regenerate css', 'safe mode', 'debug bar', 'sync library', 'elementor' ], ], 'replace-url' => [ 'title' => esc_html__( 'Replace URL', 'elementor' ), 'icon' => 'tools', 'url' => $tools_url . '#tab-replace_url', 'keywords' => [ 'tools', 'replace url', 'domain', 'elementor' ], ], 'maintenance-mode' => [ 'title' => esc_html__( 'Maintenance Mode', 'elementor' ), 'icon' => 'tools', 'url' => $tools_url . '#tab-maintenance_mode', 'keywords' => [ 'tools', 'maintenance', 'coming soon', 'elementor' ], ], 'import-export' => [ 'title' => esc_html__( 'Import Export', 'elementor' ), 'icon' => 'import-export', 'url' => $tools_url . '#tab-import-export-kit', 'keywords' => [ 'tools', 'import export', 'import', 'export', 'kit' ], ], ]; if ( ElementorTools::can_user_rollback_versions() ) { $items['version-control'] = [ 'title' => esc_html__( 'Version Control', 'elementor' ), 'icon' => 'time-line', 'url' => $tools_url . '#tab-versions', 'keywords' => [ 'tools', 'version', 'control', 'rollback', 'beta', 'elementor' ], ]; } return $items; } } modules/finder/template.php 0000644 00000003632 15162355077 0012026 0 ustar 00 <?php namespace Elementor\Modules\Finder; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } ?> <script type="text/template" id="tmpl-elementor-finder"> <div id="elementor-finder__search"> <i class="eicon-search" aria-hidden="true"></i> <input id="elementor-finder__search__input" placeholder="<?php echo esc_attr__( 'Type to find anything in Elementor', 'elementor' ); ?>" autocomplete="off"> </div> <div id="elementor-finder__content"></div> </script> <script type="text/template" id="tmpl-elementor-finder-results-container"> <div id="elementor-finder__no-results"><?php echo esc_html__( 'No Results Found', 'elementor' ); ?></div> <div id="elementor-finder__results"></div> </script> <script type="text/template" id="tmpl-elementor-finder__results__category"> <div class="elementor-finder__results__category__title">{{{ title }}}</div> <div class="elementor-finder__results__category__items"></div> </script> <script type="text/template" id="tmpl-elementor-finder__results__item"> <a href="{{ url }}" class="elementor-finder__results__item__link"> <div class="elementor-finder__results__item__icon"> <i class="eicon-{{{ icon }}}" aria-hidden="true"></i> </div> <div class="elementor-finder__results__item__title">{{{ title }}}</div> <# if ( description ) { #> <div class="elementor-finder__results__item__description">- {{{ description }}}</div> <# } #> <# if ( lock ) { #> <div class="elementor-finder__results__item__badge"><i class="{{{ lock.badge.icon }}}"></i>{{ lock.badge.text }}</div> <# } #> </a> <# if ( actions.length ) { #> <div class="elementor-finder__results__item__actions"> <# jQuery.each( actions, function() { #> <a class="elementor-finder__results__item__action elementor-finder__results__item__action--{{ this.name }}" href="{{ this.url }}" target="_blank"> <i class="eicon-{{{ this.icon }}}"></i> </a> <# } ); #> </div> <# } #> </script> modules/finder/base-category.php 0000644 00000003127 15162355077 0012737 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Finder; use Elementor\Core\Base\Base_Object; use Elementor\Plugin; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Base Category * * Base class for Elementor Finder categories. */ abstract class Base_Category extends Base_Object { /** * Get title. * * @since 2.3.0 * @abstract * @access public * * @return string */ abstract public function get_title(); /** * Get a unique category ID. * * TODO: Make abstract. * * @since 3.5.0 * @deprecated 3.5.0 * @access public * * @return string */ public function get_id() { Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( get_class( $this ) . '::' . __FUNCTION__, '3.5.0', 'This method will be replaced with an abstract method.' ); return ''; } /** * Get category items. * * @since 2.3.0 * @abstract * @access public * * @param array $options * * @return array */ abstract public function get_category_items( array $options = [] ); /** * Is dynamic. * * Determine if the category is dynamic. * * @since 2.3.0 * @access public * * @return bool */ public function is_dynamic() { return false; } /** * Get init settings. * * @since 2.3.0 * @access protected * * @return array */ protected function get_init_settings() { $settings = [ 'title' => $this->get_title(), 'dynamic' => $this->is_dynamic(), ]; if ( ! $settings['dynamic'] ) { $settings['items'] = $this->get_category_items(); } return $settings; } } modules/finder/categories-manager.php 0000644 00000007273 15162355077 0013755 0 ustar 00 <?php namespace Elementor\Core\Common\Modules\Finder; use Elementor\Plugin; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Categories_Manager { /** * @access private * * @var Base_Category[] */ private $categories; /** * @var array */ private $categories_list = [ 'edit', 'general', 'create', 'site', 'settings', 'tools', ]; /** * Add category. * * @since 2.3.0 * @deprecated 3.5.0 Use `register()` method instead. * @access public * * @param string $category_name * @param Base_Category $category * * @deprecated 3.5.0 Use `register()` method instead. */ public function add_category( $category_name, Base_Category $category ) { Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.5.0', 'register()' ); $this->register( $category, $category_name ); } /** * Register finder category. * * @since 3.5.0 * @access public * * @param Base_Category $finder_category_instance An Instance of a category. * @param string $finder_category_name A Category name. Deprecated parameter. * * @return void */ public function register( Base_Category $finder_category_instance, $finder_category_name = null ) { // TODO: For BC. Remove in the future. if ( $finder_category_name ) { Plugin::instance()->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_argument( '$finder_category_name', '3.5.0' ); } else { $finder_category_name = $finder_category_instance->get_id(); } $this->categories[ $finder_category_name ] = $finder_category_instance; } /** * Unregister a finder category. * * @param string $finder_category_name - Category to unregister. * * @return void * @since 3.6.0 * @access public */ public function unregister( $finder_category_name ) { unset( $this->categories[ $finder_category_name ] ); } /** * Get categories. * * Retrieve the registered categories, or a specific category if the category name * is provided as a parameter. * * @since 2.3.0 * @access public * * @param string $category Category name. * * @return Base_Category|Base_Category[]|null */ public function get_categories( $category = '' ) { if ( ! $this->categories ) { $this->init_categories(); } if ( $category ) { if ( isset( $this->categories[ $category ] ) ) { return $this->categories[ $category ]; } return null; } return $this->categories; } /** * Init categories. * * Used to initialize the native finder categories. * * @since 2.3.0 * @access private */ private function init_categories() { foreach ( $this->categories_list as $category_name ) { $class_name = __NAMESPACE__ . '\Categories\\' . $category_name; $this->register( new $class_name() ); } /** * Elementor Finder categories init. * * Fires after Elementor Finder initialize it's native categories. * * This hook should be used to add your own Finder categories. * * @since 2.3.0 * @deprecated 3.5.0 Use `elementor/finder/register` hook instead. * * @param Categories_Manager $this. */ Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->do_deprecated_action( 'elementor/finder/categories/init', [ $this ], '3.5.0', 'elementor/finder/register' ); /** * Elementor Finder categories registration. * * Fires after Elementor Finder initialize it's native categories. * * This hook should be used to register your own Finder categories. * * @since 3.5.0 * * @param Categories_Manager $this Finder Categories manager. */ do_action( 'elementor/finder/register', $this ); } } app.php 0000644 00000015254 15162355100 0006042 0 ustar 00 <?php namespace Elementor\Core\Common; use Elementor\Core\Base\App as BaseApp; use Elementor\Core\Common\Modules\Ajax\Module as Ajax; use Elementor\Core\Common\Modules\Finder\Module as Finder; use Elementor\Core\Common\Modules\Connect\Module as Connect; use Elementor\Core\Common\Modules\EventTracker\Module as Event_Tracker; use Elementor\Core\Files\Uploads_Manager; use Elementor\Core\Settings\Manager as SettingsManager; use Elementor\Icons_Manager; use Elementor\Plugin; use Elementor\Utils; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * App * * Elementor's common app that groups shared functionality, components and configuration * * @since 2.3.0 */ class App extends BaseApp { private $templates = []; /** * App constructor. * * @since 2.3.0 * @access public */ public function __construct() { $this->add_default_templates(); add_action( 'elementor/editor/before_enqueue_scripts', [ $this, 'register_scripts' ], 9 ); add_action( 'admin_enqueue_scripts', [ $this, 'register_scripts' ], 9 ); add_action( 'wp_enqueue_scripts', [ $this, 'register_scripts' ], 9 ); add_action( 'elementor/editor/before_enqueue_styles', [ $this, 'register_styles' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'register_styles' ] ); add_action( 'wp_enqueue_scripts', [ $this, 'register_styles' ], 9 ); add_action( 'elementor/editor/footer', [ $this, 'print_templates' ] ); add_action( 'admin_footer', [ $this, 'print_templates' ] ); add_action( 'wp_footer', [ $this, 'print_templates' ] ); } /** * Init components * * Initializing common components. * * @since 2.3.0 * @access public */ public function init_components() { $this->add_component( 'ajax', new Ajax() ); if ( current_user_can( 'manage_options' ) ) { if ( ! is_customize_preview() ) { $this->add_component( 'finder', new Finder() ); } } $this->add_component( 'connect', new Connect() ); $this->add_component( 'event-tracker', new Event_Tracker() ); } /** * Get name. * * Retrieve the app name. * * @since 2.3.0 * @access public * * @return string Common app name. */ public function get_name() { return 'common'; } /** * Register scripts. * * Register common scripts. * * @since 2.3.0 * @access public */ public function register_scripts() { wp_register_script( 'elementor-common-modules', $this->get_js_assets_url( 'common-modules' ), [], ELEMENTOR_VERSION, true ); wp_register_script( 'backbone-marionette', $this->get_js_assets_url( 'backbone.marionette', 'assets/lib/backbone/' ), [ 'backbone', ], '2.4.5.e1', true ); wp_register_script( 'backbone-radio', $this->get_js_assets_url( 'backbone.radio', 'assets/lib/backbone/' ), [ 'backbone', ], '1.0.4', true ); wp_register_script( 'elementor-dialog', $this->get_js_assets_url( 'dialog', 'assets/lib/dialog/' ), [ 'jquery-ui-position', ], '4.9.0', true ); wp_enqueue_script( 'elementor-common', $this->get_js_assets_url( 'common' ), [ 'jquery', 'jquery-ui-draggable', 'backbone-marionette', 'backbone-radio', 'elementor-common-modules', 'elementor-web-cli', 'elementor-dialog', 'wp-api-request', 'elementor-dev-tools', ], ELEMENTOR_VERSION, true ); wp_set_script_translations( 'elementor-common', 'elementor' ); $this->print_config(); // Used for external plugins. do_action( 'elementor/common/after_register_scripts', $this ); } /** * Register styles. * * Register common styles. * * @since 2.3.0 * @access public */ public function register_styles() { wp_register_style( 'elementor-icons', $this->get_css_assets_url( 'elementor-icons', 'assets/lib/eicons/css/' ), [], Icons_Manager::ELEMENTOR_ICONS_VERSION ); wp_enqueue_style( 'elementor-common', $this->get_css_assets_url( 'common', null, 'default', true ), [ 'elementor-icons', ], ELEMENTOR_VERSION ); wp_enqueue_style( 'e-theme-ui-light', $this->get_css_assets_url( 'theme-light' ), [], ELEMENTOR_VERSION ); } /** * Add template. * * @since 2.3.0 * @access public * * @param string $template Can be either a link to template file or template * HTML content. * @param string $type Optional. Whether to handle the template as path * or text. Default is `path`. */ public function add_template( $template, $type = 'path' ) { if ( 'path' === $type ) { ob_start(); include $template; $template = ob_get_clean(); } $this->templates[] = $template; } /** * Print Templates * * Prints all registered templates. * * @since 2.3.0 * @access public */ public function print_templates() { foreach ( $this->templates as $template ) { echo $template; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } } /** * Get init settings. * * Define the default/initial settings of the common app. * * @since 2.3.0 * @access protected * * @return array */ protected function get_init_settings() { $active_experimental_features = Plugin::$instance->experiments->get_active_features(); $all_experimental_features = Plugin::$instance->experiments->get_features(); $active_experimental_features = array_fill_keys( array_keys( $active_experimental_features ), true ); $all_experimental_features = array_map( function( $feature ) { return Plugin::$instance->experiments->is_feature_active( $feature['name'] ); }, $all_experimental_features ); $config = [ 'version' => ELEMENTOR_VERSION, 'isRTL' => is_rtl(), 'isDebug' => ( defined( 'WP_DEBUG' ) && WP_DEBUG ), 'isElementorDebug' => Utils::is_elementor_debug(), 'activeModules' => array_keys( $this->get_components() ), 'experimentalFeatures' => $active_experimental_features, 'allExperimentalFeatures' => $all_experimental_features, 'urls' => [ 'assets' => ELEMENTOR_ASSETS_URL, 'rest' => get_rest_url(), ], 'filesUpload' => [ 'unfilteredFiles' => Uploads_Manager::are_unfiltered_uploads_enabled(), ], ]; /** * Localize common settings. * * Filters the editor localized settings. * * @since 1.0.0 * * @param array $config Common configuration. */ return apply_filters( 'elementor/common/localize_settings', $config ); } /** * Add default templates. * * Register common app default templates. * * @since 2.3.0 * @access private */ private function add_default_templates() { $default_templates = [ 'includes/editor-templates/library-layout.php', ]; foreach ( $default_templates as $template ) { $this->add_template( ELEMENTOR_PATH . $template ); } } } status-tooltip.php 0000644 00000003615 15162360043 0010275 0 ustar 00 <?php if (!defined('WORDFENCE_VERSION')) { exit; } /** * @var string $id */ ?> <script type="text/x-jquery-template" id="<?php echo esc_attr($id); ?>-tmpl"> <div class="wf-circle-tooltip-block"> <div class="wf-circle-tooltip-header"><h4><?php echo esc_html($title) ?></h4></div> <div class="wf-circle-tooltip-body wf-flex-vertical wf-flex-align-left wf-flex-full-width"> <?php if (isset($statusExtra) && !empty($statusExtra)) { echo $statusExtra; } ?> <div class="wf-flex-row"> <div class="wf-tooltip-status-circle wf-flex-row-0"> {{html statusCircle}} </div> <div class="wf-flex-row-1"> <?php if (empty($statusList)): ?> <p><?php echo wp_kses(__('<strong>Congratulations!</strong> You\'ve optimized configurations for this feature! If you want to learn more about how this score is determined, click the link below.', 'wordfence'), array('strong'=>array())); ?></p> <p><a target="_blank" rel="noopener noreferrer" href="<?php echo esc_url($helpLink) ?>"><?php esc_html_e('How does Wordfence determine this?', 'wordfence') ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></p> <?php else: ?> <h4><?php esc_html_e('How do I get to 100%?', 'wordfence') ?></h4> <ul> <?php foreach ($statusList as $listItem): ?> <li class="wf-flex-row"> <strong class="wf-flex-row-0"><?php echo $listItem['percentage'] * 100 ?>%</strong> <span class="wf-flex-row-1"><?php echo esc_html($listItem['title']) ?></span> </li> <?php endforeach ?> </ul> <p><a target="_blank" rel="noopener noreferrer" href="<?php echo esc_url($helpLink) ?>"><?php esc_html_e('How does Wordfence determine this?', 'wordfence') ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></p> <?php endif ?> </div> </div> </div> </div> </script>