0

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

2
  • 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. Commented Dec 31, 2012 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). Commented Dec 31, 2012 at 18:33

3 Answers 3

3

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.

6
  • 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
    Commented Dec 31, 2012 at 16:40
  • Might be better to register the shortcode not before 'loop_start'.
    – fuxia
    Commented Dec 31, 2012 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
    Commented Dec 31, 2012 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. Commented Dec 31, 2012 at 18:30
  • @EAMann understood, I tried that method, and was unhappy with the results. Commented Dec 31, 2012 at 18:34
0

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.

0

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

add_filter('the_content','update_shortcode_catch',10);
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;

}
3
  • This seems more like what I want to do. However, it currently breaks the site. Commented Jan 11, 2013 at 18:18
  • *Doesn't break the site, just doesn't work. Commented Jan 11, 2013 at 18:27
  • 1
    Doesn't work because strpos is called with the wrong arguments. I'll edit the answer ;) Commented Mar 11, 2016 at 11:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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