DEV3 Technologies home

Checkout field with validation and order meta

Add a custom checkout field, validate it server side, and save it to the order with high-performance storage support.

WooCommerceFormswoocommercecheckoutvalidationorder-meta

Code

<?php
/**
 * "Delivery instructions" and "Tax reference" checkout fields.
 *
 * @package Acme_Core
 */

defined( 'ABSPATH' ) || exit;

// 1. Show the field after the order notes.
add_action( 'woocommerce_after_order_notes', static function ( WC_Checkout $checkout ): void {
	woocommerce_form_field( 'acme_tax_ref', array(
		'type'        => 'text',
		'label'       => __( 'Tax reference (optional)', 'acme-core' ),
		'placeholder' => 'AB-123456',
		'required'    => false,
		'class'       => array( 'form-row-wide' ),
	), $checkout->get_value( 'acme_tax_ref' ) );
} );

// 2. Validate on submit. wc_add_notice() with "error" blocks the order.
add_action( 'woocommerce_checkout_process', static function (): void {
	// phpcs:ignore WordPress.Security.NonceVerification.Missing -- WooCommerce verifies the checkout nonce.
	$ref = isset( $_POST['acme_tax_ref'] ) ? strtoupper( trim( wc_clean( wp_unslash( $_POST['acme_tax_ref'] ) ) ) ) : '';

	if ( '' !== $ref && ! preg_match( '/^[A-Z]{2}-\d{6}$/', $ref ) ) {
		wc_add_notice(
			__( 'Tax reference must look like AB-123456.', 'acme-core' ),
			'error',
			array( 'id' => 'acme_tax_ref' ) // Lets the form focus the field.
		);
	}
} );

// 3. Save to the order (works with HPOS because we use the order object).
add_action( 'woocommerce_checkout_create_order', static function ( WC_Order $order ): void {
	// phpcs:ignore WordPress.Security.NonceVerification.Missing
	$ref = isset( $_POST['acme_tax_ref'] ) ? strtoupper( trim( wc_clean( wp_unslash( $_POST['acme_tax_ref'] ) ) ) ) : '';
	if ( '' !== $ref ) {
		$order->update_meta_data( '_acme_tax_ref', $ref );
	}
} );

// 4. Show it in the order screen.
add_action( 'woocommerce_admin_order_data_after_billing_address', static function ( WC_Order $order ): void {
	$ref = $order->get_meta( '_acme_tax_ref' );
	if ( $ref ) {
		echo '<p><strong>' . esc_html__( 'Tax reference', 'acme-core' ) . ':</strong> ' . esc_html( $ref ) . '</p>';
	}
} );

How it works

What it solves

Stores often need one extra piece of customer data, such as a tax number or delivery note, and need to be sure it is well formed before an order is created. This snippet covers display, validation, storage and admin output as four small hooks.

How it works

woocommerce_form_field renders the input using the theme's form styling and repopulates it after an error. During woocommerce_checkout_process the posted value is cleaned with wc_clean, normalised and matched against a pattern; adding an error notice stops the order. A valid value is stored with update_meta_data on the order object in woocommerce_checkout_create_order, which is compatible with custom order tables, and printed escaped on the admin order screen.

An empty value is allowed because the field is optional.

Adapting it

Change the pattern or make the field required by testing for the empty string as well. Show the value on emails with woocommerce_email_order_meta_fields. For the block-based checkout, register the field with the Additional Checkout Fields API instead; this version targets the classic shortcode checkout.

Pitfalls

  • Do not rely on the HTML pattern attribute alone.
  • Use the order object rather than post meta functions.
  • Nonce handling belongs to WooCommerce here; keep the ignore comments narrow.
  • Normalising case before validation avoids false errors.

How to use it

Place the file in your plugin and load it when WooCommerce is active.

Open the classic checkout page and try a bad value such as 1234.

Find the saved reference in the order's billing section in the admin.

Licence: GPL-2.0-or-later. This snippet comes from WordPress code and is GPL-2.0-or-later.

Related snippets