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

914 lines 26.2 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
23 private $plain_notices = [
24 'api_notice',
25 'api_upgrade_plugin',
26 'tracker',
27 'tracker_last_update',
28 'rate_us_feedback',
29 'role_manager_promote',
30 'experiment_promotion',
31 'send_app_promotion',
32 'site_mailer_promotion',
33 'plugin_image_optimization',
34 'ally_pages_promotion',
35 ];
36
37 private $elementor_pages_count = null;
38
39 private $install_time = null;
40
41 private $current_screen_id = null;
42
43 private function get_notices() {
44 /**
45 * Admin notices.
46 *
47 * Filters Elementor admin notices.
48 *
49 * This hook can be used by external developers to manage existing
50 * admin notice or to add new notices for Elementor add-ons.
51 *
52 * @param array $notices A list of notice classes.
53 */
54 $notices = apply_filters( 'elementor/core/admin/notices', [] );
55
56 return $notices;
57 }
58
59 private function get_install_time() {
60 if ( null === $this->install_time ) {
61 $this->install_time = Plugin::$instance->get_install_time();
62 }
63
64 return $this->install_time;
65 }
66
67 private function get_elementor_pages_count() {
68 if ( null === $this->elementor_pages_count ) {
69 $elementor_pages = new \WP_Query( [
70 'no_found_rows' => true,
71 'post_type' => 'any',
72 'post_status' => 'publish',
73 'fields' => 'ids',
74 'update_post_meta_cache' => false,
75 'update_post_term_cache' => false,
76 'meta_key' => '_elementor_edit_mode',
77 'meta_value' => 'builder',
78 ] );
79
80 $this->elementor_pages_count = $elementor_pages->post_count;
81 }
82
83 return $this->elementor_pages_count;
84 }
85
86 private function notice_api_upgrade_plugin() {
87 $upgrade_notice = Api::get_upgrade_notice();
88 if ( empty( $upgrade_notice ) ) {
89 return false;
90 }
91
92 if ( ! current_user_can( 'update_plugins' ) ) {
93 return false;
94 }
95
96 if ( ! $this->is_elementor_admin_screen_with_system_info() ) {
97 return false;
98 }
99
100 // Check for upgrades.
101 $update_plugins = get_site_transient( 'update_plugins' );
102
103 $has_remote_update_package = ! ( empty( $update_plugins ) || empty( $update_plugins->response[ ELEMENTOR_PLUGIN_BASE ] ) || empty( $update_plugins->response[ ELEMENTOR_PLUGIN_BASE ]->package ) );
104
105 if ( ! $has_remote_update_package && empty( $upgrade_notice['update_link'] ) ) {
106 return false;
107 }
108
109 if ( $has_remote_update_package ) {
110 $product = $update_plugins->response[ ELEMENTOR_PLUGIN_BASE ];
111
112 $details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $product->slug . '&section=changelog&TB_iframe=true&width=600&height=800' );
113 $upgrade_url = wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' . ELEMENTOR_PLUGIN_BASE ), 'upgrade-plugin_' . ELEMENTOR_PLUGIN_BASE );
114 $new_version = $product->new_version;
115 } else {
116 $upgrade_url = $upgrade_notice['update_link'];
117 $details_url = $upgrade_url;
118
119 $new_version = $upgrade_notice['version'];
120 }
121
122 // Check if upgrade messages should be shown.
123 if ( version_compare( ELEMENTOR_VERSION, $upgrade_notice['version'], '>=' ) ) {
124 return false;
125 }
126
127 $notice_id = 'upgrade_notice_' . $upgrade_notice['version'];
128 if ( User::is_user_notice_viewed( $notice_id ) ) {
129 return false;
130 }
131
132 $message = sprintf(
133 /* translators: 1: Details URL, 2: Accessibility text, 3: Version number, 4: Update URL, 5: Accessibility text. */
134 __( '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' ),
135 esc_url( $details_url ),
136 esc_attr( sprintf(
137 /* translators: %s: Elementor version. */
138 __( 'View Elementor version %s details', 'elementor' ),
139 $new_version
140 ) ),
141 $new_version,
142 esc_url( $upgrade_url ),
143 esc_attr( esc_html__( 'Update Now', 'elementor' ) )
144 );
145
146 $options = [
147 'title' => esc_html__( 'Update Notification', 'elementor' ),
148 'description' => $message,
149 'button' => [
150 'icon_classes' => 'dashicons dashicons-update',
151 'text' => esc_html__( 'Update Now', 'elementor' ),
152 'url' => $upgrade_url,
153 ],
154 'id' => $notice_id,
155 ];
156
157 $this->print_admin_notice( $options );
158
159 return true;
160 }
161
162 private function notice_api_notice() {
163 $admin_notice = Api::get_admin_notice();
164 if ( empty( $admin_notice ) ) {
165 return false;
166 }
167
168 if ( ! current_user_can( 'manage_options' ) ) {
169 return false;
170 }
171
172 if ( ! $this->is_elementor_admin_screen_with_system_info() ) {
173 return false;
174 }
175
176 $notice_id = 'admin_notice_api_' . $admin_notice['notice_id'];
177 if ( User::is_user_notice_viewed( $notice_id ) ) {
178 return false;
179 }
180
181 $options = [
182 'title' => esc_html__( 'Update Notification', 'elementor' ),
183 'description' => $admin_notice['notice_text'],
184 'id' => $notice_id,
185 ];
186
187 $this->print_admin_notice( $options );
188
189 return true;
190 }
191
192 private function notice_tracker() {
193 if ( ! current_user_can( 'manage_options' ) ) {
194 return false;
195 }
196
197 // Show tracker notice after 24 hours from installed time.
198 if ( strtotime( '+24 hours', $this->get_install_time() ) > time() ) {
199 return false;
200 }
201
202 if ( '1' === get_option( 'elementor_tracker_notice' ) ) {
203 return false;
204 }
205
206 if ( Tracker::is_allow_track() ) {
207 return false;
208 }
209
210 if ( 2 > $this->get_elementor_pages_count() ) {
211 return false;
212 }
213
214 // TODO: Skip for development env.
215 $optin_url = wp_nonce_url( add_query_arg( 'elementor_tracker', 'opt_into' ), 'opt_into' );
216 $optout_url = wp_nonce_url( add_query_arg( 'elementor_tracker', 'opt_out' ), 'opt_out' );
217
218 $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' );
219
220 /**
221 * Tracker admin description text.
222 *
223 * Filters the admin notice text for non-sensitive data collection.
224 *
225 * @since 1.0.0
226 *
227 * @param string $tracker_description_text Description text displayed in admin notice.
228 */
229 $tracker_description_text = apply_filters( 'elementor/tracker/admin_description_text', $tracker_description_text );
230
231 $message = esc_html( $tracker_description_text ) . ' <a href="https://go.elementor.com/usage-data-tracking/" target="_blank">' . esc_html__( 'Learn more.', 'elementor' ) . '</a>';
232
233 $options = [
234 'title' => esc_html__( 'Want to shape the future of web creation?', 'elementor' ),
235 'description' => $message,
236 'dismissible' => false,
237 'button' => [
238 'text' => esc_html__( 'Sure! I\'d love to help', 'elementor' ),
239 'url' => $optin_url,
240 'type' => 'cta',
241 ],
242 'button_secondary' => [
243 'text' => esc_html__( 'No thanks', 'elementor' ),
244 'url' => $optout_url,
245 'variant' => 'outline',
246 'type' => 'cta',
247 ],
248 ];
249
250 $this->print_admin_notice( $options );
251
252 return true;
253 }
254
255 private function notice_tracker_last_update() {
256 if ( ! current_user_can( 'manage_options' ) ) {
257 return false;
258 }
259
260 if ( ! Tracker::has_terms_changed() ) {
261 return false;
262 }
263
264 $notice_id = 'tracker_last_update_' . Tracker::LAST_TERMS_UPDATED;
265
266 if ( User::is_user_notice_viewed( $notice_id ) ) {
267 return false;
268 }
269
270 $optin_url = wp_nonce_url( add_query_arg( 'elementor_tracker', 'opt_into' ), 'opt_into' );
271
272 $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' );
273
274 $options = [
275 'id' => $notice_id,
276 'title' => esc_html__( 'Update regarding usage data collection', 'elementor' ),
277 'description' => $message,
278 'button' => [
279 'text' => esc_html__( 'Opt in', 'elementor' ),
280 'url' => $optin_url,
281 'type' => 'cta',
282 ],
283 'button_secondary' => [
284 'text' => esc_html__( 'Learn more', 'elementor' ),
285 'url' => 'https://go.elementor.com/wp-dash-update-usage-notice/',
286 'new_tab' => true,
287 'type' => 'cta',
288 ],
289 ];
290
291 $this->print_admin_notice( $options );
292
293 return true;
294 }
295
296 private function notice_rate_us_feedback() {
297 $notice_id = 'rate_us_feedback';
298
299 if ( ! current_user_can( 'manage_options' ) ) {
300 return false;
301 }
302
303 if ( 'dashboard' !== $this->current_screen_id || User::is_user_notice_viewed( $notice_id ) ) {
304 return false;
305 }
306
307 if ( 10 >= $this->get_elementor_pages_count() ) {
308 return false;
309 }
310
311 $dismiss_url = add_query_arg( [
312 'action' => 'elementor_set_admin_notice_viewed',
313 'notice_id' => esc_attr( $notice_id ),
314 '_wpnonce' => wp_create_nonce( 'elementor_set_admin_notice_viewed' ),
315 ], admin_url( 'admin-post.php' ) );
316
317 $options = [
318 'title' => esc_html__( 'Congrats!', 'elementor' ),
319 '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' ),
320 'id' => $notice_id,
321 'button' => [
322 'text' => esc_html__( 'Happy To Help', 'elementor' ),
323 'url' => 'https://go.elementor.com/admin-review/',
324 'new_tab' => true,
325 'type' => 'cta',
326 ],
327 'button_secondary' => [
328 'text' => esc_html__( 'Hide Notification', 'elementor' ),
329 'classes' => [ 'e-notice-dismiss' ],
330 'url' => esc_url_raw( $dismiss_url ),
331 'new_tab' => true,
332 'type' => 'cta',
333 ],
334 ];
335
336 $this->print_admin_notice( $options );
337
338 return true;
339 }
340
341 private function notice_role_manager_promote() {
342 $notice_id = 'role_manager_promote';
343
344 if ( Utils::has_pro() ) {
345 return false;
346 }
347
348 if ( ! current_user_can( 'manage_options' ) ) {
349 return false;
350 }
351
352 if ( 'elementor_page_elementor-role-manager' !== $this->current_screen_id || User::is_user_notice_viewed( $notice_id ) ) {
353 return false;
354 }
355
356 $users = new \WP_User_Query( [
357 'fields' => 'ID',
358 'number' => 10,
359 ] );
360
361 if ( 5 > $users->get_total() ) {
362 return false;
363 }
364
365 $options = [
366 'title' => esc_html__( 'Managing a multi-user site?', 'elementor' ),
367 'description' => esc_html__( 'With Elementor Pro, you can control user access and make sure no one messes up your design.', 'elementor' ),
368 'id' => $notice_id,
369
370 'button' => [
371 'text' => esc_html__( 'Learn More', 'elementor' ),
372 'url' => 'https://go.elementor.com/plugin-promotion-role-manager/',
373 'new_tab' => true,
374 'type' => 'cta',
375 ],
376 ];
377
378 $options = Filtered_Promotions_Manager::get_filtered_promotion_data( $options, 'core/admin/notice_role_manager_promote', 'button', 'url' );
379
380 $this->print_admin_notice( $options );
381
382 return true;
383 }
384
385 private function notice_experiment_promotion() {
386 $notice_id = 'experiment_promotion';
387
388 if ( ! current_user_can( 'manage_options' ) || User::is_user_notice_viewed( $notice_id ) ) {
389 return false;
390 }
391
392 $experiments = Plugin::$instance->experiments;
393 $is_all_performance_features_active = (
394 $experiments->is_feature_active( 'e_font_icon_svg' )
395 );
396
397 if ( $is_all_performance_features_active ) {
398 return false;
399 }
400
401 $options = [
402 'title' => esc_html__( 'Improve your site’s performance score.', 'elementor' ),
403 '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' ),
404 'id' => $notice_id,
405 'button' => [
406 'text' => esc_html__( 'Try it out', 'elementor' ),
407 'url' => Settings::get_settings_tab_url( 'experiments' ),
408 'type' => 'cta',
409 ],
410 'button_secondary' => [
411 'text' => esc_html__( 'Learn more', 'elementor' ),
412 'url' => 'https://go.elementor.com/wp-dash-experiment-promotion/',
413 'new_tab' => true,
414 'type' => 'cta',
415 ],
416 ];
417
418 $this->print_admin_notice( $options );
419
420 return true;
421 }
422
423 private function site_has_forms_plugins() {
424 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' );
425 }
426
427 private function site_has_woocommerce() {
428 return class_exists( 'WooCommerce' );
429 }
430
431 private function get_installed_form_plugin_name() {
432 static $detected_form_plugin = null;
433
434 if ( null !== $detected_form_plugin ) {
435 return $detected_form_plugin;
436 }
437
438 $form_plugins_constants_to_name_mapper = [
439 'WPFORMS_VERSION' => 'WPForms',
440 'WPCF7_VERSION' => 'Contact Form 7',
441 ];
442
443 foreach ( $form_plugins_constants_to_name_mapper as $constant => $name ) {
444 if ( defined( $constant ) ) {
445 $detected_form_plugin = $name;
446 return $detected_form_plugin;
447 }
448 }
449
450 $form_plugins_classes_to_name_mapper = [
451 '\GFCommon' => 'Gravity Forms',
452 '\Ninja_Forms' => 'Ninja Forms',
453 ];
454
455 foreach ( $form_plugins_classes_to_name_mapper as $class => $name ) {
456 if ( class_exists( $class ) ) {
457 $detected_form_plugin = $name;
458 return $detected_form_plugin;
459 }
460 }
461
462 $detected_form_plugin = false;
463 return $detected_form_plugin;
464 }
465
466 private function notice_send_app_promotion() {
467 $notice_id = 'send_app_promotion';
468
469 if ( ! $this->is_elementor_page() && ! $this->is_elementor_admin_screen() ) {
470 return false;
471 }
472
473 if ( time() < $this->get_install_time() + ( 60 * DAY_IN_SECONDS ) ) {
474 return false;
475 }
476
477 if ( ! current_user_can( 'install_plugins' ) || User::is_user_notice_viewed( $notice_id ) ) {
478 return false;
479 }
480
481 $plugin_file_path = 'send/send-app.php';
482 $plugin_slug = 'send-app';
483
484 $cta_data = $this->get_plugin_cta_data( $plugin_slug, $plugin_file_path );
485 if ( empty( $cta_data ) ) {
486 return false;
487 }
488
489 $title = sprintf( esc_html__( 'Turn leads into loyal shoppers', 'elementor' ) );
490
491 $options = [
492 'title' => $title,
493 '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' ),
494 'id' => $notice_id,
495 'type' => 'cta',
496 'button' => [
497 'text' => $cta_data['text'],
498 'url' => $cta_data['url'],
499 'type' => 'cta',
500 ],
501 'button_secondary' => [
502 'text' => esc_html__( 'Learn more', 'elementor' ),
503 'url' => 'https://go.elementor.com/Formslearnmore',
504 'new_tab' => true,
505 'type' => 'cta',
506 ],
507 ];
508
509 $this->print_admin_notice( $options );
510
511 return true;
512 }
513
514 private function notice_ally_pages_promotion() {
515 global $pagenow;
516 $notice_id = 'ally_pages_promotion';
517
518 if ( 'edit.php' !== $pagenow || empty( $_GET['post_type'] ) || 'page' !== $_GET['post_type'] ) {
519 return false;
520 }
521
522 if ( ! current_user_can( 'manage_options' ) || User::is_user_notice_viewed( $notice_id ) ) {
523 return false;
524 }
525
526 $plugin_file_path = 'pojo-accessibility/pojo-accessibility.php';
527 $plugin_slug = 'pojo-accessibility';
528
529 $cta_data = $this->get_plugin_cta_data( $plugin_slug, $plugin_file_path );
530 if ( empty( $cta_data ) ) {
531 return false;
532 }
533
534 $options = [
535 'title' => esc_html__( 'Make sure your site has an accessibility statement page', 'elementor' ),
536 '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' ),
537 'id' => $notice_id,
538 'type' => 'cta',
539 'button' => [
540 'text' => $cta_data['text'],
541 'url' => self::add_plg_campaign_data( $cta_data['url'], [
542 'name' => 'elementor_ea11y_campaign',
543 'campaign' => 'acc-statement-plg-pages',
544 'source' => 'wp-pages',
545 'medium' => 'wp-dash',
546 ] ),
547 'type' => 'cta',
548 ],
549 'button_secondary' => [
550 'text' => esc_html__( 'Learn more', 'elementor' ),
551 'url' => 'https://go.elementor.com/acc-plg-learn-more',
552 'new_tab' => true,
553 'type' => 'cta',
554 ],
555 ];
556
557 $this->print_admin_notice( $options );
558
559 return true;
560 }
561
562 private function notice_site_mailer_promotion() {
563 $notice_id = 'site_mailer_promotion';
564 $has_forms = $this->site_has_forms_plugins();
565 $has_woocommerce = $this->site_has_woocommerce();
566
567 if ( ! $has_forms && ! $has_woocommerce ) {
568 return false;
569 }
570
571 if ( ! $this->is_elementor_page() && ! $this->is_elementor_admin_screen() ) {
572 return false;
573 }
574
575 if ( ( Utils::has_pro() && ! $has_woocommerce ) || ! current_user_can( 'install_plugins' ) || User::is_user_notice_viewed( $notice_id ) ) {
576 return false;
577 }
578
579 $plugin_file_path = 'site-mailer/site-mailer.php';
580 $plugin_slug = 'site-mailer';
581
582 $cta_data = $this->get_plugin_cta_data( $plugin_slug, $plugin_file_path );
583 if ( empty( $cta_data ) ) {
584 return false;
585 }
586
587 $options = [
588 'title' => esc_html__( 'Ensure your form emails avoid the spam folder!', 'elementor' ),
589 'description' => esc_html__( 'Use Site Mailer for improved email deliverability, detailed email logs, and an easy setup.', 'elementor' ),
590 'id' => $notice_id,
591 'type' => 'cta',
592 'button' => [
593 'text' => $cta_data['text'],
594 'url' => $cta_data['url'],
595 'type' => 'cta',
596 ],
597 'button_secondary' => [
598 'text' => esc_html__( 'Learn more', 'elementor' ),
599 'url' => 'https://go.elementor.com/sm-core-form/',
600 'new_tab' => true,
601 'type' => 'cta',
602 ],
603 ];
604
605 if ( $this->should_render_woocommerce_hint( $has_forms, $has_woocommerce ) ) {
606 // We include WP's default notice class so it will be properly handled by WP's js handler
607 // And add a new one to distinguish between the two types of notices
608 $options['classes'] = [ 'notice', 'e-notice', 'sm-notice-wc' ];
609 $options['title'] = esc_html__( 'Improve Transactional Email Deliverability', 'elementor' );
610 $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' );
611 }
612
613 $this->print_admin_notice( $options );
614
615 return true;
616 }
617
618 private function should_render_woocommerce_hint( $has_forms, $has_woocommerce ): bool {
619 if ( ! $has_forms && ! $has_woocommerce ) {
620 return false;
621 }
622
623 if ( ! $has_forms && $has_woocommerce ) {
624 return true;
625 }
626
627 if ( $has_forms && $has_woocommerce && Utils::has_pro() ) {
628 return true;
629 }
630
631 if ( ! $has_woocommerce ) {
632 return false;
633 }
634
635 return (bool) wp_rand( 0, 1 );
636 }
637
638 private function is_elementor_page(): bool {
639 return 0 === strpos( $this->current_screen_id, 'elementor_page' );
640 }
641
642 private function is_elementor_admin_screen(): bool {
643 return in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library' ], true );
644 }
645
646 private function is_elementor_admin_screen_with_system_info(): bool {
647 return in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library', 'elementor_page_elementor-system-info', 'dashboard' ], true );
648 }
649
650 private function get_plugin_cta_data( $plugin_slug, $plugin_file_path ) {
651 if ( is_plugin_active( $plugin_file_path ) ) {
652 return false;
653 }
654
655 if ( $this->is_plugin_installed( $plugin_file_path ) ) {
656 $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 );
657 $cta_text = esc_html__( 'Activate Plugin', 'elementor' );
658 } else {
659 $url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $plugin_slug ), 'install-plugin_' . $plugin_slug );
660 $cta_text = esc_html__( 'Install Plugin', 'elementor' );
661 }
662
663 return [
664 'url' => $url,
665 'text' => $cta_text,
666 ];
667 }
668
669 /**
670 * For testing purposes
671 */
672 public function get_elementor_version() {
673 return ELEMENTOR_VERSION;
674 }
675
676 private function notice_plugin_image_optimization() {
677 $notice_id = 'plugin_image_optimization';
678
679 if ( 'upload' !== $this->current_screen_id ) {
680 return false;
681 }
682
683 if ( ! current_user_can( 'manage_options' ) || User::is_user_notice_viewed( $notice_id ) ) {
684 return false;
685 }
686
687 $attachments = new \WP_Query( [
688 'post_type' => 'attachment',
689 'post_status' => 'any',
690 'fields' => 'ids',
691 ] );
692
693 if ( 1 > $attachments->found_posts ) {
694 return false;
695 }
696
697 $plugin_file_path = 'image-optimization/image-optimization.php';
698 $plugin_slug = 'image-optimization';
699
700 $cta_data = $this->get_plugin_cta_data( $plugin_slug, $plugin_file_path );
701
702 if ( empty( $cta_data ) ) {
703 return false;
704 }
705
706 $options = [
707 'title' => esc_html__( 'Speed up your website with Image Optimizer by Elementor', 'elementor' ),
708 'description' => esc_html__( 'Automatically compress and optimize images, resize larger files, or convert to WebP. Optimize images individually, in bulk, or on upload.', 'elementor' ),
709 'id' => $notice_id,
710 'type' => 'cta',
711 'button_secondary' => [
712 'text' => $cta_data['text'],
713 'url' => $cta_data['url'],
714 'type' => 'cta',
715 ],
716 ];
717
718 $this->print_admin_notice( $options );
719
720 return true;
721 }
722
723 private function is_plugin_installed( $file_path ): bool {
724 $installed_plugins = get_plugins();
725
726 return isset( $installed_plugins[ $file_path ] );
727 }
728
729 public function print_admin_notice( array $options, $exclude_pages = self::DEFAULT_EXCLUDED_PAGES ) {
730 global $pagenow;
731
732 if ( in_array( $pagenow, $exclude_pages, true ) ) {
733 return;
734 }
735
736 $default_options = [
737 'id' => null,
738 'title' => '',
739 'description' => '',
740 'classes' => [ 'notice', 'e-notice' ], // We include WP's default notice class so it will be properly handled by WP's js handler
741 'type' => '',
742 'dismissible' => true,
743 'icon' => 'eicon-elementor',
744 'button' => [],
745 'button_secondary' => [],
746 ];
747
748 $options = array_replace_recursive( $default_options, $options );
749
750 $notice_classes = $options['classes'];
751 $dismiss_button = '';
752 $icon = '';
753
754 if ( $options['type'] ) {
755 $notice_classes[] = 'e-notice--' . $options['type'];
756 }
757
758 $wrapper_attributes = [];
759
760 if ( $options['dismissible'] ) {
761 $label = esc_html__( 'Dismiss this notice.', 'elementor' );
762 $notice_classes[] = 'e-notice--dismissible';
763 $dismiss_button = '<i class="e-notice__dismiss" role="button" aria-label="' . $label . '" tabindex="0"></i>';
764
765 $wrapper_attributes['data-nonce'] = wp_create_nonce( 'elementor_set_admin_notice_viewed' );
766 }
767
768 if ( $options['icon'] ) {
769 $notice_classes[] = 'e-notice--extended';
770 $icon = '<div class="e-notice__icon-wrapper"><i class="' . esc_attr( $options['icon'] ) . '" aria-hidden="true"></i></div>';
771 }
772
773 $wrapper_attributes['class'] = $notice_classes;
774
775 if ( $options['id'] ) {
776 $wrapper_attributes['data-notice_id'] = $options['id'];
777 }
778 ?>
779 <div <?php Utils::print_html_attributes( $wrapper_attributes ); ?>>
780 <?php echo $dismiss_button; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
781 <div class="e-notice__aside">
782 <?php echo $icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
783 </div>
784 <div class="e-notice__content">
785 <?php if ( $options['title'] ) { ?>
786 <h3><?php echo wp_kses_post( $options['title'] ); ?></h3>
787 <?php } ?>
788
789 <?php if ( $options['description'] ) { ?>
790 <p><?php echo wp_kses_post( $options['description'] ); ?></p>
791 <?php } ?>
792
793 <?php if ( ! empty( $options['button']['text'] ) || ! empty( $options['button_secondary']['text'] ) ) { ?>
794 <div class="e-notice__actions">
795 <?php
796 foreach ( [ $options['button'], $options['button_secondary'] ] as $index => $button_settings ) {
797 if ( empty( $button_settings['variant'] ) && $index ) {
798 $button_settings['variant'] = 'outline';
799 }
800
801 if ( empty( $button_settings['text'] ) ) {
802 continue;
803 }
804
805 $button = new Button( $button_settings );
806 $button->print_button();
807 } ?>
808 </div>
809 <?php } ?>
810 </div>
811 </div>
812 <?php }
813
814 public function admin_notices() {
815 $this->install_time = Plugin::$instance->get_install_time();
816 $this->current_screen_id = get_current_screen()->id;
817
818 foreach ( $this->plain_notices as $notice ) {
819 $method_callback = "notice_{$notice}";
820 if ( $this->$method_callback() ) {
821 return;
822 }
823 }
824
825 /** @var Base_Notice $notice_instance */
826 foreach ( $this->get_notices() as $notice_instance ) {
827 if ( ! $notice_instance->should_print() ) {
828 continue;
829 }
830
831 $this->print_admin_notice( $notice_instance->get_config() );
832
833 // It exits the method to make sure it prints only one notice.
834 return;
835 }
836 }
837
838 public function maybe_log_campaign() {
839 if ( empty( $_GET['plg_campaign'] ) || empty( $_GET['plg_campaign_name'] ) ) {
840 return;
841 }
842
843 $allowed_plgs = [
844 'elementor_image_optimization_campaign',
845 'elementor_ea11y_campaign',
846 'elementor_site_mailer_campaign',
847 ];
848
849 if ( ! in_array( $_GET['plg_campaign_name'], $allowed_plgs, true ) ) {
850 return;
851 }
852
853 if ( ! isset( $_GET['plg_campaign_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['plg_campaign_nonce'] ), sanitize_key( $_GET['plg_campaign_name'] ) ) ) {
854 return;
855 }
856
857 if ( ! current_user_can( 'manage_options' ) ) {
858 return;
859 }
860
861 if ( empty( $_GET['plg_source'] ) || empty( $_GET['plg_medium'] ) ) {
862 return;
863 }
864
865 $campaign_data = [
866 'source' => sanitize_key( $_GET['plg_source'] ),
867 'campaign' => sanitize_key( $_GET['plg_campaign'] ),
868 'medium' => sanitize_key( $_GET['plg_medium'] ),
869 ];
870
871 set_transient( sanitize_key( $_GET['plg_campaign_name'] ), $campaign_data, 30 * DAY_IN_SECONDS );
872 }
873
874 public static function add_plg_campaign_data( $url, $campaign_data ) {
875
876 foreach ( [ 'name', 'campaign' ] as $key ) {
877 if ( empty( $campaign_data[ $key ] ) ) {
878 return $url;
879 }
880 }
881
882 return add_query_arg( [
883 'plg_campaign_name' => $campaign_data['name'],
884 'plg_campaign' => $campaign_data['campaign'],
885 'plg_source' => empty( $campaign_data['source'] ) ? '' : $campaign_data['source'],
886 'plg_medium' => empty( $campaign_data['medium'] ) ? '' : $campaign_data['medium'],
887 'plg_campaign_nonce' => wp_create_nonce( $campaign_data['name'] ),
888 ], $url );
889 }
890
891 /**
892 * @since 2.9.0
893 * @access public
894 */
895 public function __construct() {
896 add_action( 'admin_notices', [ $this, 'admin_notices' ], 20 );
897 add_action( 'admin_action_install-plugin', [ $this, 'maybe_log_campaign' ] );
898 }
899
900 /**
901 * Get module name.
902 *
903 * Retrieve the module name.
904 *
905 * @since 2.9.0
906 * @access public
907 *
908 * @return string Module name.
909 */
910 public function get_name() {
911 return 'admin-notices';
912 }
913 }
914