Skip to content

Commit 2982a5f

Browse files
dognose24Copilotkangzj
authored
Improve Post Stats cache handling for invalid or error data (#46211)
* Remove post stats cache * changelog * Improve post stats cache handling for invalid or error data * Update changelog * Respect the cache first and return errors or invalid data as they were * Keep WP errors from cache along with the valid response * Update annotations * Update annotations Co-authored-by: Copilot <[email protected]> * Apply suggestions from code review Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Jasper Kang <[email protected]>
1 parent c65298a commit 2982a5f

File tree

2 files changed

+56
-23
lines changed

2 files changed

+56
-23
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: patch
2+
Type: changed
3+
4+
Improve Post Stats cache handling for invalid or error data

projects/packages/stats/src/class-wpcom-stats.php

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,11 @@ protected function fetch_stats( $args = array() ) {
488488
*
489489
* Unlike the above function, this caches data in the post meta table. As such,
490490
* it prevents wp_options from blowing up when retrieving views for large numbers
491-
* of posts at the same time. However, the final response is the same as above.
491+
* of posts at the same time.
492+
*
493+
* This function returns valid arrays and WP_Error objects from cache if within the expiration period.
494+
* If the cached entry is malformed or invalid, a refresh is triggered regardless of cache time.
495+
* This self-healing behavior reduces API calls when remote fetch fails, but ensures data validity.
492496
*
493497
* @param array $args Query parameters.
494498
* @param int $post_id Post ID to acquire stats for.
@@ -503,34 +507,59 @@ protected function fetch_post_stats( $args, $post_id ) {
503507
if ( $stats_cache ) {
504508
$data = reset( $stats_cache );
505509

506-
if (
507-
! is_array( $data )
508-
|| empty( $data )
509-
|| is_wp_error( $data )
510-
) {
511-
return $data;
512-
}
513-
514-
$time = key( $data );
515-
$views = $data[ $time ] ?? null;
516-
517-
// Bail if data is malformed.
518-
if ( ! is_numeric( $time ) || ! is_array( $views ) ) {
519-
return $data;
520-
}
510+
// Check if we have a valid cache structure with a time key.
511+
if ( is_array( $data ) && ! empty( $data ) ) {
512+
$time = key( $data );
521513

522-
/** This filter is already documented in projects/packages/stats/src/class-wpcom-stats.php */
523-
$expiration = apply_filters(
524-
'jetpack_fetch_stats_cache_expiration',
525-
self::STATS_CACHE_EXPIRATION_IN_MINUTES * MINUTE_IN_SECONDS
526-
);
514+
// If we have a numeric time, check if cache is still valid.
515+
if ( is_numeric( $time ) ) {
516+
/** This filter is already documented in projects/packages/stats/src/class-wpcom-stats.php */
517+
$expiration = apply_filters(
518+
'jetpack_fetch_stats_cache_expiration',
519+
self::STATS_CACHE_EXPIRATION_IN_MINUTES * MINUTE_IN_SECONDS
520+
);
527521

528-
if ( ( time() - $time ) < $expiration ) {
529-
return array_merge( array( 'cached_at' => $time ), $views );
522+
// If within cache period, return cached data after type validation.
523+
if ( ( time() - $time ) < $expiration ) {
524+
$cached_value = $data[ $time ];
525+
526+
// If it's an array or WP_Error, handle appropriately.
527+
if ( is_wp_error( $cached_value ) ) {
528+
return $cached_value;
529+
}
530+
if ( is_array( $cached_value ) ) {
531+
return array_merge( array( 'cached_at' => $time ), $cached_value );
532+
}
533+
534+
// For any other unexpected type, treat as malformed cache.
535+
// Fall through to refresh.
536+
}
537+
}
530538
}
531539
}
532540

541+
// Cache doesn't exist, is expired, or is malformed - refresh it.
542+
return $this->refresh_post_stats_cache( $endpoint, $args, $post_id, $meta_name );
543+
}
544+
545+
/**
546+
* Force fetch stats from WPCOM, and always update cache.
547+
*
548+
* This function will cache the result regardless of whether the fetch succeeds
549+
* or fails. This ensures that failed requests are also cached, reducing the
550+
* frequency of API calls when the remote service is experiencing issues.
551+
*
552+
* @param string $endpoint The stats endpoint.
553+
* @param array $args The query arguments.
554+
* @param int $post_id The post ID.
555+
* @param string $meta_name The meta name.
556+
*
557+
* @return array|WP_Error
558+
*/
559+
protected function refresh_post_stats_cache( $endpoint, $args, $post_id, $meta_name ) {
533560
$wpcom_stats = $this->fetch_remote_stats( $endpoint, $args );
561+
562+
// Always cache the result, even if it's an error or empty.
534563
update_post_meta( $post_id, $meta_name, array( time() => $wpcom_stats ) );
535564

536565
return $wpcom_stats;

0 commit comments

Comments
 (0)