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

Add Single Product Details block #8225

Merged
merged 25 commits into from
Feb 16, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d46e480
Add minimum structure for Single Product Details block
thealexandrelara Jan 17, 2023
e743ebe
Add tests for Single Product Details block
thealexandrelara Jan 20, 2023
f87de21
wip: create block structure and add initial styles
thealexandrelara Jan 25, 2023
561f6f8
Add block details to the SingleProductDetails.php file
thealexandrelara Jan 26, 2023
d07b9b5
Render tabs title with empty content
thealexandrelara Jan 27, 2023
9c90f71
Use woocommerce_output_product_data_tabs function to retrieve tabs data
thealexandrelara Jan 27, 2023
eb0ce4a
Remove customizations for the Single Product Details block
thealexandrelara Jan 30, 2023
22be4e9
Merge branch 'trunk' into feat/add-single-product-details-block
thealexandrelara Jan 30, 2023
2a4baad
Remove unnecessary console.log from the Edit.tsx file
thealexandrelara Jan 31, 2023
8e05b71
Remove block classname from block wrapper
thealexandrelara Jan 31, 2023
f70ab0c
Remove unnecessary WooCommerce tabs filter from the BlockTemplatesCon…
thealexandrelara Jan 31, 2023
4ea37cb
Merge branch 'trunk' into feat/add-single-product-details-block
thealexandrelara Jan 31, 2023
ad70695
Remove attributes property from the block registration
thealexandrelara Jan 31, 2023
fd83c09
Remove isExperimental flag for the Single Product Details block
thealexandrelara Jan 31, 2023
3661133
Remove get_classes_and_styles_by_attributes method from SingleProduct…
thealexandrelara Jan 31, 2023
8a9196e
Prevent Single Product Details block from apppearing in Pages or Posts
thealexandrelara Jan 31, 2023
edcac21
Fix PHP Coding Standards warnings
thealexandrelara Feb 1, 2023
528b9ce
Merge branch 'trunk' into feat/add-single-product-details-block
gigitux Feb 13, 2023
0ba35e1
update block name
gigitux Feb 13, 2023
af09b77
Merge branch 'feat/add-single-product-details-block' of https://githu…
gigitux Feb 13, 2023
93bcb28
fix SCSS linter error
gigitux Feb 13, 2023
7742ffe
Merge branch 'trunk' of https://github.com/woocommerce/woocommerce-bl…
gigitux Feb 14, 2023
96fab80
move blocks into product-elements folder and rename to product-details
gigitux Feb 14, 2023
43dd558
avoid 404 error
gigitux Feb 15, 2023
85e6247
disable js asset enqueue
gigitux Feb 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions assets/js/blocks/single-product-details/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "woocommerce/single-product-details",
"version": "1.0.0",
"title": "Single Product Details",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we name it Product Details or Single Product Details? 🤔 cc @vivialice

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just name it Product Details for now.

"description": "A block that allows your customers to see details and reviews about the product.",
"category": "woocommerce",
"keywords": [ "WooCommerce" ],
"supports": {},
"attributes": {},
"textdomain": "woo-gutenberg-products-block",
"apiVersion": 2,
"$schema": "https://schemas.wp.org/trunk/block.json"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Miss the declaration for the icon. Any idea about what icon should we pick? @vivialice

}
93 changes: 93 additions & 0 deletions assets/js/blocks/single-product-details/block.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* External dependencies
*/
import classnames from 'classnames';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/

interface SingleProductTab {
id: string;
title: string;
active: boolean;
content: string | undefined;
}

const ProductTabTitle = ( {
id,
title,
active,
}: Pick< SingleProductTab, 'id' | 'title' | 'active' > ) => {
return (
<li
className={ classnames( `${ id }_tab`, {
active,
} ) }
id={ `tab-title-${ id }` }
role="tab"
aria-controls={ `tab-${ id }` }
>
<a href={ `#tab-${ id }` }>{ title }</a>
</li>
);
};

