Skip to content
This repository was archived by the owner on Feb 23, 2024. It is now read-only.

Commit b7e090a

Browse files
Create the Products by Attribute template (#7660)
* Create the `Products by Attribute` template * bot: update checkstyle.xml * Fix typo * Rename template to `taxonomy-product_attribute` * Rename test template file * bot: update checkstyle.xml * Fix test enabling archives for shade attribute Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent e2b559d commit b7e090a

File tree

11 files changed

+149
-13
lines changed

11 files changed

+149
-13
lines changed

assets/js/blocks/classic-template/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ This block does not have any customizable options available, so any style or cus
1818
### Props
1919

2020
- `attributes`
21-
- `template`: `single-product` | `archive-product` | `taxonomy-product_cat` | `taxonomy-product_tag`
21+
- `template`: `single-product` | `archive-product` | `taxonomy-product_cat` | `taxonomy-product_tag` | `taxonomy-product_attribute`
2222
- `align`: `wide` | `full`
2323

2424
```html

assets/js/blocks/classic-template/constants.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ export const TEMPLATES: TemplateDetails = {
3838
),
3939
placeholder: 'archive-product',
4040
},
41+
'taxonomy-product_attribute': {
42+
title: __(
43+
'WooCommerce Product Attribute Block',
44+
'woo-gutenberg-products-block'
45+
),
46+
placeholder: 'archive-product',
47+
},
4148
'product-search-results': {
4249
title: __(
4350
'WooCommerce Product Search Results Block',

assets/js/blocks/classic-template/test/utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ const TEMPLATES = {
2020
title: 'Product Taxonomy Title',
2121
placeholder: 'Product Taxonomy Placeholder',
2222
},
23+
'taxonomy-product_attribute': {
24+
title: 'Product Attribute Title',
25+
placeholder: 'Product Attribute Placeholder',
26+
},
2327
};
2428

2529
describe( 'getTemplateDetailsBySlug', function () {

src/BlockTemplatesController.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
namespace Automattic\WooCommerce\Blocks;
33

44
use Automattic\WooCommerce\Blocks\Domain\Package;
5+
use Automattic\WooCommerce\Blocks\Templates\ProductAttributeTemplate;
56
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
67

78
/**
@@ -110,7 +111,7 @@ public function get_block_file_template( $template, $id, $template_type ) {
110111

111112
list( $template_id, $template_slug ) = $template_name_parts;
112113

113-
// If the theme has an archive-product.html template, but not a taxonomy-product_cat/tag.html template let's use the themes archive-product.html template.
114+
// If the theme has an archive-product.html template, but not a taxonomy-product_cat/tag/attribute.html template let's use the themes archive-product.html template.
114115
if ( BlockTemplateUtils::template_is_eligible_for_product_archive_fallback( $template_slug ) ) {
115116
$template_path = BlockTemplateUtils::get_theme_template_path( 'archive-product' );
116117
$template_object = BlockTemplateUtils::create_new_block_template_object( $template_path, $template_type, $template_slug, true );
@@ -330,7 +331,7 @@ function ( $template ) use ( $template_slug ) {
330331
continue;
331332
}
332333

333-
// If the theme has an archive-product.html template, but not a taxonomy-product_cat.html template let's use the themes archive-product.html template.
334+
// If the theme has an archive-product.html template, but not a taxonomy-product_cat/tag/attribute.html template let's use the themes archive-product.html template.
334335
if ( BlockTemplateUtils::template_is_eligible_for_product_archive_fallback( $template_slug ) ) {
335336
$template_file = BlockTemplateUtils::get_theme_template_path( 'archive-product' );
336337
$templates[] = BlockTemplateUtils::create_new_block_template_object( $template_file, $template_type, $template_slug, true );
@@ -439,8 +440,8 @@ public function render_block_template() {
439440
}
440441

441442
if ( isset( $queried_object->taxonomy ) && taxonomy_is_product_attribute( $queried_object->taxonomy ) &&
442-
! BlockTemplateUtils::theme_has_template( 'archive-product' ) &&
443-
$this->block_template_is_available( 'archive-product' )
443+
! BlockTemplateUtils::theme_has_template( ProductAttributeTemplate::SLUG ) &&
444+
$this->block_template_is_available( ProductAttributeTemplate::SLUG )
444445
) {
445446
add_filter( 'woocommerce_has_block_template', '__return_true', 10, 0 );
446447
}

src/BlockTypes/ClassicTemplate.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
22
namespace Automattic\WooCommerce\Blocks\BlockTypes;
33

4+
use Automattic\WooCommerce\Blocks\Templates\ProductAttributeTemplate;
45
use Automattic\WooCommerce\Blocks\Templates\ProductSearchResultsTemplate;
56
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
67
use WC_Query;
@@ -61,7 +62,7 @@ protected function render( $attributes, $content, $block ) {
6162
$frontend_scripts::load_scripts();
6263
}
6364

64-
$archive_templates = array( 'archive-product', 'taxonomy-product_cat', 'taxonomy-product_tag', ProductSearchResultsTemplate::SLUG );
65+
$archive_templates = array( 'archive-product', 'taxonomy-product_cat', 'taxonomy-product_tag', ProductAttributeTemplate::SLUG, ProductSearchResultsTemplate::SLUG );
6566

6667
if ( 'single-product' === $attributes['template'] ) {
6768
return $this->render_single_product();

src/Templates/ProductAttributeTemplate.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* @internal
99
*/
1010
class ProductAttributeTemplate {
11-
const SLUG = 'archive-product';
11+
const SLUG = 'taxonomy-product_attribute';
1212

1313
/**
1414
* Constructor.
@@ -25,14 +25,14 @@ protected function init() {
2525
}
2626

2727
/**
28-
* Render the Archive Product Template for product attributes.
28+
* Renders the Product by Attribute template for product attributes taxonomy pages.
2929
*
3030
* @param array $templates Templates that match the product attributes taxonomy.
3131
*/
3232
public function update_taxonomy_template_hierarchy( $templates ) {
3333
$queried_object = get_queried_object();
3434
if ( taxonomy_is_product_attribute( $queried_object->taxonomy ) && wc_current_theme_is_fse_theme() ) {
35-
array_unshift( $templates, self::SLUG );
35+
array_splice( $templates, count( $templates ) - 1, 0, self::SLUG );
3636
}
3737

3838
return $templates;

src/Utils/BlockTemplateUtils.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
22
namespace Automattic\WooCommerce\Blocks\Utils;
33

4+
use Automattic\WooCommerce\Blocks\Templates\ProductAttributeTemplate;
45
use Automattic\WooCommerce\Blocks\Templates\ProductSearchResultsTemplate;
56
use Automattic\WooCommerce\Blocks\Domain\Services\FeatureGating;
67
use Automattic\WooCommerce\Blocks\Options;
@@ -312,6 +313,10 @@ public static function get_plugin_block_template_types() {
312313
'title' => _x( 'Products by Tag', 'Template name', 'woo-gutenberg-products-block' ),
313314
'description' => __( 'Displays products filtered by a tag.', 'woo-gutenberg-products-block' ),
314315
),
316+
ProductAttributeTemplate::SLUG => array(
317+
'title' => _x( 'Products by Attribute', 'Template name', 'woo-gutenberg-products-block' ),
318+
'description' => __( 'Displays products filtered by an attribute.', 'woo-gutenberg-products-block' ),
319+
),
315320
ProductSearchResultsTemplate::SLUG => array(
316321
'title' => _x( 'Product Search Results', 'Template name', 'woo-gutenberg-products-block' ),
317322
'description' => __( 'Displays search results for your store.', 'woo-gutenberg-products-block' ),
@@ -449,14 +454,14 @@ public static function get_block_template( $id, $template_type ) {
449454
/**
450455
* Checks if we can fallback to the `archive-product` template for a given slug
451456
*
452-
* `taxonomy-product_cat` and `taxonomy-product_tag` templates can generally use the
453-
* `archive-product` as a fallback if there are no specific overrides.
457+
* `taxonomy-product_cat`, `taxonomy-product_tag`, `taxonomy-attribute` templates can
458+
* generally use the `archive-product` as a fallback if there are no specific overrides.
454459
*
455460
* @param string $template_slug Slug to check for fallbacks.
456461
* @return boolean
457462
*/
458463
public static function template_is_eligible_for_product_archive_fallback( $template_slug ) {
459-
$eligible_for_fallbacks = array( 'taxonomy-product_cat', 'taxonomy-product_tag' );
464+
$eligible_for_fallbacks = array( 'taxonomy-product_cat', 'taxonomy-product_tag', ProductAttributeTemplate::SLUG );
460465

461466
return in_array( $template_slug, $eligible_for_fallbacks, true )
462467
&& ! self::theme_has_template( $template_slug )
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<!-- wp:template-part {"slug":"header","tagName":"header"} /-->
2+
<!-- wp:group {"layout":{"inherit":true}} -->
3+
<div class="wp-block-group"><!-- wp:woocommerce/legacy-template {"template":"taxonomy-product_attribute"} /--></div>
4+
<!-- /wp:group -->
5+
<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->

tests/e2e/fixtures/fixture-data.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ const Attributes = () => [
2626
],
2727
},
2828
{
29-
attribute: { name: 'Shade' },
29+
attribute: {
30+
name: 'Shade',
31+
has_archives: true,
32+
},
3033
terms: [
3134
{
3235
name: 'Red',

tests/e2e/specs/backend/site-editing-templates.test.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@ const BLOCK_DATA = {
9393
},
9494
name: 'woocommerce/legacy-template',
9595
},
96+
'taxonomy-product_attribute': {
97+
attributes: {
98+
placeholder: 'archive-product',
99+
template: 'taxonomy-product_attribute',
100+
title: 'WooCommerce Product Attribute Block',
101+
},
102+
name: 'woocommerce/legacy-template',
103+
},
96104
'product-search-results': {
97105
attributes: {
98106
title: 'WooCommerce Product Search Results Block',
@@ -516,6 +524,100 @@ describe( 'Store Editing Templates', () => {
516524
} );
517525
} );
518526

527+
describe( 'Products by Attribute template', () => {
528+
it( 'default template from WooCommerce Blocks is available on an FSE theme', async () => {
529+
const EXPECTED_TEMPLATE = defaultTemplateProps(
530+
'Products by Attribute'
531+
);
532+
533+
await goToTemplatesList();
534+
535+
const templates = await getAllTemplates();
536+
537+
try {
538+
expect( templates ).toContainEqual( EXPECTED_TEMPLATE );
539+
} catch ( ok ) {
540+
// Depending on the speed of the execution and whether Chrome is headless or not
541+
// the id might be parsed or not
542+
543+
expect( templates ).toContainEqual( {
544+
...EXPECTED_TEMPLATE,
545+
addedBy: WOOCOMMERCE_PARSED_ID,
546+
} );
547+
}
548+
} );
549+
550+
runOnlyWhenGutenbergIsDisabled( () =>
551+
it( 'should contain the "WooCommerce Product Taxonomy Block" classic template', async () => {
552+
await goToTemplateEditor( {
553+
postId: 'woocommerce/woocommerce//taxonomy-product_attribute',
554+
} );
555+
556+
const [ classicBlock ] = await filterCurrentBlocks(
557+
( block ) =>
558+
block.name ===
559+
BLOCK_DATA[ 'taxonomy-product_attribute' ].name
560+
);
561+
562+
expect( classicBlock.attributes.template ).toBe(
563+
BLOCK_DATA[ 'taxonomy-product_attribute' ].attributes
564+
.template
565+
);
566+
expect( await getCurrentSiteEditorContent() ).toMatchSnapshot();
567+
} )
568+
);
569+
570+
it( 'should show the action menu if the template has been customized by the user', async () => {
571+
const EXPECTED_TEMPLATE = {
572+
...defaultTemplateProps( 'Products by Attribute' ),
573+
hasActions: true,
574+
};
575+
576+
await visitTemplateAndAddCustomParagraph(
577+
'taxonomy-product_attribute'
578+
);
579+
580+
await goToTemplatesList( { waitFor: 'actions' } );
581+
582+
const templates = await getAllTemplates();
583+
584+
try {
585+
expect( templates ).toContainEqual( EXPECTED_TEMPLATE );
586+
} catch ( ok ) {
587+
// Depending on the speed of the execution and whether Chrome is headless or not
588+
// the id might be parsed or not
589+
590+
expect( templates ).toContainEqual( {
591+
...EXPECTED_TEMPLATE,
592+
addedBy: WOOCOMMERCE_PARSED_ID,
593+
} );
594+
}
595+
} );
596+
597+
it( 'should preserve and correctly show the user customization on the back-end', async () => {
598+
await goToTemplateEditor( {
599+
postId: 'woocommerce/woocommerce//taxonomy-product_attribute',
600+
} );
601+
602+
await expect( canvas() ).toMatchElement(
603+
SELECTORS.blocks.paragraph,
604+
{
605+
text: CUSTOMIZED_STRING,
606+
timeout: DEFAULT_TIMEOUT,
607+
}
608+
);
609+
} );
610+
611+
it( 'should show the user customization on the front-end', async () => {
612+
await page.goto( new URL( '/shade/red', BASE_URL ) );
613+
614+
await expect( page ).toMatchElement( 'p', {
615+
text: CUSTOMIZED_STRING,
616+
timeout: DEFAULT_TIMEOUT,
617+
} );
618+
} );
619+
} );
620+
519621
describe( 'Product Search Results block template', () => {
520622
it( 'default template from WooCommerce Blocks is available on an FSE theme', async () => {
521623
const EXPECTED_TEMPLATE = defaultTemplateProps(

0 commit comments

Comments
 (0)