2011-09-16 08:10:12 +00:00
< ? php
/**
* Contains the query functions for WooCommerce which alter the front - end post queries and loops .
*
2012-01-27 16:38:39 +00:00
* @ class WC_Query
2011-09-16 08:10:12 +00:00
* @ package WooCommerce
* @ category Class
* @ author WooThemes
*/
2012-01-27 16:38:39 +00:00
class WC_Query {
2011-09-16 08:10:12 +00:00
2011-11-15 15:15:12 +00:00
var $unfiltered_product_ids = array (); // Unfiltered product ids (before layered nav etc)
var $filtered_product_ids = array (); // Filtered product ids (after layered nav)
var $post__in = array (); // Product id's that match the layered nav + price filter
2011-09-16 08:10:12 +00:00
var $meta_query = '' ; // The meta query for the page
2011-11-15 15:15:12 +00:00
var $layered_nav_post__in = array (); // posts matching layered nav only
2011-09-16 08:10:12 +00:00
var $layered_nav_product_ids = array (); // Stores posts matching layered nav, so price filter can find max price in view
/** constructor */
function __construct () {
2011-12-22 19:55:08 +00:00
add_filter ( 'pre_get_posts' , array ( & $this , 'pre_get_posts' ) );
2012-03-26 14:34:23 +00:00
add_filter ( 'the_posts' , array ( & $this , 'the_posts' ), 11 , 2 );
2011-12-22 19:55:08 +00:00
add_filter ( 'wp' , array ( & $this , 'remove_product_query' ) );
2011-09-16 08:10:12 +00:00
}
2011-12-22 19:55:08 +00:00
2011-09-16 08:10:12 +00:00
/**
2011-12-22 19:55:08 +00:00
* Hook into pre_get_posts to do the main product query
2011-09-16 08:10:12 +00:00
*/
2012-03-02 21:34:17 +00:00
function pre_get_posts ( $q ) {
2012-03-05 14:43:55 +00:00
global $woocommerce ;
2012-03-02 21:34:17 +00:00
// Only apply to product categories, the product post archive, the shop page, product tags, and product attribute taxonomies
2011-10-04 09:32:42 +00:00
if (
2012-03-26 14:34:23 +00:00
( ! $q -> is_main_query () ) // Abort if this isn't the main query
||
( ! $q -> is_post_type_archive ( 'product' ) && ! $q -> is_tax ( array_merge ( array ( 'product_cat' , 'product_tag' ), $woocommerce -> get_attribute_taxonomy_names () ) ) ) // Abort if we're not on a post type archive/prduct taxonomy
2011-10-04 09:32:42 +00:00
)
return ;
2012-03-02 21:34:17 +00:00
$this -> product_query ( $q );
2011-12-22 19:55:08 +00:00
// We're on a shop page so queue the woocommerce_get_products_in_view function
add_action ( 'wp' , array ( & $this , 'get_products_in_view' ), 2 );
// And remove the pre_get_posts hook
remove_filter ( 'pre_get_posts' , array ( & $this , 'pre_get_posts' ) );
}
2012-03-26 14:34:23 +00:00
/**
* Hook into the_posts to do the main product query if needed - relevanssi compatibility
*/
function the_posts ( $posts , $query = false ) {
global $woocommerce ;
if (
( ! $query ) // Abort if theres no query
||
( empty ( $this -> post__in ) ) // Abort if we're not filtering posts
||
( ! empty ( $query -> wc_query ) ) // Abort if this query is already done
||
( empty ( $query -> query_vars [ " s " ] ) ) // Abort if this isn't a search query
||
( ! $query -> is_post_type_archive ( 'product' ) && ! $query -> is_tax ( array_merge ( array ( 'product_cat' , 'product_tag' ), $woocommerce -> get_attribute_taxonomy_names () ) ) ) // Abort if we're not on a post type archive/prduct taxonomy
)
return $posts ;
$filtered_posts = array ();
$queried_post_ids = array ();
foreach ( $posts as $post ) {
if ( in_array ( $post -> ID , $this -> post__in ) ) {
$filtered_posts [] = $post ;
$queried_post_ids [] = $post -> ID ;
}
}
$query -> posts = $filtered_posts ;
$query -> post_count = count ( $filtered_posts );
// Ensure filters are set
$this -> unfiltered_product_ids = $queried_post_ids ;
$this -> filtered_product_ids = $queried_post_ids ;
if ( sizeof ( $this -> layered_nav_post__in ) > 0 ) {
$this -> layered_nav_product_ids = array_intersect ( $this -> unfiltered_product_ids , $this -> layered_nav_post__in );
} else {
$this -> layered_nav_product_ids = $this -> unfiltered_product_ids ;
}
return $filtered_posts ;
}
2011-12-22 19:55:08 +00:00
/**
* Query the products , applying sorting / ordering etc . This applies to the main wordpress loop
*/
function product_query ( $q ) {
2012-02-10 22:15:29 +00:00
2011-09-23 11:04:51 +00:00
// Meta query
2011-09-16 08:10:12 +00:00
$meta_query = ( array ) $q -> get ( 'meta_query' );
2011-09-23 11:04:51 +00:00
$meta_query [] = $this -> visibility_meta_query ();
$meta_query [] = $this -> stock_status_meta_query ();
2011-09-16 08:10:12 +00:00
// Ordering
2011-09-23 11:04:51 +00:00
$ordering = $this -> get_catalog_ordering_args ();
2011-09-16 08:10:12 +00:00
// Get a list of post id's which match the current filters set (in the layered nav and price filter)
2012-03-02 21:34:17 +00:00
$post__in = array_unique ( apply_filters ( 'loop_shop_post_in' , array ()));
2011-09-16 08:10:12 +00:00
// Ordering query vars
2011-09-23 11:04:51 +00:00
$q -> set ( 'orderby' , $ordering [ 'orderby' ] );
$q -> set ( 'order' , $ordering [ 'order' ] );
if ( isset ( $ordering [ 'meta_key' ])) $q -> set ( 'meta_key' , $ordering [ 'meta_key' ] );
2011-09-16 08:10:12 +00:00
// Query vars that affect posts shown
2011-10-06 10:46:19 +00:00
if ( ! $q -> is_tax ( 'product_cat' ) && ! $q -> is_tax ( 'product_tag' )) $q -> set ( 'post_type' , 'product' );
2011-09-16 08:10:12 +00:00
$q -> set ( 'meta_query' , $meta_query );
$q -> set ( 'post__in' , $post__in );
2012-01-07 18:31:49 +00:00
$q -> set ( 'posts_per_page' , ( $q -> get ( 'posts_per_page' )) ? $q -> get ( 'posts_per_page' ) : apply_filters ( 'loop_shop_per_page' , get_option ( 'posts_per_page' ) ) );
2011-09-16 08:10:12 +00:00
2012-03-26 14:34:23 +00:00
// Set a special variable
$q -> set ( 'wc_query' , true );
2011-09-16 08:10:12 +00:00
// Store variables
$this -> post__in = $post__in ;
$this -> meta_query = $meta_query ;
}
2011-12-22 19:55:08 +00:00
2011-09-16 08:10:12 +00:00
/**
2011-12-22 19:55:08 +00:00
* Remove the query
2011-09-16 08:10:12 +00:00
*/
2011-12-22 19:55:08 +00:00
function remove_product_query () {
remove_filter ( 'pre_get_posts' , array ( & $this , 'pre_get_posts' ) );
2011-09-16 08:10:12 +00:00
}
/**
2011-11-13 02:15:00 +00:00
* Get an unpaginated list all product ID ' s ( both filtered and unfiltered ) . Makes use of transients .
2011-09-16 08:10:12 +00:00
*/
2012-03-02 21:34:17 +00:00
function get_products_in_view () {
2011-09-16 08:10:12 +00:00
global $wp_query ;
$unfiltered_product_ids = array ();
2011-11-13 02:15:00 +00:00
// Get WP Query for current page (without 'paged')
$current_wp_query = $wp_query -> query ;
unset ( $current_wp_query [ 'paged' ]);
// Generate a transient name based on current query
2012-03-16 16:39:16 +00:00
$transient_name = 'wc_uf_pid_' . md5 ( http_build_query ( $current_wp_query ) );
$transient_name = ( is_search ()) ? $transient_name . '_s' : $transient_name ;
2011-11-13 02:15:00 +00:00
2012-03-02 21:34:17 +00:00
if ( false === ( $unfiltered_product_ids = get_transient ( $transient_name ) ) ) {
2011-11-13 02:15:00 +00:00
// Get all visible posts, regardless of filters
$unfiltered_product_ids = get_posts (
array_merge (
$current_wp_query ,
array (
'post_type' => 'product' ,
'numberposts' => - 1 ,
'post_status' => 'publish' ,
'meta_query' => $this -> meta_query ,
'fields' => 'ids' ,
'no_found_rows' => true
)
2011-09-16 08:10:12 +00:00
)
2011-11-13 02:15:00 +00:00
);
2012-03-02 21:34:17 +00:00
set_transient ( $transient_name , $unfiltered_product_ids );
}
2011-09-16 08:10:12 +00:00
// Store the variable
2012-03-02 21:34:17 +00:00
$this -> unfiltered_product_ids = $unfiltered_product_ids ;
2011-09-16 08:10:12 +00:00
// Also store filtered posts ids...
if ( sizeof ( $this -> post__in ) > 0 ) :
2012-03-26 14:34:23 +00:00
$this -> filtered_product_ids = array_intersect ( $this -> unfiltered_product_ids , $this -> post__in );
2011-09-16 08:10:12 +00:00
else :
$this -> filtered_product_ids = $this -> unfiltered_product_ids ;
endif ;
// And filtered post ids which just take layered nav into consideration (to find max price in the price widget)
2012-03-26 14:34:23 +00:00
if ( sizeof ( $this -> layered_nav_post__in ) > 0 ) :
$this -> layered_nav_product_ids = array_intersect ( $this -> unfiltered_product_ids , $this -> layered_nav_post__in );
2011-09-16 08:10:12 +00:00
else :
$this -> layered_nav_product_ids = $this -> unfiltered_product_ids ;
endif ;
}
2011-09-23 11:04:51 +00:00
/**
* Returns an array of arguments for ordering products based on the selected values
*/
function get_catalog_ordering_args () {
2012-03-19 12:16:33 +00:00
$current_order = ( isset ( $_SESSION [ 'orderby' ])) ? $_SESSION [ 'orderby' ] : apply_filters ( 'woocommerce_default_catalog_orderby' , get_option ( 'woocommerce_default_catalog_orderby' ));
2011-09-23 11:04:51 +00:00
switch ( $current_order ) :
case 'date' :
$orderby = 'date' ;
$order = 'desc' ;
$meta_key = '' ;
break ;
case 'price' :
$orderby = 'meta_value_num' ;
$order = 'asc' ;
2011-12-24 17:05:51 +00:00
$meta_key = '_price' ;
2011-09-23 11:04:51 +00:00
break ;
default :
$orderby = 'title' ;
$order = 'asc' ;
$meta_key = '' ;
break ;
endswitch ;
$args = array ();
$args [ 'orderby' ] = $orderby ;
$args [ 'order' ] = $order ;
if ( $meta_key ) $args [ 'meta_key' ] = $meta_key ;
2011-11-17 14:32:42 +00:00
return apply_filters ( 'woocommerce_get_catalog_ordering_args' , $args );
2011-09-23 11:04:51 +00:00
}
/**
* Returns a meta query to handle product visibility
*/
function visibility_meta_query ( $compare = 'IN' ) {
if ( is_search () ) $in = array ( 'visible' , 'search' ); else $in = array ( 'visible' , 'catalog' );
$meta_query = array (
2011-12-24 17:05:51 +00:00
'key' => '_visibility' ,
2011-09-23 11:04:51 +00:00
'value' => $in ,
'compare' => $compare
);
return $meta_query ;
}
/**
* Returns a meta query to handle product stock status
*/
function stock_status_meta_query ( $status = 'instock' ) {
$meta_query = array ();
if ( get_option ( 'woocommerce_hide_out_of_stock_items' ) == 'yes' ) :
$meta_query = array (
2011-12-24 17:05:51 +00:00
'key' => '_stock_status' ,
2011-09-23 11:04:51 +00:00
'value' => $status ,
'compare' => '='
);
endif ;
return $meta_query ;
}
/**
2011-11-13 02:15:00 +00:00
* Get a list of product id ' s which should be hidden from the frontend ; useful for custom queries and loops . Makes use of transients .
2011-09-23 11:04:51 +00:00
*/
function get_hidden_product_ids () {
2012-03-16 16:39:16 +00:00
$transient_name = ( is_search ()) ? 'wc_hidden_product_ids_search' : 'wc_hidden_product_ids' ;
2011-11-13 02:15:00 +00:00
if ( false === ( $hidden_product_ids = get_transient ( $transient_name ) ) ) {
$meta_query = array ();
$meta_query [] = $this -> visibility_meta_query ( 'NOT IN' );
$meta_query [] = $this -> stock_status_meta_query ( 'outofstock' );
$hidden_product_ids = get_posts ( array (
'post_type' => 'product' ,
'numberposts' => - 1 ,
'post_status' => 'publish' ,
'meta_query' => $meta_query ,
'fields' => 'ids' ,
'no_found_rows' => true
));
set_transient ( $transient_name , $hidden_product_ids );
}
2011-09-23 11:04:51 +00:00
return ( array ) $hidden_product_ids ;
}
2011-09-16 08:10:12 +00:00
}