[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/rest-api/endpoints/ -> class-wp-rest-block-directory-controller.php (source)

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


Generated : Sun Sep 27 08:20:30 2026 Cross-referenced by PHPXref