Asked  8 Months ago    Answers:  5   Viewed   51 times

I am using the following code to add new stock statuses in WooCommerce 4.0.

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?

 Answers

26

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 ) {
    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 class
function filter_woocommerce_get_availability_class( $class, $product ) {
    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 ) {
    switch( $product->get_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:#33ffcc;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

Wednesday, March 31, 2021
 
Xavio
answered 8 Months ago
99
  • Add custom product tab
  • Add content to the product tab (checkbox)
  • Save the checkbox
  • Get value, 'yes' or 'no' and if yes, display iframe
/**
 * Add custom product setting tab.
 */
function filter_woocommerce_product_data_tabs( $default_tabs ) {
    $default_tabs['custom_tab'] = array(
        'label'   =>  __( 'Custom Tab', 'domain' ),
        'target'  =>  'wk_custom_tab_data',
        'priority' => 60,
        'class'   => array()
    );
    return $default_tabs;
}
add_filter( 'woocommerce_product_data_tabs', 'filter_woocommerce_product_data_tabs', 10, 1 );

/**
 * Contents custom product setting tab.
 */
function action_woocommerce_product_data_panels() {
    global $post;

    // Note the 'id' attribute needs to match the 'target' parameter set above
    echo '<div id="wk_custom_tab_data" class="panel woocommerce_options_panel">';

    // Add checkbox
    woocommerce_wp_checkbox( array(
        'id'        => '_allow_iframe',
        'label'     => __( 'Allow iFrame', 'woocommerce' ),
    ) );

    echo '</div>';
}
add_action( 'woocommerce_product_data_panels', 'action_woocommerce_product_data_panels', 10, 0 );

/**
 * Save the checkbox.
 */
function action_woocommerce_admin_process_product_object( $product ) {
    // Isset, yes or no
    $allow_iframe = isset( $_POST['_allow_iframe'] ) ? 'yes' : 'no';

    // Update meta
    $product->update_meta_data( '_allow_iframe', $allow_iframe );
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object', 10, 1 );

/**
 * Display iframe if checkbox = 'yes'
 */
function filter_woocommerce_single_product_image_thumbnail_html( $html, $post_thumbnail_id ) {
    // Get the global product object
    global $product;
    
    // Is a WC product
    if ( is_a( $product, 'WC_Product' ) ) {
        // Get meta
        $value = $product->get_meta( '_allow_iframe' );

        // value = 'yes'
        if ( $value == 'yes' ) {
            // Get product id
            $product_id = $product->get_id();
            
            $threed_link = 'http://myurl/' . $product_id;
            $html .= '<iframe src=' . $threed_link . ' width="99%" height="300px"></iframe>';   
        }
    }

    return $html;
}
add_filter( 'woocommerce_single_product_image_thumbnail_html', 'filter_woocommerce_single_product_image_thumbnail_html', 10, 2 );
Saturday, May 29, 2021
 
DilbertDave
answered 5 Months ago
98

Ok, first you'll need to get product variations like this:

$variations = $product->get_available_variations();

And inside options loop, you need to loop through the variations and find the current option stock status

foreach ($variations as $variation) {
    if($variation['attributes'][$name] == $option) {
        $stock = $variation['is_in_stock'];

    }
}

Outside the variations loop you need to add the wording for in-stock and out-of-stock variations

if( $stock == 1) {
    $stock_content = ' - In stock';
} else {
    $stock_content = ' - Out of stock';
}

Then change the html to include an additional variable ($stock_content)

$html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( $option  .  $stock_content ) . '</option>'; 

So a complete function will look like this:

add_filter( 'woocommerce_dropdown_variation_attribute_options_html', 'show_stock_status_in_dropdown', 10, 2);
function show_stock_status_in_dropdown( $html, $args ) {
    $options = $args['options']; 
    $product = $args['product']; 
    $attribute = $args['attribute']; 
    $name = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute ); 
    $id = $args['id'] ? $args['id'] : sanitize_title( $attribute ); 
    $class = $args['class']; 
    $show_option_none = $args['show_option_none'] ? true : false; 
    $show_option_none_text = $args['show_option_none'] ? $args['show_option_none'] : __( 'Choose an option', 'woocommerce' ); 

  // Get all product variations
    $variations = $product->get_available_variations();

    if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) { 
        $attributes = $product->get_variation_attributes(); 
        $options = $attributes[ $attribute ]; 
    } 

    $html = '<select id="' . esc_attr( $id ) . '" class="' . esc_attr( $class ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '" data-show_option_none="' . ( $show_option_none ? 'yes' : 'no' ) . '">'; 
    $html .= '<option value="">' . esc_html( $show_option_none_text ) . '</option>'; 

    if ( ! empty( $options ) ) { 
        if ( $product && taxonomy_exists( $attribute ) ) { 
          // Get terms if this is a taxonomy - ordered. We need the names too. 
          $terms = wc_get_product_terms( $product->get_id(), $attribute, array( 'fields' => 'all' ) ); 

          foreach ( $terms as $term ) { 
                if ( in_array( $term->slug, $options ) ) { 
                    $html .= '<option value="' . esc_attr( $term->slug ) . '" ' . selected( sanitize_title( $args['selected'] ), $term->slug, false ) . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $term->name ) ) . '</option>'; 
                } 
            }
        } else {
            foreach ( $options as $option ) {
                    foreach ($variations as $variation) {
                        if($variation['attributes'][$name] == $option) {
                            $stock = $variation['is_in_stock'];
                        }
                    }       
                if( $stock == 1) {
                    $stock_content = ' - (In Stock)';
                } else {
                    $stock_content = ' - (Out of Stock)';
                }
                 // This handles < 2.4.0 bw compatibility where text attributes were not sanitized. 
                $selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false ); 

                $html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( $option  .  $stock_content ) . '</option>'; 

            }
        } 
    } 

    $html .= '</select>'; 

    return $html;
}
Wednesday, June 2, 2021
 
