admin-notices.php (17603B)
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\Plugin; 8 use Elementor\Tracker; 9 use Elementor\User; 10 use Elementor\Utils; 11 use Elementor\Core\Admin\Notices\Base_Notice; 12 use Elementor\Core\Admin\Notices\Elementor_Dev_Notice; 13 14 if ( ! defined( 'ABSPATH' ) ) { 15 exit; // Exit if accessed directly. 16 } 17 18 class Admin_Notices extends Module { 19 20 private $plain_notices = [ 21 'api_notice', 22 'api_upgrade_plugin', 23 'tracker', 24 'rate_us_feedback', 25 'woocommerce_promote', 26 'cf7_promote', 27 'mc4wp_promote', 28 'popup_maker_promote', 29 'role_manager_promote', 30 ]; 31 32 private $elementor_pages_count = null; 33 34 private $install_time = null; 35 36 private $current_screen_id = null; 37 38 private function get_notices() { 39 $notices = [ 40 new Elementor_Dev_Notice(), 41 ]; 42 43 /** 44 * Admin notices. 45 * 46 * Filters Elementor admin notices. 47 * 48 * This hook can be used by external developers to manage existing 49 * admin notice or to add new notices for Elementor addons. 50 * 51 * @param array $notices A list of notice classes. 52 */ 53 $notices = apply_filters( 'elementor/core/admin/notices', $notices ); 54 55 return $notices; 56 } 57 58 private function get_install_time() { 59 if ( null === $this->install_time ) { 60 $this->install_time = Plugin::$instance->get_install_time(); 61 } 62 63 return $this->install_time; 64 } 65 66 private function get_elementor_pages_count() { 67 if ( null === $this->elementor_pages_count ) { 68 $elementor_pages = new \WP_Query( [ 69 'post_type' => 'any', 70 'post_status' => 'publish', 71 'fields' => 'ids', 72 'update_post_meta_cache' => false, 73 'update_post_term_cache' => false, 74 'meta_key' => '_elementor_edit_mode', 75 'meta_value' => 'builder', 76 ] ); 77 78 $this->elementor_pages_count = $elementor_pages->post_count; 79 } 80 81 return $this->elementor_pages_count; 82 } 83 84 private function notice_api_upgrade_plugin() { 85 $upgrade_notice = Api::get_upgrade_notice(); 86 if ( empty( $upgrade_notice ) ) { 87 return false; 88 } 89 90 if ( ! current_user_can( 'update_plugins' ) ) { 91 return false; 92 } 93 94 if ( ! in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library', 'elementor_page_elementor-system-info', 'dashboard' ], true ) ) { 95 return false; 96 } 97 98 // Check if have any upgrades. 99 $update_plugins = get_site_transient( 'update_plugins' ); 100 101 $has_remote_update_package = ! ( empty( $update_plugins ) || empty( $update_plugins->response[ ELEMENTOR_PLUGIN_BASE ] ) || empty( $update_plugins->response[ ELEMENTOR_PLUGIN_BASE ]->package ) ); 102 103 if ( ! $has_remote_update_package && empty( $upgrade_notice['update_link'] ) ) { 104 return false; 105 } 106 107 if ( $has_remote_update_package ) { 108 $product = $update_plugins->response[ ELEMENTOR_PLUGIN_BASE ]; 109 110 $details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $product->slug . '§ion=changelog&TB_iframe=true&width=600&height=800' ); 111 $upgrade_url = wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' . ELEMENTOR_PLUGIN_BASE ), 'upgrade-plugin_' . ELEMENTOR_PLUGIN_BASE ); 112 $new_version = $product->new_version; 113 } else { 114 $upgrade_url = $upgrade_notice['update_link']; 115 $details_url = $upgrade_url; 116 117 $new_version = $upgrade_notice['version']; 118 } 119 120 // Check if have upgrade notices to show. 121 if ( version_compare( ELEMENTOR_VERSION, $upgrade_notice['version'], '>=' ) ) { 122 return false; 123 } 124 125 $notice_id = 'upgrade_notice_' . $upgrade_notice['version']; 126 if ( User::is_user_notice_viewed( $notice_id ) ) { 127 return false; 128 } 129 130 $message = sprintf( 131 /* translators: 1: Details URL, 2: Accessibility text, 3: Version number, 4: Update URL, 5: Accessibility text */ 132 __( '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' ), 133 esc_url( $details_url ), 134 esc_attr( sprintf( 135 /* translators: %s: Elementor version */ 136 __( 'View Elementor version %s details', 'elementor' ), 137 $new_version 138 ) ), 139 $new_version, 140 esc_url( $upgrade_url ), 141 esc_attr( esc_html__( 'Update Elementor Now', 'elementor' ) ) 142 ); 143 144 $options = [ 145 'title' => esc_html__( 'Update Notification', 'elementor' ), 146 'description' => $message, 147 'button' => [ 148 'icon_classes' => 'dashicons dashicons-update', 149 'text' => esc_html__( 'Update Now', 'elementor' ), 150 'url' => $upgrade_url, 151 ], 152 'id' => $notice_id, 153 ]; 154 155 $this->print_admin_notice( $options ); 156 157 return true; 158 } 159 160 private function notice_api_notice() { 161 $admin_notice = Api::get_admin_notice(); 162 if ( empty( $admin_notice ) ) { 163 return false; 164 } 165 166 if ( ! current_user_can( 'manage_options' ) ) { 167 return false; 168 } 169 170 if ( ! in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library', 'elementor_page_elementor-system-info', 'dashboard' ], true ) ) { 171 return false; 172 } 173 174 $notice_id = 'admin_notice_api_' . $admin_notice['notice_id']; 175 if ( User::is_user_notice_viewed( $notice_id ) ) { 176 return false; 177 } 178 179 $options = [ 180 'title' => esc_html__( 'Update Notification', 'elementor' ), 181 'description' => $admin_notice['notice_text'], 182 'id' => $notice_id, 183 ]; 184 185 $this->print_admin_notice( $options ); 186 187 return true; 188 } 189 190 private function notice_tracker() { 191 if ( ! current_user_can( 'manage_options' ) ) { 192 return false; 193 } 194 195 // Show tracker notice after 24 hours from installed time. 196 if ( strtotime( '+24 hours', $this->get_install_time() ) > time() ) { 197 return false; 198 } 199 200 if ( '1' === get_option( 'elementor_tracker_notice' ) ) { 201 return false; 202 } 203 204 if ( Tracker::is_allow_track() ) { 205 return false; 206 } 207 208 if ( 2 > $this->get_elementor_pages_count() ) { 209 return false; 210 } 211 212 // TODO: Skip for development env. 213 $optin_url = wp_nonce_url( add_query_arg( 'elementor_tracker', 'opt_into' ), 'opt_into' ); 214 $optout_url = wp_nonce_url( add_query_arg( 'elementor_tracker', 'opt_out' ), 'opt_out' ); 215 216 $tracker_description_text = esc_html__( 'Become a super contributor by opting in to share non-sensitive plugin data and to receive periodic email updates from us.', 'elementor' ); 217 218 /** 219 * Tracker admin description text. 220 * 221 * Filters the admin notice text for non-sensitive data collection. 222 * 223 * @since 1.0.0 224 * 225 * @param string $tracker_description_text Description text displayed in admin notice. 226 */ 227 $tracker_description_text = apply_filters( 'elementor/tracker/admin_description_text', $tracker_description_text ); 228 229 $message = esc_html( $tracker_description_text ) . ' <a href="https://go.elementor.com/usage-data-tracking/" target="_blank">' . esc_html__( 'Learn more.', 'elementor' ) . '</a>'; 230 231 $options = [ 232 'title' => esc_html__( 'Love using Elementor?', 'elementor' ), 233 'description' => $message, 234 'button' => [ 235 'text' => esc_html__( 'Sure! I\'d love to help', 'elementor' ), 236 'url' => $optin_url, 237 'type' => 'cta', 238 ], 239 'button_secondary' => [ 240 'text' => esc_html__( 'No thanks', 'elementor' ), 241 'url' => $optout_url, 242 'variant' => 'outline', 243 'type' => 'cta', 244 ], 245 ]; 246 247 $this->print_admin_notice( $options ); 248 249 return true; 250 } 251 252 private function notice_rate_us_feedback() { 253 $notice_id = 'rate_us_feedback'; 254 255 if ( ! current_user_can( 'manage_options' ) ) { 256 return false; 257 } 258 259 if ( 'dashboard' !== $this->current_screen_id || User::is_user_notice_viewed( $notice_id ) ) { 260 return false; 261 } 262 263 if ( 10 >= $this->get_elementor_pages_count() ) { 264 return false; 265 } 266 267 $dismiss_url = add_query_arg( [ 268 'action' => 'elementor_set_admin_notice_viewed', 269 'notice_id' => esc_attr( $notice_id ), 270 ], admin_url( 'admin-post.php' ) ); 271 272 $options = [ 273 'title' => esc_html__( 'Congrats!', 'elementor' ), 274 'description' => esc_html__( 'You created over 10 pages with Elementor. Great job! If you can spare a minute, 275 please help us by leaving a five star review on WordPress.org.', 'elementor' ), 276 'id' => $notice_id, 277 'button' => [ 278 'text' => esc_html__( 'Happy To Help', 'elementor' ), 279 'url' => 'https://go.elementor.com/admin-review/', 280 'new_tab' => true, 281 'type' => 'cta', 282 ], 283 'button_secondary' => [ 284 'text' => esc_html__( 'Hide Notification', 'elementor' ), 285 'classes' => [ 'e-notice-dismiss' ], 286 'url' => esc_url_raw( $dismiss_url ), 287 'new_tab' => true, 288 'type' => 'cta', 289 ], 290 ]; 291 292 $this->print_admin_notice( $options ); 293 294 return true; 295 } 296 297 private function notice_woocommerce_promote() { 298 $notice_id = 'woocommerce_promote'; 299 300 if ( Utils::has_pro() || ! function_exists( 'WC' ) ) { 301 return false; 302 } 303 304 if ( ! current_user_can( 'install_plugins' ) ) { 305 return false; 306 } 307 308 if ( ! in_array( $this->current_screen_id, [ 'edit-product', 'woocommerce_page_wc-settings' ], true ) || User::is_user_notice_viewed( $notice_id ) ) { 309 return false; 310 } 311 312 if ( strtotime( '2019-08-01' ) > $this->get_install_time() ) { 313 return false; 314 } 315 316 if ( strtotime( '+24 hours', $this->get_install_time() ) > time() ) { 317 return false; 318 } 319 320 $options = [ 321 'title' => esc_html__( 'Using WooCommerce?', 'elementor' ), 322 'description' => esc_html__( 'With Elementor Pro’s WooCommerce Builder, you’ll be able to design your store without coding!', 'elementor' ), 323 'id' => $notice_id, 324 325 'button' => [ 326 'text' => esc_html__( 'Learn More', 'elementor' ), 327 'url' => 'https://go.elementor.com/plugin-promotion-woocommerce/', 328 'new_tab' => true, 329 'type' => 'cta', 330 ], 331 ]; 332 333 $this->print_admin_notice( $options ); 334 335 return true; 336 } 337 338 private function notice_cf7_promote() { 339 $notice_id = 'cf7_promote'; 340 341 if ( Utils::has_pro() || ! defined( 'WPCF7_VERSION' ) ) { 342 return false; 343 } 344 345 if ( ! current_user_can( 'install_plugins' ) ) { 346 return false; 347 } 348 349 if ( ! in_array( $this->current_screen_id, [ 'toplevel_page_wpcf7', 'contact_page_wpcf7-integration' ], true ) || User::is_user_notice_viewed( $notice_id ) ) { 350 return false; 351 } 352 353 if ( strtotime( '2019-08-01' ) > $this->get_install_time() ) { 354 return false; 355 } 356 357 if ( strtotime( '+24 hours', $this->get_install_time() ) > time() ) { 358 return false; 359 } 360 361 $options = [ 362 'title' => esc_html__( 'Using Elementor & Contact Form 7?', 'elementor' ), 363 'description' => esc_html__( 'Try out Elementor Pro and design your forms visually with one powerful tool.', 'elementor' ), 364 365 'id' => $notice_id, 366 'button' => [ 367 'text' => esc_html__( 'Learn More', 'elementor' ), 368 'url' => 'https://go.elementor.com/plugin-promotion-contactform7/', 369 'new_tab' => true, 370 'type' => 'cta', 371 ], 372 ]; 373 374 $this->print_admin_notice( $options ); 375 376 return true; 377 } 378 379 private function notice_mc4wp_promote() { 380 $notice_id = 'mc4wp_promote'; 381 382 if ( Utils::has_pro() || ! defined( 'MC4WP_VERSION' ) ) { 383 return false; 384 } 385 386 if ( ! current_user_can( 'install_plugins' ) ) { 387 return false; 388 } 389 390 if ( ! in_array( $this->current_screen_id, [ 'toplevel_page_mailchimp-for-wp', 'mc4wp_page_mailchimp-for-wp-forms', 'mc4wp_page_mailchimp-for-wp-integrations', 'mc4wp_page_mailchimp-for-wp-other', 'mc4wp_page_mailchimp-for-wp-extensions' ], true ) || User::is_user_notice_viewed( $notice_id ) ) { 391 return false; 392 } 393 394 if ( strtotime( '2019-08-01' ) > $this->get_install_time() ) { 395 return false; 396 } 397 398 if ( strtotime( '+24 hours', $this->get_install_time() ) > time() ) { 399 return false; 400 } 401 402 $options = [ 403 'title' => esc_html__( 'Want to design better MailChimp forms?', 'elementor' ), 404 'description' => esc_html__( 'Use Elementor Pro and enjoy unlimited integrations, visual design, templates and more.', 'elementor' ), 405 'dismissible' => true, 406 'id' => $notice_id, 407 408 'button' => [ 409 'text' => esc_html__( 'Learn More', 'elementor' ), 410 'url' => 'https://go.elementor.com/plugin-promotion-mc4wp/', 411 'new_tab' => true, 412 'type' => 'cta', 413 ], 414 ]; 415 416 $this->print_admin_notice( $options ); 417 418 return true; 419 } 420 421 private function notice_popup_maker_promote() { 422 $notice_id = 'popup_maker_promote'; 423 424 if ( Utils::has_pro() || ! class_exists( 'Popup_Maker' ) ) { 425 return false; 426 } 427 428 if ( ! current_user_can( 'install_plugins' ) ) { 429 return false; 430 } 431 432 if ( ! in_array( $this->current_screen_id, [ 'edit-popup', 'popup_page_pum-settings' ], true ) || User::is_user_notice_viewed( $notice_id ) ) { 433 return false; 434 } 435 436 if ( strtotime( '2019-08-01' ) > $this->get_install_time() ) { 437 return false; 438 } 439 440 if ( strtotime( '+24 hours', $this->get_install_time() ) > time() ) { 441 return false; 442 } 443 444 $options = [ 445 'title' => esc_html__( 'Using popups on your site?', 'elementor' ), 446 'description' => esc_html__( 'Build outstanding popups using Elementor Pro and get more leads, sales and subscribers.', 'elementor' ), 447 'dismissible' => true, 448 'id' => $notice_id, 449 450 'button' => [ 451 'text' => esc_html__( 'Learn More', 'elementor' ), 452 'url' => 'https://go.elementor.com/plugin-promotion-popupmaker/', 453 'new_tab' => true, 454 'type' => 'cta', 455 ], 456 ]; 457 458 $this->print_admin_notice( $options ); 459 460 return true; 461 } 462 463 private function notice_role_manager_promote() { 464 $notice_id = 'role_manager_promote'; 465 466 if ( Utils::has_pro() ) { 467 return false; 468 } 469 470 if ( ! current_user_can( 'manage_options' ) ) { 471 return false; 472 } 473 474 if ( 'elementor_page_elementor-role-manager' !== $this->current_screen_id || User::is_user_notice_viewed( $notice_id ) ) { 475 return false; 476 } 477 478 $users = new \WP_User_Query( [ 479 'fields' => 'ID', 480 'number' => 10, 481 ] ); 482 483 if ( 5 > $users->get_total() ) { 484 return false; 485 } 486 487 $options = [ 488 'title' => esc_html__( 'Managing a multi-user site?', 'elementor' ), 489 'description' => esc_html__( 'With Elementor Pro, you can control user access and make sure no one messes up your design.', 'elementor' ), 490 'id' => $notice_id, 491 492 'button' => [ 493 'text' => esc_html__( 'Learn More', 'elementor' ), 494 'url' => 'https://go.elementor.com/plugin-promotion-role-manager/', 495 'new_tab' => true, 496 'type' => 'cta', 497 ], 498 ]; 499 500 $this->print_admin_notice( $options ); 501 502 return true; 503 } 504 505 public function print_admin_notice( array $options ) { 506 $default_options = [ 507 'id' => null, 508 'title' => '', 509 'description' => '', 510 'classes' => [ 'notice', 'e-notice' ], // We include WP's default notice class so it will be properly handled by WP's js handler 511 'type' => '', 512 'dismissible' => true, 513 'icon' => 'eicon-elementor', 514 'button' => [], 515 'button_secondary' => [], 516 ]; 517 518 $options = array_replace_recursive( $default_options, $options ); 519 520 $notice_classes = $options['classes']; 521 $dismiss_button = ''; 522 $icon = ''; 523 524 if ( $options['type'] ) { 525 $notice_classes[] = 'e-notice--' . $options['type']; 526 } 527 528 if ( $options['dismissible'] ) { 529 $label = esc_html__( 'Dismiss', 'elementor' ); 530 $notice_classes[] = 'e-notice--dismissible'; 531 $dismiss_button = '<i class="e-notice__dismiss" role="button" aria-label="' . $label . '" tabindex="0"></i>'; 532 } 533 534 if ( $options['icon'] ) { 535 $notice_classes[] = 'e-notice--extended'; 536 $icon = '<div class="e-notice__icon-wrapper"><i class="' . esc_attr( $options['icon'] ) . '" aria-hidden="true"></i></div>'; 537 } 538 539 $wrapper_attributes = [ 540 'class' => $notice_classes, 541 ]; 542 543 if ( $options['id'] ) { 544 $wrapper_attributes['data-notice_id'] = $options['id']; 545 } 546 ?> 547 <div <?php Utils::print_html_attributes( $wrapper_attributes ); ?>> 548 <?php echo $dismiss_button; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> 549 <div class="e-notice__aside"> 550 <?php echo $icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> 551 </div> 552 <div class="e-notice__content"> 553 <?php if ( $options['title'] ) { ?> 554 <h3><?php echo wp_kses_post( $options['title'] ); ?></h3> 555 <?php } ?> 556 557 <?php if ( $options['description'] ) { ?> 558 <p><?php echo wp_kses_post( $options['description'] ); ?></p> 559 <?php } ?> 560 561 <?php if ( ! empty( $options['button']['text'] ) || ! empty( $options['button_secondary']['text'] ) ) { ?> 562 <div class="e-notice__actions"> 563 <?php 564 foreach ( [ $options['button'], $options['button_secondary'] ] as $index => $button_settings ) { 565 if ( empty( $button_settings['variant'] ) && $index ) { 566 $button_settings['variant'] = 'outline'; 567 } 568 569 if ( empty( $button_settings['text'] ) ) { 570 continue; 571 } 572 573 $button = new Button( $button_settings ); 574 $button->print_button(); 575 } ?> 576 </div> 577 <?php } ?> 578 </div> 579 </div> 580 <?php } 581 582 public function admin_notices() { 583 $this->install_time = Plugin::$instance->get_install_time(); 584 $this->current_screen_id = get_current_screen()->id; 585 586 foreach ( $this->plain_notices as $notice ) { 587 $method_callback = "notice_{$notice}"; 588 if ( $this->$method_callback() ) { 589 return; 590 } 591 } 592 593 /** @var Base_Notice $notice_instance */ 594 foreach ( $this->get_notices() as $notice_instance ) { 595 if ( ! $notice_instance->should_print() ) { 596 continue; 597 } 598 599 $this->print_admin_notice( $notice_instance->get_config() ); 600 601 // It exits the method to make sure it prints only one notice. 602 return; 603 } 604 } 605 606 /** 607 * @since 2.9.0 608 * @access public 609 */ 610 public function __construct() { 611 add_action( 'admin_notices', [ $this, 'admin_notices' ], 20 ); 612 } 613 614 /** 615 * Get module name. 616 * 617 * Retrieve the module name. 618 * 619 * @since 2.9.0 620 * @access public 621 * 622 * @return string Module name. 623 */ 624 public function get_name() { 625 return 'admin-notices'; 626 } 627 }