Skip to content

Commit

Permalink
Fix for infinite loops in post.excerpt in specific cases (#2972)
Browse files Browse the repository at this point in the history
* test: Add test to confirm ticket #2041
* fix: Run excerpt_remove_blocks in Post::content() when called from Post::excerpt()
  • Loading branch information
Levdbas committed May 14, 2024
1 parent 295349b commit d064336
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 4 deletions.
26 changes: 23 additions & 3 deletions src/Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -1215,10 +1215,11 @@ protected function get_revised_data_from_method($method, $args = false)
*
* @param int $page Optional. The page to show if the content of the post is split into multiple
* pages. Read more about this in the [Pagination Guide](https://timber.github.io/docs/v2/guides/pagination/#paged-content-within-a-post). Default `0`.
*
* @return string
* @param int $len Optional. The number of words to show. Default `-1` (show all).
* @param bool $remove_blocks Optional. Whether to remove blocks. Defaults to false. True when called from the $post->excerpt() method.
* @return string The content of the post.
*/
public function content($page = 0, $len = -1)
public function content($page = 0, $len = -1, $remove_blocks = false)
{
if ($rd = $this->get_revised_data_from_method('content', [$page, $len])) {
return $rd;
Expand Down Expand Up @@ -1263,6 +1264,25 @@ public function content($page = 0, $len = -1)
}
}

/**
* Filters whether the content produced by block editor blocks should be removed or not from the content.
*
* If truthy then block whose content does not belong in the excerpt, will be removed.
* This removal is done using WordPress Core `excerpt_remove_blocks` function.
*
* @since 2.1.1
*
* @param bool $remove_blocks Whether blocks whose content should not be part of the excerpt should be removed
* or not from the excerpt.
*
* @see excerpt_remove_blocks() The WordPress Core function that will handle the block removal from the excerpt.
*/
$remove_blocks = (bool) \apply_filters('timber/post/content/remove_blocks', $remove_blocks);

if ($remove_blocks) {
$content = \excerpt_remove_blocks($content);
}

$content = $this->content_handle_no_teaser_block($content);
$content = \apply_filters('the_content', ($content));

Expand Down
2 changes: 1 addition & 1 deletion src/PostExcerpt.php
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ protected function run()

// Build an excerpt text from the post’s content.
if (empty($text)) {
$text = $this->post->content();
$text = $this->post->content(0, -1, true);
$text = TextHelper::remove_tags($text, $this->destroy_tags);
$text_before_trim = \trim($text);
$text_before_char_trim = '';
Expand Down
20 changes: 20 additions & 0 deletions tests/assets/block-tests/block-register.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

register_block_type('timber/test-block', [
'render_callback' => 'render_block_example',
'api_version' => 3,
'attributes' => [
'post_id' => [
'type' => 'integer',
],
],
]);

function render_block_example($attributes, $content = '', $wp_block = null)
{
// get the dynamically set post ID from the block attributes. We do it this way because get_the_ID() doesn't work in the block context during phpUnit tests.
return Timber::compile('block-template.twig', [
'post' => Timber::get_post($attributes['post_id']),
'attributes' => $attributes,
]);
}
6 changes: 6 additions & 0 deletions tests/assets/block-tests/block-template.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{{ post.excerpt({
words: 100,
read_more: false
})
}}
<p>What is love</p>
29 changes: 29 additions & 0 deletions tests/test-timber-post-excerpt.php
Original file line number Diff line number Diff line change
Expand Up @@ -356,4 +356,33 @@ function ($defaults) {

$this->assertEquals('Let this be the content, albeit a very short one!&hellip;', (string) $excerpt);
}

/**
* Checks if the excerpt is correctly generated when the content contains a block.
* Prior to this fix, the excerpt would cause infinite loops (which show up as a segmentation fault in PHPunit).
*
* @ticket https://github.com/timber/timber/issues/2041
*
* @return void
*/
public function testExcerptWithCustomBlock()
{
require_once 'assets/block-tests/block-register.php';

// Create an empty post
$post_id = $this->factory->post->create([
'post_excerpt' => '',
'post_content' => '',
]);

// Update the post with a block and pass the post ID to the block
$this->factory->post->update_object($post_id, [
'post_excerpt' => '',
'post_content' => '<!-- wp:timber/test-block { "post_id": ' . $post_id . '} /--> Some other content',
]);

$post = Timber::get_post($post_id);

$this->assertEquals('Some other content', (string) $post->excerpt());
}
}

0 comments on commit d064336

Please sign in to comment.