Skip to content

Instantly share code, notes, and snippets.

@plugin-republic
Last active August 3, 2026 11:07
Show Gist options
  • Select an option

  • Save plugin-republic/d3f1a6b6969ce367aba100fad4b84f0c to your computer and use it in GitHub Desktop.

Select an option

Save plugin-republic/d3f1a6b6969ce367aba100fad4b84f0c to your computer and use it in GitHub Desktop.
<?php
/**
* Snippet: Add a 'Shipping speed' radio field (Standard / Express) to the checkout page,
* inside the order review table immediately below the subtotal row and above the
* shipping/payment method options.
*
* Selecting 'Express' adds a 15% fee based on the cart's current total.
* The field is saved to the order as post meta and shown on the admin order screen.
*
* Usage: add this file as an mu-plugin, or require it from your theme/child-theme
* functions.php, or paste the contents into a plugin such as Code Snippets.
*/
define( 'CSSR_FIELD_KEY', 'shipping_speed' );
define( 'CSSR_EXPRESS_FEE_PERCENT', 15 );
/**
* Render the radio field as a row in the order review table, right after the
* cart subtotal row and before shipping/payment methods are shown.
*/
add_action( 'woocommerce_review_order_after_cart_contents', 'cssr_render_shipping_speed_field' );
function cssr_render_shipping_speed_field() {
$chosen = WC()->session ? WC()->session->get( CSSR_FIELD_KEY, 'standard' ) : 'standard';
?>
<tr class="cssr-shipping-speed">
<th><?php esc_html_e( 'Shipping speed', 'woocommerce' ); ?></th>
<td>
<div id="cssr_shipping_speed_field">
<?php
woocommerce_form_field(
CSSR_FIELD_KEY,
array(
'type' => 'radio',
'class' => array( 'cssr-shipping-speed-field form-row-wide' ),
'options' => array(
'standard' => __( 'Standard', 'woocommerce' ),
'express' => sprintf(
/* translators: %d: express fee percentage */
__( 'Express (+%d%% of cart total)', 'woocommerce' ),
CSSR_EXPRESS_FEE_PERCENT
),
),
'required' => true,
),
$chosen
);
?>
</div>
</td>
</tr>
<?php
}
/**
* Require a selection before allowing the order to be placed.
*/
add_action( 'woocommerce_checkout_process', 'cssr_validate_shipping_speed_field' );
function cssr_validate_shipping_speed_field() {
if ( empty( $_POST[ CSSR_FIELD_KEY ] ) ) {
wc_add_notice( __( 'Please choose a shipping speed.', 'woocommerce' ), 'error' );
}
}
/**
* Persist the selection to the order and session so it survives page reloads
* and is available when the fee is calculated.
*/
add_action( 'woocommerce_checkout_create_order', 'cssr_save_shipping_speed_to_order', 10, 2 );
function cssr_save_shipping_speed_to_order( $order, $data ) {
if ( ! empty( $_POST[ CSSR_FIELD_KEY ] ) ) {
$value = sanitize_text_field( wp_unslash( $_POST[ CSSR_FIELD_KEY ] ) );
$order->update_meta_data( '_' . CSSR_FIELD_KEY, $value );
}
}
/**
* Keep the chosen value in the WC session, updated on every checkout field change,
* so the cart fee recalculates live via AJAX (woocommerce_update_order_review).
*/
add_action( 'woocommerce_checkout_update_order_review', 'cssr_store_shipping_speed_in_session' );
function cssr_store_shipping_speed_in_session( $post_data ) {
parse_str( $post_data, $data );
$value = isset( $data[ CSSR_FIELD_KEY ] ) ? sanitize_text_field( wp_unslash( $data[ CSSR_FIELD_KEY ] ) ) : 'standard';
WC()->session->set( CSSR_FIELD_KEY, $value );
}
/**
* Add the 15% express fee to the cart when 'Express' is selected.
*/
add_action( 'woocommerce_cart_calculate_fees', 'cssr_add_express_fee' );
function cssr_add_express_fee( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
if ( ! WC()->session ) {
return;
}
$shipping_speed = WC()->session->get( CSSR_FIELD_KEY );
if ( 'express' !== $shipping_speed ) {
return;
}
$fee = $cart->get_cart_contents_total() * ( CSSR_EXPRESS_FEE_PERCENT / 100 );
if ( $fee > 0 ) {
$cart->add_fee( __( 'Express shipping fee (15%)', 'woocommerce' ), $fee, true );
}
}
/**
* Show the chosen shipping speed on the admin order edit screen.
*/
add_action( 'woocommerce_admin_order_data_after_billing_address', 'cssr_display_shipping_speed_in_admin' );
function cssr_display_shipping_speed_in_admin( $order ) {
$value = $order->get_meta( '_' . CSSR_FIELD_KEY );
if ( ! $value ) {
return;
}
$label = 'express' === $value ? __( 'Express', 'woocommerce' ) : __( 'Standard', 'woocommerce' );
echo '<p><strong>' . esc_html__( 'Shipping speed', 'woocommerce' ) . ':</strong> ' . esc_html( $label ) . '</p>';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment