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

Making filter block contextual on the front end #10919

Merged
merged 25 commits into from
Oct 9, 2023
Merged

Conversation

dinhtungdu
Copy link
Member

@dinhtungdu dinhtungdu commented Sep 12, 2023

What

Partial fixes #10985

Why

Testing Instructions

Please consider any edge cases this change may have, and also other areas of the product this may impact.

  1. Update the $colleciton_data_params_mapping property as follow
	private $collection_data_params_mapping = array(
		'calculate_price_range'         => 'woocommerce/price-filter',
		'calculate_stock_status_counts' => 'woocommerce/stock-filter',
		'calculate_attribute_counts'    => 'woocommerce/attribute-filter',
		'calculate_rating_counts'       => 'woocommerce/rating-filter',
	);
  1. Edit line 182-184 of CollectionFilter.php file:
		if ( ! empty( $response['body'] ) ) {
			error_log( print_r( $response['body'], true ) );
			return $response['body'];
		}
  1. On a new page, add the Product Collection block.
  2. Apply some Filter settings, like Stock status, Product Attribute, Taxonomies.
  3. Then add Collection Filters block to the block above.
  4. Add Price filter, Stock filter, to the Collection Filters block.
  5. Visit the page on the front end.
  6. Check the log, see the data includes the correct price range that matches the Product Collection block's results.
  • Do not include in the Testing Notes
  • Should be tested by the development team exclusively

Screenshots or screencast

Before After

WooCommerce Visibility

Required:

  • WooCommerce Core
  • Feature plugin
  • Experimental
  • N/A

Checklist

Required:

  • This PR has either a [type] label or a [skip-changelog] label.
  • This PR is assigned to a milestone.

Conditional:

  • This PR has a changelog description (if [skip-changelog] label is not present).
  • This PR adds/removes a feature flag & I've updated this doc.
  • This PR adds/removes an experimental interfaces, and I've updated this doc.
  • This PR has been accessibility tested.
  • This PR has had any necessary documentation added/updated.

Changelog

Add suggested changelog entry here.

@dinhtungdu dinhtungdu self-assigned this Sep 12, 2023
@github-actions
Copy link
Contributor

handle other product taxonomies

handle other product taxonomies


// @todo handle other product taxonomies
unset( $query['taxQuery'] );
}
foreach ( $query as $key => $value ) {
if ( isset( $this->product_params_mapping[ $key ] ) ) {
$params[ $this->product_params_mapping[ $key ] ] = $value;
} else {
$params[ $key ] = $value;
}
}

🚀 This comment was generated by the automations bot based on a todo comment in e413a30 in #10919. cc @dinhtungdu

@dinhtungdu dinhtungdu added the skip-changelog PRs that you don't want to appear in the changelog. label Sep 12, 2023
@github-actions
Copy link
Contributor

github-actions bot commented Sep 12, 2023

The release ZIP for this PR is accessible via:

https://wcblocks.wpcomstaging.com/wp-content/uploads/woocommerce-gutenberg-products-block-10919.zip

Script Dependencies Report

There is no changed script dependency between this branch and trunk.

This comment was automatically generated by the ./github/compare-assets action.

TypeScript Errors Report

  • Files with errors: 521
  • Total errors: 2320

🎉 🎉 This PR does not introduce new TS errors.

comments-aggregator

@github-actions
Copy link
Contributor

github-actions bot commented Sep 12, 2023

Size Change: +16 B (0%)

Total Size: 1.47 MB

