PluginProbe
WebberZone Top 10 — Popular Posts / 4.3.4
WebberZone Top 10 — Popular Posts v4.3.4
4.5.1 4.5.0 4.4.3 4.4.2 4.4.1 4.4.0 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 trunk 1.0 1.0.1 1.1 1.2 1.3 1.4 1.4.1 1.5 1.5.1 1.5.2 1.5.3 1.6 1.6.1 All 117 releases
top-10 / includes / frontend / class-rest-api.php

class-rest-api.php in WebberZone Top 10 — Popular Posts 4.3.4, at includes/frontend/class-rest-api.php

469 lines 12.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * REST API class.
4 *
5 * @package WebberZone\Top_Ten\Frontend
6 */
7
8 namespace WebberZone\Top_Ten\Frontend;
9
10 use WebberZone\Top_Ten\Counter;
11
12 if ( ! defined( 'WPINC' ) ) {
13 die;
14 }
15
16 /**
17 * REST API class.
18 *
19 * @since 3.0.0
20 */
21 class REST_API extends \WP_REST_Controller {
22
23 /**
24 * Posts Route.
25 *
26 * @since 3.3.0
27 *
28 * @var string Posts Route.
29 */
30 public $posts_route;
31
32 /**
33 * Tracker Route.
34 *
35 * @since 3.3.0
36 *
37 * @var string Tracker Route.
38 */
39 public $tracker_route;
40
41 /**
42 * Counter Route.
43 *
44 * @since 4.0.0
45 *
46 * @var string Counter Route.
47 */
48 public $counter_route;
49
50 /**
51 * Main constructor.
52 *
53 * @since 3.0.0
54 */
55 public function __construct() {
56 $this->namespace = 'top-10/v1';
57 $this->posts_route = 'popular-posts';
58 $this->tracker_route = 'tracker';
59 $this->counter_route = 'counter';
60 }
61
62 /**
63 * Initialises the Top 10 REST API adding the necessary routes.
64 *
65 * @since 3.0.0
66 */
67 public function register_routes() {
68 register_rest_route(
69 $this->namespace,
70 '/' . $this->posts_route,
71 array(
72 'methods' => \WP_REST_Server::READABLE,
73 'callback' => array( $this, 'get_items' ),
74 'permission_callback' => array( $this, 'permissions_check' ),
75 'args' => $this->get_items_params(),
76 )
77 );
78 register_rest_route(
79 $this->namespace,
80 '/' . $this->posts_route . '/(?P<id>[\d]+)',
81 array(
82 'methods' => \WP_REST_Server::READABLE,
83 'callback' => array( $this, 'get_item' ),
84 'permission_callback' => array( $this, 'permissions_check' ),
85 'args' => array(
86 'id' => array(
87 'description' => __( 'Post ID.', 'top-10' ),
88 'type' => 'integer',
89 ),
90 ),
91 )
92 );
93 register_rest_route(
94 $this->namespace,
95 '/' . $this->tracker_route,
96 array(
97 'methods' => \WP_REST_Server::CREATABLE,
98 'callback' => array( $this, 'update_post_count' ),
99 'permission_callback' => array( $this, 'permissions_check' ),
100 'args' => $this->get_tracker_params(),
101 )
102 );
103 register_rest_route(
104 $this->namespace,
105 '/' . $this->counter_route . '/(?P<id>[\d]+)',
106 array(
107 'methods' => \WP_REST_Server::READABLE,
108 'callback' => array( $this, 'get_counter' ),
109 'permission_callback' => array( $this, 'permissions_check' ),
110 'args' => $this->get_counter_params(),
111 )
112 );
113 }
114
115 /**
116 * Check if a given request has access to get items
117 *
118 * @param \WP_REST_Request $request Full data about the request.
119 *
120 * @return \WP_Error|bool
121 */
122 public function permissions_check( \WP_REST_Request $request ) {
123 $context = $request->get_param( 'context' );
124
125 if ( 'edit' === $context && ! current_user_can( 'edit_posts' ) ) {
126 return new \WP_Error(
127 'rest_forbidden_context',
128 __( 'Sorry, you are not allowed to view this context.', 'top-10' ),
129 array( 'status' => rest_authorization_required_code() )
130 );
131 }
132
133 return apply_filters( 'top_ten_rest_api_permissions_check', true, $request );
134 }
135
136 /**
137 * Get popular posts.
138 *
139 * @since 3.0.0
140 *
141 * @param \WP_REST_Request $request WP Rest request.
142 * @return mixed|\WP_REST_Response Array of post objects or post IDs.
143 */
144 public function get_items( $request ) {
145 $popular_posts = array();
146
147 $args = $request->get_params();
148
149 /**
150 * Filter the REST API arguments before they passed to get_tptn_posts().
151 *
152 * @since 3.0.0
153 *
154 * @param array $args Arguments array.
155 * @param \WP_REST_Request $request WP Rest request.
156 */
157 $args = apply_filters( 'top_ten_rest_api_get_tptn_posts_args', $args, $request );
158
159 $results = Display::get_posts( $args );
160
161 if ( ! empty( $results ) ) {
162 foreach ( $results as $popular_post ) {
163 if ( ! $this->check_read_permission( $popular_post, $request ) ) {
164 continue;
165 }
166
167 $popular_posts[] = $this->prepare_item( $popular_post, $request );
168 }
169 }
170 return rest_ensure_response( $popular_posts );
171 }
172
173 /**
174 * Get a popular post by ID. Also includes the number of views.
175 *
176 * @since 3.0.0
177 *
178 * @param \WP_REST_Request $request WP Rest request.
179 * @return mixed|\WP_REST_Response Array of post objects or post IDs.
180 */
181 public function get_item( $request ) {
182
183 $id = $request->get_param( 'id' );
184
185 $error = new \WP_Error(
186 'rest_post_invalid_id',
187 __( 'Invalid post ID.', 'top-10' ),
188 array( 'status' => 404 )
189 );
190
191 if ( (int) $id <= 0 ) {
192 return $error;
193 }
194
195 $post = get_post( (int) $id );
196 if ( empty( $post ) || empty( $post->ID ) || ! $this->check_read_permission( $post, $request ) ) {
197 return $error;
198 }
199
200 $post = $this->prepare_item( $post, $request );
201
202 return rest_ensure_response( $post );
203 }
204
205 /**
206 * Get a popular post by ID. Also includes the number of views.
207 *
208 * @since 3.0.0
209 *
210 * @param \WP_Post $popular_post Popular Post object.
211 * @param \WP_REST_Request $request WP Rest request.
212 * @return array|mixed The formatted Popular Post object.
213 */
214 public function prepare_item( $popular_post, $request ) {
215
216 // Need to prepare items for the rest response.
217 $posts_controller = new \WP_REST_Posts_Controller( $popular_post->post_type );
218 $data = $posts_controller->prepare_item_for_response( $popular_post, $request );
219
220 // Add pageviews from popular_post object to response.
221 $visits = isset( $popular_post->visits ) ? $popular_post->visits : Counter::get_post_count_only( $popular_post->ID );
222 $data->data['visits'] = absint( $visits );
223
224 return $this->prepare_response_for_collection( $data );
225 }
226
227 /**
228 * Update post count.
229 *
230 * @since 3.0.0
231 *
232 * @param \WP_REST_Request $request WP Rest request.
233 * @return mixed|\WP_REST_Response Array of post objects or post IDs.
234 */
235 public function update_post_count( $request ) {
236
237 $id = absint( $request->get_param( 'top_ten_id' ) );
238 $blog_id = absint( $request->get_param( 'top_ten_blog_id' ) );
239 $activate_counter = absint( $request->get_param( 'activate_counter' ) );
240 $top_ten_debug = absint( $request->get_param( 'top_ten_debug' ) );
241
242 $str = \WebberZone\Top_Ten\Tracker::update_count( $id, $blog_id, $activate_counter );
243
244 if ( 1 === $top_ten_debug ) {
245 return rest_ensure_response( $str );
246 } else {
247 $response = new \WP_REST_Response( '', 204 );
248 $response->header( 'Cache-Control', 'max-age=15, s-maxage=0' );
249 return $response;
250 }
251 }
252
253 /**
254 * Get the counter.
255 *
256 * @since 4.0.0
257 *
258 * @param \WP_REST_Request $request WP Rest request.
259 * @return mixed|\WP_REST_Response Array of post objects or post IDs.
260 */
261 public function get_counter( $request ) {
262 $id = absint( $request->get_param( 'id' ) );
263
264 $error = new \WP_Error(
265 'rest_post_invalid_id',
266 __( 'Invalid post ID.', 'top-10' ),
267 array( 'status' => 404 )
268 );
269
270 if ( (int) $id <= 0 ) {
271 return $error;
272 }
273
274 $args = array();
275
276 $counter = sanitize_text_field( $request->get_param( 'counter' ) ) ? sanitize_text_field( $request->get_param( 'counter' ) ) : 'total';
277 $blog_id = absint( $request->get_param( 'blog_id' ) ) ? absint( $request->get_param( 'blog_id' ) ) : get_current_blog_id();
278
279 $from_date = sanitize_text_field( $request->get_param( 'from_date' ) );
280 $to_date = sanitize_text_field( $request->get_param( 'to_date' ) );
281
282 if ( ! empty( $from_date ) ) {
283 $args['from_date'] = $from_date;
284 }
285 if ( ! empty( $to_date ) ) {
286 $args['to_date'] = $to_date;
287 }
288
289 $counter = absint( Counter::get_post_count_only( (int) $id, $counter, $blog_id, $args ) );
290
291 return rest_ensure_response( $counter );
292 }
293
294 /**
295 * Get the arguments for fetching the popular posts.
296 *
297 * @since 3.0.0
298 *
299 * @return array Top 10 REST API popular posts arguments.
300 */
301 public function get_items_params() {
302 $args = array(
303 'limit' => array(
304 'description' => esc_html__( 'Number of posts', 'top-10' ),
305 'type' => 'integer',
306 'sanitize_callback' => 'absint',
307 ),
308 'post_types' => array(
309 'description' => esc_html__( 'Post types', 'top-10' ),
310 'type' => 'string',
311 ),
312 'context' => array(
313 'description' => esc_html__( 'Scope under which the request is made; determines fields present in response.', 'top-10' ),
314 'type' => 'string',
315 'enum' => array( 'view', 'embed', 'edit' ),
316 'default' => 'view',
317 ),
318 );
319
320 return apply_filters( 'top_ten_rest_api_get_items_params', $args );
321 }
322
323 /**
324 * Get the arguments for tracking posts.
325 *
326 * @since 3.0.0
327 *
328 * @return array Top 10 REST API popular posts arguments.
329 */
330 public function get_tracker_params() {
331 $args = array(
332 'top_ten_id' => array(
333 'description' => esc_html__( 'ID of the post.', 'top-10' ),
334 'type' => 'integer',
335 'sanitize_callback' => 'absint',
336 ),
337 'top_ten_blog_id' => array(
338 'description' => esc_html__( 'Blog ID of the post.', 'top-10' ),
339 'type' => 'integer',
340 'sanitize_callback' => 'absint',
341 ),
342 'activate_counter' => array(
343 'description' => esc_html__( 'Activate counter flag.', 'top-10' ),
344 'type' => 'integer',
345 'sanitize_callback' => 'absint',
346 ),
347 'top_ten_debug' => array(
348 'description' => esc_html__( 'Debug flag.', 'top-10' ),
349 'type' => 'integer',
350 'sanitize_callback' => 'absint',
351 ),
352 );
353
354 return apply_filters( 'top_ten_rest_api_get_tracker_params', $args );
355 }
356
357 /**
358 * Get counter params.
359 *
360 * @since 4.0.0
361 *
362 * @return array Top 10 REST API counter arguments.
363 */
364 public function get_counter_params() {
365 $args = array(
366 'id' => array(
367 'description' => esc_html__( 'ID of the post.', 'top-10' ),
368 'type' => 'integer',
369 'sanitize_callback' => 'absint',
370 ),
371 'counter' => array(
372 'description' => esc_html__( 'Counter type.', 'top-10' ),
373 'type' => 'string',
374 'sanitize_callback' => 'sanitize_text_field',
375 ),
376 'blog_id' => array(
377 'description' => esc_html__( 'Blog ID.', 'top-10' ),
378 'type' => 'integer',
379 'sanitize_callback' => 'absint',
380 ),
381 'from_date' => array(
382 'description' => esc_html__( 'From date.', 'top-10' ),
383 'type' => 'string',
384 'sanitize_callback' => 'sanitize_text_field',
385 ),
386 'to_date' => array(
387 'description' => esc_html__( 'To date.', 'top-10' ),
388 'type' => 'string',
389 'sanitize_callback' => 'sanitize_text_field',
390 ),
391 );
392
393 return apply_filters( 'top_ten_rest_api_get_counter_params', $args );
394 }
395
396 /**
397 * Checks if a given post type can be viewed or managed.
398 *
399 * @since 3.0.0
400 *
401 * @param \WP_Post_Type|string $post_type Post type name or object.
402 * @return bool Whether the post type is allowed in REST.
403 */
404 protected function check_is_post_type_allowed( $post_type ) {
405 if ( ! is_object( $post_type ) ) {
406 $post_type = get_post_type_object( $post_type );
407 }
408
409 if ( ! empty( $post_type ) && ! empty( $post_type->show_in_rest ) ) {
410 return true;
411 }
412
413 return false;
414 }
415
416 /**
417 * Checks if a post can be read.
418 *
419 * Correctly handles posts with the inherit status.
420 *
421 * @since 3.0.0
422 *
423 * @param \WP_Post $post Post object.
424 * @param \WP_REST_Request $request WP Rest request.
425 * @return bool Whether the post can be read.
426 */
427 public function check_read_permission( $post, $request = null ) {
428 $post_type = get_post_type_object( $post->post_type );
429 if ( ! $this->check_is_post_type_allowed( $post_type ) ) {
430 return false;
431 }
432
433 // If context is 'edit', require edit permissions to prevent exposing sensitive data like passwords.
434 if ( $request && 'edit' === $request->get_param( 'context' ) ) {
435 if ( ! current_user_can( 'edit_post', $post->ID ) ) {
436 return false;
437 }
438 }
439
440 // Is the post readable?
441 if ( 'publish' === $post->post_status || current_user_can( 'read_post', $post->ID ) ) {
442 return true;
443 }
444
445 $post_status_obj = get_post_status_object( $post->post_status );
446 if ( $post_status_obj && $post_status_obj->public ) {
447 return true;
448 }
449
450 // Can we read the parent if we're inheriting?
451 if ( 'inherit' === $post->post_status && $post->post_parent > 0 ) {
452 $parent = get_post( $post->post_parent );
453 if ( $parent ) {
454 return $this->check_read_permission( $parent, $request );
455 }
456 }
457
458 /*
459 * If there isn't a parent, but the status is set to inherit, assume
460 * it's published (as per get_post_status()).
461 */
462 if ( 'inherit' === $post->post_status ) {
463 return true;
464 }
465
466 return false;
467 }
468 }
469