I have a shortcode called update which is used as follows

[update title='' date=''] this is some update, etc. etc. 2 paragraphs or more [/update]

This outputs some html that wrap the title, date and content in some html.

Along wit this, I would like spit out a single line at the top of the content that outputs just the title and date with an anchor that jumps to the point where the update was created.

I've looked high and low, but I cant seem to find a way to position the shortcode just above the content.

Any help appreciated!

Thank you

  • Did you write the update function into your functions.php file? If not that's what you'd need to do first. Next, what do you mean by position the shortcode just above the content? Do you mean at the top of each page, or the top of each post? It will be different depending on your definition of "just above the content" because content types are treated differently depending on what they are in WP. – Melanie Sumner Dec 31 '12 at 15:57
  • My shortcode works fine, and is written in the functions.php. I need to output the title attribute from the shortcode, above the_content(), but below the post header (title / thumb / author / etc). – Joshua Richards Dec 31 '12 at 18:33

A cleaner way than my first suggestion would be this:

  • Run the shortcode handler two times: 1. before the content is parsed, 2. during the regular content parsing.
  • Store the data you want to prepend in a variable.

It is important to use 'the_post' as first entry. Otherwise you can get strange side effect in cases where a widget or some other code uses the_content filters.

add_shortcode( 'test',  array ( 'WPSE_77804_Shortcode', 'shortcode_handler' ) );
add_action( 'the_post', array ( 'WPSE_77804_Shortcode', 'store_output' ) );

class WPSE_77804_Shortcode
    protected static $storage = '';

    public static function store_output( $post )

        // maybe someone else has done this already, so we don't have to try again.
        '' === self::$storage && do_shortcode( $post->post_content );

        '' !== self::$storage
            && add_filter( 'the_content', array ( __CLASS__, 'prepend_content' ) );

    public static function shortcode_handler( $attrs, $content = '' )
        if ( '' === self::$storage )
            if ( isset ( $attrs['title'] ) )
                self::$storage .= $attrs['title'];

            if ( isset ( $attrs['date'] ) )
                self::$storage .= ' ' . $attrs['date'];

        // you might do much more here and return the complete string
        return '|' . self::$storage . '|' . $content;

    public static function prepend_content( $content )
        return self::$storage . '<hr>' . $content;

Related answer for galleries.

|improve this answer|||||
  • 1
    If someone runs do_shortcode on the content outside of the Loop, echoed content will print in strange places-- before the HTTP headers, for example. I wouldn't do this unless I were personally managing the site. – s_ha_dum Dec 31 '12 at 16:40
  • Might be better to register the shortcode not before 'loop_start'. – fuxia Dec 31 '12 at 16:43
  • Don't just call print inside a shortcode. Whatever you print will render at the top of the content, but you have zero control as to where exactly in the markup it does appear. – EAMann Dec 31 '12 at 18:08
  • so my post structure is as follows <header> thumb, title, meta etc. </header> <section> content </section> i need the shortcode to go in the section, above the content, using echo or print, just outputs it above the header. I need more control. – Joshua Richards Dec 31 '12 at 18:30
  • @EAMann understood, I tried that method, and was unhappy with the results. – Joshua Richards Dec 31 '12 at 18:34

It sounds like the way to handle this is to use a global array in your theme's functions.php, and add to it whenever one of these shortcodes is processed. Finally, a filter on the_content can be used to place the extra links at the top.

Start by initializing the global:

add_action( 'after_setup_theme', 'update_init' );
function update_init() {
    global $update_links;
    $update_links = array();

Then add the following code to your shortcode processing function:

global $update_links;
$update_links[] = "<a href='#$title-$date'>$title - $date</a>";

The above also assumes that your shortcode replacement includes an anchor tag of $title-$date.

Finally, add a content filter to add the update links to your content:

add_filter( 'the_content', 'the_content_update_links', 90);    
function the_content_update_links($content) {
    global $update_links;
    if(count($update_links)) $content = implode("<br />", $update_links).$content;
    return $output;

You can change the way the links are put together - I just put a break between them but it would be simple to loop through and create an unordered list or wrap the links in a div.

|improve this answer|||||

You can catch your shortcode before its "time for shortcodes" using the_content filter hook and return it before the rest of the content:

function update_shortcode_catch($content){
    //early exit if not found
    if (strpos($content, '[update') === false)
        return $content;

    //extract shortcode (could use regex)
    $shortcode_start = explode('[update', $content);
    $shortcode_end = explode('[/update]', $shortcode_start[1]);
    $shortcode = '[update' . $shortcode_end[0] . '[/update]';

    //render the update shortcode
    $update = do_shortcode($shortcode);

    //remove the shortcode from te content
    $content = str_replace($shortcode, "", $content);

    //then return the update before the content
    return $update.$content;

|improve this answer|||||
  • This seems more like what I want to do. However, it currently breaks the site. – Joshua Richards Jan 11 '13 at 18:18
  • *Doesn't break the site, just doesn't work. – Joshua Richards Jan 11 '13 at 18:27
  • 1
    Doesn't work because strpos is called with the wrong arguments. I'll edit the answer ;) – Alessandro Vendruscolo Mar 11 '16 at 11:35

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.