PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-beta
Jetpack – WP Security, Backup, Speed, & Growth v16.3-beta
16.3 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 All 508 releases
← All changes | modules/subscriptions.php +179 -190 12.8.3 → 16.3-beta View file →
@@ -1,27 +1,34 @@
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
26 33 // Loads the User Content Link Redirection feature.
27 34 require_once __DIR__ . '/subscriptions/jetpack-user-content-link-redirection.php';
@@ -43,13 +50,13 @@
43 50 function jetpack_subscriptions_cherry_pick_server_data() {
44 51 $data = array();
45 52
46 53 foreach ( $_SERVER as $key => $value ) {
47 - if ( ! is_string( $value ) || 0 === strpos( $key, 'HTTP_COOKIE' ) ) {
54 + if ( ! is_string( $value ) || str_starts_with( $key, 'HTTP_COOKIE' ) ) {
48 55 continue;
49 56 }
50 57
51 - 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 ) ) {
52 59 $data[ $key ] = $value;
53 60 }
54 61 }
55 62
@@ -57,8 +64,10 @@
57 64 }
58 65
59 66 /**
60 67 * Main class file for the Subscriptions module.
68 + *
69 + * @phan-constructor-used-for-side-effects
61 70 */
62 71 class Jetpack_Subscriptions {
63 72 /**
64 73 * Whether Jetpack has been instantiated or not.
@@ -127,8 +136,10 @@
127 136 add_filter( 'post_updated_messages', array( $this, 'update_published_message' ), 18, 1 );
128 137
129 138 // Set "social_notifications_subscribe" option during the first-time activation.
130 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' ) );
131 142
132 143 // Hide subscription messaging in Publish panel for posts that were published in the past
133 144 add_action( 'init', array( $this, 'register_post_meta' ), 20 );
134 145 add_action( 'transition_post_status', array( $this, 'maybe_set_first_published_status' ), 10, 3 );
@@ -134,8 +145,22 @@
134 145 add_action( 'transition_post_status', array( $this, 'maybe_set_first_published_status' ), 10, 3 );
135 146
136 147 // Add Subscribers menu to Jetpack navigation.
137 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();
138 163 }
139 164
140 165 /**
141 166 * Jetpack_Subscriptions::xmlrpc_methods()
@@ -357,32 +382,14 @@
357 382 'discussion',
358 383 'stc_enabled'
359 384 );
360 385
361 - /** Enable Subscribe Modal */
362 -
363 - /** This filter is documented in plugins/jetpack/modules/subscriptions/subscribe-module/class-jetpack-subscribe-module.php */
364 - if ( apply_filters( 'jetpack_subscriptions_modal_enabled', false ) ) {
365 - add_settings_field(
366 - 'jetpack_subscriptions_comment_subscribe',
367 - __( 'Enable Subscribe Modal', 'jetpack' ),
368 - array( $this, 'subscribe_modal_setting' ),
369 - 'discussion',
370 - 'jetpack_subscriptions'
371 - );
372 -
373 - register_setting(
374 - 'discussion',
375 - 'sm_enabled'
376 - );
377 - }
378 -
379 - /** Email me whenever: Someone follows my blog */
386 + /** Email me whenever: Someone subscribes to my blog */
380 387 /* @since 8.1 */
381 388
382 389 add_settings_section(
383 390 'notifications_section',
384 - __( 'Someone follows my blog', 'jetpack' ),
391 + __( 'Someone subscribes to my blog', 'jetpack' ),
385 392 array( $this, 'social_notifications_subscribe_section' ),
386 393 'discussion'
387 394 );
388 395
@@ -398,47 +405,8 @@
398 405 'discussion',
399 406 'social_notifications_subscribe',
400 407 array( $this, 'social_notifications_subscribe_validate' )
401 408 );
402 -
403 - /** Subscription Messaging Options */
404 -
405 - register_setting(
406 - 'reading',
407 - 'subscription_options',
408 - array( $this, 'validate_settings' )
409 - );
410 -
411 - add_settings_section(
412 - 'email_settings',
413 - __( 'Follower Settings', 'jetpack' ),
414 - array( $this, 'reading_section' ),
415 - 'reading'
416 - );
417 -
418 - add_settings_field(
419 - 'invitation',
420 - __( 'Blog follow email text', 'jetpack' ),
421 - array( $this, 'setting_invitation' ),
422 - 'reading',
423 - 'email_settings'
424 - );
425 -
426 - add_settings_field(
427 - 'comment-follow',
428 - __( 'Comment follow email text', 'jetpack' ),
429 - array( $this, 'setting_comment_follow' ),
430 - 'reading',
431 - 'email_settings'
432 - );
433 -
434 - add_settings_field(
435 - 'welcome',
436 - __( 'Welcome email text', 'jetpack' ),
437 - array( $this, 'setting_welcome' ),
438 - 'reading',
439 - 'email_settings'
440 - );
441 409 }
442 410
443 411 /**
444 412 * Discussions setting section blurb.
@@ -497,25 +465,9 @@
497 465 <?php
498 466 }
499 467
500 468 /**
501 - * Subscribe Modal Toggle.
502 - */
503 - public function subscribe_modal_setting() {
504 -
505 - $sm_enabled = get_option( 'sm_enabled', 1 );
506 - ?>
507 -
508 - <p class="description">
509 - <input type="checkbox" name="sm_enabled" id="jetpack-subscribe-modal" value="1" <?php checked( $sm_enabled, 1 ); ?> />
510 - <?php esc_html_e( 'Show a popup subscribe modal to readers.', 'jetpack' ); ?>
511 - </p>
512 -
513 - <?php
514 - }
515 -
516 - /**
517 - * Someone follows my blog section
469 + * Someone subscribes to my blog section
518 470 *
519 471 * @since 8.1
520 472 */
521 473 public function social_notifications_subscribe_section() {
@@ -539,9 +491,9 @@
539 491 <?php
540 492 }
541 493
542 494 /**
543 - * Someone follows my blog Toggle
495 + * Someone subscribes to my blog Toggle
544 496 *
545 497 * @since 8.1
546 498 */
547 499 public function social_notifications_subscribe_field() {
@@ -551,9 +503,9 @@
551 503 <label>
552 504 <input type="checkbox" name="social_notifications_subscribe" id="social_notifications_subscribe" value="1" <?php checked( $checked ); ?> />
553 505 <?php
554 506 /* translators: this is a label for a setting that starts with "Email me whenever" */
555 - esc_html_e( 'Someone follows my blog', 'jetpack' );
507 + esc_html_e( 'Someone subscribes to my blog', 'jetpack' );
556 508 ?>
557 509 </label>
558 510 <?php
559 511 }
@@ -558,9 +510,9 @@
558 510 <?php
559 511 }
560 512
561 513 /**
562 - * Validate "Someone follows my blog" option
514 + * Validate "Someone subscribes to my blog" option
563 515 *
564 516 * @since 8.1
565 517 *
566 518 * @param String $input the input string to be validated.
@@ -576,92 +528,8 @@
576 528 return 'on';
577 529 }
578 530
579 531 /**
580 - * Validate settings for the Subscriptions module.
581 - *
582 - * @param array $settings Settings to be validated.
583 - */
584 - public function validate_settings( $settings ) {
585 - global $allowedposttags;
586 -
587 - $default = $this->get_default_settings();
588 -
589 - // Blog Follow.
590 - $settings['invitation'] = trim( wp_kses( $settings['invitation'], $allowedposttags ) );
591 - if ( empty( $settings['invitation'] ) ) {
592 - $settings['invitation'] = $default['invitation'];
593 - }
594 -
595 - // Comments Follow (single post).
596 - $settings['comment_follow'] = trim( wp_kses( $settings['comment_follow'], $allowedposttags ) );
597 - if ( empty( $settings['comment_follow'] ) ) {
598 - $settings['comment_follow'] = $default['comment_follow'];
599 - }
600 -
601 - return $settings;
602 - }
603 -
604 - /**
605 - * HTML output helper for Reading section.
606 - */
607 - public function reading_section() {
608 - echo '<p id="follower-settings">';
609 - esc_html_e( 'These settings change emails sent from your blog to followers.', 'jetpack' );
610 - echo '</p>';
611 - }
612 -
613 - /**
614 - * HTML output helper for Invitation section.
615 - */
616 - public function setting_invitation() {
617 - $settings = $this->get_settings();
618 - echo '<textarea name="subscription_options[invitation]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['invitation'] ) . '</textarea>';
619 - 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>';
620 - }
621 -
622 - /**
623 - * HTML output helper for Comment Follow section.
624 - */
625 - public function setting_comment_follow() {
626 - $settings = $this->get_settings();
627 - echo '<textarea name="subscription_options[comment_follow]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['comment_follow'] ) . '</textarea>';
628 - 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>';
629 - }
630 -
631 - /**
632 - * HTML output helper for Welcome section.
633 - */
634 - public function setting_welcome() {
635 - $settings = $this->get_settings();
636 - echo '<textarea name="subscription_options[welcome]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['welcome'] ) . '</textarea>';
637 - echo '<p><span class="description">' . esc_html__( 'Welcome text sent when someone follows your blog.', 'jetpack' ) . '</span></p>';
638 - }
639 -
640 - /**
641 - * Get default settings for the Subscriptions module.
642 - */
643 - public function get_default_settings() {
644 - $site_url = get_home_url();
645 - $display_url = preg_replace( '(^https?://)', '', untrailingslashit( $site_url ) );
646 -
647 - return array(
648 - /* translators: Both %1$s and %2$s is site address */
649 - '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 ),
650 - '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' ),
651 - /* translators: %1$s is the site address */
652 - 'welcome' => sprintf( __( 'Cool, you are now subscribed to %1$s and will receive an email notification when a new post is published.', 'jetpack' ), $display_url ),
653 - );
654 - }
655 -
656 - /**
657 - * Reeturn merged `subscription_options` option with module default settings.
658 - */
659 - public function get_settings() {
660 - return wp_parse_args( (array) get_option( 'subscription_options' ), $this->get_default_settings() );
661 - }
662 -
663 - /**
664 532 * Jetpack_Subscriptions::subscribe()
665 533 *
666 534 * Send a synchronous XML-RPC subscribe to blog posts or subscribe to post comments request.
667 535 *
@@ -700,8 +568,9 @@
700 568
701 569 if ( $async ) {
702 570 XMLRPC_Async_Call::add_call( 'jetpack.subscribeToSite', 0, $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
703 571 } else {
572 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
704 573 $xml->addCall( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
705 574 }
706 575 }
707 576
@@ -709,19 +578,24 @@
709 578 return;
710 579 }
711 580
712 581 // Call.
582 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
713 583 $xml->query();
714 584
585 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
715 586 if ( $xml->isError() ) {
587 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
716 588 return $xml->get_jetpack_error();
717 589 }
718 590
591 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
719 592 $responses = $xml->getResponse();
720 593
721 594 $r = array();
722 595 foreach ( (array) $responses as $response ) {
723 596 if ( isset( $response['faultCode'] ) || isset( $response['faultString'] ) ) {
597 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
724 598 $r[] = $xml->get_jetpack_error( $response['faultCode'], $response['faultString'] );
725 599 continue;
726 600 }
727 601
@@ -761,9 +635,9 @@
761 635 * When a user submits their email via the blog subscription widget, check the details and call the subsribe() method.
762 636 */
763 637 public function widget_submit() {
764 638 // Check the nonce.
765 - if ( ! wp_verify_nonce( 'blogsub_subscribe_' . \Jetpack_Options::get_option( 'id' ) ) ) {
639 + if ( ! wp_verify_nonce( isset( $_REQUEST['_wpnonce'] ) ? sanitize_key( $_REQUEST['_wpnonce'] ) : '', 'blogsub_subscribe_' . \Jetpack_Options::get_option( 'id' ) ) ) {
766 640 return false;
767 641 }
768 642
769 643 if ( empty( $_REQUEST['email'] ) || ! is_string( $_REQUEST['email'] ) ) {
@@ -839,9 +713,9 @@
839 713 */
840 714 do_action( 'jetpack_subscriptions_form_submission', $result );
841 715
842 716 wp_safe_redirect( "$redirect#$redirect_fragment" );
843 - exit;
717 + exit( 0 );
844 718 }
845 719
846 720 /**
847 721 * Jetpack_Subscriptions::comment_subscribe_init()
@@ -852,8 +726,13 @@
852 726 */
853 727 public function comment_subscribe_init( $submit_button ) {
854 728 global $post;
855 729
730 + // Subscriptions are only available for posts so far.
731 + if ( ! $post || 'post' !== $post->post_type ) {
732 + return $submit_button;
733 + }
734 +
856 735 $comments_checked = '';
857 736 $blog_checked = '';
858 737
859 738 // Check for a comment / blog submission and set a cookie to retain the setting and check the boxes.
@@ -932,8 +811,19 @@
932 811 * @param int|string $comment_id Comment thread being subscribed to.
933 812 * @param string $approved Comment status.
934 813 */
935 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 +
936 826 if ( 'spam' === $approved ) {
937 827 return;
938 828 }
939 829
@@ -996,9 +886,9 @@
996 886 public function set_cookies( $subscribe_to_post = false, $post_id = null, $subscribe_to_blog = false ) {
997 887 $post_id = (int) $post_id;
998 888
999 889 /** This filter is already documented in core/wp-includes/comment-functions.php */
1000 - $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
890 + $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', YEAR_IN_SECONDS );
1001 891
1002 892 /**
1003 893 * Filter the Jetpack Comment cookie path.
1004 894 *
@@ -1021,15 +911,15 @@
1021 911 */
1022 912 $cookie_domain = apply_filters( 'jetpack_comment_cookie_domain', COOKIE_DOMAIN );
1023 913
1024 914 if ( $subscribe_to_post && $post_id >= 0 ) {
1025 - 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 );
1026 916 } else {
1027 917 setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
1028 918 }
1029 919
1030 920 if ( $subscribe_to_blog ) {
1031 - 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 );
1032 922 } else {
1033 923 setcookie( 'jetpack_blog_subscribe_' . self::$hash, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
1034 924 }
1035 925 }
@@ -1047,8 +937,26 @@
1047 937 }
1048 938 }
1049 939
1050 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 + /**
1051 959 * Save a flag when a post was ever published.
1052 960 *
1053 961 * It saves the post meta when the post was published and becomes a draft.
1054 962 * Then this meta is used to hide subscription messaging in Publish panel.
@@ -1057,8 +965,13 @@
1057 965 * @param string $old_status The "old" post status of the transition when saved.
1058 966 * @param object $post obj The post object.
1059 967 */
1060 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 +
1061 974 $was_post_ever_published = get_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
1062 975 if ( ! $was_post_ever_published && 'publish' === $old_status && 'draft' === $new_status ) {
1063 976 update_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
1064 977 }
@@ -1064,14 +977,24 @@
1064 977 }
1065 978 }
1066 979
1067 980 /**
1068 - * Checks if the current user can publish posts.
981 + * Checks if the current user can edit posts.
1069 982 *
1070 983 * @return bool
1071 984 */
1072 985 public function first_published_status_meta_auth_callback() {
1073 - 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 ) ) {
1074 997 return true;
1075 998 }
1076 999 return false;
1077 1000 }
@@ -1080,16 +1003,17 @@
1080 1003 * Registers the 'post_was_ever_published' post meta for use in the REST API.
1081 1004 */
1082 1005 public function register_post_meta() {
1083 1006 $jetpack_post_was_ever_published = array(
1084 - 'type' => 'boolean',
1085 - 'description' => __( 'Whether the post was ever published.', 'jetpack' ),
1086 - 'single' => true,
1087 - 'default' => false,
1088 - '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(
1089 1012 'name' => 'jetpack_post_was_ever_published',
1090 1013 ),
1091 - '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.
1092 1016 );
1093 1017
1094 1018 register_meta( 'post', '_jetpack_post_was_ever_published', $jetpack_post_was_ever_published );
1095 1019 }
@@ -1098,17 +1022,28 @@
1098 1022 * Create a Subscribers menu displayed on self-hosted sites.
1099 1023 *
1100 1024 * - It is not displayed on WordPress.com sites.
1101 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.
1102 1028 *
1103 1029 * @return void
1104 1030 */
1105 1031 public function add_subscribers_menu() {
1106 1032 /*
1107 - * 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).
1108 1043 * They already get a menu item under Users via nav-unification.
1109 1044 */
1110 - if ( ( new Host() )->is_wpcom_platform() ) {
1045 + if ( ( new Host() )->is_wpcom_platform() && get_option( 'wpcom_admin_interface' ) !== 'wp-admin' ) {
1111 1046 return;
1112 1047 }
1113 1048
1114 1049 $status = new Status();
@@ -1123,22 +1058,69 @@
1123 1058 ) {
1124 1059 return;
1125 1060 }
1126 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 +
1127 1076 $link = Redirect::get_url(
1128 - 'jetpack-menu-calypso-subscribers',
1129 - array( 'site' => $status->get_site_suffix() )
1077 + 'jetpack-menu-jetpack-manage-subscribers',
1078 + array( 'site' => $blog_id ? $blog_id : $status->get_site_suffix() )
1130 1079 );
1131 1080
1132 - add_submenu_page(
1133 - 'jetpack',
1134 - esc_attr__( 'Subscribers', 'jetpack' ),
1135 - __( '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>',
1136 1086 'manage_options',
1137 1087 esc_url( $link ),
1138 - null
1088 + null,
1089 + $position,
1090 + array( 'key' => 'jetpack-subscribers' )
1139 1091 );
1140 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 + }
1141 1123 }
1142 1124
1143 1125 Jetpack_Subscriptions::init();
1144 1126
@@ -1143,4 +1125,11 @@
1143 1125 Jetpack_Subscriptions::init();
1144 1126
1145 1127 require __DIR__ . '/subscriptions/views.php';
1146 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();