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

Reusable blocks: prevent infinite recursion #28405

Merged
merged 12 commits into from
Jan 22, 2021

Conversation

mcsf
Copy link
Contributor

@mcsf mcsf commented Jan 21, 2021

Description

Alternative to: #27012, #26951
Fixes: #18704

In contrast with the aforementioned pull requests, this builds on the opinion that any block type capable of recursion should be responsible for its own infinite loops. In other words, it isn't up to the block editor framework to detect and prevent block loops.

  • On the front end. This is the simplest end of the fix. Thanks to PHP's single-pass execution, it is enough to keep a static array inside the render_block_core_block. If a given Reusable Block ref is already present in the array, prevent further rendering and issue a PHP warning (E_USER_WARNING).

  • On the client. We resort to React context in order to identify any blocks that have already been rendered in the same render tree. The principle here is that each ReusableBlockEdit instance first reads and then expands the context:

const previouslyRenderedRefs = useContext( RenderedRefsContext );
const hasAlreadyRendered = previouslyRenderedRefs.includes( ref );
const newRenderedRefs = useMemo( () => [ ...previouslyRenderedRefs, ref ], [
	ref,
	previouslyRenderedRefs,
] );
// later
return (
	<RenderedRefsContext.Provider value={ newRenderedRefs }>
		{ /* contents go here */ }

This behaviour is encapsulated in the useNoRecursiveRenders hook, for which tests are provided.

Notes

  • useNoRecursiveRenders is general enough that other block types. The Template Part block would be able to use it directly.
  • For now, everything lives under block-library/src/block because my priority is to prevent fatals reported out there in production, but once this PR is merged we can expand the fix to Template Part.
  • Internally, useNoRecursiveRenders's previouslyRenderedRefs could be a Set instead of an Array.
  • We considered WordPress's own Context API instead of React Context, but the Context API only allows a piece of context to be overwritten by a provider's attribute. This doesn't meet our needs, as we need to keep track of a growing set of values, not a singleton.

How has this been tested?

  • Added specific tests for new hook useNoRecursiveRender
  • Manual testing involves any of:
    • Creating a Reusable Block that contains itself
    • Creating a pair of Reusable Blocks that contain each other
    • Creating a pair of (Reusable Block + Template Part) that contain each other
    • ... and ensuring neither the front end nor the editor crash.

Screenshots

Front end Editor
Captura de ecrã 2021-01-22, às 12 23 49 Captura de ecrã 2021-01-22, às 09 50 14

Types of changes

Bug fix

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR.

@mcsf mcsf added [Type] Bug An existing feature does not function as intended [Priority] High Used to indicate top priority items that need quick attention [Feature] Synced Patterns Related to synced patterns (formerly reusable blocks) [Block] Block The "Reusable Block" Block labels Jan 21, 2021
@carlomanf
Copy link

In contrast with the aforementioned pull requests, this builds on the opinion that any block type capable of recursion should be responsible for its own infinite loops.

Would your solution also handle infinite loops that involve more than one block type? (e.g. a reusable block and a template part that both include each other)

Tagging @bobbingwide

@ntsekouras
Copy link
Contributor

ntsekouras commented Jan 22, 2021

Would your solution also handle infinite loops that involve more than one block type? (e.g. a reusable block and a template part that both include each other)

I just tested this and seems to work well! I tested with many combinations, including:

  1. reusable blocks (A inserts A)
  2. reusable blocks (A contains B], B inserts A)
  3. template part (TP contains A reusable, A inserts TP)

@github-actions
Copy link

github-actions bot commented Jan 22, 2021

Size Change: +554 B (0%)

Total Size: 1.39 MB

