woocommerce/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/rest-api/extend-rest-api-update-cart.md

195 lines
11 KiB
Markdown
Raw Normal View History

# Updating the cart with the Store API <!-- omit in toc -->
## Table of Contents <!-- omit in toc -->
- [The problem](#the-problem)
- [The solution](#the-solution)
- [Basic usage](#basic-usage)
- [Things to consider](#things-to-consider)
- [Extensions cannot update the client-side cart state themselves](#extensions-cannot-update-the-client-side-cart-state-themselves)
- [Only one callback for a given namespace may be registered](#only-one-callback-for-a-given-namespace-may-be-registered)
- [API Definition](#api-definition)
- [PHP](#php)
- [JavaScript](#javascript)
- [Putting it all together](#putting-it-all-together)
- [The "Redeem" button](#the-redeem-button)
- [Registering a callback to run when the `cart/extensions` endpoint is hit](#registering-a-callback-to-run-when-the-cartextensions-endpoint-is-hit)
## The problem
You're an extension developer, and your extension does some server-side processing as a result of some client-side input, i.e. a shopper filling in an input field in the Cart sidebar, and then pressing a button.
This server-side processing causes the state of the cart to change, and you want to update the data displayed in the client-side Cart or Checkout block.
You can't simply update the client-side cart state yourself. This is restricted to prevent malfunctioning extensions inadvertently updating it with malformed or invalid data which will cause the whole block to break.
## The solution
`ExtendSchema` offers the ability for extensions to register callback functions to be executed when signalled to do so by the client-side Cart or Checkout.
WooCommerce Blocks also provides a front-end function called `extensionCartUpdate` which can be called by client-side code, this will send data (specified by you when calling `extensionCartUpdate`) to the `cart/extensions` endpoint. When this endpoint gets hit, any relevant (based on the namespace provided to `extensionCartUpdate`) callbacks get executed, and the latest server-side cart data gets returned and the block is updated with this new data.
## Basic usage
In your extension's server-side integration code:
```php
add_action('woocommerce_blocks_loaded', function() {
woocommerce_store_api_register_update_callback(
[
'namespace' => 'extension-unique-namespace',
'callback' => /* Add your callable here */
]
);
} );
```
and on the client side:
```ts
const { extensionCartUpdate } = wc.blocksCheckout;
extensionCartUpdate( {
namespace: 'extension-unique-namespace',
data: {
key: 'value',
another_key: 100,
third_key: {
fourth_key: true,
},
},
} );
```
## Things to consider
### Extensions cannot update the client-side cart state themselves
You may be wondering why it's not possible to just make a custom AJAX endpoint for your extension that will update the cart. As mentioned, extensions are not permitted to update the client-side cart's state, because doing this incorrectly would cause the entire block to break, preventing the user from continuing their checkout. Instead you _must_ do this through the `extensionCartUpdate` function.
### Only one callback for a given namespace may be registered
With this in mind, if your extension has several client-side interactions that result in different code paths being executed on the server-side, you may wish to pass additional data through in `extensionsCartUpdate`. For example if you have two actions the user can take, one to _add_ a discount, and the other to _remove_ it, you may wish to pass a key called `action` along with the other data to `extensionsCartUpdate`. Then in your callback, you can check this value to distinguish which code path you should execute.
Example:
```php
<?php
function add_discount() {
/* Do some processing here */
}
function remove_discount() {
/* Do some processing here */
}
add_action('woocommerce_blocks_loaded', function() {
woocommerce_store_api_register_update_callback(
[
'namespace' => 'extension-unique-namespace',
'callback' => function( $data ) {
if ( $data['action'] === 'add' ) {
add_discount( );
}
if ( $data['action'] === 'remove' ) {
remove_discount();
}
}
]
);
} );
```
If you try to register again, under the same namespace, the previously registered callback will be overwritten.
## API Definition
### PHP
`ExtendSchema::register_update_callback`: Used to register a callback to be executed when the `cart/extensions` endpoint gets hit with a given namespace. It takes an array of arguments
2022-09-09 08:17:00 +00:00
| Attribute | Type | Required | Description |
| ----------- | ---------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `namespace` | `string` | Yes | The namespace of your extension. This is used to determine which extension's callbacks should be executed. |
| `callback` | `Callable` | Yes | The function/method (or Callable) that will be executed when the `cart/extensions` endpoint is hit with a `namespace` that matches the one supplied. The callable should take a single argument. The data passed into the callback via this argument will be an array containing whatever data you choose to pass to it. The callable does not need to return anything, if it does, then its return value will not be used. |
### JavaScript
`extensionCartUpdate`: Used to signal that you want your registered callback to be executed, and to pass data to the callback. It takes an object as its only argument.
| Attribute | Type | Required | Description |
| ----------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `namespace` | `string` | Yes | The namespace of your extension. This is used to determine which extension's callbacks should be executed. |
| `data` | `Object` | No | The data you want to pass to your callback. Anything in the `data` key will be passed as the first (and only) argument to your callback as an associative array. |
## Putting it all together
You are the author of an extension that lets the shopper redeem points that they earn on your website for a discount on their order. There is a text field where the shopper can enter how many points they want to redeem, and a submit button that will apply the redemption.
Your extension adds these UI elements to the sidebar in the Cart and Checkout blocks using the [`DiscountsMeta`](../checkout-block/available-slot-fills.md) Slot.
More information on how to use Slots is available in our [Slots and Fills documentation](../checkout-block/slot-fills.md).
Once implemented, the sidebar has a control added to it like this:
![image](https://user-images.githubusercontent.com/5656702/125109827-bf7c8300-e0db-11eb-9e51-59921b38a0c2.png)
### The "Redeem" button
In your UI, you are tracking the value the shopper enters into the `Enter amount` box using a React `useState` variable. The variable in this example shall be called `pointsInputValue`.
When the `Redeem` button gets clicked, you want to tell the server how many points to apply to the shopper's basket, based on what they entered into the box, apply the relevant discount, update the server-side cart, and then show the updated price in the client-side sidebar.
To do this, you will need to use `extensionCartUpdate` to tell the server you want to execute your callback, and have the new cart state loaded into the UI. The `onClick` handler of the button may look like this:
```js
const { extensionCartUpdate } = window.wc.blocksCheckout;
const buttonClickHandler = () => {
extensionCartUpdate( {
namespace: 'super-coupons',
data: {
pointsInputValue,
},
} );
};
```
### Registering a callback to run when the `cart/extensions` endpoint is hit
So far, we haven't registered a callback with WooCommerce Blocks yet, so when `extensionCartUpdate` causes the `cart/extensions` endpoint to get hit, nothing will happen.
Much like adding data to the Store API (described in more detail in [Exposing your data in the Store API](./extend-rest-api-add-data.md).) we can add the callback by invoking the `register_update_callback` method on the `ExtendSchema` class from WooCommerce Blocks.
We have written a function called `redeem_points` which applies a discount to the WooCommerce cart. This function does not return anything. Note, the actual implementation of this function is not the focus of this document, so has been omitted. All that is important to note is that it modifies the WooCommerce cart.
```php
<?php
function redeem_points( $points ) {
/* Do some processing here that applies a discount to the WC cart based on the value of $points */
}
add_action('woocommerce_blocks_loaded', function() {
woocommerce_store_api_register_update_callback(
[
'namespace' => 'super-coupons',
'callback' => function( $data ) {
redeem_points( $data['points'] );
},
]
);
} );
```
Now that this is registered, when the button is pressed, the `cart/extensions` endpoint is hit, with a `namespace` of `super-coupons` our `redeem_points` function will be executed. After this has finished processing, the client-side cart will be updated by WooCommerce Blocks.
<!-- FEEDBACK -->
---
[Docs] Update links from WooCommerce.com to Woo.com for the Woo Blocks documentation (#43055) * Update woocommerce.com URLs in documentation and code files * Add changelog * Fix github repository link in extend-rest-api-add-custom-fields.md Co-authored-by: Albert Juhé Lluveras <contact@albertjuhe.com> * Add github reporter (#42974) * Add github reporter * Add changelog --------- Co-authored-by: Jon Lane <jon.lane@automattic.com> * Fix product task redirect to support grouped and external products (#43051) * Rearrange product redirection logic to better accept grouped and external produc types * Add changelog * Modify feedback modal actions (#43005) * Adapt feedback modal actions * Add changelogs * Modify comments * Fix tests * Fix test * Update class-wc-gateway-bacs.php (#43054) * Update class-wc-gateway-bacs.php Fix typo in textdomain * Add changefile(s) from automation for the following project(s): woocommerce --------- Co-authored-by: github-actions <github-actions@github.com> * [Product Block Editor]: Add `Linked product` tab (#43009) * add linked-products to group IDs * add Linked Products tab * tweak hideConditions condition * changelog * fix typo in doc comment * Introduce a product type selection within the new experience (#41823) * Create a relation between the product type and the product block template * Add 'patterns' to name the kind of products that can be created for a specific template * Resolve template using its id as a template query param * Rename ProductEditPattern to ProductTemplate * Rename get_patterns hook to woocommerce_product_editor_get_product_templates * Return the list of templates to the client * Set layout template events as array * Register the layout template based on the product template or the post type in case of product variations * Registering non supported product types * Create and register the woocommerce/product-details-section-description block * Add the product type to the section description * Create product type selector * Fix menu item style * Highlight selected menu item * Set the selected product template * Set product template title to lowercase in the content description * Rename blocks by blockTemplates under the AbstractBlockTemplate class * Rename to woocommerce_product_editor_product_templates filter * Remove product_template_ prefix from the supported_product_types map * Rename get_formatted to to_JSON and convert the props to client side like * Refactor get_product_templates * Fix icon resolution * Add a confirmation modal for unsupported product templates * Add changelog files * Remove product types using for testing * Fix redirection when changing to a non supported product template * Set the change button state to busy when it is saving the product * Fix php linter errors * Fix rebase conflict * Move ProductTemplate to Automattic\WooCommerce\Admin\Features\ProductBlockEditor namespace * Add the to_json definition to the BlockTemplateInterface * Create default product template by custom product type if it does not have a template associated yet * Fix some comments and product template creation validation * Add support to load the product template icon from an external resource * Fix php linter * Fix the changelog description * [Experimental] Interactivity Dropdown multi-select mode, ratings filter and introduce each directive (#42981) --------- Co-authored-by: David Arenas <david.arenas@automattic.com> * Introduce the transient files engine (#42877) Co-authored-by: Corey McKrill <916023+coreymckrill@users.noreply.github.com> * Change marketplace install API request to POST instead of GET (#43033) * Change marketplace install API to using POST instead of GET * Fix linting error * Add changefile(s) from automation for the following project(s): woocommerce --------- Co-authored-by: github-actions <github-actions@github.com> * Prep trunk for 8.6 cycle (#43021) Prep trunk for 8.6 cycle with version bump to 8.6.0-dev Co-authored-by: WooCommerce Bot <no-reply@woo.com> * Add Playwright tests for All Reviews, Reviews by Product and Reviews by Category blocks (#42903) * Remove Reviews blocks Puppeteer tests * Minor code cleanup * Typos * Create publishAndVisitPost() editor util * Fix subcategories when importing products in Playwright and add reviews * Add Reviews blocks tests in Playwright * More typos * Add changefile(s) from automation for the following project(s): woocommerce-blocks * Create a 'reviews' object in data.ts so we can store reviews data in one single place * Update test so instead of creating a new post in each test, we go to the already-created post * Add source comments to reviews data to match it with the script --------- Co-authored-by: github-actions <github-actions@github.com> * Release: Remove 8.5 change files (#43022) Delete changelog files from 8.5 release Co-authored-by: WooCommerce Bot <no-reply@woo.com> Co-authored-by: Alex López <alex.lopez@automattic.com> * Delete changelog files based on PR 43033 (#43079) Delete changelog files for 43033 Co-authored-by: WooCommerce Bot <no-reply@woo.com> * Delete changelog files based on PR 43051 (#43081) Delete changelog files for 43051 Co-authored-by: WooCommerce Bot <no-reply@woo.com> * Interactive Price Filter: use `context` instead of `state` (#42980) * feat: use context instead of state * fix: temporary move the context to inner element for diffing to work * fix: update context before navigation for optimistic UI * Load google analytics gtag script asynchronously in WooCommerce Blocks (#43040) Co-authored-by: github-actions <github-actions@github.com> * set WOOCOMMERCE_BLOCKS_PHASE to 1 for the production build (#43074) * set WOOCOMMERCE_BLOCKS_PHASE to 1 for the production build * Add changefile(s) from automation for the following project(s): woocommerce --------- Co-authored-by: github-actions <github-actions@github.com> * Revert "Fix schedule sales error" (#43094) Revert "Fix schedule sales error (#42700)" This reverts commit 9b800aa179b25bafebfed0da8c00eec892272cb4. * [Product Block Editor]: add Linked product sections. First approach. (#43013) * add Linked products, Upsell section * changelog * add Cross-lens section * add links to the Upsell sections * changelog * fix lint issues * fix lint issus * fix linting issue :-| * check whether the linked product group is defined * [Product Block Editor]: introduce ShoppingBags component (#43042) * add ShoppingBags component * Add ShoppingBag story * changelog * Fix: Collection data being leaked between Collection Filters blocks (#43044) * fix: CYS - change heading color (#43076) * fix: CYS - change heading color * Add changefile(s) from automation for the following project(s): woocommerce --------- Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: Patricia Hillebrandt <patriciahillebrandt@gmail.com> * Delete changelog files based on PR 43074 (#43118) Delete changelog files for 43074 Co-authored-by: WooCommerce Bot <no-reply@woo.com> * [Product Block Editor]: fix feature flag to hide the Linked products (#43119) * fix flag to hide/show product editor * changelog * Add changelog --------- Co-authored-by: Albert Juhé Lluveras <contact@albertjuhe.com> Co-authored-by: Jonathan Lane <lanej0@users.noreply.github.com> Co-authored-by: Jon Lane <jon.lane@automattic.com> Co-authored-by: louwie17 <lourensschep@gmail.com> Co-authored-by: Fernando Marichal <fernando.marichal@automattic.com> Co-authored-by: Marc Guay <marc.guay@gmail.com> Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: Damián Suárez <rdsuarez@gmail.com> Co-authored-by: Maikel David Pérez Gómez <maikel.perez@automattic.com> Co-authored-by: Sam Seay <samueljseay@gmail.com> Co-authored-by: Néstor Soriano <konamiman@konamiman.com> Co-authored-by: Corey McKrill <916023+coreymckrill@users.noreply.github.com> Co-authored-by: Kyle Nel <22053773+kdevnel@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: WooCommerce Bot <no-reply@woo.com> Co-authored-by: Alex López <alex.lopez@automattic.com> Co-authored-by: Tung Du <dinhtungdu@gmail.com> Co-authored-by: Thomas Roberts <5656702+opr@users.noreply.github.com> Co-authored-by: Luigi Teschio <gigitux@gmail.com> Co-authored-by: Patricia Hillebrandt <patriciahillebrandt@gmail.com>
2023-12-29 15:28:11 +00:00
[We're hiring!](https://woo.com/careers/) Come work with us!
🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce-blocks/issues/new?assignees=&labels=type%3A+documentation&template=--doc-feedback.md&title=Feedback%20on%20./docs/third-party-developers/extensibility/rest-api/extend-rest-api-update-cart.md)
<!-- /FEEDBACK -->