Add "Filter Products by Stock" block (https://github.com/woocommerce/woocommerce-blocks/pull/4145)
commit 4fccfd88998fde20b603d99d9866d3cb08cf7bf4 Merge: 8012b2b4 e7bd0e6e Author: groguo <eriktadevosyan07@gmail.com> Date: Fri Aug 20 13:17:42 2021 +0000 Merge from trunk commit 8012b2b40e95b90e507698de677fba059ca9ef0a Author: grogou <eriktadevosyan07@gmail.com> Date: Fri Aug 20 16:53:56 2021 +0400 Escape statuses for sql query Co-authored-by: Thomas Roberts <5656702+opr@users.noreply.github.com> commit 304348aeb5448153ad3365ff09ca37f265af87cc Author: grogou <eriktadevosyan07@gmail.com> Date: Fri Aug 20 16:53:18 2021 +0400 Allow custom stock statuses Co-authored-by: Thomas Roberts <5656702+opr@users.noreply.github.com> commit b2f01e4ed6738ef3091afbac7d4131c984b33bc7 Author: groguo <eriktadevosyan07@gmail.com> Date: Wed Jul 28 06:22:04 2021 +0000 Bring back removed css commit caafffda5de6d3f31b817ab4886847958f693e24 Author: grogou <eriktadevosyan07@gmail.com> Date: Tue Jul 27 23:35:15 2021 +0400 Update assets/js/blocks/stock-filter/block.js Co-authored-by: Thomas Roberts <5656702+opr@users.noreply.github.com> commit ae381de8aa49d0b16d2dabff7b6ecffedc511460 Author: groguo <eriktadevosyan07@gmail.com> Date: Thu Jul 15 06:50:06 2021 +0000 Fixed preview part for stock and attribute filters commit 7df5feab0a33f93786a29a625c1f27a4737c25bc Author: grogou <eriktadevosyan07@gmail.com> Date: Wed Jul 14 20:15:05 2021 +0400 Update index.js commit af0294ce6a21a0032c7eeb00fe986eddda188574 Author: groguo <eriktadevosyan07@gmail.com> Date: Wed Jul 14 15:43:06 2021 +0000 Review suggestion changes commit 16da25340fd7438e0fedd62b3e8b52bc33b80852 Author: groguo <eriktadevosyan07@gmail.com> Date: Wed Jul 14 15:40:52 2021 +0000 Linter fix commit 594125a68c5c0d854418d5f3e76fb0e18c23b0a4 Author: groguo <eriktadevosyan07@gmail.com> Date: Wed Jul 14 15:37:41 2021 +0000 Removed hideOutOfStock from AllProducts and realized hide out of stock functionality from SQL query commit 94a54e3c7c8cb94323d41a11c6bb603d0648792e Author: groguo <eriktadevosyan07@gmail.com> Date: Wed Jul 14 15:21:51 2021 +0000 Created new component for Filters elements labels commit e3d7fb2aad4b123693f0104c2ffd9af2a1273900 Author: aaron <aaron.yor@gmail.com> Date: Wed Jun 2 11:57:06 2021 +0400 Fix label includ path commit c9e3d02d5bf03614cbfd2d17ec1558dacc3252f1 Author: Seghir Nadir <nadir.seghir@gmail.com> Date: Tue Jun 1 09:46:02 2021 +0100 remove usage of mustBeString (https://github.com/woocommerce/woocommerce-blocks/pull/4294) commit b8923390e5d5433ef2c8a14891684b907051cd7e Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Mon May 31 16:07:59 2021 +0100 Lock file maintenance (https://github.com/woocommerce/woocommerce-blocks/pull/4290) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 6de68e41e2053a79cdce3e9d820c9b5656072685 Author: Thomas Roberts <5656702+opr@users.noreply.github.com> Date: Thu May 27 12:57:49 2021 +0100 Check if product can be added to cart before adding ajax class to button (https://github.com/woocommerce/woocommerce-blocks/pull/4265) commit a1ccaf4143dd9cd86f0f88ce956bcf7edb5e419a Author: Thomas Roberts <thomas.roberts@automattic.com> Date: Wed May 26 16:10:43 2021 +0100 Update version for next release commit 24f882f5d53776abe2ee6440d68485083b5a8340 Author: Thomas Roberts <thomas.roberts@automattic.com> Date: Wed May 26 15:42:21 2021 +0100 Bumping version strings to new version. commit e1fd0825b72d7cc87c6f26329359cc39278cc760 Author: Thomas Roberts <5656702+opr@users.noreply.github.com> Date: Wed May 26 15:31:37 2021 +0100 Update link to testing zip commit 35521e54b756bf265cf6d61437cd5f55629fc2d4 Author: Thomas Roberts <5656702+opr@users.noreply.github.com> Date: Wed May 26 14:04:42 2021 +0100 Fix display of itemised taxes (https://github.com/woocommerce/woocommerce-blocks/pull/4279) * Add price to itemised tax rates & hide Total when itemised taxes are on * Update snapshots for taxes in sidebar commit 7f3a1e629f04dcb71d3fb4313b3012aef13feb5f Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Wed May 26 08:52:31 2021 +0000 Update dependency downshift to v6.1.3 (https://github.com/woocommerce/woocommerce-blocks/pull/4272) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 593ef2b07f71341b3d0fc143876c24a4d50a64fb Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Wed May 26 05:04:55 2021 +0000 Update dependency @types/react to v16.14.8 (https://github.com/woocommerce/woocommerce-blocks/pull/4270) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 21f16d6d4ef10ada3f1631f72b4fb7dec1f4af72 Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Wed May 26 03:47:54 2021 +0000 Update dependency @woocommerce/e2e-utils to v0.1.5 (https://github.com/woocommerce/woocommerce-blocks/pull/4271) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 444256ea70c8b9ac89b4f4d5913396da9f4334cd Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Wed May 26 02:30:17 2021 +0000 Update dependency @types/lodash to v4.14.170 (https://github.com/woocommerce/woocommerce-blocks/pull/4269) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 5f9df572aed0b07606c7a4e5b684122a48862f94 Author: Thomas Roberts <thomas.roberts@automattic.com> Date: Tue May 25 15:31:03 2021 +0100 Create 5.2.0 testing notes commit 45abda651a668ddc4b1d36e8c76cf19d365d94c8 Author: Thomas Roberts <thomas.roberts@automattic.com> Date: Tue May 25 14:52:37 2021 +0100 Update package.json npm ci was not working correctly this will fix it. commit c3daa6ce4c71b956e08200442626a0e29a3e5daf Author: Thomas Roberts <thomas.roberts@automattic.com> Date: Tue May 25 14:26:32 2021 +0100 Update changelog and WC tested up to commit 61283092b32425450f4450d5224e156d24aa38ba Author: Thomas Roberts <5656702+opr@users.noreply.github.com> Date: Thu May 20 17:56:56 2021 +0100 Revert "Move `TextInput` to checkout package and allow it to be used for input type=number (https://github.com/woocommerce/woocommerce-blocks/pull/4238)" This reverts commitee9b2d20e0
. commit 193267b041e8e0fb9fe89bb68ad972b1f5b4b941 Author: Mike Jolley <mike.jolley@me.com> Date: Tue May 25 12:49:13 2021 +0100 Add key to each `CartTotalItem` (https://github.com/woocommerce/woocommerce-blocks/pull/4240) * Move type defs * Move type guards * Fix imports * Extract prepareTotalItems to TS file * usePaymentMethodInterface as TS file * Fix TS props * Fix currency type defs * Add return type to usePaymentMethodInterface * Add key prop to CartTotalItem * Fixed up js tests * Move SymbolPosition into type-defs package Co-authored-by: Thomas Roberts <thomas.roberts@automattic.com> commit c15e5123e47952f445fe159522f72cef290c9276 Author: Seghir Nadir <nadir.seghir@gmail.com> Date: Tue May 25 10:46:28 2021 +0100 Fix duplicate plugins by using wp.components global in the editor. (https://github.com/woocommerce/woocommerce-blocks/pull/4211) * fix duplicate slotProvider * load file on demand * add comment and load components in blocks as well * add todo block commit e2cf0baad0ee91f892a1cb1919ad0edbab0122c3 Author: Thomas Roberts <5656702+opr@users.noreply.github.com> Date: Tue May 25 08:43:46 2021 +0100 Hide "including X in taxes" when the amount of tax is 0 (https://github.com/woocommerce/woocommerce-blocks/pull/4262) * Hide "including x in taxes" if tax amount is 0 * Add jest types to tsconfig * Move SHOW_TAXES into component body This is to make the code more testable and allows us to change values. There's no significant performance impact because of this change. * Add tests and snapshots for TotalsFooterItem commit 9b44c884fc68d81d6211f40f13409fac8503c2e3 Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Mon May 24 18:14:37 2021 +0100 Update dependency @octokit/graphql to v4.6.2 (https://github.com/woocommerce/woocommerce-blocks/pull/4230) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 4973132a90ddc88e075d6d421c8677cf032c3264 Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Mon May 24 16:40:05 2021 +0100 Lock file maintenance (https://github.com/woocommerce/woocommerce-blocks/pull/4253) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit b7eabf54bad4b7e08c7f4ef1484f7fea7ab64f20 Author: Michael P. Pfeiffer <frontdevde@users.noreply.github.com> Date: Fri May 21 09:53:46 2021 +0200 Block Widgets: hide legacy widgets with a feature-complete block equivalent (https://github.com/woocommerce/woocommerce-blocks/pull/4237) * Block Widgets: hide legacy widgets with block equivalent * Unhide Products and Products by Rating widgets commit 47556b9a39125423409dea8a3ae8c8ac34396fc0 Author: Michael P. Pfeiffer <frontdevde@users.noreply.github.com> Date: Fri May 21 09:52:27 2021 +0200 Block Widgets: hide All Products and Filter blocks in the Customizer (https://github.com/woocommerce/woocommerce-blocks/pull/4225) commit 208b21281763652bdcddb7390dfe955bddff4728 Author: Thomas Roberts <5656702+opr@users.noreply.github.com> Date: Thu May 20 17:56:56 2021 +0100 Move `TextInput` to checkout package and allow it to be used for input type=number (https://github.com/woocommerce/woocommerce-blocks/pull/4238) * Move text-input to checkout package * Pass validation props directly to ValidatedTextInput * Import label relatively instead of from package * Pass validation functions to ValidatedTextInput This is so it doesn't need to get them from useValidationContext. * Add InputProps to ValidatedTextInput This will be used to control additional props on the input element of TextInput * Spread inputProps onto <input> element of TextInput * Export TextInput from @woocommerce/blocks-checkout * Add @woocommerce/blocks-checkout package to tsconfig * Allow styling to be applied to number inputs and when value is 0 * Make style order consistent * Remove inputProps to rely on rest in TextInput * Add specific prop for the inputErrorComponent * Only disallow active state if value is 0 AND type is number * Change all uses of ValidatedTextInput to also pass inputErrorComponent * Revert "Change all uses of ValidatedTextInput to also pass inputErrorComponent" This reverts commit ec734b99c20c4d29fcf778714246fc406ee37eaf. * Revert "Remove inputProps to rely on rest in TextInput" This reverts commit 1fc64cca4002206423d1fa443ff2d60130ba1ea0. * Revert "Revert "Change all uses of ValidatedTextInput to also pass inputErrorComponent"" This reverts commit 110e3606a996668be5a32698b634b7706d16cddc. * Revert "Revert "Remove inputProps to rely on rest in TextInput"" This reverts commit aeb03526c44b3fcc97a719a18930d08157a80baf. * Don't pass errorMessage to ValidatedTextInput commit 55f5bfd8cd720022380de1e811e8d1abb622209b Author: Mike Jolley <mike.jolley@me.com> Date: Thu May 20 15:07:12 2021 +0100 Create LICENSE (https://github.com/woocommerce/woocommerce-blocks/pull/4235) commit 0b10f75ddf3d01c837f466f9d3f85dbc760b3d7b Author: Albert Juhé Lluveras <contact@albertjuhe.com> Date: Thu May 20 10:58:59 2021 +0200 Update @woocommerce/components (https://github.com/woocommerce/woocommerce-blocks/pull/4100) * Add isCompact prop to components using SearchListControl * Update @woocommerce/components to 6.1.2 * Remove legacy CSS code * Add some CSS rules to override conflicting editor styles * Replace showCount prop with has-count class name * Create ExpandableSearchListItem component * Refactor ProductControl so it uses ExpandableSearchListItem * Update @woocommerce/components to 6.2.0 * Fix @woocommerce/components builds breaking * Fix a11y of expandable item list children * Set categories to an empty array by default * Render compact control in Attribute filter sidebar * Add countLabel to ProductAttributeTermControl * Fix ProductTagControl selected items * Use sentence case for countLabel * Fix wrong margins in block editor * Fix checkbox alignment * Update package-lock.json * Fix withCategories test * Fix JS error in Filter Products by Attribute block * Make input ids unique commit 587be17d62db7b956c980fac4766456511243e10 Author: Thomas Roberts <5656702+opr@users.noreply.github.com> Date: Wed May 19 10:55:15 2021 +0100 Convert TextInput and ValidatedTextInput to TypeScript (https://github.com/woocommerce/woocommerce-blocks/pull/4226) * Change index file from base/context to .ts This is to stop TS complaining when importing things from here. * Convert ValidatedTextInput to TypeScript * Convert TextInput to TypeScript * Ensure Label accepts correct HTML Attributes Props * Remove PropTypes from TextInput and ValidatedTextInput No longer needed because of TypeScript * Use correct error id to show validation message * Use HTMLElement instead of a specific element type for LabelProps * Update assets/js/base/components/text-input/validated-text-input.tsx Co-authored-by: Albert Juhé Lluveras <contact@albertjuhe.com> * Update assets/js/base/components/text-input/validated-text-input.tsx * Use correct formatting in ValidatedTextInput Co-authored-by: Albert Juhé Lluveras <contact@albertjuhe.com> commit 731c75e03100695131b4ec6afa8994e6cf9f4c00 Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Wed May 19 07:36:46 2021 +0000 Update dependency @testing-library/react-hooks to v5.1.3 (https://github.com/woocommerce/woocommerce-blocks/pull/4233) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit ef6ad8882310dff6d1aa4ae847289acddc0dfebb Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Wed May 19 04:36:44 2021 +0000 Update dependency @types/lodash to v4.14.169 (https://github.com/woocommerce/woocommerce-blocks/pull/4234) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 096463ea4bf1bddc7d61e1b04320886ee2f21770 Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Wed May 19 03:46:21 2021 +0000 Update dependency @testing-library/react to v11.2.7 (https://github.com/woocommerce/woocommerce-blocks/pull/4232) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 8722839350e6725ea80da994bb8387966b75061c Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Wed May 19 02:48:45 2021 +0000 Update dependency @stripe/react-stripe-js to v1.4.1 (https://github.com/woocommerce/woocommerce-blocks/pull/4231) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 2f7e8edfebff59eeeeeb18d65fd658d5f432419e Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Wed May 19 01:32:34 2021 +0000 Pin dependency @types/wordpress__deprecated to 2.4.2 (https://github.com/woocommerce/woocommerce-blocks/pull/4229) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 72e851a28c88653204ed8e4eff10c6bb2cb40c68 Author: Raluca Stan <raluca.stan@automattic.com> Date: Tue May 18 15:09:30 2021 +0200 Fix e2e checkout tests and adjust jest setup (https://github.com/woocommerce/woocommerce-blocks/pull/4216) * Fix checkout test - make tests independent & test also for empty cart case - make sure the Order summary is expanded with a better selector * Remove unnecessary localStorage operations from tests * Go to cart page before removing an item from cart * Remove logging observing before tests This removes unnecessary console.log interception. A big part of the logic was done for Puppeteer 1.6.1, but since 3.0.0 message.text() returns string. We allow console.error messages to surface in our tests. Although they don't cause the test to fail it might be a good addition for debugging purposes. commit 7b7119cfb0cfce5e1718804ca590a6b161d555f2 Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Tue May 18 11:27:27 2021 +0100 Lock file maintenance (https://github.com/woocommerce/woocommerce-blocks/pull/4212) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 5f84e7dabbc788b769646a9bcba5a15a57b03e33 Author: Mike Jolley <mike.jolley@me.com> Date: Tue May 18 10:37:31 2021 +0100 Convert checkout state context provider to Typescript (https://github.com/woocommerce/woocommerce-blocks/pull/4200) * git move to ts files * Type the checkout state provider * Restore for loop for error handling * Types not needed * Consolodate response handling * Unused import * Fix defaults for onCheckoutAfterProcessingWithSuccess etc * Type useEmitResponse and remove isObject checks * useEmitResponse as const * Check that redirectUrl is string * Define actions as const * data.redirectUrl should be truthy * Add redirectURL todo item as followup * remove null fallback commit fccc72bedb0f320995f62ee5d91b1c8e2e9c2fa1 Author: Thomas Roberts <5656702+opr@users.noreply.github.com> Date: Tue May 18 09:10:31 2021 +0100 Move Button and Label components to `@woocommerce/blocks-checkout` package (https://github.com/woocommerce/woocommerce-blocks/pull/4222) * Move Button to checkout package * Move Label to Components Package commit 0b91fbeac282f729dbc8e8056d2e934392f401c0 Author: Thomas Roberts <5656702+opr@users.noreply.github.com> Date: Mon May 17 15:00:57 2021 +0100 Update design of cart and checkout sidebars (https://github.com/woocommerce/woocommerce-blocks/pull/4180) * Update cart/coupon/shipping design * Add order summary heading * Move and style discounts on checkout sidebar * Add rate to tax lines * Ensure the option to display taxes itemised is available to Cart block * Output individual tax items below the total & add styles for this * Add success notice under coupon input on successful coupon addition * Add border to bottom of Totals footer * Show success message when adding coupon * Add padding to cart item rows * Add preview data to cart for when taxes are enabled * Add rate to cart response type * Add showRateAfterTaxName attribute to Cart block * Add control to cart block to show rate percentage after rate name * Add rate % in cart totals only if option is toggled on * Pass showRateAfterTaxName attribute down to TotalsTaxes * Add showRateAfterTaxName to Checkout block * Add control to block editor for showRateAfterTaxName on Checkout * Pass showRateAfterTaxName down to TotalsTaxes in Checkout * Change label for showing tax rates in cart and checkout blocks * Add test to ensure Taxes section shows in Cart block * Add tests for cart sidebar and rate percentages * Remove order summary title from checkout sidebar * Check if taxes are enabled before rendering the option to show rate %s * Add ShippingVia component to show the selected rate in sidebar * Remove value from individual tax rates * Remove bold from Shipping via label * Remove coupon added successfully message * Ensure panel headings that are h2s are the same colour as others * Clean up eslint warnings * Show rate %s by default * Update snapshots following design changes Co-authored-by: Mike Jolley <mike.jolley@me.com> commit 0464883ec668332db5a6399569880e7b3fa3ab3f Author: Albert Juhé Lluveras <contact@albertjuhe.com> Date: Sun May 16 20:00:06 2021 +0200 Don't default to fallback in getSetting if value is falsy (https://github.com/woocommerce/woocommerce-blocks/pull/4202) commit f95f12d3215caf30f1f49e1d29c5826156914a33 Author: Mike Jolley <mike.jolley@me.com> Date: Sun May 16 18:59:32 2021 +0100 Fix es lint warnings (https://github.com/woocommerce/woocommerce-blocks/pull/4206) * Un-used PropTypes import * Avoid global and use ownerDocument * receiveCart return type * ignoreRestSiblings when destructuring for @typescript-eslint/no-unused-vars * Replace lodash find * Use global rather than window * Remove lodash map * move rule to overrides commit db589e7e7f4809504b1aa83144116506a50bdd38 Author: Raluca Stan <raluca.stan@automattic.com> Date: Sun May 16 19:41:34 2021 +0200 Fix cart and checkout frontend e2e tests (https://github.com/woocommerce/woocommerce-blocks/pull/4199) * Wip: fix e2e fe tests * Test that navigation ends * Fix waitForNavigation * comment out failing php test * click the dom element * Ensure navigation happens by waiting for it. Test page title. * remove skip and update docs * Revert "comment out failing php test" This reverts commit 7c40e8caf3aa32e35e3b70eb32051251b06e0613. * Fix USD from merge conflict * Add missing check for page title * Try page.waitForFunction for text search * test to see checkout page title is correct * test checkout page url on CI * unde jest config change * Fix assertion for checkout page * remove extra localStorage item remove call Co-authored-by: Mike Jolley <mike.jolley@me.com> Co-authored-by: Nadir Seghir <nadir.seghir@gmail.com> commit b9b66f93adb5b0fdc22fc4ed9560eb6e2c1c72d9 Author: Mike Jolley <mike.jolley@me.com> Date: Thu May 13 11:49:39 2021 +0100 Set order status to pending when no payment is needed (https://github.com/woocommerce/woocommerce-blocks/pull/4186) commit 8ed63f765418ae8e7b2ee58004b4a9b1306eaeef Author: Mike Jolley <mike.jolley@me.com> Date: Thu May 13 11:21:21 2021 +0100 Remove the need for the `canMakePayment` callback in the editor context (https://github.com/woocommerce/woocommerce-blocks/pull/4188) * Force can pay true in editor context * Update docs commit 90499cb3191137264ffde07cf082db8c4d6f77de Author: Mike Jolley <mike.jolley@me.com> Date: Thu May 13 11:20:37 2021 +0100 Sync customer data during checkout with draft orders. (https://github.com/woocommerce/woocommerce-blocks/pull/4197) * Update store when email changes * Add pluckEmail helper and convert to TS * improve guard * sync draft order with customer data commit a813c931bb5f85f139429aa3bf094b2327a7f8cd Author: Albert Juhé Lluveras <contact@albertjuhe.com> Date: Thu May 13 12:14:15 2021 +0200 Set default store currency to USD in tests (https://github.com/woocommerce/woocommerce-blocks/pull/4203) commit b1408933f75ca47dc39335984bfc1fe570a72aaa Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Thu May 13 10:16:04 2021 +0200 Update dependency config to v3.3.6 (https://github.com/woocommerce/woocommerce-blocks/pull/4195) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit d68bb11bb56d882f8755162ae6657cad76dfd16f Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Thu May 13 10:15:35 2021 +0200 Update dependency cssnano to v4.1.11 (https://github.com/woocommerce/woocommerce-blocks/pull/4196) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit beadbab90fe0813c0f36cc25a9e0b14a8f8e96d2 Author: Seghir Nadir <nadir.seghir@gmail.com> Date: Wed May 12 13:32:05 2021 +0100 Add cart data to filters (https://github.com/woocommerce/woocommerce-blocks/pull/4164) * add cart data to filters * add extensions back to footer filter commit c10fdf26bc37b1efb6b22d045e3aed72f5541a2a Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Wed May 12 13:04:44 2021 +0100 Pin dependency lodash to 4.17.21 (https://github.com/woocommerce/woocommerce-blocks/pull/4193) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit f92aac55f1a6fd67fba3885311ec74bcdb41034e Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Wed May 12 13:04:13 2021 +0100 Update dependency chalk to v4.1.1 (https://github.com/woocommerce/woocommerce-blocks/pull/4194) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 27cff5109889c0abca24124c1dabcb0b78da4929 Author: Mike Jolley <mike.jolley@me.com> Date: Wed May 12 13:02:26 2021 +0100 Should be using value rather than name (https://github.com/woocommerce/woocommerce-blocks/pull/4187) commit 560972a7eb306b6a27c298b7e3218df92a848e79 Author: Thomas Roberts <5656702+opr@users.noreply.github.com> Date: Tue May 11 13:57:02 2021 +0100 Add checkout filter for coupon names (https://github.com/woocommerce/woocommerce-blocks/pull/4166) * Make extensions optional, not all filters will need to pass this through For example the CartCouponSchema has no option for extensibility (and I don't think it's needed at any rate) so extensions will always be an empty object. Rather than explicitly specifying this when running the filter, we can let it default to an empty object. * Add filter for coupon code commit 556ceb4b8a222466a73aae1ee0eac545e00802b4 Author: Thomas Roberts <5656702+opr@users.noreply.github.com> Date: Tue May 11 11:45:02 2021 +0100 Check if variation data is iterable before formatting (https://github.com/woocommerce/woocommerce-blocks/pull/4182) commit 4279db88057e83eff8af077a96eeb19dd247a8d2 Author: Darren Ethier <darren@roughsmootheng.in> Date: Mon May 10 11:21:01 2021 -0400 update package-lock (version change mostly) commit f71b24ad0f634c2cb8aeac8ae80e0ccd139a4fcd Author: Darren Ethier <darren@roughsmootheng.in> Date: Mon May 10 11:16:58 2021 -0400 update version string to dev version commit 7f9c1b2913f9c06f4d755519ef2689c56703a2c0 Author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon May 10 11:14:05 2021 -0400 Release: 5.1.0 (https://github.com/woocommerce/woocommerce-blocks/pull/4185) * Empty commit for release pull request * Add changelog * update testing notes * Bumping version strings to new version. Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: Darren Ethier <darren@roughsmootheng.in> commit 80c27354e1eb83d027eb9670aed59885c2097d3d Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Mon May 10 14:38:04 2021 +0200 Lock file maintenance (https://github.com/woocommerce/woocommerce-blocks/pull/4184) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 90074cf871d8691d0adf5808e59a75b9ace98fa7 Author: Thomas Roberts <5656702+opr@users.noreply.github.com> Date: Mon May 10 10:03:30 2021 +0100 Convert shipping components to typescript (https://github.com/woocommerce/woocommerce-blocks/pull/4135) * Add type defs for customer Taken from194ecccf78/assets/js/type-defs/customer.ts
* Convert ShippingCalculatorAddress to TypeScript * Convert ShippingCalculator to TypeScript * Convert ShippingLocation to TypeScript * Allow packageId to be a number or string in useSelectShippingRate(s) * Convert ShippingRatesControl to TypeScript * Convert ShippingOptionsStep to TypeScript * Allow package_id to be a string or number This is because of Subscriptions using strings for package IDs * Change to use CartShippingRateItemShippingRate instead of Rate * Add extra props to PackageProps type * Make ShippingAddress have the correct type * Use CartShippingRateItemShippingRate instead of Rate * Remove Rate type * Set return types to JSX.Element * Change type of props.renderOption in ShippingRatesControl * Remove customer type defs and relocate aliases to default-address-fields * Add EnteredAddress type * Import EnteredAddress from new location * Remove unnecessary eslint ignore * Remove unused variable * Remove confusing use of word Item in Shipping types * Remove confusing use of word Item in Shipping types commit 3f1be394d076bdc2a407c05d1fbf290a17c55c43 Author: Albert Juhé Lluveras <contact@albertjuhe.com> Date: Mon May 10 10:00:14 2021 +0200 Feature gate PaymentApi (https://github.com/woocommerce/woocommerce-blocks/pull/4176) * Feature gate PaymentApi * Improve payment method missing dependencies error message so it's clear it only affects blocks * Add PaymentApi feature flags to list of feature flags in docs commit ed7eded4d7134d1b69d0fd206cd1315fd9d2d40f Author: Darren Ethier <darren@roughsmootheng.in> Date: Fri May 7 16:39:28 2021 -0400 Improvements to `emitEventWithAbort`. (https://github.com/woocommerce/woocommerce-blocks/pull/4158) * modify emitEventWithAbort to change return value `emitEventWithAbort` now returns an array of responses up to the first response that triggered an error or fail response instead of aborting on success responses too. * update add to cart form context provider * update checkout state context provider * update payment method data context provider * update tests and fix thrown error handling. commit 2be9a4ea4405d5df427f4e97025aa5433019b72f Author: Raluca Stan <raluca.stan@automattic.com> Date: Fri May 7 15:50:55 2021 +0200 Add lodash as a devDependency (https://github.com/woocommerce/woocommerce-blocks/pull/4179) commit 69b3679a7e585abc8a5068df3bd2457714149939 Author: Seghir Nadir <nadir.seghir@gmail.com> Date: Wed May 5 12:59:30 2021 +0100 Don't clear email and phone fields when using separate billing address. (https://github.com/woocommerce/woocommerce-blocks/pull/4162) * preseve-billing-data * pluck empty email and phone * add issue number commit 214014750c0a1414e89ce47d84754d278e5a164f Author: Raluca Stan <raluca.stan@automattic.com> Date: Wed May 5 13:52:27 2021 +0200 Fix/cart backend test (https://github.com/woocommerce/woocommerce-blocks/pull/4153) * Fix backend cart e2e test * Adjust test structure * Fix e2e checkout backend test. Make sure the confirmation window is closed commit f8d9b9084c091f97b281f58a64f98622765a80e3 Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Wed May 5 10:08:45 2021 +0000 Update dependency @stripe/stripe-js to v1.14.0 (https://github.com/woocommerce/woocommerce-blocks/pull/4170) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 2391a40ab24439b14f56d1d6416beaf0c2d94c53 Author: Thomas Roberts <5656702+opr@users.noreply.github.com> Date: Wed May 5 10:41:48 2021 +0100 Add documentation for filters (https://github.com/woocommerce/woocommerce-blocks/pull/4167) * Rename the argument in the CheckoutFilterFunction type This only exists as an extra descriptive hint to anyone using this type, the value `label` was never used by anything so it does not need to be changed anywhere else. * Create Available Filters document * Add available filters to the extensibility README * Update docs/extensibility/available-filters.md to fix typographical error Co-authored-by: Mike Jolley <mike.jolley@me.com> Co-authored-by: Mike Jolley <mike.jolley@me.com> commit f4af89b2fce203c4f173845244724f58669a04f9 Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Wed May 5 08:10:24 2021 +0000 Update dependency @woocommerce/e2e-utils to v0.1.4 (https://github.com/woocommerce/woocommerce-blocks/pull/4172) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 6c9e786c407fd1bd6861bde3b435cec0663b8399 Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Wed May 5 03:31:52 2021 +0000 Update dependency @types/react to v16.14.6 (https://github.com/woocommerce/woocommerce-blocks/pull/4171) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 3ba4d9ed6a46f3700a7190d09eff2ba53d1bcb60 Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Wed May 5 02:23:13 2021 +0000 Update babel monorepo (https://github.com/woocommerce/woocommerce-blocks/pull/4169) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 35f71df36f92028cfb880e314623b33c077a384d Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Date: Tue May 4 14:07:05 2021 +0100 Lock file maintenance (https://github.com/woocommerce/woocommerce-blocks/pull/4163) Co-authored-by: Renovate Bot <bot@renovateapp.com> commit 4c65211b375e40691aeea7273eec34f3f54a0b3b Author: grogou <eriktadevosyan07@gmail.com> Date: Wed Apr 28 14:09:28 2021 +0000 Coped package-lock.json from trunk commit 703cb65efb8fd4ced58234d5174dc198e225e07a Author: grogou <eriktadevosyan07@gmail.com> Date: Wed Apr 28 14:00:32 2021 +0000 Reverted package-lock.json ( downgraded node version to 12 ) commit 41dfd79715d4b4f1e5cebd0e7dccfc1573ba4d36 Author: grogou <eriktadevosyan07@gmail.com> Date: Wed Apr 28 11:12:45 2021 +0000 Pre pull request clean up code commit 75fc62e99ed63389c158352b73ae898c986d92bd Author: grogou <eriktadevosyan07@gmail.com> Date: Tue Apr 27 13:03:24 2021 +0000 Added Stock Status filter commit e7bd0e6e1e171a041ac17b8b11abc812585f7645 Author: grogou <eriktadevosyan07@gmail.com> Date: Fri Aug 20 16:53:56 2021 +0400 Escape statuses for sql query Co-authored-by: Thomas Roberts <5656702+opr@users.noreply.github.com> commit 29c8493aaeb6dca6b3cf5e1954a39564ea304d87 Author: grogou <eriktadevosyan07@gmail.com> Date: Fri Aug 20 16:53:18 2021 +0400 Allow custom stock statuses Co-authored-by: Thomas Roberts <5656702+opr@users.noreply.github.com> commit 63ecd04bf09a53049bdb10d3919acf6ced7ead8a Author: groguo <eriktadevosyan07@gmail.com> Date: Wed Jul 28 06:22:04 2021 +0000 Bring back removed css commit 27e0233cb67f60f650856455a0ff32c6d73c35e3 Author: grogou <eriktadevosyan07@gmail.com> Date: Tue Jul 27 23:35:15 2021 +0400 Update assets/js/blocks/stock-filter/block.js Co-authored-by: Thomas Roberts <5656702+opr@users.noreply.github.com> commit 136c32ddd3f485be5aeab274c675743a235a8c25 Author: groguo <eriktadevosyan07@gmail.com> Date: Thu Jul 15 06:50:06 2021 +0000 Fixed preview part for stock and attribute filters commit ef89751b634bf223f065067f47f726b662d75ef3 Author: grogou <eriktadevosyan07@gmail.com> Date: Wed Jul 14 20:15:05 2021 +0400 Update index.js commit a63dbcef7058ffd858a71931b6fc2ead0583ae03 Author: groguo <eriktadevosyan07@gmail.com> Date: Wed Jul 14 15:43:06 2021 +0000 Review suggestion changes commit 6b0f5d2206d010c1822ab7eaf4edea9a0b79526d Author: groguo <eriktadevosyan07@gmail.com> Date: Wed Jul 14 15:40:52 2021 +0000 Linter fix commit 791b38b31782367864e1bb8f26716b7fef0e63a8 Author: groguo <eriktadevosyan07@gmail.com> Date: Wed Jul 14 15:37:41 2021 +0000 Removed hideOutOfStock from AllProducts and realized hide out of stock functionality from SQL query commit 1a7a002d5eac271c6f2331e3e66411f3127282b1 Author: groguo <eriktadevosyan07@gmail.com> Date: Wed Jul 14 15:21:51 2021 +0000 Created new component for Filters elements labels commit d9b7fae24d4235a0f8f424e7e74cd250e62bc897 Author: aaron <aaron.yor@gmail.com> Date: Wed Jun 2 11:57:06 2021 +0400 Fix label includ path commit 5311584362dca4c6e5a91de5fdfbff29297799ea Merge: 92a0da3f1b87589f
Author: aaron <aaron.yor@gmail.com> Date: Wed Jun 2 11:52:48 2021 +0400 Merge remote-tracking branch 'core/trunk' into add/stock-filter # Conflicts: # package-lock.json commit d8e6dabaa3282855c6c91c908d6a1443ea9732f1 Merge:583113e3
2b695215
Author: grogou <eriktadevosyan07@gmail.com> Date: Fri Apr 30 12:28:09 2021 +0400 Merge pull request woocommerce/woocommerce-blocks#1 from woocommerce/trunk Fork update commit 92a0da3f8c37aa46ce2330cb8095ab7077d01555 Author: grogou <eriktadevosyan07@gmail.com> Date: Wed Apr 28 14:09:28 2021 +0000 Coped package-lock.json from trunk commit ae0d12b57a5be6f1a39577404c017174489345f8 Author: grogou <eriktadevosyan07@gmail.com> Date: Wed Apr 28 14:00:32 2021 +0000 Reverted package-lock.json ( downgraded node version to 12 ) commit 5e0c7f9fe36bc9358743b7af7d9e47ce66f8ac08 Author: grogou <eriktadevosyan07@gmail.com> Date: Wed Apr 28 11:12:45 2021 +0000 Pre pull request clean up code commit 105b3f75a2b42f12f6924091f51bfa91c84b4984 Author: grogou <eriktadevosyan07@gmail.com> Date: Tue Apr 27 13:03:24 2021 +0000 Added Stock Status filter
This commit is contained in:
parent
1d79bb6365
commit
44db8317a7
|
@ -5,13 +5,18 @@ import { _n, sprintf } from '@wordpress/i18n';
|
||||||
import Label from '@woocommerce/base-components/label';
|
import Label from '@woocommerce/base-components/label';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The label for an attribute term filter.
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The label for an filter elements.
|
||||||
*
|
*
|
||||||
* @param {Object} props Incoming props for the component.
|
* @param {Object} props Incoming props for the component.
|
||||||
* @param {string} props.name The name for the label.
|
* @param {string} props.name The name for the label.
|
||||||
* @param {number} props.count The count of products this attribute is attached to.
|
* @param {number} props.count The count of products this status is attached to.
|
||||||
*/
|
*/
|
||||||
const AttributeFilterLabel = ( { name, count } ) => {
|
const FilterElementLabel = ( { name, count } ) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{ name }
|
{ name }
|
||||||
|
@ -30,7 +35,7 @@ const AttributeFilterLabel = ( { name, count } ) => {
|
||||||
) }
|
) }
|
||||||
wrapperElement="span"
|
wrapperElement="span"
|
||||||
wrapperProps={ {
|
wrapperProps={ {
|
||||||
className: 'wc-block-attribute-filter-list-count',
|
className: 'wc-filter-element-label-list-count',
|
||||||
} }
|
} }
|
||||||
/>
|
/>
|
||||||
) }
|
) }
|
||||||
|
@ -38,4 +43,4 @@ const AttributeFilterLabel = ( { name, count } ) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AttributeFilterLabel;
|
export default FilterElementLabel;
|
|
@ -0,0 +1,9 @@
|
||||||
|
.wc-filter-element-label-list-count {
|
||||||
|
&::before {
|
||||||
|
content: " (";
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
content: ")";
|
||||||
|
}
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
|
@ -9,10 +9,7 @@ import PropTypes from 'prop-types';
|
||||||
*/
|
*/
|
||||||
import ProductList from './product-list';
|
import ProductList from './product-list';
|
||||||
|
|
||||||
const ProductListContainer = ( {
|
const ProductListContainer = ( { attributes } ) => {
|
||||||
attributes,
|
|
||||||
hideOutOfStockItems = false,
|
|
||||||
} ) => {
|
|
||||||
const [ currentPage, setPage ] = useState( 1 );
|
const [ currentPage, setPage ] = useState( 1 );
|
||||||
const [ currentSort, setSort ] = useState( attributes.orderby );
|
const [ currentSort, setSort ] = useState( attributes.orderby );
|
||||||
useEffect( () => {
|
useEffect( () => {
|
||||||
|
@ -31,7 +28,6 @@ const ProductListContainer = ( {
|
||||||
return (
|
return (
|
||||||
<ProductList
|
<ProductList
|
||||||
attributes={ attributes }
|
attributes={ attributes }
|
||||||
hideOutOfStockItems={ hideOutOfStockItems }
|
|
||||||
currentPage={ currentPage }
|
currentPage={ currentPage }
|
||||||
onPageChange={ onPageChange }
|
onPageChange={ onPageChange }
|
||||||
onSortChange={ onSortChange }
|
onSortChange={ onSortChange }
|
||||||
|
|
|
@ -27,12 +27,7 @@ import ProductSortSelect from './product-sort-select';
|
||||||
import ProductListItem from './product-list-item';
|
import ProductListItem from './product-list-item';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
const generateQuery = ( {
|
const generateQuery = ( { sortValue, currentPage, attributes } ) => {
|
||||||
sortValue,
|
|
||||||
currentPage,
|
|
||||||
attributes,
|
|
||||||
hideOutOfStockItems,
|
|
||||||
} ) => {
|
|
||||||
const { columns, rows } = attributes;
|
const { columns, rows } = attributes;
|
||||||
const getSortArgs = ( orderName ) => {
|
const getSortArgs = ( orderName ) => {
|
||||||
switch ( orderName ) {
|
switch ( orderName ) {
|
||||||
|
@ -62,9 +57,6 @@ const generateQuery = ( {
|
||||||
catalog_visibility: 'catalog',
|
catalog_visibility: 'catalog',
|
||||||
per_page: columns * rows,
|
per_page: columns * rows,
|
||||||
page: currentPage,
|
page: currentPage,
|
||||||
...( hideOutOfStockItems && {
|
|
||||||
stock_status: [ 'instock', 'onbackorder' ],
|
|
||||||
} ),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -118,14 +110,24 @@ const ProductList = ( {
|
||||||
onSortChange,
|
onSortChange,
|
||||||
sortValue,
|
sortValue,
|
||||||
scrollToTop,
|
scrollToTop,
|
||||||
hideOutOfStockItems = false,
|
|
||||||
} ) => {
|
} ) => {
|
||||||
|
// These are possible filters.
|
||||||
|
const [ productAttributes, setProductAttributes ] = useQueryStateByKey(
|
||||||
|
'attributes',
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
const [ productStockStatus, setProductStockStatus ] = useQueryStateByKey(
|
||||||
|
'stock_status',
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
const [ minPrice, setMinPrice ] = useQueryStateByKey( 'min_price' );
|
||||||
|
const [ maxPrice, setMaxPrice ] = useQueryStateByKey( 'max_price' );
|
||||||
|
|
||||||
const [ queryState ] = useSynchronizedQueryState(
|
const [ queryState ] = useSynchronizedQueryState(
|
||||||
generateQuery( {
|
generateQuery( {
|
||||||
attributes,
|
attributes,
|
||||||
sortValue,
|
sortValue,
|
||||||
currentPage,
|
currentPage,
|
||||||
hideOutOfStockItems,
|
|
||||||
} )
|
} )
|
||||||
);
|
);
|
||||||
const { products, totalProducts, productsLoading } = useStoreProducts(
|
const { products, totalProducts, productsLoading } = useStoreProducts(
|
||||||
|
@ -135,14 +137,6 @@ const ProductList = ( {
|
||||||
const totalQuery = extractPaginationAndSortAttributes( queryState );
|
const totalQuery = extractPaginationAndSortAttributes( queryState );
|
||||||
const { dispatchStoreEvent } = useStoreEvents();
|
const { dispatchStoreEvent } = useStoreEvents();
|
||||||
|
|
||||||
// These are possible filters.
|
|
||||||
const [ productAttributes, setProductAttributes ] = useQueryStateByKey(
|
|
||||||
'attributes',
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
const [ minPrice, setMinPrice ] = useQueryStateByKey( 'min_price' );
|
|
||||||
const [ maxPrice, setMaxPrice ] = useQueryStateByKey( 'max_price' );
|
|
||||||
|
|
||||||
// Only update previous query totals if the query is different and the total number of products is a finite number.
|
// Only update previous query totals if the query is different and the total number of products is a finite number.
|
||||||
const previousQueryTotals = usePrevious(
|
const previousQueryTotals = usePrevious(
|
||||||
{ totalQuery, totalProducts },
|
{ totalQuery, totalProducts },
|
||||||
|
@ -209,6 +203,7 @@ const ProductList = ( {
|
||||||
const hasProducts = products.length !== 0 || productsLoading;
|
const hasProducts = products.length !== 0 || productsLoading;
|
||||||
const hasFilters =
|
const hasFilters =
|
||||||
productAttributes.length > 0 ||
|
productAttributes.length > 0 ||
|
||||||
|
productStockStatus.length > 0 ||
|
||||||
Number.isFinite( minPrice ) ||
|
Number.isFinite( minPrice ) ||
|
||||||
Number.isFinite( maxPrice );
|
Number.isFinite( maxPrice );
|
||||||
|
|
||||||
|
@ -224,6 +219,7 @@ const ProductList = ( {
|
||||||
<NoMatchingProducts
|
<NoMatchingProducts
|
||||||
resetCallback={ () => {
|
resetCallback={ () => {
|
||||||
setProductAttributes( [] );
|
setProductAttributes( [] );
|
||||||
|
setProductStockStatus( [] );
|
||||||
setMinPrice( null );
|
setMinPrice( null );
|
||||||
setMaxPrice( null );
|
setMaxPrice( null );
|
||||||
} }
|
} }
|
||||||
|
@ -254,7 +250,6 @@ const ProductList = ( {
|
||||||
|
|
||||||
ProductList.propTypes = {
|
ProductList.propTypes = {
|
||||||
attributes: PropTypes.object.isRequired,
|
attributes: PropTypes.object.isRequired,
|
||||||
hideOutOfStockItems: PropTypes.bool,
|
|
||||||
// From withScrollToTop.
|
// From withScrollToTop.
|
||||||
scrollToTop: PropTypes.func,
|
scrollToTop: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,6 +36,7 @@ const buildCollectionDataQuery = ( collectionDataQueryState ) => {
|
||||||
export const useCollectionData = ( {
|
export const useCollectionData = ( {
|
||||||
queryAttribute,
|
queryAttribute,
|
||||||
queryPrices,
|
queryPrices,
|
||||||
|
queryStock,
|
||||||
queryState,
|
queryState,
|
||||||
} ) => {
|
} ) => {
|
||||||
let context = useQueryStateContext();
|
let context = useQueryStateContext();
|
||||||
|
@ -50,9 +51,14 @@ export const useCollectionData = ( {
|
||||||
calculatePriceRangeQueryState,
|
calculatePriceRangeQueryState,
|
||||||
setCalculatePriceRangeQueryState,
|
setCalculatePriceRangeQueryState,
|
||||||
] = useQueryStateByKey( 'calculate_price_range', null, context );
|
] = useQueryStateByKey( 'calculate_price_range', null, context );
|
||||||
|
const [
|
||||||
|
calculateStockStatusQueryState,
|
||||||
|
setCalculateStockStatusQueryState,
|
||||||
|
] = useQueryStateByKey( 'calculate_stock_status_counts', null, context );
|
||||||
|
|
||||||
const currentQueryAttribute = useShallowEqual( queryAttribute || {} );
|
const currentQueryAttribute = useShallowEqual( queryAttribute || {} );
|
||||||
const currentQueryPrices = useShallowEqual( queryPrices );
|
const currentQueryPrices = useShallowEqual( queryPrices );
|
||||||
|
const currentQueryStock = useShallowEqual( queryStock );
|
||||||
|
|
||||||
useEffect( () => {
|
useEffect( () => {
|
||||||
if (
|
if (
|
||||||
|
@ -93,6 +99,19 @@ export const useCollectionData = ( {
|
||||||
calculatePriceRangeQueryState,
|
calculatePriceRangeQueryState,
|
||||||
] );
|
] );
|
||||||
|
|
||||||
|
useEffect( () => {
|
||||||
|
if (
|
||||||
|
calculateStockStatusQueryState !== currentQueryStock &&
|
||||||
|
currentQueryStock !== undefined
|
||||||
|
) {
|
||||||
|
setCalculateStockStatusQueryState( currentQueryStock );
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
currentQueryStock,
|
||||||
|
setCalculateStockStatusQueryState,
|
||||||
|
calculateStockStatusQueryState,
|
||||||
|
] );
|
||||||
|
|
||||||
// Defer the select query so all collection-data query vars can be gathered.
|
// Defer the select query so all collection-data query vars can be gathered.
|
||||||
const [ shouldSelect, setShouldSelect ] = useState( false );
|
const [ shouldSelect, setShouldSelect ] = useState( false );
|
||||||
const [ debouncedShouldSelect ] = useDebounce( shouldSelect, 200 );
|
const [ debouncedShouldSelect ] = useDebounce( shouldSelect, 200 );
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
*/
|
*/
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { useQueryStateByKey } from '@woocommerce/base-context/hooks';
|
import { useQueryStateByKey } from '@woocommerce/base-context/hooks';
|
||||||
|
import { getSetting } from '@woocommerce/settings';
|
||||||
import { useMemo } from '@wordpress/element';
|
import { useMemo } from '@wordpress/element';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
@ -31,9 +32,39 @@ const ActiveFiltersBlock = ( {
|
||||||
'attributes',
|
'attributes',
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
const [ productStockStatus, setProductStockStatus ] = useQueryStateByKey(
|
||||||
|
'stock_status',
|
||||||
|
[]
|
||||||
|
);
|
||||||
const [ minPrice, setMinPrice ] = useQueryStateByKey( 'min_price' );
|
const [ minPrice, setMinPrice ] = useQueryStateByKey( 'min_price' );
|
||||||
const [ maxPrice, setMaxPrice ] = useQueryStateByKey( 'max_price' );
|
const [ maxPrice, setMaxPrice ] = useQueryStateByKey( 'max_price' );
|
||||||
|
|
||||||
|
const STOCK_STATUS_OPTIONS = getSetting( 'stockStatusOptions', [] );
|
||||||
|
const activeStockStatusFilters = useMemo( () => {
|
||||||
|
if ( productStockStatus.length > 0 ) {
|
||||||
|
return productStockStatus.map( ( slug ) => {
|
||||||
|
return renderRemovableListItem( {
|
||||||
|
type: __( 'Stock Status', 'woo-gutenberg-products-block' ),
|
||||||
|
name: STOCK_STATUS_OPTIONS[ slug ],
|
||||||
|
removeCallback: () => {
|
||||||
|
const newStatuses = productStockStatus.filter(
|
||||||
|
( status ) => {
|
||||||
|
return status !== slug;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
setProductStockStatus( newStatuses );
|
||||||
|
},
|
||||||
|
displayStyle: blockAttributes.displayStyle,
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
STOCK_STATUS_OPTIONS,
|
||||||
|
productStockStatus,
|
||||||
|
setProductStockStatus,
|
||||||
|
blockAttributes.displayStyle,
|
||||||
|
] );
|
||||||
|
|
||||||
const activePriceFilters = useMemo( () => {
|
const activePriceFilters = useMemo( () => {
|
||||||
if ( ! Number.isFinite( minPrice ) && ! Number.isFinite( maxPrice ) ) {
|
if ( ! Number.isFinite( minPrice ) && ! Number.isFinite( maxPrice ) ) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -75,6 +106,7 @@ const ActiveFiltersBlock = ( {
|
||||||
const hasFilters = () => {
|
const hasFilters = () => {
|
||||||
return (
|
return (
|
||||||
productAttributes.length > 0 ||
|
productAttributes.length > 0 ||
|
||||||
|
productStockStatus.length > 0 ||
|
||||||
Number.isFinite( minPrice ) ||
|
Number.isFinite( minPrice ) ||
|
||||||
Number.isFinite( maxPrice )
|
Number.isFinite( maxPrice )
|
||||||
);
|
);
|
||||||
|
@ -125,6 +157,7 @@ const ActiveFiltersBlock = ( {
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{ activePriceFilters }
|
{ activePriceFilters }
|
||||||
|
{ activeStockStatusFilters }
|
||||||
{ activeAttributeFilters }
|
{ activeAttributeFilters }
|
||||||
</>
|
</>
|
||||||
) }
|
) }
|
||||||
|
@ -135,6 +168,7 @@ const ActiveFiltersBlock = ( {
|
||||||
setMinPrice( undefined );
|
setMinPrice( undefined );
|
||||||
setMaxPrice( undefined );
|
setMaxPrice( undefined );
|
||||||
setProductAttributes( [] );
|
setProductAttributes( [] );
|
||||||
|
setProductStockStatus( [] );
|
||||||
} }
|
} }
|
||||||
>
|
>
|
||||||
<Label
|
<Label
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
import { useCallback, useEffect, useState, useMemo } from '@wordpress/element';
|
import { useCallback, useEffect, useState, useMemo } from '@wordpress/element';
|
||||||
import CheckboxList from '@woocommerce/base-components/checkbox-list';
|
import CheckboxList from '@woocommerce/base-components/checkbox-list';
|
||||||
import DropdownSelector from '@woocommerce/base-components/dropdown-selector';
|
import DropdownSelector from '@woocommerce/base-components/dropdown-selector';
|
||||||
|
import Label from '@woocommerce/base-components/filter-element-label';
|
||||||
import FilterSubmitButton from '@woocommerce/base-components/filter-submit-button';
|
import FilterSubmitButton from '@woocommerce/base-components/filter-submit-button';
|
||||||
import isShallowEqual from '@wordpress/is-shallow-equal';
|
import isShallowEqual from '@wordpress/is-shallow-equal';
|
||||||
import { decodeEntities } from '@wordpress/html-entities';
|
import { decodeEntities } from '@wordpress/html-entities';
|
||||||
|
@ -22,7 +23,6 @@ import { decodeEntities } from '@wordpress/html-entities';
|
||||||
*/
|
*/
|
||||||
import { getAttributeFromID } from '../../utils/attributes';
|
import { getAttributeFromID } from '../../utils/attributes';
|
||||||
import { updateAttributeFilter } from '../../utils/attributes-query';
|
import { updateAttributeFilter } from '../../utils/attributes-query';
|
||||||
import Label from './label';
|
|
||||||
import { previewAttributeObject, previewOptions } from './preview';
|
import { previewAttributeObject, previewOptions } from './preview';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import Label from './label';
|
import Label from '@woocommerce/base-components/filter-element-label';
|
||||||
|
|
||||||
export const previewOptions = [
|
export const previewOptions = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
.wc-block-attribute-filter {
|
.wc-block-attribute-filter {
|
||||||
margin-bottom: $gap-large;
|
margin-bottom: $gap-large;
|
||||||
|
|
||||||
.wc-block-attribute-filter-list-count {
|
|
||||||
&::before {
|
|
||||||
content: " (";
|
|
||||||
}
|
|
||||||
&::after {
|
|
||||||
content: ")";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.wc-block-attribute-filter-list {
|
.wc-block-attribute-filter-list {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
|
@ -25,10 +16,6 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.wc-block-attribute-filter-list-count {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-single .wc-block-attribute-filter-list-count,
|
.is-single .wc-block-attribute-filter-list-count,
|
||||||
|
|
|
@ -6,7 +6,6 @@ import PropTypes from 'prop-types';
|
||||||
import { ProductListContainer } from '@woocommerce/base-components/product-list';
|
import { ProductListContainer } from '@woocommerce/base-components/product-list';
|
||||||
import { InnerBlockLayoutContextProvider } from '@woocommerce/shared-context';
|
import { InnerBlockLayoutContextProvider } from '@woocommerce/shared-context';
|
||||||
import { gridBlockPreview } from '@woocommerce/resource-previews';
|
import { gridBlockPreview } from '@woocommerce/resource-previews';
|
||||||
import { getSetting } from '@woocommerce/settings';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The All Products Block.
|
* The All Products Block.
|
||||||
|
@ -26,8 +25,6 @@ class Block extends Component {
|
||||||
return gridBlockPreview;
|
return gridBlockPreview;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hideOutOfStockItems = getSetting( 'hideOutOfStockItems', false );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Todo classes
|
* Todo classes
|
||||||
*
|
*
|
||||||
|
@ -42,7 +39,6 @@ class Block extends Component {
|
||||||
<ProductListContainer
|
<ProductListContainer
|
||||||
attributes={ attributes }
|
attributes={ attributes }
|
||||||
urlParameterSuffix={ urlParameterSuffix }
|
urlParameterSuffix={ urlParameterSuffix }
|
||||||
hideOutOfStockItems={ hideOutOfStockItems }
|
|
||||||
/>
|
/>
|
||||||
</InnerBlockLayoutContextProvider>
|
</InnerBlockLayoutContextProvider>
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,278 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
|
import { speak } from '@wordpress/a11y';
|
||||||
|
import { usePrevious, useShallowEqual } from '@woocommerce/base-hooks';
|
||||||
|
import {
|
||||||
|
useQueryStateByKey,
|
||||||
|
useQueryStateByContext,
|
||||||
|
useCollectionData,
|
||||||
|
} from '@woocommerce/base-context/hooks';
|
||||||
|
import { getSetting } from '@woocommerce/settings';
|
||||||
|
import { useCallback, useEffect, useState, useMemo } from '@wordpress/element';
|
||||||
|
import CheckboxList from '@woocommerce/base-components/checkbox-list';
|
||||||
|
import FilterSubmitButton from '@woocommerce/base-components/filter-submit-button';
|
||||||
|
import Label from '@woocommerce/base-components/filter-element-label';
|
||||||
|
import isShallowEqual from '@wordpress/is-shallow-equal';
|
||||||
|
import { decodeEntities } from '@wordpress/html-entities';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { previewOptions } from './preview';
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
|
const hideOutOfStockItems = getSetting( 'hideOutOfStockItems', false );
|
||||||
|
const { outofstock, ...otherStockStatusOptions } = getSetting(
|
||||||
|
'stockStatusOptions',
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
const STOCK_STATUS_OPTIONS = hideOutOfStockItems
|
||||||
|
? otherStockStatusOptions
|
||||||
|
: { outofstock, ...otherStockStatusOptions };
|
||||||
|
// Filter added to handle if there are slugs without a corresponding name defined.
|
||||||
|
const initialOptions = Object.entries( STOCK_STATUS_OPTIONS )
|
||||||
|
.map( ( [ slug, name ] ) => ( { slug, name } ) )
|
||||||
|
.filter( ( status ) => !! status.name )
|
||||||
|
.sort( ( a, b ) => a.slug.localeCompare( b.slug ) );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component displaying an stock status filter.
|
||||||
|
*
|
||||||
|
* @param {Object} props Incoming props for the component.
|
||||||
|
* @param {Object} props.attributes Incoming block attributes.
|
||||||
|
* @param {boolean} props.isEditor
|
||||||
|
*/
|
||||||
|
const StockStatusFilterBlock = ( {
|
||||||
|
attributes: blockAttributes,
|
||||||
|
isEditor = false,
|
||||||
|
} ) => {
|
||||||
|
const [ checked, setChecked ] = useState( [] );
|
||||||
|
const [ displayedOptions, setDisplayedOptions ] = useState(
|
||||||
|
blockAttributes.isPreview ? previewOptions : []
|
||||||
|
);
|
||||||
|
|
||||||
|
const [ queryState ] = useQueryStateByContext();
|
||||||
|
const [
|
||||||
|
productStockStatusQuery,
|
||||||
|
setProductStockStatusQuery,
|
||||||
|
] = useQueryStateByKey( 'stock_status', [] );
|
||||||
|
|
||||||
|
const {
|
||||||
|
results: filteredCounts,
|
||||||
|
isLoading: filteredCountsLoading,
|
||||||
|
} = useCollectionData( {
|
||||||
|
queryStock: true,
|
||||||
|
queryState,
|
||||||
|
} );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get count data about a given status by slug.
|
||||||
|
*/
|
||||||
|
const getFilteredStock = useCallback(
|
||||||
|
( slug ) => {
|
||||||
|
if ( ! filteredCounts.stock_status_counts ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return filteredCounts.stock_status_counts.find(
|
||||||
|
( { status, count } ) =>
|
||||||
|
status === slug && Number( count ) !== 0
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[ filteredCounts ]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare intersection of all stock statuses and filtered counts to get a list of options to display.
|
||||||
|
*/
|
||||||
|
useEffect( () => {
|
||||||
|
/**
|
||||||
|
* Checks if a status slug is in the query state.
|
||||||
|
*
|
||||||
|
* @param {string} queryStatus The status slug to check.
|
||||||
|
*/
|
||||||
|
const isStockStatusInQueryState = ( queryStatus ) => {
|
||||||
|
if ( ! queryState?.stock_status ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return queryState.stock_status.some( ( { status = [] } ) =>
|
||||||
|
status.includes( queryStatus )
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if ( filteredCountsLoading || blockAttributes.isPreview ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newOptions = initialOptions
|
||||||
|
.map( ( status ) => {
|
||||||
|
const filteredStock = getFilteredStock( status.slug );
|
||||||
|
|
||||||
|
if (
|
||||||
|
! filteredStock &&
|
||||||
|
! checked.includes( status.slug ) &&
|
||||||
|
! isStockStatusInQueryState( status.slug )
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const count = filteredStock ? Number( filteredStock.count ) : 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: status.slug,
|
||||||
|
name: decodeEntities( status.name ),
|
||||||
|
label: (
|
||||||
|
<Label
|
||||||
|
name={ decodeEntities( status.name ) }
|
||||||
|
count={ blockAttributes.showCounts ? count : null }
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
} )
|
||||||
|
.filter( Boolean );
|
||||||
|
|
||||||
|
setDisplayedOptions( newOptions );
|
||||||
|
}, [
|
||||||
|
blockAttributes.showCounts,
|
||||||
|
blockAttributes.isPreview,
|
||||||
|
filteredCountsLoading,
|
||||||
|
getFilteredStock,
|
||||||
|
checked,
|
||||||
|
queryState.stock_status,
|
||||||
|
] );
|
||||||
|
|
||||||
|
const onSubmit = useCallback(
|
||||||
|
( isChecked ) => {
|
||||||
|
if ( isEditor ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( isChecked ) {
|
||||||
|
setProductStockStatusQuery( checked );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[ isEditor, setProductStockStatusQuery, checked ]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Track checked STATE changes - if state changes, update the query.
|
||||||
|
useEffect( () => {
|
||||||
|
if ( ! blockAttributes.showFilterButton ) {
|
||||||
|
onSubmit( checked );
|
||||||
|
}
|
||||||
|
}, [ blockAttributes.showFilterButton, checked, onSubmit ] );
|
||||||
|
|
||||||
|
const checkedQuery = useMemo( () => {
|
||||||
|
return productStockStatusQuery;
|
||||||
|
}, [ productStockStatusQuery ] );
|
||||||
|
|
||||||
|
const currentCheckedQuery = useShallowEqual( checkedQuery );
|
||||||
|
const previousCheckedQuery = usePrevious( currentCheckedQuery );
|
||||||
|
// Track Stock query changes so the block reflects current filters.
|
||||||
|
useEffect( () => {
|
||||||
|
if (
|
||||||
|
! isShallowEqual( previousCheckedQuery, currentCheckedQuery ) && // Checked query changed.
|
||||||
|
! isShallowEqual( checked, currentCheckedQuery ) // Checked query doesn't match the UI.
|
||||||
|
) {
|
||||||
|
setChecked( currentCheckedQuery );
|
||||||
|
}
|
||||||
|
}, [ checked, currentCheckedQuery, previousCheckedQuery ] );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a checkbox in the list changes, update state.
|
||||||
|
*/
|
||||||
|
const onChange = useCallback(
|
||||||
|
( checkedValue ) => {
|
||||||
|
const getFilterNameFromValue = ( filterValue ) => {
|
||||||
|
const { name } = displayedOptions.find(
|
||||||
|
( option ) => option.value === filterValue
|
||||||
|
);
|
||||||
|
|
||||||
|
return name;
|
||||||
|
};
|
||||||
|
|
||||||
|
const announceFilterChange = ( { filterAdded, filterRemoved } ) => {
|
||||||
|
const filterAddedName = filterAdded
|
||||||
|
? getFilterNameFromValue( filterAdded )
|
||||||
|
: null;
|
||||||
|
const filterRemovedName = filterRemoved
|
||||||
|
? getFilterNameFromValue( filterRemoved )
|
||||||
|
: null;
|
||||||
|
if ( filterAddedName ) {
|
||||||
|
speak(
|
||||||
|
sprintf(
|
||||||
|
/* translators: %s stock statuses (for example: 'instock'...) */
|
||||||
|
__(
|
||||||
|
'%s filter added.',
|
||||||
|
'woo-gutenberg-products-block'
|
||||||
|
),
|
||||||
|
filterAddedName
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else if ( filterRemovedName ) {
|
||||||
|
speak(
|
||||||
|
sprintf(
|
||||||
|
/* translators: %s stock statuses (for example:'instock'...) */
|
||||||
|
__(
|
||||||
|
'%s filter removed.',
|
||||||
|
'woo-gutenberg-products-block'
|
||||||
|
),
|
||||||
|
filterRemovedName
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const previouslyChecked = checked.includes( checkedValue );
|
||||||
|
|
||||||
|
const newChecked = checked.filter(
|
||||||
|
( value ) => value !== checkedValue
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( ! previouslyChecked ) {
|
||||||
|
newChecked.push( checkedValue );
|
||||||
|
newChecked.sort();
|
||||||
|
announceFilterChange( { filterAdded: checkedValue } );
|
||||||
|
} else {
|
||||||
|
announceFilterChange( { filterRemoved: checkedValue } );
|
||||||
|
}
|
||||||
|
|
||||||
|
setChecked( newChecked );
|
||||||
|
},
|
||||||
|
[ checked, displayedOptions ]
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( displayedOptions.length === 0 ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TagName = `h${ blockAttributes.headingLevel }`;
|
||||||
|
const isLoading = ! blockAttributes.isPreview && ! STOCK_STATUS_OPTIONS;
|
||||||
|
const isDisabled = ! blockAttributes.isPreview && filteredCountsLoading;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{ ! isEditor && blockAttributes.heading && (
|
||||||
|
<TagName>{ blockAttributes.heading }</TagName>
|
||||||
|
) }
|
||||||
|
<div className="wc-block-stock-filter">
|
||||||
|
<CheckboxList
|
||||||
|
className={ 'wc-block-stock-filter-list' }
|
||||||
|
options={ displayedOptions }
|
||||||
|
checked={ checked }
|
||||||
|
onChange={ onChange }
|
||||||
|
isLoading={ isLoading }
|
||||||
|
isDisabled={ isDisabled }
|
||||||
|
/>
|
||||||
|
{ blockAttributes.showFilterButton && (
|
||||||
|
<FilterSubmitButton
|
||||||
|
className="wc-block-stock-filter__button"
|
||||||
|
disabled={ isLoading || isDisabled }
|
||||||
|
onClick={ () => onSubmit( checked ) }
|
||||||
|
/>
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StockStatusFilterBlock;
|
|
@ -0,0 +1,130 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { InspectorControls } from '@wordpress/block-editor';
|
||||||
|
import {
|
||||||
|
Disabled,
|
||||||
|
PanelBody,
|
||||||
|
ToggleControl,
|
||||||
|
withSpokenMessages,
|
||||||
|
} from '@wordpress/components';
|
||||||
|
import HeadingToolbar from '@woocommerce/editor-components/heading-toolbar';
|
||||||
|
import BlockTitle from '@woocommerce/editor-components/block-title';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import Block from './block.js';
|
||||||
|
import './editor.scss';
|
||||||
|
|
||||||
|
const Edit = ( { attributes, setAttributes } ) => {
|
||||||
|
const {
|
||||||
|
className,
|
||||||
|
heading,
|
||||||
|
headingLevel,
|
||||||
|
showCounts,
|
||||||
|
showFilterButton,
|
||||||
|
} = attributes;
|
||||||
|
|
||||||
|
const getInspectorControls = () => {
|
||||||
|
return (
|
||||||
|
<InspectorControls key="inspector">
|
||||||
|
<PanelBody
|
||||||
|
title={ __( 'Content', 'woo-gutenberg-products-block' ) }
|
||||||
|
>
|
||||||
|
<ToggleControl
|
||||||
|
label={ __(
|
||||||
|
'Product count',
|
||||||
|
'woo-gutenberg-products-block'
|
||||||
|
) }
|
||||||
|
help={
|
||||||
|
showCounts
|
||||||
|
? __(
|
||||||
|
'Product count is visible.',
|
||||||
|
'woo-gutenberg-products-block'
|
||||||
|
)
|
||||||
|
: __(
|
||||||
|
'Product count is hidden.',
|
||||||
|
'woo-gutenberg-products-block'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
checked={ showCounts }
|
||||||
|
onChange={ () =>
|
||||||
|
setAttributes( {
|
||||||
|
showCounts: ! showCounts,
|
||||||
|
} )
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<p>
|
||||||
|
{ __(
|
||||||
|
'Heading Level',
|
||||||
|
'woo-gutenberg-products-block'
|
||||||
|
) }
|
||||||
|
</p>
|
||||||
|
<HeadingToolbar
|
||||||
|
isCollapsed={ false }
|
||||||
|
minLevel={ 2 }
|
||||||
|
maxLevel={ 7 }
|
||||||
|
selectedLevel={ headingLevel }
|
||||||
|
onChange={ ( newLevel ) =>
|
||||||
|
setAttributes( { headingLevel: newLevel } )
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</PanelBody>
|
||||||
|
<PanelBody
|
||||||
|
title={ __(
|
||||||
|
'Block Settings',
|
||||||
|
'woo-gutenberg-products-block'
|
||||||
|
) }
|
||||||
|
>
|
||||||
|
<ToggleControl
|
||||||
|
label={ __(
|
||||||
|
'Filter button',
|
||||||
|
'woo-gutenberg-products-block'
|
||||||
|
) }
|
||||||
|
help={
|
||||||
|
showFilterButton
|
||||||
|
? __(
|
||||||
|
'Products will only update when the button is pressed.',
|
||||||
|
'woo-gutenberg-products-block'
|
||||||
|
)
|
||||||
|
: __(
|
||||||
|
'Products will update as options are selected.',
|
||||||
|
'woo-gutenberg-products-block'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
checked={ showFilterButton }
|
||||||
|
onChange={ ( value ) =>
|
||||||
|
setAttributes( {
|
||||||
|
showFilterButton: value,
|
||||||
|
} )
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</PanelBody>
|
||||||
|
</InspectorControls>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{ getInspectorControls() }
|
||||||
|
{
|
||||||
|
<div className={ className }>
|
||||||
|
<BlockTitle
|
||||||
|
headingLevel={ headingLevel }
|
||||||
|
heading={ heading }
|
||||||
|
onChange={ ( value ) =>
|
||||||
|
setAttributes( { heading: value } )
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Disabled>
|
||||||
|
<Block attributes={ attributes } isEditor={ true } />
|
||||||
|
</Disabled>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withSpokenMessages( Edit );
|
|
@ -0,0 +1,36 @@
|
||||||
|
.wc-block-stock-filter {
|
||||||
|
.components-placeholder__instructions {
|
||||||
|
border-bottom: 1px solid #e0e2e6;
|
||||||
|
width: 100%;
|
||||||
|
padding-bottom: 1em;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
}
|
||||||
|
.components-placeholder__label svg {
|
||||||
|
fill: currentColor;
|
||||||
|
margin-right: 1ch;
|
||||||
|
}
|
||||||
|
.components-placeholder__fieldset {
|
||||||
|
display: block; /* Disable flex box */
|
||||||
|
}
|
||||||
|
.woocommerce-search-list__search {
|
||||||
|
border-top: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
.wc-block-stock-filter__add-stock-button {
|
||||||
|
margin: 0 0 1em;
|
||||||
|
vertical-align: middle;
|
||||||
|
height: auto;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: currentColor;
|
||||||
|
margin-left: 0.5ch;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.wc-block-stock-filter__read_more_button {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { withRestApiHydration } from '@woocommerce/block-hocs';
|
||||||
|
import { renderFrontend } from '@woocommerce/base-utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import Block from './block.js';
|
||||||
|
|
||||||
|
const getProps = ( el ) => {
|
||||||
|
return {
|
||||||
|
attributes: {
|
||||||
|
showCounts: el.dataset.showCounts === 'true',
|
||||||
|
heading: el.dataset.heading,
|
||||||
|
headingLevel: el.dataset.headingLevel || 3,
|
||||||
|
showFilterButton: el.dataset.showFilterButton === 'true',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
renderFrontend( {
|
||||||
|
selector: '.wp-block-woocommerce-stock-filter',
|
||||||
|
Block: withRestApiHydration( Block ),
|
||||||
|
getProps,
|
||||||
|
} );
|
|
@ -0,0 +1,93 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { registerBlockType } from '@wordpress/blocks';
|
||||||
|
import { Icon, server } from '@woocommerce/icons';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import edit from './edit.js';
|
||||||
|
|
||||||
|
registerBlockType( 'woocommerce/stock-filter', {
|
||||||
|
title: __( 'Filter Products by Stock', 'woo-gutenberg-products-block' ),
|
||||||
|
icon: {
|
||||||
|
src: <Icon srcElement={ server } />,
|
||||||
|
foreground: '#96588a',
|
||||||
|
},
|
||||||
|
category: 'woocommerce',
|
||||||
|
keywords: [ __( 'WooCommerce', 'woo-gutenberg-products-block' ) ],
|
||||||
|
description: __(
|
||||||
|
'Allow customers to filter the grid by products stock status. Works in combination with the All Products block.',
|
||||||
|
'woo-gutenberg-products-block'
|
||||||
|
),
|
||||||
|
supports: {
|
||||||
|
html: false,
|
||||||
|
multiple: false,
|
||||||
|
},
|
||||||
|
example: {
|
||||||
|
attributes: {
|
||||||
|
isPreview: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
attributes: {
|
||||||
|
heading: {
|
||||||
|
type: 'string',
|
||||||
|
default: __(
|
||||||
|
'Filter by stock status',
|
||||||
|
'woo-gutenberg-products-block'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
headingLevel: {
|
||||||
|
type: 'number',
|
||||||
|
default: 3,
|
||||||
|
},
|
||||||
|
showCounts: {
|
||||||
|
type: 'boolean',
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
showFilterButton: {
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Are we previewing?
|
||||||
|
*/
|
||||||
|
isPreview: {
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
edit,
|
||||||
|
// Save the props to post content.
|
||||||
|
save( { attributes } ) {
|
||||||
|
const {
|
||||||
|
className,
|
||||||
|
showCounts,
|
||||||
|
heading,
|
||||||
|
headingLevel,
|
||||||
|
showFilterButton,
|
||||||
|
} = attributes;
|
||||||
|
const data = {
|
||||||
|
'data-show-counts': showCounts,
|
||||||
|
'data-heading': heading,
|
||||||
|
'data-heading-level': headingLevel,
|
||||||
|
};
|
||||||
|
if ( showFilterButton ) {
|
||||||
|
data[ 'data-show-filter-button' ] = showFilterButton;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={ classNames( 'is-loading', className ) }
|
||||||
|
{ ...data }
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-hidden
|
||||||
|
className="wc-block-product-stock-filter__placeholder"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
} );
|
|
@ -0,0 +1,22 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import Label from '@woocommerce/base-components/filter-element-label';
|
||||||
|
|
||||||
|
export const previewOptions = [
|
||||||
|
{
|
||||||
|
value: 'preview-1',
|
||||||
|
name: 'In Stock',
|
||||||
|
label: <Label name="In Stock" count={ 3 } />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'preview-2',
|
||||||
|
name: 'Out of sotck',
|
||||||
|
label: <Label name="Out of stock" count={ 3 } />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'preview-3',
|
||||||
|
name: 'On backorder',
|
||||||
|
label: <Label name="On backorder" count={ 2 } />,
|
||||||
|
},
|
||||||
|
];
|
|
@ -0,0 +1,29 @@
|
||||||
|
.wc-block-stock-filter {
|
||||||
|
margin-bottom: $gap-large;
|
||||||
|
|
||||||
|
.wc-block-stock-filter-list {
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
label {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-single,
|
||||||
|
.wc-block-dropdown-selector .wc-block-dropdown-selector__list {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wc-block-stock-filter__button {
|
||||||
|
margin-top: $gap-smaller;
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ const blocks = {
|
||||||
},
|
},
|
||||||
'price-filter': {},
|
'price-filter': {},
|
||||||
'attribute-filter': {},
|
'attribute-filter': {},
|
||||||
|
'stock-filter': {},
|
||||||
'active-filters': {},
|
'active-filters': {},
|
||||||
cart: {
|
cart: {
|
||||||
customDir: 'cart-checkout/cart',
|
customDir: 'cart-checkout/cart',
|
||||||
|
|
|
@ -27,6 +27,5 @@ class AllProducts extends AbstractBlock {
|
||||||
$this->asset_data_registry->add( 'min_rows', wc_get_theme_support( 'product_blocks::min_rows', 1 ), true );
|
$this->asset_data_registry->add( 'min_rows', wc_get_theme_support( 'product_blocks::min_rows', 1 ), true );
|
||||||
$this->asset_data_registry->add( 'max_rows', wc_get_theme_support( 'product_blocks::max_rows', 6 ), true );
|
$this->asset_data_registry->add( 'max_rows', wc_get_theme_support( 'product_blocks::max_rows', 6 ), true );
|
||||||
$this->asset_data_registry->add( 'default_rows', wc_get_theme_support( 'product_blocks::default_rows', 3 ), true );
|
$this->asset_data_registry->add( 'default_rows', wc_get_theme_support( 'product_blocks::default_rows', 3 ), true );
|
||||||
$this->asset_data_registry->add( 'hideOutOfStockItems', 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ), true );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
namespace Automattic\WooCommerce\Blocks\BlockTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AttributeFilter class.
|
||||||
|
*/
|
||||||
|
class StockFilter extends AbstractBlock {
|
||||||
|
/**
|
||||||
|
* Block name.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $block_name = 'stock-filter';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra data passed through from server to client for block.
|
||||||
|
*
|
||||||
|
* @param array $stock_statuses Any stock statuses that currently are available from the block.
|
||||||
|
* Note, this will be empty in the editor context when the block is
|
||||||
|
* not in the post content on editor load.
|
||||||
|
*/
|
||||||
|
protected function enqueue_data( array $stock_statuses = [] ) {
|
||||||
|
parent::enqueue_data( $stock_statuses );
|
||||||
|
$this->asset_data_registry->add( 'stockStatusOptions', wc_get_product_stock_status_options(), true );
|
||||||
|
$this->asset_data_registry->add( 'hideOutOfStockItems', 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ), true );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -116,6 +116,7 @@ final class BlockTypesController {
|
||||||
'AllProducts',
|
'AllProducts',
|
||||||
'PriceFilter',
|
'PriceFilter',
|
||||||
'AttributeFilter',
|
'AttributeFilter',
|
||||||
|
'StockFilter',
|
||||||
'ActiveFilters',
|
'ActiveFilters',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -139,6 +140,7 @@ final class BlockTypesController {
|
||||||
'AllProducts',
|
'AllProducts',
|
||||||
'PriceFilter',
|
'PriceFilter',
|
||||||
'AttributeFilter',
|
'AttributeFilter',
|
||||||
|
'StockFilter',
|
||||||
'ActiveFilters',
|
'ActiveFilters',
|
||||||
'Cart',
|
'Cart',
|
||||||
'Checkout',
|
'Checkout',
|
||||||
|
|
|
@ -47,10 +47,11 @@ class ProductCollectionData extends AbstractRoute {
|
||||||
*/
|
*/
|
||||||
protected function get_route_response( \WP_REST_Request $request ) {
|
protected function get_route_response( \WP_REST_Request $request ) {
|
||||||
$data = [
|
$data = [
|
||||||
'min_price' => null,
|
'min_price' => null,
|
||||||
'max_price' => null,
|
'max_price' => null,
|
||||||
'attribute_counts' => null,
|
'attribute_counts' => null,
|
||||||
'rating_counts' => null,
|
'stock_status_counts' => null,
|
||||||
|
'rating_counts' => null,
|
||||||
];
|
];
|
||||||
$filters = new ProductQueryFilters();
|
$filters = new ProductQueryFilters();
|
||||||
|
|
||||||
|
@ -64,6 +65,20 @@ class ProductCollectionData extends AbstractRoute {
|
||||||
$data['max_price'] = $price_results->max_price;
|
$data['max_price'] = $price_results->max_price;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! empty( $request['calculate_stock_status_counts'] ) ) {
|
||||||
|
$filter_request = clone $request;
|
||||||
|
$counts = $filters->get_stock_status_counts( $filter_request );
|
||||||
|
|
||||||
|
$data['stock_status_counts'] = [];
|
||||||
|
|
||||||
|
foreach ( $counts as $key => $value ) {
|
||||||
|
$data['stock_status_counts'][] = (object) [
|
||||||
|
'status' => $key,
|
||||||
|
'count' => $value,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! empty( $request['calculate_attribute_counts'] ) ) {
|
if ( ! empty( $request['calculate_attribute_counts'] ) ) {
|
||||||
$taxonomy__or_queries = [];
|
$taxonomy__or_queries = [];
|
||||||
$taxonomy__and_queries = [];
|
$taxonomy__and_queries = [];
|
||||||
|
@ -148,6 +163,12 @@ class ProductCollectionData extends AbstractRoute {
|
||||||
'default' => false,
|
'default' => false,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$params['calculate_stock_status_counts'] = [
|
||||||
|
'description' => __( 'If true, calculates stock counts for products in the collection.', 'woo-gutenberg-products-block' ),
|
||||||
|
'type' => 'boolean',
|
||||||
|
'default' => false,
|
||||||
|
];
|
||||||
|
|
||||||
$params['calculate_attribute_counts'] = [
|
$params['calculate_attribute_counts'] = [
|
||||||
'description' => __( 'If requested, calculates attribute term counts for products in the collection.', 'woo-gutenberg-products-block' ),
|
'description' => __( 'If requested, calculates attribute term counts for products in the collection.', 'woo-gutenberg-products-block' ),
|
||||||
'type' => 'array',
|
'type' => 'array',
|
||||||
|
|
|
@ -29,7 +29,7 @@ class ProductCollectionDataSchema extends AbstractSchema {
|
||||||
*/
|
*/
|
||||||
public function get_properties() {
|
public function get_properties() {
|
||||||
return [
|
return [
|
||||||
'price_range' => [
|
'price_range' => [
|
||||||
'description' => __( 'Min and max prices found in collection of products, provided using the smallest unit of the currency.', 'woo-gutenberg-products-block' ),
|
'description' => __( 'Min and max prices found in collection of products, provided using the smallest unit of the currency.', 'woo-gutenberg-products-block' ),
|
||||||
'type' => [ 'object', 'null' ],
|
'type' => [ 'object', 'null' ],
|
||||||
'context' => [ 'view', 'edit' ],
|
'context' => [ 'view', 'edit' ],
|
||||||
|
@ -52,7 +52,7 @@ class ProductCollectionDataSchema extends AbstractSchema {
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
'attribute_counts' => [
|
'attribute_counts' => [
|
||||||
'description' => __( 'Returns number of products within attribute terms.', 'woo-gutenberg-products-block' ),
|
'description' => __( 'Returns number of products within attribute terms.', 'woo-gutenberg-products-block' ),
|
||||||
'type' => [ 'array', 'null' ],
|
'type' => [ 'array', 'null' ],
|
||||||
'context' => [ 'view', 'edit' ],
|
'context' => [ 'view', 'edit' ],
|
||||||
|
@ -75,7 +75,7 @@ class ProductCollectionDataSchema extends AbstractSchema {
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'rating_counts' => [
|
'rating_counts' => [
|
||||||
'description' => __( 'Returns number of products with each average rating.', 'woo-gutenberg-products-block' ),
|
'description' => __( 'Returns number of products with each average rating.', 'woo-gutenberg-products-block' ),
|
||||||
'type' => [ 'array', 'null' ],
|
'type' => [ 'array', 'null' ],
|
||||||
'context' => [ 'view', 'edit' ],
|
'context' => [ 'view', 'edit' ],
|
||||||
|
@ -98,6 +98,29 @@ class ProductCollectionDataSchema extends AbstractSchema {
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
'stock_status_counts' => [
|
||||||
|
'description' => __( 'Returns number of products with each stock status.', 'woo-gutenberg-products-block' ),
|
||||||
|
'type' => [ 'array', 'null' ],
|
||||||
|
'context' => [ 'view', 'edit' ],
|
||||||
|
'readonly' => true,
|
||||||
|
'items' => [
|
||||||
|
'type' => 'object',
|
||||||
|
'properties' => [
|
||||||
|
'status' => [
|
||||||
|
'description' => __( 'Status', 'woo-gutenberg-products-block' ),
|
||||||
|
'type' => 'string',
|
||||||
|
'context' => [ 'view', 'edit' ],
|
||||||
|
'readonly' => true,
|
||||||
|
],
|
||||||
|
'count' => [
|
||||||
|
'description' => __( 'Number of products.', 'woo-gutenberg-products-block' ),
|
||||||
|
'type' => 'integer',
|
||||||
|
'context' => [ 'view', 'edit' ],
|
||||||
|
'readonly' => true,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,14 +132,15 @@ class ProductCollectionDataSchema extends AbstractSchema {
|
||||||
*/
|
*/
|
||||||
public function get_item_response( $data ) {
|
public function get_item_response( $data ) {
|
||||||
return [
|
return [
|
||||||
'price_range' => ! is_null( $data['min_price'] ) && ! is_null( $data['max_price'] ) ? (object) $this->prepare_currency_response(
|
'price_range' => ! is_null( $data['min_price'] ) && ! is_null( $data['max_price'] ) ? (object) $this->prepare_currency_response(
|
||||||
[
|
[
|
||||||
'min_price' => $this->prepare_money_response( $data['min_price'], wc_get_price_decimals() ),
|
'min_price' => $this->prepare_money_response( $data['min_price'], wc_get_price_decimals() ),
|
||||||
'max_price' => $this->prepare_money_response( $data['max_price'], wc_get_price_decimals() ),
|
'max_price' => $this->prepare_money_response( $data['max_price'], wc_get_price_decimals() ),
|
||||||
]
|
]
|
||||||
) : null,
|
) : null,
|
||||||
'attribute_counts' => $data['attribute_counts'],
|
'attribute_counts' => $data['attribute_counts'],
|
||||||
'rating_counts' => $data['rating_counts'],
|
'rating_counts' => $data['rating_counts'],
|
||||||
|
'stock_status_counts' => $data['stock_status_counts'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,6 +319,9 @@ class ProductQuery {
|
||||||
if ( $wp_query->get( 'stock_status' ) ) {
|
if ( $wp_query->get( 'stock_status' ) ) {
|
||||||
$args['join'] = $this->append_product_sorting_table_join( $args['join'] );
|
$args['join'] = $this->append_product_sorting_table_join( $args['join'] );
|
||||||
$args['where'] .= ' AND wc_product_meta_lookup.stock_status IN ("' . implode( '","', array_map( 'esc_sql', $wp_query->get( 'stock_status' ) ) ) . '")';
|
$args['where'] .= ' AND wc_product_meta_lookup.stock_status IN ("' . implode( '","', array_map( 'esc_sql', $wp_query->get( 'stock_status' ) ) ) . '")';
|
||||||
|
} elseif ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
|
||||||
|
$args['join'] = $this->append_product_sorting_table_join( $args['join'] );
|
||||||
|
$args['where'] .= ' AND wc_product_meta_lookup.stock_status NOT IN ("outofstock")';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $wp_query->get( 'min_price' ) || $wp_query->get( 'max_price' ) ) {
|
if ( $wp_query->get( 'min_price' ) || $wp_query->get( 'max_price' ) ) {
|
||||||
|
|
|
@ -47,6 +47,72 @@ class ProductQueryFilters {
|
||||||
return $wpdb->get_row( $price_filter_sql ); // phpcs:ignore
|
return $wpdb->get_row( $price_filter_sql ); // phpcs:ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get stock status counts for the current products.
|
||||||
|
*
|
||||||
|
* @param \WP_REST_Request $request The request object.
|
||||||
|
* @return array status=>count pairs.
|
||||||
|
*/
|
||||||
|
public function get_stock_status_counts( $request ) {
|
||||||
|
global $wpdb;
|
||||||
|
$product_query = new ProductQuery();
|
||||||
|
$stock_status_options = array_map( 'esc_sql', array_keys( wc_get_product_stock_status_options() ) );
|
||||||
|
$hide_outofstock_items = get_option( 'woocommerce_hide_out_of_stock_items' );
|
||||||
|
if ( 'yes' === $hide_outofstock_items ) {
|
||||||
|
unset( $stock_status_options['outofstock'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
add_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10, 2 );
|
||||||
|
add_filter( 'posts_pre_query', '__return_empty_array' );
|
||||||
|
|
||||||
|
$query_args = $product_query->prepare_objects_query( $request );
|
||||||
|
unset( $query_args['stock_status'] );
|
||||||
|
$query_args['no_found_rows'] = true;
|
||||||
|
$query_args['posts_per_page'] = -1;
|
||||||
|
$query = new \WP_Query();
|
||||||
|
$result = $query->query( $query_args );
|
||||||
|
$product_query_sql = $query->request;
|
||||||
|
|
||||||
|
remove_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10 );
|
||||||
|
remove_filter( 'posts_pre_query', '__return_empty_array' );
|
||||||
|
|
||||||
|
$stock_status_counts = array();
|
||||||
|
|
||||||
|
foreach ( $stock_status_options as $status ) {
|
||||||
|
$stock_status_count_sql = $this->generate_stock_status_count_query( $status, $product_query_sql, $stock_status_options );
|
||||||
|
|
||||||
|
$result = $wpdb->get_row( $stock_status_count_sql ); // phpcs:ignore
|
||||||
|
$stock_status_counts[ $status ] = $result->status_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $stock_status_counts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate calculate query by stock status.
|
||||||
|
*
|
||||||
|
* @param string $status status to calculate.
|
||||||
|
* @param string $product_query_sql product query for current filter state.
|
||||||
|
* @param array $stock_status_options available stock status options.
|
||||||
|
*
|
||||||
|
* @return false|string
|
||||||
|
*/
|
||||||
|
private function generate_stock_status_count_query( $status, $product_query_sql, $stock_status_options ) {
|
||||||
|
if ( ! in_array( $status, $stock_status_options, true ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
global $wpdb;
|
||||||
|
$status = esc_sql( $status );
|
||||||
|
return "
|
||||||
|
SELECT COUNT( DISTINCT posts.ID ) as status_count
|
||||||
|
FROM {$wpdb->posts} as posts
|
||||||
|
INNER JOIN {$wpdb->postmeta} as postmeta ON posts.ID = postmeta.post_id
|
||||||
|
AND postmeta.meta_key = '_stock_status'
|
||||||
|
AND postmeta.meta_value = '{$status}'
|
||||||
|
WHERE posts.ID IN ( {$product_query_sql} )
|
||||||
|
";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get attribute counts for the current products.
|
* Get attribute counts for the current products.
|
||||||
*
|
*
|
||||||
|
|
|
@ -100,6 +100,7 @@ const LegacyMainConfig = {
|
||||||
'all-products',
|
'all-products',
|
||||||
'price-filter',
|
'price-filter',
|
||||||
'attribute-filter',
|
'attribute-filter',
|
||||||
|
'stock-filter',
|
||||||
'active-filters',
|
'active-filters',
|
||||||
'checkout',
|
'checkout',
|
||||||
'cart',
|
'cart',
|
||||||
|
@ -123,6 +124,7 @@ const LegacyFrontendConfig = {
|
||||||
'all-products',
|
'all-products',
|
||||||
'price-filter',
|
'price-filter',
|
||||||
'attribute-filter',
|
'attribute-filter',
|
||||||
|
'stock-filter',
|
||||||
'active-filters',
|
'active-filters',
|
||||||
'checkout',
|
'checkout',
|
||||||
'cart',
|
'cart',
|
||||||
|
@ -139,6 +141,7 @@ const LegacyStylingConfig = {
|
||||||
'all-products',
|
'all-products',
|
||||||
'price-filter',
|
'price-filter',
|
||||||
'attribute-filter',
|
'attribute-filter',
|
||||||
|
'stock-filter',
|
||||||
'active-filters',
|
'active-filters',
|
||||||
'checkout',
|
'checkout',
|
||||||
'cart',
|
'cart',
|
||||||
|
|
Loading…
Reference in New Issue