Using action hooks inside of a shortcode

I am trying to create a modular plugin that includes action hooks for developers to add content before and after the main shortcode content. I’m having some trouble because anything I do in the function called by the action hook is always echoed out at the top of the shortcode instead of inside the shortcode where it belongs.

I’ve been searching and I did come across this response from Pippin Williams on a recent ThemeForest thread, where he recommends using output buffering. I haven’t gotten this to work properly for me, and I’ve read elsewhere that output buffering should only be used as a last resort, so I’m still looking for a clean solution.

Read More

The simplest shortcode ever:

add_shortcode('shortcode','example_shortcode');

function example_shortcode( $atts ) {

  $shortcode_output = "<p>Some shortcode content.</p>";
  $shortcode_output .= "<p>More shortcode content.</p>";

  return $shortcode_output;

}

Now lets add an action:

add_shortcode('shortcode','example_shortcode');

function example_shortcode( $atts ) {

  $shortcode_output = "<p>Some shortcode content.</p>";
  $shortcode_output .= "<p>More shortcode content.</p>";

  do_action('below_shortcode');

  return $shortcode_output;
}

add_action('below_shortcode', 'example_action_output');

function example_action_output() {
    echo "<p>This should be output at the end.</p>";
}

The contents of example_action_output() are returned above the shortcode content because of the echo statement. I tried output buffering as recommended by Pippin:

add_shortcode('shortcode','example_shortcode');

function example_shortcode( $atts ) {

  $shortcode_output = "<p>Some shortcode content.</p>";
  $shortcode_output .= "<p>More shortcode content.</p>";

  ob_start();
  do_action('below_shortcode');
  return ob_get_clean();

  return $shortcode_output;
}

add_action('below_shortcode', 'example_action_output');

function example_action_output() {
    echo "<p>This should be output at the end.</p>";
}

This returned the contents of example_action_output(), but wiped out the rest of my shortcode. Any suggestions?

Thanks,
Dalton

Related posts

Leave a Reply

2 comments

  1. Try this:

    function example_shortcode( $atts ) {
    
        $shortcode_output = "<p>Some shortcode content.</p>";
        $shortcode_output .= "<p>More shortcode content.</p>";
    
        ob_start();
            do_action('below_shortcode');
            $below_shortcode = ob_get_contents();
        ob_end_clean();
    
        $shortcode_output .= $below_shortcode
    
        return $shortcode_output;
    }
    
  2. My answer would include a filter function that adds the text like this:

    add_shortcode('shortcode','example_shortcode');
    
    function example_shortcode( $atts ) {
    
        $shortcode_output = "<p>Some shortcode content.</p>";
        $shortcode_output .= "<p>More shortcode content.</p>";
    
        $shortcode_output .= apply_filter('below_shortcode', $shortcode_output);
    
        return $shortcode_output;
    }
    
    add_filter('below_shortcode', 'example_action_output', 10, 1);
    
    function example_action_output( $text = '' ) {
        return $text . "<p>This should be output at the end.</p>";
    }