Introduction
When operating a WooCommerce-based e-commerce site, deep customization is key to improving management efficiency and user experience. This article explains how to implement two core features via code: 1) Adding bulk action functionality for custom order statuses to manage orders quickly, and 2) Adding custom dropdown fields to the user registration and 'My Account' pages to collect richer user information.
Adding Bulk Actions for Custom Order Statuses
WooCommerce's admin area supports bulk changes for core order statuses (e.g., Processing, Completed) by default. To add a bulk action option for a custom status (e.g., 'Awaiting Shipment'), you need to extend functionality via hooks.
Implementation Code
Add the following code to your theme's functions.php file or a custom functionality plugin.
// 1. Register bulk action option
add_filter( 'bulk_actions-edit-shop_order', 'custom_register_bulk_action' );
function custom_register_bulk_action( $bulk_actions ) {
$bulk_actions['mark_awaiting_shipment'] = 'Mark as Awaiting Shipment';
return $bulk_actions;
}
// 2. Process bulk action request
add_action( 'admin_action_mark_awaiting_shipment', 'custom_bulk_process_status' );
function custom_bulk_process_status() {
if ( ! isset( $_REQUEST['post'] ) || ! is_array( $_REQUEST['post'] ) ) {
return;
}
foreach ( $_REQUEST['post'] as $order_id ) {
$order = wc_get_order( $order_id );
if ( $order ) {
$order->update_status( 'wc-awaiting-shipment', 'Status updated via bulk action', true );
}
}
$location = add_query_arg( array(
'post_type' => 'shop_order',
'marked_awaiting_shipment' => 1,
'changed' => count( $_REQUEST['post'] ),
'ids' => join( ',', $_REQUEST['post'] ),
'post_status' => 'all'
), 'edit.php' );
wp_redirect( admin_url( $location ) );
exit;
}
// 3. Display success notice
add_action( 'admin_notices', 'custom_bulk_action_admin_notice' );
function custom_bulk_action_admin_notice() {
global $pagenow, $typenow;
if ( $typenow == 'shop_order' && $pagenow == 'edit.php' && isset( $_REQUEST['marked_awaiting_shipment'] ) ) {
$count = intval( $_REQUEST['changed'] );
echo '<div class="updated"><p>Successfully updated status for ' . $count . ' order(s).</p></div>';
}
}
Key Points
- Hook Match: The
edit-shop_orderinbulk_actions-edit-shop_orderis the screen ID for the order list page. - Action Naming: The second part of
admin_action_mark_awaiting_shipmentmust match the registered array key (mark_awaiting_shipment). - Status Identifier: The status identifier used in
update_status()(e.g.,wc-awaiting-shipment) must be a valid, registered status in the system.
Adding a Custom Dropdown Field to the Registration Form
To collect user attributes (e.g., customer type), we need to add a dropdown selection to the registration form and ensure data is saved and displayed correctly.
Complete Implementation Code
The following code demonstrates adding a 'Customer Type' field, covering frontend display, data saving, and backend/frontend edit display.
// 1. Add dropdown field to registration form
add_action( 'woocommerce_register_form', 'add_extra_register_select_field' );
function add_extra_register_select_field() {
?>
<p class="form-row form-row-wide">
<label for="customer_type">Customer Type <span class="required">*</span></label>
<select id="customer_type" name="customer_type" required>
<option value="">Please select...</option>
<option value="individual">Individual</option>
<option value="company">Company</option>
<option value="reseller">Reseller</option>
</select>
</p>
<?php
}
// 2. Save field value on registration
add_action( 'woocommerce_created_customer', 'save_extra_register_fields' );
function save_extra_register_fields( $customer_id ) {
if ( isset( $_POST['customer_type'] ) ) {
update_user_meta( $customer_id, 'customer_type', sanitize_text_field( $_POST['customer_type'] ) );
}
}
// 3. Display field in admin user edit page
add_action( 'show_user_profile', 'show_extra_register_fields_admin' );
add_action( 'edit_user_profile', 'show_extra_register_fields_admin' );
function show_extra_register_fields_admin( $user ) {
$value = get_user_meta( $user->ID, 'customer_type', true );
?>
<h3>Additional Information</h3>
<table class="form-table">
<tr>
<th><label for="customer_type">Customer Type</label></th>
<td>
<select id="customer_type" name="customer_type">
<option value="">Please select...</option>
<option value="individual" <?php selected( $value, 'individual' ); ?>>Individual</option>
<option value="company" <?php selected( $value, 'company' ); ?>>Company</option>
<option value="reseller" <?php selected( $value, 'reseller' ); ?>>Reseller</option>
</select>
</td>
</tr>
</table>
<?php
}
// 4. Display field in frontend 'My Account' edit page
add_action( 'woocommerce_edit_account_form', 'show_extra_register_fields_frontend' );
function show_extra_register_fields_frontend() {
$user_id = get_current_user_id();
$value = get_user_meta( $user_id, 'customer_type', true );
?>
<p class="form-row form-row-wide">
<label for="customer_type">Customer Type <span class="required">*</span></label>
<select id="customer_type" name="customer_type">
<option value="">Please select...</option>
<option value="individual" <?php selected( $value, 'individual' ); ?>>Individual</option>
<option value="company" <?php selected( $value, 'company' ); ?>>Company</option>
<option value="reseller" <?php selected( $value, 'reseller' ); ?>>Reseller</option>
</select>
</p>
<?php
}
// 5. Save updates from admin and frontend edit pages
add_action( 'personal_options_update', 'save_extra_register_fields_admin' );
add_action( 'edit_user_profile_update', 'save_extra_register_fields_admin' );
add_action( 'woocommerce_save_account_details', 'save_extra_register_fields_admin' );
function save_extra_register_fields_admin( $customer_id ) {
if ( isset( $_POST['customer_type'] ) ) {
update_user_meta( $customer_id, 'customer_type', sanitize_text_field( $_POST['customer_type'] ) );
}
}
Functional Logic
- Frontend Registration: Uses the
woocommerce_register_formhook to insert HTML below the standard form. - Data Storage: Uses
update_user_metato store data in thewp_usermetatable, with sanitization for security. - Multi-end Display: Hooks into backend and frontend edit pages to ensure the field is visible and editable everywhere.
- Data Synchronization: Save logic is hooked to corresponding update actions to ensure changes take effect.
Modifying Payment Gateway Title and Description
Sometimes, to improve conversion or align with brand tone, you need to modify the text displayed for a payment gateway. For example, changing 'Cash on Delivery' to a more descriptive phrase.
// Modify payment gateway title
add_filter( 'woocommerce_gateway_title', 'custom_payment_gateway_title', 25, 2 );
function custom_payment_gateway_title( $title, $gateway_id ) {
if ( 'cod' === $gateway_id ) { // 'cod' is the default ID for Cash on Delivery
$title = 'Pay with Cash or Card on Delivery';
}
return $title;
}
// Modify payment gateway description
add_filter( 'woocommerce_gateway_description', 'custom_payment_gateway_description', 25, 2 );
function custom_payment_gateway_description( $description, $gateway_id ) {
if ( 'cod' === $gateway_id ) {
$description = 'Pay when your order is delivered. Supports cash and mobile payments.';
}
return $description;
}
Summary and Considerations
- Code Placement: Place code in a child theme's
functions.phpor a custom plugin to avoid loss during theme updates. - Security: Always sanitize user input (e.g.,
$_POST) using functions likesanitize_text_fieldto prevent XSS attacks. - Testing Environment: Changes to order status and payment logic affect core operations. Test thoroughly on a staging site before deploying to production.
- Extensibility: The provided code is a template. Adjust field names, option values, and logic based on your specific business needs.