Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: changed

adds new post meta for newsletter debug info to post sync
1 change: 1 addition & 0 deletions projects/packages/sync/src/class-defaults.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
);

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
134 changes: 134 additions & 0 deletions projects/plugins/jetpack/modules/subscriptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -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';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php
/**
* Subscriptions Helper
*
* This class provides helper functions for the Subscriptions module.
*
* @package jetpack
*/

use Automattic\Jetpack\Connection\Client;

/**
* Class Jetpack_Subscriptions_Helper
*/
class Jetpack_Subscriptions_Helper {
/**
* Fetch subscriber statistics from WordPress.com API.
* Results are cached for 5 minutes to reduce API requests.
*
* @since $$next-version$$
*
* @param int $site_id The site ID to fetch stats for.
* @return array|WP_Error Associative array with subscriber stats on success, WP_Error on failure.
* Returns array with keys: 'email_subscribers', 'paid_subscribers', 'all_subscribers', 'aggregate'.
*/
public static function fetch_subscriber_stats( $site_id ) {
if ( ! $site_id ) {
return new WP_Error( 'invalid_site_id', __( 'Invalid site ID provided.', 'jetpack' ) );
}

// Check cache first.
$cache_key = 'jetpack_subscriber_stats_' . $site_id;
$cached = get_transient( $cache_key );
if ( false !== $cached ) {
return $cached;
}

$stats_path = sprintf( '/sites/%d/subscribers/stats', $site_id );
$response = Client::wpcom_json_api_request_as_blog(
$stats_path,
'2',
array(),
null,
'wpcom'
);

if ( is_wp_error( $response ) ) {
return $response;
}

$stats_code = wp_remote_retrieve_response_code( $response );
if ( 200 !== $stats_code ) {
return new WP_Error(
'http_error',
sprintf(
/* translators: %d is the HTTP response code */
__( 'HTTP error %d when fetching subscriber stats.', 'jetpack' ),
$stats_code
),
array( 'status' => $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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* @package jetpack
*/

use Automattic\Jetpack\Connection\Client;
use Automattic\Jetpack\Modules;

/**
Expand Down Expand Up @@ -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'];
}
}

Expand Down
Loading