Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add custom stock status to products in WooCommerce 4+

I am using the following code to add new stock statuses in WooCommerce 4+

The new statuses are:

  • Preorder
  • Contact us
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'     => __( 'Available', 'woocommerce' ), //changed the name
        'outofstock'  => __( 'Sold out', 'woocommerce' ), //changed the name
        'onbackorder' => __( 'Preorder : Pending Distributor release', 'woocommerce' ), //changed the name
        'contact'     => __( 'Contact us for Availability', 'woocommerce' ), //added new one
        'preorder'    => __( 'On Preorder: Pending Distributor release', 'woocommerce' ), //added new one
    ), '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' => __( 'Available', 'woocommerce' ), 'class' => 'in-stock' ); //changed name
        break;
        case 'outofstock':
            $data = array( 'availability' => __( 'Sold Out', 'woocommerce' ), 'class' => 'out-of-stock' ); //changed name
        break;
        case 'onbackorder':
            $data = array( 'availability' => __( 'Preorder : Pending Distributor release', 'woocommerce' ), 'class' => 'onbackorder' ); //changed name
        break;
        case 'contact':
            $data = array( 'availability' => __( 'Contact us for Availability', 'woocommerce' ), 'class' => 'contact' ); //added new one
        break;
        case 'preorder':
            $data = array( 'availability' => __( 'On Preorder : Pending Distributor release', 'woocommerce' ), 'class' => 'preorder' ); //added new one
        break;
    }
    return $data;
}
add_action('woocommerce_get_availability', 'woocommerce_get_custom_availability', 10, 4);

Works:

  • Backend: The new status is added in the dropdown menu, I can select the status I want

Does not work:

  • Front end: on single product page is not showing the correct status

  • Backend: Display the new status on the admin products list table

Someone who can assist me with this?

like image 947
Allstars-FT Avatar asked May 14 '20 11:05

Allstars-FT


People also ask

How does WooCommerce show stock status on product page?

If the 'Stock display format' option on WooCommerce → Settings → Products → Inventory is set to display the quantity remaining in stock, then every product will have detailed stock information. In stock products will display the exact number remaining in stock.

How do I change stock levels in WooCommerce?

You can easily change stock levels in WooCommerce by going to WooCommerce > Products, finding the product you want to change, and clicking Edit. Under the Inventory section, simply change the Stock Qty field to your desired amount and update.


2 Answers

Last update: 04/22 - Tested in WordPress 5.9.2 & WooCommerce 6.3.1

Code goes in functions.php file of the active child theme (or active theme).


Use woocommerce_product_stock_status_options

instead of woocommerce_product_options_stock_status.

This way you can immediately add a status instead of replace the existing dropdown


Also use woocommerce_get_availability_text & woocommerce_get_availability_class opposite woocommerce_get_availability.

This way you don't have to add the existing statuses again

// Add new stock status options
function filter_woocommerce_product_stock_status_options( $status ) {
    // Add new statuses
    $status['pre_order'] = __( 'Pre order', 'woocommerce' );
    $status['contact_us'] = __( 'Contact us', 'woocommerce' );

    return $status;
}
add_filter( 'woocommerce_product_stock_status_options', 'filter_woocommerce_product_stock_status_options', 10, 1 );

// Availability text
function filter_woocommerce_get_availability_text( $availability, $product ) {
    // Get stock status
    switch( $product->get_stock_status() ) {
        case 'pre_order':
            $availability = __( 'Pre order', 'woocommerce' );
        break;
        case 'contact_us':
            $availability = __( 'Contact us', 'woocommerce' );
        break;
    }

    return $availability; 
}
add_filter( 'woocommerce_get_availability_text', 'filter_woocommerce_get_availability_text', 10, 2 );

// Availability CSS class
function filter_woocommerce_get_availability_class( $class, $product ) {
    // Get stock status
    switch( $product->get_stock_status() ) {
        case 'pre_order':
            $class = 'pre-order';
        break;
        case 'contact_us':
            $class = 'contact-us';
        break;
    }

    return $class;
}
add_filter( 'woocommerce_get_availability_class', 'filter_woocommerce_get_availability_class', 10, 2 );

enter image description here


Use woocommerce_admin_stock_html to display the new stock status on the admin products list table

