Multiple versions of RSS feed? One with full content, one with the excerpt

I’m not sure how to word my question and I have been searching all day, to no avail.

I am looking for a method to create two versions of my RSS feeds, one with the full content and one with only the excerpt.

Read More

Mainly, I want to do this for the “Author” feeds. I would like two feeds created for each Author. One with the full content and one with the excerpt. If nothing else, I would like the author RSS feed to only have excerpts, but the main website RSS feed must ALWAYS be a full content feed.

The reason? The website in question is a sports website. I want to offer the RSS in full content for those who want it, but I also automatically post my own articles on my personal website (a few others do as well). When the article is posted to my own website, I want to only include the excerpt, with a link to the full original article.

I do not care the method used, whether code or plugin.

UPDATE

I have been working to try to get the methods described by Michael Ecklund and Ian Dunn to work. I have not been able to get either to work. Both methods still show the complete article in the RSS feed and not the excerpt.

I’m not sure if it makes a difference, but I just remembered I use the Advanced Excerpt plugin to manage the excerpts on my website. I have not tried disabling this plugin, as it controls the homepage, category pages, tags pages, author pages and more.

Related posts

Leave a Reply

4 comments

  1. My approach would be to:

    1. On the Reading Options page, set the For each article in a feed, show... option to Full Text so that, by default, feeds will include the entire post.
    2. Pass a custom URL parameter to each individual feed when you want the excerpt instead of the full text. e.g., http://example.com/author/username/feed?format=excerpt. Make sure you don’t use a reserved term for the parameter name.
    3. Hook into the feed creation process and modify the content based on whether or not the custom parameter is present in the current feed’s URL.
    4. If it is present, override the feed’s content to only display the excerpt instead of the full text.
    5. When you want the full content, just use the regular URL. e.g., http://example.com/author/username/feed.

    Here’s some code that does that, using format as the parameter name. You can use any parameter name you want, as long as you update each part of the code that references it. Put the code inside a functionality plugin.

    function truncateFeedContent( $content )
    {
        if( get_query_var( 'format' ) == 'excerpt' )
        {
            $content = get_the_excerpt();
            $content = apply_filters( 'the_excerpt_rss', $content );
        }
    
        return $content;
    }
    add_filter( 'the_content_feed', 'truncateFeedContent' );
    
    function addFormatQueryVar( $queryVars )
    {
        $queryVars[] = 'format';
    
        return $queryVars;
    }
    add_filter( 'query_vars', 'addFormatQueryVar' );
    

    To avoid a conflict with the Advanced Excerpt plugin, add this code to the functionality plugin as well. It will disable Advanced Excerpt’s functionality on feed URLs, but leave it in tact for all other pages.

    function stopAdvancedExcerptOnFeeds()
    {
        if( is_feed() )
            remove_filter( 'get_the_excerpt', array( 'AdvancedExcerpt', 'filter' ) );
    }
    add_action( 'pre_get_posts', 'stopAdvancedExcerptOnFeeds' );
    
  2. Plugin

    Here’s a tiny plugin that allows you to override the Full-Text/Summary feed option, through a simple GET parameter:

    <?php
    /**
     * Plugin Name: Feeds with Summary Or Full Text
     * Description: GET parameter _summary with values yes or no
     * Plugin URI:  http://wordpress.stackexchange.com/a/195197/26350
     */
    add_action( 'rss_tag_pre', function( $tag )
    {
        $summary = filter_input( INPUT_GET, '_summary', FILTER_SANITIZE_STRING );
        if( 'yes' === $summary )
            add_filter( 'option_rss_use_excerpt', '__return_true' );
        elseif( 'no' === $summary )
            add_filter( 'option_rss_use_excerpt', '__return_false' );
    } );
    

    It respects the current settings, without the GET parameter. I use the underscore to avoid possible name collisions, but otherwise I took on the challenge to keep the plugin very simple & short 😉 We could easily use the $tag argument, to constrain this to rss2 or atom, if needed. Remember to use cache busting parameters when testing this in your browser.

    Usage Examples

    example.tld/feed/?_summary=yes  // Summary
    example.tld/feed/?_summary=no   // Full Text
    example.tld/feed/               // Uses Default settings
    
    example.tld/author/anna/feed/?_summary=yes  // Summary
    example.tld/author/anna/feed/?_summary=no   // Full Text
    example.tld/author/anna/feed/               // Uses Default settings
    
  3. You would access a short version with excerpt on the address:
    http://www.dicazine.com.br/author/admin/feed?version=short

    The less the better:

    add_filter('the_content','author_feed_version',10);
    function author_feed_version($content) {
        if(is_feed()){
            if($_GET['version'] == 'version')
                $content = limit_words(strip_tags($content),100);
        }
        return $content;
    } function limit_words($string, $word_limit){ $words = explode(" ",$string); return implode(" ",array_splice($words,0,$word_limit)); }
  4. There is actually quite an easy approach to accomplish this particular task.

    METHOD ONE

    Follow these steps to easily create a custom RSS feed in your WordPress website:

    1. Create a custom page template. Name it your_custom_feed.php
    2. Paste the code in the first code block into your_custom_feed.php
    3. Upload your_custom_feed.php to your currently active WordPress
      theme directory.
    4. Paste the second code block into your currently active WordPress functions.php file.
    5. Deactivate and reactivate your theme for it to take effect.

    You can now access your Custom Feed at: your-domain.com/custom-feed/user-slug/

    Credits go to Joost de Valk for publishing an excellent article. However, I slightly modified his code from the original article.

    <?php
    /*
    Template Name: Custom Feed
    */
    
    //----------------------------------------
    //  CONFIGURE THIS
    //----------------------------------------
    $contentType = 'excerpt';// Enter 'excerpt' or 'content'
    $numposts = 5;// Enter number of posts to display for each author
    
    
    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    //  NO MORE CONFIGURATION NECESSARY
    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    
    function custom_rss_date( $timestamp = null ) {
        $timestamp = ($timestamp==null) ? time() : $timestamp;
        echo date(DATE_RSS, $timestamp);
    }
    
    function custom_rss_text_limit($string, $length, $replacer = '...') { 
        $string = strip_tags($string);
        if(strlen($string) > $length)
        return (preg_match('/^(.*)W.*$/', substr($string, 0, $length+1), $matches) ? $matches[1] : substr($string, 0, $length)) . $replacer;   
        return $string; 
    }
    
    function custom_rss_post_id() {
        global $wp_query;
        $thePostID = $wp_query->post->ID;
        return $thePostID;
    }
    
    $thePage = get_page(custom_rss_post_id());
    
    $posts = query_posts('showposts='.$numposts.'&author_name='.$thePage->post_name);
    
    $lastpost = $numposts - 1;
    
    header('Content-Type: ' . feed_content_type('rss-http') . '; charset=' . get_option('blog_charset'), true);
    echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>';
    ?>
    <rss version="2.0"
        xmlns:content="http://purl.org/rss/1.0/modules/content/"
        xmlns:wfw="http://wellformedweb.org/CommentAPI/"
        xmlns:dc="http://purl.org/dc/elements/1.1/"
        xmlns:atom="http://www.w3.org/2005/Atom"
        xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
        xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
        <?php do_action('rss2_ns'); ?>
    >
        <channel>
            <title>
            <?php bloginfo_rss('name'); wp_title_rss(); ?>
            </title>
            <atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
            <link>
            <?php bloginfo_rss('url') ?>
            </link>
            <description>
                <?php bloginfo_rss("description") ?>
            </description>
            <lastBuildDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_lastpostmodified('GMT'), false); ?></lastBuildDate>
            <language>
                <?php bloginfo_rss( 'language' ); ?>
            </language>
            <sy:updatePeriod><?php echo apply_filters( 'rss_update_period', 'hourly' ); ?></sy:updatePeriod>
            <sy:updateFrequency><?php echo apply_filters( 'rss_update_frequency', '1' ); ?></sy:updateFrequency>
            <?php foreach ($posts as $post) { ?>
            <item>
            <title><?php echo get_the_title($post->ID); ?></title>
            <link>
            <?php echo get_permalink($post->ID); ?>
            </link>
            <description>
           <?php 
                if(!empty($contentType) && $contentType == 'excerpt'){
                    echo '<![CDATA['.custom_rss_text_limit($post->post_content, 500).']]>';
                } elseif(!empty($contentType) && $contentType == 'content'){
                    echo '<![CDATA['.apply_filters('the_content', $post->post_content).']]>';
                }         
           ?>
           </description>
            <pubDate>
                <?php custom_rss_date( strtotime($post->post_date_gmt) ); ?>
            </pubDate>
            <guid><?php echo get_permalink($post->ID); ?></guid>
            </item>
            <?php } ?>
        </channel>
    </rss>
    

    You could place this in your current active WordPress theme functions.php file:

    // Tell the hourly cronjob what operation it needs to perform.
    add_action('update_custom_user_feeds', 'create_custom_user_feeds');
    
    // Create a cronjob to update our custom feeds hourly.
    function cron_custom_user_feeds(){
        if(!wp_next_scheduled('update_custom_user_feeds')){
            wp_schedule_event(current_time('timestamp'), 'hourly', 'update_custom_user_feeds');
        }
    }
    add_action('init', 'cron_custom_user_feeds');
    
    // Delete our hourly cronjob when the theme is changed.
    function clear_custom_user_feeds(){
        wp_clear_scheduled_hook('update_custom_user_feeds');
    }
    add_action('switch_theme', 'clear_custom_user_feeds');
    
    // Generate the custom user feeds
    function create_custom_user_feeds(){
        // "Custom Feed" is the main feed page.
        $feedParent = get_page_by_title('Custom Feed', 'OBJECT', 'page');
        if(!$feedParent){
            $pageData = array(
                'post_title' => 'Custom Feed',
                'post_name' => 'custom-feed',
                'post_status' => 'publish',
                'post_type' => 'page'
            );
            // Create custom user feed.
            $parentID = wp_insert_post($pageData);
        } else{
            $parentID = $feedParent->ID;    
        }
        $wpUsers = get_users();
        for($i = 0; $i < count($wpUsers); $i++){
            // Check if the custom user feed already exists.
            $userFeed = get_page_by_title($wpUsers[$i]->user_nicename, 'OBJECT', 'page');
            if(!$userFeed){
                $pageData = array(
                    'post_title' => $wpUsers[$i]->user_nicename,
                    'post_name' => $wpUsers[$i]->user_nicename,
                    'post_status' => 'publish',
                    'post_type' => 'page',
                    'post_parent' => $parentID
                );
                // Create custom user feed.
                $insertPage = wp_insert_post($pageData);
                if($insertPage){
                    // Assign our custom feed template.
                    update_post_meta($insertPage, '_wp_page_template', 'your_custom_feed.php');
                }
            }
        }
        // Attempt to flush caches
        wp_cache_flush();
        if(function_exists('w3tc_objectcache_flush')){
            w3tc_objectcache_flush();
        }
        if(function_exists('w3tc_pgcache_flush')){
            w3tc_pgcache_flush();
        }
        if(function_exists('w3tc_minify_flush')){
            w3tc_minify_flush();
        }
        if(function_exists('w3tc_dbcache_flush')){
            w3tc_dbcache_flush();
        }
    }
    

    Now, I’m not saying this solution is practical, but it works.

    Alternatively, you can possibly make some usage from this class I made which uses add_feed();

    METHOD TWO

    Directions for using this class method within your theme. (Note: This class could easily be integrated into a plugin.)

    1. Create a sub-directory in your currently active WordPress theme.
      Name it: “inc”. (Directory structure should look like:
      ./wp-content/themes/your_theme/inc/)
    2. Create a PHP file and place the code block below (Third/last code
      block in this answer) in the file. Save it as custom-feeds.php
    3. Upload custom-feeds.php into your “inc” directory.
    4. May need to deactivate and reactivate your theme for it to take
      effect.

    You can now access your Custom Feed at: your-domain.com/feed/custom-user-slug/

    Note: you can change the prefix “custom-” to anything you want. Just configure the settings in the class constructor.

    <?php
    if(!class_exists('custom_feeds')){
        class custom_feeds{
    
            private $feed_settings;
            private $feed_data;
    
            public function __construct(){
    
                // Configure the Feed
                $this->feed_settings['number_posts'] = -1;// # of feed items, -1 means all posts
                $this->feed_settings['content_type'] = 'excerpt';// Excerpt or Content
                $this->feed_settings['excerpt_length'] = 500;// if excerpt, display how many characters?
                $this->feed_settings['offset_posts'] = 0;// Skip # of recent posts
                $this->feed_settings['custom_prefix'] = 'custom';// domain.com/feed/{prefix}-feed-name/
                $this->feed_settings['signature_link'] = false;// add link back to your site after the content.
    
                // Specify what type of feed you want to create.
                $this->prepare_feed('user');// All users, nice names
                //$this->prepare_feed('user', 'some-user');// Specific user's nice name
    
                // Prepare the feed
                add_action('init', array($this, 'setup_custom_feeds')); 
            }
    
            public function setup_custom_feeds(){
                global $wp_rewrite;
                // Add a feed for each type.
                foreach($this->feed_data as $type => $posts){
                    add_feed($this->feed_settings['custom_prefix'].'-'.$type, call_user_func_array(array($this, 'display_feed'), array($type, $posts)));
                }   
                // Flush rewrite rules.
                $wp_rewrite->flush_rules();
                // Attempt to flush caches.
                $this->flush_all_caches();          
            }
    
            public function prepare_feed($type, $nice_name=NULL){ 
                if($type == 'user'){
                    if(!is_null($nice_name)){
                        // Get specified user.
                        $data[] = get_user_by('slug', $nice_name);
                    } else{
                        // Get all users.
                        $data = get_users();
                    }
                    // Find posts for our request.
                    for($i = 0; $i < count($data); $i++){
                        $userPosts = new WP_Query(array('posts_per_page' => intval($this->feed_settings['number_posts']), 'author_name' => $data[$i]->user_nicename, 'offset' => intval($this->feed_settings['offset_posts'])));
                        wp_reset_postdata();
                        if(!empty($userPosts->posts)){
                            $theData[$data[$i]->user_nicename] = $userPosts->posts;
                        }
                    }
                } 
                $this->feed_data = $theData;
            }
    
            public function display_feed($type, $posts){
                $current_feed = explode('/feed/', $this->self_link());
                if($this->feed_settings['custom_prefix'].'-'.$type == $current_feed[1]){
                    header('Content-Type: '.feed_content_type('rss-http').'; charset='.get_option('blog_charset'), true);
                    echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'.PHP_EOL;
                    echo '<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"';
                    do_action('rss2_ns');
                    echo '>'.PHP_EOL;
                    echo '<channel>'.PHP_EOL;
                    echo '<title>';
                    bloginfo_rss('name'); 
                    wp_title_rss();
                    echo '</title>'.PHP_EOL;
                    echo '<atom:link href="'.$this->self_link().'" rel="self" type="application/rss+xml" />'.PHP_EOL;
                    echo '<link>'.get_bloginfo_rss('url').'</link>'.PHP_EOL;
                    echo '<description>'.get_bloginfo_rss('description').'</description>'.PHP_EOL;
                    echo '<lastBuildDate>'.mysql2date('D, d M Y H:i:s +0000', get_lastpostmodified('GMT'), false).'</lastBuildDate>'.PHP_EOL;
                    echo '<language>'.get_bloginfo_rss('language').'</language>'.PHP_EOL;
                    echo '<sy:updatePeriod>'.apply_filters('rss_update_period', 'hourly').'</sy:updatePeriod>'.PHP_EOL;
                    echo '<sy:updateFrequency>'.apply_filters('rss_update_frequency', '1').'></sy:updateFrequency>'.PHP_EOL;
                    // Begin displaying posts in our feed.
                    foreach($posts as $post){
                        echo '<item>'.PHP_EOL;
                        echo '<title>'.$post->post_title.'</title>'.PHP_EOL;
                        echo '<link>'.get_permalink($post->ID).'</link>'.PHP_EOL;
                        echo '<description>'.PHP_EOL;
                        if($this->feed_settings['signature_link']){
                            $feed_signature = '<h3>Original Post:<br /> <a title="'.$post->post_title.'" href="'.get_permalink($post->ID).'">'.$post->post_title.'</a></h3>';
                        } else{
                            $feed_signature = '';
                        }
                        if(!empty($this->feed_settings['content_type']) && $this->feed_settings['content_type'] == 'excerpt'){
                            echo '<![CDATA['.$this->custom_rss_text_limit($post->post_content, intval($this->feed_settings['excerpt_length'])).$feed_signature.']]>'.PHP_EOL;
    
                        } elseif(!empty($this->feed_settings['content_type']) && $this->feed_settings['content_type'] == 'content'){
                            echo '<![CDATA['.apply_filters('the_content', $post->post_content).$feed_signature.']]>'.PHP_EOL;
                        }         
                        echo '</description>'.PHP_EOL;
                        echo '<pubDate>'.$this->custom_rss_date(strtotime($post->post_date_gmt)).'</pubDate>'.PHP_EOL;
                        echo '<guid>'.$post->guid.'</guid>'.PHP_EOL;
                        echo '</item>'.PHP_EOL;
                    }
                    echo '</channel>'.PHP_EOL;
                    echo '</rss>'.PHP_EOL;
                }
            }
    
            private function custom_rss_date($timestamp = null){
                $timestamp = ($timestamp==null) ? time() : $timestamp;
                return date(DATE_RSS, $timestamp);
            }
    
            private function custom_rss_text_limit($string, $length, $replacer = '...'){ 
                $string = strip_tags($string);
                if(strlen($string) > $length)
                    return (preg_match('/^(.*)W.*$/', substr($string, 0, $length+1), $matches) ? $matches[1] : substr($string, 0, $length)) . $replacer;   
                return $string; 
            }
    
            private function self_link(){
                $host = @parse_url(home_url());
                $host = $host['host'];
                $return = esc_url(
                    'http'
                    . ( (isset($_SERVER['https']) && $_SERVER['https'] == 'on') ? 's' : '' ) . '://'
                    . $host
                    . stripslashes($_SERVER['REQUEST_URI'])
                );
                return $return;
            }
    
            private function flush_all_caches(){
                wp_cache_flush();
                if(function_exists('w3tc_objectcache_flush')){
                   w3tc_objectcache_flush();
                }
                if(function_exists('w3tc_pgcache_flush')){
                   w3tc_pgcache_flush();
                }
                if(function_exists('w3tc_minify_flush')){
                   w3tc_minify_flush();
                }
                if(function_exists('w3tc_dbcache_flush')){
                   w3tc_dbcache_flush();
                }
            }
    
        }// END custom_feeds class.
    
        // Instantiate the class.
        $custom_feeds = new custom_feeds();
    
    }// END custom_feeds class exists.
    ?>
    

    Note: I don’t know how well it would perform on large scale websites. Although, the way I have setup this class, allows for easy manipulation. You could use this same class for generating feeds of a custom post type, or custom taxonomy as well. My Custom Feeds class has been tested on WordPress 3.4.1 and works correctly.

    If you wanted to use it the way I have it currently setup, all you would need to do is configure the feed settings in the class constructor.