Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Experimental] Add: QueryFilters class to calculate filter data for product queries #42811

Merged
merged 20 commits into from
Jan 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const getUrl = ( context: PriceFilterContext ) => {
searchParams.delete( 'min_price' );
}

if ( maxPrice < maxRange ) {
if ( maxPrice < maxRange && maxPrice > minRange ) {
searchParams.set( 'max_price', maxPrice.toString() );
} else {
searchParams.delete( 'max_price' );
Expand Down
4 changes: 4 additions & 0 deletions plugins/woocommerce/changelog/42811-add-collection-filterer
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: add
Comment: Add `QueryFilters` class to calculate filter data for product queries. Update new interactive filter blocks to use `QueryFilters` instead of internal REST API requests.

44 changes: 0 additions & 44 deletions plugins/woocommerce/src/Blocks/BlockTypes/ClassicTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,12 @@ class ClassicTemplate extends AbstractDynamicBlock {
*/
protected $api_version = '2';

const FILTER_PRODUCTS_BY_STOCK_QUERY_PARAM = 'filter_stock_status';

/**
* Initialize this block.
*/
protected function initialize() {
parent::initialize();
add_filter( 'render_block', array( $this, 'add_alignment_class_to_wrapper' ), 10, 2 );
add_filter( 'woocommerce_product_query_meta_query', array( $this, 'filter_products_by_stock' ) );
add_action( 'enqueue_block_assets', array( $this, 'enqueue_block_assets' ) );
}

Expand Down Expand Up @@ -377,47 +374,6 @@ public function add_alignment_class_to_wrapper( string $content, array $block )
return preg_replace( $pattern_get_class, '$0 ' . $align_class_and_style['class'], $content, 1 );
}


/**
* Filter products by stock status when as query param there is "filter_stock_status"
*
* @param array $meta_query Meta query.
* @return array
*/
public function filter_products_by_stock( $meta_query ) {
global $wp_query;

if (
is_admin() ||
! $wp_query->is_main_query() ||
! isset( $_GET[ self::FILTER_PRODUCTS_BY_STOCK_QUERY_PARAM ] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
) {
return $meta_query;
}

$stock_status = array_keys( wc_get_product_stock_status_options() );
$values = sanitize_text_field( wp_unslash( $_GET[ self::FILTER_PRODUCTS_BY_STOCK_QUERY_PARAM ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended

$values_to_array = explode( ',', $values );

$filtered_values = array_filter(
$values_to_array,
function( $value ) use ( $stock_status ) {
return in_array( $value, $stock_status, true );
}
);

if ( ! empty( $filtered_values ) ) {

$meta_query[] = array(
'key' => '_stock_status',
'value' => $filtered_values,
'compare' => 'IN',
);
}
return $meta_query;
}

/**
* Get the frontend style handle for this block type.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,6 @@ protected function render( $attributes, $content, $block ) {
*/
$active_filters = apply_filters( 'collection_active_filters_data', array(), $this->get_filter_query_params( $query_id ) );

if ( empty( $active_filters ) ) {
return '';
}

$context = array(
'queryId' => $query_id,
'params' => array_keys( $this->get_filter_query_params( $query_id ) ),
Expand All @@ -69,21 +65,23 @@ protected function render( $attributes, $content, $block ) {
?>

<div <?php echo $wrapper_attributes; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
<?php echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<ul class="wc-block-active-filters__list %3$s">
<?php foreach ( $active_filters as $filter ) : ?>
<li>
<span class="wc-block-active-filters__list-item-type"><?php echo esc_html( $filter['type'] ); ?>: </span>
<ul>
<?php $this->render_items( $filter['items'], $attributes['displayStyle'] ); ?>
</ul>
</li>
<?php endforeach; ?>
</ul>
<button class="wc-block-active-filters__clear-all" data-wc-on--click="actions.clearAll">
<span aria-hidden="true"><?php echo esc_html__( 'Clear All', 'woocommerce' ); ?></span>
<span class="screen-reader-text"><?php echo esc_html__( 'Clear All Filters', 'woocommerce' ); ?></span>
</button>
<?php if ( ! empty( $active_filters ) ) : ?>
<?php echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<ul class="wc-block-active-filters__list %3$s">
<?php foreach ( $active_filters as $filter ) : ?>
<li>
<span class="wc-block-active-filters__list-item-type"><?php echo esc_html( $filter['type'] ); ?>: </span>
<ul>
<?php $this->render_items( $filter['items'], $attributes['displayStyle'] ); ?>
</ul>
</li>
<?php endforeach; ?>
</ul>
<button class="wc-block-active-filters__clear-all" data-wc-on--click="actions.clearAll">
<span aria-hidden="true"><?php echo esc_html__( 'Clear All', 'woocommerce' ); ?></span>
<span class="screen-reader-text"><?php echo esc_html__( 'Clear All Filters', 'woocommerce' ); ?></span>
</button>
<?php endif; ?>
</div>

<?php
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,25 +128,33 @@ function( $term ) use ( $product_attribute ) {
* @return string Rendered block type output.
*/
protected function render( $attributes, $content, $block ) {
if (
is_admin() ||
empty( $block->context['collectionData']['attribute_counts'] ) ||
empty( $attributes['attributeId'] )
) {
// don't render if its admin, or ajax in progress.
if ( is_admin() || wp_doing_ajax() || empty( $attributes['attributeId'] ) ) {
return '';
}

$product_attribute = wc_get_attribute( $attributes['attributeId'] );

$attribute_counts = array_reduce(
$block->context['collectionData']['attribute_counts'],
$attribute_counts = array_reduce(
$block->context['collectionData']['attribute_counts'] ?? [],
function( $acc, $count ) {
$acc[ $count['term'] ] = $count['count'];
return $acc;
},
[]
);

if ( empty( $attribute_counts ) ) {
return sprintf(
'<div %s></div>',
get_block_wrapper_attributes(
array(
'data-wc-interactive' => wp_json_encode( array( 'namespace' => 'woocommerce/collection-attribute-filter' ) ),
)
),
);

}

$attribute_terms = get_terms(
array(
'taxonomy' => $product_attribute->slug,
Expand Down Expand Up @@ -199,6 +207,10 @@ function( $term ) use ( $attribute_counts, $selected_terms ) {
* @param bool $attributes Block attributes.
*/
private function render_attribute_dropdown( $options, $attributes ) {
if ( empty( $options ) ) {
return '';
}

$text_color_class_and_style = StyleAttributesUtils::get_text_color_class_and_style( $attributes );
$text_color = $text_color_class_and_style['value'] ?? '';

Expand Down Expand Up @@ -235,6 +247,10 @@ private function render_attribute_dropdown( $options, $attributes ) {
* @param bool $attributes Block attributes.
*/
private function render_attribute_list( $options, $attributes ) {
if ( empty( $options ) ) {
return '';
}

$output = '<ul class="wc-block-checkbox-list wc-block-components-checkbox-list wc-block-stock-filter-list">';
foreach ( $options as $option ) {
$output .= $this->render_list_item_template( $option, $attributes['showCounts'] );
Expand Down