Skip to content

Latest commit

 

History

History
369 lines (294 loc) · 10.1 KB

README.md

File metadata and controls

369 lines (294 loc) · 10.1 KB

Combined Query

WordPress plugin - Combined Query

###Description

This experimental plugin allows you to combine multiple WP_Query queries into a single one, using the combined_query attribute.

This started as an answer on Stackoverflow, see here and here.

The idea behind this plugin is to combine the SQL queries for each WP_Query() query with UNION or UNION ALL.

I first noticed this technique in a great answer on WordPress Development by Mike Schinkel.

I use the trick mentioned here to preserve the order of UNION sub queries.

This implementation supports combining N sub-queries.

###Notice about the new 1.0.0 version

This version is a total rewrite of the plugin.

The WP_Combine_Query class has been removed in favour of simply using the combined_query attribute of the WP_Query class.

Now the plugin only supports PHP versions 5.4+.

###Default Settings

The default setup for the combined_query attribute:

'combined_query' => [        
    'args'   => [],         // [ $args1, $args2, ... ]
    'union'  => 'UNION',    // Possible values are UNION or UNION ALL
 ]

###Custom filters

There are two custom filters currently available:

// Modify combined ordering:
add_filter( 'cq_orderby', function( $orderby ) {
    return $orderby;
});

// Modify sub fields:
add_filter( 'cq_sub_fields', function( $fields ) {
    return $fields;
});

###Installation

Upload the plugin to your plugin folder and activate it.

Then use some of the examples below in your theme or a plugin.

###Example 1a:

Here we want to display the first published page in an alphabetical order and then the three oldest published posts:

//-----------------
// Sub query #1:
//-----------------
$args1 = [
   'post_type'      => 'page',
   'posts_per_page' => 1,
   'orderby'        => 'title',
   'order'          => 'asc',
];

//-----------------
// Sub query #2:
//-----------------
$args2 = [
   'post_type'      => 'post',
   'posts_per_page' => 3,
   'orderby'        => 'date',
   'order'          => 'asc',
];

//---------------------------
// Combined queries #1 + #2:
//---------------------------
$args = [
    'posts_per_page' => 4,
    'combined_query' => [        
        'args'   => [ $args1, $args2 ],
        'union'  => 'UNION',
    ]
];

//---------
// Output:
//---------
$q = new WP_Query( $args );
if( $q->have_posts() ):
?><ul><?php
    while( $q->have_posts() ): $q->the_post();
        ?><li><a href="<?php the_permalink();?>"><?php the_title();?></a></li><?php
    endwhile;
?></ul><?php
    wp_reset_postdata();
else:
    _e( 'Sorry no posts found!' );
endif;       

###Example 1b:

If we want to order the combined query in example 1a, we can use for example:

//---------------------------
// Combined queries #1 + #2:
//---------------------------
$args = [
    'posts_per_page' => 4,
    'orderby'        => [ 'date' => 'asc', 'title' => 'desc' ]
    'combined_query' => [        
        'args'   => [ $args1, $args2 ],
    ]
];

###Example 2:

