WordPress / gutenberg

The Block Editor project for WordPress and beyond. Plugin is available from the official repository.
https://wordpress.org/gutenberg/
Other
10.46k stars 4.18k forks source link

[Block] Post Excerpt - Allow inline HTML tags #49449

Open cuemarie opened 1 year ago

cuemarie commented 1 year ago

What problem does this address?

The Post Excerpt has traditionally allowed limited HTML formatting (strong, em, etc), but it's being stripped by the Post Excerpt Block. Could we have an option to keep formatting?

People like being able to format their excerpts by hand for many reasons. Here's one case, where a WordPress.com user wants to add a little extra meta to the excerpt, and it works fine unless they use the Post Excerpt Block for designing their site. Other example use-cases include: haiku, adding links, sectioning off a part for emphasis, etc. This all gets removed in the Post Excerpt Block.

The workaround for now is to use some other posts-related block, but they don't offer as much control as the query loop.

What is your proposed solution?

The Post Excerpt Block has its own text-formatting features; OP wonders if that's why they're being stripped. Maybe we could only strip tags if one of those features is utilized, and otherwise display the inline HTML as entered?

t-hamano commented 1 year ago

@cuemarie

Thanks for the report.

I think the problem is a bug. The post excerpt should not remove HTML tags by default, but this block removes HTML tags on the front end. Below are the results of the test on Twenty Twenty One.

When the excerpt contains HTML tags, the Post Excerpt block outputs the HTML tags on the editor:

editor

However, this block removes HTML on the front end:

frontend

Twenty Twenty One uses the_excerpt() function to display excerpts in the home template, and HTML tags are output:

home

webmandesign commented 1 year ago

I've just experienced the same issue.

Everything is working fine with WordPress 6.2.2 for me, but as soon as I activate Gutenberg 16.1.2, the inline HTML is stripped out from Post Excerpt block output.

I think the issue is related to word trimming in the block output. The wp_trim_words() function strips all tags before it processes the string and in Post Excerpt block this function is executed all the time, even when excerptLength attribute is not set/changed for the block.

Please fix this somehow.

cuemarie commented 1 year ago

Reported in 6488076-zen.

Hey @christianguerrag ! User reports like the one you've shared here are best reported on issues in https://github.com/WordPress/wp-calypso/ , rather than here in the https://github.com/WordPress/gutenberg/ repo. Even though https://github.com/Automattic/wp-calypso/issues/74675 directs to this report as an underlying issue, we use the wp-calypso one to track feedback from WordPress.com customers, as this issue will not be specific to just that hosting environment. Would you please share your report over there instead? Thanks!

StevenDufresne commented 1 year ago

Although I don't know if it's the best long term strategy, you should be able to patch this by hooking into block_type_metadata and setting excerptLength false.

Try:

function filter_post_excerpt_attrs( $metadata ) {
    if ( 'core/post-excerpt' === $metadata['name'] ) {
        $metadata["attributes"]["excerptLength"] = false;
    }

    return $metadata;
};

add_filter( 'block_type_metadata', 'filter_post_excerpt_attrs', 10 );
lisia123 commented 11 months ago

Hello. In which file is this filter to insert? Best regards, lisia

StevenDufresne commented 11 months ago

That's specific to your project setup. Technically any plugin, mu-plugin or theme function file should work.

lisia123 commented 11 months ago

Hello Steven! Great, I inserted it in the function.php and the problem is fixed. Thanks a lot. lisia

lisia123 commented 11 months ago

Hello Steven, just for information: When I edit the page with a query loop, the HTML code from the text excerpt appears in the query and not the formatted text - see attachment.

Loop-Github-001

Best regards, lisia

Felix-Kiz commented 10 months ago

function filter_post_excerpt_attrs( $metadata ) { if ( 'core/post-excerpt' === $metadata['name'] ) { $metadata["attributes"]["excerptLength"] = false; }

return $metadata;

};

add_filter( 'block_type_metadata', 'filter_post_excerpt_attrs', 10 );

Warning: Undefined array key "excerptLength" in ...\wp-includes\blocks\post-excerpt.php on line 27

Hi everybody! It seems I founded a stable solution: You need to take that ...\wp-includes\blocks\post-excerpt.php, and then begining at the line 27 is a block of code: $excerpt_length = $attributes['excerptLength']; $excerpt = get_the_excerpt( $block->context['postId'] ); if ( isset( $excerpt_length ) ) { $excerpt = wp_trim_words( $excerpt, $excerpt_length ); }

then comment out or delete: $excerpt = wp_trim_words( $excerpt, $excerpt_length ); save post-excerpt.php I understand it is silly, but it works! It is also heals up when WooCommerce product short description removes HTML tags.

Peter-HVD commented 9 months ago

This should be marked as an urgent bug because it is long-established WordPress functionality that HTML tags are not stripped from custom excerpts. I have just built a site with a block theme for the first time, and my client is confused and complains that it is not working as their previous theme did. It's not acceptable to have to say "the WordPress people have taken an arbitrary decision to change the way it works and there's nothing I can do about it".

Felix-Kiz commented 9 months ago

This should be marked as an urgent bug because it is long-established WordPress functionality that HTML tags are not stripped from custom excerpts. I have just built a site with a block theme for the first time, and my client is confused and complains that it is not working as their previous theme did. It's not acceptable to have to say "the WordPress people have taken an arbitrary decision to change the way it works and there's nothing I can do about it".

Hi Peter-HVD, As a solution to fix that try the method mentioned above by me. It works 100% in post excerpt, WooCommerce products short description and anywhere else, where excerpt incorporated.

Peter-HVD commented 9 months ago

As a solution to fix that try the method mentioned above by me. It works 100% in post excerpt, WooCommerce products short description and anywhere else, where excerpt incorporated.

I've always gone by the adage that you shouldn't ever edit core files as you will lose the mod next update. @StevenDufresne's code to change the excerpt length, however, does work for me and I can recommend it, even though it is spamming my debug.log file with those Undefined array key errors.

However, I shouldn't have to change or add any code - my point is that it should be honouring the way WP has always worked! Hopefully it's a bug that will get fixed soon. Thanks.

justintadlock commented 3 months ago

I haven't fully tested this to know if there are any consequences that I'm not seeing, but I needed to get excerpts working as they have traditionally worked in WordPress. The following code:

  1. Only runs when a user has written a custom excerpt.
  2. Allows a subset of inline tags (italic, bold, etc.) in custom excerpts.
  3. Removes the excerpt length only when there's a custom excerpt.
  4. Lets you still control the excerpt length for the Post Excerpt block when there is an automatic/generated excerpt.

Feel free to use, test, or modify as needed:

<?php 

// Add a filter on `pre_render_block` to determine if the excerpt is manual. If
// so, add a filter to `wp_trim_words` to handle formatting ourself.

add_filter('pre_render_block', 'themeslug_pre_render_excerpt', 10, 3);

function themeslug_pre_render_excerpt(
    ?string $pre_render,
    array $block,
    ?WP_Block $parent_block
): ?string {
    if (
        'core/post-excerpt' === $block['blockName']
        && is_null($pre_render)
        && ! is_null($parent_block)
        && isset($parent_block->context['postId'])
        && has_excerpt($parent_block->context['postId'])
    ) {
        add_filter('wp_trim_words', 'themeslug_format_excerpt', 10, 4);
    }

    return $pre_render;
}

// Add a filter to Post Excerpt block to remove the filter we added earlier on
// the `wp_trim_words` hook.

add_filter('render_block_core/post-excerpt', 'themeslug_render_post_excerpt');

function themeslug_render_post_excerpt(string $content): string
{
    if ($priority = has_filter('wp_trim_words', 'themeslug_format_excerpt')) {
        remove_filter('wp_trim_words', 'themeslug_format_excerpt', $priority);
    }

    return $content;
}

// Used to filter `wp_trim_words` to allow manual excerpts to work, limiting to
// a subset of inline HTML tags.

function themeslug_format_excerpt(
    string $text,
    int $num_words,
    string $more,
    string $original_text
): string {
    return wp_kses($original_text, [
        'a'       => [ 'href' => true, 'title' => true, 'class' => true ],
        'abbr'    => [ 'title' => true ],
        'acronym' => [ 'title' => true ],
        'bold'    => [ 'class' => true ],
        'code'    => [ 'class' => true ],
        'em'      => [ 'class' => true ],
        'i'       => [ 'class' => true ],
        'mark'    => [ 'class' => true ],
        'small'   => [ 'class' => true ],
        'span'    => [ 'class' => true ],
        'strong'  => [ 'class' => true ]
    ]);
}
drjimvp commented 3 months ago

The contribution by justintadlock worked great for me.

lancewillett commented 1 month ago

Commenting to vote up allowing basic HTML in excerpts again, since block themes and Site Editor experience are now the way many new users will use WordPress. Ran into this helping a friend set up a new website: they expected a line break added with <br> in the post excerpt to show up on the front-end display, matching how the content appears to be saved in the editor.

jnz31 commented 1 month ago

+1 please include a filter like kses where one could include tags that should not be stripped or some similar solution. stripping everything without any adjustments is such a bummer. the solution by @StevenDufresne throws php warning, so not really a solution here..

talldan commented 1 month ago

I had a look into this. I think there are some options for fixing it, but it might be good to get some further feedback first.

Here's a quick breakdown of the state of things

Options for fixing:

draganescu commented 1 month ago

Could we just try and preserve markup but also the trim?

I don't have a strong opinion. I do think that, compared to classic themes, block themes introduced a change that was likely not meant (?) to alter WP historical hehavior of not trimming manual excerpt. But that was something else, may I say. In the highly intreactive context of the block editor, setting a trim value in a post loop just to have some excerpts trimmed and some not is very confusing.

If we proceed with not trimming manual excerpts we should have a sort of help text mentioning manual excerpts are not affected by this setting, right there in the inspector.

But I think best would be to always respect that, on both auto and manual excerpts but also preserve markup ... if that is somehow magically possible ...

justintadlock commented 1 month ago

Make the block work more like WordPress has traditionally and don't limit the length of manual excerpts. The change would have an effect on existing sites - suddenly manual excerpts would be unlimited by the length attribute. I think this would be fine. There might be valid cases for limiting the length of manual excerpts (e.g. grid layouts of posts where the height of cell should have as much balance as possible). Would be good to get thoughts on this.

This was a change that was introduced in Gutenberg 15.2 (WP 6.3?) from what I can see: https://github.com/WordPress/gutenberg/pull/44964

With that change, sites were already suddenly impacted by two things:

Trimming manual excerpts while preserving HTML would only fix 1/2 of the bug. If going this route, there needs to be a way to turn off trimming of manual excerpts. Otherwise, some developers are still stuck with overly complicated fixes in place.

Personally, I'd be in favor of a second control for applying/not-applying trimming to manual excerpts. At the very least, the attribute (something like trimManualExcerpt) that a theme author can set in the block markup, even if a UI control doesn't exist.

Honestly, this would likely be the best of both worlds. There are scenarios where it makes sense to trim both (grid layouts with posts that should be relatively uniform) and scenarios where the full manual excerpt works better (more traditional top-down lists of posts).