0

On our site, we're using custom stock statuses for our products. We use the below code to achieve that, and it works, but there are some issues on variable products, where it changes back to the default status.

We want to use it on variable products, to display a main stock status for the whole product, but when we select our custom stock status, it will suddenly change it back to the standard stock status after some time. It saves the setting when we update the product, but it will eventually change it back after some time.

Here is our code, which is placed in our functions.php file. Hope you can help or point me in the right direction:

function add_custom_stock_type() {
    ?>
    <script type="text/javascript">
    jQuery(function(){
        jQuery('._stock_status_field').not('.custom-stock-status').remove();
    });
    </script>
<?php   

    woocommerce_wp_select( array( 'id' => '_stock_status', 'wrapper_class' => 'custom-stock-status', 'label' => __( 'Stock status', 'woocommerce' ), 'options' => array(
        'instock' => __( 'På lager/fjernlager', 'woocommerce' ),
        'bestillingsvare' => __( 'Bestillingsvare', 'woocommerce' ), // The new option !!!
        'outofstock' => __( 'Ikke på lager', 'woocommerce' ),
    ), 'desc_tip' => true, 'description' => __( 'Controls whether or not the product is listed as "in stock" or "out of stock" on the frontend.', 'woocommerce' ) ) );
}
add_action('woocommerce_product_options_stock_status', 'add_custom_stock_type');

function save_custom_stock_status( $product_id ) {
    update_post_meta( $product_id, '_stock_status', wc_clean( $_POST['_stock_status'] ) );
}
add_action('woocommerce_process_product_meta', 'save_custom_stock_status',99,1);

function woo_add_custom_general_fields_save_two( $post_id ){
    // Select
    $woocommerce_select = $_POST['_stock_status'];
    if( !empty( $woocommerce_select ) )
        update_post_meta( $post_id, '_stock_status', esc_attr( $woocommerce_select ) );
    else
    update_post_meta( $post_id, '_stock_status', '' );
    }