Filename Size Change
build/block-editor/index.js 123 kB +259 B (0%)
build/block-library/blocks/cover/editor-rtl.css 505 B -19 B (-4%)
build/block-library/blocks/cover/editor.css 503 B -19 B (-4%)
build/block-library/blocks/cover/style-rtl.css 1.35 kB +52 B (+4%)
build/block-library/blocks/cover/style.css 1.35 kB +53 B (+4%)
build/block-library/editor-rtl.css 9.19 kB -7 B (0%)
build/block-library/editor.css 9.18 kB -7 B (0%)
build/block-library/index.js 143 kB +153 B (0%)
build/block-library/style-rtl.css 8.69 kB +48 B (+1%)
build/block-library/style.css 8.7 kB +45 B (+1%)
build/components/index.js 274 kB -4 B (0%)
ℹ️ View Unchanged
Filename Size Change
build/a11y/index.js 1.14 kB 0 B
build/annotations/index.js 3.77 kB 0 B
build/api-fetch/index.js 3.4 kB 0 B
build/autop/index.js 2.84 kB 0 B
build/blob/index.js 665 B 0 B
build/block-directory/index.js 9.08 kB 0 B
build/block-directory/style-rtl.css 1.01 kB 0 B
build/block-directory/style.css 1.01 kB 0 B
build/block-editor/style-rtl.css 11.9 kB 0 B
build/block-editor/style.css 11.9 kB 0 B
build/block-library/blocks/archives/editor-rtl.css 196 B 0 B
build/block-library/blocks/archives/editor.css 196 B 0 B
build/block-library/blocks/audio/editor-rtl.css 194 B 0 B
build/block-library/blocks/audio/editor.css 194 B 0 B
build/block-library/blocks/audio/style-rtl.css 225 B 0 B
build/block-library/blocks/audio/style.css 225 B 0 B
build/block-library/blocks/block/editor-rtl.css 283 B 0 B
build/block-library/blocks/block/editor.css 283 B 0 B
build/block-library/blocks/button/editor-rtl.css 576 B 0 B
build/block-library/blocks/button/editor.css 577 B 0 B
build/block-library/blocks/button/style-rtl.css 552 B 0 B
build/block-library/blocks/button/style.css 552 B 0 B
build/block-library/blocks/buttons/editor-rtl.css 345 B 0 B
build/block-library/blocks/buttons/editor.css 346 B 0 B
build/block-library/blocks/buttons/style-rtl.css 419 B 0 B
build/block-library/blocks/buttons/style.css 419 B 0 B
build/block-library/blocks/calendar/style-rtl.css 319 B 0 B
build/block-library/blocks/calendar/style.css 319 B 0 B
build/block-library/blocks/categories/editor-rtl.css 210 B 0 B
build/block-library/blocks/categories/editor.css 209 B 0 B
build/block-library/blocks/categories/style-rtl.css 208 B 0 B
build/block-library/blocks/categories/style.css 208 B 0 B
build/block-library/blocks/code/style-rtl.css 216 B 0 B
build/block-library/blocks/code/style.css 216 B 0 B
build/block-library/blocks/columns/editor-rtl.css 300 B 0 B
build/block-library/blocks/columns/editor.css 299 B 0 B
build/block-library/blocks/columns/style-rtl.css 529 B 0 B
build/block-library/blocks/columns/style.css 528 B 0 B
build/block-library/blocks/embed/editor-rtl.css 594 B 0 B
build/block-library/blocks/embed/editor.css 595 B 0 B
build/block-library/blocks/embed/style-rtl.css 489 B 0 B
build/block-library/blocks/embed/style.css 489 B 0 B
build/block-library/blocks/file/editor-rtl.css 314 B 0 B
build/block-library/blocks/file/editor.css 313 B 0 B
build/block-library/blocks/file/style-rtl.css 352 B 0 B
build/block-library/blocks/file/style.css 352 B 0 B
build/block-library/blocks/freeform/editor-rtl.css 2.55 kB 0 B
build/block-library/blocks/freeform/editor.css 2.55 kB 0 B
build/block-library/blocks/gallery/editor-rtl.css 783 B 0 B
build/block-library/blocks/gallery/editor.css 783 B 0 B
build/block-library/blocks/gallery/style-rtl.css 1.17 kB 0 B
build/block-library/blocks/gallery/style.css 1.17 kB 0 B
build/block-library/blocks/group/editor-rtl.css 433 B 0 B
build/block-library/blocks/group/editor.css 432 B 0 B
build/block-library/blocks/group/style-rtl.css 190 B 0 B
build/block-library/blocks/group/style.css 190 B 0 B
build/block-library/blocks/heading/editor-rtl.css 248 B 0 B
build/block-library/blocks/heading/editor.css 248 B 0 B
build/block-library/blocks/heading/style-rtl.css 212 B 0 B
build/block-library/blocks/heading/style.css 212 B 0 B
build/block-library/blocks/html/editor-rtl.css 384 B 0 B
build/block-library/blocks/html/editor.css 385 B 0 B
build/block-library/blocks/image/editor-rtl.css 801 B 0 B
build/block-library/blocks/image/editor.css 800 B 0 B
build/block-library/blocks/image/style-rtl.css 569 B 0 B
build/block-library/blocks/image/style.css 570 B 0 B
build/block-library/blocks/latest-comments/editor-rtl.css 277 B 0 B
build/block-library/blocks/latest-comments/editor.css 275 B 0 B
build/block-library/blocks/latest-comments/style-rtl.css 382 B 0 B
build/block-library/blocks/latest-comments/style.css 382 B 0 B
build/block-library/blocks/latest-posts/editor-rtl.css 254 B 0 B
build/block-library/blocks/latest-posts/editor.css 254 B 0 B
build/block-library/blocks/latest-posts/style-rtl.css 634 B 0 B
build/block-library/blocks/latest-posts/style.css 634 B 0 B
build/block-library/blocks/list/editor-rtl.css 203 B 0 B
build/block-library/blocks/list/editor.css 203 B 0 B
build/block-library/blocks/list/style-rtl.css 201 B 0 B
build/block-library/blocks/list/style.css 201 B 0 B
build/block-library/blocks/media-text/editor-rtl.css 311 B 0 B
build/block-library/blocks/media-text/editor.css 311 B 0 B
build/block-library/blocks/media-text/style-rtl.css 642 B 0 B
build/block-library/blocks/media-text/style.css 640 B 0 B
build/block-library/blocks/more/editor-rtl.css 545 B 0 B
build/block-library/blocks/more/editor.css 545 B 0 B
build/block-library/blocks/navigation-link/editor-rtl.css 503 B 0 B
build/block-library/blocks/navigation-link/editor.css 504 B 0 B
build/block-library/blocks/navigation-link/style-rtl.css 805 B 0 B
build/block-library/blocks/navigation-link/style.css 803 B 0 B
build/block-library/blocks/navigation/editor-rtl.css 1.49 kB 0 B
build/block-library/blocks/navigation/editor.css 1.48 kB 0 B
build/block-library/blocks/navigation/style-rtl.css 289 B 0 B
build/block-library/blocks/navigation/style.css 289 B 0 B
build/block-library/blocks/nextpage/editor-rtl.css 507 B 0 B
build/block-library/blocks/nextpage/editor.css 507 B 0 B
build/block-library/blocks/paragraph/editor-rtl.css 236 B 0 B
build/block-library/blocks/paragraph/editor.css 236 B 0 B
build/block-library/blocks/paragraph/style-rtl.css 392 B 0 B
build/block-library/blocks/paragraph/style.css 392 B 0 B
build/block-library/blocks/post-author/editor-rtl.css 329 B 0 B
build/block-library/blocks/post-author/editor.css 329 B 0 B
build/block-library/blocks/post-author/style-rtl.css 303 B 0 B
build/block-library/blocks/post-author/style.css 303 B 0 B
build/block-library/blocks/post-comments-form/style-rtl.css 358 B 0 B
build/block-library/blocks/post-comments-form/style.css 358 B 0 B
build/block-library/blocks/post-content/editor-rtl.css 262 B 0 B
build/block-library/blocks/post-content/editor.css 262 B 0 B
build/block-library/blocks/post-excerpt/editor-rtl.css 206 B 0 B
build/block-library/blocks/post-excerpt/editor.css 206 B 0 B
build/block-library/blocks/post-featured-image/editor-rtl.css 453 B 0 B
build/block-library/blocks/post-featured-image/editor.css 453 B 0 B
build/block-library/blocks/post-featured-image/style-rtl.css 223 B 0 B
build/block-library/blocks/post-featured-image/style.css 223 B 0 B
build/block-library/blocks/preformatted/style-rtl.css 193 B 0 B
build/block-library/blocks/preformatted/style.css 193 B 0 B
build/block-library/blocks/pullquote/editor-rtl.css 304 B 0 B
build/block-library/blocks/pullquote/editor.css 304 B 0 B
build/block-library/blocks/pullquote/style-rtl.css 428 B 0 B
build/block-library/blocks/pullquote/style.css 428 B 0 B
build/block-library/blocks/query-loop/editor-rtl.css 217 B 0 B
build/block-library/blocks/query-loop/editor.css 216 B 0 B
build/block-library/blocks/query-loop/style-rtl.css 427 B 0 B
build/block-library/blocks/query-loop/style.css 429 B 0 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 243 B 0 B
build/block-library/blocks/query-pagination-numbers/editor.css 240 B 0 B
build/block-library/blocks/query-pagination/editor-rtl.css 390 B 0 B
build/block-library/blocks/query-pagination/editor.css 379 B 0 B
build/block-library/blocks/query-pagination/style-rtl.css 288 B 0 B
build/block-library/blocks/query-pagination/style.css 288 B 0 B
build/block-library/blocks/query/editor-rtl.css 279 B 0 B
build/block-library/blocks/query/editor.css 279 B 0 B
build/block-library/blocks/quote/editor-rtl.css 195 B 0 B
build/block-library/blocks/quote/editor.css 195 B 0 B
build/block-library/blocks/quote/style-rtl.css 284 B 0 B
build/block-library/blocks/quote/style.css 285 B 0 B
build/block-library/blocks/rss/editor-rtl.css 307 B 0 B
build/block-library/blocks/rss/editor.css 309 B 0 B
build/block-library/blocks/rss/style-rtl.css 394 B 0 B
build/block-library/blocks/rss/style.css 393 B 0 B
build/block-library/blocks/search/editor-rtl.css 285 B 0 B
build/block-library/blocks/search/editor.css 285 B 0 B
build/block-library/blocks/search/style-rtl.css 454 B 0 B
build/block-library/blocks/search/style.css 456 B 0 B
build/block-library/blocks/separator/editor-rtl.css 229 B 0 B
build/block-library/blocks/separator/editor.css 229 B 0 B
build/block-library/blocks/separator/style-rtl.css 352 B 0 B
build/block-library/blocks/separator/style.css 352 B 0 B
build/block-library/blocks/shortcode/editor-rtl.css 603 B 0 B
build/block-library/blocks/shortcode/editor.css 603 B 0 B
build/block-library/blocks/site-logo/editor-rtl.css 321 B 0 B
build/block-library/blocks/site-logo/editor.css 321 B 0 B
build/block-library/blocks/site-logo/style-rtl.css 238 B 0 B
build/block-library/blocks/site-logo/style.css 238 B 0 B
build/block-library/blocks/social-link/editor-rtl.css 283 B 0 B
build/block-library/blocks/social-link/editor.css 283 B 0 B
build/block-library/blocks/social-links/editor-rtl.css 811 B 0 B
build/block-library/blocks/social-links/editor.css 810 B 0 B
build/block-library/blocks/social-links/style-rtl.css 1.48 kB 0 B
build/block-library/blocks/social-links/style.css 1.48 kB 0 B
build/block-library/blocks/spacer/editor-rtl.css 416 B 0 B
build/block-library/blocks/spacer/editor.css 416 B 0 B
build/block-library/blocks/spacer/style-rtl.css 184 B 0 B
build/block-library/blocks/spacer/style.css 184 B 0 B
build/block-library/blocks/subhead/editor-rtl.css 223 B 0 B
build/block-library/blocks/subhead/editor.css 223 B 0 B
build/block-library/blocks/subhead/style-rtl.css 210 B 0 B
build/block-library/blocks/subhead/style.css 210 B 0 B
build/block-library/blocks/table/editor-rtl.css 593 B 0 B
build/block-library/blocks/table/editor.css 593 B 0 B
build/block-library/blocks/table/style-rtl.css 501 B 0 B
build/block-library/blocks/table/style.css 501 B 0 B
build/block-library/blocks/tag-cloud/editor-rtl.css 237 B 0 B
build/block-library/blocks/tag-cloud/editor.css 235 B 0 B
build/block-library/blocks/tag-cloud/style-rtl.css 221 B 0 B
build/block-library/blocks/tag-cloud/style.css 221 B 0 B
build/block-library/blocks/template-part/editor-rtl.css 794 B 0 B
build/block-library/blocks/template-part/editor.css 794 B 0 B
build/block-library/blocks/text-columns/editor-rtl.css 220 B 0 B
build/block-library/blocks/text-columns/editor.css 220 B 0 B
build/block-library/blocks/text-columns/style-rtl.css 283 B 0 B
build/block-library/blocks/text-columns/style.css 283 B 0 B
build/block-library/blocks/verse/editor-rtl.css 194 B 0 B
build/block-library/blocks/verse/editor.css 194 B 0 B
build/block-library/blocks/verse/style-rtl.css 215 B 0 B
build/block-library/blocks/verse/style.css 215 B 0 B
build/block-library/blocks/video/editor-rtl.css 617 B 0 B
build/block-library/blocks/video/editor.css 617 B 0 B
build/block-library/blocks/video/style-rtl.css 303 B 0 B
build/block-library/blocks/video/style.css 304 B 0 B
build/block-library/common-rtl.css 1.01 kB 0 B
build/block-library/common.css 1.01 kB 0 B
build/block-library/theme-rtl.css 860 B 0 B
build/block-library/theme.css 860 B 0 B
build/block-serialization-default-parser/index.js 1.88 kB 0 B
build/block-serialization-spec-parser/index.js 3.06 kB 0 B
build/blocks/index.js 48.3 kB 0 B
build/components/style-rtl.css 15.5 kB 0 B
build/components/style.css 15.5 kB 0 B
build/compose/index.js 11.2 kB 0 B
build/core-data/index.js 15.2 kB 0 B
build/data-controls/index.js 830 B 0 B
build/data/index.js 8.97 kB 0 B
build/date/index.js 31.8 kB 0 B
build/deprecated/index.js 769 B 0 B
build/dom-ready/index.js 571 B 0 B
build/dom/index.js 4.93 kB 0 B
build/edit-navigation/index.js 11.1 kB 0 B
build/edit-navigation/style-rtl.css 938 B 0 B
build/edit-navigation/style.css 944 B 0 B
build/edit-post/index.js 306 kB 0 B
build/edit-post/style-rtl.css 6.51 kB 0 B
build/edit-post/style.css 6.5 kB 0 B
build/edit-site/index.js 24 kB 0 B
build/edit-site/style-rtl.css 4.01 kB 0 B
build/edit-site/style.css 4.01 kB 0 B
build/edit-widgets/index.js 23.6 kB 0 B
build/edit-widgets/style-rtl.css 3.17 kB 0 B
build/edit-widgets/style.css 3.18 kB 0 B
build/editor/editor-styles-rtl.css 543 B 0 B
build/editor/editor-styles.css 545 B 0 B
build/editor/index.js 41.8 kB 0 B
build/editor/style-rtl.css 3.89 kB 0 B
build/editor/style.css 3.89 kB 0 B
build/element/index.js 4.62 kB 0 B
build/escape-html/index.js 735 B 0 B
build/format-library/index.js 6.77 kB 0 B
build/format-library/style-rtl.css 637 B 0 B
build/format-library/style.css 639 B 0 B
build/hooks/index.js 2.27 kB 0 B
build/html-entities/index.js 623 B 0 B
build/i18n/index.js 3.56 kB 0 B
build/is-shallow-equal/index.js 699 B 0 B
build/keyboard-shortcuts/index.js 2.53 kB 0 B
build/keycodes/index.js 1.93 kB 0 B
build/list-reusable-blocks/index.js 3.14 kB 0 B
build/list-reusable-blocks/style-rtl.css 629 B 0 B
build/list-reusable-blocks/style.css 628 B 0 B
build/media-utils/index.js 5.32 kB 0 B
build/notices/index.js 1.85 kB 0 B
build/nux/index.js 3.41 kB 0 B
build/nux/style-rtl.css 731 B 0 B
build/nux/style.css 727 B 0 B
build/plugins/index.js 2.54 kB 0 B
build/primitives/index.js 1.42 kB 0 B
build/priority-queue/index.js 789 B 0 B
build/redux-routine/index.js 2.84 kB 0 B
build/reusable-blocks/index.js 2.92 kB 0 B
build/rich-text/index.js 13.4 kB 0 B
build/server-side-render/index.js 2.76 kB 0 B
build/shortcode/index.js 1.7 kB 0 B
build/token-list/index.js 1.27 kB 0 B
build/url/index.js 3.02 kB 0 B
build/viewport/index.js 1.86 kB 0 B
build/warning/index.js 1.14 kB 0 B
build/wordcount/index.js 1.22 kB 0 B

