PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-beta
Jetpack – WP Security, Backup, Speed, & Growth v16.3-beta
16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 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 All 507 releases
← All changes | modules/subscriptions.php +183 -172 12.6.4 → 16.3-beta View file →
@@ -1,29 +1,39 @@
1 1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName)
2 2 /**
3 3 * Module Name: Newsletter
4 - * Module Description: Let visitors subscribe to new posts and comments via email
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, newsletter
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;
18 19 use Automattic\Jetpack\Connection\Manager as Connection_Manager;
19 20 use Automattic\Jetpack\Connection\XMLRPC_Async_Call;
21 +use Automattic\Jetpack\Newsletter\Settings as Newsletter_Settings;
22 +use Automattic\Jetpack\Newsletter\Urls as Newsletter_Urls;
20 23 use Automattic\Jetpack\Redirect;
21 24 use Automattic\Jetpack\Status;
22 25 use Automattic\Jetpack\Status\Host;
23 26
27 +if ( ! defined( 'ABSPATH' ) ) {
28 + exit( 0 );
29 +}
30 +
24 31 add_action( 'jetpack_modules_loaded', 'jetpack_subscriptions_load' );
25 32
33 +// Loads the User Content Link Redirection feature.
34 +require_once __DIR__ . '/subscriptions/jetpack-user-content-link-redirection.php';
35 +
26 36 /**
27 37 * Loads the Subscriptions module.
28 38 */
29 39 function jetpack_subscriptions_load() {
@@ -40,13 +50,13 @@
40 50 function jetpack_subscriptions_cherry_pick_server_data() {
41 51 $data = array();
42 52
43 53 foreach ( $_SERVER as $key => $value ) {
44 - if ( ! is_string( $value ) || 0 === strpos( $key, 'HTTP_COOKIE' ) ) {
54 + if ( ! is_string( $value ) || str_starts_with( $key, 'HTTP_COOKIE' ) ) {
45 55 continue;
46 56 }
47 57
48 - if ( 0 === strpos( $key, 'HTTP_' ) || in_array( $key, array( 'REMOTE_ADDR', 'REQUEST_URI', 'DOCUMENT_URI' ), true ) ) {
58 + if ( str_starts_with( $key, 'HTTP_' ) || in_array( $key, array( 'REMOTE_ADDR', 'REQUEST_URI', 'DOCUMENT_URI' ), true ) ) {
49 59 $data[ $key ] = $value;
50 60 }
51 61 }
52 62
@@ -54,8 +64,10 @@
54 64 }
55 65
56 66 /**
57 67 * Main class file for the Subscriptions module.
68 + *
69 + * @phan-constructor-used-for-side-effects
58 70 */
59 71 class Jetpack_Subscriptions {
60 72 /**
61 73 * Whether Jetpack has been instantiated or not.
@@ -124,8 +136,10 @@
124 136 add_filter( 'post_updated_messages', array( $this, 'update_published_message' ), 18, 1 );
125 137
126 138 // Set "social_notifications_subscribe" option during the first-time activation.
127 139 add_action( 'jetpack_activate_module_subscriptions', array( $this, 'set_social_notifications_subscribe' ) );
140 + add_action( 'jetpack_activate_module_subscriptions', array( $this, 'set_featured_image_in_email_default' ) );
141 + add_action( 'jetpack_activate_module_subscriptions', array( $this, 'set_newsletter_send_default' ) );
128 142
129 143 // Hide subscription messaging in Publish panel for posts that were published in the past
130 144 add_action( 'init', array( $this, 'register_post_meta' ), 20 );
131 145 add_action( 'transition_post_status', array( $this, 'maybe_set_first_published_status' ), 10, 3 );
@@ -131,8 +145,22 @@
131 145 add_action( 'transition_post_status', array( $this, 'maybe_set_first_published_status' ), 10, 3 );
132 146
133 147 // Add Subscribers menu to Jetpack navigation.
134 148 add_action( 'jetpack_admin_menu', array( $this, 'add_subscribers_menu' ) );
149 +
150 + // Customize the configuration URL to lead to the Subscriptions settings.
151 + add_filter(
152 + 'jetpack_module_configuration_url_subscriptions',
153 + function () {
154 + return Newsletter_Urls::get_newsletter_settings_url();
155 + }
156 + );
157 +
158 + // Track categories created through the category editor page
159 + add_action( 'wp_ajax_add-tag', array( $this, 'track_newsletter_category_creation' ), 1 );
160 +
161 + $newsletter_settings = new Newsletter_Settings();
162 + $newsletter_settings::init();
135 163 }
136 164
137 165 /**
138 166 * Jetpack_Subscriptions::xmlrpc_methods()
@@ -354,32 +382,14 @@
354 382 'discussion',
355 383 'stc_enabled'
356 384 );
357 385
358 - /** Enable Subscribe Modal */
359 -
360 - /** This filter is documented in plugins/jetpack/modules/subscriptions/subscribe-module/class-jetpack-subscribe-module.php */
361 - if ( apply_filters( 'jetpack_subscriptions_modal_enabled', false ) ) {
362 - add_settings_field(
363 - 'jetpack_subscriptions_comment_subscribe',
364 - __( 'Enable Subscribe Modal', 'jetpack' ),
365 - array( $this, 'subscribe_modal_setting' ),
366 - 'discussion',
367 - 'jetpack_subscriptions'
368 - );
369 -
370 - register_setting(
371 - 'discussion',
372 - 'sm_enabled'
373 - );
374 - }
375 -
376 - /** Email me whenever: Someone follows my blog */
386 + /** Email me whenever: Someone subscribes to my blog */
377 387 /* @since 8.1 */
378 388
379 389 add_settings_section(
380 390 'notifications_section',
381 - __( 'Someone follows my blog', 'jetpack' ),
391 + __( 'Someone subscribes to my blog', 'jetpack' ),
382 392 array( $this, 'social_notifications_subscribe_section' ),
383 393 'discussion'
384 394 );
385 395
@@ -395,39 +405,8 @@
395 405 'discussion',
396 406 'social_notifications_subscribe',
397 407 array( $this, 'social_notifications_subscribe_validate' )
398 408 );
399 -
400 - /** Subscription Messaging Options */
401 -
402 - register_setting(
403 - 'reading',
404 - 'subscription_options',
405 - array( $this, 'validate_settings' )
406 - );
407 -
408 - add_settings_section(
409 - 'email_settings',
410 - __( 'Follower Settings', 'jetpack' ),
411 - array( $this, 'reading_section' ),
412 - 'reading'
413 - );
414 -
415 - add_settings_field(
416 - 'invitation',
417 - __( 'Blog follow email text', 'jetpack' ),
418 - array( $this, 'setting_invitation' ),
419 - 'reading',
420 - 'email_settings'
421 - );
422 -
423 - add_settings_field(
424 - 'comment-follow',
425 - __( 'Comment follow email text', 'jetpack' ),
426 - array( $this, 'setting_comment_follow' ),
427 - 'reading',
428 - 'email_settings'
429 - );
430 409 }
431 410
432 411 /**
433 412 * Discussions setting section blurb.
@@ -486,25 +465,9 @@
486 465 <?php
487 466 }
488 467
489 468 /**
490 - * Subscribe Modal Toggle.
491 - */
492 - public function subscribe_modal_setting() {
493 -
494 - $sm_enabled = get_option( 'sm_enabled', 1 );
495 - ?>
496 -
497 - <p class="description">
498 - <input type="checkbox" name="sm_enabled" id="jetpack-subscribe-modal" value="1" <?php checked( $sm_enabled, 1 ); ?> />
499 - <?php esc_html_e( 'Show a popup subscribe modal to readers.', 'jetpack' ); ?>
500 - </p>
501 -
502 - <?php
503 - }
504 -
505 - /**
506 - * Someone follows my blog section
469 + * Someone subscribes to my blog section
507 470 *
508 471 * @since 8.1
509 472 */
510 473 public function social_notifications_subscribe_section() {
@@ -528,9 +491,9 @@
528 491 <?php
529 492 }
530 493
531 494 /**
532 - * Someone follows my blog Toggle
495 + * Someone subscribes to my blog Toggle
533 496 *
534 497 * @since 8.1
535 498 */
536 499 public function social_notifications_subscribe_field() {
@@ -540,9 +503,9 @@
540 503 <label>
541 504 <input type="checkbox" name="social_notifications_subscribe" id="social_notifications_subscribe" value="1" <?php checked( $checked ); ?> />
542 505 <?php
543 506 /* translators: this is a label for a setting that starts with "Email me whenever" */
544 - esc_html_e( 'Someone follows my blog', 'jetpack' );
507 + esc_html_e( 'Someone subscribes to my blog', 'jetpack' );
545 508 ?>
546 509 </label>
547 510 <?php
548 511 }
@@ -547,9 +510,9 @@
547 510 <?php
548 511 }
549 512
550 513 /**
551 - * Validate "Someone follows my blog" option
514 + * Validate "Someone subscribes to my blog" option
552 515 *
553 516 * @since 8.1
554 517 *
555 518 * @param String $input the input string to be validated.
@@ -565,81 +528,8 @@
565 528 return 'on';
566 529 }
567 530
568 531 /**
569 - * Validate settings for the Subscriptions module.
570 - *
571 - * @param array $settings Settings to be validated.
572 - */
573 - public function validate_settings( $settings ) {
574 - global $allowedposttags;
575 -
576 - $default = $this->get_default_settings();
577 -
578 - // Blog Follow.
579 - $settings['invitation'] = trim( wp_kses( $settings['invitation'], $allowedposttags ) );
580 - if ( empty( $settings['invitation'] ) ) {
581 - $settings['invitation'] = $default['invitation'];
582 - }
583 -
584 - // Comments Follow (single post).
585 - $settings['comment_follow'] = trim( wp_kses( $settings['comment_follow'], $allowedposttags ) );
586 - if ( empty( $settings['comment_follow'] ) ) {
587 - $settings['comment_follow'] = $default['comment_follow'];
588 - }
589 -
590 - return $settings;
591 - }
592 -
593 - /**
594 - * HTML output helper for Reading section.
595 - */
596 - public function reading_section() {
597 - echo '<p id="follower-settings">';
598 - esc_html_e( 'These settings change emails sent from your blog to followers.', 'jetpack' );
599 - echo '</p>';
600 - }
601 -
602 - /**
603 - * HTML output helper for Invitation section.
604 - */
605 - public function setting_invitation() {
606 - $settings = $this->get_settings();
607 - echo '<textarea name="subscription_options[invitation]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['invitation'] ) . '</textarea>';
608 - 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>';
609 - }
610 -
611 - /**
612 - * HTML output helper for Comment Follow section.
613 - */
614 - public function setting_comment_follow() {
615 - $settings = $this->get_settings();
616 - echo '<textarea name="subscription_options[comment_follow]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['comment_follow'] ) . '</textarea>';
617 - 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>';
618 - }
619 -
620 - /**
621 - * Get default settings for the Subscriptions module.
622 - */
623 - public function get_default_settings() {
624 - $site_url = get_home_url();
625 - $display_url = preg_replace( '(^https?://)', '', untrailingslashit( $site_url ) );
626 -
627 - return array(
628 - /* translators: Both %1$s and %2$s is site address */
629 - '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 ),
630 - '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' ),
631 - );
632 - }
633 -
634 - /**
635 - * Reeturn merged `subscription_options` option with module default settings.
636 - */
637 - public function get_settings() {
638 - return wp_parse_args( (array) get_option( 'subscription_options' ), $this->get_default_settings() );
639 - }
640 -
641 - /**
642 532 * Jetpack_Subscriptions::subscribe()
643 533 *
644 534 * Send a synchronous XML-RPC subscribe to blog posts or subscribe to post comments request.
645 535 *
@@ -678,8 +568,9 @@
678 568
679 569 if ( $async ) {
680 570 XMLRPC_Async_Call::add_call( 'jetpack.subscribeToSite', 0, $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
681 571 } else {
572 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
682 573 $xml->addCall( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
683 574 }
684 575 }
685 576
@@ -687,19 +578,24 @@
687 578 return;
688 579 }
689 580
690 581 // Call.
582 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
691 583 $xml->query();
692 584
585 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
693 586 if ( $xml->isError() ) {
587 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
694 588 return $xml->get_jetpack_error();
695 589 }
696 590
591 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
697 592 $responses = $xml->getResponse();
698 593
699 594 $r = array();
700 595 foreach ( (array) $responses as $response ) {
701 596 if ( isset( $response['faultCode'] ) || isset( $response['faultString'] ) ) {
597 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
702 598 $r[] = $xml->get_jetpack_error( $response['faultCode'], $response['faultString'] );
703 599 continue;
704 600 }
705 601
@@ -739,10 +635,10 @@
739 635 * When a user submits their email via the blog subscription widget, check the details and call the subsribe() method.
740 636 */
741 637 public function widget_submit() {
742 638 // Check the nonce.
743 - if ( is_user_logged_in() ) {
744 - check_admin_referer( 'blogsub_subscribe_' . get_current_blog_id() );
639 + if ( ! wp_verify_nonce( isset( $_REQUEST['_wpnonce'] ) ? sanitize_key( $_REQUEST['_wpnonce'] ) : '', 'blogsub_subscribe_' . \Jetpack_Options::get_option( 'id' ) ) ) {
640 + return false;
745 641 }
746 642
747 643 if ( empty( $_REQUEST['email'] ) || ! is_string( $_REQUEST['email'] ) ) {
748 644 return false;
@@ -817,9 +713,9 @@
817 713 */
818 714 do_action( 'jetpack_subscriptions_form_submission', $result );
819 715
820 716 wp_safe_redirect( "$redirect#$redirect_fragment" );
821 - exit;
717 + exit( 0 );
822 718 }
823 719
824 720 /**
825 721 * Jetpack_Subscriptions::comment_subscribe_init()
@@ -830,8 +726,13 @@
830 726 */
831 727 public function comment_subscribe_init( $submit_button ) {
832 728 global $post;
833 729
730 + // Subscriptions are only available for posts so far.
731 + if ( ! $post || 'post' !== $post->post_type ) {
732 + return $submit_button;
733 + }
734 +
834 735 $comments_checked = '';
835 736 $blog_checked = '';
836 737
837 738 // Check for a comment / blog submission and set a cookie to retain the setting and check the boxes.
@@ -910,8 +811,19 @@
910 811 * @param int|string $comment_id Comment thread being subscribed to.
911 812 * @param string $approved Comment status.
912 813 */
913 814 public function comment_subscribe_submit( $comment_id, $approved ) {
815 + /**
816 + * Filters whether to skip comment subscription processing.
817 + *
818 + * @since 15.5
819 + *
820 + * @param bool $skip Whether to skip comment subscription. Default false.
821 + */
822 + if ( apply_filters( 'jetpack_subscription_comment_subscribe_skip', false ) ) {
823 + return;
824 + }
825 +
914 826 if ( 'spam' === $approved ) {
915 827 return;
916 828 }
917 829
@@ -974,9 +886,9 @@
974 886 public function set_cookies( $subscribe_to_post = false, $post_id = null, $subscribe_to_blog = false ) {
975 887 $post_id = (int) $post_id;
976 888
977 889 /** This filter is already documented in core/wp-includes/comment-functions.php */
978 - $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
890 + $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', YEAR_IN_SECONDS );
979 891
980 892 /**
981 893 * Filter the Jetpack Comment cookie path.
982 894 *
@@ -999,15 +911,15 @@
999 911 */
1000 912 $cookie_domain = apply_filters( 'jetpack_comment_cookie_domain', COOKIE_DOMAIN );
1001 913
1002 914 if ( $subscribe_to_post && $post_id >= 0 ) {
1003 - setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, 1, time() + $cookie_lifetime, $cookie_path, $cookie_domain, is_ssl(), true );
915 + setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, '1', time() + $cookie_lifetime, $cookie_path, $cookie_domain, is_ssl(), true );
1004 916 } else {
1005 917 setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
1006 918 }
1007 919
1008 920 if ( $subscribe_to_blog ) {
1009 - setcookie( 'jetpack_blog_subscribe_' . self::$hash, 1, time() + $cookie_lifetime, $cookie_path, $cookie_domain, is_ssl(), true );
921 + setcookie( 'jetpack_blog_subscribe_' . self::$hash, '1', time() + $cookie_lifetime, $cookie_path, $cookie_domain, is_ssl(), true );
1010 922 } else {
1011 923 setcookie( 'jetpack_blog_subscribe_' . self::$hash, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
1012 924 }
1013 925 }
@@ -1025,8 +937,26 @@
1025 937 }
1026 938 }
1027 939
1028 940 /**
941 + * Set the featured image in email option to `1` when the Subscriptions module is activated in the first time.
942 + *
943 + * @return void
944 + */
945 + public function set_featured_image_in_email_default() {
946 + add_option( 'wpcom_featured_image_in_email', 1 );
947 + }
948 +
949 + /**
950 + * Set the email post to subscribers default option to `1` when the Subscriptions module is activated for the first time.
951 + *
952 + * @return void
953 + */
954 + public function set_newsletter_send_default() {
955 + add_option( 'wpcom_newsletter_send_default', 1 );
956 + }
957 +
958 + /**
1029 959 * Save a flag when a post was ever published.
1030 960 *
1031 961 * It saves the post meta when the post was published and becomes a draft.
1032 962 * Then this meta is used to hide subscription messaging in Publish panel.
@@ -1035,8 +965,13 @@
1035 965 * @param string $old_status The "old" post status of the transition when saved.
1036 966 * @param object $post obj The post object.
1037 967 */
1038 968 public function maybe_set_first_published_status( $new_status, $old_status, $post ) {
969 + // Subscriptions are only available for posts so far.
970 + if ( ! $post instanceof \WP_Post || 'post' !== $post->post_type ) {
971 + return;
972 + }
973 +
1039 974 $was_post_ever_published = get_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
1040 975 if ( ! $was_post_ever_published && 'publish' === $old_status && 'draft' === $new_status ) {
1041 976 update_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
1042 977 }
@@ -1042,14 +977,24 @@
1042 977 }
1043 978 }
1044 979
1045 980 /**
1046 - * Checks if the current user can publish posts.
981 + * Checks if the current user can edit posts.
1047 982 *
1048 983 * @return bool
1049 984 */
1050 985 public function first_published_status_meta_auth_callback() {
1051 - if ( current_user_can( 'publish_posts' ) ) {
986 + /**
987 + * Filter the capability required to edit the "was ever published" post meta.
988 + *
989 + * @module subscriptions
990 + *
991 + * @since 13.4
992 + *
993 + * @param string $capability User capability needed to edit the "was ever published" meta. Default to edit_posts.
994 + */
995 + $capability = apply_filters( 'jetpack_subscriptions_post_was_ever_published_capability', 'edit_posts' );
996 + if ( current_user_can( $capability ) ) {
1052 997 return true;
1053 998 }
1054 999 return false;
1055 1000 }
@@ -1058,16 +1003,17 @@
1058 1003 * Registers the 'post_was_ever_published' post meta for use in the REST API.
1059 1004 */
1060 1005 public function register_post_meta() {
1061 1006 $jetpack_post_was_ever_published = array(
1062 - 'type' => 'boolean',
1063 - 'description' => __( 'Whether the post was ever published.', 'jetpack' ),
1064 - 'single' => true,
1065 - 'default' => false,
1066 - 'show_in_rest' => array(
1007 + 'type' => 'boolean',
1008 + 'description' => __( 'Whether the post was ever published.', 'jetpack' ),
1009 + 'single' => true,
1010 + 'default' => false,
1011 + 'show_in_rest' => array(
1067 1012 'name' => 'jetpack_post_was_ever_published',
1068 1013 ),
1069 - 'auth_callback' => array( $this, 'first_published_status_meta_auth_callback' ),
1014 + 'auth_callback' => array( $this, 'first_published_status_meta_auth_callback' ),
1015 + 'object_subtype' => 'post', // Subscriptions are only for the post post type so far, so we can limit this meta to posts only.
1070 1016 );
1071 1017
1072 1018 register_meta( 'post', '_jetpack_post_was_ever_published', $jetpack_post_was_ever_published );
1073 1019 }
@@ -1076,17 +1022,28 @@
1076 1022 * Create a Subscribers menu displayed on self-hosted sites.
1077 1023 *
1078 1024 * - It is not displayed on WordPress.com sites.
1079 1025 * - It directs you to Calypso to the existing Subscribers page.
1026 + * - It is retired once the Newsletter modernization filter is on, since the
1027 + * unified Newsletter page then owns the Subscribers tab.
1080 1028 *
1081 1029 * @return void
1082 1030 */
1083 1031 public function add_subscribers_menu() {
1084 1032 /*
1085 - * Do not display any menu on WoA and WordPress.com Simple sites.
1033 + * Referenced as a string literal (mirrors Newsletter\Settings::MODERNIZATION_FILTER)
1034 + * to keep this bootstrap path safe if the packaged Newsletter Settings class does
1035 + * not expose the constant yet.
1036 + */
1037 + if ( apply_filters( 'rsm_jetpack_ui_modernization_newsletter', true ) ) {
1038 + return;
1039 + }
1040 +
1041 + /*
1042 + * Do not display any menu on WoA and WordPress.com Simple sites (unless Classic wp-admin is enabled).
1086 1043 * They already get a menu item under Users via nav-unification.
1087 1044 */
1088 - if ( ( new Host() )->is_wpcom_platform() ) {
1045 + if ( ( new Host() )->is_wpcom_platform() && get_option( 'wpcom_admin_interface' ) !== 'wp-admin' ) {
1089 1046 return;
1090 1047 }
1091 1048
1092 1049 $status = new Status();
@@ -1101,22 +1058,69 @@
1101 1058 ) {
1102 1059 return;
1103 1060 }
1104 1061
1062 + /**
1063 + * Enables the new in development subscribers in wp-admin dashboard.
1064 + *
1065 + * @since 9.5.0
1066 + *
1067 + * @param bool If the new dashboard is enabled. Defaults on for every site; hosts
1068 + * can opt out with this filter.
1069 + */
1070 + if ( apply_filters( 'jetpack_wp_admin_subscriber_management_enabled', true ) ) {
1071 + return;
1072 + }
1073 +
1074 + $blog_id = Connection_Manager::get_site_id( true );
1075 +
1105 1076 $link = Redirect::get_url(
1106 - 'jetpack-menu-calypso-subscribers',
1107 - array( 'site' => $status->get_site_suffix() )
1077 + 'jetpack-menu-jetpack-manage-subscribers',
1078 + array( 'site' => $blog_id ? $blog_id : $status->get_site_suffix() )
1108 1079 );
1109 1080
1110 - add_submenu_page(
1111 - 'jetpack',
1112 - esc_attr__( 'Subscribers', 'jetpack' ),
1113 - __( 'Subscribers', 'jetpack' ) . ' <span class="dashicons dashicons-external"></span>',
1081 + $position = defined( Admin_Menu::class . '::POSITION_EXTERNAL' ) ? Admin_Menu::POSITION_EXTERNAL : 100;
1082 +
1083 + Admin_Menu::add_menu(
1084 + __( 'Subscribers', 'jetpack' ),
1085 + __( 'Subscribers', 'jetpack' ) . ' <span aria-hidden="true">↗</span>',
1114 1086 'manage_options',
1115 1087 esc_url( $link ),
1116 - null
1088 + null,
1089 + $position,
1090 + array( 'key' => 'jetpack-subscribers' )
1117 1091 );
1118 1092 }
1093 +
1094 + /**
1095 + * Record tracks event if categories is created when user enters
1096 + * the edit category page through the newsletter settings page.
1097 + *
1098 + * @return void
1099 + */
1100 + public function track_newsletter_category_creation() {
1101 +
1102 + // phpcs:disable WordPress.Security.NonceVerification.Missing
1103 + if ( empty( $_POST['_wp_http_referer'] ) ) {
1104 + return;
1105 + }
1106 +
1107 + if ( strpos( sanitize_url( wp_unslash( $_POST['_wp_http_referer'] ) ), 'referer=newsletter-categories' ) > -1 ) {
1108 +
1109 + $parent = filter_var( empty( $_POST['parent'] ) ? 0 : wp_unslash( $_POST['parent'] ), FILTER_SANITIZE_NUMBER_INT );
1110 +
1111 + $is_child_category = $parent > 0;
1112 +
1113 + $tracking = new Automattic\Jetpack\Tracking();
1114 + $tracking->tracks_record_event(
1115 + wp_get_current_user(),
1116 + 'jetpack_newsletter_add_category',
1117 + array(
1118 + 'is_child_category' => $is_child_category,
1119 + )
1120 + );
1121 + }
1122 + }
1119 1123 }
1120 1124
1121 1125 Jetpack_Subscriptions::init();
1122 1126
@@ -1121,4 +1125,11 @@
1121 1125 Jetpack_Subscriptions::init();
1122 1126
1123 1127 require __DIR__ . '/subscriptions/views.php';
1124 1128 require __DIR__ . '/subscriptions/subscribe-modal/class-jetpack-subscribe-modal.php';
1129 +require __DIR__ . '/subscriptions/subscribe-overlay/class-jetpack-subscribe-overlay.php';
1130 +require __DIR__ . '/subscriptions/subscribe-floating-button/class-jetpack-subscribe-floating-button.php';
1131 +require __DIR__ . '/subscriptions/newsletter-widget/class-jetpack-newsletter-dashboard-widget.php';
1132 +require_once __DIR__ . '/subscriptions/email-design-editor/class-jetpack-email-design-editor.php';
1133 +
1134 +require_once __DIR__ . '/subscriptions/abilities/class-newsletter-abilities.php';
1135 +\Automattic\Jetpack\Plugin\Abilities\Newsletter_Abilities::init();