PluginProbe
Parse.ly / 3.12.0
Parse.ly v3.12.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 / Endpoints / class-base-endpoint.php

class-base-endpoint.php in Parse.ly 3.12.0, at src/Endpoints/class-base-endpoint.php

182 lines 4.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Endpoints: Base endpoint class
4 *
5 * @package Parsely
6 * @since 3.11.0
7 */
8
9 declare(strict_types=1);
10
11 namespace Parsely\Endpoints;
12
13 use Parsely\Parsely;
14 use WP_REST_Server;
15
16 use function Parsely\Utils\convert_endpoint_to_filter_key;
17
18 /**
19 * Base class for API endpoints.
20 *
21 * Most endpoint classes should derive from this class. Child classes must add a
22 * protected `ENDPOINT` constant.
23 *
24 * @since 3.2.0
25 * @since 3.11.0 Moved from Base_Endpoint_Remote into Base_Endpoint.
26 *
27 * @phpstan-import-type WP_HTTP_Request_Args from Parsely
28 *
29 * @phpstan-type API_Error array{
30 * code: int,
31 * message: string,
32 * htmlMessage: string,
33 * }
34 */
35 abstract class Base_Endpoint {
36 protected const ENDPOINT = '';
37
38 /**
39 * Indicates whether the endpoint is public or protected behind permissions.
40 *
41 * @since 3.7.0
42 * @since 3.11.0 Moved from Base_Endpoint_Remote into Base_Endpoint.
43 *
44 * @var bool
45 */
46 protected $is_public_endpoint = false;
47
48 /**
49 * Parsely Instance.
50 *
51 * @since 3.11.0 Moved from Base_Endpoint_Remote into Base_Endpoint.
52 *
53 * @var Parsely
54 */
55 protected $parsely;
56
57 /**
58 * User capability based on which we should allow access to the endpoint.
59 *
60 * `null` should be used for all public endpoints.
61 *
62 * @since 3.7.0
63 * @since 3.11.0 Moved from Base_Endpoint_Remote into Base_Endpoint.
64 *
65 * @var string|null
66 */
67 protected $user_capability;
68
69 /**
70 * Constructor.
71 *
72 * @param Parsely $parsely Parsely instance.
73 *
74 * @since 3.2.0
75 * @since 3.7.0 Added user capability checks based on `is_public_endpoint` attribute.
76 * @since 3.11.0 Moved from Base_Endpoint_Remote into Base_Endpoint.
77 */
78 public function __construct( Parsely $parsely ) {
79 $this->parsely = $parsely;
80
81 if ( $this->is_public_endpoint ) {
82 $this->user_capability = null;
83 } else {
84 /**
85 * Filter to change the default user capability for all private endpoints.
86 *
87 * @var string
88 */
89 $default_user_capability = apply_filters(
90 'wp_parsely_user_capability_for_all_private_apis',
91 'publish_posts'
92 );
93
94 /**
95 * Filter to change the user capability for the specific API endpoint.
96 *
97 * @var string
98 */
99 $endpoint_specific_user_capability = apply_filters(
100 'wp_parsely_user_capability_for_' . convert_endpoint_to_filter_key( static::ENDPOINT ) . '_api',
101 $default_user_capability
102 );
103
104 $this->user_capability = $endpoint_specific_user_capability;
105 }
106 }
107
108 /**
109 * Checks if the current user is allowed to make the API call.
110 *
111 * @since 3.7.0
112 * @since 3.11.0 Moved from Base_Endpoint_Remote into Base_Endpoint.
113 *
114 * @return bool
115 */
116 public function is_user_allowed_to_make_api_call(): bool {
117 // This endpoint does not require any capability checks.
118 if ( is_null( $this->user_capability ) ) {
119 return true;
120 }
121
122 // The user has the required capability to access this endpoint.
123 // phpcs:ignore WordPress.WP.Capabilities.Undetermined
124 if ( current_user_can( $this->user_capability ) ) {
125 return true;
126 }
127
128 return false;
129 }
130
131 /**
132 * Registers the endpoint's WP REST route.
133 *
134 * @since 3.11.0 Moved from Base_Endpoint_Remote into Base_Endpoint.
135 *
136 * @param string $endpoint The endpoint's route (e.g. /stats/posts).
137 * @param string $callback The callback function to call when the endpoint is hit.
138 */
139 public function register_endpoint( string $endpoint, string $callback ): void {
140 if ( ! apply_filters( 'wp_parsely_enable_' . convert_endpoint_to_filter_key( $endpoint ) . '_api_proxy', true ) ) {
141 return;
142 }
143
144 $get_items_args = array(
145 'query' => array(
146 'default' => array(),
147 'sanitize_callback' => function ( array $query ) {
148 $sanitized_query = array();
149 foreach ( $query as $key => $value ) {
150 $sanitized_query[ sanitize_key( $key ) ] = sanitize_text_field( $value );
151 }
152
153 return $sanitized_query;
154 },
155 ),
156 );
157
158 $rest_route_args = array(
159 array(
160 'methods' => WP_REST_Server::READABLE,
161 'callback' => array( $this, $callback ),
162 'permission_callback' => array( $this, 'permission_callback' ),
163 'args' => $get_items_args,
164 'show_in_index' => static::permission_callback(),
165 ),
166 );
167
168 register_rest_route( 'wp-parsely/v1', $endpoint, $rest_route_args );
169 }
170
171 /**
172 * Determines if there are enough permissions to call the endpoint.
173 *
174 * @since 3.11.0 Moved from Base_Endpoint_Remote into Base_Endpoint.
175 *
176 * @return bool
177 */
178 public function permission_callback(): bool {
179 return $this->is_user_allowed_to_make_api_call();
180 }
181 }
182