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

Commit

Permalink
Making filter block contextual on the front end (#10919)
Browse files Browse the repository at this point in the history
  • Loading branch information
dinhtungdu authored Oct 9, 2023
1 parent 7b9b79b commit 92076d1
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 22 deletions.
1 change: 1 addition & 0 deletions assets/js/blocks/collection-filters/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"html": false,
"reusable": false
},
"usesContext": [ "query" ],
"ancestor": [ "woocommerce/product-collection" ],
"apiVersion": 2,
"$schema": "https://schemas.wp.org/trunk/block.json"
Expand Down
136 changes: 114 additions & 22 deletions src/BlockTypes/CollectionFilters.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public function modify_inner_blocks_context( $context, $parsed_block, $parent_bl
$context['isCollectionFiltersInnerBlock'] = true;

if (
isset( $parsed_block['blockName'] ) ||
isset( $parsed_block['blockName'] ) &&
in_array( $parsed_block['blockName'], $this->collection_data_params_mapping, true )
) {
$context['collectionData'] = $this->current_response;
Expand All @@ -148,28 +148,27 @@ public function modify_inner_blocks_context( $context, $parsed_block, $parent_bl
* @return array
*/
private function get_aggregated_collection_data( $block ) {
$collection_data_params = array();
$inner_blocks = array();
$inner_blocks = $this->get_inner_blocks_recursive( $block->inner_blocks );

do {
$inner_blocks = array_merge(
$this->get_inner_blocks_recursive( $block->inner_blocks->current() ),
$inner_blocks
);
$block->inner_blocks->next();
} while ( $block->inner_blocks->valid() );

foreach ( $this->collection_data_params_mapping as $key => $block_name ) {
$collection_data_params[ $key ] = ( in_array( $block_name, $inner_blocks, true ) );
}
$collection_data_params = array_map(
function( $block_name ) use ( $inner_blocks ) {
return in_array( $block_name, $inner_blocks, true );
},
$this->collection_data_params_mapping
);

if ( empty( array_filter( $collection_data_params ) ) ) {
return array();
}

$products_params = $this->get_formatted_products_params( $block->context['query'] );

$response = Package::container()->get( Hydration::class )->get_rest_api_response_data(
add_query_arg(
$collection_data_params,
array_merge(
$products_params,
$collection_data_params,
),
'/wc/store/v1/products/collection-data'
)
);
Expand All @@ -184,18 +183,111 @@ private function get_aggregated_collection_data( $block ) {
/**
* Get all inner blocks recursively.
*
* @param WP_Block $block The block to get inner blocks from.
* @param array $results The results array.
* @param WP_Block_List $inner_blocks The block to get inner blocks from.
* @param array $results The results array.
*
* @return array
*/
private function get_inner_blocks_recursive( $block, $results = array() ) {
$results[] = $block->name;
if ( ! empty( $block->inner_blocks ) ) {
foreach ( $block->inner_blocks as $inner_block ) {
$results = $this->get_inner_blocks_recursive( $inner_block, $results );
private function get_inner_blocks_recursive( $inner_blocks, &$results = array() ) {
if ( is_a( $inner_blocks, 'WP_Block_List' ) ) {
foreach ( $inner_blocks as $inner_block ) {
$results[] = $inner_block->name;
$this->get_inner_blocks_recursive(
$inner_block->inner_blocks,
$results
);
}
}

return $results;
}

/**
* Get formatted products params for ProductCollectionData route from the
* query context.
*
* @param array $query The query context.
* @return array
*/
private function get_formatted_products_params( $query ) {
$params = array();

if ( empty( $query['isProductCollectionBlock'] ) ) {
return $params;
}

/**
* The following params can be passed directly to Store API endpoints.
*/
$shared_params = array( 'exclude', 'offset', 'order', 'serach' );
array_walk(
$shared_params,
function( $key ) use ( $query, &$params ) {
$params[ $key ] = $query[ $key ] ?? '';
}
);

/**
* The following params just need to transform the key, their value can
* be passed as it is to the Store API.
*/
$mapped_params = array(
'orderBy' => 'orderby',
'pages' => 'page',
'parents' => 'parent',
'perPage' => 'per_page',
'woocommerceStockStatus' => 'stock_status',
'woocommerceOnSale' => 'on_sale',
'woocommerceHandPickedProducts' => 'include',
);
array_walk(
$mapped_params,
function( $mapped_key, $original_key ) use ( $query, &$params ) {
$params[ $mapped_key ] = $query[ $original_key ] ?? '';
}
);

/**
* The value of taxQuery and woocommerceAttributes need additional
* transformation to the shape that Store API accepts.
*/
$taxonomy_mapper = function( $key ) {
$mapping = array(
'product_tag' => 'tag',
'product_cat' => 'category',
);

return $mapping[ $key ] ?? '_unstable_tax_' . $key;
};

if ( is_array( $query['taxQuery'] ) ) {
array_walk(
$query['taxQuery'],
function( $terms, $taxonomy ) use ( $taxonomy_mapper, &$params ) {
$params[ $taxonomy_mapper( $taxonomy ) ] = implode( ',', $terms );
}
);
}

if ( is_array( $query['woocommerceAttributes'] ) ) {
array_walk(
$query['woocommerceAttributes'],
function( $attribute ) use ( &$params ) {
$params['attributes'][] = array(
'attribute' => $attribute['taxonomy'],
'term_id' => $attribute['termId'],
);
}
);
}

/**
* Product Collection determines the product visibility based on stock
* statuses. We need to pass the catalog_visibility param to the Store
* API to make sure the product visibility is correct.
*/
$params['catalog_visibility'] = is_search() ? 'catalog' : 'visible';

return array_filter( $params );
}
}

0 comments on commit 92076d1

Please sign in to comment.