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

618 lines 17.9 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_lazyload' ) &&
354 $experiments->is_feature_active( 'e_optimized_css_loading' ) &&
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_design_not_appearing() {
385 $installs_history = get_option( 'elementor_install_history', [] );
386 $is_first_install = 1 === count( $installs_history );
387
388 if ( $is_first_install || ! current_user_can( 'update_plugins' ) ) {
389 return false;
390 }
391
392 $notice_id = 'design_not_appearing';
393 $notice = User::get_user_notices()[ $notice_id ] ?? [];
394 $notice_version = $notice['meta']['version'] ?? null;
395 $is_version_changed = $this->get_elementor_version() !== $notice_version;
396
397 if ( $is_version_changed ) {
398 User::set_user_notice( $notice_id, false, [ 'version' => $this->get_elementor_version() ] );
399 }
400
401 if ( ! in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library', 'elementor_page_elementor-system-info', 'dashboard', 'update-core', 'plugins' ], true ) ) {
402 return false;
403 }
404
405 if ( User::is_user_notice_viewed( $notice_id ) ) {
406 return false;
407 }
408
409 $options = [
410 'title' => esc_html__( 'The version was updated successfully!', 'elementor' ),
411 'description' => sprintf(
412 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' ),
413 '<a href="https://go.elementor.com/wp-dash-changes-do-not-appear-online/" target="_blank">',
414 '</a>'
415 ),
416 'id' => $notice_id,
417 ];
418
419 $excluded_pages = [];
420 $this->print_admin_notice( $options, $excluded_pages );
421
422 return true;
423 }
424
425 // For testing purposes
426 public function get_elementor_version() {
427 return ELEMENTOR_VERSION;
428 }
429
430 private function notice_plugin_image_optimization() {
431 $notice_id = 'plugin_image_optimization';
432
433 if ( 'upload' !== $this->current_screen_id ) {
434 return false;
435 }
436
437 if ( ! current_user_can( 'manage_options' ) || User::is_user_notice_viewed( $notice_id ) ) {
438 return false;
439 }
440
441 $attachments = new \WP_Query( [
442 'post_type' => 'attachment',
443 'post_status' => 'any',
444 'fields' => 'ids',
445 ] );
446
447 if ( 1 > $attachments->found_posts ) {
448 return false;
449 }
450
451 $plugin_file_path = 'image-optimization/image-optimization.php';
452 $plugin_slug = 'image-optimization';
453
454 if ( is_plugin_active( $plugin_file_path ) ) {
455 return false;
456 }
457
458 if ( $this->is_plugin_installed( $plugin_file_path ) ) {
459 $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 );
460 $cta_text = esc_html__( 'Activate Plugin', 'elementor' );
461 } else {
462 $url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $plugin_slug ), 'install-plugin_' . $plugin_slug );
463 $cta_text = esc_html__( 'Install Plugin', 'elementor' );
464 }
465
466 $options = [
467 'title' => esc_html__( 'Speed up your website with Image Optimizer by Elementor', 'elementor' ),
468 'description' => esc_html__( 'Automatically compress and optimize images, resize larger files, or convert to WebP. Optimize images individually, in bulk, or on upload.', 'elementor' ),
469 'id' => $notice_id,
470 'type' => 'cta',
471 'button_secondary' => [
472 'text' => $cta_text,
473 'url' => $url,
474 'type' => 'cta',
475 ],
476 ];
477
478 $this->print_admin_notice( $options );
479
480 return true;
481 }
482
483 private function is_plugin_installed( $file_path ): bool {
484 $installed_plugins = get_plugins();
485
486 return isset( $installed_plugins[ $file_path ] );
487 }
488
489 public function print_admin_notice( array $options, $exclude_pages = self::DEFAULT_EXCLUDED_PAGES ) {
490 global $pagenow;
491
492 if ( in_array( $pagenow, $exclude_pages, true ) ) {
493 return;
494 }
495
496 $default_options = [
497 'id' => null,
498 'title' => '',
499 'description' => '',
500 'classes' => [ 'notice', 'e-notice' ], // We include WP's default notice class so it will be properly handled by WP's js handler
501 'type' => '',
502 'dismissible' => true,
503 'icon' => 'eicon-elementor',
504 'button' => [],
505 'button_secondary' => [],
506 ];
507
508 $options = array_replace_recursive( $default_options, $options );
509
510 $notice_classes = $options['classes'];
511 $dismiss_button = '';
512 $icon = '';
513
514 if ( $options['type'] ) {
515 $notice_classes[] = 'e-notice--' . $options['type'];
516 }
517
518 if ( $options['dismissible'] ) {
519 $label = esc_html__( 'Dismiss this notice.', 'elementor' );
520 $notice_classes[] = 'e-notice--dismissible';
521 $dismiss_button = '<i class="e-notice__dismiss" role="button" aria-label="' . $label . '" tabindex="0"></i>';
522 }
523
524 if ( $options['icon'] ) {
525 $notice_classes[] = 'e-notice--extended';
526 $icon = '<div class="e-notice__icon-wrapper"><i class="' . esc_attr( $options['icon'] ) . '" aria-hidden="true"></i></div>';
527 }
528
529 $wrapper_attributes = [
530 'class' => $notice_classes,
531 ];
532
533 if ( $options['id'] ) {
534 $wrapper_attributes['data-notice_id'] = $options['id'];
535 }
536 ?>
537 <div <?php Utils::print_html_attributes( $wrapper_attributes ); ?>>
538 <?php echo $dismiss_button; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
539 <div class="e-notice__aside">
540 <?php echo $icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
541 </div>
542 <div class="e-notice__content">
543 <?php if ( $options['title'] ) { ?>
544 <h3><?php echo wp_kses_post( $options['title'] ); ?></h3>
545 <?php } ?>
546
547 <?php if ( $options['description'] ) { ?>
548 <p><?php echo wp_kses_post( $options['description'] ); ?></p>
549 <?php } ?>
550
551 <?php if ( ! empty( $options['button']['text'] ) || ! empty( $options['button_secondary']['text'] ) ) { ?>
552 <div class="e-notice__actions">
553 <?php
554 foreach ( [ $options['button'], $options['button_secondary'] ] as $index => $button_settings ) {
555 if ( empty( $button_settings['variant'] ) && $index ) {
556 $button_settings['variant'] = 'outline';
557 }
558
559 if ( empty( $button_settings['text'] ) ) {
560 continue;
561 }
562
563 $button = new Button( $button_settings );
564 $button->print_button();
565 } ?>
566 </div>
567 <?php } ?>
568 </div>
569 </div>
570 <?php }
571
572 public function admin_notices() {
573 $this->install_time = Plugin::$instance->get_install_time();
574 $this->current_screen_id = get_current_screen()->id;
575
576 foreach ( $this->plain_notices as $notice ) {
577 $method_callback = "notice_{$notice}";
578 if ( $this->$method_callback() ) {
579 return;
580 }
581 }
582
583 /** @var Base_Notice $notice_instance */
584 foreach ( $this->get_notices() as $notice_instance ) {
585 if ( ! $notice_instance->should_print() ) {
586 continue;
587 }
588
589 $this->print_admin_notice( $notice_instance->get_config() );
590
591 // It exits the method to make sure it prints only one notice.
592 return;
593 }
594 }
595
596 /**
597 * @since 2.9.0
598 * @access public
599 */
600 public function __construct() {
601 add_action( 'admin_notices', [ $this, 'admin_notices' ], 20 );
602 }
603
604 /**
605 * Get module name.
606 *
607 * Retrieve the module name.
608 *
609 * @since 2.9.0
610 * @access public
611 *
612 * @return string Module name.
613 */
614 public function get_name() {
615 return 'admin-notices';
616 }
617 }
618