Skip to content

Template Part: Fix boolean operator in description fallback - #86102

Merged
westonruter merged 14 commits into
WordPress:trunkfrom
noruzzamans:fix/phpstan-template-part-description
Nov 7, 2026
Merged

westonruter merged 14 commits into
WordPress:trunkfrom
noruzzamans:fix/phpstan-template-part-description

Conversation

@noruzzamans

Copy link
Copy Markdown
Member

What?

See #86088

Replaces the boolean || operator with a ternary check in build_template_part_block_instance_variations() for the template part description fallback, and removes the resolved entry from the PHPStan baseline.

Why?

In PHP, 'description' => $template_part->description || ' ' evaluates the right side of || as a boolean operator, resulting in true (a boolean) rather than the template part's actual description or the non-breaking space fallback string. PHPStan flags this with booleanOr.rightAlwaysTrue.

Using a proper ternary fallback ! empty( $template_part->description ) ? $template_part->description : ' ' preserves the actual description string when available and only falls back to ' ' when empty. This resolves 1 of the errors initially baselined in #66693.

How?

  • Updated packages/block-library/src/template-part/index.php to use ! empty( $template_part->description ) ? $template_part->description : ' '.
  • Removed the corresponding booleanOr.rightAlwaysTrue entry for packages/block-library/src/template-part/index.php from tools/phpstan/baseline.neon.

Testing Instructions

  1. Run composer phpstan and confirm it passes with no unmatched ignored errors.
  2. Run composer phpstan:baselines and confirm tools/phpstan/baseline.neon has no further changes.
  3. Smoke test on the front end / editor:
    • Insert a Template Part block in the site editor.
    • Verify that existing template part variations display their titles and descriptions properly in the modal/inserter.

Testing Instructions for Keyboard

Not applicable. There are no UI changes.

Screenshots or screencast

Not applicable.

Use of AI Tools

I used Claude Code to identify the affected occurrence and draft the change. I reviewed the diff and take responsibility for it.

@github-actions github-actions Bot added the [Package] Block library /packages/block-library label Nov 1, 2026
@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

🤖 PR meta 🤖

Preview in WordPress Playground

🎉 Props

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: noruzzamans <noruzzaman@git.wordpress.org>
Co-authored-by: westonruter <westonruter@git.wordpress.org>
Co-authored-by: Deepak-Bhojwani <deepakbhojwani@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.


Props Bot commands

You can trigger Props Bot actions by commenting on this PR:

  • @propsbot add <username> to give props to a GitHub user. Requires write access.
  • @propsbot remove <username> to leave a user out of the props. Requires write access.
  • @propsbot refresh to refresh this list. Adding the props-bot label works too.

Updated as activity occurs, without notifying anyone named here. Add the props-bot label to refresh.

@huzaifaalmesbah huzaifaalmesbah added [Type] Code Quality Issues or PRs that relate to code quality props-bot Manually triggers Props Bot to ensure the list of props is up to date. labels Nov 1, 2026
@github-actions github-actions Bot removed the props-bot Manually triggers Props Bot to ensure the list of props is up to date. label Nov 1, 2026
@noruzzamans
noruzzamans force-pushed the fix/phpstan-template-part-description branch from 72d84b8 to 6dcbc53 Compare November 3, 2026 04:54

@westonruter westonruter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense. It was seemingly committed thinking of the behavior in JavaScript, but PHP behaves differently: https://3v4l.org/ihhLU#v8.5.11

westonruter and others added 2 commits November 3, 2026 00:56
Resolves the conflict in tools/phpstan/baseline.neon by regenerating it with `composer phpstan:baselines` on the merged tree.

Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com>
Claude-Code-Session-Id: f6bd014a-b8bb-45fb-a7bb-f386806f2350
…ack.

