I'm currently using this code in my functions.php file to retrieve a list of products on sale when the URL parameter sale=1 is used. The function only returns 'simple' products though and not 'variable' products. Is there a way to modify it to get it to return 'variable' products as well?
add_action('pre_get_posts','sale_items');
function sale_items($query) {
if (!is_admin() && ($query->is_post_type_archive( 'product' ) || $query->is_tax( get_object_taxonomies( 'product' ))) && isset($_GET['sale']) && $_GET['sale'] == 1) {
$meta_query = array(
array(
'key' => '_sale_price',
'value' => 0,
'compare' => '>',
'type' => 'numeric'
)
);
$query->set('meta_query',$meta_query);
}
}
In order to get the new query to work with an AJAX Product Filter Plugin aswell, it will require some plugin modification and I would like to hire someone to do this.
Arnav Joy answers:
Hi Floy ,
I would like to work in your project let me know if you have interested my email is : [email protected]
floy comments:
Hey Arnav,
Please check your email for details!
floy comments:
Thanks for solving this one Arnav.
Works as expected.
Kyle answers:
Woocommerce uses 'product_type' as a taxonomy, so I am guessing in your query there that it reverts to searching simple by default.
Try adding this tax query to your meta query:
$tax_query = array(
array(
'key' => 'product_type',
'field' => 'slug',
'terms' => array( 'simple', 'variable' )
)
);
$query->set('tax_query',$tax_query);
Kyle comments:
Woocommerce hides it by default, but you can actually still view the taxonomy page for product type. Add this to your site url:
/wp-admin/edit-tags.php?taxonomy=product_type&post_type=product
Kyle comments:
Try this:
add_action('pre_get_posts','sale_items');
function sale_items($query) {
if (!is_admin() && ($query->is_post_type_archive( 'product' ) || $query->is_tax( get_object_taxonomies( 'product' ))) && isset($_GET['sale']) && $_GET['sale'] == 1) {
$meta_query = array(
array(
'key' => '_sale_price',
'value' => 0,
'compare' => '>',
'type' => 'numeric'
)
);
$query->set('meta_query',$meta_query);
$tax_query = array(
array(
'key' => 'product_type',
'field' => 'slug',
'terms' => array( 'simple', 'variable' )
)
);
$query->set('tax_query',$tax_query);
}
floy comments:
I wrote that exact block of code based off your first answer and unfortunately it returns nothing. Not even simple products!
Kyle comments:
My mistake, wrong label there. It should be 'taxonomy' not 'key' for mine:
add_action('pre_get_posts','sale_items');
function sale_items($query) {
if (!is_admin() && ($query->is_post_type_archive( 'product' ) || $query->is_tax( get_object_taxonomies( 'product' ))) && isset($_GET['sale']) && $_GET['sale'] == 1) {
$meta_query = array(
array(
'key' => '_sale_price',
'value' => 0,
'compare' => '>',
'type' => 'numeric'
)
);
$query->set('meta_query',$meta_query);
$tax_query = array(
array(
'taxonomy' => 'product_type',
'field' => 'slug',
'terms' => array( 'simple', 'variable' )
)
);
$query->set('tax_query',$tax_query);
}
}
floy comments:
Still failing to show variable products.
Kyle comments:
How you implementing the sale price attribute for simple products vs variable products? Are you using a Variable products sale price under attributes and variations?
floy comments:
Inserting it via the Product Data pane and the Variations tab. Thats the only place you can insert a Sale price for the variations of a variable product.
Kyle comments:
The issue is your meta_query. Woocommerce does not store the _sale_price meta value for a simple product in the same Post in the database as it does for a Variable product. It literally creates an entire new post for variations under the post_type 'product_variation'.
This means when your meta_query you have up there will always be empty for Variable products because the _sale_price meta field for variable products are not stored in a different post altogether.
floy comments:
I thought it might be something like that after browsing some of the woocommerce codex.
Is there anyway of utilizing the following code to create a function which will allow it to work as desired?
/**
* Function that returns an array containing the IDs of the products that are on sale.
*
* @since 2.0
* @access public
* @return array
*/
function woocommerce_get_product_ids_on_sale() {
// Load from cache
$product_ids_on_sale = get_transient( 'wc_products_onsale' );
// Valid cache found
if ( false !== $product_ids_on_sale )
return $product_ids_on_sale;
$on_sale = get_posts( array(
'post_type' => array( 'product', 'product_variation' ),
'posts_per_page' => -1,
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => '_sale_price',
'value' => 0,
'compare' => '>=',
'type' => 'DECIMAL',
),
array(
'key' => '_sale_price',
'value' => '',
'compare' => '!=',
'type' => '',
)
),
'fields' => 'id=>parent',
) );
$product_ids = array_keys( $on_sale );
$parent_ids = array_values( $on_sale );
// Check for scheduled sales which have not started
foreach ( $product_ids as $key => $id ) {
if ( get_post_meta( $id, '_sale_price_dates_from', true ) > current_time( 'timestamp' ) ) {
unset( $product_ids[ $key ] );
}
}
$product_ids_on_sale = array_unique( array_merge( $product_ids, $parent_ids ) );
set_transient( 'wc_products_onsale', $product_ids_on_sale );
return $product_ids_on_sale;
}
Kyle comments:
Yes, my first thought is to actually use that function, then use the array of IDs and modify the query with those.
If I am understanding your desired end goal, that function retrieves what you are looking for right?
floy comments:
Technically it should! Seeing as though that function is used to display sale products of both the simple and variable type it should be able to be used to achieve the desired result!
Kyle comments:
It may end up displaying grouped and external product_type products as well (if you use those), so the tax_query I have above can be used to filter those out the same way it was meant to bring in the missing ones.
Let me know how you do.
floy comments:
I had no luck with using woocommerce_get_product_ids_on_sale(). It returns an array of ALL (simple and variable) items on sale and disregards the current taxonomy being viewed. Not to mention it returns a bunch of random ID's which aren't even on sale as well :/
Any ideas?
Kyle comments:
Let me try some ideas I have and I will let you know what I come up with.
Kyle
Kyle comments:
Here is the first piece. The function returns the post IDs for products and product_variations. This will filter out the variations and return an array of all products (only products) on sale.
function return_products(){
$products_on_sale = woocommerce_get_product_ids_on_sale();
$the_ids = array();
foreach ($products_on_sale as $product_on_sale => $value){
$type = get_post_type($value);
if($type == 'product'){
$the_ids[] = (int)$value;
}
}
return $the_ids;
}
The last step is to add this to your query filters
Kyle comments:
Were you able to finish up from there?
Navjot Singh answers:
Try this code
add_action('pre_get_posts','sale_items');
function sale_items($query) {
if (!is_admin() && ($query->is_post_type_archive( array('product', 'product_variation') ) || $query->is_tax( get_object_taxonomies( array('product','product_variation' )))) && isset($_GET['sale']) && $_GET['sale'] == 1) {
$meta_query = array(
array(
'key' => '_sale_price',
'value' => 0,
'compare' => '>',
'type' => 'numeric'
)
);
$query->set('meta_query',$meta_query);
}
}
Woocommerce stores variable products under a different post type called "product_variation".
floy comments:
Hmm that still only shows simple products.