Skip to content
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 applying bindings or pattern overrides to button blocks with empty text #62220

Merged
merged 8 commits into from
Jun 10, 2024

Conversation

talldan
Copy link
Contributor

@talldan talldan commented Jun 3, 2024

What?

Fixes #61303

An issue for block bindings and pattern overrides is when a button block's text is left empty, the editor saves no html due to a conditional return in the block's save function.

When a binding tries dynamically to update a button block in this state, it won't be able to due to the missing content.

This PR changes the button block so that the conditional rendering is implemented dynamically on the server. This allows block bindings to dynamically change the content of the block, even when there's empty text.

How?

Uses the tag processor to check for inner content.

The text of a button block is a sourced attribute, so the sever is unable to parse the attribute value, so it needs to be read from the content.

Testing Instructions

  1. Create a synced pattern with an empty button block (no text defined)
  2. Allow overrides for the button block
  3. Save the pattern
  4. Create a new post and insert the pattern you just created
  5. Enter some text into the button
  6. Preview the post

Expected: The button should appear with the override text.

As a general smoke test, it's also worth checking that buttons outside of patterns continue to work as expected when they have and do not have text.

You should also be able to add a button that has text to a pattern, and then override it with no text, and it won't render in the frontend

Screenshots or screencast

Editor

Screenshot 2024-06-03 at 4 26 47 pm

Frontend

Screenshot 2024-06-03 at 4 27 58 pm

@talldan talldan added [Type] Bug An existing feature does not function as intended [Block] Buttons Affects the Buttons Block [Feature] Block bindings labels Jun 3, 2024
@talldan talldan self-assigned this Jun 3, 2024
Copy link

github-actions bot commented Jun 3, 2024

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

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: talldan <talldanwp@git.wordpress.org>
Co-authored-by: dmsnell <dmsnell@git.wordpress.org>
Co-authored-by: kevin940726 <kevin940726@git.wordpress.org>
Co-authored-by: SantosGuillamot <santosguillamot@git.wordpress.org>

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

Copy link

github-actions bot commented Jun 3, 2024

This pull request has changed or added PHP files. Please confirm whether these changes need to be synced to WordPress Core, and therefore featured in the next release of WordPress.

If so, it is recommended to create a new Trac ticket and submit a pull request to the WordPress Core Github repository soon after this pull request is merged.

If you're unsure, you can always ask for help in the #core-editor channel in WordPress Slack.

Thank you! ❤️

View changed files
❔ packages/block-library/src/button/index.php
❔ lib/blocks.php

Comment on lines 20 to 53
$p = new WP_HTML_Tag_Processor( $content );

/*
* The button block can render an `<a>` or `<button>` and also has a
* `<div>` wrapper. Find the a or button tag.
*
*/
$tag = null;
while ( $p->next_tag() ) {
$tag = $p->get_tag();
if ( 'A' === $tag || 'BUTTON' === $tag ) {
break;
}
}

// If this happens, the likelihood is there's no block content.
if ( null === $tag ) {
return '';
}

