WordPress.org

Make WordPress Core

Ticket #46133: 46133.3.diff

File 46133.3.diff, 5.6 KB (added by azaozz, 11 months ago)
  • src/wp-includes/blocks.php

     
    125125 * @return string The parsed and filtered content.
    126126 */
    127127function excerpt_remove_blocks( $content ) {
    128         $allowed_blocks = array(
     128        $allowed_inner_blocks = array(
    129129                // Classic blocks have their blockName set to null.
    130130                null,
    131                 'core/columns',
    132131                'core/freeform',
    133132                'core/heading',
    134133                'core/html',
     
    141140                'core/table',
    142141                'core/verse',
    143142        );
     143
     144        $allowed_blocks = array_merge( $allowed_inner_blocks, array( 'core/columns' ) );
     145
    144146        /**
    145147         * Filters the list of blocks that can contribute to the excerpt.
    146148         *
     
    154156        $allowed_blocks = apply_filters( 'excerpt_allowed_blocks', $allowed_blocks );
    155157        $blocks         = parse_blocks( $content );
    156158        $output         = '';
     159
    157160        foreach ( $blocks as $block ) {
    158161                if ( in_array( $block['blockName'], $allowed_blocks, true ) ) {
     162                        if ( ! empty( $block['innerBlocks'] ) ) {
     163                                if ( 'core/columns' === $block['blockName'] ) {
     164                                        $output .= _excerpt_render_inner_columns_blocks( $block, $allowed_inner_blocks );
     165                                        continue;
     166                                }
     167
     168                                // Skip the block if it has disallowed or nested inner blocks.
     169                                foreach ( $block['innerBlocks'] as $inner_block ) {
     170                                        if (
     171                                                ! in_array( $inner_block['blockName'], $allowed_inner_blocks, true ) ||
     172                                                ! empty( $inner_block['innerBlocks'] )
     173                                        ) {
     174                                                continue 2;
     175                                        }
     176                                }
     177                        }
     178
    159179                        $output .= render_block( $block );
    160180                }
    161181        }
    162          return $output;
     182
     183        return $output;
    163184}
    164185
    165186/**
     187 * Render inner blocks from the `core/columns` block for generating an excerpt.
     188 *
     189 * @since 5.2.0
     190 * @access private
     191 *
     192 * @param array $columns        The parsed columns block.
     193 * @param array $allowed_blocks The list of allowed inner blocks.
     194 * @return string The rendered inner blocks.
     195 */
     196function _excerpt_render_inner_columns_blocks( $columns, $allowed_blocks ) {
     197        $output = '';
     198
     199        foreach ( $columns['innerBlocks'] as $column ) {
     200                foreach ( $column['innerBlocks'] as $inner_block ) {
     201                        if ( in_array( $inner_block['blockName'], $allowed_blocks, true ) && empty( $inner_block['innerBlocks'] ) ) {
     202                                $output .= render_block( $inner_block );
     203                        }
     204                }
     205        }
     206
     207        return $output;
     208}
     209
     210/**
    166211 * Renders a single block into a HTML string.
    167212 *
    168213 * @since 5.0.0
  • tests/phpunit/tests/formatting/ExcerptRemoveBlocks.php

     
     1<?php
     2
     3/**
     4 * @group formatting
     5 * @covers ::excerpt_remove_blocks
     6 * @ticket 46133
     7 */
     8class Tests_Formatting_ExcerptRemoveBlocks extends WP_UnitTestCase {
     9
     10        public static $post_id;
     11
     12        public $content = '
     13<!-- wp:paragraph -->
     14<p>paragraph</p>
     15<!-- /wp:paragraph -->
     16<!-- wp:latest-posts {"postsToShow":3,"displayPostDate":true,"order":"asc","orderBy":"title"} /-->
     17<!-- wp:spacer -->
     18<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>
     19<!-- /wp:spacer -->
     20<!-- wp:columns {"columns":1} -->
     21<div class="wp-block-columns has-1-columns">
     22        <!-- wp:column -->
     23        <div class="wp-block-column">
     24                <!-- wp:archives {"displayAsDropdown":false,"showPostCounts":false} /-->
     25               
     26                <!-- wp:paragraph -->
     27                <p>paragraph inside column</p>
     28                <!-- /wp:paragraph -->
     29        </div>
     30        <!-- /wp:column -->
     31</div>
     32<!-- /wp:columns -->
     33';
     34
     35        public $filtered_content = '
     36
     37<p>paragraph</p>
     38
     39
     40
     41
     42                <p>paragraph inside column</p>
     43               
     44';
     45
     46        /**
     47         * Fake block rendering function.
     48         *
     49         * @since 5.2.0
     50         *
     51         * @return string Block output.
     52         */
     53        function render_fake_block() {
     54                return get_the_excerpt( self::$post_id );
     55        }
     56
     57        /**
     58         * Set up.
     59         *
     60         * @since 5.2.0
     61         */
     62        function setUp() {
     63                parent::setUp();
     64                self::$post_id = $this->factory()->post->create(
     65                        array(
     66                                'post_excerpt' => '', // Empty excerpt, so it has to be generated.
     67                                'post_content' => '<!-- wp:core/fake /-->',
     68                        )
     69                );
     70                register_block_type(
     71                        'core/fake',
     72                        array(
     73                                'render_callback' => array( $this, 'render_fake_block' ),
     74                        )
     75                );
     76        }
     77
     78        /**
     79         * Tear down.
     80         *
     81         * @since 5.2.0
     82         */
     83        function tearDown() {
     84                parent::tearDown();
     85                $registry = WP_Block_Type_Registry::get_instance();
     86                $registry->unregister( 'core/fake' );
     87                wp_delete_post( self::$post_id, true );
     88        }
     89
     90        /**
     91         * Tests excerpt_remove_blocks().
     92         *
     93         * @ticket 46133
     94         */
     95        function test_excerpt_remove_blocks() {
     96                // Simple dynamic block..
     97                $content = '<!-- wp:core/block /-->';
     98
     99                $this->assertEmpty( excerpt_remove_blocks( $content ) );
     100
     101                // Dynamic block with options, embedded in other content.
     102                $this->assertEquals( $this->filtered_content, excerpt_remove_blocks( $this->content ) );
     103        }
     104
     105        /**
     106         * Tests that dynamic blocks don't cause an out-of-memory error.
     107         *
     108         * When dynamic blocks happen to generate an excerpt, they can cause an
     109         * infinite loop if that block is part of the post's content.
     110         *
     111         * `wp_trim_excerpt()` applies the `the_content` filter, which has
     112         * `do_blocks` attached to it, trying to render the block which again will
     113         * attempt to return an excerpt of that post.
     114         *
     115         * This infinite loop can be avoided by stripping dynamic blocks before
     116         * `the_content` gets applied, just like shortcodes.
     117         *
     118         * @ticket 46133
     119         */
     120        function test_excerpt_infinite_loop() {
     121                $query = new WP_Query(
     122                        array(
     123                                'post__in' => array( self::$post_id ),
     124                        )
     125                );
     126                $query->the_post();
     127                $this->assertEmpty( do_blocks( '<!-- wp:core/fake /-->' ) );
     128        }
     129}