[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> entity-fields.php (source)

   1  <?php
   2  /**
   3   * Entity Fields API.
   4   *
   5   * A field definition is the serializable subset of the DataViews Field API:
   6   * every property that is plain data (`id`, `type`, `label`, `elements`,
   7   * `filterBy`, `isValid`, …). Properties that are JavaScript callbacks or
   8   * components (`render`, `Edit` as a component, `getValue`, `setValue`, `sort`,
   9   * `isVisible`, `getElements`, …) cannot be declared here. They are provided by
  10   * a script module registered for the entity along with its fields: its default
  11   * export maps field ids to the properties of each field that are JavaScript. An
  12   * entity can have several modules. Each module applies to the fields it was
  13   * registered with, see {@see wp_get_registered_entity_field_modules()}.
  14   *
  15   * Fields are registered on the `wp_entity_fields_api_init` action, and only there,
  16   * with {@see wp_register_entity_fields()}, {@see wp_update_entity_fields()}, and
  17   * {@see wp_unregister_entity_fields()}. The other functions read the registry.
  18   *
  19   * Fields can also be declared as files, grouped in a field collection, which
  20   * a `wp_entity_fields_api_init` callback registers with
  21   * {@see wp_register_entity_field_collection()}. A collection is for a single
  22   * entity. WordPress core registers its own fields this way, from
  23   * packages/core-fields: the defaults every post type derives from its
  24   * supports in code, the fields of single post types as collections.
  25   *
  26   * The registered fields are exposed by the `/wp/v2/entity-fields` REST API
  27   * route, see {@see WP_REST_Entity_Fields_Controller}.
  28   *
  29   * @package WordPress
  30   * @subpackage Entity Fields API
  31   * @since 7.2.0
  32   */
  33  
  34  /**
  35   * Registers fields for an entity, see
  36   * {@see WP_Entity_Fields_Registry::register()}.
  37   *
  38   * It only runs on the `wp_entity_fields_api_init` action.
  39   *
  40   * @since 7.2.0
  41   *
  42   * @param string      $origin        Who registers the fields: `core`, or
  43   *                                   the slug of the plugin or theme.
  44   * @param string      $kind          The entity kind (e.g. `postType`).
  45   * @param string      $name          The entity name (e.g. `page`).
  46   * @param array[]     $fields        The list of field definitions, each with an `id`.
  47   * @param string|null $script_module The id of the script module providing
  48   *                                   the JavaScript parts of the fields, if any.
  49   * @return string[] The ids of the fields registered, in the order of the
  50   *                  call. Empty when none is.
  51   */
  52  function wp_register_entity_fields( $origin, $kind, $name, $fields, $script_module = null ) {
  53      return WP_Entity_Fields_Registry::get_instance()->register( $origin, $kind, $name, $fields, $script_module );
  54  }
  55  
  56  /**
  57   * Updates registered fields of an entity, see
  58   * {@see WP_Entity_Fields_Registry::update()}.
  59   *
  60   * It only runs on the `wp_entity_fields_api_init` action.
  61   *
  62   * @since 7.2.0
  63   *
  64   * @param string      $origin        Who updates the fields: `core`, or
  65   *                                   the slug of the plugin or theme.
  66   * @param string      $kind          The entity kind (e.g. `postType`).
  67   * @param string      $name          The entity name (e.g. `page`).
  68   * @param array[]     $fields        The list of partial field definitions,
  69   *                                   each with the `id` of a registered field.
  70   * @param string|null $script_module The id of the script module providing
  71   *                                   the JavaScript parts of the fields, if any.
  72   * @return string[] The ids of the fields updated, in the order of the
  73   *                  call. Empty when none is.
  74   */
  75  function wp_update_entity_fields( $origin, $kind, $name, $fields, $script_module = null ) {
  76      return WP_Entity_Fields_Registry::get_instance()->update( $origin, $kind, $name, $fields, $script_module );
  77  }
  78  
  79  /**
  80   * Unregisters fields of an entity, see
  81   * {@see WP_Entity_Fields_Registry::unregister()}.
  82   *
  83   * It only runs on the `wp_entity_fields_api_init` action.
  84   *
  85   * @since 7.2.0
  86   *
  87   * @param string        $kind The entity kind (e.g. `postType`).
  88   * @param string        $name The entity name (e.g. `page`).
  89   * @param string[]|null $ids  The ids of the fields to unregister. Default
  90   *                            null, every field of the entity.
  91   * @return array[] The list of the definitions unregistered, in
  92   *                 registration order. Empty when none is.
  93   */
  94  function wp_unregister_entity_fields( $kind, $name, $ids = null ) {
  95      return WP_Entity_Fields_Registry::get_instance()->unregister( $kind, $name, $ids );
  96  }
  97  
  98  /**
  99   * Returns the fields registered for the given entity.
 100   *
 101   * @since 7.2.0
 102   *
 103   * @param string $kind The entity kind (e.g. `postType`).
 104   * @param string $name The entity name (e.g. `page`).
 105   * @return array[] The list of registered field definitions, in registration
 106   *                 order. Empty until the `init` action has completed: a
 107   *                 read before then is refused.
 108   */
 109  function wp_get_registered_entity_fields( $kind, $name ) {
 110      return WP_Entity_Fields_Registry::get_instance()->get_registered( $kind, $name );
 111  }
 112  
 113  /**
 114   * Returns the ids of the script modules registered for the given entity.
 115   *
 116   * @since 7.2.0
 117   *
 118   * @param string $kind The entity kind (e.g. `postType`).
 119   * @param string $name The entity name (e.g. `page`).
 120   * @return array<string, string[]> The ids of the fields each module applies
 121   *                                 to, keyed by module id, in registration
 122   *                                 order. Empty until the `init` action has
 123   *                                 completed: a read before then is refused.
 124   */
 125  function wp_get_registered_entity_field_modules( $kind, $name ) {
 126      return WP_Entity_Fields_Registry::get_instance()->get_registered_field_modules( $kind, $name );
 127  }
 128  
 129  /**
 130   * Returns the ids of all script modules registered for any entity.
 131   *
 132   * @since 7.2.0
 133   *
 134   * @return array<string, array<string, string[]>> The lists of module ids,
 135   *                                                keyed by kind, then by
 136   *                                                name. Empty until the
 137   *                                                `init` action has
 138   *                                                completed: a read before
 139   *                                                then is refused.
 140   */
 141  function wp_get_all_registered_entity_field_modules() {
 142      return WP_Entity_Fields_Registry::get_instance()->get_all_registered_field_modules();
 143  }
 144  
 145  /**
 146   * Declares the script modules of the entity fields as dependencies of the
 147   * editor script.
 148   *
 149   * The editor imports the script modules of an entity on demand, with a dynamic
 150   * `import()` the browser resolves through the import map of the page. Listing
 151   * the modules as dynamic `module_dependencies` of the `wp-editor` script adds
 152   * them to the import map of every page that loads the editor script: the post
 153   * editor, the site editor, and the pages booted by `@wordpress/boot`, whose
 154   * prerequisites depend on it. A dynamic dependency is only listed in the
 155   * import map; the module is fetched when it is imported.
 156   *
 157   * Reading the registry fires `wp_entity_fields_api_init`, so the fields and their
 158   * script modules are registered on demand. It only reads the registry on the
 159   * pages that load the editor script, not on every admin request (heartbeat,
 160   * Ajax, other screens). It runs on `admin_footer`, the last action before the
 161   * import map is printed that fires both in the admin template and in the pages
 162   * rendered outside it, which print the import map themselves. By then `init`
 163   * has completed, so the supports the default fields derive from are final.
 164   * The registry only accepts registrations while the action fires, so the
 165   * modules declared here are the modules of every field the page can show.
 166   *
 167   * It is hooked to `admin_footer` without arguments, so the global scripts
 168   * registry is used. In other scenarios (tests), the scripts are given directly.
 169   *
 170   * @since 7.2.0
 171   * @access private
 172   *
 173   * @param WP_Scripts|null $scripts Optional. The scripts registry. Default null,
 174   *                                 the global one.
 175   */
 176  function _wp_add_entity_field_modules_to_editor_script( $scripts = null ) {
 177      if ( ! $scripts instanceof WP_Scripts ) {
 178          $scripts = wp_scripts();
 179      }
 180  
 181      /*
 182       * The fields are loaded by the editor package, see
 183       * packages/editor/src/dataviews/store/private-resolvers.ts in Gutenberg,
 184       * which means any screen that wants to use this mechanism needs to load
 185       * the editor script.
 186       */
 187      if ( ! $scripts->query( 'wp-editor', 'enqueued' ) && ! $scripts->query( 'wp-editor', 'done' ) ) {
 188          return;
 189      }
 190  
 191      $kinds = wp_get_all_registered_entity_field_modules();
 192      if ( empty( $kinds ) ) {
 193          return;
 194      }
 195  
 196      $dependencies = $scripts->get_data( 'wp-editor', 'module_dependencies' );
 197      $dependencies = is_array( $dependencies ) ? $dependencies : array();
 198  
 199      $declared = array();
 200      foreach ( $dependencies as $dependency ) {
 201          $declared[] = is_array( $dependency ) ? $dependency['id'] : $dependency;
 202      }
 203  
 204      $added = false;
 205      foreach ( $kinds as $entities ) {
 206          foreach ( $entities as $modules ) {
 207              foreach ( $modules as $module ) {
 208                  if ( ! in_array( $module, $declared, true ) ) {
 209                      $dependencies[] = array(
 210                          'id'     => $module,
 211                          'import' => 'dynamic',
 212                      );
 213                      $declared[]     = $module;
 214                      $added          = true;
 215                  }
 216              }
 217          }
 218      }
 219  
 220      if ( $added ) {
 221          // `add_data()` replaces the value, hence the merge above.
 222          $scripts->add_data( 'wp-editor', 'module_dependencies', $dependencies );
 223      }
 224  }
 225  
 226  /**
 227   * Returns the fields of a field collection, see
 228   * {@see WP_Entity_Fields_Registry::get_collection_fields()}.
 229   *
 230   * @since 7.2.0
 231   *
 232   * @param string $directory The directory of the collection.
 233   * @return array<string, array> The fields of the collection, keyed by id, in
 234   *                              the alphabetical order of their folders.
 235   */
 236  function wp_get_entity_field_collection_fields( $directory ) {
 237      return WP_Entity_Fields_Registry::get_instance()->get_collection_fields( $directory );
 238  }
 239  
 240  /**
 241   * Registers the fields of a field collection, see
 242   * {@see WP_Entity_Fields_Registry::register_collection()} for the format of a
 243   * collection.
 244   *
 245   * Like wp_register_entity_fields(), it only runs on the `wp_entity_fields_api_init`
 246   * action.
 247   *
 248   * @since 7.2.0
 249   *
 250   * @param string $directory The directory of the collection.
 251   * @return bool Whether the collection is valid and all of its fields are
 252   *              registered. True as well when it has no fields.
 253   */
 254  function wp_register_entity_field_collection( $directory ) {
 255      return WP_Entity_Fields_Registry::get_instance()->register_collection( $directory );
 256  }
 257  
 258  /**
 259   * Returns the paths that serve the fields of the given post types, skipping
 260   * the post types that are not registered.
 261   *
 262   * A path must match the request of the `getFieldsConfig` core data resolver,
 263   * see packages/core-data/src/resolvers.js in Gutenberg.
 264   *
 265   * @since 7.2.0
 266   * @access private
 267   *
 268   * @param string[] $post_types The post types.
 269   * @return string[] One path of the `/wp/v2/entity-fields` route per post type,
 270   *                  in the order the post types are given, without duplicates.
 271   */
 272  function _wp_get_post_type_fields_preload_paths( $post_types ) {
 273      $paths = array();
 274      foreach ( array_unique( $post_types ) as $post_type ) {
 275          if ( ! post_type_exists( $post_type ) ) {
 276              continue;
 277          }
 278          $paths[] = add_query_arg(
 279              array(
 280                  'kind' => 'postType',
 281                  'name' => $post_type,
 282              ),
 283              '/wp/v2/entity-fields'
 284          );
 285      }
 286  
 287      return $paths;
 288  }
 289  
 290  /**
 291   * Returns the post types whose fields the screen of the site editor being
 292   * loaded lists, from its `p` query arg.
 293   *
 294   * The screens are the routes in
 295   * packages/edit-site/src/components/site-editor-routes in Gutenberg: the
 296   * lists and the editors of pages, templates, patterns, and template parts.
 297   * The patterns screen lists both patterns and template parts.
 298   *
 299   * @since 7.2.0
 300   * @access private
 301   *
 302   * @return string[] The post types, empty for any other screen.
 303   */
 304  function _wp_get_site_editor_screen_post_types() {
 305      // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Only picks what to preload.
 306      $path     = isset( $_GET['p'] ) && is_string( $_GET['p'] ) ? sanitize_text_field( wp_unslash( $_GET['p'] ) ) : '';
 307      $segments = explode( '/', trim( $path, '/' ) );
 308  
 309      switch ( $segments[0] ) {
 310          case 'page':
 311              return array( 'page' );
 312          case 'template':
 313          case 'wp_template':
 314              return array( 'wp_template' );
 315          case 'pattern':
 316              return array( 'wp_block', 'wp_template_part' );
 317          case 'wp_block':
 318              return array( 'wp_block' );
 319          case 'wp_template_part':
 320              return array( 'wp_template_part' );
 321      }
 322      return array();
 323  }
 324  
 325  /**
 326   * Preloads the fields of the post types the site editor lists.
 327   *
 328   * The site editor reads them from the `/wp/v2/entity-fields` route before it
 329   * can list the post fields, see `useFields` in
 330   * packages/editor/src/dataviews/fields-loader/index.ts in Gutenberg: those of
 331   * the edited post, if any, and of the post types of the screen it opens on.
 332   *
 333   * The post editor is left untouched: it only reads the fields in the
 334   * DataForm-based inspector, an experiment of the Gutenberg plugin which
 335   * preloads them on its own.
 336   *
 337   * @since 7.2.0
 338   * @access private
 339   *
 340   * @param array                   $paths   REST API paths to preload.
 341   * @param WP_Block_Editor_Context $context Block editor context.
 342   * @return array Filtered preload paths.
 343   */
 344  function _wp_preload_entity_fields( $paths, $context ) {
 345      if ( 'core/edit-site' !== $context->name ) {
 346          return $paths;
 347      }
 348  
 349      $post_types = array();
 350      if ( isset( $context->post ) ) {
 351          $post_types[] = $context->post->post_type;
 352      }
 353      $post_types = array_merge( $post_types, _wp_get_site_editor_screen_post_types() );
 354  
 355      return array_merge(
 356          $paths,
 357          _wp_get_post_type_fields_preload_paths( $post_types )
 358      );
 359  }


Generated : Tue Oct 20 08:20:34 2026 Cross-referenced by PHPXref