How To List All Posts Of An Archive, A Category Or A Search Result

Archive pages are usually paged according to your settings in options/reading. Sometimes you may want to offer a page with all posts for an archive (time, category, search result).

You need:

  • a separate address for the unpaged archive,
  • a filter for the internal WordPress query and
  • a link to your ‘all posts’ page.

We put everything into a class to avoid name collisions and to keep the global namespace clean.
We name the file class.View_All_Posts.php.

Let’s start with the class, the parameter and a checker, this is easy:

class View_All_Posts
{
    /**
     * GET parameter to trigger a complete, not paged archive.
     * @var string
     */
    protected $all_param = 'all';

    /**
     * Are we there already?
     *
     * @return bool
     */
    public function is_all_posts()
    {
        return isset ( $_GET[$this->all_param] );
    }
}

For the address I use a very simple approach: a GET parameter named all. You may change the name here; just stay with ASCII chars from a—z. все_сообщения will get you in trouble!

Next we need a constructor that manages our work:

    public function __construct()
    {
        /* Register the query argument. */
        add_filter('query_vars', array ( $this, 'add_query_arg') );

        /* Hook into the query. */
        add_action('pre_get_posts', array ( $this, 'view_all_posts') );
    }

The constructor references two internal functions – add_query_arg() and view_all_posts(), which we build next:

    /**
     * Registers the query arg in WordPress.
     * Otherwise it will be unset.
     *
     * @param  array $vars Already registered query args.
     * @return array
     */
    public function add_query_arg( array $vars )
    {
        return array_merge( $vars, array ( $this->query_arg ) );
    }

    /**
     * Alters the query to remove the paging.
     * @return void
     */
    public function view_all_posts()
    {
        if ( ! $this->is_all_posts() )
        {
            return;
        }

        $GLOBALS['wp_query']->query_vars['nopaging'] = TRUE;

        return;
    }

The first function just registers our GET parameter in WordPress. The second alters the query to the database and removes the paging.

We are almost done. A template tag for the link would be nice, wouldn’t it?

    /**
     * Creates the markup for the link.
     *
     * Usage in archive.php, category.php or search.php:
     * $GLOBALS['view_all_posts']->get_allposts_link();
     *
     * @param  string $text Linktext
     * @param  bool   $print echo or return
     * @return string|void
     */
    public function get_allposts_link(
        $text   = 'View all posts'
    ,   $before = ';'
    ,   $print  = TRUE
    )
    {
        if ( $this->is_all_posts()
         or $GLOBALS['wp_query']->found_posts <= get_option('posts_per_page')
        )
        {   // No link needed.
            return;
        }

        if ( isset ( $_SERVER['QUERY_STRING'] )
            && ! empty ( $_SERVER['QUERY_STRING'] )
        )
        {
            /* We have already visible GET parameters: /?hello=world. */
            $new_url = $_SERVER['REQUEST_URI'] . '&';
        }
        else
        {
            /* Note the difference: REQUEST_URL doesn't include
             * the query string while REQUEST_URI does. */
            $new_url = $_SERVER['REQUEST_URL'] . '?';
        }

        $link = "$before$text$after";

        if ( $print )
        {
            print $link;
            return;
        }
        return $link;
    }

Note: $GLOBALS['wp_query']->found_posts holds the sum of all posts for a given query, not just for the current page. Useful if you want to print out the total number on a paged archive.

If you want to avoid duplicate content, hide the full archives from search engines in your header:

    /**
     * Prevents indexing from search engines.
     *
     * Add this as an action to 'wp_head'.
     *
     * @return void
     */
    public function meta_noindex()
    {
        if ( $this->is_all_posts() )
        {
             print '';
        }
    }

Our class is complete. Now we put an object of the class into the global namespace …

$GLOBALS['view_all_posts'] = new View_All_Posts;

… add an action to wp_head

add_action(
    'wp_head'
,   array ( $GLOBALS['view_all_posts'], 'meta_noindex' )
);

… and include the file into the functions.php of our theme:

require_once dirname(__FILE__) . DIRECTORY_SEPARATOR
    . 'class.View_All_Posts.php';

In our archive templates (archive.php, category.php, search.php) we print the link:

$GLOBALS['view_all_posts']->get_allposts_link();

Done.

Oh, wait … maybe you want to see the full code? And a download link?

Here’s the link: Download class.View_All_Posts.php

The complete code:

/**
 * Adds a view all posts page to any query.
 * @author Thomas Scholz http://toscho.de
 * @version 1.1
 */
class View_All_Posts
{
    /**
     * GET parameter to trigger a complete, not paged archive.
     * @var string
     */
    protected $all_param = 'all';

    public function __construct()
    {
        /* Register the query argument. */
        add_filter('query_vars', array ( $this, 'add_query_arg') );

        /* Hook into the query. */
        add_action('pre_get_posts', array ( $this, 'view_all_posts') );
    }

    /**
     * Registers the query arg in WordPress.
     * Otherwise it will be unset.
     *
     * @param  array $vars Already registered query args.
     * @return array
     */
    public function add_query_arg( array $vars )
    {
        return array_merge( $vars, array ( $this->query_arg ) );
    }

    /**
     * Alters the query to remove the paging.
     * @return void
     */
    public function view_all_posts()
    {
        if ( ! $this->is_all_posts() )
        {
            return;
        }

        $GLOBALS['wp_query']->query_vars['nopaging'] = TRUE;

        return;
    }

    /**
     * Are we there already?
     *
     * @return bool
     */
    public function is_all_posts()
    {
        return isset ( $_GET[$this->all_param] );
    }

    /**
     * Creates the markup for the link.
     *
     * Usage in archive.php, category.php or search.php:
     * $GLOBALS['view_all_posts']->get_allposts_link();
     *
     * @param  string $text Linktext
     * @param  bool   $print echo or return
     * @return string|void
     */
    public function get_allposts_link(
        $text   = 'View all posts'
    ,   $before = ''
    ,   $print  = TRUE
    )
    {
        if ( $this->is_all_posts()
        or $GLOBALS['wp_query']->found_posts <= get_option('posts_per_page')
        )
        {   // No link needed.
            return;
        }

        if ( isset ( $_SERVER['QUERY_STRING'] )
            && ! empty ( $_SERVER['QUERY_STRING'] )
        )
        {
            /* We have already visible GET parameters: /?hello=world. */
            $new_url = $_SERVER['REQUEST_URI'] . '&';
        }
        else
        {
            /* Note the difference: REQUEST_URL doesn't include
             * the query string while REQUEST_URI does. */
            $new_url = $_SERVER['REQUEST_URL'] . '?';
        }

         $link = "$before$text$after";

        if ( $print )
        {
            print $link;
            return;
        }
        return $link;
    }
}

$GLOBALS['view_all_posts'] = new View_All_Posts;

Mission completed. Any suggestions?

Guest Post

Thomas ScholzThis post is written by Thomas Scholz toscho.de, a good friend of us and a web designer from Halle, Germany.

Thank you very much from our part to Thomas.


Posted

in

by

Tags:

Comments

7 responses to “How To List All Posts Of An Archive, A Category Or A Search Result”

  1. Milemann Avatar
    Milemann

    Hi Thomas!

    looks realy good but … it dosen’t show anything on my test blogs…
    i’ve try it on wp3.0 and on wp2.9.2

    btw …
    wp3.0 does not show posts with post_status=future even when i try to show it with:

    $ main_query = new WP_Query ($ query_string. ‘Category_name = Concerts & post_status = publish, future & order = ASC’);

  2. Thomas Scholz Avatar

    @Milemann Where don’t you see anything? On the result page “/?all”?

    Do you get useful errors, when you turn error reporting on your wp-config.php?

    define(‘WP_DEBUG’, true);

  3. Milemann Avatar
    Milemann

    i’ve put the class file into the template folder,
    into funtions.php –
    require_once dirname(__FILE__) . DIRECTORY_SEPARATOR
    . ‘class.View_All_Posts.php’;
    into archive.php –
    “$GLOBALS[‘view_all_posts’]->get_allposts_link();”

    does it mean that in this case all postlinks should appear on each archiv site?

    i try to invoke the site with
    http://192.168.178.25/bbgwp/?m=201006&paged=all
    even with
    http://192.168.178.25/bbgwp/?m=201006

    i dont see the any postlinks either any errors??

  4. Thomas Scholz Avatar

    @Milemann The link will be displayed only if you have more posts in the archive than the normal page shows. This is checked by:

    $GLOBALS[‘wp_query’]->found_posts <= get_option('posts_per_page')

    To force the link set the post per page option to a very low value.

  5. Milemann Avatar
    Milemann

    ok!
    i’ve got it.
    I misunderstood the approach of your class …

    my other problem after update to 3.0
    i have the query in the archive.php like:
    $main_query = new WP_Query($query_string.’&post_status=publish,future&order=ASC’);
    to show planned events.

    i have a lot of future posts, when i want to get month archives with future date:
    http://192.168.178.25/bbgwp/?m=201009
    wo3.0 redirected to 404
    (in 2.9.2 it works pretty well)

    do you have an idea how to fix it??

  6. Obaid Mahmood Avatar

    Hi,
    I need help to make sidebar widget (header-images) customized. Like already at this website in right side column, each widget has its own header image. I want the same on my blog can you please help me with this? If required i can provide you my coding also.

    I appreciate your kind help in this regard.

  7. Michael Avatar

    Sorry Obaid, but we can’t offer such a service 😉