How to create an archive for all posts that do not have a post format?

The title says it all. I need working pagination, correct post count etc. Basically a new page for posts but with a filter for post formats.

Things I have tried so far:

Read More

1) Created a new rewrite rule for /no-formats/ that gets the id of the page that loads home.php and appends an argument (?no_post_format=true). Then hooked to ‘pre_get_posts’, checked for that argument and added a tax_query to the main query that excludes all posts with post formats.
This did not work because a rewrite rule to the home page causes a redirect to the actual home page. So /no-formats/ becomes /home/ and my argument is lost.

Not the actual code but to give you an idea of what I mean:

add_rewrite_rule( 'no-formats/?$', 'index.php?p='. get_option( 'page_for_posts' ) . '&no_post_format=true', 'top' );

2) Created a new page and tried to replicate the behavior of the page that displays posts and added the mentioned tax_query exclude. I just couldn’t come up with any way to get an exact duplication of the home page. Maybe have to dig deeper into WP core.

Does somebody have any ideas that could push me into the right direction?

Related posts

2 comments

  1. For me I’d used a little different approach:

    1. use an endpoint to create an url like http://example.com/no-formats/
    2. hooking pre_get_posts to set the proper query if needed
    3. filter template_include to force WP to use home.php instead of duplicating it

    No more.

    add_action('init', 'add_no_format_endpoint');
    
    function add_no_format_endpoint() {
      add_rewrite_endpoint( 'no-formats', EP_ROOT );
    }
    
    add_action('pre_get_posts', 'handle_no_format');
    
    function handle_no_format( $q ) {
      if ( $q->is_main_query() && is_home() && isset( $q->query['no-formats'] ) ) {
        unset( $q->query['no-formats'] );
        $q->is_home = FALSE; // <- add this if you have setted a static page as frontpage
        $tax_q =  array(
          'taxonomy' => 'post_format',
          'field' => 'id',
          'operator' => 'NOT IN',
          'terms' => get_terms( 'post_format', array( 'fields' => 'ids' ) )
        );
        $q->set( 'tax_query', array( $tax_q) );
        add_filter( 'template_include', 'force_home_template', 999 );
      }
    }
    
    function force_home_template() {
      return locate_template( array( 'home.php', 'index.php' ), FALSE );
    }
    

    Remember to visit Settings->Permalinks in you dashboard to flush rewrite rules.

  2. Edit

    Note: you can use the same technique for a custom page template, with a custom loop via new WP_Query():

    // Post Formats
    $post_formats_array = array(
        'post-format-aside',
        'post-format-audio',
        'post-format-chat',
        'post-format-gallery',
        'post-format-image',
        'post-format-link',
        'post-format-status',
        'post-format-quote',
        'post-format-video'
    );
    // Custom query args
    $standard_posts_query_args = array(    
        'tax_query' => array(
            array(
                'taxonomy' => 'post_format',
                'field' => 'slug',
                // Use array defined above,
                // or try omitting 'terms' entirely
                'terms' => $post_formats_array,             
                'operator' => 'NOT IN'
            )
        )
    );
    // Custom query
    $standard_posts = new WP_Query( $standard_posts_query_args );
    
    // Custom query loop
    if ( $standard_posts->have_posts() ) : while ( $standard_posts->have_posts() ) : $standard_posts->the_post();
        // Loop markup here
    endwhile; endif;
    

    Pagination

    For pagination, please refer to this Question/Answer.

    Original Answer

    Why not just exclude posts with post formats from the main posts archive?

    function wpse129372_filter_posts_archive( $query ) {
        if ( $query->is_main_query && $query->is_archive() ) {
            $post_formats_array = array(
                'post-format-aside',
                'post-format-audio',
                'post-format-chat',
                'post-format-gallery',
                'post-format-image',
                'post-format-link',
                'post-format-status',
                'post-format-quote',
                'post-format-video'
            );
            $tax_query = array(
                array(
                    'taxonomy' => 'post_format',
                    'field' => 'slug',
                    // Use array defined above,
                    // or try omitting 'terms' entirely
                    'terms' => $post_formats_array,             
                    'operator' => 'NOT IN'
                )
            );
            $query->set( 'tax_query', $tax_query );
        }
    }
    add_action( 'pre_get_posts', 'wpse129372_filter_posts_archive' );
    

    This, paired with (I assume) custom template files (or custom page templates) for posts with post formats, would be a fairly simple way to show only “standard” posts in the archive index.

Comments are closed.