Search code examples
phpwordpresswoocommerceproducthook-wordpress

Adding "Sale" product category to products that are on sale in Woocommerce


As part of a WooCommerce site I want to have a sale page that lists sale items (with pagination and filtering). I think the best way to do this is to have a 'Sale' category that is added automatically to any posts that are part of the sale (as category pages allow for filtering and pagination automatically.

I have this code so far to programatically add the sale category to products when you save them:

function update_test( $product) { 
wp_set_object_terms($product, 'sale', 'product_cat', true );
}

add_action( 'save_post', 'update_test', 1, 2);`

However, I only want this to happen if a product is on sale (i.e has sale price set) so that saving posts that are not on sale does not add the sale category. I have tried several different things, but have had no luck. I tried this, but it didnt work:

function update_test( $product ) { 
if($product->is_on_sale()){
wp_set_object_terms($product, 'sale', 'product_cat', true );
}
}

add_action( 'save_post', 'update_test', 1, 2);`

but this just made my site freeze on save.

Any ideas?

Andy


Solution

  • Updated 2 (October 2018)

    save_post is a WordPress hook that works with $post_id argument and target all kind of posts. You need to target product custom WooCommerce post_type first in a condition (and publish post_status).

    Also as it's not a post object you can't use is_on_sale() method with it. But you can use get_post_meta() function to check if the sale price is set in the product.

    Here is the fully functional and tested code (for simple products only):

    add_action( 'save_post_product', 'update_product_set_sale_cat' );
    function update_product_set_sale_cat( $post_id ) {
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
            return $post_id;
        }
    
        if ( ! current_user_can( 'edit_product', $post_id ) ) {
            return $post_id;
        }
    
        if( get_post_status( $post_id ) == 'publish' && isset($_POST['_sale_price']) ) {
            $sale_price = $_POST['_sale_price'];
    
            if( $sale_price >= 0 && ! has_term( 'Sale', 'product_cat', $post_id ) ){
                wp_set_object_terms($post_id, 'sale', 'product_cat', true );
            }
        }
    }
    

    Code goes in function.php file of your active child theme (or active theme). Tested and works.

    Related: Auto remove Sale product category from not on sale products in Woocommerce