|
| 1 | +# Filters |
| 2 | +Like traditional WordPress filters (you register a callback with a specific filter, your callback accepts a number of |
| 3 | +arguments, then it returns a value), we are introducing filters to the WooCommerce Blocks extension. These will function |
| 4 | +very similarly to the traditional filters. |
| 5 | + |
| 6 | +Your extension will use `__experimentalRegisterCheckoutFilter` to set up a filter. |
| 7 | + |
| 8 | +This function has the following signature: |
| 9 | + |
| 10 | +```typescript |
| 11 | +( |
| 12 | + namespace: string, |
| 13 | + filters: Record< string, CheckoutFilterFunction > |
| 14 | +) |
| 15 | +``` |
| 16 | + |
| 17 | +and a `CheckoutFilterFunction` has this signature: |
| 18 | + |
| 19 | +```typescript |
| 20 | +type CheckoutFilterFunction = < T >( |
| 21 | + value: T, |
| 22 | + extensions: Record< string, unknown >, |
| 23 | + args?: CheckoutFilterArguments |
| 24 | +) => T; |
| 25 | +``` |
| 26 | + |
| 27 | +In this, you'll specify which filter you want to work with (available filters are listed below) and the |
| 28 | +function (`CheckoutFilterFunction`) to execute when this filter is applied. |
| 29 | + |
| 30 | +When the `CheckoutFilterFunction` is invoked, the following arguments are passed to it: |
| 31 | +- `value` - The value to be filtered. |
| 32 | +- `extensions` A n object containing extension data. If your extension has extended any of the store's API routes, one |
| 33 | + of the keys of this object will be your extension's namespace. The value will contain any data you add to the endpoint. |
| 34 | + Each key in the `extensions` object is an extension namespace, so a third party extension cannot interfere with _your_ |
| 35 | + extension's schema modifications, unless there is a naming collision, so please ensure your extension has a unique |
| 36 | + namespace that is unlikely to conflict with other extensions. |
| 37 | +- `args` - An object containing any additional data passed to the filter function. This usually (but not always) contains at least a key |
| 38 | +called `context`. The value of `context` will be (at the moment) either `cart` or `checkout`. This is provided to inform |
| 39 | + extensions about the exact location that the filter is being applied. The same filter can be applied in multiple |
| 40 | + places. |
| 41 | + |
| 42 | +## Available filters |
| 43 | + |
| 44 | +This section of the document will list the filters that are currently available to extensions, where exactly |
| 45 | +the filter is applied, and what data might be passed to the `CheckoutFilterFunction`. |
| 46 | + |
| 47 | +### Cart Line Items |
| 48 | +Line items refers to each item listed in the cart or checkout. For instance |
| 49 | +the "Sunglasses" and "Beanie with logo" in this image are the line items. |
| 50 | + |
| 51 | +<img src="https://user-images.githubusercontent.com/5656702/117027554-b7c3eb00-acf4-11eb-8af1-b8bedbe20e05.png" width=600 /> |
| 52 | + |
| 53 | +The following filters are available for line items: |
| 54 | + |
| 55 | +| Filter name | Description | Return type | |
| 56 | +|---|---|---| |
| 57 | +| `itemName` | Used to change the name of the item before it is rendered onto the page | `string` |
| 58 | +| `cartItemPrice` | This is the price of the item, multiplied by the number of items in the cart. | `string` and **must** contain the substring `<price/>` where the price should appear. |
| 59 | +| `subtotalPriceFormat` | This is the price of a single item. Irrespective of the number in the cart, this value will always be the current price of _one_ item. | `string` and **must** contain the substring `<price/>` where the price should appear. |
| 60 | +| `saleBadgePriceFormat` | This is amount of money saved when buying this item. It is the difference between the item's regular price and its sale price. | `string` and **must** contain the substring `<price/>` where the price should appear. |
| 61 | + |
| 62 | +Each of these filters has the following arguments passed to it: `{ context: 'cart', cartItem: CartItem }` ([CartItem](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/c00da597efe4c16fcf5481c213d8052ec5df3766/assets/js/type-defs/cart.ts#L113)) |
| 63 | + |
| 64 | +### Order Summary Items |
| 65 | +In the Checkout block, there is a sidebar that contains a summary of what the customer is about to purchase. |
| 66 | +There are some filters available to modify the way certain elements are displayed on each item. |
| 67 | + |
| 68 | +The sale badges are not shown here, so those filters are not applied in the Order Summary. |
| 69 | + |
| 70 | +<img src="https://user-images.githubusercontent.com/5656702/117026942-1b014d80-acf4-11eb-8515-b9b777d96a74.png" width=400 /> |
| 71 | + |
| 72 | +| Filter name | Description | Return type | |
| 73 | +|---|---|---| |
| 74 | +| `itemName` | Used to change the name of the item before it is rendered onto the page | `string` |
| 75 | +| `cartItemPrice` | This is the price of the item, multiplied by the number of items in the cart. | `string` and **must** contain the substring `<price/>` where the price should appear. |
| 76 | +| `subtotalPriceFormat` | This is the price of a single item. Irrespective of the number in the cart, this value will always be the current price of _one_ item. | `string` and **must** contain the substring `<price/>` where the price should appear. |
| 77 | + |
| 78 | +Each of these filters has the following additional arguments passed to it: `{ context: 'summary', cartItem: CartItem }` ([CartItem](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/c00da597efe4c16fcf5481c213d8052ec5df3766/assets/js/type-defs/cart.ts#L113)) |
| 79 | + |
| 80 | +### Totals footer item (in Cart and Checkout) |
| 81 | + |
| 82 | +The word 'Total' that precedes the amount due, present in both the Cart _and_ Checkout blocks, is also passed through filters. |
| 83 | + |
| 84 | +| Filter name | Description | Return type | |
| 85 | +|---|---|---| |
| 86 | +| `totalLabel` | This is the label for the cart total. It defaults to 'Total' (or the word for 'Total' if using translations). | `string` |
| 87 | + |
| 88 | +There are no additional arguments passed to this filter. |
| 89 | + |
| 90 | +## Examples |
| 91 | + |
| 92 | +### Changing the wording of the Totals label in the Cart and Checkout |
| 93 | +For this example, let's suppose we are building an extension that lets customers pay a deposit, and defer the full amount until a later date. |
| 94 | + |
| 95 | +To make it easier to understand what the customer is paying and why, let's change the value of `Total` to `Deposit due today`. |
| 96 | + |
| 97 | +1. We need to create a `CheckoutFilterFunction`. |
| 98 | +```typescript |
| 99 | +const replaceTotalWithDeposit = () => 'Deposit due today'; |
| 100 | +``` |
| 101 | +2. Now we need to register this filter function, and have it executed when the `totalLabel` filter is applied. |
| 102 | + We can access the `__experimentalRegisterCheckoutFilters` function on the `window.wc.blocksCheckout` object. |
| 103 | + As long as your extension's script is enqueued _after_ WooCommerce Blocks' scripts (i.e. by registering `wc-blocks-checkout` as a dependency), then this will be available. |
| 104 | + ```typescript |
| 105 | +const { __experimentalRegisterCheckoutFilters } = window.wc.blocksCheckout; |
| 106 | +__experimentalRegisterCheckoutFilters( 'my-hypothetical-deposit-plugin', { |
| 107 | + totalLabel: replaceTotalWithDeposit |
| 108 | +} ); |
| 109 | +``` |
| 110 | + |
| 111 | +| Before | After | |
| 112 | +|---|---| |
| 113 | +| <img src="https://user-images.githubusercontent.com/5656702/117032889-cc56b200-acf9-11eb-9bf7-ae5f6a0b1538.png" width=300 /> | <img src="https://user-images.githubusercontent.com/5656702/117033039-ec867100-acf9-11eb-95d5-50c06bf2923c.png" width=300 /> | |
| 114 | + |
| 115 | + |
| 116 | +### Changing the format of the item's single price |
| 117 | +Let's say we want to add a little bit of text after an item's single price **in the Cart only**, just to make sure our customers know |
| 118 | +that's the price per item. |
| 119 | + |
| 120 | +1. We will need to register a function to be executed when the `subtotalPriceFormat` is applied. Since we only want this to happen in the |
| 121 | +Cart context, our function will need to check the additional arguments passed to it to ensure the `context` value is `cart`. |
| 122 | + |
| 123 | +We can see from the table above, that our function needs to return a string that contains a substring of `<price/>`. |
| 124 | +This is a placeholder for the numeric value. The Cart block will interpolate the value into the string we return. |
| 125 | +```typescript |
| 126 | +const appendTextToPriceInCart = ( value, extensions, args ) => { |
| 127 | + if( args?.context !== 'cart') { |
| 128 | + // Return early since this filter is not being applied in the Cart context. |
| 129 | + // We must return the original value we received here. |
| 130 | + return value; |
| 131 | + } |
| 132 | + return '<price/> per item'; |
| 133 | +}; |
| 134 | +``` |
| 135 | +2. Now we must register it. Refer to the first example for information about `__experimentalRegisterCheckoutFilters`. |
| 136 | +```typescript |
| 137 | +const { __experimentalRegisterCheckoutFilters } = window.wc.blocksCheckout; |
| 138 | +__experimentalRegisterCheckoutFilters( 'my-hypothetical-price-plugin', { |
| 139 | + subtotalPriceFormat: appendTextToPriceInCart |
| 140 | +} ); |
| 141 | +``` |
| 142 | + |
| 143 | + |
| 144 | +| Before | After | |
| 145 | +|---|---| |
| 146 | +| <img src="https://user-images.githubusercontent.com/5656702/117035086-d5488300-acfb-11eb-9954-feb326916168.png" width=400 /> | <img src="https://user-images.githubusercontent.com/5656702/117035616-70415d00-acfc-11eb-98d3-6c8096817e5b.png" width=400 /> | |
| 147 | + |
| 148 | +## Troubleshooting |
| 149 | +If you are logged in to the store as an administrator, you should be shown an error like this if your filter is not |
| 150 | +working correctly. |
| 151 | + |
| 152 | +<img src="https://user-images.githubusercontent.com/5656702/117035848-b4ccf880-acfc-11eb-870a-31ae86dd6496.png" width=600 /> |
| 153 | + |
| 154 | +The error will also be shown in your console. |
0 commit comments