403Webshell
Server IP : 109.234.162.214  /  Your IP : 216.73.216.112
Web Server : Apache
System : Linux servd162214.srv.odns.fr 4.18.0-372.26.1.lve.1.el8.x86_64 #1 SMP Fri Sep 16 14:08:19 EDT 2022 x86_64
User : carpe ( 1178)
PHP Version : 8.0.30
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /home/carpe/./public_html/space/lbrm3v/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /home/carpe/./public_html/space/lbrm3v/common.tar
app.php000064400000014555151221631420006044 0ustar00<?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' ] );
		add_action( 'admin_enqueue_scripts', [ $this, 'register_scripts' ] );
		add_action( 'wp_enqueue_scripts', [ $this, 'register_scripts' ] );

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

		$active_experimental_features = array_fill_keys( array_keys( $active_experimental_features ), true );

		$config = [
			'version' => ELEMENTOR_VERSION,
			'isRTL' => is_rtl(),
			'isDebug' => ( defined( 'WP_DEBUG' ) && WP_DEBUG ),
			'isElementorDebug' => ( defined( 'ELEMENTOR_DEBUG' ) && ELEMENTOR_DEBUG ),
			'activeModules' => array_keys( $this->get_components() ),
			'experimentalFeatures' => $active_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 );
		}
	}
}
modules/ajax/module.php000064400000016235151221631420011141 0ustar00<?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/apps/connect.php000064400000000673151221631420012755 0ustar00<?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-user-app.php000064400000001060151221631420013757 0ustar00<?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/base-app.php000064400000047404151221631420013017 0ustar00<?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 = '';

			echo sprintf(
				'%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( static::OPTION_CONNECT_SITE_KEY );
			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 ) ) {
			// 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 ( 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' ),
			] );

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

				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/common-app.php000064400000001614151221631420013366 0ustar00<?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.php000064400000007342151221631420012770 0ustar00<?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' );

		return array_replace_recursive( $settings, [
			'library_connect' => [
				'is_connected' => $is_connected,
				'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' ] );
	}

	/**
	 * 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/connect/admin.php000064400000003645151221631420011453 0ustar00<?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 ( 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 ] );
			}
		}
	}

	/**
	 * @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.php000064400000002236151221631420013705 0ustar00<?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.php000064400000013526151221631420011647 0ustar00<?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';

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

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

		return [];
	}

	/**
	 * 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/event-tracker/data/controller.php000064400000003513151221631420014572 0ustar00<?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/personal-data.php000064400000003711151221631420014230 0ustar00<?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.php000064400000001642151221631420012764 0ustar00<?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/db.php000064400000011405151221631420012062 0ustar00<?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'] = 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/template.php000064400000003631151221631420012007 0ustar00<?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/categories-manager.php000064400000007272151221631420013736 0ustar00<?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 );
	}
}
modules/finder/categories/settings.php000064400000003643151221631420014164 0ustar00<?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' ],
			],
			'advanced' => [
				'title' => esc_html__( 'Advanced', 'elementor' ),
				'url' => ElementorSettings::get_settings_tab_url( 'advanced' ),
				'keywords' => [ 'advanced', '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/create.php000064400000005535151221631420013571 0ustar00<?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/site.php000064400000004046151221631420013266 0ustar00<?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/general.php000064400000004450151221631420013736 0ustar00<?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/edit.php000064400000005270151221631420013247 0ustar00<?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/tools.php000064400000004054151221631420013461 0ustar00<?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/module.php000064400000005063151221631420011462 0ustar00<?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/base-category.php000064400000003126151221631420012720 0ustar00<?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;
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit