Completed
Push — master ( 0688b4...aad3f4 )
by Joro
49:06 queued 39:48
created

Router::attachment_data_args_schema()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
namespace Carbon_Fields\REST_API;
4
5
use Carbon_Fields\Helper\Helper;
6
use Carbon_Fields\Container\Repository as ContainerRepository;
7
8
/**
9
* Register custom routes for REST API
10
*/
11
class Router {
12
13
	/**
14
	 * Carbon Fields routes
15
	 *
16
	 * @var array
17
	 */
18
	protected $routes = array(
19
		'post_meta' => array(
20
			'path'                => '/posts/(?P<id>\d+)',
21
			'callback'            => 'get_post_meta',
22
			'permission_callback' => 'allow_access',
23
			'methods'             => 'GET',
24
		),
25
		'term_meta' => array(
26
			'path'                => '/terms/(?P<id>\d+)',
27
			'callback'            => 'get_term_meta',
28
			'permission_callback' => 'allow_access',
29
			'methods'             => 'GET',
30
		),
31
		'user_meta' => array(
32
			'path'                => '/users/(?P<id>\d+)',
33
			'callback'            => 'get_user_meta',
34
			'permission_callback' => 'allow_access',
35
			'methods'             => 'GET',
36
		),
37
		'comment_meta' => array(
38
			'path'                => '/comments/(?P<id>\d+)',
39
			'callback'            => 'get_comment_meta',
40
			'permission_callback' => 'allow_access',
41
			'methods'             => 'GET',
42
		),
43
		'theme_options' => array(
44
			'path'                => '/options/',
45
			'callback'            => 'options_accessor',
46
			'permission_callback' => 'options_permission',
47
			'methods'             => array( 'GET', 'POST' ),
48
		),
49
		'association_data' => array(
50
			'path'                => '/association',
51
			'callback'            => 'get_association_data',
52
			'permission_callback' => 'allow_access',
53
			'methods'             => 'GET',
54
		),
55
		'attachment_data' => array(
56
			'path'                => '/attachment',
57
			'callback'            => 'get_attachment_data',
58
			'permission_callback' => 'allow_access',
59
			'methods'             => 'GET',
60
			'args'                => 'attachment_data_args_schema',
61
		),
62
		'block_renderer' => array(
63
			'path'                => '/block-renderer',
64
			'callback'            => 'block_renderer',
65
			'permission_callback' => 'block_renderer_permission',
66
			'methods'             => 'POST',
67
			'args'                => 'block_renderer_args_schema',
68
		)
69
	);
70
71
	/**
72
	 * Version of the API
73
	 *
74
	 * @see set_version()
75
	 * @see get_version()
76
	 * @var string
77
	 */
78
	protected $version = '1';
79
80
	/**
81
	 * Vendor slug for the API
82
	 *
83
	 * @see set_vendor()
84
	 * @see get_vendor()
85
	 * @var string
86
	 */
87
	protected $vendor = 'carbon-fields';
88
89
	/**
90
	 * ContainerRepository instance
91
	 *
92
	 * @var ContainerRepository
93
	 */
94
	protected $container_repository;
95
96
	/**
97
	 * @param ContainerRepository $container_repository
98
	 */
99
	public function __construct( ContainerRepository $container_repository ) {
100
		$this->container_repository = $container_repository;
101
	}
102
103
	/**
104
	 * Boot up functionality
105
	 */
106
	public function boot() {
107
		add_action( 'rest_api_init', array( $this, 'register_routes' ), 15 );
108
	}
109
110
	/**
111
	 * Set routes
112
	 *
113
	 * @param array $routes
114
	 */
115
	public function set_routes( $routes ) {
116
		$this->routes = $routes;
117
	}
118
119
	/**
120
	 * Return routes
121
	 *
122
	 * @return array
123
	 */
124
	public function get_routes() {
125
		return $this->routes;
126
	}
127
128
	/**
129
	 * Set version
130
	 *
131
	 * @param string $version
132
	 */
133
	public function set_version( $version ) {
134
		$this->version = $version;
135
	}
136
137
	/**
138
	 * Return version
139
	 *
140
	 * @return string
141
	 */
142
	public function get_version() {
143
		return $this->version;
144
	}
145
146
	/**
147
	 * Set vendor
148
	 *
149
	 * @param string $vendor
150
	 */
151
	public function set_vendor( $vendor ) {
152
		$this->vendor = $vendor;
153
	}
154
155
	/**
156
	 * Return vendor
157
	 *
158
	 * @return string
159
	 */
160
	public function get_vendor() {
161
		return $this->vendor;
162
	}
163
164
	/**
165
	 * Allow access to an endpoint
166
	 *
167
	 * @return bool
168
	 */
169
	public function allow_access() {
170
		return true;
171
	}
172
173
	/**
174
	 * Register custom routes
175
	 *
176
	 * @see  register_route()
177
	 */
178
	public function register_routes() {
179
		foreach ( $this->routes as $route ) {
180
			$this->register_route( $route );
181
		}
182
	}
183
184
	/**
185
	 * Register a custom REST route
186
	 *
187
	 * @param  array $route
188
	 */
189
	protected function register_route( $route ) {
190
		register_rest_route( $this->get_vendor() . '/v' . $this->get_version(), $route['path'], array(
191
			'methods'             => $route['methods'],
192
			'permission_callback' => array( $this, $route['permission_callback'] ),
193
			'callback'            => array( $this, $route['callback'] ),
194
			'args'                => isset( $route['args'] ) ? call_user_func( array( $this, $route['args'] ) ) : array(),
195
		) );
196
	}
197
198
	/**
199
	 * Proxy method for handling get/set for theme options
200
	 *
201
	 * @param  \WP_REST_Request $request
202
	 * @return array|\WP_REST_Response
203
	 */
204
	public function options_accessor( $request ) {
205
		$request_type = $request->get_method();
206
207
		if ( $request_type === 'POST' ) {
208
			return $this->set_options( $request );
209
		}
210
211
		return $this->get_options();
212
	}
213
214
	/**
215
	 * Proxy method for handling theme options permissions
216
	 *
217
	 * @param  \WP_REST_Request $request
218
	 * @return bool
219
	 */
220
	public function options_permission( $request ) {
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
221
		return current_user_can( 'manage_options' );
222
	}
223
224
	/**
225
	 * Wrapper method used for retrieving data from Data_Manager
226
	 *
227
	 * @param  string $container_type
228
	 * @param  string $object_id
229
	 * @return array
230
	 */
231
	protected function get_all_field_values( $container_type, $object_id = null ) {
232
		$object_id = ( $object_id !== '' ) ? $object_id : null;
233
234
		$containers = $this->container_repository->get_containers( $container_type );
235
		$fields = array();
236
		foreach ( $containers as $container ) {
237
			$fields = array_merge( $fields, $container->get_fields() );
238
		}
239
240
		$values = array();
241
		foreach ( $fields as $field ) {
242
			if ( ! $field->get_visible_in_rest_api() ) {
243
				continue;
244
			}
245
			$values[ $field->get_base_name() ] = Helper::get_value( $object_id, $container_type, '', $field->get_base_name() );
246
		}
247
		return $values;
248
	}
249
250
	/**
251
	 * Get Carbon Fields post meta values
252
	 *
253
	 * @param  array $data
254
	 * @return array
255
	 */
256
	public function get_post_meta( $data ) {
257
		$carbon_data = $this->get_all_field_values( 'post_meta', $data['id'] );
258
		return array( 'carbon_fields' => $carbon_data );
259
	}
260
261
	/**
262
	 * Get Carbon Fields user meta values
263
	 *
264
	 * @param  array $data
265
	 * @return array
266
	 */
267
	public function get_user_meta( $data ) {
268
		$carbon_data = $this->get_all_field_values( 'user_meta', $data['id'] );
269
		return array( 'carbon_fields' => $carbon_data );
270
	}
271
272
	/**
273
	 * Get Carbon Fields term meta values
274
	 *
275
	 * @param  array $data
276
	 * @return array
277
	 */
278
	public function get_term_meta( $data ) {
279
		$carbon_data = $this->get_all_field_values( 'term_meta', $data['id'] );
280
		return array( 'carbon_fields' => $carbon_data );
281
	}
282
283
	/**
284
	 * Get Carbon Fields comment meta values
285
	 *
286
	 * @param  array $data
287
	 * @return array
288
	 */
289
	public function get_comment_meta( $data ) {
290
		$carbon_data = $this->get_all_field_values( 'comment_meta', $data['id'] );
291
		return array( 'carbon_fields' => $carbon_data );
292
	}
293
294
	/**
295
	 * Get Carbon Fields association options data.
296
	 *
297
	 * @access public
298
	 *
299
	 * @return array
300
	 */
301
	public function get_association_data() {
302
		$container_id = $_GET['container_id'];
303
		$field_id     = $_GET['field_id'];
304
		$options      = isset( $_GET['options'] ) ? explode( ';', $_GET['options'] ) : array();
305
		$return_value = array();
306
307
		/** @var \Carbon_Fields\Field\Association_Field $field */
308
		$field = Helper::get_field( null, $container_id, $field_id );
309
310
		$options = array_map( function ( $option ) {
311
			$option = explode( ':', $option );
312
313
			return [
314
				'id'      => $option[0],
315
				'type'    => $option[1],
316
				'subtype' => $option[2],
317
			];
318
		}, $options );
319
320
		foreach ( $options as $option ) {
321
			$item = array(
322
				'type'       => $option['type'],
323
				'subtype'    => $option['subtype'],
324
				'thumbnail'  => $field->get_thumbnail_by_type( $option['id'], $option['type'], $option['subtype'] ),
325
				'id'         => intval( $option['id'] ),
326
				'title'      => $field->get_title_by_type( $option['id'], $option['type'], $option['subtype'] ),
327
				'label'      => $field->get_item_label( $option['id'], $option['type'], $option['subtype'] ),
328
				'is_trashed' => ( $option['type'] == 'post' && get_post_status( $option['id'] ) === 'trash' ),
329
			);
330
331
			$return_value[] = $item;
332
		}
333
334
		return $return_value;
335
	}
336
337
	/**
338
	 * Get attachment data by given ID or URL.
339
	 *
340
	 * @return array
341
	 */
342
	public function get_attachment_data() {
343
		$type  = sanitize_text_field( $_GET['type'] );
344
		$value = sanitize_text_field( $_GET['value'] );
345
346
		return Helper::get_attachment_metadata( $value, $type );
347
	}
348
349
	/**
350
	 * Retrieve Carbon theme options
351
	 *
352
	 * @return array
353
	 */
354
	protected function get_options() {
355
		$carbon_data = $this->get_all_field_values( 'theme_options' );
356
		return array( 'carbon_fields' => $carbon_data );
357
	}
358
359
	/**
360
	 * Set Carbon theme options
361
	 *
362
	 * @param \WP_REST_Request $request Full data about the request.
363
	 * @return \WP_Error|\WP_REST_Response
364
	 */
365
	protected function set_options( $request ) {
366
		$options = $request->get_params();
367
368
		if ( empty( $options ) ) {
369
			return new \WP_REST_Response( __( 'No option names provided', 'carbon-fields' ) );
370
		}
371
372
		foreach ( $options as $key => $value ) {
373
			try {
374
				Helper::set_value( null, 'Theme_Options', '', $key, $value );
375
			} catch ( \Exception $e ) {
376
				return new \WP_REST_Response( wp_strip_all_tags( $e->getMessage() ) );
377
			}
378
		}
379
380
		return new \WP_REST_Response( __( 'Theme Options updated.', 'carbon-fields' ), 200 );
381
	}
382
383
	/**
384
	 * Checks if a given request has access to read blocks.
385
	 *
386
	 * @see https://github.com/WordPress/WordPress/blob/master/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php#L78-L116
387
	 *
388
	 * @param  \WP_REST_Request
389
	 * @return true|\WP_Error
390
	 */
391
	public function block_renderer_permission( $request ) {
392
		global $post;
393
394
		$post_id = isset( $request['post_id'] ) ? intval( $request['post_id'] ) : 0;
395
396
		if ( 0 < $post_id ) {
397
			$post = get_post( $post_id );
398
399 View Code Duplication
			if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
400
				return new \WP_Error(
401
					'block_cannot_read',
402
					__( 'Sorry, you are not allowed to read blocks of this post.', 'carbon-fields' ),
403
					array(
404
						'status' => rest_authorization_required_code(),
405
					)
406
				);
407
			}
408 View Code Duplication
		} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
409
			if ( ! current_user_can( 'edit_posts' ) ) {
410
				return new \WP_Error(
411
					'block_cannot_read',
412
					__( 'Sorry, you are not allowed to read blocks as this user.', 'carbon-fields' ),
413
					array(
414
						'status' => rest_authorization_required_code(),
415
					)
416
				);
417
			}
418
		}
