| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Tue Oct 20 08:20:34 2026 | Cross-referenced by PHPXref |