// Admin stock html
function filter_woocommerce_admin_stock_html( $stock_html, $product ) {
    // Simple
    if ( $product->is_type( 'simple' ) ) {
        // Get stock status
        $product_stock_status = $product->get_stock_status();
    // Variable
    } elseif ( $product->is_type( 'variable' ) ) {
        foreach( $product->get_visible_children() as $variation_id ) {
            // Get product
            $variation = wc_get_product( $variation_id );
            
            // Get stock status
            $product_stock_status = $variation->get_stock_status();
            
            /*
            Currently the status of the last variant in the loop will be displayed.
            
            So from here you need to add your own logic, depending on what you expect from your custom stock status.
            
            By default, for the existing statuses. The status displayed on the admin products list table for variable products is determined as:
            
            - Product should be in stock if a child is in stock.
            - Product should be out of stock if all children are out of stock.
            - Product should be on backorder if all children are on backorder.
            - Product should be on backorder if at least one child is on backorder and the rest are out of stock.
            */
        }
    }
    
    // Stock status
    switch( $product_stock_status ) {
        case 'pre_order':
            $stock_html = '<mark class="pre-order" style="background:transparent none;color:#33ccff;font-weight:700;line-height:1;">' . __( 'Pre order', 'woocommerce' ) . '</mark>';
        break;
        case 'contact_us':
            $stock_html = '<mark class="contact-us" style="background:transparent none;color:#cc33ff;font-weight:700;line-height:1;">' . __( 'Contact us', 'woocommerce' ) . '</mark>';
        break;
    }
 
    return $stock_html;
}
add_filter( 'woocommerce_admin_stock_html', 'filter_woocommerce_admin_stock_html', 10, 2 );

enter image description here



Optional: if desired, the custom stock status can be used in hooks where you already have access to the $product object or you can use global $product.

1) No access to the $product object, use global $product as is the case for example with the woocommerce_shop_loop_item_title or the woocommerce_single_product_summary hook

function woocommerce_my_callback() {
    // An example based on global $product
    // Get the global product object
    global $product;

    // Is a WC product
    if ( is_a( $product, 'WC_Product' ) ) {
        // Get stock status
        $product_stock_status = $product->get_stock_status();

        // Use this line during testing, delete afterwards!
        echo '<p style="color:red;font-size:20px;">DEBUG INFORMATION = ' . $product_stock_status . '</p>';
        
        // Compare
        if ( $product_stock_status == 'My custom stock status' ) {
            // Etc..
        }
    }
}
add_action( 'woocommerce_shop_loop_item_title', 'woocommerce_my_callback', 10 );
add_action( 'woocommerce_single_product_summary', 'woocommerce_my_callback', 10 );

2) Access to the $product object, because it's passed by default to the callback function. As is the case for example with the woocommerce_get_price_html hook

function filter_woocommerce_get_price_html( $price, $product ) {
    // Is a WC product
    if ( is_a( $product, 'WC_Product' ) ) {
        // Get stock status
        $product_stock_status = $product->get_stock_status();

        // Use this line during testing, delete afterwards!
        echo '<p style="color:red;font-size:20px;">DEBUG INFORMATION = ' . $product_stock_status . '</p>';
        
        // Compare
        if ( $product_stock_status == 'My custom stock status' ) {
            // Etc..
            // $price .= ' my text';
        }
    }

    return $price;
}
add_filter( 'woocommerce_get_price_html', 'filter_woocommerce_get_price_html', 10, 2 );
like image 121
7uc1f3r Avatar answered Oct 10 '22 17:10

7uc1f3r


In addition to filters provided by 7uc1f3r woocommerce_product_export_product_column_stock_status filter is required to display custom stock status in exported products CSV file:

function add_custom_stock_csv_data( $_, $product ) {
  $status = $product->get_stock_status( 'edit' );
  switch( $status ) {
    case 'pre_order':
    case 'contact_us':
      return $status;
    case 'onbackorder':
      return 'backorder';
    case 'instock':
      return 1;
    default:
      return 0;
  }
}
add_filter( 'woocommerce_product_export_product_column_stock_status', 'add_custom_stock_csv_data', 10, 2 );
like image 23
lwd8cmd Avatar answered Oct 10 '22 16:10

lwd8cmd