PluginProbe
Gutenberg / 10.7.3
Gutenberg v10.7.3
23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 7.4.0 All 402 releases
gutenberg / lib / class-wp-rest-pattern-directory-controller.php

class-wp-rest-pattern-directory-controller.php in Gutenberg 10.7.3, at lib/class-wp-rest-pattern-directory-controller.php

300 lines 8.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Start: Include for phase 2
4 * Block Pattern Directory REST API: WP_REST_Pattern_Directory_Controller class
5 *
6 * @since 5.8.0
7 * @package gutenberg
8 */
9
10 /**
11 * Controller which provides REST endpoint for block patterns.
12 *
13 * This simply proxies the endpoint at http://api.wordpress.org/patterns/1.0/. That isn't necessary for
14 * functionality, but is desired for privacy. It prevents api.wordpress.org from knowing the user's IP address.
15 *
16 * This class can be removed when plugin support requires WordPress 5.8.0+.
17 *
18 * @since 5.8.0
19 *
20 * @see WP_REST_Controller
21 */
22 class WP_REST_Pattern_Directory_Controller extends WP_REST_Controller {
23
24 /**
25 * Constructs the controller.
26 */
27 public function __construct() {
28 $this->namespace = 'wp/v2';
29 $this->rest_base = 'pattern-directory';
30 }
31
32 /**
33 * Registers the necessary REST API routes.
34 */
35 public function register_routes() {
36 register_rest_route(
37 $this->namespace,
38 '/' . $this->rest_base . '/patterns',
39 array(
40 array(
41 'methods' => WP_REST_Server::READABLE,
42 'callback' => array( $this, 'get_items' ),
43 'permission_callback' => array( $this, 'get_items_permissions_check' ),
44 'args' => $this->get_collection_params(),
45 ),
46 'schema' => array( $this, 'get_public_item_schema' ),
47 )
48 );
49 }
50
51 /**
52 * Checks whether a given request has permission to view the local pattern directory.
53 *
54 * @since 5.8.0
55 *
56 * @param WP_REST_Request $request Full details about the request.
57 *
58 * @return WP_Error|bool True if the request has permission, WP_Error object otherwise.
59 */
60 public function get_items_permissions_check( $request ) {
61 if ( current_user_can( 'edit_posts' ) ) {
62 return true;
63 }
64
65 foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) {
66 if ( current_user_can( $post_type->cap->edit_posts ) ) {
67 return true;
68 }
69 }
70
71 return new WP_Error(
72 'rest_pattern_directory_cannot_view',
73 __( 'Sorry, you are not allowed to browse the local block pattern directory.', 'gutenberg' ),
74 array( 'status' => rest_authorization_required_code() )
75 );
76 }
77
78 /**
79 * Search and retrieve block patterns metadata
80 *
81 * @since 5.8.0
82 *
83 * @param WP_REST_Request $request Full details about the request.
84 *
85 * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
86 */
87 public function get_items( $request ) {
88 $query_args = array();
89 $category_id = $request['category'];
90 $keyword_id = $request['keyword'];
91 $search_term = $request['search'];
92
93 if ( $category_id ) {
94 $query_args['pattern-categories'] = $category_id;
95 }
96
97 if ( $keyword_id ) {
98 $query_args['pattern-keywords'] = $keyword_id;
99 }
100
101 if ( $search_term ) {
102 $query_args['search'] = $search_term;
103 }
104
105 $api_url = add_query_arg(
106 array_map( 'rawurlencode', $query_args ),
107 'http://api.wordpress.org/patterns/1.0/'
108 );
109
110 if ( wp_http_supports( array( 'ssl' ) ) ) {
111 $api_url = set_url_scheme( $api_url, 'https' );
112 }
113
114 $wporg_response = wp_remote_get( $api_url );
115 $raw_patterns = json_decode( wp_remote_retrieve_body( $wporg_response ) );
116
117 if ( is_wp_error( $wporg_response ) ) {
118 $wporg_response->add_data( array( 'status' => 500 ) );
119
120 return $wporg_response;
121 }
122
123 // Make sure w.org returned valid data.
124 if ( ! is_array( $raw_patterns ) ) {
125 return new WP_Error(
126 'pattern_api_failed',
127 sprintf(
128 /* translators: %s: Support forums URL. */
129 __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.', 'gutenberg' ),
130 __( 'https://wordpress.org/support/forums/', 'gutenberg' )
131 ),
132 array(
133 'status' => 500,
134 'response' => wp_remote_retrieve_body( $wporg_response ),
135 )
136 );
137 }
138
139 $response = array();
140
141 if ( $raw_patterns ) {
142 foreach ( $raw_patterns as $pattern ) {
143 $response[] = $this->prepare_response_for_collection(
144 $this->prepare_item_for_response( $pattern, $request )
145 );
146 }
147 }
148
149 return new WP_REST_Response( $response );
150 }
151
152 /**
153 * Prepare a raw pattern before it's output in an API response.
154 *
155 * @since 5.8.0
156 *
157 * @param object $raw_pattern A pattern from api.wordpress.org, before any changes.
158 * @param WP_REST_Request $request Request object.
159 *
160 * @return WP_REST_Response
161 */
162 public function prepare_item_for_response( $raw_pattern, $request ) {
163 $prepared_pattern = array(
164 'id' => absint( $raw_pattern->id ),
165 'title' => sanitize_text_field( $raw_pattern->title->rendered ),
166 'content' => wp_kses_post( $raw_pattern->pattern_content ),
167 'categories' => array_map( 'sanitize_title', $raw_pattern->category_slugs ),
168 'keywords' => array_map( 'sanitize_title', $raw_pattern->keyword_slugs ),
169 'description' => sanitize_text_field( $raw_pattern->meta->wpop_description ),
170 'viewport_width' => absint( $raw_pattern->meta->wpop_viewport_width ),
171 );
172
173 $prepared_pattern = $this->add_additional_fields_to_object( $prepared_pattern, $request );
174
175 $response = new WP_REST_Response( $prepared_pattern );
176
177 /**
178 * Filters the REST API response for a pattern.
179 *
180 * @since 5.8.0
181 *
182 * @param WP_REST_Response $response The response object.
183 * @param object $raw_pattern The unprepared pattern.
184 * @param WP_REST_Request $request The request object.
185 */
186 return apply_filters( 'rest_prepare_block_pattern', $response, $raw_pattern, $request );
187 }
188
189 /**
190 * Retrieves the pattern's schema, conforming to JSON Schema.
191 *
192 * @since 5.8.0
193 *
194 * @return array Item schema data.
195 */
196 public function get_item_schema() {
197 if ( $this->schema ) {
198 return $this->add_additional_fields_schema( $this->schema );
199 }
200
201 $this->schema = array(
202 '$schema' => 'http://json-schema.org/draft-04/schema#',
203 'title' => 'pattern-directory-item',
204 'type' => 'object',
205 'properties' => array(
206 'id' => array(
207 'description' => __( 'The pattern ID.', 'gutenberg' ),
208 'type' => 'integer',
209 'minimum' => 1,
210 'context' => array( 'view', 'embed' ),
211 ),
212
213 'title' => array(
214 'description' => __( 'The pattern title, in human readable format.', 'gutenberg' ),
215 'type' => 'string',
216 'minLength' => 1,
217 'context' => array( 'view', 'embed' ),
218 ),
219
220 'content' => array(
221 'description' => __( 'The pattern content.', 'gutenberg' ),
222 'type' => 'string',
223 'minLength' => 1,
224 'context' => array( 'view', 'embed' ),
225 ),
226
227 'categories' => array(
228 'description' => __( "The pattern's category slugs.", 'gutenberg' ),
229 'type' => 'array',
230 'uniqueItems' => true,
231 'items' => array( 'type' => 'string' ),
232 'context' => array( 'view', 'embed' ),
233 ),
234
235 'keywords' => array(
236 'description' => __( "The pattern's keyword slugs.", 'gutenberg' ),
237 'type' => 'array',
238 'uniqueItems' => true,
239 'items' => array( 'type' => 'string' ),
240 'context' => array( 'view', 'embed' ),
241 ),
242
243 'description' => array(
244 'description' => __( 'A description of the pattern.', 'gutenberg' ),
245 'type' => 'string',
246 'minLength' => 1,
247 'context' => array( 'view', 'embed' ),
248 ),
249
250 'viewport_width' => array(
251 'description' => __( 'The preferred width of the viewport when previewing a pattern, in pixels.', 'gutenberg' ),
252 'type' => 'integer',
253 'context' => array( 'view', 'embed' ),
254 ),
255 ),
256 );
257
258 return $this->add_additional_fields_schema( $this->schema );
259 }
260
261 /**
262 * Retrieves the search params for the patterns collection.
263 *
264 * @since 5.8.0
265 *
266 * @return array Collection parameters.
267 */
268 public function get_collection_params() {
269 $query_params = parent::get_collection_params();
270
271 // Pagination is not supported.
272 unset( $query_params['page'] );
273 unset( $query_params['per_page'] );
274
275 $query_params['search']['minLength'] = 1;
276 $query_params['context']['default'] = 'view';
277
278 $query_params['category'] = array(
279 'description' => __( 'Limit results to those matching a category ID.', 'gutenberg' ),
280 'type' => 'integer',
281 'minimum' => 1,
282 );
283
284 $query_params['keyword'] = array(
285 'description' => __( 'Limit results to those matching a keyword ID.', 'gutenberg' ),
286 'type' => 'integer',
287 'minimum' => 1,
288 );
289
290 /**
291 * Filter collection parameters for the pattern directory controller.
292 *
293 * @since 5.8.0
294 *
295 * @param array $query_params JSON Schema-formatted collection parameters.
296 */
297 return apply_filters( 'rest_pattern_directory_collection_params', $query_params );
298 }
299 }
300