Skip to content

Commit

Permalink
fix: attribute selection from PDPs with tokenized ECE (#10306)
Browse files Browse the repository at this point in the history
Co-authored-by: Brett Shumaker <[email protected]>
  • Loading branch information
frosso and brettshumaker authored Feb 13, 2025
1 parent 6d62c07 commit a7b4631
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 18 deletions.
4 changes: 4 additions & 0 deletions changelog/fix-tokenized-ece-attribute-selection
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fix

fix: attribute selection from PDPs with tokenized ECE
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
/* eslint-disable jsx-a11y/accessible-emoji */

/**
* External dependencies
*/
import { applyFilters } from '@wordpress/hooks';
import { render } from '@testing-library/react';

/**
* Internal dependencies
*/
import '../wc-product-page';

describe( 'ECE product page compatibility', () => {
it( 'returns the variation data', () => {
render(
<form className="variations_form">
<table className="variations" role="presentation">
<tbody>
<tr>
<th className="label">
<label htmlFor="pa_color">Color</label>
</th>
<td className="value">
<select
id="pa_color"
name="attribute_pa_color"
data-attribute_name="attribute_pa_color"
defaultValue="red"
>
<option value="">Choose an option</option>
<option value="blue">Blue</option>
<option value="green">Green</option>
<option value="red">Red</option>
</select>
</td>
</tr>
<tr>
<th className="label">
<label htmlFor="logo">Logo</label>
</th>
<td className="value">
<select
id="logo"
name="attribute_logo"
data-attribute_name="attribute_logo"
defaultValue="Yes"
>
<option value="">Choose an option</option>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
</td>
</tr>
</tbody>
</table>
<div className="single_variation_wrap">
<input type="hidden" name="product_id" value="10" />
</div>
</form>
);
const productData = applyFilters(
'wcpay.express-checkout.cart-add-item',
{
variation: [],
}
);

expect( productData ).toStrictEqual( {
id: 10,
variation: [
{
attribute: 'Color',
value: 'red',
},
{
attribute: 'attribute_pa_color',
value: 'red',
},
{
attribute: 'Logo',
value: 'Yes',
},
{
attribute: 'attribute_logo',
value: 'Yes',
},
],
} );
} );
it( 'ensures compatibility with plugins modifying the DOM with additional markup', () => {
// this markup is simulating the output of the "woo-variation-swatches" plugin.
render(
<form className="variations_form">
<table className="variations">
<tbody>
<tr>
<th className="label">
<label htmlFor="size%f0%9f%98%86">
Size😆
<span className="cfvsw-selected-label">
Medium
</span>
</label>
</th>
<td className="value woo-variation-items-wrapper">
<select
id="size%f0%9f%98%86"
name="attribute_size%f0%9f%98%86"
data-attribute_name="attribute_size%f0%9f%98%86"
defaultValue="Medium"
>
<option value="">Choose an option</option>
<option value="Small">Small</option>
<option value="Medium">Medium</option>
</select>
</td>
</tr>
<tr>
<th className="label">
<label htmlFor="color-%e2%9c%8f%ef%b8%8f">
Color ✏️
</label>
<span>: Blue</span>
</th>
<td className="value woo-variation-items-wrapper">
<select
id="color-%e2%9c%8f%ef%b8%8f"
name="attribute_color-%e2%9c%8f%ef%b8%8f"
data-attribute_name="attribute_color-%e2%9c%8f%ef%b8%8f"
defaultValue="Green"
>
<option value="">Choose an option</option>
<option value="Blue">Blue</option>
<option value="Green">Green</option>
</select>
</td>
</tr>
<tr>
<th className="label">
<label htmlFor="autograph-choice-%e2%9c%8f%ef%b8%8f">
Autograph choice ✏️
</label>
<span>: Yes 👍</span>
</th>
<td className="value woo-variation-items-wrapper">
<select
id="autograph-choice-%e2%9c%8f%ef%b8%8f"
name="attribute_autograph-choice-%e2%9c%8f%ef%b8%8f"
data-attribute_name="attribute_autograph-choice-%e2%9c%8f%ef%b8%8f"
defaultValue="Yes 👍"
>
<option value="">Choose an option</option>
<option value="Yes 👍">Yes 👍</option>
<option value="No 👎">No 👎</option>
</select>
</td>
</tr>
</tbody>
</table>
<div className="single_variation_wrap">
<input type="hidden" name="product_id" value="10" />
</div>
</form>
);
const productData = applyFilters(
'wcpay.express-checkout.cart-add-item',
{
variation: [],
}
);

expect( productData ).toStrictEqual( {
id: 10,
variation: [
{
attribute: 'Size😆',
value: 'Medium',
},
{
attribute: 'attribute_size%f0%9f%98%86',
value: 'Medium',
},
{
attribute: 'Color ✏️',
value: 'Green',
},
{
attribute: 'attribute_color-%e2%9c%8f%ef%b8%8f',
value: 'Green',
},
{
attribute: 'Autograph choice ✏️',
value: 'Yes 👍',
},
{
attribute: 'attribute_autograph-choice-%e2%9c%8f%ef%b8%8f',
value: 'Yes 👍',
},
],
} );
} );
} );
46 changes: 28 additions & 18 deletions client/tokenized-express-checkout/compatibility/wc-product-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,16 @@ addFilter(
'wcpay.express-checkout.cart-add-item',
'automattic/wcpay/express-checkout',
( productData ) => {
const $variationInformation = jQuery( '.single_variation_wrap' );
if ( ! $variationInformation.length ) {
const variationInformation = document.querySelector(
'.single_variation_wrap'
);
if ( ! variationInformation ) {
return productData;
}

const productId = $variationInformation
.find( 'input[name="product_id"]' )
.val();
const productId = variationInformation.querySelector(
'input[name="product_id"]'
).value;
return {
...productData,
id: parseInt( productId, 10 ),
Expand All @@ -55,31 +57,39 @@ addFilter(
'wcpay.express-checkout.cart-add-item',
'automattic/wcpay/express-checkout',
( productData ) => {
const $variationsForm = jQuery( '.variations_form' );
if ( ! $variationsForm.length ) {
const variationsForm = document.querySelector( '.variations_form' );
if ( ! variationsForm ) {
return productData;
}

const attributes = [];
const $variationSelectElements = $variationsForm.find(
const variationSelectElements = variationsForm.querySelectorAll(
'.variations select'
);
$variationSelectElements.each( function () {
const $select = jQuery( this );
Array.from( variationSelectElements ).forEach( function ( select ) {
const attributeName =
$select.data( 'attribute_name' ) || $select.attr( 'name' );
select.dataset.attribute_name || select.dataset.name;

attributes.push( {
// The Store API accepts the variable attribute's label, rather than an internal identifier:
// https://github.com/woocommerce/woocommerce-blocks/blob/trunk/src/StoreApi/docs/cart.md#add-item
// It's an unfortunate hack that doesn't work when labels have special characters in them.
attribute: document.querySelector(
`label[for="${ attributeName.replace(
'attribute_',
''
) }"]`
).innerHTML,
value: $select.val() || '',
// fallback until https://github.com/woocommerce/woocommerce/pull/55317 has been consolidated in WC Core.
attribute: Array.from(
document.querySelector(
`label[for="${ attributeName.replace(
'attribute_',
''
) }"]`
).childNodes
)[ 0 ].textContent,
value: select.value || '',
} );

// proper logic for https://github.com/woocommerce/woocommerce/pull/55317 .
attributes.push( {
attribute: attributeName,
value: select.value || '',
} );
} );

Expand Down

0 comments on commit a7b4631

Please sign in to comment.