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 +180 -172 12.7.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,39 +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 409 }
434 410
435 411 /**
436 412 * Discussions setting section blurb.
@@ -489,25 +465,9 @@
489 465 <?php
490 466 }
491 467
492 468 /**
493 - * Subscribe Modal Toggle.
494 - */
495 - public function subscribe_modal_setting() {
496 -
497 - $sm_enabled = get_option( 'sm_enabled', 1 );
498 - ?>
499 -
500 - <p class="description">
501 - <input type="checkbox" name="sm_enabled" id="jetpack-subscribe-modal" value="1" <?php checked( $sm_enabled, 1 ); ?> />
502 - <?php esc_html_e( 'Show a popup subscribe modal to readers.', 'jetpack' ); ?>
503 - </p>
504 -
505 - <?php
506 - }
507 -
508 - /**
509 - * Someone follows my blog section
469 + * Someone subscribes to my blog section
510 470 *
511 471 * @since 8.1
512 472 */
513 473 public function social_notifications_subscribe_section() {
@@ -531,9 +491,9 @@
531 491 <?php
532 492 }
533 493
534 494 /**
535 - * Someone follows my blog Toggle
495 + * Someone subscribes to my blog Toggle
536 496 *
537 497 * @since 8.1
538 498 */
539 499 public function social_notifications_subscribe_field() {
@@ -543,9 +503,9 @@
543 503 <label>
544 504 <input type="checkbox" name="social_notifications_subscribe" id="social_notifications_subscribe" value="1" <?php checked( $checked ); ?> />
545 505 <?php
546 506 /* translators: this is a label for a setting that starts with "Email me whenever" */
547 - esc_html_e( 'Someone follows my blog', 'jetpack' );
507 + esc_html_e( 'Someone subscribes to my blog', 'jetpack' );
548 508 ?>
549 509 </label>
550 510 <?php
551 511 }
@@ -550,9 +510,9 @@
550 510 <?php
551 511 }
552 512
553 513 /**
554 - * Validate "Someone follows my blog" option
514 + * Validate "Someone subscribes to my blog" option
555 515 *
556 516 * @since 8.1
557 517 *
558 518 * @param String $input the input string to be validated.
@@ -568,81 +528,8 @@
568 528 return 'on';
569 529 }
570 530
571 531 /**
572 - * Validate settings for the Subscriptions module.
573 - *
574 - * @param array $settings Settings to be validated.
575 - */
576 - public function validate_settings( $settings ) {
577 - global $allowedposttags;
578 -
579 - $default = $this->get_default_settings();
580 -
581 - // Blog Follow.
582 - $settings['invitation'] = trim( wp_kses( $settings['invitation'], $allowedposttags ) );
583 - if ( empty( $settings['invitation'] ) ) {
584 - $settings['invitation'] = $default['invitation'];
585 - }
586 -
587 - // Comments Follow (single post).
588 - $settings['comment_follow'] = trim( wp_kses( $settings['comment_follow'], $allowedposttags ) );
589 - if ( empty( $settings['comment_follow'] ) ) {
590 - $settings['comment_follow'] = $default['comment_follow'];
591 - }
592 -
593 - return $settings;
594 - }
595 -
596 - /**
597 - * HTML output helper for Reading section.
598 - */
599 - public function reading_section() {
600 - echo '<p id="follower-settings">';
601 - esc_html_e( 'These settings change emails sent from your blog to followers.', 'jetpack' );
602 - echo '</p>';
603 - }
604 -
605 - /**
606 - * HTML output helper for Invitation section.
607 - */
608 - public function setting_invitation() {
609 - $settings = $this->get_settings();
610 - echo '<textarea name="subscription_options[invitation]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['invitation'] ) . '</textarea>';
611 - 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>';
612 - }
613 -
614 - /**
615 - * HTML output helper for Comment Follow section.
616 - */
617 - public function setting_comment_follow() {
618 - $settings = $this->get_settings();
619 - echo '<textarea name="subscription_options[comment_follow]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['comment_follow'] ) . '</textarea>';
620 - 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>';
621 - }
622 -
623 - /**
624 - * Get default settings for the Subscriptions module.
625 - */
626 - public function get_default_settings() {
627 - $site_url = get_home_url();
628 - $display_url = preg_replace( '(^https?://)', '', untrailingslashit( $site_url ) );
629 -
630 - return array(
631 - /* translators: Both %1$s and %2$s is site address */
632 - '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 ),
633 - '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' ),
634 - );
635 - }
636 -
637 - /**
638 - * Reeturn merged `subscription_options` option with module default settings.
639 - */
640 - public function get_settings() {
641 - return wp_parse_args( (array) get_option( 'subscription_options' ), $this->get_default_settings() );
642 - }
643 -
644 - /**
645 532 * Jetpack_Subscriptions::subscribe()
646 533 *
647 534 * Send a synchronous XML-RPC subscribe to blog posts or subscribe to post comments request.
648 535 *
@@ -681,8 +568,9 @@
681 568
682 569 if ( $async ) {
683 570 XMLRPC_Async_Call::add_call( 'jetpack.subscribeToSite', 0, $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
684 571 } else {
572 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
685 573 $xml->addCall( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
686 574 }
687 575 }
688 576
@@ -690,19 +578,24 @@
690 578 return;
691 579 }
692 580
693 581 // Call.
582 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
694 583 $xml->query();
695 584
585 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
696 586 if ( $xml->isError() ) {
587 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
697 588 return $xml->get_jetpack_error();
698 589 }
699 590
591 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
700 592 $responses = $xml->getResponse();
701 593
702 594 $r = array();
703 595 foreach ( (array) $responses as $response ) {
704 596 if ( isset( $response['faultCode'] ) || isset( $response['faultString'] ) ) {
597 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
705 598 $r[] = $xml->get_jetpack_error( $response['faultCode'], $response['faultString'] );
706 599 continue;
707 600 }
708 601
@@ -742,10 +635,10 @@
742 635 * When a user submits their email via the blog subscription widget, check the details and call the subsribe() method.
743 636 */
744 637 public function widget_submit() {
745 638 // Check the nonce.
746 - if ( is_user_logged_in() ) {
747 - 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;
748 641 }
749 642
750 643 if ( empty( $_REQUEST['email'] ) || ! is_string( $_REQUEST['email'] ) ) {
751 644 return false;
@@ -820,9 +713,9 @@
820 713 */
821 714 do_action( 'jetpack_subscriptions_form_submission', $result );
822 715
823 716 wp_safe_redirect( "$redirect#$redirect_fragment" );
824 - exit;
717 + exit( 0 );
825 718 }
826 719
827 720 /**
828 721 * Jetpack_Subscriptions::comment_subscribe_init()
@@ -833,8 +726,13 @@
833 726 */
834 727 public function comment_subscribe_init( $submit_button ) {
835 728 global $post;
836 729
730 + // Subscriptions are only available for posts so far.
731 + if ( ! $post || 'post' !== $post->post_type ) {
732 + return $submit_button;
733 + }
734 +
837 735 $comments_checked = '';
838 736 $blog_checked = '';
839 737
840 738 // Check for a comment / blog submission and set a cookie to retain the setting and check the boxes.
@@ -913,8 +811,19 @@
913 811 * @param int|string $comment_id Comment thread being subscribed to.
914 812 * @param string $approved Comment status.
915 813 */
916 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 +
917 826 if ( 'spam' === $approved ) {
918 827 return;
919 828 }
920 829
@@ -977,9 +886,9 @@
977 886 public function set_cookies( $subscribe_to_post = false, $post_id = null, $subscribe_to_blog = false ) {
978 887 $post_id = (int) $post_id;
979 888
980 889 /** This filter is already documented in core/wp-includes/comment-functions.php */
981 - $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
890 + $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', YEAR_IN_SECONDS );
982 891
983 892 /**
984 893 * Filter the Jetpack Comment cookie path.
985 894 *
@@ -1002,15 +911,15 @@
1002 911 */
1003 912 $cookie_domain = apply_filters( 'jetpack_comment_cookie_domain', COOKIE_DOMAIN );
1004 913
1005 914 if ( $subscribe_to_post && $post_id >= 0 ) {
1006 - 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 );
1007 916 } else {
1008 917 setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
1009 918 }
1010 919
1011 920 if ( $subscribe_to_blog ) {
1012 - 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 );
1013 922 } else {
1014 923 setcookie( 'jetpack_blog_subscribe_' . self::$hash, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
1015 924 }
1016 925 }
@@ -1028,8 +937,26 @@
1028 937 }
1029 938 }
1030 939
1031 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 + /**
1032 959 * Save a flag when a post was ever published.
1033 960 *
1034 961 * It saves the post meta when the post was published and becomes a draft.
1035 962 * Then this meta is used to hide subscription messaging in Publish panel.
@@ -1038,8 +965,13 @@
1038 965 * @param string $old_status The "old" post status of the transition when saved.
1039 966 * @param object $post obj The post object.
1040 967 */
1041 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 +
1042 974 $was_post_ever_published = get_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
1043 975 if ( ! $was_post_ever_published && 'publish' === $old_status && 'draft' === $new_status ) {
1044 976 update_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
1045 977 }
@@ -1045,14 +977,24 @@
1045 977 }
1046 978 }
1047 979
1048 980 /**
1049 - * Checks if the current user can publish posts.
981 + * Checks if the current user can edit posts.
1050 982 *
1051 983 * @return bool
1052 984 */
1053 985 public function first_published_status_meta_auth_callback() {
1054 - 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 ) ) {
1055 997 return true;
1056 998 }
1057 999 return false;
1058 1000 }
@@ -1061,16 +1003,17 @@
1061 1003 * Registers the 'post_was_ever_published' post meta for use in the REST API.
1062 1004 */
1063 1005 public function register_post_meta() {
1064 1006 $jetpack_post_was_ever_published = array(
1065 - 'type' => 'boolean',
1066 - 'description' => __( 'Whether the post was ever published.', 'jetpack' ),
1067 - 'single' => true,
1068 - 'default' => false,
1069 - '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(
1070 1012 'name' => 'jetpack_post_was_ever_published',
1071 1013 ),
1072 - '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.
1073 1016 );
1074 1017
1075 1018 register_meta( 'post', '_jetpack_post_was_ever_published', $jetpack_post_was_ever_published );
1076 1019 }
@@ -1079,17 +1022,28 @@
1079 1022 * Create a Subscribers menu displayed on self-hosted sites.
1080 1023 *
1081 1024 * - It is not displayed on WordPress.com sites.
1082 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.
1083 1028 *
1084 1029 * @return void
1085 1030 */
1086 1031 public function add_subscribers_menu() {
1087 1032 /*
1088 - * 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).
1089 1043 * They already get a menu item under Users via nav-unification.
1090 1044 */
1091 - if ( ( new Host() )->is_wpcom_platform() ) {
1045 + if ( ( new Host() )->is_wpcom_platform() && get_option( 'wpcom_admin_interface' ) !== 'wp-admin' ) {
1092 1046 return;
1093 1047 }
1094 1048
1095 1049 $status = new Status();
@@ -1104,22 +1058,69 @@
1104 1058 ) {
1105 1059 return;
1106 1060 }
1107 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 +
1108 1076 $link = Redirect::get_url(
1109 - 'jetpack-menu-calypso-subscribers',
1110 - array( 'site' => $status->get_site_suffix() )
1077 + 'jetpack-menu-jetpack-manage-subscribers',
1078 + array( 'site' => $blog_id ? $blog_id : $status->get_site_suffix() )
1111 1079 );
1112 1080
1113 - add_submenu_page(
1114 - 'jetpack',
1115 - esc_attr__( 'Subscribers', 'jetpack' ),
1116 - __( '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>',
1117 1086 'manage_options',
1118 1087 esc_url( $link ),
1119 - null
1088 + null,
1089 + $position,
1090 + array( 'key' => 'jetpack-subscribers' )
1120 1091 );
1121 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 + }
1122 1123 }
1123 1124
1124 1125 Jetpack_Subscriptions::init();
1125 1126
@@ -1124,4 +1125,11 @@
1124 1125 Jetpack_Subscriptions::init();
1125 1126
1126 1127 require __DIR__ . '/subscriptions/views.php';
1127 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();