24 Simple Woocommerce Hacks For Every Store

Let’s hack your Woocommerce shop a bit. That is, in this post I’ll show you 24 simple Woocommerce hacks that will save your time and money.

Now, in order to make this work, add your chosen snippets shown to your child theme’s functions.php file or better yet, use a snippet manager like Code Snippets.

There is also a WpCodeBox plugin, which is my favorite code snippets manager for WordPress. This is a premium plugin and if you’re interested, then grab WPCodeBox with a nice 20% discount here (SAVE 20% Coupon WPSH20).

Video: 24 Simple Woocommerce Hacks For Every Store

In this video I will show you how to add all those snippets and how will they affect your site.

How to activate Woocommerce catalog mode and add enquiry form on single product pages?

This snipper here below activates catalog mode and displays a product enquiry form on single product page

add_filter( 'woocommerce_is_purchasable', '__return_false'); // DISABLING PURCHASE FUNCTIONALITY AND REMOVING ADD TO CART BUTTON FROM NORMAL PRODUCTS

remove_action('woocommerce_single_variation', 'woocommerce_single_variation', 10); // REMOVING PRICE FROM VARIATIONS

remove_action('woocommerce_single_variation', 'woocommerce_single_variation_add_to_cart_button', 20); // REMOVING ADD TO CART BUTTON FROM VARIATIONS

// Add an enquiry form on Woocommerce single product page
add_action( 'woocommerce_single_product_summary', 'single_product_message', 20 );
 
function single_product_message() {
    echo '<p class="woocommerce-message">Send us an enquiry </p>';
	echo do_shortcode(''); // Your contact form shortcode goes here. 
}

How to Add conditional Woocommerce product category page messages

With the help of this code snippet here you can add a message to all Woocommerce product category pages.

<span role="button" tabindex="0" data-code="// Custom message on Woocommerce shop page and all category pages
add_action( 'woocommerce_before_main_content', 'shop_message', 20 );
function shop_message() {
echo '<p class="woocommerce-message">Free shipping for all orders

// Custom message on Woocommerce shop page and all category pages
add_action( 'woocommerce_before_main_content', 'shop_message', 20 );
function shop_message() {
echo '<p class="woocommerce-message">Free shipping for all orders</p>'; // Change your message here
}

How to add message to specific Woocommerce category page?

If you need to add a message to the scpecific Woocommerce product category page (Storage catogory, for example) then use this code instead.

<span role="button" tabindex="0" data-code="// Message for specific category
add_action( 'woocommerce_before_main_content', 'category_message', 20 );
function category_message() {
if ( is_product_category( 'storage' ) ) { // Change your vategory slug here
echo '<p class="woocommerce-message">Estimated shipping time: 2-3 weeks

// Message for specific category
add_action( 'woocommerce_before_main_content', 'category_message', 20 );
function category_message() {
 if ( is_product_category( 'storage' ) ) { // Change your vategory slug here
echo '<p class="woocommerce-message">Estimated shipping time: 2-3 weeks</p>'; // Change your message here
}
}

How to add one message to specific Woocommerce category page and another message to all other category pages?

Now lets add a one message to the Sotrage category page and another message to all other categories.

<span role="button" tabindex="0" data-code="// One message for specific category (storage) and another for all other categories
add_action( 'woocommerce_before_shop_loop', 'conditional_message', 1 );
function conditional_message() {
if ( is_product_category( 'storage' ) ) { // Change your vategory slug here
echo '<p class="woocommerce-message">Estimated delivery time: 2-3 weeks</p>';// Change your Storage category message here
} else {
echo '<p class="woocommerce-message">Estimated delivery time: 1 week

// One message for specific category (storage) and another for all other categories
add_action( 'woocommerce_before_shop_loop', 'conditional_message', 1 );
function conditional_message() {
if ( is_product_category( 'storage' ) ) { // Change your vategory slug here
echo '<p class="woocommerce-message">Estimated delivery time: 2-3 weeks</p>';// Change your Storage category message here 
} else {
echo '<p class="woocommerce-message">Estimated delivery time: 1 week</p>'; // Change your shop-wide message here
}
}

How to remove category product count in product archives?

As you probably have seen the category loop has a product count shown next to the category name. This code will hide Woocommerce product count in product archives.

add_filter( 'woocommerce_subcategory_count_html', '__return_false' );

How to remove category product count in product archives?

As you probably have seen the category loop has a product count shown next to the category name. This code will hide Woocommerce product count in product archives.

add_filter( 'woocommerce_subcategory_count_html', '__return_false' );

How to Display the Discount Percentage on the Woocommerce Sale Badge?

By default Woocommerce shows a badge with the “Sale” text. If you would kike to show a discount percentage instead, then use this code here below.

<span role="button" tabindex="0" data-code="add_action( 'woocommerce_sale_flash', 'sale_badge_percentage', 25 );

function sale_badge_percentage() {
global $product;
if ( ! $product->is_on_sale() ) return;
if ( $product->is_type( 'simple' ) ) {
$max_percentage = ( ( $product->get_regular_price() – $product->get_sale_price() ) / $product->get_regular_price() ) * 100;
} elseif ( $product->is_type( 'variable' ) ) {
$max_percentage = 0;
foreach ( $product->get_children() as $child_id ) {
$variation = wc_get_product( $child_id );
$price = $variation->get_regular_price();
$sale = $variation->get_sale_price();
if ( $price != 0 && ! empty( $sale ) ) $percentage = ( $price – $sale ) / $price * 100;
if ( $percentage > $max_percentage ) {
$max_percentage = $percentage;
}
}
}
if ( $max_percentage > 0 ) echo "<span class='onsale'>-" . round($max_percentage) . "%

add_action( 'woocommerce_sale_flash', 'sale_badge_percentage', 25 );
 
function sale_badge_percentage() {
   global $product;
   if ( ! $product->is_on_sale() ) return;
   if ( $product->is_type( 'simple' ) ) {
      $max_percentage = ( ( $product->get_regular_price() - $product->get_sale_price() ) / $product->get_regular_price() ) * 100;
   } elseif ( $product->is_type( 'variable' ) ) {
      $max_percentage = 0;
      foreach ( $product->get_children() as $child_id ) {
         $variation = wc_get_product( $child_id );
         $price = $variation->get_regular_price();
         $sale = $variation->get_sale_price();
         if ( $price != 0 && ! empty( $sale ) ) $percentage = ( $price - $sale ) / $price * 100;
         if ( $percentage > $max_percentage ) {
            $max_percentage = $percentage;
         }
      }
   }
   if ( $max_percentage > 0 ) echo "<span class='onsale'>-" . round($max_percentage) . "%</span>"; // If you would like to show -40% off then add text after % sign
}

How to Display “NEW” Badge for Woocommerce Recent Products that are less than 30 days old?

Step 1: Add the code snippet here below

<span role="button" tabindex="0" data-code="// New badge for recent products
add_action( 'woocommerce_before_shop_loop_item_title', 'new_badge', 3 );

function new_badge() {
global $product;
$newness_days = 30; // Number of days the badge is shown
$created = strtotime( $product->get_date_created() );
if ( ( time() – ( 60 * 60 * 24 * $newness_days ) ) < $created ) {
echo '<span class="new-badge onsale">' . esc_html__( 'NEW', 'woocommerce' ) . '

// New badge for recent products
add_action( 'woocommerce_before_shop_loop_item_title', 'new_badge', 3 );
          
function new_badge() {
   global $product;
   $newness_days = 30; // Number of days the badge is shown
   $created = strtotime( $product->get_date_created() );
   if ( ( time() - ( 60 * 60 * 24 * $newness_days ) ) < $created ) {
      echo '<span class="new-badge onsale">' . esc_html__( 'NEW', 'woocommerce' ) . '</span>';
   }
}

Step 2: Customize your badge

Pay attention thought that the CSS shown here below may need tweaking and it depend on your theme. So, tweak it accordingly.

// “NEW” Badge for Woocommerce Recent Products that are less than 30 days old
.woocommerce ul.products li.product .new-badge.onsale {
	background: #ffcc00;
	top: 50px;
	z-index: 10;
	left: 0px;
	color: #000;
	font-weight: 700;
	text-transform: uppercase;
	font-size: 0.9em;
	border-radius: 0px;
	min-width: 60px;
	padding-left: 19px !important;
}
span.new-badge.onsale:after {
	border: 5px solid #ffcc00;
border-color: transparent transparent #ffcc00 #ffcc00;
	border-width: 9px 6px;
	position: absolute;
	right: -10px;
	bottom: 0;
	content: '';
}
span.new-badge.onsale:before {
border: 5px solid #ffcc00;
    border-color: #ffcc00 transparent transparent #ffcc00;
    border-width: 9px 6px;
    position: absolute;
    right: -10px;
    top: 0;
    content: '';
}

If you would like to show it as a vertical ribbon then add this piece of CSS.

span.new-badge.onsale {
min-width: 60px;
-moz-transform: rotate(90deg);
    -webkit-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
    transform: rotate(90deg);
}

How to display custom product badges with checking a checkbox?

Next, let’s add a checkbox at your single product edit page. If you check this then the text “Free shipping” is shown on the single product page below the title. See these screenshots here below, and you’ll see how it will also display it for the badge we’re going to create in the next chapter.

How to display custom product badges on WooCommerce?
How to display custom product badges on WooCommerce?

If you would like to change the text shown in the badge, then just modify it in line 34. Also, change the text in lines 7 and 9 accordingly.

Now, let’s display custom product badges with checking a checkbox.

<span role="button" tabindex="0" data-code="// Step 1: Add checkbox

add_action( 'woocommerce_product_options_general_product_data', 'checkbox_badge' );

function checkbox_badge() {
woocommerce_wp_checkbox( array(
'id' => 'checkbox_badge',
'class' => '',
'label' => 'Display free shipping badge'
)
);
}

// Step 2: Save checkbox selection

add_action( 'save_post', 'save_checkbox_badge_selection' );

function save_checkbox_badge_selection( $product_id ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return;
if ( isset( $_POST['checkbox_badge'] ) ) {
update_post_meta( $product_id, 'checkbox_badge', $_POST['checkbox_badge'] );
} else delete_post_meta( $product_id, 'checkbox_badge' );
}

// Step 3: Display custom badge at single product page

add_action( 'woocommerce_single_product_summary', 'display_checkbox_badge', 7 );

function display_checkbox_badge() {
global $product;
if ( get_post_meta( $product->get_id(), 'checkbox_badge', true ) ) {
echo '
<div class="custom-badge-1">Free shipping

// Step 1: Add checkbox 

add_action( 'woocommerce_product_options_general_product_data', 'checkbox_badge' );        
  
function checkbox_badge() {           
woocommerce_wp_checkbox( array( 
'id' => 'checkbox_badge', 
'class' => '', 
'label' => 'Display free shipping badge'
) 
);      
}

// Step 2: Save checkbox selection
  
add_action( 'save_post', 'save_checkbox_badge_selection' );
  
function save_checkbox_badge_selection( $product_id ) {
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
        return;
    if ( isset( $_POST['checkbox_badge'] ) ) {
            update_post_meta( $product_id, 'checkbox_badge', $_POST['checkbox_badge'] );
    } else delete_post_meta( $product_id, 'checkbox_badge' );
}

// Step 3: Display custom badge at single product page
  
add_action( 'woocommerce_single_product_summary', 'display_checkbox_badge', 7 );
  
function display_checkbox_badge() {
    global $product;     
    if ( get_post_meta( $product->get_id(), 'checkbox_badge', true ) ) {
        echo '
<div class="custom-badge-1">Free shipping</div>'; // Change this text if needed
    }
}

Custom CSS for the product badge.

/* Display custom product badges with checking a checkbox */
.custom-badge-1 {
  font-size: 13px;
	color: #fff;
	font-weight: 600;
	background: #E54C60;
	border: 2px solid #E54C60;
	text-align: center;
	padding: 7px;
	display: inline;
}
.entry-summary .price {
	margin-top: 1em;
}

How to display Woocommerce stock amount and stock status on Woocommerce archive pages?

Sometimes there is a need to display Woocommerce stock amount and stock status on Woocommerce arhcive pages. Therefore, this snippet will help you out.

It will display Woocommerce stock amoutn and stock statuses like this:

  • 25 in stock
  • Out of stock
  • In stock
  • Available on backorder
  • For variable products it may be “In stock (some items)”
<span role="button" tabindex="0" data-code="//* Enqueue scripts
add_action( 'wp_enqueue_scripts', 'wpsh_stock_status_archive', 11 );
function wpsh_stock_status_archive() {

// Activate clip styles
wp_enqueue_style( 'wpsh-stock-status-archive-style',
plugins_url( 'clip-style.css', __FILE__ ), array(),
'1.0.0'
);
}

//* Add stock status to archive pages
add_action( 'woocommerce_after_shop_loop_item', 'wpsh_add_stock_status_archive', 3 );
function wpsh_add_stock_status_archive() {

global $product;
$availability = $append = null;

// Add status for single products
if( $product->is_type( 'simple' ) ) {

$availability = $product->get_availability();
$class = $availability[ 'class' ];
$output = $availability[ 'availability' ];
}

// Add status for variable products
elseif( $product->is_type( 'variable' ) ) {

$status = array();

// Get status class for each variation
foreach ( $product->get_children() as $child_id ) {

$variation = $product->get_child( $child_id );
$availability = $variation->get_availability();

// Abandon if stock management is disabled on any variation
if( ! array_filter( $availability ) )
return;

$status[] = $availability[ 'class' ];
}

/**
* Compile final output and class based on
* availability classes set by WooCommerce
*/
if( in_array( 'in-stock', $status ) ) {
$output = __( 'In stock', 'wp-clips' );
$class = 'in-stock';
}
elseif( in_array( 'available-on-backorder', $status ) ) {
$output = __( 'Available on backorder', 'wp-clips' );
$class = 'available-on-backorder';
}
elseif( in_array( 'out-of-stock', $status ) ) {
$output = __( 'Out of stock', 'wp-clips' );
$class = 'out-of-stock';
}

// Append output if some items out of stock or available on backorder
if( ( in_array( 'available-on-backorder', $status ) && $class == 'in-stock' ) ||
( in_array( 'out-of-stock', $status ) && $class != 'out-of-stock' ) )
$append = ' ' . __( '(some items)', 'wp-clips' );
}

// Output only if set
if( isset( $availability ) ){
echo '<span class="archive-stock ' . esc_attr( $class ) . '">' . esc_html( $output ) . esc_html( $append ) . '

//* Enqueue scripts
add_action( 'wp_enqueue_scripts', 'wpsh_stock_status_archive', 11 );
function wpsh_stock_status_archive() {

	// Activate clip styles
	wp_enqueue_style(  'wpsh-stock-status-archive-style', 
						plugins_url( 'clip-style.css', __FILE__ ), array(),
						'1.0.0' 
	);
}

//* Add stock status to archive pages
add_action( 'woocommerce_after_shop_loop_item', 'wpsh_add_stock_status_archive', 3 );
function wpsh_add_stock_status_archive() {

    global $product;
	$availability = $append = null;

	// Add status for single products
	if( $product->is_type( 'simple' ) ) {

		$availability = $product->get_availability();
		$class = $availability[ 'class' ];
		$output = $availability[ 'availability' ];
	}

	// Add status for variable products
	elseif( $product->is_type( 'variable' ) ) {

		$status = array();

		// Get status class for each variation
		foreach ( $product->get_children() as $child_id ) {
			
				$variation = $product->get_child( $child_id );
				$availability = $variation->get_availability();
				
				// Abandon if stock management is disabled on any variation
				if( ! array_filter( $availability ) )
					return;

				$status[] = $availability[ 'class' ];
		}

		/**
		 * Compile final output and class based on
		 * availability classes set by WooCommerce
		 */
		if( in_array( 'in-stock', $status ) ) {
			$output = __( 'In stock', 'wp-clips' );
			$class = 'in-stock';
		}
		elseif( in_array( 'available-on-backorder', $status ) ) {
			$output = __( 'Available on backorder', 'wp-clips' );
			$class = 'available-on-backorder';
		}
		elseif( in_array( 'out-of-stock', $status ) ) {
			$output = __( 'Out of stock', 'wp-clips' );
			$class = 'out-of-stock';
		}

		// Append output if some items out of stock or available on backorder
		if( ( in_array( 'available-on-backorder', $status ) && $class == 'in-stock' ) ||
			( in_array( 'out-of-stock', $status ) && $class != 'out-of-stock' ) )
			$append = ' ' . __( '(some items)', 'wp-clips' );
	}

	// Output only if set 
	if( isset( $availability ) ){
		echo '<span class="archive-stock ' . esc_attr( $class ) . '">' . esc_html( $output ) . esc_html( $append ) . '</span>';	
	}
}

As with the other snippets you can customize it with this piece of CSS.

/* Display Woocommerce stock amount and stock status on Woocommerce archive pages */
.archive-stock  {
	font-size: 13px;
	margin: 5px 0px 10px 0px;
}

How to change Woocommerce add to cart button text if product is in backorder?

IThere are people who are confused about the backorders and different Woocommerce stock statuses. This lead to to problem where custome did not realize that the product was available on backorder (that means out of stock) and ordered it knowing that it will ship soon.

Therefore, you may want to change Woocommerce add to cart button text only for backorder products. Now, if you combine it with the custom field (shown above) then the end result will look like this:

How to change Woocommerce add to cart button text if product is in backorder?

Looks good, isn’t it? So, use this code snippet.

// changes Woocommerce Single product page add to cart button only text if product is in backorder
add_filter( 'woocommerce_product_single_add_to_cart_text', 'wc_ninja_change_backorder_button', 10, 2 );
function wc_ninja_change_backorder_button( $text, $product ){
	if ( $product->is_on_backorder( 1 ) ) {
		$text = __( 'Pre-order', 'woocommerce' );
	}
	return $text;
}

// changes Woocommerce category page add to cart button only text if product is in backorder
add_filter( 'woocommerce_product_add_to_cart_text', 'wc_ninja_change_backorder_button1', 10, 2 );
function wc_ninja_change_backorder_button1( $text, $product ){
    if ( $product->is_on_backorder( 1 ) ) {
        $text = __( 'Pre-order', 'woocommerce' );
    }
    return $text;
  }

How to create and display custom product field?

First, let’s create a new Woocommerce single product custom field and let’s output it in the desired place. The end result will look like the one here below on the screenshot.

Woocommerce Single Product Page Hacks

So, just grab this code and use it accordingly.

<span role="button" tabindex="0" data-code="// Add custom field to Woocommerce backend under General tab
add_action( 'woocommerce_product_options_general_product_data', 'wpsh_add_text_field' );
function wpsh_add_text_field() {
woocommerce_wp_text_input( array(
'id' => '_shipping_time',
'label' => __( 'Shipping info', 'woocommerce' ),
'description' => __( 'This is a custom field, you can write here anything you want.', 'woocommerce' ),
'desc_tip' => 'true',
'type' => 'text'
) );
}

// Save custom field values
add_action( 'woocommerce_admin_process_product_object', 'wpsh_save_field', 10, 1 );
function wpsh_save_field( $product ) {
if ( isset( $_POST['_shipping_time'] ) ) {
$product->update_meta_data( '_shipping_time', sanitize_text_field( $_POST['_shipping_time'] ) );
}
}

// Display this custom field on Woocommerce single product pages
add_action( 'woocommerce_product_meta_end', 'wpsh_display_on_single_product_page', 10 );
function wpsh_display_on_single_product_page() {
global $product;

// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// Get meta
$text = $product->get_meta( '_shipping_time' );
// NOT empty
if ( ! empty ( $text ) ) {
echo '<div class="woocommerce-message">Estimated shipping time: ' . $text . '</div>';
}
}
}
// Display this custom field on Woocommerce archive pages
add_action( 'woocommerce_after_shop_loop_item', 'wpsh_display_on_archive_page', 10 );
function wpsh_display_on_archive_page() {
global $product;
// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// Get meta
$text = $product->get_meta( '_shipping_time' );
// NOT empty
if ( ! empty ( $text ) ) {
echo '<div class="custom-text">Estimated shipping time: ' . $text . '

// Add custom field to Woocommerce backend under General tab
add_action( 'woocommerce_product_options_general_product_data', 'wpsh_add_text_field' );
function wpsh_add_text_field() {
    woocommerce_wp_text_input( array(
        'id'            => '_shipping_time',
        'label'         => __( 'Shipping info', 'woocommerce' ),
        'description'   => __( 'This is a custom field, you can write here anything you want.', 'woocommerce' ),
        'desc_tip'      => 'true',
        'type'          => 'text'
    ) );
}


// Save custom field values
add_action( 'woocommerce_admin_process_product_object', 'wpsh_save_field', 10, 1 );
function wpsh_save_field( $product ) {
    if ( isset( $_POST['_shipping_time'] ) ) {        
        $product->update_meta_data( '_shipping_time', sanitize_text_field( $_POST['_shipping_time'] ) );
    }
}

// Display this custom field on Woocommerce single product pages
add_action( 'woocommerce_product_meta_end', 'wpsh_display_on_single_product_page', 10 );
function wpsh_display_on_single_product_page() {
    global $product;
    
    // Is a WC product
    if ( is_a( $product, 'WC_Product' ) ) {
        // Get meta
        $text = $product->get_meta( '_shipping_time' );
        // NOT empty
        if ( ! empty ( $text ) ) {
            echo '<div class="woocommerce-message">Estimated shipping time: ' . $text . '</div>';
        }
    }
}
// Display this custom field on Woocommerce archive pages
add_action( 'woocommerce_after_shop_loop_item', 'wpsh_display_on_archive_page', 10 );
function wpsh_display_on_archive_page() {
    global $product;
    // Is a WC product
    if ( is_a( $product, 'WC_Product' ) ) {
        // Get meta
        $text = $product->get_meta( '_shipping_time' );
        // NOT empty
        if ( ! empty ( $text ) ) {
            echo '<div class="custom-text">Estimated shipping time: ' . $text . '</div>';
        }
    }
}

How to create custom tab?

This snippet here below creates new custom Woocommerce single product tab and it contains text and contact form. Just replace the content as you like and you’re good to go.

add_filter( 'woocommerce_product_tabs', 'custom_tab' );
function custom_tab( $tabs ) {	
	// Adds the new tab
	$tabs['form'] = array(
		'title' 	=> __( 'Send us an enquiry', 'woocommerce' ),
		'priority' 	=> 30,
		'callback' 	=> 'custom_tab_content'
	);
	return $tabs;
}
function custom_tab_content() {

	// The new tab content

	echo '<h4>Send us an enquiry</h4>';
	echo '<p>Lorem ipsum dolor sit amet consectetur adipiscing elit ultricies convallis volutpat, placerat proin scelerisque eget velit tellus at nibh risus. </p>';
	echo do_shortcode( '' );
}

How to display “You save” for sale price?

Take a look at the screenshot here below. This is what these snippets are doing for you.

Useful Woocommerce Single Product Page Hacks

So, in order to make it work like that use this snippet. Pay attention, that this one here below works only with simple products. For variable products take a look at the nex snippet.

<span role="button" tabindex="0" data-code="function you_save_text_for_product() {
global $product;

// works for Simple and Variable type
$regular_price = get_post_meta( $product->get_id(), '_regular_price', true ); // 36.32
$sale_price = get_post_meta( $product->get_id(), '_sale_price', true ); // 24.99

if( !empty($sale_price) ) {

$saved_amount = $regular_price – $sale_price;
$currency_symbol = get_woocommerce_currency_symbol();

$percentage = round( ( ( $regular_price – $sale_price ) / $regular_price ) * 100 );
?>
<p class="you_save_price">You save: <?php echo $currency_symbol .''. number_format($saved_amount, 2, '.', ''); ?></p>

function you_save_text_for_product() {
	global $product;

	// works for Simple and Variable type
	$regular_price 	= get_post_meta( $product->get_id(), '_regular_price', true ); // 36.32
	$sale_price 	= get_post_meta( $product->get_id(), '_sale_price', true ); // 24.99
		
	if( !empty($sale_price) ) {
	
		$saved_amount 		= $regular_price - $sale_price;
		$currency_symbol 	= get_woocommerce_currency_symbol();

		$percentage = round( ( ( $regular_price - $sale_price ) / $regular_price ) * 100 );
		?>
			<p class="you_save_price">You save: <?php echo $currency_symbol .''. number_format($saved_amount, 2, '.', ''); ?></p>				
		<?php		
	} 
		
}
add_action( 'woocommerce_single_product_summary', 'you_save_text_for_product', 12 ); // hook priority

If you would like to customize the look of it then take a look at the you_save_price CCS class. Now go to Customizer >> Additional CSS and add this small piece of CSS to customize it.

.you_save_price {
	background: #f9f9f9;
	padding: 10px;
	border: 1px dashed #ddd;
	width: 150px;
	font-size: 14px;
	font-weight: 600;
	margin-top: 10px;
}

Now, this code above shows the saved amount only for simple products. If you would also like to show it for variable products, then add this piece of code.

<span role="button" tabindex="0" data-code="// For product variations (on variable products)
add_filter( 'woocommerce_available_variation', 'variable_product_saving_amount', 10, 3 );
function variable_product_saving_amount( $data, $product, $variation ) {

if( $variation->is_on_sale() ) {
$saved_amount = $data['display_regular_price'] – $data['display_price'];
$percentage = round( $saved_amount / $data['display_regular_price'] * 100 );

$data['price_html'] .= '<p id="you_save_price">'. __("You Save") .': ' . wc_price($saved_amount) . ' ('.$percentage.'%)

// For product variations (on variable products)
add_filter( 'woocommerce_available_variation', 'variable_product_saving_amount', 10, 3 );
function variable_product_saving_amount( $data, $product, $variation ) {

    if( $variation->is_on_sale() ) {
        $saved_amount  = $data['display_regular_price'] - $data['display_price'];
        $percentage    = round( $saved_amount / $data['display_regular_price'] * 100 );

        $data['price_html'] .= '<p id="you_save_price">'. __("You Save") .': ' . wc_price($saved_amount) . ' ('.$percentage.'%)</p>';
    }
    return $data;
}

How to display “You save” amount on the Woocommerce cart and checkout page?

In case you need to display “You save” amount on the Woocommerce cart and checkout page, then use this snippet.

// Display the "You save" line before the subtotal on the Woocommerce cart and checkout pages
add_action( 'woocommerce_cart_totals_before_order_total', 'wpsh_display_you_save_cart' );
add_action( 'woocommerce_review_order_before_order_total', 'wpsh_display_you_save_checkout' );

function wpsh_display_you_save_cart() {
    display_you_save_message();
}

function wpsh_display_you_save_checkout() {
    display_you_save_message();
}

function display_you_save_message() {
    // Get the current WooCommerce cart object
    $cart = WC()->cart;
    $total_savings = 0;
    $tax_based_prices = get_option('woocommerce_prices_include_tax') === 'no';

    // Loop through cart items to calculate total savings
    foreach ( $cart->get_cart() as $cart_item ) {
        $product = $cart_item['data'];
        $quantity = $cart_item['quantity'];

        // Get the correct regular and sale price
        if ( $product->is_type('variable') && $cart_item['variation_id'] ) {
            $variation = wc_get_product( $cart_item['variation_id'] );
            $regular_price = floatval($variation->get_regular_price());
            $sale_price = floatval($variation->get_sale_price());
        } else {
            $regular_price = floatval($product->get_regular_price());
            $sale_price = floatval($product->get_sale_price());
        }

        // Adjust prices if entered exclusive of tax
        if ( $tax_based_prices ) {
            $regular_price = wc_get_price_including_tax($product, array('price' => $regular_price));
            $sale_price = wc_get_price_including_tax($product, array('price' => $sale_price));
        }

        // Ensure sale price is lower than regular price
        if ( $sale_price && $regular_price > $sale_price ) {
            $total_savings += ( $regular_price - $sale_price ) * $quantity;
        }
    }

    // Display the total savings if any
    if ( $total_savings > 0 ) {
        echo '<tr class="order-total">
                <th>' . __( 'You save', 'woocommerce' ) . ':</th>
                <td data-title="' . __( 'You save', 'woocommerce' ) . '">' . wc_price( $total_savings ) . '</td>
              </tr>';
    }
}

How to hide Woocommerce product prices for out-of-stock products?

This snippet here below hides Woocommerce product price for out-of-stock products

add_filter( 'woocommerce_get_price_html', 'wpsh_hide_price', 9999, 2 );
 
function wpsh_hide_price( $price, $product ) {
   if ( is_admin() ) return $price; // BAIL IF BACKEND
   if ( ! $product->is_in_stock() ) {
      $price = apply_filters( 'woocommerce_empty_price_html', '', $product );
   }
   return $price;
}

How to Display a Contact Form Only When a Woocommerce Product is Out Of Stock?

Code Snippets plugin is a free plugin that allows you to run PHP/HTML/CSS/JavaScript code snippets on your site without the need to modify functions.php. The plugin can be found here. Another option is to paste the code to your child theme’s functions.php file.

<span role="button" tabindex="0" data-code="/* Show contact form instead of "Out Of Stock" message */

add_action('woocommerce_single_product_summary', 'out_of_stock_show_form', 20);
function out_of_stock_show_form() {
global $product;
if(!$product->is_in_stock( )) {
echo '<div class="your-form">';
echo 'Unfortunately this product is out of stock.<br>Contact us for more information';
echo do_shortcode('[your-shortcode]'); // Replace with your own contact form shortcode
echo '</div>';
}
}

/* This will show your contact form when the variation is out of stock */

add_filter( 'woocommerce_available_variation', 'variation_out_of_stock_show_form', 10, 3 );
function variation_out_of_stock_show_form( $data, $product, $variation ) {
if( ! $data['is_in_stock'] )
{
$data['availability_html'] = '<div class="your-form">';
$data['availability_html'] .= 'Unfortunately this product is out of stock.<br>Contact us for more information';
$data['availability_html'] .= do_shortcode('[your-shortcode]'); // Replace with your own contact form shortcode
$data['availability_html'] .= '

/* Show contact form instead of "Out Of Stock" message */

add_action('woocommerce_single_product_summary', 'out_of_stock_show_form', 20);
function out_of_stock_show_form() {
    global $product;
    if(!$product->is_in_stock( )) {
        echo  '<div class="your-form">';
        echo  'Unfortunately this product is out of stock.<br>Contact us for more information';
        echo  do_shortcode('[your-shortcode]'); // Replace with your own contact form shortcode
        echo  '</div>';
    }
}
 
/* This will show your contact form when the variation is out of stock */

add_filter( 'woocommerce_available_variation', 'variation_out_of_stock_show_form', 10, 3 );
function variation_out_of_stock_show_form( $data, $product, $variation ) {
    if( ! $data['is_in_stock'] )
    {
        $data['availability_html'] = '<div class="your-form">';
        $data['availability_html'] .= 'Unfortunately this product is out of stock.<br>Contact us for more information';
        $data['availability_html'] .= do_shortcode('[your-shortcode]'); // Replace with your own contact form shortcode
        $data['availability_html'] .= '</div>';
    }
    return $data;
}

Pay attention to the line which contains [your-shortcode]. This is the place you should add your contact form shortcode.

How to disable (grey out) selection of out-of-stock variation?

For your customers, it is much easier to choose only the available variations. Therefore, I’ll show you how to disable /grey out) a selection of out-of-stock product variations.

add_filter( 'woocommerce_variation_is_active', 'disable_variations_out_of_stock', 10, 2 );
 
function disable_variations_out_of_stock( $is_active, $variation ) {
    if ( ! $variation->is_in_stock() ) return false;
    return $is_active;
}

How to add custom stock status to products in WooCommerce?

Woocommerce comes with default stock statuses “in stock”, “out of stock” and “available on backorder”. If you would like to add custom stock status to products in WooCommerce then use this snippet here below.

This snippet here below adds four additional stock statuses to Woocommerce.

  • Pre order
  • Due in stock in 14 days
  • Due in stock in 21 days
  • Due in stock in 31 days

This is the end result.

How to add custom stock status to products in WooCommerce?

Pay attention that to add or remove your custom stock statuses you need to remove some lines accordingly. Take a look at the video above that shows how to do that (see video starting at 2:10) .

<span role="button" tabindex="0" data-code="// Add custom stock status to products in WooCommerce
function filter_woocommerce_product_stock_status_options( $status ) {
// Add new statuses
$status['pre_order'] = __( 'Pre order', 'woocommerce' );
$status['due_in_14'] = __( 'Due in stock in 14 days', 'woocommerce' );
$status['due_in_21'] = __( 'Due in stock in 21 days', 'woocommerce' );
$status['due_in_31'] = __( 'Due in stock in 31 days', '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 'due_in_14':
$availability = __( 'Due in stock in 14 days', 'woocommerce' );
break;
case 'due_in_21':
$availability = __( 'Due in stock in 21 days', 'woocommerce' );
break;
case 'due_in_31':
$availability = __( 'Due in stock in 31 days', '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 'due_in_14':
$class = 'due-in-14';
break;
case 'due_in_21':
$class = 'due-in-21';
break;
case 'due_in_31':
$class = 'due-in-31';
break;
}

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

// 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 'due_in_14':
$stock_html = '<mark class="due-in-14" style="background:transparent none;color:#666;font-weight:700;line-height:1;">' . __( 'Due in stock in 14 days', 'woocommerce' ) . '</mark>';
break;
case 'due_in_21':
$stock_html = '<mark class="due-in-21" style="background:transparent none;color:#2a2a2a;font-weight:700;line-height:1;">' . __( 'Due in stock in 21 days', 'woocommerce' ) . '</mark>';
break;
case 'due_in_31':
$stock_html = '<mark class="due-in-31" style="background:transparent none;color:#2a2a2a;font-weight:700;line-height:1;">' . __( 'Due in stock in 31 days', 'woocommerce' ) . '

// Add custom stock status to products in WooCommerce
function filter_woocommerce_product_stock_status_options( $status ) {
    // Add new statuses
    $status['pre_order'] = __( 'Pre order', 'woocommerce' );
    $status['due_in_14'] = __( 'Due in stock in 14 days', 'woocommerce' );
  	$status['due_in_21'] = __( 'Due in stock in 21 days', 'woocommerce' );
    $status['due_in_31'] = __( 'Due in stock in 31 days', '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 'due_in_14':
            $availability = __( 'Due in stock in 14 days', 'woocommerce' );
        break;
		case 'due_in_21':
            $availability = __( 'Due in stock in 21 days', 'woocommerce' );
        break;
		case 'due_in_31':
            $availability = __( 'Due in stock in 31 days', '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 'due_in_14':
            $class = 'due-in-14';
        break;
		case 'due_in_21':
            $class = 'due-in-21';
        break;
		case 'due_in_31':
            $class = 'due-in-31';
        break;
    }

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

// 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 'due_in_14':
            $stock_html = '<mark class="due-in-14" style="background:transparent none;color:#666;font-weight:700;line-height:1;">' . __( 'Due in stock in 14 days', 'woocommerce' ) . '</mark>';
        break;
		case 'due_in_21':
            $stock_html = '<mark class="due-in-21" style="background:transparent none;color:#2a2a2a;font-weight:700;line-height:1;">' . __( 'Due in stock in 21 days', 'woocommerce' ) . '</mark>';
        break;
		case 'due_in_31':
            $stock_html = '<mark class="due-in-31" style="background:transparent none;color:#2a2a2a;font-weight:700;line-height:1;">' . __( 'Due in stock in 31 days', 'woocommerce' ) . '</mark>';
        break;
    }
 
    return $stock_html;
}
add_filter( 'woocommerce_admin_stock_html', 'filter_woocommerce_admin_stock_html', 10, 2 );

How to remove Woocommerce reviews tab?

See another video I made on how to create, rename, remove and reorder custom product tabs.

add_filter( 'woocommerce_product_tabs', 'remove_review_tab', 98 );
function remove_review_tab( $tabs ) {
    unset( $tabs['reviews'] ); // Remove the reviews tab
    return $tabs;
}

How to create custom order statuses for Woocommerce?

Now let’s take a look at how to create custom order status for Woocommerce. With the help of this snippet I’m going to create a custom status called “In-progress” that is displayed on both backend and front-end order pages.

<span role="button" tabindex="0" data-code="// Add custom Woocommerce order status
function register_in_progress_order_status() {
register_post_status( 'wc-invoiced', array(
'label' => _x( 'In-progress', 'Order Status', 'woocommerce' ),
'public' => true,
'exclude_from_search' => false,
'show_in_all_admin_list' => true,
'show_in_admin_status_list' => true,
'label_count' => _n_noop( 'In-progress <span class="count">(%s)</span>', 'In-progress <span class="count">(%s)</span>', 'woocommerce' )
)
);
}

add_action( 'init', 'register_in_progress_order_status' );

function my_invoiced_order_status( $order_statuses ){
$order_statuses['wc-invoiced'] = _x( 'In-progress', 'Order Status', 'woocommerce' );
return $order_statuses;

}
add_filter( 'wc_order_statuses', 'my_invoiced_order_status' );

function show_in_bulk_actions() {
global $post_type;

if( 'shop_order' == $post_type ) {
?>
<script type="text/javascript">
jQuery(document).ready(function(){
jQuery('<option>').val('mark_invoiced').text('<?php _e( 'Change Status to In-progress','woocommerce' ); ?>').appendTo("select[name='action']");
jQuery('<option>').val('mark_invoiced').text('<?php _e( 'Change Status to In-progress','woocommerce' ); ?>').appendTo("select[name='action2']");
});
</script>

// Add custom Woocommerce order status
function register_in_progress_order_status() {
    register_post_status( 'wc-invoiced', array(
            'label' => _x( 'In-progress', 'Order Status', 'woocommerce' ),
            'public' => true,
            'exclude_from_search' => false,
            'show_in_all_admin_list' => true,
            'show_in_admin_status_list' => true,
            'label_count' => _n_noop( 'In-progress <span class="count">(%s)</span>', 'In-progress <span class="count">(%s)</span>', 'woocommerce' )
        )
    );
}

add_action( 'init', 'register_in_progress_order_status' );

function my_invoiced_order_status( $order_statuses ){
    $order_statuses['wc-invoiced'] = _x( 'In-progress', 'Order Status', 'woocommerce' );
    return $order_statuses;

}
add_filter( 'wc_order_statuses', 'my_invoiced_order_status' );

function show_in_bulk_actions() {
    global $post_type;

    if( 'shop_order' == $post_type ) {
        ?>
            <script type="text/javascript">
                jQuery(document).ready(function(){
                    jQuery('<option>').val('mark_invoiced').text('<?php _e( 'Change Status to In-progress','woocommerce' ); ?>').appendTo("select[name='action']");
                    jQuery('<option>').val('mark_invoiced').text('<?php _e( 'Change Status to In-progress','woocommerce' ); ?>').appendTo("select[name='action2']");
                });
            </script>
        <?php
    }
}
add_action( 'admin_footer', 'show_in_bulk_actions' );

How to display customer phone and email in Woocommerce orders table?

Take a look at the screenshot below, and you’ll see that there is a customer phone and email that is displayed in Woocommerce orders table. If you would like to achieve the same result, then use this snippet here below.

Display customer email in Woocommerce orders table
<span role="button" tabindex="0" data-code="// Display customer phone and email in Woocommerce orders table
add_action( 'manage_shop_order_posts_custom_column' , 'wpsh_phone_and_email_column', 50, 2 );
function wpsh_phone_and_email_column( $column, $post_id ) {
if ( $column == 'order_number' )
{
global $the_order;
// Display customer phone in Woocommerce orders table
if( $phone = $the_order->get_billing_phone() ){
$phone_wp_dashicon = '<span class="dashicons dashicons-phone"></span> ';
echo '<br><a href="tel:'.$phone.'">' . $phone_wp_dashicon . $phone.'</a></strong>';
}
// Display customer email in Woocommerce orders table
if( $email = $the_order->get_billing_email() ){
echo '<br><strong><a href="mailto:'.$email.'">' . $email . '</a>

// Display customer phone and email in Woocommerce orders table
add_action( 'manage_shop_order_posts_custom_column' , 'wpsh_phone_and_email_column', 50, 2 );
function wpsh_phone_and_email_column( $column, $post_id ) {
    if ( $column == 'order_number' )
    {
        global $the_order;
 // Display customer phone in Woocommerce orders table
        if( $phone = $the_order->get_billing_phone() ){
            $phone_wp_dashicon = '<span class="dashicons dashicons-phone"></span> ';
            echo '<br><a href="tel:'.$phone.'">' . $phone_wp_dashicon . $phone.'</a></strong>';
        }
	 // Display customer email in Woocommerce orders table
	          if( $email = $the_order->get_billing_email() ){
            echo '<br><strong><a href="mailto:'.$email.'">' . $email . '</a></strong>';
        }
    }
}

How to autocomplete Woocommerce processing orders?

Why would you need to autocomplete Woocommerce processing orders? For example, if you’re selling virtual product (Courses etc.) and you would like to add an access to it right after payments.

// Autocomplete Woocommerce processing orders

add_filter( 'woocommerce_payment_complete_order_status', 'processing_orders_autocomplete', 9999 );
function processing_orders_autocomplete() {
   return 'completed';
}

How to autocomplete all Woocommerce orders?

But (just “but) what if you would like to autocomplete all Woocommerce orders? That is evan on-hold orders? If this is the case then use this nippet here below.

// Auto Complete all WooCommerce orders.

add_action( 'woocommerce_thankyou', 'wpsh_complete_all_orders' );
function wpsh_complete_all_orders( $order_id ) { 
    if ( ! $order_id ) {
        return;
    }
    $order = wc_get_order( $order_id );
    $order->update_status( 'completed' );
}

How to Add Purchased products tab to Woocommerce my account page?

Now let’s add Purchased products tab to Woocommerce my account page (se the screenshot above). This tabb displays your recently purchased products in the separate tabe.

<span role="button" tabindex="0" data-code="// Add Purchased products tab to Woocommerce my account page

// here we hook the My Account menu links and add our custom one
add_filter( 'woocommerce_account_menu_items', 'wpsh_purchased_products', 40 );
function wpsh_purchased_products( $menu_links ){

// Set 5 in this line to something else if you would like to move the position of the tab
return array_slice( $menu_links, 0, 5, true )
+ array( 'purchased-products' => 'Purchased Products' )
+ array_slice( $menu_links, 2, NULL, true );

}

add_action( 'init', 'wpsh_purchased_products_endpoint' );
function wpsh_purchased_products_endpoint() {
add_rewrite_endpoint( 'purchased-products', EP_PAGES );
}

// Add purchased porducts as a tab content
add_action( 'woocommerce_account_purchased-products_endpoint', 'wpsh_purchased_products_content' );
function wpsh_purchased_products_content() {

global $wpdb;

// Purchased products are sorted by date
$purchased_products_ids = $wpdb->get_col(
$wpdb->prepare(
"
SELECT itemmeta.meta_value
FROM " . $wpdb->prefix . "woocommerce_order_itemmeta itemmeta
INNER JOIN " . $wpdb->prefix . "woocommerce_order_items items
ON itemmeta.order_item_id = items.order_item_id
INNER JOIN $wpdb->posts orders
ON orders.ID = items.order_id
INNER JOIN $wpdb->postmeta ordermeta
ON orders.ID = ordermeta.post_id
WHERE itemmeta.meta_key = '_product_id'
AND ordermeta.meta_key = '_customer_user'
AND ordermeta.meta_value = %s
ORDER BY orders.post_date DESC
",
get_current_user_id()
)
);

// Don’t display duplicate products
$purchased_products_ids = array_unique( $purchased_products_ids );
if( ! empty( $purchased_products_ids ) ) {

echo '<div class="woocommerce-message">Purchased products

// Add Purchased products tab to Woocommerce my account page

// here we hook the My Account menu links and add our custom one
add_filter( 'woocommerce_account_menu_items', 'wpsh_purchased_products', 40 );
function wpsh_purchased_products( $menu_links ){

// Set 5 in this line to something else if you would like to move the position of the tab
	return array_slice( $menu_links, 0, 5, true )
	+ array( 'purchased-products' => 'Purchased Products' )
	+ array_slice( $menu_links, 2, NULL, true );

}

add_action( 'init', 'wpsh_purchased_products_endpoint' );
function wpsh_purchased_products_endpoint() {
	add_rewrite_endpoint( 'purchased-products', EP_PAGES );
}

// Add purchased porducts as a tab content
add_action( 'woocommerce_account_purchased-products_endpoint', 'wpsh_purchased_products_content' );
function wpsh_purchased_products_content() {

	global $wpdb;

	// Purchased products are sorted by date
	$purchased_products_ids = $wpdb->get_col( 
		$wpdb->prepare(
			"
			SELECT      itemmeta.meta_value
			FROM        " . $wpdb->prefix . "woocommerce_order_itemmeta itemmeta
			INNER JOIN  " . $wpdb->prefix . "woocommerce_order_items items
			            ON itemmeta.order_item_id = items.order_item_id
			INNER JOIN  $wpdb->posts orders
			            ON orders.ID = items.order_id
			INNER JOIN  $wpdb->postmeta ordermeta
			            ON orders.ID = ordermeta.post_id
			WHERE       itemmeta.meta_key = '_product_id'
			            AND ordermeta.meta_key = '_customer_user'
			            AND ordermeta.meta_value = %s
			ORDER BY    orders.post_date DESC
			",
			get_current_user_id()
		)
	);

	// Don’t display duplicate products
	$purchased_products_ids = array_unique( $purchased_products_ids );
	if( ! empty( $purchased_products_ids ) ) {
	  
	 echo '<div class="woocommerce-message">Purchased products</div>';
	  
		$purchased_products = new WP_Query( array(
			'post_type' => 'product',
			'post_status' => 'publish',
			'post__in' => $purchased_products_ids,
			'orderby' => 'post__in',
			'posts_per_page' => -1,
		) );
	
		woocommerce_product_loop_start();

		while ( $purchased_products->have_posts() ) : $purchased_products->the_post();

			wc_get_template_part( 'content', 'product' );

		endwhile;

		woocommerce_product_loop_end();

		woocommerce_reset_loop();
		wp_reset_postdata();

	} else {
	  // Change this text if needed)
		echo 'Unfortunately you have no purchases yet';
	}
}

How to add “Order again” button to Woocommerce my account page?

As menitonet above, we’re goint to add “Order again” button to Woocommerce my account page. Use this snippet here below.

// Add "Order again" button to Woocommerce my account page
add_filter( 'woocommerce_my_account_my_orders_actions', 'wpsh_order_again_button', 9999, 2 );
    
function wpsh_order_again_button( $actions, $order ) {
    if ( $order->has_status( 'completed' ) ) {
        $actions['order-again'] = array(
            'url' => wp_nonce_url( add_query_arg( 'order_again', $order->get_id(), wc_get_cart_url() ), 'woocommerce-order_again' ),
            'name' => __( 'Order again', 'woocommerce' ),
        );
    }
    return $actions;
}

How to add “Cancel” button to Woocommerce my account page?

Take a look at this screenshot here. As you see, there are two custom buttons (“Cancel” and “Order again” buttons). So, if you would like to add “Cancel” button to Woocommerce my account page, then use this snippet here below.

NB! Pay attention at the line 8. In it you can set the delay in days. Currently it is set to 3 dayst, that is withnin 3 days it’s allowed to cancel the order.

How to add "Cancel" button to Woocommerce my account page?

// Add "Cancel" button to Woocommerce my account page

add_filter( 'woocommerce_valid_order_statuses_for_cancel', 'wpsh_add_cancel_button', 20, 2 );
function wpsh_add_cancel_button( $statuses, $order = '' ){

    // Set HERE the order statuses where you want the cancel button to appear
    $custom_statuses    = array( 'pending', 'processing', 'on-hold', 'failed' );

    // Set HERE the delay (in days)
    $duration = 3; // 3 days

    // UPDATE: Get the order ID and the WC_Order object
    if( ! is_object( $order ) && isset($_GET['order_id']) )
        $order = wc_get_order( absint( $_GET['order_id'] ) );

    $delay = $duration*24*60*60; // (duration in seconds)
    $date_created_time  = strtotime($order->get_date_created()); // Creation date time stamp
    $date_modified_time = strtotime($order->get_date_modified()); // Modified date time stamp
    $now = strtotime("now"); // Now  time stamp

    // Using Creation date time stamp
    if ( ( $date_created_time + $delay ) >= $now ) return $custom_statuses;
    else return $statuses;
}

How to add Woocommerce product ID column?

Next, let’s customize Woocommerce admin dashboard further. Sometimes you may need to visually see your Woocommerce product ID columns. This snippet will help you out.

// Add Woocommerce produc ID column?

function woo_product_extra_columns($columns)
{
	$newcolumns = array(
		"cb"       		=> "<input type  = "checkbox" />",
		"product_ID"    => esc_html__('ID', 'woocommerce'),
	);
	$columns = array_merge($newcolumns, $columns);
	
	return $columns;
}
add_filter("manage_edit-product_columns", "woo_product_extra_columns");

function woo_product_extra_columns_content($column)
{
	global $post;
	
	$product_id = $post->ID;
	switch ($column)
	{
		case "product_ID":
			echo $product_id;
		break;		
	}
}
add_action("manage_posts_custom_column",  "woo_product_extra_columns_content");

// Adjust column size
add_action('admin_head', 'my_column_width');
function my_column_width() {
    echo '<style type="text/css">';
    echo '.column-product_ID { width:40px; }';
    echo '</style>';
}
  • How to hide company field based on a Woocommerce custom checkout radio selection?
  • How to use Woocommerce coupons in 23 different ways? (23 simple hacks)
  • How to Customize Woocommerce Orders page? (20 hacks)
  • How to customize Woocommerce cart page? 21 useful Woocommerce Cart Page Hacks
  • How to Customize Woocommerce shop and category page? 17 useful hacks
  • How to customize Woocommerce Single Product Page | 14 Useful Hacks
  • How to Customize Woocommerce Checkout page? 28 useful hacks
  • How to customize Woocommerce Single Product Page | 14 Useful Hacks
  • How to Hide Woocommerce Shipping Methods (Conditionally) – 15 Hacks
  • How to Customize Woocommerce Stock Status? (17 hacks)

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top