PluginProbe
Parse.ly / 3.18.1
Parse.ly v3.18.1
3.24.1 3.24.0 3.23.7 3.23.6 3.23.5 3.23.4 3.23.3 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.17.0 3.18.0 3.18.1 3.19.0 3.19.1 3.19.2 3.19.3 3.2.0 3.2.1 3.20.0 3.20.1 3.20.2 3.20.3 All 105 releases
wp-parsely / src / rest-api / stats / class-endpoint-posts.php

class-endpoint-posts.php in Parse.ly 3.18.1, at src/rest-api/stats/class-endpoint-posts.php

300 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Stats API Endpoint: Posts
4 *
5 * @package Parsely
6 * @since 3.17.0
7 */
8
9 declare(strict_types=1);
10
11 namespace Parsely\REST_API\Stats;
12
13 use Parsely\REST_API\Base_Endpoint;
14 use Parsely\Services\Content_API\Content_API_Service;
15 use WP_Error;
16 use WP_REST_Request;
17 use WP_REST_Response;
18 use stdClass;
19
20 /**
21 * The Stats API Posts endpoint.
22 *
23 * Provides an endpoint for retrieving posts.
24 *
25 * @since 3.17.0
26 */
27 class Endpoint_Posts extends Base_Endpoint {
28 use Post_Data_Trait;
29
30 public const TOP_POSTS_DEFAULT_LIMIT = 5;
31 public const SORT_DEFAULT = 'views';
32
33 /**
34 * The metrics that can be sorted by.
35 *
36 * @since 3.17.0
37 *
38 * @var array<int, string>
39 * @see https://docs.parse.ly/api-available-metrics/
40 */
41 public const SORT_METRICS = array(
42 'views',
43 'mobile_views',
44 'tablet_views',
45 'desktop_views',
46 'visitors',
47 'visitors_new',
48 'visitors_returning',
49 'engaged_minutes',
50 'avg_engaged',
51 'avg_engaged_new',
52 'avg_engaged_returning',
53 'social_interactions',
54 'fb_interactions',
55 'tw_interactions',
56 'pi_interactions',
57 'social_referrals',
58 'fb_referrals',
59 'tw_referrals',
60 'pi_referrals',
61 'search_refs',
62 );
63
64 /**
65 * The Parse.ly Content API service.
66 *
67 * @since 3.17.0
68 *
69 * @var Content_API_Service
70 */
71 public $content_api;
72
73 /**
74 * Constructor.
75 *
76 * @since 3.17.0
77 *
78 * @param Stats_Controller $controller The stats controller.
79 */
80 public function __construct( Stats_Controller $controller ) {
81 parent::__construct( $controller );
82 $this->content_api = $this->parsely->get_content_api();
83 }
84
85 /**
86 * Returns the endpoint name.
87 *
88 * @since 3.17.0
89 *
90 * @return string
91 */
92 public static function get_endpoint_name(): string {
93 return 'posts';
94 }
95
96 /**
97 * Registers the routes for the objects of the controller.
98 *
99 * @since 3.17.0
100 */
101 public function register_routes(): void {
102 /**
103 * GET /posts
104 * Retrieves posts for the given criteria.
105 */
106 $this->register_rest_route(
107 '/',
108 array( 'GET' ),
109 array( $this, 'get_posts' ),
110 array_merge(
111 array(
112 'period_start' => array(
113 'description' => 'The start of the period to query.',
114 'type' => 'string',
115 'required' => false,
116 ),
117 'period_end' => array(
118 'description' => 'The end of the period to query.',
119 'type' => 'string',
120 'required' => false,
121 ),
122 'pub_date_start' => array(
123 'description' => 'The start of the publication date range to query.',
124 'type' => 'string',
125 'required' => false,
126 ),
127 'pub_date_end' => array(
128 'description' => 'The end of the publication date range to query.',
129 'type' => 'string',
130 'required' => false,
131 ),
132 'limit' => array(
133 'description' => 'The number of posts to return.',
134 'type' => 'integer',
135 'required' => false,
136 'default' => self::TOP_POSTS_DEFAULT_LIMIT,
137 ),
138 'sort' => array(
139 'description' => 'The sort order of the posts.',
140 'type' => 'string',
141 'enum' => self::SORT_METRICS,
142 'default' => self::SORT_DEFAULT,
143 'required' => false,
144 ),
145 'page' => array(
146 'description' => 'The page to fetch.',
147 'type' => 'integer',
148 'required' => false,
149 'default' => 1,
150 ),
151 'author' => array(
152 'description' => 'Comma-separated list of authors to filter by.',
153 'type' => 'string',
154 'required' => false,
155 'validate_callback' => array( $this, 'validate_max_length_is_5' ),
156 'sanitize_callback' => array( $this, 'sanitize_string_to_array' ),
157 ),
158 'section' => array(
159 'description' => 'Comma-separated list of sections to filter by.',
160 'type' => 'string',
161 'required' => false,
162 'validate_callback' => array( $this, 'validate_max_length_is_5' ),
163 'sanitize_callback' => array( $this, 'sanitize_string_to_array' ),
164 ),
165 'tag' => array(
166 'description' => 'Comma-separated list of tags to filter by.',
167 'type' => 'string',
168 'required' => false,
169 'validate_callback' => array( $this, 'validate_max_length_is_5' ),
170 'sanitize_callback' => array( $this, 'sanitize_string_to_array' ),
171 ),
172 'segment' => array(
173 'description' => 'The segment to filter by.',
174 'type' => 'string',
175 'required' => false,
176 ),
177 'urls' => array(
178 'description' => 'The URLs to fetch data for.',
179 'type' => 'array',
180 'sanitize_callback' => array( $this, 'sanitize_urls' ),
181 'required' => false,
182 ),
183 ),
184 $this->get_itm_source_param_args()
185 )
186 );
187 }
188
189 /**
190 * Sanitizes a string to an array, splitting it by commas.
191 *
192 * @since 3.17.0
193 *
194 * @param string|array<string> $str The string to sanitize.
195 * @return array<string> The sanitized array.
196 */
197 public function sanitize_string_to_array( $str ): array {
198 if ( is_array( $str ) ) {
199 return $str;
200 }
201
202 return explode( ',', $str );
203 }
204
205 /**
206 * Sanitizes all the items of an array as URLs.
207 *
208 * @since 3.18.0
209 *
210 * @param array<string> $urls The array to sanitize.
211 * @return array<string> The sanitized array.
212 */
213 public function sanitize_urls( array $urls ): array {
214 return array_map( 'sanitize_url', $urls );
215 }
216
217 /**
218 * Validates that the parameter has at most 5 items.
219 *
220 * @since 3.17.0
221 *
222 * @param string|array<string> $string_or_array The string or array to validate.
223 * @return true|WP_Error
224 */
225 public function validate_max_length_is_5( $string_or_array ) {
226 if ( is_string( $string_or_array ) ) {
227 $string_or_array = $this->sanitize_string_to_array( $string_or_array );
228 }
229
230 if ( count( $string_or_array ) > 5 ) {
231 return new WP_Error( 'invalid_param', __( 'The parameter must have at most 5 items.', 'wp-parsely' ) );
232 }
233
234 return true;
235 }
236
237 /**
238 * API Endpoint: GET /stats/posts
239 *
240 * Retrieves the posts with the given query parameters.
241 *
242 * @since 3.17.0
243 *
244 * @param WP_REST_Request $request The request.
245 * @return array<string, stdClass>|WP_Error|WP_REST_Response
246 */
247 public function get_posts( WP_REST_Request $request ) {
248 $params = $request->get_params();
249
250 // Setup the itm_source if it is provided.
251 $this->set_itm_source_from_request( $request );
252
253 /**
254 * The raw analytics data, received by the API.
255 *
256 * @var array<stdClass>|WP_Error $analytics_request
257 */
258 $analytics_request = $this->content_api->get_posts(
259 array(
260 'period_start' => $params['period_start'] ?? null,
261 'period_end' => $params['period_end'] ?? null,
262 'pub_date_start' => $params['pub_date_start'] ?? null,
263 'pub_date_end' => $params['pub_date_end'] ?? null,
264 'limit' => $params['limit'] ?? self::TOP_POSTS_DEFAULT_LIMIT,
265 'sort' => $params['sort'] ?? self::SORT_DEFAULT,
266 'page' => $params['page'] ?? 1,
267 'author' => $params['author'] ?? null,
268 'section' => $params['section'] ?? null,
269 'tag' => $params['tag'] ?? null,
270 'segment' => $params['segment'] ?? null,
271 'itm_source' => $params['itm_source'] ?? null,
272 'urls' => $params['urls'] ?? null,
273 )
274 );
275
276 if ( is_wp_error( $analytics_request ) ) {
277 return $analytics_request;
278 }
279
280 // Process the data.
281 $posts = array();
282
283 /**
284 * The analytics data object.
285 *
286 * @var array<string,array<mixed>> $analytics_request
287 */
288 foreach ( $analytics_request as $item ) {
289 $posts[] = $this->extract_post_data( $item );
290 }
291
292 $response_data = array(
293 'params' => $params,
294 'data' => $posts,
295 );
296
297 return new WP_REST_Response( $response_data, 200 );
298 }
299 }
300