Filename Size Change
build/collection-filters.js 1.63 kB +16 B (+1%)
ℹ️ View Unchanged
Filename Size
build/1796-frontend.js 23.2 kB
build/4124-frontend.js 23.9 kB
build/7138-frontend.js 24.2 kB
build/8280-frontend.js 8.48 kB
build/active-filters-frontend.js 7.03 kB
build/active-filters-rtl.css 2 kB
build/active-filters-wrapper-frontend.js 7.39 kB
build/active-filters-wrapper-rtl.css 1.86 kB
build/active-filters-wrapper.css 1.86 kB
build/active-filters.css 2 kB
build/active-filters.js 6.5 kB
build/add-to-cart-form-rtl.css 375 B
build/add-to-cart-form.css 373 B
build/all-products-frontend.js 9.88 kB
build/all-products-rtl.css 4.56 kB
build/all-products.css 4.56 kB
build/all-products.js 40.1 kB
build/all-reviews-rtl.css 1.79 kB
build/all-reviews.css 1.79 kB
build/all-reviews.js 7.84 kB
build/attribute-filter-frontend.js 20.4 kB
build/attribute-filter-rtl.css 4.16 kB
build/attribute-filter-wrapper-frontend.js 21.6 kB
build/attribute-filter-wrapper-rtl.css 1.65 kB
build/attribute-filter-wrapper.css 1.65 kB
build/attribute-filter.css 4.15 kB
build/attribute-filter.js 11.7 kB
build/base-components-stock-filter-wrapper~attribute-filter-wrapper~rating-filter-wrapper-style.scss-rtl.css 3.12 kB
build/base-components-stock-filter-wrapper~attribute-filter-wrapper~rating-filter-wrapper-style.scss.css 3.12 kB
build/blocks-checkout.js 33.9 kB
build/breadcrumbs-rtl.css 234 B
build/breadcrumbs.css 234 B
build/breadcrumbs.js 2.03 kB
build/cart-blocks/cart-accepted-payment-methods-frontend.js 1.4 kB
build/cart-blocks/cart-accepted-payment-methods-style.js 153 B
build/cart-blocks/cart-cross-sells-frontend.js 268 B
build/cart-blocks/cart-cross-sells-products-frontend.js 10.9 kB
build/cart-blocks/cart-cross-sells-products-style.js 153 B
build/cart-blocks/cart-cross-sells-style.js 269 B
build/cart-blocks/cart-express-payment-frontend.js 5.36 kB
build/cart-blocks/cart-express-payment-style.js 155 B
build/cart-blocks/cart-items-frontend.js 273 B
build/cart-blocks/cart-items-style.js 240 B
build/cart-blocks/cart-line-items-frontend.js 14.4 kB
build/cart-blocks/cart-line-items-style.js 153 B
build/cart-blocks/cart-order-summary-frontend.js 3.5 kB
build/cart-blocks/cart-order-summary-style.js 341 B
build/cart-blocks/cart-totals-frontend.js 290 B
build/cart-blocks/cart-totals-style.js 253 B
build/cart-blocks/empty-cart-frontend.js 367 B
build/cart-blocks/empty-cart-style.js 365 B
build/cart-blocks/filled-cart-frontend.js 605 B
build/cart-blocks/filled-cart-style.js 333 B
build/cart-blocks/order-summary-coupon-form-frontend.js 3.88 kB
build/cart-blocks/order-summary-coupon-form-style.js 155 B
build/cart-blocks/order-summary-discount-frontend.js 3.98 kB
build/cart-blocks/order-summary-discount-style.js 155 B
build/cart-blocks/order-summary-fee-frontend.js 288 B
build/cart-blocks/order-summary-fee-style.js 153 B
build/cart-blocks/order-summary-heading-frontend.js 346 B
build/cart-blocks/order-summary-heading-style.js 351 B
build/cart-blocks/order-summary-shipping-frontend.js 3.53 kB
build/cart-blocks/order-summary-shipping-style.js 204 B
build/cart-blocks/order-summary-subtotal-frontend.js 291 B
build/cart-blocks/order-summary-subtotal-style.js 154 B
build/cart-blocks/order-summary-taxes-frontend.js 456 B
build/cart-blocks/order-summary-taxes-style.js 202 B
build/cart-blocks/proceed-to-checkout-frontend.js 7.59 kB
build/cart-blocks/proceed-to-checkout-style.js 1.08 kB
build/cart-frontend.js 28.9 kB
build/cart-rtl.css 9.92 kB
build/cart.css 9.91 kB
build/cart.js 39.9 kB
build/catalog-sorting-rtl.css 259 B
build/catalog-sorting.css 259 B
build/catalog-sorting.js 1.69 kB
build/checkout-blocks/actions-frontend.js 8.11 kB
build/checkout-blocks/actions-style.js 1.01 kB
build/checkout-blocks/billing-address-frontend.js 9.76 kB
build/checkout-blocks/billing-address-style.js 573 B
build/checkout-blocks/contact-information-frontend.js 2.08 kB
build/checkout-blocks/contact-information-style.js 651 B
build/checkout-blocks/express-payment-frontend.js 5.89 kB
build/checkout-blocks/fields-frontend.js 297 B
build/checkout-blocks/fields-style.js 271 B
build/checkout-blocks/order-note-frontend.js 1.14 kB
build/checkout-blocks/order-summary-cart-items-frontend.js 11.8 kB
build/checkout-blocks/order-summary-cart-items-style.js 153 B
build/checkout-blocks/order-summary-coupon-form-frontend.js 3.97 kB
build/checkout-blocks/order-summary-coupon-form-style.js 155 B
build/checkout-blocks/order-summary-discount-frontend.js 4.06 kB
build/checkout-blocks/order-summary-discount-style.js 154 B
build/checkout-blocks/order-summary-fee-frontend.js 291 B
build/checkout-blocks/order-summary-fee-style.js 155 B
build/checkout-blocks/order-summary-frontend.js 3.58 kB
build/checkout-blocks/order-summary-shipping-frontend.js 3.53 kB
build/checkout-blocks/order-summary-shipping-style.js 154 B
build/checkout-blocks/order-summary-style.js 341 B
build/checkout-blocks/order-summary-subtotal-frontend.js 289 B
build/checkout-blocks/order-summary-subtotal-style.js 155 B
build/checkout-blocks/order-summary-taxes-frontend.js 456 B
build/checkout-blocks/order-summary-taxes-style.js 201 B
build/checkout-blocks/payment-frontend.js 15.6 kB
build/checkout-blocks/payment-style.js 504 B
build/checkout-blocks/pickup-options-frontend.js 17.4 kB
build/checkout-blocks/pickup-options-style.js 476 B
build/checkout-blocks/shipping-address-frontend.js 9.74 kB
build/checkout-blocks/shipping-address-style.js 514 B
build/checkout-blocks/shipping-method-frontend.js 2.65 kB
build/checkout-blocks/shipping-method-style.js 1.41 kB
build/checkout-blocks/shipping-methods-frontend.js 25.3 kB
build/checkout-blocks/shipping-methods-style.js 450 B
build/checkout-blocks/terms-frontend.js 1.55 kB
build/checkout-blocks/terms-style.js 1.02 kB
build/checkout-blocks/totals-frontend.js 334 B
build/checkout-blocks/totals-style.js 301 B
build/checkout-frontend.js 30.5 kB
build/checkout-rtl.css 9.4 kB
build/checkout.css 9.39 kB
build/checkout.js 42.8 kB
build/classic-shortcode-rtl.css 242 B
build/classic-shortcode.css 241 B
build/classic-shortcode.js 4.4 kB
build/customer-account-rtl.css 410 B
build/customer-account.css 409 B
build/customer-account.js 3.17 kB
build/featured-category-rtl.css 974 B
build/featured-category.css 973 B
build/featured-category.js 13.6 kB
build/featured-product-rtl.css 1.02 kB
build/featured-product.css 1.02 kB
build/featured-product.js 13.7 kB
build/filter-wrapper-frontend.js 14.5 kB
build/filter-wrapper-rtl.css 378 B
build/filter-wrapper.css 378 B
build/filter-wrapper.js 2.37 kB
build/handpicked-products.js 7.22 kB
build/legacy-template-rtl.css 240 B
build/legacy-template.css 240 B
build/legacy-template.js 7.72 kB
build/mini-cart-component-frontend.js 30.7 kB
build/mini-cart-contents-block/cart-button-frontend.js 1.86 kB
build/mini-cart-contents-block/cart-button-style.js 1.23 kB
build/mini-cart-contents-block/checkout-button-frontend.js 1.95 kB
build/mini-cart-contents-block/checkout-button-style.js 1.43 kB
build/mini-cart-contents-block/empty-cart-frontend.js 374 B
build/mini-cart-contents-block/empty-cart-style.js 378 B
build/mini-cart-contents-block/filled-cart-frontend.js 284 B
build/mini-cart-contents-block/filled-cart-style.js 288 B
build/mini-cart-contents-block/footer-frontend.js 3.87 kB
build/mini-cart-contents-block/footer-style.js 1.95 kB
build/mini-cart-contents-block/items-frontend.js 247 B
build/mini-cart-contents-block/items-style.js 251 B
build/mini-cart-contents-block/products-table-frontend.js 13.8 kB
build/mini-cart-contents-block/shopping-button-frontend.js 501 B
build/mini-cart-contents-block/shopping-button-style.js 361 B
build/mini-cart-contents-block/title-frontend.js 2.04 kB
build/mini-cart-contents-block/title-items-counter-frontend.js 1.74 kB
build/mini-cart-contents-block/title-items-counter-style.js 1.2 kB
build/mini-cart-contents-block/title-label-frontend.js 1.68 kB
build/mini-cart-contents-block/title-label-style.js 1.14 kB
build/mini-cart-contents-block/title-style.js 1.38 kB
build/mini-cart-contents-rtl.css 3.23 kB
build/mini-cart-contents.css 3.21 kB
build/mini-cart-contents.js 16.1 kB
build/mini-cart-frontend.js 2.25 kB
build/mini-cart-rtl.css 2.44 kB
build/mini-cart.css 2.45 kB
build/mini-cart.js 5.98 kB
build/order-confirmation-additional-information-rtl.css 365 B
build/order-confirmation-additional-information.css 364 B
build/order-confirmation-additional-information.js 1.57 kB
build/order-confirmation-billing-address-rtl.css 398 B
build/order-confirmation-billing-address.css 397 B
build/order-confirmation-billing-address.js 1.55 kB
build/order-confirmation-billing-wrapper.js 1.5 kB
build/order-confirmation-downloads-rtl.css 478 B
build/order-confirmation-downloads-wrapper.js 1.57 kB
build/order-confirmation-downloads.css 479 B
build/order-confirmation-downloads.js 1.9 kB
build/order-confirmation-shipping-address-rtl.css 399 B
build/order-confirmation-shipping-address.css 397 B
build/order-confirmation-shipping-address.js 1.55 kB
build/order-confirmation-shipping-wrapper.js 1.5 kB
build/order-confirmation-status-rtl.css 280 B
build/order-confirmation-status.css 280 B
build/order-confirmation-status.js 1.54 kB
build/order-confirmation-summary-rtl.css 461 B
build/order-confirmation-summary.css 460 B
build/order-confirmation-summary.js 1.75 kB
build/order-confirmation-totals-rtl.css 595 B
build/order-confirmation-totals-wrapper.js 1.79 kB
build/order-confirmation-totals.css 594 B
build/order-confirmation-totals.js 2.16 kB
build/packages-style-rtl.css 3.59 kB
build/packages-style.css 3.59 kB
build/page-content-wrapper.js 1.85 kB
build/price-filter-frontend.js 13.1 kB
build/price-filter-rtl.css 2.68 kB
build/price-filter-wrapper-frontend.js 13.3 kB
build/price-filter-wrapper-rtl.css 2.54 kB
build/price-filter-wrapper.css 2.54 kB
build/price-filter.css 2.68 kB
build/price-filter.js 7.77 kB
build/price-format.js 913 B
build/product-add-to-cart-frontend.js 8.11 kB
build/product-add-to-cart-rtl.css 1.38 kB
build/product-add-to-cart.css 1.38 kB
build/product-add-to-cart.js 8.35 kB
build/product-average-rating-frontend.js 1.88 kB
build/product-average-rating.js 1.4 kB
build/product-best-sellers.js 7.04 kB
build/product-button-frontend.js 4.93 kB
build/product-button-interactivity-frontend.js 8.48 kB
build/product-button-rtl.css 1.14 kB
build/product-button.css 1.14 kB
build/product-button.js 4.64 kB
build/product-categories-rtl.css 654 B
build/product-categories.css 654 B
build/product-categories.js 2.58 kB
build/product-category.js 7.97 kB
build/product-collection.js 13.6 kB
build/product-details-rtl.css 397 B
build/product-details.css 394 B
build/product-gallery-frontend.js 392 B
build/product-gallery-large-image-frontend.js 416 B
build/product-gallery-large-image-next-previous.js 4.14 kB
build/product-gallery-large-image.js 2.36 kB
build/product-gallery-pager.js 3.39 kB
build/product-gallery-rtl.css 1.04 kB
build/product-gallery-thumbnails.js 3.81 kB
build/product-gallery.css 1.04 kB
build/product-gallery.js 9.31 kB
build/product-image-frontend.js 2.89 kB
build/product-image-gallery-rtl.css 307 B
build/product-image-gallery.css 306 B
build/product-image-rtl.css 997 B
build/product-image.css 995 B
build/product-image.js 2.68 kB
build/product-new.js 7.3 kB
build/product-on-sale.js 7.29 kB
build/product-price-frontend.js 8.1 kB
build/product-price-rtl.css 678 B
build/product-price.css 677 B
build/product-price.js 2.65 kB
build/product-query-rtl.css 350 B
build/product-query.css 349 B
build/product-query.js 11.4 kB
build/product-rating-counter-frontend.js 2.19 kB
build/product-rating-counter.js 1.71 kB
build/product-rating-frontend.js 2.53 kB
build/product-rating-rtl.css 247 B
build/product-rating-stars-frontend.js 2.43 kB
build/product-rating-stars-rtl.css 899 B
build/product-rating-stars.css 900 B
build/product-rating-stars.js 1.95 kB
build/product-rating.css 246 B
build/product-rating.js 2.05 kB
build/product-results-count-rtl.css 230 B
build/product-results-count.css 230 B
build/product-results-count.js 1.65 kB
build/product-reviews-rtl.css 458 B
build/product-reviews.css 458 B
build/product-sale-badge-frontend.js 2.01 kB
build/product-sale-badge-rtl.css 438 B
build/product-sale-badge.css 437 B
build/product-sale-badge.js 1.69 kB
build/product-search-rtl.css 419 B
build/product-search.css 417 B
build/product-search.js 2.6 kB
build/product-sku-frontend.js 2.02 kB
build/product-sku-rtl.css 240 B
build/product-sku.css 239 B
build/product-sku.js 1.53 kB
build/product-stock-indicator-frontend.js 2.19 kB
build/product-stock-indicator-rtl.css 232 B
build/product-stock-indicator.css 232 B
build/product-stock-indicator.js 1.71 kB
build/product-summary-frontend.js 2.35 kB
build/product-summary-rtl.css 549 B
build/product-summary.css 549 B
build/product-summary.js 1.87 kB
build/product-tag.js 7.5 kB
build/product-template-rtl.css 423 B
build/product-template.css 422 B
build/product-template.js 2.8 kB
build/product-title-frontend.js 2.31 kB
build/product-title-rtl.css 693 B
build/product-title.css 694 B
build/product-title.js 2.04 kB
build/product-top-rated.js 7.57 kB
build/products-by-attribute.js 8.02 kB
build/rating-filter-frontend.js 19.3 kB
build/rating-filter-rtl.css 4.22 kB
build/rating-filter-wrapper-frontend.js 20.3 kB
build/rating-filter-wrapper-rtl.css 1.73 kB
build/rating-filter-wrapper.css 1.73 kB
build/rating-filter.css 4.21 kB
build/rating-filter.js 6.33 kB
build/reviews-by-category-rtl.css 1.79 kB
build/reviews-by-category.css 1.79 kB
build/reviews-by-category.js 11.4 kB
build/reviews-by-product-rtl.css 1.79 kB
build/reviews-by-product.css 1.79 kB
build/reviews-by-product.js 12.7 kB
build/reviews-frontend.js 6.52 kB
build/single-product-rtl.css 378 B
build/single-product.css 378 B
build/single-product.js 11 kB
build/stock-filter-frontend.js 19.4 kB
build/stock-filter-rtl.css 4.01 kB
build/stock-filter-wrapper-frontend.js 20.5 kB
build/stock-filter-wrapper-rtl.css 1.49 kB
build/stock-filter-wrapper.css 1.49 kB
build/stock-filter.css 4 kB
build/stock-filter.js 6.95 kB
build/store-notices.js 1.67 kB
build/wc-blocks-classic-template-revert-button-style-rtl.css 240 B
build/wc-blocks-classic-template-revert-button-style.css 239 B
build/wc-blocks-classic-template-revert-button.js 1.18 kB
build/wc-blocks-data.js 19.6 kB
build/wc-blocks-editor-style-rtl.css 7.07 kB
build/wc-blocks-editor-style.css 7.07 kB
build/wc-blocks-google-analytics.js 1.16 kB
build/wc-blocks-middleware.js 735 B
build/wc-blocks-registry.js 2.74 kB
build/wc-blocks-rtl.css 2.47 kB
build/wc-blocks-shared-context.js 850 B
build/wc-blocks-shared-hocs.js 1.4 kB
build/wc-blocks-vendors.js 64 kB
build/wc-blocks.css 2.47 kB
build/wc-blocks.js 2.61 kB
build/wc-interactivity.js 10.7 kB
build/wc-payment-method-bacs.js 406 B
build/wc-payment-method-cheque.js 401 B
build/wc-payment-method-cod.js 508 B
build/wc-payment-method-paypal.js 437 B
build/wc-settings.js 2.4 kB
build/wc-shipping-method-pickup-location.js 29.3 kB

