PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 15.0.3
Jetpack – WP Security, Backup, Speed, & Growth v15.0.3
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / sal / class.json-api-links.php
jetpack / sal Last commit date
class.json-api-date.php 11 months ago class.json-api-links.php 1 year ago class.json-api-metadata.php 1 year ago class.json-api-platform-jetpack.php 1 year ago class.json-api-platform.php 1 year ago class.json-api-post-base.php 1 year ago class.json-api-post-jetpack.php 1 year ago class.json-api-site-base.php 11 months ago class.json-api-site-jetpack-base.php 1 year ago class.json-api-site-jetpack.php 1 year ago class.json-api-token.php 1 year ago
class.json-api-links.php
451 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * WPCOM_JSON_API_Links class.
4 *
5 * @package automattic/jetpack
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit( 0 );
10 }
11
12 require_once __DIR__ . '/../class.json-api.php';
13
14 /**
15 * Base class for WPCOM_JSON_API_Links.
16 */
17 class WPCOM_JSON_API_Links {
18
19 /**
20 * An instance of the WPCOM_JSON_API.
21 *
22 * @var WPCOM_JSON_API
23 */
24 private $api;
25
26 /**
27 * A WPCOM_JSON_API_Links instance.
28 *
29 * @var WPCOM_JSON_API_Links
30 */
31 private static $instance;
32
33 /**
34 * An array of the closest supported version of an endpoint to the current endpoint.
35 *
36 * @var array
37 */
38 private $closest_endpoint_cache_by_version = array();
39
40 /**
41 * An array including the current api endpoint as well as the max versions found if that endpoint doesn't exist.
42 *
43 * @var array
44 */
45 private $matches_by_version = array();
46
47 /**
48 * An array including the cached endpoint path versions.
49 *
50 * @var array
51 */
52 private $cache_result = null;
53
54 /**
55 * Creates a new instance of the WPCOM_JSON_API_Links class.
56 *
57 * @return WPCOM_JSON_API_Links
58 */
59 public static function getInstance() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
60 if ( null === self::$instance ) {
61 self::$instance = new self();
62 }
63
64 return self::$instance;
65 }
66
67 /**
68 * WPCOM_JSON_API_Links constructor.
69 *
70 * Method protected for singleton.
71 */
72 protected function __construct() {
73 $this->api = WPCOM_JSON_API::init();
74 }
75
76 /**
77 * An empty, private __clone method to prohibit cloning of this instance.
78 */
79 private function __clone() { }
80
81 /**
82 * Overriding PHP's default __wakeup method to prvent unserializing of the instance, and return an error message.
83 *
84 * @return never
85 */
86 public function __wakeup() {
87 die( "Please don't __wakeup WPCOM_JSON_API_Links" );
88 }
89
90 /**
91 * Generate a URL to an endpoint
92 *
93 * Used to construct meta links in API responses
94 *
95 * @param mixed ...$args Optional arguments to be appended to URL.
96 * @return string Endpoint URL
97 **/
98 public function get_link( ...$args ) {
99 $format = array_shift( $args );
100 $base = WPCOM_JSON_API__BASE;
101
102 $path = array_pop( $args );
103
104 if ( $path ) {
105 $path = '/' . ltrim( $path, '/' );
106 // tack the path onto the end of the format string.
107 // have to escape %'s in the path as %% because
108 // we're about to pass it through sprintf and we don't
109 // want it to see the % as a placeholder.
110 $format .= str_replace( '%', '%%', $path );
111 }
112
113 // Escape any % in args before using sprintf.
114 $escaped_args = array();
115 foreach ( $args as $arg_key => $arg_value ) {
116 $escaped_args[ $arg_key ] = str_replace( '%', '%%', $arg_value );
117 }
118
119 $relative_path = vsprintf( $format, $escaped_args );
120
121 if ( ! wp_startswith( $relative_path, '.' ) ) {
122 // Generic version. Match the requested version as best we can.
123 $api_version = $this->get_closest_version_of_endpoint( $format, $relative_path );
124 $base = substr( $base, 0, - 1 ) . $api_version;
125 }
126
127 // escape any % in the relative path before running it through sprintf again.
128 $relative_path = str_replace( '%', '%%', $relative_path );
129 // http, WPCOM_JSON_API__BASE, ... , path.
130 // %s , %s , $format, %s.
131 return esc_url_raw( sprintf( "https://%s$relative_path", $base ) );
132 }
133
134 /**
135 * Generate the /me prefixed endpoint URL
136 *
137 * Used to construct meta links in API responses, specific to WordPress.com user account pages.
138 *
139 * @param string $path Optional path to be appended to the URL.
140 * @return string /me endpoint URL
141 **/
142 public function get_me_link( $path = '' ) {
143 return $this->get_link( '/me', $path );
144 }
145
146 /**
147 * Generate the endpoint URL for taxonomies
148 *
149 * Used to construct meta links in API responses, specific to taxonomies.
150 *
151 * @param int $blog_id The site's Jetpack blog ID.
152 * @param int $taxonomy_id The taxonomy ID (for example of the category, tag).
153 * @param string $taxonomy_type The taxonomy type (for example category, tag).
154 * @param string $path Optional path to be appended to the URL.
155 * @return string Endpoint URL including taxonomy information.
156 **/
157 public function get_taxonomy_link( $blog_id, $taxonomy_id, $taxonomy_type, $path = '' ) {
158 switch ( $taxonomy_type ) {
159 case 'category':
160 return $this->get_link( '/sites/%d/categories/slug:%s', $blog_id, $taxonomy_id, $path );
161
162 case 'post_tag':
163 return $this->get_link( '/sites/%d/tags/slug:%s', $blog_id, $taxonomy_id, $path );
164
165 default:
166 return $this->get_link( '/sites/%d/taxonomies/%s/terms/slug:%s', $blog_id, $taxonomy_type, $taxonomy_id, $path );
167 }
168 }
169
170 /**
171 * Generate the endpoint URL for media links
172 *
173 * Used to construct meta links in API responses, specific to media links.
174 *
175 * @param int $blog_id The site's Jetpack blog ID.
176 * @param int $media_id The media item ID.
177 * @param string $path Optional path to be appended to the URL.
178 * @return string Endpoint URL including media information.
179 **/
180 public function get_media_link( $blog_id, $media_id, $path = '' ) {
181 return $this->get_link( '/sites/%d/media/%d', $blog_id, $media_id, $path );
182 }
183
184 /**
185 * Generate the site link endpoint URL
186 *
187 * Used to construct meta links in API responses, specific to /site links.
188 *
189 * @param int $blog_id The site's Jetpack blog ID.
190 * @param string $path Optional path to be appended to the URL.
191 * @return string Endpoint URL including site information.
192 **/
193 public function get_site_link( $blog_id, $path = '' ) {
194 return $this->get_link( '/sites/%d', $blog_id, $path );
195 }
196
197 /**
198 * Generate the posts endpoint URL
199 *
200 * Used to construct meta links in API responses, specific to posts links.
201 *
202 * @param int $blog_id The site's Jetpack blog ID.
203 * @param int $post_id The post ID.
204 * @param string $path Optional path to be appended to the URL.
205 * @return string Endpoint URL including post information.
206 **/
207 public function get_post_link( $blog_id, $post_id, $path = '' ) {
208 return $this->get_link( '/sites/%d/posts/%d', $blog_id, $post_id, $path );
209 }
210
211 /**
212 * Generate the comments endpoint URL
213 *
214 * Used to construct meta links in API responses, specific to comments links.
215 *
216 * @param int $blog_id The site's Jetpack blog ID.
217 * @param int $comment_id The comment ID.
218 * @param string $path Optional path to be appended to the URL.
219 * @return string Endpoint URL including comment information.
220 **/
221 public function get_comment_link( $blog_id, $comment_id, $path = '' ) {
222 return $this->get_link( '/sites/%d/comments/%d', $blog_id, $comment_id, $path );
223 }
224
225 /**
226 * Generate the endpoint URL for Publicize connections
227 *
228 * Used to construct meta links in API responses, specific to Publicize connections.
229 *
230 * @param int $blog_id The site's Jetpack blog ID.
231 * @param int $publicize_connection_id The ID of the Publicize connection.
232 * @param string $path Optional path to be appended to the URL.
233 * @return string Endpoint URL including Publicize connection information.
234 **/
235 public function get_publicize_connection_link( $blog_id, $publicize_connection_id, $path = '' ) {
236 return $this->get_link( '.1/sites/%d/publicize-connections/%d', $blog_id, $publicize_connection_id, $path );
237 }
238
239 /**
240 * Generate the endpoint URL for a single Publicize connection including a Keyring connection
241 *
242 * Used to construct meta links in API responses, specific to a single Publicize and Keyring connection.
243 *
244 * @param int $keyring_token_id The ID of the Keyring connection.
245 * @param string $path Optional path to be appended to the URL.
246 * @return string Endpoint URL including specific Keyring connection information for a specific Publicize connection.
247 **/
248 public function get_publicize_connections_link( $keyring_token_id, $path = '' ) {
249 return $this->get_link( '.1/me/publicize-connections/?keyring_connection_ID=%d', $keyring_token_id, $path );
250 }
251
252 /**
253 * Generate the endpoint URL for a single Keyring connection
254 *
255 * Used to construct meta links in API responses, specific to a Keyring connections.
256 *
257 * @param int $keyring_token_id The ID of the Keyring connection.
258 * @param string $path Optional path to be appended to the URL.
259 * @return string Endpoint URL including specific Keyring connection.
260 **/
261 public function get_keyring_connection_link( $keyring_token_id, $path = '' ) {
262 return $this->get_link( '.1/me/keyring-connections/%d', $keyring_token_id, $path );
263 }
264
265 /**
266 * Generate the endpoint URL for an external service that can be integrated with via Keyring
267 *
268 * Used to construct meta links in API responses, specific to an external service.
269 *
270 * @param int $external_service The ID of the external service.
271 * @param string $path Optional path to be appended to the URL.
272 * @return string Endpoint URL including information about an external service that WordPress.com or Jetpack sites can integrate with via keyring.
273 **/
274 public function get_external_service_link( $external_service, $path = '' ) {
275 return $this->get_link( '.1/meta/external-services/%s', $external_service, $path );
276 }
277
278 /**
279 * Try to find the closest supported version of an endpoint to the current endpoint
280 *
281 * For example, if we were looking at the path /animals/panda:
282 * - if the current endpoint is v1.3 and there is a v1.3 of /animals/%s available, we return 1.3
283 * - if the current endpoint is v1.3 and there is no v1.3 of /animals/%s known, we fall back to the
284 * maximum available version of /animals/%s, e.g. 1.1
285 *
286 * This method is used in get_link() to construct meta links for API responses.
287 *
288 * @param string $template_path The generic endpoint path, e.g. /sites/%s .
289 * @param string $path The current endpoint path, relative to the version, e.g. /sites/12345 .
290 * @param string $request_method Request method used to access the endpoint path .
291 * @return string The current version, or otherwise the maximum version available
292 */
293 public function get_closest_version_of_endpoint( $template_path, $path, $request_method = 'GET' ) {
294 $closest_endpoint_cache_by_version = & $this->closest_endpoint_cache_by_version;
295
296 $closest_endpoint_cache = & $closest_endpoint_cache_by_version[ $this->api->version ];
297 if ( ! $closest_endpoint_cache ) {
298 $closest_endpoint_cache_by_version[ $this->api->version ] = array();
299 $closest_endpoint_cache = & $closest_endpoint_cache_by_version[ $this->api->version ];
300 }
301
302 if ( ! isset( $closest_endpoint_cache[ $template_path ] ) ) {
303 $closest_endpoint_cache[ $template_path ] = array();
304 } elseif ( isset( $closest_endpoint_cache[ $template_path ][ $request_method ] ) ) {
305 return $closest_endpoint_cache[ $template_path ][ $request_method ];
306 }
307
308 $path = untrailingslashit( $path );
309
310 // /help is a special case - always use the current request version
311 if ( wp_endswith( $path, '/help' ) ) {
312 $closest_endpoint_cache[ $template_path ][ $request_method ] = $this->api->version;
313 return $this->api->version;
314 }
315
316 $matches_by_version = & $this->matches_by_version;
317
318 // try to match out of saved matches.
319 if ( ! isset( $matches_by_version[ $this->api->version ] ) ) {
320 $matches_by_version[ $this->api->version ] = array();
321 }
322 foreach ( $matches_by_version[ $this->api->version ] as $match ) {
323 $regex = $match->regex;
324 if ( preg_match( "#^$regex\$#", $path ) ) {
325 $closest_endpoint_cache[ $template_path ][ $request_method ] = $match->version;
326 return $match->version;
327 }
328 }
329
330 $endpoint_path_versions = $this->get_endpoint_path_versions();
331 $last_path_segment = $this->get_last_segment_of_relative_path( $path );
332 $max_version_found = null;
333
334 foreach ( $endpoint_path_versions as $endpoint_last_path_segment => $endpoints ) {
335
336 // Does the last part of the path match the path key? (e.g. 'posts')
337 // If the last part contains a placeholder (e.g. %s), we want to carry on.
338 // phpcs:ignore Universal.Operators.StrictComparisons.LooseNotEqual
339 if ( $last_path_segment != $endpoint_last_path_segment && ! strstr( $endpoint_last_path_segment, '%' ) ) {
340 continue;
341 }
342
343 foreach ( $endpoints as $endpoint ) {
344 // Does the request method match?
345 if ( ! in_array( $request_method, $endpoint['request_methods'], true ) ) {
346 continue;
347 }
348
349 $endpoint_path = untrailingslashit( (string) $endpoint['path'] );
350 $endpoint_path_regex = str_replace( array( '%s', '%d' ), array( '([^/?&]+)', '(\d+)' ), $endpoint_path );
351
352 if ( ! preg_match( "#^$endpoint_path_regex\$#", $path ) ) {
353 continue;
354 }
355
356 // Make sure the endpoint exists at the same version.
357 if ( null !== $this->api->version &&
358 version_compare( $this->api->version, $endpoint['min_version'], '>=' ) &&
359 version_compare( $this->api->version, $endpoint['max_version'], '<=' )
360 ) {
361 array_push(
362 $matches_by_version[ $this->api->version ],
363 (object) array(
364 'version' => $this->api->version,
365 'regex' => $endpoint_path_regex,
366 )
367 );
368 $closest_endpoint_cache[ $template_path ][ $request_method ] = $this->api->version;
369 return $this->api->version;
370 }
371
372 // If the endpoint doesn't exist at the same version, record the max version we found.
373 if ( empty( $max_version_found ) || version_compare( $max_version_found['version'], $endpoint['max_version'], '<' ) ) {
374 $max_version_found = array(
375 'version' => $endpoint['max_version'],
376 'regex' => $endpoint_path_regex,
377 );
378 }
379 }
380 }
381
382 // If the endpoint version is less than the requested endpoint version, return the max version found.
383 if ( ! empty( $max_version_found ) ) {
384 array_push(
385 $matches_by_version[ $this->api->version ],
386 (object) $max_version_found
387 );
388 $closest_endpoint_cache[ $template_path ][ $request_method ] = $max_version_found['version'];
389 return $max_version_found['version'];
390 }
391
392 // Otherwise, use the API version of the current request.
393 return $this->api->version;
394 }
395
396 /**
397 * Get an array of endpoint paths with their associated versions
398 *
399 * @return array Array of endpoint paths, min_versions and max_versions, keyed by last segment of path
400 **/
401 protected function get_endpoint_path_versions() {
402
403 if ( ! empty( $this->cache_result ) ) {
404 return $this->cache_result;
405 }
406
407 /*
408 * Create a map of endpoints and their min/max versions keyed by the last segment of the path (e.g. 'posts')
409 * This reduces the search space when finding endpoint matches in get_closest_version_of_endpoint()
410 */
411 $endpoint_path_versions = array();
412
413 foreach ( $this->api->endpoints as $key => $endpoint_objects ) {
414
415 // @todo As with the todo in class.json-api.php, we need to determine if anything depends on this being serialized and hence unserialized, rather than e.g. JSON.
416 // The key contains a serialized path, min_version and max_version.
417 list( $path, $min_version, $max_version ) = unserialize( $key ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize -- Legacy, see serialization at class.json-api.php.
418
419 // Grab the last component of the relative path to use as the top-level key.
420 $last_path_segment = $this->get_last_segment_of_relative_path( $path );
421
422 $endpoint_path_versions[ $last_path_segment ][] = array(
423 'path' => $path,
424 'min_version' => $min_version,
425 'max_version' => $max_version,
426 'request_methods' => array_keys( $endpoint_objects ),
427 );
428 }
429
430 $this->cache_result = $endpoint_path_versions;
431
432 return $endpoint_path_versions;
433 }
434
435 /**
436 * Grab the last segment of a relative path
437 *
438 * @param string $path Path.
439 * @return string Last path segment
440 */
441 protected function get_last_segment_of_relative_path( $path ) {
442 $path_parts = array_filter( explode( '/', $path ) );
443
444 if ( empty( $path_parts ) ) {
445 return null;
446 }
447
448 return end( $path_parts );
449 }
450 }
451