Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I have a feed from an events calendar that once put in the WordPress RSS widget displays the feed items in reverse chronological order. So the events that are farthest in the future display first, and the events that are coming up soon are displaying last.

We are only displaying the title from the feed (the event name) and the pubdate from the feed (which is the date of the event).

Does anyone know of a way using SimplePie, a plugin or editing the default RSS widget's output (without modifying core) to output chronologically so that the oldest post (in this case event) displays first and newer posts display at the end of the list?

I've already tried changing the feed itself so the order is chronological, but the RSS widget continues to sort it by the pubdate. Unfortunately, using a calendar plugin or custom post type is not ideal because we need to be able to update this feed in one place and display the events across many different sites.

share|improve this question

6 Answers 6

up vote 1 down vote accepted
+50

This should do the trick. Put the following code in your functions.php and then check out the RSS Widget. It will have an option to reverse the order of the feeds.

/**
 * RSS widget class
 */
class Reverse_Widget_RSS extends WP_Widget {

function __construct() {
    $widget_ops = array( 'description' => __('Entries from any RSS or Atom feed ( with Reverse Order Option )') );
    $control_ops = array( 'width' => 400, 'height' => 200 );
    parent::__construct( 'rss', __('RSS'), $widget_ops, $control_ops );
}

function widget($args, $instance) {

    if ( isset($instance['error']) && $instance['error'] )
        return;

    extract($args, EXTR_SKIP);

    $url = $instance['url'];
    while ( stristr($url, 'http') != $url )
        $url = substr($url, 1);

    if ( empty($url) )
        return;

    // self-url destruction sequence
    if ( in_array( untrailingslashit( $url ), array( site_url(), home_url() ) ) )
        return;

    $rss = fetch_feed($url);
    $title = $instance['title'];
    $desc = '';
    $link = '';

    if ( ! is_wp_error($rss) ) {
        $desc = esc_attr(strip_tags(@html_entity_decode($rss->get_description(), ENT_QUOTES, get_option('blog_charset'))));
        if ( empty($title) )
            $title = esc_html(strip_tags($rss->get_title()));
        $link = esc_url(strip_tags($rss->get_permalink()));
        while ( stristr($link, 'http') != $link )
            $link = substr($link, 1);
    }

    if ( empty($title) )
        $title = empty($desc) ? __('Unknown Feed') : $desc;

    $title = apply_filters('widget_title', $title, $instance, $this->id_base);
    $url = esc_url(strip_tags($url));
    $icon = includes_url('images/rss.png');
    if ( $title )
        $title = "<a class='rsswidget' href='$url' title='" . esc_attr__( 'Syndicate this content' ) ."'><img style='border:0' width='14' height='14' src='$icon' alt='RSS' /></a> <a class='rsswidget' href='$link' title='$desc'>$title</a>";

    echo $before_widget;
    if ( $title )
        echo $before_title . $title . $after_title;
    reverse_widget_rss_output( $rss, $instance );
    echo $after_widget;

    if ( ! is_wp_error($rss) )
        $rss->__destruct();
    unset($rss);
}

function update($new_instance, $old_instance) {
    $testurl = ( isset($new_instance['url']) && ($new_instance['url'] != $old_instance['url']) );
    return reverse_widget_rss_process( $new_instance, $testurl );
}

function form($instance) {

    if ( empty($instance) )
        $instance = array( 'title' => '', 'url' => '', 'items' => 10, 'error' => false, 'show_summary' => 0, 'show_author' => 0, 'show_date' => 0, 'reverse' => 0 );
    $instance['number'] = $this->number;

    reverse_widget_rss_form( $instance );
}
}

