From a415c29efee45520ae252d2aa28f1083a521cd7b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 09:56:49 +0200 Subject: Adding upstream version 6.4.3+dfsg1. Signed-off-by: Daniel Baumann --- wp-includes/block-template.php | 360 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+) create mode 100644 wp-includes/block-template.php (limited to 'wp-includes/block-template.php') diff --git a/wp-includes/block-template.php b/wp-includes/block-template.php new file mode 100644 index 0000000..7030e2e --- /dev/null +++ b/wp-includes/block-template.php @@ -0,0 +1,360 @@ +id; + + if ( empty( $block_template->content ) && is_user_logged_in() ) { + $_wp_current_template_content = + sprintf( + /* translators: %s: Template title */ + __( 'Empty template: %s' ), + $block_template->title + ); + } elseif ( ! empty( $block_template->content ) ) { + $_wp_current_template_content = $block_template->content; + } + if ( isset( $_GET['_wp-find-template'] ) ) { + wp_send_json_success( $block_template ); + } + } else { + if ( $template ) { + return $template; + } + + if ( 'index' === $type ) { + if ( isset( $_GET['_wp-find-template'] ) ) { + wp_send_json_error( array( 'message' => __( 'No matching template found.' ) ) ); + } + } else { + return ''; // So that the template loader keeps looking for templates. + } + } + + // Add hooks for template canvas. + // Add viewport meta tag. + add_action( 'wp_head', '_block_template_viewport_meta_tag', 0 ); + + // Render title tag with content, regardless of whether theme has title-tag support. + remove_action( 'wp_head', '_wp_render_title_tag', 1 ); // Remove conditional title tag rendering... + add_action( 'wp_head', '_block_template_render_title_tag', 1 ); // ...and make it unconditional. + + // This file will be included instead of the theme's template file. + return ABSPATH . WPINC . '/template-canvas.php'; +} + +/** + * Returns the correct 'wp_template' to render for the request template type. + * + * @access private + * @since 5.8.0 + * @since 5.9.0 Added the `$fallback_template` parameter. + * + * @param string $template_type The current template type. + * @param string[] $template_hierarchy The current template hierarchy, ordered by priority. + * @param string $fallback_template A PHP fallback template to use if no matching block template is found. + * @return WP_Block_Template|null template A template object, or null if none could be found. + */ +function resolve_block_template( $template_type, $template_hierarchy, $fallback_template ) { + if ( ! $template_type ) { + return null; + } + + if ( empty( $template_hierarchy ) ) { + $template_hierarchy = array( $template_type ); + } + + $slugs = array_map( + '_strip_template_file_suffix', + $template_hierarchy + ); + + // Find all potential templates 'wp_template' post matching the hierarchy. + $query = array( + 'slug__in' => $slugs, + ); + $templates = get_block_templates( $query ); + + // Order these templates per slug priority. + // Build map of template slugs to their priority in the current hierarchy. + $slug_priorities = array_flip( $slugs ); + + usort( + $templates, + static function ( $template_a, $template_b ) use ( $slug_priorities ) { + return $slug_priorities[ $template_a->slug ] - $slug_priorities[ $template_b->slug ]; + } + ); + + $theme_base_path = get_stylesheet_directory() . DIRECTORY_SEPARATOR; + $parent_theme_base_path = get_template_directory() . DIRECTORY_SEPARATOR; + + // Is the active theme a child theme, and is the PHP fallback template part of it? + if ( + str_starts_with( $fallback_template, $theme_base_path ) && + ! str_contains( $fallback_template, $parent_theme_base_path ) + ) { + $fallback_template_slug = substr( + $fallback_template, + // Starting position of slug. + strpos( $fallback_template, $theme_base_path ) + strlen( $theme_base_path ), + // Remove '.php' suffix. + -4 + ); + + // Is our candidate block template's slug identical to our PHP fallback template's? + if ( + count( $templates ) && + $fallback_template_slug === $templates[0]->slug && + 'theme' === $templates[0]->source + ) { + // Unfortunately, we cannot trust $templates[0]->theme, since it will always + // be set to the active theme's slug by _build_block_template_result_from_file(), + // even if the block template is really coming from the active theme's parent. + // (The reason for this is that we want it to be associated with the active theme + // -- not its parent -- once we edit it and store it to the DB as a wp_template CPT.) + // Instead, we use _get_block_template_file() to locate the block template file. + $template_file = _get_block_template_file( 'wp_template', $fallback_template_slug ); + if ( $template_file && get_template() === $template_file['theme'] ) { + // The block template is part of the parent theme, so we + // have to give precedence to the child theme's PHP template. + array_shift( $templates ); + } + } + } + + return count( $templates ) ? $templates[0] : null; +} + +/** + * Displays title tag with content, regardless of whether theme has title-tag support. + * + * @access private + * @since 5.8.0 + * + * @see _wp_render_title_tag() + */ +function _block_template_render_title_tag() { + echo '' . wp_get_document_title() . '' . "\n"; +} + +/** + * Returns the markup for the current template. + * + * @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_Query $wp_query + * + * @return string Block template markup. + */ +function get_the_block_template_html() { + global $_wp_current_template_id, $_wp_current_template_content, $wp_embed, $wp_query; + + if ( ! $_wp_current_template_content ) { + if ( is_user_logged_in() ) { + return '

' . esc_html__( 'No matching template found' ) . '

'; + } + return; + } + + $content = $wp_embed->run_shortcode( $_wp_current_template_content ); + $content = $wp_embed->autoembed( $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 = wp_filter_content_tags( $content, 'template' ); + $content = str_replace( ']]>', ']]>', $content ); + + // Wrap block template in .wp-site-blocks to allow for specific descendant styles + // (e.g. `.wp-site-blocks > *`). + return '
' . $content . '
'; +} + +/** + * Renders a 'viewport' meta tag. + * + * This is hooked into {@see 'wp_head'} to decouple its output from the default template canvas. + * + * @access private + * @since 5.8.0 + */ +function _block_template_viewport_meta_tag() { + echo '' . "\n"; +} + +/** + * Strips .php or .html suffix from template file names. + * + * @access private + * @since 5.8.0 + * + * @param string $template_file Template file name. + * @return string Template file name without extension. + */ +function _strip_template_file_suffix( $template_file ) { + return preg_replace( '/\.(php|html)$/', '', $template_file ); +} + +/** + * Removes post details from block context when rendering a block template. + * + * @access private + * @since 5.8.0 + * + * @param array $context Default context. + * + * @return array Filtered context. + */ +function _block_template_render_without_post_block_context( $context ) { + /* + * When loading a template directly and not through a page that resolves it, + * the top-level post ID and type context get set to that of the template. + * Templates are just the structure of a site, and they should not be available + * as post context because blocks like Post Content would recurse infinitely. + */ + if ( isset( $context['postType'] ) && 'wp_template' === $context['postType'] ) { + unset( $context['postId'] ); + unset( $context['postType'] ); + } + + return $context; +} + +/** + * Sets the current WP_Query to return auto-draft posts. + * + * The auto-draft status indicates a new post, so allow the the WP_Query instance to + * return an auto-draft post for template resolution when editing a new post. + * + * @access private + * @since 5.9.0 + * + * @param WP_Query $wp_query Current WP_Query instance, passed by reference. + */ +function _resolve_template_for_new_post( $wp_query ) { + if ( ! $wp_query->is_main_query() ) { + return; + } + + remove_filter( 'pre_get_posts', '_resolve_template_for_new_post' ); + + // Pages. + $page_id = isset( $wp_query->query['page_id'] ) ? $wp_query->query['page_id'] : null; + + // Posts, including custom post types. + $p = isset( $wp_query->query['p'] ) ? $wp_query->query['p'] : null; + + $post_id = $page_id ? $page_id : $p; + $post = get_post( $post_id ); + + if ( + $post && + 'auto-draft' === $post->post_status && + current_user_can( 'edit_post', $post->ID ) + ) { + $wp_query->set( 'post_status', 'auto-draft' ); + } +} -- cgit v1.2.3