WordPress.org

Ready to get started?Download WordPress

Forums

[resolved] Calling get_the_excerpt from a filter on the_content kills shortcodes (15 posts)

  1. djeyewater
    Member
    Posted 10 months ago #

    I am writing a plugin that inserts some content after the_content. So I am doing this by adding a filter to the_content. As part of this, I need to get the summary of the post. But if I call get_the_excerpt from within the filter, then shortcodes in the_content stop being parsed.

    When a page / post is viewed, shortcodes will show up as unprocessed shortcodes.

    add_filter('the_content', 'myTest');
     function myTest($content){
    	//content filters are run on get_the_excerpt, so we must remove our filter before calling it to avoid an infinite loop
    	remove_filter('the_content', 'myTest');
    	$summary=get_the_excerpt();
    	add_filter('the_content', 'myTest');
    	return $content.'<p>Content edited</p>';
     }

    Shortcodes can be made to work by using wp_trim_words instead of get_the_excerpt, e.g.

    add_filter('the_content', 'myTest');
     function myTest($content){
    	global $post;
    	$summary=$post->post_excerpt ? $post->post_excerpt : wp_trim_words($content,55);
    	return $content.'<p>Content edited</p>';
     }

    So, two questions:

    1. Why does this happen?
    2. Is using wp_trim_words in this case a suitable alternative?

    Thanks

    Dave

  2. mindctrl
    Member
    Posted 10 months ago #

    I'm not quite clear on what you're trying to do exactly. Are you trying to use shortcodes in the excerpt or the content?

  3. djeyewater
    Member
    Posted 10 months ago #

    I'm not trying to do either of those things. I'm trying to get_the_excerpt from within a filter on the_content.

    But doing this will make any shortcodes within the_content so that they aren't parsed.

    Example:

    • Create a new post that contains the shortcode [caption].
    • View the post - it will be empty because the shortcode is parsed correctly.
    • Now add the code to your theme's function.php:
      add_filter('the_content', 'myTest');
       function myTest($content){
      	//content filters are run on get_the_excerpt, so we must remove our filter before calling it to avoid an infinite loop
      	remove_filter('the_content', 'myTest');
      	$summary=get_the_excerpt();
      	add_filter('the_content', 'myTest');
      	return $content.'<p>Content edited</p>';
       }
    • View the post again - you will see the text [caption] as shortcodes are now not being parsed.
  4. mindctrl
    Member
    Posted 10 months ago #

    Can you try explaining what you want to do without using code to explain it? You originally said you were trying to insert some content after the_content. When you say you need to get a "summary" of the post, I'm taking you to mean the excerpt? So, are you trying to append the excerpt data to the end of the content data? If so, something like this should work - note: add_action and not add_filter:

    function mytest( $content ) {
    
    	// Append the excerpt data to the content data and wrap it in a div element
    	$content .= '<div>' . get_the_excerpt() . '</div>';
    
    	return $content;
    }
    add_action( 'the_content', 'mytest' );
  5. djeyewater
    Member
    Posted 10 months ago #

    Thanks for the suggestion, I've just tried using add_action instead of add_filter, but it gives exactly the same result. It seems that actions on the_content are processed when you call get_the_excerpt as well - your example gave me an infinite loop error.

    add_action('the_content', 'myTest');
     function myTest($content){
    	//content filters are run on get_the_excerpt, so we must remove our filter before calling it to avoid an infinite loop
    	remove_action('the_content', 'myTest');
    	$content .= '<div>' . get_the_excerpt() . '</div>';
    	add_action('the_content', 'myTest');
    	return $content;
     }

    Yes, I'm trying to append the excerpt to the end of the content (as part of a URL). For the purposes of this example though I omitted the detail, the main point is that calling get_the_excerpt is stopping shortcodes from being processed.

  6. mindctrl
    Member
    Posted 10 months ago #

    I see. Will this work for you? It works in my testing here.

    function mytest( $content ) {
    
            global $post;
    
            // Append the excerpt data to the content data and wrap it in a div element
            $content .= '<div>' . $post->post_excerpt . '</div>';
    
            return $content;
    }
    add_action( 'the_content', 'mytest' );

    I see you were doing something similar in the first post, but then trimming if there was no manual excerpt. I think you're ok with that. The only other workaround I can think of off the top of my head would be to do a custom trim function, and I'm not sure what you'd gain from that.

  7. mindctrl
    Member
    Posted 10 months ago #

    Curious, what's the use case for this? Lacking details makes it hard to understand what you're doing. I've never seen anyone wanting to append the excerpt, or a trimmed version of the content, below the content.

  8. djeyewater
    Member
    Posted 10 months ago #

    The use case is for a sharing link at the end of the article. The excerpt needs to be used (url encoded) as part of a URL. Then when you click on that link, the page will open up with the share text pre-filled with the excerpt and link.

    Unfortunately your example using $post->post_excerpt won't always work as it relies on the post excerpt meta being filled out (which isn't always the case). get_the_excerpt returns $post->post_excerpt if it exists, or otherwise it trims the_content down.

    I believe the solution I gave in my original question
    $summary=$post->post_excerpt ? $post->post_excerpt : wp_trim_words($content,55); is probably pretty similar to what get_the_excerpt does, though I haven't actually looked at the code for get_the_excerpt.

    What I'd like to know is:

    1. Why do shortcodes stop working when get_the_excerpt is called from an action or filter on the_content
    2. Is my workaround okay, or is it not taking account of something that could cause issues

    Cheers

    Dave

  9. bcworkz
    Member
    Posted 10 months ago #

    Hello, I hope you all don't mind my jumping in.

    The shortcode expansion is hooked into 'the_content' just like you are hooking into it. If you alter the priority of your hook, you should be able to get the shortcodes expanded before you get the content.

    If that doesn't work out, you could always run your excerpt through do_shortcode() to get it expanded. Even if already expanded, other than being redundant, no harm done.

    @mindctrl- can you reference where a do_action() call is invoking the 'the_content' action? All such calls I can find for 'the_content' are apply_filters(). AFAIK, 'the_content' is a filter tag, yet it seems to work as an action, which I find curious.

  10. mindctrl
    Member
    Posted 10 months ago #

    djeyewater, I don't see a problem using your solution in the original post using wp_trim_words.

    As to why shortcodes stop working, I believe it's caused by the wp_trim_excerpt function stripping them and replacing the brackets with html entities instead of the plain bracket characters.

  11. mindctrl
    Member
    Posted 10 months ago #

    bcworkz, you're right. I don't think there's any difference, and the reason I suggested it earlier as I had done that in some code I've written before using the add_action.

    I just took a look at the add_action function, and it looks like this:

    function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
    	        return add_filter($tag, $function_to_add, $priority, $accepted_args);
    }

    So that's why it works either way.

  12. djeyewater
    Member
    Posted 10 months ago #

    bcworkz, thanks for the suggestion. I just tried a priority of 99 and the shortcodes were parsed correctly. I think for practical reasons I'll stick with my wp_trim_words workaround if there aren't any issues with it. (Having to remove the filter/action before calling get_the_excerpt and then adding it again after to prevent recursion is a bit messy). But at least now I know the answer.

    Thanks for your suggestions too mindctrl. I didn't know that add_action was just a shortcut to add_filter.

    Cheers

    Dave

  13. mindctrl
    Member
    Posted 10 months ago #

    djeyewater, the add/remove is a bit messy. Does something this work instead?

    function get_my_excerpt_data() {
    	global $post, $content;
    	$excerpt_data = $post->post_excerpt ? $post->post_excerpt : wp_trim_words( $content, 55 );
    
    	return $excerpt_data;
    }
    
    function mytest( $content ) {
    	global $post;
    
    	// Append the excerpt data to the content data
    	$content .= get_my_excerpt_data();
    
    	return $content;
    }
    add_filter( 'the_content', 'mytest' );
  14. djeyewater
    Member
    Posted 10 months ago #

    I'm not planning to use the add/remove bit as it is messy, I'm planning to use the workaround given in my original post:

    add_filter('the_content', 'myTest');
     function myTest($content){
    	global $post;
    	$summary=$post->post_excerpt ? $post->post_excerpt : wp_trim_words($content,55);
    	return $content.'<p>Content edited</p>';
     }
  15. bcworkz
    Member
    Posted 10 months ago #

    djeyewater, I'm glad you've arrived at a solution.

    FWIW, while add_action() is obviously a synonym for add_filter(), it begs the question why have two when one will do?

    It appears they were once two separate, distinct hook types. We see add_filter() stores the callback in the global $wp_filters, so of course action hooks are stored there as well. But then we see in do_actions() the callbacks to use are taken from both $wp_filters and $wp_action. Yet I see no code anywhere that stores callbacks in $wp_action. I'm guessing these hooks were once separate and unrelated. Someone eventually realized there was no functional difference and the two were essentially merged. To avoid compatibility issues, things were setup so code worked either way.

Reply

You must log in to post.

About this Topic