function reverse_widget_rss_output( $rss, $args = array() ) {
if ( is_string( $rss ) ) {
    $rss = fetch_feed($rss);
} elseif ( is_array($rss) && isset($rss['url']) ) {
    $args = $rss;
    $rss = fetch_feed($rss['url']);
} elseif ( !is_object($rss) ) {
    return;
}

if ( is_wp_error($rss) ) {
    if ( is_admin() || current_user_can('manage_options') )
        echo '<p>' . sprintf( __('<strong>RSS Error</strong>: %s'), $rss->get_error_message() ) . '</p>';
    return;
}

$default_args = array( 'show_author' => 0, 'show_date' => 0, 'show_summary' => 0, 'reverse' => 0 );
$args = wp_parse_args( $args, $default_args );
extract( $args, EXTR_SKIP );

$items = (int) $items;
if ( $items < 1 || 20 < $items )
    $items = 10;
$show_summary  = (int) $show_summary;
$show_author   = (int) $show_author;
$show_date     = (int) $show_date;
$reverse       = (int) $reverse;

if ( !$rss->get_item_quantity() ) {
    echo '<ul><li>' . __( 'An error has occurred; the feed is probably down. Try again later.' ) . '</li></ul>';
    $rss->__destruct();
    unset($rss);
    return;
}

    if( $reverse )
        $feed_items = array_reverse( $rss->get_items(0, $items) );
    else
        $feed_items = $rss->get_items(0, $items);

echo '<ul>';
foreach ( $feed_items as $item ) {
    $link = $item->get_link();
    while ( stristr($link, 'http') != $link )
        $link = substr($link, 1);
    $link = esc_url(strip_tags($link));
    $title = esc_attr(strip_tags($item->get_title()));
    if ( empty($title) )
        $title = __('Untitled');

    $desc = str_replace( array("\n", "\r"), ' ', esc_attr( strip_tags( @html_entity_decode( $item->get_description(), ENT_QUOTES, get_option('blog_charset') ) ) ) );
    $desc = wp_html_excerpt( $desc, 360 );

    // Append ellipsis. Change existing [...] to [&hellip;].
    if ( '[...]' == substr( $desc, -5 ) )
        $desc = substr( $desc, 0, -5 ) . '[&hellip;]';
    elseif ( '[&hellip;]' != substr( $desc, -10 ) )
        $desc .= ' [&hellip;]';

    $desc = esc_html( $desc );

    if ( $show_summary ) {
        $summary = "<div class='rssSummary'>$desc</div>";
    } else {
        $summary = '';
    }

    $date = '';
    if ( $show_date ) {
        $date = $item->get_date( 'U' );

        if ( $date ) {
            $date = ' <span class="rss-date">' . date_i18n( get_option( 'date_format' ), $date ) . '</span>';
        }
    }

    $author = '';
    if ( $show_author ) {
        $author = $item->get_author();
        if ( is_object($author) ) {
            $author = $author->get_name();
            $author = ' <cite>' . esc_html( strip_tags( $author ) ) . '</cite>';
        }
    }

    if ( $link == '' ) {
        echo "<li>$title{$date}{$summary}{$author}</li>";
    } else {
        echo "<li><a class='rsswidget' href='$link' title='$desc'>$title</a>{$date}{$summary}{$author}</li>";
    }
}
echo '</ul>';
$rss->__destruct();
unset($rss);
}

function reverse_widget_rss_process( $widget_rss, $check_feed = true ) {
$items = (int) $widget_rss['items'];
if ( $items < 1 || 20 < $items )
    $items = 10;
$url           = esc_url_raw(strip_tags( $widget_rss['url'] ));
$title         = trim(strip_tags( $widget_rss['title'] ));
$show_summary  = isset($widget_rss['show_summary']) ? (int) $widget_rss['show_summary'] : 0;
$show_author   = isset($widget_rss['show_author']) ? (int) $widget_rss['show_author'] :0;
$show_date     = isset($widget_rss['show_date']) ? (int) $widget_rss['show_date'] : 0;
$reverse       = isset($widget_rss['reverse']) ? (int) $widget_rss['reverse'] : 0;

if ( $check_feed ) {
    $rss = fetch_feed($url);
    $error = false;
    $link = '';
    if ( is_wp_error($rss) ) {
        $error = $rss->get_error_message();
    } else {
        $link = esc_url(strip_tags($rss->get_permalink()));
        while ( stristr($link, 'http') != $link )
            $link = substr($link, 1);

        $rss->__destruct();
        unset($rss);
    }
}
return compact( 'title', 'url', 'link', 'items', 'error', 'show_summary', 'show_author', 'show_date', 'reverse' );
}

