Using action hooks inside of a shortcode

The question:

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.

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

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 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;
}

Method 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>";
}


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment