Файловый менеджер - Редактировать - /var/www/xthruster/html/wp-content/uploads/flags/editor.tar
Назад
template.php 0000644 00000001226 14720517252 0007076 0 ustar 00 <?php use ElementorPro\License\Admin as LicenseAdmin; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } ?> <script type="text/template" id="tmpl-elementor-pro-template-library-activate-license-button"> <a class="elementor-template-library-template-action elementor-button go-pro" href="<?php // PHPCS - the function LicenseAdmin::get_url() is safe. echo LicenseAdmin::get_url(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>" target="_blank"> <i class="eicon-external-link-square"></i> <span class="elementor-button-title"><?php echo esc_html__( 'Activate License', 'elementor-pro' ); ?></span> </a> </script> editor.php 0000644 00000037267 14720517252 0006567 0 ustar 00 <?php namespace Elementor\Core\Editor; use Elementor\Core\Breakpoints\Manager as Breakpoints_Manager; use Elementor\Core\Common\Modules\Ajax\Module; use Elementor\Core\Debug\Loading_Inspection_Manager; use Elementor\Core\Editor\Loader\Editor_Loader_Factory; use Elementor\Core\Editor\Loader\Editor_Loader_Interface; use Elementor\Core\Experiments\Manager as Experiments_Manager; use Elementor\Core\Settings\Manager as SettingsManager; use Elementor\Plugin; use Elementor\TemplateLibrary\Source_Local; use Elementor\Utils; use Elementor\Core\Editor\Data; use Elementor\Modules\EditorAppBar\Module as App_Bar_Module; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Elementor editor. * * Elementor editor handler class is responsible for initializing Elementor * editor and register all the actions needed to display the editor. * * @since 1.0.0 */ class Editor { /** * User capability required to access Elementor editor. */ const EDITING_CAPABILITY = 'edit_posts'; /** * The const is deprecated, it remains here for backward compatibility. * * @deprecated Use App_Bar_Module::EXPERIMENT_NAME instead */ const EDITOR_V2_EXPERIMENT_NAME = App_Bar_Module::EXPERIMENT_NAME; /** * Post ID. * * Holds the ID of the current post being edited. * * @since 1.0.0 * @access private * * @var int Post ID. */ private $post_id; /** * Whether the edit mode is active. * * Used to determine whether we are in edit mode. * * @since 1.0.0 * @access private * * @var bool Whether the edit mode is active. */ private $is_edit_mode; /** * @var Notice_Bar */ public $notice_bar; /** * @var Promotion */ public $promotion; /** * @var Editor_Loader_Interface */ private $loader; /** * Init. * * Initialize Elementor editor. Registers all needed actions to run Elementor, * removes conflicting actions etc. * * Fired by `admin_action_elementor` action. * * @since 1.0.0 * @access public * * @param bool $die Optional. Whether to die at the end. Default is `true`. */ public function init( $die = true ) { if ( empty( $_REQUEST['post'] ) ) { return; } $this->set_post_id( absint( $_REQUEST['post'] ) ); if ( ! $this->is_edit_mode( $this->post_id ) ) { return; } // BC: From 2.9.0, the editor shouldn't handle the global post / current document. // Use requested id and not the global in order to avoid conflicts with plugins that changes the global post. query_posts( [ 'p' => $this->post_id, 'post_type' => get_post_type( $this->post_id ), ] ); Plugin::$instance->db->switch_to_post( $this->post_id ); $document = Plugin::$instance->documents->get( $this->post_id ); Plugin::$instance->documents->switch_to_document( $document ); // Change mode to Builder $document->set_is_built_with_elementor( true ); // End BC. Loading_Inspection_Manager::instance()->register_inspections(); // Send MIME Type header like WP admin-header. @header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) ); add_filter( 'show_admin_bar', '__return_false' ); // Remove all WordPress actions remove_all_actions( 'wp_head' ); remove_all_actions( 'wp_print_styles' ); remove_all_actions( 'wp_print_head_scripts' ); remove_all_actions( 'wp_footer' ); // Handle `wp_head` add_action( 'wp_head', 'wp_enqueue_scripts', 1 ); add_action( 'wp_head', 'wp_print_styles', 8 ); add_action( 'wp_head', 'wp_print_head_scripts', 9 ); add_action( 'wp_head', 'wp_site_icon' ); add_action( 'wp_head', [ $this, 'editor_head_trigger' ], 30 ); // Handle `wp_footer` add_action( 'wp_footer', 'wp_print_footer_scripts', 20 ); add_action( 'wp_footer', 'wp_auth_check_html', 30 ); add_action( 'wp_footer', [ $this, 'wp_footer' ] ); // Handle `wp_enqueue_scripts` remove_all_actions( 'wp_enqueue_scripts' ); // Also remove all scripts hooked into after_wp_tiny_mce. remove_all_actions( 'after_wp_tiny_mce' ); add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ], 999999 ); add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_styles' ], 999999 ); // Setup default heartbeat options add_filter( 'heartbeat_settings', function( $settings ) { $settings['interval'] = 15; return $settings; } ); // Tell to WP Cache plugins do not cache this request. Utils::do_not_cache(); do_action( 'elementor/editor/init' ); $this->get_loader()->print_root_template(); // From the action it's an empty string, from tests its `false` if ( false !== $die ) { die; } } /** * Retrieve post ID. * * Get the ID of the current post. * * @since 1.8.0 * @access public * * @return int Post ID. */ public function get_post_id() { return $this->post_id; } /** * Redirect to new URL. * * Used as a fallback function for the old URL structure of Elementor page * edit URL. * * Fired by `template_redirect` action. * * @since 1.6.0 * @access public */ public function redirect_to_new_url() { if ( ! isset( $_GET['elementor'] ) ) { return; } $document = Plugin::$instance->documents->get( get_the_ID() ); if ( ! $document ) { wp_die( esc_html__( 'Document not found.', 'elementor' ) ); } if ( ! $document->is_editable_by_current_user() || ! $document->is_built_with_elementor() ) { return; } wp_safe_redirect( $document->get_edit_url() ); die; } /** * Whether the edit mode is active. * * Used to determine whether we are in the edit mode. * * @since 1.0.0 * @access public * * @param int $post_id Optional. Post ID. Default is `null`, the current * post ID. * * @return bool Whether the edit mode is active. */ public function is_edit_mode( $post_id = null ) { if ( null !== $this->is_edit_mode ) { return $this->is_edit_mode; } if ( empty( $post_id ) ) { $post_id = $this->post_id; } $document = Plugin::$instance->documents->get( $post_id ); if ( ! $document || ! $document->is_editable_by_current_user() ) { return false; } /** @var Module ajax */ $ajax_data = Plugin::$instance->common->get_component( 'ajax' )->get_current_action_data(); if ( ! empty( $ajax_data ) && 'get_document_config' === $ajax_data['action'] ) { return true; } // Ajax request as Editor mode $actions = [ 'elementor', // Templates 'elementor_get_templates', 'elementor_save_template', 'elementor_get_template', 'elementor_delete_template', 'elementor_import_template', 'elementor_library_direct_actions', ]; if ( isset( $_REQUEST['action'] ) && in_array( $_REQUEST['action'], $actions ) ) { return true; } return false; } /** * Lock post. * * Mark the post as currently being edited by the current user. * * @since 1.0.0 * @access public * * @param int $post_id The ID of the post being edited. */ public function lock_post( $post_id ) { if ( ! function_exists( 'wp_set_post_lock' ) ) { require_once ABSPATH . 'wp-admin/includes/post.php'; } wp_set_post_lock( $post_id ); } /** * Get locked user. * * Check what user is currently editing the post. * * @since 1.0.0 * @access public * * @param int $post_id The ID of the post being edited. * * @return \WP_User|false User information or false if the post is not locked. */ public function get_locked_user( $post_id ) { if ( ! function_exists( 'wp_check_post_lock' ) ) { require_once ABSPATH . 'wp-admin/includes/post.php'; } $locked_user = wp_check_post_lock( $post_id ); if ( ! $locked_user ) { return false; } return get_user_by( 'id', $locked_user ); } /** * NOTICE: This method not in use, it's here for backward compatibility. * * Print Editor Template. * * Include the wrapper template of the editor. * * @since 2.2.0 * @access public */ public function print_editor_template() { include ELEMENTOR_PATH . 'includes/editor-templates/editor-wrapper.php'; } /** * Enqueue scripts. * * Registers all the editor scripts and enqueues them. * * @since 1.0.0 * @access public */ public function enqueue_scripts() { remove_action( 'wp_enqueue_scripts', [ $this, __FUNCTION__ ], 999999 ); global $wp_styles, $wp_scripts; // Reset global variable $wp_styles = new \WP_Styles(); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited $wp_scripts = new \WP_Scripts(); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited $this->get_loader()->register_scripts(); /** * Before editor enqueue scripts. * * Fires before Elementor editor scripts are enqueued. * * @since 1.0.0 */ do_action( 'elementor/editor/before_enqueue_scripts' ); // Tweak for WP Admin menu icons wp_print_styles( 'editor-buttons' ); $this->get_loader()->enqueue_scripts(); Plugin::$instance->controls_manager->enqueue_control_scripts(); /** * After editor enqueue scripts. * * Fires after Elementor editor scripts are enqueued. * * @since 1.0.0 */ do_action( 'elementor/editor/after_enqueue_scripts' ); } /** * Enqueue styles. * * Registers all the editor styles and enqueues them. * * @since 1.0.0 * @access public */ public function enqueue_styles() { /** * Before editor enqueue styles. * * Fires before Elementor editor styles are enqueued. * * @since 1.0.0 */ do_action( 'elementor/editor/before_enqueue_styles' ); $this->get_loader()->register_styles(); $this->get_loader()->enqueue_styles(); $this->enqueue_theme_ui_styles(); $breakpoints = Plugin::$instance->breakpoints->get_breakpoints(); // The two breakpoints under 'tablet' need to be checked for values. if ( $breakpoints[ Breakpoints_Manager::BREAKPOINT_KEY_MOBILE ]->is_custom() || $breakpoints[ Breakpoints_Manager::BREAKPOINT_KEY_MOBILE_EXTRA ]->is_enabled() ) { wp_add_inline_style( 'elementor-editor', '.elementor-device-tablet #elementor-preview-responsive-wrapper { width: ' . Plugin::$instance->breakpoints->get_device_min_breakpoint( Breakpoints_Manager::BREAKPOINT_KEY_TABLET ) . 'px; }' ); } /** * After editor enqueue styles. * * Fires after Elementor editor styles are enqueued. * * @since 1.0.0 */ do_action( 'elementor/editor/after_enqueue_styles' ); } private function enqueue_theme_ui_styles() { $ui_theme_selected = SettingsManager::get_settings_managers( 'editorPreferences' )->get_model()->get_settings( 'ui_theme' ); $ui_themes = [ 'light', 'dark', ]; if ( 'auto' === $ui_theme_selected || ! in_array( $ui_theme_selected, $ui_themes, true ) ) { $ui_light_theme_media_queries = '(prefers-color-scheme: light)'; $ui_dark_theme_media_queries = '(prefers-color-scheme: dark)'; } else { $ui_light_theme_media_queries = 'none'; $ui_dark_theme_media_queries = 'none'; if ( 'light' === $ui_theme_selected ) { $ui_light_theme_media_queries = 'all'; } elseif ( 'dark' === $ui_theme_selected ) { $ui_dark_theme_media_queries = 'all'; } } $this->enqueue_theme_ui( 'light', $ui_light_theme_media_queries ); $this->enqueue_theme_ui( 'dark', $ui_dark_theme_media_queries ); } private function enqueue_theme_ui( $ui_theme, $ui_theme_media_queries = 'all' ) { $suffix = Utils::is_script_debug() ? '' : '.min'; wp_enqueue_style( 'e-theme-ui-' . $ui_theme, ELEMENTOR_ASSETS_URL . 'css/theme-' . $ui_theme . $suffix . '.css', [], ELEMENTOR_VERSION, $ui_theme_media_queries ); } /** * Editor head trigger. * * Fires the 'elementor/editor/wp_head' action in the head tag in Elementor * editor. * * @since 1.0.0 * @access public */ public function editor_head_trigger() { /** * Elementor editor head. * * Fires on Elementor editor head tag. * * Used to prints scripts or any other data in the head tag. * * @since 1.0.0 */ do_action( 'elementor/editor/wp_head' ); } /** * WP footer. * * Prints Elementor editor with all the editor templates, and render controls, * widgets and content elements. * * Fired by `wp_footer` action. * * @since 1.0.0 * @access public */ public function wp_footer() { $plugin = Plugin::$instance; $plugin->controls_manager->render_controls(); $plugin->widgets_manager->render_widgets_content(); $plugin->elements_manager->render_elements_content(); $plugin->dynamic_tags->print_templates(); $this->get_loader()->register_additional_templates(); /** * Elementor editor footer. * * Fires on Elementor editor before closing the body tag. * * Used to prints scripts or any other HTML before closing the body tag. * * @since 1.0.0 */ do_action( 'elementor/editor/footer' ); } /** * Set edit mode. * * Used to update the edit mode. * * @since 1.0.0 * @access public * * @param bool $edit_mode Whether the edit mode is active. */ public function set_edit_mode( $edit_mode ) { $this->is_edit_mode = $edit_mode; } /** * Editor constructor. * * Initializing Elementor editor and redirect from old URL structure of * Elementor editor. * * @since 1.0.0 * @access public */ public function __construct() { Plugin::$instance->data_manager_v2->register_controller( new Data\Globals\Controller() ); $this->notice_bar = new Notice_Bar(); $this->promotion = new Promotion(); add_action( 'admin_action_elementor', [ $this, 'init' ] ); add_action( 'template_redirect', [ $this, 'redirect_to_new_url' ] ); // Handle autocomplete feature for URL control. add_filter( 'wp_link_query_args', [ $this, 'filter_wp_link_query_args' ] ); add_filter( 'wp_link_query', [ $this, 'filter_wp_link_query' ] ); } /** * @since 2.2.0 * @access public */ public function filter_wp_link_query_args( $query ) { $library_cpt_key = array_search( Source_Local::CPT, $query['post_type'], true ); if ( false !== $library_cpt_key ) { unset( $query['post_type'][ $library_cpt_key ] ); } return $query; } /** * @since 2.2.0 * @access public */ public function filter_wp_link_query( $results ) { // PHPCS - The user data is not used. if ( isset( $_POST['editor'] ) && 'elementor' === $_POST['editor'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing $post_type_object = get_post_type_object( 'post' ); $post_label = $post_type_object->labels->singular_name; foreach ( $results as & $result ) { if ( 'post' === get_post_type( $result['ID'] ) ) { $result['info'] = $post_label; } } } return $results; } public function set_post_id( $post_id ) { $this->post_id = $post_id; } /** * Get loader. * * @return Editor_Loader_Interface */ private function get_loader() { if ( ! $this->loader ) { $this->loader = Editor_Loader_Factory::create(); $this->loader->init(); } return $this->loader; } /** * Get elements presets. * * @return array */ public function get_elements_presets() { $element_types = Plugin::$instance->elements_manager->get_element_types(); $presets = []; foreach ( $element_types as $el_type => $element ) { $this->check_element_for_presets( $element, $el_type, $presets ); } return $presets; } /** * @return void */ private function check_element_for_presets( $element, $el_type, &$presets ) { $element_presets = $element->get_panel_presets(); if ( empty( $element_presets ) ) { return; } foreach ( $element_presets as $key => $preset ) { $this->maybe_add_preset( $el_type, $preset, $key, $presets ); } } /** * @return void */ private function maybe_add_preset( $el_type, $preset, $key, &$presets ) { if ( $this->is_valid_preset( $el_type, $preset ) ) { $presets[ $key ] = $preset; } } /** * @return boolean */ private function is_valid_preset( $el_type, $preset ) { return isset( $preset['replacements']['custom']['originalWidget'] ) && $el_type === $preset['replacements']['custom']['originalWidget']; } } promotion.php 0000644 00000002711 14720517252 0007311 0 ustar 00 <?php namespace Elementor\Core\Editor; use Elementor\Core\Utils\Promotions\Filtered_Promotions_Manager; use Elementor\Utils; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } class Promotion { /** * @return array */ public function get_elements_promotion() { return Filtered_Promotions_Manager::get_filtered_promotion_data( $this->get_promotion_data(), 'elementor/editor/promotion/get_elements_promotion', 'action_button', 'url' ); } /** * @return array */ private function get_action_button_content(): array { $has_pro = Utils::has_pro(); return $has_pro ? [ 'text' => __( 'Connect & Activate', 'elementor' ), 'url' => admin_url( 'admin.php?page=elementor-license' ), ] : [ 'text' => __( 'Upgrade Now', 'elementor' ), 'url' => 'https://go.elementor.com/go-pro-%s', ]; } /** * @return string */ private function get_promotion_url(): string { return Utils::has_pro() ? admin_url( 'admin.php?page=elementor-license' ) : 'https://go.elementor.com/go-pro-%s'; } /** * @return array */ private function get_promotion_data(): array { return [ /* translators: %s: Widget title. */ 'title' => __( '%s Widget', 'elementor' ), /* translators: %s: Widget title. */ 'content' => __( 'Use %s widget and dozens more pro features to extend your toolbox and build sites faster and better.', 'elementor' ), 'action_button' => $this->get_action_button_content(), ]; } } notice-bar.php 0000644 00000010052 14720517252 0007303 0 ustar 00 <?php namespace Elementor\Core\Editor; use Elementor\Core\Base\Base_Object; use Elementor\Core\Common\Modules\Ajax\Module as Ajax; use Elementor\Core\Utils\Promotions\Filtered_Promotions_Manager; use Elementor\Plugin; use Elementor\Utils; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } class Notice_Bar extends Base_Object { protected function get_init_settings() { if ( Plugin::$instance->get_install_time() > strtotime( '-1 days' ) ) { return []; } $upgrade_url = 'https://go.elementor.com/go-pro-editor-notice-bar/'; $config = [ 'description' => $this->get_description(), 'upgrade_text' => $this->get_upgrade_text(), 'upgrade_url' => $upgrade_url, ]; $config = Filtered_Promotions_Manager::get_filtered_promotion_data( $config, 'elementor/notice-bar/custom_promotion', 'upgrade_url' ); return [ 'muted_period' => 14, 'option_key' => '_elementor_editor_upgrade_notice_dismissed', 'message' => $config['description'] ?? $this->get_description(), 'action_title' => $config['upgrade_text'] ?? $this->get_upgrade_text(), 'action_url' => $config['upgrade_url'] ?? $upgrade_url, ]; } public function get_upgrade_text() { return esc_html__( 'Upgrade Now', 'elementor' ); } public function get_description() { return esc_html__( 'Unleash the full power of Elementor\'s features and web creation tools.', 'elementor' ); } final public function get_notice() { if ( ! $this->has_access_to_notice() ) { return null; } $settings = $this->get_settings(); if ( empty( $settings['option_key'] ) ) { return null; } $dismissed_time = get_option( $settings['option_key'] ); if ( $dismissed_time ) { if ( $dismissed_time > strtotime( '-' . $settings['muted_period'] . ' days' ) ) { return null; } $this->set_notice_dismissed(); } return $this; } protected function render_action( $type ) { $settings = $this->get_settings(); // TODO: Make the API better. The bad naming is because of BC. $prefix_map = [ 'primary' => '', 'secondary' => 'secondary_', ]; $prefix = $prefix_map[ $type ]; $action_title = "{$prefix}action_title"; $action_url = "{$prefix}action_url"; $action_message = "{$prefix}message"; $action_target = "{$prefix}action_target"; if ( empty( $settings[ $action_title ] ) || empty( $settings[ $action_url ] ) || empty( $settings[ $action_message ] ) ) { return; } ?> <div class="e-notice-bar__message <?php echo esc_attr( "e-notice-bar__{$type}_message" ); ?>"> <?php Utils::print_unescaped_internal_string( sprintf( $settings[ $action_message ], $settings[ $action_url ] ) ); ?> </div> <div class="e-notice-bar__action <?php echo esc_attr( "e-notice-bar__{$type}_action" ); ?>"> <a href="<?php Utils::print_unescaped_internal_string( $settings[ $action_url ] ); ?>" target="<?php echo empty( $settings[ $action_target ] ) ? '_blank' : esc_attr( $settings[ $action_target ] ); ?>" > <?php Utils::print_unescaped_internal_string( $settings[ $action_title ] ); ?> </a> </div> <?php } public function render() { $settings = $this->get_settings(); $icon = empty( $settings['icon'] ) ? 'eicon-elementor-square' : esc_attr( $settings['icon'] ); ?> <div id="e-notice-bar" class="e-notice-bar"> <i class="e-notice-bar__icon <?php echo esc_attr( $icon ); ?>"></i> <?php $this->render_action( 'primary' ); $this->render_action( 'secondary' ); ?> <i id="e-notice-bar__close" class="e-notice-bar__close eicon-close"></i> </div> <?php } public function __construct() { add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_actions' ] ); } public function set_notice_dismissed() { if ( ! $this->has_access_to_notice() ) { throw new \Exception( 'Access denied' ); } update_option( $this->get_settings( 'option_key' ), time() ); } public function register_ajax_actions( Ajax $ajax ) { $ajax->register_ajax_action( 'notice_bar_dismiss', [ $this, 'set_notice_dismissed' ] ); } private function has_access_to_notice() { return current_user_can( 'manage_options' ); } } data/globals/controller.php 0000644 00000002023 14721565512 0012001 0 ustar 00 <?php namespace Elementor\Core\Editor\Data\Globals; use Elementor\Data\V2\Base\Controller as Controller_Base; use Elementor\Data\V2\Base\Endpoint; use Elementor\Plugin; class Controller extends Controller_Base { public function get_name() { return 'globals'; } public function register_endpoints() { $this->register_endpoint( new Endpoints\Colors( $this ) ); $this->register_endpoint( new Endpoints\Typography( $this ) ); } public function get_collection_params() { // Does not have 'get_items' args (OPTIONS). // Maybe TODO: try `$this->get_index_endpoint()->get_collection_params()`. return []; } public function get_permission_callback( $request ) { // Allow internal get global values. (e.g render global.css for a visitor) if ( 'GET' === $request->get_method() && Plugin::$instance->data_manager_v2->is_internal() ) { return true; } return current_user_can( 'edit_posts' ); } protected function register_index_endpoint() { $this->register_endpoint( new Endpoint\Index\AllChildren( $this ) ); } } data/globals/endpoints/base.php 0000644 00000003200 14721565512 0012531 0 ustar 00 <?php namespace Elementor\Core\Editor\Data\Globals\Endpoints; use Elementor\Data\V2\Base\Endpoint; use Elementor\Data\V2\Base\Exceptions\Data_Exception; use Elementor\Data\V2\Base\Exceptions\Error_404; use Elementor\Plugin; abstract class Base extends Endpoint { protected function register() { parent::register(); $args = [ 'id_arg_type_regex' => '[\w]+', ]; $this->register_item_route( \WP_REST_Server::READABLE, $args ); $this->register_item_route( \WP_REST_Server::CREATABLE, $args ); $this->register_item_route( \WP_REST_Server::DELETABLE, $args ); } public function get_items( $request ) { return $this->get_kit_items(); } /** * @inheritDoc * @throws \Elementor\Data\V2\Base\Exceptions\Error_404 */ public function get_item( $id, $request ) { $items = $this->get_kit_items(); if ( ! isset( $items[ $id ] ) ) { throw new Error_404( esc_html__( 'The Global value you are trying to use is not available.', 'elementor' ), 'global_not_found' ); } return $items[ $id ]; } public function create_item( $id, $request ) { $item = $request->get_body_params(); if ( ! isset( $item['title'] ) ) { return new Data_Exception( esc_html__( 'Invalid title', 'elementor' ), 'invalid_title' ); } $kit = Plugin::$instance->kits_manager->get_active_kit(); $item['id'] = $id; $db_item = $this->convert_db_format( $item ); $kit->add_repeater_row( 'custom_' . $this->get_name(), $db_item ); return $item; } abstract protected function get_kit_items(); /** * @param array $item frontend format. * @return array backend format. */ abstract protected function convert_db_format( $item ); } data/globals/endpoints/colors.php 0000644 00000002027 14721565512 0013126 0 ustar 00 <?php namespace Elementor\Core\Editor\Data\Globals\Endpoints; use Elementor\Plugin; class Colors extends Base { public function get_name() { return 'colors'; } public function get_format() { return 'globals/colors/{id}'; } protected function get_kit_items() { $result = []; $kit = Plugin::$instance->kits_manager->get_active_kit_for_frontend(); $system_items = $kit->get_settings_for_display( 'system_colors' ); $custom_items = $kit->get_settings_for_display( 'custom_colors' ); if ( ! $system_items ) { $system_items = []; } if ( ! $custom_items ) { $custom_items = []; } $items = array_merge( $system_items, $custom_items ); foreach ( $items as $index => $item ) { $id = $item['_id']; $result[ $id ] = [ 'id' => $id, 'title' => $item['title'] ?? '', 'value' => $item['color'] ?? '', ]; } return $result; } protected function convert_db_format( $item ) { return [ '_id' => $item['id'], 'title' => $item['title'] ?? '', 'color' => $item['value'] ?? '', ]; } } data/globals/endpoints/typography.php 0000644 00000003137 14721565512 0014036 0 ustar 00 <?php namespace Elementor\Core\Editor\Data\Globals\Endpoints; use Elementor\Plugin; class Typography extends Base { public function get_name() { return 'typography'; } public function get_format() { return 'globals/typography/{id}'; } protected function get_kit_items() { $result = []; $kit = Plugin::$instance->kits_manager->get_active_kit_for_frontend(); // Use raw settings that doesn't have default values. $kit_raw_settings = $kit->get_data( 'settings' ); if ( isset( $kit_raw_settings['system_typography'] ) ) { $system_items = $kit_raw_settings['system_typography']; } else { // Get default items, but without empty defaults. $control = $kit->get_controls( 'system_typography' ); $system_items = $control['default']; } $custom_items = $kit->get_settings( 'custom_typography' ); if ( ! $custom_items ) { $custom_items = []; } $items = array_merge( $system_items, $custom_items ); foreach ( $items as $index => &$item ) { foreach ( $item as $setting => $value ) { $new_setting = str_replace( 'styles_', '', $setting, $count ); if ( $count ) { $item[ $new_setting ] = $value; unset( $item[ $setting ] ); } } $id = $item['_id']; $result[ $id ] = [ 'title' => $item['title'] ?? '', 'id' => $id, ]; unset( $item['_id'], $item['title'] ); $result[ $id ]['value'] = $item; } return $result; } protected function convert_db_format( $item ) { $db_format = [ '_id' => $item['id'], 'title' => $item['title'] ?? '', ]; $db_format = array_merge( $item['value'], $db_format ); return $db_format; } } loader/editor-loader-interface.php 0000644 00000002162 14721565512 0013224 0 ustar 00 <?php namespace Elementor\Core\Editor\Loader; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } interface Editor_Loader_Interface { /** * Init function purpose is to prepare some stuff that should be available for other methods * and register some hooks * * @return void */ public function init(); /** * Register all the scripts for the editor. * * @return void */ public function register_scripts(); /** * Enqueue all the scripts for the editor. * * @return void */ public function enqueue_scripts(); /** * Register all the styles for the editor. * * @return void */ public function register_styles(); /** * Enqueue all the styles for the editor. * * @return void */ public function enqueue_styles(); /** * Print the actual initial html for the editor, later on, the scripts takeover and renders the JS apps. * * @return void */ public function print_root_template(); /** * Register additional templates that are required for the marionette part of the application * * @return void */ public function register_additional_templates(); } loader/v1/editor-v1-loader.php 0000644 00000004073 14721565512 0012143 0 ustar 00 <?php namespace Elementor\Core\Editor\Loader\V1; use Elementor\Core\Editor\Loader\Common\Editor_Common_Scripts_Settings; use Elementor\Core\Editor\Loader\Editor_Base_Loader; use Elementor\Plugin; use Elementor\Utils; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Editor_V1_Loader extends Editor_Base_Loader { /** * @return void */ public function init() { // Loading UI and Icons v2 scrips for the use of new features that should live in V1. $packages_to_register = [ 'ui', 'icons', 'query' ]; foreach ( $packages_to_register as $package ) { $this->assets_config_provider->load( $package ); } } /** * @return void */ public function register_scripts() { parent::register_scripts(); $assets_url = $this->config->get( 'assets_url' ); $min_suffix = $this->config->get( 'min_suffix' ); foreach ( $this->assets_config_provider->all() as $package => $config ) { wp_register_script( $config['handle'], "{$assets_url}js/packages/{$package}/{$package}{$min_suffix}.js", $config['deps'], ELEMENTOR_VERSION, true ); } wp_register_script( 'elementor-editor-loader-v1', "{$assets_url}js/editor-loader-v1{$min_suffix}.js", [ 'elementor-editor' ], ELEMENTOR_VERSION, true ); } /** * @return void */ public function enqueue_scripts() { parent::enqueue_scripts(); // Must be last. wp_enqueue_script( 'elementor-editor-loader-v1' ); Utils::print_js_config( 'elementor-editor', 'ElementorConfig', Editor_Common_Scripts_Settings::get() ); } /** * @return void */ public function print_root_template() { // Exposing the path for the view part to render the body of the editor template. $body_file_path = __DIR__ . '/templates/editor-body-v1.view.php'; include ELEMENTOR_PATH . 'includes/editor-templates/editor-wrapper.php'; } /** * @return void */ public function register_additional_templates() { parent::register_additional_templates(); Plugin::$instance->common->add_template( ELEMENTOR_PATH . 'includes/editor-templates/responsive-bar.php' ); } } loader/v1/templates/editor-body-v1.view.php 0000644 00000003102 14721565512 0014571 0 ustar 00 <?php namespace Elementor\Core\Editor\Loader\V1\Templates; use Elementor\Plugin; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } $notice = Plugin::$instance->editor->notice_bar->get_notice(); ?> <div id="elementor-loading"> <div class="elementor-loader-wrapper"> <div class="elementor-loader" aria-hidden="true"> <div class="elementor-loader-boxes"> <div class="elementor-loader-box"></div> <div class="elementor-loader-box"></div> <div class="elementor-loader-box"></div> <div class="elementor-loader-box"></div> </div> </div> <div class="elementor-loading-title"><?php echo esc_html__( 'Loading', 'elementor' ); ?></div> </div> </div> <h1 class="elementor-screen-only"><?php echo sprintf( esc_html__( 'Edit "%s" with Elementor', 'elementor' ), esc_html( get_the_title() ) ); ?></h1> <div id="elementor-editor-wrapper"> <aside id="elementor-panel" class="elementor-panel" aria-labelledby="elementor-panel-header-title"></aside> <main id="elementor-preview" aria-label="<?php echo esc_attr__( 'Preview', 'elementor' ); ?>"> <div id="elementor-responsive-bar"></div> <div id="elementor-preview-responsive-wrapper" class="elementor-device-desktop elementor-device-rotate-portrait"> <div id="elementor-preview-loading"> <i class="eicon-loading eicon-animation-spin" aria-hidden="true"></i> </div> <?php if ( $notice ) { $notice->render(); } // IFrame will be created here by the Javascript later. ?> </div> </main> <aside id="elementor-navigator" aria-labelledby="elementor-navigator__header__title"></aside> </div> loader/v1/js/editor-loader-v1.js 0000644 00000000032 14721565512 0012373 0 ustar 00 window.elementor.start(); loader/editor-base-loader.php 0000644 00000013200 14721565512 0012171 0 ustar 00 <?php namespace Elementor\Core\Editor\Loader; use Elementor\Core\Utils\Assets_Config_Provider; use Elementor\Core\Utils\Collection; use Elementor\Plugin; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } abstract class Editor_Base_Loader implements Editor_Loader_Interface { /** * @var Collection */ protected $config; /** * @var Assets_Config_Provider */ protected $assets_config_provider; /** * @param Collection $config * @param Assets_Config_Provider $assets_config_provider\ */ public function __construct( Collection $config, Assets_Config_Provider $assets_config_provider ) { $this->config = $config; $this->assets_config_provider = $assets_config_provider; } /** * @return void */ public function register_scripts() { $assets_url = $this->config->get( 'assets_url' ); $min_suffix = $this->config->get( 'min_suffix' ); wp_register_script( 'elementor-editor-modules', "{$assets_url}js/editor-modules{$min_suffix}.js", [ 'elementor-common-modules' ], ELEMENTOR_VERSION, true ); wp_register_script( 'elementor-editor-document', "{$assets_url}js/editor-document{$min_suffix}.js", [ 'elementor-common-modules' ], ELEMENTOR_VERSION, true ); wp_register_script( 'perfect-scrollbar', "{$assets_url}lib/perfect-scrollbar/js/perfect-scrollbar{$min_suffix}.js", [], '1.4.0', true ); wp_register_script( 'jquery-easing', "{$assets_url}lib/jquery-easing/jquery-easing{$min_suffix}.js", [ 'jquery' ], '1.3.2', true ); wp_register_script( 'nprogress', "{$assets_url}lib/nprogress/nprogress{$min_suffix}.js", [], '0.2.0', true ); wp_register_script( 'tipsy', "{$assets_url}lib/tipsy/tipsy{$min_suffix}.js", [ 'jquery' ], '1.0.0', true ); wp_register_script( 'jquery-elementor-select2', "{$assets_url}lib/e-select2/js/e-select2.full{$min_suffix}.js", [ 'jquery' ], '4.0.6-rc.1', true ); wp_register_script( 'flatpickr', "{$assets_url}lib/flatpickr/flatpickr{$min_suffix}.js", [ 'jquery' ], '4.6.13', true ); wp_register_script( 'ace', 'https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.5/ace.js', [], '1.2.5', true ); wp_register_script( 'ace-language-tools', 'https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.5/ext-language_tools.js', [ 'ace' ], '1.2.5', true ); wp_register_script( 'jquery-hover-intent', "{$assets_url}lib/jquery-hover-intent/jquery-hover-intent{$min_suffix}.js", [], '1.0.0', true ); wp_register_script( 'nouislider', "{$assets_url}lib/nouislider/nouislider{$min_suffix}.js", [], '13.0.0', true ); wp_register_script( 'pickr', "{$assets_url}lib/pickr/pickr.min.js", [], '1.8.2', true ); wp_register_script( 'elementor-editor', "{$assets_url}js/editor{$min_suffix}.js", [ 'elementor-common', 'elementor-editor-modules', 'elementor-editor-document', 'wp-auth-check', 'jquery-ui-sortable', 'jquery-ui-resizable', 'perfect-scrollbar', 'nprogress', 'tipsy', 'imagesloaded', 'heartbeat', 'jquery-elementor-select2', 'flatpickr', 'ace', 'ace-language-tools', 'jquery-hover-intent', 'nouislider', 'pickr', 'react', 'react-dom', ], ELEMENTOR_VERSION, true ); wp_set_script_translations( 'elementor-editor', 'elementor' ); wp_register_script( 'elementor-responsive-bar', "{$assets_url}js/responsive-bar{$min_suffix}.js", [ 'elementor-editor' ], ELEMENTOR_VERSION, true ); wp_set_script_translations( 'elementor-responsive-bar', 'elementor' ); } /** * @return void */ public function enqueue_scripts() { wp_enqueue_script( 'elementor-responsive-bar' ); } /** * @return void */ public function register_styles() { $assets_url = $this->config->get( 'assets_url' ); $min_suffix = $this->config->get( 'min_suffix' ); $direction_suffix = $this->config->get( 'direction_suffix' ); wp_register_style( 'font-awesome', "{$assets_url}lib/font-awesome/css/font-awesome{$min_suffix}.css", [], '4.7.0' ); wp_register_style( 'elementor-select2', "{$assets_url}lib/e-select2/css/e-select2{$min_suffix}.css", [], '4.0.6-rc.1' ); wp_register_style( 'google-font-roboto', 'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700', [], ELEMENTOR_VERSION ); wp_register_style( 'flatpickr', "{$assets_url}lib/flatpickr/flatpickr{$min_suffix}.css", [], '4.6.13' ); wp_register_style( 'pickr', "{$assets_url}lib/pickr/themes/monolith.min.css", [], '1.8.2' ); wp_register_style( 'elementor-editor', "{$assets_url}css/editor{$direction_suffix}{$min_suffix}.css", [ 'elementor-common', 'elementor-select2', 'elementor-icons', 'wp-auth-check', 'google-font-roboto', 'flatpickr', 'pickr', ], ELEMENTOR_VERSION ); wp_register_style( 'elementor-responsive-bar', "{$assets_url}css/responsive-bar{$min_suffix}.css", [], ELEMENTOR_VERSION ); } /** * @return void */ public function enqueue_styles() { wp_enqueue_style( 'elementor-editor' ); wp_enqueue_style( 'elementor-responsive-bar' ); } /** * @return void */ public function register_additional_templates() { $templates = [ 'global', 'panel', 'panel-elements', 'repeater', 'templates', 'navigator', 'hotkeys', 'responsive-bar', ]; $templates = apply_filters( 'elementor/editor/templates', $templates ); foreach ( $templates as $template ) { Plugin::$instance->common->add_template( ELEMENTOR_PATH . "includes/editor-templates/{$template}.php" ); } } } loader/editor-loader-factory.php 0000644 00000002450 14721565512 0012733 0 ustar 00 <?php namespace Elementor\Core\Editor\Loader; use Elementor\Core\Editor\Editor; use Elementor\Core\Editor\Loader\V1\Editor_V1_Loader; use Elementor\Core\Editor\Loader\V2\Editor_V2_Loader; use Elementor\Core\Utils\Assets_Config_Provider; use Elementor\Core\Utils\Collection; use Elementor\Plugin; use Elementor\Utils; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Editor_Loader_Factory { /** * @return Editor_Loader_Interface */ public static function create() { $config = new Collection( [ 'assets_url' => ELEMENTOR_ASSETS_URL, 'min_suffix' => ( Utils::is_script_debug() || Utils::is_elementor_tests() ) ? '' : '.min', 'direction_suffix' => is_rtl() ? '-rtl' : '', ] ); $assets_config_provider = ( new Assets_Config_Provider() ) ->set_path_resolver( function ( $name ) { return ELEMENTOR_ASSETS_PATH . "js/packages/{$name}/{$name}.asset.php"; } ); if ( static::should_use_v2_loader() ) { return new Editor_V2_Loader( $config, $assets_config_provider ); } return new Editor_V1_Loader( $config, $assets_config_provider ); } /** * If there are v2 packages enqueued, we should use the V2 loader. * * @return bool */ private static function should_use_v2_loader() { return ! empty( Editor_V2_Loader::get_packages_to_enqueue() ); } } loader/v2/scss/editor-v2-app-bar-overrides.scss 0000644 00000002142 14721565512 0015353 0 ustar 00 /** * Here should be only styles that related to the Editor v1, and should be overridden when using the Editor v2. */ body { --editor-v2-top-bar-height: 48px; } #elementor-editor-wrapper { height: calc(100vh - var(--editor-v2-top-bar-height)); } body.elementor-navigator-docked #elementor-navigator { height: calc(100% - var(--editor-v2-top-bar-height)); top: var(--editor-v2-top-bar-height); } .elementor-panel #elementor-panel-header-menu-button, .elementor-panel #elementor-panel-header-add-button, .elementor-panel #elementor-panel-footer { display: none; } .elementor-panel #elementor-panel-header { font-weight: 700; background-color: var( --e-a-bg-default ); color: var( --e-a-color-txt-accent ); border-block-end: var( --e-a-border ); height: 48px; } // Make the MCE full-screen work properly with the top bar. .elementor-control-type-wysiwyg .mce-fullscreen { inset: var(--editor-v2-top-bar-height) 0 0 0; & > .mce-container-body { display: flex; flex-direction: column; height: 100%; & > .mce-edit-area { flex-grow: 1; & > iframe { height: 100% !important; } } } } loader/v2/templates/editor-body-v2.view.php 0000644 00000003160 14721565512 0014577 0 ustar 00 <?php namespace Elementor\Core\Editor\Loader\V2\Templates; use Elementor\Plugin; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } $notice = Plugin::$instance->editor->notice_bar->get_notice(); ?> <div id="elementor-loading"> <div class="elementor-loader-wrapper"> <div class="elementor-loader" aria-hidden="true"> <div class="elementor-loader-boxes"> <div class="elementor-loader-box"></div> <div class="elementor-loader-box"></div> <div class="elementor-loader-box"></div> <div class="elementor-loader-box"></div> </div> </div> <div class="elementor-loading-title"><?php echo esc_html__( 'Loading', 'elementor' ); ?></div> </div> </div> <h1 class="elementor-screen-only"><?php echo sprintf( esc_html__( 'Edit "%s" with Elementor', 'elementor' ), esc_html( get_the_title() ) ); ?></h1> <div id="elementor-editor-wrapper-v2"></div> <div id="elementor-editor-wrapper"> <aside id="elementor-panel" class="elementor-panel" aria-labelledby="elementor-panel-header-title"></aside> <main id="elementor-preview" aria-label="<?php echo esc_attr__( 'Preview', 'elementor' ); ?>"> <div id="elementor-responsive-bar"></div> <div id="elementor-preview-responsive-wrapper" class="elementor-device-desktop elementor-device-rotate-portrait"> <div id="elementor-preview-loading"> <i class="eicon-loading eicon-animation-spin" aria-hidden="true"></i> </div> <?php if ( $notice ) { $notice->render(); } // IFrame will be created here by the Javascript later. ?> </div> </main> <aside id="elementor-navigator" aria-labelledby="elementor-navigator__header__title"></aside> </div> loader/v2/js/editor-environment-v2.js 0000644 00000000251 14721565512 0013476 0 ustar 00 if ( ! window.elementorV2?.env ) { throw new Error( 'The "@elementor/env" package was not loaded.' ); } window.elementorV2.env.initEnv( window.elementorEditorV2Env ); loader/v2/js/editor-loader-v2.js 0000644 00000000625 14721565512 0012405 0 ustar 00 window.__elementorEditorV1LoadingPromise = new Promise( ( resolve ) => { window.addEventListener( 'elementor/init', () => { resolve(); }, { once: true } ); } ); window.elementor.start(); if ( ! window.elementorV2?.editor ) { throw new Error( 'The "@elementor/editor" package was not loaded.' ); } window.elementorV2 .editor .init( document.getElementById( 'elementor-editor-wrapper-v2' ), ); loader/v2/editor-v2-loader.php 0000644 00000011661 14721565512 0012146 0 ustar 00 <?php namespace Elementor\Core\Editor\Loader\V2; use Elementor\Core\Editor\Loader\Common\Editor_Common_Scripts_Settings; use Elementor\Core\Editor\Loader\Editor_Base_Loader; use Elementor\Core\Utils\Assets_Translation_Loader; use Elementor\Core\Utils\Collection; use Elementor\Utils; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Editor_V2_Loader extends Editor_Base_Loader { const APP_PACKAGE = 'editor'; const ENV_PACKAGE = 'env'; /** * Packages that should only be registered, unless some other asset depends on them. */ const LIBS = [ 'editor-responsive', 'editor-v1-adapters', self::ENV_PACKAGE, 'icons', 'locations', 'menus', 'query', 'schema', 'store', 'ui', 'utils', 'wp-media', ]; /** * Additional dependencies for packages that rely on global variables, rather than * an explicit npm dependency (e.g. `window.elementor`, `window.wp`, etc.). */ const ADDITIONAL_DEPS = [ 'editor-v1-adapters' => [ 'elementor-web-cli', ], 'wp-media' => [ 'media-models', ], ]; /** * @return void */ public function init() { $packages = array_merge( $this->get_packages_to_enqueue(), self::LIBS ); $packages_with_app = array_merge( $packages, [ self::APP_PACKAGE ] ); foreach ( $packages_with_app as $package ) { $this->assets_config_provider->load( $package ); } do_action( 'elementor/editor/v2/init' ); } /** * @return void */ public function register_scripts() { parent::register_scripts(); $assets_url = $this->config->get( 'assets_url' ); $min_suffix = $this->config->get( 'min_suffix' ); foreach ( $this->assets_config_provider->all() as $package => $config ) { if ( self::ENV_PACKAGE === $package ) { wp_register_script( 'elementor-editor-environment-v2', "{$assets_url}js/editor-environment-v2{$min_suffix}.js", [ $config['handle'] ], ELEMENTOR_VERSION, true ); } if ( static::APP_PACKAGE === $package ) { wp_register_script( 'elementor-editor-loader-v2', "{$assets_url}js/editor-loader-v2{$min_suffix}.js", [ 'elementor-editor', $config['handle'] ], ELEMENTOR_VERSION, true ); } $additional_deps = self::ADDITIONAL_DEPS[ $package ] ?? []; $deps = array_merge( $config['deps'], $additional_deps ); wp_register_script( $config['handle'], "{$assets_url}js/packages/{$package}/{$package}{$min_suffix}.js", $deps, ELEMENTOR_VERSION, true ); } $packages_handles = $this->assets_config_provider->pluck( 'handle' )->all(); Assets_Translation_Loader::for_handles( $packages_handles, 'elementor' ); do_action( 'elementor/editor/v2/scripts/register' ); } /** * @return void */ public function enqueue_scripts() { do_action( 'elementor/editor/v2/scripts/enqueue/before' ); parent::enqueue_scripts(); wp_enqueue_script( 'elementor-editor-environment-v2' ); $env_config = $this->assets_config_provider->get( self::ENV_PACKAGE ); if ( $env_config ) { $client_env = apply_filters( 'elementor/editor/v2/scripts/env', [] ); Utils::print_js_config( $env_config['handle'], 'elementorEditorV2Env', $client_env ); } $packages_with_app = array_merge( $this->get_packages_to_enqueue(), [ self::APP_PACKAGE ] ); foreach ( $this->assets_config_provider->only( $packages_with_app ) as $config ) { wp_enqueue_script( $config['handle'] ); } do_action( 'elementor/editor/v2/scripts/enqueue' ); Utils::print_js_config( 'elementor-editor', 'ElementorConfig', Editor_Common_Scripts_Settings::get() ); // Must be last. wp_enqueue_script( 'elementor-editor-loader-v2' ); do_action( 'elementor/editor/v2/scripts/enqueue/after' ); } /** * @return void */ public function register_styles() { parent::register_styles(); $assets_url = $this->config->get( 'assets_url' ); $min_suffix = $this->config->get( 'min_suffix' ); foreach ( $this->get_styles() as $style ) { wp_register_style( "elementor-{$style}", "{$assets_url}css/{$style}{$min_suffix}.css", [ 'elementor-editor' ], ELEMENTOR_VERSION ); } do_action( 'elementor/editor/v2/styles/register' ); } /** * @return void */ public function enqueue_styles() { parent::enqueue_styles(); foreach ( $this->get_styles() as $style ) { wp_enqueue_style( "elementor-{$style}" ); } do_action( 'elementor/editor/v2/styles/enqueue' ); } /** * @return void */ public function print_root_template() { // Exposing the path for the view part to render the body of the editor template. $body_file_path = __DIR__ . '/templates/editor-body-v2.view.php'; include ELEMENTOR_PATH . 'includes/editor-templates/editor-wrapper.php'; } public static function get_packages_to_enqueue() : array { return apply_filters( 'elementor/editor/v2/packages', [] ); } private function get_styles() : array { $styles = apply_filters( 'elementor/editor/v2/styles', [] ); return Collection::make( $styles ) ->unique() ->all(); } } loader/common/editor-common-scripts-settings.php 0000644 00000016545 14721565512 0016135 0 ustar 00 <?php namespace Elementor\Core\Editor\Loader\Common; use Elementor\Api; use Elementor\Core\Debug\Loading_Inspection_Manager; use Elementor\Core\Settings\Manager as SettingsManager; use Elementor\Group_Control_Typography; use Elementor\Icons_Manager; use Elementor\Modules\Apps\Module as AppsModule; use Elementor\Modules\EditorEvents\Module as EditorEventsModule; use Elementor\Modules\Home\Module as Home_Module; use Elementor\Plugin; use Elementor\Settings; use Elementor\Shapes; use Elementor\Tools; use Elementor\User; use Elementor\Utils; use Elementor\Core\Utils\Promotions\Filtered_Promotions_Manager; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Editor_Common_Scripts_Settings { public static function get() { $settings = SettingsManager::get_settings_managers_config(); // Moved to document since 2.9.0. unset( $settings['page'] ); $document = Plugin::$instance->documents->get_doc_or_auto_save( Plugin::$instance->editor->get_post_id() ); $kits_manager = Plugin::$instance->kits_manager; $page_title_selector = $kits_manager->get_current_settings( 'page_title_selector' ); $page_title_selector .= ', .elementor-page-title .elementor-heading-title'; $client_env = [ 'initial_document' => $document->get_config(), 'version' => ELEMENTOR_VERSION, 'home_url' => home_url(), 'admin_settings_url' => admin_url( 'admin.php?page=' . Home_Module::get_elementor_settings_page_id() ), 'admin_tools_url' => admin_url( 'admin.php?page=' . Tools::PAGE_ID ), 'admin_apps_url' => admin_url( 'admin.php?page=' . AppsModule::PAGE_ID ), 'autosave_interval' => AUTOSAVE_INTERVAL, 'tabs' => Plugin::$instance->controls_manager->get_tabs(), 'controls' => Plugin::$instance->controls_manager->get_controls_data(), 'elements' => Plugin::$instance->elements_manager->get_element_types_config(), 'globals' => [ 'defaults_enabled' => [ 'colors' => $kits_manager->is_custom_colors_enabled(), 'typography' => $kits_manager->is_custom_typography_enabled(), ], ], 'icons' => [ 'libraries' => Icons_Manager::get_icon_manager_tabs_config(), 'goProURL' => 'https://go.elementor.com/go-pro-icon-library/', ], 'fa4_to_fa5_mapping_url' => ELEMENTOR_ASSETS_URL . 'lib/font-awesome/migration/mapping.js', 'settings' => $settings, 'wp_editor' => static::get_wp_editor_config(), 'settings_page_link' => Settings::get_url(), 'tools_page_link' => Tools::get_url(), 'tools_page_nonce' => wp_create_nonce( 'tools-page-from-editor' ), 'elementor_site' => 'https://go.elementor.com/about-elementor/', 'docs_elementor_site' => 'https://go.elementor.com/docs/', 'help_the_content_url' => 'https://go.elementor.com/the-content-missing/', 'help_flexbox_bc_url' => 'https://go.elementor.com/flexbox-layout-bc/', 'elementPromotionURL' => 'https://go.elementor.com/go-pro-%s', 'dynamicPromotionURL' => 'https://go.elementor.com/go-pro-dynamic-tag', 'additional_shapes' => Shapes::get_additional_shapes_for_config(), 'user' => [ 'restrictions' => Plugin::$instance->role_manager->get_user_restrictions_array(), 'is_administrator' => current_user_can( 'manage_options' ), 'introduction' => User::get_introduction_meta(), 'dismissed_editor_notices' => User::get_dismissed_editor_notices(), 'locale' => get_user_locale(), ], 'preview' => [ 'help_preview_error_url' => 'https://go.elementor.com/preview-not-loaded/', 'help_preview_http_error_url' => 'https://go.elementor.com/preview-not-loaded/#permissions', 'help_preview_http_error_500_url' => 'https://go.elementor.com/500-error/', 'debug_data' => Loading_Inspection_Manager::instance()->run_inspections(), ], 'locale' => get_locale(), 'rich_editing_enabled' => filter_var( get_user_meta( get_current_user_id(), 'rich_editing', true ), FILTER_VALIDATE_BOOLEAN ), 'page_title_selector' => $page_title_selector, 'tinymceHasCustomConfig' => class_exists( 'Tinymce_Advanced' ) || class_exists( 'Advanced_Editor_Tools' ), 'inlineEditing' => Plugin::$instance->widgets_manager->get_inline_editing_config(), 'dynamicTags' => Plugin::$instance->dynamic_tags->get_config(), 'ui' => [ 'defaultGenericFonts' => $kits_manager->get_current_settings( 'default_generic_fonts' ), ], // Empty array for BC to avoid errors. 'i18n' => [], // 'responsive' contains the custom breakpoints config introduced in Elementor v3.2.0 'responsive' => [ 'breakpoints' => Plugin::$instance->breakpoints->get_breakpoints_config(), 'icons_map' => Plugin::$instance->breakpoints->get_responsive_icons_classes_map(), ], 'promotion' => [ 'elements' => Plugin::$instance->editor->promotion->get_elements_promotion(), ], 'editor_events' => EditorEventsModule::get_editor_events_config(), 'promotions' => [ 'notes' => Filtered_Promotions_Manager::get_filtered_promotion_data( [ 'upgrade_url' => 'https://go.elementor.com/go-pro-notes/' ], 'elementor/panel/notes/custom_promotion', 'upgrade_url' ), ], 'fontVariableRanges' => Group_Control_Typography::get_font_variable_ranges(), ]; if ( ! Utils::has_pro() && current_user_can( 'manage_options' ) ) { $client_env['promotionWidgets'] = Api::get_promotion_widgets(); } if ( Plugin::$instance->experiments->is_feature_active( 'container' ) ) { $client_env['elementsPresets'] = Plugin::$instance->editor->get_elements_presets(); } static::bc_move_document_filters(); /** * Localize editor settings. * * Filters the editor localized settings. * * @since 1.0.0 * * @param array $client_env Editor configuration. * @param int $post_id The ID of the current post being edited. */ return apply_filters( 'elementor/editor/localize_settings', $client_env ); } private static function bc_move_document_filters() { global $wp_filter; $old_tag = 'elementor/editor/localize_settings'; $new_tag = 'elementor/document/config'; if ( ! has_filter( $old_tag ) ) { return; } foreach ( $wp_filter[ $old_tag ] as $priority => $filters ) { foreach ( $filters as $filter_id => $filter_args ) { if ( 2 === $filter_args['accepted_args'] ) { remove_filter( $old_tag, $filter_id, $priority ); add_filter( $new_tag, $filter_args['function'], $priority, 2 ); } } } } /** * Get WordPress editor config. * * Config the default WordPress editor with custom settings for Elementor use. * * @since 1.9.0 * @access private */ private static function get_wp_editor_config() { // Remove all TinyMCE plugins. remove_all_filters( 'mce_buttons', 10 ); remove_all_filters( 'mce_external_plugins', 10 ); if ( ! class_exists( '\_WP_Editors', false ) ) { require ABSPATH . WPINC . '/class-wp-editor.php'; } // WordPress 4.8 and higher if ( method_exists( '\_WP_Editors', 'print_tinymce_scripts' ) ) { \_WP_Editors::print_default_editor_scripts(); \_WP_Editors::print_tinymce_scripts(); } ob_start(); wp_editor( '%%EDITORCONTENT%%', 'elementorwpeditor', [ 'editor_class' => 'elementor-wp-editor', 'editor_height' => 250, 'drag_drop_upload' => true, ] ); $config = ob_get_clean(); // Don't call \_WP_Editors methods again remove_action( 'admin_print_footer_scripts', [ '_WP_Editors', 'editor_js' ], 50 ); remove_action( 'admin_print_footer_scripts', [ '_WP_Editors', 'print_default_editor_scripts' ], 45 ); \_WP_Editors::editor_js(); return $config; } } class-wpml-tm-editors.php 0000644 00000000166 14721573277 0011446 0 ustar 00 <?php class WPML_TM_Editors { const ATE = 'ate'; const WPML = 'wpml'; const WP = 'wp'; const NONE = 'none'; } ATERetry.php 0000644 00000001532 14721573277 0006734 0 ustar 00 <?php namespace WPML\TM\Editor; use WPML\LIB\WP\Option; class ATERetry { /** * @param int $jobId * * @return bool */ public static function hasFailed( $jobId ) { return self::getCount( $jobId ) >= 0; } /** * @param int $jobId * * @return int */ public static function getCount( $jobId ) { return (int) Option::getOr( self::getOptionName( $jobId ), - 1 ); } /** * @param int $jobId */ public static function incrementCount( $jobId ) { Option::update( self::getOptionName( $jobId ), self::getCount( $jobId ) + 1 ); } /** * @param int $jobId */ public static function reset( $jobId ) { Option::delete( self::getOptionName( $jobId ) ); } /** * @param int $jobId * * @return string */ public static function getOptionName( $jobId ) { return sprintf( 'wpml-ate-job-retry-counter-%d', $jobId ); } } class-wpml-tm-old-jobs-editor.php 0000644 00000003613 14721573277 0012772 0 ustar 00 <?php class WPML_TM_Old_Jobs_Editor { const OPTION_NAME = 'wpml-old-jobs-editor'; /** @var wpdb */ private $wpdb; /** @var WPML_Translation_Job_Factory */ private $job_factory; public function __construct( WPML_Translation_Job_Factory $job_factory ) { global $wpdb; $this->wpdb = $wpdb; $this->job_factory = $job_factory; } /** * @param int $job_id * * @return null|string */ public function get( $job_id ) { $current_editor = $this->get_current_editor( $job_id ); if ( WPML_TM_Editors::NONE === $current_editor || WPML_TM_Editors::ATE === $current_editor ) { return $current_editor; } else { return get_option( self::OPTION_NAME, null ); } } /** * @param int $job_id * * @return bool */ public function shouldStickToWPMLEditor( $job_id ) { $sql = " SELECT job.editor FROM {$this->wpdb->prefix}icl_translate_job job WHERE job.job_id < %d AND job.rid = ( SELECT rid FROM {$this->wpdb->prefix}icl_translate_job WHERE job_id = %s ) ORDER BY job.job_id DESC "; $previousJobEditor = $this->wpdb->get_var( $this->wpdb->prepare( $sql, $job_id, $job_id ) ); return $previousJobEditor === WPML_TM_Editors::WPML && get_option( self::OPTION_NAME, null ) === WPML_TM_Editors::WPML; } /** * @return string */ public function editorForTranslationsPreviouslyCreatedUsingCTE( ) { return get_option( self::OPTION_NAME, WPML_TM_Editors::WPML ); } public function set( $job_id, $editor ) { $data = [ 'editor' => $editor ]; if ( $editor !== WPML_TM_Editors::ATE ) { $data['editor_job_id'] = null; } $this->job_factory->update_job_data( $job_id, $data ); } /** * @param int $job_id * * @return null|string */ public function get_current_editor( $job_id ) { $sql = "SELECT editor FROM {$this->wpdb->prefix}icl_translate_job WHERE job_id = %d"; return $this->wpdb->get_var( $this->wpdb->prepare( $sql, $job_id ) ); } } ManualJobCreationErrorNotice.php 0000644 00000007163 14721573277 0013014 0 ustar 00 <?php namespace WPML\TM\Editor; use WPML\FP\Cast; use WPML\FP\Fns; use WPML\FP\Logic; use WPML\FP\Obj; use WPML\FP\Relation; use WPML\LIB\WP\Hooks; use WPML\TM\API\Jobs; use WPML\UIPage; use function WPML\Container\make; use function WPML\FP\pipe; class ManualJobCreationErrorNotice implements \IWPML_Backend_Action { const RETRY_LIMIT = 3; public function add_hooks() { if ( \WPML_TM_ATE_Status::is_enabled() ) { Hooks::onAction( 'wp_loaded' ) ->then( function () { /** @var \WPML_Notices $notices */ $notices = make( \WPML_Notices::class ); if ( isset( $_GET['ateJobCreationError'] ) ) { $notice = $notices->create_notice( __CLASS__, $this->getContent( $_GET ) ); $notice->set_css_class_types( 'error' ); $notice->set_dismissible( false ); $notices->add_notice( $notice ); } else { $notices->remove_notice( 'default', __CLASS__ ); } } ); } } /** * @param array $params * * @return string */ private function getContent( array $params ) { $isATENotActiveError = pipe( Obj::prop( 'ateJobCreationError' ), Cast::toInt(), Relation::equals( Editor::ATE_IS_NOT_ACTIVE ) ); $isRetryLimitExceeded = pipe( Obj::prop( 'jobId' ), [ ATERetry::class, 'getCount' ], Relation::gt( self::RETRY_LIMIT ) ); return Logic::cond( [ [ $isATENotActiveError, [ self::class, 'ateNotActiveMessage' ] ], [ $isRetryLimitExceeded, [ self::class, 'retryMessage' ] ], [ Fns::always( true ), [ self::class, 'retryFailedMessage' ] ] ], $params ); } public static function retryMessage( array $params ) { $returnUrl = \remove_query_arg( [ 'ateJobCreationError', 'jobId' ], Jobs::getCurrentUrl() ); $jobId = Obj::prop( 'jobId', $params ); if ( ! is_numeric( $jobId ) ) { return sprintf( '<div class="wpml-display-flex wpml-display-flex-center">%1$s</div>', __( "WPML didn't manage to translate this page.", 'wpml-translation-management' ) ); } $jobEditUrl = Jobs::getEditUrl( $returnUrl, (int) $jobId ); $fallbackErrorMessage = sprintf( '<div class="wpml-display-flex wpml-display-flex-center">%1$s <a class="button wpml-margin-left-sm" href="%2$s">%3$s</a></div>', __( "WPML didn't manage to translate this page.", 'wpml-translation-management' ), $jobEditUrl, __( 'Try again', 'wpml-translation-management' ) ); $tryAgainTextLink = sprintf( '<a href="%1$s">%2$s</a>', $jobEditUrl, __( 'Try again', 'wpml-translation-management' ) ); $ateApiErrorMessage = ATEDetailedErrorMessage::readDetailedError( $tryAgainTextLink ); return $ateApiErrorMessage ?: $fallbackErrorMessage; } public static function retryFailedMessage() { $fallbackErrorMessage = '<div>' . sprintf( __( 'WPML tried to translate this page three times and failed. To get it fixed, contact %s', 'wpml-translation-management' ), '<a target=\'_blank\' href="https://wpml.org/forums/forum/english-support/">' . __( 'WPML support', 'wpml-translation-management' ) . '</a>' ) . '</div>'; $ateApiErrorMessage = ATEDetailedErrorMessage::readDetailedError(); return $ateApiErrorMessage ?: $fallbackErrorMessage; } public static function ateNotActiveMessage() { return '<div>' . sprintf( __( 'WPML’s Advanced Translation Editor is enabled but not activated. Go to %s to resolve the issue.', 'wpml-translation-management' ), '<a href="' . UIPage::getTMDashboard() . '">' . __( 'WPML Translation Management Dashboard', 'wpml-translation-management' ) . '</a>' ) . '</div>'; } } Editor.php 0000644 00000030330 14721573277 0006521 0 ustar 00 <?php namespace WPML\TM\Editor; use WPML\FP\Either; use WPML\FP\Fns; use WPML\FP\Left; use WPML\FP\Logic; use WPML\FP\Obj; use WPML\FP\Relation; use WPML\FP\Right; use WPML\LIB\WP\User; use WPML\Setup\Option as SetupOption; use WPML\TM\API\Jobs; use WPML\TM\ATE\Log\Entry; use WPML\TM\ATE\Log\Storage; use WPML\TM\ATE\Review\ReviewStatus; use WPML\TM\ATE\Sync\Trigger; use WPML\TM\Jobs\Manual; use WPML\TM\Menu\TranslationQueue\CloneJobs; use function WPML\Container\make; use function WPML\FP\curryN; use function WPML\FP\invoke; use function WPML\FP\pipe; class Editor { const ATE_JOB_COULD_NOT_BE_CREATED = 101; const ATE_EDITOR_URL_COULD_NOT_BE_FETCHED = 102; const ATE_IS_NOT_ACTIVE = 103; /** @var CloneJobs */ private $clone_jobs; /** @var Manual */ private $manualJobs; /** * Editor constructor. * * @param CloneJobs $clone_jobs * @param Manual $manualJobs */ public function __construct( CloneJobs $clone_jobs, Manual $manualJobs ) { $this->clone_jobs = $clone_jobs; $this->manualJobs = $manualJobs; } /** * @param array $params * * @return array */ public function open( $params ) { $shouldOpenCTE = function ( $jobObject ) use ( $params ) { if ( ! \WPML_TM_ATE_Status::is_enabled() ) { return true; } if ( $this->isNewJobCreated( $params, $jobObject ) ) { return wpml_tm_load_old_jobs_editor()->shouldStickToWPMLEditor( $jobObject->get_id() ); } return wpml_tm_load_old_jobs_editor()->editorForTranslationsPreviouslyCreatedUsingCTE() === \WPML_TM_Editors::WPML && wpml_tm_load_old_jobs_editor()->get_current_editor( $jobObject->get_id() ) === \WPML_TM_Editors::WPML; }; /** * It maybe needed when a job was translated via the Translation Proxy before and now, we want to open it in the editor. * * @param \WPML_Element_Translation_Job $jobObject * * @return \WPML_Element_Translation_Job */ $maybeUpdateTranslationServiceColumn = function ( $jobObject ) { if ( $jobObject->get_translation_service() !== 'local' ) { $jobObject->set_basic_data_property( 'translation_service', 'local' ); Jobs::setTranslationService( $jobObject->get_id(), 'local' ); } return $jobObject; }; $dataOfTranslationCreatedInNativeEditorViaConnection = $this->manualJobs->maybeGetDataIfTranslationCreatedInNativeEditorViaConnection( $params ); if ( $dataOfTranslationCreatedInNativeEditorViaConnection ) { update_post_meta( $dataOfTranslationCreatedInNativeEditorViaConnection['originalPostId'], \WPML_TM_Post_Edit_TM_Editor_Mode::POST_META_KEY_USE_NATIVE, 'yes' ); return $this->displayWPNative( $dataOfTranslationCreatedInNativeEditorViaConnection ); } return Either::of( $params ) ->map( [ $this->manualJobs, 'createOrReuse' ] ) ->filter( Logic::isTruthy() ) ->filter( invoke( 'user_can_translate' )->with( User::getCurrent() ) ) ->map( $maybeUpdateTranslationServiceColumn ) ->map( Logic::ifElse( $shouldOpenCTE, $this->displayCTE(), $this->tryToDisplayATE( $params ) ) ) ->getOrElse( [ 'editor' => \WPML_TM_Editors::NONE, 'jobObject' => null ] ); } /** * @param array $params * @param \WPML_Element_Translation_Job $jobObject * * @return array */ private function tryToDisplayATE( $params = null, $jobObject = null ) { $fn = curryN( 2, function ( $params, $jobObject ) { $handleNotActiveATE = Logic::ifElse( [ \WPML_TM_ATE_Status::class, 'is_active' ], Either::of(), pipe( $this->handleATEJobCreationError( $params, self::ATE_IS_NOT_ACTIVE ), Either::left() ) ); /** * Create a new ATE job when somebody clicks the "pencil" icon to edit existing translation. * * @param \WPML_Element_Translation_Job $jobObject * * @return Either<\WPML_Element_Translation_Job> */ $cloneCompletedATEJob = function ( $jobObject ) use ( $params ) { if ( $this->isValidATEJob( $jobObject ) && (int) $jobObject->get_status_value() === ICL_TM_COMPLETE ) { $sentFrom = isset( $params['preview'] ) ? Jobs::SENT_FROM_REVIEW : Jobs::SENT_MANUALLY; return $this->clone_jobs->cloneCompletedATEJob( $jobObject, $sentFrom ) ->bimap( $this->handleATEJobCreationError( $params, self::ATE_JOB_COULD_NOT_BE_CREATED ), Fns::identity() ); } return Either::of( $jobObject ); }; $handleMissingATEJob = function ( $jobObject ) use ( $params ) { // ATE editor is already set. All fine, we can proceed. if ( $this->isValidATEJob( $jobObject ) ) { return Either::of( $jobObject ); } /** * The new job has been created because either there was no translation at all or translation was "needs update". * The ATE job could not be created inside WPML_TM_ATE_Jobs_Actions::added_translation_jobs ,and we have to return the error message. */ if ( $this->isNewJobCreated( $params, $jobObject ) ) { return Either::left( $this->handleATEJobCreationError( $params, self::ATE_JOB_COULD_NOT_BE_CREATED, $jobObject ) ); } /** * It creates a corresponding job in ATE for already existing WPML job in such situations: * 1. Previously job was created in CTE, but a user selected the setting to translate existing CTE jobs in ATE * 2. The job used to be handled by the Translation Proxy or the native WP editor * 3. ATE job could not be created before and user clicked "Retry" button * 4. Job was sent via basket and ATE job could not be created */ return $this->createATECounterpartForExistingWPMLJob( $params, $jobObject ); }; return Either::of( $jobObject ) ->chain( $handleNotActiveATE ) ->chain( $cloneCompletedATEJob ) ->chain( $handleMissingATEJob ) ->map( Fns::tap( pipe( invoke( 'get_id' ), Jobs::setStatus( Fns::__, ICL_TM_IN_PROGRESS ) ) ) ) ->map( $this->openATE( $params ) ) ->coalesce( Fns::identity(), Fns::identity() ) ->get(); } ); return call_user_func_array( $fn, func_get_args() ); } /** * @param \WPML_Element_Translation_Job $jobObject * * @return array */ private function displayCTE( $jobObject = null ) { $fn = curryN( 1, function ( $jobObject ) { wpml_tm_load_old_jobs_editor()->set( $jobObject->get_id(), \WPML_TM_Editors::WPML ); return [ 'editor' => \WPML_TM_Editors::WPML, 'jobObject' => $jobObject ]; } ); return call_user_func_array( $fn, func_get_args() ); } /** * @param array $dataOfTranslationCreatedInNativeEditorViaConnection * * @return array */ private function displayWPNative( array $dataOfTranslationCreatedInNativeEditorViaConnection ) { $url = 'post.php?' . http_build_query( [ 'lang' => $dataOfTranslationCreatedInNativeEditorViaConnection['targetLanguageCode'], 'action' => 'edit', 'post_type' => str_replace( 'post_', '', $dataOfTranslationCreatedInNativeEditorViaConnection['postType'] ), 'post' => $dataOfTranslationCreatedInNativeEditorViaConnection['translatedPostId'] ] ); return [ 'editor' => \WPML_TM_Editors::WP, 'jobObject' => null, 'url' => $url ]; } /** * @param \WPML_Element_Translation_Job $jobObject * * @return void */ private function maybeSetReviewStatus( $jobObject ) { if ( Relation::propEq( 'review_status', ReviewStatus::NEEDS_REVIEW, $jobObject->to_array() ) ) { Jobs::setReviewStatus( $jobObject->get_id(), SetupOption::shouldBeReviewed() ? ReviewStatus::EDITING : null ); } } /** * It returns an url to place where a user should be redirected. The url contains a job id and error's code. * * @param array $params * @param int $code * @param \WPML_Element_Translation_Job $jobObject * * @return array */ private function handleATEJobCreationError( $params = null, $code = null, $jobObject = null ) { $fn = curryN( 3, function ( $params, $code, $jobObject ) { ATERetry::incrementCount( $jobObject->get_id() ); $retryCount = ATERetry::getCount( $jobObject->get_id() ); if ( $retryCount > 0 ) { Storage::add( Entry::retryJob( $jobObject->get_id(), [ 'retry_count' => ATERetry::getCount( $jobObject->get_id() ) ] ) ); } return [ 'editor' => \WPML_TM_Editors::ATE, 'url' => add_query_arg( [ 'ateJobCreationError' => $code, 'jobId' => $jobObject->get_id() ], $this->getReturnUrl( $params ) ) ]; } ); return call_user_func_array( $fn, func_get_args() ); } /** * It asserts a job's editor. * * @param string $editor * @param \WPML_Element_Translation_Job $jobObject * * @return bool */ private function isJobEditorEqualTo( $editor, $jobObject ) { return $jobObject->get_basic_data_property( 'editor' ) === $editor; } /** * It checks if we created a new entry in wp_icl_translate_job table. * It happens when none translation for a specific language has existed so far or when a translation has been "needs update". * * @param array $params * @param \WPML_Element_Translation_Job $jobObject * * @return bool */ private function isNewJobCreated( $params , $jobObject ) { return (int) $jobObject->get_id() !== (int) Obj::prop( 'job_id', $params ); } /** * @param array $params * @param \WPML_Element_Translation_Job $jobObject * * @return callable|Left<array>|Right<\WPML_Element_Translation_Job> */ private function createATECounterpartForExistingWPMLJob( $params, $jobObject ) { if ( $this->clone_jobs->cloneWPMLJob( $jobObject->get_id() ) ) { ATERetry::reset( $jobObject->get_id() ); $jobObject->set_basic_data_property( 'editor', \WPML_TM_Editors::ATE ); return Either::of( $jobObject ); } return Either::left( $this->handleATEJobCreationError( $params, self::ATE_JOB_COULD_NOT_BE_CREATED, $jobObject ) ); } /** * At this stage, we know that a corresponding job in ATE is created and we should open ATE editor. * We are trying to do that. * * @param array $params * @param \WPML_Element_Translation_Job $jobObject * * @return false|mixed */ private function openATE( $params = null, $jobObject = null ) { $fn = curryN( 2, function ( $params, $jobObject ) { $this->maybeSetReviewStatus( $jobObject ); $editor_url = apply_filters( 'wpml_tm_ate_jobs_editor_url', '', $jobObject->get_id(), $this->getReturnUrl( $params ) ); if ( $editor_url ) { $response['editor'] = \WPML_TM_Editors::ATE; $response['url'] = $editor_url; $response['jobObject'] = $jobObject; return $response; } return $this->handleATEJobCreationError( $params, self::ATE_EDITOR_URL_COULD_NOT_BE_FETCHED, $jobObject ); } ); return call_user_func_array( $fn, func_get_args() ); } /** * @return string */ private function getReturnUrl( $params ) { $return_url = ''; if ( array_key_exists( 'return_url', $params ) ) { $return_url = filter_var( $params['return_url'], FILTER_SANITIZE_URL ); $return_url_parts = wp_parse_url( (string) $return_url ); $admin_url = get_admin_url(); $admin_url_parts = wp_parse_url( $admin_url ); if ( strpos( $return_url_parts['path'], $admin_url_parts['path'] ) === 0 ) { $admin_url_parts['path'] = $return_url_parts['path']; } else { $admin_url_parts = $return_url_parts; } $admin_url_parts['query'] = $this->prepareQueryParameters( Obj::propOr( '', 'query', $return_url_parts ), Obj::prop( 'lang', $params ) ); $return_url = http_build_url( $admin_url_parts ); } return $return_url; } private function prepareQueryParameters( $query, $returnLanguage ) { $parameters = []; parse_str( $query, $parameters ); unset( $parameters['ate_original_id'] ); unset( $parameters['back'] ); unset( $parameters['complete'] ); if ( $returnLanguage ) { // We need the lang parameter to display the post list in the language which was used before ATE. $parameters['lang'] = $returnLanguage; } return http_build_query( $parameters ); } /** * @param \WPML_Element_Translation_Job $jobObject * * @return bool */ private function isValidATEJob( \WPML_Element_Translation_Job $jobObject ) { return $this->isJobEditorEqualTo( \WPML_TM_Editors::ATE, $jobObject ) && (int) $jobObject->get_basic_data_property( 'editor_job_id' ) > 0; } } ATEDetailedErrorMessage.php 0000644 00000006676 14721573277 0011677 0 ustar 00 <?php namespace WPML\TM\Editor; use WPML\FP\Str; use WPML\FP\Cast; use WPML\FP\Obj; use WPML\FP\Relation; use WPML\LIB\WP\Option; use WPML\TM\ATE\ClonedSites\ApiCommunication; use WPML\UIPage; use function WPML\FP\pipe; class ATEDetailedErrorMessage { const ERROR_DETAILS_OPTION = 'wpml_ate_error_details'; /** * Parses error data and saves it to options table. * * @param $errorResponse * * @return void */ public static function saveDetailedError( $errorResponse ) { $errorCode = $errorResponse->get_error_code(); $errorMessage = $errorResponse->get_error_message(); $errorData = $errorResponse->get_error_data( $errorCode ); $errorDetails = [ 'code' => $errorCode, 'message' => $errorMessage, 'error_data' => $errorData, ]; self::saveErrorDetailsInOptions( $errorDetails ); } /** * Returns single or multiple formatted error message depending on errors array existence in response. * * @param string $appendText * * @return string|null */ public static function readDetailedError( $appendText = null ) { $errorDetails = Option::getOr( self::ERROR_DETAILS_OPTION, [] ); $detailedError = self::hasValidExplainedMessage( $errorDetails ) ? self::formattedDetailedErrors( $errorDetails, $appendText ) : ( self::isSiteMigrationError( $errorDetails ) ? self::formattedSiteMigrationError( $errorDetails ) : null ); self::deleteErrorDetailsFromOptions(); // deleting the option after message is ready to be displayed. return $detailedError; } /** * Checks if valid explained message exists in error response. * * @param array $errorDetails * * @return mixed */ private static function hasValidExplainedMessage( $errorDetails ) { $hasExplainedMessage = pipe( Obj::path( [ 'error_data', 0, 'explained_message' ] ), Str::len(), Cast::toBool() ); return $hasExplainedMessage( $errorDetails ); } /** * Checks if error is "Site moved or copied" (Happens when error code is 426) * * @param array $errorDetails * * @return mixed */ private static function isSiteMigrationError( $errorDetails ) { $isSiteMigrationError = pipe( Obj::prop( 'code' ), Cast::toInt(), Relation::equals( ApiCommunication::SITE_CLONED_ERROR ) ); return $isSiteMigrationError( $errorDetails ); } /** * The purpose of this function is to avoid the case when redirect is happened and data saved in this static class is lost * * @return void */ private static function saveErrorDetailsInOptions( $errorDetails ) { Option::updateWithoutAutoLoad( self::ERROR_DETAILS_OPTION, $errorDetails ); } /** * Deletes the error details from options. * * @return void */ private static function deleteErrorDetailsFromOptions() { Option::delete( self::ERROR_DETAILS_OPTION ); } /** * Returns multiple formatted error messages from errors array. * * @param array $errorDetails * @param string $appendText * * @return string */ private static function formattedDetailedErrors( array $errorDetails, $appendText ) { $appendText = $appendText ? '<div>' . $appendText . '</div>' : ''; $allErrors = '<div>'; foreach ( Obj::prop( 'error_data', $errorDetails ) as $error ) { $allErrors .= '<div>' . Obj::propOr( '', 'explained_message', $error ) . '</div>'; } return $allErrors . $appendText . '</div>'; } private static function formattedSiteMigrationError( $errorDetails ) { return '<div>' . Obj::prop( 'message', $errorDetails ) . '</div>'; } } ClassicEditorActions.php 0000644 00000002100 14721573277 0011336 0 ustar 00 <?php namespace WPML\TM\Editor; class ClassicEditorActions { public function addHooks() { add_action( 'wp_ajax_wpml_save_job_ajax', [ $this, 'saveJob' ] ); } public function saveJob() { if ( ! wpml_is_action_authenticated( 'wpml_save_job' ) ) { wp_send_json_error( 'Permission denied.' ); return; } $data = []; $post_data = \WPML_TM_Post_Data::strip_slashes_for_single_quote( $_POST['data'] ); parse_str( $post_data, $data ); /** * It filters job data * * @param array $data */ $data = apply_filters( 'wpml_translation_editor_save_job_data', $data ); $job = \WPML\Container\make( \WPML_TM_Editor_Job_Save::class ); $job_details = [ 'job_type' => $data['job_post_type'], 'job_id' => $data['job_post_id'], 'target' => $data['target_lang'], 'translation_complete' => isset( $data['complete'] ) ? true : false, ]; $job = apply_filters( 'wpml-translation-editor-fetch-job', $job, $job_details ); $ajax_response = $job->save( $data ); $ajax_response->send_json(); } }
| ver. 1.4 |
Github
|
.
| PHP 7.4.3-4ubuntu2.24 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка