Add dynamic rendering + SSR to Products by Attribute (https://github.com/woocommerce/woocommerce-blocks/pull/602)
* Add dynamic rendering + SSR to Products by Attribute * Fix spacing lint issue
This commit is contained in:
parent
e0ff109781
commit
bfa7724fe3
|
@ -2,89 +2,31 @@
|
|||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { addQueryArgs } from '@wordpress/url';
|
||||
import apiFetch from '@wordpress/api-fetch';
|
||||
import { BlockControls, InspectorControls } from '@wordpress/editor';
|
||||
import { BlockControls, InspectorControls, ServerSideRender } from '@wordpress/editor';
|
||||
import {
|
||||
Button,
|
||||
Disabled,
|
||||
PanelBody,
|
||||
Placeholder,
|
||||
Spinner,
|
||||
Toolbar,
|
||||
withSpokenMessages,
|
||||
} from '@wordpress/components';
|
||||
import classnames from 'classnames';
|
||||
import { Component, Fragment } from '@wordpress/element';
|
||||
import { debounce } from 'lodash';
|
||||
import Gridicon from 'gridicons';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import getQuery from '../../utils/get-query';
|
||||
import GridContentControl from '../../components/grid-content-control';
|
||||
import GridLayoutControl from '../../components/grid-layout-control';
|
||||
import ProductAttributeControl from '../../components/product-attribute-control';
|
||||
import ProductOrderbyControl from '../../components/product-orderby-control';
|
||||
import ProductPreview from '../../components/product-preview';
|
||||
|
||||
/**
|
||||
* Component to handle edit mode of "Products by Attribute".
|
||||
*/
|
||||
class ProductsByAttributeBlock extends Component {
|
||||
constructor() {
|
||||
super( ...arguments );
|
||||
this.state = {
|
||||
products: [],
|
||||
loaded: false,
|
||||
};
|
||||
|
||||
this.debouncedGetProducts = debounce( this.getProducts.bind( this ), 200 );
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if ( this.props.attributes.attributes ) {
|
||||
this.getProducts();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate( prevProps ) {
|
||||
const hasChange = [
|
||||
'attributes',
|
||||
'attrOperator',
|
||||
'columns',
|
||||
'orderby',
|
||||
'rows',
|
||||
].reduce( ( acc, key ) => {
|
||||
return acc || prevProps.attributes[ key ] !== this.props.attributes[ key ];
|
||||
}, false );
|
||||
if ( hasChange ) {
|
||||
this.debouncedGetProducts();
|
||||
}
|
||||
}
|
||||
|
||||
getProducts() {
|
||||
const blockAttributes = this.props.attributes;
|
||||
if ( ! blockAttributes.attributes.length ) {
|
||||
// We've removed all selected attributes, or no attributes have been selected yet.
|
||||
this.setState( { products: [], loaded: true } );
|
||||
return;
|
||||
}
|
||||
apiFetch( {
|
||||
path: addQueryArgs(
|
||||
'/wc-blocks/v1/products',
|
||||
getQuery( blockAttributes, this.props.name )
|
||||
),
|
||||
} )
|
||||
.then( ( products ) => {
|
||||
this.setState( { products, loaded: true } );
|
||||
} )
|
||||
.catch( () => {
|
||||
this.setState( { products: [], loaded: true } );
|
||||
} );
|
||||
}
|
||||
|
||||
getInspectorControls() {
|
||||
const { setAttributes } = this.props;
|
||||
const {
|
||||
|
@ -199,20 +141,8 @@ class ProductsByAttributeBlock extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { setAttributes } = this.props;
|
||||
const { columns, editMode, contentVisibility } = this.props.attributes;
|
||||
const { loaded, products = [] } = this.state;
|
||||
const classes = classnames( {
|
||||
'wc-block-products-grid': true,
|
||||
'wc-block-products-attribute': true,
|
||||
[ `cols-${ columns }` ]: columns,
|
||||
'is-loading': ! loaded,
|
||||
'is-not-found': loaded && ! products.length,
|
||||
'is-hidden-title': ! contentVisibility.title,
|
||||
'is-hidden-price': ! contentVisibility.price,
|
||||
'is-hidden-rating': ! contentVisibility.rating,
|
||||
'is-hidden-button': ! contentVisibility.button,
|
||||
} );
|
||||
const { attributes, name, setAttributes } = this.props;
|
||||
const { editMode } = attributes;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
|
@ -232,27 +162,9 @@ class ProductsByAttributeBlock extends Component {
|
|||
{ editMode ? (
|
||||
this.renderEditMode()
|
||||
) : (
|
||||
<div className={ classes }>
|
||||
{ products.length ? (
|
||||
products.map( ( product ) => (
|
||||
<ProductPreview product={ product } key={ product.id } />
|
||||
) )
|
||||
) : (
|
||||
<Placeholder
|
||||
icon={ <Gridicon icon="custom-post-type" /> }
|
||||
label={ __(
|
||||
'Products by Attribute',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
>
|
||||
{ ! loaded ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
__( 'No products found.', 'woo-gutenberg-products-block' )
|
||||
) }
|
||||
</Placeholder>
|
||||
) }
|
||||
</div>
|
||||
<Disabled>
|
||||
<ServerSideRender block={ name } attributes={ attributes } />
|
||||
</Disabled>
|
||||
) }
|
||||
</Fragment>
|
||||
);
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import classnames from 'classnames';
|
||||
import Gridicon from 'gridicons';
|
||||
import { RawHTML } from '@wordpress/element';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
|
@ -12,9 +10,11 @@ import { registerBlockType } from '@wordpress/blocks';
|
|||
*/
|
||||
import './editor.scss';
|
||||
import Block from './block';
|
||||
import getShortcode from '../../utils/get-shortcode';
|
||||
import { deprecatedConvertToShortcode } from '../../utils/deprecations';
|
||||
|
||||
registerBlockType( 'woocommerce/products-by-attribute', {
|
||||
const blockTypeName = 'woocommerce/products-by-attribute';
|
||||
|
||||
registerBlockType( blockTypeName, {
|
||||
title: __( 'Products by Attribute', 'woo-gutenberg-products-block' ),
|
||||
icon: {
|
||||
src: <Gridicon icon="custom-post-type" />,
|
||||
|
@ -92,6 +92,48 @@ registerBlockType( 'woocommerce/products-by-attribute', {
|
|||
},
|
||||
},
|
||||
|
||||
deprecated: [
|
||||
{
|
||||
// Deprecate shortcode save method in favor of dynamic rendering.
|
||||
attributes: {
|
||||
attributes: {
|
||||
type: 'array',
|
||||
default: [],
|
||||
},
|
||||
attrOperator: {
|
||||
type: 'string',
|
||||
default: 'any',
|
||||
},
|
||||
columns: {
|
||||
type: 'number',
|
||||
default: wc_product_block_data.default_columns,
|
||||
},
|
||||
editMode: {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
},
|
||||
contentVisibility: {
|
||||
type: 'object',
|
||||
default: {
|
||||
title: true,
|
||||
price: true,
|
||||
rating: true,
|
||||
button: true,
|
||||
},
|
||||
},
|
||||
orderby: {
|
||||
type: 'string',
|
||||
default: 'date',
|
||||
},
|
||||
rows: {
|
||||
type: 'number',
|
||||
default: wc_product_block_data.default_rows,
|
||||
},
|
||||
},
|
||||
save: deprecatedConvertToShortcode( blockTypeName ),
|
||||
},
|
||||
],
|
||||
|
||||
/**
|
||||
* Renders and manages the block.
|
||||
*/
|
||||
|
@ -99,29 +141,7 @@ registerBlockType( 'woocommerce/products-by-attribute', {
|
|||
return <Block { ...props } />;
|
||||
},
|
||||
|
||||
/**
|
||||
* Save the block content in the post content. Block content is saved as a products shortcode.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
save( props ) {
|
||||
const {
|
||||
align,
|
||||
contentVisibility,
|
||||
} = props.attributes; /* eslint-disable-line react/prop-types */
|
||||
const classes = classnames(
|
||||
align ? `align${ align }` : '',
|
||||
{
|
||||
'is-hidden-title': ! contentVisibility.title,
|
||||
'is-hidden-price': ! contentVisibility.price,
|
||||
'is-hidden-rating': ! contentVisibility.rating,
|
||||
'is-hidden-button': ! contentVisibility.button,
|
||||
}
|
||||
);
|
||||
return (
|
||||
<RawHTML className={ classes }>
|
||||
{ getShortcode( props, 'woocommerce/products-by-attribute' ) }
|
||||
</RawHTML>
|
||||
);
|
||||
save() {
|
||||
return null;
|
||||
},
|
||||
} );
|
||||
|
|
|
@ -264,9 +264,70 @@ class WGPB_Block_Library {
|
|||
register_block_type(
|
||||
'woocommerce/products-by-attribute',
|
||||
array(
|
||||
'editor_script' => 'wc-products-attribute',
|
||||
'editor_style' => 'wc-block-editor',
|
||||
'style' => 'wc-block-style',
|
||||
'render_callback' => array( __CLASS__, 'render_products_by_attribute' ),
|
||||
'editor_script' => 'wc-products-attribute',
|
||||
'editor_style' => 'wc-block-editor',
|
||||
'style' => 'wc-block-style',
|
||||
'attributes' => array(
|
||||
'attributes' => array(
|
||||
'type' => 'array',
|
||||
'items' => array(
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'id' => array(
|
||||
'type' => 'number',
|
||||
),
|
||||
'attr_slug' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
),
|
||||
'default' => array(),
|
||||
),
|
||||
'attrOperator' => array(
|
||||
'type' => 'string',
|
||||
'default' => 'any',
|
||||
),
|
||||
'columns' => array(
|
||||
'type' => 'number',
|
||||
'default' => wc_get_theme_support( 'product_blocks::default_columns', 3 ),
|
||||
),
|
||||
'contentVisibility' => array(
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'title' => array(
|
||||
'type' => 'boolean',
|
||||
'default' => true,
|
||||
),
|
||||
'price' => array(
|
||||
'type' => 'boolean',
|
||||
'default' => true,
|
||||
),
|
||||
'rating' => array(
|
||||
'type' => 'boolean',
|
||||
'default' => true,
|
||||
),
|
||||
'button' => array(
|
||||
'type' => 'boolean',
|
||||
'default' => true,
|
||||
),
|
||||
),
|
||||
),
|
||||
'editMode' => array(
|
||||
'type' => 'boolean',
|
||||
'default' => true,
|
||||
),
|
||||
'orderby' => array(
|
||||
'type' => 'string',
|
||||
'enum' => array( 'date', 'popularity', 'price_asc', 'price_desc', 'rating', 'title' ),
|
||||
'default' => 'date',
|
||||
),
|
||||
'rows' => array(
|
||||
'type' => 'number',
|
||||
'default' => wc_get_theme_support( 'product_blocks::default_rows', 1 ),
|
||||
),
|
||||
|
||||
),
|
||||
)
|
||||
);
|
||||
register_block_type(
|
||||
|
@ -444,6 +505,20 @@ class WGPB_Block_Library {
|
|||
return $block->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Products by attribute: Include and render the dynamic block.
|
||||
*
|
||||
* @param array $attributes Block attributes. Default empty array.
|
||||
* @param string $content Block content. Default empty string.
|
||||
* @return string Rendered block type output.
|
||||
*/
|
||||
public static function render_products_by_attribute( $attributes, $content ) {
|
||||
require_once dirname( __FILE__ ) . '/class-wgpb-block-products-by-attribute.php';
|
||||
|
||||
$block = new WGPB_Block_Products_By_Attribute( $attributes, $content );
|
||||
return $block->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Top rated products: Include and render the dynamic block.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* Display the Products by Attribute block in the post content.
|
||||
* NOTE: DO NOT edit this file in WooCommerce core, this is generated from woocommerce-gutenberg-products-block.
|
||||
*
|
||||
* @package WooCommerce\Blocks
|
||||
* @version 2.1.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for getting products by attribute for display.
|
||||
*/
|
||||
class WGPB_Block_Products_By_Attribute extends WGPB_Block_Grid_Base {
|
||||
/**
|
||||
* Block name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $block_name = 'products-by-attribute';
|
||||
|
||||
/**
|
||||
* Set args specific to this block
|
||||
*
|
||||
* @param array $query_args Query args.
|
||||
*/
|
||||
protected function set_block_query_args( &$query_args ) {
|
||||
if ( ! empty( $this->attributes['attributes'] ) ) {
|
||||
$taxonomy = sanitize_title( $this->attributes['attributes'][0]['attr_slug'] );
|
||||
$terms = wp_list_pluck( $this->attributes['attributes'], 'id' );
|
||||
|
||||
$query_args['tax_query'][] = array(
|
||||
'taxonomy' => $taxonomy,
|
||||
'terms' => array_map( 'absint', $terms ),
|
||||
'field' => 'term_id',
|
||||
'operator' => 'all' === $this->attributes['attrOperator'] ? 'AND' : 'IN',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue