PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.0
Jetpack – WP Security, Backup, Speed, & Growth v16.0
16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
← All changes | modules/subscriptions.php +148 -56 13.3.316.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 */
@@ -14,14 +14,20 @@
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;
20 22 use Automattic\Jetpack\Redirect;
21 23 use Automattic\Jetpack\Status;
22 24 use Automattic\Jetpack\Status\Host;
23 25
26 +if ( ! defined( 'ABSPATH' ) ) {
27 + exit( 0 );
28 +}
29 +
24 30 add_action( 'jetpack_modules_loaded', 'jetpack_subscriptions_load' );
25 31
26 32 // Loads the User Content Link Redirection feature.
27 33 require_once __DIR__ . '/subscriptions/jetpack-user-content-link-redirection.php';
@@ -57,8 +63,10 @@
57 63 }
58 64
59 65 /**
60 66 * Main class file for the Subscriptions module.
67 + *
68 + * @phan-constructor-used-for-side-effects
61 69 */
62 70 class Jetpack_Subscriptions {
63 71 /**
64 72 * Whether Jetpack has been instantiated or not.
@@ -127,8 +135,10 @@
127 135 add_filter( 'post_updated_messages', array( $this, 'update_published_message' ), 18, 1 );
128 136
129 137 // Set "social_notifications_subscribe" option during the first-time activation.
130 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' ) );
131 141
132 142 // Hide subscription messaging in Publish panel for posts that were published in the past
133 143 add_action( 'init', array( $this, 'register_post_meta' ), 20 );
134 144 add_action( 'transition_post_status', array( $this, 'maybe_set_first_published_status' ), 10, 3 );
@@ -145,8 +155,11 @@
145 155 );
146 156
147 157 // Track categories created through the category editor page
148 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();
149 162 }
150 163
151 164 /**
152 165 * Jetpack_Subscriptions::xmlrpc_methods()
@@ -368,23 +381,8 @@
368 381 'discussion',
369 382 'stc_enabled'
370 383 );
371 384
372 - /** Enable Subscribe Modal */
373 -
374 - add_settings_field(
375 - 'jetpack_subscriptions_comment_subscribe',
376 - __( 'Enable Subscribe Modal', 'jetpack' ),
377 - array( $this, 'subscribe_modal_setting' ),
378 - 'discussion',
379 - 'jetpack_subscriptions'
380 - );
381 -
382 - register_setting(
383 - 'discussion',
384 - 'sm_enabled'
385 - );
386 -
387 385 /** Email me whenever: Someone subscribes to my blog */
388 386 /* @since 8.1 */
389 387
390 388 add_settings_section(
@@ -466,24 +464,8 @@
466 464 <?php
467 465 }
468 466
469 467 /**
470 - * Subscribe Modal Toggle.
471 - */
472 - public function subscribe_modal_setting() {
473 -
474 - $sm_enabled = get_option( 'sm_enabled', 1 );
475 - ?>
476 -
477 - <p class="description">
478 - <input type="checkbox" name="sm_enabled" id="jetpack-subscribe-modal" value="1" <?php checked( $sm_enabled, 1 ); ?> />
479 - <?php esc_html_e( 'Show a popup subscribe modal to readers.', 'jetpack' ); ?>
480 - </p>
481 -
482 - <?php
483 - }
484 -
485 - /**
486 468 * Someone subscribes to my blog section
487 469 *
488 470 * @since 8.1
489 471 */
@@ -585,8 +567,9 @@
585 567
586 568 if ( $async ) {
587 569 XMLRPC_Async_Call::add_call( 'jetpack.subscribeToSite', 0, $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
588 570 } else {
571 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
589 572 $xml->addCall( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
590 573 }
591 574 }
592 575
@@ -594,19 +577,24 @@
594 577 return;
595 578 }
596 579
597 580 // Call.
581 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
598 582 $xml->query();
599 583
584 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
600 585 if ( $xml->isError() ) {
586 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
601 587 return $xml->get_jetpack_error();
602 588 }
603 589
590 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
604 591 $responses = $xml->getResponse();
605 592
606 593 $r = array();
607 594 foreach ( (array) $responses as $response ) {
608 595 if ( isset( $response['faultCode'] ) || isset( $response['faultString'] ) ) {
596 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
609 597 $r[] = $xml->get_jetpack_error( $response['faultCode'], $response['faultString'] );
610 598 continue;
611 599 }
612 600
@@ -724,9 +712,9 @@
724 712 */
725 713 do_action( 'jetpack_subscriptions_form_submission', $result );
726 714
727 715 wp_safe_redirect( "$redirect#$redirect_fragment" );
728 - exit;
716 + exit( 0 );
729 717 }
730 718
731 719 /**
732 720 * Jetpack_Subscriptions::comment_subscribe_init()
@@ -822,8 +810,19 @@
822 810 * @param int|string $comment_id Comment thread being subscribed to.
823 811 * @param string $approved Comment status.
824 812 */
825 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 +
826 825 if ( 'spam' === $approved ) {
827 826 return;
828 827 }
829 828
@@ -886,9 +885,9 @@
886 885 public function set_cookies( $subscribe_to_post = false, $post_id = null, $subscribe_to_blog = false ) {
887 886 $post_id = (int) $post_id;
888 887
889 888 /** This filter is already documented in core/wp-includes/comment-functions.php */
890 - $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
889 + $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', YEAR_IN_SECONDS );
891 890
892 891 /**
893 892 * Filter the Jetpack Comment cookie path.
894 893 *
@@ -911,15 +910,15 @@
911 910 */
912 911 $cookie_domain = apply_filters( 'jetpack_comment_cookie_domain', COOKIE_DOMAIN );
913 912
914 913 if ( $subscribe_to_post && $post_id >= 0 ) {
915 - 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 );
916 915 } else {
917 916 setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
918 917 }
919 918
920 919 if ( $subscribe_to_blog ) {
921 - 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 );
922 921 } else {
923 922 setcookie( 'jetpack_blog_subscribe_' . self::$hash, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
924 923 }
925 924 }
@@ -937,8 +936,26 @@
937 936 }
938 937 }
939 938
940 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 + /**
941 958 * Save a flag when a post was ever published.
942 959 *
943 960 * It saves the post meta when the post was published and becomes a draft.
944 961 * Then this meta is used to hide subscription messaging in Publish panel.
@@ -947,8 +964,13 @@
947 964 * @param string $old_status The "old" post status of the transition when saved.
948 965 * @param object $post obj The post object.
949 966 */
950 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 +
951 973 $was_post_ever_published = get_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
952 974 if ( ! $was_post_ever_published && 'publish' === $old_status && 'draft' === $new_status ) {
953 975 update_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
954 976 }
@@ -954,14 +976,24 @@
954 976 }
955 977 }
956 978
957 979 /**
958 - * Checks if the current user can publish posts.
980 + * Checks if the current user can edit posts.
959 981 *
960 982 * @return bool
961 983 */
962 984 public function first_published_status_meta_auth_callback() {
963 - if ( current_user_can( 'publish_posts' ) ) {
985 + /**
986 + * Filter the capability required to edit the "was ever published" post meta.
987 + *
988 + * @module subscriptions
989 + *
990 + * @since 13.4
991 + *
992 + * @param string $capability User capability needed to edit the "was ever published" meta. Default to edit_posts.
993 + */
994 + $capability = apply_filters( 'jetpack_subscriptions_post_was_ever_published_capability', 'edit_posts' );
995 + if ( current_user_can( $capability ) ) {
964 996 return true;
965 997 }
966 998 return false;
967 999 }
@@ -970,16 +1002,17 @@
970 1002 * Registers the 'post_was_ever_published' post meta for use in the REST API.
971 1003 */
972 1004 public function register_post_meta() {
973 1005 $jetpack_post_was_ever_published = array(
974 - 'type' => 'boolean',
975 - 'description' => __( 'Whether the post was ever published.', 'jetpack' ),
976 - 'single' => true,
977 - 'default' => false,
978 - '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(
979 1011 'name' => 'jetpack_post_was_ever_published',
980 1012 ),
981 - '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.
982 1015 );
983 1016
984 1017 register_meta( 'post', '_jetpack_post_was_ever_published', $jetpack_post_was_ever_published );
985 1018 }
@@ -988,13 +1021,58 @@
988 1021 * Create a Subscribers menu displayed on self-hosted sites.
989 1022 *
990 1023 * - It is not displayed on WordPress.com sites.
991 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.
992 1028 *
993 1029 * @return void
994 1030 */
995 1031 public function add_subscribers_menu() {
996 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 + /*
997 1075 * Do not display any menu on WoA and WordPress.com Simple sites (unless Classic wp-admin is enabled).
998 1076 * They already get a menu item under Users via nav-unification.
999 1077 */
1000 1078 if ( ( new Host() )->is_wpcom_platform() && get_option( 'wpcom_admin_interface' ) !== 'wp-admin' ) {
@@ -1013,27 +1091,35 @@
1013 1091 ) {
1014 1092 return;
1015 1093 }
1016 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 +
1017 1108 $blog_id = Connection_Manager::get_site_id( true );
1018 1109
1019 - $source = 'jetpack-menu-calypso-subscribers';
1020 - if ( get_option( 'wpcom_admin_interface' ) === 'wp-admin' ) {
1021 - $source = 'jetpack-menu-jetpack-manage-subscribers';
1022 - }
1023 -
1024 1110 $link = Redirect::get_url(
1025 - $source,
1111 + 'jetpack-menu-jetpack-manage-subscribers',
1026 1112 array( 'site' => $blog_id ? $blog_id : $status->get_site_suffix() )
1027 1113 );
1028 1114
1029 - add_submenu_page(
1030 - 'jetpack',
1031 - esc_attr__( 'Subscribers', 'jetpack' ),
1032 - __( 'Subscribers', 'jetpack' ) . ' <span class="dashicons dashicons-external"></span>',
1115 + Admin_Menu::add_menu(
1116 + __( 'Subscribers', 'jetpack' ),
1117 + __( 'Subscribers', 'jetpack' ) . ' <span aria-hidden="true">↗</span>',
1033 1118 'manage_options',
1034 1119 esc_url( $link ),
1035 - null
1120 + null,
1121 + 15
1036 1122 );
1037 1123 }
1038 1124
1039 1125 /**
@@ -1070,4 +1156,10 @@
1070 1156 Jetpack_Subscriptions::init();
1071 1157
1072 1158 require __DIR__ . '/subscriptions/views.php';
1073 1159 require __DIR__ . '/subscriptions/subscribe-modal/class-jetpack-subscribe-modal.php';
1160 +require __DIR__ . '/subscriptions/subscribe-overlay/class-jetpack-subscribe-overlay.php';
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();