Commit b8aad9c7cef for woocommerce
commit b8aad9c7ceff346c518f9eadca01b5fdc6b9026e
Author: Justin P <228780+layoutd@users.noreply.github.com>
Date: Thu Oct 15 17:21:44 2026 +0200
Use a placeholder-less order attribution origin label as the whole origin (#69030)
* Use a placeholder-less order attribution origin label as the whole origin
* Add changelog for order attribution origin label fix
* Only treat a %s placeholder as a format string in the origin label
* Recognize every sprintf string placeholder and escaped percent signs in the origin label
* Accept the sprintf space flag when a width follows it in the origin label
diff --git a/plugins/woocommerce/changelog/48740-order-attribution-label-without-placeholder b/plugins/woocommerce/changelog/48740-order-attribution-label-without-placeholder
new file mode 100644
index 00000000000..0c00c46242b
--- /dev/null
+++ b/plugins/woocommerce/changelog/48740-order-attribution-label-without-placeholder
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Show the custom origin label an extension sets for an order's attribution source instead of "Unknown".
diff --git a/plugins/woocommerce/src/Internal/Traits/OrderAttributionMeta.php b/plugins/woocommerce/src/Internal/Traits/OrderAttributionMeta.php
index a77f3359991..a381afa3cf2 100644
--- a/plugins/woocommerce/src/Internal/Traits/OrderAttributionMeta.php
+++ b/plugins/woocommerce/src/Internal/Traits/OrderAttributionMeta.php
@@ -344,8 +344,11 @@ trait OrderAttributionMeta {
/**
* Filter the label for the order origin.
*
- * This label should have a %s placeholder for the formatted source to be inserted
- * via sprintf().
+ * A label with a %s placeholder (any sprintf() string placeholder, or an escaped %%)
+ * has the formatted source inserted via sprintf(). A label without one, including a
+ * label with a lone percent sign, is used as the complete origin, which lets custom
+ * source types show their own text instead of "Unknown". An empty label falls back
+ * to the formatted source.
*
* @since 8.5.0
*
@@ -362,8 +365,12 @@ trait OrderAttributionMeta {
$formatted_source
);
- if ( false === strpos( $label, '%' ) ) {
- return $formatted_source;
+ // Any sprintf() string placeholder (%s, %1$s, %10s, %-10s, %'.10s) or an escaped %% means the
+ // label is a format string, as every label was before plain labels were accepted. A lone
+ // percent sign is literal text: the space flag only counts when a width follows it, so
+ // "50% sale" is not a placeholder while "% 10s" still is.
+ if ( ! preg_match( '/(?<!%)(?:%%)*%(?:\d+\$)?(?:[-+0]|\'.| (?=\d))*\d*(?:\.\d+)?s|%%/', $label ) ) {
+ return '' === $label ? $formatted_source : $label;
}
return sprintf( $label, $formatted_source );
diff --git a/plugins/woocommerce/tests/php/src/Internal/Orders/OrderAttributionControllerTest.php b/plugins/woocommerce/tests/php/src/Internal/Orders/OrderAttributionControllerTest.php
index 53a6c1914a0..bef88403d82 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Orders/OrderAttributionControllerTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Orders/OrderAttributionControllerTest.php
@@ -127,7 +127,7 @@ class OrderAttributionControllerTest extends WP_UnitTestCase {
);
$anon_test = Closure::bind(
- function( $order ) {
+ function ( $order ) {
$this->output_origin_column( $order );
},
$this->attribution_class,
@@ -151,6 +151,71 @@ class OrderAttributionControllerTest extends WP_UnitTestCase {
}
}
+ /**
+ * Data provider for test_output_origin_column_uses_filtered_label.
+ *
+ * @return array[] Source type, source, filtered label, expected output.
+ */
+ public function provider_filtered_origin_labels(): array {
+ return array(
+ 'plain label, custom type' => array( 'trade-show', '', 'Trade show', 'Trade show' ),
+ // A placeholder is still filled with the formatted source, which is "Unknown" for a custom type.
+ '%s placeholder, custom type' => array( 'trade-show', 'booth-12', 'Trade show: %s', 'Trade show: Unknown' ),
+ 'positional placeholder' => array( 'trade-show', '', 'Trade show: %1$s', 'Trade show: Unknown' ),
+ 'width-qualified placeholder' => array( 'trade-show', '', '[%10s]', '[ Unknown]' ),
+ 'left-aligned width placeholder' => array( 'trade-show', '', '[%-10s]', '[Unknown ]' ),
+ 'space flag with width placeholder' => array( 'trade-show', '', '[% 10s]', '[ Unknown]' ),
+ 'custom padding placeholder' => array( 'trade-show', '', "[%'.10s]", '[...Unknown]' ),
+ 'empty label falls back' => array( 'trade-show', '', '', 'Unknown' ),
+ 'plain label, built-in type' => array( 'utm', 'example', 'Campaign', 'Campaign' ),
+ // A lone percent sign is literal text and must not reach sprintf().
+ 'lone percent sign' => array( 'trade-show', '', '100% organic', '100% organic' ),
+ 'percent followed by a space and s' => array( 'trade-show', '', '50% sale', '50% sale' ),
+ // An escaped percent sign keeps sprintf() semantics, as every label had before.
+ 'escaped percent sign' => array( 'trade-show', '', '100%% organic', '100% organic' ),
+ 'escaped percent before s' => array( 'trade-show', '', 'Save %%s today', 'Save %s today' ),
+ 'escaped percent and a placeholder' => array( 'trade-show', '', '100%% from %s', '100% from Unknown' ),
+ );
+ }
+
+ /**
+ * @testdox A filtered label is used as the whole origin unless it is a sprintf() format string.
+ * @dataProvider provider_filtered_origin_labels
+ *
+ * @param string $source_type Source type meta value.
+ * @param string $source Source meta value.
+ * @param string $label Label returned by the filter.
+ * @param string $expected_output Expected column output.
+ */
+ public function test_output_origin_column_uses_filtered_label( string $source_type, string $source, string $label, string $expected_output ): void {
+ $anon_test = Closure::bind(
+ function ( $order ) {
+ $this->output_origin_column( $order );
+ },
+ $this->attribution_class,
+ $this->attribution_class
+ );
+
+ $order = $this->getMockBuilder( WC_Order::class )
+ ->onlyMethods( array( 'get_meta' ) )
+ ->getMock();
+ $order->method( 'get_meta' )
+ ->willReturnOnConsecutiveCalls( $source_type, $source );
+
+ $label_filter = function () use ( $label ) {
+ return $label;
+ };
+ add_filter( 'wc_order_attribution_origin_label', $label_filter );
+
+ ob_start();
+ $anon_test( $order );
+ $output = ob_get_clean();
+
+ remove_filter( 'wc_order_attribution_origin_label', $label_filter );
+
+ $this->assertSame( $expected_output, $output );
+ }
+
/**
* Tests that stamp_html_element outputs the correct HTML element.
*