Skip to content

fix: a block post keeps its excerpt when the content filters are off - #59

Merged
dereuromark merged 2 commits into
mainfrom
fix/block-excerpt-without-content-filters
Aug 27, 2026
Merged

dereuromark merged 2 commits into
mainfrom
fix/block-excerpt-without-content-filters

Conversation

@dereuromark

Copy link
Copy Markdown
Contributor

Found on a live site: seven of ten posts on the homepage had an empty excerpt. The three that did not were authored in another block format whose plugin handles this case.

Cause

registerFilters() gates the excerpt filter behind the content options:

if ($this->options['enable_posts'] || $this->options['enable_pages']) {
    add_filter('the_content', [$this, 'filterContent'], 5);
    add_filter('get_the_excerpt', [$this, 'filterExcerpt'], 5);
}

The block does not share that gate. It renders through its own render_callback whatever those options say. So a site with both off - one that authors in blocks rather than through the content filter - renders its posts correctly and shows nothing on every archive. I confirmed on the live site that filterExcerpt was simply absent from the get_the_excerpt callback list.

Empty rather than raw, because of core: wp_trim_excerpt() builds a missing excerpt through excerpt_remove_blocks(), which keeps an allowlist of core blocks and drops every dynamic third-party block. A post whose whole body is one wpdjot/djot block has nothing left to trim.

Fix

The filter is registered unconditionally. Doing only that would hand this plugin every excerpt on the site, including posts it has nothing to do with, so filterExcerpt() returns early when the content filters are off and the post carries no djot block.

Verified

Applied to the live site and re-fetched the homepage after a cache flush: all ten posts now carry an excerpt, where seven were empty before. composer test (107 tests), stan and cs-check all clean.

Not covered by a test

filterExcerpt() needs add_filter, has_block and a global post, and tests/bootstrap.php stubs only a few WordPress functions - there is no Plugin-level test to extend. Worth adding, but it is a bigger change than this fix and I did not want to bundle them.

Does not overlap #58, which touches filterContent/shouldFilterContent rather than registration or the excerpt.

Copilot AI lite review requested due to automatic review settings August 27, 2026 23:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes empty excerpts for posts authored entirely as wpdjot/djot (or legacy wp-djot/djot) blocks when the plugin’s content filters are disabled, by ensuring excerpt filtering is still available for block-based content.

Changes:

  • Register the get_the_excerpt filter unconditionally so block-only posts can still produce excerpts even when content filters are off.
  • Add a conditional early-return in filterExcerpt() intended to avoid touching excerpts for posts that don’t contain Djot blocks when content filters are disabled.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/Plugin.php
Comment on lines +252 to +256
// With the content filters off this runs only to rescue a block
// excerpt; anything else is not this plugin's to rewrite.
if (
!$this->options['enable_posts'] && !$this->options['enable_pages']
&& !has_block('wpdjot/djot', $post) && !has_block('wp-djot/djot', $post)
Copilot AI review requested due to automatic review settings August 27, 2026 23:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/Plugin.php:256

  • The new bailout that avoids rewriting unrelated excerpts runs after the manual-excerpt branch (if ($excerpt) { ... }). With content filters disabled, the excerpt filter is now always registered, so manual excerpts for posts that do not contain a Djot block will still be run through convertExcerpt() and wp_strip_all_tags(), which is a behavior change for content the plugin doesn’t own.
        // With the content filters off this runs only to rescue a block
        // excerpt; anything else is not this plugin's to rewrite.
        if (
            !$this->options['enable_posts'] && !$this->options['enable_pages']
            && !has_block('wpdjot/djot', $post) && !has_block('wp-djot/djot', $post)

The excerpt filter was registered only when enable_posts or enable_pages
was on:

    if ($this->options['enable_posts'] || $this->options['enable_pages']) {
        add_filter('the_content', [$this, 'filterContent'], 5);
        add_filter('get_the_excerpt', [$this, 'filterExcerpt'], 5);
    }

The block does not share that gate. It renders through its own callback
whatever those options say, so a site with both off - one that authors in
blocks rather than through the content filter - renders its posts
correctly and shows an empty excerpt on every archive.

The reason it ends up empty rather than raw is core: wp_trim_excerpt()
builds a missing excerpt with excerpt_remove_blocks(), which keeps an
allowlist of core blocks and drops every dynamic third-party one. A post
whose whole body is a wpdjot/djot block therefore has nothing left to
trim.

Registering the filter unconditionally would hand this plugin every
excerpt on the site, including posts it has nothing to do with, so
filterExcerpt() now returns early when the content filters are off and
the post carries no djot block.

Found on a live site where seven of ten posts on the homepage had no
excerpt; the three that did were the ones authored in another block
format whose plugin handles this case.
The excerpt regression lived in registerFilters(), so no test that called
filterExcerpt() could have caught it: the hook was simply never added
when both content options were off. What was missing was a test that
asks the hook registry what got registered.

tests/bootstrap.php gains a minimal one - add_filter, add_action,
apply_filters, add_shortcode, has_block, wp_strip_all_tags and the two
is_* the init path calls - plus wp_test_callbacks() to read it back and
wp_test_reset_filters() to isolate each test.

Verified by reverting the fix: the regression test fails, the other two
stay green.

Worth recording how close this came to testing nothing. The first draft
seeded the options under `wpdjot_settings`' old name, so getOptions()
fell back to defaults with both content options ON - and two of the
three tests passed for a reason that had nothing to do with what they
claimed. The third test, which asserts the content filter stays gated,
is what exposed it.
Copilot AI review requested due to automatic review settings August 27, 2026 23:37
@dereuromark
dereuromark force-pushed the fix/block-excerpt-without-content-filters branch from af92e93 to 9ef935e Compare August 27, 2026 23:37
@dereuromark
dereuromark merged commit 8701b66 into main Aug 27, 2026
9 checks passed
@dereuromark
dereuromark deleted the fix/block-excerpt-without-content-filters branch August 27, 2026 23:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/Plugin.php:256

  • The new early-return guard only runs when the excerpt is empty. When content filters are disabled and a non-Djot post has a manual excerpt, this filter will still run the excerpt through Converter::convertExcerpt(), which contradicts the intent of “anything else is not this plugin's to rewrite” and can unexpectedly rewrite excerpts site‑wide even with both content options off. Consider moving the ownership guard (based on options + has_block) before the manual-excerpt conversion so non-Djot posts are left untouched when filters are off.
        // With the content filters off this runs only to rescue a block
        // excerpt; anything else is not this plugin's to rewrite.
        if (
            !$this->options['enable_posts'] && !$this->options['enable_pages']
            && !has_block('wpdjot/djot', $post) && !has_block('wp-djot/djot', $post)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants