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

915 lines 26.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\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 $experiments->is_feature_active( 'e_optimized_markup' )
396 );
397
398 if ( $is_all_performance_features_active ) {
399 return false;
400 }
401
402 $options = [
403 'title' => esc_html__( 'Improve your site’s performance score.', 'elementor' ),
404 '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' ),
405 'id' => $notice_id,
406 'button' => [
407 'text' => esc_html__( 'Try it out', 'elementor' ),
408 'url' => Settings::get_settings_tab_url( 'experiments' ),
409 'type' => 'cta',
410 ],
411 'button_secondary' => [
412 'text' => esc_html__( 'Learn more', 'elementor' ),
413 'url' => 'https://go.elementor.com/wp-dash-experiment-promotion/',
414 'new_tab' => true,
415 'type' => 'cta',
416 ],
417 ];
418
419 $this->print_admin_notice( $options );
420
421 return true;
422 }
423
424 private function site_has_forms_plugins() {
425 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' );
426 }
427
428 private function site_has_woocommerce() {
429 return class_exists( 'WooCommerce' );
430 }
431
432 private function get_installed_form_plugin_name() {
433 static $detected_form_plugin = null;
434
435 if ( null !== $detected_form_plugin ) {
436 return $detected_form_plugin;
437 }
438
439 $form_plugins_constants_to_name_mapper = [
440 'WPFORMS_VERSION' => 'WPForms',
441 'WPCF7_VERSION' => 'Contact Form 7',
442 ];
443
444 foreach ( $form_plugins_constants_to_name_mapper as $constant => $name ) {
445 if ( defined( $constant ) ) {
446 $detected_form_plugin = $name;
447 return $detected_form_plugin;
448 }
449 }
450
451 $form_plugins_classes_to_name_mapper = [
452 '\GFCommon' => 'Gravity Forms',
453 '\Ninja_Forms' => 'Ninja Forms',
454 ];
455
456 foreach ( $form_plugins_classes_to_name_mapper as $class => $name ) {
457 if ( class_exists( $class ) ) {
458 $detected_form_plugin = $name;
459 return $detected_form_plugin;
460 }
461 }
462
463 $detected_form_plugin = false;
464 return $detected_form_plugin;
465 }
466
467 private function notice_send_app_promotion() {
468 $notice_id = 'send_app_promotion';
469
470 if ( ! $this->is_elementor_page() && ! $this->is_elementor_admin_screen() ) {
471 return false;
472 }
473
474 if ( time() < $this->get_install_time() + ( 60 * DAY_IN_SECONDS ) ) {
475 return false;
476 }
477
478 if ( ! current_user_can( 'install_plugins' ) || User::is_user_notice_viewed( $notice_id ) ) {
479 return false;
480 }
481
482 $plugin_file_path = 'send/send-app.php';
483 $plugin_slug = 'send-app';
484
485 $cta_data = $this->get_plugin_cta_data( $plugin_slug, $plugin_file_path );
486 if ( empty( $cta_data ) ) {
487 return false;
488 }
489
490 $title = sprintf( esc_html__( 'Turn leads into loyal shoppers', 'elementor' ) );
491
492 $options = [
493 'title' => $title,
494 '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' ),
495 'id' => $notice_id,
496 'type' => 'cta',
497 'button' => [
498 'text' => $cta_data['text'],
499 'url' => $cta_data['url'],
500 'type' => 'cta',
501 ],
502 'button_secondary' => [
503 'text' => esc_html__( 'Learn more', 'elementor' ),
504 'url' => 'https://go.elementor.com/Formslearnmore',
505 'new_tab' => true,
506 'type' => 'cta',
507 ],
508 ];
509
510 $this->print_admin_notice( $options );
511
512 return true;
513 }
514
515 private function notice_ally_pages_promotion() {
516 global $pagenow;
517 $notice_id = 'ally_pages_promotion';
518
519 if ( 'edit.php' !== $pagenow || empty( $_GET['post_type'] ) || 'page' !== $_GET['post_type'] ) {
520 return false;
521 }
522
523 if ( ! current_user_can( 'manage_options' ) || User::is_user_notice_viewed( $notice_id ) ) {
524 return false;
525 }
526
527 $plugin_file_path = 'pojo-accessibility/pojo-accessibility.php';
528 $plugin_slug = 'pojo-accessibility';
529
530 $cta_data = $this->get_plugin_cta_data( $plugin_slug, $plugin_file_path );
531 if ( empty( $cta_data ) ) {
532 return false;
533 }
534
535 $options = [
536 'title' => esc_html__( 'Make sure your site has an accessibility statement page', 'elementor' ),
537 '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' ),
538 'id' => $notice_id,
539 'type' => 'cta',
540 'button' => [
541 'text' => $cta_data['text'],
542 'url' => self::add_plg_campaign_data( $cta_data['url'], [
543 'name' => 'elementor_ea11y_campaign',
544 'campaign' => 'acc-statement-plg-pages',
545 'source' => 'wp-pages',
546 'medium' => 'wp-dash',
547 ] ),
548 'type' => 'cta',
549 ],
550 'button_secondary' => [
551 'text' => esc_html__( 'Learn more', 'elementor' ),
552 'url' => 'https://go.elementor.com/acc-plg-learn-more',
553 'new_tab' => true,
554 'type' => 'cta',
555 ],
556 ];
557
558 $this->print_admin_notice( $options );
559
560 return true;
561 }
562
563 private function notice_site_mailer_promotion() {
564 $notice_id = 'site_mailer_promotion';
565 $has_forms = $this->site_has_forms_plugins();
566 $has_woocommerce = $this->site_has_woocommerce();
567
568 if ( ! $has_forms && ! $has_woocommerce ) {
569 return false;
570 }
571
572 if ( ! $this->is_elementor_page() && ! $this->is_elementor_admin_screen() ) {
573 return false;
574 }
575
576 if ( ( Utils::has_pro() && ! $has_woocommerce ) || ! current_user_can( 'install_plugins' ) || User::is_user_notice_viewed( $notice_id ) ) {
577 return false;
578 }
579
580 $plugin_file_path = 'site-mailer/site-mailer.php';
581 $plugin_slug = 'site-mailer';
582
583 $cta_data = $this->get_plugin_cta_data( $plugin_slug, $plugin_file_path );
584 if ( empty( $cta_data ) ) {
585 return false;
586 }
587
588 $options = [
589 'title' => esc_html__( 'Ensure your form emails avoid the spam folder!', 'elementor' ),
590 'description' => esc_html__( 'Use Site Mailer for improved email deliverability, detailed email logs, and an easy setup.', 'elementor' ),
591 'id' => $notice_id,
592 'type' => 'cta',
593 'button' => [
594 'text' => $cta_data['text'],
595 'url' => $cta_data['url'],
596 'type' => 'cta',
597 ],
598 'button_secondary' => [
599 'text' => esc_html__( 'Learn more', 'elementor' ),
600 'url' => 'https://go.elementor.com/sm-core-form/',
601 'new_tab' => true,
602 'type' => 'cta',
603 ],
604 ];
605
606 if ( $this->should_render_woocommerce_hint( $has_forms, $has_woocommerce ) ) {
607 // We include WP's default notice class so it will be properly handled by WP's js handler
608 // And add a new one to distinguish between the two types of notices
609 $options['classes'] = [ 'notice', 'e-notice', 'sm-notice-wc' ];
610 $options['title'] = esc_html__( 'Improve Transactional Email Deliverability', 'elementor' );
611 $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' );
612 }
613
614 $this->print_admin_notice( $options );
615
616 return true;
617 }
618
619 private function should_render_woocommerce_hint( $has_forms, $has_woocommerce ): bool {
620 if ( ! $has_forms && ! $has_woocommerce ) {
621 return false;
622 }
623
624 if ( ! $has_forms && $has_woocommerce ) {
625 return true;
626 }
627
628 if ( $has_forms && $has_woocommerce && Utils::has_pro() ) {
629 return true;
630 }
631
632 if ( ! $has_woocommerce ) {
633 return false;
634 }
635
636 return (bool) wp_rand( 0, 1 );
637 }
638
639 private function is_elementor_page(): bool {
640 return 0 === strpos( $this->current_screen_id, 'elementor_page' );
641 }
642
643 private function is_elementor_admin_screen(): bool {
644 return in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library' ], true );
645 }
646
647 private function is_elementor_admin_screen_with_system_info(): bool {
648 return in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library', 'elementor_page_elementor-system-info', 'dashboard' ], true );
649 }
650
651 private function get_plugin_cta_data( $plugin_slug, $plugin_file_path ) {
652 if ( is_plugin_active( $plugin_file_path ) ) {
653 return false;
654 }
655
656 if ( $this->is_plugin_installed( $plugin_file_path ) ) {
657 $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 );
658 $cta_text = esc_html__( 'Activate Plugin', 'elementor' );
659 } else {
660 $url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $plugin_slug ), 'install-plugin_' . $plugin_slug );
661 $cta_text = esc_html__( 'Install Plugin', 'elementor' );
662 }
663
664 return [
665 'url' => $url,
666 'text' => $cta_text,
667 ];
668 }
669
670 /**
671 * For testing purposes
672 */
673 public function get_elementor_version() {
674 return ELEMENTOR_VERSION;
675 }
676
677 private function notice_plugin_image_optimization() {
678 $notice_id = 'plugin_image_optimization';
679
680 if ( 'upload' !== $this->current_screen_id ) {
681 return false;
682 }
683
684 if ( ! current_user_can( 'manage_options' ) || User::is_user_notice_viewed( $notice_id ) ) {
685 return false;
686 }
687
688 $attachments = new \WP_Query( [
689 'post_type' => 'attachment',
690 'post_status' => 'any',
691 'fields' => 'ids',
692 ] );
693
694 if ( 1 > $attachments->found_posts ) {
695 return false;
696 }
697
698 $plugin_file_path = 'image-optimization/image-optimization.php';
699 $plugin_slug = 'image-optimization';
700
701 $cta_data = $this->get_plugin_cta_data( $plugin_slug, $plugin_file_path );
702
703 if ( empty( $cta_data ) ) {
704 return false;
705 }
706
707 $options = [
708 'title' => esc_html__( 'Speed up your website with Image Optimizer by Elementor', 'elementor' ),
709 'description' => esc_html__( 'Automatically compress and optimize images, resize larger files, or convert to WebP. Optimize images individually, in bulk, or on upload.', 'elementor' ),
710 'id' => $notice_id,
711 'type' => 'cta',
712 'button_secondary' => [
713 'text' => $cta_data['text'],
714 'url' => $cta_data['url'],
715 'type' => 'cta',
716 ],
717 ];
718
719 $this->print_admin_notice( $options );
720
721 return true;
722 }
723
724 private function is_plugin_installed( $file_path ): bool {
725 $installed_plugins = get_plugins();
726
727 return isset( $installed_plugins[ $file_path ] );
728 }
729
730 public function print_admin_notice( array $options, $exclude_pages = self::DEFAULT_EXCLUDED_PAGES ) {
731 global $pagenow;
732
733 if ( in_array( $pagenow, $exclude_pages, true ) ) {
734 return;
735 }
736
737 $default_options = [
738 'id' => null,
739 'title' => '',
740 'description' => '',
741 'classes' => [ 'notice', 'e-notice' ], // We include WP's default notice class so it will be properly handled by WP's js handler
742 'type' => '',
743 'dismissible' => true,
744 'icon' => 'eicon-elementor',
745 'button' => [],
746 'button_secondary' => [],
747 ];
748
749 $options = array_replace_recursive( $default_options, $options );
750
751 $notice_classes = $options['classes'];
752 $dismiss_button = '';
753 $icon = '';
754
755 if ( $options['type'] ) {
756 $notice_classes[] = 'e-notice--' . $options['type'];
757 }
758
759 $wrapper_attributes = [];
760
761 if ( $options['dismissible'] ) {
762 $label = esc_html__( 'Dismiss this notice.', 'elementor' );
763 $notice_classes[] = 'e-notice--dismissible';
764 $dismiss_button = '<i class="e-notice__dismiss" role="button" aria-label="' . $label . '" tabindex="0"></i>';
765
766 $wrapper_attributes['data-nonce'] = wp_create_nonce( 'elementor_set_admin_notice_viewed' );
767 }
768
769 if ( $options['icon'] ) {
770 $notice_classes[] = 'e-notice--extended';
771 $icon = '<div class="e-notice__icon-wrapper"><i class="' . esc_attr( $options['icon'] ) . '" aria-hidden="true"></i></div>';
772 }
773
774 $wrapper_attributes['class'] = $notice_classes;
775
776 if ( $options['id'] ) {
777 $wrapper_attributes['data-notice_id'] = $options['id'];
778 }
779 ?>
780 <div <?php Utils::print_html_attributes( $wrapper_attributes ); ?>>
781 <?php echo $dismiss_button; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
782 <div class="e-notice__aside">
783 <?php echo $icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
784 </div>
785 <div class="e-notice__content">
786 <?php if ( $options['title'] ) { ?>
787 <h3><?php echo wp_kses_post( $options['title'] ); ?></h3>
788 <?php } ?>
789
790 <?php if ( $options['description'] ) { ?>
791 <p><?php echo wp_kses_post( $options['description'] ); ?></p>
792 <?php } ?>
793
794 <?php if ( ! empty( $options['button']['text'] ) || ! empty( $options['button_secondary']['text'] ) ) { ?>
795 <div class="e-notice__actions">
796 <?php
797 foreach ( [ $options['button'], $options['button_secondary'] ] as $index => $button_settings ) {
798 if ( empty( $button_settings['variant'] ) && $index ) {
799 $button_settings['variant'] = 'outline';
800 }
801
802 if ( empty( $button_settings['text'] ) ) {
803 continue;
804 }
805
806 $button = new Button( $button_settings );
807 $button->print_button();
808 } ?>
809 </div>
810 <?php } ?>
811 </div>
812 </div>
813 <?php }
814
815 public function admin_notices() {
816 $this->install_time = Plugin::$instance->get_install_time();
817 $this->current_screen_id = get_current_screen()->id;
818
819 foreach ( $this->plain_notices as $notice ) {
820 $method_callback = "notice_{$notice}";
821 if ( $this->$method_callback() ) {
822 return;
823 }
824 }
825
826 /** @var Base_Notice $notice_instance */
827 foreach ( $this->get_notices() as $notice_instance ) {
828 if ( ! $notice_instance->should_print() ) {
829 continue;
830 }
831
832 $this->print_admin_notice( $notice_instance->get_config() );
833
834 // It exits the method to make sure it prints only one notice.
835 return;
836 }
837 }
838
839 public function maybe_log_campaign() {
840 if ( empty( $_GET['plg_campaign'] ) || empty( $_GET['plg_campaign_name'] ) ) {
841 return;
842 }
843
844 $allowed_plgs = [
845 'elementor_image_optimization_campaign',
846 'elementor_ea11y_campaign',
847 'elementor_site_mailer_campaign',
848 ];
849
850 if ( ! in_array( $_GET['plg_campaign_name'], $allowed_plgs, true ) ) {
851 return;
852 }
853
854 if ( ! isset( $_GET['plg_campaign_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['plg_campaign_nonce'] ), sanitize_key( $_GET['plg_campaign_name'] ) ) ) {
855 return;
856 }
857
858 if ( ! current_user_can( 'manage_options' ) ) {
859 return;
860 }
861
862 if ( empty( $_GET['plg_source'] ) || empty( $_GET['plg_medium'] ) ) {
863 return;
864 }
865
866 $campaign_data = [
867 'source' => sanitize_key( $_GET['plg_source'] ),
868 'campaign' => sanitize_key( $_GET['plg_campaign'] ),
869 'medium' => sanitize_key( $_GET['plg_medium'] ),
870 ];
871
872 set_transient( sanitize_key( $_GET['plg_campaign_name'] ), $campaign_data, 30 * DAY_IN_SECONDS );
873 }
874
875 public static function add_plg_campaign_data( $url, $campaign_data ) {
876
877 foreach ( [ 'name', 'campaign' ] as $key ) {
878 if ( empty( $campaign_data[ $key ] ) ) {
879 return $url;
880 }
881 }
882
883 return add_query_arg( [
884 'plg_campaign_name' => $campaign_data['name'],
885 'plg_campaign' => $campaign_data['campaign'],
886 'plg_source' => empty( $campaign_data['source'] ) ? '' : $campaign_data['source'],
887 'plg_medium' => empty( $campaign_data['medium'] ) ? '' : $campaign_data['medium'],
888 'plg_campaign_nonce' => wp_create_nonce( $campaign_data['name'] ),
889 ], $url );
890 }
891
892 /**
893 * @since 2.9.0
894 * @access public
895 */
896 public function __construct() {
897 add_action( 'admin_notices', [ $this, 'admin_notices' ], 20 );
898 add_action( 'admin_action_install-plugin', [ $this, 'maybe_log_campaign' ] );
899 }
900
901 /**
902 * Get module name.
903 *
904 * Retrieve the module name.
905 *
906 * @since 2.9.0
907 * @access public
908 *
909 * @return string Module name.
910 */
911 public function get_name() {
912 return 'admin-notices';
913 }
914 }
915