function reverse_widget_rss_form( $args, $inputs = null ) {

$default_inputs = array( 'url' => true, 'title' => true, 'items' => true, 'show_summary' => true, 'show_author' => true, 'show_date' => true, 'reverse' => true );
$inputs = wp_parse_args( $inputs, $default_inputs );
extract( $args );
extract( $inputs, EXTR_SKIP);

$number = esc_attr( $number );
$title  = esc_attr( $title );
$url    = esc_url( $url );
$items  = (int) $items;
if ( $items < 1 || 20 < $items )
    $items  = 10;
$show_summary   = (int) $show_summary;
$show_author    = (int) $show_author;
$show_date      = (int) $show_date;
$reverse      = (int) $reverse;

if ( !empty($error) )
    echo '<p class="widget-error"><strong>' . sprintf( __('RSS Error: %s'), $error) . '</strong></p>';

if ( $inputs['url'] ) :
?>
<p><label for="rss-url-<?php echo $number; ?>"><?php _e('Enter the RSS feed URL here:'); ?></label>
<input class="widefat" id="rss-url-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][url]" type="text" value="<?php echo $url; ?>" /></p>
<?php endif; if ( $inputs['title'] ) : ?>
<p><label for="rss-title-<?php echo $number; ?>"><?php _e('Give the feed a title (optional):'); ?></label>
<input class="widefat" id="rss-title-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][title]" type="text" value="<?php echo $title; ?>" /></p>
<?php endif; if ( $inputs['items'] ) : ?>
<p><label for="rss-items-<?php echo $number; ?>"><?php _e('How many items would you like to display?'); ?></label>
<select id="rss-items-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][items]">
<?php
    for ( $i = 1; $i <= 20; ++$i )
        echo "<option value='$i' " . ( $items == $i ? "selected='selected'" : '' ) . ">$i</option>";
?>
</select></p>
<?php endif; if ( $inputs['show_summary'] ) : ?>
<p><input id="rss-show-summary-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][show_summary]" type="checkbox" value="1" <?php if ( $show_summary ) echo 'checked="checked"'; ?>/>
<label for="rss-show-summary-<?php echo $number; ?>"><?php _e('Display item content?'); ?></label></p>
<?php endif; if ( $inputs['show_author'] ) : ?>
<p><input id="rss-show-author-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][show_author]" type="checkbox" value="1" <?php if ( $show_author ) echo 'checked="checked"'; ?>/>
<label for="rss-show-author-<?php echo $number; ?>"><?php _e('Display item author if available?'); ?></label></p>
<?php endif; if ( $inputs['show_date'] ) : ?>
<p><input id="rss-show-date-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][show_date]" type="checkbox" value="1" <?php if ( $show_date ) echo 'checked="checked"'; ?>/>
<label for="rss-show-date-<?php echo $number; ?>"><?php _e('Display item date?'); ?></label></p>
<?php endif; if ( $inputs['reverse'] ) : ?>
<p><input id="rss-reverse-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][reverse]" type="checkbox" value="1" <?php if ( $reverse ) echo 'checked="checked"'; ?>/>
<label for="rss-reverse-<?php echo $number; ?>"><?php _e('Reverse Order?'); ?></label></p>
<?php
endif;
foreach ( array_keys($default_inputs) as $input ) :
    if ( 'hidden' === $inputs[$input] ) :
        $id = str_replace( '_', '-', $input );
?>
<input type="hidden" id="rss-<?php echo $id; ?>-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][<?php echo $input; ?>]" value="<?php echo $$input; ?>" />
<?php
    endif;
    endforeach;
}

function register_rss_widget() {
    unregister_widget( 'WP_Widget_RSS' );
    register_widget( 'Reverse_Widget_RSS' );
}
add_action( 'widgets_init', 'register_rss_widget' );
share|improve this answer
    
This worked like a charm and having the option on a per feed basis is much better than dealing with a global change. Thanks! –  Joshua Lynch Nov 30 '11 at 19:11
    
Glad to hear that :) –  Joshua Abenazer Nov 30 '11 at 19:12

Adding the following code to your theme's functions.php file should do the trick:

function feedFilter($query) {
    if ($query->is_feed) {
        $query->set('order','ASC');
        $query->set('orderby','date');
        }
    return $query;
}
add_filter('pre_get_posts','feedFilter');

Note: this will affect all RSS feeds. You could target more specific feeds by doing further checks on what the query is for (ie not just "is_feed" as in the example).

This is an article for further info on Custom Queries:

http://codex.wordpress.org/Custom_Queries

share|improve this answer

Easiest way would be replacing the core RSS widget with a custom job that reverses the feed items before display. Something like:

<?php foreach (array_reverse($feed->get_items()) as $item): ?>
share|improve this answer

Not sure if anyone else is dealing with this or if the answer in this post is outdated, but this is the method I used which was drastically less duplicated code:

add_action('wp_feed_options', 'myaction_reverse_feed');

function myaction_reverse_feed(&$feed, $url=NULL){

    if(!$url){
        $url = $feed->feed_url;
    }


    if(!class_exists('SimplePieReversed')){
        class SimplePieReversed extends SimplePie {
            public static function sort_items($a, $b)
            {
                return $a->get_date('U') >= $b->get_date('U');
            }
        }
    }

    $feed = new SimplePieReversed();

    $feed->set_sanitize_class( 'WP_SimplePie_Sanitize_KSES' );
    // We must manually overwrite $feed->sanitize because SimplePie's
    // constructor sets it before we have a chance to set the sanitization class
    $feed->sanitize = new WP_SimplePie_Sanitize_KSES();

    $feed->set_cache_class( 'WP_Feed_Cache' );
    $feed->set_file_class( 'WP_SimplePie_File' );

    $feed->set_feed_url($url);
    $feed->set_cache_duration( apply_filters( 'wp_feed_cache_transient_lifetime', 12 * HOUR_IN_SECONDS, $url ) );
}
share|improve this answer

setting up a CPT would still be preferred, so you could add a meta field for start date. each post type would have its own RSS feed independent of posts.

share|improve this answer

First place you should look at is the default-widgets.php file in the includes folder and the WP_Widget_RSS class which uses the wp_widget_rss_output function to render the RSS output. The function doesn't have any convenient filters or actions you can hook to to override it's behavior, meaning that you're better off creating your own widget.

You can simply copy and paste the whole WP_Widget_RSS class (renaming it of course) into a plugin or your functions.php file (don't forget the wp_widget_rss_output, wp_widget_rss_form and wp_widget_rss_process functions) and then do the appropriate modifications (don't forget to modify the widget name and slug.)

Hope this helps! Good luck :)

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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