PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.2
Jetpack – WP Security, Backup, Speed, & Growth v16.2
16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 All 502 releases
← All changes | modules/subscriptions.php +222 -130 12.3.216.2 View file →
@@ -1,25 +1,38 @@
1 1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName)
2 2 /**
3 - * Module Name: Subscriptions
4 - * Module Description: Let visitors subscribe to new posts and comments via email
3 + * Module Name: Newsletter
4 + * Module Description: Grow your subscriber list and deliver your content directly to their email inbox.
5 5 * Sort Order: 9
6 6 * Recommendation Order: 8
7 7 * First Introduced: 1.2
8 8 * Requires Connection: Yes
9 9 * Requires User Connection: Yes
10 - * Auto Activate: No
10 + * Auto Activate: Yes
11 11 * Module Tags: Social
12 12 * Feature: Engagement
13 - * Additional Search Queries: subscriptions, subscription, email, follow, followers, subscribers, signup
13 + * Additional Search Queries: subscriptions, subscription, email, follow, followers, subscribers, signup, newsletter, creator
14 14 */
15 15
16 16 // phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move classes to appropriately-named class files.
17 17
18 +use Automattic\Jetpack\Admin_UI\Admin_Menu;
19 +use Automattic\Jetpack\Connection\Manager as Connection_Manager;
18 20 use Automattic\Jetpack\Connection\XMLRPC_Async_Call;
21 +use Automattic\Jetpack\Newsletter\Settings as Newsletter_Settings;
22 +use Automattic\Jetpack\Redirect;
23 +use Automattic\Jetpack\Status;
24 +use Automattic\Jetpack\Status\Host;
19 25
26 +if ( ! defined( 'ABSPATH' ) ) {
27 + exit( 0 );
28 +}
29 +
20 30 add_action( 'jetpack_modules_loaded', 'jetpack_subscriptions_load' );
21 31
32 +// Loads the User Content Link Redirection feature.
33 +require_once __DIR__ . '/subscriptions/jetpack-user-content-link-redirection.php';
34 +
22 35 /**
23 36 * Loads the Subscriptions module.
24 37 */
25 38 function jetpack_subscriptions_load() {
@@ -36,13 +49,13 @@
36 49 function jetpack_subscriptions_cherry_pick_server_data() {
37 50 $data = array();
38 51
39 52 foreach ( $_SERVER as $key => $value ) {
40 - if ( ! is_string( $value ) || 0 === strpos( $key, 'HTTP_COOKIE' ) ) {
53 + if ( ! is_string( $value ) || str_starts_with( $key, 'HTTP_COOKIE' ) ) {
41 54 continue;
42 55 }
43 56
44 - if ( 0 === strpos( $key, 'HTTP_' ) || in_array( $key, array( 'REMOTE_ADDR', 'REQUEST_URI', 'DOCUMENT_URI' ), true ) ) {
57 + if ( str_starts_with( $key, 'HTTP_' ) || in_array( $key, array( 'REMOTE_ADDR', 'REQUEST_URI', 'DOCUMENT_URI' ), true ) ) {
45 58 $data[ $key ] = $value;
46 59 }
47 60 }
48 61
@@ -50,8 +63,10 @@
50 63 }
51 64
52 65 /**
53 66 * Main class file for the Subscriptions module.
67 + *
68 + * @phan-constructor-used-for-side-effects
54 69 */
55 70 class Jetpack_Subscriptions {
56 71 /**
57 72 * Whether Jetpack has been instantiated or not.
@@ -120,12 +135,31 @@
120 135 add_filter( 'post_updated_messages', array( $this, 'update_published_message' ), 18, 1 );
121 136
122 137 // Set "social_notifications_subscribe" option during the first-time activation.
123 138 add_action( 'jetpack_activate_module_subscriptions', array( $this, 'set_social_notifications_subscribe' ) );
139 + add_action( 'jetpack_activate_module_subscriptions', array( $this, 'set_featured_image_in_email_default' ) );
140 + add_action( 'jetpack_activate_module_subscriptions', array( $this, 'set_newsletter_send_default' ) );
124 141
125 142 // Hide subscription messaging in Publish panel for posts that were published in the past
126 143 add_action( 'init', array( $this, 'register_post_meta' ), 20 );
127 144 add_action( 'transition_post_status', array( $this, 'maybe_set_first_published_status' ), 10, 3 );
145 +
146 + // Add Subscribers menu to Jetpack navigation.
147 + add_action( 'jetpack_admin_menu', array( $this, 'add_subscribers_menu' ) );
148 +
149 + // Customize the configuration URL to lead to the Subscriptions settings.
150 + add_filter(
151 + 'jetpack_module_configuration_url_subscriptions',
152 + function () {
153 + return Jetpack::admin_url( array( 'page' => 'jetpack#/newsletter' ) );
154 + }
155 + );
156 +
157 + // Track categories created through the category editor page
158 + add_action( 'wp_ajax_add-tag', array( $this, 'track_newsletter_category_creation' ), 1 );
159 +
160 + $newsletter_settings = new Newsletter_Settings();
161 + $newsletter_settings::init();
128 162 }
129 163
130 164 /**
131 165 * Jetpack_Subscriptions::xmlrpc_methods()
@@ -347,14 +381,14 @@
347 381 'discussion',
348 382 'stc_enabled'
349 383 );
350 384
351 - /** Email me whenever: Someone follows my blog */
385 + /** Email me whenever: Someone subscribes to my blog */
352 386 /* @since 8.1 */
353 387
354 388 add_settings_section(
355 389 'notifications_section',
356 - __( 'Someone follows my blog', 'jetpack' ),
390 + __( 'Someone subscribes to my blog', 'jetpack' ),
357 391 array( $this, 'social_notifications_subscribe_section' ),
358 392 'discussion'
359 393 );
360 394
@@ -370,39 +404,8 @@
370 404 'discussion',
371 405 'social_notifications_subscribe',
372 406 array( $this, 'social_notifications_subscribe_validate' )
373 407 );
374 -
375 - /** Subscription Messaging Options */
376 -
377 - register_setting(
378 - 'reading',
379 - 'subscription_options',
380 - array( $this, 'validate_settings' )
381 - );
382 -
383 - add_settings_section(
384 - 'email_settings',
385 - __( 'Follower Settings', 'jetpack' ),
386 - array( $this, 'reading_section' ),
387 - 'reading'
388 - );
389 -
390 - add_settings_field(
391 - 'invitation',
392 - __( 'Blog follow email text', 'jetpack' ),
393 - array( $this, 'setting_invitation' ),
394 - 'reading',
395 - 'email_settings'
396 - );
397 -
398 - add_settings_field(
399 - 'comment-follow',
400 - __( 'Comment follow email text', 'jetpack' ),
401 - array( $this, 'setting_comment_follow' ),
402 - 'reading',
403 - 'email_settings'
404 - );
405 408 }
406 409
407 410 /**
408 411 * Discussions setting section blurb.
@@ -461,9 +464,9 @@
461 464 <?php
462 465 }
463 466
464 467 /**
465 - * Someone follows my blog section
468 + * Someone subscribes to my blog section
466 469 *
467 470 * @since 8.1
468 471 */
469 472 public function social_notifications_subscribe_section() {
@@ -487,9 +490,9 @@
487 490 <?php
488 491 }
489 492
490 493 /**
491 - * Someone follows my blog Toggle
494 + * Someone subscribes to my blog Toggle
492 495 *
493 496 * @since 8.1
494 497 */
495 498 public function social_notifications_subscribe_field() {
@@ -499,9 +502,9 @@
499 502 <label>
500 503 <input type="checkbox" name="social_notifications_subscribe" id="social_notifications_subscribe" value="1" <?php checked( $checked ); ?> />
501 504 <?php
502 505 /* translators: this is a label for a setting that starts with "Email me whenever" */
503 - esc_html_e( 'Someone follows my blog', 'jetpack' );
506 + esc_html_e( 'Someone subscribes to my blog', 'jetpack' );
504 507 ?>
505 508 </label>
506 509 <?php
507 510 }
@@ -506,9 +509,9 @@
506 509 <?php
507 510 }
508 511
509 512 /**
510 - * Validate "Someone follows my blog" option
513 + * Validate "Someone subscribes to my blog" option
511 514 *
512 515 * @since 8.1
513 516 *
514 517 * @param String $input the input string to be validated.
@@ -524,81 +527,8 @@
524 527 return 'on';
525 528 }
526 529
527 530 /**
528 - * Validate settings for the Subscriptions module.
529 - *
530 - * @param array $settings Settings to be validated.
531 - */
532 - public function validate_settings( $settings ) {
533 - global $allowedposttags;
534 -
535 - $default = $this->get_default_settings();
536 -
537 - // Blog Follow.
538 - $settings['invitation'] = trim( wp_kses( $settings['invitation'], $allowedposttags ) );
539 - if ( empty( $settings['invitation'] ) ) {
540 - $settings['invitation'] = $default['invitation'];
541 - }
542 -
543 - // Comments Follow (single post).
544 - $settings['comment_follow'] = trim( wp_kses( $settings['comment_follow'], $allowedposttags ) );
545 - if ( empty( $settings['comment_follow'] ) ) {
546 - $settings['comment_follow'] = $default['comment_follow'];
547 - }
548 -
549 - return $settings;
550 - }
551 -
552 - /**
553 - * HTML output helper for Reading section.
554 - */
555 - public function reading_section() {
556 - echo '<p id="follower-settings">';
557 - esc_html_e( 'These settings change emails sent from your blog to followers.', 'jetpack' );
558 - echo '</p>';
559 - }
560 -
561 - /**
562 - * HTML output helper for Invitation section.
563 - */
564 - public function setting_invitation() {
565 - $settings = $this->get_settings();
566 - echo '<textarea name="subscription_options[invitation]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['invitation'] ) . '</textarea>';
567 - echo '<p><span class="description">' . esc_html__( 'Introduction text sent when someone follows your blog. (Site and confirmation details will be automatically added for you.)', 'jetpack' ) . '</span></p>';
568 - }
569 -
570 - /**
571 - * HTML output helper for Comment Follow section.
572 - */
573 - public function setting_comment_follow() {
574 - $settings = $this->get_settings();
575 - echo '<textarea name="subscription_options[comment_follow]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['comment_follow'] ) . '</textarea>';
576 - echo '<p><span class="description">' . esc_html__( 'Introduction text sent when someone follows a post on your blog. (Site and confirmation details will be automatically added for you.)', 'jetpack' ) . '</span></p>';
577 - }
578 -
579 - /**
580 - * Get default settings for the Subscriptions module.
581 - */
582 - public function get_default_settings() {
583 - $site_url = get_home_url();
584 - $display_url = preg_replace( '(^https?://)', '', untrailingslashit( $site_url ) );
585 -
586 - return array(
587 - /* translators: Both %1$s and %2$s is site address */
588 - 'invitation' => sprintf( __( "Howdy,\nYou recently subscribed to <a href='%1\$s'>%2\$s</a> and we need to verify the email you provided. Once you confirm below, you'll be able to receive and read new posts.\n\nIf you believe this is an error, ignore this message and nothing more will happen.", 'jetpack' ), $site_url, $display_url ),
589 - 'comment_follow' => __( "Howdy.\n\nYou recently followed one of my posts. This means you will receive an email when new comments are posted.\n\nTo activate, click confirm below. If you believe this is an error, ignore this message and we'll never bother you again.", 'jetpack' ),
590 - );
591 - }
592 -
593 - /**
594 - * Reeturn merged `subscription_options` option with module default settings.
595 - */
596 - public function get_settings() {
597 - return wp_parse_args( (array) get_option( 'subscription_options' ), $this->get_default_settings() );
598 - }
599 -
600 - /**
601 531 * Jetpack_Subscriptions::subscribe()
602 532 *
603 533 * Send a synchronous XML-RPC subscribe to blog posts or subscribe to post comments request.
604 534 *
@@ -637,8 +567,9 @@
637 567
638 568 if ( $async ) {
639 569 XMLRPC_Async_Call::add_call( 'jetpack.subscribeToSite', 0, $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
640 570 } else {
571 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
641 572 $xml->addCall( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
642 573 }
643 574 }
644 575
@@ -646,19 +577,24 @@
646 577 return;
647 578 }
648 579
649 580 // Call.
581 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
650 582 $xml->query();
651 583
584 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
652 585 if ( $xml->isError() ) {
586 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
653 587 return $xml->get_jetpack_error();
654 588 }
655 589
590 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
656 591 $responses = $xml->getResponse();
657 592
658 593 $r = array();
659 594 foreach ( (array) $responses as $response ) {
660 595 if ( isset( $response['faultCode'] ) || isset( $response['faultString'] ) ) {
596 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
661 597 $r[] = $xml->get_jetpack_error( $response['faultCode'], $response['faultString'] );
662 598 continue;
663 599 }
664 600
@@ -698,10 +634,10 @@
698 634 * When a user submits their email via the blog subscription widget, check the details and call the subsribe() method.
699 635 */
700 636 public function widget_submit() {
701 637 // Check the nonce.
702 - if ( is_user_logged_in() ) {
703 - check_admin_referer( 'blogsub_subscribe_' . get_current_blog_id() );
638 + if ( ! wp_verify_nonce( isset( $_REQUEST['_wpnonce'] ) ? sanitize_key( $_REQUEST['_wpnonce'] ) : '', 'blogsub_subscribe_' . \Jetpack_Options::get_option( 'id' ) ) ) {
639 + return false;
704 640 }
705 641
706 642 if ( empty( $_REQUEST['email'] ) || ! is_string( $_REQUEST['email'] ) ) {
707 643 return false;
@@ -776,9 +712,9 @@
776 712 */
777 713 do_action( 'jetpack_subscriptions_form_submission', $result );
778 714
779 715 wp_safe_redirect( "$redirect#$redirect_fragment" );
780 - exit;
716 + exit( 0 );
781 717 }
782 718
783 719 /**
784 720 * Jetpack_Subscriptions::comment_subscribe_init()
@@ -789,8 +725,13 @@
789 725 */
790 726 public function comment_subscribe_init( $submit_button ) {
791 727 global $post;
792 728
729 + // Subscriptions are only available for posts so far.
730 + if ( ! $post || 'post' !== $post->post_type ) {
731 + return $submit_button;
732 + }
733 +
793 734 $comments_checked = '';
794 735 $blog_checked = '';
795 736
796 737 // Check for a comment / blog submission and set a cookie to retain the setting and check the boxes.
@@ -869,8 +810,19 @@
869 810 * @param int|string $comment_id Comment thread being subscribed to.
870 811 * @param string $approved Comment status.
871 812 */
872 813 public function comment_subscribe_submit( $comment_id, $approved ) {
814 + /**
815 + * Filters whether to skip comment subscription processing.
816 + *
817 + * @since 15.5
818 + *
819 + * @param bool $skip Whether to skip comment subscription. Default false.
820 + */
821 + if ( apply_filters( 'jetpack_subscription_comment_subscribe_skip', false ) ) {
822 + return;
823 + }
824 +
873 825 if ( 'spam' === $approved ) {
874 826 return;
875 827 }
876 828
@@ -933,9 +885,9 @@
933 885 public function set_cookies( $subscribe_to_post = false, $post_id = null, $subscribe_to_blog = false ) {
934 886 $post_id = (int) $post_id;
935 887
936 888 /** This filter is already documented in core/wp-includes/comment-functions.php */
937 - $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
889 + $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', YEAR_IN_SECONDS );
938 890
939 891 /**
940 892 * Filter the Jetpack Comment cookie path.
941 893 *
@@ -958,15 +910,15 @@
958 910 */
959 911 $cookie_domain = apply_filters( 'jetpack_comment_cookie_domain', COOKIE_DOMAIN );
960 912
961 913 if ( $subscribe_to_post && $post_id >= 0 ) {
962 - setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, 1, time() + $cookie_lifetime, $cookie_path, $cookie_domain, is_ssl(), true );
914 + setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, '1', time() + $cookie_lifetime, $cookie_path, $cookie_domain, is_ssl(), true );
963 915 } else {
964 916 setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
965 917 }
966 918
967 919 if ( $subscribe_to_blog ) {
968 - setcookie( 'jetpack_blog_subscribe_' . self::$hash, 1, time() + $cookie_lifetime, $cookie_path, $cookie_domain, is_ssl(), true );
920 + setcookie( 'jetpack_blog_subscribe_' . self::$hash, '1', time() + $cookie_lifetime, $cookie_path, $cookie_domain, is_ssl(), true );
969 921 } else {
970 922 setcookie( 'jetpack_blog_subscribe_' . self::$hash, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
971 923 }
972 924 }
@@ -984,8 +936,26 @@
984 936 }
985 937 }
986 938
987 939 /**
940 + * Set the featured image in email option to `1` when the Subscriptions module is activated in the first time.
941 + *
942 + * @return void
943 + */
944 + public function set_featured_image_in_email_default() {
945 + add_option( 'wpcom_featured_image_in_email', 1 );
946 + }
947 +
948 + /**
949 + * Set the email post to subscribers default option to `1` when the Subscriptions module is activated for the first time.
950 + *
951 + * @return void
952 + */
953 + public function set_newsletter_send_default() {
954 + add_option( 'wpcom_newsletter_send_default', 1 );
955 + }
956 +
957 + /**
988 958 * Save a flag when a post was ever published.
989 959 *
990 960 * It saves the post meta when the post was published and becomes a draft.
991 961 * Then this meta is used to hide subscription messaging in Publish panel.
@@ -994,8 +964,13 @@
994 964 * @param string $old_status The "old" post status of the transition when saved.
995 965 * @param object $post obj The post object.
996 966 */
997 967 public function maybe_set_first_published_status( $new_status, $old_status, $post ) {
968 + // Subscriptions are only available for posts so far.
969 + if ( ! $post instanceof \WP_Post || 'post' !== $post->post_type ) {
970 + return;
971 + }
972 +
998 973 $was_post_ever_published = get_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
999 974 if ( ! $was_post_ever_published && 'publish' === $old_status && 'draft' === $new_status ) {
1000 975 update_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
1001 976 }
@@ -1001,14 +976,24 @@
1001 976 }
1002 977 }
1003 978
1004 979 /**
1005 - * Checks if the current user can publish posts.
980 + * Checks if the current user can edit posts.
1006 981 *
1007 982 * @return bool
1008 983 */
1009 984 public function first_published_status_meta_auth_callback() {
1010 - if ( current_user_can( 'publish_posts' ) ) {
985 + /**
986 + * Filter the capability required to edit the "was ever published" post meta.
987 + *
988 + * @module subscriptions
989 + *
990 + * @since 13.4
991 + *
992 + * @param string $capability User capability needed to edit the "was ever published" meta. Default to edit_posts.
993 + */
994 + $capability = apply_filters( 'jetpack_subscriptions_post_was_ever_published_capability', 'edit_posts' );
995 + if ( current_user_can( $capability ) ) {
1011 996 return true;
1012 997 }
1013 998 return false;
1014 999 }
@@ -1017,22 +1002,129 @@
1017 1002 * Registers the 'post_was_ever_published' post meta for use in the REST API.
1018 1003 */
1019 1004 public function register_post_meta() {
1020 1005 $jetpack_post_was_ever_published = array(
1021 - 'type' => 'boolean',
1022 - 'description' => __( 'Whether the post was ever published.', 'jetpack' ),
1023 - 'single' => true,
1024 - 'default' => false,
1025 - 'show_in_rest' => array(
1006 + 'type' => 'boolean',
1007 + 'description' => __( 'Whether the post was ever published.', 'jetpack' ),
1008 + 'single' => true,
1009 + 'default' => false,
1010 + 'show_in_rest' => array(
1026 1011 'name' => 'jetpack_post_was_ever_published',
1027 1012 ),
1028 - 'auth_callback' => array( $this, 'first_published_status_meta_auth_callback' ),
1013 + 'auth_callback' => array( $this, 'first_published_status_meta_auth_callback' ),
1014 + 'object_subtype' => 'post', // Subscriptions are only for the post post type so far, so we can limit this meta to posts only.
1029 1015 );
1030 1016
1031 1017 register_meta( 'post', '_jetpack_post_was_ever_published', $jetpack_post_was_ever_published );
1032 1018 }
1033 1019
1020 + /**
1021 + * Create a Subscribers menu displayed on self-hosted sites.
1022 + *
1023 + * - It is not displayed on WordPress.com sites.
1024 + * - It directs you to Calypso to the existing Subscribers page.
1025 + * - It is retired once the Newsletter modernization filter is on, since the
1026 + * unified Newsletter page then owns the Subscribers tab.
1027 + *
1028 + * @return void
1029 + */
1030 + public function add_subscribers_menu() {
1031 + /*
1032 + * Referenced as a string literal (mirrors Newsletter\Settings::MODERNIZATION_FILTER)
1033 + * to keep this bootstrap path safe if the packaged Newsletter Settings class does
1034 + * not expose the constant yet.
1035 + */
1036 + if ( apply_filters( 'rsm_jetpack_ui_modernization_newsletter', true ) ) {
1037 + return;
1038 + }
1039 +
1040 + /*
1041 + * Do not display any menu on WoA and WordPress.com Simple sites (unless Classic wp-admin is enabled).
1042 + * They already get a menu item under Users via nav-unification.
1043 + */
1044 + if ( ( new Host() )->is_wpcom_platform() && get_option( 'wpcom_admin_interface' ) !== 'wp-admin' ) {
1045 + return;
1046 + }
1047 +
1048 + $status = new Status();
1049 +
1050 + /*
1051 + * Do not display if we're in Offline mode,
1052 + * or if the user is not connected.
1053 + */
1054 + if (
1055 + $status->is_offline_mode()
1056 + || ! ( new Connection_Manager( 'jetpack' ) )->is_user_connected()
1057 + ) {
1058 + return;
1059 + }
1060 +
1061 + /**
1062 + * Enables the new in development subscribers in wp-admin dashboard.
1063 + *
1064 + * @since 9.5.0
1065 + *
1066 + * @param bool If the new dashboard is enabled. Defaults on for every site; hosts
1067 + * can opt out with this filter.
1068 + */
1069 + if ( apply_filters( 'jetpack_wp_admin_subscriber_management_enabled', true ) ) {
1070 + return;
1071 + }
1072 +
1073 + $blog_id = Connection_Manager::get_site_id( true );
1074 +
1075 + $link = Redirect::get_url(
1076 + 'jetpack-menu-jetpack-manage-subscribers',
1077 + array( 'site' => $blog_id ? $blog_id : $status->get_site_suffix() )
1078 + );
1079 +
1080 + Admin_Menu::add_menu(
1081 + __( 'Subscribers', 'jetpack' ),
1082 + __( 'Subscribers', 'jetpack' ) . ' <span aria-hidden="true">↗</span>',
1083 + 'manage_options',
1084 + esc_url( $link ),
1085 + null,
1086 + 100
1087 + );
1088 + }
1089 +
1090 + /**
1091 + * Record tracks event if categories is created when user enters
1092 + * the edit category page through the newsletter settings page.
1093 + *
1094 + * @return void
1095 + */
1096 + public function track_newsletter_category_creation() {
1097 +
1098 + // phpcs:disable WordPress.Security.NonceVerification.Missing
1099 + if ( empty( $_POST['_wp_http_referer'] ) ) {
1100 + return;
1101 + }
1102 +
1103 + if ( strpos( sanitize_url( wp_unslash( $_POST['_wp_http_referer'] ) ), 'referer=newsletter-categories' ) > -1 ) {
1104 +
1105 + $parent = filter_var( empty( $_POST['parent'] ) ? 0 : wp_unslash( $_POST['parent'] ), FILTER_SANITIZE_NUMBER_INT );
1106 +
1107 + $is_child_category = $parent > 0;
1108 +
1109 + $tracking = new Automattic\Jetpack\Tracking();
1110 + $tracking->tracks_record_event(
1111 + wp_get_current_user(),
1112 + 'jetpack_newsletter_add_category',
1113 + array(
1114 + 'is_child_category' => $is_child_category,
1115 + )
1116 + );
1117 + }
1118 + }
1034 1119 }
1035 1120
1036 1121 Jetpack_Subscriptions::init();
1037 1122
1038 1123 require __DIR__ . '/subscriptions/views.php';
1124 +require __DIR__ . '/subscriptions/subscribe-modal/class-jetpack-subscribe-modal.php';
1125 +require __DIR__ . '/subscriptions/subscribe-overlay/class-jetpack-subscribe-overlay.php';
1126 +require __DIR__ . '/subscriptions/subscribe-floating-button/class-jetpack-subscribe-floating-button.php';
1127 +require __DIR__ . '/subscriptions/newsletter-widget/class-jetpack-newsletter-dashboard-widget.php';
1128 +
1129 +require_once __DIR__ . '/subscriptions/abilities/class-newsletter-abilities.php';
1130 +\Automattic\Jetpack\Plugin\Abilities\Newsletter_Abilities::init();