diff --git a/projects/packages/sync/changelog/add-post-meta-subscribers-list-at-send b/projects/packages/sync/changelog/add-post-meta-subscribers-list-at-send new file mode 100644 index 0000000000000..03e93b0cba335 --- /dev/null +++ b/projects/packages/sync/changelog/add-post-meta-subscribers-list-at-send @@ -0,0 +1,4 @@ +Significance: minor +Type: changed + +adds new post meta for newsletter debug info to post sync diff --git a/projects/packages/sync/src/class-defaults.php b/projects/packages/sync/src/class-defaults.php index 5bdaf3883ed7e..3e066bddb7618 100644 --- a/projects/packages/sync/src/class-defaults.php +++ b/projects/packages/sync/src/class-defaults.php @@ -790,6 +790,7 @@ public static function get_multisite_callable_whitelist() { 'videopress_guid', 'vimeo_poster_image', '_jetpack_blogging_prompt_key', + '_jetpack_newsletter_initial_debug_info', 'footnotes', // Core footnotes block ); diff --git a/projects/plugins/jetpack/changelog/add-post-meta-subscribers-list-at-send b/projects/plugins/jetpack/changelog/add-post-meta-subscribers-list-at-send new file mode 100644 index 0000000000000..97ab63f5128a7 --- /dev/null +++ b/projects/plugins/jetpack/changelog/add-post-meta-subscribers-list-at-send @@ -0,0 +1,5 @@ +Significance: patch +Type: other + +Adds newsletter debug info to post meta on initial publish. +Adds helper class for requesting stats, and updates the newsletter dashboard widgetp to use this as well. diff --git a/projects/plugins/jetpack/modules/subscriptions.php b/projects/plugins/jetpack/modules/subscriptions.php index e8341a063918e..5435998a42635 100644 --- a/projects/plugins/jetpack/modules/subscriptions.php +++ b/projects/plugins/jetpack/modules/subscriptions.php @@ -18,16 +18,23 @@ use Automattic\Jetpack\Admin_UI\Admin_Menu; use Automattic\Jetpack\Connection\Manager as Connection_Manager; use Automattic\Jetpack\Connection\XMLRPC_Async_Call; +use Automattic\Jetpack\Extensions\Premium_Content\Subscription_Service\Abstract_Token_Subscription_Service; use Automattic\Jetpack\Newsletter\Settings as Newsletter_Settings; use Automattic\Jetpack\Redirect; use Automattic\Jetpack\Status; use Automattic\Jetpack\Status\Host; use Automattic\Jetpack\Subscribers_Dashboard\Dashboard as Subscribers_Dashboard; +use const Automattic\Jetpack\Extensions\Subscriptions\META_NAME_FOR_POST_LEVEL_ACCESS_SETTINGS; if ( ! defined( 'ABSPATH' ) ) { exit( 0 ); } +// Load required classes and constants. +require_once JETPACK__PLUGIN_DIR . 'extensions/blocks/subscriptions/constants.php'; +require_once JETPACK__PLUGIN_DIR . 'extensions/blocks/premium-content/_inc/subscription-service/include.php'; +require_once JETPACK__PLUGIN_DIR . '_inc/lib/class-jetpack-newsletter-category-helper.php'; + add_action( 'jetpack_modules_loaded', 'jetpack_subscriptions_load' ); // Loads the User Content Link Redirection feature. @@ -133,6 +140,8 @@ public function __construct() { add_filter( 'jetpack_published_post_flags', array( $this, 'set_post_flags' ), 10, 2 ); + add_action( 'jetpack_published_post', array( $this, 'store_initial_debug_info' ), 10, 3 ); + add_filter( 'post_updated_messages', array( $this, 'update_published_message' ), 18, 1 ); // Set "social_notifications_subscribe" option during the first-time activation. @@ -993,6 +1002,130 @@ public function register_post_meta() { register_meta( 'post', '_jetpack_post_was_ever_published', $jetpack_post_was_ever_published ); } + /** + * Store the initial debug info when a post is first published. + * + * This method is called when a post is published and emails are sent to subscribers. + * It stores the subscriber count and metadata in post meta for debugging purposes. + * + * @since $$next-version$$ + * + * @param int $post_ID Post ID. + * @param array $flags Post flags including send_subscription. + * @param WP_Post $post Post object. + * + * @return void + */ + public function store_initial_debug_info( $post_ID, $flags, $post ) { + // Only store for posts. + if ( 'post' !== $post->post_type ) { + return; + } + + // Only store once - check if we've already stored debug info for this post. + $existing_subscribers = get_post_meta( $post_ID, '_jetpack_newsletter_initial_debug_info', true ); + if ( ! empty( $existing_subscribers ) ) { + return; + } + + // Fetch subscriber data from WordPress.com API. + $subscriber_data = $this->get_subscriber_data(); + + // Get email subscription setting for this post. + $dont_email = get_post_meta( $post_ID, '_jetpack_dont_email_post_to_subs', true ); + $email_to_subs_disabled = ! empty( $dont_email ); + + // Also store the final determination from the flags (includes more checks than post_meta). + $will_send_to_subscribers = isset( $flags['send_subscription'] ) && $flags['send_subscription']; + + // Get newsletter access level for this post. + // Use constant for meta key if available, fallback to string. + $access_level_meta_key = defined( 'Automattic\\Jetpack\\Extensions\\Subscriptions\\META_NAME_FOR_POST_LEVEL_ACCESS_SETTINGS' ) + ? META_NAME_FOR_POST_LEVEL_ACCESS_SETTINGS + : '_jetpack_newsletter_access'; + + $newsletter_access_level = get_post_meta( $post_ID, $access_level_meta_key, true ); + if ( empty( $newsletter_access_level ) ) { + // Use constant for default value. + $newsletter_access_level = Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_EVERYBODY; + } + + // Get newsletter categories information. + $newsletter_categories_enabled = (bool) get_option( 'wpcom_newsletter_categories_enabled', false ); + $post_categories = wp_get_post_categories( $post_ID ); + $newsletter_category_ids = Jetpack_Newsletter_Category_Helper::get_category_ids(); + $post_newsletter_categories = array(); + $post_non_newsletter_categories = array(); + + if ( $newsletter_categories_enabled && ! empty( $newsletter_category_ids ) && ! empty( $post_categories ) ) { + // Find which of the post's categories are newsletter categories. + $post_newsletter_categories = array_intersect( $post_categories, $newsletter_category_ids ); + $post_newsletter_categories = array_values( array_map( 'intval', $post_newsletter_categories ) ); + + // Find which of the post's categories are NOT newsletter categories. + $post_non_newsletter_categories = array_diff( $post_categories, $newsletter_category_ids ); + $post_non_newsletter_categories = array_values( array_map( 'intval', $post_non_newsletter_categories ) ); + } elseif ( ! empty( $post_categories ) ) { + // If newsletter categories are not enabled, all post categories are non-newsletter categories. + $post_non_newsletter_categories = array_values( array_map( 'intval', $post_categories ) ); + } + + // Store subscriber data with timestamp. + $data_to_store = array( + 'timestamp' => current_time( 'mysql' ), + 'email_subscribers' => isset( $subscriber_data['email_subscribers'] ) ? (int) $subscriber_data['email_subscribers'] : 0, + 'paid_subscribers' => isset( $subscriber_data['paid_subscribers'] ) ? (int) $subscriber_data['paid_subscribers'] : 0, + 'all_subscribers' => isset( $subscriber_data['all_subscribers'] ) ? (int) $subscriber_data['all_subscribers'] : 0, + 'email_to_subs_disabled' => $email_to_subs_disabled, + 'will_send_to_subscribers' => $will_send_to_subscribers, + 'newsletter_access_level' => $newsletter_access_level, + 'newsletter_categories_enabled' => $newsletter_categories_enabled, + 'newsletter_category_ids' => $post_newsletter_categories, + 'non_newsletter_category_ids' => $post_non_newsletter_categories, + ); + + update_post_meta( $post_ID, '_jetpack_newsletter_initial_debug_info', $data_to_store ); + } + + /** + * Get subscriber data from WordPress.com API. + * + * @since $$next-version$$ + * + * @return array Subscriber data including counts and email list. + */ + private function get_subscriber_data() { + $subscriber_data = array( + 'email_subscribers' => 0, + 'paid_subscribers' => 0, + 'all_subscribers' => 0, + 'email_subscriber_list' => array(), + ); + + // Only fetch if Jetpack is connected. + if ( ! Jetpack::is_connection_ready() ) { + return $subscriber_data; + } + + $site_id = Jetpack_Options::get_option( 'id' ); + + // First, get subscriber counts from stats endpoint. + $stats = Jetpack_Subscriptions_Helper::fetch_subscriber_stats( $site_id ); + if ( ! is_wp_error( $stats ) ) { + if ( isset( $stats['email_subscribers'] ) ) { + $subscriber_data['email_subscribers'] = $stats['email_subscribers']; + } + if ( isset( $stats['paid_subscribers'] ) ) { + $subscriber_data['paid_subscribers'] = $stats['paid_subscribers']; + } + if ( isset( $stats['all_subscribers'] ) ) { + $subscriber_data['all_subscribers'] = $stats['all_subscribers']; + } + } + + return $subscriber_data; + } + /** * Create a Subscribers menu displayed on self-hosted sites. * @@ -1085,6 +1218,7 @@ public function track_newsletter_category_creation() { Jetpack_Subscriptions::init(); require __DIR__ . '/subscriptions/views.php'; +require __DIR__ . '/subscriptions/class-jetpack-subscriptions-helper.php'; require __DIR__ . '/subscriptions/subscribe-modal/class-jetpack-subscribe-modal.php'; require __DIR__ . '/subscriptions/subscribe-overlay/class-jetpack-subscribe-overlay.php'; require __DIR__ . '/subscriptions/subscribe-floating-button/class-jetpack-subscribe-floating-button.php'; diff --git a/projects/plugins/jetpack/modules/subscriptions/class-jetpack-subscriptions-helper.php b/projects/plugins/jetpack/modules/subscriptions/class-jetpack-subscriptions-helper.php new file mode 100644 index 0000000000000..dbf78e11c1bfd --- /dev/null +++ b/projects/plugins/jetpack/modules/subscriptions/class-jetpack-subscriptions-helper.php @@ -0,0 +1,97 @@ + $stats_code ) + ); + } + + $subscriber_counts = json_decode( wp_remote_retrieve_body( $response ), true ); + if ( ! is_array( $subscriber_counts ) ) { + return new WP_Error( 'invalid_response', __( 'Invalid response format from API.', 'jetpack' ) ); + } + + $stats = array( + 'email_subscribers' => 0, + 'paid_subscribers' => 0, + 'all_subscribers' => 0, + 'aggregate' => array(), + ); + + if ( isset( $subscriber_counts['counts']['email_subscribers'] ) ) { + $stats['email_subscribers'] = (int) $subscriber_counts['counts']['email_subscribers']; + } + + if ( isset( $subscriber_counts['counts']['paid_subscribers'] ) ) { + $stats['paid_subscribers'] = (int) $subscriber_counts['counts']['paid_subscribers']; + } + + if ( isset( $subscriber_counts['counts']['all_subscribers'] ) ) { + $stats['all_subscribers'] = (int) $subscriber_counts['counts']['all_subscribers']; + } + + if ( isset( $subscriber_counts['aggregate'] ) && is_array( $subscriber_counts['aggregate'] ) ) { + $stats['aggregate'] = $subscriber_counts['aggregate']; + } + + // Cache successful responses for 5 minutes. + set_transient( $cache_key, $stats, 5 * MINUTE_IN_SECONDS ); + + return $stats; + } +} diff --git a/projects/plugins/jetpack/modules/subscriptions/newsletter-widget/class-jetpack-newsletter-dashboard-widget.php b/projects/plugins/jetpack/modules/subscriptions/newsletter-widget/class-jetpack-newsletter-dashboard-widget.php index 0208d46df14ca..4f6706cdfad48 100644 --- a/projects/plugins/jetpack/modules/subscriptions/newsletter-widget/class-jetpack-newsletter-dashboard-widget.php +++ b/projects/plugins/jetpack/modules/subscriptions/newsletter-widget/class-jetpack-newsletter-dashboard-widget.php @@ -5,7 +5,6 @@ * @package jetpack */ -use Automattic\Jetpack\Connection\Client; use Automattic\Jetpack\Modules; /** @@ -56,32 +55,23 @@ public static function get_config_data() { ); if ( Jetpack::is_connection_ready() ) { - $site_id = Jetpack_Options::get_option( 'id' ); - $api_path = sprintf( '/sites/%d/subscribers/stats', $site_id ); - $response = Client::wpcom_json_api_request_as_blog( - $api_path, - '2', - array(), - null, - 'wpcom' - ); - - if ( 200 === wp_remote_retrieve_response_code( $response ) ) { - $subscriber_counts = json_decode( wp_remote_retrieve_body( $response ), true ); - if ( isset( $subscriber_counts['counts']['email_subscribers'] ) ) { - $config_data['emailSubscribers'] = (int) $subscriber_counts['counts']['email_subscribers']; + $site_id = Jetpack_Options::get_option( 'id' ); + $stats = Jetpack_Subscriptions_Helper::fetch_subscriber_stats( $site_id ); + if ( ! is_wp_error( $stats ) ) { + if ( isset( $stats['email_subscribers'] ) ) { + $config_data['emailSubscribers'] = $stats['email_subscribers']; } - if ( isset( $subscriber_counts['counts']['paid_subscribers'] ) ) { - $config_data['paidSubscribers'] = (int) $subscriber_counts['counts']['paid_subscribers']; + if ( isset( $stats['paid_subscribers'] ) ) { + $config_data['paidSubscribers'] = $stats['paid_subscribers']; } - if ( isset( $subscriber_counts['counts']['all_subscribers'] ) ) { - $config_data['allSubscribers'] = (int) $subscriber_counts['counts']['all_subscribers']; + if ( isset( $stats['all_subscribers'] ) ) { + $config_data['allSubscribers'] = $stats['all_subscribers']; } - if ( isset( $subscriber_counts['aggregate'] ) ) { - $config_data['subscriberTotalsByDate'] = $subscriber_counts['aggregate']; + if ( isset( $stats['aggregate'] ) ) { + $config_data['subscriberTotalsByDate'] = $stats['aggregate']; } }