PluginProbe ʕ •ᴥ•ʔ
WP Popular Posts / 6.3.1
WP Popular Posts v6.3.1
4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.2.0 4.2.1 4.2.2 5.0.0 5.0.1 5.0.2 5.1.0 5.2.0 5.2.1 5.2.2 5.2.3 5.2.4 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 6.0.0 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.1.0 6.1.1 6.1.2 6.1.3 6.1.4 6.2.0 6.2.1 6.3.0 6.3.1 6.3.2 6.3.3 6.3.4 6.4.0 6.4.1 6.4.2 7.0.0 7.0.1 7.1.0 7.2.0 7.3.0 7.3.1 7.3.2 7.3.3 7.3.4 7.3.5 7.3.6 7.3.7 7.3.8 7.4.0 trunk 2.3.7 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.2 4.0.3 4.0.5 4.0.6
wordpress-popular-posts / src / Rest / ViewLoggerEndpoint.php
wordpress-popular-posts / src / Rest Last commit date
Controller.php 2 years ago Endpoint.php 2 years ago PostsEndpoint.php 2 years ago TaxonomiesEndpoint.php 2 years ago ThemesEndpoint.php 2 years ago ThumbnailsEndpoint.php 2 years ago ViewLoggerEndpoint.php 2 years ago WidgetEndpoint.php 2 years ago
ViewLoggerEndpoint.php
263 lines
1 <?php
2 namespace WordPressPopularPosts\Rest;
3
4 use WordPressPopularPosts\Helper;
5
6 class ViewLoggerEndpoint extends Endpoint {
7
8 /**
9 * Registers the endpoint(s).
10 *
11 * @since 5.3.0
12 */
13 public function register()
14 {
15 $version = '1';
16 $namespace = 'wordpress-popular-posts/v' . $version;
17
18 register_rest_route($namespace, '/popular-posts', [
19 [
20 'methods' => \WP_REST_Server::CREATABLE,
21 'callback' => [$this, 'update_views_count'],
22 'permission_callback' => '__return_true',
23 'args' => $this->get_tracking_params(),
24 ]
25 ]);
26 }
27
28 /**
29 * Updates the views count of a post / page.
30 *
31 * @since 4.1.0
32 *
33 * @param \WP_REST_Request $request Full details about the request.
34 * @return string
35 */
36 public function update_views_count($request) {
37 global $wpdb;
38
39 $post_ID = $request->get_param('wpp_id');
40 $sampling = $request->get_param('sampling');
41 $sampling_rate = $request->get_param('sampling_rate');
42
43 // Sampling settings from database
44 $_sampling = $this->config['tools']['sampling']['active'];
45 $_sampling_rate = $this->config['tools']['sampling']['rate'];
46
47 // Let's make sure that sampling settings we got
48 // on this request are what we expect
49 $sampling = $sampling != $_sampling ? $_sampling : $sampling;
50 $sampling_rate = $sampling_rate != $_sampling_rate ? $_sampling_rate : $sampling_rate;
51
52 $table = $wpdb->prefix . 'popularposts';
53 $wpdb->show_errors();
54
55 // Get translated object ID
56 $post_ID = $this->translate->get_object_id(
57 $post_ID,
58 get_post_type($post_ID),
59 true,
60 $this->translate->get_default_language()
61 );
62
63 $now = Helper::now();
64 $curdate = Helper::curdate();
65 $views = ($sampling)
66 ? $sampling_rate
67 : 1;
68
69 $original_views_count = $views;
70 $views = apply_filters('wpp_update_views_count_value', $views, $post_ID, $sampling, $sampling_rate);
71
72 if ( ! Helper::is_number($views) || $views <= 0 ) {
73 $views = $original_views_count;
74 }
75
76 // Allow WP themers / coders perform an action
77 // before updating views count
78 if ( has_action('wpp_pre_update_views') ) {
79 do_action('wpp_pre_update_views', $post_ID, $views);
80 }
81
82 $result1 = false;
83 $result2 = false;
84
85 $exec_time = 0;
86 $start = Helper::microtime_float();
87
88 // Store views data in persistent object cache
89 if (
90 wp_using_ext_object_cache()
91 && defined('WPP_CACHE_VIEWS')
92 && WPP_CACHE_VIEWS
93 ) {
94
95 $now_datetime = new \DateTime($now, wp_timezone());
96 $timestamp = $now_datetime->getTimestamp();
97 $date_time = $now_datetime->format('Y-m-d H:i');
98 $date_time_with_seconds = $now_datetime->format('Y-m-d H:i:s');
99 $high_accuracy = false;
100
101 $key = $high_accuracy ? $timestamp : $date_time;
102
103 $wpp_cache = wp_cache_get('_wpp_cache', 'transient');
104
105 if ( ! $wpp_cache ) {
106 $wpp_cache = [
107 'last_updated' => $date_time_with_seconds,
108 'data' => [
109 $post_ID => [
110 $key => 1
111 ]
112 ]
113 ];
114 } else {
115 if ( ! isset($wpp_cache['data'][$post_ID][$key]) ) {
116 $wpp_cache['data'][$post_ID][$key] = 1;
117 } else {
118 $wpp_cache['data'][$post_ID][$key] += 1;
119 }
120 }
121
122 // Update cache
123 wp_cache_set('_wpp_cache', $wpp_cache, 'transient', 0);
124
125 // How long has it been since the last time we saved to the database?
126 $last_update = $now_datetime->diff(new \DateTime($wpp_cache['last_updated'], wp_timezone()));
127 $diff_in_minutes = $last_update->days * 24 * 60;
128 $diff_in_minutes += $last_update->h * 60;
129 $diff_in_minutes += $last_update->i;
130
131 // It's been more than 2 minutes, save everything to DB
132 if ( $diff_in_minutes > 2 ) {
133
134 $query_data = "INSERT INTO {$table}data (`postid`,`day`,`last_viewed`,`pageviews`) VALUES ";
135 $query_summary = "INSERT INTO {$table}summary (`postid`,`pageviews`,`view_date`,`view_datetime`) VALUES ";
136
137 foreach( $wpp_cache['data'] as $pid => $data ) {
138 $views_count = 0;
139
140 foreach( $data as $ts => $cached_views ){
141 $views_count += $cached_views;
142 $ts = Helper::is_timestamp($ts) ? $ts : strtotime($ts);
143
144 $query_summary .= $wpdb->prepare('(%d,%d,%s,%s),', [
145 $pid,
146 $cached_views,
147 date('Y-m-d', $ts),
148 date('Y-m-d H:i:s', $ts)
149 ]);
150 }
151
152 $query_data .= $wpdb->prepare( '(%d,%s,%s,%s),', [
153 $pid,
154 $date_time_with_seconds,
155 $date_time_with_seconds,
156 $views_count
157 ]);
158 }
159
160 $query_data = rtrim($query_data, ',') . ' ON DUPLICATE KEY UPDATE pageviews=pageviews+VALUES(pageviews),last_viewed=VALUES(last_viewed);';
161 $query_summary = rtrim($query_summary, ',') . ';';
162
163 // Clear cache
164 $wpp_cache['last_updated'] = $date_time_with_seconds;
165 $wpp_cache['data'] = [];
166 wp_cache_set('_wpp_cache', $wpp_cache, 'transient', 0);
167
168 // Save
169 $result1 = $wpdb->query($query_data); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- We already prepared $query_data above
170 $result2 = $wpdb->query($query_summary); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- We already prepared $query_summary above
171 }
172 else {
173 $result1 = true;
174 $result2 = true;
175 }
176 } // Live update to the DB
177 else {
178 // Update all-time table
179 //phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $table is safe to use
180 $result1 = $wpdb->query($wpdb->prepare(
181 "INSERT INTO {$table}data
182 (postid, day, last_viewed, pageviews) VALUES (%d, %s, %s, %d)
183 ON DUPLICATE KEY UPDATE pageviews = pageviews + %d, last_viewed = %s;",
184 $post_ID,
185 $now,
186 $now,
187 $views,
188 $views,
189 $now
190 ));
191 //phpcs:enable
192
193 // Update range (summary) table
194 //phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $table is safe to use
195 $result2 = $wpdb->query($wpdb->prepare(
196 "INSERT INTO {$table}summary
197 (postid, pageviews, view_date, view_datetime) VALUES (%d, %d, %s, %s)
198 ON DUPLICATE KEY UPDATE pageviews = pageviews + %d, view_datetime = %s;",
199 $post_ID,
200 $views,
201 $curdate,
202 $now,
203 $views,
204 $now
205 ));
206 //phpcs:enable
207 }
208
209 $end = Helper::microtime_float();
210 $exec_time += round($end - $start, 6);
211
212 $response = ['results' => ''];
213
214 if ( ! $result1 || ! $result2 ) {
215 $response['results'] = 'WPP: failed to update views count!';
216 return new \WP_REST_Response($response, 500);
217 }
218
219 // Allow WP themers / coders perform an action
220 // after updating views count
221 if ( has_action('wpp_post_update_views') ) {
222 do_action('wpp_post_update_views', $post_ID);
223 }
224
225 $response['results'] = 'WPP: OK. Execution time: ' . $exec_time . ' seconds';
226 return new \WP_REST_Response($response, 201);
227 }
228
229 /**
230 * Retrieves the query params for tracking views count.
231 *
232 * @since 4.1.0
233 *
234 * @return array Query parameters for tracking views count.
235 */
236 public function get_tracking_params()
237 {
238 return [
239 'wpp_id' => [
240 'description' => __('The post / page ID.'),
241 'type' => 'integer',
242 'default' => 0,
243 'sanitize_callback' => 'absint',
244 'validate_callback' => 'rest_validate_request_arg',
245 ],
246 'sampling' => [
247 'description' => __('Enables Data Sampling.'),
248 'type' => 'integer',
249 'default' => 0,
250 'sanitize_callback' => 'absint',
251 'validate_callback' => 'rest_validate_request_arg',
252 ],
253 'sampling_rate' => [
254 'description' => __('Sets the Sampling Rate.'),
255 'type' => 'integer',
256 'default' => 100,
257 'sanitize_callback' => 'absint',
258 'validate_callback' => 'rest_validate_request_arg',
259 ]
260 ];
261 }
262 }
263