const ProductTabContent = ( {
id,
content,
}: Pick< SingleProductTab, 'id' | 'content' > ) => {
return (
<div
className={ `${ id }_tab` }
id={ `tab-title-${ id }` }
role="tab"
aria-controls={ `tab-${ id }` }
>
{ content }
</div>
);
};

export const SingleProductDetails = () => {
const productTabs = [
{
id: 'description',
title: 'Description',
active: true,
content: __(
'This block lists description, attributes and reviews for a single product.',
'woo-gutenberg-products-block'
),
},
{
id: 'additional_information',
title: 'Additional Information',
active: false,
},
{ id: 'reviews', title: 'Reviews', active: false },
];
const tabsTitle = productTabs.map( ( { id, title, active } ) => (
<ProductTabTitle
key={ id }
id={ id }
title={ title }
active={ active }
/>
) );
const tabsContent = productTabs.map( ( { id, content } ) => (
<ProductTabContent key={ id } id={ id } content={ content } />
) );

return (
<div className="woocommerce-tabs wc-tabs-wrapper">
thealexandrelara marked this conversation as resolved.
Show resolved Hide resolved
<ul className="tabs" role="tablist">
{ tabsTitle }
</ul>
{ tabsContent }
</div>
);
};

export default SingleProductDetails;
35 changes: 35 additions & 0 deletions assets/js/blocks/single-product-details/edit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* External dependencies
*/
import classNames from 'classnames';
import { useBlockProps } from '@wordpress/block-editor';
import { Disabled } from '@wordpress/components';
import type { BlockEditProps } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import Block from './block';
import { Attributes } from './types';
import './editor.scss';

const Edit = ( { attributes, ...rest }: BlockEditProps< Attributes > ) => {
console.log( { attributes } );
thealexandrelara marked this conversation as resolved.
Show resolved Hide resolved
console.log( { rest } );
thealexandrelara marked this conversation as resolved.
Show resolved Hide resolved
const { className } = attributes;
const blockProps = useBlockProps( {
className: classNames( 'wc-block-single-product-details', className ),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the same idea about "no custom class", we could refactor this code in this way:

Suggested change
className: classNames( 'wc-block-single-product-details', className ),
className: className ,

} );

return (
<>
<div { ...blockProps }>
<Disabled>
<Block />
</Disabled>
</div>
</>
);
};

export default Edit;
5 changes: 5 additions & 0 deletions assets/js/blocks/single-product-details/editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.wc-block-single-product-details {
ul.tabs.li {
list-style-type: none;
}
}
20 changes: 20 additions & 0 deletions assets/js/blocks/single-product-details/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* External dependencies
*/
import { registerBlockType } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import metadata from './block.json';
import edit from './edit';

registerBlockType( metadata, {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make the block available only on the Single Product Template. I created a util function to do this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that function is not merged into trunk yet, right?

attributes: {
thealexandrelara marked this conversation as resolved.
Show resolved Hide resolved
...metadata.attributes,
},
edit,
save() {
return null;
},
} );
46 changes: 46 additions & 0 deletions assets/js/blocks/single-product-details/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
.wp-block-woocommerce-single-product-details {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we resolve #8314, is this CSS still necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope we don't need it anymore after solving that issue; however, if we need to change some things in the UX I think we still are going to need this

ul.tabs {
list-style: none;
padding: 0 0 0 1em;
margin: 0 0 1.618em;
overflow: hidden;
position: relative;
border-bottom: 1px solid $gray-200;

li {
border: 1px solid $gray-200;
background-color: $white;
display: inline-block;
position: relative;
z-index: 0;
border-radius: 4px 4px 0 0;
margin: 0;
padding: 0.5em 1em;
opacity: 0.5;

a {
display: inline-block;
font-weight: 700;
color: $black;
text-decoration: none;

&:hover {
text-decoration: none;
color: lighten($black, 10%);
}
}

&.active {
background: $gray-100;
z-index: 2;
border-bottom-color: $gray-200;
opacity: 1;

a {
color: inherit;
text-shadow: inherit;
}
}
}
}
}
3 changes: 3 additions & 0 deletions assets/js/blocks/single-product-details/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface Attributes {
className?: string;
}
3 changes: 3 additions & 0 deletions bin/webpack-entries.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ const blocks = {
'single-product': {
isExperimental: true,
},
'single-product-details': {
isExperimental: true,
thealexandrelara marked this conversation as resolved.
Show resolved Hide resolved
},
'stock-filter': {},
};

