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

957 lines 27.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
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 const LOCAL_GOOGLE_FONTS_DISABLED_NOTICE_ID = 'local_google_fonts_disabled';
23
24 private $plain_notices = [
25 'api_notice',
26 'api_upgrade_plugin',
27 'tracker',
28 'tracker_last_update',
29 'rate_us_feedback',
30 'role_manager_promote',
31 'experiment_promotion',
32 'send_app_promotion',
33 'site_mailer_promotion',
34 'plugin_image_optimization',
35 'ally_pages_promotion',
36 self::LOCAL_GOOGLE_FONTS_DISABLED_NOTICE_ID,
37 ];
38
39 private $elementor_pages_count = null;
40
41 private $install_time = null;
42
43 private $current_screen_id = null;
44
45 private function get_notices() {
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', [] );
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 ( ! $this->is_elementor_admin_screen_with_system_info() ) {
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 ( ! $this->is_elementor_admin_screen_with_system_info() ) {
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 helping us understand how you use our service to enhance your experience and improve our product.', '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__( 'Want to shape the future of web creation?', 'elementor' ),
237 'description' => $message,
238 'dismissible' => false,
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_tracker_last_update() {
258 if ( ! current_user_can( 'manage_options' ) ) {
259 return false;
260 }
261
262 if ( ! Tracker::has_terms_changed() ) {
263 return false;
264 }
265
266 $notice_id = 'tracker_last_update_' . Tracker::LAST_TERMS_UPDATED;
267
268 if ( User::is_user_notice_viewed( $notice_id ) ) {
269 return false;
270 }
271
272 $optin_url = wp_nonce_url( add_query_arg( 'elementor_tracker', 'opt_into' ), 'opt_into' );
273
274 $message = esc_html__( 'We\'re updating our Terms and Conditions to include the collection of usage and behavioral data. This information helps us understand how you use Elementor so we can make informed improvements to the product.', 'elementor' );
275
276 $options = [
277 'id' => $notice_id,
278 'title' => esc_html__( 'Update regarding usage data collection', 'elementor' ),
279 'description' => $message,
280 'button' => [
281 'text' => esc_html__( 'Opt in', 'elementor' ),
282 'url' => $optin_url,
283 'type' => 'cta',
284 ],
285 'button_secondary' => [
286 'text' => esc_html__( 'Learn more', 'elementor' ),
287 'url' => 'https://go.elementor.com/wp-dash-update-usage-notice/',
288 'new_tab' => true,
289 'type' => 'cta',
290 ],
291 ];
292
293 $this->print_admin_notice( $options );
294
295 return true;
296 }
297
298 private function notice_rate_us_feedback() {
299 $notice_id = 'rate_us_feedback';
300
301 if ( ! current_user_can( 'manage_options' ) ) {
302 return false;
303 }
304
305 if ( 'dashboard' !== $this->current_screen_id || User::is_user_notice_viewed( $notice_id ) ) {
306 return false;
307 }
308
309 if ( 10 >= $this->get_elementor_pages_count() ) {
310 return false;
311 }
312
313 $dismiss_url = add_query_arg( [
314 'action' => 'elementor_set_admin_notice_viewed',
315 'notice_id' => esc_attr( $notice_id ),
316 '_wpnonce' => wp_create_nonce( 'elementor_set_admin_notice_viewed' ),
317 ], admin_url( 'admin-post.php' ) );
318
319 $options = [
320 'title' => esc_html__( 'Congrats!', 'elementor' ),
321 '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' ),
322 'id' => $notice_id,
323 'button' => [
324 'text' => esc_html__( 'Happy To Help', 'elementor' ),
325 'url' => 'https://go.elementor.com/admin-review/',
326 'new_tab' => true,
327 'type' => 'cta',
328 ],
329 'button_secondary' => [
330 'text' => esc_html__( 'Hide Notification', 'elementor' ),
331 'classes' => [ 'e-notice-dismiss' ],
332 'url' => esc_url_raw( $dismiss_url ),
333 'new_tab' => true,
334 'type' => 'cta',
335 ],
336 ];
337
338 $this->print_admin_notice( $options );
339
340 return true;
341 }
342
343 private function notice_role_manager_promote() {
344 $notice_id = 'role_manager_promote';
345
346 if ( Utils::has_pro() ) {
347 return false;
348 }
349
350 if ( ! current_user_can( 'manage_options' ) ) {
351 return false;
352 }
353
354 if ( 'elementor_page_elementor-role-manager' !== $this->current_screen_id || User::is_user_notice_viewed( $notice_id ) ) {
355 return false;
356 }
357
358 $users = new \WP_User_Query( [
359 'fields' => 'ID',
360 'number' => 10,
361 ] );
362
363 if ( 5 > $users->get_total() ) {
364 return false;
365 }
366
367 $options = [
368 'title' => esc_html__( 'Managing a multi-user site?', 'elementor' ),
369 'description' => esc_html__( 'With Elementor Pro, you can control user access and make sure no one messes up your design.', 'elementor' ),
370 'id' => $notice_id,
371
372 'button' => [
373 'text' => esc_html__( 'Learn More', 'elementor' ),
374 'url' => 'https://go.elementor.com/plugin-promotion-role-manager/',
375 'new_tab' => true,
376 'type' => 'cta',
377 ],
378 ];
379
380 $options = Filtered_Promotions_Manager::get_filtered_promotion_data( $options, 'core/admin/notice_role_manager_promote', 'button', 'url' );
381
382 $this->print_admin_notice( $options );
383
384 return true;
385 }
386
387 private function notice_experiment_promotion() {
388 $notice_id = 'experiment_promotion';
389
390 if ( ! current_user_can( 'manage_options' ) || User::is_user_notice_viewed( $notice_id ) ) {
391 return false;
392 }
393
394 $experiments = Plugin::$instance->experiments;
395 $is_all_performance_features_active = (
396 $experiments->is_feature_active( 'e_font_icon_svg' ) &&
397 $experiments->is_feature_active( 'e_optimized_markup' )
398 );
399
400 if ( $is_all_performance_features_active ) {
401 return false;
402 }
403
404 $options = [
405 'title' => esc_html__( 'Improve your site’s performance score.', 'elementor' ),
406 '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' ),
407 'id' => $notice_id,
408 'button' => [
409 'text' => esc_html__( 'Try it out', 'elementor' ),
410 'url' => Settings::get_settings_tab_url( 'experiments' ),
411 'type' => 'cta',
412 ],
413 'button_secondary' => [
414 'text' => esc_html__( 'Learn more', 'elementor' ),
415 'url' => 'https://go.elementor.com/wp-dash-experiment-promotion/',
416 'new_tab' => true,
417 'type' => 'cta',
418 ],
419 ];
420
421 $this->print_admin_notice( $options );
422
423 return true;
424 }
425
426 private function site_has_forms_plugins() {
427 return defined( 'WPFORMS_VERSION' ) || defined( 'WPCF7_VERSION' ) || defined( 'FLUENTFORM_VERSION' ) || class_exists( '\GFCommon' ) || class_exists( '\Ninja_Forms' ) || function_exists( 'load_formidable_forms' ) || did_action( 'metform/after_load' ) || defined( 'FORMINATOR_PLUGIN_BASENAME' );
428 }
429
430 private function site_has_woocommerce() {
431 return class_exists( 'WooCommerce' );
432 }
433
434 private function get_installed_form_plugin_name() {
435 static $detected_form_plugin = null;
436
437 if ( null !== $detected_form_plugin ) {
438 return $detected_form_plugin;
439 }
440
441 $form_plugins_constants_to_name_mapper = [
442 'WPFORMS_VERSION' => 'WPForms',
443 'WPCF7_VERSION' => 'Contact Form 7',
444 ];
445
446 foreach ( $form_plugins_constants_to_name_mapper as $constant => $name ) {
447 if ( defined( $constant ) ) {
448 $detected_form_plugin = $name;
449 return $detected_form_plugin;
450 }
451 }
452
453 $form_plugins_classes_to_name_mapper = [
454 '\GFCommon' => 'Gravity Forms',
455 '\Ninja_Forms' => 'Ninja Forms',
456 ];
457
458 foreach ( $form_plugins_classes_to_name_mapper as $class => $name ) {
459 if ( class_exists( $class ) ) {
460 $detected_form_plugin = $name;
461 return $detected_form_plugin;
462 }
463 }
464
465 $detected_form_plugin = false;
466 return $detected_form_plugin;
467 }
468
469 private function notice_send_app_promotion() {
470 $notice_id = 'send_app_promotion';
471
472 if ( ! $this->is_elementor_page() && ! $this->is_elementor_admin_screen() ) {
473 return false;
474 }
475
476 if ( time() < $this->get_install_time() + ( 60 * DAY_IN_SECONDS ) ) {
477 return false;
478 }
479
480 if ( ! current_user_can( 'install_plugins' ) || User::is_user_notice_viewed( $notice_id ) ) {
481 return false;
482 }
483
484 $plugin_file_path = 'send/send-app.php';
485 $plugin_slug = 'send-app';
486
487 $cta_data = $this->get_plugin_cta_data( $plugin_slug, $plugin_file_path );
488 if ( empty( $cta_data ) ) {
489 return false;
490 }
491
492 $title = sprintf( esc_html__( 'Turn leads into loyal shoppers', 'elementor' ) );
493
494 $options = [
495 'title' => $title,
496 'description' => esc_html__( 'Collecting leads is just the beginning. With Send by Elementor, you can manage contacts, launch automations, and turn form submissions into sales.', 'elementor' ),
497 'id' => $notice_id,
498 'type' => 'cta',
499 'button' => [
500 'text' => $cta_data['text'],
501 'url' => $cta_data['url'],
502 'type' => 'cta',
503 ],
504 'button_secondary' => [
505 'text' => esc_html__( 'Learn more', 'elementor' ),
506 'url' => 'https://go.elementor.com/Formslearnmore',
507 'new_tab' => true,
508 'type' => 'cta',
509 ],
510 ];
511
512 $this->print_admin_notice( $options );
513
514 return true;
515 }
516
517 private function notice_local_google_fonts_disabled() {
518
519 if ( ! $this->is_elementor_page() && ! $this->is_elementor_admin_screen() ) {
520 return false;
521 }
522
523 if ( User::is_user_notice_viewed( self::LOCAL_GOOGLE_FONTS_DISABLED_NOTICE_ID ) ) {
524 return false;
525 }
526
527 $is_local_gf_enabled = (bool) get_option( 'elementor_local_google_fonts', '0' );
528
529 if ( $is_local_gf_enabled ) {
530 return false;
531 }
532
533 $options = [
534 'title' => esc_html__( 'Important: Local Google Fonts Settings in Elementor', 'elementor' ),
535 'description' => esc_html__( 'Please note: The "Load Google Fonts Locally" feature has been disabled by default on all websites. To turn it back on, go to Elementor → Settings → Performance → Enable Load Google Fonts Locally.', 'elementor' ),
536 'id' => self::LOCAL_GOOGLE_FONTS_DISABLED_NOTICE_ID,
537 'type' => '',
538 'button' => [
539 'text' => esc_html__( 'Take me there', 'elementor' ),
540 'url' => '../wp-admin/admin.php?page=elementor-settings#tab-performance',
541 'new_tab' => false,
542 'type' => 'cta',
543 ],
544 'button_secondary' => [
545 'text' => esc_html__( 'Learn more', 'elementor' ),
546 'url' => 'https://go.elementor.com/wp-dash-google-fonts-locally-notice/',
547 'new_tab' => true,
548 'type' => 'cta',
549 ],
550 ];
551
552 $this->print_admin_notice( $options );
553
554 return true;
555 }
556
557 private function notice_ally_pages_promotion() {
558 global $pagenow;
559 $notice_id = 'ally_pages_promotion';
560
561 if ( 'edit.php' !== $pagenow || empty( $_GET['post_type'] ) || 'page' !== $_GET['post_type'] ) {
562 return false;
563 }
564
565 if ( ! current_user_can( 'manage_options' ) || User::is_user_notice_viewed( $notice_id ) ) {
566 return false;
567 }
568
569 $plugin_file_path = 'pojo-accessibility/pojo-accessibility.php';
570 $plugin_slug = 'pojo-accessibility';
571
572 $cta_data = $this->get_plugin_cta_data( $plugin_slug, $plugin_file_path );
573 if ( empty( $cta_data ) ) {
574 return false;
575 }
576
577 $options = [
578 'title' => esc_html__( 'Make sure your site has an accessibility statement page', 'elementor' ),
579 'description' => esc_html__( 'Create a more inclusive site experience for all your visitors. With Ally, it\'s easy to add your statement page in just a few clicks.', 'elementor' ),
580 'id' => $notice_id,
581 'type' => 'cta',
582 'button' => [
583 'text' => $cta_data['text'],
584 'url' => self::add_plg_campaign_data( $cta_data['url'], [
585 'name' => 'elementor_ea11y_campaign',
586 'campaign' => 'acc-statement-plg-pages',
587 'source' => 'wp-pages',
588 'medium' => 'wp-dash',
589 ] ),
590 'type' => 'cta',
591 ],
592 'button_secondary' => [
593 'text' => esc_html__( 'Learn more', 'elementor' ),
594 'url' => 'https://go.elementor.com/acc-plg-learn-more',
595 'new_tab' => true,
596 'type' => 'cta',
597 ],
598 ];
599
600 $this->print_admin_notice( $options );
601
602 return true;
603 }
604
605 private function notice_site_mailer_promotion() {
606 $notice_id = 'site_mailer_promotion';
607 $has_forms = $this->site_has_forms_plugins();
608 $has_woocommerce = $this->site_has_woocommerce();
609
610 if ( ! $has_forms && ! $has_woocommerce ) {
611 return false;
612 }
613
614 if ( ! $this->is_elementor_page() && ! $this->is_elementor_admin_screen() ) {
615 return false;
616 }
617
618 if ( ( Utils::has_pro() && ! $has_woocommerce ) || ! current_user_can( 'install_plugins' ) || User::is_user_notice_viewed( $notice_id ) ) {
619 return false;
620 }
621
622 $plugin_file_path = 'site-mailer/site-mailer.php';
623 $plugin_slug = 'site-mailer';
624
625 $cta_data = $this->get_plugin_cta_data( $plugin_slug, $plugin_file_path );
626 if ( empty( $cta_data ) ) {
627 return false;
628 }
629
630 $options = [
631 'title' => esc_html__( 'Ensure your form emails avoid the spam folder!', 'elementor' ),
632 'description' => esc_html__( 'Use Site Mailer for improved email deliverability, detailed email logs, and an easy setup.', 'elementor' ),
633 'id' => $notice_id,
634 'type' => 'cta',
635 'button' => [
636 'text' => $cta_data['text'],
637 'url' => $cta_data['url'],
638 'type' => 'cta',
639 ],
640 'button_secondary' => [
641 'text' => esc_html__( 'Learn more', 'elementor' ),
642 'url' => 'https://go.elementor.com/sm-core-form/',
643 'new_tab' => true,
644 'type' => 'cta',
645 ],
646 ];
647
648 if ( $this->should_render_woocommerce_hint( $has_forms, $has_woocommerce ) ) {
649 // We include WP's default notice class so it will be properly handled by WP's js handler
650 // And add a new one to distinguish between the two types of notices
651 $options['classes'] = [ 'notice', 'e-notice', 'sm-notice-wc' ];
652 $options['title'] = esc_html__( 'Improve Transactional Email Deliverability', 'elementor' );
653 $options['description'] = esc_html__( 'Use Elementor\'s Site Mailer to ensure your store emails like purchase confirmations, shipping updates and more are reliably delivered.', 'elementor' );
654 }
655
656 $this->print_admin_notice( $options );
657
658 return true;
659 }
660
661 private function should_render_woocommerce_hint( $has_forms, $has_woocommerce ): bool {
662 if ( ! $has_forms && ! $has_woocommerce ) {
663 return false;
664 }
665
666 if ( ! $has_forms && $has_woocommerce ) {
667 return true;
668 }
669
670 if ( $has_forms && $has_woocommerce && Utils::has_pro() ) {
671 return true;
672 }
673
674 if ( ! $has_woocommerce ) {
675 return false;
676 }
677
678 return (bool) wp_rand( 0, 1 );
679 }
680
681 private function is_elementor_page(): bool {
682 return 0 === strpos( $this->current_screen_id, 'elementor_page' );
683 }
684
685 private function is_elementor_admin_screen(): bool {
686 return in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library' ], true );
687 }
688
689 private function is_elementor_admin_screen_with_system_info(): bool {
690 return in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library', 'elementor_page_elementor-system-info', 'dashboard' ], true );
691 }
692
693 private function get_plugin_cta_data( $plugin_slug, $plugin_file_path ) {
694 if ( is_plugin_active( $plugin_file_path ) ) {
695 return false;
696 }
697
698 if ( $this->is_plugin_installed( $plugin_file_path ) ) {
699 $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 );
700 $cta_text = esc_html__( 'Activate Plugin', 'elementor' );
701 } else {
702 $url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $plugin_slug ), 'install-plugin_' . $plugin_slug );
703 $cta_text = esc_html__( 'Install Plugin', 'elementor' );
704 }
705
706 return [
707 'url' => $url,
708 'text' => $cta_text,
709 ];
710 }
711
712 /**
713 * For testing purposes
714 */
715 public function get_elementor_version() {
716 return ELEMENTOR_VERSION;
717 }
718
719 private function notice_plugin_image_optimization() {
720 $notice_id = 'plugin_image_optimization';
721
722 if ( 'upload' !== $this->current_screen_id ) {
723 return false;
724 }
725
726 if ( ! current_user_can( 'manage_options' ) || User::is_user_notice_viewed( $notice_id ) ) {
727 return false;
728 }
729
730 $attachments = new \WP_Query( [
731 'post_type' => 'attachment',
732 'post_status' => 'any',
733 'fields' => 'ids',
734 ] );
735
736 if ( 1 > $attachments->found_posts ) {
737 return false;
738 }
739
740 $plugin_file_path = 'image-optimization/image-optimization.php';
741 $plugin_slug = 'image-optimization';
742
743 $cta_data = $this->get_plugin_cta_data( $plugin_slug, $plugin_file_path );
744
745 if ( empty( $cta_data ) ) {
746 return false;
747 }
748
749 $options = [
750 'title' => esc_html__( 'Speed up your website with Image Optimizer by Elementor', 'elementor' ),
751 'description' => esc_html__( 'Automatically compress and optimize images, resize larger files, or convert to WebP. Optimize images individually, in bulk, or on upload.', 'elementor' ),
752 'id' => $notice_id,
753 'type' => 'cta',
754 'button_secondary' => [
755 'text' => $cta_data['text'],
756 'url' => $cta_data['url'],
757 'type' => 'cta',
758 ],
759 ];
760
761 $this->print_admin_notice( $options );
762
763 return true;
764 }
765
766 private function is_plugin_installed( $file_path ): bool {
767 $installed_plugins = get_plugins();
768
769 return isset( $installed_plugins[ $file_path ] );
770 }
771
772 public function print_admin_notice( array $options, $exclude_pages = self::DEFAULT_EXCLUDED_PAGES ) {
773 global $pagenow;
774
775 if ( in_array( $pagenow, $exclude_pages, true ) ) {
776 return;
777 }
778
779 $default_options = [
780 'id' => null,
781 'title' => '',
782 'description' => '',
783 'classes' => [ 'notice', 'e-notice' ], // We include WP's default notice class so it will be properly handled by WP's js handler
784 'type' => '',
785 'dismissible' => true,
786 'icon' => 'eicon-elementor',
787 'button' => [],
788 'button_secondary' => [],
789 ];
790
791 $options = array_replace_recursive( $default_options, $options );
792
793 $notice_classes = $options['classes'];
794 $dismiss_button = '';
795 $icon = '';
796
797 if ( $options['type'] ) {
798 $notice_classes[] = 'e-notice--' . $options['type'];
799 }
800
801 $wrapper_attributes = [];
802
803 if ( $options['dismissible'] ) {
804 $label = esc_html__( 'Dismiss this notice.', 'elementor' );
805 $notice_classes[] = 'e-notice--dismissible';
806 $dismiss_button = '<i class="e-notice__dismiss" role="button" aria-label="' . $label . '" tabindex="0"></i>';
807
808 $wrapper_attributes['data-nonce'] = wp_create_nonce( 'elementor_set_admin_notice_viewed' );
809 }
810
811 if ( $options['icon'] ) {
812 $notice_classes[] = 'e-notice--extended';
813 $icon = '<div class="e-notice__icon-wrapper"><i class="' . esc_attr( $options['icon'] ) . '" aria-hidden="true"></i></div>';
814 }
815
816 $wrapper_attributes['class'] = $notice_classes;
817
818 if ( $options['id'] ) {
819 $wrapper_attributes['data-notice_id'] = $options['id'];
820 }
821 ?>
822 <div <?php Utils::print_html_attributes( $wrapper_attributes ); ?>>
823 <?php echo $dismiss_button; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
824 <div class="e-notice__aside">
825 <?php echo $icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
826 </div>
827 <div class="e-notice__content">
828 <?php if ( $options['title'] ) { ?>
829 <h3><?php echo wp_kses_post( $options['title'] ); ?></h3>
830 <?php } ?>
831
832 <?php if ( $options['description'] ) { ?>
833 <p><?php echo wp_kses_post( $options['description'] ); ?></p>
834 <?php } ?>
835
836 <?php if ( ! empty( $options['button']['text'] ) || ! empty( $options['button_secondary']['text'] ) ) { ?>
837 <div class="e-notice__actions">
838 <?php
839 foreach ( [ $options['button'], $options['button_secondary'] ] as $index => $button_settings ) {
840 if ( empty( $button_settings['variant'] ) && $index ) {
841 $button_settings['variant'] = 'outline';
842 }
843
844 if ( empty( $button_settings['text'] ) ) {
845 continue;
846 }
847
848 $button = new Button( $button_settings );
849 $button->print_button();
850 } ?>
851 </div>
852 <?php } ?>
853 </div>
854 </div>
855 <?php }
856
857 public function admin_notices() {
858 $this->install_time = Plugin::$instance->get_install_time();
859 $this->current_screen_id = get_current_screen()->id;
860
861 foreach ( $this->plain_notices as $notice ) {
862 $method_callback = "notice_{$notice}";
863 if ( $this->$method_callback() ) {
864 return;
865 }
866 }
867
868 /** @var Base_Notice $notice_instance */
869 foreach ( $this->get_notices() as $notice_instance ) {
870 if ( ! $notice_instance->should_print() ) {
871 continue;
872 }
873
874 $this->print_admin_notice( $notice_instance->get_config() );
875
876 // It exits the method to make sure it prints only one notice.
877 return;
878 }
879 }
880
881 public function maybe_log_campaign() {
882 if ( empty( $_GET['plg_campaign'] ) || empty( $_GET['plg_campaign_name'] ) ) {
883 return;
884 }
885
886 $allowed_plgs = [
887 'elementor_image_optimization_campaign',
888 'elementor_ea11y_campaign',
889 'elementor_site_mailer_campaign',
890 ];
891
892 if ( ! in_array( $_GET['plg_campaign_name'], $allowed_plgs, true ) ) {
893 return;
894 }
895
896 if ( ! isset( $_GET['plg_campaign_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['plg_campaign_nonce'] ), sanitize_key( $_GET['plg_campaign_name'] ) ) ) {
897 return;
898 }
899
900 if ( ! current_user_can( 'manage_options' ) ) {
901 return;
902 }
903
904 if ( empty( $_GET['plg_source'] ) || empty( $_GET['plg_medium'] ) ) {
905 return;
906 }
907
908 $campaign_data = [
909 'source' => sanitize_key( $_GET['plg_source'] ),
910 'campaign' => sanitize_key( $_GET['plg_campaign'] ),
911 'medium' => sanitize_key( $_GET['plg_medium'] ),
912 ];
913
914 set_transient( sanitize_key( $_GET['plg_campaign_name'] ), $campaign_data, 30 * DAY_IN_SECONDS );
915 }
916
917 public static function add_plg_campaign_data( $url, $campaign_data ) {
918
919 foreach ( [ 'name', 'campaign' ] as $key ) {
920 if ( empty( $campaign_data[ $key ] ) ) {
921 return $url;
922 }
923 }
924
925 return add_query_arg( [
926 'plg_campaign_name' => $campaign_data['name'],
927 'plg_campaign' => $campaign_data['campaign'],
928 'plg_source' => empty( $campaign_data['source'] ) ? '' : $campaign_data['source'],
929 'plg_medium' => empty( $campaign_data['medium'] ) ? '' : $campaign_data['medium'],
930 'plg_campaign_nonce' => wp_create_nonce( $campaign_data['name'] ),
931 ], $url );
932 }
933
934 /**
935 * @since 2.9.0
936 * @access public
937 */
938 public function __construct() {
939 add_action( 'admin_notices', [ $this, 'admin_notices' ], 20 );
940 add_action( 'admin_action_install-plugin', [ $this, 'maybe_log_campaign' ] );
941 }
942
943 /**
944 * Get module name.
945 *
946 * Retrieve the module name.
947 *
948 * @since 2.9.0
949 * @access public
950 *
951 * @return string Module name.
952 */
953 public function get_name() {
954 return 'admin-notices';
955 }
956 }
957