PluginProbe
Elementor Website Builder – more than just a page builder / 3.34.1
Elementor Website Builder – more than just a page builder v3.34.1
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 3.34.1, at core/admin/admin.php

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