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

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