At Woo, our Happiness Engineers spend a lot of time in the trenches with merchants, answering support tickets, debugging custom setups, and building quick solutions to unblock workflows. Sometimes, what starts as a one-off request turns into something reusable and worth sharing.
Here are five real-world snippets our Happiness Engineer, Shameem Reza, originally wrote to solve specific merchant problems. If you manage or support WooCommerce stores, these might come in handy.
1. 🚚 Show estimated shipping time on product pages

The problem:
A merchant wanted to display estimated shipping times for each product or variation without needing a heavy plugin.
The solution:
A lightweight plugin that adds a custom “Shipping Time” field to products and variations. It automatically updates on the product page when a customer selects a variation.
Features:
- Adds a shipping time input field in the product editor.
- Dynamically shows the shipping estimate on the frontend.
- Compatible with variable products and default variations.
See the code 👇
<?php
/*
* Plugin Name: WooCommerce Shipping Time Display
* Plugin URI: https://wcwiz.com/how-to-show-shipping-time-on-woocommerce-product-page/
* Description: Adds a custom shipping time field to WooCommerce products and displays it on the product page.
* Version: 1.9
* Author: Shameem Reza
* Author URI: https://shameem.dev
* License: GPL2
* Text Domain: wc-shipping-time
* Domain Path: /languages
* WC requires at least: 5.0
* WC tested up to: 9.6.2
* Requires PHP: 7.3
* Requires Plugins: woocommerce
*/
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly.
}
// Declare HPOS compatibility
add_action('before_woocommerce_init', function () {
if (class_exists('AutomatticWooCommerceUtilitiesFeaturesUtil')) {
AutomatticWooCommerceUtilitiesFeaturesUtil::declare_compatibility('custom_order_tables', __FILE__, true);
}
});
/**
* Add shipping time field to WooCommerce simple products.
*/
function wcst_add_shipping_time_field() {
woocommerce_wp_text_input([
'id' => '_shipping_time',
'label' => __('Shipping Time', 'wc-shipping-time'),
'description' => __('Enter shipping time, e.g., 24H, 48H, 3 days', 'wc-shipping-time'),
'desc_tip' => true,
]);
}
add_action('woocommerce_product_options_general_product_data', 'wcst_add_shipping_time_field');
/**
* Save the shipping time field data for simple products.
*/
function wcst_save_shipping_time_field($post_id) {
if (isset($_POST['_shipping_time'])) {
update_post_meta($post_id, '_shipping_time', sanitize_text_field($_POST['_shipping_time']));
}
}
add_action('woocommerce_process_product_meta', 'wcst_save_shipping_time_field');
/**
* Add shipping time field to variations.
*/
function wcst_add_shipping_time_to_variations($loop, $variation_data, $variation) {
woocommerce_wp_text_input([
'id' => "variation_shipping_time_$variation->ID",
'label' => __('Shipping Time', 'wc-shipping-time'),
'description' => __('Enter shipping time for this variation, e.g., 24H, 48H, 3 days', 'wc-shipping-time'),
'desc_tip' => true,
'type' => 'text',
'value' => get_post_meta($variation->ID, '_shipping_time', true),
]);
}
add_action('woocommerce_variation_options_pricing', 'wcst_add_shipping_time_to_variations', 10, 3);
/**
* Save shipping time for variations.
*/
function wcst_save_shipping_time_variation($variation_id) {
if (isset($_POST["variation_shipping_time_$variation_id"])) {
update_post_meta($variation_id, '_shipping_time', sanitize_text_field($_POST["variation_shipping_time_$variation_id"]));
}
}
add_action('woocommerce_save_product_variation', 'wcst_save_shipping_time_variation', 10, 2);
/**
* Pass variation shipping time data to WooCommerce variation system.
*/
function wcst_add_variation_shipping_time_data($data, $product, $variation) {
if (!is_array($data)) {
$data = [];
}
$shipping_time = get_post_meta($variation->get_id(), '_shipping_time', true);
$data['shipping_time'] = !empty($shipping_time) ? $shipping_time : '';
return $data;
}
add_filter('woocommerce_available_variation', 'wcst_add_variation_shipping_time_data', 10, 3);
/**
* Display the shipping time on the product page and support default variations.
*/
function wcst_display_shipping_time() {
global $product;
if (!$product || !is_a($product, 'WC_Product')) {
return;
}
$shipping_time = '';
// Handle default variation selection
if ($product->is_type('variable')) {
$default_attributes = $product->get_default_attributes();
foreach ($product->get_available_variations() as $variation) {
$match = true;
foreach ($default_attributes as $attribute => $value) {
if ($variation['attributes']['attribute_' . $attribute] !== $value) {
$match = false;
break;
}
}
if ($match) {
$variation_id = $variation['variation_id'];
$shipping_time = get_post_meta($variation_id, '_shipping_time', true);
break;
}
}
}
// Fallback to parent product shipping time if no variation has shipping time
if (empty($shipping_time)) {
$shipping_time = get_post_meta($product->get_id(), '_shipping_time', true);
}
?>
<p id="wcst-shipping-time" style="display: <?php echo empty($shipping_time) ? 'none' : 'block'; ?>;">
<strong><?php echo esc_html__('Shipping Time:', 'wc-shipping-time'); ?></strong>
<span><?php echo esc_html($shipping_time); ?></span>
</p>
<script type="text/javascript">
jQuery(document).ready(function($) {
$('form.variations_form').on('found_variation', function(event, variation) {
if (variation.shipping_time) {
$('#wcst-shipping-time').show();
$('#wcst-shipping-time span').text(variation.shipping_time);
} else {
$('#wcst-shipping-time').hide();
}
});
$('form.variations_form').on('reset_data', function() {
$('#wcst-shipping-time').hide();
});
});
</script>
<?php
}
add_action('woocommerce_single_product_summary', 'wcst_display_shipping_time', 20);
2. 🎁 Stop auto-renewal for gifted subscriptions