Expand Down
2 changes: 1 addition & 1 deletion src/BlockTemplatesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ protected function init() {
add_filter( 'get_block_templates', array( $this, 'add_block_templates' ), 10, 3 );
add_filter( 'current_theme_supports-block-templates', array( $this, 'remove_block_template_support_for_shop_page' ) );
add_filter( 'taxonomy_template_hierarchy', array( $this, 'add_archive_product_to_eligible_for_fallback_templates' ), 10, 1 );

add_filter( 'woocommerce_product_tabs', 'woocommerce_default_product_tabs' );
thealexandrelara marked this conversation as resolved.
Show resolved Hide resolved
thealexandrelara marked this conversation as resolved.
Show resolved Hide resolved
if ( $this->package->is_experimental_build() ) {
add_action( 'after_switch_theme', array( $this, 'check_should_use_blockified_product_grid_templates' ), 10, 2 );
}
Expand Down
54 changes: 54 additions & 0 deletions src/BlockTypes/SingleProductDetails.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace Automattic\WooCommerce\Blocks\BlockTypes;

use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;

/**
* SingleProductDetails class.
*/
class SingleProductDetails extends AbstractBlock {
/**
* Block name.
*
* @var string
*/
protected $block_name = 'single-product-details';

/**
* Render the block.
*
* @param array $attributes Block attributes.
* @param string $content Block content.
* @param WP_Block $block Block instance.
*
* @return string Rendered block output.
*/
protected function render( $attributes, $content, $block ) {
$tabs = $this->render_tabs();

$classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes );
thealexandrelara marked this conversation as resolved.
Show resolved Hide resolved

return sprintf(
'<div class="wp-block-woocommerce-single-product-details %1$s" style="%2$s">
%3$s
</div>',
esc_attr( $classes_and_styles['classes'] ),
esc_attr( $classes_and_styles['styles'] ),
$tabs,
);
}

protected function render_tabs(){
ob_start();

while ( have_posts() ) {
the_post();
woocommerce_output_product_data_tabs();
}

$tabs = ob_get_clean();

return $tabs;
}
}
1 change: 1 addition & 0 deletions src/BlockTypesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ protected function get_block_types() {
'RatingFilter',
'ReviewsByCategory',
'ReviewsByProduct',
'SingleProductDetails',
thealexandrelara marked this conversation as resolved.
Show resolved Hide resolved
'StockFilter',
];

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"title":"Single Product Details Block","pageContent":"<!-- wp:woocommerce/single-product-details /-->"}
32 changes: 32 additions & 0 deletions tests/e2e/specs/backend/single-produt-details.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* External dependencies
*/
import { getAllBlocks, switchUserToAdmin } from '@wordpress/e2e-test-utils';
import { visitBlockPage } from '@woocommerce/blocks-test-utils';

/**
* Internal dependencies
*/
import { insertBlockDontWaitForInsertClose } from '../../utils.js';

const block = {
name: 'Single Product Details',
slug: 'woocommerce/single-product-details',
class: '.wc-block-single-product-details',
};

describe( `${ block.name } Block`, () => {
beforeAll( async () => {
await switchUserToAdmin();
await visitBlockPage( `${ block.name } Block` );
} );

it( 'can be inserted more than once', async () => {
await insertBlockDontWaitForInsertClose( block.name );
expect( await getAllBlocks() ).toHaveLength( 2 );
} );

it( 'renders without crashing', async () => {
await expect( page ).toRenderBlock( block );
} );
} );