The description is rendered as React text, not HTML, so the `&nbsp;` entity would be shown literally as six characters in the block card and inserter preview of any template part without a description, and would also make every such template part match an inserter search for "nbsp". A U+00A0 character keeps the value non-falsy, which is what prevents the fallback to the block's own description, while rendering as blank.

Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com>
Claude-Code-Session-Id: f6bd014a-b8bb-45fb-a7bb-f386806f2350
@westonruter

Copy link
Copy Markdown
Member

🤖 Comment by Claude Opus 5.5 · medium effort

Two commits were pushed to this branch:

  • 89ec6a5 merges trunk and resolves the conflict in tools/phpstan/baseline.neon by regenerating it with composer phpstan:baselines on the merged tree. The result differs from trunk only by the removed booleanOr.rightAlwaysTrue entry for template-part/index.php.
  • d4899fb changes the fallback from the '&nbsp;' entity to a real non-breaking space, "\u{00A0}" (see the first finding below).

Review

The fix is correct in intent: $template_part->description || '&nbsp;' always evaluated to boolean true, so template part descriptions never reached the editor. Since React renders nothing for true, the bug was invisible. Fixing it, however, changes what users see, which surfaced the findings below.

1. The &nbsp; entity would be shown literally (fixed in d4899fb)

With the ternary, a template part without a description sent the six-character string &nbsp; to the client. The description is rendered as React text, not HTML ({ description } in packages/block-editor/src/components/block-card/index.tsx, and in the inserter preview panel), so &nbsp; would appear verbatim under the title in the block sidebar and inserter preview. Previously the boolean true rendered as nothing. A U+00A0 character keeps the value non-falsy (which is what prevents the fallback to the block's own description) while rendering as blank.

2. Inserter search matched the placeholder (fixed in d4899fb)

search-items.ts ranks matches on item.description with SEARCH_RANK.CONTAINS. With &nbsp; as the description, searching for "nbsp" (or even "bs") would list every template part lacking a description. The U+00A0 character resolves this as well.

3. Descriptions are not entity-decoded

Template part descriptions now reach the client for the first time, but unlike the title (which goes through decodeEntities() in packages/block-library/src/template-part/index.js), the description is not decoded. A description stored as Header &amp; navigation would be displayed with the literal &amp;. Decoding it alongside the title on the client may be worth considering.

4. Edge cases in the ! empty() check

! empty() treats a description of "0" as missing and replaces it with the placeholder, while a whitespace-only description passes the check and shows an apparently empty description. '' !== trim( $template_part->description ) would match the intent more precisely, though these are minor.

5. The underlying cause is the client-side fallback

The placeholder exists only because packages/block-editor/src/components/use-block-display-information/index.ts uses match.description || blockType.description, so any falsy variation description falls back to the parent block's description. The code comment itself calls the workaround hacky. Changing that to match.description ?? blockType.description and sending '' from PHP would remove the special case entirely. That touches shared infrastructure, so it is likely better as a follow-up than as part of this PR.

6. No CHANGELOG entry or test

Since template part descriptions will now be visible in the editor where they were not before, this affects users, and per the repo guidelines a short entry in packages/block-library/CHANGELOG.md is warranted. There is also no PHPUnit coverage of the description returned by build_template_part_block_instance_variations(), which is how the boolean bug went unnoticed; a test asserting both the real-description and the empty-description cases would guard against regressions.

@westonruter westonruter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on Claude's findings, I'm changing to request changes.

@noruzzamans

Copy link
Copy Markdown
Member Author

I have added the unit test coverage and changelog entry per the review findings:

  1. Added test_build_template_part_block_instance_variations_description to phpunit/blocks/render-template-part-test.php, asserting that template parts with descriptions retain their string and template parts with empty descriptions fall back to \u{00A0}.
  2. Hardened the description presence check with isset( $template_part->description ) && '' !== trim( (string) $template_part->description ) to cleanly handle whitespace and string edge cases.
  3. Added a changelog entry to packages/block-library/CHANGELOG.md under Bug Fixes.

@noruzzamans

Copy link
Copy Markdown
Member Author

I have pushed an update addressing the CI failures:

  1. PHPStan: Switched the description presence check to '' !== trim( $template_part->description ) instead of isset(), since WP_Block_Template::$description is non-nullable in the stubs.
  2. Unit Tests / PHP 8.5: Explicitly assigned the wp_template_part_area taxonomy term in the test fixture and guarded $template_part->area ?? '' against null to avoid the PHP 8.5 null array offset deprecation.
  3. Changelog validation: Removed the blank line inside the bug fixes list in packages/block-library/CHANGELOG.md.

@Deepak-Bhojwani Deepak-Bhojwani left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested this locally against current trunk (6504787).

The branch conflicts with trunk in tools/phpstan/baseline.neon and packages/block-library/CHANGELOG.md. To test, I merged it into trunk, kept trunk's versions of both files, and ran composer phpstan:baselines:

  • The only change to the baseline from trunk is the removal of the booleanOr.rightAlwaysTrue entry for template-part/index.php, with no new errors.
  • composer phpstan then passes with no errors and no unmatched ignored errors.

On the code:

  • '' !== trim( $template_part->description ) is safe without a cast, since WP_Block_Template::$description is declared as string with a default of ''.
  • $template_part->area ?? '' is justified, since WP_Block_Template::$area is string|null.

One point from the earlier review that still seems open is #3: the description now reaches the client for the first time, but unlike the title, it is not passed through decodeEntities() in packages/block-library/src/template-part/index.js. A description like Header &amp; navigation would be shown with the literal entity. That could be handled here or in a follow-up.

The CHANGELOG.md entry will also need to be moved when resolving the conflict, since new entries have been added under Bug Fixes on trunk.

Environment: Windows 11, PHP 8.2.29, Composer 2.11.1, stubs generated from wordpress-develop@27307a20f9ba. I did not run the new PHPUnit test, since I don't have wp-env available here.

noruzzamans and others added 9 commits November 7, 2026 20:26
Resolve the conflict in tools/phpstan/baseline.neon by keeping the removals from both sides: trunk dropped the navigation, CSS rules store, and style engine entries, while this branch dropped the template part entry.

Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com>
Claude-Code-Session-Id: ce1705f2-5544-4c8e-842a-9ada9a5d974c
The template part variation description test adds the theme support, but the base test case's tear_down() does not restore theme features, so the support leaked into every later test in the run.

Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com>
Claude-Code-Session-Id: ce1705f2-5544-4c8e-842a-9ada9a5d974c
The @ticket annotation refers to a Core Trac ticket, so a Gutenberg PR number there points at an unrelated ticket.

Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com>
Claude-Code-Session-Id: ce1705f2-5544-4c8e-842a-9ada9a5d974c
The fallback to Core's unprefixed build_template_part_block_instance_variations() could only run when the plugin's build is missing, and then it would test Core's copy, which still has the buggy || operator, instead of the plugin's code. Calling the gutenberg_-prefixed function directly makes a missing build fail loudly, matching the other tests in phpunit/blocks.

Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com>
Claude-Code-Session-Id: ce1705f2-5544-4c8e-842a-9ada9a5d974c
Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com>
Claude-Code-Session-Id: ce1705f2-5544-4c8e-842a-9ada9a5d974c
The description check trims the value, so a description made only of whitespace also falls back to a non-breaking space. Cover that case, and assert that wp_insert_post() stores the whitespace excerpt unchanged, so the test keeps exercising the trim.

Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com>
Claude-Code-Session-Id: ce1705f2-5544-4c8e-842a-9ada9a5d974c
Say what changes for users, that template part descriptions now show in the inserter, rather than describing the boolean operator in the code.

Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com>
Claude-Code-Session-Id: ce1705f2-5544-4c8e-842a-9ada9a5d974c
@westonruter
westonruter merged commit e37bcfc into WordPress:trunk Nov 7, 2026
82 checks passed
@github-actions github-actions Bot added this to the Gutenberg 24.5 milestone Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Package] Block library /packages/block-library [Type] Code Quality Issues or PRs that relate to code quality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants