Created
November 6, 2025 10:20
-
-
Save thierrypigot/6eebc1b52203dd188b9d71e45c44baef to your computer and use it in GitHub Desktop.
Change the template used for singleposts based on their category, switching to a specific custom FSE (Full Site Editing) template when applicable. WordPress
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Change the template used for single posts based on their category, | |
| * switching to a specific custom FSE (Full Site Editing) template when applicable. | |
| * | |
| * Uses the `single_template_hierarchy` filter to insert the custom template | |
| * at the top of the hierarchy when the post belongs to the target category. | |
| * | |
| * This method works: | |
| * - On the front end (normal post display) | |
| * - In the Site Editor (edit/preview mode) | |
| * | |
| * WordPress automatically looks for FSE templates in the hierarchy via `resolve_block_template()`. | |
| * | |
| * --- | |
| * CONTEXT & EXAMPLE | |
| * --- | |
| * This snippet demonstrates how to dynamically assign a Full Site Editing template | |
| * for single posts belonging to a specific category. | |
| * | |
| * Example: | |
| * - Target category: “Actualités” | |
| * - Category ID: 3 | |
| * - Category slug: `actualites` | |
| * - Custom FSE template: `Single actualites` | |
| * - Custom FSE template slug: `wp-custom-template-single-actualites` | |
| * | |
| * When a post belongs to this category, WordPress will use the | |
| * `wp-custom-template-single-actualites` block template | |
| * (defined in the Site Editor or in the theme’s `wp_template` post type). | |
| * | |
| * For all other posts, the default single template hierarchy is preserved. | |
| * | |
| * --- | |
| * @param array $templates The current template hierarchy. | |
| * @return array The modified hierarchy with the category-specific custom template added first. | |
| * | |
| * @author Thierry Pigot - www.wearewp.pro | |
| * @license MIT | |
| */ | |
| function twentytwentyfive_child_change_single_template( $templates ) { | |
| // Make sure this is indeed a single template hierarchy. | |
| // The first element should be 'single' or start with 'single-'. | |
| if ( empty( $templates ) || ( ! str_starts_with( $templates[0], 'single' ) && 'singular' !== $templates[0] ) ) { | |
| return $templates; | |
| } | |
| // Retrieve the current post (works both on the front end and inside the Site Editor via REST API). | |
| $current_post = null; | |
| // First, try to get it with get_queried_object() (front end). | |
| if ( is_singular( 'post' ) ) { | |
| $current_post = get_queried_object(); | |
| } | |
| // If we're in the Site Editor, try to get the post from the REST request. | |
| if ( ! $current_post && isset( $_GET['postId'] ) && is_numeric( $_GET['postId'] ) ) { | |
| $current_post = get_post( (int) $_GET['postId'] ); | |
| } | |
| // If we still don't have a post, try to infer it from the slug. | |
| if ( ! $current_post && ! empty( $templates[0] ) && str_starts_with( $templates[0], 'single-post-' ) ) { | |
| // The slug is like 'single-post-{slug}', so let's try to get the post from that. | |
| $post_slug = str_replace( 'single-post-', '', $templates[0] ); | |
| $current_post = get_page_by_path( $post_slug, OBJECT, 'post' ); | |
| } | |
| // If no post was found, do nothing. | |
| if ( ! $current_post || ! isset( $current_post->ID ) || 'post' !== $current_post->post_type ) { | |
| return $templates; | |
| } | |
| // Check if the post belongs to the "Actualités" category (ID: 3). | |
| // You can use either the ID or the slug. | |
| if ( ! has_category( 3, $current_post->ID ) && ! has_category( 'actualites', $current_post->ID ) ) { | |
| return $templates; | |
| } | |
| // Slug of the custom FSE template (without the 'wp_template/' prefix). | |
| // Example: 'wp-custom-template-single-actualites' as found in the editor URL. | |
| $custom_template_slug = 'wp-custom-template-single-actualites'; | |
| // Check if the custom template exists before adding it. | |
| $theme_slug = get_stylesheet(); | |
| $template_id = $theme_slug . '//' . $custom_template_slug; | |
| $custom_template = get_block_template( $template_id, 'wp_template' ); | |
| // If the template exists, prepend it to the hierarchy. | |
| if ( $custom_template && ! empty( $custom_template->content ) ) { | |
| array_unshift( $templates, $custom_template_slug ); | |
| } | |
| return $templates; | |
| } | |
| add_filter( 'single_template_hierarchy', 'twentytwentyfive_child_change_single_template', 10, 1 ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment