NOTE: The issue I'm encountering is specific to Block Themes; I understand how to filter the text returned from the_excerpt
in a Classic Theme.
What I would like to only show read more text when when wp:post-excerpt
meets excerptLength
. However, when I use, for example,
<!-- wp:post-excerpt {"moreText":"Read More","excerptLength":40, "showMoreOnNewLine":false} /-->
in a template/pattern, all posts on the pages that use this template/pattern have a "Read More" link, even if the except text length had not met the value excerptLength
(shows even if there is no excerpt).
Referencing the source for Excerpt linked to from https://developer.wordpress.org/block-editor/reference-guides/core-blocks/#excerpt, I see an easy fix: move the except_more
filter logic into the if ( isset( $excerpt_length )
conditional. I suppose then my question is more of a general one: how would I go about overriding function render_block_core_post_excerpt
(source: https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/post-excerpt/index.php)? Add logic in functions.php
that checks for the existence of function render_block_core_post_excerpt
, deregister it, then redefine and register the override? Would the action hook be init
?
To be perfectly clear, I already have a excerpt_more
filter in functions.php
that works as expected in a Classic Theme style query loop that calls the_excerpt
. It does not affect the results of <!-- wp:post-excerpt -->
.
EDIT: For anyone curious, following from WordPress Buddha's answer, the override function I ended up using is as follows,
// Source: https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/post-excerpt/index.php
function render_block_core_post_excerpt_override($attributes, $content, $block)
{
if (! isset($block->context['postId'])) {
return '';
}
/*
* The purpose of the excerpt length setting is to limit the length of both
* automatically generated and user-created excerpts.
* Because the excerpt_length filter only applies to auto generated excerpts,
* wp_trim_words is used instead.
*/
$excerpt_length = $attributes['excerptLength'];
$excerpt = get_the_excerpt($block->context['postId']);
if (isset($excerpt_length) && (str_word_count($excerpt) > $excerpt_length)) {
$excerpt = wp_trim_words($excerpt, $excerpt_length);
$more_text = ! empty($attributes['moreText']) ? '<a class="wp-block-post-excerpt__more-link" href="' . esc_url(get_the_permalink($block->context['postId'])) . '">' . wp_kses_post($attributes['moreText']) . '</a>' : '';
$filter_excerpt_more = static function ($more) use ($more_text) {
return empty($more_text) ? $more : '';
};
/**
* Some themes might use `excerpt_more` filter to handle the
* `more` link displayed after a trimmed excerpt. Since the
* block has a `more text` attribute we have to check and
* override if needed the return value from this filter.
* So if the block's attribute is not empty override the
* `excerpt_more` filter and return nothing. This will
* result in showing only one `read more` link at a time.
*/
add_filter('excerpt_more', $filter_excerpt_more);
$content = '<p class="wp-block-post-excerpt__excerpt">' . $excerpt;
$show_more_on_new_line = ! isset($attributes['showMoreOnNewLine']) || $attributes['showMoreOnNewLine'];
if ($show_more_on_new_line && ! empty($more_text)) {
$content .= '</p><p class="wp-block-post-excerpt__more-text">' . $more_text . '</p>';
} else {
$content .= " $more_text</p>";
}
remove_filter('excerpt_more', $filter_excerpt_more);
} else {
$content = '<p class="wp-block-post-excerpt__excerpt">' . $excerpt . '</p>';
}
$classes = array();
if (isset($attributes['textAlign'])) {
$classes[] = 'has-text-align-' . $attributes['textAlign'];
}
if (isset($attributes['style']['elements']['link']['color']['text'])) {
$classes[] = 'has-link-color';
}
$wrapper_attributes = get_block_wrapper_attributes(array('class' => implode(' ', $classes)));
return sprintf('<div %1$s>%2$s</div>', $wrapper_attributes, $content);
}
This function will,
- trim the excerpt if
excerptLength
is set and the number of words in the excerpt exceeds that value. - add a 'Read More' link if the excerpt will be trimmed.
render_block_core_post_excerpt()
) is not pluggable, i.e. it's not wrapped with aif ( ! function_exists() )
check. You could override the post excerpt block'srender_callback
, but perhaps you can first try overriding theexcerpt_length
value (to max40
)? (That block also overrides the value, to 100, but only on the admin and REST API sides - see source)