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

1,163 lines 36.3 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\Upgrade\Manager;
8 use Elementor\Core\Utils\Hints;
9 use Elementor\Core\Utils\Promotions\Filtered_Promotions_Manager;
10 use Elementor\Plugin;
11 use Elementor\Settings;
12 use Elementor\Tracker;
13 use Elementor\User;
14 use Elementor\Utils;
15 use Elementor\Core\Admin\Notices\Base_Notice;
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit; // Exit if accessed directly.
19 }
20
21 class Admin_Notices extends Module {
22
23 const DEFAULT_EXCLUDED_PAGES = [ 'plugins.php', 'plugin-install.php', 'plugin-editor.php' ];
24 const LOCAL_GOOGLE_FONTS_DISABLED_NOTICE_ID = 'local_google_fonts_disabled';
25 const LOCAL_GOOGLE_FONTS_NOTICE_MIN_VERSION = '3.33.3';
26
27 const EXIT_EARLY_FOR_BACKWARD_COMPATIBILITY = false;
28
29 private $plain_notices = [
30 'api_notice',
31 'api_upgrade_plugin',
32 'tracker',
33 'tracker_last_update',
34 'rate_us_feedback',
35 'role_manager_promote',
36 'experiment_promotion',
37 'site_mailer_promotion',
38 'plugin_image_optimization',
39 'ally_pages_promotion',
40 self::LOCAL_GOOGLE_FONTS_DISABLED_NOTICE_ID,
41 ];
42
43 private $elementor_pages_count = null;
44
45 private $install_time = null;
46
47 private $current_screen_id = null;
48
49 private function get_notices() {
50 /**
51 * Admin notices.
52 *
53 * Filters Elementor admin notices.
54 *
55 * This hook can be used by external developers to manage existing
56 * admin notice or to add new notices for Elementor add-ons.
57 *
58 * @param array $notices A list of notice classes.
59 */
60 $notices = apply_filters( 'elementor/core/admin/notices', [] );
61
62 return $notices;
63 }
64
65 private function get_install_time() {
66 if ( null === $this->install_time ) {
67 $this->install_time = Plugin::$instance->get_install_time();
68 }
69
70 return $this->install_time;
71 }
72
73 private function get_elementor_pages_count() {
74 if ( null === $this->elementor_pages_count ) {
75 $elementor_pages = new \WP_Query( [
76 'no_found_rows' => true,
77 'post_type' => 'any',
78 'post_status' => 'publish',
79 'fields' => 'ids',
80 'update_post_meta_cache' => false,
81 'update_post_term_cache' => false,
82 'meta_key' => '_elementor_edit_mode',
83 'meta_value' => 'builder',
84 ] );
85
86 $this->elementor_pages_count = $elementor_pages->post_count;
87 }
88
89 return $this->elementor_pages_count;
90 }
91
92 private function notice_api_upgrade_plugin() {
93 $upgrade_notice = Api::get_upgrade_notice();
94 if ( empty( $upgrade_notice ) ) {
95 return false;
96 }
97
98 if ( ! current_user_can( 'update_plugins' ) ) {
99 return false;
100 }
101
102 if ( ! $this->is_elementor_admin_screen_with_system_info() ) {
103 return false;
104 }
105
106 // Check for upgrades.
107 $update_plugins = get_site_transient( 'update_plugins' );
108
109 $has_remote_update_package = ! ( empty( $update_plugins ) || empty( $update_plugins->response[ ELEMENTOR_PLUGIN_BASE ] ) || empty( $update_plugins->response[ ELEMENTOR_PLUGIN_BASE ]->package ) );
110
111 if ( ! $has_remote_update_package && empty( $upgrade_notice['update_link'] ) ) {
112 return false;
113 }
114
115 if ( $has_remote_update_package ) {
116 $product = $update_plugins->response[ ELEMENTOR_PLUGIN_BASE ];
117
118 $details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $product->slug . '&section=changelog&TB_iframe=true&width=600&height=800' );
119 $upgrade_url = wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' . ELEMENTOR_PLUGIN_BASE ), 'upgrade-plugin_' . ELEMENTOR_PLUGIN_BASE );
120 $new_version = $product->new_version;
121 } else {
122 $upgrade_url = $upgrade_notice['update_link'];
123 $details_url = $upgrade_url;
124
125 $new_version = $upgrade_notice['version'];
126 }
127
128 // Check if upgrade messages should be shown.
129 if ( version_compare( ELEMENTOR_VERSION, $upgrade_notice['version'], '>=' ) ) {
130 return false;
131 }
132
133 $notice_id = 'upgrade_notice_' . $upgrade_notice['version'];
134 if ( User::is_user_notice_viewed( $notice_id ) ) {
135 return false;
136 }
137
138 $message = sprintf(
139 /* translators: 1: Details URL, 2: Accessibility text, 3: Version number, 4: Update URL, 5: Accessibility text. */
140 __( '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' ),
141 esc_url( $details_url ),
142 sprintf(
143 /* translators: %s: Elementor version. */
144 esc_attr__( 'View Elementor version %s details', 'elementor' ),
145 $new_version
146 ),
147 $new_version,
148 esc_url( $upgrade_url ),
149 esc_attr__( 'Update Now', 'elementor' )
150 );
151
152 $options = [
153 'title' => esc_html__( 'Update Notification', 'elementor' ),
154 'description' => $message,
155 'button' => [
156 'icon_classes' => 'dashicons dashicons-update',
157 'text' => esc_html__( 'Update Now', 'elementor' ),
158 'url' => $upgrade_url,
159 ],
160 'id' => $notice_id,
161 ];
162
163 $this->print_admin_notice( $options );
164
165 return true;
166 }
167
168 private function notice_api_notice() {
169 $admin_notice = Api::get_admin_notice();
170 if ( empty( $admin_notice ) ) {
171 return false;
172 }
173
174 if ( ! current_user_can( 'manage_options' ) ) {
175 return false;
176 }
177
178 if ( ! $this->is_elementor_admin_screen_with_system_info() ) {
179 return false;
180 }
181
182 $notice_id = 'admin_notice_api_' . $admin_notice['notice_id'];
183 if ( User::is_user_notice_viewed( $notice_id ) ) {
184 return false;
185 }
186
187 $options = [
188 'title' => esc_html__( 'Update Notification', 'elementor' ),
189 'description' => $admin_notice['notice_text'],
190 'id' => $notice_id,
191 ];
192
193 $this->print_admin_notice( $options );
194
195 return true;
196 }
197
198 private function notice_tracker() {
199 if ( ! current_user_can( 'manage_options' ) ) {
200 return false;
201 }
202
203 // Show tracker notice after 24 hours from installed time.
204 if ( strtotime( '+24 hours', $this->get_install_time() ) > time() ) {
205 return false;
206 }
207
208 if ( '1' === get_option( 'elementor_tracker_notice' ) ) {
209 return false;
210 }
211
212 if ( Tracker::is_allow_track() ) {
213 return false;
214 }
215
216 if ( 2 > $this->get_elementor_pages_count() ) {
217 return false;
218 }
219
220 // TODO: Skip for development env.
221 $optin_url = wp_nonce_url( add_query_arg( 'elementor_tracker', 'opt_into' ), 'opt_into' );
222 $optout_url = wp_nonce_url( add_query_arg( 'elementor_tracker', 'opt_out' ), 'opt_out' );
223
224 $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' );
225
226 /**
227 * Tracker admin description text.
228 *
229 * Filters the admin notice text for non-sensitive data collection.
230 *
231 * @since 1.0.0
232 *
233 * @param string $tracker_description_text Description text displayed in admin notice.
234 */
235 $tracker_description_text = apply_filters( 'elementor/tracker/admin_description_text', $tracker_description_text );
236
237 $message = esc_html( $tracker_description_text ) . ' <a href="https://go.elementor.com/usage-data-tracking/" target="_blank">' . esc_html__( 'Learn more.', 'elementor' ) . '</a>';
238
239 $options = [
240 'title' => esc_html__( 'Want to shape the future of web creation?', 'elementor' ),
241 'description' => $message,
242 'dismissible' => false,
243 'button' => [
244 'text' => esc_html__( 'Sure! I\'d love to help', 'elementor' ),
245 'url' => $optin_url,
246 'type' => 'cta',
247 ],
248 'button_secondary' => [
249 'text' => esc_html__( 'No thanks', 'elementor' ),
250 'url' => $optout_url,
251 'variant' => 'outline',
252 'type' => 'cta',
253 ],
254 ];
255
256 $this->print_admin_notice( $options );
257
258 return true;
259 }
260
261 private function notice_tracker_last_update() {
262 if ( ! current_user_can( 'manage_options' ) ) {
263 return false;
264 }
265
266 if ( ! Tracker::has_terms_changed() ) {
267 return false;
268 }
269
270 $notice_id = 'tracker_last_update_' . Tracker::LAST_TERMS_UPDATED;
271
272 if ( User::is_user_notice_viewed( $notice_id ) ) {
273 return false;
274 }
275
276 $optin_url = wp_nonce_url( add_query_arg( 'elementor_tracker', 'opt_into' ), 'opt_into' );
277
278 $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' );
279
280 $options = [
281 'id' => $notice_id,
282 'title' => esc_html__( 'Update regarding usage data collection', 'elementor' ),
283 'description' => $message,
284 'button' => [
285 'text' => esc_html__( 'Opt in', 'elementor' ),
286 'url' => $optin_url,
287 'type' => 'cta',
288 ],
289 'button_secondary' => [
290 'text' => esc_html__( 'Learn more', 'elementor' ),
291 'url' => 'https://go.elementor.com/wp-dash-update-usage-notice/',
292 'new_tab' => true,
293 'type' => 'cta',
294 ],
295 ];
296
297 $this->print_admin_notice( $options );
298
299 return true;
300 }
301
302 private function notice_rate_us_feedback() {
303 $notice_id = 'rate_us_feedback';
304
305 if ( ! current_user_can( 'manage_options' ) ) {
306 return false;
307 }
308
309 if ( 'dashboard' !== $this->current_screen_id || User::is_user_notice_viewed( $notice_id ) ) {
310 return false;
311 }
312
313 if ( 10 >= $this->get_elementor_pages_count() ) {
314 return false;
315 }
316
317 $dismiss_url = add_query_arg( [
318 'action' => 'elementor_set_admin_notice_viewed',
319 'notice_id' => esc_attr( $notice_id ),
320 '_wpnonce' => wp_create_nonce( 'elementor_set_admin_notice_viewed' ),
321 ], admin_url( 'admin-post.php' ) );
322
323 $options = [
324 'title' => esc_html__( 'Congrats!', 'elementor' ),
325 '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' ),
326 'id' => $notice_id,
327 'button' => [
328 'text' => esc_html__( 'Happy To Help', 'elementor' ),
329 'url' => 'https://go.elementor.com/admin-review/',
330 'new_tab' => true,
331 'type' => 'cta',
332 ],
333 'button_secondary' => [
334 'text' => esc_html__( 'Hide Notification', 'elementor' ),
335 'classes' => [ 'e-notice-dismiss' ],
336 'url' => esc_url_raw( $dismiss_url ),
337 'new_tab' => true,
338 'type' => 'cta',
339 ],
340 ];
341
342 $this->print_admin_notice( $options );
343
344 return true;
345 }
346
347 private function notice_role_manager_promote() {
348 $notice_id = 'role_manager_promote';
349
350 if ( Utils::has_pro() ) {
351 return false;
352 }
353
354 if ( ! current_user_can( 'manage_options' ) ) {
355 return false;
356 }
357
358 if ( 'elementor_page_elementor-role-manager' !== $this->current_screen_id || User::is_user_notice_viewed( $notice_id ) ) {
359 return false;
360 }
361
362 $users = new \WP_User_Query( [
363 'fields' => 'ID',
364 'number' => 10,
365 ] );
366
367 if ( 5 > $users->get_total() ) {
368 return false;
369 }
370
371 $options = [
372 'title' => esc_html__( 'Managing a multi-user site?', 'elementor' ),
373 'description' => esc_html__( 'With Elementor Pro, you can control user access and make sure no one messes up your design.', 'elementor' ),
374 'id' => $notice_id,
375
376 'button' => [
377 'text' => esc_html__( 'Learn More', 'elementor' ),
378 'url' => 'https://go.elementor.com/plugin-promotion-role-manager/',
379 'new_tab' => true,
380 'type' => 'cta',
381 ],
382 ];
383
384 $options = Filtered_Promotions_Manager::get_filtered_promotion_data( $options, 'core/admin/notice_role_manager_promote', 'button', 'url' );
385
386 $this->print_admin_notice( $options );
387
388 return true;
389 }
390
391 private function notice_experiment_promotion() {
392 $notice_id = 'experiment_promotion';
393
394 if ( ! current_user_can( 'manage_options' ) || User::is_user_notice_viewed( $notice_id ) ) {
395 return false;
396 }
397
398 $experiments = Plugin::$instance->experiments;
399 $is_all_performance_features_active = (
400 $experiments->is_feature_active( 'e_font_icon_svg' ) &&
401 $experiments->is_feature_active( 'e_optimized_markup' )
402 );
403
404 if ( $is_all_performance_features_active ) {
405 return false;
406 }
407
408 $options = [
409 'title' => esc_html__( 'Improve your site’s performance score.', 'elementor' ),
410 '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' ),
411 'id' => $notice_id,
412 'button' => [
413 'text' => esc_html__( 'Try it out', 'elementor' ),
414 'url' => Settings::get_settings_tab_url( 'experiments' ),
415 'type' => 'cta',
416 ],
417 'button_secondary' => [
418 'text' => esc_html__( 'Learn more', 'elementor' ),
419 'url' => 'https://go.elementor.com/wp-dash-experiment-promotion/',
420 'new_tab' => true,
421 'type' => 'cta',
422 ],
423 ];
424
425 $this->print_admin_notice( $options );
426
427 return true;
428 }
429
430 private function site_has_forms_plugins() {
431 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' );
432 }
433
434 private function site_has_woocommerce() {
435 return class_exists( 'WooCommerce' );
436 }
437
438 private function get_installed_form_plugin_name() {
439 static $detected_form_plugin = null;
440
441 if ( null !== $detected_form_plugin ) {
442 return $detected_form_plugin;
443 }
444
445 $form_plugins_constants_to_name_mapper = [
446 'WPFORMS_VERSION' => 'WPForms',
447 'WPCF7_VERSION' => 'Contact Form 7',
448 ];
449
450 foreach ( $form_plugins_constants_to_name_mapper as $constant => $name ) {
451 if ( defined( $constant ) ) {
452 $detected_form_plugin = $name;
453 return $detected_form_plugin;
454 }
455 }
456
457 $form_plugins_classes_to_name_mapper = [
458 '\GFCommon' => 'Gravity Forms',
459 '\Ninja_Forms' => 'Ninja Forms',
460 ];
461
462 foreach ( $form_plugins_classes_to_name_mapper as $class => $name ) {
463 if ( class_exists( $class ) ) {
464 $detected_form_plugin = $name;
465 return $detected_form_plugin;
466 }
467 }
468
469 $detected_form_plugin = false;
470 return $detected_form_plugin;
471 }
472
473 private function notice_local_google_fonts_disabled() {
474
475 if ( ! $this->is_elementor_page() && ! $this->is_elementor_admin_screen() ) {
476 return false;
477 }
478
479 if ( ! Manager::had_install_prior_to( self::LOCAL_GOOGLE_FONTS_NOTICE_MIN_VERSION ) ) {
480 return false;
481 }
482
483 if ( User::is_user_notice_viewed( self::LOCAL_GOOGLE_FONTS_DISABLED_NOTICE_ID ) ) {
484 return false;
485 }
486
487 $is_local_gf_enabled = (bool) get_option( 'elementor_local_google_fonts', '0' );
488
489 if ( $is_local_gf_enabled ) {
490 return false;
491 }
492
493 $options = [
494 'title' => esc_html__( 'Important: Local Google Fonts Settings in Elementor', 'elementor' ),
495 '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' ),
496 'id' => self::LOCAL_GOOGLE_FONTS_DISABLED_NOTICE_ID,
497 'type' => '',
498 'button' => [
499 'text' => esc_html__( 'Take me there', 'elementor' ),
500 'url' => '../wp-admin/admin.php?page=elementor-settings#tab-performance',
501 'new_tab' => false,
502 'type' => 'cta',
503 ],
504 'button_secondary' => [
505 'text' => esc_html__( 'Learn more', 'elementor' ),
506 'url' => 'https://go.elementor.com/wp-dash-google-fonts-locally-notice/',
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_ally_pages_promotion() {
518 global $pagenow;
519 $notice_id = 'ally_pages_promotion';
520
521 if ( 'edit.php' !== $pagenow || empty( $_GET['post_type'] ) || 'page' !== $_GET['post_type'] ) {
522 return false;
523 }
524
525 if ( ! current_user_can( 'manage_options' ) ) {
526 return false;
527 }
528
529 if ( User::is_user_notice_viewed( $notice_id ) ) {
530 return false;
531 }
532
533 $plugin_slug = 'pojo-accessibility';
534 $plugin_file_path = 'pojo-accessibility/pojo-accessibility.php';
535
536 $one_subscription = Hints::is_plugin_connected_to_one_subscription();
537 $is_installed = Hints::is_plugin_installed( $plugin_slug );
538 $is_active = Hints::is_plugin_active( $plugin_slug );
539
540 if ( $is_active ) {
541 return false;
542 }
543
544 if ( $one_subscription ) {
545 $learn_more_url = 'https://go.elementor.com/acc-plg-learn-more-one';
546
547 if ( ! $is_installed ) {
548 $description = esc_html__( 'Make sure your site has an accessibility statement page. Install Web Accessibility, included in ONE, to create it in a few clicks.', 'elementor' );
549 $button_text = esc_html__( 'Install now', 'elementor' );
550 $button_url = $this->get_plugin_button_install_url( $plugin_slug );
551 $campaign_data = [
552 'name' => 'elementor_ea11y_campaign',
553 'campaign' => 'acc-statement-plg-pages-one-install',
554 'source' => 'wp-pages-one-install',
555 'medium' => 'wp-dash-one',
556 ];
557 } elseif ( ! $is_active ) {
558 $description = esc_html__( 'Your ONE subscription includes Web Accessibility. Activate it to create your accessibility statement page quickly.', 'elementor' );
559 $button_text = esc_html__( 'Activate now', 'elementor' );
560 $button_url = $this->get_plugin_button_activate_url( $plugin_file_path );
561 $campaign_data = [
562 'name' => 'elementor_ea11y_campaign',
563 'campaign' => 'acc-statement-plg-pages-one-activate',
564 'source' => 'wp-pages-one-activate',
565 'medium' => 'wp-dash-one',
566 ];
567 }
568 } else {
569 $description = esc_html__( "Create a more inclusive site experience for all your visitors. With Web Accessibility, it's easy to add your statement page in just a few clicks.", 'elementor' );
570 $learn_more_url = 'https://go.elementor.com/acc-plg-learn-more';
571
572 if ( ! $is_installed ) {
573 $button_text = esc_html__( 'Install now', 'elementor' );
574 $button_url = $this->get_plugin_button_install_url( $plugin_slug );
575 $campaign_data = [
576 'name' => 'elementor_ea11y_campaign',
577 'campaign' => 'acc-statement-plg-pages-install',
578 'source' => 'wp-pages-install',
579 'medium' => 'wp-dash',
580 ];
581 } elseif ( ! $is_active ) {
582 $button_text = esc_html__( 'Activate now', 'elementor' );
583 $button_url = $this->get_plugin_button_activate_url( $plugin_file_path );
584 $campaign_data = [
585 'name' => 'elementor_ea11y_campaign',
586 'campaign' => 'acc-statement-plg-pages-activate',
587 'source' => 'wp-pages-activate',
588 'medium' => 'wp-dash',
589 ];
590 }
591 }
592
593 $options = [
594 'title' => esc_html__( 'Make sure your site has an accessibility statement page', 'elementor' ),
595 'description' => $description,
596 'id' => $notice_id,
597 'type' => 'cta',
598 'button' => [
599 'text' => $button_text,
600 'url' => self::add_plg_campaign_data( $button_url, $campaign_data ),
601 'type' => 'cta',
602 ],
603 'button_secondary' => [
604 'text' => esc_html__( 'Learn more', 'elementor' ),
605 'url' => $learn_more_url,
606 'new_tab' => true,
607 'type' => 'cta',
608 ],
609 ];
610
611 $this->print_admin_notice( $options );
612
613 return true;
614 }
615
616 private function notice_site_mailer_promotion() {
617 $notice_id = 'site_mailer_promotion';
618 $has_forms = $this->site_has_forms_plugins();
619 $has_woocommerce = $this->site_has_woocommerce();
620
621 if ( ! $has_forms && ! $has_woocommerce ) {
622 return false;
623 }
624
625 if ( ! $this->is_elementor_page() && ! $this->is_elementor_admin_screen() ) {
626 return false;
627 }
628
629 if ( ( Utils::has_pro() && ! $has_woocommerce ) || ! current_user_can( 'install_plugins' ) || User::is_user_notice_viewed( $notice_id ) ) {
630 return false;
631 }
632
633 $plugin_slug = 'site-mailer';
634 $plugin_file_path = 'site-mailer/site-mailer.php';
635
636 $one_subscription = Hints::is_plugin_connected_to_one_subscription();
637 $is_woocommerce = $this->should_render_woocommerce_hint( $has_forms, $has_woocommerce );
638 $is_installed = Hints::is_plugin_installed( $plugin_slug );
639 $is_active = Hints::is_plugin_active( $plugin_slug );
640
641 if ( $is_active ) {
642 return false;
643 }
644
645 if ( $one_subscription ) {
646 if ( $is_woocommerce ) {
647 $title = esc_html__( 'Improve transactional email deliverability', 'elementor' );
648
649 if ( ! $is_installed ) {
650 $description = esc_html__( 'Use Email Deliverability to ensure store emails like purchase confirmations and shipping updates reach the inbox every time. Included in your ONE subscription.', 'elementor' );
651 $button_text = esc_html__( 'Install now', 'elementor' );
652 $button_url = $this->get_plugin_button_install_url( $plugin_slug );
653 $campaign_data = [
654 'name' => 'elementor_site_mailer_campaign',
655 'campaign' => 'sm-plg-one',
656 'source' => 'sm-core-woo-one-install',
657 'medium' => 'wp-dash',
658 ];
659 } elseif ( ! $is_active ) {
660 $description = esc_html__( 'Email Deliverability is installed and included in your ONE subscription. Activate it to ensure store emails like purchase confirmations and shipping updates reach the inbox every time.', 'elementor' );
661 $button_text = esc_html__( 'Activate now', 'elementor' );
662 $button_url = $this->get_plugin_button_activate_url( $plugin_file_path );
663 $campaign_data = [
664 'name' => 'elementor_site_mailer_campaign',
665 'campaign' => 'sm-plg-one',
666 'source' => 'sm-core-woo-one-activate',
667 'medium' => 'wp-dash',
668 ];
669 }
670 } else {
671 $title = esc_html__( 'Keep your form emails out of the spam folder', 'elementor' );
672
673 if ( ! $is_installed ) {
674 $description = esc_html__( 'Use Email Deliverability to ensure emails reach the inbox and track delivery with built-in logs. Included in your ONE subscription.', 'elementor' );
675 $button_text = esc_html__( 'Install now', 'elementor' );
676 $button_url = $this->get_plugin_button_install_url( $plugin_slug );
677 $campaign_data = [
678 'name' => 'elementor_site_mailer_campaign',
679 'campaign' => 'sm-plg-one',
680 'source' => 'sm-core-form-one-install',
681 'medium' => 'wp-dash',
682 ];
683 } elseif ( ! $is_active ) {
684 $description = esc_html__( 'Use Email Deliverability to ensure emails reach the inbox and track delivery with built-in logs. Email Deliverability is included in your ONE subscription. Activate it to continue.', 'elementor' );
685 $button_text = esc_html__( 'Activate now', 'elementor' );
686 $button_url = $this->get_plugin_button_activate_url( $plugin_file_path );
687 $campaign_data = [
688 'name' => 'elementor_site_mailer_campaign',
689 'campaign' => 'sm-plg-one',
690 'source' => 'sm-core-form-one-activate',
691 'medium' => 'wp-dash',
692 ];
693 }
694 }
695 // phpcs:ignore Universal.ControlStructures.DisallowLonelyIf.Found
696 } else {
697 if ( $is_woocommerce ) {
698 $title = esc_html__( 'Improve Transactional Email Deliverability', 'elementor' );
699 $description = esc_html__( "Use Elementor's Email Deliverability to ensure your store emails like purchase confirmations, shipping updates and more are reliably delivered.", 'elementor' );
700
701 if ( ! $is_installed ) {
702 $button_text = esc_html__( 'Install now', 'elementor' );
703 $button_url = $this->get_plugin_button_install_url( $plugin_slug );
704 $campaign_data = [
705 'name' => 'elementor_site_mailer_campaign',
706 'campaign' => 'sm-plg',
707 'source' => 'sm-core-woo-install',
708 'medium' => 'wp-dash',
709 ];
710 } elseif ( ! $is_active ) {
711 $button_text = esc_html__( 'Activate now', 'elementor' );
712 $button_url = $this->get_plugin_button_activate_url( $plugin_file_path );
713 $campaign_data = [
714 'name' => 'elementor_site_mailer_campaign',
715 'campaign' => 'sm-plg',
716 'source' => 'sm-core-woo-activate',
717 'medium' => 'wp-dash',
718 ];
719 }
720 } else {
721 $title = esc_html__( 'Ensure your form emails avoid the spam folder!', 'elementor' );
722 $description = esc_html__( 'Use Email Deliverability for improved email deliverability, detailed email logs, and an easy setup.', 'elementor' );
723
724 if ( ! $is_installed ) {
725 $button_text = esc_html__( 'Install now', 'elementor' );
726 $button_url = $this->get_plugin_button_install_url( $plugin_slug );
727 $campaign_data = [
728 'name' => 'elementor_site_mailer_campaign',
729 'campaign' => 'sm-plg',
730 'source' => 'sm-core-form-install',
731 'medium' => 'wp-dash',
732 ];
733 } elseif ( ! $is_active ) {
734 $button_text = esc_html__( 'Activate now', 'elementor' );
735 $button_url = $this->get_plugin_button_activate_url( $plugin_file_path );
736 $campaign_data = [
737 'name' => 'elementor_site_mailer_campaign',
738 'campaign' => 'sm-plg',
739 'source' => 'sm-core-form-activate',
740 'medium' => 'wp-dash',
741 ];
742 }
743 }
744 }
745
746 $learn_more_url = $one_subscription && $is_woocommerce
747 ? 'https://go.elementor.com/sm-woo-learn-more-one'
748 : 'https://go.elementor.com/sm-core-form/';
749
750 $options = [
751 'title' => $title,
752 'description' => $description,
753 'id' => $notice_id,
754 'type' => 'cta',
755 'button' => [
756 'text' => $button_text,
757 'url' => self::add_plg_campaign_data( $button_url, $campaign_data ),
758 'type' => 'cta',
759 'data' => [
760 'campaign' => $campaign_data['campaign'],
761 'source' => $campaign_data['source'],
762 'medium' => $campaign_data['medium'],
763 ],
764 ],
765 'button_secondary' => [
766 'text' => esc_html__( 'Learn more', 'elementor' ),
767 'url' => $learn_more_url,
768 'new_tab' => true,
769 'type' => 'cta',
770 ],
771 ];
772
773 if ( $is_woocommerce ) {
774 // We include WP's default notice class so it will be properly handled by WP's js handler
775 // And add a new one to distinguish between the two types of notices
776 $options['classes'] = [ 'notice', 'e-notice', 'sm-notice-wc' ];
777 }
778
779 $this->print_admin_notice( $options );
780
781 return true;
782 }
783
784 private function should_render_woocommerce_hint( $has_forms, $has_woocommerce ): bool {
785 if ( ! $has_forms && ! $has_woocommerce ) {
786 return false;
787 }
788
789 if ( ! $has_forms && $has_woocommerce ) {
790 return true;
791 }
792
793 if ( $has_forms && $has_woocommerce && Utils::has_pro() ) {
794 return true;
795 }
796
797 if ( ! $has_woocommerce ) {
798 return false;
799 }
800
801 return (bool) wp_rand( 0, 1 );
802 }
803
804 private function is_elementor_page(): bool {
805 return 0 === strpos( $this->current_screen_id, 'elementor_page' );
806 }
807
808 private function is_elementor_admin_screen(): bool {
809 return in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library' ], true );
810 }
811
812 private function is_elementor_admin_screen_with_system_info(): bool {
813 return in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library', 'elementor_page_elementor-system-info', 'dashboard' ], true );
814 }
815 private function get_plugin_button_install_url( $plugin_slug ) {
816 return wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $plugin_slug ), 'install-plugin_' . $plugin_slug );
817 }
818
819 private function get_plugin_button_activate_url( $plugin_file_path ) {
820 return 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 );
821 }
822
823 private function get_plugin_button_connect_url( $plugin_settings_page ) {
824 return self_admin_url( $plugin_settings_page );
825 }
826
827 private function get_plugin_cta_data( $plugin_slug, $plugin_file_path ) {
828 if ( Hints::is_plugin_active( $plugin_slug ) ) {
829 return false;
830 }
831
832 if ( Hints::is_plugin_installed( $plugin_slug ) ) {
833 $url = $this->get_plugin_button_activate_url( $plugin_file_path );
834 $cta_text = esc_html__( 'Activate now', 'elementor' );
835 } else {
836 $url = $this->get_plugin_button_install_url( $plugin_slug );
837 $cta_text = esc_html__( 'Install now', 'elementor' );
838 }
839
840 return [
841 'url' => $url,
842 'text' => $cta_text,
843 ];
844 }
845
846 /**
847 * For testing purposes
848 */
849 public function get_elementor_version() {
850 return ELEMENTOR_VERSION;
851 }
852
853 private function notice_plugin_image_optimization() {
854 $notice_id = 'plugin_image_optimization';
855
856 if ( 'upload' !== $this->current_screen_id ) {
857 return false;
858 }
859
860 if ( ! current_user_can( 'manage_options' ) ) {
861 return false;
862 }
863
864 if ( User::is_user_notice_viewed( $notice_id ) ) {
865 return false;
866 }
867
868 $attachments = new \WP_Query( [
869 'post_type' => 'attachment',
870 'post_status' => 'any',
871 'fields' => 'ids',
872 ] );
873
874 if ( 1 > $attachments->found_posts ) {
875 return false;
876 }
877
878 $plugin_slug = 'image-optimization';
879 $plugin_file_path = 'image-optimization/image-optimization.php';
880
881 $one_subscription = Hints::is_plugin_connected_to_one_subscription();
882 $is_installed = Hints::is_plugin_installed( $plugin_slug );
883 $is_active = Hints::is_plugin_active( $plugin_slug );
884
885 if ( $is_active ) {
886 return false;
887 }
888
889 if ( $one_subscription ) {
890 if ( ! $is_installed ) {
891 $description = esc_html__( 'Automatically optimize images to improve site speed and performance. Included with your ONE subscription.', 'elementor' );
892 $button_text = esc_html__( 'Install now', 'elementor' );
893 $button_url = $this->get_plugin_button_install_url( $plugin_slug );
894 $campaign_data = [
895 'name' => 'elementor_image_optimization_campaign',
896 'campaign' => 'io-plg-one',
897 'source' => 'io-wp-media-library-one-install',
898 'medium' => 'wp-dash-one',
899 ];
900 } elseif ( ! $is_active ) {
901 $description = esc_html__( 'Your ONE subscription includes Image Optimization. Activate it to optimize images and improve site performance.', 'elementor' );
902 $button_text = esc_html__( 'Activate now', 'elementor' );
903 $button_url = $this->get_plugin_button_activate_url( $plugin_file_path );
904 $campaign_data = [
905 'name' => 'elementor_image_optimization_campaign',
906 'campaign' => 'io-plg-one',
907 'source' => 'io-wp-media-library-one-activate',
908 'medium' => 'wp-dash-one',
909 ];
910 }
911 } else {
912 $description = esc_html__( 'Automatically compress and optimize images, resize larger files, or convert to WebP. Optimize images individually, in bulk, or on upload.', 'elementor' );
913
914 if ( ! $is_installed ) {
915 $button_text = esc_html__( 'Install now', 'elementor' );
916 $button_url = $this->get_plugin_button_install_url( $plugin_slug );
917 $campaign_data = [
918 'name' => 'elementor_image_optimization_campaign',
919 'campaign' => 'io-plg',
920 'source' => 'io-wp-media-library-install',
921 'medium' => 'wp-dash',
922 ];
923 } elseif ( ! $is_active ) {
924 $button_text = esc_html__( 'Activate now', 'elementor' );
925 $button_url = $this->get_plugin_button_activate_url( $plugin_file_path );
926 $campaign_data = [
927 'name' => 'elementor_image_optimization_campaign',
928 'campaign' => 'io-plg',
929 'source' => 'io-wp-media-library-activate',
930 'medium' => 'wp-dash',
931 ];
932 }
933 }
934
935 $options = [
936 'title' => esc_html__( 'Speed up your website with Image Optimization', 'elementor' ),
937 'description' => $description,
938 'id' => $notice_id,
939 'type' => 'cta',
940 'button' => [
941 'text' => $button_text,
942 'url' => self::add_plg_campaign_data( $button_url, $campaign_data ),
943 'type' => 'cta',
944 'data' => [
945 'campaign' => $campaign_data['campaign'],
946 'source' => $campaign_data['source'],
947 'medium' => $campaign_data['medium'],
948 ],
949 ],
950 ];
951
952 $this->print_admin_notice( $options );
953
954 return true;
955 }
956
957 public function print_admin_notice( array $options, $exclude_pages = self::DEFAULT_EXCLUDED_PAGES ) {
958 global $pagenow;
959
960 if ( in_array( $pagenow, $exclude_pages, true ) ) {
961 return;
962 }
963
964 $default_options = [
965 'id' => null,
966 'title' => '',
967 'description' => '',
968 'classes' => [ 'notice', 'e-notice' ], // We include WP's default notice class so it will be properly handled by WP's js handler
969 'type' => '',
970 'dismissible' => true,
971 'icon' => 'eicon-elementor-circle',
972 'button' => [],
973 'button_secondary' => [],
974 ];
975
976 $options = array_replace_recursive( $default_options, $options );
977
978 $notice_classes = $options['classes'];
979 $dismiss_button = '';
980 $icon = '';
981
982 if ( $options['type'] ) {
983 $notice_classes[] = 'e-notice--' . $options['type'];
984 }
985
986 $wrapper_attributes = [
987 'role' => 'region',
988 'aria-label' => esc_html__( 'Elementor notice', 'elementor' ),
989 ];
990
991 if ( $options['dismissible'] ) {
992 $label = esc_html__( 'Dismiss this notice.', 'elementor' );
993 $notice_classes[] = 'e-notice--dismissible';
994 $dismiss_button = '<i class="e-notice__dismiss" role="button" aria-label="' . $label . '" tabindex="0"></i>';
995
996 $wrapper_attributes['data-nonce'] = wp_create_nonce( 'elementor_set_admin_notice_viewed' );
997 }
998
999 if ( $options['icon'] ) {
1000 $notice_classes[] = 'e-notice--extended';
1001 $icon = '<div class="e-notice__icon-wrapper"><i class="' . esc_attr( $options['icon'] ) . '" aria-hidden="true"></i></div>';
1002 }
1003
1004 $wrapper_attributes['class'] = $notice_classes;
1005
1006 if ( $options['id'] ) {
1007 $wrapper_attributes['data-notice_id'] = $options['id'];
1008 }
1009
1010 if ( ! empty( $options['source'] ) ) {
1011 $wrapper_attributes['data-source'] = $options['source'];
1012 }
1013 ?>
1014 <div <?php Utils::print_html_attributes( $wrapper_attributes ); ?>>
1015 <?php echo $dismiss_button; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1016 <div class="e-notice__aside">
1017 <?php echo $icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1018 </div>
1019 <div class="e-notice__content">
1020 <?php if ( $options['title'] ) { ?>
1021 <h3><?php echo wp_kses_post( $options['title'] ); ?></h3>
1022 <?php } ?>
1023
1024 <?php if ( $options['description'] ) { ?>
1025 <p><?php echo wp_kses_post( $options['description'] ); ?></p>
1026 <?php } ?>
1027
1028 <?php if ( ! empty( $options['button']['text'] ) || ! empty( $options['button_secondary']['text'] ) ) { ?>
1029 <div class="e-notice__actions">
1030 <?php
1031 $one_subscription = Hints::is_plugin_connected_to_one_subscription();
1032 foreach ( [ $options['button'], $options['button_secondary'] ] as $index => $button_settings ) {
1033 if ( empty( $button_settings['variant'] ) && $index ) {
1034 $button_settings['variant'] = 'outline';
1035 }
1036
1037 if ( empty( $button_settings['text'] ) ) {
1038 continue;
1039 }
1040
1041 if ( $one_subscription ) {
1042 if ( ! isset( $button_settings['classes'] ) ) {
1043 $button_settings['classes'] = [];
1044 }
1045 if ( ! is_array( $button_settings['classes'] ) ) {
1046 $button_settings['classes'] = [ $button_settings['classes'] ];
1047 }
1048 // index 0 = button, index 1 = button_secondary
1049 $button_class = ( 0 === $index ) ? 'button-primary' : 'button-secondary';
1050 $button_settings['classes'][] = $button_class;
1051 }
1052
1053 $button = new Button( $button_settings );
1054 $button->print_button();
1055 } ?>
1056 </div>
1057 <?php } ?>
1058 </div>
1059 </div>
1060 <?php }
1061
1062 public function admin_notices() {
1063 $this->install_time = Plugin::$instance->get_install_time();
1064 $this->current_screen_id = get_current_screen()->id;
1065
1066 foreach ( $this->plain_notices as $notice ) {
1067 $method_callback = "notice_{$notice}";
1068 if ( $this->$method_callback() ) {
1069 return;
1070 }
1071 }
1072
1073 /** @var Base_Notice $notice_instance */
1074 foreach ( $this->get_notices() as $notice_instance ) {
1075 if ( ! $notice_instance->should_print() ) {
1076 continue;
1077 }
1078
1079 $this->print_admin_notice( $notice_instance->get_config() );
1080
1081 // It exits the method to make sure it prints only one notice.
1082 return;
1083 }
1084 }
1085
1086 public function maybe_log_campaign() {
1087 if ( empty( $_GET['plg_campaign'] ) || empty( $_GET['plg_campaign_name'] ) ) {
1088 return;
1089 }
1090
1091 $allowed_plgs = [
1092 'elementor_image_optimization_campaign',
1093 'elementor_ea11y_campaign',
1094 'elementor_site_mailer_campaign',
1095 ];
1096
1097 if ( ! in_array( $_GET['plg_campaign_name'], $allowed_plgs, true ) ) {
1098 return;
1099 }
1100
1101 if ( ! isset( $_GET['plg_campaign_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['plg_campaign_nonce'] ), sanitize_key( $_GET['plg_campaign_name'] ) ) ) {
1102 return;
1103 }
1104
1105 if ( ! current_user_can( 'manage_options' ) ) {
1106 return;
1107 }
1108
1109 if ( empty( $_GET['plg_source'] ) || empty( $_GET['plg_medium'] ) ) {
1110 return;
1111 }
1112
1113 $campaign_data = [
1114 'source' => sanitize_key( $_GET['plg_source'] ),
1115 'campaign' => sanitize_key( $_GET['plg_campaign'] ),
1116 'medium' => sanitize_key( $_GET['plg_medium'] ),
1117 ];
1118
1119 set_transient( sanitize_key( $_GET['plg_campaign_name'] ), $campaign_data, 30 * DAY_IN_SECONDS );
1120 }
1121
1122 public static function add_plg_campaign_data( $url, $campaign_data ) {
1123
1124 foreach ( [ 'name', 'campaign' ] as $key ) {
1125 if ( empty( $campaign_data[ $key ] ) ) {
1126 return $url;
1127 }
1128 }
1129
1130 return add_query_arg( [
1131 'plg_campaign_name' => $campaign_data['name'],
1132 'plg_campaign' => $campaign_data['campaign'],
1133 'plg_source' => empty( $campaign_data['source'] ) ? '' : $campaign_data['source'],
1134 'plg_medium' => empty( $campaign_data['medium'] ) ? '' : $campaign_data['medium'],
1135 'plg_campaign_nonce' => wp_create_nonce( $campaign_data['name'] ),
1136 ], $url );
1137 }
1138
1139 /**
1140 * @since 2.9.0
1141 * @access public
1142 */
1143 public function __construct() {
1144 add_action( 'admin_notices', [ $this, 'admin_notices' ], 20 );
1145 add_action( 'admin_action_install-plugin', [ $this, 'maybe_log_campaign' ] );
1146 add_action( 'admin_action_activate', [ $this, 'maybe_log_campaign' ] );
1147 }
1148
1149 /**
1150 * Get module name.
1151 *
1152 * Retrieve the module name.
1153 *
1154 * @since 2.9.0
1155 * @access public
1156 *
1157 * @return string Module name.
1158 */
1159 public function get_name() {
1160 return 'admin-notices';
1161 }
1162 }
1163