PluginProbe ʕ •ᴥ•ʔ
WP Popular Posts / trunk
WP Popular Posts vtrunk
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 4 years ago Endpoint.php 4 years ago PostsEndpoint.php 1 year ago TaxonomiesEndpoint.php 5 years ago ThemesEndpoint.php 4 years ago ThumbnailsEndpoint.php 5 years ago ViewLoggerEndpoint.php 8 months ago WidgetEndpoint.php 1 year ago
ViewLoggerEndpoint.php
352 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 = '2';
16 $namespace = 'wordpress-popular-posts/v' . $version;
17
18 register_rest_route($namespace, '/views/(?P<id>[\d]+)', [
19 [
20 'methods' => \WP_REST_Server::READABLE,
21 'callback' => [$this, 'get_views_count'],
22 'permission_callback' => '__return_true',
23 'args' => $this->get_views_params(),
24 ]
25 ]);
26
27 register_rest_route($namespace, '/views/(?P<id>[\d]+)', [
28 [
29 'methods' => \WP_REST_Server::CREATABLE,
30 'callback' => [$this, 'update_views_count'],
31 'permission_callback' => '__return_true',
32 'args' => $this->get_tracking_params(),
33 ]
34 ]);
35 }
36
37 /**
38 * Returs the views count of a post/page.
39 *
40 * @since 7.0.0
41 *
42 * @param \WP_REST_Request $request Full details about the request.
43 * @return string Views count string.
44 */
45 public function get_views_count($request) {
46 $post_id = $request->get_param('id');
47 $range = in_array( $request->get_param('range'), ['last24hours', 'last7days', 'last30days', 'all', 'custom'] ) ? $request->get_param('range') : 'all';
48 $time_unit = in_array( $request->get_param('time_unit'), ['minute', 'hour', 'day', 'week', 'month'] ) ? $request->get_param('time_unit') : 'hour';
49 $time_quantity = $request->get_param('time_quantity');
50 $include_views_text = 1 == $request->get_param('include_views_text') ? 1 : 0;
51
52 $views_count_shortcode = '[wpp_views_count post_id=' . $post_id . ' include_views_text=' . $include_views_text . ' range="' . $range . '"';
53
54 if ( 'custom' == $range ) {
55 $views_count_shortcode .= ' time_unit="' . $time_unit . '" time_quantity=' . $time_quantity;
56 }
57
58 $views_count_shortcode .= ']';
59
60 $response['text'] = do_shortcode($views_count_shortcode);
61
62 return new \WP_REST_Response( $response, 200 );
63 }
64
65 /**
66 * Updates the views count of a post / page.
67 *
68 * @since 4.1.0
69 *
70 * @param \WP_REST_Request $request Full details about the request.
71 * @return string
72 */
73 public function update_views_count($request) {
74 global $wpdb;
75
76 $post_ID = $request->get_param('id');
77
78 $sampling = $request->get_param('sampling');
79 $sampling_rate = $request->get_param('sampling_rate');
80
81 // Sampling settings from database
82 $_sampling = $this->config['tools']['sampling']['active'];
83 $_sampling_rate = $this->config['tools']['sampling']['rate'];
84
85 // Let's make sure that sampling settings we got
86 // on this request are what we expect
87 $sampling = $sampling != $_sampling ? $_sampling : $sampling;
88 $sampling_rate = $sampling_rate != $_sampling_rate ? $_sampling_rate : $sampling_rate;
89
90 $table = $wpdb->prefix . 'popularposts';
91 $data_table = "{$table}data";
92 $summary_table = "{$table}summary";
93 $wpdb->show_errors();
94
95 // Get translated object ID
96 $post_ID = $this->translate->get_object_id(
97 $post_ID,
98 get_post_type($post_ID),
99 true,
100 $this->translate->get_default_language()
101 );
102
103 $now = Helper::now();
104 $curdate = Helper::curdate();
105 $views = ($sampling)
106 ? $sampling_rate
107 : 1;
108
109 $original_views_count = $views;
110 $views = apply_filters('wpp_update_views_count_value', $views, $post_ID, $sampling, $sampling_rate);
111
112 if ( ! Helper::is_number($views) || $views <= 0 ) {
113 $views = $original_views_count;
114 }
115
116 // Allow WP themers / coders perform an action
117 // before updating views count
118 if ( has_action('wpp_pre_update_views') ) {
119 do_action('wpp_pre_update_views', $post_ID, $views);
120 }
121
122 $result1 = false;
123 $result2 = false;
124
125 $exec_time = 0;
126 $start = Helper::microtime_float();
127
128 // Store views data in persistent object cache
129 if (
130 wp_using_ext_object_cache()
131 && defined('WPP_CACHE_VIEWS')
132 && WPP_CACHE_VIEWS
133 ) {
134
135 $now_datetime = new \DateTime($now, wp_timezone());
136 $timestamp = $now_datetime->getTimestamp();
137 $date_time = $now_datetime->format('Y-m-d H:i');
138 $date_time_with_seconds = $now_datetime->format('Y-m-d H:i:s');
139 $high_accuracy = false;
140
141 $key = $high_accuracy ? $timestamp : $date_time;
142
143 $wpp_cache = wp_cache_get('_wpp_cache', 'transient');
144
145 if ( ! $wpp_cache ) {
146 $wpp_cache = [
147 'last_updated' => $date_time_with_seconds,
148 'data' => [
149 $post_ID => [
150 $key => 1
151 ]
152 ]
153 ];
154 } else {
155 if ( ! isset($wpp_cache['data'][$post_ID][$key]) ) {
156 $wpp_cache['data'][$post_ID][$key] = 1;
157 } else {
158 $wpp_cache['data'][$post_ID][$key] += 1;
159 }
160 }
161
162 // Update cache
163 wp_cache_set('_wpp_cache', $wpp_cache, 'transient', 0);
164
165 // How long has it been since the last time we saved to the database?
166 $last_update = $now_datetime->diff(new \DateTime($wpp_cache['last_updated'], wp_timezone()));
167 $diff_in_minutes = $last_update->days * 24 * 60;
168 $diff_in_minutes += $last_update->h * 60;
169 $diff_in_minutes += $last_update->i;
170
171 // It's been more than 2 minutes, save everything to DB
172 if ( $diff_in_minutes > 2 ) {
173
174 $query_data = $wpdb->prepare("INSERT INTO %i (`postid`,`day`,`last_viewed`,`pageviews`) VALUES ", $data_table);
175 $query_summary = $wpdb->prepare("INSERT INTO %i (`postid`,`pageviews`,`view_date`,`view_datetime`) VALUES ", $summary_table);
176
177 foreach( $wpp_cache['data'] as $pid => $data ) {
178 $views_count = 0;
179
180 foreach( $data as $ts => $cached_views ){
181 $views_count += $cached_views;
182 $ts = Helper::is_timestamp($ts) ? $ts : strtotime($ts);
183
184 $query_summary .= $wpdb->prepare('(%d,%d,%s,%s),', [
185 $pid,
186 $cached_views,
187 date('Y-m-d', $ts),
188 date('Y-m-d H:i:s', $ts)
189 ]);
190 }
191
192 $query_data .= $wpdb->prepare( '(%d,%s,%s,%s),', [
193 $pid,
194 $date_time_with_seconds,
195 $date_time_with_seconds,
196 $views_count
197 ]);
198 }
199
200 $query_data = rtrim($query_data, ',') . ' ON DUPLICATE KEY UPDATE pageviews=pageviews+VALUES(pageviews),last_viewed=VALUES(last_viewed);';
201 $query_summary = rtrim($query_summary, ',') . ';';
202
203 // Clear cache
204 $wpp_cache['last_updated'] = $date_time_with_seconds;
205 $wpp_cache['data'] = [];
206 wp_cache_set('_wpp_cache', $wpp_cache, 'transient', 0);
207
208 // Save
209 //phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.PreparedSQL.NotPrepared -- We already prepared $query_data and $query_summary above
210 $result1 = $wpdb->query($query_data);
211 $result2 = $wpdb->query($query_summary);
212 //phpcs:enable
213 }
214 else {
215 $result1 = true;
216 $result2 = true;
217 }
218 } // Live update to the DB
219 else {
220 //phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
221 // Update all-time table
222 $result1 = $wpdb->query($wpdb->prepare(
223 "INSERT INTO %i
224 (postid, day, last_viewed, pageviews) VALUES (%d, %s, %s, %d)
225 ON DUPLICATE KEY UPDATE pageviews = pageviews + %d, last_viewed = %s;",
226 $data_table,
227 $post_ID,
228 $now,
229 $now,
230 $views,
231 $views,
232 $now
233 ));
234
235 // Update range (summary) table
236 $result2 = $wpdb->query($wpdb->prepare(
237 "INSERT INTO %i
238 (postid, pageviews, view_date, view_datetime) VALUES (%d, %d, %s, %s)
239 ON DUPLICATE KEY UPDATE pageviews = pageviews + %d, view_datetime = %s;",
240 $summary_table,
241 $post_ID,
242 $views,
243 $curdate,
244 $now,
245 $views,
246 $now
247 ));
248 //phpcs:enable
249 }
250
251 $end = Helper::microtime_float();
252 $exec_time += round($end - $start, 6);
253
254 $response = ['results' => ''];
255
256 if ( ! $result1 || ! $result2 ) {
257 $response['results'] = 'WPP: failed to update views count!';
258 return new \WP_REST_Response($response, 500);
259 }
260
261 // Allow WP themers / coders perform an action
262 // after updating views count
263 if ( has_action('wpp_post_update_views') ) {
264 do_action('wpp_post_update_views', $post_ID);
265 }
266
267 $response['results'] = 'WPP: OK. Execution time: ' . $exec_time . ' seconds';
268 return new \WP_REST_Response($response, 201);
269 }
270
271 /**
272 * Retrieves the query params for tracking views count.
273 *
274 * @since 4.1.0
275 *
276 * @return array Query parameters for tracking views count.
277 */
278 public function get_tracking_params()
279 {
280 return [
281 'id' => [
282 'type' => 'integer',
283 'minimum' => 1,
284 'sanitize_callback' => 'absint',
285 'validate_callback' => 'rest_validate_request_arg',
286 ],
287 'sampling' => [
288 'description' => __('Enables Data Sampling.'),
289 'type' => 'integer',
290 'default' => 0,
291 'sanitize_callback' => 'absint',
292 'validate_callback' => 'rest_validate_request_arg',
293 ],
294 'sampling_rate' => [
295 'description' => __('Sets the Sampling Rate.'),
296 'type' => 'integer',
297 'default' => 100,
298 'sanitize_callback' => 'absint',
299 'validate_callback' => 'rest_validate_request_arg',
300 ]
301 ];
302 }
303
304 /**
305 * Retrieves the query params for getting post/page/cpt views count.
306 *
307 * @since 7.0.0
308 *
309 * @return array Query parameters for getting post/page/cpt views count.
310 */
311 public function get_views_params()
312 {
313 return [
314 'id' => [
315 'type' => 'integer',
316 'minimum' => 1,
317 'sanitize_callback' => 'absint',
318 'validate_callback' => 'rest_validate_request_arg',
319 ],
320 'range' => [
321 'type' => 'string',
322 'enum' => ['last24hours', 'last7days', 'last30days', 'all', 'custom'],
323 'default' => 'all',
324 'sanitize_callback' => 'sanitize_text_field',
325 'validate_callback' => '__return_true'
326 ],
327 'time_unit' => [
328 'type' => 'string',
329 'enum' => ['minute', 'hour', 'day', 'week', 'month'],
330 'default' => 'hour',
331 'sanitize_callback' => 'sanitize_text_field',
332 'validate_callback' => 'rest_validate_request_arg',
333 ],
334 'time_quantity' => [
335 'type' => 'integer',
336 'default' => 24,
337 'minimum' => 1,
338 'sanitize_callback' => 'absint',
339 'validate_callback' => 'rest_validate_request_arg',
340 ],
341 'include_views_text' => [
342 'type' => 'integer',
343 'default' => 1,
344 'sanitize_callback' => 'absint',
345 'validate_callback' => function($param, $request, $key) {
346 return is_numeric($param);
347 }
348 ],
349 ];
350 }
351 }
352