compressed-size-action

@dinhtungdu dinhtungdu changed the title Making filter block contextual Making filter block contextual on the front end Sep 18, 2023
@dinhtungdu dinhtungdu marked this pull request as ready for review September 18, 2023 14:09
@woocommercebot woocommercebot requested a review from a team September 18, 2023 14:09
@dinhtungdu dinhtungdu added type: enhancement The issue is a request for an enhancement. block-type: filter blocks Issues related to all of the filter blocks. labels Sep 18, 2023
Copy link
Contributor

@sunyatasattva sunyatasattva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for submitting this! I have some minor comments, let me know what you think.

Comment on lines 222 to 240
$params_mapping = array(
'exclude' => 'exclude',
'offset' => 'offset',
'order' => 'order',
'orderBy' => 'orderby',
'pages' => 'page',
'parents' => 'parent',
'perPage' => 'per_page',
'search' => 'search',
'woocommerceStockStatus' => 'stock_status',
'woocommerceOnSale' => 'on_sale',
'woocommerceHandPickedProducts' => 'include',
);

foreach ( $query as $key => $value ) {
if ( isset( $params_mapping[ $key ] ) ) {
$params[ $params_mapping[ $key ] ] = $value;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mm, I'm not convinced about this… 🤔

I've got two suggestions:

  1. Either let's not put in the params_mapping any param that doesn't require any mapping. The downside of this solution is that we are allowing arbitrary key/value pairs. Probably harmless and, actually, future-proof in a way, but I understand if you want to avoid it.
  2. Second solution would be to have an $accepted_params array which would just be array( 'exclude', 'offset', 'order', … ) and then do:
foreach ( $query as $key => $value ) {
    if ( in_array( $key, $accepted_params ) ) {
       $params[ $key ] = $value;
    }
    
	if ( isset( $params_mapping[ $key ] ) ) {
		$params[ $params_mapping[ $key ] ] = $value;
	}
}

I guess I just don't like strings mapping to themselves haha. I think it would be more explicit and clear to differentiate params that are accepted as is, and params that needs conversion, if you know what I mean.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let my try to convince you...

  1. The reason I create a list of param here is, when devs look at this method, they'll know exactly what is being passed to the API, they don't have to jump to other classes to look for this information. When we update the Product Collection query, yes we have to update it here, but I consider it as the trade-off for explicitness.
  2. The logic I'm using here is, I consider there are 2 types of param: ones don't need transform the value and ones need. Breaking the first type into two types increase the complexity of the logic IMO. In the example you shared above, there is an additional condition, there is also the need of another variable declaration for $accepted_params as well.

I would rewrite the loop like this to be more explicit:

		foreach ( $params_mapping as $key => $mapped_key ) {
			if ( isset( $query[ $key ] ) ) {
				$params[ $mapped_key ] = $query[ $key ];
			}
		}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: I updated this PR to do so.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I create a list of param here is, when devs look at this method, they'll know exactly what is being passed to the API […]

For me, that's why I was suggesting it. Because at first glance it was confusing to see: I was expecting params_mapping to be params that require some mapping! :D Then I started to notice that some of them don't require any transformation, and that was the first surprise. The second surprise was when I noticed some of them don't require almost any transformation, but just a bit (e.g. parentsparent), and I had confused this latter type for the former type. So, I had two moments of confusion.

The logic I'm using here is, I consider there are 2 types of param: ones don't need transform the value and ones need.

For me there are three types:

  1. Params that are passed as is.
  2. Params that require a key mapping.
  3. Params that require a value mapping.

So, personally, I remain unconvinced 🙃 but Code Review is a place for me to bounce ideas and this is not a big deal for me. So if you feel strongly about your approach, I'm totally fine with it: it's still very good code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me try with three param types and see how the code goes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sunyatasattva can you please take a look at dadcb89 (#10919)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me, if you're happy with it. If you're not convinced, feel free to revert. The comments are a nice add!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sunyatasattva I'm happy with using three params types, but not with the implementation, it's too imperative. Then I ended up with https://github.com/woocommerce/woocommerce-blocks/pull/10919/files/dcfbfd9765e85494c992f5eeefe78c216fbd3010..96eb82cbaa56cb7b35eb4e2b80b7dc6e56f17892. Can you please take another look and let me know what do you think? It's not really declarative as I wanted, but I think it's better to move on and comeback for refactoring later.

}

if ( ! empty( $query['taxQuery'] ) ) {
foreach ( $query['taxQuery'] as $taxonomy => $value ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so, if this was JavaScript, what I would do is: I would transform my mapping object $params_mapping such as it would be a Record< string, string | ( key: string ) => string > if you know what I mean, so that I could iterate the keys in the same loop above and do all transformations there.

Then, I would refactor these little transformations into their own functions as to put away implementation details from this method.

I don't know if this is nice in PHP, but just a suggestion.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you share an example in JS on the idea you're talking about? I want to make sure we're on the same page. We're doing the similar thing for editor anyway so it won't be thrown away.

so that I could iterate the keys in the same loop above and do all transformations there.

Do you mean processing top level keys and nested keys inside one loop? Also process the transformation for both value can passed as it is and value need different transformation?

Then, I would refactor these little transformations into their own functions as to put away implementation details from this method.

Please keep in mind that the current method is already implementation details. I'm happy to split it down btw, as long as it doesn't make the function harder to read.

Again, I think it's easier for us if you can provide some code demonstrate your idea.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you share an example in JS on the idea you're talking about? I want to make sure we're on the same page. We're doing the similar thing for editor anyway so it won't be thrown away.

Maybe something like this?

const PARAMS_MAP = {
  parents: "parent",
  perPage: "per_page",
  taxQuery: ( key ) => {
    const map = {
         product_cat: "category",
         product_tag: "tag",
    };
    
    return map[ key ] || `_unstable_tax_${ key }`;
  }
}

return Object.entries( query ).reduce( ( acc, [ key, value ] ) => {
   const mapper = PARAMS_MAP[ key ];
   const newKey = typeof mapper === "function" ? mapper( key ) : mapper;
   
   acc[ newKey ] = value;
   return acc;
}, {} );

Do you mean processing top level keys and nested keys inside one loop? Also process the transformation for both value can passed as it is and value need different transformation?

Sorry not sure what you mean with this?

Please keep in mind that the current method is already implementation details. I'm happy to split it down btw, as long as it doesn't make the function harder to read.

Yes, that's a good point. Maybe I'm too trigger-happy when it comes to split stuff. But I like the idea of having the key/value conversion responsibility to be separate. But maybe it's too overkill!

Copy link
Member Author

@dinhtungdu dinhtungdu Sep 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean processing top level keys and nested keys inside one loop?

Sorry not sure what you mean with this?

In the code above, you process keys of both top level param like parents, perPage, and nested keys like product_cat and product_tag. If we have like 5 or 10 params like taxQuery, that probably makes more sense to me to map everything in one place, but here we're doing so for just taxQuery.

Also process the transformation for both value can passed as it is and value need different transformation?

I meant, in this case, we have to transform the value of nested keys of taxQuery, they're originally arrays, but we need comma separated strings to pass it to the Store API.

Btw, just a note if we reuse the snippet above, I tested it and it didn't return the desired shape.

Screenshot image

} elseif ( 'product_tag' === $taxonomy ) {
$key = 'tag';
} else {
$key = '_unstable_tax_' . $taxonomy;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha I didn't know of _unstable_tax_.

Copy link
Contributor

@sunyatasattva sunyatasattva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After our discussions, I'm happy to approve!

@github-actions github-actions bot added this to the 11.2.0 milestone Sep 20, 2023
@tarunvijwani tarunvijwani modified the milestones: 11.2.0, 11.3.0 Sep 25, 2023
@tarunvijwani
Copy link

Bumping the PR to the next release

@dinhtungdu dinhtungdu merged commit 92076d1 into trunk Oct 9, 2023
@dinhtungdu dinhtungdu deleted the contextual-filter branch October 9, 2023 08:22
Comment on lines +191 to 203
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;
}
Copy link
Member Author

@dinhtungdu dinhtungdu Oct 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function can be refactored into this:

	private function get_inner_blocks_recursive( $inner_blocks, &$results = array() ) {
		if ( ! is_a( $inner_blocks, 'WP_Block_List' ) ) {
			return $results;
		}

		return array_reduce(
			iterator_to_array( $inner_blocks ),
			function( $acc, $inner_block ) {
				$acc[] = $inner_block->name;
				return $this->get_inner_blocks_recursive(
					$inner_block->inner_blocks,
					$acc
				);
			},
			$results
		);
	}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think this looks better? 🤔 I kinda like the first version with the loop to be honest.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without the short circuit, I do, but iterator_to_array() only accepts arrays from PHP 8.2, so we need that short circuit, which kinda decreases the readability.

We can remove the short circuit to make the logic flow less divergent, but I don't really like the inline condition.

	private function get_inner_blocks_recursive( $inner_blocks, &$results = array() ) {
		return array_reduce(
			is_a( $inner_blocks, 'WP_Block_List' ) ? iterator_to_array( $inner_blocks ) : array(),
			function( $acc, $inner_block ) {
				$acc[] = $inner_block->name;
				return $this->get_inner_blocks_recursive(
					$inner_block->inner_blocks,
					$acc
				);
			},
			$results
		);
	}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
block-type: filter blocks Issues related to all of the filter blocks. skip-changelog PRs that you don't want to appear in the changelog. type: enhancement The issue is a request for an enhancement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make filter blocks contextual
4 participants