Home
Softono

Wp Combine Queries

Open source MIT PHP
70
Stars
10
Forks
1
Issues
4
Watchers
4 years
Last Commit

 About Wp Combine Queries

WordPress: Combine multiple WPQuery() queries into a single one, through the custom 'combinedquery' attribute of the WP_Query class.

Platforms

Web Self-hosted

Languages

PHP

Links

Need Help Installing Wp Combine Queries?

We provide expert installation service for this software. Our team will install, configure, and secure Wp Combine Queries on your server. plans start at just $30.

Wp Combine Queries

View on GitHub

Combine Query

WordPress plugin - Combine Query

Build Status GitHub license Packagist

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+.

Settings

The supported settings for the combined_query attribute:

'combined_query' => [        
	'args'           => [ $args1, $args2, ... ], // Array (default [])
	'union'          => 'UNION',                 // String Possible values are UNION or UNION ALL (default UNION)
	'posts_per_page' => 10,                      // Integer 1,2,...
	'offset'         => 0,                       // Integer 0,1,...
	'orderby'        => 'meta_value_num',        // String (post_name, ..., name, ..., none, meta_value, meta_value_num )
	'order'          => 'DESC',                  // String (ASC,DESC)
]

If you want to remove duplicated posts use UNION, else use 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;
});

To keep the order by arguments arg1, arg2, ... use:

'combined_query' => [
    ...
    'orderby' => 'none',
    ...
]

or

add_filter( 'cq_orderby', '__return_empty_string' );
$query = new WP_Query( $args );
remove_filter( 'cq_orderby', '__return_empty_string' );

Installation

Upload the plugin to the plugin folder and activate it.

To install dependencies with Composer (not required):

composer install

or

php composer.phar install

within our folder. See here for more information on how to install Composer.

Then play with the examples below, in your theme or in a plugin.

Have fun ;-)

Example 1:

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 = [
	'combined_query' => [        
		'args'           => [ $args1, $args2 ],
		'union'          => 'UNION',
		'posts_per_page' => 4,
		'orderby'        => 'none',
	]
];

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

Example 2:

Here we want to display all foo posts with a date query, sorted by comment count and after that all bar posts sorted by comment count. Then we sort all by decreasing comment count.

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

//-----------------   
// Sub query #2:
//-----------------
$args2 = [
	'post_type'           => 'bar',
	'orderby'             => 'comment_count',
	'order'               => 'desc',
	'posts_per_page'      => 100, // adjust to your needs
];

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

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

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 sub fields:
add_filter( 'cq_sub_fields', $callback = function( $fields ) {
    return $fields . ', meta_value';
});

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

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

remove_filter( 'cq_sub_fields', $callback );

Example 4:

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

 $args = [ 
    'combined_query' => [        
	'args' => [ $args1, $args2, $args3, $args4 ],
	...
    ]
  ];

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

Example 5:

The above examples are all for secondary queries. So let's add a query 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',
	];

	//-----------------
	// Original query #2:
	//-----------------    
	$args2 = $q->query;

	//---------------------------
	// Combined queries #1 + #2:
	//---------------------------
	$args = [
		'combined_query' => [
			'args'           => [ $args1, $args2 ],
			'union'          => 'UNION',
			'posts_per_page' => 4,
			'orderby'        => 'none',
		]
	];
    
	//-----------------------
	// Modify the Main query:
	//-----------------------
	$q->set( 'combined_query', $args['combined_query'] );
    }
} );

Changelog

(2022-03-03)

  • Fixed: Wrong plugin URI in header (Props: therealgilles)

1.2.2 (2021-02-20)

  • Fixed: Fixes #14 regarding subsequent queries. (Props: @Suranex)

1.2.1 (2020-09-14)

  • Fixed: Readme.

1.2.0 (2020-09-14)

  • Added: Support for ordering by 'none'.
  • Added: Test cases.
  • Added: Support for adding parameters (posts_per_page, offset, orderby, order) inside combined_query args.
  • Fixed: Hooks handling for pre_get_posts example.
  • Adjusted: Examples.

1.1.1 (2020-09-04)

  • Added: Example how to keep the order by arguments arg1, arg2, ...
  • Adjusted: UNION ALL test

1.1.0 (2020-09-04)

  • Added: Ticket #19 - Add test cases for argument order workaround. (Props: therealgilles)
  • Cleanup: phpcs

1.0.5 (2016-05-08)

  • Fixed: Ticket #8 - Fallback for those who don't use Composer.
  • Improved: Removed an explicit call to $GLOBALS['wpdb'] through the use keyword.
  • Improved: Simplified the namespace to only CombinedQuery.

1.0.4 (2016-04-21)

  • Fixed: Adjusted the paged bug that sneaked in with verion 1.0.2 yesterday.
  • Improved: Simplified the example that uses get_query_var() that can now handle default as an input parameter.

1.0.3 (2016-04-21)

  • Fixed: Ticket #7 - Not able to set the "UNION ALL" union option
  • Improved: Inline docs

1.0.2 (2016-04-20)

  • Fixed: Ticket #6 - Escape % in the Generator class. (Props: @DArcMattr)
  • Improved: Inline docs

1.0.1 (2015-11-09)

  • Fixed: Remove vendor dependency and let the user install it via 'composer install' (Props: @pdufour)
  • Fixed: Ignore sticky posts in the EmptyQuery class

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)