// Build a string of the inner text.
$text = '';
while ( $p->next_token() ) {
switch ( $p->get_token_name() ) {
case '#text':
$text .= $p->get_modifiable_text();
break;

case 'BR':
$text .= '';
break;
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I haven't written a lot of tag processor code, so would be happy to receive feedback on this.

Copy link
Member

Choose a reason for hiding this comment

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

this is great @talldan! here are some thoughts. it looks like you're attempting to remove all content inside the button except for the plain text content. that is, no formatting, no spans, no inline images, etc… I don't speak to whether that's a great idea or not, but I can provide feedback for the HTML API use in doing so.

first of all, this is technically the domain of the HTML Processor, which knows HTML structure, but since that's not really ready yet this will suffice. you did the right thing using the Tag Processor.

this code, however, is going to grab only the first text nodeat the start of the A or BUTTON. Maybe we don't expect any other content, but if you want to (unreliably) limit it to the inner contents, then you can add one more step which would improve the reliability a little bit and capture more text.

// Build a string of the inner text.
$text = '';
while ( $p->next_token() ) {
	switch ( $p->get_token_name() ) {
		/*
         * Neither `A` nor `BUTTON` can nest, so it doesn't matter
         * if these are opening or closing tags. Both will close
         * the open element.
         */
		case $tag:
			break;

		case '#text':
			$text .= $p->get_modifiable_text();
			continue;

		case 'BR':
			$text .= "\n";
			continue;
	}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

case $tag:
break;

Thanks for the feedback! Should this also break out of the while loop in addition to the switch? I believe in PHP break 2 can be used to break two levels, but I might change it from a switch to an if statement.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it looks like you're attempting to remove all content inside the button except for the plain text content. that is, no formatting, no spans, no inline images, etc… I don't speak to whether that's a great idea or not, but I can provide feedback for the HTML API use in doing so.

The goal in this PR is for the replace the old static implementation (removed in this PR):

if ( RichText.isEmpty( text ) ) {
return null;
}

Retaining the HTML from the save function allows for bindings to work with empty buttons.

It looks like the conditional logic introduced as a result of this issue - #17221.

It's not an accessibility reason. How many years have I incorrectly believed that?! I'll update the comment in the code.

Copy link
Contributor Author

@talldan talldan Jun 4, 2024

Choose a reason for hiding this comment

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

I did some further testing and realized there's also the case of inline images. I've now simplified the code down to just this:

// If the next token is the closing tag, the button is empty.
$p->next_token();
$is_empty = $p->get_token_name() === $tag;

if ( $is_empty ) {
	return '';
}

Which should better match how RichText.isEmpty works (even a space is considered content) - https://github.com/WordPress/gutenberg/blob/trunk/packages/rich-text/src/is-empty.js.

I should've endeavoured to match that implementation first.

Anything I might be overlooking here? I'll work on adding some tests for this.

Copy link
Member

Choose a reason for hiding this comment

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

It's probably good enough, but keep in mind that there could be comments in there too.

$is_empty = true;
while ( $p->next_token() && $tag !== $p->get_token_name() && $is_empty ) {
	if ( '#comment' !== $p->get_token_type() ) {
		// Anything else implies this is not empty.
		$is_empty = false;
	}
}

@talldan talldan added the No Core Sync Required Indicates that any changes do not need to be synced to WordPress Core label Jun 3, 2024
@talldan talldan changed the title Update button block conditional rendering to be dynamic Fix applying bindings or pattern overrides to button blocks with empty text Jun 3, 2024
Copy link

github-actions bot commented Jun 3, 2024

Size Change: -11 B (0%)

Total Size: 1.75 MB

Filename Size Change
build/block-library/index.min.js 219 kB -11 B (-0.01%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 951 B
build/annotations/index.min.js 2.26 kB
build/api-fetch/index.min.js 2.31 kB
build/autop/index.min.js 2.12 kB
build/blob/index.min.js 579 B
build/block-directory/index.min.js 7.31 kB
build/block-directory/style-rtl.css 1.02 kB
build/block-directory/style.css 1.02 kB
build/block-editor/content-rtl.css 4.57 kB
build/block-editor/content.css 4.57 kB
build/block-editor/default-editor-styles-rtl.css 394 B
build/block-editor/default-editor-styles.css 394 B
build/block-editor/index.min.js 263 kB
build/block-editor/style-rtl.css 15.6 kB
build/block-editor/style.css 15.6 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 149 B
build/block-library/blocks/audio/editor.css 151 B
build/block-library/blocks/audio/style-rtl.css 125 B
build/block-library/blocks/audio/style.css 125 B
build/block-library/blocks/audio/theme-rtl.css 126 B
build/block-library/blocks/audio/theme.css 126 B
build/block-library/blocks/avatar/editor-rtl.css 115 B
build/block-library/blocks/avatar/editor.css 115 B
build/block-library/blocks/avatar/style-rtl.css 104 B
build/block-library/blocks/avatar/style.css 104 B
build/block-library/blocks/button/editor-rtl.css 310 B
build/block-library/blocks/button/editor.css 310 B
build/block-library/blocks/button/style-rtl.css 538 B
build/block-library/blocks/button/style.css 538 B
build/block-library/blocks/buttons/editor-rtl.css 336 B
build/block-library/blocks/buttons/editor.css 336 B
build/block-library/blocks/buttons/style-rtl.css 328 B
build/block-library/blocks/buttons/style.css 328 B
build/block-library/blocks/calendar/style-rtl.css 240 B
build/block-library/blocks/calendar/style.css 240 B
build/block-library/blocks/categories/editor-rtl.css 113 B
build/block-library/blocks/categories/editor.css 112 B
build/block-library/blocks/categories/style-rtl.css 124 B
build/block-library/blocks/categories/style.css 124 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 121 B
build/block-library/blocks/code/style.css 121 B
build/block-library/blocks/code/theme-rtl.css 122 B
build/block-library/blocks/code/theme.css 122 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 420 B
build/block-library/blocks/columns/style.css 420 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 124 B
build/block-library/blocks/comment-author-avatar/editor.css 124 B
build/block-library/blocks/comment-content/style-rtl.css 90 B
build/block-library/blocks/comment-content/style.css 90 B
build/block-library/blocks/comment-template/style-rtl.css 200 B
build/block-library/blocks/comment-template/style.css 199 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 221 B
build/block-library/blocks/comments-pagination/editor.css 211 B
build/block-library/blocks/comments-pagination/style-rtl.css 234 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 832 B
build/block-library/blocks/comments/editor.css 832 B
build/block-library/blocks/comments/style-rtl.css 632 B
build/block-library/blocks/comments/style.css 631 B
build/block-library/blocks/cover/editor-rtl.css 668 B
build/block-library/blocks/cover/editor.css 669 B
build/block-library/blocks/cover/style-rtl.css 1.62 kB
build/block-library/blocks/cover/style.css 1.6 kB
build/block-library/blocks/details/editor-rtl.css 65 B
build/block-library/blocks/details/editor.css 65 B
build/block-library/blocks/details/style-rtl.css 86 B
build/block-library/blocks/details/style.css 86 B
build/block-library/blocks/embed/editor-rtl.css 314 B
build/block-library/blocks/embed/editor.css 314 B
build/block-library/blocks/embed/style-rtl.css 411 B
build/block-library/blocks/embed/style.css 411 B
build/block-library/blocks/embed/theme-rtl.css 126 B
build/block-library/blocks/embed/theme.css 126 B
build/block-library/blocks/file/editor-rtl.css 326 B
build/block-library/blocks/file/editor.css 326 B
build/block-library/blocks/file/style-rtl.css 278 B
build/block-library/blocks/file/style.css 279 B
build/block-library/blocks/file/view.min.js 324 B
build/block-library/blocks/footnotes/style-rtl.css 198 B
build/block-library/blocks/footnotes/style.css 197 B
build/block-library/blocks/form-input/editor-rtl.css 229 B
build/block-library/blocks/form-input/editor.css 229 B
build/block-library/blocks/form-input/style-rtl.css 342 B
build/block-library/blocks/form-input/style.css 342 B
build/block-library/blocks/form-submission-notification/editor-rtl.css 344 B
build/block-library/blocks/form-submission-notification/editor.css 341 B
build/block-library/blocks/form-submit-button/style-rtl.css 69 B
build/block-library/blocks/form-submit-button/style.css 69 B
build/block-library/blocks/form/view.min.js 470 B
build/block-library/blocks/freeform/editor-rtl.css 2.6 kB
build/block-library/blocks/freeform/editor.css 2.6 kB
build/block-library/blocks/gallery/editor-rtl.css 958 B
build/block-library/blocks/gallery/editor.css 962 B
build/block-library/blocks/gallery/style-rtl.css 1.71 kB
build/block-library/blocks/gallery/style.css 1.71 kB
build/block-library/blocks/gallery/theme-rtl.css 108 B
build/block-library/blocks/gallery/theme.css 108 B
build/block-library/blocks/group/editor-rtl.css 402 B
build/block-library/blocks/group/editor.css 402 B
build/block-library/blocks/group/style-rtl.css 103 B
build/block-library/blocks/group/style.css 103 B
build/block-library/blocks/group/theme-rtl.css 79 B
build/block-library/blocks/group/theme.css 79 B
build/block-library/blocks/heading/style-rtl.css 188 B
build/block-library/blocks/heading/style.css 188 B
build/block-library/blocks/html/editor-rtl.css 346 B
build/block-library/blocks/html/editor.css 347 B
build/block-library/blocks/image/editor-rtl.css 890 B
build/block-library/blocks/image/editor.css 889 B
build/block-library/blocks/image/style-rtl.css 1.52 kB
build/block-library/blocks/image/style.css 1.51 kB
build/block-library/blocks/image/theme-rtl.css 137 B
build/block-library/blocks/image/theme.css 137 B
build/block-library/blocks/image/view.min.js 1.54 kB
build/block-library/blocks/latest-comments/style-rtl.css 355 B
build/block-library/blocks/latest-comments/style.css 354 B
build/block-library/blocks/latest-posts/editor-rtl.css 204 B
build/block-library/blocks/latest-posts/editor.css 204 B
build/block-library/blocks/latest-posts/style-rtl.css 509 B
build/block-library/blocks/latest-posts/style.css 510 B
build/block-library/blocks/list/style-rtl.css 104 B
build/block-library/blocks/list/style.css 104 B
build/block-library/blocks/media-text/editor-rtl.css 304 B
build/block-library/blocks/media-text/editor.css 303 B
build/block-library/blocks/media-text/style-rtl.css 506 B
build/block-library/blocks/media-text/style.css 504 B
build/block-library/blocks/more/editor-rtl.css 427 B
build/block-library/blocks/more/editor.css 427 B
build/block-library/blocks/navigation-link/editor-rtl.css 663 B
build/block-library/blocks/navigation-link/editor.css 664 B
build/block-library/blocks/navigation-link/style-rtl.css 192 B
build/block-library/blocks/navigation-link/style.css 191 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 295 B
build/block-library/blocks/navigation-submenu/editor.css 294 B
build/block-library/blocks/navigation/editor-rtl.css 2.22 kB
build/block-library/blocks/navigation/editor.css 2.23 kB
build/block-library/blocks/navigation/style-rtl.css 2.25 kB
build/block-library/blocks/navigation/style.css 2.24 kB
build/block-library/blocks/navigation/view.min.js 1.03 kB
build/block-library/blocks/nextpage/editor-rtl.css 392 B
build/block-library/blocks/nextpage/editor.css 392 B
build/block-library/blocks/page-list/editor-rtl.css 378 B
build/block-library/blocks/page-list/editor.css 378 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 236 B
build/block-library/blocks/paragraph/editor.css 236 B
build/block-library/blocks/paragraph/style-rtl.css 341 B
build/block-library/blocks/paragraph/style.css 340 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 506 B
build/block-library/blocks/post-comments-form/style.css 506 B
build/block-library/blocks/post-content/editor-rtl.css 74 B
build/block-library/blocks/post-content/editor.css 74 B
build/block-library/blocks/post-date/style-rtl.css 62 B
build/block-library/blocks/post-date/style.css 62 B
build/block-library/blocks/post-excerpt/editor-rtl.css 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-excerpt/style-rtl.css 141 B
build/block-library/blocks/post-excerpt/style.css 141 B
build/block-library/blocks/post-featured-image/editor-rtl.css 729 B
build/block-library/blocks/post-featured-image/editor.css 726 B
build/block-library/blocks/post-featured-image/style-rtl.css 341 B
build/block-library/blocks/post-featured-image/style.css 341 B
build/block-library/blocks/post-navigation-link/style-rtl.css 215 B
build/block-library/blocks/post-navigation-link/style.css 214 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 399 B
build/block-library/blocks/post-template/style.css 398 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-time-to-read/style-rtl.css 70 B
build/block-library/blocks/post-time-to-read/style.css 70 B
build/block-library/blocks/post-title/style-rtl.css 100 B
build/block-library/blocks/post-title/style.css 100 B
build/block-library/blocks/preformatted/style-rtl.css 125 B
build/block-library/blocks/preformatted/style.css 125 B
build/block-library/blocks/pullquote/editor-rtl.css 134 B
build/block-library/blocks/pullquote/editor.css 134 B
build/block-library/blocks/pullquote/style-rtl.css 342 B
build/block-library/blocks/pullquote/style.css 342 B
build/block-library/blocks/pullquote/theme-rtl.css 167 B
build/block-library/blocks/pullquote/theme.css 167 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 121 B
build/block-library/blocks/query-pagination-numbers/editor.css 118 B
build/block-library/blocks/query-pagination/editor-rtl.css 220 B
build/block-library/blocks/query-pagination/editor.css 208 B
build/block-library/blocks/query-pagination/style-rtl.css 287 B
build/block-library/blocks/query-pagination/style.css 283 B
build/block-library/blocks/query-title/style-rtl.css 64 B
build/block-library/blocks/query-title/style.css 64 B
build/block-library/blocks/query/editor-rtl.css 502 B
build/block-library/blocks/query/editor.css 502 B
build/block-library/blocks/query/view.min.js 958 B
build/block-library/blocks/quote/style-rtl.css 238 B
build/block-library/blocks/quote/style.css 238 B
build/block-library/blocks/quote/theme-rtl.css 221 B
build/block-library/blocks/quote/theme.css 225 B
build/block-library/blocks/read-more/style-rtl.css 138 B
build/block-library/blocks/read-more/style.css 138 B
build/block-library/blocks/rss/editor-rtl.css 101 B
build/block-library/blocks/rss/editor.css 101 B
build/block-library/blocks/rss/style-rtl.css 288 B
build/block-library/blocks/rss/style.css 287 B
build/block-library/blocks/search/editor-rtl.css 183 B
build/block-library/blocks/search/editor.css 183 B
build/block-library/blocks/search/style-rtl.css 684 B
build/block-library/blocks/search/style.css 683 B
build/block-library/blocks/search/theme-rtl.css 113 B
build/block-library/blocks/search/theme.css 113 B
build/block-library/blocks/search/view.min.js 475 B
build/block-library/blocks/separator/editor-rtl.css 100 B
build/block-library/blocks/separator/editor.css 100 B
build/block-library/blocks/separator/style-rtl.css 248 B
build/block-library/blocks/separator/style.css 248 B
build/block-library/blocks/separator/theme-rtl.css 195 B
build/block-library/blocks/separator/theme.css 195 B
build/block-library/blocks/shortcode/editor-rtl.css 286 B
build/block-library/blocks/shortcode/editor.css 286 B
build/block-library/blocks/site-logo/editor-rtl.css 806 B
build/block-library/blocks/site-logo/editor.css 803 B
build/block-library/blocks/site-logo/style-rtl.css 218 B
build/block-library/blocks/site-logo/style.css 218 B
build/block-library/blocks/site-tagline/editor-rtl.css 87 B
build/block-library/blocks/site-tagline/editor.css 87 B
build/block-library/blocks/site-title/editor-rtl.css 123 B
build/block-library/blocks/site-title/editor.css 123 B
build/block-library/blocks/site-title/style-rtl.css 71 B
build/block-library/blocks/site-title/style.css 71 B
build/block-library/blocks/social-link/editor-rtl.css 338 B
build/block-library/blocks/social-link/editor.css 338 B
build/block-library/blocks/social-links/editor-rtl.css 676 B
build/block-library/blocks/social-links/editor.css 675 B
build/block-library/blocks/social-links/style-rtl.css 1.5 kB
build/block-library/blocks/social-links/style.css 1.5 kB
build/block-library/blocks/spacer/editor-rtl.css 346 B
build/block-library/blocks/spacer/editor.css 346 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 394 B
build/block-library/blocks/table/editor.css 394 B
build/block-library/blocks/table/style-rtl.css 640 B
build/block-library/blocks/table/style.css 639 B
build/block-library/blocks/table/theme-rtl.css 145 B
build/block-library/blocks/table/theme.css 145 B
build/block-library/blocks/tag-cloud/style-rtl.css 266 B
build/block-library/blocks/tag-cloud/style.css 265 B
build/block-library/blocks/template-part/editor-rtl.css 393 B
build/block-library/blocks/template-part/editor.css 393 B
build/block-library/blocks/template-part/theme-rtl.css 113 B
build/block-library/blocks/template-part/theme.css 113 B
build/block-library/blocks/term-description/style-rtl.css 108 B
build/block-library/blocks/term-description/style.css 108 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 165 B
build/block-library/blocks/text-columns/style.css 165 B
build/block-library/blocks/verse/style-rtl.css 98 B
build/block-library/blocks/verse/style.css 98 B
build/block-library/blocks/video/editor-rtl.css 553 B
build/block-library/blocks/video/editor.css 554 B
build/block-library/blocks/video/style-rtl.css 186 B
build/block-library/blocks/video/style.css 186 B
build/block-library/blocks/video/theme-rtl.css 126 B
build/block-library/blocks/video/theme.css 126 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.11 kB
build/block-library/common.css 1.11 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/editor-rtl.css 12 kB
build/block-library/editor.css 12 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/reset-rtl.css 470 B
build/block-library/reset.css 470 B
build/block-library/style-rtl.css 14.6 kB
build/block-library/style.css 14.6 kB
build/block-library/theme-rtl.css 698 B
build/block-library/theme.css 703 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.87 kB
build/blocks/index.min.js 52.2 kB
build/commands/index.min.js 15.2 kB
build/commands/style-rtl.css 955 B
build/commands/style.css 952 B
build/components/index.min.js 223 kB
build/components/style-rtl.css 12 kB
build/components/style.css 12 kB
build/compose/index.min.js 12.9 kB
build/core-commands/index.min.js 2.74 kB
build/core-data/index.min.js 72.5 kB
build/customize-widgets/index.min.js 10.9 kB
build/customize-widgets/style-rtl.css 1.35 kB
build/customize-widgets/style.css 1.35 kB
build/data-controls/index.min.js 641 B
build/data/index.min.js 8.99 kB
build/date/index.min.js 18 kB
build/deprecated/index.min.js 458 B
build/dom-ready/index.min.js 325 B
build/dom/index.min.js 4.65 kB
build/edit-post/classic-rtl.css 578 B
build/edit-post/classic.css 580 B
build/edit-post/index.min.js 12.4 kB
build/edit-post/style-rtl.css 2.31 kB
build/edit-post/style.css 2.31 kB
build/edit-site/index.min.js 207 kB
build/edit-site/posts-rtl.css 955 B
build/edit-site/posts.css 955 B
build/edit-site/style-rtl.css 11.7 kB
build/edit-site/style.css 11.7 kB
build/edit-widgets/index.min.js 17.6 kB
build/edit-widgets/style-rtl.css 4.19 kB
build/edit-widgets/style.css 4.19 kB
build/editor/index.min.js 97.6 kB
build/editor/style-rtl.css 9.22 kB
build/editor/style.css 9.22 kB
build/element/index.min.js 4.83 kB
build/escape-html/index.min.js 537 B
build/format-library/index.min.js 8.1 kB
build/format-library/style-rtl.css 494 B
build/format-library/style.css 493 B
build/hooks/index.min.js 1.54 kB
build/html-entities/index.min.js 445 B
build/i18n/index.min.js 3.58 kB
build/interactivity/debug.min.js 16.5 kB
build/interactivity/file.min.js 447 B
build/interactivity/image.min.js 1.68 kB
build/interactivity/index.min.js 13.4 kB
build/interactivity/navigation.min.js 1.16 kB
build/interactivity/query.min.js 742 B
build/interactivity/router.min.js 2.8 kB
build/interactivity/search.min.js 615 B
build/is-shallow-equal/index.min.js 526 B
build/keyboard-shortcuts/index.min.js 1.31 kB
build/keycodes/index.min.js 1.46 kB
build/list-reusable-blocks/index.min.js 2.17 kB
build/list-reusable-blocks/style-rtl.css 846 B
build/list-reusable-blocks/style.css 846 B
build/media-utils/index.min.js 2.92 kB
build/modules/importmap-polyfill.min.js 12.3 kB
build/notices/index.min.js 946 B
build/nux/index.min.js 1.58 kB
build/nux/style-rtl.css 749 B
build/nux/style.css 745 B
build/patterns/index.min.js 6.47 kB
build/patterns/style-rtl.css 594 B
build/patterns/style.css 593 B
build/plugins/index.min.js 1.81 kB
build/preferences-persistence/index.min.js 2.06 kB
build/preferences/index.min.js 2.89 kB
build/preferences/style-rtl.css 715 B
build/preferences/style.css 715 B
build/primitives/index.min.js 829 B
build/priority-queue/index.min.js 1.54 kB
build/private-apis/index.min.js 994 B
build/react-i18n/index.min.js 630 B
build/react-refresh-entry/index.min.js 9.47 kB
build/react-refresh-runtime/index.min.js 6.76 kB
build/redux-routine/index.min.js 2.69 kB
build/reusable-blocks/index.min.js 2.72 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 10.1 kB
build/router/index.min.js 1.95 kB
build/server-side-render/index.min.js 1.94 kB
build/shortcode/index.min.js 1.4 kB
build/style-engine/index.min.js 2.01 kB
build/token-list/index.min.js 579 B
build/url/index.min.js 3.85 kB
build/vendors/react-dom.min.js 42.8 kB
build/vendors/react-jsx-runtime.min.js 560 B
build/vendors/react.min.js 2.65 kB
build/viewport/index.min.js 965 B
build/warning/index.min.js 250 B
build/widgets/index.min.js 7.19 kB
build/widgets/style-rtl.css 1.16 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.03 kB

compressed-size-action

@talldan talldan added the Backport to WP 6.7 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta label Jun 3, 2024
Copy link
Member

@dmsnell dmsnell left a comment

Choose a reason for hiding this comment

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

This is a change I don't fully understand, so I'm probably overlooking something, but it looks like it wipes out all buttons, which seems non-optimal. Should we be checking for some condition before trashing the HTML?

Also even when we choose to, it might help to provide more insightful checks than "we didn't find an A or a BUTTON" in case plugin code has modified the markup in a way we don't expect. Perhaps we assume that if the tags are missing then someone else modified the content intentionally and we should leave it alone.

If this is for the block bindings, would it help avoid unintentional corruption if we looked for some block attribute indicating that we intend to perform Block Binding on it?

I'm just a bit nervous from this that the effect is a broad stroke that introduces normal corruption for the sake of fixing one much-rarer edge case. But like I acknowledge, I'm probably missing something major.

packages/block-library/src/button/index.php Outdated Show resolved Hide resolved
packages/block-library/src/button/index.php Outdated Show resolved Hide resolved
Comment on lines 20 to 53
$p = new WP_HTML_Tag_Processor( $content );

/*
* The button block can render an `<a>` or `<button>` and also has a
* `<div>` wrapper. Find the a or button tag.
*
*/
$tag = null;
while ( $p->next_tag() ) {
$tag = $p->get_tag();
if ( 'A' === $tag || 'BUTTON' === $tag ) {
break;
}
}

// If this happens, the likelihood is there's no block content.
if ( null === $tag ) {
return '';
}

// Build a string of the inner text.
$text = '';
while ( $p->next_token() ) {
switch ( $p->get_token_name() ) {
case '#text':
$text .= $p->get_modifiable_text();
break;

case 'BR':
$text .= '';
break;
}
}
Copy link
Member

Choose a reason for hiding this comment

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

this is great @talldan! here are some thoughts. it looks like you're attempting to remove all content inside the button except for the plain text content. that is, no formatting, no spans, no inline images, etc… I don't speak to whether that's a great idea or not, but I can provide feedback for the HTML API use in doing so.

first of all, this is technically the domain of the HTML Processor, which knows HTML structure, but since that's not really ready yet this will suffice. you did the right thing using the Tag Processor.

this code, however, is going to grab only the first text nodeat the start of the A or BUTTON. Maybe we don't expect any other content, but if you want to (unreliably) limit it to the inner contents, then you can add one more step which would improve the reliability a little bit and capture more text.

// Build a string of the inner text.
$text = '';
while ( $p->next_token() ) {
	switch ( $p->get_token_name() ) {
		/*
         * Neither `A` nor `BUTTON` can nest, so it doesn't matter
         * if these are opening or closing tags. Both will close
         * the open element.
         */
		case $tag:
			break;

		case '#text':
			$text .= $p->get_modifiable_text();
			continue;

		case 'BR':
			$text .= "\n";
			continue;
	}
}

@SantosGuillamot
Copy link
Contributor

SantosGuillamot commented Jun 3, 2024

If I am not mistaken, we don't need to process the content and modify it. Right now, the modifications of the block attributes to apply the bindings are done during the rendering. This means that we can check if the text attribute exists (or if it is empty). In that case, we just return null. And if not, we just return the content. Something like this:

if ( empty( $attributes["text"] ) ) {
    return null;
} else {
    return $content;
}

I quickly tested and it seems to work, but I didn't take a close look at the different scenarios. Do you think something like that could work?

@talldan
Copy link
Contributor Author

talldan commented Jun 4, 2024

I quickly tested and it seems to work, but I didn't take a close look at the different scenarios. Do you think something like that could work?

@SantosGuillamot My first hope is that the solution would be as simple as that, but I don't think it is. My understanding is that what you propose will only work when bindings are applied ($attributes[ 'text' ] only has a value due to the block binding). When the button block is used normally without bindings it will still need the conditional rendering to work as expected.

@SantosGuillamot
Copy link
Contributor

Oh, okay. I had assumed that attributes[ "text "] existed for normal buttons as well. Trying to understand better what we want, is this right?

  • If attributes[ "text" ] exist: return content.
  • If the BUTTON or A tag HAS inner text: return content.
  • If the BUTTON or A tag HAS NOT inner text: return null.

If that's the case and I'm understanding it correctly, @dmsnell can help better identify the easiest way to do that check now. I can't say if the current approach is the right one or not.

If I am not mistaken, and according to this comment, in the future, we could potentially rely on the HTML processor to read the inner text (something like $p->get_inner_text()). Ideally, I imagine something like this:

if ( ! empty( $attributes[ "text" ] ) ) {
    return $content;
}

while ( $p->next_tag() ) {
    $tag = $p->get_tag();
    if ( 'A' === $tag || 'BUTTON' === $tag ) {
        if ( $p->get_inner_text() ){
            return $content;
        } else {
            return null;
        }
    }
}

But again, I believe this is not possible right now and I am not that familiar with the HTML API, so it may be wrong.

Copy link

github-actions bot commented Jun 4, 2024

Flaky tests detected in 9de03b5.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/9445102255
📝 Reported issues:

@kevin940726
Copy link
Member

From my testing in a pattern with the empty second button.

<!-- wp:block {"ref":199,"content":{"2":{"text":"123"}}} /-->

In the editor it looks correctly:

image

However, on the frontend, the second button disappears and magically erases the first character.
image

Is there something I'm doing wrong?

@talldan
Copy link
Contributor Author

talldan commented Jun 5, 2024

Is there something I'm doing wrong?

I couldn't reproduce it, and I'm not sure how that could happen.

I'll do some more testing. It has been pretty challenging working on this fix as my local xdebug isn't working for block PHP. Not sure what's causing that.

@talldan
Copy link
Contributor Author

talldan commented Jun 5, 2024

There's one caveat that I'll note for testing, this won't work for patterns already saved before you checked out this branch. Those patterns are already missing the button markup, so there's very little that can be done to fix them (beyond making the button block completely dynamic).

And as a side note, I managed to figure out what was happening with xdebug. A breakpoint needs to be set in the build/block-library/blocks/button.php file, it won't work in the source file. It's a bit of an inconvenience, not sure if there's a way to solve that.

@kevin940726
Copy link
Member

I couldn't reproduce it, and I'm not sure how that could happen.

I can only reproduce it if the override for the empty button starts with a number. e.g. Button 2 works correctly, but 2Button 2 doesn't work for some reason. Could anyone verify this?

@talldan
Copy link
Contributor Author

talldan commented Jun 6, 2024

I can only reproduce it if the override for the empty button starts with a number. e.g. Button 2 works correctly, but 2Button 2 doesn't work for some reason. Could anyone verify this?

Yep, I can reproduce it now, thanks for the extra info!

@talldan
Copy link
Contributor Author

talldan commented Jun 6, 2024

I can reproduce that in trunk as well using a non-empty button, so it must be a problem with the bindings code.

@kevin940726
Copy link
Member

I can reproduce that in trunk as well using a non-empty button, so it must be a problem with the bindings code.

Yep. I think it's related to #62347, thanks for @Mamaduka for the mention!

@SantosGuillamot
Copy link
Contributor

I just answered in the mentioned issue:

I believe it is caused by this refactoring of the replacement logic: #61236. My fault for using regex 🤦

The idea behind that pull request was to simplify the logic to support more attributes, but that didn't make it to 6.6. We should probably go back to the previous implementation and refactor the logic once the HTML API adds new methods to help with that.

Copy link
Member

@kevin940726 kevin940726 left a comment

Choose a reason for hiding this comment

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

Works for me! I'll leave the binding code for others with more knowledge to review though.

@SantosGuillamot
Copy link
Contributor

I've tested it and it seems to work fine! Regarding bindings, I think it is ready. But I'll defer it to @dmsnell because most of the changes are related to how to use the HTML Tag Processor.

Copy link
Member

@dmsnell dmsnell left a comment

Choose a reason for hiding this comment

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

I could have added an approval before, but mainly I'm only examining the HTML API usage, and it seems fine what's happening here, so from that angle the patch is good.

@talldan talldan force-pushed the update/button-block-optional-rendering-to-be-dynamic branch from 61f1e67 to f622395 Compare June 10, 2024 07:50
@talldan talldan enabled auto-merge (squash) June 10, 2024 08:45
@talldan talldan merged commit 9c3dabc into trunk Jun 10, 2024
63 checks passed
@talldan talldan deleted the update/button-block-optional-rendering-to-be-dynamic branch June 10, 2024 09:07
@github-actions github-actions bot added this to the Gutenberg 18.6 milestone Jun 10, 2024
ellatrix pushed a commit that referenced this pull request Jun 11, 2024
…y text (#62220)

* Dynamically check button text and avoid rendering a button when empty

* Handle both anchor and button tags

* Fix lint issues

* Address review feedback

* Simplify checks for empty content

* Check for comment tokens

* Update native test snapshots

* Update initial HTML native test snippet

----

Co-authored-by: talldan <talldanwp@git.wordpress.org>
Co-authored-by: dmsnell <dmsnell@git.wordpress.org>
Co-authored-by: kevin940726 <kevin940726@git.wordpress.org>
Co-authored-by: SantosGuillamot <santosguillamot@git.wordpress.org>
ellatrix pushed a commit that referenced this pull request Jun 11, 2024
…y text (#62220)

* Dynamically check button text and avoid rendering a button when empty

* Handle both anchor and button tags

* Fix lint issues

* Address review feedback

* Simplify checks for empty content

* Check for comment tokens

* Update native test snapshots

* Update initial HTML native test snippet

----

Co-authored-by: talldan <talldanwp@git.wordpress.org>
Co-authored-by: dmsnell <dmsnell@git.wordpress.org>
Co-authored-by: kevin940726 <kevin940726@git.wordpress.org>
Co-authored-by: SantosGuillamot <santosguillamot@git.wordpress.org>
patil-vipul pushed a commit to patil-vipul/gutenberg that referenced this pull request Jun 17, 2024
…y text (WordPress#62220)

* Dynamically check button text and avoid rendering a button when empty

* Handle both anchor and button tags

* Fix lint issues

* Address review feedback

* Simplify checks for empty content

* Check for comment tokens

* Update native test snapshots

* Update initial HTML native test snippet

----

Co-authored-by: talldan <talldanwp@git.wordpress.org>
Co-authored-by: dmsnell <dmsnell@git.wordpress.org>
Co-authored-by: kevin940726 <kevin940726@git.wordpress.org>
Co-authored-by: SantosGuillamot <santosguillamot@git.wordpress.org>
@ellatrix ellatrix removed the Backport to WP 6.7 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta label Jun 18, 2024
@ellatrix
Copy link
Member

This was cherry-picked to the wp/6.6 branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Buttons Affects the Buttons Block [Feature] Block bindings No Core Sync Required Indicates that any changes do not need to be synced to WordPress Core [Type] Bug An existing feature does not function as intended
Projects
No open projects
Status: Done
5 participants