The problem:
Could gifted subscriptions expire after a year without charging the gift giver again?
The solution:
This snippet:
- Automatically sets them to manual renewal.
- Cancels any scheduled payments in the background.
Bonus: It logs everything to help with debugging.
See the code 👇
// Hook into the subscription creation process
add_action( 'woocommerce_checkout_subscription_created', 'set_gifted_subscription_to_manual_renewal', 10, 2 );
function set_gifted_subscription_to_manual_renewal( $subscription, $order ) {
// Check if the subscription is gifted using the gifting plugin's functionality
if ( class_exists( 'WCS_Gifting' ) && WCS_Gifting::is_gifted_subscription( $subscription ) ) {
// Set the subscription to manual renewal
$subscription->set_requires_manual_renewal( true );
// Cancel any scheduled renewal actions
as_unschedule_all_actions( 'woocommerce_scheduled_subscription_payment', [ 'subscription_id' => $subscription->get_id() ] );
// Log the action for debugging
wc_get_logger()->info(
'Gifted subscription ID ' . $subscription->get_id() . ' renewals canceled and set to manual.',
[ 'source' => 'woocommerce' ]
);
// Save the subscription changes
$subscription->save();
}
}
// Additional safeguard: Ensure gifted subscriptions remain manual during payment
add_action( 'woocommerce_subscription_payment_complete', 'cancel_gifted_subscription_renewals', 10, 1 );
function cancel_gifted_subscription_renewals( $subscription ) {
// Verify gifted subscription using the gifting plugin
if ( class_exists( 'WCS_Gifting' ) && WCS_Gifting::is_gifted_subscription( $subscription ) ) {
// Cancel scheduled renewal actions
as_unschedule_all_actions( 'woocommerce_scheduled_subscription_payment', [ 'subscription_id' => $subscription->get_id() ] );
// Log the cancellation for confirmation
wc_get_logger()->info(
'Gifted subscription ID ' . $subscription->get_id() . ' scheduled renewals canceled post-payment.',
[ 'source' => 'woocommerce' ]
);
}
}
3. 📦 Restock items when subscriptions are canceled

