-
Notifications
You must be signed in to change notification settings - Fork 5
fix(templates): hybrid themes (wp_is_block_theme() false) still list/edit real templates — BLOCK-37 #61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(templates): hybrid themes (wp_is_block_theme() false) still list/edit real templates — BLOCK-37 #61
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -122,14 +122,6 @@ public function get_templates( array $args ) { | |
| return $type; | ||
| } | ||
|
|
||
| if ( ! wp_is_block_theme() ) { | ||
| return array( | ||
| 'templates' => array(), | ||
| 'count' => 0, | ||
| 'note' => __( 'Active theme is not a block theme; no block templates exist.', 'gk-block-mcp' ), | ||
| ); | ||
| } | ||
|
|
||
| $query = array(); | ||
|
|
||
| if ( 'wp_template_part' === $type && ! empty( $args['area'] ) ) { | ||
|
|
@@ -163,10 +155,20 @@ static function ( $template ) use ( $source ) { | |
|
|
||
| $formatted = array_map( array( $this, 'format_template_summary' ), $templates ); | ||
|
|
||
| return array( | ||
| $result = array( | ||
| 'templates' => $formatted, | ||
| 'count' => count( $formatted ), | ||
| ); | ||
|
|
||
| // A hybrid theme (wp_is_block_theme() false, e.g. no templates/index.html) | ||
| // can still have real templates/parts get_block_templates() finds via | ||
| // theme files or DB overrides, so an empty result alone doesn't mean | ||
| // "not a block theme" — only note that when it's also actually true. | ||
| if ( empty( $formatted ) && ! wp_is_block_theme() ) { | ||
| $result['note'] = __( 'Active theme is not a full block theme; only registered block templates/parts are listed.', 'gk-block-mcp' ); | ||
|
Comment on lines
+167
to
+168
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win Assign conditional checks to named variables. These conditions inline Proposed pattern- if ( empty( $formatted ) && ! wp_is_block_theme() ) {
+ $has_templates = ! empty( $formatted );
+ $is_block_theme = wp_is_block_theme();
+ if ( ! $has_templates && ! $is_block_theme ) {Apply the same As per coding guidelines, checks must be assigned to named variables before conditionals. Also applies to: 283-284, 394-395 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| } | ||
|
|
||
| return $result; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -254,14 +256,6 @@ public function update_template( $id, $type, array $args ) { | |
| return $type; | ||
| } | ||
|
|
||
| if ( ! wp_is_block_theme() ) { | ||
| return new \WP_Error( | ||
| 'classic_theme', | ||
| __( 'Active theme is not a block theme; there are no block templates to edit.', 'gk-block-mcp' ), | ||
| array( 'status' => 400 ) | ||
| ); | ||
| } | ||
|
|
||
| $id = is_string( $id ) ? sanitize_text_field( $id ) : ''; | ||
| if ( '' === $id ) { | ||
| return new \WP_Error( | ||
|
|
@@ -281,8 +275,18 @@ public function update_template( $id, $type, array $args ) { | |
| ); | ||
| } | ||
|
|
||
| // Gate on whether the id actually resolves, not wp_is_block_theme(): | ||
| // a hybrid theme (no templates/index.html) can still have real, | ||
| // resolvable templates/parts, and those are meaningful to edit. | ||
| $template = get_block_template( $id, $type ); | ||
| if ( ! $template ) { | ||
| if ( ! wp_is_block_theme() ) { | ||
| return new \WP_Error( | ||
| 'classic_theme', | ||
| __( 'Active theme is not a block theme; there are no block templates to edit.', 'gk-block-mcp' ), | ||
| array( 'status' => 400 ) | ||
| ); | ||
| } | ||
|
Comment on lines
281
to
+289
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Map the file structure first
git ls-files wordpress-plugin/gk-block-mcp/includes/class-template-manager.php
# Show outline if available, then relevant line ranges
if command -v ast-grep >/dev/null 2>&1; then
ast-grep outline wordpress-plugin/gk-block-mcp/includes/class-template-manager.php --view expanded || true
fi
nl -ba wordpress-plugin/gk-block-mcp/includes/class-template-manager.php | sed -n '240,430p'Repository: GravityKit/block-mcp Length of output: 973 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Find all occurrences of the error codes and template lookup helpers.
rg -n "classic_theme|not_found|get_block_template|wp_is_block_theme|template-part|footer" wordpress-plugin/gk-block-mcp/includes/class-template-manager.php wordpress-plugin/gk-block-mcp/includes -g '*.php'Repository: GravityKit/block-mcp Length of output: 8951 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the public methods that return the template-not-found errors.
python3 - <<'PY'
from pathlib import Path
p = Path('wordpress-plugin/gk-block-mcp/includes/class-template-manager.php')
text = p.read_text()
for needle in ['function', 'classic_theme', 'not_found']:
pass
# Print the surrounding blocks for methods containing get_block_template
lines = text.splitlines()
for i, line in enumerate(lines, start=1):
if 'get_block_template' in line or 'classic_theme' in line or 'not_found' in line:
start = max(1, i-25)
end = min(len(lines), i+35)
print(f"\n--- lines {start}-{end} around line {i} ---")
for n in range(start, end+1):
print(f"{n:4d}: {lines[n-1]}")
PYRepository: GravityKit/block-mcp Length of output: 33623 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Read only the relevant section around the two reported ranges.
nl -ba wordpress-plugin/gk-block-mcp/includes/class-template-manager.php | sed -n '260,420p'Repository: GravityKit/block-mcp Length of output: 198 🌐 Web query:
💡 Result: In WordPress, the behavior you are observing regarding wp_is_block_theme, get_block_template, and template discovery is rooted in how WordPress distinguishes between "full" block themes and hybrid themes [1][2]. wp_is_block_theme Functionality The function wp_is_block_theme specifically checks whether a theme is a block-based theme [3]. Internally, it wraps wp_get_theme->is_block_theme, which determines this status by checking for the presence of an index.html file in either the /templates/ or /block-templates/ directory of the theme [4][5]. If your hybrid theme relies on traditional PHP templates (e.g., index.php) and does not have an index.html block template at the root, wp_is_block_theme will return false, correctly identifying it as a classic or hybrid theme rather than a pure block theme [4][2]. get_block_template and Template Discovery The function get_block_template retrieves a block template object (WP_Block_Template) by its ID (e.g., 'theme_slug//template_slug') [6]. When you call this function for a template that does not exist in the database (customized via the Site Editor), WordPress falls back to get_block_file_template to look for the template file on the file system [7]. If you are encountering a "not found" or null result when calling get_block_template in a hybrid theme: 1. File Location: Ensure your block template files are correctly placed in the /templates/ or /block-templates/ directories of your theme [4][2]. 2. Theme Support: For hybrid themes to utilize block templates, ensure that the theme has explicitly declared support for them. While block template parts (via the /parts directory) can be used with broad theme support, full block templates may require the theme to be recognized as having block-template capabilities [1][8]. 3. Hybrid vs. Full Block: In a hybrid theme, the PHP template hierarchy (index.php, single.php) still takes precedence [2]. If WordPress locates a PHP template for a given request, it may bypass the block template discovery logic unless you are specifically using functions or hooks that force the rendering of a block template [9]. If you are developing a hybrid theme and need to access a block template file, verify that the ID passed to get_block_template matches the expected 'theme_slug//template_slug' format and that the file resides in the expected directory [6][7]. If you are seeing unexpected nulls, it is likely because the internal discovery mechanism is either failing to find the file due to pathing or because the current page request is resolving to a PHP template file, leading WordPress to skip the block template search [9]. Citations:
🌐 Web query:
💡 Result: In WordPress, themes are generally categorized based on their architecture and compatibility with Full Site Editing (FSE). While WordPress recognizes two official types—Classic and Block—the term Hybrid is widely used by the developer community to describe themes that bridge these two approaches [1][2]. wp_is_block_theme The function wp_is_block_theme is a boolean helper introduced in WordPress 5.9.0 [3][4]. It returns true if the active theme is a Block theme and false otherwise [3]. Under the hood, it acts as a wrapper for wp_get_theme->is_block_theme [5][4]. Specifically, it determines if a theme is a block-based theme by checking for the presence of an index.html block template (usually located in /templates/ or /block-templates/) [3][5]. Theme Semantics 1. Block Themes: These are designed for Full Site Editing (FSE) [6]. They use HTML-based block templates (stored in a /templates/ directory) and a theme.json file to manage global styles, settings, and layout [7]. In these themes, the Site Editor is the primary tool for customization, replacing traditional Customizer menus and widgets [7][8]. 2. Classic Themes: These rely on the traditional WordPress structure, utilizing PHP template files (e.g., index.php, single.php) and the WordPress Customizer for site-wide settings [6][7]. While they support the block editor for post/page content, they do not use block-based site templates [7]. 3. Hybrid Themes: This is a non-official, community-recognized category [1][9]. A hybrid theme is essentially a classic theme that has adopted selected block features [2]. These themes maintain a classic PHP-based structure but incorporate modern elements such as theme.json, block patterns, or block-based template parts [1][2]. This allows developers to offer modern design flexibility while retaining the stability and specific workflows (like the Customizer) associated with classic themes [10][6]. Summary Table Theme Type | Core Architecture | Primary Customization | FSE Support --- | --- | --- | --- Block | HTML Block Templates | Site Editor [7] | Full Classic | PHP Templates [6] | Customizer [7] | None Hybrid | PHP Templates [6] | Customizer + Blocks [6] | Partial [6] Because wp_is_block_theme checks specifically for the presence of block-based template files [3][5], it will return false for both classic and hybrid themes, as neither relies on the full block-template architecture required for a theme to be classified as a Block theme [1][9]. Citations:
Return 🤖 Prompt for AI Agents |
||
| return new \WP_Error( | ||
| 'not_found', | ||
| sprintf( /* translators: %s: template id */ __( 'Template "%s" not found.', 'gk-block-mcp' ), $id ), | ||
|
|
@@ -375,14 +379,6 @@ public function reset_template( $id, $type = 'wp_template' ) { | |
| return $type; | ||
| } | ||
|
|
||
| if ( ! wp_is_block_theme() ) { | ||
| return new \WP_Error( | ||
| 'classic_theme', | ||
| __( 'Active theme is not a block theme; there are no template overrides to reset.', 'gk-block-mcp' ), | ||
| array( 'status' => 400 ) | ||
| ); | ||
| } | ||
|
|
||
| $id = is_string( $id ) ? sanitize_text_field( $id ) : ''; | ||
| if ( '' === $id ) { | ||
| return new \WP_Error( | ||
|
|
@@ -392,8 +388,16 @@ public function reset_template( $id, $type = 'wp_template' ) { | |
| ); | ||
| } | ||
|
|
||
| // Same resolution-based gate as update_template() — see its comment. | ||
| $template = get_block_template( $id, $type ); | ||
| if ( ! $template ) { | ||
| if ( ! wp_is_block_theme() ) { | ||
| return new \WP_Error( | ||
| 'classic_theme', | ||
| __( 'Active theme is not a block theme; there are no template overrides to reset.', 'gk-block-mcp' ), | ||
| array( 'status' => 400 ) | ||
| ); | ||
| } | ||
| return new \WP_Error( | ||
| 'not_found', | ||
| sprintf( /* translators: %s: template id */ __( 'Template "%s" not found.', 'gk-block-mcp' ), $id ), | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -95,6 +95,25 @@ private function find_block_theme() { | |
| return null; | ||
| } | ||
|
|
||
| /** | ||
| * Register the fixture theme directory containing "hybrid-theme" (a | ||
| * theme with templates/ and parts/ files but no templates/index.html, | ||
| * so wp_is_block_theme() is false). A separate root from | ||
| * ensure_theme_root_resolvable()'s dummy one; by the time it's | ||
| * registered the "more than one root" workaround already applies, so | ||
| * this one just needs to contain the fixture. | ||
| * | ||
| * @return void | ||
| */ | ||
| private function register_hybrid_theme_root() { | ||
| register_theme_directory( dirname( __DIR__ ) . '/fixtures/themes' ); | ||
| // search_theme_directories() memoizes its scan in a function-local | ||
| // static for the rest of the process; by this point in the run | ||
| // something has always already forced that memoization without | ||
| // this root, so appending it here is invisible until forced. | ||
| wp_clean_themes_cache(); | ||
| } | ||
|
Comment on lines
+98
to
+115
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Keep changed PHP comments limited to current behavior and contracts.
As per coding guidelines, “Comments and docblocks must document current behavior and hard contracts” and must omit historical journals and off-tree references. 📍 Affects 2 files
🤖 Prompt for AI AgentsSource: Coding guidelines |
||
|
|
||
| /** | ||
| * Find a formatted template row by slug. | ||
| * | ||
|
|
@@ -294,4 +313,39 @@ public function test_get_template_invalid_type_returns_error() { | |
| $this->assertInstanceOf( \WP_Error::class, $result ); | ||
| $this->assertSame( 'invalid_type', $result->get_error_code() ); | ||
| } | ||
|
|
||
| // ── get_templates(): hybrid theme ───────────────────────────────── | ||
|
|
||
| /** | ||
| * A theme can have real templates and parts on disk without satisfying | ||
| * wp_is_block_theme() (which checks specifically for templates/index.html | ||
| * or block-templates/index.html). The old unconditional | ||
| * `! wp_is_block_theme()` short-circuit hid those templates/parts | ||
| * entirely and printed a note claiming none exist. | ||
| */ | ||
| public function test_get_templates_hybrid_theme_lists_real_templates_and_parts() { | ||
| $this->register_hybrid_theme_root(); | ||
| switch_theme( 'hybrid-theme' ); | ||
| $this->assertFalse( wp_is_block_theme(), 'Fixture must reproduce wp_is_block_theme() === false to exercise the hybrid case.' ); | ||
|
|
||
| $templates = $this->tm->get_templates( array( 'type' => 'wp_template' ) ); | ||
| $this->assertNotNull( $this->find_by_slug( $templates['templates'], 'single' ) ); | ||
| $this->assertArrayNotHasKey( 'note', $templates ); | ||
|
|
||
| $parts = $this->tm->get_templates( array( 'type' => 'wp_template_part' ) ); | ||
| $this->assertNotNull( $this->find_by_slug( $parts['templates'], 'footer' ) ); | ||
| $this->assertArrayNotHasKey( 'note', $parts ); | ||
| } | ||
|
|
||
| /** | ||
| * The note is informational, not a blanket "any empty result" flag: an | ||
| * empty result on a real block theme (e.g. an area filter matching | ||
| * nothing) must not carry a "not a block theme" note that isn't true. | ||
| */ | ||
| public function test_get_templates_full_block_theme_empty_result_has_no_note() { | ||
| $result = $this->tm->get_templates( array( 'type' => 'wp_template_part', 'area' => 'no-such-area' ) ); | ||
|
|
||
| $this->assertSame( array(), $result['templates'] ); | ||
| $this->assertArrayNotHasKey( 'note', $result ); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -101,6 +101,19 @@ private function find_block_theme() { | |||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||
| * Register the fixture theme directory containing "hybrid-theme". See | ||||||||||||||||||||||||
| * TemplateManagerTest::register_hybrid_theme_root() for the rationale. | ||||||||||||||||||||||||
| * | ||||||||||||||||||||||||
| * @return void | ||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||
| private function register_hybrid_theme_root() { | ||||||||||||||||||||||||
| register_theme_directory( dirname( __DIR__ ) . '/fixtures/themes' ); | ||||||||||||||||||||||||
| // See TemplateManagerTest::register_hybrid_theme_root() — forces | ||||||||||||||||||||||||
| // search_theme_directories()'s memoized scan to pick this root up. | ||||||||||||||||||||||||
| wp_clean_themes_cache(); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // ── Gate ─────────────────────────────────────────────────────────── | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||
|
|
@@ -473,4 +486,74 @@ public function test_update_template_rolls_back_new_override_when_area_term_assi | |||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
| $this->assertCount( 0, $matching->posts, 'A term-assignment failure must not leave an orphaned override post behind.' ); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // ── Hybrid theme (wp_is_block_theme() false, but a part resolves) ─── | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||
| * A hybrid theme's template part resolves via get_block_template(), | ||||||||||||||||||||||||
| * so a gated write against it must succeed — the old unconditional | ||||||||||||||||||||||||
| * `! wp_is_block_theme()` 400 guard blocked this even though the part | ||||||||||||||||||||||||
| * genuinely renders on such a site. | ||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||
| public function test_update_template_creates_override_for_hybrid_theme_template_part() { | ||||||||||||||||||||||||
| update_option( Template_Manager::ALLOW_TEMPLATE_EDITS_OPTION, '1' ); | ||||||||||||||||||||||||
| $this->register_hybrid_theme_root(); | ||||||||||||||||||||||||
| switch_theme( 'hybrid-theme' ); | ||||||||||||||||||||||||
| $this->assertFalse( wp_is_block_theme(), 'Fixture must reproduce wp_is_block_theme() === false to exercise the hybrid case.' ); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| $result = $this->tm->update_template( | ||||||||||||||||||||||||
| 'hybrid-theme//footer', | ||||||||||||||||||||||||
| 'wp_template_part', | ||||||||||||||||||||||||
| array( 'content' => '<!-- wp:paragraph --><p>Overridden footer</p><!-- /wp:paragraph -->' ) | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| $this->assertIsArray( $result ); | ||||||||||||||||||||||||
| $this->assertTrue( $result['success'] ); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| $fetched = $this->tm->get_template( 'hybrid-theme//footer', 'wp_template_part' ); | ||||||||||||||||||||||||
| $this->assertSame( 'custom', $fetched['source'] ); | ||||||||||||||||||||||||
| $this->assertStringContainsString( 'Overridden footer', $fetched['content'] ); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||
| * reset_template must be gated the same way — resolution, not | ||||||||||||||||||||||||
| * wp_is_block_theme() — so it can revert the override this test just | ||||||||||||||||||||||||
| * created on a hybrid theme. | ||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||
| public function test_reset_template_reverts_hybrid_theme_override() { | ||||||||||||||||||||||||
| update_option( Template_Manager::ALLOW_TEMPLATE_EDITS_OPTION, '1' ); | ||||||||||||||||||||||||
| $this->register_hybrid_theme_root(); | ||||||||||||||||||||||||
| switch_theme( 'hybrid-theme' ); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| $updated = $this->tm->update_template( | ||||||||||||||||||||||||
| 'hybrid-theme//footer', | ||||||||||||||||||||||||
| 'wp_template_part', | ||||||||||||||||||||||||
| array( 'content' => '<!-- wp:paragraph --><p>Overridden</p><!-- /wp:paragraph -->' ) | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
| $this->assertTrue( $updated['success'] ); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| $reset = $this->tm->reset_template( 'hybrid-theme//footer', 'wp_template_part' ); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| $this->assertIsArray( $reset ); | ||||||||||||||||||||||||
| $this->assertTrue( $reset['success'] ); | ||||||||||||||||||||||||
| $this->assertNull( get_post( $updated['wp_id'] ) ); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||
| * Unchanged regression: a genuinely classic theme (no templates/parts | ||||||||||||||||||||||||
| * at all) still gets the specific, actionable "classic_theme" 400 — | ||||||||||||||||||||||||
| * proves the resolution-based gate doesn't regress into a generic | ||||||||||||||||||||||||
| * not_found for the case that guard exists to make clearer. | ||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||
| public function test_update_template_classic_theme_still_returns_400_when_nothing_resolves() { | ||||||||||||||||||||||||
| update_option( Template_Manager::ALLOW_TEMPLATE_EDITS_OPTION, '1' ); | ||||||||||||||||||||||||
| switch_theme( 'default' ); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| $result = $this->tm->update_template( 'default//does-not-exist', 'wp_template', array( 'content' => '<!-- wp:paragraph --><p>x</p><!-- /wp:paragraph -->' ) ); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| $this->assertInstanceOf( \WP_Error::class, $result ); | ||||||||||||||||||||||||
| $this->assertSame( 'classic_theme', $result->get_error_code() ); | ||||||||||||||||||||||||
| $data = $result->get_error_data(); | ||||||||||||||||||||||||
| $this->assertSame( 400, $data['status'] ); | ||||||||||||||||||||||||
|
Comment on lines
+554
to
+557
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Narrow PHPStan still sees Proposed fix- $this->assertInstanceOf( \WP_Error::class, $result );
+ if ( ! $result instanceof \WP_Error ) {
+ $this->fail( 'Expected a classic_theme error.' );
+ return;
+ }
$this->assertSame( 'classic_theme', $result->get_error_code() );📝 Committable suggestion
Suggested change
🧰 Tools🪛 PHPStan (2.2.5)[error] 555-555: Cannot call method get_error_code() on array|WP_Error. (method.nonObject) [error] 556-556: Cannot call method get_error_data() on array|WP_Error. (method.nonObject) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| <!-- wp:paragraph --> | ||
| <p>Hybrid Footer Part</p> | ||
| <!-- /wp:paragraph --> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| /* | ||
| Theme Name: Hybrid Theme | ||
| Theme URI: https://wordpress.org/ | ||
| Description: For testing purposes only — a "hybrid" theme with no templates/index.html or block-templates/index.html (so wp_is_block_theme() is false) but real files under templates/ and parts/ (so get_block_templates() still finds them). | ||
| Version: 1.0.0 | ||
| Text Domain: hybrid-theme | ||
| */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| <!-- wp:paragraph --> | ||
| <p>Hybrid Single Template</p> | ||
| <!-- /wp:paragraph --> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Clarify the
wp_idcontract.The PHP formatter exposes
wp_idwhenever the resolved template has that property; it does not requirehas_theme_file. Describing it as non-null only when an override shadows a theme file overstates the guarantee. Say that it identifies a database-backed template or override.Based on
Template_Manager::format_template_summary(),wp_idis independent of thehas_theme_filefield.🤖 Prompt for AI Agents