Merge branch 'fix/49635-48841-refunded-taxes' into fix/49635-tax-totals
This commit is contained in:
commit
6c6ef915ef
|
@ -20,8 +20,8 @@ To get up and running within the WooCommerce Monorepo, you will need to make sur
|
||||||
Once you've installed all of the prerequisites, you can run the following commands to get everything working.
|
Once you've installed all of the prerequisites, you can run the following commands to get everything working.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Ensure that you're using the correct version of Node
|
# Ensure that correct version of Node is installed and being used
|
||||||
nvm use
|
nvm install
|
||||||
# Install the PHP and Composer dependencies for all of the plugins, packages, and tools
|
# Install the PHP and Composer dependencies for all of the plugins, packages, and tools
|
||||||
pnpm install
|
pnpm install
|
||||||
# Build all of the plugins, packages, and tools in the monorepo
|
# Build all of the plugins, packages, and tools in the monorepo
|
||||||
|
|
240
changelog.txt
240
changelog.txt
|
@ -1,5 +1,245 @@
|
||||||
== Changelog ==
|
== Changelog ==
|
||||||
|
|
||||||
|
= 9.3.1 2024-09-12 =
|
||||||
|
|
||||||
|
* Tweak - Disable remote logging feature by default [#51312](https://github.com/woocommerce/woocommerce/pull/51312)
|
||||||
|
|
||||||
|
= 9.3.0 2024-09-10 =
|
||||||
|
|
||||||
|
**WooCommerce**
|
||||||
|
|
||||||
|
* Enhancement - Add query params masking to remote logger [#51108](https://github.com/woocommerce/woocommerce/pull/51108)
|
||||||
|
* Update - Added more paths to remote logger query param whitelist [#51108](https://github.com/woocommerce/woocommerce/pull/51108)
|
||||||
|
* Fix - Revert update to React 18 in Checkout block. [#51289](https://github.com/woocommerce/woocommerce/pull/51289)
|
||||||
|
* Fix - Add check to ensure themes API is safe [#51081](https://github.com/woocommerce/woocommerce/pull/51081)
|
||||||
|
* Fix - CYS - Remove usage of `prepare_item_for_response` function in `Images` endpoint. [#50923](https://github.com/woocommerce/woocommerce/pull/50923)
|
||||||
|
* Fix - Add ability for a screen reader to announce the current tab on a single product page. [#50373](https://github.com/woocommerce/woocommerce/pull/50373)
|
||||||
|
* Fix - Add a label to the product pagination for the woocommerce pagination [#49924](https://github.com/woocommerce/woocommerce/pull/49924)
|
||||||
|
* Fix - Add aria-current to the current link in My Account side nav [#49800](https://github.com/woocommerce/woocommerce/pull/49800)
|
||||||
|
* Fix - Add aria-label on View order button to aid in accessibility for screen readers [#49424](https://github.com/woocommerce/woocommerce/pull/49424)
|
||||||
|
* Fix - Add CSS outline for site visibility badge keyboard accessibility [#50794](https://github.com/woocommerce/woocommerce/pull/50794)
|
||||||
|
* Fix - Add scope attribute and aria-label to the product attributes table [#49768](https://github.com/woocommerce/woocommerce/pull/49768)
|
||||||
|
* Fix - Add to Cart with Options - Fix translation when used inside the Single Product block. [#50628](https://github.com/woocommerce/woocommerce/pull/50628)
|
||||||
|
* Fix - Allow verified parameter to be set by REST API request [#50525](https://github.com/woocommerce/woocommerce/pull/50525)
|
||||||
|
* Fix - Avoid PHP warnings if `add-to-cart.php` template does not pass `aria-describedby_text` [#48969](https://github.com/woocommerce/woocommerce/pull/48969)
|
||||||
|
* Fix - Cart block: Strip HTML tags and decode HTML entities in quantity change notifications. [#50541](https://github.com/woocommerce/woocommerce/pull/50541)
|
||||||
|
* Fix - Changed from using React.render to React.createRoot for marketing coupons as it has been deprecated since React 18 [#48832](https://github.com/woocommerce/woocommerce/pull/48832)
|
||||||
|
* Fix - Changed from using React.render to React.createRoot for payment methods promotion, shipping settings region zone as it has been deprecated since React 18 [#48835](https://github.com/woocommerce/woocommerce/pull/48835)
|
||||||
|
* Fix - Changed from using React.render to React.createRoot for print shipping banner as it has been deprecated since React 18 [#48831](https://github.com/woocommerce/woocommerce/pull/48831)
|
||||||
|
* Fix - Changed from using React.render to React.createRoot for product-usage-notice-modal as it has been deprecated since React 18 [#50765](https://github.com/woocommerce/woocommerce/pull/50765)
|
||||||
|
* Fix - Changed from using React.render to React.createRoot for wc addon tour as it has been deprecated since React 18 [#48833](https://github.com/woocommerce/woocommerce/pull/48833)
|
||||||
|
* Fix - Changed from using React.render to React.createRoot for WCAdmin uses as it has been deprecated since React 18 [#48785](https://github.com/woocommerce/woocommerce/pull/48785)
|
||||||
|
* Fix - Changed instances of prime marks inappropriately used when apostrophes are supposed to be used for some parts of WC Admin JS/TS/TSX files [#50776](https://github.com/woocommerce/woocommerce/pull/50776)
|
||||||
|
* Fix - Clear product unique ID (`global_unique_id`) when duplicating products. [#50629](https://github.com/woocommerce/woocommerce/pull/50629)
|
||||||
|
* Fix - Compatibility Layer: fix 'woocommerce_before_single_product_summary' hook position. [#50392](https://github.com/woocommerce/woocommerce/pull/50392)
|
||||||
|
* Fix - CYS - Improve the error when a request fails due to permissions [#50211](https://github.com/woocommerce/woocommerce/pull/50211)
|
||||||
|
* Fix - CYS - Update the "show_on_front" setting to "posts" to avoid overriding the "page" template. [#50083](https://github.com/woocommerce/woocommerce/pull/50083)
|
||||||
|
* Fix - CYS: disable zoom out on fonts/color pairs iframe [#50498](https://github.com/woocommerce/woocommerce/pull/50498)
|
||||||
|
* Fix - CYS: Fix auto scroll when a new block is added. [#50431](https://github.com/woocommerce/woocommerce/pull/50431)
|
||||||
|
* Fix - CYS: Improve opt in flow [#50529](https://github.com/woocommerce/woocommerce/pull/50529)
|
||||||
|
* Fix - Display address card for virtual products if shopper's address is known [#50127](https://github.com/woocommerce/woocommerce/pull/50127)
|
||||||
|
* Fix - Enable skipped E2E tests for attributes #50143 [#50143](https://github.com/woocommerce/woocommerce/pull/50143)
|
||||||
|
* Fix - Ensure coupon errors are visible on block checkout when invalid coupons are removed. [#50412](https://github.com/woocommerce/woocommerce/pull/50412)
|
||||||
|
* Fix - Ensure low and no stock email notification routine is triggered whenever product stock changes [#49583](https://github.com/woocommerce/woocommerce/pull/49583)
|
||||||
|
* Fix - Ensure session object is initialized before attempting to get chosen shipping methods [#50774](https://github.com/woocommerce/woocommerce/pull/50774)
|
||||||
|
* Fix - Ensure that the orders REST endpoint behaves the same as the UI when updating an order to remove a line item. [#50606](https://github.com/woocommerce/woocommerce/pull/50606)
|
||||||
|
* Fix - Featured Product: Fix variable product Selection dropdown #50633 [#50633](https://github.com/woocommerce/woocommerce/pull/50633)
|
||||||
|
* Fix - Fix "Product Meta" translations - Register the block server side. [#50625](https://github.com/woocommerce/woocommerce/pull/50625)
|
||||||
|
* Fix - Fix: ensure the global product object is always ready for compatibility layer by disabling default render routine of Product Templates inner blocks. [#49971](https://github.com/woocommerce/woocommerce/pull/49971)
|
||||||
|
* Fix - Fix activating the installed subscription when the user has multiple active licenses for the same product. [#49803](https://github.com/woocommerce/woocommerce/pull/49803)
|
||||||
|
* Fix - Fix address heading level on My Account page. [#49764](https://github.com/woocommerce/woocommerce/pull/49764)
|
||||||
|
* Fix - Fix an admin bar CSS positioning bug in WordPress.com on mobile [#50709](https://github.com/woocommerce/woocommerce/pull/50709)
|
||||||
|
* Fix - Fix cart shortcode updates when not used on the main cart page. [#50524](https://github.com/woocommerce/woocommerce/pull/50524)
|
||||||
|
* Fix - Fix core profiler checkbox vertical alignment and border color [#50151](https://github.com/woocommerce/woocommerce/pull/50151)
|
||||||
|
* Fix - Fix core profiler set up my store button and TOS are too close to each other [#50579](https://github.com/woocommerce/woocommerce/pull/50579)
|
||||||
|
* Fix - Fix e2e Google for WooCommerce strict mode violation error [#50189](https://github.com/woocommerce/woocommerce/pull/50189)
|
||||||
|
* Fix - Fixed Core Profiler's sticky footer button problem [#50727](https://github.com/woocommerce/woocommerce/pull/50727)
|
||||||
|
* Fix - Fixed placeholders in the classic cart shipping calculator to update with country selection. [#49684](https://github.com/woocommerce/woocommerce/pull/49684)
|
||||||
|
* Fix - Fixes a bug where some express payment buttons weren't being rendered correctly [#49304](https://github.com/woocommerce/woocommerce/pull/49304)
|
||||||
|
* Fix - Fix extensionCartUpdates to surface generic error messages, and include documentation for the error handling. [#49762](https://github.com/woocommerce/woocommerce/pull/49762)
|
||||||
|
* Fix - Fix focus order on checkout block page. [#49649](https://github.com/woocommerce/woocommerce/pull/49649)
|
||||||
|
* Fix - Fix navigation badge decreases when installing extension in "Grow your business task" [#50584](https://github.com/woocommerce/woocommerce/pull/50584)
|
||||||
|
* Fix - Fix page titles of the cart and checkout page when using blocks and FSE themes. [#49986](https://github.com/woocommerce/woocommerce/pull/49986)
|
||||||
|
* Fix - Fix rescheduling of actions that are blocked by other delayed actions [#50082](https://github.com/woocommerce/woocommerce/pull/50082)
|
||||||
|
* Fix - Fix the "Add payment methods" link in LYS congrat screen redirects to a blank page [#50609](https://github.com/woocommerce/woocommerce/pull/50609)
|
||||||
|
* Fix - Fix translation - Avoid registering blocks in the wrong context. [#50615](https://github.com/woocommerce/woocommerce/pull/50615)
|
||||||
|
* Fix - Fix `Product meta` console error. [#50680](https://github.com/woocommerce/woocommerce/pull/50680)
|
||||||
|
* Fix - Fix `store-title` endpoint - Pass default value to `get_option`. [#50673](https://github.com/woocommerce/woocommerce/pull/50673)
|
||||||
|
* Fix - Hide save changes button in main payments screen [#50064](https://github.com/woocommerce/woocommerce/pull/50064)
|
||||||
|
* Fix - In Remote Specs, treat empty arrays as valid cached values so individual engines can return default values. [#50521](https://github.com/woocommerce/woocommerce/pull/50521)
|
||||||
|
* Fix - Keep focus on shipping option input once selected [#49360](https://github.com/woocommerce/woocommerce/pull/49360)
|
||||||
|
* Fix - Make the matching variations alert a live region [#50132](https://github.com/woocommerce/woocommerce/pull/50132)
|
||||||
|
* Fix - Only count published products in productCount [#50503](https://github.com/woocommerce/woocommerce/pull/50503)
|
||||||
|
* Fix - Prevent fatal error if NULL is provided in array_search under Jetpack Stats [#50696](https://github.com/woocommerce/woocommerce/pull/50696)
|
||||||
|
* Fix - Prevent Store API orders being placed with empty state [#50028](https://github.com/woocommerce/woocommerce/pull/50028)
|
||||||
|
* Fix - Prevent sync-on-read from affecting results of HPOS diff CLI tool. [#49726](https://github.com/woocommerce/woocommerce/pull/49726)
|
||||||
|
* Fix - Product Collection: Fix max price query to include prices less or equal to the given max value. [#49917](https://github.com/woocommerce/woocommerce/pull/49917)
|
||||||
|
* Fix - Product Collection: fix the preview if used in Products by specific Category or Tag [#49889](https://github.com/woocommerce/woocommerce/pull/49889)
|
||||||
|
* Fix - Product Price block: prevent price amounts from breaking into multiple lines [#50660](https://github.com/woocommerce/woocommerce/pull/50660)
|
||||||
|
* Fix - Properly detect active plugins in multisite WP installations. [#50417](https://github.com/woocommerce/woocommerce/pull/50417)
|
||||||
|
* Fix - Reduce error noise in the user profile screen, by removing the requirement for custom fields to have a class attribute. [#48079](https://github.com/woocommerce/woocommerce/pull/48079)
|
||||||
|
* Fix - Remove Active Shipping Zones check for displaying shipping calculator on the Cart Page. [#49214](https://github.com/woocommerce/woocommerce/pull/49214)
|
||||||
|
* Fix - Single product block - Fix translation for title and description in edit mode. [#50599](https://github.com/woocommerce/woocommerce/pull/50599)
|
||||||
|
* Fix - Store API: Do not resume pending orders--create a new order instead [#50531](https://github.com/woocommerce/woocommerce/pull/50531)
|
||||||
|
* Fix - Transform labels in shipping zone region selector to decode html entities [#50694](https://github.com/woocommerce/woocommerce/pull/50694)
|
||||||
|
* Fix - Treat post_type=product as a shop page. [#50567](https://github.com/woocommerce/woocommerce/pull/50567)
|
||||||
|
* Fix - Update product order status colors to ensure accessible color contrasts [#49934](https://github.com/woocommerce/woocommerce/pull/49934)
|
||||||
|
* Add - Add an additional field for the email settings that sets the footer text color [#49648](https://github.com/woocommerce/woocommerce/pull/49648)
|
||||||
|
* Add - Add blueprint behind a feature flag for testing purposes. [#49763](https://github.com/woocommerce/woocommerce/pull/49763)
|
||||||
|
* Add - Add field for the email footer text color [#49648](https://github.com/woocommerce/woocommerce/pull/49648)
|
||||||
|
* Add - Add function to clear system status theme info cache [#50803](https://github.com/woocommerce/woocommerce/pull/50803)
|
||||||
|
* Add - Add methods required by extensions to control product feature usage based on subscription status. [#50218](https://github.com/woocommerce/woocommerce/pull/50218)
|
||||||
|
* Add - Add parameter to avoid attempting to create the logs directory if it doesn't exist [#49766](https://github.com/woocommerce/woocommerce/pull/49766)
|
||||||
|
* Add - Add Pattern button to no blocks view on the CYS assembler [#49981](https://github.com/woocommerce/woocommerce/pull/49981)
|
||||||
|
* Add - Add reactified main payments screen [#49972](https://github.com/woocommerce/woocommerce/pull/49972)
|
||||||
|
* Add - Add reactify-classic-payments-settings feature flag [#49966](https://github.com/woocommerce/woocommerce/pull/49966)
|
||||||
|
* Add - Add tracks for WordPress Importer/Export pages. [#50769](https://github.com/woocommerce/woocommerce/pull/50769)
|
||||||
|
* Add - Add `FilteredGetDataTrait`, `OrderAwareControllerTrait`, and `StatsDataStoreTrait` for extension developers to reuse while creating custom Analytics [#49425](https://github.com/woocommerce/woocommerce/pull/49425)
|
||||||
|
* Add - Implement server-side remote error logging [#49599](https://github.com/woocommerce/woocommerce/pull/49599)
|
||||||
|
* Add - Inform screen reader users when mini cart updates [#48295](https://github.com/woocommerce/woocommerce/pull/48295)
|
||||||
|
* Add - Integrate JS remote logging package in WooCommerce Admin [#50134](https://github.com/woocommerce/woocommerce/pull/50134)
|
||||||
|
* Add - Product Collection: emit the JS event when PC block is rendered [#50166](https://github.com/woocommerce/woocommerce/pull/50166)
|
||||||
|
* Add - Product Collection: Enable Context-Aware Previews by Adding `usesReference` to `registerProductCollection` [#49796](https://github.com/woocommerce/woocommerce/pull/49796)
|
||||||
|
* Add - Track frequency of unhandled JS errors with MC Stats [#50155](https://github.com/woocommerce/woocommerce/pull/50155)
|
||||||
|
* Add - Use MC Stats for PHP fatal error counting [#49658](https://github.com/woocommerce/woocommerce/pull/49658)
|
||||||
|
* Add - [E2E tests]: Add product description using the block editor #50232 [#50232](https://github.com/woocommerce/woocommerce/pull/50232)
|
||||||
|
* Update - Update WooCommerce Shipping Promo Banner to install the latest version of WooCommerce Shipping instead of WCS&T. [#50970](https://github.com/woocommerce/woocommerce/pull/50970)
|
||||||
|
* Update - Add abbreviations for fields GTIN, UPC, EAN, OR ISBN [#50042](https://github.com/woocommerce/woocommerce/pull/50042)
|
||||||
|
* Update - Add additional fields to new product editor e2e tests. [#50241](https://github.com/woocommerce/woocommerce/pull/50241)
|
||||||
|
* Update - Add confirmation prompt for site visibility settings when changing from live to coming soon mode [#50759](https://github.com/woocommerce/woocommerce/pull/50759)
|
||||||
|
* Update - Add pattern validation for global_unique_id [#50501](https://github.com/woocommerce/woocommerce/pull/50501)
|
||||||
|
* Update - Add remote logger as a log handler to wc logger [#50430](https://github.com/woocommerce/woocommerce/pull/50430)
|
||||||
|
* Update - Add request_uri prop to remote logging data [#50671](https://github.com/woocommerce/woocommerce/pull/50671)
|
||||||
|
* Update - Add woocommerce_coming_soon option for all sites [#50581](https://github.com/woocommerce/woocommerce/pull/50581)
|
||||||
|
* Update - Comment: Fix typos in documentation. [#50282](https://github.com/woocommerce/woocommerce/pull/50282)
|
||||||
|
* Update - CYS - Add tests for the Full Composability feature. [#49748](https://github.com/woocommerce/woocommerce/pull/49748)
|
||||||
|
* Update - CYS - Run appropriate tests depending on the WordPress version. [#50016](https://github.com/woocommerce/woocommerce/pull/50016)
|
||||||
|
* Update - CYS - Update icon and text colors in the assembler. [#50478](https://github.com/woocommerce/woocommerce/pull/50478)
|
||||||
|
* Update - CYS: Improve opt-in flow fonts. [#50086](https://github.com/woocommerce/woocommerce/pull/50086)
|
||||||
|
* Update - CYS: Improve opt-in flow patterns. [#50080](https://github.com/woocommerce/woocommerce/pull/50080)
|
||||||
|
* Update - CYS: Improve tracking survey [#50196](https://github.com/woocommerce/woocommerce/pull/50196)
|
||||||
|
* Update - CYS: Improve tracking survey [#50354](https://github.com/woocommerce/woocommerce/pull/50354)
|
||||||
|
* Update - CYS: Update the tracking URL to the external Fiverr link in sidebar of the **Add your logo** screen. [#50753](https://github.com/woocommerce/woocommerce/pull/50753)
|
||||||
|
* Update - Enable remote logging feature flag [#50351](https://github.com/woocommerce/woocommerce/pull/50351)
|
||||||
|
* Update - feat: add `aria-required` attributes to WC form fields [#48371](https://github.com/woocommerce/woocommerce/pull/48371)
|
||||||
|
* Update - Fixed log-out link behavior so that redirects work, and so that security nonces are automatically added to link in navigation menus. [#49605](https://github.com/woocommerce/woocommerce/pull/49605)
|
||||||
|
* Update - Migrate LYS user meta [#50664](https://github.com/woocommerce/woocommerce/pull/50664)
|
||||||
|
* Update - Move marketing task to things to do next task list [#50487](https://github.com/woocommerce/woocommerce/pull/50487)
|
||||||
|
* Update - Move site visibility badge to admin bar. [#50775](https://github.com/woocommerce/woocommerce/pull/50775)
|
||||||
|
* Update - Remove "Need help?" modal from onboarding [#47812](https://github.com/woocommerce/woocommerce/pull/47812)
|
||||||
|
* Update - Remove all links from the CYS sidebars [#50414](https://github.com/woocommerce/woocommerce/pull/50414)
|
||||||
|
* Update - Remove remote API call from marketing task [#50479](https://github.com/woocommerce/woocommerce/pull/50479)
|
||||||
|
* Update - Remove WooCommerce Navigation client side feature and deprecate PHP classes. [#50190](https://github.com/woocommerce/woocommerce/pull/50190)
|
||||||
|
* Update - Renamed columns inside In-App Marketplace > My subscriptions and added action to turn auto-renewal on for a subscription [#49985](https://github.com/woocommerce/woocommerce/pull/49985)
|
||||||
|
* Update - Rename woocommerce_is_store_page to woocommerce_is_extension_store_page [#50771](https://github.com/woocommerce/woocommerce/pull/50771)
|
||||||
|
* Update - Reverting the new `buttonAttributes` API. This will be included in a later release [#50763](https://github.com/woocommerce/woocommerce/pull/50763)
|
||||||
|
* Update - Revert the Zoom Out feature for the CYS experience [#50535](https://github.com/woocommerce/woocommerce/pull/50535)
|
||||||
|
* Update - Show expiring and expired notices to active and unconnected subscriptions [#50383](https://github.com/woocommerce/woocommerce/pull/50383)
|
||||||
|
* Update - Store API: Remove the need for nonces when using cart tokens. Remove deprecated X-WC-Store-API-Nonce header. [#50025](https://github.com/woocommerce/woocommerce/pull/50025)
|
||||||
|
* Update - Strip HTML tags from aria-label in wc_help_tip function [#50103](https://github.com/woocommerce/woocommerce/pull/50103)
|
||||||
|
* Update - Text adjustments on shipping zones settings page [#50136](https://github.com/woocommerce/woocommerce/pull/50136)
|
||||||
|
* Update - Update AdditionalPayments task to use default payment gateways [#50674](https://github.com/woocommerce/woocommerce/pull/50674)
|
||||||
|
* Update - Update add product task button section UI [#50580](https://github.com/woocommerce/woocommerce/pull/50580)
|
||||||
|
* Update - Update all blocks to use API Version 3. [#48720](https://github.com/woocommerce/woocommerce/pull/48720)
|
||||||
|
* Update - Update Blueprint settings layout. [#50724](https://github.com/woocommerce/woocommerce/pull/50724)
|
||||||
|
* Update - Update core profiler continue button container on extension screen [#50582](https://github.com/woocommerce/woocommerce/pull/50582)
|
||||||
|
* Update - Update Store Alert actions to have unique keys. [#50424](https://github.com/woocommerce/woocommerce/pull/50424)
|
||||||
|
* Update - Update WooCommercePayments task is_supported to use default suggestions [#50585](https://github.com/woocommerce/woocommerce/pull/50585)
|
||||||
|
* Update - Enhance CSV path and upload handling in product import [#51344](https://github.com/woocommerce/woocommerce/pull/51344)
|
||||||
|
* Dev - Execute test env setup on host instead of wp-env container [#51021](https://github.com/woocommerce/woocommerce/pull/51021)
|
||||||
|
* Dev - Added code docs with examples to the Analytics classes [#49425](https://github.com/woocommerce/woocommerce/pull/49425)
|
||||||
|
* Dev - Add lost password e2e tests [#50611](https://github.com/woocommerce/woocommerce/pull/50611)
|
||||||
|
* Dev - Add unit tests for the product_add_publish track. [#49916](https://github.com/woocommerce/woocommerce/pull/49916)
|
||||||
|
* Dev - CI: introduce PHPUnit tests sharding. [#50084](https://github.com/woocommerce/woocommerce/pull/50084)
|
||||||
|
* Dev - CI: minor speed boost of wp-env startup. [#50445](https://github.com/woocommerce/woocommerce/pull/50445)
|
||||||
|
* Dev - CI: speedup assets size verification job execution time. [#50178](https://github.com/woocommerce/woocommerce/pull/50178)
|
||||||
|
* Dev - CI: Use a single shard when re-running failed tests in CI [#50492](https://github.com/woocommerce/woocommerce/pull/50492)
|
||||||
|
* Dev - CI config: update changes list to include more paths [#50399](https://github.com/woocommerce/woocommerce/pull/50399)
|
||||||
|
* Dev - Clean up unused images [#50516](https://github.com/woocommerce/woocommerce/pull/50516)
|
||||||
|
* Dev - CYS - Document possible Intro pages [#50171](https://github.com/woocommerce/woocommerce/pull/50171)
|
||||||
|
* Dev - CYS - Move the "ai/patterns" endpoint to woocommerce admin API. [#50372](https://github.com/woocommerce/woocommerce/pull/50372)
|
||||||
|
* Dev - CYS - Move the "ai/store-info" endpoint to woocommerce admin API [#50363](https://github.com/woocommerce/woocommerce/pull/50363)
|
||||||
|
* Dev - CYS - Move the ai/business-description endpoint to woocommerce admin API [#50359](https://github.com/woocommerce/woocommerce/pull/50359)
|
||||||
|
* Dev - CYS - Move the ai/store-title endpoint to woocommerce admin API [#50352](https://github.com/woocommerce/woocommerce/pull/50352)
|
||||||
|
* Dev - CYS - Move the `ai/images` endpoint to woocommerce admin API [#50365](https://github.com/woocommerce/woocommerce/pull/50365)
|
||||||
|
* Dev - CYS - Move the `ai/product` endpoint to woocommerce admin API. [#50393](https://github.com/woocommerce/woocommerce/pull/50393)
|
||||||
|
* Dev - CYS: add E2E tests for fonts installation. [#50210](https://github.com/woocommerce/woocommerce/pull/50210)
|
||||||
|
* Dev - E2E tests: add a flaky test reporter for Core e2e tests [#50259](https://github.com/woocommerce/woocommerce/pull/50259)
|
||||||
|
* Dev - E2E tests: add an option to skip the env setup script running before test execution [#50620](https://github.com/woocommerce/woocommerce/pull/50620)
|
||||||
|
* Dev - E2E tests: add buildkite-test-collector for blocks e2e tests [#50642](https://github.com/woocommerce/woocommerce/pull/50642)
|
||||||
|
* Dev - E2E tests: add environment reporter [#49988](https://github.com/woocommerce/woocommerce/pull/49988)
|
||||||
|
* Dev - E2E tests: add hpos-disabled env and tagged tests with hpos tag [#50448](https://github.com/woocommerce/woocommerce/pull/50448)
|
||||||
|
* Dev - E2E tests: fixed broken logo picker tests [#50473](https://github.com/woocommerce/woocommerce/pull/50473)
|
||||||
|
* Dev - E2E tests: fix flakiness in page-loads customer page test [#50559](https://github.com/woocommerce/woocommerce/pull/50559)
|
||||||
|
* Dev - E2E tests: fix flakiness in product attributes test [#50485](https://github.com/woocommerce/woocommerce/pull/50485)
|
||||||
|
* Dev - E2E tests: removed Github reporter [#50256](https://github.com/woocommerce/woocommerce/pull/50256)
|
||||||
|
* Dev - E2E tests: Removed unnecessary pause in the test [#50043](https://github.com/woocommerce/woocommerce/pull/50043)
|
||||||
|
* Dev - E2E tests for verifying approve, spam and reply to product reviews. [#50060](https://github.com/woocommerce/woocommerce/pull/50060)
|
||||||
|
* Dev - Fix E2E tests SKU field id #49729 [#49729](https://github.com/woocommerce/woocommerce/pull/49729)
|
||||||
|
* Dev - Fixes a flaky product variations e2e test [#50807](https://github.com/woocommerce/woocommerce/pull/50807)
|
||||||
|
* Dev - Fix Metrics CI job [#50214](https://github.com/woocommerce/woocommerce/pull/50214)
|
||||||
|
* Dev - Fix optional param in PHPdoc for `WC_Admin_Marketplace_Promotions` to generate code-reference w/o warnings [#50732](https://github.com/woocommerce/woocommerce/pull/50732)
|
||||||
|
* Dev - Fix the Metrics job by adding a missing NVM install step [#50482](https://github.com/woocommerce/woocommerce/pull/50482)
|
||||||
|
* Dev - Make the Metrics tests use utilities provided by the updated @wordpress/e2e-test-utils-playwright package. [#50626](https://github.com/woocommerce/woocommerce/pull/50626)
|
||||||
|
* Dev - Mark ReportTable tableData prop as not required [#50816](https://github.com/woocommerce/woocommerce/pull/50816)
|
||||||
|
* Dev - Monorepo: enable new linting rules for PHP (PSR-4 naming, Strict types declaration). [#49438](https://github.com/woocommerce/woocommerce/pull/49438)
|
||||||
|
* Dev - Monorepo: tweak Webpack loaders paths filtering for better build perfromance. [#49714](https://github.com/woocommerce/woocommerce/pull/49714)
|
||||||
|
* Dev - move block theme docs to docs site folder [#50638](https://github.com/woocommerce/woocommerce/pull/50638)
|
||||||
|
* Dev - move part of checkout docs to main docs folder [#49984](https://github.com/woocommerce/woocommerce/pull/49984)
|
||||||
|
* Dev - Move `ReportError` to `@woocommerce/components` as `AnalyticsError` [#50108](https://github.com/woocommerce/woocommerce/pull/50108)
|
||||||
|
* Dev - moving product collection docs to main docs folder [#50368](https://github.com/woocommerce/woocommerce/pull/50368)
|
||||||
|
* Dev - Reduce duplicated code in Analytics controllers, unify their behavior and API. [#49425](https://github.com/woocommerce/woocommerce/pull/49425)
|
||||||
|
* Dev - Reduce the amount of duplicated code in Analytics `DataStore`s. [#49425](https://github.com/woocommerce/woocommerce/pull/49425)
|
||||||
|
* Dev - Removed defaultProps from React functional components since they will be deprecated for React 19 [#50266](https://github.com/woocommerce/woocommerce/pull/50266)
|
||||||
|
* Dev - Removed directive to disable woocommerce_coming_soon in e2e tests so that we get better test coverage [#50344](https://github.com/woocommerce/woocommerce/pull/50344)
|
||||||
|
* Dev - Render a React placeholder for offline and WooCommerce Payments settings sections [#50008](https://github.com/woocommerce/woocommerce/pull/50008)
|
||||||
|
* Dev - Replace `Automattic\WooCommerce\Admin\API\Reports\*\Query` classes with a single `GenericQuery` class. [#49425](https://github.com/woocommerce/woocommerce/pull/49425)
|
||||||
|
* Dev - Switch `render()` to `createRoot().render()` to use React 18 features. [#48843](https://github.com/woocommerce/woocommerce/pull/48843)
|
||||||
|
* Dev - Tests: moved api core tests as a suite in e2e-pw [#50024](https://github.com/woocommerce/woocommerce/pull/50024)
|
||||||
|
* Dev - Tweak the lost password e2e logic [#50666](https://github.com/woocommerce/woocommerce/pull/50666)
|
||||||
|
* Dev - Update @wordpress/e2e-test-utils-playwright core dependency to wp-6.6 [#50274](https://github.com/woocommerce/woocommerce/pull/50274)
|
||||||
|
* Dev - Updated e2e tests docs to clarify the use of environments [#50530](https://github.com/woocommerce/woocommerce/pull/50530)
|
||||||
|
* Dev - Updated the workflow prompting for testing instructions to only run once (preventing double comments) [#50034](https://github.com/woocommerce/woocommerce/pull/50034)
|
||||||
|
* Dev - Update E2E tests for linked list and variation creation with new component changes. [#50128](https://github.com/woocommerce/woocommerce/pull/50128)
|
||||||
|
* Dev - Update lys e2e tests to test with both classic and block themes [#50657](https://github.com/woocommerce/woocommerce/pull/50657)
|
||||||
|
* Dev - Update Playwright to 1.46.1 from 1.45.1 [#50772](https://github.com/woocommerce/woocommerce/pull/50772)
|
||||||
|
* Dev - Update WP version to 6.6 in Blocks wp-env config. [#49704](https://github.com/woocommerce/woocommerce/pull/49704)
|
||||||
|
* Dev - Use stricter text selector on test [#50848](https://github.com/woocommerce/woocommerce/pull/50848)
|
||||||
|
* Dev - [Filter Products by Price]: Update view when changing the min/max value #50651 [#50651](https://github.com/woocommerce/woocommerce/pull/50651)
|
||||||
|
* Tweak - Disable remote logging feature by default [#51312](https://github.com/woocommerce/woocommerce/pull/51312)
|
||||||
|
* Tweak - Add GTIN in structured data [#50087](https://github.com/woocommerce/woocommerce/pull/50087)
|
||||||
|
* Tweak - Add link to title, remove link from a description, minor copy changes to site visibility settings page [#50781](https://github.com/woocommerce/woocommerce/pull/50781)
|
||||||
|
* Tweak - Add the `woocommerce_should_clear_cart_after_payment` filter to influence whether the cart should be cleared after payment. [#44515](https://github.com/woocommerce/woocommerce/pull/44515)
|
||||||
|
* Tweak - allows the quantity selector on block cart page to render as readonly when editable is false [#49450](https://github.com/woocommerce/woocommerce/pull/49450)
|
||||||
|
* Tweak - Bump Jetpack COnnection, Jetpack Constants and a8c MC Stats [#50471](https://github.com/woocommerce/woocommerce/pull/50471)
|
||||||
|
* Tweak - Extract the checkbox list option logic into its own component [#50566](https://github.com/woocommerce/woocommerce/pull/50566)
|
||||||
|
* Tweak - Make `geolocation_ajax_get_location_hash` case-insensitive, to reduce the number of cache misses. [#45439](https://github.com/woocommerce/woocommerce/pull/45439)
|
||||||
|
* Tweak - Optimize large image files [#50517](https://github.com/woocommerce/woocommerce/pull/50517)
|
||||||
|
* Tweak - Product Collection: fix the PHP deprecated warning [#50661](https://github.com/woocommerce/woocommerce/pull/50661)
|
||||||
|
* Tweak - Reduce core profiler sticky footer height [#50788](https://github.com/woocommerce/woocommerce/pull/50788)
|
||||||
|
* Tweak - Remove colon from product data meta box checkboxes [#50619](https://github.com/woocommerce/woocommerce/pull/50619)
|
||||||
|
* Tweak - Remove the code related to the automatic Products (Beta) -> Product Collection upgrade. [#50440](https://github.com/woocommerce/woocommerce/pull/50440)
|
||||||
|
* Tweak - Set timeout to 2 seconds for helper product-usage-notice-rules endpoint request [#50821](https://github.com/woocommerce/woocommerce/pull/50821)
|
||||||
|
* Tweak - Update size of site visibility badge. [#50792](https://github.com/woocommerce/woocommerce/pull/50792)
|
||||||
|
* Tweak - Vertically center product meta elements [#50826](https://github.com/woocommerce/woocommerce/pull/50826)
|
||||||
|
* Performance - Cache order dates in options for performance. [#50066](https://github.com/woocommerce/woocommerce/pull/50066)
|
||||||
|
* Performance - Compress pattern placeholder image assets [#50405](https://github.com/woocommerce/woocommerce/pull/50405)
|
||||||
|
* Performance - Improve performance of maybe_assign_default_product_cat by only dropping cache and term recounting if changes were made in the database [#50006](https://github.com/woocommerce/woocommerce/pull/50006)
|
||||||
|
* Performance - Improve setup_tasks_remaining performance [#50655](https://github.com/woocommerce/woocommerce/pull/50655)
|
||||||
|
* Enhancement - Add a filter to override the SKU database lock. [#49755](https://github.com/woocommerce/woocommerce/pull/49755)
|
||||||
|
* Enhancement - Add email type to Checkout block email field. [#48611](https://github.com/woocommerce/woocommerce/pull/48611)
|
||||||
|
* Enhancement - Add filter `woocommerce_is_store_page` to modify whether Coming Soon mode considers a URL a store page or not. [#50174](https://github.com/woocommerce/woocommerce/pull/50174)
|
||||||
|
* Enhancement - Add username in email reset-password link [#49737](https://github.com/woocommerce/woocommerce/pull/49737)
|
||||||
|
* Enhancement - CYS: improve CTA [#50278](https://github.com/woocommerce/woocommerce/pull/50278)
|
||||||
|
* Enhancement - Ensure `wccomHelper` data is only loaded on the Extensions page where it's needed. [#49758](https://github.com/woocommerce/woocommerce/pull/49758)
|
||||||
|
* Enhancement - Fixed minor issues in the developer documentation recently added by public resources team [#50845](https://github.com/woocommerce/woocommerce/pull/50845)
|
||||||
|
* Enhancement - Hide zoomed product images for screen readers. [#50003](https://github.com/woocommerce/woocommerce/pull/50003)
|
||||||
|
* Enhancement - Improve hover style on product tabs when using the Minimal style in the Product Details block [#50605](https://github.com/woocommerce/woocommerce/pull/50605)
|
||||||
|
* Enhancement - Make screen readers announce notice messages once page loads. [#50061](https://github.com/woocommerce/woocommerce/pull/50061)
|
||||||
|
* Enhancement - Refactor: Migrate the All Products block to API version 3 [#50203](https://github.com/woocommerce/woocommerce/pull/50203)
|
||||||
|
* Enhancement - Remove opacity from the hover style of the mini cart button [#50240](https://github.com/woocommerce/woocommerce/pull/50240)
|
||||||
|
* Enhancement - Use standard link color in legal disclaimers on core profiler [#50830](https://github.com/woocommerce/woocommerce/pull/50830)
|
||||||
|
|
||||||
= 9.2.3 2024-08-26 =
|
= 9.2.3 2024-08-26 =
|
||||||
|
|
||||||
**WooCommerce**
|
**WooCommerce**
|
||||||
|
|
|
@ -339,11 +339,11 @@ This results in the following address form (the billing form will be the same):
|
||||||
The rendered markup looks like this:
|
The rendered markup looks like this:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<input type="text" id="shipping-namespace-gov-id" autocapitalize="off"
|
<input type="text" id="shipping-namespace-gov-id" autocapitalize="off"
|
||||||
autocomplete="government-id" aria-label="custom aria label"
|
autocomplete="government-id" aria-label="custom aria label"
|
||||||
aria-describedby="some-element" required="" aria-invalid="true"
|
aria-describedby="some-element" required="" aria-invalid="true"
|
||||||
title="Title to show on hover" pattern="[A-Z0-9]{5}"
|
title="Title to show on hover" pattern="[A-Z0-9]{5}"
|
||||||
data-custom="custom data" value="" >
|
data-custom="custom data" value="" >
|
||||||
```
|
```
|
||||||
|
|
||||||
### Rendering a checkbox field
|
### Rendering a checkbox field
|
||||||
|
|
|
@ -81,7 +81,7 @@ const modifyCartItemClass = ( defaultValue, extensions, args ) => {
|
||||||
|
|
||||||
const modifyCartItemPrice = ( defaultValue, extensions, args ) => {
|
const modifyCartItemPrice = ( defaultValue, extensions, args ) => {
|
||||||
if ( isOrderSummaryContext( args ) ) {
|
if ( isOrderSummaryContext( args ) ) {
|
||||||
return '<price/> for all items';
|
return '<price/> for all items';
|
||||||
}
|
}
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
};
|
};
|
||||||
|
@ -95,7 +95,7 @@ const modifyItemName = ( defaultValue, extensions, args ) => {
|
||||||
|
|
||||||
const modifySubtotalPriceFormat = ( defaultValue, extensions, args ) => {
|
const modifySubtotalPriceFormat = ( defaultValue, extensions, args ) => {
|
||||||
if ( isOrderSummaryContext( args ) ) {
|
if ( isOrderSummaryContext( args ) ) {
|
||||||
return '<price/> per item';
|
return '<price/> per item';
|
||||||
}
|
}
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
};
|
};
|
||||||
|
|
|
@ -106,17 +106,17 @@ The `cartItemPrice` filter allows to format the order summary item price.
|
||||||
|
|
||||||
### Parameters <!-- omit in toc -->
|
### Parameters <!-- omit in toc -->
|
||||||
|
|
||||||
- _defaultValue_ `string` (default: `<price/>`) - The default order summary item price.
|
- _defaultValue_ `string` (default: `<price/>`) - The default order summary item price.
|
||||||
- _extensions_ `object` (default: `{}`) - The extensions object.
|
- _extensions_ `object` (default: `{}`) - The extensions object.
|
||||||
- _args_ `object` - The arguments object with the following keys:
|
- _args_ `object` - The arguments object with the following keys:
|
||||||
- _cart_ `object` - The cart object from `wc/store/cart`, see [Cart object](#cart-object).
|
- _cart_ `object` - The cart object from `wc/store/cart`, see [Cart object](#cart-object).
|
||||||
- _cartItem_ `object` - The order summary item object from `wc/store/cart`, see [order summary item object](#cart-item-object).
|
- _cartItem_ `object` - The order summary item object from `wc/store/cart`, see [order summary item object](#cart-item-object).
|
||||||
- _context_ `string` (allowed values: `cart` or `summary`) - The context of the item.
|
- _context_ `string` (allowed values: `cart` or `summary`) - The context of the item.
|
||||||
- _validation_ `boolean` - Checks if the return value contains the substring `<price/>`.
|
- _validation_ `boolean` - Checks if the return value contains the substring `<price/>`.
|
||||||
|
|
||||||
### Returns <!-- omit in toc -->
|
### Returns <!-- omit in toc -->
|
||||||
|
|
||||||
- `string` - The modified format of the order summary item price, which must contain the substring `<price/>`, or the original price format.
|
- `string` - The modified format of the order summary item price, which must contain the substring `<price/>`, or the original price format.
|
||||||
|
|
||||||
### Code examples <!-- omit in toc -->
|
### Code examples <!-- omit in toc -->
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ const modifyCartItemPrice = ( defaultValue, extensions, args, validation ) => {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return '<price/> for all items';
|
return '<price/> for all items';
|
||||||
};
|
};
|
||||||
|
|
||||||
registerCheckoutFilters( 'example-extension', {
|
registerCheckoutFilters( 'example-extension', {
|
||||||
|
@ -153,14 +153,14 @@ const modifyCartItemPrice = ( defaultValue, extensions, args, validation ) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
|
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
|
||||||
return '<price/> to keep you ☀️';
|
return '<price/> to keep you ☀️';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( args?.cartItem?.name === 'Sunglasses' ) {
|
if ( args?.cartItem?.name === 'Sunglasses' ) {
|
||||||
return '<price/> to keep you ❄️';
|
return '<price/> to keep you ❄️';
|
||||||
}
|
}
|
||||||
|
|
||||||
return '<price/> for all items';
|
return '<price/> for all items';
|
||||||
};
|
};
|
||||||
|
|
||||||
registerCheckoutFilters( 'example-extension', {
|
registerCheckoutFilters( 'example-extension', {
|
||||||
|
@ -261,17 +261,17 @@ The `subtotalPriceFormat` filter allows to format the order summary item subtota
|
||||||
|
|
||||||
### Parameters <!-- omit in toc -->
|
### Parameters <!-- omit in toc -->
|
||||||
|
|
||||||
- _defaultValue_ `string` (default: `<price/>`) - The default order summary item subtotal price.
|
- _defaultValue_ `string` (default: `<price/>`) - The default order summary item subtotal price.
|
||||||
- _extensions_ `object` (default: `{}`) - The extensions object.
|
- _extensions_ `object` (default: `{}`) - The extensions object.
|
||||||
- _args_ `object` - The arguments object with the following keys:
|
- _args_ `object` - The arguments object with the following keys:
|
||||||
- _cart_ `object` - The cart object from `wc/store/cart`, see [Cart object](#cart-object).
|
- _cart_ `object` - The cart object from `wc/store/cart`, see [Cart object](#cart-object).
|
||||||
- _cartItem_ `object` - The order summary item object from `wc/store/cart`, see [order summary item object](#cart-item-object).
|
- _cartItem_ `object` - The order summary item object from `wc/store/cart`, see [order summary item object](#cart-item-object).
|
||||||
- _context_ `string` (allowed values: `cart` or `summary`) - The context of the item.
|
- _context_ `string` (allowed values: `cart` or `summary`) - The context of the item.
|
||||||
- _validation_ `boolean` - Checks if the return value contains the substring `<price/>`.
|
- _validation_ `boolean` - Checks if the return value contains the substring `<price/>`.
|
||||||
|
|
||||||
### Returns <!-- omit in toc -->
|
### Returns <!-- omit in toc -->
|
||||||
|
|
||||||
- `string` - The modified format of the order summary item subtotal price, which must contain the substring `<price/>`, or the original price format.
|
- `string` - The modified format of the order summary item subtotal price, which must contain the substring `<price/>`, or the original price format.
|
||||||
|
|
||||||
### Code examples <!-- omit in toc -->
|
### Code examples <!-- omit in toc -->
|
||||||
|
|
||||||
|
@ -292,7 +292,7 @@ const modifySubtotalPriceFormat = (
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return '<price/> per item';
|
return '<price/> per item';
|
||||||
};
|
};
|
||||||
|
|
||||||
registerCheckoutFilters( 'example-extension', {
|
registerCheckoutFilters( 'example-extension', {
|
||||||
|
@ -318,14 +318,14 @@ const modifySubtotalPriceFormat = (
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
|
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
|
||||||
return '<price/> per warm beanie';
|
return '<price/> per warm beanie';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( args?.cartItem?.name === 'Sunglasses' ) {
|
if ( args?.cartItem?.name === 'Sunglasses' ) {
|
||||||
return '<price/> per cool sunglasses';
|
return '<price/> per cool sunglasses';
|
||||||
}
|
}
|
||||||
|
|
||||||
return '<price/> per item';
|
return '<price/> per item';
|
||||||
};
|
};
|
||||||
|
|
||||||
registerCheckoutFilters( 'example-extension', {
|
registerCheckoutFilters( 'example-extension', {
|
||||||
|
|
|
@ -71,11 +71,11 @@ The `totalValue` filter allows to format the total price in the footer of the Ca
|
||||||
- _extensions_ `object` (default: `{}`) - The extensions object.
|
- _extensions_ `object` (default: `{}`) - The extensions object.
|
||||||
- _args_ `object` - The arguments object with the following keys:
|
- _args_ `object` - The arguments object with the following keys:
|
||||||
- _cart_ `object` - The cart object from `wc/store/cart`, see [Cart object](#cart-object).
|
- _cart_ `object` - The cart object from `wc/store/cart`, see [Cart object](#cart-object).
|
||||||
- _validation_ `boolean` - Checks if the return value contains the substring `<price/>`.
|
- _validation_ `boolean` - Checks if the return value contains the substring `<price/>`.
|
||||||
|
|
||||||
### Returns <!-- omit in toc -->
|
### Returns <!-- omit in toc -->
|
||||||
|
|
||||||
- `string` - The modified format of the total price, which must contain the substring `<price/>`, or the original price format.
|
- `string` - The modified format of the total price, which must contain the substring `<price/>`, or the original price format.
|
||||||
|
|
||||||
### Code example <!-- omit in toc -->
|
### Code example <!-- omit in toc -->
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ The `totalValue` filter allows to format the total price in the footer of the Ca
|
||||||
const { registerCheckoutFilters } = window.wc.blocksCheckout;
|
const { registerCheckoutFilters } = window.wc.blocksCheckout;
|
||||||
|
|
||||||
const modifyTotalsPrice = ( defaultValue, extensions, args, validation ) => {
|
const modifyTotalsPrice = ( defaultValue, extensions, args, validation ) => {
|
||||||
return 'Pay <price/> now';
|
return 'Pay <price/> now';
|
||||||
};
|
};
|
||||||
|
|
||||||
registerCheckoutFilters( 'my-extension', {
|
registerCheckoutFilters( 'my-extension', {
|
||||||
|
|
|
@ -22,11 +22,11 @@ const { ExperimentalOrderMeta } = window.wc.blocksCheckout;
|
||||||
|
|
||||||
const render = () => {
|
const render = () => {
|
||||||
return (
|
return (
|
||||||
<ExperimentalOrderMeta>
|
<ExperimentalOrderMeta>
|
||||||
<div class="wc-block-components-totals-wrapper">
|
<div class="wc-block-components-totals-wrapper">
|
||||||
{ __( 'Yearly recurring total ...', 'YOUR-TEXTDOMAIN' ) }
|
{ __( 'Yearly recurring total ...', 'YOUR-TEXTDOMAIN' ) }
|
||||||
</div>
|
</div>
|
||||||
</ExperimentalOrderMeta>
|
</ExperimentalOrderMeta>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,9 +61,9 @@ const { ExperimentalOrderShippingPackages } = window.wc.blocksCheckout;
|
||||||
|
|
||||||
const render = () => {
|
const render = () => {
|
||||||
return (
|
return (
|
||||||
<ExperimentalOrderShippingPackages>
|
<ExperimentalOrderShippingPackages>
|
||||||
<div>{ __( 'Express Shipping', 'YOUR-TEXTDOMAIN' ) }</div>
|
<div>{ __( 'Express Shipping', 'YOUR-TEXTDOMAIN' ) }</div>
|
||||||
</ExperimentalOrderShippingPackages>
|
</ExperimentalOrderShippingPackages>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -104,14 +104,14 @@ const { ExperimentalOrderLocalPickupPackages } = window.wc.blocksCheckout;
|
||||||
|
|
||||||
const render = () => {
|
const render = () => {
|
||||||
return (
|
return (
|
||||||
<ExperimentalOrderLocalPickupPackages>
|
<ExperimentalOrderLocalPickupPackages>
|
||||||
<div>
|
<div>
|
||||||
{ __(
|
{ __(
|
||||||
'By using our convenient local pickup option, you can come to our store and pick up your order. We will send you and email when your order is ready for pickup.',
|
'By using our convenient local pickup option, you can come to our store and pick up your order. We will send you and email when your order is ready for pickup.',
|
||||||
'YOUR-TEXTDOMAIN'
|
'YOUR-TEXTDOMAIN'
|
||||||
) }
|
) }
|
||||||
</div>
|
</div>
|
||||||
</ExperimentalOrderLocalPickupPackages>
|
</ExperimentalOrderLocalPickupPackages>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -143,11 +143,11 @@ const { ExperimentalDiscountsMeta } = window.wc.blocksCheckout;
|
||||||
|
|
||||||
const render = () => {
|
const render = () => {
|
||||||
return (
|
return (
|
||||||
<ExperimentalDiscountsMeta>
|
<ExperimentalDiscountsMeta>
|
||||||
<div class="wc-block-components-totals-wrapper">
|
<div class="wc-block-components-totals-wrapper">
|
||||||
{ __( 'You have 98683 coins to spend ...', 'YOUR-TEXTDOMAIN' ) }
|
{ __( 'You have 98683 coins to spend ...', 'YOUR-TEXTDOMAIN' ) }
|
||||||
</div>
|
</div>
|
||||||
</ExperimentalDiscountsMeta>
|
</ExperimentalDiscountsMeta>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,8 @@ The options you feed the configuration instance should be an object in this shap
|
||||||
```js
|
```js
|
||||||
const options = {
|
const options = {
|
||||||
name: 'my_payment_method',
|
name: 'my_payment_method',
|
||||||
content: <div>A React node</div>,
|
content: <div>A React node</div>,
|
||||||
edit: <div>A React node</div>,
|
edit: <div>A React node</div>,
|
||||||
canMakePayment: () => true,
|
canMakePayment: () => true,
|
||||||
paymentMethodId: 'new_payment_method',
|
paymentMethodId: 'new_payment_method',
|
||||||
supports: {
|
supports: {
|
||||||
|
|
|
@ -32,14 +32,14 @@ const { registerPlugin } = wp.plugins;
|
||||||
const { ExperimentalOrderMeta } = wc.blocksCheckout;
|
const { ExperimentalOrderMeta } = wc.blocksCheckout;
|
||||||
|
|
||||||
const MyCustomComponent = ( { cart, extensions } ) => {
|
const MyCustomComponent = ( { cart, extensions } ) => {
|
||||||
return <div className="my-component">Hello WooCommerce</div>;
|
return <div className="my-component">Hello WooCommerce</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const render = () => {
|
const render = () => {
|
||||||
return (
|
return (
|
||||||
<ExperimentalOrderMeta>
|
<ExperimentalOrderMeta>
|
||||||
<MyCustomComponent />
|
<MyCustomComponent />
|
||||||
</ExperimentalOrderMeta>
|
</ExperimentalOrderMeta>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -295,7 +295,7 @@ function custom_override_checkout_fields( $fields ) {
|
||||||
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
|
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
|
||||||
|
|
||||||
function my_custom_checkout_field_display_admin_order_meta($order){
|
function my_custom_checkout_field_display_admin_order_meta($order){
|
||||||
echo '<p><strong>'. esc_html__( 'Phone From Checkout Form' ) . ':</strong> ' . esc_html( $order->get_meta( '_shipping_phone', true ) ) . '</p>';
|
echo '<p><strong>'. esc_html__( 'Phone From Checkout Form' ) . ':</strong> ' . esc_html( $order->get_meta( '_shipping_phone', true ) ) . '</p>';
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -317,7 +317,7 @@ add_action( 'woocommerce_after_order_notes', 'my_custom_checkout_field' );
|
||||||
|
|
||||||
function my_custom_checkout_field( $checkout ) {
|
function my_custom_checkout_field( $checkout ) {
|
||||||
|
|
||||||
echo '<div id="my_custom_checkout_field"><h2>' . esc_html__( 'My Field' ) . '</h2>';
|
echo '<div id="my_custom_checkout_field"><h2>' . esc_html__( 'My Field' ) . '</h2>';
|
||||||
|
|
||||||
woocommerce_form_field(
|
woocommerce_form_field(
|
||||||
'my_field_name',
|
'my_field_name',
|
||||||
|
@ -330,7 +330,7 @@ function my_custom_checkout_field( $checkout ) {
|
||||||
$checkout->get_value( 'my_field_name' )
|
$checkout->get_value( 'my_field_name' )
|
||||||
);
|
);
|
||||||
|
|
||||||
echo '</div>';
|
echo '</div>';
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -387,7 +387,7 @@ If you wish to display the custom field value on the admin order edition page, y
|
||||||
add_action( 'woocommerce_admin_order_data_after_billing_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
|
add_action( 'woocommerce_admin_order_data_after_billing_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
|
||||||
|
|
||||||
function my_custom_checkout_field_display_admin_order_meta( $order ){
|
function my_custom_checkout_field_display_admin_order_meta( $order ){
|
||||||
echo '<p><strong>' . esc_html__( 'My Field' ) . ':</strong> ' . esc_html( $order->get_meta( 'My Field', true ) ) . '</p>';
|
echo '<p><strong>' . esc_html__( 'My Field' ) . ':</strong> ' . esc_html( $order->get_meta( 'My Field', true ) ) . '</p>';
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ function woocommerce_custom_field_example() {
|
||||||
$custom_field_value = get_post_meta( $product->get_id(), 'woo_custom_field', true );
|
$custom_field_value = get_post_meta( $product->get_id(), 'woo_custom_field', true );
|
||||||
|
|
||||||
if ( ! empty( $custom_field_value ) ) {
|
if ( ! empty( $custom_field_value ) ) {
|
||||||
echo '<div class="custom-field">' . esc_html( $custom_field_value ) . '</div>';
|
echo '<div class="custom-field">' . esc_html( $custom_field_value ) . '</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ if ( defined( 'WC_LOG_DIR' ) ) {
|
||||||
$log_url = add_query_arg( 'log_file', $log_key, $log_url );
|
$log_url = add_query_arg( 'log_file', $log_key, $log_url );
|
||||||
|
|
||||||
// Add a link to the logs to the label
|
// Add a link to the logs to the label
|
||||||
$label .= ' | ' . sprintf( \_\_( '%1$sView Log%2$s', 'your-textdomain-here' ), '<a href\="' . esc_url( $log_url ) . '">', '</a\>' );
|
$label .= ' | ' . sprintf( \_\_( '%1$sView Log%2$s', 'your-textdomain-here' ), '<a href\="' . esc_url( $log_url ) . '">', '</a\>' );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the logging option to the form fields
|
// Add the logging option to the form fields
|
||||||
|
|
|
@ -100,7 +100,7 @@
|
||||||
"menu_title": "Slot and Fill",
|
"menu_title": "Slot and Fill",
|
||||||
"tags": "reference",
|
"tags": "reference",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/slot-fills.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/slot-fills.md",
|
||||||
"hash": "f83a5fbef86e5ef6b0ec1d63fdbcbf4742f54de1125e535fa0f32f5f80ec794a",
|
"hash": "a232ca3d53f10857170113f6dc5b37ac7ae629e852629bac015a8d3c2cd1bbc4",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/slot-fills.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/slot-fills.md",
|
||||||
"id": "e388101586765dd9aca752d66d667d74951a1504"
|
"id": "e388101586765dd9aca752d66d667d74951a1504"
|
||||||
},
|
},
|
||||||
|
@ -136,7 +136,7 @@
|
||||||
"menu_title": "Available Slots",
|
"menu_title": "Available Slots",
|
||||||
"tags": "reference",
|
"tags": "reference",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/available-slot-fills.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/available-slot-fills.md",
|
||||||
"hash": "770da9156eea1fdc24db0736ce4ccd44ebde4f3b0373cd875b1ae88d4d9c8a49",
|
"hash": "444d9892cb6552c8394ecdf81816952987b59bc79fa53f3083c3d14a89d1e961",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/available-slot-fills.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/available-slot-fills.md",
|
||||||
"id": "c7ac16eee5540b06b6db928f5d03282ff177e84e"
|
"id": "c7ac16eee5540b06b6db928f5d03282ff177e84e"
|
||||||
},
|
},
|
||||||
|
@ -145,14 +145,14 @@
|
||||||
"menu_title": "Additional Checkout Fields",
|
"menu_title": "Additional Checkout Fields",
|
||||||
"tags": "reference",
|
"tags": "reference",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/additional-checkout-fields.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/additional-checkout-fields.md",
|
||||||
"hash": "1b034ede098b933b6b00a9a27ba33e418b1c88c4883e2b9b191092e32866f7b9",
|
"hash": "641615864f627be4bb42574df378cea91f4a7fda9edab099558bad06b92ce62d",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/additional-checkout-fields.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/additional-checkout-fields.md",
|
||||||
"id": "cb5dd8d59043a4e53929121b45da7b33b1661ab8"
|
"id": "cb5dd8d59043a4e53929121b45da7b33b1661ab8"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"categories": [
|
"categories": [
|
||||||
{
|
{
|
||||||
"content": "\nThis document lists the filters that are currently available to extensions and offers usage information for each one of them. Information on registering filters can be found on the [Checkout - Filter Registry](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/packages/checkout/filter-registry/README.md) page.\n\n## Cart Line Items filters\n\nThe following [Cart Line Items filters](./cart-line-items.md) are available:\n\n- `cartItemClass`\n- `cartItemPrice`\n- `itemName`\n- `saleBadgePriceFormat`\n- `showRemoveItemLink`\n- `subtotalPriceFormat`\n\nThe following screenshot shows which parts the individual filters affect:\n\n![Cart Line Items](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-26-at-13.12.33.png)\n\n## Order Summary Items filters\n\nThe following [Order Summary Items filters](./order-summary-items.md) are available:\n\n- `cartItemClass`\n- `cartItemPrice`\n- `itemName`\n- `subtotalPriceFormat`\n\nThe following screenshot shows which parts the individual filters affect:\n\n![Order Summary Items](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-26-at-16.29.45.png)\n\n## Totals Footer Item filter\n\nThe following [Totals Footer Item filter](./totals-footer-item.md) is available:\n\n- `totalLabel`\n- `totalValue`\n\n## Checkout and place order button filters\n\nThe following [Checkout and place order button filters](./checkout-and-place-order-button.md) are available:\n\n- `proceedToCheckoutButtonLabel`\n- `proceedToCheckoutButtonLink`\n- `placeOrderButtonLabel`\n\n## Coupon filters\n\nThe following [Coupon filters](./coupons.md) are available:\n\n- `coupons`\n- `showApplyCouponNotice`\n- `showRemoveCouponNotice`\n\n## Additional Cart and Checkout inner block types filter\n\nThe following [Additional Cart and Checkout inner block types filter](./additional-cart-checkout-inner-block-types.md) is available:\n\n- `additionalCartCheckoutInnerBlockTypes`\n\n## Combined filters\n\nFilters can also be combined. The following example shows how to combine some of the available filters.\n\n```tsx\nconst { registerCheckoutFilters } = window.wc.blocksCheckout;\n\nconst isOrderSummaryContext = ( args ) => args?.context === 'summary';\n\nconst modifyCartItemClass = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn 'my-custom-class';\n\t}\n\treturn defaultValue;\n};\n\nconst modifyCartItemPrice = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn '<price/> for all items';\n\t}\n\treturn defaultValue;\n};\n\nconst modifyItemName = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn `${ defaultValue }`;\n\t}\n\treturn defaultValue;\n};\n\nconst modifySubtotalPriceFormat = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn '<price/> per item';\n\t}\n\treturn defaultValue;\n};\n\nregisterCheckoutFilters( 'example-extension', {\n\tcartItemClass: modifyCartItemClass,\n\tcartItemPrice: modifyCartItemPrice,\n\titemName: modifyItemName,\n\tsubtotalPriceFormat: modifySubtotalPriceFormat,\n} );\n```\n\n## Troubleshooting\n\nIf you are logged in to the store as an administrator, you should be shown an error like this if your filter is not\nworking correctly. The error will also be shown in your console.\n\n![Troubleshooting](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-30-at-10.52.53.png)\n\n\n",
|
"content": "\nThis document lists the filters that are currently available to extensions and offers usage information for each one of them. Information on registering filters can be found on the [Checkout - Filter Registry](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/packages/checkout/filter-registry/README.md) page.\n\n## Cart Line Items filters\n\nThe following [Cart Line Items filters](./cart-line-items.md) are available:\n\n- `cartItemClass`\n- `cartItemPrice`\n- `itemName`\n- `saleBadgePriceFormat`\n- `showRemoveItemLink`\n- `subtotalPriceFormat`\n\nThe following screenshot shows which parts the individual filters affect:\n\n![Cart Line Items](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-26-at-13.12.33.png)\n\n## Order Summary Items filters\n\nThe following [Order Summary Items filters](./order-summary-items.md) are available:\n\n- `cartItemClass`\n- `cartItemPrice`\n- `itemName`\n- `subtotalPriceFormat`\n\nThe following screenshot shows which parts the individual filters affect:\n\n![Order Summary Items](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-26-at-16.29.45.png)\n\n## Totals Footer Item filter\n\nThe following [Totals Footer Item filter](./totals-footer-item.md) is available:\n\n- `totalLabel`\n- `totalValue`\n\n## Checkout and place order button filters\n\nThe following [Checkout and place order button filters](./checkout-and-place-order-button.md) are available:\n\n- `proceedToCheckoutButtonLabel`\n- `proceedToCheckoutButtonLink`\n- `placeOrderButtonLabel`\n\n## Coupon filters\n\nThe following [Coupon filters](./coupons.md) are available:\n\n- `coupons`\n- `showApplyCouponNotice`\n- `showRemoveCouponNotice`\n\n## Additional Cart and Checkout inner block types filter\n\nThe following [Additional Cart and Checkout inner block types filter](./additional-cart-checkout-inner-block-types.md) is available:\n\n- `additionalCartCheckoutInnerBlockTypes`\n\n## Combined filters\n\nFilters can also be combined. The following example shows how to combine some of the available filters.\n\n```tsx\nconst { registerCheckoutFilters } = window.wc.blocksCheckout;\n\nconst isOrderSummaryContext = ( args ) => args?.context === 'summary';\n\nconst modifyCartItemClass = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn 'my-custom-class';\n\t}\n\treturn defaultValue;\n};\n\nconst modifyCartItemPrice = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn '<price/> for all items';\n\t}\n\treturn defaultValue;\n};\n\nconst modifyItemName = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn `${ defaultValue }`;\n\t}\n\treturn defaultValue;\n};\n\nconst modifySubtotalPriceFormat = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn '<price/> per item';\n\t}\n\treturn defaultValue;\n};\n\nregisterCheckoutFilters( 'example-extension', {\n\tcartItemClass: modifyCartItemClass,\n\tcartItemPrice: modifyCartItemPrice,\n\titemName: modifyItemName,\n\tsubtotalPriceFormat: modifySubtotalPriceFormat,\n} );\n```\n\n## Troubleshooting\n\nIf you are logged in to the store as an administrator, you should be shown an error like this if your filter is not\nworking correctly. The error will also be shown in your console.\n\n![Troubleshooting](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-30-at-10.52.53.png)\n\n\n",
|
||||||
"category_slug": "cart-and-checkout-available-filters",
|
"category_slug": "cart-and-checkout-available-filters",
|
||||||
"category_title": "Available Filters",
|
"category_title": "Available Filters",
|
||||||
"posts": [
|
"posts": [
|
||||||
|
@ -161,7 +161,7 @@
|
||||||
"menu_title": "Totals Footer Item",
|
"menu_title": "Totals Footer Item",
|
||||||
"tags": "reference",
|
"tags": "reference",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/available-filters/totals-footer-item.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/available-filters/totals-footer-item.md",
|
||||||
"hash": "3a9869d7d7beadb8117c100c3b58675e416e16386ee753f78e1a9087e768053f",
|
"hash": "6cf668422809b036dca7c1996ae907497a38631dd5bfb7e67d6bf3620425e411",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/available-filters/totals-footer-item.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/available-filters/totals-footer-item.md",
|
||||||
"id": "90a9b8df374082f1713866a58b810303adb4d3da"
|
"id": "90a9b8df374082f1713866a58b810303adb4d3da"
|
||||||
},
|
},
|
||||||
|
@ -170,7 +170,7 @@
|
||||||
"menu_title": "Order Summary Items",
|
"menu_title": "Order Summary Items",
|
||||||
"tags": "reference",
|
"tags": "reference",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/available-filters/order-summary-items.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/available-filters/order-summary-items.md",
|
||||||
"hash": "36f1bfa8d192b106d28d71334b42413d4c289a0a8d1f5b76b2f905d6fa453883",
|
"hash": "1796f53f3d67dd6b47fe8d7f67cbd69bddcaa6416bb5a0cc1a0fc99f42ea9d10",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/available-filters/order-summary-items.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/available-filters/order-summary-items.md",
|
||||||
"id": "78eb3b135f82a3624a49979e3e93334295abd060"
|
"id": "78eb3b135f82a3624a49979e3e93334295abd060"
|
||||||
},
|
},
|
||||||
|
@ -223,7 +223,7 @@
|
||||||
"menu_title": "Payment Method Integration",
|
"menu_title": "Payment Method Integration",
|
||||||
"tags": "reference",
|
"tags": "reference",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md",
|
||||||
"hash": "f60acaaea4a6ac4adf637bc7069c966e01db089f9dfaa937def91165a71a4255",
|
"hash": "138ffbf27e79ec8b35d2c46e87e3663c203d91fc9ba3f76c43f3cbe76258e5bf",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md",
|
||||||
"id": "c9a763b6976ecf03aeb961577c17c31f1ac7c420",
|
"id": "c9a763b6976ecf03aeb961577c17c31f1ac7c420",
|
||||||
"links": {
|
"links": {
|
||||||
|
@ -363,7 +363,7 @@
|
||||||
"menu_title": "Add link to logged data",
|
"menu_title": "Add link to logged data",
|
||||||
"tags": "code-snippets",
|
"tags": "code-snippets",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/link-to-logged-data.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/link-to-logged-data.md",
|
||||||
"hash": "fd1c3a58da8b7eed11da841d901b4d3cc117c6753c3b3834f3de41ea266490b9",
|
"hash": "4e51c120a6ea7b14c0e43f11e8eb1b785e4447fbe2b997f5789f10b57c485137",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/link-to-logged-data.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/link-to-logged-data.md",
|
||||||
"id": "34da337f79be5ce857024f541a99d302174ca37d"
|
"id": "34da337f79be5ce857024f541a99d302174ca37d"
|
||||||
},
|
},
|
||||||
|
@ -389,7 +389,7 @@
|
||||||
"menu_title": "Displaying custom fields in theme",
|
"menu_title": "Displaying custom fields in theme",
|
||||||
"tags": "code-snippet",
|
"tags": "code-snippet",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/displaying_custom_fields_in_your_theme_or_site.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/displaying_custom_fields_in_your_theme_or_site.md",
|
||||||
"hash": "8048c2e9e5d25268d17d4f4ca7929e265eddbd4653318dd8f544856ddecd39dd",
|
"hash": "013acf9daaef92daf49e49315b2c0eba730b96adb8078eaab1146db4afc5270b",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/displaying_custom_fields_in_your_theme_or_site.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/displaying_custom_fields_in_your_theme_or_site.md",
|
||||||
"id": "3e3fd004afda355cf9dbb05f0967523d6d0da1ce"
|
"id": "3e3fd004afda355cf9dbb05f0967523d6d0da1ce"
|
||||||
},
|
},
|
||||||
|
@ -405,7 +405,7 @@
|
||||||
"post_title": "Customizing checkout fields using actions and filters",
|
"post_title": "Customizing checkout fields using actions and filters",
|
||||||
"tags": "code-snippet",
|
"tags": "code-snippet",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/customising-checkout-fields.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/customising-checkout-fields.md",
|
||||||
"hash": "8bbfe162402e484ae89427e1aedaed4faa57555b64b5a77ca800f701524314cb",
|
"hash": "ce63f640d5b91d85c3bbb80128d8a19e9c00d1c0e252abd4f958e29dcc1e60ce",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/customising-checkout-fields.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/customising-checkout-fields.md",
|
||||||
"id": "83097d3b7414557fc80dcf9f8f1a708bbdcdd884"
|
"id": "83097d3b7414557fc80dcf9f8f1a708bbdcdd884"
|
||||||
},
|
},
|
||||||
|
@ -676,7 +676,7 @@
|
||||||
{
|
{
|
||||||
"post_title": "Settings API",
|
"post_title": "Settings API",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/settings-api.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/settings-api.md",
|
||||||
"hash": "ca80728c56d60bb7416bb2865678b9e04807d0e208a4df56b8efaf32e9ac465d",
|
"hash": "9015453d8be72871bb26a450b86e542aa698c67b93284a04cd2b18008113bf43",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/settings-api.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/settings-api.md",
|
||||||
"id": "ed56b97b9de350074a302373ebaaa5dcce727e8b"
|
"id": "ed56b97b9de350074a302373ebaaa5dcce727e8b"
|
||||||
},
|
},
|
||||||
|
@ -691,7 +691,7 @@
|
||||||
"post_title": "Integrating with coming soon mode",
|
"post_title": "Integrating with coming soon mode",
|
||||||
"tags": "how-to, coming-soon",
|
"tags": "how-to, coming-soon",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/integrating-coming-soon-mode.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/integrating-coming-soon-mode.md",
|
||||||
"hash": "8c2087952ae79bb4c3e3977c57d9e933fcfaa418a5bc643b3827059daa5879a7",
|
"hash": "791cd6d3928b3aafc72a24d0283a404a90a0f021c7c36edaa445eb44978114a3",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/integrating-coming-soon-mode.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/integrating-coming-soon-mode.md",
|
||||||
"id": "787743efb6ef0ad509b17735eaf58b2a9a08afbc"
|
"id": "787743efb6ef0ad509b17735eaf58b2a9a08afbc"
|
||||||
},
|
},
|
||||||
|
@ -700,7 +700,7 @@
|
||||||
"menu_title": "Creating custom settings",
|
"menu_title": "Creating custom settings",
|
||||||
"tags": "how-to",
|
"tags": "how-to",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/implementing-settings.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/implementing-settings.md",
|
||||||
"hash": "604d455f9e413c23a208c174ba25611c333e02eef0bafb0d38253f8dd8e3a04c",
|
"hash": "5cab83a84bb7eb11090bac244754fdae1f8aef1030850d12c29c09054c50bc61",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/implementing-settings.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/implementing-settings.md",
|
||||||
"id": "58bcbd3a0cd3b3e5fe738c3bb625cf9b7747c99a"
|
"id": "58bcbd3a0cd3b3e5fe738c3bb625cf9b7747c99a"
|
||||||
},
|
},
|
||||||
|
@ -727,7 +727,7 @@
|
||||||
"menu_title": "Implement merchant onboarding",
|
"menu_title": "Implement merchant onboarding",
|
||||||
"tags": "how-to",
|
"tags": "how-to",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/handling-merchant-onboarding.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/handling-merchant-onboarding.md",
|
||||||
"hash": "c73e3c5015e6cda3be9ebd2d5fbda590ac9fa599e5fb02163c971c01060970ad",
|
"hash": "85fc7d70f47fdb195ad2c690d3b95565169221f9e4d7afa98e88f3824ad0e267",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/handling-merchant-onboarding.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/handling-merchant-onboarding.md",
|
||||||
"id": "89fe15dc232379f546852822230c334d3d940b93"
|
"id": "89fe15dc232379f546852822230c334d3d940b93"
|
||||||
},
|
},
|
||||||
|
@ -814,7 +814,7 @@
|
||||||
"menu_title": "Add custom product types to Add Products onboarding list",
|
"menu_title": "Add custom product types to Add Products onboarding list",
|
||||||
"tags": "how-to",
|
"tags": "how-to",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/adding-custom-products-to-add-products-onboarding-list.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/adding-custom-products-to-add-products-onboarding-list.md",
|
||||||
"hash": "60e50ef5d7e2ac6d0745c31031140df1dbb3c1b8724230cab1eaedebe3814688",
|
"hash": "92a8e17f2cd8dc32a78f03970ded1beec2fd60cadbf14c8cefcabbf7abae59c5",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/adding-custom-products-to-add-products-onboarding-list.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/adding-custom-products-to-add-products-onboarding-list.md",
|
||||||
"id": "747321d7fd2eb5c9c3351ea38374dfc80d3ec968"
|
"id": "747321d7fd2eb5c9c3351ea38374dfc80d3ec968"
|
||||||
},
|
},
|
||||||
|
@ -861,7 +861,7 @@
|
||||||
"menu_title": "Troubleshooting Endpoints",
|
"menu_title": "Troubleshooting Endpoints",
|
||||||
"tags": "how-to",
|
"tags": "how-to",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/getting-started/troubleshooting-endpoints.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/getting-started/troubleshooting-endpoints.md",
|
||||||
"hash": "1a015d82f4d82cc2d9f13f188f03c4e6e03b98ea9d22c5a7710547e7d3c8c78f",
|
"hash": "448bcd827ff44e9eb10d039bfd933cd63a37df05bd694bf80f9d9f978a3afdf5",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/getting-started/troubleshooting-endpoints.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/getting-started/troubleshooting-endpoints.md",
|
||||||
"id": "dff57bd736ae83850bfc7e4ac994bd22141d96ee",
|
"id": "dff57bd736ae83850bfc7e4ac994bd22141d96ee",
|
||||||
"links": {
|
"links": {
|
||||||
|
@ -874,7 +874,7 @@
|
||||||
"menu_title": "Development environment setup",
|
"menu_title": "Development environment setup",
|
||||||
"tags": "tutorial, setup",
|
"tags": "tutorial, setup",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/getting-started/development-environment.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/getting-started/development-environment.md",
|
||||||
"hash": "b9f56987247aee67eaa2c74d1059e1cadfd335fa81c77b76c0717648d5631c0f",
|
"hash": "bf5d77349ea64d1b8e19fe6b7472be35ed92406c5aafe677ce92363fb13f94d4",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/getting-started/development-environment.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/getting-started/development-environment.md",
|
||||||
"id": "9080572a3904349c44c565ca7e1bef1212c58757"
|
"id": "9080572a3904349c44c565ca7e1bef1212c58757"
|
||||||
},
|
},
|
||||||
|
@ -903,7 +903,7 @@
|
||||||
"menu_title": "Customizing Endpoint URLs",
|
"menu_title": "Customizing Endpoint URLs",
|
||||||
"tags": "how-to",
|
"tags": "how-to",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/getting-started/customizing-endpoint-urls.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/getting-started/customizing-endpoint-urls.md",
|
||||||
"hash": "7feda75b07a1c11d533afabc7781abb80438ce2fa2c3fb37c173e1275098e720",
|
"hash": "364ed14d70c49498ba5017104b9c83743322d5095c215262d4311866a76181e5",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/getting-started/customizing-endpoint-urls.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/getting-started/customizing-endpoint-urls.md",
|
||||||
"id": "c19e1b1da6543f8a95ee04ba120f4f171f8e6e40",
|
"id": "c19e1b1da6543f8a95ee04ba120f4f171f8e6e40",
|
||||||
"links": {
|
"links": {
|
||||||
|
@ -956,7 +956,7 @@
|
||||||
"post_title": "HPOS CLI Tools",
|
"post_title": "HPOS CLI Tools",
|
||||||
"tags": "reference",
|
"tags": "reference",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/high-performance-order-storage/cli-tools.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/high-performance-order-storage/cli-tools.md",
|
||||||
"hash": "8cd823759ce20551d582c39f57ae79f9e0227a8cb0131146e6b7dac5e7312708",
|
"hash": "63e5edd55720c963de6700854515ea51946ff734b716ab61793955308b72af91",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/high-performance-order-storage/cli-tools.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/high-performance-order-storage/cli-tools.md",
|
||||||
"id": "cdd9d9ad5777d978ba953e3478fbb61cab8fdf59"
|
"id": "cdd9d9ad5777d978ba953e3478fbb61cab8fdf59"
|
||||||
}
|
}
|
||||||
|
@ -1050,7 +1050,7 @@
|
||||||
"menu_title": "Registering custom collections",
|
"menu_title": "Registering custom collections",
|
||||||
"tags": "how-to",
|
"tags": "how-to",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/product-collection-block/register-product-collection.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/product-collection-block/register-product-collection.md",
|
||||||
"hash": "27c321bed35524d74019e015f5eed6cdca7e6c2efe0bc89ffdd2b9b5d43c47e8",
|
"hash": "6d32bc27924226b032e03624dbeedde3c899c2e8eb777a1fece93bed99544f03",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/product-collection-block/register-product-collection.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/product-collection-block/register-product-collection.md",
|
||||||
"id": "3bf26fc7c56ae6e6a56e1171f750f5204fcfcece"
|
"id": "3bf26fc7c56ae6e6a56e1171f750f5204fcfcece"
|
||||||
},
|
},
|
||||||
|
@ -1117,7 +1117,7 @@
|
||||||
{
|
{
|
||||||
"post_title": "Extending the product form with custom fields",
|
"post_title": "Extending the product form with custom fields",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/product-editor-development/how-to-guides/custom-field-tutorial.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/product-editor-development/how-to-guides/custom-field-tutorial.md",
|
||||||
"hash": "f0d0273c0d65739d605448492bfbe684f0ed33f9e6e274df06f26e83cb6ba341",
|
"hash": "dfa00ed71af6eda1f539684657d5c880850ececea4c07bd11e89a605fab77ec7",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/product-editor-development/how-to-guides/custom-field-tutorial.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/product-editor-development/how-to-guides/custom-field-tutorial.md",
|
||||||
"id": "fed80efbb225df9054fadd6e1fc45c2cd03e7f99"
|
"id": "fed80efbb225df9054fadd6e1fc45c2cd03e7f99"
|
||||||
}
|
}
|
||||||
|
@ -1329,7 +1329,7 @@
|
||||||
"menu_title": "Extend analytics reports",
|
"menu_title": "Extend analytics reports",
|
||||||
"tags": "how-to",
|
"tags": "how-to",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/reporting/extending-woocommerce-admin-reports.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/reporting/extending-woocommerce-admin-reports.md",
|
||||||
"hash": "b694b0e857d3ca60acdef2ffaae329a93f0a0243eacc4b192562c7f507f169b3",
|
"hash": "56712b3583d0b0a4d96eb19153e5abcb8a386fcd083fa56481acf1be530afa25",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/reporting/extending-woocommerce-admin-reports.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/reporting/extending-woocommerce-admin-reports.md",
|
||||||
"id": "3ef20148084c97d7f62b565b92df844392ac27f7"
|
"id": "3ef20148084c97d7f62b565b92df844392ac27f7"
|
||||||
},
|
},
|
||||||
|
@ -1498,7 +1498,7 @@
|
||||||
"post_title": "Classic theme development handbook",
|
"post_title": "Classic theme development handbook",
|
||||||
"menu_title": "Classic theme development",
|
"menu_title": "Classic theme development",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/theme-development/classic-theme-developer-handbook.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/theme-development/classic-theme-developer-handbook.md",
|
||||||
"hash": "1194437fbc2ec82d60c8b73a9742ec650bd90fe734758c3a2b27ed852d4d14f7",
|
"hash": "95ce7250479a5133bba6c68939d86e4e79708c65044d70727c73f6a88f716da7",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/theme-development/classic-theme-developer-handbook.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/theme-development/classic-theme-developer-handbook.md",
|
||||||
"id": "c2fde53e1dc3efbded3cfe1fb4df27136a3799a4"
|
"id": "c2fde53e1dc3efbded3cfe1fb4df27136a3799a4"
|
||||||
}
|
}
|
||||||
|
@ -1775,7 +1775,7 @@
|
||||||
"menu_title": "Commands",
|
"menu_title": "Commands",
|
||||||
"tags": "reference",
|
"tags": "reference",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/wc-cli/wc-cli-commands.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/wc-cli/wc-cli-commands.md",
|
||||||
"hash": "a926ff45642539e0edc6b4e3dfeba4b31c2d01082700af132a2e8d56cfa25ec5",
|
"hash": "17bbb18fd0ad0523a5b864f74acbec64c853ae7b42ecd7e6d9dbce1fbe2669aa",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/wc-cli/wc-cli-commands.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/wc-cli/wc-cli-commands.md",
|
||||||
"id": "73d6bc6468d23a9e93d16d574399105b143e43af"
|
"id": "73d6bc6468d23a9e93d16d574399105b143e43af"
|
||||||
},
|
},
|
||||||
|
@ -1804,5 +1804,5 @@
|
||||||
"categories": []
|
"categories": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"hash": "8199f0d3c854474839300ed606f03f9f286ace35f65d7c47ffc6477762eaf51e"
|
"hash": "dfe48a2a48d383c1f4e5b5bb4258d369dd4e80ac8582462b16bbfedd879cb0bf"
|
||||||
}
|
}
|
|
@ -45,8 +45,8 @@ addFilter(
|
||||||
key: 'custom-product',
|
key: 'custom-product',
|
||||||
title: __('Custom product', 'custom-product'),
|
title: __('Custom product', 'custom-product'),
|
||||||
content: __('Create an awesome custom product.', 'custom-product'),
|
content: __('Create an awesome custom product.', 'custom-product'),
|
||||||
before: <FolderMultipleIcon />,
|
before: <FolderMultipleIcon />,
|
||||||
after: <Icon icon={chevronRight} />,
|
after: <Icon icon={chevronRight} />,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -448,7 +448,7 @@ class ExampleNote {
|
||||||
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
|
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
|
||||||
|
|
||||||
// Set the type of layout the note uses. Supported layout types are:
|
// Set the type of layout the note uses. Supported layout types are:
|
||||||
// 'banner', 'plain', 'thumbnail'
|
// 'plain', 'thumbnail'
|
||||||
$note->set_layout( 'plain' );
|
$note->set_layout( 'plain' );
|
||||||
|
|
||||||
// Set the image for the note. This property renders as the src
|
// Set the image for the note. This property renders as the src
|
||||||
|
|
|
@ -227,19 +227,19 @@ public function generate_button_html( $key, $data ) {
|
||||||
|
|
||||||
ob_start();
|
ob_start();
|
||||||
?>
|
?>
|
||||||
<tr valign="top">
|
<tr valign="top">
|
||||||
<th scope="row" class="titledesc">
|
<th scope="row" class="titledesc">
|
||||||
<label for="<?php echo esc_attr( $field ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></label>
|
<label for="<?php echo esc_attr( $field ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></label>
|
||||||
<?php echo $this->get_tooltip_html( $data ); ?>
|
<?php echo $this->get_tooltip_html( $data ); ?>
|
||||||
</th>
|
</th>
|
||||||
<td class="forminp">
|
<td class="forminp">
|
||||||
<fieldset>
|
<fieldset<
|
||||||
<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
|
<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
|
||||||
<button class="<?php echo esc_attr( $data['class'] ); ?>" type="button" name="<?php echo esc_attr( $field ); ?>" id="<?php echo esc_attr( $field ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" <?php echo $this->get_custom_attribute_html( $data ); ?>><?php echo wp_kses_post( $data['title'] ); ?></button>
|
<button class="<?php echo esc_attr( $data['class'] ); ?>" type="button" name="<?php echo esc_attr( $field ); ?>" id="<?php echo esc_attr( $field ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" <?php echo $this->get_custom_attribute_html( $data ); ?>><?php echo wp_kses_post( $data['title'] ); ?></button>
|
||||||
<?php echo $this->get_description_html( $data ); ?>
|
<?php echo $this->get_description_html( $data ); ?>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php
|
<?php
|
||||||
return ob_get_clean();
|
return ob_get_clean();
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,7 +160,7 @@ Use the following example to exclude a certain page based on the page's ID. Repl
|
||||||
|
|
||||||
```php
|
```php
|
||||||
add_filter( 'woocommerce_coming_soon_exclude', function( $is_excluded ) {
|
add_filter( 'woocommerce_coming_soon_exclude', function( $is_excluded ) {
|
||||||
if ( get_the_ID() === <page-id> ) {
|
if ( get_the_ID() === <page-id> ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return $is_excluded;
|
return $is_excluded;
|
||||||
|
|
|
@ -70,10 +70,10 @@ Create a method called `admin_options` containing the following:
|
||||||
```php
|
```php
|
||||||
function admin_options() {
|
function admin_options() {
|
||||||
?>
|
?>
|
||||||
<h2><?php esc_html_e( 'Your plugin name', 'your-text-domain' ); ?></h2>
|
<h2><?php esc_html_e( 'Your plugin name', 'your-text-domain' ); ?></h2>
|
||||||
<table class="form-table">
|
<table class="form-table">
|
||||||
<?php $this->generate_settings_html(); ?>
|
<?php $this->generate_settings_html(); ?>
|
||||||
</table>
|
</table>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -48,24 +48,24 @@ Gateways need to use these methods for full 2.1+ compatibility.
|
||||||
On Windows servers, the **web.config** file may not be set correctly to allow for the endpoints to work correctly. In this case, clicking on endpoint links (e.g. /edit-account/ or /customer-logout/) may appear to do nothing except refresh the page. In order to resolve this, try simplifying the **web.config** file on your Windows server. Here's a sample file configuration:
|
On Windows servers, the **web.config** file may not be set correctly to allow for the endpoints to work correctly. In this case, clicking on endpoint links (e.g. /edit-account/ or /customer-logout/) may appear to do nothing except refresh the page. In order to resolve this, try simplifying the **web.config** file on your Windows server. Here's a sample file configuration:
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<<>?xml version="1.0" encoding="UTF-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<system.webServer>
|
<system.webServer>
|
||||||
<handlers accessPolicy="Read, Execute, Script" />
|
<handlers accessPolicy="Read, Execute, Script" />
|
||||||
<rewrite>
|
<rewrite>
|
||||||
<rules>
|
<rules>
|
||||||
<rule name="wordpress" patternSyntax="Wildcard">
|
<rule name="wordpress" patternSyntax="Wildcard">
|
||||||
<match url="*" />
|
<match url="*" />
|
||||||
<conditions>
|
<conditions>
|
||||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||||
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
||||||
</conditions>
|
</conditions>
|
||||||
<action type="Rewrite" url="index.php" />
|
<action type="Rewrite" url="index.php" />
|
||||||
</rule>
|
</rule>
|
||||||
</rules>
|
</rules>
|
||||||
</rewrite>
|
</rewrite>
|
||||||
</system.webServer>
|
</system.webServer>
|
||||||
</configuration>
|
</configuration>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Pages direct to wrong place
|
### Pages direct to wrong place
|
||||||
|
@ -74,6 +74,6 @@ Landing on the wrong page when clicking an endpoint URL is typically caused by i
|
||||||
|
|
||||||
### How to Remove "Downloads" from My Account
|
### How to Remove "Downloads" from My Account
|
||||||
|
|
||||||
Sometimes the "Downloads" endpoint on the "My account" page does not need to be displayed. This can be removed by going to **WooCommerce → Settings → Advanced → Account endpoints** and clearing the Downloads endpoint field.
|
Sometimes the "Downloads" endpoint on the "My account" page does not need to be displayed. This can be removed by going to **WooCommerce > Settings > Advanced > Account endpoints** and clearing the Downloads endpoint field.
|
||||||
|
|
||||||
![Account endpoints](https://developer.woocommerce.com/wp-content/uploads/2023/12/Screenshot-2023-04-09-at-11.45.58-PM.png)
|
![Account endpoints](https://developer.woocommerce.com/wp-content/uploads/2023/12/Screenshot-2023-04-09-at-11.45.58-PM.png)
|
||||||
|
|
|
@ -14,7 +14,7 @@ If you would like to contribute to the WooCommerce core platform; please read ou
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
WooCommerce does adhere to WordPress code standards and guidelines, so it’s best to familiarize yourself with [WordPress Development](https://learn.wordpress.org/tutorial/introduction-to-wordpress/) as well as [PHP](https://www.php.net/).
|
WooCommerce does adhere to WordPress code standards and guidelines, so it's best to familiarize yourself with [WordPress Development](https://learn.wordpress.org/tutorial/introduction-to-wordpress/) as well as [PHP](https://www.php.net/).
|
||||||
|
|
||||||
Knowledge and understanding of [WooCommerce Hooks and Filters](https://woocommerce.com/document/introduction-to-hooks-actions-and-filters/) will allow you to add and change code without editing core files. You can learn more about WordPress hooks and filters in the [WordPress Plugin Development Handbook](https://developer.wordpress.org/plugins/hooks/).
|
Knowledge and understanding of [WooCommerce Hooks and Filters](https://woocommerce.com/document/introduction-to-hooks-actions-and-filters/) will allow you to add and change code without editing core files. You can learn more about WordPress hooks and filters in the [WordPress Plugin Development Handbook](https://developer.wordpress.org/plugins/hooks/).
|
||||||
|
|
||||||
|
@ -80,22 +80,16 @@ git clone https://github.com/woocommerce/woocommerce.git
|
||||||
cd woocommerce
|
cd woocommerce
|
||||||
```
|
```
|
||||||
|
|
||||||
### Activate the required Node version
|
### Install and Activate the required Node version
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
nvm use
|
nvm install
|
||||||
Found '/path/to/woocommerce/.nvmrc' with version <v12>
|
Found '/path/to/woocommerce/.nvmrc' with version <v20>
|
||||||
Now using node v12.21.0 (npm v6.14.11)
|
v20.17.0 is already installed.
|
||||||
|
Now using node v20.17.0 (npm v10.8.2)
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: if you don't have the required version of Node installed, NVM will alert you so you can install it:
|
Note: if you don't have the required version of Node installed, NVM will install it.
|
||||||
|
|
||||||
```sh
|
|
||||||
Found '/path/to/woocommerce/.nvmrc' with version <v12>
|
|
||||||
N/A: version "v12 -> N/A" is not yet installed.
|
|
||||||
|
|
||||||
You need to run "nvm install v12" to install it before using it.
|
|
||||||
```
|
|
||||||
|
|
||||||
### Install dependencies
|
### Install dependencies
|
||||||
|
|
||||||
|
|
|
@ -18,24 +18,24 @@ For more information, learn how to [Customize Endpoints](./customizing-endpoint-
|
||||||
On Windows servers, the **web.config** file may not be set correctly to allow for the endpoints to work correctly. In this case, clicking on endpoint links (e.g. /edit-account/ or /customer-logout/) may appear to do nothing except refresh the page. In order to resolve this, try simplifying the **web.config** file on your Windows server. Here's a sample file configuration:
|
On Windows servers, the **web.config** file may not be set correctly to allow for the endpoints to work correctly. In this case, clicking on endpoint links (e.g. /edit-account/ or /customer-logout/) may appear to do nothing except refresh the page. In order to resolve this, try simplifying the **web.config** file on your Windows server. Here's a sample file configuration:
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<system.webServer>
|
<system.webServer>
|
||||||
<handlers accessPolicy="Read, Execute, Script" />
|
<handlers accessPolicy="Read, Execute, Script" />
|
||||||
<rewrite>
|
<rewrite>
|
||||||
<rules>
|
<rules>
|
||||||
<rule name="wordpress" patternSyntax="Wildcard">
|
<rule name="wordpress" patternSyntax="Wildcard">
|
||||||
<match url="*" />
|
<match url="*" />
|
||||||
<conditions>
|
<conditions>
|
||||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||||
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
||||||
</conditions>
|
</conditions>
|
||||||
<action type="Rewrite" url="index.php" />
|
<action type="Rewrite" url="index.php" />
|
||||||
</rule>
|
</rule>
|
||||||
</rules>
|
</rules>
|
||||||
</rewrite>
|
</rewrite>
|
||||||
</system.webServer>
|
</system.webServer>
|
||||||
</configuration>
|
</configuration>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Pages direct to wrong place
|
## Pages direct to wrong place
|
||||||
|
@ -44,6 +44,6 @@ Landing on the wrong page when clicking an endpoint URL is typically caused by i
|
||||||
|
|
||||||
## How to Remove "Downloads" from My Account
|
## How to Remove "Downloads" from My Account
|
||||||
|
|
||||||
Sometimes the "Downloads" endpoint on the "My account" page does not need to be displayed. This can be removed by going to **WooCommerce → Settings → Advanced → Account endpoints** and clearing the Downloads endpoint field.
|
Sometimes the "Downloads" endpoint on the "My account" page does not need to be displayed. This can be removed by going to **WooCommerce > Settings > Advanced > Account endpoints** and clearing the Downloads endpoint field.
|
||||||
|
|
||||||
![Account endpoints](https://developer.woocommerce.com/wp-content/uploads/2023/12/Screenshot-2023-04-09-at-11.45.58-PM.png)
|
![Account endpoints](https://developer.woocommerce.com/wp-content/uploads/2023/12/Screenshot-2023-04-09-at-11.45.58-PM.png)
|
||||||
|
|
|
@ -229,7 +229,7 @@ The backfill command can be used to selectively migrate order data (or whole ord
|
||||||
The exact syntax for this command is as follows:
|
The exact syntax for this command is as follows:
|
||||||
|
|
||||||
```plaintext
|
```plaintext
|
||||||
wp wc hpos backfill <order_id> --from=<datastore> --to=<datastore> [--meta_keys=<meta_keys>] [--props=<props>]
|
wp wc hpos backfill <order_id> --from=<datastore> --to=<datastore> [--meta_keys=<meta_keys>] [--props=<props>]
|
||||||
```
|
```
|
||||||
|
|
||||||
You have to specify which datastore to use as source (either `posts` or `hpos`) and which one to use as destination. The `--meta_keys` and `--props` arguments receive a comma separated list of meta keys and order properties, which can be used to move only certain data from one datastore to the other, instead of the whole order.
|
You have to specify which datastore to use as source (either `posts` or `hpos`) and which one to use as destination. The `--meta_keys` and `--props` arguments receive a comma separated list of meta keys and order properties, which can be used to move only certain data from one datastore to the other, instead of the whole order.
|
||||||
|
|
|
@ -36,7 +36,7 @@ We will explain important arguments that can be passed to `__experimentalRegiste
|
||||||
|
|
||||||
A Collection is defined by an object that can contain the following fields:
|
A Collection is defined by an object that can contain the following fields:
|
||||||
|
|
||||||
- `name` (type `string`): A unique and machine-readable collection name. We recommend using the format `<plugin-name>/product-collection/<collection-name>`. Both `<plugin-name>` and `<collection-name>` should consist only of alphanumeric characters and hyphens (e.g., `my-plugin/product-collection/my-collection`).
|
- `name` (type `string`): A unique and machine-readable collection name. We recommend using the format `<plugin-name>/product-collection/<collection-name>`. Both `<plugin-name>` and `<collection-name>` should consist only of alphanumeric characters and hyphens (e.g., `my-plugin/product-collection/my-collection`).
|
||||||
- `title` (type `string`): The title of the collection, which will be displayed in various places including the block inserter and collection chooser.
|
- `title` (type `string`): The title of the collection, which will be displayed in various places including the block inserter and collection chooser.
|
||||||
- `description` (optional, type `string`): A human-readable description of the collection.
|
- `description` (optional, type `string`): A human-readable description of the collection.
|
||||||
- `innerBlocks` (optional, type `Array[]`): An array of inner blocks that will be added to the collection. If not provided, the default inner blocks will be used.
|
- `innerBlocks` (optional, type `Array[]`): An array of inner blocks that will be added to the collection. If not provided, the default inner blocks will be used.
|
||||||
|
|
|
@ -62,7 +62,7 @@ In React:
|
||||||
import { registerBlockType } from '@wordpress/blocks';
|
import { registerBlockType } from '@wordpress/blocks';
|
||||||
|
|
||||||
function Edit() {
|
function Edit() {
|
||||||
return <p>Hello World (from the editor).</p>;
|
return <p>Hello World (from the editor).</p>;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerBlockType( 'tutorial/new-product-form-field', {
|
registerBlockType( 'tutorial/new-product-form-field', {
|
||||||
|
@ -217,8 +217,8 @@ function Edit( { attributes } ) {
|
||||||
|
|
||||||
const blockProps = useWooBlockProps( attributes );
|
const blockProps = useWooBlockProps( attributes );
|
||||||
return (
|
return (
|
||||||
<div { ...blockProps }>
|
<div { ...blockProps }>
|
||||||
<ComboboxControl
|
<ComboboxControl
|
||||||
label="Example dropdown"
|
label="Example dropdown"
|
||||||
value={ value }
|
value={ value }
|
||||||
onChange={ setValue }
|
onChange={ setValue }
|
||||||
|
@ -232,8 +232,8 @@ function Edit( { attributes } ) {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -32,7 +32,7 @@ npm run create-wc-extension
|
||||||
After choosing a name, move into that folder and start webpack to watch and build files.
|
After choosing a name, move into that folder and start webpack to watch and build files.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd ../<my-plugin-name>
|
cd ../<my-plugin-name>
|
||||||
npm install
|
npm install
|
||||||
npm start
|
npm start
|
||||||
```
|
```
|
||||||
|
|
|
@ -73,11 +73,11 @@ add_action('woocommerce_before_main_content', 'my_theme_wrapper_start', 10);
|
||||||
add_action('woocommerce_after_main_content', 'my_theme_wrapper_end', 10);
|
add_action('woocommerce_after_main_content', 'my_theme_wrapper_end', 10);
|
||||||
|
|
||||||
function my_theme_wrapper_start() {
|
function my_theme_wrapper_start() {
|
||||||
echo '<section id="main">';
|
echo '<section id="main">';
|
||||||
}
|
}
|
||||||
|
|
||||||
function my_theme_wrapper_end() {
|
function my_theme_wrapper_end() {
|
||||||
echo '</section>';
|
echo '</section>';
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
### wc customer_download
|
### wc customer_download
|
||||||
|
|
||||||
#### wc customer_download list <customer_id>
|
#### wc customer_download list <customer_id>
|
||||||
|
|
||||||
- `--customer_id` - Unique identifier for the resource.
|
- `--customer_id` - Unique identifier for the resource.
|
||||||
- `--context` - Scope under which the request is made; determines fields present in response.
|
- `--context` - Scope under which the request is made; determines fields present in response.
|
||||||
|
@ -198,7 +198,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
### wc order_note
|
### wc order_note
|
||||||
|
|
||||||
#### wc order_note list <order_id>
|
#### wc order_note list <order_id>
|
||||||
|
|
||||||
- `--order_id` - The order ID.
|
- `--order_id` - The order ID.
|
||||||
- `--context` - Scope under which the request is made; determines fields present in response.
|
- `--context` - Scope under which the request is made; determines fields present in response.
|
||||||
|
@ -211,14 +211,14 @@ Default: table
|
||||||
|
|
||||||
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
#### wc order_note create <order_id>
|
#### wc order_note create <order_id>
|
||||||
|
|
||||||
- `--order_id` - The order ID.
|
- `--order_id` - The order ID.
|
||||||
- `--note` - Order note content. (*Required*)
|
- `--note` - Order note content. (*Required*)
|
||||||
- `--customer_note` - If true, the note will be shown to customers and they will be notified. If false, the note will be for admin reference only.
|
- `--customer_note` - If true, the note will be shown to customers and they will be notified. If false, the note will be for admin reference only.
|
||||||
- `--porcelain` - Output just the id when the operation is successful.
|
- `--porcelain` - Output just the id when the operation is successful.
|
||||||
|
|
||||||
#### wc order_note get <order_id> [id]
|
#### wc order_note get <order_id> [id]
|
||||||
|
|
||||||
- `--id` - Unique identifier for the resource.
|
- `--id` - Unique identifier for the resource.
|
||||||
- `--order_id` - The order ID.
|
- `--order_id` - The order ID.
|
||||||
|
@ -231,7 +231,7 @@ Default: table
|
||||||
|
|
||||||
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
#### wc order_note delete <order_id> [id]
|
#### wc order_note delete <order_id> [id]
|
||||||
|
|
||||||
- `--id` - Unique identifier for the resource.
|
- `--id` - Unique identifier for the resource.
|
||||||
- `--order_id` - The order ID.
|
- `--order_id` - The order ID.
|
||||||
|
@ -240,7 +240,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
### wc shop_order_refund
|
### wc shop_order_refund
|
||||||
|
|
||||||
#### wc shop_order_refund list <order_id>
|
#### wc shop_order_refund list <order_id>
|
||||||
|
|
||||||
- `--order_id` - The order ID.
|
- `--order_id` - The order ID.
|
||||||
- `--context` - Scope under which the request is made; determines fields present in response.
|
- `--context` - Scope under which the request is made; determines fields present in response.
|
||||||
|
@ -265,7 +265,7 @@ Default: table
|
||||||
|
|
||||||
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
#### wc shop_order_refund create <order_id>
|
#### wc shop_order_refund create <order_id>
|
||||||
|
|
||||||
- `--order_id` - The order ID.
|
- `--order_id` - The order ID.
|
||||||
- `--amount` - Refund amount.
|
- `--amount` - Refund amount.
|
||||||
|
@ -276,7 +276,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
- `--api_refund` - When true, the payment gateway API is used to generate the refund.
|
- `--api_refund` - When true, the payment gateway API is used to generate the refund.
|
||||||
- `--porcelain` - Output just the id when the operation is successful.
|
- `--porcelain` - Output just the id when the operation is successful.
|
||||||
|
|
||||||
#### wc shop_order_refund get <order_id> [id]
|
#### wc shop_order_refund get <order_id> [id]
|
||||||
|
|
||||||
- `--order_id` - The order ID.
|
- `--order_id` - The order ID.
|
||||||
- `--id` - Unique identifier for the resource.
|
- `--id` - Unique identifier for the resource.
|
||||||
|
@ -289,7 +289,7 @@ Default: table
|
||||||
|
|
||||||
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
#### wc shop_order_refund delete <order_id> [id]
|
#### wc shop_order_refund delete <order_id> [id]
|
||||||
|
|
||||||
- `--order_id` - The order ID.
|
- `--order_id` - The order ID.
|
||||||
- `--id` - Unique identifier for the resource.
|
- `--id` - Unique identifier for the resource.
|
||||||
|
@ -386,7 +386,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
### wc product_attribute_term
|
### wc product_attribute_term
|
||||||
|
|
||||||
#### wc product_attribute_term list <attribute_id>
|
#### wc product_attribute_term list <attribute_id>
|
||||||
|
|
||||||
- `--attribute_id` - Unique identifier for the attribute of the terms.
|
- `--attribute_id` - Unique identifier for the attribute of the terms.
|
||||||
- `--context` - Scope under which the request is made; determines fields present in response.
|
- `--context` - Scope under which the request is made; determines fields present in response.
|
||||||
|
@ -409,7 +409,7 @@ Default: table
|
||||||
|
|
||||||
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
#### wc product_attribute_term create <attribute_id>
|
#### wc product_attribute_term create <attribute_id>
|
||||||
|
|
||||||
- `--attribute_id` - Unique identifier for the attribute of the terms.
|
- `--attribute_id` - Unique identifier for the attribute of the terms.
|
||||||
- `--name` - Name for the resource. (*Required*)
|
- `--name` - Name for the resource. (*Required*)
|
||||||
|
@ -418,7 +418,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
- `--menu_order` - Menu order, used to custom sort the resource.
|
- `--menu_order` - Menu order, used to custom sort the resource.
|
||||||
- `--porcelain` - Output just the id when the operation is successful.
|
- `--porcelain` - Output just the id when the operation is successful.
|
||||||
|
|
||||||
#### wc product_attribute_term get <attribute_id> [id]
|
#### wc product_attribute_term get <attribute_id> [id]
|
||||||
|
|
||||||
- `--id` - Unique identifier for the resource.
|
- `--id` - Unique identifier for the resource.
|
||||||
- `--attribute_id` - Unique identifier for the attribute of the terms.
|
- `--attribute_id` - Unique identifier for the attribute of the terms.
|
||||||
|
@ -431,7 +431,7 @@ Default: table
|
||||||
|
|
||||||
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
#### wc product_attribute_term update <attribute_id> [id]
|
#### wc product_attribute_term update <attribute_id> [id]
|
||||||
|
|
||||||
- `--id` - Unique identifier for the resource.
|
- `--id` - Unique identifier for the resource.
|
||||||
- `--attribute_id` - Unique identifier for the attribute of the terms.
|
- `--attribute_id` - Unique identifier for the attribute of the terms.
|
||||||
|
@ -441,7 +441,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
- `--menu_order` - Menu order, used to custom sort the resource.
|
- `--menu_order` - Menu order, used to custom sort the resource.
|
||||||
- `--porcelain` - Output just the id when the operation is successful.
|
- `--porcelain` - Output just the id when the operation is successful.
|
||||||
|
|
||||||
#### wc product_attribute_term delete <attribute_id> [id]
|
#### wc product_attribute_term delete <attribute_id> [id]
|
||||||
|
|
||||||
- `--id` - Unique identifier for the resource.
|
- `--id` - Unique identifier for the resource.
|
||||||
- `--attribute_id` - Unique identifier for the attribute of the terms.
|
- `--attribute_id` - Unique identifier for the attribute of the terms.
|
||||||
|
@ -565,7 +565,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
### wc product_review
|
### wc product_review
|
||||||
|
|
||||||
#### wc product_review list <product_id>
|
#### wc product_review list <product_id>
|
||||||
|
|
||||||
- `--product_id` - Unique identifier for the variable product.
|
- `--product_id` - Unique identifier for the variable product.
|
||||||
- `--id` - Unique identifier for the variation.
|
- `--id` - Unique identifier for the variation.
|
||||||
|
@ -578,7 +578,7 @@ Default: table
|
||||||
|
|
||||||
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
#### wc product_review create <product_id>
|
#### wc product_review create <product_id>
|
||||||
|
|
||||||
- `--product_id` - Unique identifier for the variable product.
|
- `--product_id` - Unique identifier for the variable product.
|
||||||
- `--id` - Unique identifier for the variation.
|
- `--id` - Unique identifier for the variation.
|
||||||
|
@ -590,7 +590,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
- `--email` - Email of the reviewer. (*Required*)
|
- `--email` - Email of the reviewer. (*Required*)
|
||||||
- `--porcelain` - Output just the id when the operation is successful.
|
- `--porcelain` - Output just the id when the operation is successful.
|
||||||
|
|
||||||
#### wc product_review get <product_id> [id]
|
#### wc product_review get <product_id> [id]
|
||||||
|
|
||||||
- `--product_id` - Unique identifier for the variable product.
|
- `--product_id` - Unique identifier for the variable product.
|
||||||
- `--id` - Unique identifier for the resource.
|
- `--id` - Unique identifier for the resource.
|
||||||
|
@ -603,7 +603,7 @@ Default: table
|
||||||
|
|
||||||
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
#### wc product_review update <product_id> [id]
|
#### wc product_review update <product_id> [id]
|
||||||
|
|
||||||
- `--product_id` - Unique identifier for the variable product.
|
- `--product_id` - Unique identifier for the variable product.
|
||||||
- `--id` - Unique identifier for the resource.
|
- `--id` - Unique identifier for the resource.
|
||||||
|
@ -615,7 +615,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
- `--email` - Reviewer email.
|
- `--email` - Reviewer email.
|
||||||
- `--porcelain` - Output just the id when the operation is successful.
|
- `--porcelain` - Output just the id when the operation is successful.
|
||||||
|
|
||||||
#### wc product_review delete <product_id> [id]
|
#### wc product_review delete <product_id> [id]
|
||||||
|
|
||||||
- `--product_id` - Unique identifier for the variable product.
|
- `--product_id` - Unique identifier for the variable product.
|
||||||
- `--id` - Unique identifier for the resource.
|
- `--id` - Unique identifier for the resource.
|
||||||
|
@ -893,7 +893,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
### wc product_variation
|
### wc product_variation
|
||||||
|
|
||||||
#### wc product_variation list <product_id>
|
#### wc product_variation list <product_id>
|
||||||
|
|
||||||
- `--product_id` - Unique identifier for the variable product.
|
- `--product_id` - Unique identifier for the variable product.
|
||||||
- `--context` - Scope under which the request is made; determines fields present in response.
|
- `--context` - Scope under which the request is made; determines fields present in response.
|
||||||
|
@ -932,7 +932,7 @@ Default: table
|
||||||
|
|
||||||
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
#### wc product_variation create <product_id>
|
#### wc product_variation create <product_id>
|
||||||
|
|
||||||
- `--product_id` - Unique identifier for the variable product.
|
- `--product_id` - Unique identifier for the variable product.
|
||||||
- `--description` - Variation description.
|
- `--description` - Variation description.
|
||||||
|
@ -964,7 +964,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
- `--meta_data` - Meta data.
|
- `--meta_data` - Meta data.
|
||||||
- `--porcelain` - Output just the id when the operation is successful.
|
- `--porcelain` - Output just the id when the operation is successful.
|
||||||
|
|
||||||
#### wc product_variation get <product_id> [id]
|
#### wc product_variation get <product_id> [id]
|
||||||
|
|
||||||
- `--product_id` - Unique identifier for the variable product.
|
- `--product_id` - Unique identifier for the variable product.
|
||||||
- `--id` - Unique identifier for the variation.
|
- `--id` - Unique identifier for the variation.
|
||||||
|
@ -977,7 +977,7 @@ Default: table
|
||||||
|
|
||||||
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
|
|
||||||
#### wc product_variation update <product_id> [id]
|
#### wc product_variation update <product_id> [id]
|
||||||
|
|
||||||
- `--product_id` - Unique identifier for the variable product.
|
- `--product_id` - Unique identifier for the variable product.
|
||||||
- `--id` - Unique identifier for the variation.
|
- `--id` - Unique identifier for the variation.
|
||||||
|
@ -1010,7 +1010,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
|
||||||
- `--meta_data` - Meta data.
|
- `--meta_data` - Meta data.
|
||||||
- `--porcelain` - Output just the id when the operation is successful.
|
- `--porcelain` - Output just the id when the operation is successful.
|
||||||
|
|
||||||
#### wc product_variation delete <product_id> [id]
|
#### wc product_variation delete <product_id> [id]
|
||||||
|
|
||||||
- `--product_id` - Unique identifier for the variable product.
|
- `--product_id` - Unique identifier for the variable product.
|
||||||
- `--id` - Unique identifier for the variation.
|
- `--id` - Unique identifier for the variation.
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: fix
|
||||||
|
|
||||||
|
Removed the leftover user meta from the help panel spotlight
|
|
@ -15,7 +15,6 @@ export type UserPreferences = {
|
||||||
dashboard_chart_type?: string;
|
dashboard_chart_type?: string;
|
||||||
dashboard_leaderboard_rows?: string;
|
dashboard_leaderboard_rows?: string;
|
||||||
dashboard_sections?: string;
|
dashboard_sections?: string;
|
||||||
help_panel_highlight_shown?: string;
|
|
||||||
homepage_layout?: string;
|
homepage_layout?: string;
|
||||||
homepage_stats?: string;
|
homepage_stats?: string;
|
||||||
orders_report_columns?: string;
|
orders_report_columns?: string;
|
||||||
|
|
|
@ -300,15 +300,28 @@ const exitToWooHome = fromPromise( async () => {
|
||||||
window.location.href = getNewPath( {}, '/', {} );
|
window.location.href = getNewPath( {}, '/', {} );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
const getPluginNameParam = (
|
||||||
|
pluginsSelected: CoreProfilerStateMachineContext[ 'pluginsSelected' ]
|
||||||
|
) => {
|
||||||
|
if ( pluginsSelected.includes( 'woocommerce-payments' ) ) {
|
||||||
|
return 'woocommerce-payments';
|
||||||
|
}
|
||||||
|
return 'jetpack-ai';
|
||||||
|
};
|
||||||
|
|
||||||
const redirectToJetpackAuthPage = ( {
|
const redirectToJetpackAuthPage = ( {
|
||||||
event,
|
event,
|
||||||
|
context,
|
||||||
}: {
|
}: {
|
||||||
context: CoreProfilerStateMachineContext;
|
context: CoreProfilerStateMachineContext;
|
||||||
event: { output: { url: string } };
|
event: { output: { url: string } };
|
||||||
} ) => {
|
} ) => {
|
||||||
const url = new URL( event.output.url );
|
const url = new URL( event.output.url );
|
||||||
url.searchParams.set( 'installed_ext_success', '1' );
|
url.searchParams.set( 'installed_ext_success', '1' );
|
||||||
url.searchParams.set( 'plugin_name', 'jetpack-ai' );
|
url.searchParams.set(
|
||||||
|
'plugin_name',
|
||||||
|
getPluginNameParam( context.pluginsSelected )
|
||||||
|
);
|
||||||
window.location.href = url.toString();
|
window.location.href = url.toString();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,11 @@ import { mergeBaseAndUserConfigs } from '@wordpress/edit-site/build-module/compo
|
||||||
import { unlock } from '@wordpress/edit-site/build-module/lock-unlock';
|
import { unlock } from '@wordpress/edit-site/build-module/lock-unlock';
|
||||||
import { isEqual, noop } from 'lodash';
|
import { isEqual, noop } from 'lodash';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { trackEvent } from '~/customize-store/tracking';
|
||||||
|
|
||||||
const { GlobalStylesContext } = unlock( blockEditorPrivateApis );
|
const { GlobalStylesContext } = unlock( blockEditorPrivateApis );
|
||||||
|
|
||||||
// Removes the typography settings from the styles when the user is changing
|
// Removes the typography settings from the styles when the user is changing
|
||||||
|
@ -100,6 +105,24 @@ export const VariationContainer = ( { variation, children } ) => {
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
if ( variation.settings.color?.palette ) {
|
||||||
|
trackEvent(
|
||||||
|
'customize_your_store_assembler_hub_color_palette_item_click',
|
||||||
|
{
|
||||||
|
item: variation.title,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( variation.settings.typography ) {
|
||||||
|
trackEvent(
|
||||||
|
'customize_your_store_assembler_hub_typography_item_click',
|
||||||
|
{
|
||||||
|
item: variation.title,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectOnEnter = ( event ) => {
|
const selectOnEnter = ( event ) => {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { unlock } from '@wordpress/edit-site/build-module/lock-unlock';
|
||||||
import { CustomizeStoreContext } from '../';
|
import { CustomizeStoreContext } from '../';
|
||||||
import { SidebarNavigationScreen } from './sidebar-navigation-screen';
|
import { SidebarNavigationScreen } from './sidebar-navigation-screen';
|
||||||
import { ColorPalette, ColorPanel } from './global-styles';
|
import { ColorPalette, ColorPanel } from './global-styles';
|
||||||
|
import { trackEvent } from '~/customize-store/tracking';
|
||||||
import { FlowType } from '~/customize-store/types';
|
import { FlowType } from '~/customize-store/types';
|
||||||
|
|
||||||
const { GlobalStylesContext } = unlock( blockEditorPrivateApis );
|
const { GlobalStylesContext } = unlock( blockEditorPrivateApis );
|
||||||
|
@ -27,6 +28,14 @@ const SidebarNavigationScreenColorPaletteContent = () => {
|
||||||
const hasCreatedOwnColors = !! (
|
const hasCreatedOwnColors = !! (
|
||||||
user.settings.color && user.settings.color.palette.hasCreatedOwnColors
|
user.settings.color && user.settings.color.palette.hasCreatedOwnColors
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function handlePanelBodyToggle( open?: boolean ) {
|
||||||
|
trackEvent(
|
||||||
|
'customize_your_store_assembler_hub_color_palette_create_toggle',
|
||||||
|
{ open }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Wrap in a BlockEditorProvider to ensure that the Iframe's dependencies are
|
// Wrap in a BlockEditorProvider to ensure that the Iframe's dependencies are
|
||||||
// loaded. This is necessary because the Iframe component waits until
|
// loaded. This is necessary because the Iframe component waits until
|
||||||
// the block editor store's `__internalIsInitialized` is true before
|
// the block editor store's `__internalIsInitialized` is true before
|
||||||
|
@ -45,6 +54,7 @@ const SidebarNavigationScreenColorPaletteContent = () => {
|
||||||
className="woocommerce-customize-store__color-panel-container"
|
className="woocommerce-customize-store__color-panel-container"
|
||||||
title={ __( 'or create your own', 'woocommerce' ) }
|
title={ __( 'or create your own', 'woocommerce' ) }
|
||||||
initialOpen={ hasCreatedOwnColors }
|
initialOpen={ hasCreatedOwnColors }
|
||||||
|
onToggle={ handlePanelBodyToggle }
|
||||||
>
|
>
|
||||||
<ColorPanel />
|
<ColorPanel />
|
||||||
</PanelBody>
|
</PanelBody>
|
||||||
|
|
|
@ -297,16 +297,26 @@ const LogoEdit = ( {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleMediaUploadSelect( media: { id: string; url: string } ) {
|
||||||
|
onInitialSelectLogo( media );
|
||||||
|
trackEvent( 'customize_your_store_assembler_hub_logo_select' );
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! logoUrl ) {
|
if ( ! logoUrl ) {
|
||||||
return (
|
return (
|
||||||
<MediaUploadCheck>
|
<MediaUploadCheck>
|
||||||
<MediaUpload
|
<MediaUpload
|
||||||
onSelect={ onInitialSelectLogo }
|
onSelect={ handleMediaUploadSelect }
|
||||||
allowedTypes={ ALLOWED_MEDIA_TYPES }
|
allowedTypes={ ALLOWED_MEDIA_TYPES }
|
||||||
render={ ( { open }: { open: () => void } ) => (
|
render={ ( { open }: { open: () => void } ) => (
|
||||||
<Button
|
<Button
|
||||||
variant="link"
|
variant="link"
|
||||||
onClick={ open }
|
onClick={ () => {
|
||||||
|
open();
|
||||||
|
trackEvent(
|
||||||
|
'customize_your_store_assembler_hub_logo_add_click'
|
||||||
|
);
|
||||||
|
} }
|
||||||
className="block-library-site-logo__inspector-upload-container"
|
className="block-library-site-logo__inspector-upload-container"
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
|
@ -351,10 +361,17 @@ const LogoEdit = ( {
|
||||||
<>
|
<>
|
||||||
<MediaUploadCheck>
|
<MediaUploadCheck>
|
||||||
<MediaUpload
|
<MediaUpload
|
||||||
onSelect={ onInitialSelectLogo }
|
onSelect={ handleMediaUploadSelect }
|
||||||
allowedTypes={ ALLOWED_MEDIA_TYPES }
|
allowedTypes={ ALLOWED_MEDIA_TYPES }
|
||||||
render={ ( { open }: { open: () => void } ) =>
|
render={ ( { open }: { open: () => void } ) =>
|
||||||
cloneElement( logoImg, { onClick: open } )
|
cloneElement( logoImg, {
|
||||||
|
onClick() {
|
||||||
|
open();
|
||||||
|
trackEvent(
|
||||||
|
'customize_your_store_assembler_hub_logo_edit_click'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
} )
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</MediaUploadCheck>
|
</MediaUploadCheck>
|
||||||
|
@ -478,6 +495,9 @@ export const SidebarNavigationScreenLogo = ( {
|
||||||
media
|
media
|
||||||
);
|
);
|
||||||
onClose();
|
onClose();
|
||||||
|
trackEvent(
|
||||||
|
'customize_your_store_assembler_hub_logo_select'
|
||||||
|
);
|
||||||
} }
|
} }
|
||||||
allowedTypes={
|
allowedTypes={
|
||||||
ALLOWED_MEDIA_TYPES
|
ALLOWED_MEDIA_TYPES
|
||||||
|
@ -490,6 +510,9 @@ export const SidebarNavigationScreenLogo = ( {
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={ () => {
|
onClick={ () => {
|
||||||
open();
|
open();
|
||||||
|
trackEvent(
|
||||||
|
'customize_your_store_assembler_hub_logo_replace_click'
|
||||||
|
);
|
||||||
} }
|
} }
|
||||||
>
|
>
|
||||||
{ __(
|
{ __(
|
||||||
|
@ -508,6 +531,9 @@ export const SidebarNavigationScreenLogo = ( {
|
||||||
onClick={ () => {
|
onClick={ () => {
|
||||||
onClose();
|
onClose();
|
||||||
onRemoveLogo();
|
onRemoveLogo();
|
||||||
|
trackEvent(
|
||||||
|
'customize_your_store_assembler_hub_logo_remove_click'
|
||||||
|
);
|
||||||
} }
|
} }
|
||||||
>
|
>
|
||||||
{ __(
|
{ __(
|
||||||
|
|
|
@ -8,8 +8,18 @@
|
||||||
min-height: 500px;
|
min-height: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.woocommerce-marketplace__content .woocommerce-customize-store-banner .woocommerce-customize-store-banner-content {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (min-width: $breakpoint-medium) {
|
@media screen and (min-width: $breakpoint-medium) {
|
||||||
.woocommerce-marketplace__content {
|
.woocommerce-marketplace__content {
|
||||||
padding: $grid-unit-60 $grid-unit-40;
|
padding: $grid-unit-60 $grid-unit-40;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: $breakpoint-medium) {
|
||||||
|
.woocommerce-marketplace__content .woocommerce-customize-store-banner .woocommerce-customize-store-banner-content {
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -73,7 +73,8 @@ export default function Content(): JSX.Element {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
query.tab === undefined ||
|
query.tab === undefined ||
|
||||||
( query.tab && [ '', 'discover' ].includes( query.tab ) )
|
( query.tab &&
|
||||||
|
[ '', 'discover', 'my-subscriptions' ].includes( query.tab ) )
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -196,6 +197,9 @@ export default function Content(): JSX.Element {
|
||||||
{ selectedTab !== 'business-services' && (
|
{ selectedTab !== 'business-services' && (
|
||||||
<SubscriptionsExpiredExpiringNotice type="expiring" />
|
<SubscriptionsExpiredExpiringNotice type="expiring" />
|
||||||
) }
|
) }
|
||||||
|
{ selectedTab !== 'business-services' && (
|
||||||
|
<SubscriptionsExpiredExpiringNotice type="missing" />
|
||||||
|
) }
|
||||||
|
|
||||||
{ renderContent() }
|
{ renderContent() }
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,6 +13,7 @@ import ProductLoader from '../product-loader/product-loader';
|
||||||
import { MarketplaceContext } from '../../contexts/marketplace-context';
|
import { MarketplaceContext } from '../../contexts/marketplace-context';
|
||||||
import { ProductType } from '../product-list/types';
|
import { ProductType } from '../product-list/types';
|
||||||
import './discover.scss';
|
import './discover.scss';
|
||||||
|
import { recordMarketplaceView } from '~/marketplace/utils/tracking';
|
||||||
|
|
||||||
export default function Discover(): JSX.Element | null {
|
export default function Discover(): JSX.Element | null {
|
||||||
const [ productGroups, setProductGroups ] = useState<
|
const [ productGroups, setProductGroups ] = useState<
|
||||||
|
@ -28,10 +29,17 @@ export default function Discover(): JSX.Element | null {
|
||||||
return product.id;
|
return product.id;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
// This is a new event specific to the Discover tab, added with Woo 8.4.
|
||||||
recordEvent( 'marketplace_discover_viewed', {
|
recordEvent( 'marketplace_discover_viewed', {
|
||||||
view: 'discover',
|
view: 'discover',
|
||||||
product_ids,
|
product_ids,
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
// This is the new page view event added with Woo 8.3. It's improved with the marketplace_discover_viewed event
|
||||||
|
// but we'll keep it for a while to keep it compatible.
|
||||||
|
recordMarketplaceView( {
|
||||||
|
view: 'discover',
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the content for this screen
|
// Get the content for this screen
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
.woocommerce-marketplace__footer {
|
.woocommerce-marketplace__footer {
|
||||||
background: $gray-0;
|
background: $gray-0;
|
||||||
border-top: 1px solid $gray-200;
|
border-radius: 4px;
|
||||||
|
max-width: 1600px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: $content-spacing-xlarge $content-spacing-small;
|
padding: $content-spacing-xlarge $content-spacing-small;
|
||||||
|
|
||||||
|
@ -34,16 +35,6 @@
|
||||||
gap: $large-gap;
|
gap: $large-gap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.woocommerce-marketplace__footer-logo {
|
|
||||||
color: $wp-gray-50;
|
|
||||||
display: flex;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 20px;
|
|
||||||
gap: $small-gap;
|
|
||||||
margin: 48px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: $breakpoint-medium) {
|
@media screen and (min-width: $breakpoint-medium) {
|
||||||
.woocommerce-marketplace__footer {
|
.woocommerce-marketplace__footer {
|
||||||
padding: $content-spacing-xlarge $content-spacing-large;
|
padding: $content-spacing-xlarge $content-spacing-large;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { check, commentContent, shield } from '@wordpress/icons';
|
import { check, commentContent, shield, people } from '@wordpress/icons';
|
||||||
import { createInterpolateElement } from '@wordpress/element';
|
import { createInterpolateElement } from '@wordpress/element';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,7 +10,6 @@ import { createInterpolateElement } from '@wordpress/element';
|
||||||
*/
|
*/
|
||||||
import './footer.scss';
|
import './footer.scss';
|
||||||
import IconWithText from '../icon-with-text/icon-with-text';
|
import IconWithText from '../icon-with-text/icon-with-text';
|
||||||
import WooIcon from '../../assets/images/woo-icon.svg';
|
|
||||||
import { MARKETPLACE_HOST } from '../constants';
|
import { MARKETPLACE_HOST } from '../constants';
|
||||||
|
|
||||||
const refundPolicyTitle = createInterpolateElement(
|
const refundPolicyTitle = createInterpolateElement(
|
||||||
|
@ -71,10 +70,14 @@ function FooterContent(): JSX.Element {
|
||||||
'woocommerce'
|
'woocommerce'
|
||||||
) }
|
) }
|
||||||
/>
|
/>
|
||||||
</div>
|
<IconWithText
|
||||||
<div className="woocommerce-marketplace__footer-logo">
|
icon={ people }
|
||||||
<img src={ WooIcon } alt="Woo Logo" aria-hidden="true" />
|
title={ __( 'Support the ecosystem', 'woocommerce' ) }
|
||||||
<span>{ __( 'Woo Marketplace', 'woocommerce' ) }</span>
|
description={ __(
|
||||||
|
'Our team and partners are continuously improving your extensions, themes, and WooCommerce experience.',
|
||||||
|
'woocommerce'
|
||||||
|
) }
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
"mktpl-tabs mktpl-tabs mktpl-tabs" auto / 1fr 320px 36px;
|
"mktpl-tabs mktpl-tabs mktpl-tabs" auto / 1fr 320px 36px;
|
||||||
padding: 0 $content-spacing-large;
|
padding: 0 $content-spacing-large;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
position: sticky;
|
||||||
|
top: var(--wp-admin--admin-bar--height, 32px);
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
/* On narrow screens, "stack" header items and hide the bottom border */
|
/* On narrow screens, "stack" header items and hide the bottom border */
|
||||||
@media (width <= $breakpoint-medium) {
|
@media (width <= $breakpoint-medium) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import './icon-with-text.scss';
|
||||||
|
|
||||||
export interface IconWithTextProps {
|
export interface IconWithTextProps {
|
||||||
icon: JSX.Element;
|
icon: JSX.Element;
|
||||||
title: ReactElement;
|
title: ReactElement | string;
|
||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,12 @@ export default function SubscriptionsExpiredExpiringNotice(
|
||||||
dismissed:
|
dismissed:
|
||||||
'woo_subscription_expiring_notice_in_marketplace_dismissed',
|
'woo_subscription_expiring_notice_in_marketplace_dismissed',
|
||||||
},
|
},
|
||||||
|
'woo-subscription-missing-notice': {
|
||||||
|
shown: 'woo_subscription_missing_notice_in_marketplace_shown',
|
||||||
|
clicked: 'woo_subscription_missing_notice_in_marketplace_clicked',
|
||||||
|
dismissed:
|
||||||
|
'woo_subscription_missing_notice_in_marketplace_dismissed',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let notice = null;
|
let notice = null;
|
||||||
|
@ -51,6 +57,9 @@ export default function SubscriptionsExpiredExpiringNotice(
|
||||||
} else if ( type === 'expiring' ) {
|
} else if ( type === 'expiring' ) {
|
||||||
notice = wccomSettings?.subscription_expiring_notice || {};
|
notice = wccomSettings?.subscription_expiring_notice || {};
|
||||||
notice_id = 'woo-subscription-expiring-notice';
|
notice_id = 'woo-subscription-expiring-notice';
|
||||||
|
} else if ( type === 'missing' ) {
|
||||||
|
notice = wccomSettings?.subscription_missing_notice || {};
|
||||||
|
notice_id = 'woo-subscription-missing-notice';
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
&__product-card {
|
&__product-card {
|
||||||
padding: $large-gap;
|
padding: $large-gap;
|
||||||
border-radius: $grid-unit-05 !important;
|
border-radius: $grid-unit-05 !important;
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
/* When product card is loading, contents will be empty and we render skeleton loader wireframes: */
|
/* When product card is loading, contents will be empty and we render skeleton loader wireframes: */
|
||||||
&.is-loading {
|
&.is-loading {
|
||||||
|
@ -243,7 +244,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.woocommerce-marketplace__product-card--theme {
|
&.woocommerce-marketplace__product-card--theme {
|
||||||
padding: 0 0 $medium-gap;
|
padding: 0 0 $large-gap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.woocommerce-marketplace__product-card__content {
|
.woocommerce-marketplace__product-card__content {
|
||||||
|
@ -265,10 +266,10 @@
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
.woocommerce-marketplace__product-card__header {
|
.woocommerce-marketplace__product-card__header {
|
||||||
padding-left: $medium-gap;
|
padding: 0 $large-gap;
|
||||||
}
|
}
|
||||||
.woocommerce-marketplace__product-card__footer {
|
.woocommerce-marketplace__product-card__footer {
|
||||||
padding: 0 $medium-gap;
|
padding: 0 $large-gap;
|
||||||
}
|
}
|
||||||
.woocommerce-marketplace__product-card__price {
|
.woocommerce-marketplace__product-card__price {
|
||||||
margin-right: $medium-gap;
|
margin-right: $medium-gap;
|
||||||
|
@ -313,7 +314,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $small-gap;
|
gap: $small-gap;
|
||||||
padding: 16px 24px;
|
padding: $large-gap;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,6 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#wpbody-content {
|
|
||||||
/* Prevent double-scrollbar issue on WooCommerce > Extension pages */
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-layout__primary {
|
.woocommerce-layout__primary {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import domReady from '@wordpress/dom-ready';
|
||||||
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
|
|
||||||
|
domReady( () => {
|
||||||
|
const purchaseSubscriptionLink = document.querySelectorAll(
|
||||||
|
'.woocommerce-purchase-subscription'
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( purchaseSubscriptionLink.length > 0 ) {
|
||||||
|
recordEvent( 'woo_purchase_subscription_in_plugins_shown' );
|
||||||
|
purchaseSubscriptionLink.forEach( ( link ) => {
|
||||||
|
link.addEventListener( 'click', function () {
|
||||||
|
recordEvent( 'woo_purchase_subscription_in_plugins_clicked' );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
} );
|
|
@ -83,7 +83,7 @@ class SimpleInboxNote {
|
||||||
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
|
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
|
||||||
|
|
||||||
// Set the type of layout the note uses. Supported layout types are:
|
// Set the type of layout the note uses. Supported layout types are:
|
||||||
// 'banner', 'plain', 'thumbnail'.
|
// 'plain', 'thumbnail'.
|
||||||
$note->set_layout( 'plain' );
|
$note->set_layout( 'plain' );
|
||||||
|
|
||||||
// Set the image for the note. This property renders as the src
|
// Set the image for the note. This property renders as the src
|
||||||
|
|
|
@ -73,7 +73,6 @@ function get_mock_note_data() {
|
||||||
return array(
|
return array(
|
||||||
'content' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud.',
|
'content' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud.',
|
||||||
'info' => array(
|
'info' => array(
|
||||||
'banner' => $plugin_url . 'images/admin-notes/banner.jpg',
|
|
||||||
'thumbnail' => $plugin_url . 'images/admin-notes/thumbnail.jpg',
|
'thumbnail' => $plugin_url . 'images/admin-notes/thumbnail.jpg',
|
||||||
'plain' => '',
|
'plain' => '',
|
||||||
),
|
),
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: patch
|
||||||
|
Type: update
|
||||||
|
|
||||||
|
Deprecate unsupported Inbox note banner layout
|
|
@ -1,114 +1,26 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { __, _n, sprintf } from '@wordpress/i18n';
|
|
||||||
import clsx from 'clsx';
|
|
||||||
import {
|
import {
|
||||||
useInnerBlockLayoutContext,
|
useInnerBlockLayoutContext,
|
||||||
useProductDataContext,
|
useProductDataContext,
|
||||||
} from '@woocommerce/shared-context';
|
} from '@woocommerce/shared-context';
|
||||||
import { useStyleProps } from '@woocommerce/base-hooks';
|
import { useStyleProps } from '@woocommerce/base-hooks';
|
||||||
import { withProductDataContext } from '@woocommerce/shared-hocs';
|
import { withProductDataContext } from '@woocommerce/shared-hocs';
|
||||||
import { isNumber, ProductResponseItem } from '@woocommerce/types';
|
import {
|
||||||
|
ProductRating,
|
||||||
|
getAverageRating,
|
||||||
|
getRatingCount,
|
||||||
|
} from '@woocommerce/editor-components/product-rating';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
type RatingProps = {
|
|
||||||
reviews: number;
|
|
||||||
rating: number;
|
|
||||||
parentClassName?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getAverageRating = (
|
|
||||||
product: Omit< ProductResponseItem, 'average_rating' > & {
|
|
||||||
average_rating: string;
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
const rating = parseFloat( product.average_rating );
|
|
||||||
|
|
||||||
return Number.isFinite( rating ) && rating > 0 ? rating : 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getRatingCount = ( product: ProductResponseItem ) => {
|
|
||||||
const count = isNumber( product.review_count )
|
|
||||||
? product.review_count
|
|
||||||
: parseInt( product.review_count, 10 );
|
|
||||||
|
|
||||||
return Number.isFinite( count ) && count > 0 ? count : 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getStarStyle = ( rating: number ) => ( {
|
|
||||||
width: ( rating / 5 ) * 100 + '%',
|
|
||||||
} );
|
|
||||||
|
|
||||||
const NoRating = ( { parentClassName }: { parentClassName: string } ) => {
|
|
||||||
const starStyle = getStarStyle( 0 );
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={ clsx(
|
|
||||||
'wc-block-components-product-rating-stars__norating-container',
|
|
||||||
`${ parentClassName }-product-rating-stars__norating-container`
|
|
||||||
) }
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
'wc-block-components-product-rating-stars__norating'
|
|
||||||
}
|
|
||||||
role="img"
|
|
||||||
>
|
|
||||||
<span style={ starStyle } />
|
|
||||||
</div>
|
|
||||||
<span>{ __( 'No Reviews', 'woocommerce' ) }</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Rating = ( props: RatingProps ): JSX.Element => {
|
|
||||||
const { rating, reviews, parentClassName } = props;
|
|
||||||
|
|
||||||
const starStyle = getStarStyle( rating );
|
|
||||||
|
|
||||||
const ratingText = sprintf(
|
|
||||||
/* translators: %f is referring to the average rating value */
|
|
||||||
__( 'Rated %f out of 5', 'woocommerce' ),
|
|
||||||
rating
|
|
||||||
);
|
|
||||||
|
|
||||||
const ratingHTML = {
|
|
||||||
__html: sprintf(
|
|
||||||
/* translators: %1$s is referring to the average rating value, %2$s is referring to the number of ratings */
|
|
||||||
_n(
|
|
||||||
'Rated %1$s out of 5 based on %2$s customer rating',
|
|
||||||
'Rated %1$s out of 5 based on %2$s customer ratings',
|
|
||||||
reviews,
|
|
||||||
'woocommerce'
|
|
||||||
),
|
|
||||||
sprintf( '<strong class="rating">%f</strong>', rating ),
|
|
||||||
sprintf( '<span class="rating">%d</span>', reviews )
|
|
||||||
),
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={ clsx(
|
|
||||||
'wc-block-components-product-rating-stars__stars',
|
|
||||||
`${ parentClassName }__product-rating-stars__stars`
|
|
||||||
) }
|
|
||||||
role="img"
|
|
||||||
aria-label={ ratingText }
|
|
||||||
>
|
|
||||||
<span style={ starStyle } dangerouslySetInnerHTML={ ratingHTML } />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ProductRatingStarsProps {
|
interface ProductRatingStarsProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
textAlign?: string;
|
textAlign?: string;
|
||||||
isDescendentOfSingleProductBlock: boolean;
|
|
||||||
isDescendentOfQueryLoop: boolean;
|
isDescendentOfQueryLoop: boolean;
|
||||||
postId: number;
|
postId: number;
|
||||||
productId: number;
|
productId: number;
|
||||||
|
@ -116,42 +28,29 @@ interface ProductRatingStarsProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Block = ( props: ProductRatingStarsProps ): JSX.Element | null => {
|
export const Block = ( props: ProductRatingStarsProps ): JSX.Element | null => {
|
||||||
const { textAlign, shouldDisplayMockedReviewsWhenProductHasNoReviews } =
|
const {
|
||||||
props;
|
textAlign = '',
|
||||||
|
shouldDisplayMockedReviewsWhenProductHasNoReviews,
|
||||||
|
} = props;
|
||||||
const styleProps = useStyleProps( props );
|
const styleProps = useStyleProps( props );
|
||||||
const { parentClassName } = useInnerBlockLayoutContext();
|
const { parentClassName } = useInnerBlockLayoutContext();
|
||||||
const { product } = useProductDataContext();
|
const { product } = useProductDataContext();
|
||||||
const rating = getAverageRating( product );
|
const rating = getAverageRating( product );
|
||||||
const reviews = getRatingCount( product );
|
const reviews = getRatingCount( product );
|
||||||
|
const className = 'wc-block-components-product-rating-stars';
|
||||||
const className = clsx(
|
|
||||||
styleProps.className,
|
|
||||||
'wc-block-components-product-rating-stars',
|
|
||||||
{
|
|
||||||
[ `${ parentClassName }__product-rating` ]: parentClassName,
|
|
||||||
[ `has-text-align-${ textAlign }` ]: textAlign,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const mockedRatings = shouldDisplayMockedReviewsWhenProductHasNoReviews ? (
|
|
||||||
<NoRating parentClassName={ parentClassName } />
|
|
||||||
) : null;
|
|
||||||
|
|
||||||
const content = reviews ? (
|
|
||||||
<Rating
|
|
||||||
rating={ rating }
|
|
||||||
reviews={ reviews }
|
|
||||||
parentClassName={ parentClassName }
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
mockedRatings
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ className } style={ styleProps.style }>
|
<ProductRating
|
||||||
<div className="wc-block-components-product-rating-stars__container">
|
className={ className }
|
||||||
{ content }
|
showMockedReviews={
|
||||||
</div>
|
shouldDisplayMockedReviewsWhenProductHasNoReviews
|
||||||
</div>
|
}
|
||||||
|
styleProps={ styleProps }
|
||||||
|
parentClassName={ parentClassName }
|
||||||
|
reviews={ reviews }
|
||||||
|
rating={ rating }
|
||||||
|
textAlign={ textAlign }
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,129 +1,23 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { __, _n, sprintf } from '@wordpress/i18n';
|
|
||||||
import clsx from 'clsx';
|
|
||||||
import {
|
import {
|
||||||
useInnerBlockLayoutContext,
|
useInnerBlockLayoutContext,
|
||||||
useProductDataContext,
|
useProductDataContext,
|
||||||
} from '@woocommerce/shared-context';
|
} from '@woocommerce/shared-context';
|
||||||
import { useStyleProps } from '@woocommerce/base-hooks';
|
import { useStyleProps } from '@woocommerce/base-hooks';
|
||||||
import { withProductDataContext } from '@woocommerce/shared-hocs';
|
import { withProductDataContext } from '@woocommerce/shared-hocs';
|
||||||
import { isNumber, ProductResponseItem } from '@woocommerce/types';
|
import {
|
||||||
|
ProductRating,
|
||||||
|
getAverageRating,
|
||||||
|
getRatingCount,
|
||||||
|
} from '@woocommerce/editor-components/product-rating';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
type RatingProps = {
|
|
||||||
reviews: number;
|
|
||||||
rating: number;
|
|
||||||
parentClassName?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getAverageRating = (
|
|
||||||
product: Omit< ProductResponseItem, 'average_rating' > & {
|
|
||||||
average_rating: string;
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
const rating = parseFloat( product.average_rating );
|
|
||||||
|
|
||||||
return Number.isFinite( rating ) && rating > 0 ? rating : 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getRatingCount = ( product: ProductResponseItem ) => {
|
|
||||||
const count = isNumber( product.review_count )
|
|
||||||
? product.review_count
|
|
||||||
: parseInt( product.review_count, 10 );
|
|
||||||
|
|
||||||
return Number.isFinite( count ) && count > 0 ? count : 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getStarStyle = ( rating: number ) => ( {
|
|
||||||
width: ( rating / 5 ) * 100 + '%',
|
|
||||||
} );
|
|
||||||
|
|
||||||
const NoRating = ( { parentClassName }: { parentClassName: string } ) => {
|
|
||||||
const starStyle = getStarStyle( 0 );
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={ clsx(
|
|
||||||
'wc-block-components-product-rating__norating-container',
|
|
||||||
`${ parentClassName }-product-rating__norating-container`
|
|
||||||
) }
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={ 'wc-block-components-product-rating__norating' }
|
|
||||||
role="img"
|
|
||||||
>
|
|
||||||
<span style={ starStyle } />
|
|
||||||
</div>
|
|
||||||
<span>{ __( 'No Reviews', 'woocommerce' ) }</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Rating = ( props: RatingProps ): JSX.Element => {
|
|
||||||
const { rating, reviews, parentClassName } = props;
|
|
||||||
|
|
||||||
const starStyle = getStarStyle( rating );
|
|
||||||
|
|
||||||
const ratingText = sprintf(
|
|
||||||
/* translators: %f is referring to the average rating value */
|
|
||||||
__( 'Rated %f out of 5', 'woocommerce' ),
|
|
||||||
rating
|
|
||||||
);
|
|
||||||
|
|
||||||
const ratingHTML = {
|
|
||||||
__html: sprintf(
|
|
||||||
/* translators: %1$s is referring to the average rating value, %2$s is referring to the number of ratings */
|
|
||||||
_n(
|
|
||||||
'Rated %1$s out of 5 based on %2$s customer rating',
|
|
||||||
'Rated %1$s out of 5 based on %2$s customer ratings',
|
|
||||||
reviews,
|
|
||||||
'woocommerce'
|
|
||||||
),
|
|
||||||
sprintf( '<strong class="rating">%f</strong>', rating ),
|
|
||||||
sprintf( '<span class="rating">%d</span>', reviews )
|
|
||||||
),
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={ clsx(
|
|
||||||
'wc-block-components-product-rating__stars',
|
|
||||||
`${ parentClassName }__product-rating__stars`
|
|
||||||
) }
|
|
||||||
role="img"
|
|
||||||
aria-label={ ratingText }
|
|
||||||
>
|
|
||||||
<span style={ starStyle } dangerouslySetInnerHTML={ ratingHTML } />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ReviewsCount = ( props: { reviews: number } ): JSX.Element => {
|
|
||||||
const { reviews } = props;
|
|
||||||
|
|
||||||
const reviewsCount = sprintf(
|
|
||||||
/* translators: %s is referring to the total of reviews for a product */
|
|
||||||
_n(
|
|
||||||
'(%s customer review)',
|
|
||||||
'(%s customer reviews)',
|
|
||||||
reviews,
|
|
||||||
'woocommerce'
|
|
||||||
),
|
|
||||||
reviews
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span className="wc-block-components-product-rating__reviews_count">
|
|
||||||
{ reviewsCount }
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
type ProductRatingProps = {
|
type ProductRatingProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
textAlign?: string;
|
textAlign?: string;
|
||||||
|
@ -136,7 +30,7 @@ type ProductRatingProps = {
|
||||||
|
|
||||||
export const Block = ( props: ProductRatingProps ): JSX.Element | undefined => {
|
export const Block = ( props: ProductRatingProps ): JSX.Element | undefined => {
|
||||||
const {
|
const {
|
||||||
textAlign,
|
textAlign = '',
|
||||||
isDescendentOfSingleProductBlock,
|
isDescendentOfSingleProductBlock,
|
||||||
shouldDisplayMockedReviewsWhenProductHasNoReviews,
|
shouldDisplayMockedReviewsWhenProductHasNoReviews,
|
||||||
} = props;
|
} = props;
|
||||||
|
@ -146,38 +40,22 @@ export const Block = ( props: ProductRatingProps ): JSX.Element | undefined => {
|
||||||
const rating = getAverageRating( product );
|
const rating = getAverageRating( product );
|
||||||
const reviews = getRatingCount( product );
|
const reviews = getRatingCount( product );
|
||||||
|
|
||||||
const className = clsx(
|
const className = 'wc-block-components-product-rating';
|
||||||
styleProps.className,
|
|
||||||
'wc-block-components-product-rating',
|
|
||||||
{
|
|
||||||
[ `${ parentClassName }__product-rating` ]: parentClassName,
|
|
||||||
[ `has-text-align-${ textAlign }` ]: textAlign,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const mockedRatings = shouldDisplayMockedReviewsWhenProductHasNoReviews ? (
|
|
||||||
<NoRating parentClassName={ parentClassName } />
|
|
||||||
) : null;
|
|
||||||
|
|
||||||
const content = reviews ? (
|
|
||||||
<Rating
|
|
||||||
rating={ rating }
|
|
||||||
reviews={ reviews }
|
|
||||||
parentClassName={ parentClassName }
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
mockedRatings
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( reviews || shouldDisplayMockedReviewsWhenProductHasNoReviews ) {
|
if ( reviews || shouldDisplayMockedReviewsWhenProductHasNoReviews ) {
|
||||||
return (
|
return (
|
||||||
<div className={ className } style={ styleProps.style }>
|
<ProductRating
|
||||||
<div className="wc-block-components-product-rating__container">
|
className={ className }
|
||||||
{ content }
|
showReviewCount={ isDescendentOfSingleProductBlock }
|
||||||
{ reviews && isDescendentOfSingleProductBlock ? (
|
showMockedReviews={
|
||||||
<ReviewsCount reviews={ reviews } />
|
shouldDisplayMockedReviewsWhenProductHasNoReviews
|
||||||
) : null }
|
}
|
||||||
</div>
|
styleProps={ styleProps }
|
||||||
</div>
|
parentClassName={ parentClassName }
|
||||||
|
reviews={ reviews }
|
||||||
|
rating={ rating }
|
||||||
|
textAlign={ textAlign }
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,6 +32,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
.wc-block-components-button__text {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.outlined {
|
&.outlined {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: currentColor;
|
color: currentColor;
|
||||||
|
|
|
@ -18,4 +18,5 @@ export { default as ShippingRatesControlPackage } from './shipping-rates-control
|
||||||
export { default as PaymentMethodIcons } from './payment-method-icons';
|
export { default as PaymentMethodIcons } from './payment-method-icons';
|
||||||
export { default as PaymentMethodLabel } from './payment-method-label';
|
export { default as PaymentMethodLabel } from './payment-method-label';
|
||||||
export { default as AdditionalFieldsPlaceholder } from './additional-fields-placeholder';
|
export { default as AdditionalFieldsPlaceholder } from './additional-fields-placeholder';
|
||||||
|
export { default as PasswordStrengthMeter } from './password-strength-meter';
|
||||||
export * from './totals';
|
export * from './totals';
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
}
|
}
|
||||||
.wc-block-components-password-strength__meter[value="2"],
|
.wc-block-components-password-strength__meter[value="2"],
|
||||||
.wc-block-components-password-strength__meter[value="2"] + .wc-block-components-password-strength__result {
|
.wc-block-components-password-strength__meter[value="2"] + .wc-block-components-password-strength__result {
|
||||||
color: #ff6f00;
|
color: $alert-red;
|
||||||
}
|
}
|
||||||
.wc-block-components-password-strength__meter[value="3"],
|
.wc-block-components-password-strength__meter[value="3"],
|
||||||
.wc-block-components-password-strength__meter[value="3"] + .wc-block-components-password-strength__result {
|
.wc-block-components-password-strength__meter[value="3"] + .wc-block-components-password-strength__result {
|
|
@ -18,7 +18,7 @@
|
||||||
&:focus {
|
&:focus {
|
||||||
background-color: $input-background-dark;
|
background-color: $input-background-dark;
|
||||||
color: $input-text-dark;
|
color: $input-text-dark;
|
||||||
box-shadow: 0 0 0 2px $input-border-gray;
|
box-shadow: 0 0 0 2px $input-border-dark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,12 +40,16 @@
|
||||||
color: $input-text-active;
|
color: $input-text-active;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: 0;
|
outline: none;
|
||||||
box-shadow: 0 0 0 1px inherit;
|
box-shadow: 0 0 0 2px $input-border-gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-dark-controls & {
|
.has-dark-controls & {
|
||||||
color: $input-text-dark;
|
color: $input-text-dark;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: 0 0 0 2px $input-border-dark;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-error & {
|
.has-error & {
|
||||||
|
|
|
@ -6,11 +6,7 @@ import { useState } from '@wordpress/element';
|
||||||
import { ValidatedTextInput } from '@woocommerce/blocks-components';
|
import { ValidatedTextInput } from '@woocommerce/blocks-components';
|
||||||
import { useDispatch, useSelect } from '@wordpress/data';
|
import { useDispatch, useSelect } from '@wordpress/data';
|
||||||
import { CHECKOUT_STORE_KEY } from '@woocommerce/block-data';
|
import { CHECKOUT_STORE_KEY } from '@woocommerce/block-data';
|
||||||
|
import PasswordStrengthMeter from '@woocommerce/base-components/cart-checkout/password-strength-meter';
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import PasswordStrengthMeter from '../../password-strength-meter';
|
|
||||||
|
|
||||||
const CreatePassword = () => {
|
const CreatePassword = () => {
|
||||||
const [ passwordStrength, setPasswordStrength ] = useState( 0 );
|
const [ passwordStrength, setPasswordStrength ] = useState( 0 );
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
{
|
||||||
|
"name": "woocommerce/order-confirmation-create-account",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"title": "Account Creation",
|
||||||
|
"description": "Allow customers to create an account after their purchase. Configure this feature in your store settings.",
|
||||||
|
"category": "woocommerce",
|
||||||
|
"keywords": [
|
||||||
|
"WooCommerce"
|
||||||
|
],
|
||||||
|
"attributes": {
|
||||||
|
"customerEmail": {
|
||||||
|
"type": "string",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"nonceToken": {
|
||||||
|
"type": "string",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"align": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "wide"
|
||||||
|
},
|
||||||
|
"className": {
|
||||||
|
"type": "string",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"hasDarkControls": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"supports": {
|
||||||
|
"color": {
|
||||||
|
"background": true,
|
||||||
|
"text": true,
|
||||||
|
"button": true
|
||||||
|
},
|
||||||
|
"multiple": false,
|
||||||
|
"align": [
|
||||||
|
"wide",
|
||||||
|
"full"
|
||||||
|
],
|
||||||
|
"html": false,
|
||||||
|
"spacing": {
|
||||||
|
"padding": true,
|
||||||
|
"margin": true,
|
||||||
|
"__experimentalDefaultControls": {
|
||||||
|
"margin": false,
|
||||||
|
"padding": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"textdomain": "woocommerce",
|
||||||
|
"apiVersion": 3,
|
||||||
|
"$schema": "https://schemas.wp.org/trunk/block.json"
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import type { TemplateArray, BlockAttributes } from '@wordpress/blocks';
|
||||||
|
import { Disabled, PanelBody, ToggleControl } from '@wordpress/components';
|
||||||
|
import {
|
||||||
|
InnerBlocks,
|
||||||
|
useBlockProps,
|
||||||
|
InspectorControls,
|
||||||
|
} from '@wordpress/block-editor';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import './style.scss';
|
||||||
|
import { SITE_TITLE } from '../../../settings/shared/default-constants';
|
||||||
|
import Form from './form';
|
||||||
|
|
||||||
|
const defaultTemplate = [
|
||||||
|
[
|
||||||
|
'core/heading',
|
||||||
|
{
|
||||||
|
level: 3,
|
||||||
|
content: sprintf(
|
||||||
|
/* translators: %s: site name */
|
||||||
|
__( 'Create an account with %s', 'woocommerce' ),
|
||||||
|
SITE_TITLE
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'core/list',
|
||||||
|
{},
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'core/list-item',
|
||||||
|
{
|
||||||
|
content: __( 'Faster future purchases', 'woocommerce' ),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'core/list-item',
|
||||||
|
{
|
||||||
|
content: __( 'Securely save payment info', 'woocommerce' ),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'core/list-item',
|
||||||
|
{
|
||||||
|
content: __(
|
||||||
|
'Track orders & view shopping history',
|
||||||
|
'woocommerce'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
] as TemplateArray;
|
||||||
|
|
||||||
|
type EditProps = {
|
||||||
|
attributes: {
|
||||||
|
hasDarkControls: boolean;
|
||||||
|
};
|
||||||
|
setAttributes: ( attrs: BlockAttributes ) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Edit = ( {
|
||||||
|
attributes,
|
||||||
|
setAttributes,
|
||||||
|
}: EditProps ): JSX.Element => {
|
||||||
|
const className = clsx( 'wc-block-order-confirmation-create-account', {
|
||||||
|
'has-dark-controls': attributes.hasDarkControls,
|
||||||
|
} );
|
||||||
|
const blockProps = useBlockProps( {
|
||||||
|
className,
|
||||||
|
} );
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div { ...blockProps }>
|
||||||
|
<InnerBlocks
|
||||||
|
allowedBlocks={ [
|
||||||
|
'core/heading',
|
||||||
|
'core/paragraph',
|
||||||
|
'core/list',
|
||||||
|
'core/list-item',
|
||||||
|
'core/image',
|
||||||
|
] }
|
||||||
|
template={ defaultTemplate }
|
||||||
|
templateLock={ false }
|
||||||
|
/>
|
||||||
|
<Disabled>
|
||||||
|
<Form isEditor={ true } />
|
||||||
|
</Disabled>
|
||||||
|
<InspectorControls>
|
||||||
|
<PanelBody title={ __( 'Style', 'woocommerce' ) }>
|
||||||
|
<ToggleControl
|
||||||
|
label={ __( 'Dark mode inputs', 'woocommerce' ) }
|
||||||
|
help={ __(
|
||||||
|
'Inputs styled specifically for use on dark background colors.',
|
||||||
|
'woocommerce'
|
||||||
|
) }
|
||||||
|
checked={ attributes.hasDarkControls }
|
||||||
|
onChange={ () =>
|
||||||
|
setAttributes( {
|
||||||
|
hasDarkControls: ! attributes.hasDarkControls,
|
||||||
|
} )
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</PanelBody>
|
||||||
|
</InspectorControls>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Save = (): JSX.Element => {
|
||||||
|
return (
|
||||||
|
<div { ...useBlockProps.save() }>
|
||||||
|
<InnerBlocks.Content />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Edit;
|
|
@ -0,0 +1,143 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { useState, createInterpolateElement } from '@wordpress/element';
|
||||||
|
import Button from '@woocommerce/base-components/button';
|
||||||
|
import PasswordStrengthMeter from '@woocommerce/base-components/cart-checkout/password-strength-meter';
|
||||||
|
import { PRIVACY_URL, TERMS_URL } from '@woocommerce/block-settings';
|
||||||
|
import { ValidatedTextInput } from '@woocommerce/blocks-components';
|
||||||
|
import { useSelect } from '@wordpress/data';
|
||||||
|
import { VALIDATION_STORE_KEY } from '@woocommerce/block-data';
|
||||||
|
|
||||||
|
const termsPageLink = TERMS_URL ? (
|
||||||
|
<a href={ TERMS_URL } target="_blank" rel="noreferrer">
|
||||||
|
{ __( 'Terms', 'woocommerce' ) }
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<span>{ __( 'Terms', 'woocommerce' ) }</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
const privacyPageLink = PRIVACY_URL ? (
|
||||||
|
<a href={ PRIVACY_URL } target="_blank" rel="noreferrer">
|
||||||
|
{ __( 'Privacy Policy', 'woocommerce' ) }
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<span>{ __( 'Privacy Policy', 'woocommerce' ) }</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
const Form = ( {
|
||||||
|
attributes: blockAttributes,
|
||||||
|
isEditor,
|
||||||
|
}: {
|
||||||
|
attributes?: { customerEmail?: string; nonceToken?: string };
|
||||||
|
isEditor: boolean;
|
||||||
|
} ) => {
|
||||||
|
const [ isLoading, setIsLoading ] = useState( false );
|
||||||
|
const [ password, setPassword ] = useState( '' );
|
||||||
|
const [ passwordStrength, setPasswordStrength ] = useState( 0 );
|
||||||
|
const hasValidationError = useSelect( ( select ) =>
|
||||||
|
select( VALIDATION_STORE_KEY ).getValidationError( 'account-password' )
|
||||||
|
);
|
||||||
|
const customerEmail =
|
||||||
|
blockAttributes?.customerEmail ||
|
||||||
|
( isEditor ? 'customer@email.com' : '' );
|
||||||
|
const nonceToken = blockAttributes?.nonceToken || '';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form
|
||||||
|
className={ 'wc-block-order-confirmation-create-account-form' }
|
||||||
|
id="create-account"
|
||||||
|
method="POST"
|
||||||
|
action="#create-account"
|
||||||
|
onSubmit={ ( event ) => {
|
||||||
|
if ( hasValidationError ) {
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIsLoading( true );
|
||||||
|
} }
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
{ createInterpolateElement(
|
||||||
|
__( 'Set a password for <email/>', 'woocommerce' ),
|
||||||
|
{
|
||||||
|
email: <strong>{ customerEmail }</strong>,
|
||||||
|
}
|
||||||
|
) }
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
<ValidatedTextInput
|
||||||
|
disabled={ isLoading }
|
||||||
|
type="password"
|
||||||
|
label={ __( 'Password', 'woocommerce' ) }
|
||||||
|
className={ `wc-block-components-address-form__password` }
|
||||||
|
value={ password }
|
||||||
|
required={ true }
|
||||||
|
errorId={ 'account-password' }
|
||||||
|
customValidityMessage={ (
|
||||||
|
validity: ValidityState
|
||||||
|
): string | undefined => {
|
||||||
|
if (
|
||||||
|
validity.valueMissing ||
|
||||||
|
validity.badInput ||
|
||||||
|
validity.typeMismatch
|
||||||
|
) {
|
||||||
|
return __(
|
||||||
|
'Please enter a valid password',
|
||||||
|
'woocommerce'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} }
|
||||||
|
customValidation={ ( inputObject ) => {
|
||||||
|
if ( passwordStrength < 2 ) {
|
||||||
|
inputObject.setCustomValidity(
|
||||||
|
__(
|
||||||
|
'Please create a stronger password',
|
||||||
|
'woocommerce'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} }
|
||||||
|
onChange={ ( value: string ) => setPassword( value ) }
|
||||||
|
feedback={
|
||||||
|
<PasswordStrengthMeter
|
||||||
|
password={ password }
|
||||||
|
onChange={ ( strength: number ) =>
|
||||||
|
setPasswordStrength( strength )
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
className={
|
||||||
|
'wc-block-order-confirmation-create-account-button'
|
||||||
|
}
|
||||||
|
type="submit"
|
||||||
|
disabled={ !! hasValidationError || ! password || isLoading }
|
||||||
|
showSpinner={ isLoading }
|
||||||
|
>
|
||||||
|
{ __( 'Create account', 'woocommerce' ) }
|
||||||
|
</Button>
|
||||||
|
<input type="hidden" name="email" value={ customerEmail } />
|
||||||
|
<input type="hidden" name="password" value={ password } />
|
||||||
|
<input type="hidden" name="create-account" value="1" />
|
||||||
|
<input type="hidden" name="_wpnonce" value={ nonceToken } />
|
||||||
|
<p className={ 'wc-block-order-confirmation-create-account-terms' }>
|
||||||
|
{ createInterpolateElement(
|
||||||
|
/* translators: %1$s terms page link, %2$s privacy page link. */
|
||||||
|
__(
|
||||||
|
'By creating an account you agree to our <terms/> and <privacy/>.',
|
||||||
|
'woocommerce'
|
||||||
|
),
|
||||||
|
{ terms: termsPageLink, privacy: privacyPageLink }
|
||||||
|
) }
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Form;
|
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { renderFrontend } from '@woocommerce/base-utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import Block from './form';
|
||||||
|
import { parseAttributes } from './utils';
|
||||||
|
|
||||||
|
const getProps = ( el: HTMLElement ) => {
|
||||||
|
return {
|
||||||
|
attributes: parseAttributes( el.dataset ),
|
||||||
|
isEditor: false,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// This does not replace the entire block markup, just the form part.
|
||||||
|
renderFrontend( {
|
||||||
|
selector: '.woocommerce-order-confirmation-create-account-form',
|
||||||
|
Block,
|
||||||
|
getProps,
|
||||||
|
} );
|
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { registerBlockType } from '@wordpress/blocks';
|
||||||
|
import { Icon, people } from '@wordpress/icons';
|
||||||
|
import { isExperimentalBlocksEnabled } from '@woocommerce/block-settings';
|
||||||
|
import { ExternalLink } from '@wordpress/components';
|
||||||
|
import { ADMIN_URL } from '@woocommerce/settings';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import metadata from './block.json';
|
||||||
|
import { Save, Edit } from './edit';
|
||||||
|
|
||||||
|
if ( isExperimentalBlocksEnabled() ) {
|
||||||
|
registerBlockType( metadata, {
|
||||||
|
apiVersion: 3,
|
||||||
|
description: (
|
||||||
|
<>
|
||||||
|
{ metadata.description }
|
||||||
|
<br />
|
||||||
|
<ExternalLink
|
||||||
|
href={ `${ ADMIN_URL }admin.php?page=wc-settings&tab=account` }
|
||||||
|
>
|
||||||
|
{ __( 'Manage account settings', 'woocommerce' ) }
|
||||||
|
</ExternalLink>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
icon: {
|
||||||
|
src: (
|
||||||
|
<Icon
|
||||||
|
icon={ people }
|
||||||
|
className="wc-block-editor-components-block-icon"
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
attributes: {
|
||||||
|
...metadata.attributes,
|
||||||
|
},
|
||||||
|
edit: Edit,
|
||||||
|
save: Save,
|
||||||
|
} );
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
.wc-block-order-confirmation-create-account {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: $gap;
|
||||||
|
padding: $gap-larger;
|
||||||
|
margin-top: $gap-larger !important;
|
||||||
|
margin-bottom: $gap-larger !important;
|
||||||
|
background: rgba(0, 0, 0, 0.04);
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-order-confirmation-create-account-content,
|
||||||
|
.block-editor-block-list__layout {
|
||||||
|
> :first-child {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
}
|
||||||
|
> :last-child {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
li {
|
||||||
|
margin-bottom: $gap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $gap;
|
||||||
|
|
||||||
|
p,
|
||||||
|
.wc-block-components-text-input {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wc-block-components-button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wc-block-order-confirmation-create-account-terms {
|
||||||
|
@include font-size(small);
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
a,
|
||||||
|
span {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wc-block-components-password-strength.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-order-confirmation-create-account-success {
|
||||||
|
text-align: center;
|
||||||
|
padding: $gap-larger 0;
|
||||||
|
|
||||||
|
> :first-child {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
}
|
||||||
|
> :last-child {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
export const parseAttributes = ( data: Record< string, unknown > ) => {
|
||||||
|
return {
|
||||||
|
customerEmail: data?.customerEmail || '',
|
||||||
|
nonceToken: data?.nonceToken || '',
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,3 +1,16 @@
|
||||||
|
.wc-block-order-confirmation-status-description {
|
||||||
|
.woocommerce-verify-email {
|
||||||
|
margin-top: $gap-larger;
|
||||||
|
#verify-email {
|
||||||
|
width: 50%;
|
||||||
|
|
||||||
|
@include breakpoint("<782px") {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.wc-block-order-confirmation-status {
|
.wc-block-order-confirmation-status {
|
||||||
margin-top: $gap;
|
margin-top: $gap;
|
||||||
margin-bottom: $gap;
|
margin-bottom: $gap;
|
||||||
|
|
|
@ -36,12 +36,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.woocommerce-verify-email {
|
|
||||||
margin-top: $gap-larger;
|
|
||||||
#verify-email {
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.has-background {
|
&.has-background {
|
||||||
padding: $gap;
|
padding: $gap;
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reason for using this component instead of the core/disabled component is
|
||||||
|
* that the Disabled component disrupts the focus on inner blocks. For example,
|
||||||
|
* when a heading block is nested inside, the text cursor, which indicates the
|
||||||
|
* editable area, isn't visible when focused on the heading block.
|
||||||
|
*
|
||||||
|
* This component only uses CSS to control the selected behavior of inner
|
||||||
|
* blocks, which fixes the abovementioned issues. However, being a static
|
||||||
|
* component comes with a limitation: this component is meant to be placed
|
||||||
|
* directly inside the block wrapper element that holds block props.
|
||||||
|
*/
|
||||||
|
export const InitialDisabled = ( {
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
} ): JSX.Element => (
|
||||||
|
<div className="wc-block-product-filter-components-initial-disabled">
|
||||||
|
<div className="wc-block-product-filter-components-initial-disabled-overlay" />
|
||||||
|
{ children }
|
||||||
|
</div>
|
||||||
|
);
|
|
@ -0,0 +1,17 @@
|
||||||
|
.wc-block-product-filter-components-initial-disabled {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.wc-block-product-filter-components-initial-disabled-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
.is-selected > &,
|
||||||
|
.has-child-selected > & {
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { Icon } from '@wordpress/components';
|
||||||
|
import { info } from '@wordpress/icons';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A custom notice component is designed specifically for new filter blocks. We
|
||||||
|
* are not reusing the existing components because we have a new design for the
|
||||||
|
* filter blocks notice. We want users to utilize the sidebar for attribute
|
||||||
|
* settings, so we are keeping the new notice minimal."
|
||||||
|
*/
|
||||||
|
export const Notice = ( { children }: { children: React.ReactNode } ) => (
|
||||||
|
<div className="wc-block-product-filter-components-notice">
|
||||||
|
<Icon
|
||||||
|
className="wc-block-product-filter-components-notice__icon"
|
||||||
|
icon={ info }
|
||||||
|
/>
|
||||||
|
<div className="wc-block-product-filter-components-notice__content">
|
||||||
|
{ children }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
|
@ -0,0 +1,17 @@
|
||||||
|
.wc-block-product-filter-components-notice {
|
||||||
|
display: flex;
|
||||||
|
padding: $gap;
|
||||||
|
gap: $gap-smaller;
|
||||||
|
border: 1px solid;
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
fill: $alert-red;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
> * {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,3 +3,9 @@ export const BlockOverlayAttribute = {
|
||||||
MOBILE: 'mobile',
|
MOBILE: 'mobile',
|
||||||
ALWAYS: 'always',
|
ALWAYS: 'always',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
export const EXCLUDED_BLOCKS = [
|
||||||
|
'woocommerce/product-filter-attribute',
|
||||||
|
'woocommerce/product-collection',
|
||||||
|
'core/query',
|
||||||
|
];
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { getSetting } from '@woocommerce/settings';
|
import { getSetting } from '@woocommerce/settings';
|
||||||
import { AttributeSetting } from '@woocommerce/types';
|
|
||||||
import {
|
import {
|
||||||
InnerBlocks,
|
InnerBlocks,
|
||||||
InspectorControls,
|
InspectorControls,
|
||||||
|
@ -37,10 +36,6 @@ import './editor.scss';
|
||||||
import { type BlockAttributes } from './types';
|
import { type BlockAttributes } from './types';
|
||||||
import { BlockOverlayAttribute } from './constants';
|
import { BlockOverlayAttribute } from './constants';
|
||||||
|
|
||||||
const defaultAttribute = getSetting< AttributeSetting >(
|
|
||||||
'defaultProductFilterAttribute'
|
|
||||||
);
|
|
||||||
|
|
||||||
const TEMPLATE: InnerBlockTemplate[] = [
|
const TEMPLATE: InnerBlockTemplate[] = [
|
||||||
[
|
[
|
||||||
'core/heading',
|
'core/heading',
|
||||||
|
@ -50,42 +45,8 @@ const TEMPLATE: InnerBlockTemplate[] = [
|
||||||
content: __( 'Filters', 'woocommerce' ),
|
content: __( 'Filters', 'woocommerce' ),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[ 'woocommerce/product-filter-active' ],
|
||||||
'woocommerce/product-filter',
|
[ 'woocommerce/product-filter-attribute' ],
|
||||||
{
|
|
||||||
filterType: 'active-filters',
|
|
||||||
heading: __( 'Active', 'woocommerce' ),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'woocommerce/product-filter',
|
|
||||||
{
|
|
||||||
filterType: 'price-filter',
|
|
||||||
heading: __( 'Price', 'woocommerce' ),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'woocommerce/product-filter',
|
|
||||||
{
|
|
||||||
filterType: 'stock-filter',
|
|
||||||
heading: __( 'Status', 'woocommerce' ),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'woocommerce/product-filter',
|
|
||||||
{
|
|
||||||
filterType: 'attribute-filter',
|
|
||||||
heading: defaultAttribute.attribute_label,
|
|
||||||
attributeId: parseInt( defaultAttribute.attribute_id, 10 ),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'woocommerce/product-filter',
|
|
||||||
{
|
|
||||||
filterType: 'rating-filter',
|
|
||||||
heading: __( 'Rating', 'woocommerce' ),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
'core/buttons',
|
'core/buttons',
|
||||||
{ layout: { type: 'flex' } },
|
{ layout: { type: 'flex' } },
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { getContext as getContextFn, store } from '@woocommerce/interactivity';
|
import {
|
||||||
|
getContext as getContextFn,
|
||||||
|
store,
|
||||||
|
navigate as navigateFn,
|
||||||
|
} from '@woocommerce/interactivity';
|
||||||
|
import { getSetting } from '@woocommerce/settings';
|
||||||
|
|
||||||
export interface ProductFiltersContext {
|
export interface ProductFiltersContext {
|
||||||
isDialogOpen: boolean;
|
isDialogOpen: boolean;
|
||||||
|
@ -11,7 +16,7 @@ export interface ProductFiltersContext {
|
||||||
const getContext = ( ns?: string ) =>
|
const getContext = ( ns?: string ) =>
|
||||||
getContextFn< ProductFiltersContext >( ns );
|
getContextFn< ProductFiltersContext >( ns );
|
||||||
|
|
||||||
const productFilters = {
|
store( 'woocommerce/product-filters', {
|
||||||
state: {
|
state: {
|
||||||
isDialogOpen: () => {
|
isDialogOpen: () => {
|
||||||
const context = getContext();
|
const context = getContext();
|
||||||
|
@ -36,8 +41,41 @@ const productFilters = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
callbacks: {},
|
callbacks: {},
|
||||||
};
|
} );
|
||||||
|
|
||||||
store( 'woocommerce/product-filters', productFilters );
|
const isBlockTheme = getSetting< boolean >( 'isBlockTheme' );
|
||||||
|
const isProductArchive = getSetting< boolean >( 'isProductArchive' );
|
||||||
|
const needsRefresh = getSetting< boolean >(
|
||||||
|
'needsRefreshForInteractivityAPI',
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
export type ProductFilters = typeof productFilters;
|
export function navigate( href: string, options = {} ) {
|
||||||
|
/**
|
||||||
|
* We may need to reset the current page when changing filters.
|
||||||
|
* This is because the current page may not exist for this set
|
||||||
|
* of filters and will 404 when the user navigates to it.
|
||||||
|
*
|
||||||
|
* There are different pagination formats to consider, as documented here:
|
||||||
|
* https://github.com/WordPress/gutenberg/blob/317eb8f14c8e1b81bf56972cca2694be250580e3/packages/block-library/src/query-pagination-numbers/index.php#L22-L85
|
||||||
|
*/
|
||||||
|
const url = new URL( href );
|
||||||
|
// When pretty permalinks are enabled, the page number may be in the path name.
|
||||||
|
url.pathname = url.pathname.replace( /\/page\/[0-9]+/i, '' );
|
||||||
|
// When plain permalinks are enabled, the page number may be in the "paged" query parameter.
|
||||||
|
url.searchParams.delete( 'paged' );
|
||||||
|
// On posts and pages the page number will be in a query parameter that
|
||||||
|
// identifies which block we are paginating.
|
||||||
|
url.searchParams.forEach( ( _, key ) => {
|
||||||
|
if ( key.match( /^query(?:-[0-9]+)?-page$/ ) ) {
|
||||||
|
url.searchParams.delete( key );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
// Make sure to update the href with the changes.
|
||||||
|
href = url.href;
|
||||||
|
|
||||||
|
if ( needsRefresh || ( ! isBlockTheme && isProductArchive ) ) {
|
||||||
|
return ( window.location.href = href );
|
||||||
|
}
|
||||||
|
return navigateFn( href, options );
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||||
"name": "woocommerce/product-filter-active",
|
"name": "woocommerce/product-filter-active",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"title": "Filter Options",
|
"title": "Active (Experimental)",
|
||||||
"description": "Display the currently active filters.",
|
"description": "Display the currently active filters.",
|
||||||
"category": "woocommerce",
|
"category": "woocommerce",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
@ -11,11 +11,10 @@
|
||||||
"textdomain": "woocommerce",
|
"textdomain": "woocommerce",
|
||||||
"apiVersion": 3,
|
"apiVersion": 3,
|
||||||
"ancestor": [
|
"ancestor": [
|
||||||
"woocommerce/product-filter"
|
"woocommerce/product-filters"
|
||||||
],
|
],
|
||||||
"supports": {
|
"supports": {
|
||||||
"interactivity": true,
|
"interactivity": true,
|
||||||
"inserter": false,
|
|
||||||
"color": {
|
"color": {
|
||||||
"text": true,
|
"text": true,
|
||||||
"background": false
|
"background": false
|
||||||
|
@ -27,7 +26,7 @@
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"displayStyle": {
|
"displayStyle": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "list"
|
"default": "chips"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { store, getContext } from '@woocommerce/interactivity';
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { navigate } from '../product-filter/frontend';
|
import { navigate } from '../../frontend';
|
||||||
|
|
||||||
type ActiveFiltersContext = {
|
type ActiveFiltersContext = {
|
||||||
queryId: number;
|
queryId: number;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*/
|
*/
|
||||||
import { registerBlockType } from '@wordpress/blocks';
|
import { registerBlockType } from '@wordpress/blocks';
|
||||||
import { isExperimentalBlocksEnabled } from '@woocommerce/block-settings';
|
import { isExperimentalBlocksEnabled } from '@woocommerce/block-settings';
|
||||||
import { productFilterOptions } from '@woocommerce/icons';
|
import { productFilterActive } from '@woocommerce/icons';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
|
@ -14,7 +14,7 @@ import './style.scss';
|
||||||
|
|
||||||
if ( isExperimentalBlocksEnabled() ) {
|
if ( isExperimentalBlocksEnabled() ) {
|
||||||
registerBlockType( metadata, {
|
registerBlockType( metadata, {
|
||||||
icon: productFilterOptions,
|
icon: productFilterActive,
|
||||||
edit: Edit,
|
edit: Edit,
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||||
"name": "woocommerce/product-filter-attribute",
|
"name": "woocommerce/product-filter-attribute",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"title": "Filter Options",
|
"title": "Attribute (Experimental)",
|
||||||
"description": "Enable customers to filter the product grid by selecting one or more attributes, such as color.",
|
"description": "Enable customers to filter the product grid by selecting one or more attributes, such as color.",
|
||||||
"category": "woocommerce",
|
"category": "woocommerce",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
@ -11,11 +11,10 @@
|
||||||
"textdomain": "woocommerce",
|
"textdomain": "woocommerce",
|
||||||
"apiVersion": 3,
|
"apiVersion": 3,
|
||||||
"ancestor": [
|
"ancestor": [
|
||||||
"woocommerce/product-filter"
|
"woocommerce/product-filters"
|
||||||
],
|
],
|
||||||
"supports": {
|
"supports": {
|
||||||
"interactivity": true,
|
"interactivity": true,
|
||||||
"inserter": false,
|
|
||||||
"color": {
|
"color": {
|
||||||
"text": true,
|
"text": true,
|
||||||
"background": false,
|
"background": false,
|
||||||
|
@ -78,7 +77,7 @@
|
||||||
},
|
},
|
||||||
"displayStyle": {
|
"displayStyle": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "list"
|
"default": "woocommerce/product-filter-checkbox-list"
|
||||||
},
|
},
|
||||||
"selectType": {
|
"selectType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -100,5 +99,10 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default":true
|
"default":true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"attributes": {
|
||||||
|
"isPreview": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { __, sprintf } from '@wordpress/i18n';
|
|
||||||
import { Icon, chevronDown } from '@wordpress/icons';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import { PreviewDropdown } from '../../components/preview-dropdown';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
label: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AttributeDropdown = ( { label }: Props ) => {
|
|
||||||
return (
|
|
||||||
<div className="wc-block-attribute-filter style-dropdown">
|
|
||||||
<PreviewDropdown
|
|
||||||
placeholder={ sprintf(
|
|
||||||
/* translators: %s attribute name. */
|
|
||||||
__( 'Select %s', 'woocommerce' ),
|
|
||||||
label
|
|
||||||
) }
|
|
||||||
/>
|
|
||||||
<Icon icon={ chevronDown } size={ 30 } />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -1,86 +0,0 @@
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { sort } from 'fast-sort';
|
|
||||||
import { __, sprintf, _n } from '@wordpress/i18n';
|
|
||||||
import { SearchListControl } from '@woocommerce/editor-components/search-list-control';
|
|
||||||
import { getSetting } from '@woocommerce/settings';
|
|
||||||
import { SearchListItem } from '@woocommerce/editor-components/search-list-control/types';
|
|
||||||
import { AttributeSetting } from '@woocommerce/types';
|
|
||||||
|
|
||||||
const ATTRIBUTES = getSetting< AttributeSetting[] >( 'attributes', [] );
|
|
||||||
|
|
||||||
type AttributeSelectControlsProps = {
|
|
||||||
isCompact: boolean;
|
|
||||||
setAttributeId: ( id: number ) => void;
|
|
||||||
attributeId: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AttributeSelectControls = ( {
|
|
||||||
isCompact,
|
|
||||||
setAttributeId,
|
|
||||||
attributeId,
|
|
||||||
}: AttributeSelectControlsProps ) => {
|
|
||||||
const messages = {
|
|
||||||
clear: __( 'Clear selected attribute', 'woocommerce' ),
|
|
||||||
list: __( 'Product Attributes', 'woocommerce' ),
|
|
||||||
noItems: __(
|
|
||||||
"Your store doesn't have any product attributes.",
|
|
||||||
'woocommerce'
|
|
||||||
),
|
|
||||||
search: __( 'Search for a product attribute:', 'woocommerce' ),
|
|
||||||
selected: ( n: number ) =>
|
|
||||||
sprintf(
|
|
||||||
/* translators: %d is the number of attributes selected. */
|
|
||||||
_n(
|
|
||||||
'%d attribute selected',
|
|
||||||
'%d attributes selected',
|
|
||||||
n,
|
|
||||||
'woocommerce'
|
|
||||||
),
|
|
||||||
n
|
|
||||||
),
|
|
||||||
updated: __(
|
|
||||||
'Product attribute search results updated.',
|
|
||||||
'woocommerce'
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
const list = sort(
|
|
||||||
ATTRIBUTES.map( ( item ) => {
|
|
||||||
return {
|
|
||||||
id: parseInt( item.attribute_id, 10 ),
|
|
||||||
name: item.attribute_label,
|
|
||||||
};
|
|
||||||
} )
|
|
||||||
).asc( 'name' );
|
|
||||||
|
|
||||||
const onChange = ( selected: SearchListItem[] ) => {
|
|
||||||
if ( ! selected || ! selected.length ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedId = selected[ 0 ].id;
|
|
||||||
const productAttribute = ATTRIBUTES.find(
|
|
||||||
( attribute ) => attribute.attribute_id === selectedId.toString()
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( ! productAttribute || attributeId === selectedId ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setAttributeId( selectedId as number );
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SearchListControl
|
|
||||||
className="woocommerce-product-attributes"
|
|
||||||
list={ list }
|
|
||||||
selected={ list.filter( ( { id } ) => id === attributeId ) }
|
|
||||||
onChange={ onChange }
|
|
||||||
messages={ messages }
|
|
||||||
isSingle
|
|
||||||
isCompact={ isCompact }
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -1,68 +0,0 @@
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { __ } from '@wordpress/i18n';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ideally, this component should belong to packages/interactivity-components.
|
|
||||||
* But we haven't export it as a packages so we place it here temporary.
|
|
||||||
*/
|
|
||||||
export const Preview = ( { items }: { items: string[] } ) => {
|
|
||||||
const threshold = 15;
|
|
||||||
const isLongList = items.length > threshold;
|
|
||||||
return (
|
|
||||||
<div className="wc-block-interactivity-components-checkbox-list">
|
|
||||||
<ul className="wc-block-interactivity-components-checkbox-list__list">
|
|
||||||
{ ( isLongList ? items.slice( 0, threshold ) : items ).map(
|
|
||||||
( item, index ) => (
|
|
||||||
<li
|
|
||||||
key={ index }
|
|
||||||
className="wc-block-interactivity-components-checkbox-list__item"
|
|
||||||
>
|
|
||||||
<label
|
|
||||||
htmlFor={ `interactive-checkbox-${ index }` }
|
|
||||||
className=" wc-block-interactivity-components-checkbox-list__label"
|
|
||||||
>
|
|
||||||
<span className="wc-block-interactive-components-checkbox-list__input-wrapper">
|
|
||||||
<span className="wc-block-interactivity-components-checkbox-list__input-wrapper">
|
|
||||||
<input
|
|
||||||
name={ `interactive-checkbox-${ index }` }
|
|
||||||
type="checkbox"
|
|
||||||
className="wc-block-interactivity-components-checkbox-list__input"
|
|
||||||
// Harded coded some checked items for styling purpose.
|
|
||||||
defaultChecked={ [
|
|
||||||
1, 3, 4,
|
|
||||||
].includes( index ) }
|
|
||||||
/>
|
|
||||||
<svg
|
|
||||||
className="wc-block-interactivity-components-checkbox-list__mark"
|
|
||||||
viewBox="0 0 10 8"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M9.25 1.19922L3.75 6.69922L1 3.94922"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="1.5"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<span className="wc-block-interactivity-components-checkbox-list__text">
|
|
||||||
{ item }
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
) }
|
|
||||||
</ul>
|
|
||||||
{ isLongList && (
|
|
||||||
<span className="wc-block-interactivity-components-checkbox-list__show-more">
|
|
||||||
<small>{ __( 'Show more…', 'woocommerce' ) }</small>
|
|
||||||
</span>
|
|
||||||
) }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -1,55 +0,0 @@
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { __ } from '@wordpress/i18n';
|
|
||||||
import { Icon, category, external } from '@wordpress/icons';
|
|
||||||
import { getAdminLink } from '@woocommerce/settings';
|
|
||||||
import { Placeholder, Button } from '@wordpress/components';
|
|
||||||
|
|
||||||
export const AttributesPlaceholder = ( {
|
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
children: React.ReactNode;
|
|
||||||
} ) => (
|
|
||||||
<Placeholder
|
|
||||||
className="wc-block-attribute-filter"
|
|
||||||
icon={ <Icon icon={ category } /> }
|
|
||||||
label={ __( 'Filter by Attribute', 'woocommerce' ) }
|
|
||||||
instructions={ __(
|
|
||||||
'Enable customers to filter the product grid by selecting one or more attributes, such as color.',
|
|
||||||
'woocommerce'
|
|
||||||
) }
|
|
||||||
>
|
|
||||||
{ children }
|
|
||||||
</Placeholder>
|
|
||||||
);
|
|
||||||
|
|
||||||
export const NoAttributesPlaceholder = () => (
|
|
||||||
<AttributesPlaceholder>
|
|
||||||
<p>
|
|
||||||
{ __(
|
|
||||||
"Attributes are needed for filtering your products. You haven't created any attributes yet.",
|
|
||||||
'woocommerce'
|
|
||||||
) }
|
|
||||||
</p>
|
|
||||||
<Button
|
|
||||||
className="wc-block-attribute-filter__add-attribute-button"
|
|
||||||
variant="secondary"
|
|
||||||
href={ getAdminLink(
|
|
||||||
'edit.php?post_type=product&page=product_attributes'
|
|
||||||
) }
|
|
||||||
target="_top"
|
|
||||||
>
|
|
||||||
{ __( 'Add new attribute', 'woocommerce' ) + ' ' }
|
|
||||||
<Icon icon={ external } />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
className="wc-block-attribute-filter__read_more_button"
|
|
||||||
variant="tertiary"
|
|
||||||
href="https://woocommerce.com/document/managing-product-taxonomies/"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
{ __( 'Learn more', 'woocommerce' ) }
|
|
||||||
</Button>
|
|
||||||
</AttributesPlaceholder>
|
|
||||||
);
|
|
|
@ -5,49 +5,71 @@ import { __ } from '@wordpress/i18n';
|
||||||
|
|
||||||
export const attributeOptionsPreview = [
|
export const attributeOptionsPreview = [
|
||||||
{
|
{
|
||||||
id: 23,
|
label: __( 'Blue', 'woocommerce' ),
|
||||||
name: __( 'Blue', 'woocommerce' ),
|
value: 'blue',
|
||||||
slug: 'blue',
|
rawData: {
|
||||||
attr_slug: 'blue',
|
id: 23,
|
||||||
description: '',
|
name: __( 'Blue', 'woocommerce' ),
|
||||||
parent: 0,
|
slug: 'blue',
|
||||||
count: 4,
|
attr_slug: 'blue',
|
||||||
|
description: '',
|
||||||
|
parent: 0,
|
||||||
|
count: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 29,
|
label: __( 'Gray', 'woocommerce' ),
|
||||||
name: __( 'Gray', 'woocommerce' ),
|
value: 'gray',
|
||||||
slug: 'gray',
|
selected: true,
|
||||||
attr_slug: 'gray',
|
rawData: {
|
||||||
description: '',
|
id: 29,
|
||||||
parent: 0,
|
name: __( 'Gray', 'woocommerce' ),
|
||||||
count: 3,
|
slug: 'gray',
|
||||||
|
attr_slug: 'gray',
|
||||||
|
description: '',
|
||||||
|
parent: 0,
|
||||||
|
count: 3,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 24,
|
label: __( 'Green', 'woocommerce' ),
|
||||||
name: __( 'Green', 'woocommerce' ),
|
value: 'green',
|
||||||
slug: 'green',
|
rawData: {
|
||||||
attr_slug: 'green',
|
id: 24,
|
||||||
description: '',
|
name: __( 'Green', 'woocommerce' ),
|
||||||
parent: 0,
|
slug: 'green',
|
||||||
count: 3,
|
attr_slug: 'green',
|
||||||
|
description: '',
|
||||||
|
parent: 0,
|
||||||
|
count: 3,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 25,
|
label: __( 'Red', 'woocommerce' ),
|
||||||
name: __( 'Red', 'woocommerce' ),
|
value: 'red',
|
||||||
slug: 'red',
|
selected: true,
|
||||||
attr_slug: 'red',
|
rawData: {
|
||||||
description: '',
|
id: 25,
|
||||||
parent: 0,
|
name: __( 'Red', 'woocommerce' ),
|
||||||
count: 4,
|
slug: 'red',
|
||||||
|
attr_slug: 'red',
|
||||||
|
description: '',
|
||||||
|
parent: 0,
|
||||||
|
count: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 30,
|
label: __( 'Yellow', 'woocommerce' ),
|
||||||
name: __( 'Yellow', 'woocommerce' ),
|
value: 'yellow',
|
||||||
slug: 'yellow',
|
rawData: {
|
||||||
attr_slug: 'yellow',
|
id: 30,
|
||||||
description: '',
|
name: __( 'Yellow', 'woocommerce' ),
|
||||||
parent: 0,
|
slug: 'yellow',
|
||||||
count: 1,
|
attr_slug: 'yellow',
|
||||||
|
description: '',
|
||||||
|
parent: 0,
|
||||||
|
count: 1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -5,29 +5,34 @@ import {
|
||||||
useCollection,
|
useCollection,
|
||||||
useCollectionData,
|
useCollectionData,
|
||||||
} from '@woocommerce/base-context/hooks';
|
} from '@woocommerce/base-context/hooks';
|
||||||
import { getSetting } from '@woocommerce/settings';
|
|
||||||
import {
|
import {
|
||||||
AttributeSetting,
|
AttributeSetting,
|
||||||
AttributeTerm,
|
AttributeTerm,
|
||||||
objectHasProp,
|
objectHasProp,
|
||||||
} from '@woocommerce/types';
|
} from '@woocommerce/types';
|
||||||
import { useBlockProps } from '@wordpress/block-editor';
|
import {
|
||||||
import { Disabled, Notice, withSpokenMessages } from '@wordpress/components';
|
useBlockProps,
|
||||||
import { useEffect, useState, useMemo } from '@wordpress/element';
|
useInnerBlocksProps,
|
||||||
|
BlockContextProvider,
|
||||||
|
} from '@wordpress/block-editor';
|
||||||
|
import { withSpokenMessages } from '@wordpress/components';
|
||||||
|
import { useEffect, useState } from '@wordpress/element';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { getSetting } from '@woocommerce/settings';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { AttributeDropdown } from './components/attribute-dropdown';
|
import { Inspector } from './inspector';
|
||||||
import { Preview as CheckboxListPreview } from './components/checkbox-list-editor';
|
|
||||||
import { Inspector } from './components/inspector';
|
|
||||||
import { NoAttributesPlaceholder } from './components/placeholder';
|
|
||||||
import { attributeOptionsPreview } from './constants';
|
import { attributeOptionsPreview } from './constants';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
import { EditProps, isAttributeCounts } from './types';
|
import { EditProps, isAttributeCounts } from './types';
|
||||||
import { getAttributeFromId } from './utils';
|
import { getAttributeFromId } from './utils';
|
||||||
import './editor.scss';
|
import { getAllowedBlocks } from '../../utils';
|
||||||
|
import { EXCLUDED_BLOCKS } from '../../constants';
|
||||||
|
import { FilterOptionItem } from '../../types';
|
||||||
|
import { InitialDisabled } from '../../components/initial-disabled';
|
||||||
|
import { Notice } from '../../components/notice';
|
||||||
|
|
||||||
const ATTRIBUTES = getSetting< AttributeSetting[] >( 'attributes', [] );
|
const ATTRIBUTES = getSetting< AttributeSetting[] >( 'attributes', [] );
|
||||||
|
|
||||||
|
@ -47,8 +52,10 @@ const Edit = ( props: EditProps ) => {
|
||||||
const attributeObject = getAttributeFromId( attributeId );
|
const attributeObject = getAttributeFromId( attributeId );
|
||||||
|
|
||||||
const [ attributeOptions, setAttributeOptions ] = useState<
|
const [ attributeOptions, setAttributeOptions ] = useState<
|
||||||
AttributeTerm[]
|
FilterOptionItem[]
|
||||||
>( [] );
|
>( [] );
|
||||||
|
const [ isOptionsLoading, setIsOptionsLoading ] =
|
||||||
|
useState< boolean >( true );
|
||||||
|
|
||||||
const { results: attributeTerms, isLoading: isTermsLoading } =
|
const { results: attributeTerms, isLoading: isTermsLoading } =
|
||||||
useCollection< AttributeTerm >( {
|
useCollection< AttributeTerm >( {
|
||||||
|
@ -59,7 +66,7 @@ const Edit = ( props: EditProps ) => {
|
||||||
query: { orderby: 'menu_order', hide_empty: hideEmpty },
|
query: { orderby: 'menu_order', hide_empty: hideEmpty },
|
||||||
} );
|
} );
|
||||||
|
|
||||||
const { results: filteredCounts, isLoading: isCountsLoading } =
|
const { results: filteredCounts, isLoading: isFilterCountsLoading } =
|
||||||
useCollectionData( {
|
useCollectionData( {
|
||||||
queryAttribute: {
|
queryAttribute: {
|
||||||
taxonomy: attributeObject?.taxonomy || '',
|
taxonomy: attributeObject?.taxonomy || '',
|
||||||
|
@ -69,90 +76,137 @@ const Edit = ( props: EditProps ) => {
|
||||||
isEditor: true,
|
isEditor: true,
|
||||||
} );
|
} );
|
||||||
|
|
||||||
const isLoading = isTermsLoading || isCountsLoading;
|
|
||||||
|
|
||||||
useEffect( () => {
|
useEffect( () => {
|
||||||
|
if ( isTermsLoading || isFilterCountsLoading ) return;
|
||||||
|
|
||||||
const termIdHasProducts =
|
const termIdHasProducts =
|
||||||
objectHasProp( filteredCounts, 'attribute_counts' ) &&
|
objectHasProp( filteredCounts, 'attribute_counts' ) &&
|
||||||
isAttributeCounts( filteredCounts.attribute_counts )
|
isAttributeCounts( filteredCounts.attribute_counts )
|
||||||
? filteredCounts.attribute_counts.map( ( term ) => term.term )
|
? filteredCounts.attribute_counts.map( ( term ) => term.term )
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
if ( termIdHasProducts.length === 0 && hideEmpty )
|
if ( termIdHasProducts.length === 0 && hideEmpty ) {
|
||||||
return setAttributeOptions( [] );
|
setAttributeOptions( [] );
|
||||||
|
} else {
|
||||||
|
setAttributeOptions(
|
||||||
|
attributeTerms
|
||||||
|
.filter( ( term ) => {
|
||||||
|
if ( hideEmpty )
|
||||||
|
return termIdHasProducts.includes( term.id );
|
||||||
|
return true;
|
||||||
|
} )
|
||||||
|
.sort( ( a, b ) => {
|
||||||
|
switch ( sortOrder ) {
|
||||||
|
case 'name-asc':
|
||||||
|
return a.name > b.name ? 1 : -1;
|
||||||
|
case 'name-desc':
|
||||||
|
return a.name < b.name ? 1 : -1;
|
||||||
|
case 'count-asc':
|
||||||
|
return a.count > b.count ? 1 : -1;
|
||||||
|
case 'count-desc':
|
||||||
|
default:
|
||||||
|
return a.count < b.count ? 1 : -1;
|
||||||
|
}
|
||||||
|
} )
|
||||||
|
.map( ( term, index ) => ( {
|
||||||
|
label: showCounts
|
||||||
|
? `${ term.name } (${ term.count })`
|
||||||
|
: term.name,
|
||||||
|
value: term.id.toString(),
|
||||||
|
selected: index === 1,
|
||||||
|
rawData: term,
|
||||||
|
} ) )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
setAttributeOptions(
|
setIsOptionsLoading( false );
|
||||||
attributeTerms
|
}, [
|
||||||
.filter( ( term ) => {
|
showCounts,
|
||||||
if ( hideEmpty )
|
attributeTerms,
|
||||||
return termIdHasProducts.includes( term.id );
|
filteredCounts,
|
||||||
return true;
|
sortOrder,
|
||||||
} )
|
hideEmpty,
|
||||||
.sort( ( a, b ) => {
|
isTermsLoading,
|
||||||
switch ( sortOrder ) {
|
isFilterCountsLoading,
|
||||||
case 'name-asc':
|
] );
|
||||||
return a.name > b.name ? 1 : -1;
|
|
||||||
case 'name-desc':
|
|
||||||
return a.name < b.name ? 1 : -1;
|
|
||||||
case 'count-asc':
|
|
||||||
return a.count > b.count ? 1 : -1;
|
|
||||||
case 'count-desc':
|
|
||||||
default:
|
|
||||||
return a.count < b.count ? 1 : -1;
|
|
||||||
}
|
|
||||||
} )
|
|
||||||
);
|
|
||||||
}, [ attributeTerms, filteredCounts, sortOrder, hideEmpty ] );
|
|
||||||
|
|
||||||
const Wrapper = ( { children }: { children: React.ReactNode } ) => (
|
const { children, ...innerBlocksProps } = useInnerBlocksProps(
|
||||||
<div { ...useBlockProps() }>
|
useBlockProps(),
|
||||||
<Inspector { ...props } />
|
{
|
||||||
{ children }
|
allowedBlocks: getAllowedBlocks( EXCLUDED_BLOCKS ),
|
||||||
</div>
|
template: [
|
||||||
|
[
|
||||||
|
'core/group',
|
||||||
|
{
|
||||||
|
layout: {
|
||||||
|
type: 'flex',
|
||||||
|
flexWrap: 'nowrap',
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
name: __( 'Header', 'woocommerce' ),
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
spacing: {
|
||||||
|
blockGap: '0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'core/heading',
|
||||||
|
{
|
||||||
|
level: 3,
|
||||||
|
content:
|
||||||
|
attributeObject?.label ||
|
||||||
|
__( 'Attribute', 'woocommerce' ),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'woocommerce/product-filter-clear-button',
|
||||||
|
{
|
||||||
|
lock: {
|
||||||
|
remove: true,
|
||||||
|
move: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
displayStyle,
|
||||||
|
{
|
||||||
|
lock: {
|
||||||
|
remove: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const loadingState = useMemo( () => {
|
const isLoading =
|
||||||
return [ ...Array( 5 ) ].map( ( x, i ) => (
|
isTermsLoading || isFilterCountsLoading || isOptionsLoading;
|
||||||
<li
|
|
||||||
key={ i }
|
|
||||||
style={ {
|
|
||||||
/* stylelint-disable */
|
|
||||||
width: Math.floor( Math.random() * ( 100 - 25 ) ) + '%',
|
|
||||||
} }
|
|
||||||
>
|
|
||||||
|
|
||||||
</li>
|
|
||||||
) );
|
|
||||||
}, [] );
|
|
||||||
|
|
||||||
if ( isPreview ) {
|
|
||||||
return (
|
|
||||||
<Wrapper>
|
|
||||||
<Disabled>
|
|
||||||
<CheckboxListPreview
|
|
||||||
items={ attributeOptionsPreview.map( ( term ) => {
|
|
||||||
if ( showCounts )
|
|
||||||
return `${ term.name } (${ term.count })`;
|
|
||||||
return term.name;
|
|
||||||
} ) }
|
|
||||||
/>
|
|
||||||
</Disabled>
|
|
||||||
</Wrapper>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Block rendering starts.
|
|
||||||
if ( Object.keys( ATTRIBUTES ).length === 0 )
|
if ( Object.keys( ATTRIBUTES ).length === 0 )
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<div { ...innerBlocksProps }>
|
||||||
<NoAttributesPlaceholder />
|
<Inspector { ...props } />
|
||||||
</Wrapper>
|
<Notice>
|
||||||
|
<p>
|
||||||
|
{ __(
|
||||||
|
"Attributes are needed for filtering your products. You haven't created any attributes yet.",
|
||||||
|
'woocommerce'
|
||||||
|
) }
|
||||||
|
</p>
|
||||||
|
</Notice>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( ! attributeId || ! attributeObject )
|
if ( ! attributeId || ! attributeObject )
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<div { ...innerBlocksProps }>
|
||||||
<Notice status="warning" isDismissible={ false }>
|
<Inspector { ...props } />
|
||||||
|
<Notice>
|
||||||
<p>
|
<p>
|
||||||
{ __(
|
{ __(
|
||||||
'Please select an attribute to use this filter!',
|
'Please select an attribute to use this filter!',
|
||||||
|
@ -160,22 +214,14 @@ const Edit = ( props: EditProps ) => {
|
||||||
) }
|
) }
|
||||||
</p>
|
</p>
|
||||||
</Notice>
|
</Notice>
|
||||||
</Wrapper>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( isLoading )
|
if ( ! isLoading && attributeTerms.length === 0 )
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<div { ...innerBlocksProps }>
|
||||||
<ul className="is-loading wp-block-woocommerce-product-filter-attribute__loading">
|
<Inspector { ...props } />
|
||||||
{ loadingState }
|
<Notice>
|
||||||
</ul>
|
|
||||||
</Wrapper>
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( attributeTerms.length === 0 )
|
|
||||||
return (
|
|
||||||
<Wrapper>
|
|
||||||
<Notice status="warning" isDismissible={ false }>
|
|
||||||
<p>
|
<p>
|
||||||
{ __(
|
{ __(
|
||||||
'There are no products with the selected attributes.',
|
'There are no products with the selected attributes.',
|
||||||
|
@ -183,30 +229,28 @@ const Edit = ( props: EditProps ) => {
|
||||||
) }
|
) }
|
||||||
</p>
|
</p>
|
||||||
</Notice>
|
</Notice>
|
||||||
</Wrapper>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<div { ...innerBlocksProps }>
|
||||||
<Disabled>
|
<Inspector { ...props } />
|
||||||
{ displayStyle === 'dropdown' ? (
|
<InitialDisabled>
|
||||||
<AttributeDropdown
|
<BlockContextProvider
|
||||||
label={
|
value={ {
|
||||||
attributeObject.label ||
|
filterData: {
|
||||||
__( 'attribute', 'woocommerce' )
|
items:
|
||||||
}
|
attributeOptions.length === 0 && isPreview
|
||||||
/>
|
? attributeOptionsPreview
|
||||||
) : (
|
: attributeOptions,
|
||||||
<CheckboxListPreview
|
isLoading,
|
||||||
items={ attributeOptions.map( ( term ) => {
|
},
|
||||||
if ( showCounts )
|
} }
|
||||||
return `${ term.name } (${ term.count })`;
|
>
|
||||||
return term.name;
|
{ children }
|
||||||
} ) }
|
</BlockContextProvider>
|
||||||
/>
|
</InitialDisabled>
|
||||||
) }
|
</div>
|
||||||
</Disabled>
|
|
||||||
</Wrapper>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
.wp-block-woocommerce-product-filter-attribute__loading {
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
li {
|
|
||||||
@include placeholder();
|
|
||||||
margin: 5px 0;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,7 +8,7 @@ import { HTMLElementEvent } from '@woocommerce/types';
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { navigate } from '../product-filter/frontend';
|
import { navigate } from '../../frontend';
|
||||||
|
|
||||||
type AttributeFilterContext = {
|
type AttributeFilterContext = {
|
||||||
attributeSlug: string;
|
attributeSlug: string;
|
||||||
|
@ -106,5 +106,12 @@ store( 'woocommerce/product-filter-attribute', {
|
||||||
|
|
||||||
navigate( getUrl( selectedTerms, attributeSlug, queryType ) );
|
navigate( getUrl( selectedTerms, attributeSlug, queryType ) );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
clearFilters: () => {
|
||||||
|
const { attributeSlug, queryType } =
|
||||||
|
getContext< ActiveAttributeFilterContext >();
|
||||||
|
|
||||||
|
navigate( getUrl( [], attributeSlug, queryType ) );
|
||||||
|
},
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -2,18 +2,21 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { isExperimentalBlocksEnabled } from '@woocommerce/block-settings';
|
import { isExperimentalBlocksEnabled } from '@woocommerce/block-settings';
|
||||||
import { productFilterOptions } from '@woocommerce/icons';
|
import { productFilterAttribute } from '@woocommerce/icons';
|
||||||
import { getSetting } from '@woocommerce/settings';
|
import { getSetting } from '@woocommerce/settings';
|
||||||
import { registerBlockType } from '@wordpress/blocks';
|
|
||||||
import { AttributeSetting } from '@woocommerce/types';
|
import { AttributeSetting } from '@woocommerce/types';
|
||||||
|
import { registerBlockType } from '@wordpress/blocks';
|
||||||
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import metadata from './block.json';
|
import metadata from './block.json';
|
||||||
import Edit from './edit';
|
import Edit from './edit';
|
||||||
|
import Save from './save';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
|
const ATTRIBUTES = getSetting< AttributeSetting[] >( 'attributes', [] );
|
||||||
if ( isExperimentalBlocksEnabled() ) {
|
if ( isExperimentalBlocksEnabled() ) {
|
||||||
const defaultAttribute = getSetting< AttributeSetting >(
|
const defaultAttribute = getSetting< AttributeSetting >(
|
||||||
'defaultProductFilterAttribute'
|
'defaultProductFilterAttribute'
|
||||||
|
@ -21,7 +24,7 @@ if ( isExperimentalBlocksEnabled() ) {
|
||||||
|
|
||||||
registerBlockType( metadata, {
|
registerBlockType( metadata, {
|
||||||
edit: Edit,
|
edit: Edit,
|
||||||
icon: productFilterOptions,
|
icon: productFilterAttribute,
|
||||||
attributes: {
|
attributes: {
|
||||||
...metadata.attributes,
|
...metadata.attributes,
|
||||||
attributeId: {
|
attributeId: {
|
||||||
|
@ -29,5 +32,25 @@ if ( isExperimentalBlocksEnabled() ) {
|
||||||
default: parseInt( defaultAttribute.attribute_id, 10 ),
|
default: parseInt( defaultAttribute.attribute_id, 10 ),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
save: Save,
|
||||||
|
variations: ATTRIBUTES.map( ( attribute, index ) => {
|
||||||
|
return {
|
||||||
|
name: `product-filter-attribute-${ attribute.attribute_name }`,
|
||||||
|
title: `${ attribute.attribute_label } (Experimental)`,
|
||||||
|
description: sprintf(
|
||||||
|
// translators: %s is the attribute label.
|
||||||
|
__(
|
||||||
|
`Enable customers to filter the product collection by selecting one or more %s attributes.`,
|
||||||
|
'woocommerce'
|
||||||
|
),
|
||||||
|
attribute.attribute_label
|
||||||
|
),
|
||||||
|
attributes: {
|
||||||
|
attributeId: parseInt( attribute.attribute_id, 10 ),
|
||||||
|
},
|
||||||
|
isActive: [ 'attributeId' ],
|
||||||
|
isDefault: index === 0,
|
||||||
|
};
|
||||||
|
} ),
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,9 @@ import { getSetting } from '@woocommerce/settings';
|
||||||
import { AttributeSetting } from '@woocommerce/types';
|
import { AttributeSetting } from '@woocommerce/types';
|
||||||
import { InspectorControls } from '@wordpress/block-editor';
|
import { InspectorControls } from '@wordpress/block-editor';
|
||||||
import { dispatch, useSelect } from '@wordpress/data';
|
import { dispatch, useSelect } from '@wordpress/data';
|
||||||
import { createInterpolateElement } from '@wordpress/element';
|
import { createInterpolateElement, useState } from '@wordpress/element';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { Block, getBlockTypes, createBlock } from '@wordpress/blocks';
|
||||||
import {
|
import {
|
||||||
ComboboxControl,
|
ComboboxControl,
|
||||||
PanelBody,
|
PanelBody,
|
||||||
|
@ -23,12 +24,15 @@ import {
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { sortOrderOptions } from '../constants';
|
import { sortOrderOptions } from './constants';
|
||||||
import { BlockAttributes, EditProps } from '../types';
|
import { BlockAttributes, EditProps } from './types';
|
||||||
import { getAttributeFromId } from '../utils';
|
import { getAttributeFromId } from './utils';
|
||||||
|
import { getInnerBlockByName } from '../../utils';
|
||||||
|
|
||||||
const ATTRIBUTES = getSetting< AttributeSetting[] >( 'attributes', [] );
|
const ATTRIBUTES = getSetting< AttributeSetting[] >( 'attributes', [] );
|
||||||
|
|
||||||
|
let displayStyleOptions: Block[] = [];
|
||||||
|
|
||||||
export const Inspector = ( {
|
export const Inspector = ( {
|
||||||
clientId,
|
clientId,
|
||||||
attributes,
|
attributes,
|
||||||
|
@ -43,47 +47,29 @@ export const Inspector = ( {
|
||||||
hideEmpty,
|
hideEmpty,
|
||||||
clearButton,
|
clearButton,
|
||||||
} = attributes;
|
} = attributes;
|
||||||
const { updateBlockAttributes } = dispatch( 'core/block-editor' );
|
const { updateBlockAttributes, insertBlock, replaceBlock } =
|
||||||
const { productFilterWrapperBlockId, productFilterWrapperHeadingBlockId } =
|
dispatch( 'core/block-editor' );
|
||||||
useSelect(
|
const filterBlock = useSelect(
|
||||||
( select ) => {
|
( select ) => {
|
||||||
if ( ! clientId )
|
return select( 'core/block-editor' ).getBlock( clientId );
|
||||||
return {
|
},
|
||||||
productFilterWrapperBlockId: undefined,
|
[ clientId ]
|
||||||
productFilterWrapperHeadingBlockId: undefined,
|
);
|
||||||
};
|
const [ displayStyleBlocksAttributes, setDisplayStyleBlocksAttributes ] =
|
||||||
|
useState< Record< string, unknown > >( {} );
|
||||||
|
|
||||||
const { getBlockParentsByBlockName, getBlock } =
|
const filterHeadingBlock = getInnerBlockByName(
|
||||||
select( 'core/block-editor' );
|
filterBlock,
|
||||||
|
'core/heading'
|
||||||
|
);
|
||||||
|
|
||||||
const parentBlocksByBlockName = getBlockParentsByBlockName(
|
if ( displayStyleOptions.length === 0 ) {
|
||||||
clientId,
|
displayStyleOptions = getBlockTypes().filter( ( blockType ) =>
|
||||||
'woocommerce/product-filter'
|
blockType.ancestor?.includes(
|
||||||
);
|
'woocommerce/product-filter-attribute'
|
||||||
|
)
|
||||||
if ( parentBlocksByBlockName.length === 0 )
|
|
||||||
return {
|
|
||||||
productFilterWrapperBlockId: undefined,
|
|
||||||
productFilterWrapperHeadingBlockId: undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
const parentBlockId = parentBlocksByBlockName[ 0 ];
|
|
||||||
|
|
||||||
const parentBlock = getBlock( parentBlockId );
|
|
||||||
const headerGroupBlock = parentBlock?.innerBlocks.find(
|
|
||||||
( block ) => block.name === 'core/group'
|
|
||||||
);
|
|
||||||
const headingBlock = headerGroupBlock?.innerBlocks.find(
|
|
||||||
( block ) => block.name === 'core/heading'
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
productFilterWrapperBlockId: parentBlockId,
|
|
||||||
productFilterWrapperHeadingBlockId: headingBlock?.clientId,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
[ clientId ]
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -102,17 +88,9 @@ export const Inspector = ( {
|
||||||
} );
|
} );
|
||||||
const attributeObject =
|
const attributeObject =
|
||||||
getAttributeFromId( numericId );
|
getAttributeFromId( numericId );
|
||||||
if ( productFilterWrapperBlockId ) {
|
if ( filterHeadingBlock ) {
|
||||||
updateBlockAttributes(
|
updateBlockAttributes(
|
||||||
productFilterWrapperBlockId,
|
filterHeadingBlock.clientId,
|
||||||
{
|
|
||||||
attributeId: numericId,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if ( productFilterWrapperHeadingBlockId ) {
|
|
||||||
updateBlockAttributes(
|
|
||||||
productFilterWrapperHeadingBlockId,
|
|
||||||
{
|
{
|
||||||
content:
|
content:
|
||||||
attributeObject?.label ??
|
attributeObject?.label ??
|
||||||
|
@ -188,17 +166,46 @@ export const Inspector = ( {
|
||||||
value={ displayStyle }
|
value={ displayStyle }
|
||||||
onChange={ (
|
onChange={ (
|
||||||
value: BlockAttributes[ 'displayStyle' ]
|
value: BlockAttributes[ 'displayStyle' ]
|
||||||
) => setAttributes( { displayStyle: value } ) }
|
) => {
|
||||||
|
if ( ! filterBlock ) return;
|
||||||
|
const currentStyleBlock = getInnerBlockByName(
|
||||||
|
filterBlock,
|
||||||
|
displayStyle
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( currentStyleBlock ) {
|
||||||
|
setDisplayStyleBlocksAttributes( {
|
||||||
|
...displayStyleBlocksAttributes,
|
||||||
|
[ displayStyle ]:
|
||||||
|
currentStyleBlock.attributes,
|
||||||
|
} );
|
||||||
|
replaceBlock(
|
||||||
|
currentStyleBlock.clientId,
|
||||||
|
createBlock(
|
||||||
|
value,
|
||||||
|
displayStyleBlocksAttributes[ value ] ||
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
insertBlock(
|
||||||
|
createBlock( value ),
|
||||||
|
filterBlock.innerBlocks.length,
|
||||||
|
filterBlock.clientId,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setAttributes( { displayStyle: value } );
|
||||||
|
} }
|
||||||
style={ { width: '100%' } }
|
style={ { width: '100%' } }
|
||||||
>
|
>
|
||||||
<ToggleGroupControlOption
|
{ displayStyleOptions.map( ( blockType ) => (
|
||||||
label={ __( 'List', 'woocommerce' ) }
|
<ToggleGroupControlOption
|
||||||
value="list"
|
key={ blockType.name }
|
||||||
/>
|
label={ blockType.title }
|
||||||
<ToggleGroupControlOption
|
value={ blockType.name }
|
||||||
label={ __( 'Chips', 'woocommerce' ) }
|
/>
|
||||||
value="chips"
|
) ) }
|
||||||
/>
|
|
||||||
</ToggleGroupControl>
|
</ToggleGroupControl>
|
||||||
<ToggleControl
|
<ToggleControl
|
||||||
label={ __( 'Product counts', 'woocommerce' ) }
|
label={ __( 'Product counts', 'woocommerce' ) }
|
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
|
||||||
|
|
||||||
|
const Save = () => {
|
||||||
|
const blockProps = useBlockProps.save();
|
||||||
|
const innerBlocksProps = useInnerBlocksProps.save( blockProps );
|
||||||
|
return <div { ...innerBlocksProps } />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Save;
|
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||||
|
"name": "woocommerce/product-filter-checkbox-list",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"title": "List",
|
||||||
|
"description": "Display a list of filter options.",
|
||||||
|
"category": "woocommerce",
|
||||||
|
"keywords": [
|
||||||
|
"WooCommerce"
|
||||||
|
],
|
||||||
|
"textdomain": "woocommerce",
|
||||||
|
"apiVersion": 3,
|
||||||
|
"ancestor": [
|
||||||
|
"woocommerce/product-filter-attribute"
|
||||||
|
],
|
||||||
|
"supports": {
|
||||||
|
"color": {
|
||||||
|
"enableContrastChecker": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"usesContext": [
|
||||||
|
"filterData"
|
||||||
|
],
|
||||||
|
"attributes": {
|
||||||
|
"optionElementBorder": {
|
||||||
|
"type": "string",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"customOptionElementBorder": {
|
||||||
|
"type": "string",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"optionElementSelected": {
|
||||||
|
"type": "string",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"customOptionElementSelected": {
|
||||||
|
"type": "string",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"optionElement": {
|
||||||
|
"type": "string",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"customOptionElement": {
|
||||||
|
"type": "string",
|
||||||
|
"default": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,223 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { Icon } from '@wordpress/components';
|
||||||
|
import { checkMark } from '@woocommerce/icons';
|
||||||
|
import { useMemo } from '@wordpress/element';
|
||||||
|
import {
|
||||||
|
useBlockProps,
|
||||||
|
withColors,
|
||||||
|
InspectorControls,
|
||||||
|
// @ts-expect-error - no types.
|
||||||
|
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
|
||||||
|
__experimentalColorGradientSettingsDropdown as ColorGradientSettingsDropdown,
|
||||||
|
// @ts-expect-error - no types.
|
||||||
|
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
|
||||||
|
__experimentalUseMultipleOriginColorsAndGradients as useMultipleOriginColorsAndGradients,
|
||||||
|
} from '@wordpress/block-editor';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import './style.scss';
|
||||||
|
import './editor.scss';
|
||||||
|
import { EditProps } from './types';
|
||||||
|
|
||||||
|
const Edit = ( props: EditProps ): JSX.Element => {
|
||||||
|
const {
|
||||||
|
clientId,
|
||||||
|
context,
|
||||||
|
attributes,
|
||||||
|
setAttributes,
|
||||||
|
optionElementBorder,
|
||||||
|
setOptionElementBorder,
|
||||||
|
optionElementSelected,
|
||||||
|
setOptionElementSelected,
|
||||||
|
optionElement,
|
||||||
|
setOptionElement,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const {
|
||||||
|
customOptionElementBorder,
|
||||||
|
customOptionElementSelected,
|
||||||
|
customOptionElement,
|
||||||
|
} = attributes;
|
||||||
|
const { filterData } = context;
|
||||||
|
const { isLoading, items } = filterData;
|
||||||
|
|
||||||
|
const colorGradientSettings = useMultipleOriginColorsAndGradients();
|
||||||
|
const blockProps = useBlockProps( {
|
||||||
|
className: clsx( 'wc-block-product-filter-checkbox-list', {
|
||||||
|
'is-loading': isLoading,
|
||||||
|
'has-option-element-border-color':
|
||||||
|
optionElementBorder.color || customOptionElementBorder,
|
||||||
|
'has-option-element-selected-color':
|
||||||
|
optionElementSelected.color || customOptionElementSelected,
|
||||||
|
'has-option-element-color':
|
||||||
|
optionElement.color || customOptionElement,
|
||||||
|
} ),
|
||||||
|
style: {
|
||||||
|
'--wc-product-filter-checkbox-list-option-element-border':
|
||||||
|
optionElementBorder.color || customOptionElementBorder,
|
||||||
|
'--wc-product-filter-checkbox-list-option-element-selected':
|
||||||
|
optionElementSelected.color || customOptionElementSelected,
|
||||||
|
'--wc-product-filter-checkbox-list-option-element':
|
||||||
|
optionElement.color || customOptionElement,
|
||||||
|
},
|
||||||
|
} );
|
||||||
|
|
||||||
|
const loadingState = useMemo( () => {
|
||||||
|
return [ ...Array( 5 ) ].map( ( x, i ) => (
|
||||||
|
<li
|
||||||
|
key={ i }
|
||||||
|
style={ {
|
||||||
|
/* stylelint-disable */
|
||||||
|
width: Math.floor( Math.random() * ( 100 - 25 ) ) + '%',
|
||||||
|
} }
|
||||||
|
>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
) );
|
||||||
|
}, [] );
|
||||||
|
|
||||||
|
if ( ! items ) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const threshold = 15;
|
||||||
|
const isLongList = items.length > threshold;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div { ...blockProps }>
|
||||||
|
<ul className="wc-block-product-filter-checkbox-list__list">
|
||||||
|
{ isLoading && loadingState }
|
||||||
|
{ ! isLoading &&
|
||||||
|
( isLongList
|
||||||
|
? items.slice( 0, threshold )
|
||||||
|
: items
|
||||||
|
).map( ( item, index ) => (
|
||||||
|
<li
|
||||||
|
key={ index }
|
||||||
|
className="wc-block-product-filter-checkbox-list__item"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
htmlFor={ `interactive-checkbox-${ index }` }
|
||||||
|
className=" wc-block-product-filter-checkbox-list__label"
|
||||||
|
>
|
||||||
|
<span className="wc-block-interactive-components-checkbox-list__input-wrapper">
|
||||||
|
<span className="wc-block-product-filter-checkbox-list__input-wrapper">
|
||||||
|
<input
|
||||||
|
name={ `interactive-checkbox-${ index }` }
|
||||||
|
type="checkbox"
|
||||||
|
className="wc-block-product-filter-checkbox-list__input"
|
||||||
|
defaultChecked={
|
||||||
|
!! item.selected
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Icon
|
||||||
|
className="wc-block-product-filter-checkbox-list__mark"
|
||||||
|
icon={ checkMark }
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span className="wc-block-product-filter-checkbox-list__text">
|
||||||
|
{ item.label }
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
) ) }
|
||||||
|
</ul>
|
||||||
|
{ ! isLoading && isLongList && (
|
||||||
|
<span className="wc-block-product-filter-checkbox-list__show-more">
|
||||||
|
<small>{ __( 'Show more…', 'woocommerce' ) }</small>
|
||||||
|
</span>
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
|
<InspectorControls group="color">
|
||||||
|
{ colorGradientSettings.hasColorsOrGradients && (
|
||||||
|
<ColorGradientSettingsDropdown
|
||||||
|
__experimentalIsRenderedInSidebar
|
||||||
|
settings={ [
|
||||||
|
{
|
||||||
|
label: __(
|
||||||
|
'Option Element Border',
|
||||||
|
'woocommerce'
|
||||||
|
),
|
||||||
|
colorValue:
|
||||||
|
optionElementBorder.color ||
|
||||||
|
customOptionElementBorder,
|
||||||
|
isShownByDefault: true,
|
||||||
|
enableAlpha: true,
|
||||||
|
onColorChange: ( colorValue: string ) => {
|
||||||
|
setOptionElementBorder( colorValue );
|
||||||
|
setAttributes( {
|
||||||
|
customOptionElementBorder: colorValue,
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
resetAllFilter: () => {
|
||||||
|
setOptionElementBorder( '' );
|
||||||
|
setAttributes( {
|
||||||
|
customOptionElementBorder: '',
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __(
|
||||||
|
'Option Element (Selected)',
|
||||||
|
'woocommerce'
|
||||||
|
),
|
||||||
|
colorValue:
|
||||||
|
optionElementSelected.color ||
|
||||||
|
customOptionElementSelected,
|
||||||
|
isShownByDefault: true,
|
||||||
|
enableAlpha: true,
|
||||||
|
onColorChange: ( colorValue: string ) => {
|
||||||
|
setOptionElementSelected( colorValue );
|
||||||
|
setAttributes( {
|
||||||
|
customOptionElementSelected: colorValue,
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
resetAllFilter: () => {
|
||||||
|
setOptionElementSelected( '' );
|
||||||
|
setAttributes( {
|
||||||
|
customOptionElementSelected: '',
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __( 'Option Element', 'woocommerce' ),
|
||||||
|
colorValue:
|
||||||
|
optionElement.color || customOptionElement,
|
||||||
|
isShownByDefault: true,
|
||||||
|
enableAlpha: true,
|
||||||
|
onColorChange: ( colorValue: string ) => {
|
||||||
|
setOptionElement( colorValue );
|
||||||
|
setAttributes( {
|
||||||
|
customOptionElement: colorValue,
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
resetAllFilter: () => {
|
||||||
|
setOptionElement( '' );
|
||||||
|
setAttributes( {
|
||||||
|
customOptionElement: '',
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
},
|
||||||
|
] }
|
||||||
|
panelId={ clientId }
|
||||||
|
{ ...colorGradientSettings }
|
||||||
|
/>
|
||||||
|
) }
|
||||||
|
</InspectorControls>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withColors( {
|
||||||
|
optionElementBorder: 'option-element-border',
|
||||||
|
optionElementSelected: 'option-element-border',
|
||||||
|
optionElement: 'option-element',
|
||||||
|
} )( Edit );
|
|
@ -0,0 +1,10 @@
|
||||||
|
.wc-block-product-filter-checkbox-list.is-loading {
|
||||||
|
.wc-block-product-filter-checkbox-list__list {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
@include placeholder();
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { getContext, store } from '@woocommerce/interactivity';
|
||||||
|
import { HTMLElementEvent } from '@woocommerce/types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type CheckboxListContext = {
|
||||||
|
items: {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
checked: boolean;
|
||||||
|
}[];
|
||||||
|
showAll: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
store( 'woocommerce/product-filter-checkbox-list', {
|
||||||
|
actions: {
|
||||||
|
showAllItems: () => {
|
||||||
|
const context = getContext< CheckboxListContext >();
|
||||||
|
context.showAll = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
selectCheckboxItem: ( event: HTMLElementEvent< HTMLInputElement > ) => {
|
||||||
|
const context = getContext< CheckboxListContext >();
|
||||||
|
const value = event.target.value;
|
||||||
|
|
||||||
|
context.items = context.items.map( ( item ) => {
|
||||||
|
if ( item.value.toString() === value ) {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
checked: ! item.checked,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} );
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { isExperimentalBlocksEnabled } from '@woocommerce/block-settings';
|
||||||
|
import { productFilterOptions } from '@woocommerce/icons';
|
||||||
|
import { registerBlockType } from '@wordpress/blocks';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import metadata from './block.json';
|
||||||
|
import Edit from './edit';
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
|
if ( isExperimentalBlocksEnabled() ) {
|
||||||
|
registerBlockType( metadata, {
|
||||||
|
edit: Edit,
|
||||||
|
icon: productFilterOptions,
|
||||||
|
} );
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
:where(.wc-block-product-filter-checkbox-list__list) {
|
||||||
|
list-style: none outside;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wc-block-product-filter-checkbox-list__item.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
:where(.wc-block-product-filter-checkbox-list__label) {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
gap: 0.625em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wc-block-product-filter-checkbox-list__item .wc-block-product-filter-checkbox-list__label {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(.wc-block-product-filter-checkbox-list__input-wrapper) {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wc-block-product-filter-checkbox-list__input-wrapper::before {
|
||||||
|
content: "";
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
background: currentColor;
|
||||||
|
opacity: 0.1;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
border-radius: 2px;
|
||||||
|
|
||||||
|
.has-option-element-color & {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(.wc-block-product-filter-checkbox-list__input) {
|
||||||
|
appearance: none;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid var(--wc-product-filter-checkbox-list-option-element-border, transparent);
|
||||||
|
color: inherit;
|
||||||
|
display: block;
|
||||||
|
font-size: inherit;
|
||||||
|
height: 1em;
|
||||||
|
margin: 0;
|
||||||
|
width: 1em;
|
||||||
|
background: var(--wc-product-filter-checkbox-list-option-element, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wc-block-product-filter-checkbox-list__input:checked + .wc-block-product-filter-checkbox-list__mark {
|
||||||
|
display: block;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wc-block-product-filter-checkbox-list__input:focus {
|
||||||
|
outline-width: 1px;
|
||||||
|
outline-color: var(--wc-product-filter-checkbox-list-option-element-border, currentColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(.wc-block-product-filter-checkbox-list__mark) {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: none;
|
||||||
|
height: 1em;
|
||||||
|
left: 0;
|
||||||
|
padding: 0.2em;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 1em;
|
||||||
|
color: var(--wc-product-filter-checkbox-list-option-element-selected, currentColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(.wc-block-product-filter-checkbox-list__show-more) {
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wc-block-product-filter-checkbox-list__show-more.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { BlockEditProps } from '@wordpress/blocks';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { FilterBlockContext } from '../../types';
|
||||||
|
|
||||||
|
export type Color = {
|
||||||
|
slug: string;
|
||||||
|
class: string;
|
||||||
|
name: string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BlockAttributes = {
|
||||||
|
className: string;
|
||||||
|
optionElementBorder: string;
|
||||||
|
customOptionElementBorder: string;
|
||||||
|
optionElementSelected: string;
|
||||||
|
customOptionElementSelected: string;
|
||||||
|
optionElement: string;
|
||||||
|
customOptionElement: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type EditProps = BlockEditProps< BlockAttributes > & {
|
||||||
|
context: FilterBlockContext;
|
||||||
|
optionElementBorder: Color;
|
||||||
|
setOptionElementBorder: ( value: string ) => void;
|
||||||
|
optionElementSelected: Color;
|
||||||
|
setOptionElementSelected: ( value: string ) => void;
|
||||||
|
optionElement: Color;
|
||||||
|
setOptionElement: ( value: string ) => void;
|
||||||
|
};
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||||
|
"name": "woocommerce/product-filter-chips",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"title": "Chips",
|
||||||
|
"description": "Display filter options as chips.",
|
||||||
|
"category": "woocommerce",
|
||||||
|
"keywords": [
|
||||||
|
"WooCommerce"
|
||||||
|
],
|
||||||
|
"textdomain": "woocommerce",
|
||||||
|
"apiVersion": 3,
|
||||||
|
"ancestor": [
|
||||||
|
"woocommerce/product-filter-attribute"
|
||||||
|
],
|
||||||
|
"supports": {},
|
||||||
|
"usesContext": [
|
||||||
|
"filterData",
|
||||||
|
"isParentSelected"
|
||||||
|
],
|
||||||
|
"attributes": {}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { useBlockProps } from '@wordpress/block-editor';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
|
const Edit = () => {
|
||||||
|
return <div { ...useBlockProps() }>These are chips.</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Edit;
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { isExperimentalBlocksEnabled } from '@woocommerce/block-settings';
|
||||||
|
import { productFilterOptions } from '@woocommerce/icons';
|
||||||
|
import { registerBlockType } from '@wordpress/blocks';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import metadata from './block.json';
|
||||||
|
import Edit from './edit';
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
|
if ( isExperimentalBlocksEnabled() ) {
|
||||||
|
registerBlockType( metadata, {
|
||||||
|
edit: Edit,
|
||||||
|
icon: productFilterOptions,
|
||||||
|
} );
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
:where(.wc-block-product-filter-chips) {
|
||||||
|
// WIP
|
||||||
|
}
|
|
@ -6,13 +6,9 @@ import { BlockEditProps } from '@wordpress/blocks';
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { BLOCK_NAME_MAP } from './constants';
|
|
||||||
|
|
||||||
export type FilterType = keyof typeof BLOCK_NAME_MAP;
|
|
||||||
|
|
||||||
export type BlockAttributes = {
|
export type BlockAttributes = {
|
||||||
filterType: FilterType;
|
className: string;
|
||||||
heading: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EditProps = BlockEditProps< BlockAttributes >;
|
export type EditProps = BlockEditProps< BlockAttributes >;
|
|
@ -1,3 +1,8 @@
|
||||||
|
/**
|
||||||
|
* Logic in this file is unused and should be moved to product-fitlers block.
|
||||||
|
*
|
||||||
|
* @see https://github.com/woocommerce/woocommerce/issues/50868
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
|
@ -6,7 +11,7 @@ import { store, getContext } from '@woocommerce/interactivity';
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { navigate } from '../product-filter/frontend';
|
import { navigate } from '../../frontend';
|
||||||
|
|
||||||
const getQueryParams = ( e: Event ) => {
|
const getQueryParams = ( e: Event ) => {
|
||||||
const filterNavContainer = ( e.target as HTMLElement )?.closest(
|
const filterNavContainer = ( e.target as HTMLElement )?.closest(
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { debounce } from '@woocommerce/base-utils';
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { navigate } from '../product-filter/frontend';
|
import { navigate } from '../../frontend';
|
||||||
import type { PriceFilterContext, PriceFilterStore } from './types';
|
import type { PriceFilterContext, PriceFilterStore } from './types';
|
||||||
|
|
||||||
const getUrl = ( context: PriceFilterContext ) => {
|
const getUrl = ( context: PriceFilterContext ) => {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue