3

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

  • 1
    Is anything else hooked to below_shortcode? Could you not implement it as a filter & return the output instead? – TheDeadMedic Jul 25 '12 at 12:57
  • I was planning to use the hooks to build the plugin internally, and then make those hooks available to developers as well, so yes, theoretically more than one function could be attached to the same hook. – Dalton Jul 25 '12 at 13:03
  • Just FYI, your version using my output buffer method is incorrect. You have two return statements, meaning only the first one will actually return anything. You should use $shortcode_output .= ob_get_clean(); instead of `return ob_get_clean();'. – Pippin Jul 25 '12 at 14:01
  • @Pippin: thanks, yeah, figured that out after seeing Kalengi's answer. It all makes sense now. – Dalton Jul 25 '12 at 14:44
4

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;
}
  • 1
    As the OP mentioned, he wants to avoid output buffering. – kaiser Jul 25 '12 at 13:15
  • I'd be willing to use output buffering if that's the best way to do it. I guess I need to do more research into output buffering and consider the implications. – Dalton Jul 25 '12 at 13:19
  • 1
    The good news is that definitely works, so thank you. Now I have a bunch of follow up questions about output buffering and whether I should be using a filter instead of an action to accomplish this. :-) – Dalton Jul 25 '12 at 13:29
  • The suggestion by @TheDeadMedic is actually a better way to go. The WP way is to use filters if you want users of your plugin to add content to the plugin's output pipeline. – KalenGi Jul 25 '12 at 15:05
  • Use ob_get_clean() and save yourself a step – jgraup Aug 27 '16 at 17:38
0

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>";
}
  • A filter hook is a very clean way of doing it. The catch here being that OP wanted a solution that supports an action hook – KalenGi Aug 28 '16 at 15:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.