PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.0
Jetpack – WP Security, Backup, Speed, & Growth v16.0
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 14.3.1 14.4.2 All 500 releases
← All changes | modules/subscriptions.php +132 -17 14.4.216.0 View file →
@@ -1,14 +1,14 @@
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 13 * Additional Search Queries: subscriptions, subscription, email, follow, followers, subscribers, signup, newsletter, creator
14 14 */
@@ -17,12 +17,17 @@
17 17
18 18 use Automattic\Jetpack\Admin_UI\Admin_Menu;
19 19 use Automattic\Jetpack\Connection\Manager as Connection_Manager;
20 20 use Automattic\Jetpack\Connection\XMLRPC_Async_Call;
21 +use Automattic\Jetpack\Newsletter\Settings as Newsletter_Settings;
21 22 use Automattic\Jetpack\Redirect;
22 23 use Automattic\Jetpack\Status;
23 24 use Automattic\Jetpack\Status\Host;
24 25
26 +if ( ! defined( 'ABSPATH' ) ) {
27 + exit( 0 );
28 +}
29 +
25 30 add_action( 'jetpack_modules_loaded', 'jetpack_subscriptions_load' );
26 31
27 32 // Loads the User Content Link Redirection feature.
28 33 require_once __DIR__ . '/subscriptions/jetpack-user-content-link-redirection.php';
@@ -58,8 +63,10 @@
58 63 }
59 64
60 65 /**
61 66 * Main class file for the Subscriptions module.
67 + *
68 + * @phan-constructor-used-for-side-effects
62 69 */
63 70 class Jetpack_Subscriptions {
64 71 /**
65 72 * Whether Jetpack has been instantiated or not.
@@ -128,8 +135,10 @@
128 135 add_filter( 'post_updated_messages', array( $this, 'update_published_message' ), 18, 1 );
129 136
130 137 // Set "social_notifications_subscribe" option during the first-time activation.
131 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' ) );
132 141
133 142 // Hide subscription messaging in Publish panel for posts that were published in the past
134 143 add_action( 'init', array( $this, 'register_post_meta' ), 20 );
135 144 add_action( 'transition_post_status', array( $this, 'maybe_set_first_published_status' ), 10, 3 );
@@ -146,8 +155,11 @@
146 155 );
147 156
148 157 // Track categories created through the category editor page
149 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();
150 162 }
151 163
152 164 /**
153 165 * Jetpack_Subscriptions::xmlrpc_methods()
@@ -555,8 +567,9 @@
555 567
556 568 if ( $async ) {
557 569 XMLRPC_Async_Call::add_call( 'jetpack.subscribeToSite', 0, $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
558 570 } else {
571 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
559 572 $xml->addCall( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
560 573 }
561 574 }
562 575
@@ -564,19 +577,24 @@
564 577 return;
565 578 }
566 579
567 580 // Call.
581 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
568 582 $xml->query();
569 583
584 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
570 585 if ( $xml->isError() ) {
586 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
571 587 return $xml->get_jetpack_error();
572 588 }
573 589
590 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
574 591 $responses = $xml->getResponse();
575 592
576 593 $r = array();
577 594 foreach ( (array) $responses as $response ) {
578 595 if ( isset( $response['faultCode'] ) || isset( $response['faultString'] ) ) {
596 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
579 597 $r[] = $xml->get_jetpack_error( $response['faultCode'], $response['faultString'] );
580 598 continue;
581 599 }
582 600
@@ -792,8 +810,19 @@
792 810 * @param int|string $comment_id Comment thread being subscribed to.
793 811 * @param string $approved Comment status.
794 812 */
795 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 +
796 825 if ( 'spam' === $approved ) {
797 826 return;
798 827 }
799 828
@@ -856,9 +885,9 @@
856 885 public function set_cookies( $subscribe_to_post = false, $post_id = null, $subscribe_to_blog = false ) {
857 886 $post_id = (int) $post_id;
858 887
859 888 /** This filter is already documented in core/wp-includes/comment-functions.php */
860 - $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
889 + $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', YEAR_IN_SECONDS );
861 890
862 891 /**
863 892 * Filter the Jetpack Comment cookie path.
864 893 *
@@ -881,15 +910,15 @@
881 910 */
882 911 $cookie_domain = apply_filters( 'jetpack_comment_cookie_domain', COOKIE_DOMAIN );
883 912
884 913 if ( $subscribe_to_post && $post_id >= 0 ) {
885 - 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 );
886 915 } else {
887 916 setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
888 917 }
889 918
890 919 if ( $subscribe_to_blog ) {
891 - 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 );
892 921 } else {
893 922 setcookie( 'jetpack_blog_subscribe_' . self::$hash, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
894 923 }
895 924 }
@@ -907,8 +936,26 @@
907 936 }
908 937 }
909 938
910 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 + /**
911 958 * Save a flag when a post was ever published.
912 959 *
913 960 * It saves the post meta when the post was published and becomes a draft.
914 961 * Then this meta is used to hide subscription messaging in Publish panel.
@@ -917,8 +964,13 @@
917 964 * @param string $old_status The "old" post status of the transition when saved.
918 965 * @param object $post obj The post object.
919 966 */
920 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 +
921 973 $was_post_ever_published = get_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
922 974 if ( ! $was_post_ever_published && 'publish' === $old_status && 'draft' === $new_status ) {
923 975 update_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
924 976 }
@@ -924,23 +976,23 @@
924 976 }
925 977 }
926 978
927 979 /**
928 - * Checks if the current user can publish posts.
980 + * Checks if the current user can edit posts.
929 981 *
930 982 * @return bool
931 983 */
932 984 public function first_published_status_meta_auth_callback() {
933 985 /**
934 - * Filter the capability to view if a post was ever published in the Subscription Module.
986 + * Filter the capability required to edit the "was ever published" post meta.
935 987 *
936 988 * @module subscriptions
937 989 *
938 990 * @since 13.4
939 991 *
940 - * @param string $capability User capability needed to view if a post was ever published. Default to publish_posts.
992 + * @param string $capability User capability needed to edit the "was ever published" meta. Default to edit_posts.
941 993 */
942 - $capability = apply_filters( 'jetpack_subscriptions_post_was_ever_published_capability', 'publish_posts' );
994 + $capability = apply_filters( 'jetpack_subscriptions_post_was_ever_published_capability', 'edit_posts' );
943 995 if ( current_user_can( $capability ) ) {
944 996 return true;
945 997 }
946 998 return false;
@@ -950,16 +1002,17 @@
950 1002 * Registers the 'post_was_ever_published' post meta for use in the REST API.
951 1003 */
952 1004 public function register_post_meta() {
953 1005 $jetpack_post_was_ever_published = array(
954 - 'type' => 'boolean',
955 - 'description' => __( 'Whether the post was ever published.', 'jetpack' ),
956 - 'single' => true,
957 - 'default' => false,
958 - '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(
959 1011 'name' => 'jetpack_post_was_ever_published',
960 1012 ),
961 - '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.
962 1015 );
963 1016
964 1017 register_meta( 'post', '_jetpack_post_was_ever_published', $jetpack_post_was_ever_published );
965 1018 }
@@ -968,13 +1021,58 @@
968 1021 * Create a Subscribers menu displayed on self-hosted sites.
969 1022 *
970 1023 * - It is not displayed on WordPress.com sites.
971 1024 * - It directs you to Calypso to the existing Subscribers page.
1025 + * - Once the Newsletter modernization filter is on, the unified Newsletter
1026 + * page owns the Subscribers tab, so the Calypso shortcut is replaced by a
1027 + * transitional announcement page pointing there.
972 1028 *
973 1029 * @return void
974 1030 */
975 1031 public function add_subscribers_menu() {
976 1032 /*
1033 + * Staged-rollout default for both modernization filters: on for
1034 + * Automatticians and for the percentage cohort (currently 0%, bucketed by
1035 + * the stable wpcom blog ID), off everywhere else. Delegated to the canonical
1036 + * Newsletter\Settings::is_modernization_rollout_enabled() so the cohort math
1037 + * has a single source of truth; guarded with method_exists so this bootstrap
1038 + * path stays safe if the packaged Newsletter Settings class is an older copy
1039 + * that doesn't expose the helper yet.
1040 + */
1041 + $modernization_rollout_default = method_exists( '\Automattic\Jetpack\Newsletter\Settings', 'is_modernization_rollout_enabled' )
1042 + && \Automattic\Jetpack\Newsletter\Settings::is_modernization_rollout_enabled();
1043 +
1044 + /*
1045 + * Once the Newsletter modernization filter is on, the unified Newsletter
1046 + * page owns the Subscribers tab and this standalone Calypso shortcut is
1047 + * retired. In its place, a transitional announcement page tells people
1048 + * where subscriber management moved and lets them remove the menu item.
1049 + *
1050 + * This is evaluated first — before the WoA/Simple and connection guards
1051 + * below — and returns, so the legacy Calypso shortcut is never added once
1052 + * the filter is on.
1053 + *
1054 + * The announcement page itself is registered here only on self-hosted
1055 + * Jetpack. On WordPress.com (Simple and WoA) jetpack-mu-wpcom's
1056 + * wpcom-admin-menu owns the Subscribers entry and registers the
1057 + * announcement page there; doing it here as well would duplicate the menu
1058 + * (and double the page-view tracking) on Atomic, where both run.
1059 + *
1060 + * Referenced as a string literal (mirrors Newsletter\Settings::MODERNIZATION_FILTER)
1061 + * to keep this bootstrap path safe if the packaged Newsletter Settings class does
1062 + * not expose the constant yet.
1063 + */
1064 + if ( apply_filters( 'rsm_jetpack_ui_modernization_newsletter', $modernization_rollout_default ) ) {
1065 + if (
1066 + ! ( new Host() )->is_wpcom_platform()
1067 + && class_exists( '\Automattic\Jetpack\Newsletter\Subscribers_Announcement' )
1068 + ) {
1069 + \Automattic\Jetpack\Newsletter\Subscribers_Announcement::add_menu();
1070 + }
1071 + return;
1072 + }
1073 +
1074 + /*
977 1075 * Do not display any menu on WoA and WordPress.com Simple sites (unless Classic wp-admin is enabled).
978 1076 * They already get a menu item under Users via nav-unification.
979 1077 */
980 1078 if ( ( new Host() )->is_wpcom_platform() && get_option( 'wpcom_admin_interface' ) !== 'wp-admin' ) {
@@ -993,8 +1091,21 @@
993 1091 ) {
994 1092 return;
995 1093 }
996 1094
1095 + /**
1096 + * Enables the new in development subscribers in wp-admin dashboard.
1097 + *
1098 + * @since 9.5.0
1099 + *
1100 + * @param bool If the new dashboard is enabled. Defaults to the staged-rollout
1101 + * cohort: true for Automatticians and the percentage cohort
1102 + * (currently 0%), false elsewhere.
1103 + */
1104 + if ( apply_filters( 'jetpack_wp_admin_subscriber_management_enabled', $modernization_rollout_default ) ) {
1105 + return;
1106 + }
1107 +
997 1108 $blog_id = Connection_Manager::get_site_id( true );
998 1109
999 1110 $link = Redirect::get_url(
1000 1111 'jetpack-menu-jetpack-manage-subscribers',
@@ -1002,13 +1113,13 @@
1002 1113 );
1003 1114
1004 1115 Admin_Menu::add_menu(
1005 1116 __( 'Subscribers', 'jetpack' ),
1006 - __( 'Subscribers', 'jetpack' ) . ' <span class="dashicons dashicons-external"></span>',
1117 + __( 'Subscribers', 'jetpack' ) . ' <span aria-hidden="true">↗</span>',
1007 1118 'manage_options',
1008 1119 esc_url( $link ),
1009 1120 null,
1010 - 11
1121 + 15
1011 1122 );
1012 1123 }
1013 1124
1014 1125 /**
@@ -1047,4 +1158,8 @@
1047 1158 require __DIR__ . '/subscriptions/views.php';
1048 1159 require __DIR__ . '/subscriptions/subscribe-modal/class-jetpack-subscribe-modal.php';
1049 1160 require __DIR__ . '/subscriptions/subscribe-overlay/class-jetpack-subscribe-overlay.php';
1050 1161 require __DIR__ . '/subscriptions/subscribe-floating-button/class-jetpack-subscribe-floating-button.php';
1162 +require __DIR__ . '/subscriptions/newsletter-widget/class-jetpack-newsletter-dashboard-widget.php';
1163 +
1164 +require_once __DIR__ . '/subscriptions/abilities/class-newsletter-abilities.php';
1165 +\Automattic\Jetpack\Plugin\Abilities\Newsletter_Abilities::init();