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

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