| @@ -3,11 +3,10 @@ | ||
| 3 | 3 | |
| 4 | 4 | use Elementor\Core\Breakpoints\Manager as Breakpoints_Manager; |
| 5 | 5 | use Elementor\Core\Common\Modules\Ajax\Module; |
| 6 | 6 | use Elementor\Core\Debug\Loading_Inspection_Manager; |
| 7 | -use Elementor\Core\Editor\Loader\Editor_Loader; | |
| 8 | -use Elementor\Core\Utils\Assets_Config_Provider; | |
| 9 | -use Elementor\Core\Utils\Collection; | |
| 7 | +use Elementor\Core\Editor\Config_Providers\Config_Provider_Factory; | |
| 8 | +use Elementor\Core\Experiments\Manager as Experiments_Manager; | |
| 10 | 9 | use Elementor\Core\Settings\Manager as SettingsManager; |
| 11 | 10 | use Elementor\Plugin; |
| 12 | 11 | use Elementor\TemplateLibrary\Source_Local; |
| 13 | 12 | use Elementor\Utils; |
| @@ -31,8 +30,10 @@ | ||
| 31 | 30 | * User capability required to access Elementor editor. |
| 32 | 31 | */ |
| 33 | 32 | const EDITING_CAPABILITY = 'edit_posts'; |
| 34 | 33 | |
| 34 | + const EDITOR_V2_EXPERIMENT_NAME = 'editor_v2'; | |
| 35 | + | |
| 35 | 36 | /** |
| 36 | 37 | * Post ID. |
| 37 | 38 | * |
| 38 | 39 | * Holds the ID of the current post being edited. |
| @@ -81,11 +82,11 @@ | ||
| 81 | 82 | * |
| 82 | 83 | * @since 1.0.0 |
| 83 | 84 | * @access public |
| 84 | 85 | * |
| 85 | - * @param bool $to_die Optional. Whether to die at the end. Default is `true`. | |
| 86 | + * @param bool $die Optional. Whether to die at the end. Default is `true`. | |
| 86 | 87 | */ |
| 87 | - public function init( $to_die = true ) { | |
| 88 | + public function init( $die = true ) { | |
| 88 | 89 | if ( empty( $_REQUEST['post'] ) ) { |
| 89 | 90 | return; |
| 90 | 91 | } |
| 91 | 92 | |
| @@ -117,10 +118,8 @@ | ||
| 117 | 118 | |
| 118 | 119 | // Send MIME Type header like WP admin-header. |
| 119 | 120 | @header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) ); |
| 120 | 121 | |
| 121 | - self::send_document_isolation_policy_header(); | |
| 122 | - | |
| 123 | 122 | add_filter( 'show_admin_bar', '__return_false' ); |
| 124 | 123 | |
| 125 | 124 | // Remove all WordPress actions |
| 126 | 125 | remove_all_actions( 'wp_head' ); |
| @@ -162,9 +161,9 @@ | ||
| 162 | 161 | |
| 163 | 162 | $this->get_loader()->print_root_template(); |
| 164 | 163 | |
| 165 | 164 | // From the action it's an empty string, from tests its `false` |
| 166 | - if ( false !== $to_die ) { | |
| 165 | + if ( false !== $die ) { | |
| 167 | 166 | die; |
| 168 | 167 | } |
| 169 | 168 | } |
| 170 | 169 | |
| @@ -212,67 +211,8 @@ | ||
| 212 | 211 | die; |
| 213 | 212 | } |
| 214 | 213 | |
| 215 | 214 | /** |
| 216 | - * Whether the current request targets the Elementor editor. | |
| 217 | - * | |
| 218 | - * Unlike `is_edit_mode()`, this is not affected by temporary `set_edit_mode()` overrides. | |
| 219 | - * | |
| 220 | - * @since 4.1.0 | |
| 221 | - * @access public | |
| 222 | - * | |
| 223 | - * @return bool Whether the current request targets the Elementor editor. | |
| 224 | - */ | |
| 225 | - public function is_editor_request() { | |
| 226 | - $common = Plugin::$instance->common; | |
| 227 | - | |
| 228 | - if ( $common ) { | |
| 229 | - /** @var Module ajax */ | |
| 230 | - $ajax_data = $common->get_component( 'ajax' )->get_current_action_data(); | |
| 231 | - | |
| 232 | - if ( ! empty( $ajax_data ) && 'get_document_config' === $ajax_data['action'] ) { | |
| 233 | - return true; | |
| 234 | - } | |
| 235 | - } | |
| 236 | - | |
| 237 | - if ( $this->is_editor_admin_screen() ) { | |
| 238 | - return true; | |
| 239 | - } | |
| 240 | - | |
| 241 | - return $this->is_editor_ajax_request(); | |
| 242 | - } | |
| 243 | - | |
| 244 | - private function is_editor_admin_screen(): bool { | |
| 245 | - if ( ! function_exists( 'get_current_screen' ) ) { | |
| 246 | - return false; | |
| 247 | - } | |
| 248 | - | |
| 249 | - $screen = get_current_screen(); | |
| 250 | - | |
| 251 | - if ( ! $screen ) { | |
| 252 | - return false; | |
| 253 | - } | |
| 254 | - | |
| 255 | - return isset( $_GET['action'] ) && 'elementor' === $_GET['action'] && in_array( $screen->base, [ 'post', 'toplevel_page_elementor' ], true ); | |
| 256 | - } | |
| 257 | - | |
| 258 | - private function is_editor_ajax_request(): bool { | |
| 259 | - $actions = apply_filters( 'elementor/editor/ajax_actions', [ | |
| 260 | - 'elementor', | |
| 261 | - | |
| 262 | - // Templates | |
| 263 | - 'elementor_get_templates', | |
| 264 | - 'elementor_save_template', | |
| 265 | - 'elementor_get_template', | |
| 266 | - 'elementor_delete_template', | |
| 267 | - 'elementor_import_template', | |
| 268 | - 'elementor_library_direct_actions', | |
| 269 | - ] ); | |
| 270 | - | |
| 271 | - return isset( $_REQUEST['action'] ) && in_array( $_REQUEST['action'], $actions, true ); | |
| 272 | - } | |
| 273 | - | |
| 274 | - /** | |
| 275 | 215 | * Whether the edit mode is active. |
| 276 | 216 | * |
| 277 | 217 | * Used to determine whether we are in the edit mode. |
| 278 | 218 | * |
| @@ -413,9 +353,11 @@ | ||
| 413 | 353 | |
| 414 | 354 | // Tweak for WP Admin menu icons |
| 415 | 355 | wp_print_styles( 'editor-buttons' ); |
| 416 | 356 | |
| 357 | + $this->get_loader()->print_client_settings(); | |
| 417 | 358 | $this->get_loader()->enqueue_scripts(); |
| 359 | + $this->get_loader()->load_scripts_translations(); | |
| 418 | 360 | |
| 419 | 361 | Plugin::$instance->controls_manager->enqueue_control_scripts(); |
| 420 | 362 | |
| 421 | 363 | /** |
| @@ -548,8 +490,10 @@ | ||
| 548 | 490 | $plugin->controls_manager->render_controls(); |
| 549 | 491 | $plugin->widgets_manager->render_widgets_content(); |
| 550 | 492 | $plugin->elements_manager->render_elements_content(); |
| 551 | 493 | |
| 494 | + $plugin->schemes_manager->print_schemes_templates(); | |
| 495 | + | |
| 552 | 496 | $plugin->dynamic_tags->print_templates(); |
| 553 | 497 | |
| 554 | 498 | $this->get_loader()->register_additional_templates(); |
| 555 | 499 | |
| @@ -596,92 +540,16 @@ | ||
| 596 | 540 | |
| 597 | 541 | add_action( 'admin_action_elementor', [ $this, 'init' ] ); |
| 598 | 542 | add_action( 'template_redirect', [ $this, 'redirect_to_new_url' ] ); |
| 599 | 543 | |
| 544 | + $this->register_editor_v2_experiment(); | |
| 545 | + | |
| 600 | 546 | // Handle autocomplete feature for URL control. |
| 601 | 547 | add_filter( 'wp_link_query_args', [ $this, 'filter_wp_link_query_args' ] ); |
| 602 | 548 | add_filter( 'wp_link_query', [ $this, 'filter_wp_link_query' ] ); |
| 603 | - | |
| 604 | - add_filter( 'replace_editor', [ $this, 'filter_replace_editor' ], 10, 2 ); | |
| 605 | 549 | } |
| 606 | 550 | |
| 607 | 551 | /** |
| 608 | - * Whether the Document-Isolation-Policy header should be sent on the | |
| 609 | - * Elementor editor screen and the editor preview iframe. | |
| 610 | - * | |
| 611 | - * DIP places the document in its own agent cluster, which is the prerequisite | |
| 612 | - * for cross-origin isolation features such as SharedArrayBuffer (required by | |
| 613 | - * WordPress core's client-side media processing introduced in WP 7.1). | |
| 614 | - * | |
| 615 | - * Both the editor parent document and the preview iframe must send the same | |
| 616 | - * DIP header so they join the same agent cluster and synchronous DOM access | |
| 617 | - * between them (e.g. `iframe.contentWindow.elementorFrontend`) keeps working. | |
| 618 | - * | |
| 619 | - * The header is only honored by browsers on a secure context (HTTPS or | |
| 620 | - * localhost) so the helper short-circuits on insecure origins to avoid | |
| 621 | - * sending a header that the browser will ignore. | |
| 622 | - * | |
| 623 | - * @since 4.1.0 | |
| 624 | - * | |
| 625 | - * @return bool | |
| 626 | - */ | |
| 627 | - public static function should_use_document_isolation_policy() { | |
| 628 | - if ( ! is_ssl() ) { | |
| 629 | - $raw_host = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : ''; | |
| 630 | - $host = strtolower( (string) strtok( $raw_host, ':' ) ); | |
| 631 | - | |
| 632 | - if ( 'localhost' !== $host && ! str_ends_with( $host, '.localhost' ) ) { | |
| 633 | - return false; | |
| 634 | - } | |
| 635 | - } | |
| 636 | - | |
| 637 | - /** | |
| 638 | - * Filters whether Elementor sends the Document-Isolation-Policy header | |
| 639 | - * on the editor screen and preview iframe. | |
| 640 | - * | |
| 641 | - * @since 4.1.0 | |
| 642 | - * | |
| 643 | - * @param bool $enabled Whether DIP is enabled. Defaults to true on a secure context. | |
| 644 | - */ | |
| 645 | - return (bool) apply_filters( 'elementor/editor/use_document_isolation_policy', true ); | |
| 646 | - } | |
| 647 | - | |
| 648 | - /** | |
| 649 | - * Send the Document-Isolation-Policy header for the current response. | |
| 650 | - * | |
| 651 | - * Safe to call from both the Elementor editor screen handler and the | |
| 652 | - * preview iframe handler. No-op when {@see self::should_use_document_isolation_policy()} | |
| 653 | - * returns false. | |
| 654 | - * | |
| 655 | - * @since 4.1.0 | |
| 656 | - */ | |
| 657 | - public static function send_document_isolation_policy_header() { | |
| 658 | - if ( ! self::should_use_document_isolation_policy() || headers_sent() ) { | |
| 659 | - return; | |
| 660 | - } | |
| 661 | - | |
| 662 | - header( 'Document-Isolation-Policy: isolate-and-credentialless' ); | |
| 663 | - } | |
| 664 | - | |
| 665 | - /** | |
| 666 | - * Signals to WordPress that Elementor is replacing the block editor on its own editor page, | |
| 667 | - * so that block-editor-specific behaviour (e.g. WP 7.0 COOP/COEP isolation headers) is not | |
| 668 | - * applied when the Elementor editor is active. | |
| 669 | - * | |
| 670 | - * @param bool $replace Whether the editor is being replaced. | |
| 671 | - * @param \WP_Post $post The post being edited. | |
| 672 | - * | |
| 673 | - * @return bool | |
| 674 | - */ | |
| 675 | - public function filter_replace_editor( $replace, $post ) { | |
| 676 | - if ( isset( $_REQUEST['action'] ) && 'elementor' === $_REQUEST['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 677 | - return true; | |
| 678 | - } | |
| 679 | - | |
| 680 | - return $replace; | |
| 681 | - } | |
| 682 | - | |
| 683 | - /** | |
| 684 | 552 | * @since 2.2.0 |
| 685 | 553 | * @access public |
| 686 | 554 | */ |
| 687 | 555 | public function filter_wp_link_query_args( $query ) { |
| @@ -724,22 +592,10 @@ | ||
| 724 | 592 | * @return Editor_Loader |
| 725 | 593 | */ |
| 726 | 594 | private function get_loader() { |
| 727 | 595 | if ( ! $this->loader ) { |
| 728 | - $this->loader = new Editor_Loader( | |
| 729 | - new Collection( [ | |
| 730 | - 'assets_url' => ELEMENTOR_ASSETS_URL, | |
| 731 | - 'min_suffix' => ( Utils::is_script_debug() || Utils::is_elementor_tests() ) ? '' : '.min', | |
| 732 | - 'direction_suffix' => is_rtl() ? '-rtl' : '', | |
| 733 | - ] ), | |
| 734 | - ( new Assets_Config_Provider() )->set_path_resolver( | |
| 735 | - function ( $name ) { | |
| 736 | - return ELEMENTOR_ASSETS_PATH . "js/packages/{$name}/{$name}.asset.php"; | |
| 737 | - } | |
| 738 | - ) | |
| 739 | - ); | |
| 740 | - | |
| 741 | - $this->loader->init(); | |
| 596 | + $this->loader = new Editor_Loader( Config_Provider_Factory::create() ); | |
| 597 | + $this->loader->register_hooks(); | |
| 742 | 598 | } |
| 743 | 599 | |
| 744 | 600 | return $this->loader; |
| 745 | 601 | } |
| @@ -744,51 +600,25 @@ | ||
| 744 | 600 | return $this->loader; |
| 745 | 601 | } |
| 746 | 602 | |
| 747 | 603 | /** |
| 748 | - * Get elements presets. | |
| 604 | + * Adding Editor V2 experiment. | |
| 749 | 605 | * |
| 750 | - * @return array | |
| 751 | - */ | |
| 752 | - public function get_elements_presets() { | |
| 753 | - $element_types = Plugin::$instance->elements_manager->get_element_types(); | |
| 754 | - $presets = []; | |
| 755 | - | |
| 756 | - foreach ( $element_types as $el_type => $element ) { | |
| 757 | - $this->check_element_for_presets( $element, $el_type, $presets ); | |
| 758 | - } | |
| 759 | - | |
| 760 | - return $presets; | |
| 761 | - } | |
| 762 | - | |
| 763 | - /** | |
| 764 | 606 | * @return void |
| 607 | + * @throws \Exception | |
| 765 | 608 | */ |
| 766 | - private function check_element_for_presets( $element, $el_type, &$presets ) { | |
| 767 | - $element_presets = $element->get_panel_presets(); | |
| 768 | - | |
| 769 | - if ( empty( $element_presets ) ) { | |
| 770 | - return; | |
| 771 | - } | |
| 772 | - | |
| 773 | - foreach ( $element_presets as $key => $preset ) { | |
| 774 | - $this->maybe_add_preset( $el_type, $preset, $key, $presets ); | |
| 775 | - } | |
| 776 | - } | |
| 777 | - | |
| 778 | - /** | |
| 779 | - * @return void | |
| 780 | - */ | |
| 781 | - private function maybe_add_preset( $el_type, $preset, $key, &$presets ) { | |
| 782 | - if ( $this->is_valid_preset( $el_type, $preset ) ) { | |
| 783 | - $presets[ $key ] = $preset; | |
| 784 | - } | |
| 785 | - } | |
| 786 | - | |
| 787 | - /** | |
| 788 | - * @return boolean | |
| 789 | - */ | |
| 790 | - private function is_valid_preset( $el_type, $preset ) { | |
| 791 | - return isset( $preset['replacements']['custom']['originalWidget'] ) | |
| 792 | - && $el_type === $preset['replacements']['custom']['originalWidget']; | |
| 609 | + private function register_editor_v2_experiment() { | |
| 610 | + Plugin::$instance->experiments->add_feature( [ | |
| 611 | + 'name' => static::EDITOR_V2_EXPERIMENT_NAME, | |
| 612 | + 'title' => esc_html__( 'Editor Top Bar', 'elementor' ), | |
| 613 | + 'description' => sprintf( | |
| 614 | + esc_html__( | |
| 615 | + 'Get a sneak peek of the new Editor powered by React. The beautiful design and experimental layout of the Top bar are just some of the exciting tools on their way. %s', | |
| 616 | + 'elementor' | |
| 617 | + ), | |
| 618 | + '<a href="https://go.elementor.com/wp-dash-elementor-top-bar/" target="_blank">' . esc_html__( 'Learn more', 'elementor' ) . '</a>' | |
| 619 | + ), | |
| 620 | + 'default' => Experiments_Manager::STATE_INACTIVE, | |
| 621 | + 'status' => Experiments_Manager::RELEASE_STATUS_ALPHA, | |
| 622 | + ] ); | |
| 793 | 623 | } |
| 794 | 624 | } |