editor.php (24928B)
1 <?php 2 namespace Elementor\Core\Editor; 3 4 use Elementor\Api; 5 use Elementor\Core\Breakpoints\Breakpoint; 6 use Elementor\Core\Breakpoints\Manager as Breakpoints_Manager; 7 use Elementor\Core\Common\Modules\Ajax\Module; 8 use Elementor\Core\Common\Modules\Ajax\Module as Ajax; 9 use Elementor\Core\Debug\Loading_Inspection_Manager; 10 use Elementor\Core\Files\Assets\Files_Upload_Handler; 11 use Elementor\Core\Schemes\Manager as Schemes_Manager; 12 use Elementor\Core\Settings\Manager as SettingsManager; 13 use Elementor\Icons_Manager; 14 use Elementor\Plugin; 15 use Elementor\Settings; 16 use Elementor\Shapes; 17 use Elementor\TemplateLibrary\Source_Local; 18 use Elementor\Tools; 19 use Elementor\User; 20 use Elementor\Utils; 21 use Elementor\Core\Editor\Data; 22 23 if ( ! defined( 'ABSPATH' ) ) { 24 exit; // Exit if accessed directly. 25 } 26 27 /** 28 * Elementor editor. 29 * 30 * Elementor editor handler class is responsible for initializing Elementor 31 * editor and register all the actions needed to display the editor. 32 * 33 * @since 1.0.0 34 */ 35 class Editor { 36 37 /** 38 * The nonce key for Elementor editor. 39 * @deprecated 2.3.0 40 */ 41 const EDITING_NONCE_KEY = 'elementor-editing'; 42 43 /** 44 * User capability required to access Elementor editor. 45 */ 46 const EDITING_CAPABILITY = 'edit_posts'; 47 48 /** 49 * Post ID. 50 * 51 * Holds the ID of the current post being edited. 52 * 53 * @since 1.0.0 54 * @access private 55 * 56 * @var int Post ID. 57 */ 58 private $post_id; 59 60 /** 61 * Whether the edit mode is active. 62 * 63 * Used to determine whether we are in edit mode. 64 * 65 * @since 1.0.0 66 * @access private 67 * 68 * @var bool Whether the edit mode is active. 69 */ 70 private $is_edit_mode; 71 72 /** 73 * @var Notice_Bar 74 */ 75 public $notice_bar; 76 77 /** 78 * Init. 79 * 80 * Initialize Elementor editor. Registers all needed actions to run Elementor, 81 * removes conflicting actions etc. 82 * 83 * Fired by `admin_action_elementor` action. 84 * 85 * @since 1.0.0 86 * @access public 87 * 88 * @param bool $die Optional. Whether to die at the end. Default is `true`. 89 */ 90 public function init( $die = true ) { 91 if ( empty( $_REQUEST['post'] ) ) { 92 return; 93 } 94 95 $this->set_post_id( absint( $_REQUEST['post'] ) ); 96 97 if ( ! $this->is_edit_mode( $this->post_id ) ) { 98 return; 99 } 100 101 // BC: From 2.9.0, the editor shouldn't handle the global post / current document. 102 // Use requested id and not the global in order to avoid conflicts with plugins that changes the global post. 103 query_posts( [ 104 'p' => $this->post_id, 105 'post_type' => get_post_type( $this->post_id ), 106 ] ); 107 108 Plugin::$instance->db->switch_to_post( $this->post_id ); 109 110 $document = Plugin::$instance->documents->get( $this->post_id ); 111 112 Plugin::$instance->documents->switch_to_document( $document ); 113 114 // Change mode to Builder 115 $document->set_is_built_with_elementor( true ); 116 117 // End BC. 118 119 Loading_Inspection_Manager::instance()->register_inspections(); 120 121 // Send MIME Type header like WP admin-header. 122 @header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) ); 123 124 add_filter( 'show_admin_bar', '__return_false' ); 125 126 // Remove all WordPress actions 127 remove_all_actions( 'wp_head' ); 128 remove_all_actions( 'wp_print_styles' ); 129 remove_all_actions( 'wp_print_head_scripts' ); 130 remove_all_actions( 'wp_footer' ); 131 132 // Handle `wp_head` 133 add_action( 'wp_head', 'wp_enqueue_scripts', 1 ); 134 add_action( 'wp_head', 'wp_print_styles', 8 ); 135 add_action( 'wp_head', 'wp_print_head_scripts', 9 ); 136 add_action( 'wp_head', 'wp_site_icon' ); 137 add_action( 'wp_head', [ $this, 'editor_head_trigger' ], 30 ); 138 139 // Handle `wp_footer` 140 add_action( 'wp_footer', 'wp_print_footer_scripts', 20 ); 141 add_action( 'wp_footer', 'wp_auth_check_html', 30 ); 142 add_action( 'wp_footer', [ $this, 'wp_footer' ] ); 143 144 // Handle `wp_enqueue_scripts` 145 remove_all_actions( 'wp_enqueue_scripts' ); 146 147 // Also remove all scripts hooked into after_wp_tiny_mce. 148 remove_all_actions( 'after_wp_tiny_mce' ); 149 150 add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ], 999999 ); 151 add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_styles' ], 999999 ); 152 153 // Setup default heartbeat options 154 add_filter( 'heartbeat_settings', function( $settings ) { 155 $settings['interval'] = 15; 156 return $settings; 157 } ); 158 159 // Tell to WP Cache plugins do not cache this request. 160 Utils::do_not_cache(); 161 162 do_action( 'elementor/editor/init' ); 163 164 $this->print_editor_template(); 165 166 // From the action it's an empty string, from tests its `false` 167 if ( false !== $die ) { 168 die; 169 } 170 } 171 172 /** 173 * Retrieve post ID. 174 * 175 * Get the ID of the current post. 176 * 177 * @since 1.8.0 178 * @access public 179 * 180 * @return int Post ID. 181 */ 182 public function get_post_id() { 183 return $this->post_id; 184 } 185 186 /** 187 * Redirect to new URL. 188 * 189 * Used as a fallback function for the old URL structure of Elementor page 190 * edit URL. 191 * 192 * Fired by `template_redirect` action. 193 * 194 * @since 1.6.0 195 * @access public 196 */ 197 public function redirect_to_new_url() { 198 if ( ! isset( $_GET['elementor'] ) ) { 199 return; 200 } 201 202 $document = Plugin::$instance->documents->get( get_the_ID() ); 203 204 if ( ! $document ) { 205 wp_die( esc_html__( 'Document not found.', 'elementor' ) ); 206 } 207 208 if ( ! $document->is_editable_by_current_user() || ! $document->is_built_with_elementor() ) { 209 return; 210 } 211 212 wp_safe_redirect( $document->get_edit_url() ); 213 die; 214 } 215 216 /** 217 * Whether the edit mode is active. 218 * 219 * Used to determine whether we are in the edit mode. 220 * 221 * @since 1.0.0 222 * @access public 223 * 224 * @param int $post_id Optional. Post ID. Default is `null`, the current 225 * post ID. 226 * 227 * @return bool Whether the edit mode is active. 228 */ 229 public function is_edit_mode( $post_id = null ) { 230 if ( null !== $this->is_edit_mode ) { 231 return $this->is_edit_mode; 232 } 233 234 if ( empty( $post_id ) ) { 235 $post_id = $this->post_id; 236 } 237 238 $document = Plugin::$instance->documents->get( $post_id ); 239 240 if ( ! $document || ! $document->is_editable_by_current_user() ) { 241 return false; 242 } 243 244 /** @var Module ajax */ 245 $ajax_data = Plugin::$instance->common->get_component( 'ajax' )->get_current_action_data(); 246 247 if ( ! empty( $ajax_data ) && 'get_document_config' === $ajax_data['action'] ) { 248 return true; 249 } 250 251 // Ajax request as Editor mode 252 $actions = [ 253 'elementor', 254 255 // Templates 256 'elementor_get_templates', 257 'elementor_save_template', 258 'elementor_get_template', 259 'elementor_delete_template', 260 'elementor_import_template', 261 'elementor_library_direct_actions', 262 ]; 263 264 if ( isset( $_REQUEST['action'] ) && in_array( $_REQUEST['action'], $actions ) ) { 265 return true; 266 } 267 268 return false; 269 } 270 271 /** 272 * Lock post. 273 * 274 * Mark the post as currently being edited by the current user. 275 * 276 * @since 1.0.0 277 * @access public 278 * 279 * @param int $post_id The ID of the post being edited. 280 */ 281 public function lock_post( $post_id ) { 282 if ( ! function_exists( 'wp_set_post_lock' ) ) { 283 require_once ABSPATH . 'wp-admin/includes/post.php'; 284 } 285 286 wp_set_post_lock( $post_id ); 287 } 288 289 /** 290 * Get locked user. 291 * 292 * Check what user is currently editing the post. 293 * 294 * @since 1.0.0 295 * @access public 296 * 297 * @param int $post_id The ID of the post being edited. 298 * 299 * @return \WP_User|false User information or false if the post is not locked. 300 */ 301 public function get_locked_user( $post_id ) { 302 if ( ! function_exists( 'wp_check_post_lock' ) ) { 303 require_once ABSPATH . 'wp-admin/includes/post.php'; 304 } 305 306 $locked_user = wp_check_post_lock( $post_id ); 307 if ( ! $locked_user ) { 308 return false; 309 } 310 311 return get_user_by( 'id', $locked_user ); 312 } 313 314 /** 315 * Print Editor Template. 316 * 317 * Include the wrapper template of the editor. 318 * 319 * @since 2.2.0 320 * @access public 321 */ 322 public function print_editor_template() { 323 include ELEMENTOR_PATH . 'includes/editor-templates/editor-wrapper.php'; 324 } 325 326 /** 327 * Enqueue scripts. 328 * 329 * Registers all the editor scripts and enqueues them. 330 * 331 * @since 1.0.0 332 * @access public 333 */ 334 public function enqueue_scripts() { 335 remove_action( 'wp_enqueue_scripts', [ $this, __FUNCTION__ ], 999999 ); 336 337 global $wp_styles, $wp_scripts; 338 339 $plugin = Plugin::$instance; 340 341 // Reset global variable 342 $wp_styles = new \WP_Styles(); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited 343 $wp_scripts = new \WP_Scripts(); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited 344 345 $suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || defined( 'ELEMENTOR_TESTS' ) && ELEMENTOR_TESTS ) ? '' : '.min'; 346 347 wp_register_script( 348 'elementor-editor-modules', 349 ELEMENTOR_ASSETS_URL . 'js/editor-modules' . $suffix . '.js', 350 [ 351 'elementor-common-modules', 352 ], 353 ELEMENTOR_VERSION, 354 true 355 ); 356 357 wp_register_script( 358 'elementor-editor-document', 359 ELEMENTOR_ASSETS_URL . 'js/editor-document' . $suffix . '.js', 360 [ 361 'elementor-common-modules', 362 ], 363 ELEMENTOR_VERSION, 364 true 365 ); 366 // Hack for waypoint with editor mode. 367 wp_register_script( 368 'elementor-waypoints', 369 ELEMENTOR_ASSETS_URL . 'lib/waypoints/waypoints-for-editor.js', 370 [ 371 'jquery', 372 ], 373 '4.0.2', 374 true 375 ); 376 377 wp_register_script( 378 'perfect-scrollbar', 379 ELEMENTOR_ASSETS_URL . 'lib/perfect-scrollbar/js/perfect-scrollbar' . $suffix . '.js', 380 [], 381 '1.4.0', 382 true 383 ); 384 385 wp_register_script( 386 'jquery-easing', 387 ELEMENTOR_ASSETS_URL . 'lib/jquery-easing/jquery-easing' . $suffix . '.js', 388 [ 389 'jquery', 390 ], 391 '1.3.2', 392 true 393 ); 394 395 wp_register_script( 396 'nprogress', 397 ELEMENTOR_ASSETS_URL . 'lib/nprogress/nprogress' . $suffix . '.js', 398 [], 399 '0.2.0', 400 true 401 ); 402 403 wp_register_script( 404 'tipsy', 405 ELEMENTOR_ASSETS_URL . 'lib/tipsy/tipsy' . $suffix . '.js', 406 [ 407 'jquery', 408 ], 409 '1.0.0', 410 true 411 ); 412 413 wp_register_script( 414 'jquery-elementor-select2', 415 ELEMENTOR_ASSETS_URL . 'lib/e-select2/js/e-select2.full' . $suffix . '.js', 416 [ 417 'jquery', 418 ], 419 '4.0.6-rc.1', 420 true 421 ); 422 423 wp_register_script( 424 'flatpickr', 425 ELEMENTOR_ASSETS_URL . 'lib/flatpickr/flatpickr' . $suffix . '.js', 426 [ 427 'jquery', 428 ], 429 '1.12.0', 430 true 431 ); 432 433 wp_register_script( 434 'ace', 435 'https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.5/ace.js', 436 [], 437 '1.2.5', 438 true 439 ); 440 441 wp_register_script( 442 'ace-language-tools', 443 'https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.5/ext-language_tools.js', 444 [ 445 'ace', 446 ], 447 '1.2.5', 448 true 449 ); 450 451 wp_register_script( 452 'jquery-hover-intent', 453 ELEMENTOR_ASSETS_URL . 'lib/jquery-hover-intent/jquery-hover-intent' . $suffix . '.js', 454 [], 455 '1.0.0', 456 true 457 ); 458 459 wp_register_script( 460 'nouislider', 461 ELEMENTOR_ASSETS_URL . 'lib/nouislider/nouislider' . $suffix . '.js', 462 [], 463 '13.0.0', 464 true 465 ); 466 467 wp_register_script( 468 'pickr', 469 ELEMENTOR_ASSETS_URL . 'lib/pickr/pickr.min.js', 470 [], 471 '1.5.0', 472 true 473 ); 474 475 wp_register_script( 476 'elementor-editor', 477 ELEMENTOR_ASSETS_URL . 'js/editor' . $suffix . '.js', 478 [ 479 'elementor-common', 480 'elementor-editor-modules', 481 'elementor-editor-document', 482 'wp-auth-check', 483 'jquery-ui-sortable', 484 'jquery-ui-resizable', 485 'perfect-scrollbar', 486 'nprogress', 487 'tipsy', 488 'imagesloaded', 489 'heartbeat', 490 'jquery-elementor-select2', 491 'flatpickr', 492 'ace', 493 'ace-language-tools', 494 'jquery-hover-intent', 495 'nouislider', 496 'pickr', 497 'react', 498 'react-dom', 499 ], 500 ELEMENTOR_VERSION, 501 true 502 ); 503 504 /** 505 * Before editor enqueue scripts. 506 * 507 * Fires before Elementor editor scripts are enqueued. 508 * 509 * @since 1.0.0 510 */ 511 do_action( 'elementor/editor/before_enqueue_scripts' ); 512 513 // Tweak for WP Admin menu icons 514 wp_print_styles( 'editor-buttons' ); 515 516 $settings = SettingsManager::get_settings_managers_config(); 517 // Moved to document since 2.9.0. 518 unset( $settings['page'] ); 519 520 $document = Plugin::$instance->documents->get_doc_or_auto_save( $this->post_id ); 521 $kits_manager = Plugin::$instance->kits_manager; 522 523 $page_title_selector = $kits_manager->get_current_settings( 'page_title_selector' ); 524 525 $page_title_selector .= ', .elementor-page-title .elementor-heading-title'; 526 527 $config = [ 528 'initial_document' => $document->get_config(), 529 'version' => ELEMENTOR_VERSION, 530 'home_url' => home_url(), 531 'admin_settings_url' => admin_url( 'admin.php?page=' . Settings::PAGE_ID ), 532 'admin_tools_url' => admin_url( 'admin.php?page=' . Tools::PAGE_ID ), 533 'autosave_interval' => AUTOSAVE_INTERVAL, 534 'tabs' => $plugin->controls_manager->get_tabs(), 535 'controls' => $plugin->controls_manager->get_controls_data(), 536 'elements' => $plugin->elements_manager->get_element_types_config(), 537 'schemes' => [ 538 'items' => $plugin->schemes_manager->get_registered_schemes_data(), 539 'enabled_schemes' => Schemes_Manager::get_enabled_schemes(), 540 ], 541 'globals' => [ 542 'defaults_enabled' => [ 543 'colors' => $kits_manager->is_custom_colors_enabled(), 544 'typography' => $kits_manager->is_custom_typography_enabled(), 545 ], 546 ], 547 'icons' => [ 548 'libraries' => Icons_Manager::get_icon_manager_tabs_config(), 549 'goProURL' => Utils::get_pro_link( 'https://elementor.com/pro/?utm_source=icon-library&utm_campaign=gopro&utm_medium=wp-dash' ), 550 ], 551 'filesUpload' => [ 552 'unfilteredFiles' => Files_Upload_Handler::is_enabled(), 553 ], 554 'fa4_to_fa5_mapping_url' => ELEMENTOR_ASSETS_URL . 'lib/font-awesome/migration/mapping.js', 555 'default_schemes' => $plugin->schemes_manager->get_schemes_defaults(), 556 'settings' => $settings, 557 'system_schemes' => $plugin->schemes_manager->get_system_schemes(), 558 'wp_editor' => $this->get_wp_editor_config(), 559 'settings_page_link' => Settings::get_url(), 560 'tools_page_link' => Tools::get_url(), 561 'elementor_site' => 'https://go.elementor.com/about-elementor/', 562 'docs_elementor_site' => 'https://go.elementor.com/docs/', 563 'help_the_content_url' => 'https://go.elementor.com/the-content-missing/', 564 'help_flexbox_bc_url' => 'https://go.elementor.com/flexbox-layout-bc/', 565 'elementPromotionURL' => 'https://go.elementor.com/go-pro-%s', 566 'dynamicPromotionURL' => 'https://go.elementor.com/go-pro-dynamic-tag', 567 'additional_shapes' => Shapes::get_additional_shapes_for_config(), 568 'user' => [ 569 'restrictions' => $plugin->role_manager->get_user_restrictions_array(), 570 'is_administrator' => current_user_can( 'manage_options' ), 571 'introduction' => User::get_introduction_meta(), 572 ], 573 'preview' => [ 574 'help_preview_error_url' => 'https://go.elementor.com/preview-not-loaded/', 575 'help_preview_http_error_url' => 'https://go.elementor.com/preview-not-loaded/#permissions', 576 'help_preview_http_error_500_url' => 'https://go.elementor.com/500-error/', 577 'debug_data' => Loading_Inspection_Manager::instance()->run_inspections(), 578 ], 579 'locale' => get_locale(), 580 'rich_editing_enabled' => filter_var( get_user_meta( get_current_user_id(), 'rich_editing', true ), FILTER_VALIDATE_BOOLEAN ), 581 'page_title_selector' => $page_title_selector, 582 'tinymceHasCustomConfig' => class_exists( 'Tinymce_Advanced' ) || class_exists( 'Advanced_Editor_Tools' ), 583 'inlineEditing' => Plugin::$instance->widgets_manager->get_inline_editing_config(), 584 'dynamicTags' => Plugin::$instance->dynamic_tags->get_config(), 585 'ui' => [ 586 'darkModeStylesheetURL' => ELEMENTOR_ASSETS_URL . 'css/editor-dark-mode' . $suffix . '.css', 587 'defaultGenericFonts' => $kits_manager->get_current_settings( 'default_generic_fonts' ), 588 ], 589 // Empty array for BC to avoid errors. 590 'i18n' => [], 591 // 'responsive' contains the custom breakpoints config introduced in Elementor v3.2.0 592 'responsive' => [ 593 'breakpoints' => Plugin::$instance->breakpoints->get_breakpoints_config(), 594 'icons_map' => Plugin::$instance->breakpoints->get_responsive_icons_classes_map(), 595 ], 596 ]; 597 598 if ( ! Utils::has_pro() && current_user_can( 'manage_options' ) ) { 599 $config['promotionWidgets'] = Api::get_promotion_widgets(); 600 } 601 602 $this->bc_move_document_filters(); 603 604 /** 605 * Localize editor settings. 606 * 607 * Filters the editor localized settings. 608 * 609 * @since 1.0.0 610 * 611 * @param array $config Editor configuration. 612 * @param int $post_id The ID of the current post being edited. 613 */ 614 $config = apply_filters( 'elementor/editor/localize_settings', $config ); 615 616 Utils::print_js_config( 'elementor-editor', 'ElementorConfig', $config ); 617 618 wp_enqueue_script( 'elementor-editor' ); 619 620 wp_set_script_translations( 'elementor-editor', 'elementor' ); 621 622 $plugin->controls_manager->enqueue_control_scripts(); 623 624 /** 625 * After editor enqueue scripts. 626 * 627 * Fires after Elementor editor scripts are enqueued. 628 * 629 * @since 1.0.0 630 */ 631 do_action( 'elementor/editor/after_enqueue_scripts' ); 632 } 633 634 /** 635 * Enqueue styles. 636 * 637 * Registers all the editor styles and enqueues them. 638 * 639 * @since 1.0.0 640 * @access public 641 */ 642 public function enqueue_styles() { 643 /** 644 * Before editor enqueue styles. 645 * 646 * Fires before Elementor editor styles are enqueued. 647 * 648 * @since 1.0.0 649 */ 650 do_action( 'elementor/editor/before_enqueue_styles' ); 651 652 $suffix = Utils::is_script_debug() ? '' : '.min'; 653 654 $direction_suffix = is_rtl() ? '-rtl' : ''; 655 656 wp_register_style( 657 'font-awesome', 658 ELEMENTOR_ASSETS_URL . 'lib/font-awesome/css/font-awesome' . $suffix . '.css', 659 [], 660 '4.7.0' 661 ); 662 663 wp_register_style( 664 'elementor-select2', 665 ELEMENTOR_ASSETS_URL . 'lib/e-select2/css/e-select2' . $suffix . '.css', 666 [], 667 '4.0.6-rc.1' 668 ); 669 670 wp_register_style( 671 'google-font-roboto', 672 'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700', 673 [], 674 ELEMENTOR_VERSION 675 ); 676 677 wp_register_style( 678 'flatpickr', 679 ELEMENTOR_ASSETS_URL . 'lib/flatpickr/flatpickr' . $suffix . '.css', 680 [], 681 '1.12.0' 682 ); 683 684 wp_register_style( 685 'pickr', 686 ELEMENTOR_ASSETS_URL . 'lib/pickr/themes/monolith.min.css', 687 [], 688 '1.5.0' 689 ); 690 691 wp_register_style( 692 'elementor-editor', 693 ELEMENTOR_ASSETS_URL . 'css/editor' . $direction_suffix . $suffix . '.css', 694 [ 695 'elementor-common', 696 'elementor-select2', 697 'elementor-icons', 698 'wp-auth-check', 699 'google-font-roboto', 700 'flatpickr', 701 'pickr', 702 ], 703 ELEMENTOR_VERSION 704 ); 705 706 wp_enqueue_style( 'elementor-editor' ); 707 708 $ui_theme = SettingsManager::get_settings_managers( 'editorPreferences' )->get_model()->get_settings( 'ui_theme' ); 709 710 if ( 'light' !== $ui_theme ) { 711 $ui_theme_media_queries = 'all'; 712 713 if ( 'auto' === $ui_theme ) { 714 $ui_theme_media_queries = '(prefers-color-scheme: dark)'; 715 } 716 717 wp_enqueue_style( 718 'elementor-editor-dark-mode', 719 ELEMENTOR_ASSETS_URL . 'css/editor-dark-mode' . $suffix . '.css', 720 [ 721 'elementor-editor', 722 ], 723 ELEMENTOR_VERSION, 724 $ui_theme_media_queries 725 ); 726 } 727 728 $breakpoints = Plugin::$instance->breakpoints->get_breakpoints(); 729 730 // The two breakpoints under 'tablet' need to be checked for values. 731 if ( $breakpoints[ Breakpoints_Manager::BREAKPOINT_KEY_MOBILE ]->is_custom() || $breakpoints[ Breakpoints_Manager::BREAKPOINT_KEY_MOBILE_EXTRA ]->is_enabled() ) { 732 wp_add_inline_style( 733 'elementor-editor', 734 '.elementor-device-tablet #elementor-preview-responsive-wrapper { width: ' . Plugin::$instance->breakpoints->get_device_min_breakpoint( Breakpoints_Manager::BREAKPOINT_KEY_TABLET ) . 'px; }' 735 ); 736 } 737 738 /** 739 * After editor enqueue styles. 740 * 741 * Fires after Elementor editor styles are enqueued. 742 * 743 * @since 1.0.0 744 */ 745 do_action( 'elementor/editor/after_enqueue_styles' ); 746 } 747 748 /** 749 * Get WordPress editor config. 750 * 751 * Config the default WordPress editor with custom settings for Elementor use. 752 * 753 * @since 1.9.0 754 * @access private 755 */ 756 private function get_wp_editor_config() { 757 // Remove all TinyMCE plugins. 758 remove_all_filters( 'mce_buttons', 10 ); 759 remove_all_filters( 'mce_external_plugins', 10 ); 760 761 if ( ! class_exists( '\_WP_Editors', false ) ) { 762 require ABSPATH . WPINC . '/class-wp-editor.php'; 763 } 764 765 // WordPress 4.8 and higher 766 if ( method_exists( '\_WP_Editors', 'print_tinymce_scripts' ) ) { 767 \_WP_Editors::print_default_editor_scripts(); 768 \_WP_Editors::print_tinymce_scripts(); 769 } 770 ob_start(); 771 772 wp_editor( 773 '%%EDITORCONTENT%%', 774 'elementorwpeditor', 775 [ 776 'editor_class' => 'elementor-wp-editor', 777 'editor_height' => 250, 778 'drag_drop_upload' => true, 779 ] 780 ); 781 782 $config = ob_get_clean(); 783 784 // Don't call \_WP_Editors methods again 785 remove_action( 'admin_print_footer_scripts', [ '_WP_Editors', 'editor_js' ], 50 ); 786 remove_action( 'admin_print_footer_scripts', [ '_WP_Editors', 'print_default_editor_scripts' ], 45 ); 787 788 \_WP_Editors::editor_js(); 789 790 return $config; 791 } 792 793 /** 794 * Editor head trigger. 795 * 796 * Fires the 'elementor/editor/wp_head' action in the head tag in Elementor 797 * editor. 798 * 799 * @since 1.0.0 800 * @access public 801 */ 802 public function editor_head_trigger() { 803 /** 804 * Elementor editor head. 805 * 806 * Fires on Elementor editor head tag. 807 * 808 * Used to prints scripts or any other data in the head tag. 809 * 810 * @since 1.0.0 811 */ 812 do_action( 'elementor/editor/wp_head' ); 813 } 814 815 /** 816 * WP footer. 817 * 818 * Prints Elementor editor with all the editor templates, and render controls, 819 * widgets and content elements. 820 * 821 * Fired by `wp_footer` action. 822 * 823 * @since 1.0.0 824 * @access public 825 */ 826 public function wp_footer() { 827 $plugin = Plugin::$instance; 828 829 $plugin->controls_manager->render_controls(); 830 $plugin->widgets_manager->render_widgets_content(); 831 $plugin->elements_manager->render_elements_content(); 832 833 $plugin->schemes_manager->print_schemes_templates(); 834 835 $plugin->dynamic_tags->print_templates(); 836 837 $this->init_editor_templates(); 838 839 /** 840 * Elementor editor footer. 841 * 842 * Fires on Elementor editor before closing the body tag. 843 * 844 * Used to prints scripts or any other HTML before closing the body tag. 845 * 846 * @since 1.0.0 847 */ 848 do_action( 'elementor/editor/footer' ); 849 } 850 851 /** 852 * Set edit mode. 853 * 854 * Used to update the edit mode. 855 * 856 * @since 1.0.0 857 * @access public 858 * 859 * @param bool $edit_mode Whether the edit mode is active. 860 */ 861 public function set_edit_mode( $edit_mode ) { 862 $this->is_edit_mode = $edit_mode; 863 } 864 865 /** 866 * Editor constructor. 867 * 868 * Initializing Elementor editor and redirect from old URL structure of 869 * Elementor editor. 870 * 871 * @since 1.0.0 872 * @access public 873 */ 874 public function __construct() { 875 Plugin::$instance->data_manager->register_controller( Data\Globals\Controller::class ); 876 877 $this->notice_bar = new Notice_Bar(); 878 879 add_action( 'admin_action_elementor', [ $this, 'init' ] ); 880 add_action( 'template_redirect', [ $this, 'redirect_to_new_url' ] ); 881 882 // Handle autocomplete feature for URL control. 883 add_filter( 'wp_link_query_args', [ $this, 'filter_wp_link_query_args' ] ); 884 add_filter( 'wp_link_query', [ $this, 'filter_wp_link_query' ] ); 885 } 886 887 /** 888 * @since 2.2.0 889 * @access public 890 */ 891 public function filter_wp_link_query_args( $query ) { 892 $library_cpt_key = array_search( Source_Local::CPT, $query['post_type'], true ); 893 if ( false !== $library_cpt_key ) { 894 unset( $query['post_type'][ $library_cpt_key ] ); 895 } 896 897 return $query; 898 } 899 900 /** 901 * @since 2.2.0 902 * @access public 903 */ 904 public function filter_wp_link_query( $results ) { 905 906 // PHPCS - The user data is not used. 907 if ( isset( $_POST['editor'] ) && 'elementor' === $_POST['editor'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing 908 $post_type_object = get_post_type_object( 'post' ); 909 $post_label = $post_type_object->labels->singular_name; 910 911 foreach ( $results as & $result ) { 912 if ( 'post' === get_post_type( $result['ID'] ) ) { 913 $result['info'] = $post_label; 914 } 915 } 916 } 917 918 return $results; 919 } 920 921 /** 922 * Init editor templates. 923 * 924 * Initialize default elementor templates used in the editor panel. 925 * 926 * @since 1.7.0 927 * @access private 928 */ 929 private function init_editor_templates() { 930 $template_names = [ 931 'global', 932 'panel', 933 'panel-elements', 934 'repeater', 935 'templates', 936 'navigator', 937 'hotkeys', 938 'responsive-bar', 939 ]; 940 941 foreach ( $template_names as $template_name ) { 942 Plugin::$instance->common->add_template( ELEMENTOR_PATH . "includes/editor-templates/$template_name.php" ); 943 } 944 } 945 946 private function bc_move_document_filters() { 947 global $wp_filter; 948 949 $old_tag = 'elementor/editor/localize_settings'; 950 $new_tag = 'elementor/document/config'; 951 952 if ( ! has_filter( $old_tag ) ) { 953 return; 954 } 955 956 foreach ( $wp_filter[ $old_tag ] as $priority => $filters ) { 957 foreach ( $filters as $filter_id => $filter_args ) { 958 if ( 2 === $filter_args['accepted_args'] ) { 959 remove_filter( $old_tag, $filter_id, $priority ); 960 961 add_filter( $new_tag, $filter_args['function'], $priority, 2 ); 962 963 // TODO: Hard deprecation 964 // _deprecated_hook( '`' . $old_tag . ` is no longer using post_id', '2.9.0', $new_tag' ); 965 } 966 } 967 } 968 } 969 970 public function set_post_id( $post_id ) { 971 $this->post_id = $post_id; 972 } 973 }