PluginProbe
Elementor Website Builder – more than just a page builder / 4.2.2
Elementor Website Builder – more than just a page builder v4.2.2
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / core / admin / admin.php

admin.php in Elementor Website Builder – more than just a page builder 4.2.2, at core/admin/admin.php

1,231 lines 36.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor\Core\Admin;
3
4 use Elementor\Api;
5 use Elementor\Beta_Testers;
6 use Elementor\App\Modules\Onboarding\Module as Onboarding_Module;
7 use Elementor\Core\Base\App;
8 use Elementor\Core\Upgrade\Manager as Upgrade_Manager;
9 use Elementor\Core\Utils\Assets_Config_Provider;
10 use Elementor\Core\Utils\Collection;
11 use Elementor\Modules\FloatingButtons\Module as Floating_Buttons_Module;
12 use Elementor\Plugin;
13 use Elementor\Settings;
14 use Elementor\User;
15 use Elementor\Utils;
16 use Elementor\Core\Utils\Hints;
17 use Elementor\Core\DocumentTypes\Page;
18
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit; // Exit if accessed directly.
21 }
22
23 class Admin extends App {
24
25 private $menus = [];
26
27 /**
28 * Get module name.
29 *
30 * Retrieve the module name.
31 *
32 * @since 2.3.0
33 * @access public
34 *
35 * @return string Module name.
36 */
37 public function get_name() {
38 return 'admin';
39 }
40
41 /**
42 * Check if current page is an Elementor admin page.
43 *
44 * @param \WP_Screen|null $current_screen Optional. Screen object to check. Defaults to current screen.
45 *
46 * @return bool Whether current page is an Elementor admin page.
47 */
48 public static function is_elementor_admin_page( $current_screen = null ) {
49 if ( ! $current_screen ) {
50 $current_screen = get_current_screen();
51 }
52
53 if ( ! $current_screen ) {
54 return false;
55 }
56
57 $screen_id = $current_screen->id ?? '';
58 $post_type = $current_screen->post_type ?? '';
59
60 $is_elementor_screen = strpos( $screen_id, 'elementor' ) !== false
61 || strpos( $screen_id, Floating_Buttons_Module::CPT_FLOATING_BUTTONS ) !== false;
62
63 $is_elementor_post_type = strpos( $post_type, 'elementor' ) !== false
64 || strpos( $post_type, Floating_Buttons_Module::CPT_FLOATING_BUTTONS ) !== false;
65
66 return $is_elementor_screen || $is_elementor_post_type;
67 }
68
69 /**
70 * @since 2.2.0
71 * @access public
72 */
73 public function maybe_redirect_to_getting_started() {
74 if ( ! get_transient( 'elementor_activation_redirect' ) ) {
75 return;
76 }
77
78 if ( wp_doing_ajax() ) {
79 return;
80 }
81
82 delete_transient( 'elementor_activation_redirect' );
83
84 if ( is_network_admin() || isset( $_GET['activate-multi'] ) ) {
85 return;
86 }
87
88 $already_had_onboarding = get_option( Onboarding_Module::ONBOARDING_OPTION );
89
90 // Get the latest installation from Elementor's Install log in the DB.
91 $latest_install = key( Upgrade_Manager::get_installs_history() );
92
93 if ( ! empty( $latest_install ) ) {
94 $is_new_install = version_compare( $latest_install, '3.6.0-beta', '>=' );
95 } else {
96 // If `$latest_install` is not set, Elementor was never installed on this site.
97 $is_new_install = true;
98 }
99
100 if ( $already_had_onboarding || ! $is_new_install ) {
101 return;
102 }
103
104 wp_safe_redirect( admin_url( 'admin.php?page=elementor-app#onboarding' ) );
105
106 exit;
107 }
108
109 private function register_packages() {
110 $assets_config_provider = ( new Assets_Config_Provider() )
111 ->set_path_resolver( function ( $name ) {
112 return ELEMENTOR_ASSETS_PATH . "js/packages/{$name}/{$name}.asset.php";
113 } );
114
115 Collection::make( [ 'ui', 'icons', 'query' ] )
116 ->each( function( $package ) use ( $assets_config_provider ) {
117 $suffix = Utils::is_script_debug() ? '' : '.min';
118 $config = $assets_config_provider->load( $package )->get( $package );
119
120 if ( ! $config ) {
121 return;
122 }
123
124 wp_register_script(
125 $config['handle'],
126 ELEMENTOR_ASSETS_URL . "js/packages/{$package}/{$package}{$suffix}.js",
127 $config['deps'],
128 ELEMENTOR_VERSION,
129 true
130 );
131 } );
132 }
133
134 /**
135 * Enqueue admin scripts.
136 *
137 * Registers all the admin scripts and enqueues them.
138 *
139 * Fired by `admin_enqueue_scripts` action.
140 *
141 * @since 1.0.0
142 * @access public
143 */
144 public function enqueue_scripts() {
145 wp_register_script(
146 'elementor-admin-modules',
147 $this->get_js_assets_url( 'admin-modules' ),
148 [],
149 ELEMENTOR_VERSION,
150 true
151 );
152
153 $this->register_packages();
154
155 // Temporary solution for the admin.
156 wp_register_script(
157 'elementor-ai-admin',
158 $this->get_js_assets_url( 'ai-admin' ),
159 [
160 'elementor-common',
161 'elementor-v2-ui',
162 'elementor-v2-icons',
163 ],
164 ELEMENTOR_VERSION,
165 true
166 );
167
168 wp_register_script(
169 'elementor-admin',
170 $this->get_js_assets_url( 'admin' ),
171 [
172 'elementor-common',
173 'elementor-admin-modules',
174 ],
175 ELEMENTOR_VERSION,
176 true
177 );
178
179 wp_enqueue_script( 'elementor-admin' );
180
181 wp_set_script_translations( 'elementor-admin', 'elementor' );
182
183 $this->maybe_enqueue_hints();
184
185 $this->print_config();
186 }
187
188 /**
189 * Enqueue admin styles.
190 *
191 * Registers all the admin styles and enqueues them.
192 *
193 * Fired by `admin_enqueue_scripts` action.
194 *
195 * @since 1.0.0
196 * @access public
197 */
198 public function enqueue_styles() {
199 wp_register_style(
200 'elementor-admin',
201 $this->get_css_assets_url( 'admin' ),
202 [
203 'elementor-common',
204 ],
205 ELEMENTOR_VERSION
206 );
207
208 wp_enqueue_style( 'elementor-admin' );
209
210 // It's for upgrade notice.
211 // TODO: enqueue this just if needed.
212 add_thickbox();
213 }
214
215 /**
216 * Print switch mode button.
217 *
218 * Adds a switch button in post edit screen (which has cpt support). To allow
219 * the user to switch from the native WordPress editor to Elementor builder.
220 *
221 * Fired by `edit_form_after_title` action.
222 *
223 * @since 1.0.0
224 * @access public
225 *
226 * @param \WP_Post $post The current post object.
227 */
228 public function print_switch_mode_button( $post ) {
229 // Exit if Gutenberg are active.
230 if ( did_action( 'enqueue_block_editor_assets' ) ) {
231 return;
232 }
233
234 $document = Plugin::$instance->documents->get( $post->ID );
235
236 if ( ! $document || ! $document->is_editable_by_current_user() ) {
237 return;
238 }
239
240 wp_nonce_field( basename( __FILE__ ), '_elementor_edit_mode_nonce' );
241 ?>
242 <div id="elementor-switch-mode">
243 <input id="elementor-switch-mode-input" type="hidden" name="_elementor_post_mode" value="<?php echo esc_attr( $document->is_built_with_elementor() ); ?>" />
244 <button id="elementor-switch-mode-button" type="button" class="button button-primary button-hero">
245 <span class="elementor-switch-mode-on">
246 <i class="eicon-arrow-<?php echo ( is_rtl() ) ? 'right' : 'left'; ?>" aria-hidden="true"></i>
247 <?php echo esc_html__( 'Back to WordPress Editor', 'elementor' ); ?>
248 </span>
249 <span class="elementor-switch-mode-off">
250 <i class="eicon-elementor-square" aria-hidden="true"></i>
251 <?php echo esc_html__( 'Edit with Elementor', 'elementor' ); ?>
252 </span>
253 </button>
254 </div>
255 <div id="elementor-editor">
256 <a id="elementor-go-to-edit-page-link" href="<?php echo esc_url( $document->get_edit_url() ); ?>">
257 <div id="elementor-editor-button" class="button button-primary button-hero">
258 <i class="eicon-elementor-square" aria-hidden="true"></i>
259 <?php echo esc_html__( 'Edit with Elementor', 'elementor' ); ?>
260 </div>
261 <div class="elementor-loader-wrapper">
262 <div class="elementor-loader">
263 <div class="elementor-loader-boxes">
264 <div class="elementor-loader-box"></div>
265 <div class="elementor-loader-box"></div>
266 <div class="elementor-loader-box"></div>
267 <div class="elementor-loader-box"></div>
268 </div>
269 </div>
270 <div class="elementor-loading-title"><?php echo esc_html__( 'Loading', 'elementor' ); ?></div>
271 </div>
272 </a>
273 </div>
274 <?php
275 }
276
277 /**
278 * Save post.
279 *
280 * Flag the post mode when the post is saved.
281 *
282 * Fired by `save_post` action.
283 *
284 * @since 1.0.0
285 * @access public
286 *
287 * @param int $post_id Post ID.
288 */
289 public function save_post( $post_id ) {
290 if ( ! wp_verify_nonce( Utils::get_super_global_value( $_POST, '_elementor_edit_mode_nonce' ), basename( __FILE__ ) ) ) {
291 return;
292 }
293
294 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
295 return;
296 }
297
298 Plugin::$instance->documents->get( $post_id )->set_is_built_with_elementor( ! empty( $_POST['_elementor_post_mode'] ) );
299 }
300
301 /**
302 * Add Elementor post state.
303 *
304 * Adds a new "Elementor" post state to the post table.
305 *
306 * Fired by `display_post_states` filter.
307 *
308 * @since 1.8.0
309 * @access public
310 *
311 * @param array $post_states An array of post display states.
312 * @param \WP_Post $post The current post object.
313 *
314 * @return array A filtered array of post display states.
315 */
316 public function add_elementor_post_state( $post_states, $post ) {
317 $document = Plugin::$instance->documents->get( $post->ID );
318
319 if ( $document && $document->is_built_with_elementor() && $document->is_editable_by_current_user() ) {
320 $post_states['elementor'] = esc_html__( 'Elementor', 'elementor' );
321 }
322
323 return $post_states;
324 }
325
326 /**
327 * Body status classes.
328 *
329 * Adds CSS classes to the admin body tag.
330 *
331 * Fired by `admin_body_class` filter.
332 *
333 * @since 1.0.0
334 * @access public
335 *
336 * @param string $classes Space-separated list of CSS classes.
337 *
338 * @return string Space-separated list of CSS classes.
339 */
340 public function body_status_classes( $classes ) {
341 global $pagenow;
342
343 if ( in_array( $pagenow, [ 'post.php', 'post-new.php' ], true ) && Utils::is_post_support() ) {
344 $post = get_post();
345
346 $document = Plugin::$instance->documents->get( $post->ID );
347
348 $mode_class = $document && $document->is_built_with_elementor() ? 'elementor-editor-active' : 'elementor-editor-inactive';
349
350 $classes .= ' ' . $mode_class;
351 }
352
353 return $classes;
354 }
355
356 /**
357 * Plugin action links.
358 *
359 * Adds action links to the plugin list table
360 *
361 * Fired by `plugin_action_links` filter.
362 *
363 * @since 1.0.0
364 * @access public
365 *
366 * @param array $links An array of plugin action links.
367 *
368 * @return array An array of plugin action links.
369 */
370 public function plugin_action_links( $links ) {
371 $settings_link = sprintf( '<a href="%1$s">%2$s</a>', admin_url( 'admin.php?page=' . Settings::PAGE_ID ), esc_html__( 'Settings', 'elementor' ) );
372
373 array_unshift( $links, $settings_link );
374
375 $go_pro_text = esc_html__( 'Get Elementor Pro', 'elementor' );
376 if ( Utils::is_sale_time() ) {
377 $go_pro_text = esc_html__( 'Sale! Upgrade Now', 'elementor' );
378 }
379
380 $links['go_pro'] = sprintf( '<a href="%1$s" target="_blank" class="elementor-plugins-gopro">%2$s</a>', 'https://go.elementor.com/go-pro-wp-plugins/', $go_pro_text );
381
382 return $links;
383 }
384
385 /**
386 * Plugin row meta.
387 *
388 * Adds row meta links to the plugin list table
389 *
390 * Fired by `plugin_row_meta` filter.
391 *
392 * @since 1.1.4
393 * @access public
394 *
395 * @param array $plugin_meta An array of the plugin's metadata, including
396 * the version, author, author URI, and plugin URI.
397 * @param string $plugin_file Path to the plugin file, relative to the plugins
398 * directory.
399 *
400 * @return array An array of plugin row meta links.
401 */
402 public function plugin_row_meta( $plugin_meta, $plugin_file ) {
403 if ( ELEMENTOR_PLUGIN_BASE === $plugin_file ) {
404 $row_meta = [
405 'docs' => '<a href="https://go.elementor.com/docs-admin-plugins/" aria-label="' . esc_attr__( 'View Elementor Documentation', 'elementor' ) . '" target="_blank">' . esc_html__( 'Docs & FAQs', 'elementor' ) . '</a>',
406 'ideo' => '<a href="https://go.elementor.com/yt-admin-plugins/" aria-label="' . esc_attr__( 'View Elementor Video Tutorials', 'elementor' ) . '" target="_blank">' . esc_html__( 'Video Tutorials', 'elementor' ) . '</a>',
407 ];
408
409 $plugin_meta = array_merge( $plugin_meta, $row_meta );
410 }
411
412 return $plugin_meta;
413 }
414
415 /**
416 * Admin footer text.
417 *
418 * Modifies the "Thank you" text displayed in the admin footer.
419 *
420 * Fired by `admin_footer_text` filter.
421 *
422 * @since 1.0.0
423 * @access public
424 *
425 * @param string $footer_text The content that will be printed.
426 *
427 * @return string The content that will be printed.
428 */
429 public function admin_footer_text( $footer_text ) {
430 $current_screen = get_current_screen();
431 $is_elementor_screen = ( $current_screen && false !== strpos( $current_screen->id, 'elementor' ) );
432
433 if ( $is_elementor_screen ) {
434 $footer_text = sprintf(
435 /* translators: 1: Elementor, 2: Link to plugin review */
436 __( 'Enjoyed %1$s? Please leave us a %2$s rating. We really appreciate your support!', 'elementor' ),
437 '<strong>' . esc_html__( 'Elementor', 'elementor' ) . '</strong>',
438 '<a href="https://go.elementor.com/admin-review/" target="_blank">&#9733;&#9733;&#9733;&#9733;&#9733;</a>'
439 );
440 }
441
442 return $footer_text;
443 }
444
445 /**
446 * Register dashboard widgets.
447 *
448 * Adds a new Elementor widgets to WordPress dashboard.
449 *
450 * Fired by `wp_dashboard_setup` action.
451 *
452 * @since 1.9.0
453 * @access public
454 */
455 public function register_dashboard_widgets() {
456 wp_add_dashboard_widget( 'e-dashboard-overview', esc_html__( 'Elementor Overview', 'elementor' ), [ $this, 'elementor_dashboard_overview_widget' ] );
457
458 // Move our widget to top.
459 global $wp_meta_boxes;
460
461 $dashboard = $wp_meta_boxes['dashboard']['normal']['core'];
462 $ours = [
463 'e-dashboard-overview' => $dashboard['e-dashboard-overview'],
464 ];
465
466 $wp_meta_boxes['dashboard']['normal']['core'] = array_merge( $ours, $dashboard ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
467 }
468
469 /**
470 * Displays the Elementor dashboard widget.
471 *
472 * Fired by `wp_add_dashboard_widget` function.
473 *
474 * @since 1.9.0
475 * @access public
476 */
477 public function elementor_dashboard_overview_widget() {
478 ?>
479 <div class="e-dashboard-overview e-dashboard-widget">
480 <?php
481 self::elementor_dashboard_overview_header();
482 self::elementor_dashboard_overview_recently_edited();
483 self::elementor_dashboard_overview_news_updates();
484 self::elementor_dashboard_overview_footer();
485 ?>
486 </div>
487 <?php
488 }
489
490 /**
491 * Displays the Elementor dashboard widget - header section.
492 * Fired by `elementor_dashboard_overview_widget` function.
493 *
494 * @param bool $show_versions
495 * @param bool $is_create_post_enabled
496 *
497 * @return void
498 * @since 3.12.0
499 */
500 public static function elementor_dashboard_overview_header( bool $show_versions = true, bool $is_create_post_enabled = true ) {
501 if ( User::is_current_user_can_edit_post_type( 'page' ) ) {
502 $create_new_label = esc_html__( 'Create New Page', 'elementor' );
503 $create_new_post_type = 'page';
504 } elseif ( User::is_current_user_can_edit_post_type( 'post' ) ) {
505 $create_new_label = esc_html__( 'Create New Post', 'elementor' );
506 $create_new_post_type = 'post';
507 }
508 ?>
509 <div class="e-overview__header">
510 <?php if ( $show_versions ) { ?>
511 <div class="e-overview__logo">
512 <div class="e-logo-wrapper"><i class="eicon-elementor-circle"></i></div>
513 </div>
514 <div class="e-overview__versions">
515 <span class="e-overview__version"><?php echo esc_html__( 'Elementor', 'elementor' ); ?> v<?php echo ELEMENTOR_VERSION; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
516 <?php
517 /**
518 * Elementor dashboard widget after the version.
519 * Fires after Elementor version display in the dashboard widget.
520 *
521 * @since 1.9.0
522 */
523 do_action( 'elementor/admin/dashboard_overview_widget/after_version' );
524 ?>
525 </div>
526 <?php } ?>
527 <?php if ( ! empty( $create_new_post_type ) && $is_create_post_enabled ) { ?>
528 <div class="e-overview__create">
529 <a href="<?php echo esc_url( Plugin::$instance->documents->get_create_new_post_url( $create_new_post_type ) ); ?>" class="button"><span aria-hidden="true" class="dashicons dashicons-plus"></span> <?php echo esc_html( $create_new_label ); ?></a>
530 </div>
531 <?php } ?>
532 </div>
533 <?php
534 }
535
536 /**
537 * Displays the Elementor dashboard widget - recently edited section.
538 * Fired by `elementor_dashboard_overview_widget` function.
539 *
540 * @param array $args
541 * @param bool $show_heading
542 *
543 * @return void
544 * @since 3.12.0
545 */
546 public static function elementor_dashboard_overview_recently_edited( array $args = [], bool $show_heading = true ) {
547 $recently_edited_query = Utils::get_recently_edited_posts_query( $args );
548
549 if ( $recently_edited_query->have_posts() ) { ?>
550 <div class="e-overview__recently-edited">
551 <?php if ( $show_heading ) { ?>
552 <h3 class="e-heading e-divider_bottom"><?php echo esc_html__( 'Recently Edited', 'elementor' ); ?></h3>
553 <?php } ?>
554 <ul class="e-overview__posts">
555 <?php
556 while ( $recently_edited_query->have_posts() ) {
557 $recently_edited_query->the_post();
558 $document = Plugin::$instance->documents->get( get_the_ID() );
559
560 $date = date_i18n( _x( 'M jS', 'Dashboard Overview Widget Recently Date', 'elementor' ), get_the_modified_time( 'U' ) );
561 ?>
562 <li class="e-overview__post">
563 <a href="<?php echo esc_url( $document->get_edit_url() ); ?>" class="e-overview__post-link"><?php echo esc_html( get_the_title() ); ?>
564 <span class="dashicons dashicons-edit"></span></a>
565 <span><?php echo $date; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>, <?php the_modified_time(); ?></span>
566 </li>
567 <?php } ?>
568 </ul>
569 </div>
570 <?php }
571 }
572
573 /**
574 * Displays the Elementor dashboard widget - news and updates section.
575 * Fired by `elementor_dashboard_overview_widget` function.
576 *
577 * @param int $limit_feed
578 * @param bool $show_heading
579 *
580 * @return void
581 * @since 3.12.0
582 * @access public
583 */
584 public static function elementor_dashboard_overview_news_updates( int $limit_feed = 0, bool $show_heading = true ) {
585 $elementor_feed = Api::get_feed_data();
586 if ( $limit_feed > 0 ) {
587 $elementor_feed = array_slice( $elementor_feed, 0, $limit_feed );
588 }
589
590 if ( ! empty( $elementor_feed ) ) { ?>
591 <div class="e-overview__feed">
592 <?php if ( $show_heading ) { ?>
593 <h3 class="e-heading e-divider_bottom"><?php echo esc_html__( 'News & Updates', 'elementor' ); ?></h3>
594 <?php } ?>
595 <ul class="e-overview__posts">
596 <?php foreach ( $elementor_feed as $feed_item ) { ?>
597 <li class="e-overview__post">
598 <a href="<?php echo esc_url( $feed_item['url'] ); ?>" class="e-overview__post-link" target="_blank">
599 <?php if ( ! empty( $feed_item['badge'] ) ) { ?>
600 <span class="e-overview__badge"><?php echo esc_html( $feed_item['badge'] ); ?></span>
601 <?php } ?>
602 <?php echo esc_html( $feed_item['title'] ); ?>
603 </a>
604 <p class="e-overview__post-description"><?php echo esc_html( $feed_item['excerpt'] ); ?></p>
605 </li>
606 <?php } ?>
607 </ul>
608 </div>
609 <?php }
610 }
611
612 /**
613 * Displays the Elementor dashboard widget - footer section.
614 * Fired by `elementor_dashboard_overview_widget` function.
615 *
616 * @since 3.12.0
617 */
618 public static function elementor_dashboard_overview_footer() {
619 ?>
620 <div class="e-overview__footer e-divider_top">
621 <ul>
622 <?php foreach ( self::static_get_dashboard_overview_widget_footer_actions() as $action_id => $action ) { ?>
623 <li class="e-overview__<?php echo esc_attr( $action_id ); ?>">
624 <a href="<?php echo esc_url( $action['link'] ); ?>" target="_blank"><?php echo esc_html( $action['title'] ); ?>
625 <span class="screen-reader-text"><?php echo esc_html__( '(opens in a new window)', 'elementor' ); ?></span>
626 <span aria-hidden="true" class="dashicons dashicons-external"></span></a>
627 </li>
628 <?php } ?>
629 </ul>
630 </div>
631 <?php
632 }
633
634 /**
635 * Get elementor dashboard overview widget footer actions.
636 *
637 * Retrieves the footer action links displayed in elementor dashboard widget.
638 *
639 * @since 3.12.0
640 * @access public
641 */
642 public static function static_get_dashboard_overview_widget_footer_actions() {
643 $base_actions = [
644 'blog' => [
645 'title' => esc_html__( 'Blog', 'elementor' ),
646 'link' => 'https://go.elementor.com/overview-widget-blog/',
647 ],
648 'help' => [
649 'title' => esc_html__( 'Help', 'elementor' ),
650 'link' => 'https://go.elementor.com/overview-widget-docs/',
651 ],
652 ];
653
654 $additions_actions = [];
655 $additions_actions['ai'] = [
656 'title' => esc_html__( 'Build Smart with AI', 'elementor' ),
657 'link' => 'https://go.elementor.com/overview-widget-ai/',
658 ];
659 $additions_actions['go-pro'] = [
660 'title' => esc_html__( 'Upgrade', 'elementor' ),
661 'link' => 'https://go.elementor.com/go-pro-wp-overview-widget/',
662 ];
663
664 /**
665 * Dashboard widget footer actions.
666 *
667 * Filters the additions actions displayed in Elementor dashboard widget.
668 *
669 * Developers can add new action links to Elementor dashboard widget
670 * footer using this filter.
671 *
672 * @since 1.9.0
673 *
674 * @param array $additions_actions Elementor dashboard widget footer actions.
675 */
676 $additions_actions = apply_filters( 'elementor/admin/dashboard_overview_widget/footer_actions', $additions_actions );
677
678 $actions = $base_actions + $additions_actions;
679
680 return $actions;
681 }
682
683 /**
684 * Get elementor dashboard overview widget footer actions.
685 *
686 * Retrieves the footer action links displayed in elementor dashboard widget.
687 *
688 * @since 1.9.0
689 * @access private
690 */
691 private function get_dashboard_overview_widget_footer_actions() {
692 return self::static_get_dashboard_overview_widget_footer_actions();
693 }
694
695 /**
696 * Admin action new post.
697 *
698 * When a new post action is fired the title is set to 'Elementor' and the post ID.
699 *
700 * Fired by `admin_action_elementor_new_post` action.
701 *
702 * @since 1.9.0
703 * @access public
704 */
705 public function admin_action_new_post() {
706 check_admin_referer( 'elementor_action_new_post' );
707
708 $post_type = Utils::get_super_global_value( $_GET, 'post_type' ) ?? 'post';
709
710 if ( ! User::is_current_user_can_edit_post_type( $post_type ) ) {
711 return;
712 }
713
714 if ( empty( $_GET['template_type'] ) ) {
715 $type = 'post';
716 } else {
717 $type = sanitize_text_field( wp_unslash( $_GET['template_type'] ) );
718 }
719
720 $post_data = Utils::get_super_global_value( $_GET, 'post_data' ) ?? [];
721
722 $post_data = $this->filter_post_data( $post_data );
723
724 /**
725 * Create new post meta data.
726 *
727 * Filters the meta data of any new post created.
728 *
729 * @since 2.0.0
730 *
731 * @param array $meta Post meta data.
732 */
733 $meta = [];
734
735 if ( isset( $_GET['meta'] ) && is_array( $_GET['meta'] ) ) {
736 $meta = array_map( 'sanitize_text_field', wp_unslash( $_GET['meta'] ) );
737 }
738
739 $meta = apply_filters( 'elementor/admin/create_new_post/meta', $meta );
740
741 $post_data['post_type'] = $post_type;
742
743 $document = Plugin::$instance->documents->create( $type, $post_data, $meta );
744
745 if ( is_wp_error( $document ) ) {
746 wp_die( $document ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
747 }
748
749 wp_safe_redirect( $document->get_edit_url() );
750
751 die;
752 }
753
754 public function admin_action_site_settings_redirect() {
755 check_admin_referer( 'elementor_action_site_settings_redirect' );
756
757 if ( ! current_user_can( 'edit_theme_options' ) ) {
758 wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'elementor' ) );
759 }
760
761 $active_tab = filter_input( INPUT_GET, 'active-tab', FILTER_SANITIZE_ENCODED );
762
763 $site_settings_url_config = Page::get_site_settings_url_config( $active_tab );
764
765 if ( empty( $site_settings_url_config['url'] ) ) {
766 wp_die( esc_html__( 'Unable to create or access Site Settings page.', 'elementor' ) );
767 }
768
769 wp_safe_redirect( $site_settings_url_config['url'] );
770
771 die;
772 }
773
774 /**
775 * Admin action edit website.
776 *
777 * Redirects to the homepage edit URL if it exists and is built with Elementor,
778 * otherwise redirects to create a new page.
779 *
780 * Fired by `admin_action_elementor_edit_website` action.
781 *
782 * @since 3.x.x
783 * @access public
784 */
785 public function admin_action_edit_website_redirect() {
786 check_admin_referer( 'elementor_action_edit_website' );
787
788 if ( ! User::is_current_user_can_edit_post_type( 'page' ) ) {
789 wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'elementor' ) );
790 }
791
792 $homepage_id = $this->get_homepage_id();
793 $edit_url = $this->get_edit_website_url( $homepage_id );
794
795 wp_safe_redirect( $edit_url );
796
797 die;
798 }
799
800 private function get_homepage_id(): ?int {
801 if ( get_option( 'show_on_front' ) !== 'page' ) {
802 return null;
803 }
804
805 $homepage_id = get_option( 'page_on_front' );
806
807 return $homepage_id ? (int) $homepage_id : null;
808 }
809
810 private function get_edit_website_url( ?int $homepage_id ): string {
811 if ( ! $homepage_id ) {
812 return Plugin::$instance->documents->get_create_new_post_url( 'page' );
813 }
814
815 $document = Plugin::$instance->documents->get( $homepage_id );
816
817 if ( ! $document || ! $document->is_built_with_elementor() ) {
818 return Plugin::$instance->documents->get_create_new_post_url( 'page' );
819 }
820
821 return $document->get_edit_url();
822 }
823
824 private function get_allowed_fields_for_role() {
825 $allowed_fields = [
826 'post_title',
827 'post_content',
828 'post_excerpt',
829 'post_category',
830 'post_type',
831 'tags_input',
832 ];
833
834 if ( current_user_can( 'publish_posts' ) ) {
835 $allowed_fields[] = 'post_status';
836 }
837
838 if ( current_user_can( 'edit_others_posts' ) ) {
839 $allowed_fields[] = 'post_author';
840 }
841
842 return $allowed_fields;
843 }
844
845 private function filter_post_data( $post_data ) {
846 $allowed_fields = $this->get_allowed_fields_for_role();
847 return array_filter(
848 $post_data,
849 function( $key ) use ( $allowed_fields ) {
850 return in_array( $key, $allowed_fields, true );
851 },
852 ARRAY_FILTER_USE_KEY
853 );
854 }
855 /**
856 * @since 2.3.0
857 * @access public
858 */
859 public function add_new_template_template() {
860 Plugin::$instance->common->add_template( ELEMENTOR_PATH . 'includes/admin-templates/new-template.php' );
861 }
862
863 public function add_new_floating_elements_template() {
864 Plugin::$instance->common->add_template( ELEMENTOR_PATH . 'includes/admin-templates/new-floating-elements.php' );
865 }
866
867 public function enqueue_new_floating_elements_scripts() {
868 $suffix = Utils::is_script_debug() ? '' : '.min';
869
870 wp_enqueue_script(
871 'elementor-floating-elements-modal',
872 ELEMENTOR_ASSETS_URL . 'js/floating-elements-modal' . $suffix . '.js',
873 [],
874 ELEMENTOR_VERSION,
875 true
876 );
877
878 wp_set_script_translations( 'elementor-floating-elements-modal', 'elementor' );
879 }
880
881 /**
882 * @access public
883 */
884 public function enqueue_new_template_scripts() {
885 $suffix = Utils::is_script_debug() ? '' : '.min';
886
887 wp_enqueue_script(
888 'elementor-new-template',
889 ELEMENTOR_ASSETS_URL . 'js/new-template' . $suffix . '.js',
890 [],
891 ELEMENTOR_VERSION,
892 true
893 );
894
895 wp_set_script_translations( 'elementor-new-template', 'elementor' );
896 }
897
898 /**
899 * @since 2.6.0
900 * @access public
901 */
902 public function add_beta_tester_template() {
903 Plugin::$instance->common->add_template( ELEMENTOR_PATH . 'includes/admin-templates/beta-tester.php' );
904 }
905
906 /**
907 * @access public
908 */
909 public function enqueue_beta_tester_scripts() {
910 $suffix = Utils::is_script_debug() ? '' : '.min';
911
912 wp_enqueue_script(
913 'elementor-beta-tester',
914 ELEMENTOR_ASSETS_URL . 'js/beta-tester' . $suffix . '.js',
915 [],
916 ELEMENTOR_VERSION,
917 true
918 );
919
920 wp_set_script_translations( 'elementor-beta-tester', 'elementor' );
921 }
922
923 public function init_floating_elements() {
924 $screens = [
925 'elementor_library_page_e-floating-buttons' => true,
926 'edit-e-floating-buttons' => true,
927 ];
928
929 if ( ! isset( $screens[ get_current_screen()->id ] ) ) {
930 return;
931 }
932
933 add_action( 'admin_head', [ $this, 'add_new_floating_elements_template' ] );
934 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_new_floating_elements_scripts' ] );
935 }
936
937 /**
938 * @access public
939 */
940 public function init_new_template() {
941 if ( 'edit-elementor_library' !== get_current_screen()->id ) {
942 return;
943 }
944
945 // Allow plugins to add their templates on admin_head.
946 add_action( 'admin_head', [ $this, 'add_new_template_template' ] );
947 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_new_template_scripts' ] );
948 }
949
950 public function version_update_warning( $current_version, $new_version ) {
951 $current_version_minor_part = explode( '.', $current_version )[1];
952 $new_version_minor_part = explode( '.', $new_version )[1];
953
954 if ( $current_version_minor_part === $new_version_minor_part ) {
955 return;
956 }
957 ?>
958 <hr class="e-major-update-warning__separator" />
959 <div class="e-major-update-warning">
960 <div class="e-major-update-warning__icon">
961 <i class="eicon-info-circle"></i>
962 </div>
963 <div>
964 <div class="e-major-update-warning__title">
965 <?php echo esc_html__( 'Heads up, Please backup before upgrade!', 'elementor' ); ?>
966 </div>
967 <div class="e-major-update-warning__message">
968 <?php
969 printf(
970 /* translators: %1$s Link open tag, %2$s: Link close tag. */
971 esc_html__( 'The latest update includes some substantial changes across different areas of the plugin. We highly recommend you %1$sbackup your site before upgrading%2$s, and make sure you first update in a staging environment', 'elementor' ),
972 '<a href="https://go.elementor.com/wp-dash-update-backup/">',
973 '</a>'
974 );
975 ?>
976 </div>
977 </div>
978 </div>
979 <?php
980 }
981
982 /**
983 * @access public
984 */
985 public function init_beta_tester( $current_screen ) {
986 if ( ( 'toplevel_page_elementor' === $current_screen->base ) || 'elementor_page_elementor-tools' === $current_screen->id ) {
987 add_action( 'admin_head', [ $this, 'add_beta_tester_template' ] );
988 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_beta_tester_scripts' ] );
989 }
990 }
991
992 /**
993 * Admin constructor.
994 *
995 * Initializing Elementor in WordPress admin.
996 *
997 * @since 1.0.0
998 * @access public
999 */
1000 public function __construct() {
1001 Plugin::$instance->init_common();
1002
1003 $this->add_component( 'feedback', new Feedback() );
1004 $this->add_component( 'admin-notices', new Admin_Notices() );
1005
1006 add_action( 'admin_init', [ $this, 'maybe_redirect_to_getting_started' ] );
1007
1008 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
1009 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_styles' ] );
1010
1011 add_action( 'edit_form_after_title', [ $this, 'print_switch_mode_button' ] );
1012 add_action( 'save_post', [ $this, 'save_post' ] );
1013
1014 add_filter( 'display_post_states', [ $this, 'add_elementor_post_state' ], 10, 2 );
1015
1016 add_filter( 'plugin_action_links_' . ELEMENTOR_PLUGIN_BASE, [ $this, 'plugin_action_links' ] );
1017 add_filter( 'plugin_row_meta', [ $this, 'plugin_row_meta' ], 10, 2 );
1018
1019 add_filter( 'admin_body_class', [ $this, 'body_status_classes' ] );
1020 add_filter( 'admin_footer_text', [ $this, 'admin_footer_text' ] );
1021
1022 // Register Dashboard Widgets.
1023 add_action( 'wp_dashboard_setup', [ $this, 'register_dashboard_widgets' ] );
1024
1025 // Admin Actions
1026 add_action( 'admin_action_elementor_new_post', [ $this, 'admin_action_new_post' ] );
1027 add_action( 'admin_action_elementor_site_settings_redirect', [ $this, 'admin_action_site_settings_redirect' ] );
1028 add_action( 'admin_action_elementor_edit_website_redirect', [ $this, 'admin_action_edit_website_redirect' ] );
1029
1030 add_action( 'current_screen', [ $this, 'init_new_template' ] );
1031 add_action( 'current_screen', [ $this, 'init_floating_elements' ] );
1032 add_action( 'current_screen', [ $this, 'init_beta_tester' ] );
1033
1034 add_action( 'in_plugin_update_message-' . ELEMENTOR_PLUGIN_BASE, function( $plugin_data ) {
1035 $this->version_update_warning( ELEMENTOR_VERSION, $plugin_data['new_version'] );
1036 } );
1037
1038 add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_hints' ] );
1039 }
1040
1041 /**
1042 * @since 2.3.0
1043 * @access protected
1044 */
1045 protected function get_init_settings() {
1046 $beta_tester_email = get_user_meta( get_current_user_id(), User::BETA_TESTER_META_KEY, true );
1047 $elementor_beta = get_option( 'elementor_beta', 'no' );
1048 $all_introductions = User::get_introduction_meta();
1049 $beta_tester_signup_dismissed = array_key_exists( Beta_Testers::BETA_TESTER_SIGNUP, $all_introductions );
1050
1051 $settings = [
1052 'home_url' => home_url(),
1053 'settings_url' => Settings::get_url(),
1054 'user' => [
1055 'introduction' => User::get_introduction_meta(),
1056 'restrictions' => Plugin::$instance->role_manager->get_user_restrictions_array(),
1057 'is_administrator' => current_user_can( 'manage_options' ),
1058 ],
1059 'beta_tester' => [
1060 'beta_tester_signup' => Beta_Testers::BETA_TESTER_SIGNUP,
1061 'has_email' => $beta_tester_email,
1062 'option_enabled' => 'no' !== $elementor_beta,
1063 'signup_dismissed' => $beta_tester_signup_dismissed,
1064 ],
1065 'experiments' => $this->get_experiments(),
1066 ];
1067
1068 /**
1069 * Localize settings.
1070 *
1071 * Filters the initial localize settings in the admin.
1072 *
1073 * WordPress has it's own way to pass localized data from PHP (backend) to
1074 * JS (frontend). Elementor uses this method to pass localize data in the
1075 * admin. This hook can be used to add more localized settings in addition
1076 * to the initial Elementor settings.
1077 *
1078 * @since 2.3.0
1079 *
1080 * @param array $settings Initial localize settings.
1081 */
1082 $settings = apply_filters( 'elementor/admin/localize_settings', $settings );
1083
1084 return $settings;
1085 }
1086
1087 private function get_experiments() {
1088 return ( new Collection( Plugin::$instance->experiments->get_features() ) )
1089 ->map( function ( $experiment_data ) {
1090 $dependencies = $experiment_data['dependencies'] ?? [];
1091
1092 $dependencies = ( new Collection( $dependencies ) )
1093 ->map( function ( $dependency ) {
1094 return $dependency->get_name();
1095 } )->all();
1096
1097 return [
1098 'name' => $experiment_data['name'],
1099 'title' => $experiment_data['title'] ?? $experiment_data['name'],
1100 'state' => $experiment_data['state'],
1101 'default' => $experiment_data['default'],
1102 'dependencies' => $dependencies,
1103 'messages' => $experiment_data['messages'] ?? [],
1104 ];
1105 } )->all();
1106 }
1107
1108 private function maybe_enqueue_hints() {
1109 $plugin_slug = 'image-optimization';
1110
1111 if ( ! Hints::should_display_hint( $plugin_slug ) ) {
1112 return;
1113 }
1114
1115 wp_register_script(
1116 'media-hints',
1117 $this->get_js_assets_url( 'media-hints' ),
1118 [],
1119 ELEMENTOR_VERSION,
1120 true
1121 );
1122
1123 $one_subscription = Hints::is_plugin_connected_to_one_subscription();
1124 $is_installed = Hints::is_plugin_installed( $plugin_slug );
1125 $is_active = Hints::is_plugin_active( $plugin_slug );
1126
1127 if ( $is_active ) {
1128 return;
1129 }
1130
1131 if ( $one_subscription ) {
1132 if ( ! $is_installed ) {
1133 $description = esc_html__( 'Automatically optimize images to improve site speed and performance. Included with your ONE subscription.', 'elementor' );
1134 $button_text = esc_html__( 'Install now', 'elementor' );
1135 $button_url = Hints::get_plugin_install_url( $plugin_slug );
1136 } elseif ( ! $is_active ) {
1137 $description = esc_html__( 'Image Optimization is installed and included in your ONE subscription. Activate it to optimize images and improve site performance.', 'elementor' );
1138 $button_text = esc_html__( 'Activate now', 'elementor' );
1139 $button_url = Hints::get_plugin_activate_url( $plugin_slug );
1140 }
1141 } else {
1142 $description = esc_html__( 'Optimize your images to enhance site performance by using Image Optimization.', 'elementor' );
1143 if ( ! $is_installed ) {
1144 $button_text = esc_html__( 'Install now', 'elementor' );
1145 $button_url = Hints::get_plugin_install_url( $plugin_slug );
1146 } elseif ( ! $is_active ) {
1147 $button_text = esc_html__( 'Activate now', 'elementor' );
1148 $button_url = Hints::get_plugin_activate_url( $plugin_slug );
1149 }
1150 }
1151
1152 $dismissible = 'image_optimizer_hint';
1153
1154 $title = esc_html__( 'Speed up your website with Image Optimization', 'elementor' );
1155 $content = sprintf(
1156 "<strong>%1\$s</strong><br>%2\$s <a class='e-btn-1' href='%3\$s' target='_blank'>%4\$s</a>!",
1157 $title,
1158 $description,
1159 $button_url,
1160 $button_text
1161 );
1162
1163 wp_localize_script( 'media-hints', 'elementorAdminHints', [
1164 'mediaHint' => [
1165 'display' => true,
1166 'type' => 'info',
1167 'content' => $content,
1168 'icon' => true,
1169 'dismissible' => $dismissible,
1170 'dismiss' => esc_attr__( 'Dismiss this notice.', 'elementor' ),
1171 'button_event' => $dismissible,
1172 'button_data' => base64_encode(
1173 wp_json_encode( [
1174 'action_url' => $button_url,
1175 ] ),
1176 ),
1177 ],
1178 ] );
1179
1180 wp_enqueue_script( 'media-hints' );
1181 }
1182
1183 public function register_ajax_hints( $ajax_manager ) {
1184 $ajax_manager->register_ajax_action( 'elementor_image_optimization_campaign', [ $this, 'ajax_set_image_optimization_campaign' ] );
1185 $ajax_manager->register_ajax_action( 'elementor_core_site_mailer_campaign', [ $this, 'ajax_site_mailer_campaign' ] );
1186 $ajax_manager->register_ajax_action( 'elementor_core_ally_campaign', [ $this, 'ajax_ally_campaign' ] );
1187 }
1188
1189 public function ajax_ally_campaign( $request ) {
1190 if ( ! current_user_can( 'install_plugins' ) ) {
1191 return;
1192 }
1193
1194 $campaign_data = [
1195 'campaign' => sanitize_key( $request['campaign'] ?? '' ),
1196 'source' => sanitize_key( $request['source'] ?? '' ),
1197 'medium' => sanitize_key( $request['medium'] ?? '' ),
1198 ];
1199
1200 set_transient( 'elementor_ea11y_campaign', $campaign_data, 30 * DAY_IN_SECONDS );
1201 }
1202
1203 public function ajax_set_image_optimization_campaign( $request ) {
1204 if ( ! current_user_can( 'install_plugins' ) ) {
1205 return;
1206 }
1207
1208 $campaign_data = [
1209 'campaign' => sanitize_key( $request['campaign'] ?? '' ),
1210 'source' => sanitize_key( $request['source'] ?? '' ),
1211 'medium' => sanitize_key( $request['medium'] ?? '' ),
1212 ];
1213
1214 set_transient( 'elementor_image_optimization_campaign', $campaign_data, 30 * DAY_IN_SECONDS );
1215 }
1216
1217 public function ajax_site_mailer_campaign( $request ) {
1218 if ( ! current_user_can( 'install_plugins' ) ) {
1219 return;
1220 }
1221
1222 $campaign_data = [
1223 'campaign' => sanitize_key( $request['campaign'] ?? '' ),
1224 'source' => sanitize_key( $request['source'] ?? '' ),
1225 'medium' => sanitize_key( $request['medium'] ?? '' ),
1226 ];
1227
1228 set_transient( 'elementor_site_mailer_campaign', $campaign_data, 30 * DAY_IN_SECONDS );
1229 }
1230 }
1231