compressed-size-action

@bobbingwide
Copy link
Contributor

I just tested this and seems to work well! I tested with many combinations, including:

Did you try?

  • Template or reusable block being embedded twice in the same content.

(More notes on this PR to come…)
How has this been tested?

I'd like to see these notes and test results.

Copy link
Member

@aristath aristath 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 lovely! Works as advertised and the code is clean and easy to understand.
With the exception of the !important in the .scss file this one looks good to me 👍

const RenderedRefsContext = createContext( [] );

export default function useNoRecursiveRenders( ref ) {
const previouslyRenderedRefs = useContext( RenderedRefsContext );
Copy link
Member

Choose a reason for hiding this comment

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

Not a blocker for this PR. I wanted to share my thought on how to make it general enough to use with other blocks that require the same guard (Post Content or Template Part). It looks like it would be enough to rename ref to something more generic like uniqueId and use Set rather than array of strings for checks to support compound values for more complex blocks.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, thanks for the note!

Copy link
Member

@gziolo gziolo left a comment

Choose a reason for hiding this comment

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

It looks solid, I really like useNoRecursiveRenders hook with the accompanying tests at is could be reused with other blocks. Later (after this fix is done), we can consider moving it to the @wordpress/block-editor package.

It looks like it only needs some polishing on UI side. Great work @mcsf 👏🏻

Addresses feedback by ntsekouras
mcsf added a commit that referenced this pull request Jan 22, 2021
Originally introduced in #28405 to prevent Reusable Blocks from
infinitely and fatally recurring, React hook `useNoRecursiveRenders` has
a place in the block-editor package so that other block types
susceptible to recursion can be fixed too.
@mcsf
Copy link
Contributor Author

mcsf commented Jan 22, 2021

Opened #28428 as a follow-up.

gziolo pushed a commit that referenced this pull request Jan 25, 2021
* Block Editor: Add useNoRecursiveRenders

Originally introduced in #28405 to prevent Reusable Blocks from
infinitely and fatally recurring, React hook `useNoRecursiveRenders` has
a place in the block-editor package so that other block types
susceptible to recursion can be fixed too.

* Update variables to reflect uses beyond Reusable Block

* useNoRecursiveRenders: Use Set instead of Array

* Add JSDoc comment.
@gziolo
Copy link
Member

gziolo commented Jan 25, 2021

I started playing with applying the same technique for the Template Part block that is a bit more tricky to handle as it doesn't provide a unique identifier. Anyway, when going through the PHP implementation I was worried that the change proposed prevents rendering the same Reusable block multiple times in one editor. I was able to confirm that it doesn't work, see:

Editor:
Screen Shot 2021-01-25 at 10 34 39

Front-end:
Screen Shot 2021-01-25 at 10 34 56

While it works perfectly fine in the editor because it is using Context API, in PHP it uses static variable that is shared between all function calls so it will consider any subsequent render to the same block as invalid because it isn't aware of the concepts of rendering tree.

gziolo added a commit that referenced this pull request Jan 25, 2021
Based on #28405 from @mcsf.
Tries to apply the same technique used for Reusable block to prevent infinite recursion when the same block is inserted into itself at any level of nesting.
@carlomanf
Copy link

Anyway, when going through the PHP implementation I was worried that the change proposed prevents rendering the same Reusable block multiple times in one editor. I was able to confirm that it doesn't work, see:

#26951 solved this by unsetting the block from the static variable after the end of the render. It should be an easy fix I think.

@ockham
Copy link
Contributor

ockham commented Jan 25, 2021

Thanks @gziolo for bringing this up!

I'm a bit surprised that the issue wasn't caught by this test 🤔

it( 'should be able to insert a reusable block twice', async () => {

@ockham
Copy link
Contributor

ockham commented Jan 25, 2021

Thanks @gziolo for bringing this up!

I'm a bit surprised that the issue wasn't caught by this test

it( 'should be able to insert a reusable block twice', async () => {

Ah, disregard. The e2e test checks only the editor, not the frontend (PHP).

mcsf added a commit that referenced this pull request Jan 25, 2021
Since #28405, `render_block_core_block` prevents fatal rendering loops
in Reusable Blocks by aborting if a given block has already been
rendered. This effectively prevents loops, but also unintentionally
prevented the same reusable block from being rendered twice on the same
page, even if one isn't nested in the other.

This commit fixes this by explicitly forgetting a Reusable Block after
it has finished rendering.
@mcsf
Copy link
Contributor Author

mcsf commented Jan 25, 2021

Anyway, when going through the PHP implementation I was worried that the change proposed prevents rendering the same Reusable block multiple times in one editor. I was able to confirm that it doesn't work […]

Thanks for the report! Opened a fix at #28461.

gziolo added a commit that referenced this pull request Jan 25, 2021
Based on #28405 from @mcsf.
Tries to apply the same technique used for Reusable block to prevent infinite recursion when the same block is inserted into itself at any level of nesting.
mcsf added a commit that referenced this pull request Jan 25, 2021
Since #28405, `render_block_core_block` prevents fatal rendering loops
in Reusable Blocks by aborting if a given block has already been
rendered. This effectively prevents loops, but also unintentionally
prevented the same reusable block from being rendered twice on the same
page, even if one isn't nested in the other.

This commit fixes this by explicitly forgetting a Reusable Block after
it has finished rendering.
gziolo added a commit that referenced this pull request Mar 1, 2021
Based on #28405 from @mcsf.
Tries to apply the same technique used for Reusable block to prevent infinite recursion when the same block is inserted into itself at any level of nesting.
gziolo added a commit that referenced this pull request Mar 3, 2021
Based on #28405 from @mcsf.
Tries to apply the same technique used for Reusable block to prevent infinite recursion when the same block is inserted into itself at any level of nesting.
gziolo added a commit that referenced this pull request Mar 8, 2021
Based on #28405 from @mcsf.
Tries to apply the same technique used for Reusable block to prevent infinite recursion when the same block is inserted into itself at any level of nesting.
gziolo added a commit that referenced this pull request Mar 8, 2021
* Template Part: Prevent infinite recursion
Based on #28405 from @mcsf.
Tries to apply the same technique used for Reusable block to prevent infinite recursion when the same block is inserted into itself at any level of nesting.

* Change the order of warning messages

* Prevents a block from rendering itself only when the same block type

* Fix styling issues in PHP file for Template Part block

* Add fixes for issues discovered while testing

* Ensure immutability in useNoRecursiveRenders

* Rename ref to uniqueId in the test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Block The "Reusable Block" Block [Feature] Synced Patterns Related to synced patterns (formerly reusable blocks) [Priority] High Used to indicate top priority items that need quick attention [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

500 error and 'Reusable' tab disappears when a reusable block is embedded into itself
8 participants