balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

class-wp-rest-block-directory-controller.php (9618B)


      1 <?php
      2 /**
      3  * REST API: WP_REST_Block_Directory_Controller class
      4  *
      5  * @package WordPress
      6  * @subpackage REST_API
      7  * @since 5.5.0
      8  */
      9 
     10 /**
     11  * Controller which provides REST endpoint for the blocks.
     12  *
     13  * @since 5.5.0
     14  *
     15  * @see WP_REST_Controller
     16  */
     17 class WP_REST_Block_Directory_Controller extends WP_REST_Controller {
     18 
     19 	/**
     20 	 * Constructs the controller.
     21 	 */
     22 	public function __construct() {
     23 		$this->namespace = 'wp/v2';
     24 		$this->rest_base = 'block-directory';
     25 	}
     26 
     27 	/**
     28 	 * Registers the necessary REST API routes.
     29 	 */
     30 	public function register_routes() {
     31 		register_rest_route(
     32 			$this->namespace,
     33 			'/' . $this->rest_base . '/search',
     34 			array(
     35 				array(
     36 					'methods'             => WP_REST_Server::READABLE,
     37 					'callback'            => array( $this, 'get_items' ),
     38 					'permission_callback' => array( $this, 'get_items_permissions_check' ),
     39 					'args'                => $this->get_collection_params(),
     40 				),
     41 				'schema' => array( $this, 'get_public_item_schema' ),
     42 			)
     43 		);
     44 	}
     45 
     46 	/**
     47 	 * Checks whether a given request has permission to install and activate plugins.
     48 	 *
     49 	 * @since 5.5.0
     50 	 *
     51 	 * @param WP_REST_Request $request Full details about the request.
     52 	 * @return true|WP_Error True if the request has permission, WP_Error object otherwise.
     53 	 */
     54 	public function get_items_permissions_check( $request ) {
     55 		if ( ! current_user_can( 'install_plugins' ) || ! current_user_can( 'activate_plugins' ) ) {
     56 			return new WP_Error(
     57 				'rest_block_directory_cannot_view',
     58 				__( 'Sorry, you are not allowed to browse the block directory.' ),
     59 				array( 'status' => rest_authorization_required_code() )
     60 			);
     61 		}
     62 
     63 		return true;
     64 	}
     65 
     66 	/**
     67 	 * Search and retrieve blocks metadata
     68 	 *
     69 	 * @since 5.5.0
     70 	 *
     71 	 * @param WP_REST_Request $request Full details about the request.
     72 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
     73 	 */
     74 	public function get_items( $request ) {
     75 		require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
     76 		require_once ABSPATH . 'wp-admin/includes/plugin.php';
     77 
     78 		$response = plugins_api(
     79 			'query_plugins',
     80 			array(
     81 				'block'    => $request['term'],
     82 				'per_page' => $request['per_page'],
     83 				'page'     => $request['page'],
     84 			)
     85 		);
     86 
     87 		if ( is_wp_error( $response ) ) {
     88 			$response->add_data( array( 'status' => 500 ) );
     89 
     90 			return $response;
     91 		}
     92 
     93 		$result = array();
     94 
     95 		foreach ( $response->plugins as $plugin ) {
     96 			// If the API returned a plugin with empty data for 'blocks', skip it.
     97 			if ( empty( $plugin['blocks'] ) ) {
     98 				continue;
     99 			}
    100 
    101 			$data     = $this->prepare_item_for_response( $plugin, $request );
    102 			$result[] = $this->prepare_response_for_collection( $data );
    103 		}
    104 
    105 		return rest_ensure_response( $result );
    106 	}
    107 
    108 	/**
    109 	 * Parse block metadata for a block, and prepare it for an API repsonse.
    110 	 *
    111 	 * @since 5.5.0
    112 	 *
    113 	 * @param array           $plugin  The plugin metadata.
    114 	 * @param WP_REST_Request $request Request object.
    115 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
    116 	 */
    117 	public function prepare_item_for_response( $plugin, $request ) {
    118 		// There might be multiple blocks in a plugin. Only the first block is mapped.
    119 		$block_data = reset( $plugin['blocks'] );
    120 
    121 		// A data array containing the properties we'll return.
    122 		$block = array(
    123 			'name'                => $block_data['name'],
    124 			'title'               => ( $block_data['title'] ? $block_data['title'] : $plugin['name'] ),
    125 			'description'         => wp_trim_words( $plugin['short_description'], 30, '...' ),
    126 			'id'                  => $plugin['slug'],
    127 			'rating'              => $plugin['rating'] / 20,
    128 			'rating_count'        => (int) $plugin['num_ratings'],
    129 			'active_installs'     => (int) $plugin['active_installs'],
    130 			'author_block_rating' => $plugin['author_block_rating'] / 20,
    131 			'author_block_count'  => (int) $plugin['author_block_count'],
    132 			'author'              => wp_strip_all_tags( $plugin['author'] ),
    133 			'icon'                => ( isset( $plugin['icons']['1x'] ) ? $plugin['icons']['1x'] : 'block-default' ),
    134 			'last_updated'        => gmdate( 'Y-m-d\TH:i:s', strtotime( $plugin['last_updated'] ) ),
    135 			'humanized_updated'   => sprintf(
    136 				/* translators: %s: Human-readable time difference. */
    137 				__( '%s ago' ),
    138 				human_time_diff( strtotime( $plugin['last_updated'] ) )
    139 			),
    140 		);
    141 
    142 		$this->add_additional_fields_to_object( $block, $request );
    143 
    144 		$response = new WP_REST_Response( $block );
    145 		$response->add_links( $this->prepare_links( $plugin ) );
    146 
    147 		return $response;
    148 	}
    149 
    150 	/**
    151 	 * Generates a list of links to include in the response for the plugin.
    152 	 *
    153 	 * @since 5.5.0
    154 	 *
    155 	 * @param array $plugin The plugin data from WordPress.org.
    156 	 * @return array
    157 	 */
    158 	protected function prepare_links( $plugin ) {
    159 		$links = array(
    160 			'https://api.w.org/install-plugin' => array(
    161 				'href' => add_query_arg( 'slug', urlencode( $plugin['slug'] ), rest_url( 'wp/v2/plugins' ) ),
    162 			),
    163 		);
    164 
    165 		$plugin_file = $this->find_plugin_for_slug( $plugin['slug'] );
    166 
    167 		if ( $plugin_file ) {
    168 			$links['https://api.w.org/plugin'] = array(
    169 				'href'       => rest_url( 'wp/v2/plugins/' . substr( $plugin_file, 0, - 4 ) ),
    170 				'embeddable' => true,
    171 			);
    172 		}
    173 
    174 		return $links;
    175 	}
    176 
    177 	/**
    178 	 * Finds an installed plugin for the given slug.
    179 	 *
    180 	 * @since 5.5.0
    181 	 *
    182 	 * @param string $slug The WordPress.org directory slug for a plugin.
    183 	 * @return string The plugin file found matching it.
    184 	 */
    185 	protected function find_plugin_for_slug( $slug ) {
    186 		require_once ABSPATH . 'wp-admin/includes/plugin.php';
    187 
    188 		$plugin_files = get_plugins( '/' . $slug );
    189 
    190 		if ( ! $plugin_files ) {
    191 			return '';
    192 		}
    193 
    194 		$plugin_files = array_keys( $plugin_files );
    195 
    196 		return $slug . '/' . reset( $plugin_files );
    197 	}
    198 
    199 	/**
    200 	 * Retrieves the theme's schema, conforming to JSON Schema.
    201 	 *
    202 	 * @since 5.5.0
    203 	 *
    204 	 * @return array Item schema data.
    205 	 */
    206 	public function get_item_schema() {
    207 		if ( $this->schema ) {
    208 			return $this->add_additional_fields_schema( $this->schema );
    209 		}
    210 
    211 		$this->schema = array(
    212 			'$schema'    => 'http://json-schema.org/draft-04/schema#',
    213 			'title'      => 'block-directory-item',
    214 			'type'       => 'object',
    215 			'properties' => array(
    216 				'name'                => array(
    217 					'description' => __( 'The block name, in namespace/block-name format.' ),
    218 					'type'        => 'string',
    219 					'context'     => array( 'view' ),
    220 				),
    221 				'title'               => array(
    222 					'description' => __( 'The block title, in human readable format.' ),
    223 					'type'        => 'string',
    224 					'context'     => array( 'view' ),
    225 				),
    226 				'description'         => array(
    227 					'description' => __( 'A short description of the block, in human readable format.' ),
    228 					'type'        => 'string',
    229 					'context'     => array( 'view' ),
    230 				),
    231 				'id'                  => array(
    232 					'description' => __( 'The block slug.' ),
    233 					'type'        => 'string',
    234 					'context'     => array( 'view' ),
    235 				),
    236 				'rating'              => array(
    237 					'description' => __( 'The star rating of the block.' ),
    238 					'type'        => 'integer',
    239 					'context'     => array( 'view' ),
    240 				),
    241 				'rating_count'        => array(
    242 					'description' => __( 'The number of ratings.' ),
    243 					'type'        => 'integer',
    244 					'context'     => array( 'view' ),
    245 				),
    246 				'active_installs'     => array(
    247 					'description' => __( 'The number sites that have activated this block.' ),
    248 					'type'        => 'string',
    249 					'context'     => array( 'view' ),
    250 				),
    251 				'author_block_rating' => array(
    252 					'description' => __( 'The average rating of blocks published by the same author.' ),
    253 					'type'        => 'integer',
    254 					'context'     => array( 'view' ),
    255 				),
    256 				'author_block_count'  => array(
    257 					'description' => __( 'The number of blocks published by the same author.' ),
    258 					'type'        => 'integer',
    259 					'context'     => array( 'view' ),
    260 				),
    261 				'author'              => array(
    262 					'description' => __( 'The WordPress.org username of the block author.' ),
    263 					'type'        => 'string',
    264 					'context'     => array( 'view' ),
    265 				),
    266 				'icon'                => array(
    267 					'description' => __( 'The block icon.' ),
    268 					'type'        => 'string',
    269 					'format'      => 'uri',
    270 					'context'     => array( 'view' ),
    271 				),
    272 				'last_updated'        => array(
    273 					'description' => __( 'The date when the block was last updated, in fuzzy human readable format.' ),
    274 					'type'        => 'string',
    275 					'format'      => 'date-time',
    276 					'context'     => array( 'view' ),
    277 				),
    278 				'humanized_updated'   => array(
    279 					'description' => __( 'The date when the block was last updated, in fuzzy human readable format.' ),
    280 					'type'        => 'string',
    281 					'context'     => array( 'view' ),
    282 				),
    283 			),
    284 		);
    285 
    286 		return $this->add_additional_fields_schema( $this->schema );
    287 	}
    288 
    289 	/**
    290 	 * Retrieves the search params for the blocks collection.
    291 	 *
    292 	 * @since 5.5.0
    293 	 *
    294 	 * @return array Collection parameters.
    295 	 */
    296 	public function get_collection_params() {
    297 		$query_params = parent::get_collection_params();
    298 
    299 		$query_params['context']['default'] = 'view';
    300 
    301 		$query_params['term'] = array(
    302 			'description' => __( 'Limit result set to blocks matching the search term.' ),
    303 			'type'        => 'string',
    304 			'required'    => true,
    305 			'minLength'   => 1,
    306 		);
    307 
    308 		unset( $query_params['search'] );
    309 
    310 		/**
    311 		 * Filters REST API collection parameters for the block directory controller.
    312 		 *
    313 		 * @since 5.5.0
    314 		 *
    315 		 * @param array $query_params JSON Schema-formatted collection parameters.
    316 		 */
    317 		return apply_filters( 'rest_block_directory_collection_params', $query_params );
    318 	}
    319 }