PluginProbe ʕ •ᴥ•ʔ
Reviews Feed – Add Testimonials and Customer Reviews From Google Reviews, Yelp, TripAdvisor, and More / 2.6.7
Reviews Feed – Add Testimonials and Customer Reviews From Google Reviews, Yelp, TripAdvisor, and More v2.6.7
2.11.0 2.10.0 2.9.0 2.8.0 2.7.0 2.6.7 2.6.8 2.6.5 2.6.4 2.6.3 2.6.2 2.6.0 2.5.5 2.5.4 2.5.3 2.5.2 trunk 1.0 1.0.1 1.0.2 1.0.3 1.1 1.1.1 1.1.2 1.2.0 2.0 2.1.0 2.1.1 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.5.0 2.5.1
reviews-feed / class / Common / Services / FeedCacheUpdateService.php
reviews-feed / class / Common / Services Last commit date
Upgrade 2 months ago CLIService.php 2 months ago FeedCacheUpdateService.php 2 months ago MigrationReactivationNotice.php 2 months ago SBR_Upgrader.php 2 months ago SettingsManagerService.php 2 months ago ShortcodeService.php 2 months ago SiteUrlWatcher.php 2 months ago UsageTrackingService.php 2 months ago
FeedCacheUpdateService.php
153 lines
1 <?php
2
3 /**
4 * Feed Cache Update Service
5 */
6
7 namespace SmashBalloon\Reviews\Common\Services;
8
9 if (! defined('ABSPATH')) {
10 exit;
11 }
12
13 use SmashBalloon\Reviews\Common\AuthorizationStatusCheck;
14 use SmashBalloon\Reviews\Common\FeedCacheUpdater;
15 use Smashballoon\Stubs\Services\ServiceProvider;
16
17
18 class FeedCacheUpdateService extends ServiceProvider {
19 public const CACHES_TABLE_NAME = 'sbr_feed_caches';
20
21 public const CRON_JOB_ADDITIONAL_BATCH = 'sbr_cron_additional_batch';
22
23 public const CRON_JOB_NAME = 'sbr_feed_update';
24
25 const RESULTS_PER_PAGE = 20;
26
27 const RESULTS_PER_CRON_UPDATE = 10;
28
29 /**
30 * @var AuthorizationStatusCheck
31 */
32 private $auth_check;
33
34 public function register()
35 {
36 add_shortcode('reviews-feed-cron-simulator', array( $this, 'init' ));
37 add_action(self::CRON_JOB_NAME, array( $this, 'init' ));
38 add_action(self::CRON_JOB_ADDITIONAL_BATCH, array( $this, 'init_additional_batch' ));
39
40 add_action('sbr_before_shortcode_render', array( $this, 'maybe_check_cron_schedule' ));
41 }
42
43 public function init()
44 {
45 $this->auth_check = new AuthorizationStatusCheck();
46 if ($this->should_do_updates()) {
47 $this->auth_check->update_status(
48 [ 'last_cron_update' => time() ]
49 );
50 $this->do_updates();
51 }
52 }
53
54 public function init_additional_batch()
55 {
56 $this->do_updates();
57 }
58
59 public function should_do_updates()
60 {
61 $statuses = $this->auth_check->get_statuses();
62 $time_with_minute_buffer = time() + 60;
63 $statuses['last_cron_update'] = 0;
64 if ($statuses['last_cron_update'] < $time_with_minute_buffer - $statuses['update_frequency']) {
65 return true;
66 }
67
68 return false;
69 }
70
71 public function do_updates()
72 {
73 $caches = $this->get_caches();
74
75 $updater = new FeedCacheUpdater($caches);
76 $updater->do_updates();
77
78 $num = count($caches);
79 if ($num === self::RESULTS_PER_CRON_UPDATE) {
80 // Schedule another batch in 5 minutes if needed
81 wp_schedule_single_event(time() + 300, self::CRON_JOB_ADDITIONAL_BATCH);
82 }
83 }
84
85 public function get_caches()
86 {
87 return $this->feed_caches_query(array( 'cron_update' => true ));
88 }
89
90 public function feed_caches_query($args)
91 {
92 global $wpdb;
93 $feed_cache_table_name = $wpdb->prefix . self::CACHES_TABLE_NAME;
94
95 // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared -- Table name is safely constructed from $wpdb->prefix
96 if (! isset($args['cron_update'])) {
97 $sql = "
98 SELECT * FROM $feed_cache_table_name;";
99 } else {
100 // Group by feed_id so each unique feed contributes ONE batch entry
101 // instead of one entry per cache_type. `update_or_insert()` flags
102 // both 'posts' and 'header' rows with `cron_update = 'yes'`, so a
103 // feed with both rows >12h-stale was previously yielding two batch
104 // entries, and FeedCacheUpdater::do_updates triggered a full
105 // Feed::get_set_cache() per entry — fetching reviews + header
106 // for the same feed twice in the same cron cycle. Customer
107 // Google Places API spend was 2x what it needed to be.
108 //
109 // MIN(id) / MIN(last_updated) make the query strict-mode safe
110 // when sql_mode includes ONLY_FULL_GROUP_BY; the LIMIT
111 // (`RESULTS_PER_CRON_UPDATE`) budget now yields that many
112 // unique feeds per cron tick instead of half as many feeds
113 // (when both rows for the same feed were stale).
114 //
115 // FeedCacheUpdater::do_updates only reads `feed_id` from each row,
116 // so collapsing duplicates is invisible to the caller — same feeds
117 // processed, half the HTTP fetches, no behavior change downstream.
118 $sql = $wpdb->prepare(
119 "
120 SELECT MIN(id) AS id, feed_id, MIN(last_updated) AS last_updated
121 FROM $feed_cache_table_name
122 WHERE cron_update = 'yes'
123 AND last_updated < %s
124 GROUP BY feed_id
125 ORDER BY last_updated ASC
126 LIMIT %d;",
127 gmdate('Y-m-d H:i:s', time() - 12 * HOUR_IN_SECONDS),
128 self::RESULTS_PER_CRON_UPDATE
129 );
130 }
131 $results = $wpdb->get_results($sql, ARRAY_A);
132 // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
133 return $results;
134 }
135
136 public function maybe_check_cron_schedule()
137 {
138 if (! sbr_current_user_can('manage_reviews_feed_options')) {
139 return;
140 }
141
142 self::schedule_cron_job();
143 }
144
145 public static function schedule_cron_job()
146 {
147 if (! wp_next_scheduled(self::CRON_JOB_NAME)) {
148 wp_schedule_event(time(), 'hourly', self::CRON_JOB_NAME);
149 }
150 }
151
152 }
153