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 +109 -53 13.5.2 → 16.3-beta 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,21 @@
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';
@@ -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 );
@@ -139,14 +150,17 @@
139 150 // Customize the configuration URL to lead to the Subscriptions settings.
140 151 add_filter(
141 152 'jetpack_module_configuration_url_subscriptions',
142 153 function () {
143 - return Jetpack::admin_url( array( 'page' => 'jetpack#/newsletter' ) );
154 + return Newsletter_Urls::get_newsletter_settings_url();
144 155 }
145 156 );
146 157
147 158 // Track categories created through the category editor page
148 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();
149 163 }
150 164
151 165 /**
152 166 * Jetpack_Subscriptions::xmlrpc_methods()
@@ -368,23 +382,8 @@
368 382 'discussion',
369 383 'stc_enabled'
370 384 );
371 385
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 386 /** Email me whenever: Someone subscribes to my blog */
388 387 /* @since 8.1 */
389 388
390 389 add_settings_section(
@@ -466,24 +465,8 @@
466 465 <?php
467 466 }
468 467
469 468 /**
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 469 * Someone subscribes to my blog section
487 470 *
488 471 * @since 8.1
489 472 */
@@ -585,8 +568,9 @@
585 568
586 569 if ( $async ) {
587 570 XMLRPC_Async_Call::add_call( 'jetpack.subscribeToSite', 0, $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
588 571 } else {
572 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
589 573 $xml->addCall( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
590 574 }
591 575 }
592 576
@@ -594,19 +578,24 @@
594 578 return;
595 579 }
596 580
597 581 // Call.
582 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
598 583 $xml->query();
599 584
585 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
600 586 if ( $xml->isError() ) {
587 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false, otherwise we return early
601 588 return $xml->get_jetpack_error();
602 589 }
603 590
591 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
604 592 $responses = $xml->getResponse();
605 593
606 594 $r = array();
607 595 foreach ( (array) $responses as $response ) {
608 596 if ( isset( $response['faultCode'] ) || isset( $response['faultString'] ) ) {
597 + // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- $xml is set when $async is false
609 598 $r[] = $xml->get_jetpack_error( $response['faultCode'], $response['faultString'] );
610 599 continue;
611 600 }
612 601
@@ -724,9 +713,9 @@
724 713 */
725 714 do_action( 'jetpack_subscriptions_form_submission', $result );
726 715
727 716 wp_safe_redirect( "$redirect#$redirect_fragment" );
728 - exit;
717 + exit( 0 );
729 718 }
730 719
731 720 /**
732 721 * Jetpack_Subscriptions::comment_subscribe_init()
@@ -822,8 +811,19 @@
822 811 * @param int|string $comment_id Comment thread being subscribed to.
823 812 * @param string $approved Comment status.
824 813 */
825 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 +
826 826 if ( 'spam' === $approved ) {
827 827 return;
828 828 }
829 829
@@ -886,9 +886,9 @@
886 886 public function set_cookies( $subscribe_to_post = false, $post_id = null, $subscribe_to_blog = false ) {
887 887 $post_id = (int) $post_id;
888 888
889 889 /** This filter is already documented in core/wp-includes/comment-functions.php */
890 - $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
890 + $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', YEAR_IN_SECONDS );
891 891
892 892 /**
893 893 * Filter the Jetpack Comment cookie path.
894 894 *
@@ -911,15 +911,15 @@
911 911 */
912 912 $cookie_domain = apply_filters( 'jetpack_comment_cookie_domain', COOKIE_DOMAIN );
913 913
914 914 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 );
915 + setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, '1', time() + $cookie_lifetime, $cookie_path, $cookie_domain, is_ssl(), true );
916 916 } else {
917 917 setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
918 918 }
919 919
920 920 if ( $subscribe_to_blog ) {
921 - 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 );
922 922 } else {
923 923 setcookie( 'jetpack_blog_subscribe_' . self::$hash, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
924 924 }
925 925 }
@@ -937,8 +937,26 @@
937 937 }
938 938 }
939 939
940 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 + /**
941 959 * Save a flag when a post was ever published.
942 960 *
943 961 * It saves the post meta when the post was published and becomes a draft.
944 962 * Then this meta is used to hide subscription messaging in Publish panel.
@@ -947,8 +965,13 @@
947 965 * @param string $old_status The "old" post status of the transition when saved.
948 966 * @param object $post obj The post object.
949 967 */
950 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 +
951 974 $was_post_ever_published = get_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
952 975 if ( ! $was_post_ever_published && 'publish' === $old_status && 'draft' === $new_status ) {
953 976 update_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
954 977 }
@@ -954,23 +977,23 @@
954 977 }
955 978 }
956 979
957 980 /**
958 - * Checks if the current user can publish posts.
981 + * Checks if the current user can edit posts.
959 982 *
960 983 * @return bool
961 984 */
962 985 public function first_published_status_meta_auth_callback() {
963 986 /**
964 - * Filter the capability to view if a post was ever published in the Subscription Module.
987 + * Filter the capability required to edit the "was ever published" post meta.
965 988 *
966 989 * @module subscriptions
967 990 *
968 991 * @since 13.4
969 992 *
970 - * @param string $capability User capability needed to view if a post was ever published. Default to publish_posts.
993 + * @param string $capability User capability needed to edit the "was ever published" meta. Default to edit_posts.
971 994 */
972 - $capability = apply_filters( 'jetpack_subscriptions_post_was_ever_published_capability', 'publish_posts' );
995 + $capability = apply_filters( 'jetpack_subscriptions_post_was_ever_published_capability', 'edit_posts' );
973 996 if ( current_user_can( $capability ) ) {
974 997 return true;
975 998 }
976 999 return false;
@@ -980,16 +1003,17 @@
980 1003 * Registers the 'post_was_ever_published' post meta for use in the REST API.
981 1004 */
982 1005 public function register_post_meta() {
983 1006 $jetpack_post_was_ever_published = array(
984 - 'type' => 'boolean',
985 - 'description' => __( 'Whether the post was ever published.', 'jetpack' ),
986 - 'single' => true,
987 - 'default' => false,
988 - '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(
989 1012 'name' => 'jetpack_post_was_ever_published',
990 1013 ),
991 - '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.
992 1016 );
993 1017
994 1018 register_meta( 'post', '_jetpack_post_was_ever_published', $jetpack_post_was_ever_published );
995 1019 }
@@ -998,13 +1022,24 @@
998 1022 * Create a Subscribers menu displayed on self-hosted sites.
999 1023 *
1000 1024 * - It is not displayed on WordPress.com sites.
1001 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.
1002 1028 *
1003 1029 * @return void
1004 1030 */
1005 1031 public function add_subscribers_menu() {
1006 1032 /*
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 + /*
1007 1042 * Do not display any menu on WoA and WordPress.com Simple sites (unless Classic wp-admin is enabled).
1008 1043 * They already get a menu item under Users via nav-unification.
1009 1044 */
1010 1045 if ( ( new Host() )->is_wpcom_platform() && get_option( 'wpcom_admin_interface' ) !== 'wp-admin' ) {
@@ -1023,8 +1058,20 @@
1023 1058 ) {
1024 1059 return;
1025 1060 }
1026 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 +
1027 1074 $blog_id = Connection_Manager::get_site_id( true );
1028 1075
1029 1076 $link = Redirect::get_url(
1030 1077 'jetpack-menu-jetpack-manage-subscribers',
@@ -1030,15 +1077,18 @@
1030 1077 'jetpack-menu-jetpack-manage-subscribers',
1031 1078 array( 'site' => $blog_id ? $blog_id : $status->get_site_suffix() )
1032 1079 );
1033 1080
1034 - add_submenu_page(
1035 - 'jetpack',
1036 - esc_attr__( 'Subscribers', 'jetpack' ),
1037 - __( '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>',
1038 1086 'manage_options',
1039 1087 esc_url( $link ),
1040 - null
1088 + null,
1089 + $position,
1090 + array( 'key' => 'jetpack-subscribers' )
1041 1091 );
1042 1092 }
1043 1093
1044 1094 /**
@@ -1076,4 +1126,10 @@
1076 1126
1077 1127 require __DIR__ . '/subscriptions/views.php';
1078 1128 require __DIR__ . '/subscriptions/subscribe-modal/class-jetpack-subscribe-modal.php';
1079 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();