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