PluginProbe
Parse.ly / 3.17.0
Parse.ly v3.17.0
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.17.0, at src/rest-api/stats/class-endpoint-posts.php

281 lines 7.1 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 ),
178 $this->get_itm_source_param_args()
179 )
180 );
181 }
182
183 /**
184 * Sanitizes a string to an array, splitting it by commas.
185 *
186 * @since 3.17.0
187 *
188 * @param string|array<string> $str The string to sanitize.
189 * @return array<string> The sanitized array.
190 */
191 public function sanitize_string_to_array( $str ): array {
192 if ( is_array( $str ) ) {
193 return $str;
194 }
195
196 return explode( ',', $str );
197 }
198
199 /**
200 * Validates that the parameter has at most 5 items.
201 *
202 * @since 3.17.0
203 *
204 * @param string|array<string> $string_or_array The string or array to validate.
205 * @return true|WP_Error
206 */
207 public function validate_max_length_is_5( $string_or_array ) {
208 if ( is_string( $string_or_array ) ) {
209 $string_or_array = $this->sanitize_string_to_array( $string_or_array );
210 }
211
212 if ( count( $string_or_array ) > 5 ) {
213 return new WP_Error( 'invalid_param', __( 'The parameter must have at most 5 items.', 'wp-parsely' ) );
214 }
215
216 return true;
217 }
218
219 /**
220 * API Endpoint: GET /stats/posts
221 *
222 * Retrieves the posts with the given query parameters.
223 *
224 * @since 3.17.0
225 *
226 * @param WP_REST_Request $request The request.
227 * @return array<string, stdClass>|WP_Error|WP_REST_Response
228 */
229 public function get_posts( WP_REST_Request $request ) {
230 $params = $request->get_params();
231
232 // Setup the itm_source if it is provided.
233 $this->set_itm_source_from_request( $request );
234
235 /**
236 * The raw analytics data, received by the API.
237 *
238 * @var array<stdClass>|WP_Error $analytics_request
239 */
240 $analytics_request = $this->content_api->get_posts(
241 array(
242 'period_start' => $params['period_start'] ?? null,
243 'period_end' => $params['period_end'] ?? null,
244 'pub_date_start' => $params['pub_date_start'] ?? null,
245 'pub_date_end' => $params['pub_date_end'] ?? null,
246 'limit' => $params['limit'] ?? self::TOP_POSTS_DEFAULT_LIMIT,
247 'sort' => $params['sort'] ?? self::SORT_DEFAULT,
248 'page' => $params['page'] ?? 1,
249 'author' => $params['author'] ?? null,
250 'section' => $params['section'] ?? null,
251 'tag' => $params['tag'] ?? null,
252 'segment' => $params['segment'] ?? null,
253 'itm_source' => $params['itm_source'] ?? null,
254 )
255 );
256
257 if ( is_wp_error( $analytics_request ) ) {
258 return $analytics_request;
259 }
260
261 // Process the data.
262 $posts = array();
263
264 /**
265 * The analytics data object.
266 *
267 * @var array<string,array<mixed>> $analytics_request
268 */
269 foreach ( $analytics_request as $item ) {
270 $posts[] = $this->extract_post_data( $item );
271 }
272
273 $response_data = array(
274 'params' => $params,
275 'data' => $posts,
276 );
277
278 return new WP_REST_Response( $response_data, 200 );
279 }
280 }
281