wp/wp-includes/block-template.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
--- a/wp/wp-includes/block-template.php	Thu Sep 29 08:06:27 2022 +0200
+++ b/wp/wp-includes/block-template.php	Fri Sep 05 18:40:08 2025 +0200
@@ -6,47 +6,35 @@
  */
 
 /**
- * Adds necessary filters to use 'wp_template' posts instead of theme template files.
+ * Adds necessary hooks to resolve '_wp-find-template' requests.
  *
  * @access private
  * @since 5.9.0
  */
 function _add_template_loader_filters() {
-	if ( ! current_theme_supports( 'block-templates' ) ) {
-		return;
-	}
-
-	$template_types = array_keys( get_default_block_template_types() );
-	foreach ( $template_types as $template_type ) {
-		// Skip 'embed' for now because it is not a regular template type.
-		if ( 'embed' === $template_type ) {
-			continue;
-		}
-		add_filter( str_replace( '-', '', $template_type ) . '_template', 'locate_block_template', 20, 3 );
-	}
-
-	// Request to resolve a template.
-	if ( isset( $_GET['_wp-find-template'] ) ) {
-		add_filter( 'pre_get_posts', '_resolve_template_for_new_post' );
+	if ( isset( $_GET['_wp-find-template'] ) && current_theme_supports( 'block-templates' ) ) {
+		add_action( 'pre_get_posts', '_resolve_template_for_new_post' );
 	}
 }
 
 /**
- * Find a block template with equal or higher specificity than a given PHP template file.
+ * Finds a block template with equal or higher specificity than a given PHP template file.
  *
  * Internally, this communicates the block content that needs to be used by the template canvas through a global variable.
  *
  * @since 5.8.0
+ * @since 6.3.0 Added `$_wp_current_template_id` global for editing of current template directly from the admin bar.
  *
  * @global string $_wp_current_template_content
+ * @global string $_wp_current_template_id
  *
  * @param string   $template  Path to the template. See locate_template().
  * @param string   $type      Sanitized filename without extension.
  * @param string[] $templates A list of template candidates, in descending order of priority.
- * @return string The path to the Full Site Editing template canvas file, or the fallback PHP template.
+ * @return string The path to the Site Editor template canvas file, or the fallback PHP template.
  */
 function locate_block_template( $template, $type, array $templates ) {
-	global $_wp_current_template_content;
+	global $_wp_current_template_content, $_wp_current_template_id;
 
 	if ( ! current_theme_supports( 'block-templates' ) ) {
 		return $template;
@@ -78,6 +66,8 @@
 	$block_template = resolve_block_template( $type, $templates, $template );
 
 	if ( $block_template ) {
+		$_wp_current_template_id = $block_template->id;
+
 		if ( empty( $block_template->content ) && is_user_logged_in() ) {
 			$_wp_current_template_content =
 			sprintf(
@@ -118,7 +108,7 @@
 }
 
 /**
- * Return the correct 'wp_template' to render for the request template type.
+ * Returns the correct 'wp_template' to render for the request template type.
  *
  * @access private
  * @since 5.8.0
@@ -145,7 +135,6 @@
 
 	// Find all potential templates 'wp_template' post matching the hierarchy.
 	$query     = array(
-		'theme'    => wp_get_theme()->get_stylesheet(),
 		'slug__in' => $slugs,
 	);
 	$templates = get_block_templates( $query );
@@ -166,8 +155,8 @@
 
 	// Is the active theme a child theme, and is the PHP fallback template part of it?
 	if (
-		strpos( $fallback_template, $theme_base_path ) === 0 &&
-		strpos( $fallback_template, $parent_theme_base_path ) === false
+		str_starts_with( $fallback_template, $theme_base_path ) &&
+		! str_contains( $fallback_template, $parent_theme_base_path )
 	) {
 		$fallback_template_slug = substr(
 			$fallback_template,
@@ -219,14 +208,15 @@
  * @access private
  * @since 5.8.0
  *
+ * @global string   $_wp_current_template_id
  * @global string   $_wp_current_template_content
- * @global WP_Embed $wp_embed
+ * @global WP_Embed $wp_embed                     WordPress Embed object.
+ * @global WP_Query $wp_query                     WordPress Query object.
  *
  * @return string Block template markup.
  */
 function get_the_block_template_html() {
-	global $_wp_current_template_content;
-	global $wp_embed;
+	global $_wp_current_template_id, $_wp_current_template_content, $wp_embed, $wp_query;
 
 	if ( ! $_wp_current_template_content ) {
 		if ( is_user_logged_in() ) {
@@ -237,12 +227,45 @@
 
 	$content = $wp_embed->run_shortcode( $_wp_current_template_content );
 	$content = $wp_embed->autoembed( $content );
-	$content = do_blocks( $content );
+	$content = shortcode_unautop( $content );
+	$content = do_shortcode( $content );
+
+	/*
+	 * Most block themes omit the `core/query` and `core/post-template` blocks in their singular content templates.
+	 * While this technically still works since singular content templates are always for only one post, it results in
+	 * the main query loop never being entered which causes bugs in core and the plugin ecosystem.
+	 *
+	 * The workaround below ensures that the loop is started even for those singular templates. The while loop will by
+	 * definition only go through a single iteration, i.e. `do_blocks()` is only called once. Additional safeguard
+	 * checks are included to ensure the main query loop has not been tampered with and really only encompasses a
+	 * single post.
+	 *
+	 * Even if the block template contained a `core/query` and `core/post-template` block referencing the main query
+	 * loop, it would not cause errors since it would use a cloned instance and go through the same loop of a single
+	 * post, within the actual main query loop.
+	 *
+	 * This special logic should be skipped if the current template does not come from the current theme, in which case
+	 * it has been injected by a plugin by hijacking the block template loader mechanism. In that case, entirely custom
+	 * logic may be applied which is unpredictable and therefore safer to omit this special handling on.
+	 */
+	if (
+		$_wp_current_template_id &&
+		str_starts_with( $_wp_current_template_id, get_stylesheet() . '//' ) &&
+		is_singular() &&
+		1 === $wp_query->post_count &&
+		have_posts()
+	) {
+		while ( have_posts() ) {
+			the_post();
+			$content = do_blocks( $content );
+		}
+	} else {
+		$content = do_blocks( $content );
+	}
+
 	$content = wptexturize( $content );
 	$content = convert_smilies( $content );
-	$content = shortcode_unautop( $content );
-	$content = wp_filter_content_tags( $content );
-	$content = do_shortcode( $content );
+	$content = wp_filter_content_tags( $content, 'template' );
 	$content = str_replace( ']]>', ']]>', $content );
 
 	// Wrap block template in .wp-site-blocks to allow for specific descendant styles
@@ -335,35 +358,3 @@
 		$wp_query->set( 'post_status', 'auto-draft' );
 	}
 }
-
-/**
- * Returns the correct template for the site's home page.
- *
- * @access private
- * @since 6.0.0
- *
- * @return array|null A template object, or null if none could be found.
- */
-function _resolve_home_block_template() {
-	$show_on_front = get_option( 'show_on_front' );
-	$front_page_id = get_option( 'page_on_front' );
-
-	if ( 'page' === $show_on_front && $front_page_id ) {
-		return array(
-			'postType' => 'page',
-			'postId'   => $front_page_id,
-		);
-	}
-
-	$hierarchy = array( 'front-page', 'home', 'index' );
-	$template  = resolve_block_template( 'home', $hierarchy, '' );
-
-	if ( ! $template ) {
-		return null;
-	}
-
-	return array(
-		'postType' => 'wp_template',
-		'postId'   => $template->id,
-	);
-}