function woocommerce_get_custom_availability( $data, $product ) {
    switch( $product->stock_status ) {
        case 'instock':
            $data = array( 'availability' => __( 'På lager/fjernlager', 'woocommerce' ), 'class' => 'in-stock' );
        break;
        case 'bestillingsvare':
            $data = array( 'availability' => __( 'Bestillingsvare', 'woocommerce' ), 'class' => 'bestillings-vare' );
        break;
        case 'outofstock':
            $data = array( 'availability' => __( 'Ikke på lager', 'woocommerce' ), 'class' => 'out-of-stock' );
        break;
    }
    return $data;
}
add_action('woocommerce_get_availability', 'woocommerce_get_custom_availability', 10, 2);
Mathias Beck
  • 128
  • 2
  • 12
  • What is the purpose of `woo_add_custom_general_fields_save_two()` function? – Outsource WordPress Aug 20 '18 at 12:36
  • I guess it was an attempt to try to save the fields, so it saves the settings permanently. – Mathias Beck Aug 21 '18 at 08:03
  • Stock status would be automatically updated by WooCommerce when an order completed. You can try `set_stock_status()` function in `woocommerce_reduce_order_stock()` hook. – Outsource WordPress Aug 21 '18 at 13:20
  • Yes, I know. But it changes from our custom stock status "bestillingsvare" to the "instock" status, and it does it randomly or when some of the variation is updated. – Mathias Beck Aug 22 '18 at 09:47
  • I hope it will not change randomly. When some one purchases the product, it changes while reducing the stock. Can you check and confirm this? – Outsource WordPress Aug 22 '18 at 09:50
  • It doesn't do this when an order is placed. The weird thing is, that it changes it to "instock" - not "outofstock" or "onbackorder". It still seems like it just doesn't save properly on variable products. Still no issue in single products. – Mathias Beck Aug 22 '18 at 13:17
  • I am too not sure - please deactivate plugins other than WooCommerce, switch to default theme and check. – Outsource WordPress Aug 22 '18 at 13:51
  • Hm, we can't do that on a live site. Also, we don't know when the stock status is changing back. – Mathias Beck Aug 22 '18 at 14:21
  • But you can see anything wrong with the above code on variation products? I know variation products doesn't have a main stock setting by default, I don't know if that's the issue. – Mathias Beck Aug 23 '18 at 10:59
  • No, its working fine for me (both simple & variable products). But you too saying that its working fine while saving variable product right? – Outsource WordPress Aug 23 '18 at 12:39
  • Yes, it's like it saves the option fine, but it will suddenly change it back to "instock". If I edit a single variation (like a single color option) and saves the variation only (and not updating the whole product), and then refresh the page, the stock status will change back to "instock". – Mathias Beck Aug 24 '18 at 11:47
  • Then, can you try updating the stock status on these hooks too - `woocommerce_save_product_variation` & `woocommerce_update_product_variation`? I am unable to come to an conclusion since its already working fine for me :( – Outsource WordPress Aug 24 '18 at 12:15
  • Which hook do you want me to replace? Appreciate your time! – Mathias Beck Aug 24 '18 at 13:10
  • A customer just bought a variation product with stock status "bestillingsvare" on our site, and the stock status actually did change back to "instock" as you mentioned! – Mathias Beck Aug 24 '18 at 13:14
  • Don't replace any hooks, just add these hooks in addition to `woocommerce_process_product_meta` - but confirm how to get product ID in these hooks, since both related to variations. – Outsource WordPress Aug 24 '18 at 13:16
  • Also, try adding this stock update function - http://woocommerce.wp-a2z.org/oik_api/wc_update_product_stock_status/ in the hooks which updating the stock. – Outsource WordPress Aug 24 '18 at 13:21
  • Why are you using stock status here? Can't achieve using some custom fields? – Outsource WordPress Aug 24 '18 at 13:21
  • Can't get it to work.. We use stock status, because we also use the variation stock management to control stock quantity of each item. – Mathias Beck Aug 24 '18 at 13:26
  • Then, are you having stock status for each variation? – Outsource WordPress Aug 24 '18 at 13:27
  • No, we have only one stock status for the whole variable product, but we add stock quantity for each product in the variation. I guess it is when a variation goes on backorder, the stock status change back to "instock". – Mathias Beck Aug 24 '18 at 13:34
  • Okay, if you confirm that stock status gets changing only when some one purchases (not while updating the variation), I'll try to provide a solution. – Outsource WordPress Aug 24 '18 at 13:36
  • It still seems like it also changes when I update the variation. Not the whole product, but only the variation settings. If I update the whole product, the settings are fine. – Mathias Beck Aug 24 '18 at 13:47
  • Okay then I need to analyze more, give me a day, I'll check and update. – Outsource WordPress Aug 24 '18 at 13:49
  • Thank you! Really appreciate it. – Mathias Beck Aug 24 '18 at 13:52
  • Did you checked my answer? – Outsource WordPress Aug 28 '18 at 17:27
  • Hi, yes! We are still testing it, to se if it's working when there is placed a new order. So far no issues. – Mathias Beck Aug 31 '18 at 16:19
  • I made another enhancement to prevent overriding stock status after order completion - please append the last function `woocommerce_order_change_custom_stock_status()`. – Outsource WordPress Sep 01 '18 at 06:35
  • With the updated code, it seems to work! Thank you so much - I have accepted your answer :) – Mathias Beck Sep 03 '18 at 15:34

2 Answers2

3

2019 Update:

In February 2019, WooCommerce added a filter to version 3.6.0 that allows users to add their own custom stock statuses.

Inside the function wc_get_product_stock_status_options, which defines the different stock statuses, there are 3 default built-in statuses: instock, outofstock, and onbackorder.

In order to add a custom status or remove a built-in one, you can simply use the new woocommerce_product_stock_status_options filter:

add_filter('woocommerce_product_stock_status_options', 'add_custom_stock_statuses');

function add_custom_stock_statuses($statuses) {
    // Add a new status
    $statuses['customstatus'] = __( 'My Custom Status', 'plugin-name' );

    // Remove a built-in status
    unset($statuses['onbackorder']);

    return $statuses;
}
Reuven Karasik
  • 475
  • 5
  • 14
