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

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