Add dynamic rendering + SSR to Best Selling Products block (https://github.com/woocommerce/woocommerce-blocks/pull/599)

This commit is contained in:
Kelly Dwan 2019-05-28 08:00:49 -04:00 committed by Mike Jolley
parent 751bbfcbb2
commit 9cb681fcf2
4 changed files with 78 additions and 114 deletions

View File

@ -2,70 +2,25 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import classnames from 'classnames';
import { Component, Fragment } from '@wordpress/element';
import { debounce } from 'lodash';
import Gridicon from 'gridicons';
import { InspectorControls } from '@wordpress/editor';
import { PanelBody, Placeholder, Spinner } from '@wordpress/components';
import {
Disabled,
PanelBody,
} from '@wordpress/components';
import { InspectorControls, ServerSideRender } from '@wordpress/editor';
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 ProductCategoryControl from '../../components/product-category-control';
import ProductPreview from '../../components/product-preview';
/**
* Component to handle edit mode of "Best Selling Products".
*/
class ProductBestSellersBlock extends Component {
constructor() {
super( ...arguments );
this.state = {
products: [],
loaded: false,
};
this.debouncedGetProducts = debounce( this.getProducts.bind( this ), 200 );
}
componentDidMount() {
this.getProducts();
}
componentDidUpdate( prevProps ) {
const hasChange = [ 'categories', 'catOperator', 'columns', 'rows' ].reduce(
( acc, key ) => {
return acc || prevProps.attributes[ key ] !== this.props.attributes[ key ];
},
false
);
if ( hasChange ) {
this.debouncedGetProducts();
}
}
getProducts() {
apiFetch( {
path: addQueryArgs(
'/wc-blocks/v1/products',
getQuery( this.props.attributes, this.props.name )
),
} )
.then( ( products ) => {
this.setState( { products, loaded: true } );
} )
.catch( () => {
this.setState( { products: [], loaded: true } );
} );
}
getInspectorControls() {
const { attributes, setAttributes } = this.props;
const {
@ -121,44 +76,17 @@ class ProductBestSellersBlock extends Component {
}
render() {
const { columns, contentVisibility } = this.props.attributes;
const { loaded, products = [] } = this.state;
const classes = classnames( {
'wc-block-products-grid': true,
'wc-block-best-selling-products': 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 } = this.props;
return (
<Fragment>
{ this.getInspectorControls() }
<div className={ classes }>
{ products.length ? (
products.map( ( product ) => (
<ProductPreview product={ product } key={ product.id } />
) )
) : (
<Placeholder
icon={ <Gridicon icon="stats-up-alt" /> }
label={ __(
'Best Selling Products',
'woo-gutenberg-products-block'
) }
>
{ ! loaded ? (
<Spinner />
) : (
__( 'No products found.', 'woo-gutenberg-products-block' )
) }
</Placeholder>
) }
</div>
<Disabled>
<ServerSideRender
block="woocommerce/product-best-sellers"
attributes={ attributes }
/>
</Disabled>
</Fragment>
);
}

View File

@ -2,17 +2,15 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import classnames from 'classnames';
import { createBlock, registerBlockType } from '@wordpress/blocks';
import { without } from 'lodash';
import Gridicon from 'gridicons';
import { RawHTML } from '@wordpress/element';
/**
* Internal dependencies
*/
import Block from './block';
import getShortcode from '../../utils/get-shortcode';
import { deprecatedConvertToShortcode } from '../../utils/deprecations';
import sharedAttributes, { sharedAttributeBlockTypes } from '../../utils/shared-attributes';
registerBlockType( 'woocommerce/product-best-sellers', {
@ -33,6 +31,7 @@ registerBlockType( 'woocommerce/product-best-sellers', {
attributes: {
...sharedAttributes,
},
transforms: {
from: [
{
@ -46,6 +45,14 @@ registerBlockType( 'woocommerce/product-best-sellers', {
],
},
deprecated: [
{
// Deprecate shortcode save method in favor of dynamic rendering.
attributes: sharedAttributes,
save: deprecatedConvertToShortcode( 'woocommerce/product-best-sellers' ),
},
],
/**
* Renders and manages the block.
*/
@ -53,29 +60,7 @@ registerBlockType( 'woocommerce/product-best-sellers', {
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/product-best-sellers' ) }
</RawHTML>
);
save() {
return null;
},
} );

View File

@ -192,9 +192,11 @@ class WGPB_Block_Library {
register_block_type(
'woocommerce/product-best-sellers',
array(
'editor_script' => 'wc-product-best-sellers',
'editor_style' => 'wc-block-editor',
'style' => 'wc-block-style',
'render_callback' => array( __CLASS__, 'render_product_best_sellers' ),
'editor_script' => 'wc-product-best-sellers',
'editor_style' => 'wc-block-editor',
'style' => 'wc-block-style',
'attributes' => self::get_shared_attributes(),
)
);
register_block_type(
@ -440,6 +442,20 @@ class WGPB_Block_Library {
return $block->render();
}
/**
* Best Selling Products: 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_product_best_sellers( $attributes, $content ) {
require_once dirname( __FILE__ ) . '/class-wgpb-block-product-best-sellers.php';
$block = new WGPB_Block_Product_Best_Sellers( $attributes, $content );
return $block->render();
}
/**
* Hand-picked Products: Include and render the dynamic block.
*

View File

@ -0,0 +1,35 @@
<?php
/**
* Display the Best Selling Products 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 best selling products for display.
*/
class WGPB_Block_Product_Best_Sellers extends WGPB_Block_Grid_Base {
/**
* Block name.
*
* @var string
*/
protected $block_name = 'product-best-sellers';
/**
* Set args specific to this block
*
* @param array $query_args Query args.
*/
protected function set_block_query_args( &$query_args ) {
$query_args['meta_key'] = 'total_sales'; // phpcs:ignore WordPress.DB.SlowDBQuery
$query_args['order'] = 'DESC';
$query_args['orderby'] = 'meta_value_num';
}
}