The problem:
A developer needed inventory to reflect real-time changes when subscriptions are canceled so that products could be resold right away.
The solution:
This function:
- Restocks items for both simple and variable products.
- Adjusts stock based on the quantity ordered.
It’s one of those “set it and forget it” helpers that improves inventory accuracy.
See the code 👇
add_action('woocommerce_subscription_status_cancelled', 'adjust_inventory_on_subscription_cancel', 10, 1);
function adjust_inventory_on_subscription_cancel($subscription) {
if (!$subscription) return;
foreach ($subscription->get_items() as $item) {
$product = $item->get_product();
$variation_id = $item->get_variation_id();
// Ensure the product is variable and has stock management enabled
if ($product && $product->managing_stock()) {
$current_stock = $product->get_stock_quantity();
$item_quantity = $item->get_quantity();
// Adjust stock for the specific variation or parent product
$new_stock = $current_stock + $item_quantity;
if ($variation_id) {
$variation = wc_get_product($variation_id);
if ($variation && $variation->managing_stock()) {
$variation->set_stock_quantity($new_stock);
$variation->save();
}
} else {
$product->set_stock_quantity($new_stock);
$product->save();
}
}
}
}
4. 🚫 Instantly cancel ‘pending-cancel’ subscriptions

The problem:
Some merchants want subscriptions to be canceled immediately when a customer hits “cancel,” not after the billing period ends.
The solution:
A simple listener that:
- Detects when a subscription status changes to
pending-cancel
. - Immediately updates it to
cancelled
. - Logs the change for traceability.
See the code 👇
add_action( 'woocommerce_subscription_status_updated', 'auto_cancel_pending_cancellations', 10, 3 );
function auto_cancel_pending_cancellations( $subscription, $new_status, $old_status ) {
// Ensure we are dealing with a valid subscription object
if ( is_a( $subscription, 'WC_Subscription' ) ) {
// Check if the new status is 'pending-cancel'
if ( 'pending-cancel' === $new_status ) {
// Attempt to cancel the subscription
try {
$subscription->update_status( 'cancelled' );
// Optionally log the cancellation
error_log( 'Subscription ID ' . $subscription->get_id() . ' has been automatically cancelled.' );
} catch ( Exception $e ) {
// Log any errors
error_log( 'Error cancelling subscription ID ' . $subscription->get_id() . ': ' . $e->getMessage() );
}
}
}
}
5. 🙈 Hide bundles when required products are out of stock

The problem:
A merchant wanted bundled products to disappear if any required item inside the bundle was out of stock.
The solution:
A visibility filter that:
- Checks the stock status of each bundled item.
- Hides the parent bundle if any required product is unavailable.
See the code 👇
//Hide the Bundle When a product is Out of Stock
add_filter( 'woocommerce_product_is_visible', 'hide_bundle_when_required_product_is_out_of_stock', 10, 2 );
function hide_bundle_when_required_product_is_out_of_stock( $visible, $product_id ) {
$product = wc_get_product( $product_id );
// Check if the product is a bundle
if ( $product && $product->is_type( 'bundle' ) ) {
$bundled_items = $product->get_bundled_items();
// Loop through all bundled items
foreach ( $bundled_items as $bundled_item ) {
// Check if it's a required product
if ( ! $bundled_item->is_optional() ) {
$bundled_product = $bundled_item->get_product();
// If the required product is out of stock, hide the bundle
if ( $bundled_product && ! $bundled_product->is_in_stock() ) {
return false;
}
}
}
}
return $visible;
}
Leave a Reply