[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> view-config.php (source)

   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  }


Generated : Tue Aug 4 08:20:20 2026 Cross-referenced by PHPXref