How to Customize Woocommerce Orders page? (20 hacks)

In this post I’ll show you how to customize Woocommerce orders page with the help of simple code snippets. 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.

WpCodeBox 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: How to Customize Woocommerce Orders page?

In case you have a hard time using or following snippets shown below, take a look at the video. In it I’ll show you how to use them.

How to add an Woocommerce order number search field to the WP Admin top bar?

At the moment you have to go to the Woocommerce >> Orders page in order to search orders. With the help of this hack you can do it directly from your WordPress admin bar (see screenshot)

How to add an Woocommerce order number search field to the WP Admin top bar?
<span role="button" tabindex="0" data-code="// Add an Woocommerce order number search field to the WP Admin top bar
add_action('wp_before_admin_bar_render', function() {
if(!current_user_can('administrator')) {
return;
}

global $wp_admin_bar;

$search_query = '';
if (!empty($_GET['post_type']) && $_GET['post_type'] == 'shop_order' ) {

$search_query = !empty($_GET['s']) ? $_GET['s'] : '';

if($search_query) {
$order = get_post(intval($search_query));

if($order) {
wp_redirect(get_edit_post_link($order->ID, ''));
exit;
}
}
}

$wp_admin_bar->add_menu(array(
'id' => 'admin_bar_shop_order_form',
'title' => '<form method="get" action="'.get_site_url().'/wp-admin/edit.php?post_type=shop_order">
<input name="s" type="text" placeholder="Order ID" value="' . esc_attr($search_query) . '" style="width:100px; height: 25px; padding-left: 5px;">
<button class="button button-primary" style="height: 25px; padding: 0px 10px 0px 10px; margin-left: -5px;">Check this order</button>
<input name="post_type" value="shop_order" type="hidden">

// Add an Woocommerce order number search field to the WP Admin top bar
add_action('wp_before_admin_bar_render', function() {
  if(!current_user_can('administrator')) {
    return;
  }
  
  global $wp_admin_bar;

  $search_query = '';
  if (!empty($_GET['post_type']) && $_GET['post_type'] == 'shop_order' ) {

    $search_query = !empty($_GET['s']) ? $_GET['s'] : '';

    if($search_query) {
        $order = get_post(intval($search_query));

        if($order) {
            wp_redirect(get_edit_post_link($order->ID, ''));
            exit;
        }
    }
  }

  $wp_admin_bar->add_menu(array(
    'id' => 'admin_bar_shop_order_form',
    'title' => '<form method="get" action="'.get_site_url().'/wp-admin/edit.php?post_type=shop_order">
      <input name="s" type="text" placeholder="Order ID" value="' . esc_attr($search_query) . '" style="width:100px; height: 25px; padding-left: 5px;">
      <button  class="button button-primary" style="height: 25px; padding: 0px 10px 0px 10px; margin-left: -5px;">Check this order</button>
      <input name="post_type" value="shop_order" type="hidden">
    </form>'
  ));
},100
);

How to send a custom reminder email for WooCommerce On-Hold orders after two days?

By default, Woocommerce doesn’t send out reminder emails for the on-hold emails. With the help of this snippet here you can send a custom reminder email for WooCommerce On-Hold orders after two days of order completion.

NB! Pay attention to the line 8. In it, you can change the remider delay.

<span role="button" tabindex="0" data-code="// Send a custom reminder email for WooCommerce On-Hold orders after two days of order completion

add_action( 'restrict_manage_posts', 'wpsh_payment_reminder' );
function wpsh_payment_reminder() {
global $pagenow, $post_type;

if( 'shop_order' === $post_type && 'edit.php' === $pagenow
&& get_option( 'unpaid_orders_reminder_daily_process' ) < time() ) :

$days_delay = 2; // 24 hours
$one_day = 24 * 60 * 60;
$today = strtotime( date('Y-m-d') );

$unpaid_orders = (array) wc_get_orders( array(
'limit' => -1,
'status' => 'on-hold',
'date_created' => '<' . ( $today – ($days_delay * $one_day) ),
) );

if ( sizeof($unpaid_orders) > 0 ) {
$reminder_text = __("Payment reminder email sent to customer $today.", "woocommerce");

foreach ( $unpaid_orders as $order ) {
$order->update_meta_data( '_send_on_hold', true );
$order->update_status( 'reminder', $reminder_text );

$wc_emails = WC()->mailer()->get_emails(); // Get all WC_emails objects instances
$wc_emails['WC_Email_Customer_On_Hold_Order']->trigger( $order->get_id() ); // Send email
}
}
update_option( 'unpaid_orders_reminder_daily_process', $today + $one_day );

endif;
}

add_action ( 'woocommerce_email_order_details', 'wpsh_payment_reminder_notification', 5, 4 );
function wpsh_payment_reminder_notification( $order, $sent_to_admin, $plain_text, $email ){
if ( 'customer_on_hold_order' == $email->id && $order->get_meta('_send_on_hold') ){
$order_id = $order->get_id();
$order_link = wc_get_page_permalink('myaccount').'view-order/'.$order_id.'/';
$order_number = $order->get_order_number();

echo '<h2>'.__("Do not forget about your order.").'</h2>
<p>'.sprintf( __("CUSTOM MESSAGE HERE… %s"),
'<a href="'.$order_link.'">'.__("Your My account order #").$order_number.'<a>'
) .'

// Send a custom reminder email for WooCommerce On-Hold orders after two days of order completion

add_action( 'restrict_manage_posts', 'wpsh_payment_reminder' );
function wpsh_payment_reminder() {
    global $pagenow, $post_type;

    if( 'shop_order' === $post_type && 'edit.php' === $pagenow
        && get_option( 'unpaid_orders_reminder_daily_process' ) < time() ) :

    $days_delay = 2; // 24 hours
    $one_day    = 24 * 60 * 60;
    $today      = strtotime( date('Y-m-d') );

    $unpaid_orders = (array) wc_get_orders( array(
        'limit'        => -1,
        'status'       => 'on-hold',
        'date_created' => '<' . ( $today - ($days_delay * $one_day) ),
    ) );

    if ( sizeof($unpaid_orders) > 0 ) {
        $reminder_text = __("Payment reminder email sent to customer $today.", "woocommerce");

        foreach ( $unpaid_orders as $order ) {
            $order->update_meta_data( '_send_on_hold', true );
            $order->update_status( 'reminder', $reminder_text );

            $wc_emails = WC()->mailer()->get_emails(); // Get all WC_emails objects instances
            $wc_emails['WC_Email_Customer_On_Hold_Order']->trigger( $order->get_id() ); // Send email
        }
    }
    update_option( 'unpaid_orders_reminder_daily_process', $today + $one_day );

    endif;
}

add_action ( 'woocommerce_email_order_details', 'wpsh_payment_reminder_notification', 5, 4 );
function wpsh_payment_reminder_notification( $order, $sent_to_admin, $plain_text, $email ){
    if ( 'customer_on_hold_order' == $email->id && $order->get_meta('_send_on_hold') ){
        $order_id     = $order->get_id();
        $order_link   = wc_get_page_permalink('myaccount').'view-order/'.$order_id.'/';
        $order_number = $order->get_order_number();

        echo '<h2>'.__("Do not forget about your order.").'</h2>
        <p>'.sprintf( __("CUSTOM MESSAGE HERE… %s"), 
            '<a href="'.$order_link.'">'.__("Your My account order #").$order_number.'<a>'
        ) .'</p>';

        $order->delete_meta_data('_send_on_hold');
        $order->save();
    }
}

How to create custom order status 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 Filter Woocommerce orders by coupons used?

If you would like to know how to filter Woocommerce orders by coupons used, then it’s just a snippet away. That is, use this one here below.

<span role="button" tabindex="0" data-code="// Filter Woocommerce orders by coupons used
defined( 'ABSPATH' ) or exit;

// fire it up!
add_action( 'plugins_loaded', 'wc_filter_orders_by_coupon' );

class WC_Filter_Orders_By_Coupon {
const VERSION = '1.1.0';

/** @var WC_Filter_Orders_By_Coupon single instance of this plugin */
protected static $instance;
public function __construct() {

// load translations
add_action( 'init', array( $this, 'load_translation' ) );
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {

// adds the coupon filtering dropdown to the orders page
add_action( 'restrict_manage_posts', array( $this, 'filter_orders_by_coupon_used' ) );

// makes coupons filterable
add_filter( 'posts_join', array( $this, 'add_order_items_join' ) );
add_filter( 'posts_where', array( $this, 'add_filterable_where' ) );
}
}

public function filter_orders_by_coupon_used() {
global $typenow;

if ( 'shop_order' === $typenow ) {

$args = array(
'posts_per_page' => – 1,
'orderby' => 'title',
'order' => 'asc',
'post_type' => 'shop_coupon',
'post_status' => 'publish',
);

$coupons = get_posts( $args );

if ( ! empty( $coupons ) ) : ?>

<select name="_coupons_used" id="dropdown_coupons_used">
<option value="">
<?php esc_html_e( 'Filter by coupon used', 'wc-filter-orders' ); ?>
</option>
<?php foreach ( $coupons as $coupon ) : ?>
<option value="<?php echo esc_attr( $coupon->post_title ); ?>" <?php echo esc_attr( isset( $_GET['_coupons_used'] ) ? selected( $coupon->post_title, $_GET['_coupons_used'], false ) : '' ); ?>>
<?php echo esc_html( $coupon->post_title ); ?>
</option>
<?php endforeach; ?>
</select>

// Filter Woocommerce orders by coupons used
defined( 'ABSPATH' ) or exit;

// fire it up!
add_action( 'plugins_loaded', 'wc_filter_orders_by_coupon' );

 class WC_Filter_Orders_By_Coupon {
	const VERSION = '1.1.0';

	/** @var WC_Filter_Orders_By_Coupon single instance of this plugin */
	protected static $instance;
	public function __construct() {

		// load translations
		add_action( 'init', array( $this, 'load_translation' ) );
		if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {

			// adds the coupon filtering dropdown to the orders page
			add_action( 'restrict_manage_posts', array( $this, 'filter_orders_by_coupon_used' ) );

			// makes coupons filterable
			add_filter( 'posts_join',  array( $this, 'add_order_items_join' ) );
			add_filter( 'posts_where', array( $this, 'add_filterable_where' ) );
		}
	}

	public function filter_orders_by_coupon_used() {
		global $typenow;

		if ( 'shop_order' === $typenow ) {

			$args = array(
				'posts_per_page' => - 1,
				'orderby'        => 'title',
				'order'          => 'asc',
				'post_type'      => 'shop_coupon',
				'post_status'    => 'publish',
			);

			$coupons = get_posts( $args );

			if ( ! empty( $coupons ) ) : ?>

				<select name="_coupons_used" id="dropdown_coupons_used">
					<option value="">
						<?php esc_html_e( 'Filter by coupon used', 'wc-filter-orders' ); ?>
					</option>
					<?php foreach ( $coupons as $coupon ) : ?>
						<option value="<?php echo esc_attr( $coupon->post_title ); ?>" <?php echo esc_attr( isset( $_GET['_coupons_used'] ) ? selected( $coupon->post_title, $_GET['_coupons_used'], false ) : '' ); ?>>
							<?php echo esc_html( $coupon->post_title ); ?>
						</option>
					<?php endforeach; ?>
				</select>
			<?php endif;
		}
	}

	public function add_order_items_join( $join ) {
		global $typenow, $wpdb;

		if ( 'shop_order' === $typenow && isset( $_GET['_coupons_used'] ) && ! empty( $_GET['_coupons_used'] ) ) {

			$join .= "LEFT JOIN {$wpdb->prefix}woocommerce_order_items woi ON {$wpdb->posts}.ID = woi.order_id";
		}

		return $join;
	}

	public function add_filterable_where( $where ) {
		global $typenow, $wpdb;

		if ( 'shop_order' === $typenow && isset( $_GET['_coupons_used'] ) && ! empty( $_GET['_coupons_used'] ) ) {

			// Main WHERE query part
			$where .= $wpdb->prepare( " AND woi.order_item_type='coupon' AND woi.order_item_name='%s'", wc_clean( $_GET['_coupons_used'] ) );
		}

		return $where;
	}

	public function load_translation() {
		// localization
		load_plugin_textdomain( 'wc-filter-orders', false, dirname( plugin_basename( __FILE__ ) ) . '/i18n/languages' );
	}

	public static function instance() {
		if ( is_null( self::$instance ) ) {
		 	self::$instance = new self();
		}
		return self::$instance;
	}

	public function __clone() {
		/* translators: Placeholders: %s - plugin name */
		_doing_it_wrong( __FUNCTION__, sprintf( esc_html__( 'You cannot clone instances of %s.', 'wc-filter-orders' ), 'Filter WC Orders by Coupon' ), '1.1.0' );
	}

	public function __wakeup() {
		/* translators: Placeholders: %s - plugin name */
		_doing_it_wrong( __FUNCTION__, sprintf( esc_html__( 'You cannot unserialize instances of %s.', 'wc-filter-orders' ), 'Filter WC Orders by Coupon' ), '1.1.0' );
	}
}

function wc_filter_orders_by_coupon() {
	return WC_Filter_Orders_By_Coupon::instance();
}

How to filter WooCommerce orders by payment method?

Now let’s see how to filter WooCommerce orders by payment method. Just use this snippet here below.

<span role="button" tabindex="0" data-code="// Filter Woocommerce orders by payment method
defined( 'ABSPATH' ) or exit;

// fire it up!
add_action( 'plugins_loaded', 'wc_filter_orders_by_payment' );

class WC_Filter_Orders_By_Payment {

const VERSION = '1.0.0';

/** @var WC_Filter_Orders_By_Payment single instance of this plugin */
protected static $instance;

public function __construct() {

if ( is_admin() ) {

// add bulk order filter for exported / non-exported orders
add_action( 'restrict_manage_posts', array( $this, 'filter_orders_by_payment_method') , 20 );
add_filter( 'request', array( $this, 'filter_orders_by_payment_method_query' ) );
}
}

public function filter_orders_by_payment_method() {
global $typenow;

if ( 'shop_order' === $typenow ) {

// get all payment methods, even inactive ones
$gateways = WC()->payment_gateways->payment_gateways();

?>
<select name="_shop_order_payment_method" id="dropdown_shop_order_payment_method">
<option value="">
<?php esc_html_e( 'All Payment Methods', 'wc-filter-orders-by-payment' ); ?>
</option>

<?php foreach ( $gateways as $id => $gateway ) : ?>
<option value="<?php echo esc_attr( $id ); ?>" <?php echo esc_attr( isset( $_GET['_shop_order_payment_method'] ) ? selected( $id, $_GET['_shop_order_payment_method'], false ) : '' ); ?>>
<?php echo esc_html( $gateway->get_method_title() ); ?>
</option>
<?php endforeach; ?>
</select>

// Filter Woocommerce orders by payment method
defined( 'ABSPATH' ) or exit;

// fire it up!
add_action( 'plugins_loaded', 'wc_filter_orders_by_payment' );

class WC_Filter_Orders_By_Payment {

	const VERSION = '1.0.0';

	/** @var WC_Filter_Orders_By_Payment single instance of this plugin */
	protected static $instance;

	public function __construct() {

		if ( is_admin() ) {

			// add bulk order filter for exported / non-exported orders
			add_action( 'restrict_manage_posts', array( $this, 'filter_orders_by_payment_method') , 20 );
			add_filter( 'request',               array( $this, 'filter_orders_by_payment_method_query' ) );		
		}
	}

	public function filter_orders_by_payment_method() {
		global $typenow;

		if ( 'shop_order' === $typenow ) {

			// get all payment methods, even inactive ones
			$gateways = WC()->payment_gateways->payment_gateways();

			?>
			<select name="_shop_order_payment_method" id="dropdown_shop_order_payment_method">
				<option value="">
					<?php esc_html_e( 'All Payment Methods', 'wc-filter-orders-by-payment' ); ?>
				</option>

				<?php foreach ( $gateways as $id => $gateway ) : ?>
				<option value="<?php echo esc_attr( $id ); ?>" <?php echo esc_attr( isset( $_GET['_shop_order_payment_method'] ) ? selected( $id, $_GET['_shop_order_payment_method'], false ) : '' ); ?>>
					<?php echo esc_html( $gateway->get_method_title() ); ?>
				</option>
				<?php endforeach; ?>
			</select>
			<?php
		}
	}
	public function filter_orders_by_payment_method_query( $vars ) {
		global $typenow;
		if ( 'shop_order' === $typenow && isset( $_GET['_shop_order_payment_method'] ) && ! empty( $_GET['_shop_order_payment_method'] ) ) {

			$vars['meta_key']   = '_payment_method';
			$vars['meta_value'] = wc_clean( $_GET['_shop_order_payment_method'] );
		}
		return $vars;
	}
	public static function instance() {
		if ( is_null( self::$instance ) ) {
			self::$instance = new self();
		}
		return self::$instance;
	}
}

function wc_filter_orders_by_payment() {
    return WC_Filter_Orders_By_Payment::instance();
}

How to filter Woocommerce orders by user role?

Next, let’s filter Woocommerce orders by user role. The end result is the one you see on the screenshot here below.

How to Customize Woocommerce Orders page?
<span role="button" tabindex="0" data-code="// Filter Woocommerce orders by user role

function wpsh_user_role_filter() {

global $typenow, $wp_query;

if ( in_array( $typenow, wc_get_order_types( 'order-meta-boxes' ) ) ) {
$user_role = '';

// Get all user roles
$user_roles = array( 'guest' => 'Guest' );
foreach ( get_editable_roles() as $key => $values ) {
$user_roles[ $key ] = $values['name'];
}

// Set a selected user role
if ( ! empty( $_GET['_user_role'] ) ) {
$user_role = sanitize_text_field( $_GET['_user_role'] );
}

// Display drop down
?><select name='_user_role'>
<option value=''><?php _e( 'Select a user role', 'woocommerce' ); ?></option><?php
foreach ( $user_roles as $key => $value ) :
?><option <?php selected( $user_role, $key ); ?> value='<?php echo $key; ?>'><?php echo $value; ?></option><?php
endforeach;
?></select>

// Filter Woocommerce orders by user role

function wpsh_user_role_filter() {

	global $typenow, $wp_query;

	if ( in_array( $typenow, wc_get_order_types( 'order-meta-boxes' ) ) ) {
		$user_role	= '';

		// Get all user roles
		$user_roles = array( 'guest' => 'Guest' );
		foreach ( get_editable_roles() as $key => $values ) {
			$user_roles[ $key ] = $values['name'];
		}

		// Set a selected user role
		if ( ! empty( $_GET['_user_role'] ) ) {
			$user_role	= sanitize_text_field( $_GET['_user_role'] );
		}

		// Display drop down
		?><select name='_user_role'>
			<option value=''><?php _e( 'Select a user role', 'woocommerce' ); ?></option><?php
			foreach ( $user_roles as $key => $value ) :
				?><option <?php selected( $user_role, $key ); ?> value='<?php echo $key; ?>'><?php echo $value; ?></option><?php
			endforeach;
		?></select><?php
	}

}
add_action( 'restrict_manage_posts', 'wpsh_user_role_filter' );

function wpsh_user_role_filter_where( $query ) {

	if ( ! $query->is_main_query() || empty( $_GET['_user_role'] ) || $_GET['post_type'] !== 'shop_order' ) {
		return;
	}

	if ( $_GET['_user_role'] != 'guest' ) {
		$ids = get_users( array( 'role' => sanitize_text_field( $_GET['_user_role'] ), 'fields' => 'ID' ) );
		$ids = array_map( 'absint', $ids );
	} else {
		$ids = array( 0 );
	}

	$query->set( 'meta_query', array(
		array(
			'key' => '_customer_user',
			'compare' => 'IN',
			'value' => $ids,
		)
	) );

	if ( empty( $ids ) ) {
		$query->set( 'posts_per_page', 0 );
	}
}
add_filter( 'pre_get_posts', 'wpsh_user_role_filter_where' );

How to display used coupons on WooCommerce admin orders list?

If you would like to display used coupons on WooCommerce admin orders list then use this snippet here below. If no coupons is used then “No coupons used” is displayed. See the screenshot above.

<span role="button" tabindex="0" data-code="// Display used coupons on WooCommerce admin orders list
add_filter( 'manage_edit-shop_order_columns', 'woo_customer_order_coupon_column_for_orders' );
function woo_customer_order_coupon_column_for_orders( $columns ) {
$new_columns = array();

foreach ( $columns as $column_key => $column_label ) {
if ( 'order_total' === $column_key ) {
$new_columns['order_coupons'] = __('Coupons', 'woocommerce');
}

$new_columns[$column_key] = $column_label;
}
return $new_columns;
}

add_action( 'manage_shop_order_posts_custom_column' , 'woo_display_customer_order_coupon_in_column_for_orders' );
function woo_display_customer_order_coupon_in_column_for_orders( $column ) {
global $the_order, $post;
if( $column == 'order_coupons' ) {
if( $coupons = $the_order->get_coupon_codes() ) {
echo implode(', ', $coupons) . ' ('.count($coupons).')';
} else {
echo '<small><em>'. __('No coupon used') . '</em>

// Display used coupons on WooCommerce admin orders list
add_filter( 'manage_edit-shop_order_columns', 'woo_customer_order_coupon_column_for_orders' );
function woo_customer_order_coupon_column_for_orders( $columns ) {
    $new_columns = array();

    foreach ( $columns as $column_key => $column_label ) {
        if ( 'order_total' === $column_key ) {
            $new_columns['order_coupons'] = __('Coupons', 'woocommerce');
        }

        $new_columns[$column_key] = $column_label;
    }
    return $new_columns;
}

add_action( 'manage_shop_order_posts_custom_column' , 'woo_display_customer_order_coupon_in_column_for_orders' );
function woo_display_customer_order_coupon_in_column_for_orders( $column ) {
    global $the_order, $post;
    if( $column  == 'order_coupons' ) {
        if( $coupons = $the_order->get_coupon_codes() ) {
            echo implode(', ', $coupons) . ' ('.count($coupons).')';
        } else {
            echo '<small><em>'. __('No coupon used') . '</em></small>';
        }
    }
}

How to display used coupons on Woocommerce order preview template?

With the previous snippet we’re displaying coupons in the Woocommerce admin orders list. Now, with the help of this one here we’re going to display used coupons on Woocommerce order preview template.

<span role="button" tabindex="0" data-code="// Display used coupons on Woocommerce order preview template

add_filter( 'woocommerce_admin_order_preview_get_order_details', 'wpsh_coupon_in_order_preview', 10, 2 );
function wpsh_coupon_in_order_preview( $data, $order ) {
// Replace '_custom_meta_key' by the correct postmeta key
if( $coupons = $order->get_used_coupons() ) {
$data['coupons_count'] = count($coupons); // <= Store the count in the data array.
$data['coupons_codes'] = implode(', ', $coupons); // <= Store the count in the data array.
}
return $data;
}
// Display coupon in Order preview
add_action( 'woocommerce_admin_order_preview_end', 'wpsh_coupon_in_order_preview_data' );
function wpsh_coupon_in_order_preview_data(){
// Call the stored value and display it
echo '<div><strong>' . __('Coupons used') . ' ({{data.coupons_count}})<strong>: {{data.coupons_codes}}</div>

// Display used coupons on Woocommerce order preview template

add_filter( 'woocommerce_admin_order_preview_get_order_details', 'wpsh_coupon_in_order_preview', 10, 2 );
function wpsh_coupon_in_order_preview( $data, $order ) {
    // Replace '_custom_meta_key' by the correct postmeta key
    if( $coupons = $order->get_used_coupons() ) {
        $data['coupons_count'] = count($coupons); // <= Store the count in the data array.
        $data['coupons_codes'] = implode(', ', $coupons); // <= Store the count in the data array.
    }
    return $data;
}
// Display coupon in Order preview
add_action( 'woocommerce_admin_order_preview_end', 'wpsh_coupon_in_order_preview_data' );
function wpsh_coupon_in_order_preview_data(){
    // Call the stored value and display it
    echo '<div><strong>' . __('Coupons used') . ' ({{data.coupons_count}})<strong>: {{data.coupons_codes}}</div><br>';
}

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 add custom button to Woocommerce orders page (and products page)

It’s time to add custom button to Woocommerce orders page (and products page). See the screenshot.

Add custom button to Woocommerce orders page
<span role="button" tabindex="0" data-code="// Add custom button to Woocommerce orders page
add_action( 'manage_posts_extra_tablenav', 'wpsh_button_on_orders_page', 20, 1 );
function wpsh_button_on_orders_page( $which ) {
global $typenow;

if ( 'shop_order' === $typenow && 'top' === $which ) {
?>
<div class="alignright actions custom">
<button type="submit" name="custom_" style="height:32px;" class="button" value=""><?php
// Change your URL and button text here
echo __( '<a style="text-decoration: none;" href="/wp-admin/edit.php?post_type=product">
Go to products »
</a>', 'woocommerce' ); ?></button>
</div>
<?php
}
}
// Add custom button to Woocommerce products page
add_action( 'manage_posts_extra_tablenav', 'wpsh_button_on_products_page', 20, 1 );
function wpsh_button_on_products_page( $which ) {
global $typenow;

if ( 'product' === $typenow && 'top' === $which ) {
?>
<div class="alignleft actions custom">
<button type="submit" name="custom_" style="height:32px;" class="button" value=""><?php
// Change your URL and button text here
echo __( '<a style="text-decoration: none;" href="/wp-admin/edit.php?post_type=shop_order">
Go to orders »
</a>', 'woocommerce' ); ?></button>
</div>

// Add custom button to Woocommerce orders page 
add_action( 'manage_posts_extra_tablenav', 'wpsh_button_on_orders_page', 20, 1 );
function wpsh_button_on_orders_page( $which ) {
    global $typenow;

    if ( 'shop_order' === $typenow && 'top' === $which ) {
        ?>
        <div class="alignright actions custom">
            <button type="submit" name="custom_" style="height:32px;" class="button"  value=""><?php
	  // Change your URL and button text here
                echo __( '<a style="text-decoration: none;" href="/wp-admin/edit.php?post_type=product">
				Go to products »
				</a>', 'woocommerce' ); ?></button>
        </div>
        <?php
    }
}
// Add custom button to Woocommerce products page 
add_action( 'manage_posts_extra_tablenav', 'wpsh_button_on_products_page', 20, 1 );
function wpsh_button_on_products_page( $which ) {
    global $typenow;

    if ( 'product' === $typenow && 'top' === $which ) {
        ?>
        <div class="alignleft actions custom">
            <button type="submit" name="custom_" style="height:32px;" class="button"  value=""><?php
	  	  // Change your URL and button text here
                echo __( '<a style="text-decoration: none;" href="/wp-admin/edit.php?post_type=shop_order">
				Go to orders »
				</a>', 'woocommerce' ); ?></button>
        </div>
        <?php
    }
}

How to set default Woocommerce login page to “Orders” page?

This snippet here below will redirect you to the Woocommerce “Orders” after login.

// Set default Woocommerce login page to "Orders" page
add_action( 'load-index.php', 'wpsh_redirect_to_orders' );
function wpsh_redirect_to_orders(){
    wp_redirect( admin_url( 'edit.php?post_type=shop_order' ) );
}
add_filter( 'login_redirect', 'wpsh_redirect_to_orders_dashboard', 9999, 3 );
function wpsh_redirect_to_orders_dashboard( $redirect_to, $request, $user ){
    $redirect_to = admin_url( 'edit.php?post_type=shop_order' );
    return $redirect_to;
}

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 the product image to Woocommerce my account order view at My account page?

What do I mean by that? Take a look at the screenshot below, and you’ll see that there’s an image on Woocommerce orders view at My account page.

Add the product image to Woocommerce my account order view
<span role="button" tabindex="0" data-code="// Display the product thumbnail in Woocommerce order view pages
add_filter( 'woocommerce_order_item_name', 'wpsh_display_product_image_in_order_item', 20, 3 );
function wpsh_display_product_image_in_order_item( $item_name, $item, $is_visible ) {
// Targeting view order pages only
if( is_wc_endpoint_url( 'view-order' ) ) {
$product = $item->get_product(); // Get the WC_Product object (from order item)
$thumbnail = $product->get_image(array( 50, 50)); // Get the product thumbnail (from product object)
if( $product->get_image_id() > 0 )
$item_name = '<div class="item-thumbnail">' . $thumbnail . '

// Display the product thumbnail in Woocommerce order view pages
add_filter( 'woocommerce_order_item_name', 'wpsh_display_product_image_in_order_item', 20, 3 );
function wpsh_display_product_image_in_order_item( $item_name, $item, $is_visible ) {
    // Targeting view order pages only
    if( is_wc_endpoint_url( 'view-order' ) ) {
        $product   = $item->get_product(); // Get the WC_Product object (from order item)
        $thumbnail = $product->get_image(array( 50, 50)); // Get the product thumbnail (from product object)
        if( $product->get_image_id() > 0 )
            $item_name = '<div class="item-thumbnail">' . $thumbnail . '</div>' . $item_name;
    }
    return $item_name;
}

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 “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 “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 set Woocommerce my account page orders display limit?

By default, your Woocommerce “My account” displays a bunch of orders. If you would like to set your own Woocommerce “My account” page orders display limit, then use this snippet. With the help of it we’ll set the display limit to 5 orders.

// Set Woocommerce my account page orders display limit
add_filter( 'woocommerce_my_account_my_orders_query', 'wpsh_my_account_orders_limit', 10, 1 );
function wpsh_my_account_orders_limit( $args ) {
    // Set the post per page
    $args['limit'] = 5;
    return $args;
}

How to display products name and quantity in a new column on Woocommerce “My account” page orders table?

Take a look at the “How to add “Cancel” button to Woocommerce my account page?” section above. There’s a screenshot and you’ll see that in it I display products name and quantity in a new column on Woocommerce “My account” page orders table. So, if you would like to accomplish the same result, just use this snippet here below.

<span role="button" tabindex="0" data-code="// Display How to display products name and quantity in a new column on Woocommerce "My account" page orders table

add_filter( 'woocommerce_my_account_my_orders_columns', 'wpsh_product_column', 10, 1 );
function wpsh_product_column( $columns ) {
$new_columns = [];

foreach ( $columns as $key => $name ) {
$new_columns[ $key ] = $name;

if ( 'order-status' === $key ) {
$new_columns['order-items'] = __( 'Product | Qty', 'woocommerce' );
}
}
return $new_columns;
}

add_action( 'woocommerce_my_account_my_orders_column_order-items', 'wpsh_product_column_content', 10, 1 );
function wpsh_product_column_content( $order ) {
$details = array();

foreach( $order->get_items() as $item )
$details[] = $item->get_name() . ' × ' . $item->get_quantity();

echo count( $details ) > 0 ? implode( '

// Display How to display products name and quantity in a new column on Woocommerce "My account" page orders table

add_filter( 'woocommerce_my_account_my_orders_columns', 'wpsh_product_column', 10, 1 );
function wpsh_product_column( $columns ) {
    $new_columns = [];

    foreach ( $columns as $key => $name ) {
        $new_columns[ $key ] = $name;

        if ( 'order-status' === $key ) {
            $new_columns['order-items'] = __( 'Product | Qty', 'woocommerce' );
        }
    }
    return $new_columns;
}

add_action( 'woocommerce_my_account_my_orders_column_order-items', 'wpsh_product_column_content', 10, 1 );
function wpsh_product_column_content( $order ) {
    $details = array();

    foreach( $order->get_items() as $item )
        $details[] = $item->get_name() . ' × ' . $item->get_quantity();

    echo count( $details ) > 0 ? implode( '<br>', $details ) : '–';
}

How to Link previous WooCommerce guest orders to customer account after registration?

This snippet allows you to link previous WooCommerce guest orders to customer account after registration.

// Link previous WooCommerce guest orders to customer account after registration
function action_woocommerce_created_customer( $customer_id, $new_customer_data, $password_generated ) {
    // Link past orders to this newly created customer
    wc_update_new_customer_past_orders( $customer_id );
}
add_action( 'woocommerce_created_customer', 'action_woocommerce_created_customer', 10, 3 ); 

Woocommerce hacks series

  • How to Hide Woocommerce Shipping Methods (Conditionally) – A Complete Guide

  • How to display Woocommerce my account tabs horizontally?

  • How to Customize Woocommerce Admin Dashboard? 16 hacks

  • How to Display Woocommerce Payment Methods Conditionally? (14 hacks)

  • How to Customize Woocommerce Stock Status? (17 hacks)

  • How to Add Custom Endpoints in WooCommerce?

  • How to Create Custom Product Badges for Woocommerce?

Leave a Comment

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

Scroll to Top