Commit ec46f8ab944 for woocommerce
commit ec46f8ab94493fb70c619916dfda0982027d56e1
Author: Ann <annchichi@users.noreply.github.com>
Date: Fri Jul 3 18:32:11 2026 +0800
Fix email order item alignment (#66141)
* Fix email order item alignment
* Add changelog entry for email order item alignment
* Move styles to CSS
* Update fulfillment emails
* Middle vertical align order item titles in email
* Fix email thumbnail width when image_size is a named size
The order and fulfillment email item templates computed the thumbnail
cell width by running absint() directly on image_size. When image_size
is a registered size name (e.g. "woocommerce_thumbnail") rather than an
array, absint() returns 0, collapsing the cell to 24px.
Normalize image_size through wc_get_image_size() before computing the
width so both named sizes and [width, height] arrays resolve correctly.
Guard the returned value since the woocommerce_get_image_size_{name}
filter lets third parties alter it, so 'width' is not guaranteed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Ján Mikláš <neosinner@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
diff --git a/plugins/woocommerce/changelog/fix-63238-email-order-item-alignment b/plugins/woocommerce/changelog/fix-63238-email-order-item-alignment
new file mode 100644
index 00000000000..d0cdc9500d9
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-63238-email-order-item-alignment
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Align email order item names consistently after product thumbnails.
diff --git a/plugins/woocommerce/src/Internal/EmailEditor/WooContentProcessor.php b/plugins/woocommerce/src/Internal/EmailEditor/WooContentProcessor.php
index 0b83263238f..8e35380aef0 100644
--- a/plugins/woocommerce/src/Internal/EmailEditor/WooContentProcessor.php
+++ b/plugins/woocommerce/src/Internal/EmailEditor/WooContentProcessor.php
@@ -135,7 +135,7 @@ class WooContentProcessor {
.order-item-data td {
border: 0;
padding: 0;
- vertical-align: top;
+ vertical-align: middle;
}
.order-item-data img {
border-radius: 4px;
diff --git a/plugins/woocommerce/templates/emails/email-fulfillment-items.php b/plugins/woocommerce/templates/emails/email-fulfillment-items.php
index 460374dd7c1..6598e82cf8f 100644
--- a/plugins/woocommerce/templates/emails/email-fulfillment-items.php
+++ b/plugins/woocommerce/templates/emails/email-fulfillment-items.php
@@ -12,7 +12,7 @@
*
* @see https://woocommerce.com/document/template-structure/
* @package WooCommerce\Templates\Emails
- * @version 10.8.0
+ * @version 11.0.0
*/
use Automattic\WooCommerce\Utilities\FeaturesUtil;
@@ -62,6 +62,10 @@ foreach ( $items as $item_id => $item ) :
<?php
// Show title/image etc.
if ( $show_image ) {
+ $image_dimensions = wc_get_image_size( $image_size );
+ $image_width = is_array( $image_dimensions ) && isset( $image_dimensions['width'] ) ? absint( $image_dimensions['width'] ) : 48;
+ $thumbnail_width = $image_width + 24;
+
/**
* Email Order Item Thumbnail hook.
*
@@ -69,7 +73,7 @@ foreach ( $items as $item_id => $item ) :
* @param WC_Order_Item_Product $item The item being displayed.
* @since 2.1.0
*/
- echo '<td>' . wp_kses_post( apply_filters( 'woocommerce_order_item_thumbnail', $image, $item->item ) ) . '</td>';
+ echo '<td class="email-order-item-thumbnail" style="width: ' . esc_attr( $thumbnail_width ) . 'px;">' . wp_kses_post( apply_filters( 'woocommerce_order_item_thumbnail', $image, $item->item ) ) . '</td>';
}
?>
<td>
diff --git a/plugins/woocommerce/templates/emails/email-order-items.php b/plugins/woocommerce/templates/emails/email-order-items.php
index 209f1ccc125..518c0a29688 100644
--- a/plugins/woocommerce/templates/emails/email-order-items.php
+++ b/plugins/woocommerce/templates/emails/email-order-items.php
@@ -12,7 +12,7 @@
*
* @see https://woocommerce.com/document/template-structure/
* @package WooCommerce\Templates\Emails
- * @version 10.8.0
+ * @version 11.0.0
*/
use Automattic\WooCommerce\Utilities\FeaturesUtil;
@@ -31,6 +31,13 @@ foreach ( $items as $item_id => $item ) :
$purchase_note = '';
$image = '';
+ /**
+ * Email Order Item Visibility hook.
+ *
+ * @param bool $visible Whether the order item is visible.
+ * @param WC_Order_Item_Product $item The item being displayed.
+ * @since 2.1.0
+ */
if ( ! apply_filters( 'woocommerce_order_item_visible', true, $item ) ) {
continue;
}
@@ -41,8 +48,17 @@ foreach ( $items as $item_id => $item ) :
$image = $product->get_image( $image_size );
}
+ /**
+ * Email Order Item Class hook.
+ *
+ * @param string $class The order item row class.
+ * @param WC_Order_Item_Product $item The item being displayed.
+ * @param WC_Order $order The order object.
+ * @since 2.1.0
+ */
+ $order_item_class = apply_filters( 'woocommerce_order_item_class', 'order_item', $item, $order );
?>
- <tr class="<?php echo esc_attr( apply_filters( 'woocommerce_order_item_class', 'order_item', $item, $order ) ); ?>">
+ <tr class="<?php echo esc_attr( $order_item_class ); ?>">
<td class="td font-family text-align-left" style="vertical-align: <?php echo $block_email_editor_enabled ? 'top' : 'middle'; ?>; word-wrap:break-word;">
<?php if ( $email_improvements_enabled ) { ?>
<table class="order-item-data" role="presentation">
@@ -50,6 +66,10 @@ foreach ( $items as $item_id => $item ) :
<?php
// Show title/image etc.
if ( $show_image ) {
+ $image_dimensions = wc_get_image_size( $image_size );
+ $image_width = is_array( $image_dimensions ) && isset( $image_dimensions['width'] ) ? absint( $image_dimensions['width'] ) : 48;
+ $thumbnail_width = $image_width + 24;
+
/**
* Email Order Item Thumbnail hook.
*
@@ -57,7 +77,7 @@ foreach ( $items as $item_id => $item ) :
* @param WC_Order_Item_Product $item The item being displayed.
* @since 2.1.0
*/
- echo '<td style="vertical-align: top;">' . wp_kses_post( apply_filters( 'woocommerce_order_item_thumbnail', $image, $item ) ) . '</td>';
+ echo '<td class="email-order-item-thumbnail" style="width: ' . esc_attr( $thumbnail_width ) . 'px;">' . wp_kses_post( apply_filters( 'woocommerce_order_item_thumbnail', $image, $item ) ) . '</td>';
}
?>
<td>
diff --git a/plugins/woocommerce/templates/emails/email-styles.php b/plugins/woocommerce/templates/emails/email-styles.php
index 81e033b6471..325e48fc0ad 100644
--- a/plugins/woocommerce/templates/emails/email-styles.php
+++ b/plugins/woocommerce/templates/emails/email-styles.php
@@ -12,7 +12,7 @@
*
* @see https://woocommerce.com/document/template-structure/
* @package WooCommerce\Templates\Emails
- * @version 10.8.0
+ * @version 11.0.0
*/
use Automattic\WooCommerce\Internal\Email\EmailFont;
@@ -274,7 +274,7 @@ body {
#body_content .order-item-data td {
border: 0 !important;
padding: 0 !important;
- vertical-align: top;
+ vertical-align: middle;
}
#body_content .email-order-details .order-totals td,
@@ -388,6 +388,14 @@ body {
font-family: <?php echo $safe_font_family; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>;
}
+.order-item-data {
+ width: 100%;
+}
+
+.order-item-data h3 {
+ margin: 0;
+}
+
.link {
color: <?php echo esc_attr( $link_color ); ?>;
}
diff --git a/plugins/woocommerce/tests/php/includes/emails/class-wc-email-order-items-test.php b/plugins/woocommerce/tests/php/includes/emails/class-wc-email-order-items-test.php
new file mode 100644
index 00000000000..1d2d518c143
--- /dev/null
+++ b/plugins/woocommerce/tests/php/includes/emails/class-wc-email-order-items-test.php
@@ -0,0 +1,54 @@
+<?php
+declare( strict_types = 1 );
+
+/**
+ * Tests for `email-order-items.php` template.
+ *
+ * @covers `email-order-items.php` template
+ */
+class WC_Email_Order_Items_Test extends \WC_Unit_Test_Case {
+
+ /**
+ * Order IDs created during tests.
+ *
+ * @var int[]
+ */
+ private array $order_ids = array();
+
+ /**
+ * Tear down after each test.
+ */
+ public function tearDown(): void {
+ foreach ( $this->order_ids as $order_id ) {
+ WC_Helper_Order::delete_order( $order_id );
+ }
+ $this->order_ids = array();
+
+ update_option( 'woocommerce_feature_email_improvements_enabled', 'no' );
+
+ parent::tearDown();
+ }
+
+ /**
+ * @testdox Order item image and text columns use fixed alignment with email improvements enabled.
+ */
+ public function test_order_item_image_and_text_columns_use_fixed_alignment_with_email_improvements(): void {
+ update_option( 'woocommerce_feature_email_improvements_enabled', 'yes' );
+
+ $order = WC_Helper_Order::create_order();
+ $this->order_ids[] = $order->get_id();
+
+ $content = wc_get_email_order_items( $order );
+
+ $this->assertStringContainsString(
+ '<table class="order-item-data" role="presentation">',
+ $content,
+ 'Order item data table should fill the product column so rows share the same layout.'
+ );
+ $this->assertStringContainsString(
+ '<td class="email-order-item-thumbnail" style="width: 72px;">',
+ $content,
+ 'Thumbnail column should reserve the image width plus the email improvements image gap.'
+ );
+ }
+}