Here we want to display all posts published today, sorted by comment count and after that all posts (excluding today's post) sorted by comment count. This example was provided by Robert Hue.

//-----------------
// Sub query #1:
//-----------------
$args1 = [ 
    'post_type'           => 'post',
    'orderby'             => 'comment_count',
    'posts_per_page'      => 100, // adjust to your needs
    'date_query'          => [
        [
            'after' => date('Y-m-d'),
        ],
        'inclusive'  => true,
     ]
];

//-----------------   
// Sub query #2:
//-----------------
$args2 = [
    'post_type'           => 'post',
    'orderby'             => 'comment_count',
    'posts_per_page'      => 100, // adjust to your needs
    'date_query'          => [
        [
           'before' => date('Y-m-d'),
        ],
        'inclusive'  => false,
     ]
];

//--------------------------- 
// Combined queries #1 + #2:
//---------------------------
$args = [
    'posts_per_page'      => 5,
    'ignore_sticky_posts' => 1,
    'paged'               => ( $paged = get_query_var( 'page' ) ) ? $paged : 1 ,
    'combined_query' => [        
        'args'   => [ $args1, $args2 ],
    ]
);

//---------
// Output:
//---------
// See example 1a

###Example 3:

Let's combine two meta queries and order by a common meta value:

//-----------------
// Sub query #1:
//-----------------
$args1 = [
   'post_type'      => 'cars',
   'posts_per_page' => 10,
   'orderby'        => 'title',
   'order'          => 'asc',
   'meta_query'     => [
        [
            'key'      => 'doors',
            'value'    => 0,
            'compare'  => '>=',
            'type'     => 'UNSIGNED'
        ],
    ],
];

//-----------------
// Sub query #2:
//-----------------
$args2 = [
   'post_type'      => 'post',
   'posts_per_page' => 10,
   'orderby'        => 'date',
   'order'          => 'desc',
   'tax_query' => [
        [
            'taxonomy' => 'category',
            'field'    => 'slug',
            'terms'    => 'cars',
        ],
    ],
    'meta_query'     => [
        [
            'key'      => 'doors',
            'value'    => 0,
            'compare'  => '>=',
            'type'     => 'UNSIGNED'
        ],
    ],  
];


//------------------------------
// Order by a common meta value
//------------------------------

// Modify combined ordering:
add_filter( 'cq_orderby', function( $orderby ) {
    return 'meta_value ASC';
});

// Modify sub fields:
add_filter( 'cq_sub_fields', function( $fields ) {
    return $fields . ', meta_value';
});

//---------------------------
// Combined queries #1 + #2:
//---------------------------
$args = [
    'posts_per_page' => 5,
    'orderby'        => 'meta_value',
    'order'          => 'DESC',
    'combined_query' => [        
        'args'   => [ $args1, $args2 ],
    ]
];

//---------
// Output:
//---------
// See example 1a

###Example 4:

We could also combine more than two sub queries, here's an example of four sub-queries:

 $args = [ 
     'posts_per_page' => 10,
     'paged'          => 1,
     'combined_query' => [        
         'args'   => [ $args1, $args2, $args3, $args4 ],
     ]
  ];

//---------
// Output:
//---------
// See example 1a

###Example 5:

The above examples are all for secondary queries. So let's apply Example #1a to the main home query.

add_action( 'pre_get_posts', function( \WP_Query $q )
{   
    if( $q->is_home() && $q->is_main_query() )
    {
        //-----------------
        // Sub query #1:
        //-----------------
        $args1 = [
           'post_type'	=> 'page',
           'posts_per_page' => 1,
           'orderby'        => 'title',
           'order'          => 'asc',
        ];

        //-----------------
        // Sub query #2:
        //-----------------
        $args2 = [
           'post_type'      => 'post',
           'posts_per_page' => 3,
           'orderby'        => 'date',
           'order'          => 'asc',
        ];
    
        //---------------------------
        // Combined queries #1 + #2:
        //---------------------------
        $args = [
            'posts_per_page' => 4,
            'combined_query' => [
                'args'   => [ $args1, $args2 ],
                'union'  => 'UNION',
            ]
        ];

        //-----------------------
        // Modify the Main query:
        //-----------------------
        $q->set( 'combined_query',	$args['combined_query'] );
        $q->set( 'posts_per_page',  $args['posts_per_page'] );
    }
} );

###Changelog

1.0.0 (2015-05-10)

  • ** Total Plugin Rewrite **
  • Closed: Ticket #3
  • Added: New classes Main, EmptyQuery and Generator.
  • Added: Support for 'combined_query' attribute of the WP_Query class.
  • Added: Support only for PHP 5.4+
  • Added: Autoload via Composer.
  • Added: New filter 'cq_sub_fields' instead of 'cq_sub_fields'
  • Added: New filter 'cq_orderby' instead of 'cq_orderby'

0.1.3 (2015-05-09)

  • Added: Support for ignory_sticky_posts.
  • Fixed: Minor

0.1.2 (2015-05-08)

  • Added: Support for the GitHub Updater.
  • Added: New filter 'wcq_sub_fields'
  • Added: New filter 'wcq_orderby'
  • Added: New example for meta value ordering
  • Fixed: Ordering didn't work correctly.

0.1.1

  • Changed: Coding style and autoloading (Props: @egill)

0.1 Various plugin improvements, for example:

  • Added: orderby in the combined query.
  • Added: posts_per_page in the sub queries.
  • Added: offset in the sub queries.
  • Added: paged in the sub queries.
  • Removed: sublimit in the combined query, use posts_per_page instead in sub queries.
  • Fixed: Issue #1 related to max_num_pages (Props: @hellofantastic).

0.0.4

  • Added: support for offset in the combined query

0.0.3

  • Added: GPL2+ License part
  • Removed: Dropped namespace + anonymous function for wider PHP support.

0.0.2

  • Added: Input parameter 'union' with possible values UNION and UNION ALL.
  • Fixed: Empty paged resulted in a sql error. (Props: Robert Hue)