2

Unfortunately WooCommerce not supporting any custom stock status other than its own stock statuses - instock, outofstock & onbackorder. We can achieve the custom stock status by overriding the _stock_status meta in some cases but will not be successful in all cases (like variations update).

In the above functions, you have removed the onbackorder stock status and if particular product stock status changed to 'onbackorder', then it will not be shown. Note that this is the reason for showing 'instock' since its the first option in your select box.

If you are going to use the stock status purely for admin panel display purpose only, then you can achieve this by using the following functions.

/* add custom stock status */
function woocommerce_add_custom_stock_status() {
    ?>
    <script type="text/javascript">
    jQuery(function(){
        jQuery('._stock_status_field').not('.custom-stock-status').remove();
    });
    </script>
    <?php   
    /* update custom status if backorder if varations updated */
    $real_stock_status = get_post_meta($_REQUEST['post'], '_stock_status', true );
    if($real_stock_status=="onbackorder") {
        $stock_status = get_post_meta($_REQUEST['post'], '_custom_stock_status', true ); //get status from custom meta
        update_post_meta($_REQUEST['post'], '_stock_status', wc_clean( $stock_status ));
    }

    woocommerce_wp_select( array( 'id' => '_stock_status', 'wrapper_class' => 'custom-stock-status', 'label' => __( 'Stock status', 'woocommerce' ), 'options' => array(        
        'instock' => __( 'På lager/fjernlager', 'woocommerce' ),
        'bestillingsvare' => __( 'Bestillingsvare', 'woocommerce' ), // The new option !!!
        'outofstock' => __( 'Ikke på lager', 'woocommerce' ),
    ), 'desc_tip' => true, 'description' => __( 'Controls whether or not the product is listed as "in stock" or "out of stock" on the frontend.', 'woocommerce' ) ) );    
}
add_action('woocommerce_product_options_stock_status', 'woocommerce_add_custom_stock_status');

/* save custom stock status */
function woocommerce_save_custom_stock_status( $product_id ) {
    update_post_meta( $product_id, '_stock_status', wc_clean( $_POST['_stock_status'] ) );
    update_post_meta( $product_id, '_custom_stock_status', wc_clean( $_POST['_stock_status'] ) ); //save another custom meta since '_stock_status' will be overridden
}
add_action('woocommerce_process_product_meta', 'woocommerce_save_custom_stock_status',99,1);

/* get custom stock status */
function get_custom_stock_status( $data, $product ) {
    switch( $product->stock_status ) {
        case 'instock':
            $data = array( 'availability' => __( 'På lager/fjernlager', 'woocommerce' ), 'class' => 'in-stock' );
        break;
        case 'bestillingsvare':
            $data = array( 'availability' => __( 'Bestillingsvare', 'woocommerce' ), 'class' => 'bestillings-vare' );
        break;
        case 'outofstock':
            $data = array( 'availability' => __( 'Ikke på lager', 'woocommerce' ), 'class' => 'out-of-stock' );
        break;
    }
    return $data;
}
add_action('woocommerce_get_availability', 'get_custom_stock_status', 10, 2);

/* change custom stock status after order completion */
function woocommerce_order_change_custom_stock_status( $order_id ){
    if( ! $order_id ) return;

    $order = wc_get_order( $order_id );
    $items = $order->get_items();
    foreach ( $items as $item ) {
        $product_id = $item->get_product_id();

        $real_stock_status = get_post_meta($product_id, '_stock_status', true );
        if($real_stock_status=="onbackorder") {
            $stock_status = get_post_meta($product_id, '_custom_stock_status', true ); //get status from custom meta
            update_post_meta($product_id, '_stock_status', wc_clean( $stock_status ));
        }
    }
}
add_action( 'woocommerce_thankyou', 'woocommerce_order_change_custom_stock_status', 10, 1 );

Hope this helps.

Outsource WordPress
  • 3,749
  • 2
  • 10
  • 23