Jimenemex
answered 5 Months ago
89

With the following code you can check the stock status and adjust the message accordingly.

function change_stock_message( $text, $product ) {  
    // Managing stock NOT checked
    if ( !$product->managing_stock() ) {

        // Get stock status
        if ( method_exists( $product, 'get_stock_status' ) ) {
            $stock_status = $product->get_stock_status();
        }

        // Check stock status, adjust the message accordingly
        switch ( $stock_status ) {
            case 'instock':
                $text = __( 'Available', 'woocommerce' );
                break;
            case 'outofstock':
                $text = __( 'Out of stock', 'woocommerce' );
                break;
            case 'onbackorder':
                $text = __( 'Available after 4-7 days', 'woocommerce' );
                break;
        }
    }

    return $text;
}
add_filter( 'woocommerce_get_availability_text', 'change_stock_message', 10, 2 );
Thursday, August 5, 2021
 
samayo
answered 3 Months ago
41

Try the following instead that should allow to display your custom stock availability only for the variations of a variable product (and also on simple products):

add_filter( 'woocommerce_get_stock_html', 'filter_wc_get_stock_html', 10, 2 );
function filter_wc_get_stock_html( $html, $product ) {
    if ( ! $product->is_type('variable') && ! $product->get_manage_stock() && $product->is_in_stock() ) {
        $html = '<p class="stock in-stock">' . __( "In Stock", "woocommerce" ) . '</p>';
    }

    return $html;
}

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


To exclude some product categories use the following (related to your comment):

add_filter( 'woocommerce_get_stock_html', 'filter_wc_get_stock_html', 10, 2 );
function filter_wc_get_stock_html( $html, $product ) {
    // Here define the product categories to be excluded (can be term Ids, slugs or names)
    $terms_excl = array('hoodies', 'albums');

    $product_id = $product->is_type('variation') ? $product->get_parent_id() : $product->get_id();

    if ( ! $product->is_type('variable') && ! $product->get_manage_stock() && $product->is_in_stock()
    && ! has_term( $terms_excl, 'product_cat', $product_id ) ) {
        $html = '<p class="stock in-stock">' . __( "In Stock", "woocommerce" ) . '</p>';
    }

    return $html;
}

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


Related thread: Display custom stock message if "Manage Stock" is not enabled in WooCommerce

Thursday, August 19, 2021
 
derp
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share