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