PluginProbe
Elementor Website Builder – more than just a page builder / 3.25.2
Elementor Website Builder – more than just a page builder v3.25.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-notices.php

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

688 lines 19.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\Core\Admin\UI\Components\Button;
6 use Elementor\Core\Base\Module;
7 use Elementor\Core\Utils\Promotions\Filtered_Promotions_Manager;
8 use Elementor\Plugin;
9 use Elementor\Settings;
10 use Elementor\Tracker;
11 use Elementor\User;
12 use Elementor\Utils;
13 use Elementor\Core\Admin\Notices\Base_Notice;
14 use Elementor\Core\Admin\Notices\Elementor_Dev_Notice;
15
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit; // Exit if accessed directly.
18 }
19
20 class Admin_Notices extends Module {
21
22 const DEFAULT_EXCLUDED_PAGES = [ 'plugins.php', 'plugin-install.php', 'plugin-editor.php' ];
23
24 private $plain_notices = [
25 'api_notice',
26 'api_upgrade_plugin',
27 'tracker',
28 'rate_us_feedback',
29 'role_manager_promote',
30 'experiment_promotion',
31 'site_mailer_promotion',
32 'design_not_appearing',
33 'plugin_image_optimization',
34 ];
35
36 private $elementor_pages_count = null;
37
38 private $install_time = null;
39
40 private $current_screen_id = null;
41
42 private function get_notices() {
43 $notices = [
44 new Elementor_Dev_Notice(),
45 ];
46
47 /**
48 * Admin notices.
49 *
50 * Filters Elementor admin notices.
51 *
52 * This hook can be used by external developers to manage existing
53 * admin notice or to add new notices for Elementor add-ons.
54 *
55 * @param array $notices A list of notice classes.
56 */
57 $notices = apply_filters( 'elementor/core/admin/notices', $notices );
58
59 return $notices;
60 }
61
62 private function get_install_time() {
63 if ( null === $this->install_time ) {
64 $this->install_time = Plugin::$instance->get_install_time();
65 }
66
67 return $this->install_time;
68 }
69
70 private function get_elementor_pages_count() {
71 if ( null === $this->elementor_pages_count ) {
72 $elementor_pages = new \WP_Query( [
73 'no_found_rows' => true,
74 'post_type' => 'any',
75 'post_status' => 'publish',
76 'fields' => 'ids',
77 'update_post_meta_cache' => false,
78 'update_post_term_cache' => false,
79 'meta_key' => '_elementor_edit_mode',
80 'meta_value' => 'builder',
81 ] );
82
83 $this->elementor_pages_count = $elementor_pages->post_count;
84 }
85
86 return $this->elementor_pages_count;
87 }
88
89 private function notice_api_upgrade_plugin() {
90 $upgrade_notice = Api::get_upgrade_notice();
91 if ( empty( $upgrade_notice ) ) {
92 return false;
93 }
94
95 if ( ! current_user_can( 'update_plugins' ) ) {
96 return false;
97 }
98
99 if ( ! in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library', 'elementor_page_elementor-system-info', 'dashboard' ], true ) ) {
100 return false;
101 }
102
103 // Check for upgrades.
104 $update_plugins = get_site_transient( 'update_plugins' );
105
106 $has_remote_update_package = ! ( empty( $update_plugins ) || empty( $update_plugins->response[ ELEMENTOR_PLUGIN_BASE ] ) || empty( $update_plugins->response[ ELEMENTOR_PLUGIN_BASE ]->package ) );
107
108 if ( ! $has_remote_update_package && empty( $upgrade_notice['update_link'] ) ) {
109 return false;
110 }
111
112 if ( $has_remote_update_package ) {
113 $product = $update_plugins->response[ ELEMENTOR_PLUGIN_BASE ];
114
115 $details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $product->slug . '&section=changelog&TB_iframe=true&width=600&height=800' );
116 $upgrade_url = wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' . ELEMENTOR_PLUGIN_BASE ), 'upgrade-plugin_' . ELEMENTOR_PLUGIN_BASE );
117 $new_version = $product->new_version;
118 } else {
119 $upgrade_url = $upgrade_notice['update_link'];
120 $details_url = $upgrade_url;
121
122 $new_version = $upgrade_notice['version'];
123 }
124
125 // Check if upgrade messages should be shown.
126 if ( version_compare( ELEMENTOR_VERSION, $upgrade_notice['version'], '>=' ) ) {
127 return false;
128 }
129
130 $notice_id = 'upgrade_notice_' . $upgrade_notice['version'];
131 if ( User::is_user_notice_viewed( $notice_id ) ) {
132 return false;
133 }
134
135 $message = sprintf(
136 /* translators: 1: Details URL, 2: Accessibility text, 3: Version number, 4: Update URL, 5: Accessibility text. */
137 __( 'There is a new version of Elementor Page Builder available. <a href="%1$s" class="thickbox open-plugin-details-modal" aria-label="%2$s">View version %3$s details</a> or <a href="%4$s" class="update-link" aria-label="%5$s">update now</a>.', 'elementor' ),
138 esc_url( $details_url ),
139 esc_attr( sprintf(
140 /* translators: %s: Elementor version. */
141 __( 'View Elementor version %s details', 'elementor' ),
142 $new_version
143 ) ),
144 $new_version,
145 esc_url( $upgrade_url ),
146 esc_attr( esc_html__( 'Update Now', 'elementor' ) )
147 );
148
149 $options = [
150 'title' => esc_html__( 'Update Notification', 'elementor' ),
151 'description' => $message,
152 'button' => [
153 'icon_classes' => 'dashicons dashicons-update',
154 'text' => esc_html__( 'Update Now', 'elementor' ),
155 'url' => $upgrade_url,
156 ],
157 'id' => $notice_id,
158 ];
159
160 $this->print_admin_notice( $options );
161
162 return true;
163 }
164
165 private function notice_api_notice() {
166 $admin_notice = Api::get_admin_notice();
167 if ( empty( $admin_notice ) ) {
168 return false;
169 }
170
171 if ( ! current_user_can( 'manage_options' ) ) {
172 return false;
173 }
174
175 if ( ! in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library', 'elementor_page_elementor-system-info', 'dashboard' ], true ) ) {
176 return false;
177 }
178
179 $notice_id = 'admin_notice_api_' . $admin_notice['notice_id'];
180 if ( User::is_user_notice_viewed( $notice_id ) ) {
181 return false;
182 }
183
184 $options = [
185 'title' => esc_html__( 'Update Notification', 'elementor' ),
186 'description' => $admin_notice['notice_text'],
187 'id' => $notice_id,
188 ];
189
190 $this->print_admin_notice( $options );
191
192 return true;
193 }
194
195 private function notice_tracker() {
196 if ( ! current_user_can( 'manage_options' ) ) {
197 return false;
198 }
199
200 // Show tracker notice after 24 hours from installed time.
201 if ( strtotime( '+24 hours', $this->get_install_time() ) > time() ) {
202 return false;
203 }
204
205 if ( '1' === get_option( 'elementor_tracker_notice' ) ) {
206 return false;
207 }
208
209 if ( Tracker::is_allow_track() ) {
210 return false;
211 }
212
213 if ( 2 > $this->get_elementor_pages_count() ) {
214 return false;
215 }
216
217 // TODO: Skip for development env.
218 $optin_url = wp_nonce_url( add_query_arg( 'elementor_tracker', 'opt_into' ), 'opt_into' );
219 $optout_url = wp_nonce_url( add_query_arg( 'elementor_tracker', 'opt_out' ), 'opt_out' );
220
221 $tracker_description_text = esc_html__( 'Become a super contributor by opting in to share non-sensitive plugin data and to receive periodic email updates from us.', 'elementor' );
222
223 /**
224 * Tracker admin description text.
225 *
226 * Filters the admin notice text for non-sensitive data collection.
227 *
228 * @since 1.0.0
229 *
230 * @param string $tracker_description_text Description text displayed in admin notice.
231 */
232 $tracker_description_text = apply_filters( 'elementor/tracker/admin_description_text', $tracker_description_text );
233
234 $message = esc_html( $tracker_description_text ) . ' <a href="https://go.elementor.com/usage-data-tracking/" target="_blank">' . esc_html__( 'Learn more.', 'elementor' ) . '</a>';
235
236 $options = [
237 'title' => esc_html__( 'Love using Elementor?', 'elementor' ),
238 'description' => $message,
239 'button' => [
240 'text' => esc_html__( 'Sure! I\'d love to help', 'elementor' ),
241 'url' => $optin_url,
242 'type' => 'cta',
243 ],
244 'button_secondary' => [
245 'text' => esc_html__( 'No thanks', 'elementor' ),
246 'url' => $optout_url,
247 'variant' => 'outline',
248 'type' => 'cta',
249 ],
250 ];
251
252 $this->print_admin_notice( $options );
253
254 return true;
255 }
256
257 private function notice_rate_us_feedback() {
258 $notice_id = 'rate_us_feedback';
259
260 if ( ! current_user_can( 'manage_options' ) ) {
261 return false;
262 }
263
264 if ( 'dashboard' !== $this->current_screen_id || User::is_user_notice_viewed( $notice_id ) ) {
265 return false;
266 }
267
268 if ( 10 >= $this->get_elementor_pages_count() ) {
269 return false;
270 }
271
272 $dismiss_url = add_query_arg( [
273 'action' => 'elementor_set_admin_notice_viewed',
274 'notice_id' => esc_attr( $notice_id ),
275 ], admin_url( 'admin-post.php' ) );
276
277 $options = [
278 'title' => esc_html__( 'Congrats!', 'elementor' ),
279 'description' => esc_html__( 'You created over 10 pages with Elementor. Great job! If you can spare a minute, please help us by leaving a five star review on WordPress.org.', 'elementor' ),
280 'id' => $notice_id,
281 'button' => [
282 'text' => esc_html__( 'Happy To Help', 'elementor' ),
283 'url' => 'https://go.elementor.com/admin-review/',
284 'new_tab' => true,
285 'type' => 'cta',
286 ],
287 'button_secondary' => [
288 'text' => esc_html__( 'Hide Notification', 'elementor' ),
289 'classes' => [ 'e-notice-dismiss' ],
290 'url' => esc_url_raw( $dismiss_url ),
291 'new_tab' => true,
292 'type' => 'cta',
293 ],
294 ];
295
296 $this->print_admin_notice( $options );
297
298 return true;
299 }
300
301 private function notice_role_manager_promote() {
302 $notice_id = 'role_manager_promote';
303
304 if ( Utils::has_pro() ) {
305 return false;
306 }
307
308 if ( ! current_user_can( 'manage_options' ) ) {
309 return false;
310 }
311
312 if ( 'elementor_page_elementor-role-manager' !== $this->current_screen_id || User::is_user_notice_viewed( $notice_id ) ) {
313 return false;
314 }
315
316 $users = new \WP_User_Query( [
317 'fields' => 'ID',
318 'number' => 10,
319 ] );
320
321 if ( 5 > $users->get_total() ) {
322 return false;
323 }
324
325 $options = [
326 'title' => esc_html__( 'Managing a multi-user site?', 'elementor' ),
327 'description' => esc_html__( 'With Elementor Pro, you can control user access and make sure no one messes up your design.', 'elementor' ),
328 'id' => $notice_id,
329
330 'button' => [
331 'text' => esc_html__( 'Learn More', 'elementor' ),
332 'url' => 'https://go.elementor.com/plugin-promotion-role-manager/',
333 'new_tab' => true,
334 'type' => 'cta',
335 ],
336 ];
337
338 $options = Filtered_Promotions_Manager::get_filtered_promotion_data( $options, 'core/admin/notice_role_manager_promote', 'button', 'url' );
339
340 $this->print_admin_notice( $options );
341
342 return true;
343 }
344
345 private function notice_experiment_promotion() {
346 $notice_id = 'experiment_promotion';
347
348 if ( ! current_user_can( 'manage_options' ) || User::is_user_notice_viewed( $notice_id ) ) {
349 return false;
350 }
351
352 $experiments = Plugin::$instance->experiments;
353 $is_all_performance_features_active = (
354 $experiments->is_feature_active( 'e_element_cache' ) &&
355 $experiments->is_feature_active( 'e_font_icon_svg' )
356 );
357
358 if ( $is_all_performance_features_active ) {
359 return false;
360 }
361
362 $options = [
363 'title' => esc_html__( 'Improve your site’s performance score.', 'elementor' ),
364 'description' => esc_html__( 'With our experimental speed boosting features you can go faster than ever before. Look for the Performance label on our Experiments page and activate those experiments to improve your site loading speed.', 'elementor' ),
365 'id' => $notice_id,
366 'button' => [
367 'text' => esc_html__( 'Try it out', 'elementor' ),
368 'url' => Settings::get_settings_tab_url( 'experiments' ),
369 'type' => 'cta',
370 ],
371 'button_secondary' => [
372 'text' => esc_html__( 'Learn more', 'elementor' ),
373 'url' => 'https://go.elementor.com/wp-dash-experiment-promotion/',
374 'new_tab' => true,
375 'type' => 'cta',
376 ],
377 ];
378
379 $this->print_admin_notice( $options );
380
381 return true;
382 }
383
384 private function notice_site_mailer_promotion() {
385 $notice_id = 'site_mailer_promotion';
386
387 if (
388 ! defined( 'WPFORMS_VERSION' )
389 && ! defined( 'WPCF7_VERSION' )
390 && ! defined( 'FLUENTFORM_VERSION' )
391 && ! class_exists( '\GFCommon' )
392 && ! class_exists( '\Ninja_Forms' )
393 && ! function_exists( 'load_formidable_forms' )
394 ) {
395 return false;
396 }
397
398 if ( ! $this->is_elementor_page() && ! in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library', 'dashboard' ], true ) ) {
399 return false;
400 }
401
402 if ( Utils::has_pro() || ! current_user_can( 'install_plugins' ) || User::is_user_notice_viewed( $notice_id ) ) {
403 return false;
404 }
405
406 $plugin_file_path = 'site-mailer/site-mailer.php';
407 $plugin_slug = 'site-mailer';
408
409 $cta_data = $this->get_plugin_cta_data( $plugin_slug, $plugin_file_path );
410 if ( empty( $cta_data ) ) {
411 return false;
412 }
413
414 $options = [
415 'title' => esc_html__( 'Ensure your form emails avoid the spam folder!', 'elementor' ),
416 'description' => esc_html__( 'Use Site Mailer for improved email deliverability, detailed email logs, and an easy setup.', 'elementor' ),
417 'id' => $notice_id,
418 'type' => 'cta',
419 'button' => [
420 'text' => $cta_data['text'],
421 'url' => $cta_data['url'],
422 'type' => 'cta',
423 ],
424 'button_secondary' => [
425 'text' => esc_html__( 'Learn more', 'elementor' ),
426 'url' => 'https://go.elementor.com/sm-core-form/',
427 'new_tab' => true,
428 'type' => 'cta',
429 ],
430 ];
431
432 $this->print_admin_notice( $options );
433
434 return true;
435 }
436
437 private function is_elementor_page(): bool {
438 return 0 === strpos( $this->current_screen_id, 'elementor_page' );
439 }
440
441 private function get_plugin_cta_data( $plugin_slug, $plugin_file_path ) {
442 if ( is_plugin_active( $plugin_file_path ) ) {
443 return false;
444 }
445
446 if ( $this->is_plugin_installed( $plugin_file_path ) ) {
447 $url = wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $plugin_file_path . '&amp;plugin_status=all&amp;paged=1&amp;s', 'activate-plugin_' . $plugin_file_path );
448 $cta_text = esc_html__( 'Activate Plugin', 'elementor' );
449 } else {
450 $url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $plugin_slug ), 'install-plugin_' . $plugin_slug );
451 $cta_text = esc_html__( 'Install Plugin', 'elementor' );
452 }
453
454 return [
455 'url' => $url,
456 'text' => $cta_text,
457 ];
458 }
459
460 private function notice_design_not_appearing() {
461 $installs_history = get_option( 'elementor_install_history', [] );
462 $is_first_install = 1 === count( $installs_history );
463
464 if ( $is_first_install || ! current_user_can( 'update_plugins' ) ) {
465 return false;
466 }
467
468 $notice_id = 'design_not_appearing';
469 $notice = User::get_user_notices()[ $notice_id ] ?? [];
470 $notice_version = $notice['meta']['version'] ?? null;
471 $is_version_changed = $this->get_elementor_version() !== $notice_version;
472
473 if ( $is_version_changed ) {
474 User::set_user_notice( $notice_id, false, [ 'version' => $this->get_elementor_version() ] );
475 }
476
477 if ( ! in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library', 'elementor_page_elementor-system-info', 'dashboard', 'update-core', 'plugins' ], true ) ) {
478 return false;
479 }
480
481 if ( User::is_user_notice_viewed( $notice_id ) ) {
482 return false;
483 }
484
485 $options = [
486 'title' => esc_html__( 'The version was updated successfully!', 'elementor' ),
487 'description' => sprintf(
488 esc_html__( 'Encountering issues after updating the version? Don’t worry - we’ve collected all the fixes for troubleshooting common issues. %1$sFind a solution%2$s', 'elementor' ),
489 '<a href="https://go.elementor.com/wp-dash-changes-do-not-appear-online/" target="_blank">',
490 '</a>'
491 ),
492 'id' => $notice_id,
493 ];
494
495 $excluded_pages = [];
496 $this->print_admin_notice( $options, $excluded_pages );
497
498 return true;
499 }
500
501 // For testing purposes
502 public function get_elementor_version() {
503 return ELEMENTOR_VERSION;
504 }
505
506 private function notice_plugin_image_optimization() {
507 $notice_id = 'plugin_image_optimization';
508
509 if ( 'upload' !== $this->current_screen_id ) {
510 return false;
511 }
512
513 if ( ! current_user_can( 'manage_options' ) || User::is_user_notice_viewed( $notice_id ) ) {
514 return false;
515 }
516
517 $attachments = new \WP_Query( [
518 'post_type' => 'attachment',
519 'post_status' => 'any',
520 'fields' => 'ids',
521 ] );
522
523 if ( 1 > $attachments->found_posts ) {
524 return false;
525 }
526
527 $plugin_file_path = 'image-optimization/image-optimization.php';
528 $plugin_slug = 'image-optimization';
529
530 $cta_data = $this->get_plugin_cta_data( $plugin_slug, $plugin_file_path );
531
532 if ( empty( $cta_data ) ) {
533 return false;
534 }
535
536 $options = [
537 'title' => esc_html__( 'Speed up your website with Image Optimizer by Elementor', 'elementor' ),
538 'description' => esc_html__( 'Automatically compress and optimize images, resize larger files, or convert to WebP. Optimize images individually, in bulk, or on upload.', 'elementor' ),
539 'id' => $notice_id,
540 'type' => 'cta',
541 'button_secondary' => [
542 'text' => $cta_data['text'],
543 'url' => $cta_data['url'],
544 'type' => 'cta',
545 ],
546 ];
547
548 $this->print_admin_notice( $options );
549
550 return true;
551 }
552
553 private function is_plugin_installed( $file_path ): bool {
554 $installed_plugins = get_plugins();
555
556 return isset( $installed_plugins[ $file_path ] );
557 }
558
559 public function print_admin_notice( array $options, $exclude_pages = self::DEFAULT_EXCLUDED_PAGES ) {
560 global $pagenow;
561
562 if ( in_array( $pagenow, $exclude_pages, true ) ) {
563 return;
564 }
565
566 $default_options = [
567 'id' => null,
568 'title' => '',
569 'description' => '',
570 'classes' => [ 'notice', 'e-notice' ], // We include WP's default notice class so it will be properly handled by WP's js handler
571 'type' => '',
572 'dismissible' => true,
573 'icon' => 'eicon-elementor',
574 'button' => [],
575 'button_secondary' => [],
576 ];
577
578 $options = array_replace_recursive( $default_options, $options );
579
580 $notice_classes = $options['classes'];
581 $dismiss_button = '';
582 $icon = '';
583
584 if ( $options['type'] ) {
585 $notice_classes[] = 'e-notice--' . $options['type'];
586 }
587
588 if ( $options['dismissible'] ) {
589 $label = esc_html__( 'Dismiss this notice.', 'elementor' );
590 $notice_classes[] = 'e-notice--dismissible';
591 $dismiss_button = '<i class="e-notice__dismiss" role="button" aria-label="' . $label . '" tabindex="0"></i>';
592 }
593
594 if ( $options['icon'] ) {
595 $notice_classes[] = 'e-notice--extended';
596 $icon = '<div class="e-notice__icon-wrapper"><i class="' . esc_attr( $options['icon'] ) . '" aria-hidden="true"></i></div>';
597 }
598
599 $wrapper_attributes = [
600 'class' => $notice_classes,
601 ];
602
603 if ( $options['id'] ) {
604 $wrapper_attributes['data-notice_id'] = $options['id'];
605 }
606 ?>
607 <div <?php Utils::print_html_attributes( $wrapper_attributes ); ?>>
608 <?php echo $dismiss_button; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
609 <div class="e-notice__aside">
610 <?php echo $icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
611 </div>
612 <div class="e-notice__content">
613 <?php if ( $options['title'] ) { ?>
614 <h3><?php echo wp_kses_post( $options['title'] ); ?></h3>
615 <?php } ?>
616
617 <?php if ( $options['description'] ) { ?>
618 <p><?php echo wp_kses_post( $options['description'] ); ?></p>
619 <?php } ?>
620
621 <?php if ( ! empty( $options['button']['text'] ) || ! empty( $options['button_secondary']['text'] ) ) { ?>
622 <div class="e-notice__actions">
623 <?php
624 foreach ( [ $options['button'], $options['button_secondary'] ] as $index => $button_settings ) {
625 if ( empty( $button_settings['variant'] ) && $index ) {
626 $button_settings['variant'] = 'outline';
627 }
628
629 if ( empty( $button_settings['text'] ) ) {
630 continue;
631 }
632
633 $button = new Button( $button_settings );
634 $button->print_button();
635 } ?>
636 </div>
637 <?php } ?>
638 </div>
639 </div>
640 <?php }
641
642 public function admin_notices() {
643 $this->install_time = Plugin::$instance->get_install_time();
644 $this->current_screen_id = get_current_screen()->id;
645
646 foreach ( $this->plain_notices as $notice ) {
647 $method_callback = "notice_{$notice}";
648 if ( $this->$method_callback() ) {
649 return;
650 }
651 }
652
653 /** @var Base_Notice $notice_instance */
654 foreach ( $this->get_notices() as $notice_instance ) {
655 if ( ! $notice_instance->should_print() ) {
656 continue;
657 }
658
659 $this->print_admin_notice( $notice_instance->get_config() );
660
661 // It exits the method to make sure it prints only one notice.
662 return;
663 }
664 }
665
666 /**
667 * @since 2.9.0
668 * @access public
669 */
670 public function __construct() {
671 add_action( 'admin_notices', [ $this, 'admin_notices' ], 20 );
672 }
673
674 /**
675 * Get module name.
676 *
677 * Retrieve the module name.
678 *
679 * @since 2.9.0
680 * @access public
681 *
682 * @return string Module name.
683 */
684 public function get_name() {
685 return 'admin-notices';
686 }
687 }
688