Skip to content

Commit

Permalink
Template Part: Prevent infinite recursion
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
gziolo committed Mar 3, 2021
1 parent f16ab0e commit ceec567
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 4 deletions.
22 changes: 18 additions & 4 deletions packages/block-library/src/template-part/edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useSelect } from '@wordpress/data';
import {
BlockControls,
useBlockProps,
__experimentalUseNoRecursiveRenders as useNoRecursiveRenders,
Warning,
store as blockEditorStore,
} from '@wordpress/block-editor';
Expand Down Expand Up @@ -34,6 +35,10 @@ export default function TemplatePartEdit( {
} ) {
const templatePartId = theme && slug ? theme + '//' + slug : null;

const [ hasAlreadyRendered, RecursionProvider ] = useNoRecursiveRenders(
templatePartId
);

// Set the postId block attribute if it did not exist,
// but wait until the inner blocks have loaded to allow
// new edits to trigger this.
Expand Down Expand Up @@ -70,8 +75,7 @@ export default function TemplatePartEdit( {
);

const blockProps = useBlockProps();
const isPlaceholder = ! slug;
const isEntityAvailable = ! isPlaceholder && ! isMissing;
const isEntityAvailable = slug && ! isMissing;
const TagName = tagName || getTagBasedOnArea( area );

// We don't want to render a missing state if we have any inner blocks.
Expand All @@ -91,8 +95,18 @@ export default function TemplatePartEdit( {
);
}

if ( hasAlreadyRendered ) {
return (
<TagName { ...blockProps }>
<Warning>
{ __( 'Block cannot be rendered inside itself.' ) }
</Warning>
</TagName>
);
}

return (
<>
<RecursionProvider>
<TemplatePartAdvancedControls
tagName={ tagName }
setAttributes={ setAttributes }
Expand Down Expand Up @@ -144,6 +158,6 @@ export default function TemplatePartEdit( {
) }
{ ! isPlaceholder && ! isResolved && <Spinner /> }
</TagName>
</>
</RecursionProvider>
);
}
27 changes: 27 additions & 0 deletions packages/block-library/src/template-part/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* @return string The render.
*/
function render_block_core_template_part( $attributes ) {
static $seen_content = array();

$content = null;
$area = WP_TEMPLATE_PART_AREA_UNCATEGORIZED;

Expand Down Expand Up @@ -60,6 +62,31 @@ function render_block_core_template_part( $attributes ) {
return 'Template Part Not Found';
}

if ( in_array( $content, $seen_content, true ) ) {
if ( ! is_admin() ) {
trigger_error(
sprintf(
// translators: %s is the user-provided title of the reusable block.
__( 'Could not render Template Part with the slug <strong>%s</strong>: blocks cannot be rendered inside themselves.' ),
$attributes['slug']
),
E_USER_WARNING
);
}

// WP_DEBUG_DISPLAY must only be honored when WP_DEBUG. This precedent
// is set in `wp_debug_mode()`.
$is_debug = defined( 'WP_DEBUG' ) && WP_DEBUG &&
defined( 'WP_DEBUG_DISPLAY' ) && WP_DEBUG_DISPLAY;

return $is_debug ?
// translators: Visible only in the front end, this warning takes the place of a faulty block.
__( '[block rendering halted]' ) :
'';
}

$seen_content[] = $content;

// Run through the actions that are typically taken on the_content.
$content = do_blocks( $content );
$content = wptexturize( $content );
Expand Down

0 comments on commit ceec567

Please sign in to comment.