419
420
		return true;
421
	}
422
423
	/**
424
	 * Returns the schema of the accepted arguments.
425
	 *
426
	 * @return array
427
	 */
428
	public function attachment_data_args_schema() {
429
		return array(
430
			'type'       => array(
431
				'type'        => 'string',
432
				'required'    => true,
433
				'description' => __( 'The requested type: ID or URL.', 'carbon-fields' ),
434
			),
435
			'value'    => array(
436
				'type'        => 'string',
437
				'required'    => true,
438
				'description' => __( 'The ID / URL of the attachment', 'carbon-fields' ),
439
			),
440
		);
441
	}
442
443
	/**
444
	 * Returns the schema of the accepted arguments.
445
	 *
446
	 * @see https://github.com/WordPress/WordPress/blob/master/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php#L56-L71
447
	 *
448
	 * @return array
449
	 */
450
	public function block_renderer_args_schema() {
451
		return array(
452
			'name'       => array(
453
				'type'        => 'string',
454
				'required'    => true,
455
				'description' => __( 'The name of the block.', 'carbon-fields' ),
456
			),
457
			'content'    => array(
458
				'type'        => 'string',
459
				'required'    => true,
460
				'description' => __( 'The content of the block.', 'carbon-fields' ),
461
			),
462
			'post_id'    => array(
463
				'type'        => 'integer',
464
				'description' => __( 'ID of the post context.', 'carbon-fields' ),
465
			),
466
		);
467
	}
468
469
	/**
470
	 * Returns block output from block's registered render_callback.
471
	 *
472
	 * @see https://github.com/WordPress/WordPress/blob/master/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php#L118-L154
473
	 *
474
	 * @param  \WP_REST_Request $request
475
	 * @return \WP_REST_Response|\WP_Error
476
	 */
477
	public function block_renderer( $request ) {
478
		global $post;
479
480
		$post_id = isset( $request['post_id'] ) ? intval( $request['post_id'] ) : 0;
481
482
		if ( 0 < $post_id ) {
483
			$post = get_post( $post_id );
484
485
			// Set up postdata since this will be needed if post_id was set.
486
			setup_postdata( $post );
487
		}
488
489
		$registry = \WP_Block_Type_Registry::get_instance();
490
		$block    = $registry->get_registered( $request['name'] );
491
492
		if ( null === $block ) {
493
			return new \WP_Error(
494
				'block_invalid',
495
				__( 'Invalid block.' ),
496
				array(
497
					'status' => 404,
498
				)
499
			);
500
		}
501
502
		$data = array(
503
			'rendered' => do_blocks( $request['content'] ),
504
		);
505
506
		return rest_ensure_response( $data );
507
	}
508
}
509