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

Commit cc6277f

Browse files
authored
Product Categories List: Update dropdown view (#647)
* Add the hierarchy display to the dropdown * Add navigation for when a category is selected in the dropdown * Use forEach from lodash for ie11 compat * Switch to a button-click navigation pattern for better keyboard support * Try the hidden attribute on option
1 parent 02264b7 commit cc6277f

File tree

6 files changed

+133
-54
lines changed

6 files changed

+133
-54
lines changed

assets/js/blocks/product-categories/block.js

Lines changed: 107 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,73 +2,140 @@
22
* External dependencies
33
*/
44
import { __ } from '@wordpress/i18n';
5-
import { noop } from 'lodash';
6-
import { SelectControl } from '@wordpress/components';
5+
import classnames from 'classnames';
6+
import { Component, createRef, Fragment } from '@wordpress/element';
7+
import { IconButton } from '@wordpress/components';
8+
import { repeat } from 'lodash';
79
import PropTypes from 'prop-types';
10+
import { withInstanceId } from '@wordpress/compose';
811

912
/**
1013
* Internal dependencies
1114
*/
1215
import { buildTermsTree } from './hierarchy';
1316

14-
function getCategories( { hasEmpty, isDropdown, isHierarchical } ) {
17+
function getCategories( { hasEmpty, isHierarchical } ) {
1518
const categories = wc_product_block_data.productCategories.filter(
1619
( cat ) => hasEmpty || !! cat.count
1720
);
18-
return ! isDropdown && isHierarchical ?
21+
return isHierarchical ?
1922
buildTermsTree( categories ) :
2023
categories;
2124
}
2225

2326
/**
2427
* Component displaying the categories as dropdown or list.
2528
*/
26-
const ProductCategoriesBlock = ( { attributes, isPreview = false } ) => {
27-
const { hasCount, isDropdown } = attributes;
28-
const categories = getCategories( attributes );
29-
const parentKey = 'parent-' + categories[ 0 ].term_id;
29+
class ProductCategoriesBlock extends Component {
30+
constructor() {
31+
super( ...arguments );
32+
this.select = createRef();
33+
this.onNavigate = this.onNavigate.bind( this );
34+
this.renderList = this.renderList.bind( this );
35+
this.renderOptions = this.renderOptions.bind( this );
36+
}
3037

31-
const renderList = ( items ) => (
32-
<ul key={ parentKey }>
33-
{ items.map( ( cat ) => {
34-
const count = hasCount ? <span>({ cat.count })</span> : null;
35-
return [
36-
<li key={ cat.term_id }>
37-
<a href={ isPreview ? null : cat.link }>{ cat.name }</a> { count } { /* eslint-disable-line */ }
38-
</li>,
39-
!! cat.children && !! cat.children.length && renderList( cat.children ),
40-
];
41-
} ) }
42-
</ul>
43-
);
38+
onNavigate() {
39+
const { isPreview = false } = this.props;
40+
const url = this.select.current.value;
41+
if ( 'false' === url ) {
42+
return;
43+
}
44+
const home = wc_product_block_data.homeUrl;
4445

45-
return (
46-
<div className="wc-block-product-categories">
47-
{ isDropdown ? (
48-
<SelectControl
49-
label={ __( 'Select a category', 'woo-gutenberg-products-block' ) }
50-
options={ categories.map( ( cat ) => ( {
51-
label: hasCount ? `${ cat.name } (${ cat.count })` : cat.name,
52-
value: cat.term_id,
53-
} ) ) }
54-
onChange={ noop }
55-
/>
56-
) : (
57-
renderList( categories )
58-
) }
59-
</div>
60-
);
61-
};
46+
if ( ! isPreview && 0 === url.indexOf( home ) ) {
47+
document.location.href = url;
48+
}
49+
}
50+
51+
renderList( items, depth = 0 ) {
52+
const { isPreview = false } = this.props;
53+
const { hasCount } = this.props.attributes;
54+
const parentKey = 'parent-' + items[ 0 ].term_id;
55+
56+
return (
57+
<ul key={ parentKey }>
58+
{ items.map( ( cat ) => {
59+
const count = hasCount ? <span>({ cat.count })</span> : null;
60+
return [
61+
<li key={ cat.term_id }>
62+
<a href={ isPreview ? null : cat.link }>{ cat.name }</a> { count } { /* eslint-disable-line */ }
63+
</li>,
64+
!! cat.children && !! cat.children.length && this.renderList( cat.children, depth + 1 ),
65+
];
66+
} ) }
67+
</ul>
68+
);
69+
}
70+
71+
renderOptions( items, depth = 0 ) {
72+
const { hasCount } = this.props.attributes;
73+
74+
return items.map( ( cat ) => {
75+
const count = hasCount ? `(${ cat.count })` : null;
76+
return [
77+
<option key={ cat.term_id } value={ cat.link }>
78+
{ repeat( '–', depth ) } { cat.name } { count }
79+
</option>,
80+
!! cat.children && !! cat.children.length && this.renderOptions( cat.children, depth + 1 ),
81+
];
82+
} );
83+
}
84+
85+
render() {
86+
const { attributes, instanceId } = this.props;
87+
const { isDropdown } = attributes;
88+
const categories = getCategories( attributes );
89+
const classes = classnames( {
90+
'wc-block-product-categories': true,
91+
'is-dropdown': isDropdown,
92+
'is-list': ! isDropdown,
93+
} );
94+
95+
const selectId = `prod-categories-${ instanceId }`;
96+
97+
return (
98+
<div className={ classes }>
99+
{ isDropdown ? (
100+
<Fragment>
101+
<div className="wc-block-product-categories__dropdown">
102+
<label className="screen-reader-text" htmlFor={ selectId }>
103+
{ __( 'Select a category', 'woo-gutenberg-products-block' ) }
104+
</label>
105+
<select id={ selectId } ref={ this.select }>
106+
<option value="false" hidden>
107+
{ __( 'Select a category', 'woo-gutenberg-products-block' ) }
108+
</option>
109+
{ this.renderOptions( categories ) }
110+
</select>
111+
</div>
112+
<IconButton
113+
icon="arrow-right-alt2"
114+
label={ __( 'Go to category', 'woo-gutenberg-products-block' ) }
115+
onClick={ this.onNavigate }
116+
/>
117+
</Fragment>
118+
) : (
119+
this.renderList( categories )
120+
) }
121+
</div>
122+
);
123+
}
124+
}
62125

63126
ProductCategoriesBlock.propTypes = {
64127
/**
65-
* The attributes for this block
128+
* The attributes for this block.
66129
*/
67130
attributes: PropTypes.object.isRequired,
131+
/**
132+
* A unique ID for identifying the label for the select dropdown.
133+
*/
134+
instanceId: PropTypes.number,
68135
/**
69136
* Whether this is the block preview or frontend display.
70137
*/
71138
isPreview: PropTypes.bool,
72139
};
73140

74-
export default ProductCategoriesBlock;
141+
export default withInstanceId( ProductCategoriesBlock );

assets/js/blocks/product-categories/edit.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,16 @@ export default function( { attributes, setAttributes } ) {
4242
checked={ hasCount }
4343
onChange={ () => setAttributes( { hasCount: ! hasCount } ) }
4444
/>
45-
{ ! isDropdown && (
46-
<ToggleControl
47-
label={ __( 'Show hierarchy', 'woo-gutenberg-products-block' ) }
48-
help={
49-
isHierarchical ?
50-
__( 'Hierarchy is visible.', 'woo-gutenberg-products-block' ) :
51-
__( 'Hierarchy is hidden.', 'woo-gutenberg-products-block' )
52-
}
53-
checked={ isHierarchical }
54-
onChange={ () => setAttributes( { isHierarchical: ! isHierarchical } ) }
55-
/>
56-
) }
45+
<ToggleControl
46+
label={ __( 'Show hierarchy', 'woo-gutenberg-products-block' ) }
47+
help={
48+
isHierarchical ?
49+
__( 'Hierarchy is visible.', 'woo-gutenberg-products-block' ) :
50+
__( 'Hierarchy is hidden.', 'woo-gutenberg-products-block' )
51+
}
52+
checked={ isHierarchical }
53+
onChange={ () => setAttributes( { isHierarchical: ! isHierarchical } ) }
54+
/>
5755
<ToggleControl
5856
label={ __( 'Show empty categories', 'woo-gutenberg-products-block' ) }
5957
help={

assets/js/blocks/product-categories/frontend.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/**
22
* External dependencies
33
*/
4+
import { forEach } from 'lodash';
45
import { render } from '@wordpress/element';
56

67
/**
@@ -13,7 +14,7 @@ const containers = document.querySelectorAll(
1314
);
1415

1516
if ( containers.length ) {
16-
containers.forEach( ( el ) => {
17+
forEach( containers, ( el ) => {
1718
const data = JSON.parse( JSON.stringify( el.dataset ) );
1819
const attributes = {
1920
hasCount: data.hasCount === 'true',

assets/js/blocks/product-categories/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { registerBlockType } from '@wordpress/blocks';
88
* Internal dependencies
99
*/
1010
import './editor.scss';
11+
import './style.scss';
1112
import edit from './edit.js';
1213
import { IconFolder } from '../../components/icons';
1314

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.wc-block-product-categories {
2+
margin-bottom: 1em;
3+
4+
&.is-dropdown {
5+
display: flex;
6+
}
7+
8+
select {
9+
margin-right: 0.5em;
10+
}
11+
}

assets/php/class-wgpb-block-library.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ protected static function register_style( $handle, $src, $deps = array(), $media
119119
*/
120120
public static function register_assets() {
121121
self::register_style( 'wc-block-editor', plugins_url( 'build/editor.css', WGPB_PLUGIN_FILE ), array( 'wp-edit-blocks' ) );
122-
self::register_style( 'wc-block-style', plugins_url( 'build/style.css', WGPB_PLUGIN_FILE ), array() );
122+
self::register_style( 'wc-block-style', plugins_url( 'build/style.css', WGPB_PLUGIN_FILE ), array( 'wp-components' ) );
123123

124124
// Shared libraries and components across all blocks.
125125
self::register_script( 'wc-blocks', plugins_url( 'build/blocks.js', WGPB_PLUGIN_FILE ), array(), false );
@@ -215,6 +215,7 @@ public static function print_script_block_data() {
215215
'default_height' => wc_get_theme_support( 'featured_block::default_height', 500 ),
216216
'isLargeCatalog' => $product_counts->publish > 200,
217217
'productCategories' => $product_categories,
218+
'homeUrl' => esc_js( home_url( '/' ) ),
218219
);
219220
?>
220221
<script type="text/javascript">

0 commit comments

Comments
 (0)