Commit 8194055b339 for woocommerce
commit 8194055b3397c7e8c3da0b1cdf139b1d5151fecf
Author: Ann <annchichi@users.noreply.github.com>
Date: Wed Jul 22 11:36:58 2026 +0800
Fix shipping method names on manual orders (#66811)
* Fix manual order shipping method names
* Add changelog entry for manual order shipping name fix
* Fix shipping title when clearing method
diff --git a/plugins/woocommerce/changelog/fix-manual-order-shipping-method-name b/plugins/woocommerce/changelog/fix-manual-order-shipping-method-name
new file mode 100644
index 00000000000..961a2c9067c
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-manual-order-shipping-method-name
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Use the selected shipping method name for manually created orders.
diff --git a/plugins/woocommerce/client/legacy/js/admin/meta-boxes-order.js b/plugins/woocommerce/client/legacy/js/admin/meta-boxes-order.js
index 187e7163230..d2d7ee740f1 100644
--- a/plugins/woocommerce/client/legacy/js/admin/meta-boxes-order.js
+++ b/plugins/woocommerce/client/legacy/js/admin/meta-boxes-order.js
@@ -1,5 +1,35 @@
// eslint-disable-next-line max-len
-/*global woocommerce_admin_meta_boxes, woocommerce_admin, accounting, woocommerce_admin_meta_boxes_order, wcSetClipboard, wcClearClipboard, wc_enhanced_select_params */
+/*global woocommerce_admin_meta_boxes, woocommerce_admin, accounting, woocommerce_admin_meta_boxes_order, wcSetClipboard, wcClearClipboard, wc_enhanced_select_params, module */
+
+/**
+ * Get the shipping method title to use after a method selection changes.
+ *
+ * @param {Object} args Shipping title data.
+ * @param {string} args.currentTitle Current shipping title.
+ * @param {string} args.defaultTitle Default shipping title.
+ * @param {string} args.previousTitle Previously selected method title.
+ * @param {string} args.methodValue Selected shipping method value.
+ * @param {string} args.methodTitle Selected shipping method title.
+ * @return {string} The shipping title to use.
+ */
+function getShippingMethodTitle( args ) {
+ if (
+ args.currentTitle
+ && args.currentTitle !== args.defaultTitle
+ && args.currentTitle !== args.previousTitle
+ ) {
+ return args.currentTitle;
+ }
+
+ return args.methodValue && 'other' !== args.methodValue
+ ? args.methodTitle
+ : args.defaultTitle;
+}
+
+if ( typeof module !== 'undefined' && module.exports ) {
+ module.exports = { getShippingMethodTitle };
+}
+
jQuery( function ( $ ) {
// Stand-in wcTracks.recordEvent in case tracks is not available (for any reason).
@@ -283,6 +313,7 @@ jQuery( function ( $ ) {
.on( 'click', 'button.calculate-action', this.recalculate )
.on( 'click', 'a.edit-order-item', this.edit_item )
.on( 'click', 'a.delete-order-item', this.delete_item )
+ .on( 'change', 'select.shipping_method', this.shipping_method_changed )
// Refunds
.on( 'click', '.delete_refund', this.refunds.delete_refund )
@@ -376,6 +407,30 @@ jQuery( function ( $ ) {
wc_meta_boxes_order_items.stupidtable.init();
},
+ shipping_method_changed: function() {
+ var $select = $( this );
+ var $name = $select.closest( 'tr.shipping' ).find( 'input.shipping_method_name' );
+ var title = $select.find( 'option:selected' ).text();
+ var previousTitle = $select.data( 'selected-title' ) || $select.find( 'option' ).filter( function() {
+ return this.defaultSelected;
+ } ).text();
+ var currentTitle = $name.val();
+ var defaultTitle = $name.data( 'default-shipping-title' );
+ var nextTitle = getShippingMethodTitle( {
+ currentTitle: currentTitle,
+ defaultTitle: defaultTitle,
+ previousTitle: previousTitle,
+ methodValue: $select.val(),
+ methodTitle: title
+ } );
+
+ $select.data( 'selected-title', title );
+
+ if ( currentTitle !== nextTitle ) {
+ $name.val( nextTitle ).trigger( 'change' );
+ }
+ },
+
// When the qty is changed, increase or decrease costs
quantity_changed: function() {
var $row = $( this ).closest( 'tr.item' );
diff --git a/plugins/woocommerce/client/legacy/js/admin/test/meta-boxes-order.test.js b/plugins/woocommerce/client/legacy/js/admin/test/meta-boxes-order.test.js
new file mode 100644
index 00000000000..7bd51d99ef2
--- /dev/null
+++ b/plugins/woocommerce/client/legacy/js/admin/test/meta-boxes-order.test.js
@@ -0,0 +1,42 @@
+/**
+ * Tests for the order meta box shipping method name synchronization.
+ */
+
+global.jQuery = jest.fn();
+
+const { getShippingMethodTitle } = require( '../meta-boxes-order' );
+
+describe( 'Order meta box shipping method names', () => {
+ test( 'uses the selected method title for the default shipping name', () => {
+ expect( getShippingMethodTitle( {
+ currentTitle: 'Shipping',
+ defaultTitle: 'Shipping',
+ previousTitle: 'N/A',
+ methodValue: 'free_shipping',
+ methodTitle: 'Free shipping',
+ } ) ).toBe( 'Free shipping' );
+ } );
+
+ test.each( [
+ [ 'N/A', '', 'N/A' ],
+ [ 'Other', 'other', 'Other' ],
+ ] )( 'resets an auto-synced name when selecting %s', ( label, methodValue, methodTitle ) => {
+ expect( getShippingMethodTitle( {
+ currentTitle: 'Free shipping',
+ defaultTitle: 'Shipping',
+ previousTitle: 'Free shipping',
+ methodValue,
+ methodTitle,
+ } ) ).toBe( 'Shipping' );
+ } );
+
+ test( 'preserves a custom name when selecting N/A', () => {
+ expect( getShippingMethodTitle( {
+ currentTitle: 'Local courier',
+ defaultTitle: 'Shipping',
+ previousTitle: 'Free shipping',
+ methodValue: '',
+ methodTitle: 'N/A',
+ } ) ).toBe( 'Local courier' );
+ } );
+} );
diff --git a/plugins/woocommerce/includes/admin/meta-boxes/views/html-order-shipping.php b/plugins/woocommerce/includes/admin/meta-boxes/views/html-order-shipping.php
index c00470d6eff..96477220845 100644
--- a/plugins/woocommerce/includes/admin/meta-boxes/views/html-order-shipping.php
+++ b/plugins/woocommerce/includes/admin/meta-boxes/views/html-order-shipping.php
@@ -23,7 +23,14 @@ if ( ! defined( 'ABSPATH' ) ) {
</div>
<div class="edit" style="display: none;">
<input type="hidden" name="shipping_method_id[]" value="<?php echo esc_attr( $item_id ); ?>" />
- <input type="text" class="shipping_method_name" placeholder="<?php esc_attr_e( 'Shipping name', 'woocommerce' ); ?>" name="shipping_method_title[<?php echo esc_attr( $item_id ); ?>]" value="<?php echo esc_attr( $item->get_name() ); ?>" />
+ <input
+ type="text"
+ class="shipping_method_name"
+ placeholder="<?php esc_attr_e( 'Shipping name', 'woocommerce' ); ?>"
+ name="shipping_method_title[<?php echo esc_attr( $item_id ); ?>]"
+ value="<?php echo esc_attr( $item->get_name() ); ?>"
+ data-default-shipping-title="<?php esc_attr_e( 'Shipping', 'woocommerce' ); ?>"
+ />
<select class="shipping_method" name="shipping_method[<?php echo esc_attr( $item_id ); ?>]">
<optgroup label="<?php esc_attr_e( 'Shipping method', 'woocommerce' ); ?>">
<option value=""><?php esc_html_e( 'N/A', 'woocommerce' ); ?></option>
diff --git a/plugins/woocommerce/includes/admin/wc-admin-functions.php b/plugins/woocommerce/includes/admin/wc-admin-functions.php
index 3058f360083..03cab7ad3f4 100644
--- a/plugins/woocommerce/includes/admin/wc-admin-functions.php
+++ b/plugins/woocommerce/includes/admin/wc-admin-functions.php
@@ -404,12 +404,13 @@ function wc_save_order_items( $order_id, $items ) {
// Shipping Rows.
if ( isset( $items['shipping_method_id'] ) ) {
- $data_keys = array(
+ $data_keys = array(
'shipping_method' => null,
'shipping_method_title' => null,
'shipping_cost' => 0,
'shipping_taxes' => array(),
);
+ $shipping_methods = null;
foreach ( $items['shipping_method_id'] as $item_id ) {
$item = WC_Order_Factory::get_order_item( absint( $item_id ) );
@@ -424,6 +425,22 @@ function wc_save_order_items( $order_id, $items ) {
$item_data[ $key ] = isset( $items[ $key ][ $item_id ] ) ? wc_clean( wp_unslash( $items[ $key ][ $item_id ] ) ) : $default;
}
+ $item_data['shipping_method'] = is_string( $item_data['shipping_method'] ) ? $item_data['shipping_method'] : '';
+ $item_data['shipping_method_title'] = is_string( $item_data['shipping_method_title'] ) ? $item_data['shipping_method_title'] : '';
+
+ if (
+ ! empty( $item_data['shipping_method'] ) &&
+ in_array( $item_data['shipping_method_title'], array( '', __( 'Shipping', 'woocommerce' ) ), true )
+ ) {
+ if ( null === $shipping_methods ) {
+ $shipping_methods = WC()->shipping() ? WC()->shipping()->load_shipping_methods() : array();
+ }
+
+ if ( isset( $shipping_methods[ $item_data['shipping_method'] ] ) ) {
+ $item_data['shipping_method_title'] = $shipping_methods[ $item_data['shipping_method'] ]->get_method_title();
+ }
+ }
+
$item->set_props(
array(
'method_id' => $item_data['shipping_method'],
diff --git a/plugins/woocommerce/tests/php/includes/admin/class-wc-admin-functions-test.php b/plugins/woocommerce/tests/php/includes/admin/class-wc-admin-functions-test.php
index 6619f308264..ec1727078d7 100644
--- a/plugins/woocommerce/tests/php/includes/admin/class-wc-admin-functions-test.php
+++ b/plugins/woocommerce/tests/php/includes/admin/class-wc-admin-functions-test.php
@@ -581,4 +581,34 @@ class WC_Admin_Functions_Test extends \WC_Unit_Test_Case {
$this->assertEquals( $original_product_id, $saved_item->get_product_id(), 'Reserved internal key should not overwrite core item data' );
$this->assertFalse( $saved_item->meta_exists( '_reduced_stock' ), 'Reserved hidden key should not be stored as item meta' );
}
+
+ /**
+ * @testdox wc_save_order_items() should use the shipping method title when the posted shipping title is the default label.
+ *
+ * @link https://github.com/woocommerce/woocommerce/issues/36049
+ */
+ public function test_wc_save_order_items_uses_shipping_method_title_when_posted_shipping_title_is_default_label(): void {
+ $order = WC_Helper_Order::create_order();
+ $shipping_item = new WC_Order_Item_Shipping();
+ $shipping_item->set_order_id( $order->get_id() );
+ $item_id = $shipping_item->save();
+
+ $items = array(
+ 'shipping_method_id' => array( $item_id ),
+ 'shipping_method' => array( $item_id => 'free_shipping' ),
+ 'shipping_method_title' => array( $item_id => __( 'Shipping', 'woocommerce' ) ),
+ 'shipping_cost' => array( $item_id => 0 ),
+ 'shipping_taxes' => array( $item_id => array() ),
+ );
+
+ wc_save_order_items( $order->get_id(), $items );
+
+ $saved_item = new WC_Order_Item_Shipping( $item_id );
+
+ $this->assertSame(
+ 'Free shipping',
+ $saved_item->get_name(),
+ 'Known shipping methods should use their title when the posted title is the default label'
+ );
+ }
}