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


Generated : Tue Jul 14 08:20:16 2026 Cross-referenced by PHPXref