[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/blocks/ -> template-part.php (source)

   1  <?php
   2  /**
   3   * Server-side rendering of the `core/template-part` block.
   4   *
   5   * @package WordPress
   6   */
   7  
   8  /**
   9   * Renders the `core/template-part` block on the server.
  10   *
  11   * @since 5.9.0
  12   *
  13   * @global WP_Embed $wp_embed WordPress Embed object.
  14   *
  15   * @param array $attributes The block attributes.
  16   *
  17   * @return string The render.
  18   */
  19  function render_block_core_template_part( $attributes ) {
  20      static $seen_ids = array();
  21  
  22      $template_part_id = null;
  23      $content          = null;
  24      $area             = WP_TEMPLATE_PART_AREA_UNCATEGORIZED;
  25      $theme            = $attributes['theme'] ?? get_stylesheet();
  26  
  27      if ( isset( $attributes['slug'] ) && get_stylesheet() === $theme ) {
  28          $template_part_id    = $theme . '//' . $attributes['slug'];
  29          $template_part_query = new WP_Query(
  30              array(
  31                  'post_type'           => 'wp_template_part',
  32                  'post_status'         => 'publish',
  33                  'post_name__in'       => array( $attributes['slug'] ),
  34                  'tax_query'           => array(
  35                      array(
  36                          'taxonomy' => 'wp_theme',
  37                          'field'    => 'name',
  38                          'terms'    => $theme,
  39                      ),
  40                  ),
  41                  'posts_per_page'      => 1,
  42                  'no_found_rows'       => true,
  43                  'lazy_load_term_meta' => false, // Do not lazy load term meta, as template parts only have one term.
  44              )
  45          );
  46          $template_part_post  = $template_part_query->have_posts() ? $template_part_query->next_post() : null;
  47          $block_template      = $template_part_post ? _build_block_template_result_from_post( $template_part_post ) : null;
  48          // Can be a WP_Error if the post's `wp_theme` terms can't be read, even though the query
  49          // matched on them. Report it and fall back to the theme file.
  50          if ( is_wp_error( $block_template ) ) {
  51              wp_trigger_error(
  52                  __FUNCTION__,
  53                  sprintf(
  54                      /* translators: 1: Template part ID, 2: Error message. */
  55                      __( 'Error loading the template part %1$s from the database: %2$s' ),
  56                      $template_part_id,
  57                      $block_template->get_error_message()
  58                  )
  59              );
  60          }
  61          if ( $block_template && ! is_wp_error( $block_template ) ) {
  62              // A published post might already exist if this template part was customized elsewhere
  63              // or if it's part of a customized template.
  64              $content = $block_template->content;
  65              if ( isset( $block_template->area ) ) {
  66                  $area = $block_template->area;
  67              }
  68              /**
  69               * Fires when a block template part is loaded from a template post stored in the database.
  70               *
  71               * @since 5.9.0
  72               *
  73               * @param string  $template_part_id   The requested template part namespaced to the theme.
  74               * @param array   $attributes         The block attributes.
  75               * @param WP_Post $template_part_post The template part post object.
  76               * @param string  $content            The template part content.
  77               */
  78              do_action( 'render_block_core_template_part_post', $template_part_id, $attributes, $template_part_post, $content );
  79          } else {
  80              $template_part_file_path = '';
  81              // Else, if the template part was provided by the active theme,
  82              // render the corresponding file content.
  83              if ( 0 === validate_file( $attributes['slug'] ) ) {
  84                  $block_template = get_block_file_template( $template_part_id, 'wp_template_part' );
  85  
  86                  if ( isset( $block_template->content ) ) {
  87                      $content = $block_template->content;
  88                  }
  89                  if ( isset( $block_template->area ) ) {
  90                      $area = $block_template->area;
  91                  }
  92  
  93                  // Needed for the `render_block_core_template_part_file` and `render_block_core_template_part_none` actions below.
  94                  $block_template_file = _get_block_template_file( 'wp_template_part', $attributes['slug'] );
  95                  if ( $block_template_file ) {
  96                      $template_part_file_path = $block_template_file['path'];
  97                  }
  98              }
  99  
 100              if ( '' !== $content && null !== $content ) {
 101                  /**
 102                   * Fires when a block template part is loaded from a template part in the theme.
 103                   *
 104                   * @since 5.9.0
 105                   *
 106                   * @param string $template_part_id        The requested template part namespaced to the theme.
 107                   * @param array  $attributes              The block attributes.
 108                   * @param string $template_part_file_path Absolute path to the template path.
 109                   * @param string $content                 The template part content.
 110                   */
 111                  do_action( 'render_block_core_template_part_file', $template_part_id, $attributes, $template_part_file_path, $content );
 112              } else {
 113                  /**
 114                   * Fires when a requested block template part does not exist in the database nor in the theme.
 115                   *
 116                   * @since 5.9.0
 117                   *
 118                   * @param string $template_part_id        The requested template part namespaced to the theme.
 119                   * @param array  $attributes              The block attributes.
 120                   * @param string $template_part_file_path Absolute path to the not found template path.
 121                   */
 122                  do_action( 'render_block_core_template_part_none', $template_part_id, $attributes, $template_part_file_path );
 123              }
 124          }
 125      }
 126  
 127      // WP_DEBUG_DISPLAY must only be honored when WP_DEBUG. This precedent
 128      // is set in `wp_debug_mode()`.
 129      $is_debug = WP_DEBUG && WP_DEBUG_DISPLAY;
 130  
 131      if ( is_null( $content ) ) {
 132          if ( $is_debug && isset( $attributes['slug'] ) ) {
 133              return sprintf(
 134                  /* translators: %s: Template part slug. */
 135                  __( 'Template part has been deleted or is unavailable: %s' ),
 136                  $attributes['slug']
 137              );
 138          }
 139  
 140          return '';
 141      }
 142  
 143      if ( isset( $seen_ids[ $template_part_id ] ) ) {
 144          return $is_debug ?
 145              // translators: Visible only in the front end, this warning takes the place of a faulty block.
 146              __( '[block rendering halted]' ) :
 147              '';
 148      }
 149  
 150      // Look up area definition.
 151      $area_definition = null;
 152      $defined_areas   = get_allowed_block_template_part_areas();
 153      foreach ( $defined_areas as $defined_area ) {
 154          if ( $defined_area['area'] === $area ) {
 155              $area_definition = $defined_area;
 156              break;
 157          }
 158      }
 159  
 160      // If $area is not allowed, set it back to the uncategorized default.
 161      if ( ! $area_definition ) {
 162          $area = WP_TEMPLATE_PART_AREA_UNCATEGORIZED;
 163      }
 164  
 165      // Run through the actions that are typically taken on the_content.
 166      $content = _wp_apply_block_content_filters( $content, "template_part_{$area}", $seen_ids, $template_part_id );
 167  
 168      $tag_name = $attributes['tagName'] ?? null;
 169      if ( empty( $tag_name ) || ! is_string( $tag_name ) || tag_escape( $tag_name ) !== $tag_name ) {
 170          $area_tag = 'div';
 171          if ( $area_definition && isset( $area_definition['area_tag'] ) ) {
 172              $area_tag = $area_definition['area_tag'];
 173          }
 174          $html_tag = $area_tag;
 175      } else {
 176          $html_tag = esc_attr( $attributes['tagName'] );
 177      }
 178      $wrapper_attributes = get_block_wrapper_attributes();
 179  
 180      return "<$html_tag $wrapper_attributes>" . str_replace( ']]>', ']]&gt;', $content ) . "</$html_tag>";
 181  }
 182  
 183  /**
 184   * Returns an array of area variation objects for the template part block.
 185   *
 186   * @since 6.1.0
 187   *
 188   * @param array $instance_variations The variations for instances.
 189   *
 190   * @return array Array containing the block variation objects.
 191   */
 192  function build_template_part_block_area_variations( $instance_variations ) {
 193      $variations    = array();
 194      $defined_areas = get_allowed_block_template_part_areas();
 195  
 196      foreach ( $defined_areas as $area ) {
 197          if ( 'uncategorized' !== $area['area'] && 'navigation-overlay' !== $area['area'] ) {
 198              $has_instance_for_area = false;
 199              foreach ( $instance_variations as $variation ) {
 200                  if ( $variation['attributes']['area'] === $area['area'] ) {
 201                      $has_instance_for_area = true;
 202                      break;
 203                  }
 204              }
 205  
 206              $scope = $has_instance_for_area ? array() : array( 'inserter' );
 207  
 208              $variations[] = array(
 209                  'name'        => 'area_' . $area['area'],
 210                  'title'       => $area['label'],
 211                  'description' => $area['description'],
 212                  'attributes'  => array(
 213                      'area' => $area['area'],
 214                  ),
 215                  'scope'       => $scope,
 216                  'icon'        => $area['icon'],
 217              );
 218          }
 219      }
 220      return $variations;
 221  }
 222  
 223  /**
 224   * Returns an array of instance variation objects for the template part block
 225   *
 226   * @since 6.1.0
 227   *
 228   * @return array Array containing the block variation objects.
 229   */
 230  function build_template_part_block_instance_variations() {
 231      // Block themes are unavailable during installation.
 232      if ( wp_installing() ) {
 233          return array();
 234      }
 235  
 236      if ( ! current_theme_supports( 'block-templates' ) && ! current_theme_supports( 'block-template-parts' ) ) {
 237          return array();
 238      }
 239  
 240      $variations     = array();
 241      $template_parts = get_block_templates(
 242          array(
 243              'post_type' => 'wp_template_part',
 244          ),
 245          'wp_template_part'
 246      );
 247  
 248      $defined_areas = get_allowed_block_template_part_areas();
 249      $icon_by_area  = array_combine( array_column( $defined_areas, 'area' ), array_column( $defined_areas, 'icon' ) );
 250  
 251      foreach ( $template_parts as $template_part ) {
 252          // Navigation overlay template parts should not appear in the
 253          // general inserter. They are managed through the Navigation
 254          // block's overlay template part selector.
 255          $scope = ( 'navigation-overlay' === $template_part->area )
 256              ? array()
 257              : array( 'inserter' );
 258  
 259          $variations[] = array(
 260              'name'        => 'instance_' . sanitize_title( $template_part->slug ),
 261              'title'       => $template_part->title,
 262              // If there's no description for the template part don't show the
 263              // block description. This is a bit hacky, but prevent the fallback
 264              // by using a non-breaking space so that the value of description
 265              // isn't falsey.
 266              'description' => $template_part->description || '&nbsp;',
 267              'attributes'  => array(
 268                  'slug'  => $template_part->slug,
 269                  'theme' => $template_part->theme,
 270                  'area'  => $template_part->area,
 271              ),
 272              'scope'       => $scope,
 273              'icon'        => $icon_by_area[ $template_part->area ] ?? null,
 274              'example'     => array(
 275                  'attributes' => array(
 276                      'slug'  => $template_part->slug,
 277                      'theme' => $template_part->theme,
 278                      'area'  => $template_part->area,
 279                  ),
 280              ),
 281          );
 282      }
 283      return $variations;
 284  }
 285  
 286  /**
 287   * Returns an array of all template part block variations.
 288   *
 289   * @since 5.9.0
 290   *
 291   * @return array Array containing the block variation objects.
 292   */
 293  function build_template_part_block_variations() {
 294      $instance_variations = build_template_part_block_instance_variations();
 295      $area_variations     = build_template_part_block_area_variations( $instance_variations );
 296      return array_merge( $area_variations, $instance_variations );
 297  }
 298  
 299  /**
 300   * Registers the `core/template-part` block on the server.
 301   *
 302   * @since 5.9.0
 303   */
 304  function register_block_core_template_part() {
 305      register_block_type_from_metadata(
 306          __DIR__ . '/template-part',
 307          array(
 308              'render_callback'    => 'render_block_core_template_part',
 309              'variation_callback' => 'build_template_part_block_variations',
 310          )
 311      );
 312  }
 313  add_action( 'init', 'register_block_core_template_part' );


Generated : Sun Nov 1 08:20:35 2026 Cross-referenced by PHPXref