[ 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   * 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  }


Generated : Wed Jun 24 08:20:11 2026 Cross-referenced by PHPXref