Is it possible to request several post types from a feed?

You could use add_feed() and create new feeds … for each post type combination a separate feed. That’s not what I would call flexible, so I recommend to create an endpoint.

The following code creates an endpoint for the root of a WordPress installation. After refreshing the permalinks you get a regular feed at /multifeed/ (for pages only) or /multifeed/post+page+custom/ for almost any given combination.

I am not sure why, but it seems not to work for attachments.

<?php
/*
 * Plugin Name: T5 Multi Post Type Feed
 */

add_action(
    'init',
    array ( T5_Multi_Post_Type_Feed::get_instance(), 'plugin_setup' )
);
class T5_Multi_Post_Type_Feed
{
    /**
     * Plugin instance.
     *
     * @see get_instance()
     * @type object
     */
    protected static $instance = NULL;

    /**
     * Internal handler for WordPress
     *
     * @type string
     */
    protected static $query_var="multifeed";

    /**
     * Access this plugin’s working instance
     *
     * @wp-hook init
     * @since   2012.10.03
     * @return  object of this class
     */
    public static function get_instance()
    {
        NULL === self::$instance and self::$instance = new self;

        return self::$instance;
    }

    /**
     * Used for regular plugin work.
     *
     * @wp-hook init
     * @since   2012.10.03
     * @return  void
     */
    public function plugin_setup()
    {
        add_rewrite_endpoint( self::$query_var, EP_ROOT );
        add_filter( 'request', array ( $this, 'set_query_var' ) );
        // Hook in late to allow other plugins to operate earlier.
        add_action( 'template_redirect', array ( $this, 'render' ), 100 );
    }

    /**
     * Print the feed items.
     *
     * @wp-hook template_redirect
     * @since   2012.10.03
     * @return void
     */
    public function render()
    {
        if ( ! is_front_page() or ! get_query_var( self::$query_var ) )
        {
            return;
        }

        $args       = get_query_var( self::$query_var );
        $post_types = array_filter( explode( '+', $args ) );
        query_posts( array ( 'post_type' => $post_types ) );
        // make the post object accessible in this scope. Hat tip to @Rarst. :)
        global $post;
        require WPINC . '/feed-rss2.php';
        exit;
    }

    /**
     * Set the endpoint variable to a default value.
     *
     * If the endpoint was called without further parameters it does not
     * evaluate to TRUE otherwise.
     *
     * @wp-hook request
     * @since   2012.10.03
     * @param   array $vars
     * @return  array
     */
    public function set_query_var( $vars )
    {
        // make the following code shorter
        $q       = self::$query_var;
        $default = apply_filters( 't5_multipost_default_type', 'page' );

        if ( isset ( $vars[ $q ] ) and '' === $vars[ $q ] )
        {
            $vars[ $q ] = $default;
        }

        // Sometimes WP misinterprets the request as a page request
        // and returns a 404.
        if ( ( isset ( $vars['pagename'] ) and $q === $vars['pagename'] )
            or ( isset ( $vars['page'] )
                and isset ( $vars['name'] )
                and $q === $vars['name']
            )
        )
        {
            $vars['page'] = $vars['pagename'] = $vars['name'] = FALSE;
            $vars[ $q ] = $default;
        }
        return $vars;
    }

    /**
     * Get the URL for our endpoint.
     *
     * Usage:
     * $url = T5_Multi_Post_Type_Feed::get_instance()->get_endpoint_url(
     *      array( 'post', 'attachment' )
     * );
     *
     * @return  string
     * @wp-hook plugin_row_meta
     * @since   2012.09.21
     * @return  string
     */
    public function get_endpoint_url( $types = array( 'page' ) )
    {
        $post_types = implode( '+', $types );
        // If that is false, there are no pretty permalinks.
        $has_permalinks = get_option( 'permalink_structure' );
        $home = home_url( "https://wordpress.stackexchange.com/" );

        if ( ! $has_permalinks )
        {
            return add_query_arg(
                array ( self::$query_var => $post_types ),
                $home
            );
        }

        return user_trailingslashit( $home . self::$query_var . "/$post_types" );
    }
}

Install as plugin, refresh your permalink settings by just visiting that page – and that’s it.

Leave a Comment