| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Entity view configuration API. 4 * 5 * Builds the default view configuration for an entity and exposes it through 6 * the dynamic `get_entity_view_config_{$kind}_{$name}` filter so core and third 7 * parties can provide the configuration for a specific entity. The dynamic 8 * portions of the hook name are lowercased, e.g. 9 * `get_entity_view_config_posttype_page` for the `page` post type. 10 * 11 * @package WordPress 12 * @since 7.1.0 13 */ 14 15 /** 16 * Builds the name of the dynamic filter that provides the view configuration 17 * for an entity. 18 * 19 * The entity kind and name are embedded in the hook name lowercased, so the 20 * hook follows the WordPress convention of lowercase hook names regardless of 21 * how the entity identifiers are spelled: the `postType`/`page` entity maps to 22 * the `get_entity_view_config_posttype_page` hook. 23 * 24 * @since 7.1.0 25 * 26 * @param string $kind The entity kind (e.g. `postType`). 27 * @param string $name The entity name (e.g. `page`). 28 * @return string The filter name. 29 */ 30 function wp_get_entity_view_config_hook_name( $kind, $name ) { 31 return strtolower( "get_entity_view_config_{$kind}_{$name}" ); 32 } 33 34 /** 35 * Builds the default `form` configuration for post types that don't provide their own. 36 * 37 * It is a sensible default for `post`, `page`, and custom post types alike rather 38 * than being tailored per type. Post types that need a different shape can replace 39 * it entirely with a dedicated `form` through their own filter callback. 40 * 41 * It is intentionally NOT gated by `supports`. The registered fields are the 42 * single source of truth for what applies: each field is registered for a post 43 * type based on its `supports` (and related flags such as `theme_supports`), and 44 * the editor drops any form field whose definition is absent or whose `isVisible` 45 * returns `false`. 46 * 47 * @since 7.1.0 48 * 49 * @return array The default form configuration. 50 */ 51 function _wp_get_default_posttype_form() { 52 return array( 53 'layout' => array( 'type' => 'panel' ), 54 'fields' => array( 55 array( 56 'id' => 'featured_media', 57 'layout' => array( 58 'type' => 'regular', 59 'labelPosition' => 'none', 60 ), 61 ), 62 array( 63 'id' => 'post-content-info', 64 'layout' => array( 65 'type' => 'regular', 66 'labelPosition' => 'none', 67 ), 68 ), 69 array( 70 'id' => 'excerpt', 71 'layout' => array( 72 'type' => 'panel', 73 'labelPosition' => 'top', 74 ), 75 ), 76 array( 77 'id' => 'status', 78 'label' => __( 'Status' ), 79 'children' => array( 80 array( 81 'id' => 'status', 82 'layout' => array( 83 'type' => 'regular', 84 'labelPosition' => 'none', 85 ), 86 ), 87 'scheduled_date', 88 'password', 89 'sticky', 90 ), 91 ), 92 'date', 93 'slug', 94 'author', 95 'template', 96 array( 97 'id' => 'discussion', 98 'label' => __( 'Discussion' ), 99 'children' => array( 100 array( 101 'id' => 'comment_status', 102 'layout' => array( 103 'type' => 'regular', 104 'labelPosition' => 'none', 105 ), 106 ), 107 'ping_status', 108 ), 109 ), 110 'parent', 111 'format', 112 'revisions', 113 ), 114 ); 115 } 116 117 /** 118 * Returns the view configuration for the given entity. 119 * 120 * Builds the default configuration shared by all entities and then exposes it 121 * through the dynamic `get_entity_view_config_{$kind}_{$name}` filter — with the 122 * dynamic portions lowercased, see wp_get_entity_view_config_hook_name() 123 * — so that core and third parties can provide the configuration for a 124 * specific entity. 125 * 126 * @since 7.1.0 127 * 128 * @param string $kind The entity kind (e.g. `postType`). 129 * @param string $name The entity name (e.g. `page`). 130 * @return array { 131 * The view configuration for the entity. 132 * 133 * @type array $default_view Default view configuration. 134 * @type array $default_layouts Default layouts configuration. 135 * @type array $view_list List of available views. 136 * @type array $form Form configuration. 137 * } 138 */ 139 function wp_get_entity_view_config( $kind, $name ) { 140 $default_view = array( 141 'type' => 'table', 142 'filters' => array(), 143 'sort' => array( 144 'field' => 'title', 145 'direction' => 'asc', 146 ), 147 'perPage' => 20, 148 'fields' => array( 'author', 'status' ), 149 'titleField' => 'title', 150 ); 151 $default_layouts = array( 152 'table' => array(), 153 'grid' => array(), 154 'list' => array(), 155 ); 156 $all_items_title = __( 'All items' ); 157 if ( 'postType' === $kind ) { 158 $post_type_object = get_post_type_object( $name ); 159 if ( $post_type_object && ! empty( $post_type_object->labels->all_items ) ) { 160 $all_items_title = $post_type_object->labels->all_items; 161 } 162 } 163 $view_list = array( 164 array( 165 'title' => $all_items_title, 166 'slug' => 'all', 167 ), 168 ); 169 170 $config = array( 171 'default_view' => $default_view, 172 'default_layouts' => $default_layouts, 173 'view_list' => $view_list, 174 'form' => 'postType' === $kind ? _wp_get_default_posttype_form() : array(), 175 ); 176 177 $data = new WP_View_Config_Data( $config ); 178 179 return $data->apply_filters( $kind, $name ); 180 } 181 182 /** 183 * Provides the view configuration for the `page` post type. 184 * 185 * @since 7.1.0 186 * 187 * @param WP_View_Config_Data $data The view configuration container for the entity. 188 * @return WP_View_Config_Data The updated view configuration container. 189 */ 190 function _wp_get_entity_view_config_posttype_page( $data ) { 191 $default_layouts = array( 192 'table' => array( 193 'layout' => array( 194 'styles' => array( 195 'author' => array( 196 'align' => 'start', 197 ), 198 ), 199 ), 200 ), 201 'grid' => array(), 202 'list' => array(), 203 ); 204 205 $default_view = array( 206 'type' => 'list', 207 'filters' => array(), 208 'perPage' => 20, 209 'sort' => array( 210 'field' => 'title', 211 'direction' => 'asc', 212 ), 213 'showLevels' => true, 214 'titleField' => 'title', 215 'mediaField' => 'featured_media', 216 'fields' => array( 'author', 'status' ), 217 ); 218 219 $view_list = array( 220 array( 221 'title' => __( 'Published' ), 222 'slug' => 'published', 223 'view' => array( 224 'filters' => array( 225 array( 226 'field' => 'status', 227 'operator' => 'isAny', 228 'value' => 'publish', 229 'isLocked' => true, 230 ), 231 ), 232 ), 233 ), 234 array( 235 'title' => __( 'Scheduled' ), 236 'slug' => 'future', 237 'view' => array( 238 'filters' => array( 239 array( 240 'field' => 'status', 241 'operator' => 'isAny', 242 'value' => 'future', 243 'isLocked' => true, 244 ), 245 ), 246 ), 247 ), 248 array( 249 'title' => __( 'Drafts' ), 250 'slug' => 'drafts', 251 'view' => array( 252 'filters' => array( 253 array( 254 'field' => 'status', 255 'operator' => 'isAny', 256 'value' => 'draft', 257 'isLocked' => true, 258 ), 259 ), 260 ), 261 ), 262 array( 263 'title' => __( 'Pending' ), 264 'slug' => 'pending', 265 'view' => array( 266 'filters' => array( 267 array( 268 'field' => 'status', 269 'operator' => 'isAny', 270 'value' => 'pending', 271 'isLocked' => true, 272 ), 273 ), 274 ), 275 ), 276 array( 277 'title' => __( 'Private' ), 278 'slug' => 'private', 279 'view' => array( 280 'filters' => array( 281 array( 282 'field' => 'status', 283 'operator' => 'isAny', 284 'value' => 'private', 285 'isLocked' => true, 286 ), 287 ), 288 ), 289 ), 290 array( 291 'title' => __( 'Trash' ), 292 'slug' => 'trash', 293 'view' => array( 294 'type' => 'table', 295 'layout' => $default_layouts['table']['layout'], 296 'filters' => array( 297 array( 298 'field' => 'status', 299 'operator' => 'isAny', 300 'value' => 'trash', 301 'isLocked' => true, 302 ), 303 ), 304 ), 305 ), 306 ); 307 308 $data->set( 309 array( 310 'default_view' => $default_view, 311 'default_layouts' => $default_layouts, 312 ), 313 1 314 ); 315 // Append the status views, thereby preserving the base "all items" view, 316 // so its post-type-specific title is kept. 317 $data->merge( array( 'view_list' => $view_list ), 1 ); 318 319 return $data; 320 } 321 322 /** 323 * Provides the view configuration for the `wp_block` post type. 324 * 325 * @since 7.1.0 326 * 327 * @param WP_View_Config_Data $data The view configuration container for the entity. 328 * @return WP_View_Config_Data The updated view configuration container. 329 */ 330 function _wp_get_entity_view_config_posttype_wp_block( $data ) { 331 $default_layouts = array( 332 'table' => array( 333 'layout' => array( 334 'styles' => array( 335 'author' => array( 336 'width' => '1%', 337 ), 338 ), 339 ), 340 ), 341 'grid' => array( 342 'layout' => array( 343 'badgeFields' => array( 'sync-status' ), 344 ), 345 ), 346 ); 347 348 $default_view = array( 349 'type' => 'grid', 350 'perPage' => 20, 351 'titleField' => 'title', 352 'mediaField' => 'preview', 353 'fields' => array( 'sync-status' ), 354 'filters' => array(), 355 'layout' => $default_layouts['grid']['layout'], 356 ); 357 358 $view_list = array( 359 array( 360 'title' => __( 'All patterns' ), 361 'slug' => 'all-patterns', 362 ), 363 array( 364 'title' => __( 'My patterns' ), 365 'slug' => 'my-patterns', 366 ), 367 ); 368 369 // Gather categories from the block pattern categories registry. 370 $registry = WP_Block_Pattern_Categories_Registry::get_instance(); 371 $categories = array(); 372 373 foreach ( $registry->get_all_registered() as $category ) { 374 $categories[ $category['name'] ] = $category['label']; 375 } 376 377 // Ensure "Uncategorized" is always included for patterns 378 // that have no category assigned. 379 $categories['uncategorized'] ??= __( 'Uncategorized' ); 380 381 // Also gather user-created pattern categories (wp_pattern_category taxonomy). 382 $user_terms = get_terms( 383 array( 384 'taxonomy' => 'wp_pattern_category', 385 'hide_empty' => false, 386 ) 387 ); 388 389 if ( ! is_wp_error( $user_terms ) ) { 390 foreach ( $user_terms as $term ) { 391 $categories[ $term->slug ] = $term->name; 392 } 393 } 394 395 // Sort categories alphabetically by label. 396 asort( $categories, SORT_NATURAL | SORT_FLAG_CASE ); 397 398 foreach ( $categories as $category_name => $label ) { 399 $view_list[] = array( 400 'title' => $label, 401 'slug' => $category_name, 402 ); 403 } 404 405 $form = array( 406 'layout' => array( 'type' => 'panel' ), 407 'fields' => array( 408 array( 409 'id' => 'excerpt', 410 'layout' => array( 411 'type' => 'panel', 412 'labelPosition' => 'top', 413 ), 414 ), 415 array( 416 'id' => 'post-content-info', 417 'layout' => array( 418 'type' => 'regular', 419 'labelPosition' => 'none', 420 ), 421 ), 422 'sync-status', 423 'revisions', 424 ), 425 ); 426 427 $data->set( 428 array( 429 'default_view' => $default_view, 430 'default_layouts' => $default_layouts, 431 'view_list' => $view_list, 432 'form' => $form, 433 ), 434 1 435 ); 436 437 return $data; 438 } 439 440 /** 441 * Provides the view configuration for the `wp_template_part` post type. 442 * 443 * @since 7.1.0 444 * 445 * @param WP_View_Config_Data $data The view configuration container for the entity. 446 * @return WP_View_Config_Data The updated view configuration container. 447 */ 448 function _wp_get_entity_view_config_posttype_wp_template_part( $data ) { 449 $default_layouts = array( 450 'table' => array( 451 'layout' => array( 452 'styles' => array( 453 'author' => array( 454 'width' => '1%', 455 ), 456 ), 457 ), 458 ), 459 'grid' => array( 460 'layout' => array(), 461 ), 462 ); 463 464 $default_view = array( 465 'type' => 'grid', 466 'perPage' => 20, 467 'titleField' => 'title', 468 'mediaField' => 'preview', 469 'fields' => array( 'author' ), 470 'filters' => array(), 471 'layout' => $default_layouts['grid']['layout'], 472 ); 473 474 $view_list = array( 475 array( 476 'title' => __( 'All template parts' ), 477 'slug' => 'all-parts', 478 ), 479 ); 480 481 $areas = get_allowed_block_template_part_areas(); 482 483 // Ensure default areas appear in a consistent order. 484 $preferred_order = array( 'header', 'footer', 'sidebar', 'navigation-overlay', 'uncategorized' ); 485 $ordered_areas = array(); 486 $remaining_areas = array(); 487 foreach ( $areas as $area ) { 488 $position = array_search( $area['area'], $preferred_order, true ); 489 if ( false !== $position ) { 490 $ordered_areas[ $position ] = $area; 491 } else { 492 $remaining_areas[] = $area; 493 } 494 } 495 ksort( $ordered_areas ); 496 $areas = array_merge( array_values( $ordered_areas ), $remaining_areas ); 497 498 foreach ( $areas as $area ) { 499 $view_list[] = array( 500 'title' => $area['label'], 501 'slug' => $area['area'], 502 'view' => array( 503 'filters' => array( 504 array( 505 'field' => 'area', 506 'operator' => 'is', 507 'value' => $area['area'], 508 'isLocked' => true, 509 ), 510 ), 511 ), 512 ); 513 } 514 515 $form = array( 516 'layout' => array( 'type' => 'panel' ), 517 'fields' => array( 518 array( 519 'id' => 'last_edited_date', 520 'layout' => array( 521 'type' => 'panel', 522 'labelPosition' => 'none', 523 ), 524 ), 525 'revisions', 526 ), 527 ); 528 529 $data->set( 530 array( 531 'default_view' => $default_view, 532 'default_layouts' => $default_layouts, 533 'view_list' => $view_list, 534 'form' => $form, 535 ), 536 1 537 ); 538 539 return $data; 540 } 541 542 /** 543 * Provides the view configuration for the `wp_template` post type. 544 * 545 * @since 7.1.0 546 * 547 * @param WP_View_Config_Data $data The view configuration container for the entity. 548 * @return WP_View_Config_Data The updated view configuration container. 549 */ 550 function _wp_get_entity_view_config_posttype_wp_template( $data ) { 551 $default_view = array( 552 'type' => 'grid', 553 'perPage' => 20, 554 'sort' => array( 555 'field' => 'title', 556 'direction' => 'asc', 557 ), 558 'titleField' => 'title', 559 'descriptionField' => 'description', 560 'mediaField' => 'preview', 561 'fields' => array( 'author', 'active', 'slug', 'theme' ), 562 'filters' => array(), 563 'showMedia' => true, 564 ); 565 566 $default_layouts = array( 567 'table' => array( 'showMedia' => false ), 568 'grid' => array( 'showMedia' => true ), 569 'list' => array( 'showMedia' => false ), 570 ); 571 572 $view_list = array( 573 array( 574 'title' => __( 'All templates' ), 575 'slug' => 'all', 576 ), 577 ); 578 579 $templates = get_block_templates( array(), 'wp_template' ); 580 581 // Collect unique authors, tracking whether they come from a registered 582 // source (theme, plugin, site) so we can sort those before user ones. 583 $seen_authors = array(); 584 $registered_authors = array(); 585 $user_authors = array(); 586 foreach ( $templates as $template ) { 587 /* 588 * Determine the original source of the template ('theme', 'plugin', 589 * 'site', or 'user'). 590 */ 591 $original_source = 'user'; 592 if ( 'wp_template' === $template->type || 'wp_template_part' === $template->type ) { 593 if ( $template->has_theme_file && 594 ( 'theme' === $template->origin || ( 595 empty( $template->origin ) && in_array( 596 $template->source, 597 array( 598 'theme', 599 'custom', 600 ), 601 true 602 ) ) 603 ) 604 ) { 605 /* 606 * Added by theme. 607 * Template originally provided by a theme, but customized by a user. 608 * Templates originally didn't have the 'origin' field so identify 609 * older customized templates by checking for no origin and a 'theme' 610 * or 'custom' source. 611 */ 612 $original_source = 'theme'; 613 } elseif ( 'plugin' === $template->origin ) { 614 // Added by plugin. 615 $original_source = 'plugin'; 616 } elseif ( empty( $template->has_theme_file ) && 'custom' === $template->source && empty( $template->author ) ) { 617 /* 618 * Added by site. 619 * Template was created from scratch, but has no author. Author support 620 * was only added to templates in WordPress 5.9. Fallback to showing the 621 * site logo and title. 622 */ 623 $original_source = 'site'; 624 } 625 } 626 627 // Determine a human readable text for the author of the template. 628 $author_text = ''; 629 switch ( $original_source ) { 630 case 'theme': 631 $theme_name = wp_get_theme( $template->theme )->get( 'Name' ); 632 $author_text = empty( $theme_name ) ? $template->theme : $theme_name; 633 break; 634 case 'plugin': 635 if ( ! function_exists( 'get_plugins' ) ) { 636 require_once ABSPATH . 'wp-admin/includes/plugin.php'; 637 } 638 $plugin_name = ''; 639 if ( isset( $template->plugin ) ) { 640 $plugins = wp_get_active_and_valid_plugins(); 641 642 foreach ( $plugins as $plugin_file ) { 643 $plugin_basename = plugin_basename( $plugin_file ); 644 list( $plugin_slug, ) = explode( '/', $plugin_basename ); 645 646 if ( $plugin_slug === $template->plugin ) { 647 $plugin_data = get_plugin_data( $plugin_file ); 648 649 if ( ! empty( $plugin_data['Name'] ) ) { 650 $plugin_name = $plugin_data['Name']; 651 } 652 653 break; 654 } 655 } 656 } 657 658 /* 659 * Fall back to the theme name if the plugin is not defined. That's needed to keep backwards 660 * compatibility with templates that were registered before the plugin attribute was added. 661 */ 662 if ( '' === $plugin_name ) { 663 $plugins = get_plugins(); 664 $plugin_basename = plugin_basename( sanitize_text_field( $template->theme . '.php' ) ); 665 if ( isset( $plugins[ $plugin_basename ] ) && isset( $plugins[ $plugin_basename ]['Name'] ) ) { 666 $plugin_name = $plugins[ $plugin_basename ]['Name']; 667 } else { 668 $plugin_name = $template->plugin ?? $template->theme; 669 } 670 } 671 $author_text = $plugin_name; 672 break; 673 case 'site': 674 $author_text = get_bloginfo( 'name' ); 675 break; 676 case 'user': 677 $author = get_user_by( 'id', $template->author ); 678 if ( ! $author ) { 679 $author_text = __( 'Unknown author' ); 680 } else { 681 $author_text = $author->get( 'display_name' ); 682 } 683 break; 684 } 685 686 if ( ! empty( $author_text ) && ! isset( $seen_authors[ $author_text ] ) ) { 687 $seen_authors[ $author_text ] = true; 688 $entry = array( 689 'title' => $author_text, 690 'slug' => $author_text, 691 'view' => array( 692 'filters' => array( 693 array( 694 'field' => 'author', 695 'operator' => 'is', 696 'value' => $author_text, 697 'isLocked' => true, 698 ), 699 ), 700 ), 701 ); 702 if ( 'user' === $original_source ) { 703 $user_authors[] = $entry; 704 } else { 705 $registered_authors[] = $entry; 706 } 707 } 708 } 709 710 $form = array( 711 'layout' => array( 'type' => 'panel' ), 712 'fields' => array( 713 array( 714 'id' => 'description', 715 'layout' => array( 716 'type' => 'panel', 717 'labelPosition' => 'top', 718 ), 719 ), 720 array( 721 'id' => 'description_readonly', 722 'layout' => array( 723 'type' => 'regular', 724 'labelPosition' => 'none', 725 ), 726 ), 727 array( 728 'id' => 'last_edited_date', 729 'layout' => array( 730 'type' => 'panel', 731 'labelPosition' => 'none', 732 ), 733 ), 734 'revisions', 735 // The following fields are only meaningful in the `home`/`index` 736 // template summary. They edit other entities (`root/site` and the 737 // posts page); the editor merges those records into the form data 738 // under a namespace and controls when the fields are shown. 739 'posts_page_title', 740 'posts_per_page', 741 'default_comment_status', 742 ), 743 ); 744 745 $data->set( 746 array( 747 'default_view' => $default_view, 748 'default_layouts' => $default_layouts, 749 'view_list' => array_merge( $view_list, $registered_authors, $user_authors ), 750 'form' => $form, 751 ), 752 1 753 ); 754 755 return $data; 756 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Tue Aug 4 08:20:20 2026 | Cross-referenced by PHPXref |