# Authentication Source: https://docs.cocartapi.com/api-reference/authentication Learn how to authenticate with the CoCart API for secure access. The CoCart API provides multiple authentication methods to suit different needs. While the Products API and Cart API are publicly accessible without authentication, authenticating users enables personalized shopping experiences. ## Public vs. Authenticated Access * **Public Access**: Products API and Cart API * **Authenticated Access**: Required for registered customers to access their personal carts or special access/prices to products ## Customer Authentication Methods The use of **Basic Authentication** is only required should your store allow customer registration or provide membership access for specially discounted prices that can only be made available if the user has identified themselves. To make a successful request to an API that requires Basic Authentication, you must pass one of the identify methods we support combined as an authorization header for each request. When building a request using Basic Authentication, make sure you add the Authentication: Basic HTTP header with encoded credentials over HTTPS. Requests made over plain HTTP will fail. Authentication establishes a secure customer session. In the following request examples, you would replace ``, ``, `` and `` with your credentials before sending the request: ```bash cURL theme={"system"} curl -X GET 'https://your-store.com/wp-json/cocart/v2/cart' \ -H 'Accept: application/json' \ -H 'Authorization: Basic base64_encode(:)' ``` ```php PHP theme={"system"} 'https://your-store.com/wp-json/cocart/v2/cart', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Accept: application/json', 'Authorization: Basic ' . base64_encode( . ':' . ) ] ]); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); ``` ```javascript JavaScript theme={"system"} const auth = btoa(':'); fetch('https://your-store.com/wp-json/cocart/v2/cart', { headers: { 'Accept': 'application/json', 'Authorization': `Basic ${auth}` } }); ``` ```bash cURL theme={"system"} curl -X GET 'https://your-store.com/wp-json/cocart/v2/cart' \ -H 'Authorization: Basic base64_encode(:)' ``` ```php PHP theme={"system"} '; $password = ''; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => 'https://your-store.com/wp-json/cocart/v2/cart', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Basic ' . base64_encode($email . ':' . $password) ] ]); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); ``` ```javascript JavaScript theme={"system"} const auth = btoa(':'); fetch('https://your-store.com/wp-json/cocart/v2/cart', { headers: { 'Authorization': `Basic ${auth}` } }); ``` ```bash cURL theme={"system"} curl -X GET 'https://your-store.com/wp-json/cocart/v2/cart' \ -H 'Authorization: Basic base64_encode(:)' ``` ```php PHP theme={"system"} '; $password = ''; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => 'https://your-store.com/wp-json/cocart/v2/cart', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Basic ' . base64_encode($phone . ':' . $password) ] ]); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); ``` ```javascript JavaScript theme={"system"} const auth = btoa(':'); fetch('https://your-store.com/wp-json/cocart/v2/cart', { headers: { 'Authorization': `Basic ${auth}` } }); ``` ## Storing Authentication Credentials After successful authentication, securely store the credentials using one of these methods: * **Browser Storage** * LocalStorage (with encryption) * SessionStorage (for temporary sessions) * **Storage Libraries** * [localForage](https://www.npmjs.com/package/localforage) - Offline storage with fallbacks * [PouchDB](https://pouchdb.com/) - Offline-first database * **Native Storage** * [SQLite](https://www.sqlite.org/) - For mobile applications * [Hive](https://docs.hivedb.dev/) - For Flutter applications * Secure Keychain/Keystore for mobile platforms [Learn more about web storage](#web-storage-%26-cookies) ## JWT Authentication (Recommended) For enhanced security, we strongly recommend using JWT authentication when available. JWT provides: * Stateless authentication * Better security * Reduced server load * Easier mobile/desktop integration If JWT authentication is enabled, use the token received after login for subsequent requests: ```bash cURL theme={"system"} curl -X GET 'https://your-store.com/wp-json/cocart/v2/cart' \ -H 'Authorization: Bearer jwt_token' ``` ```php PHP theme={"system"} 'https://your-store.com/wp-json/cocart/v2/cart', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $token ] ]); $cart = curl_exec($ch); curl_close($ch); ``` ```javascript JavaScript theme={"system"} const token = await getToken(); const cart = await fetch('https://your-store.com/wp-json/cocart/v2/cart', { headers: { 'Authorization': `Bearer ${token}` } }); ``` ## Cart Session Management ### Authenticating with Existing Cart If a customer begins shopping while unauthenticated, you can transfer their cart items during authentication. See [Authenticating a customer with an existing cart](/api-reference/authentication/authenticate-customer-with-existing-cart) for the process. Maintain consistent authentication across all routes after customer login to preserve the cart session. Failing to do so will create new sessions and lose cart data. ## Administrator Authentication The Sessions API requires [WooCommerce REST API Key](https://woocommerce.github.io/woocommerce-rest-api-docs/#rest-api-keys) authentication. 1. Navigate to WooCommerce → Settings → Advanced → REST API 2. Generate new keys with `READ/WRITE` permissions 3. Use the keys for Sessions API authentication: ```bash cURL theme={"system"} curl -X GET 'https://your-store.com/wp-json/cocart/v2/sessions' \ -H 'Authorization: Basic base64_encode(ck_XXXX:cs_XXXX)' ``` ```php PHP theme={"system"} 'https://your-store.com/wp-json/cocart/v2/sessions', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Basic ' . base64_encode($consumer_key . ':' . $consumer_secret) ] ]); $response = curl_exec($ch); curl_close($ch); ``` ```javascript Javascript theme={"system"} const consumerKey = 'ck_XXXXXXXXXXXXXXXXXXXXXX'; const consumerSecret = 'cs_XXXXXXXXXXXXXXXXXXXXXX'; const auth = btoa(`${consumerKey}:${consumerSecret}`); fetch('https://your-store.com/wp-json/cocart/v2/sessions', { headers: { 'Authorization': `Basic ${auth}` } }); ``` ## About Base64 Encoding * `base64_encode()` is a PHP function * `btoa()` is a JavaScript function * Both perform Base64 encoding, but are used in different environments * For Node.js, use `Buffer.from(str).toString('base64')` * For React Native, use `import { encode } from 'base-64'` ```php PHP theme={"system"} $auth = base64_encode("username:password"); ``` ```javascript JavaScript theme={"system"} const auth = btoa("username:password"); ``` ```javascript Node.js theme={"system"} const auth = Buffer.from("username:password").toString('base64'); ``` ## Trouble with Authentication? If your server configuration doesn't properly handle the Authorization header, you can pass credentials as query parameters: ```http Customer Authentication theme={"system"} /wp-json/cocart/v2/cart?username=customer&password=secret ``` ```http WooCommerce REST API Keys theme={"system"} /wp-json/cocart/v2/sessions?consumer_key=123&consumer_secret=abc ``` However, these methods are less secure and should be used only as a fallback. ## Web storage & cookies There are two types of web storage: **LocalStorage** and **SessionStorage**. These were created as improvements to using Cookies since the storage capacity for web storage is much higher than Cookie storage. However, there are different pros and cons to each of these storage options. **LocalStorage** Anything stored in local web storage is persistent. This means that the data will persist until the data is explicitly deleted. Depending on the needs of your project, you might view this as a positive. However, you should be mindful of using LocalStorage, since any changes/additions to data will be available on all future visits to the webpage in question. We would not usually recommend using LocalStorage, although there may be a few exceptions to this. If you decide to use LocalStorage, it is good to know that it supports the same-origin policy, so all data stored here will only be available via the same origin. An added performance perk of using LocalStorage would be a resulting decrease in client-server traffic since the data does not have to be sent back to the server for every HTTP request. **SessionStorage** SessionStorage is similar to LocalStorage, but the key difference is that SessionStorage is not persistent. Once the window (or tab, depending on which browser you are using) that was used to write to SessionStorage is closed, the data will be lost. This is useful in restricting read access to your token within a user session. Using SessionStorage is normally more preferable than LocalStorage when thinking in terms of security. Like LocalStorage, the perks of same-origin policy support and decreased client-server traffic apply to SessionStorage as well. **Cookies** Cookies are the more traditional way to store session data. You can set an expiration time for each cookie, which would allow for ease of revocability and restriction of access. However, the client-server traffic would definitely increase when using cookies, since the data is being sent back to the server for every HTTP request. If you decide to use cookies, you need to protect against session hijacking. By default, cookies are sent in plaintext over HTTP, which makes their contents vulnerable to packet sniffing and/or man-in-the-middle attacks where attackers may modify your traffic. You should always enforce HTTPS to protect your data in transit. This will provide confidentiality, integrity (of the data), and authentication. However, if your web application or site is available both through HTTP and HTTPS, you will also want to use the ‘Secure’ flag on the cookie. This will prevent attackers from being able to send links to the HTTP version of your site to a user and listening in on the resulting HTTP request generated. Another secondary defense against session hijacking when using cookies would be to validate the user’s identity again before any high-impact actions are carried out. One other flag to consider for improving the security of your cookies would be the ‘HttpOnly’ flag. This flag tells the browser that the cookie in question shall only be accessible from the server specified. Any attempts made by client-side scripts would be forbidden by this flag, therefore helping to protect against most cross-site scripting (XSS) attacks. WooCommerce uses the cookie method natively for handling the cart session but CoCart does not. The session cookie prevented CoCart supporting guest customers and slowed down the performance of the API. [**Troubleshoot Authentication Issues →**](../knowledge-base/troubleshoot/authentication) # Frequently Asked Questions Source: https://docs.cocartapi.com/api-reference/faq We ask the most frequently asked questions for the API CoCart does not use or rely on any WordPress or WooCommerce cookies. Standard WordPress batch requests are handled via `https://your-store.com/wp-json/batch/v1` endpoint. For example adding multiple products to the cart request looks like: ```json theme={"system"} { "requests": [ { "method": "POST", "path": "/cocart/v2/cart/add-item", "body": { "id": "35", "quantity": "2" } }, { "method": "POST", "path": "/cocart/v2/cart/add-item", "body": { "id": "36", "quantity": "5" } } ] } ``` We have more available in our [support center](/knowledge-base/faq). # Introduction Source: https://docs.cocartapi.com/api-reference/introduction Welcome to the API Reference for CoCart. **Finding it hard to decouple WooCommerce from WordPress without hitting roadblocks?** CoCart is here to eliminate the hassle of creating your own REST API endpoints for WooCommerce and provides all the essential features for a powerful, headless eCommerce experience making it easy to decouple WooCommerce from WordPress. Want to try it out? [Setup a sandbox site](/api-reference/playground) to test it out. We highly recommend looking at our [community initiatives](/resources/community) to help your journey for support and networking. We make the assumption that you are comfortable with REST API's and understand the basics of WordPress and WooCommerce. Since they are both (including CoCart) are built in PHP, we recommend having some knowledge of it as well. Have a question, checkout our [Frequently Asked Questions](/api-reference/faq) or [contact support](mailto:support@cocartapi.com) if not already answered. ## Base url The base URL is where your WordPress is installed. All requests made to CoCart API is via your WordPress site url `https://example-store.com/wp-json/cocart/` ## Request/Response Format The default response format is in JSON. Requests with a message-body use plain JSON to set or update resource attributes. Successful requests will return a `200 OK` HTTP status. Some general information about response: * Resource IDs are returned as integers. * Other number values, such as price, item counts, are returned as integers or strings. * Blank fields may return as `null` instead of being returned as blank strings or omitted. ## Body Types There are different types of body types when making a request. Make sure when using either of these body types that you have the correct `Content-Type` for the header. | Body Type | Content-Type | | --------------------- | --------------------------------- | | form-data | application/json | | raw | application/json | | x-www-form-urlencoded | application/x-www-form-urlencoded | Using **raw** works best if you are passing an object of data for a `variation` or `cart_item_data`. Use [any of the tools available](/documentation/tools) to help test the API with if you are unsure. ## Errors Occasionally you might encounter errors when accessing the REST API. Here are the possible types: | Error Code | Error Type | | --------------------------- | ------------------------------------------------------------- | | `400 Bad Request` | Invalid request, e.g. using an unsupported HTTP method. | | `401 Unauthorized` | Authentication or permission error, e.g. incorrect login. | | `403 Forbidden` | Not allowed to process this action or have permission. | | `404 Not Found` | Requests to resources that don't exist or are missing. | | `405 Method Not Allowed` | A request method is not supported for the requested resource. | | `406 Not Acceptable` | Indicates that the server could not produce a response. | | `500 Internal Server Error` | Server error | > WP REST API error example ```json theme={"system"} { "code": "rest_no_route", "message": "No route was found matching the URL and request method", "data": { "status": 404 } } ``` > CoCart error example ```json theme={"system"} { "code": "cocart_clear_cart_failed", "message": "Clearing the cart failed!", "data": { "status": 406 } } ``` Errors return both an appropriate HTTP status code and response object which contains a `code`, `message` and `data` attribute. # Refresh Token Source: https://docs.cocartapi.com/api-reference/jwt/refresh-token api-reference/jwt/openapi.json post /cocart/jwt/refresh-token Generate a new JWT token using a refresh token # Validate Token Source: https://docs.cocartapi.com/api-reference/jwt/validate-token api-reference/jwt/openapi.json post /cocart/jwt/validate-token Validate an existing JWT token # CoCart Playground Source: https://docs.cocartapi.com/api-reference/playground Setup a WooCommerce store demo with CoCart to play around. Create reproducible WooCommerce testing environment with CoCart to test out the REST API right away. It generates a blueprint that: * Configures pretty permalinks * Installs WooCommerce * Sets up basic store information * Skips the onboarding wizard * Configures basic WooCommerce settings * Imports sample products * Installs CoCart, JWT Authentication and CORS support * Installs Safe SVG and Leira Letter Avatar plugins * Installs the Storefront theme The rest is up to you to play around with. Create a free CoCart Playground with WooCommerce to test the REST API. ## How it works: * A fresh new WordPress site is created for you. * You’ll be taken straight to the WordPress admin. * Use the provided information to help you test the API. ## What to expect from Playground: * The playground is valid for **5 days**. After that the site expires, all data will be erased and can no longer be accessed. * Test CoCart on a clean WordPress sandbox. * Don’t worry about issues with CORS. It’s already setup. * Try all our core features. No strings attached. Search, filter and return product data you need. Add products to cart either as a guest or a registered customer. * Push CoCart to its limits. Don’t worry about breaking anything, it’s just a demo site. Yes to all. You are the administrator of the playground. For more information about the WordPress Playground please visit [https://wordpress.org/playground/](https://wordpress.org/playground/) Yes, not everything can be setup for the Playground. Simply go to **WooCommerce -> Settings** and on the general tab, check "Enable tax rates and calculations" and press "Save changes". Then you can see a new tab called **Tax**. Yes, not everything can be setup for the Playground. Simply go to **WooCommerce -> Settings** and on the **Shipping** tab you can create shipping zones and apply the shipping methods. WordPress Playground is not stable and may have an issue creating an environment at times. If not succeeding, please consider [creating a sandbox instead](https://app.instawp.io/launch?t=cocart-demo-core-only\&d=v2). Sandbox sites are live for **only 5 days** and also include **CoCart Plus**. Some taxes and shipping options have also been configured. # Remove Item from Cart Source: https://docs.cocartapi.com/api-reference/v1/cart/delete-remove-item api-reference/v1/openapi-cart-v1.yaml delete /item Removes a specific item from the customer's cart. # Get Cart Source: https://docs.cocartapi.com/api-reference/v1/cart/get-cart api-reference/v1/openapi-cart-v1.yaml get /get-cart Gets the cart items added by the customer. # Get Cart for Customer Source: https://docs.cocartapi.com/api-reference/v1/cart/get-cart-customer api-reference/v1/openapi-cart-v1.yaml get /get-cart/customer/{id} Gets the persistent cart for the provided customer ID. # Get Cart in Session Source: https://docs.cocartapi.com/api-reference/v1/cart/get-cart-in-session api-reference/v1/openapi-cart-v1.yaml get /get-cart/{id} Gets the cart in session for the provided cart key. # Get Cart Items Count Source: https://docs.cocartapi.com/api-reference/v1/cart/get-count-items api-reference/v1/openapi-cart-v1.yaml get /count-items Returns the count of items in the customer's cart. # Get Cart Totals Source: https://docs.cocartapi.com/api-reference/v1/cart/get-totals api-reference/v1/openapi-cart-v1.yaml get /totals Retrieves the cart totals including subtotal, taxes, shipping, and discounts. # Remove a Coupon from Cart Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/delete-remove-coupon api-reference/v1/openapi-cart-v1.yaml delete /coupon Remove a coupon from the cart using the coupon code. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Get Applied Coupons in Cart Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-applied-coupons api-reference/v1/openapi-cart-v1.yaml get /coupon Retrieve a list of all coupons currently applied to the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Check Coupons in Cart Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-check-coupons api-reference/v1/openapi-cart-v1.yaml get /check-coupons Check if coupons applied to the cart are valid. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Cart Cross Sells Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-cross-sells api-reference/v1/openapi-cart-v1.yaml get /cross-sells Gets cross-sell products for the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Get Customer Details Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-customer api-reference/v1/openapi-cart-v1.yaml get /customer Retrieve customer details associated with the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Get Fees from Cart Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-fees api-reference/v1/openapi-cart-v1.yaml get /fees Retrieve a list of all fees applied to the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Get Payment Methods Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-payment-methods api-reference/v1/openapi-cart-v1.yaml get /payment-methods Retrieve available payment methods for the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Get Item Quantities in Cart Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-quantities api-reference/v1/openapi-cart-v1.yaml get /quantities Retrieve the quantities of items currently in the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Removed Items from Cart Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-removed-items api-reference/v1/openapi-cart-v1.yaml get /removed-items Retrieve a list of items that have been removed from the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Get Shipping Methods Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-shipping-methods api-reference/v1/openapi-cart-v1.yaml get /shipping-methods Gets available shipping methods for the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Get Coupon Discount Tax Totals Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-totals-discount-coupon-tax api-reference/v1/openapi-cart-v1.yaml get /totals/discount/coupon-tax Gets the discount tax totals per coupon. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Get Fee Total Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-totals-fee api-reference/v1/openapi-cart-v1.yaml get /totals/fee Gets the total fees applied to the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Get Fee Tax Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-totals-fee-tax api-reference/v1/openapi-cart-v1.yaml get /totals/fee/tax Gets the total fee tax applied to the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Get Shipping Total Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-totals-shipping api-reference/v1/openapi-cart-v1.yaml get /totals/shipping Gets the total shipping cost for the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Get Shipping Tax Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-totals-shipping-tax api-reference/v1/openapi-cart-v1.yaml get /totals/shipping/tax Gets the total shipping tax for the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Get Subtotal Tax Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-totals-subtotal-tax api-reference/v1/openapi-cart-v1.yaml get /totals/subtotal/tax Gets the subtotal tax of the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Get Total Tax Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-totals-tax api-reference/v1/openapi-cart-v1.yaml get /totals/tax Gets the total tax for the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Get Cart Total Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/get-totals-total api-reference/v1/openapi-cart-v1.yaml get /totals/total Gets the total amount for the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Apply a Fee Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/post-add-fee api-reference/v1/openapi-cart-v1.yaml post /fees Adds a fee to the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Apply a Coupon Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/post-apply-coupon api-reference/v1/openapi-cart-v1.yaml post /coupon Applies a coupon to the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Calculate Fees Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/post-calculate-fees api-reference/v1/openapi-cart-v1.yaml post /calculate/fees Calculates the cart fees. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Calculate Shipping Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/post-calculate-shipping api-reference/v1/openapi-cart-v1.yaml post /calculate/shipping Calculates shipping for the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Set Payment Method Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/post-set-payment-method api-reference/v1/openapi-cart-v1.yaml post /payment-methods Sets a payment method for the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Set Shipping Methods Source: https://docs.cocartapi.com/api-reference/v1/cart/plus/post-set-shipping-method api-reference/v1/openapi-cart-v1.yaml post /shipping-methods Sets a shipping method for the cart. This endpoint is available in [CoCart Plus](https://cocartapi.com/pricing/?ref=mintlify). # Add Item to Cart Source: https://docs.cocartapi.com/api-reference/v1/cart/post-add-item api-reference/v1/openapi-cart-v1.yaml post /add-item Adds a product item to the customer's cart. # Calculate cart totals Source: https://docs.cocartapi.com/api-reference/v1/cart/post-calculate api-reference/v1/openapi-cart-v1.yaml post /calculate Calculates the cart totals including taxes, shipping, and discounts. # Clear the cart Source: https://docs.cocartapi.com/api-reference/v1/cart/post-clear-cart api-reference/v1/openapi-cart-v1.yaml post /clear Removes all items from the customer's cart. # Update Item in Cart Source: https://docs.cocartapi.com/api-reference/v1/cart/post-update-item api-reference/v1/openapi-cart-v1.yaml post /item Updates the quantity of a specific item in the customer's cart. # Restore Item to Cart Source: https://docs.cocartapi.com/api-reference/v1/cart/put-restore-item api-reference/v1/openapi-cart-v1.yaml put /item OpenSpec file is incomplete! Review and correct to allow documentation to generate. # Error Codes Source: https://docs.cocartapi.com/api-reference/v1/error-codes Error codes returned by the CoCart API v1. | HTTP Code | Error Code | Error Message | | --------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 | `cocart_cannot_read_cart` | Cannot read cart! | | 404 | `cocart_customer_missing` | Customer ID is required! | | 404 | `cocart_cart_key_missing` | Cart Key is required! | | 404 | `cocart_cart_in_session_not_valid` | Cart in session is not valid! | | 404 | `cocart_clear_cart_failed` | Clearing the cart failed! | | 404 | `cocart_product_id_required` | Product ID number is required! | | 405 | `cocart_product_id_not_numeric` | Product ID must be numeric! | | 405 | `cocart_quantity_not_numeric` | Quantity must be numeric! | | 404 | `cocart_product_does_not_exist` | Warning: This product does not exist! | | 403 | `cocart_product_sold_individually` | You cannot add another "%s" to your cart. | | 403 | `cocart_cannot_be_purchased` | Sorry, this product cannot be purchased. | | 404 | `cocart_product_out_of_stock` | You cannot add "%s" to the cart because the product is out of stock. %s is the product name | | 403 | `cocart_not_enough_in_stock` | You cannot add a quantity of %1$s: quantity requested for "`%3$s` remaining! | | 403 | `cocart_not_enough_stock_remaining` | You cannot add that amount to the cart — we have `%1$s` in stock and you already have `%2$s` in your cart. | | 403 | `cocart_not_ok_to_add_item` | This item can not be added to the cart. | | 403 | `cocart_cannot_add_to_cart` | You cannot add "`%s`" to your cart. %s is the product name | | 403 | `cocart_can_not_remove_item` | Unable to remove item from cart. | | 403 | `cocart_can_not_restore_item` | Unable to restore item to the cart. | | 403 | `cocart_can_not_update_item` | Unable to update item quantity in cart. | | 404 | `cocart_cart_item_key_required` | Cart item key is required! | | 404 | `cocart_no_items` | No items in cart. | | 404 | `cocart_item_not_in_cart` | Item specified does not exist in cart. | | 403 | `cocart_cannot_add_product_type_to_cart` | You cannot add "`%1$s`" to your cart as it is an "`%2$s`" product. %1$s: product name, %2$s: product type | | 400 | `cocart_invalid_variation_data` | Invalid value posted for `%1$s`. Allowed values: `%2$s` %1$s: Attribute name, %2$s: Allowed values | | 400 | `cocart_missing_variation_data` | Missing variation data for variable product. `%s` is a required field. %s: Attribute name. | | 400 | `cocart_missing_variation_data` | Missing variation data for variable product. `%s` are required fields. %s: Attribute name. | | 400 | `cocart_no_variation_found` | No matching variation found. | | 403 | `cocart_cart_invalid_parent_product` | This product cannot be added to the cart. | | 404 | `cocart_product_failed_validation` | Product did not pass validation! | | 403 | `cocart_product_sold_individually` | You cannot add another "`%s`" to your cart. | | 403 | `cocart_can_not_increase_quantity` | You can only have 1 `%s` in your cart. %s is the product name | # Get a Product Source: https://docs.cocartapi.com/api-reference/v1/products/get-product api-reference/v1/openapi-products-v1.yaml get /products/{id} Returns a single product. # Get a Product Attribute Source: https://docs.cocartapi.com/api-reference/v1/products/get-product-attribute api-reference/v1/openapi-products-v1.yaml get /products/attributes/{id} Returns a single product attribute. # Get a Product Attribute Term Source: https://docs.cocartapi.com/api-reference/v1/products/get-product-attribute-term api-reference/v1/openapi-products-v1.yaml get /products/attributes/{attribute_id}/terms/{id} Returns a single product attribute term. # Get Product Attribute Terms Source: https://docs.cocartapi.com/api-reference/v1/products/get-product-attribute-terms api-reference/v1/openapi-products-v1.yaml get /products/attributes/{attribute_id}/terms Returns a list of product attribute terms. # Get Product Attributes Source: https://docs.cocartapi.com/api-reference/v1/products/get-product-attributes api-reference/v1/openapi-products-v1.yaml get /products/attributes Returns a list of product attributes. # Get Product Categories Source: https://docs.cocartapi.com/api-reference/v1/products/get-product-categories api-reference/v1/openapi-products-v1.yaml get /products/categories Returns a list of product categories. # Get a Product Review Source: https://docs.cocartapi.com/api-reference/v1/products/get-product-review api-reference/v1/openapi-products-v1.yaml get /products/reviews/{id} Returns a single product review. # Get Product Reviews Source: https://docs.cocartapi.com/api-reference/v1/products/get-product-reviews api-reference/v1/openapi-products-v1.yaml get /products/reviews Returns a list of product reviews. # Get Product Tags Source: https://docs.cocartapi.com/api-reference/v1/products/get-product-tags api-reference/v1/openapi-products-v1.yaml get /products/tags Returns a list of product tags. # Get a Product Variation Source: https://docs.cocartapi.com/api-reference/v1/products/get-product-variation api-reference/v1/openapi-products-v1.yaml get /products/{product_id}/variations/{id} Returns a single product variation. # Get Product Variations Source: https://docs.cocartapi.com/api-reference/v1/products/get-product-variations api-reference/v1/openapi-products-v1.yaml get /products/{product_id}/variations Returns a list of product variations. # Get Products Source: https://docs.cocartapi.com/api-reference/v1/products/get-products api-reference/v1/openapi-products-v1.yaml get /products Returns a list of products. # Logout Source: https://docs.cocartapi.com/api-reference/v1/user/logout api-reference/v1/openapi-cart-v1.yaml post /logout Logs out the customer and clears their session. Originally this endpoint was used to log out a user and their cart session when relying on WooCommerce session cookie. While the endpoint is not needed to clear the users session anymore, you can still use it to clear any WordPress cookies that may have been set. # Get cart Source: https://docs.cocartapi.com/api-reference/v2/cart/get-cart api-reference/v2/openapi-v2-stable.yaml get /cart Get the full cart including all items, totals, and customer information. # Add Item to Cart Source: https://docs.cocartapi.com/api-reference/v2/cart/post-add-item api-reference/v2/openapi-v2-stable.yaml post /cart/add-item Adds a single product item to the customer's cart. # Add Items to Cart Source: https://docs.cocartapi.com/api-reference/v2/cart/post-add-items api-reference/v2/openapi-v2-stable.yaml post /cart/add-items Adds multiple product items to the customer's cart in a single request. # Calculate cart totals Source: https://docs.cocartapi.com/api-reference/v2/cart/post-calculate api-reference/v2/openapi-v2-stable.yaml post /cart/calculate Calculates the cart totals including taxes, shipping, and discounts. # Clear the cart Source: https://docs.cocartapi.com/api-reference/v2/cart/post-clear api-reference/v2/openapi-v2-stable.yaml post /cart/clear Removes all items from the customer's cart. # Variation Examples Source: https://docs.cocartapi.com/api-reference/v2/variation-examples Know all the combinations for variable products when adding to cart. ## Adding Variable Products to Cart When adding a variation from a variable product to the cart, there are several approaches you can take. Below are examples of each method and their outcomes. ### Method 1: No Attribute Data To make things clear from the start. Adding a variable product without attribute data will fail as the variation cannot be determined. This method is not recommended. ````json theme={"system"} { "id": "16", "quantity": "1" } ```json { "id": "16", "quantity": "1" } ```` **Response**: ```json theme={"system"} { "code": "cocart_no_variation_found", "message": "No matching variation found.", "data": { "status": 404 } } ``` ### Method 2: Using Attribute Data Note the lowercase "no" ```json theme={"system"} { "id": "16", "quantity": "1", "variation": { "attribute_pa_color": "green", "attribute_logo": "no" } } ``` **Response** ```json theme={"system"} { "code": "cocart_no_variation_found", "message": "No matching variation found.", "data": { "status": 404 } } ``` ```json theme={"system"} { "id": "16", "quantity": "1", "variation": { "attribute_pa_color": "blue", "attribute_logo": "No" } } ``` ### Method 3: Using Variation ID You can directly add a specific variation using its **ID**. ```json theme={"system"} { "id": "39", "quantity": "1" } ``` However, if you specify an invalid attribute with the variation ID you will receive an error. The error will provide the **allowed values**. ```json theme={"system"} { "id": "39", "quantity": "1", "variation": { "attribute_pa_color": "orange", "attribute_logo": "Yes" } } ``` **Response** ```json theme={"system"} { "code": "cocart_invalid_variation_data", "message": "Invalid value posted for Color. Allowed values: blue, green, red", "data": { "status": 400 } } ``` ### Method 4: Using Alternative Attribute Formats You can use attribute labels instead of slugs. ```json theme={"system"} { "id": "16", "quantity": "1", "variation": { "Color": "blue", "Logo": "Yes" } } ``` You can mix slugs and labels (note: label values must be exact for custom attributes). ```json theme={"system"} { "id": "16", "quantity": "1", "variation": { "pa_color": "blue", "Logo": "Yes" } } ``` ## Important Notes 1. Attribute values are case-sensitive 2. When using variation IDs, attribute data is optional 3. Custom attribute labels must match exactly 4. Values maybe limited to specific options 5. You can use either attribute slugs (`attribute_pa_color`) or labels (`Color`) # Batch Requests for the Cart Source: https://docs.cocartapi.com/documentation/batch-requests Learn how to batch request the cart To use the premium batch request for cart, you need [CoCart Plus or higher](https://cocartapi.com/pricing/). Otherwise feel free to [use the standard WordPress batch process](https://make.wordpress.org/core/2020/11/20/rest-api-batch-framework-in-wordpress-5-6/). Supports API v2 or higher. Make multiple cart requests and return 1 complete cart response. Sounds to good to be true but it is. The [standard batch processing](https://make.wordpress.org/core/2020/11/20/rest-api-batch-framework-in-wordpress-5-6/) that WordPress supports is too problematic for developers when it comes to using the cart data to present it. Seriously if you try it yourself, you would not want to use the standard way. We took away the pain of having to track and merge data together for you, so you can go about your programming with ease. It supports both authenticated users and guest customers. ## How do I use it? It’s very simple. Post your requests as you would do a standard WordPress batch request only you are using our special batch endpoint `wp-json/cocart/batch` instead. ```json theme={"system"} { "requests": [ { "method": "POST", "path": "/cocart/v2/cart/add-item", "body": { "id": "35", "quantity": "2" } }, { "method": "POST", "path": "/cocart/v2/cart/add-item", "body": { "id": "36", "quantity": "5" } } ] } ``` ## What about guest customers? Simply provide the cart key to identify the cart for the guest customer the same way you would for a singular cart endpoint. If you used the standard batch process, you would have to apply the cart key to each request, which we don’t recommend. In the following request examples, you would replace `` that identifies the guest customers cart before sending the request: ```bash cURL theme={"system"} curl -L 'https://example-store.com/wp-json/cocart/batch?cart_key=' \ -H 'Content-Type: application/json' \ -d '{ "requests": [ { "method": "POST", "path": "/cocart/v2/cart/add-item", "body": { "id": "35", "quantity": "2" } }, { "method": "POST", "path": "/cocart/v2/cart/add-item", "body": { "id": "36", "quantity": "5" } } ] }' ``` ```php PHP theme={"system"} 'https://example-store.com/wp-json/cocart/batch?cart_key=' CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Basic ' . base64_encode($username . ':' . $password) ] ]); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); ``` ```javascript Javascript theme={"system"} ``` ## The results The results is one complete cart response (if all requests are successful). You should see multiple notices return for each of the requests. Will leave you to decide how you use them. # Contributing to Documentation Source: https://docs.cocartapi.com/documentation/contributing-to-docs Learn how to contribute to CoCart API documentation Thank you for your interest in improving the CoCart API documentation! This guide will help you understand how to contribute effectively. ## Overview The CoCart API documentation is built with [Mintlify](https://mintlify.com), a modern documentation platform that uses MDX (Markdown + JSX) files and is hosted publicly on GitHub at [cocart-headless/cocart-api-documentation](https://github.com/cocart-headless/cocart-api-documentation). ## Ways to Contribute You can help improve the documentation in several ways: Correct spelling mistakes, grammar issues, or technical inaccuracies Rewrite confusing sections to make them easier to understand Contribute code examples in different programming languages Create step-by-step guides for common use cases ## Getting Started ### Prerequisites Before you begin, make sure you have: * A [GitHub account](https://github.com/signup) * [Git](https://git-scm.com/downloads) installed on your computer * [Node.js](https://nodejs.org/) (v18 or higher) installed * Basic familiarity with Markdown and Git workflows ### Setting Up Your Development Environment 1. **Fork the repository** Visit the [documentation repository](https://github.com/cocart-headless/cocart-api-documentation) and click the "Fork" button in the top-right corner. 2. **Clone your fork** ```bash theme={"system"} git clone https://github.com/YOUR-USERNAME/cocart-api-documentation.git cd cocart-api-documentation ``` 3. **Install Mintlify CLI** ```bash theme={"system"} npm install -g mintlify ``` 4. **Start the development server** ```bash theme={"system"} mintlify dev ``` The documentation will be available at `http://localhost:3000`. If `mintlify dev` isn't working, try running `mintlify install` to reinstall dependencies. ## Documentation Structure Understanding the project structure will help you navigate and contribute effectively: ``` cocart-api-documentation/ ├── docs.json # Navigation and site configuration ├── api-reference/ # API endpoint documentation │ ├── v1/ # API v1 endpoints │ ├── v2/ # API v2 endpoints │ └── jwt/ # JWT authentication endpoints ├── documentation/ # User guides and features │ ├── developers/ # Developer resources │ └── guides/ # How-to guides ├── tutorials/ # Step-by-step tutorials ├── getting-started/ # Setup and quick start guides ├── cli-reference/ # CLI command documentation ├── knowledge-base/ # FAQ and troubleshooting └── resources/ # Community and support info ``` ### Key Files * **[docs.json](https://mintlify.com/docs.json)** - Controls navigation, theme, and site settings * **MDX files** - Content pages using Markdown with React components * **CLAUDE.md** - Project-specific contribution guidelines ## Writing Guidelines ### Frontmatter Requirements Every MDX file must include frontmatter with at least these fields: ```mdx theme={"system"} --- title: "Clear, Descriptive Page Title" description: "Concise summary for SEO and navigation (1-2 sentences)" --- ``` Optional frontmatter fields: ```mdx theme={"system"} --- title: "Page Title" sidebarTitle: "Shorter Sidebar Title" description: "Page description" icon: "icon-name" # Font Awesome icon tag: "NEW" # Badge: NEW, WIP, BETA, etc. --- ``` ### Writing Style Follow these style guidelines for consistency: * Use **second-person voice** ("you") when addressing the reader * Keep tone professional but friendly * Write in active voice * Be concise and direct **Good**: "You can authenticate using Basic Auth or JWT tokens." **Bad**: "Users are able to utilize either Basic Auth or JWT tokens for authentication purposes." * Include code examples for all procedural content * Add language tags to all code blocks * Test all code examples before submitting * Include both basic and advanced use cases where appropriate * Show examples in multiple languages when possible (JavaScript, PHP, cURL) ```javascript theme={"system"} const response = await fetch('https://example.com/wp-json/cocart/v2/cart'); const cart = await response.json(); ``` * Use **relative paths** for internal links: `[link text](/path/to/page)` * Use descriptive link text (avoid "click here") * Link to relevant sections for additional context **Good**: `See [Authentication](/api-reference/authentication) for more details.` **Bad**: `Click [here](https://docs.cocartapi.com/api-reference/authentication) for more information.` * Start procedural content with prerequisites * Use clear headings to organize content * Include "What You'll Learn" or "Overview" sections for tutorials * Add "Next Steps" or "What's Next" sections where appropriate ## Using Mintlify Components Mintlify provides special components to enhance your documentation: ### Callouts Use callouts to highlight important information: ```mdx theme={"system"} This is informational content that provides helpful context. This warns users about potential issues or important considerations. This offers helpful tips or best practices. This provides additional notes or clarifications. ``` ### Cards Create card layouts for organized content: ```mdx theme={"system"} Card description Another description ``` ### Accordions Use accordions for collapsible content: ```mdx theme={"system"} Content that can be expanded/collapsed More collapsible content ``` ### Code Groups Show code in multiple languages using CodeGroup: ```bash cURL theme={"system"} curl -X GET https://example.com/wp-json/cocart/v2/cart ``` ```javascript JavaScript theme={"system"} const response = await fetch('https://example.com/wp-json/cocart/v2/cart'); ``` ```php PHP theme={"system"} $response = wp_remote_get('https://example.com/wp-json/cocart/v2/cart'); ``` For more components and options, see the [Mintlify Components Documentation](https://mintlify.com/docs/content/components/accordions). ## Contribution Workflow ### Making Changes 1. **Create a new branch** ```bash theme={"system"} git checkout -b fix/improve-authentication-docs ``` Branch naming conventions: * `fix/short-description` - Bug fixes or corrections * `add/short-description` - New content * `refactor/short-description` - Reorganizing content * `update/short-description` - Updating existing content 2. **Make your changes** Edit MDX files in your preferred text editor. The local dev server will auto-reload as you make changes. 3. **Preview your changes** Check `http://localhost:3000` to see how your changes look before committing. 4. **Update navigation** (if adding new pages) Add your new page to [docs.json](docs.json) in the appropriate section: ```json theme={"system"} { "group": "Tutorials", "pages": [ "tutorials/existing-page", "tutorials/your-new-page" ] } ``` ### Committing Changes Follow these commit guidelines: * Subject line: 50 characters or less, imperative mood * Body: Wrap at 72 characters, explain what and why * No period at end of subject line ```bash theme={"system"} git commit -m "Fix typo in authentication tutorial Corrected the endpoint URL in the Basic Auth example. The previous URL was missing the /wp-json prefix." ``` The repository may have pre-commit hooks for validation. **Never** use `--no-verify` flag. Make small, atomic commits that each address one specific change. ### Submitting Your Contribution 1. **Push your branch to GitHub** ```bash theme={"system"} git push origin fix/improve-authentication-docs ``` 2. **Create a Pull Request** * Go to your fork on GitHub * Click "Compare & pull request" * Fill out the PR template with: * Clear description of your changes * Why the changes are needed * Any related issues 3. **Address review feedback** Maintainers may request changes. Make updates to your branch and push again: ```bash theme={"system"} git add . git commit -m "Address review feedback" git push origin fix/improve-authentication-docs ``` ## Updating docs.json The [docs.json](docs.json) file controls navigation and site configuration. When updating it: ### Navigation Structure The documentation has versioned navigation (stable and pre-release): ```json theme={"system"} { "navigation": { "versions": [ { "version": "stable", "default": true, "anchors": [...] }, { "version": "pre-release", "anchors": [...] } ] } } ``` ### Adding a New Page When you add a new page, include it in the appropriate tab and group: ```json theme={"system"} { "tab": "Tutorials", "groups": [ { "group": "Tutorials", "pages": [ "tutorials/existing-tutorial", "tutorials/your-new-tutorial" ] } ] } ``` Always validate your JSON syntax. Invalid JSON will break the entire documentation site. ### docs.json Schema Refer to the [Mintlify docs.json schema](https://mintlify.com/docs.json) for complete configuration options. ## Testing Your Changes Before submitting a pull request: All links work correctly and use relative paths Code examples have been tested and work as expected Frontmatter is present and correctly formatted No spelling or grammar errors Images have alt text Content follows the writing guidelines Navigation works correctly (if you modified docs.json) Local preview renders correctly ## Content Strategy When contributing content, keep these principles in mind: Document enough for user success - not too much, not too little Prioritize accuracy and usability over comprehensiveness Write content that remains relevant over time when possible Search for existing info before adding new content ## Common Mistakes to Avoid **Do NOT:** * Skip frontmatter on any MDX file * Use absolute URLs for internal links * Include untested code examples * Make assumptions - ask for clarification instead * Use `--no-verify` when committing * Modify changelog files directly (these are maintained by the CoCart team) ## Getting Help Need help with your contribution? * **Questions about content**: Ask in the [#documentation channel](https://cocartapi.com/community/?ref=mintlify) on Discord * **Technical issues with Mintlify**: Check the [Mintlify documentation](https://mintlify.com/docs/introduction) * **Report documentation issues**: Open an issue on [GitHub](https://github.com/cocart-headless/cocart-api-documentation/issues) ## Recognition Contributors are valued members of the CoCart community! Significant contributions may be recognized: * Listed in documentation contributors * Mentioned in release notes * Invited to join the documentation team ## Resources Official Mintlify documentation Learn about MDX syntax Join our Discord community Documentation repository ## What's Next? Ready to contribute? Here are some good starting points: 1. Look for pages tagged with "WIP" (work in progress) that need completion or reviewing before finalization and tagging as "NEW" 2. Check the [GitHub issues](https://github.com/cocart-headless/cocart-api-documentation/issues) for documentation tasks 3. Review recent changes to understand current documentation priorities 4. Start with small improvements like fixing typos before tackling larger contributions Thank you for helping make CoCart documentation better for everyone! # CORS for CoCart Source: https://docs.cocartapi.com/documentation/cors Depending on your setup, you may need to enable CORS to gain access For security reasons, browsers restrict cross-origin HTTP requests initiated from scripts. Only in a local environment does the REST API simulate CORS enabled. If you are getting a warning about the cross origin headers then you will need to set it up. If you simply want to enable but don't want to add any code snippets, you can simply [install CoCart CORS Support](https://wordpress.org/plugins/cocart-cors/) plugin. ## Enable CORS ```php theme={"system"} Each action hook is documented below with its description and usage example. ## Installation Hooks ### `cocart_init` Fires once the CoCart plugin has finished loading. Made available since v3.0.0 **Usage** ```php theme={"system"} add_action( 'cocart_init', function() { // Your code here }); ``` [Search `cocart_init` in repository](https://github.com/co-cart/co-cart/search?q=cocart_init\&type=code) *** ### `cocart_updated` Runs after CoCart has been updated. Made available since v1.2.0 **Usage** ```php theme={"system"} add_action( 'cocart_updated', function() { // Your code here }); ``` [Search `cocart_updated` in repository](https://github.com/co-cart/co-cart/search?q=cocart_updated\&type=code) *** ### `cocart_installed` Runs after CoCart has been installed. Made available since v1.2.0 **Usage** ```php theme={"system"} add_action( 'cocart_installed', function() { // Your code here }); ``` [Search `cocart_installed` in repository](https://github.com/co-cart/co-cart/search?q=cocart_installed\&type=code) *** ## Session Management ### `cocart_after_session_saved_data` Fires after session data is saved. Made available since v4.2.0 **Parameters** Customer ID. Cart data. Cart expiration. Cart source. **Usage** ```php theme={"system"} add_action( 'cocart_after_session_saved_data', function() { // Your code here }, 10 ); ``` [Search `cocart_after_session_saved_data` in repository](https://github.com/co-cart/co-cart/search?q=cocart_after_session_saved_data\&type=code) *** ### `cocart_load_cart_override` Manipulate the overriding cart before it is set in session. Made available since v2.1.0 **Usage** ```php theme={"system"} add_action( 'cocart_load_cart_override', function() { // Your code here }); ``` [Search `cocart_load_cart_override` in repository](https://github.com/co-cart/co-cart/search?q=cocart_load_cart_override\&type=code) *** ### `cocart_load_cart` Manipulate the merged cart before it is set in session. Made available since v2.1.0 **Usage** ```php theme={"system"} add_action( 'cocart_load_cart', function() { // Your code here }); ``` [Search `cocart_load_cart` in repository](https://github.com/co-cart/co-cart/search?q=cocart_load_cart\&type=code) *** ### `cocart_cart_loaded` Fires once a cart has loaded. Can be used to trigger a webhook. Made available since v3.8.0 **Parameters** The cart key. **Usage** ```php theme={"system"} add_action( 'cocart_cart_loaded', function() { // Your code here }, 10 ); ``` [Search `cocart_cart_loaded` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_loaded\&type=code) *** ## Cart Updates ### `cocart_update_cart_before_totals` Fires before the cart has updated via a callback, but before cart totals are re-calculated. Made available since v4.1.0 **Parameters** The request object. The cart controller. **Usage** ```php theme={"system"} add_action( 'cocart_update_cart_before_totals', function() { // Your code here }, 10 ); ``` [Search `cocart_update_cart_before_totals` in repository](https://github.com/co-cart/co-cart/search?q=cocart_update_cart_before_totals\&type=code) *** ### `cocart_update_cart_after_totals` Fires after the cart has updated via a callback and the cart totals are re-calculated. Made available since v4.1.0 **Parameters** The request object. The cart controller. **Usage** ```php theme={"system"} add_action( 'cocart_update_cart_after_totals', function() { // Your code here }, 10 ); ``` [Search `cocart_update_cart_after_totals` in repository](https://github.com/co-cart/co-cart/search?q=cocart_update_cart_after_totals\&type=code) *** ## Cart Items Management ### `cocart_item_added_updated_in_cart` Fires if item was added again to the cart but updated the quantity. Made available since v2.1.0 **Parameters** Item key of the item added again. Item added to cart again. New quantity of the item. **Usage** ```php theme={"system"} add_action( 'cocart_item_added_updated_in_cart', function() { // Your code here }, 10 ); ``` [Search `cocart_item_added_updated_in_cart` in repository](https://github.com/co-cart/co-cart/search?q=cocart_item_added_updated_in_cart\&type=code) *** ### `cocart_item_added_to_cart` Fires once an item has been added to cart. Made available since v2.1.0 **Parameters** Item key of the item added. Item added to cart. **Usage** ```php theme={"system"} add_action( 'cocart_item_added_to_cart', function() { // Your code here }, 10 ); ``` [Search `cocart_item_added_to_cart` in repository](https://github.com/co-cart/co-cart/search?q=cocart_item_added_to_cart\&type=code) *** ### `cocart_item_removed` Fires when an item is removed from the cart. Made available since v2.0.0 **Parameters** The cart item data. **Usage** ```php theme={"system"} add_action( 'cocart_item_removed', function() { // Your code here }, 10 ); ``` [Search `cocart_item_removed` in repository](https://github.com/co-cart/co-cart/search?q=cocart_item_removed\&type=code) *** ### `cocart_item_restored` Fires when an item is restored to the cart. Made available since v2.0.0 **Parameters** The cart item data. **Usage** ```php theme={"system"} add_action( 'cocart_item_restored', function() { // Your code here }, 10 ); ``` [Search `cocart_item_restored` in repository](https://github.com/co-cart/co-cart/search?q=cocart_item_restored\&type=code) *** ### `cocart_item_quantity_changed` Fires when the quantity of an item in the cart is changed. Made available since v2.0.0 **Parameters** Item key. Item data. **Usage** ```php theme={"system"} add_action( 'cocart_item_quantity_changed', function() { // Your code here }, 10 ); ``` [Search `cocart_item_quantity_changed` in repository](https://github.com/co-cart/co-cart/search?q=cocart_item_quantity_changed\&type=code) *** ## Cart Operations ### `cocart_before_cart_emptied` Triggers before the cart is emptied. Made available since v1.0.0 **Usage** ```php theme={"system"} add_action( 'cocart_before_cart_emptied', function() { // Your code here }); ``` [Search `cocart_before_cart_emptied` in repository](https://github.com/co-cart/co-cart/search?q=cocart_before_cart_emptied\&type=code) *** ### `cocart_cart_emptied` Triggers once the cart is emptied. Made available since v1.0.0 **Usage** ```php theme={"system"} add_action( 'cocart_cart_emptied', function() { // Your code here }); ``` [Search `cocart_cart_emptied` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_emptied\&type=code) *** ### `cocart_cart_cleared` Triggers once the cart is cleared. Made available since v1.0.0 **Usage** ```php theme={"system"} add_action( 'cocart_cart_cleared', function() { // Your code here }); ``` [Search `cocart_cart_cleared` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_cleared\&type=code) *** ### `cocart_get_cart` Fires when the cart is retrieved. Made available since v2.0.0 **Parameters** Cart contents. **Usage** ```php theme={"system"} add_action( 'cocart_get_cart', function() { // Your code here }, 10 ); ``` [Search `cocart_get_cart` in repository](https://github.com/co-cart/co-cart/search?q=cocart_get_cart\&type=code) *** ## Extensions ### `cocart_register_extension_callback` Fires when an extension callback is registered. Made available since v3.1.0 **Parameters** Instance of the CoCart\_Cart\_Extension class which exposes the CoCart\_Cart\_Extension::register() method. **Usage** ```php theme={"system"} add_action( 'cocart_register_extension_callback', function() { // Your code here }, 10 ); ``` [Search `cocart_register_extension_callback` in repository](https://github.com/co-cart/co-cart/search?q=cocart_register_extension_callback\&type=code) *** ## Product Reviews ### `cocart_insert_product_review` Fires after a comment is created via the REST API. Made available since v2.0.0 **Parameters** Inserted comment object. The request object. True when creating a comment, false when updating. **Usage** ```php theme={"system"} add_action( 'cocart_insert_product_review', function() { // Your code here }, 10 ); ``` [Search `cocart_insert_product_review` in repository](https://github.com/co-cart/co-cart/search?q=cocart_insert_product_review\&type=code) *** ## Deprecated ### `cocart_update_cart_before_totals` **Deprecated:** 4.1.0 Replaced with `cocart_update_cart_before_totals` hook. Fires after the cart has updated via a callback. Made available since v3.1.0 **Usage** ```php theme={"system"} add_action( 'cocart_update_cart_before_totals', function() { // Your code here }); ``` [Search `cocart_update_cart_before_totals` in repository](https://github.com/co-cart/co-cart/search?q=cocart_update_cart_before_totals\&type=code) *** # Contributing to CoCart Source: https://docs.cocartapi.com/documentation/developers/contributing See the many ways you can contribute to CoCart There are many ways you can contribute to make CoCart better: ## Ways to Contribute Help improve our documentation by fixing errors, adding examples, or writing tutorials Submit fixes, improvements, and enhancements to the CoCart codebase Translate CoCart into your language Help other users by answering questions in our Discord community Test open issues, pull requests, or beta versions and share your findings Report bugs and issues you encounter **Contributing to Documentation?** We have a dedicated guide for documentation contributions. See [Contributing to Documentation](/documentation/contributing-to-docs) for detailed instructions on how to improve our docs. ## Contributing Code If you wish to contribute code to CoCart, please read the information in the sections below. Then [fork](https://help.github.com/articles/fork-a-repo/) the CoCart repository, commit your changes, and [submit a pull request](https://help.github.com/articles/using-pull-requests/). ### License CoCart Core is licensed under the GPLv3+, and all contributions to the project will be released under the same license. You maintain copyright over any contribution you make, and by submitting a pull request, you are agreeing to release that contribution under the GPLv3+ license. ### Getting Help If you have questions about the process to contribute code or want to discuss details of your contribution, you can ask in the #support channel in the [CoCart community Discord](https://cocartapi.com/community/?ref=mintlify) server. ## Getting Started with Development ### Prerequisites Before you begin contributing code: 1. [Setup LocalWP](https://localwp.com/releases/) and create a new WordPress site 2. Install WooCommerce and configure it with: * Dummy products (WooCommerce provides sample data) * Shipping methods * Tax settings 3. Install CoCart and start experimenting with the API ## Coding Guidelines and Development 1. Ensure you stick to the [WordPress Coding Standards](https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/) 2. Ensure you use **LF** line endings in your code editor. Use [EditorConfig](http://editorconfig.org/) if your editor supports it so that indentation, line endings and other settings are auto configured. ### Creating Branches Branch names should go by the following structure (anything in `{}` brackets is a placeholder). **short-slug** should be replaced with a short name that best describes the changes, do ask for confirmation if needed. * `refactor/{short-slug}` for refactors. * `test/{short-slug}` for changes that are only test updates or additions. * `fix/{short-slug}` for changes that fix a bug. Provide the issue number the fix is for and include that in the branch name. * `add/{short-slug}` for changes that are adding a new feature. ### Commits 1. Make sure each commit addresses an atomic unit of work that independently works. 2. Make sure the commit message has a subject line which includes a brief description of the change and (if needed), why it was necessary. Write the subject in the imperative, start with a verb, and do not end with a period. The subject line should be **no longer than 50 characters**. 3. There must be an empty line between the subject line and the rest of the commit message (if any). The commit body should be **no longer than 72 characters**. 4. The commit message should explain what caused the problem and what its consequences are (if helpful for understanding the changes). 5. The commit message should explain how the changes achieve the goal, but only if it isn't obvious. See [this post](https://chris.beams.io/posts/git-commit/) for more on this and follow all the applicable sections of the pull request template. Please avoid modifying the changelog directly or updating the .pot files. These will be updated by the CoCart team. ## Translating CoCart It is recommended to translate CoCart via the [translate.cocartapi.com](https://translate.cocartapi.com/?ref=mintlify). You can join and help by translating there. If any of the CoCart plugins are already **100% translated** for your language, join anyway! The language files are regularly updated with new strings that need translation and will likely be added soon. ## String localization guidelines 1. Use the plugins textdomain in all strings. 2. When using dynamic strings in `printf/sprintf`, if you are replacing more than 1 string, use numbered args. e.g. `Test %s string %s.` would be `Test %1$s string %2$s.` 3. Use sentence case. e.g. `Some Thing` should be `Some thing`. 4. Avoid HTML. If needed, insert the HTML using `sprintf`. For more information, see WP core document [i18n for WordPress Developers](https://codex.wordpress.org/I18n_for_WordPress_Developers). # Filters available in the core of CoCart Source: https://docs.cocartapi.com/documentation/developers/filters These filters let you control how CoCart operates for your store # Authentication & Security This category contains filters for managing authentication, security headers, CORS settings, and access permissions. `cocart_allow_origin` Filter allows you to change the allowed HTTP origin result. Made available since v2.5.1 **Parameters** Origin URL if allowed, empty string if not. **Usage** ```php theme={"system"} add_filter( 'cocart_allow_origin', function() { // Your code here }, 10 ); ``` [Search `cocart_allow_origin` in repository](https://github.com/co-cart/co-cart/search?q=cocart_allow_origin\&type=code) *** `cocart_auth_header` Filter allows you to change the authorization header. Made available since v4.1.0 **Parameters** Authorization header. **Usage** ```php theme={"system"} add_filter( 'cocart_auth_header', function() { // Your code here }, 10 ); ``` [Search `cocart_auth_header` in repository](https://github.com/co-cart/co-cart/search?q=cocart_auth_header\&type=code) *** `cocart_disable_all_cors` Modifies if the "Cross Origin Headers" are allowed. Set as false to enable support. Made available since v2.2.0 **Usage** ```php theme={"system"} add_filter( 'cocart_disable_all_cors', function() { // Your code here }); ``` [Search `cocart_disable_all_cors` in repository](https://github.com/co-cart/co-cart/search?q=cocart_disable_all_cors\&type=code) *** `cocart_install_capability` Filter the current users capabilities to install a CoCart plugin. Made available since v4.1.0 **Parameters** Capability level. **Usage** ```php theme={"system"} add_filter( 'cocart_install_capability', function() { // Your code here }, 10 ); ``` [Search `cocart_install_capability` in repository](https://github.com/co-cart/co-cart/search?q=cocart_install_capability\&type=code) *** `cocart_login_extras` Filter allows you to add extra information based on the current user. Made available since v3.8.1 **Parameters** The extra information. The current user. **Usage** ```php theme={"system"} add_filter( 'cocart_login_extras', function() { // Your code here }, 10 ); ``` [Search `cocart_login_extras` in repository](https://github.com/co-cart/co-cart/search?q=cocart_login_extras\&type=code) *** `cocart_send_nocache_headers` Send nocache headers on authenticated requests. Made available since v4.2.0 **Deprecated:** 4.3.11 No longer used. See `cocart_send_cache_control_patterns` filter instead to control which routes are not cached. **Parameters** Whether to send no-cache headers. **Usage** ```php theme={"system"} add_filter( 'cocart_send_nocache_headers', function() { // Your code here }, 10 ); ``` [Search `cocart_send_nocache_headers` in repository](https://github.com/co-cart/co-cart/search?q=cocart_send_nocache_headers\&type=code) *** # Cart Management & State This category contains filters for managing cart state, expiration, merging, and overall cart behavior. `cocart_cart_cleared_message` Filters message about the cart being cleared. Made available since v2.1.0 **Parameters** Message. **Usage** ```php theme={"system"} add_filter( 'cocart_cart_cleared_message', function() { // Your code here }, 10 ); ``` [Search `cocart_cart_cleared_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_cleared_message\&type=code) *** `cocart_cart_contents` Filter allows additional data to be returned for a specific item in cart. Made available since v2.0.0 **Parameters** Cart contents. Item key. Cart item. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_cart_contents', function() { // Your code here }, 10 ); ``` [Search `cocart_cart_contents` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_contents\&type=code) *** `cocart_cart_expiration` Filter allows you to change the amount of time before the cart has expired. Default is `(DAY_IN_SECONDS * 2)` = 2 Days - Previously 7 days. Made available since v2.1.0 **Parameters** Expiration. If user is logged in. **@since v4.4.0** **Usage** ```php theme={"system"} add_filter( 'cocart_cart_expiration', function( $expiration, $is_user_logged_in ) { // Extend cart expiration for logged-in users to 14 days. if ( $is_user_logged_in ) { return WEEK_IN_SECONDS * 2; } // Fallback to 2 days for guest users. return $expiration; }, 10, 2 ); ``` [Search `cocart_cart_expiration` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_expiration\&type=code) *** `cocart_cart_expiring` Filter allows you to change the amount of time before the cart starts to expire. Default is \`\`\`(DAY\_IN\_SECONDS \* 6)\`\` = 6 Days Made available since v2.1.0 **Usage** ```php theme={"system"} add_filter( 'cocart_cart_expiring', function() { // Your code here }); ``` [Search `cocart_cart_expiring` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_expiring\&type=code) *** `cocart_cart_items` Filter allows additional data to be returned for a specific item in cart. Made available since v2.1.0 **Parameters** Array of items in the cart. The item key currently looped. The cart item data. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_cart_items', function() { // Your code here }, 10 ); ``` [Search `cocart_cart_items` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_items\&type=code) *** `cocart_cart_source` Filter source of cart. Made available since v3.0.0 **Usage** ```php theme={"system"} add_filter( 'cocart_cart_source', function() { // Your code here }); ``` [Search `cocart_cart_source` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_source\&type=code) *** `cocart_clear_cart_failed_message` Filters message about the cart failing to clear. Made available since v2.1.0 **Parameters** Message. **Usage** ```php theme={"system"} add_filter( 'cocart_clear_cart_failed_message', function() { // Your code here }, 10 ); ``` [Search `cocart_clear_cart_failed_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_clear_cart_failed_message\&type=code) *** `cocart_cross_sells` Filters the cross sell items. Made available since v3.0.0 **Parameters** The request object. **Usage** ```php theme={"system"} add_filter( 'cocart_cross_sells', function() { // Your code here }, 10 ); ``` [Search `cocart_cross_sells` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cross_sells\&type=code) *** `cocart_empty_cart` Filter response for empty cart. Made available since v3.0.0 **Usage** ```php theme={"system"} add_filter( 'cocart_empty_cart', function() { // Your code here }); ``` [Search `cocart_empty_cart` in repository](https://github.com/co-cart/co-cart/search?q=cocart_empty_cart\&type=code) *** `cocart_filter_request_data` Filters additional requested data. Made available since v3.0.0 **Usage** ```php theme={"system"} add_filter( 'cocart_filter_request_data', function() { // Your code here }); ``` [Search `cocart_filter_request_data` in repository](https://github.com/co-cart/co-cart/search?q=cocart_filter_request_data\&type=code) *** `cocart_get_cart_item` Filters the cart item before it is returned. Made available since v3.0.0 **Parameters** Details of the item in the cart if it exists. Condition of item. Default: "add", Option: "add", "remove", "restore", "update". **Usage** ```php theme={"system"} add_filter( 'cocart_get_cart_item', function() { // Your code here }, 10 ); ``` [Search `cocart_get_cart_item` in repository](https://github.com/co-cart/co-cart/search?q=cocart_get_cart_item\&type=code) *** `cocart_merge_cart_content` Filter allows you to adjust the merged cart contents. Made available since v2.1.0 **Usage** ```php theme={"system"} add_filter( 'cocart_merge_cart_content', function() { // Your code here }); ``` [Search `cocart_merge_cart_content` in repository](https://github.com/co-cart/co-cart/search?q=cocart_merge_cart_content\&type=code) *** `cocart_return_cart_contents` Return cart content from session if set. Made available since v2.1.0 **Usage** ```php theme={"system"} add_filter( 'cocart_return_cart_contents', function() { // Your code here }); ``` [Search `cocart_return_cart_contents` in repository](https://github.com/co-cart/co-cart/search?q=cocart_return_cart_contents\&type=code) *** `cocart_return_cart_session_contents` Return cart content from session if set. Made available since v2.1.0 **Usage** ```php theme={"system"} add_filter( 'cocart_return_cart_session_contents', function() { // Your code here }); ``` [Search `cocart_return_cart_session_contents` in repository](https://github.com/co-cart/co-cart/search?q=cocart_return_cart_session_contents\&type=code) *** `cocart_return_empty_cart` Filter response for empty cart. Made available since v2.0.8 **Usage** ```php theme={"system"} add_filter( 'cocart_return_empty_cart', function() { // Your code here }); ``` [Search `cocart_return_empty_cart` in repository](https://github.com/co-cart/co-cart/search?q=cocart_return_empty_cart\&type=code) *** # Cart Items & Operations This category contains filters for cart item data, operations like adding/removing items, and item-specific messages. `cocart_can_not_remove_item_message` Filters message about can not remove item. Made available since v2.1.0 **Parameters** Message. **Usage** ```php theme={"system"} add_filter( 'cocart_can_not_remove_item_message', function() { // Your code here }, 10 ); ``` [Search `cocart_can_not_remove_item_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_can_not_remove_item_message\&type=code) *** `cocart_can_not_restore_item_message` Filters message about can not restore item. Made available since v2.1.0 **Parameters** Message. **Usage** ```php theme={"system"} add_filter( 'cocart_can_not_restore_item_message', function() { // Your code here }, 10 ); ``` [Search `cocart_can_not_restore_item_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_can_not_restore_item_message\&type=code) *** `cocart_cart_item_data` Filter allows you to alter the remaining cart item data. Made available since v3.0.0 **Parameters** The cart item data. Generated ID based on the product information when added to the cart. **Usage** ```php theme={"system"} add_filter( 'cocart_cart_item_data', function() { // Your code here }, 10 ); ``` [Search `cocart_cart_item_data` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_item_data\&type=code) *** `cocart_cart_item_key_required_message` Filters message about cart item key required. Made available since v2.1.0 **Parameters** Message. Status of which we are checking the item key. **Usage** ```php theme={"system"} add_filter( 'cocart_cart_item_key_required_message', function() { // Your code here }, 10 ); ``` [Search `cocart_cart_item_key_required_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_item_key_required_message\&type=code) *** `cocart_cart_item_name` Filter allows the product name of the item to change. Made available since v3.0.0 **Parameters** Product name. The product object. The cart item data. The item key generated based on the details of the item. **Usage** ```php theme={"system"} add_filter( 'cocart_cart_item_name', function() { // Your code here }, 10 ); ``` [Search `cocart_cart_item_name` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_item_name\&type=code) *** `cocart_cart_item_removed_message` Filter message about item removed from the cart. Made available since v2.1.0 **Parameters** Message. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_cart_item_removed_message', function() { // Your code here }, 10 ); ``` [Search `cocart_cart_item_removed_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_item_removed_message\&type=code) *** `cocart_cart_item_restored_message` Filters message about item restored. Made available since v2.1.0 **Parameters** Message. **Usage** ```php theme={"system"} add_filter( 'cocart_cart_item_restored_message', function() { // Your code here }, 10 ); ``` [Search `cocart_cart_item_restored_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_item_restored_message\&type=code) *** `cocart_cart_item_restored_title` Re-calculate totals now an item has been restored. Made available since v2.1.0 **Usage** ```php theme={"system"} add_filter( 'cocart_cart_item_restored_title', function() { // Your code here }); ``` [Search `cocart_cart_item_restored_title` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_item_restored_title\&type=code) *** `cocart_cart_item_title` Filter allows the product title of the item to change. Made available since v3.0.0 **Parameters** Product title. The product object. The cart item data. The item key generated based on the details of the item. **Usage** ```php theme={"system"} add_filter( 'cocart_cart_item_title', function() { // Your code here }, 10 ); ``` [Search `cocart_cart_item_title` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_item_title\&type=code) *** `cocart_item_added` Filter allows additional data to be returned. Made available since v2.0.0 **Parameters** Item added to cart. Item key of the item added. **Usage** ```php theme={"system"} add_filter( 'cocart_item_added', function() { // Your code here }, 10 ); ``` [Search `cocart_item_added` in repository](https://github.com/co-cart/co-cart/search?q=cocart_item_added\&type=code) *** `cocart_item_product` Filter allows you to alter the item product data returned. Made available since v2.0.0 **Parameters** The product object. The cart item data. The item key currently looped. **Usage** ```php theme={"system"} add_filter( 'cocart_item_product', function() { // Your code here }, 10 ); ``` [Search `cocart_item_product` in repository](https://github.com/co-cart/co-cart/search?q=cocart_item_product\&type=code) *** `cocart_item_removed_message` Filters message about item removed from cart. Made available since v2.1.0 **Parameters** Message. **Usage** ```php theme={"system"} add_filter( 'cocart_item_removed_message', function() { // Your code here }, 10 ); ``` [Search `cocart_item_removed_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_item_removed_message\&type=code) *** `cocart_item_restored_message` Filters message about item already restored to cart. Made available since v2.1.0 **Parameters** Message. **Usage** ```php theme={"system"} add_filter( 'cocart_item_restored_message', function() { // Your code here }, 10 ); ``` [Search `cocart_item_restored_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_item_restored_message\&type=code) *** `cocart_item_thumbnail` Filters the item thumbnail ID. Made available since v2.0.0 **Parameters** Product thumbnail ID. Cart item. Item key. **Usage** ```php theme={"system"} add_filter( 'cocart_item_thumbnail', function() { // Your code here }, 10 ); ``` [Search `cocart_item_thumbnail` in repository](https://github.com/co-cart/co-cart/search?q=cocart_item_thumbnail\&type=code) *** `cocart_item_thumbnail_size` Filters the thumbnail size of the product image. Made available since v2.0.0 **Parameters** Determines if the item in the cart is removed. **Usage** ```php theme={"system"} add_filter( 'cocart_item_thumbnail_size', function() { // Your code here }, 10 ); ``` [Search `cocart_item_thumbnail_size` in repository](https://github.com/co-cart/co-cart/search?q=cocart_item_thumbnail_size\&type=code) *** `cocart_item_thumbnail_src` Filters the source of the product thumbnail. Made available since v2.1.0 **Parameters** URL of the product thumbnail. Cart item. Item key. **Usage** ```php theme={"system"} add_filter( 'cocart_item_thumbnail_src', function() { // Your code here }, 10 ); ``` [Search `cocart_item_thumbnail_src` in repository](https://github.com/co-cart/co-cart/search?q=cocart_item_thumbnail_src\&type=code) *** `cocart_update_cart_validation` Filter allows you to determine if the updated item in cart passed validation. Made available since v2.1.0 **Parameters** True by default. Item key. Product data of the item in cart. The requested quantity to change to. **Usage** ```php theme={"system"} add_filter( 'cocart_update_cart_validation', function() { // Your code here }, 10 ); ``` [Search `cocart_update_cart_validation` in repository](https://github.com/co-cart/co-cart/search?q=cocart_update_cart_validation\&type=code) *** `cocart_update_item` Filters the update status. Made available since v2.0.1 **Parameters** Status response. Cart item. Quantity. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_update_item', function() { // Your code here }, 10 ); ``` [Search `cocart_update_item` in repository](https://github.com/co-cart/co-cart/search?q=cocart_update_item\&type=code) *** # Product Validation & Messages This category contains filters for product validation, stock checking, quantity limits, and related error messages. `cocart_add_to_cart_quantity` Filters the quantity for specified products. Made available since v2.1.0 **Parameters** The original quantity of the item. The product ID. The variation ID. The variation data. The cart item data. **Usage** ```php theme={"system"} add_filter( 'cocart_add_to_cart_quantity', function() { // Your code here }, 10 ); ``` [Search `cocart_add_to_cart_quantity` in repository](https://github.com/co-cart/co-cart/search?q=cocart_add_to_cart_quantity\&type=code) *** `cocart_add_to_cart_sold_individually_found_in_cart` Quantity for sold individual products can be filtered. Made available since v2.0.13 **Usage** ```php theme={"system"} add_filter( 'cocart_add_to_cart_sold_individually_found_in_cart', function() { // Your code here }); ``` [Search `cocart_add_to_cart_sold_individually_found_in_cart` in repository](https://github.com/co-cart/co-cart/search?q=cocart_add_to_cart_sold_individually_found_in_cart\&type=code) *** `cocart_add_to_cart_sold_individually_quantity` Quantity for sold individual products can be filtered. Made available since v2.0.13 **Usage** ```php theme={"system"} add_filter( 'cocart_add_to_cart_sold_individually_quantity', function() { // Your code here }); ``` [Search `cocart_add_to_cart_sold_individually_quantity` in repository](https://github.com/co-cart/co-cart/search?q=cocart_add_to_cart_sold_individually_quantity\&type=code) *** `cocart_can_not_increase_quantity_message` Filters message about product not being allowed to increase quantity. Made available since v1.0.0 **Parameters** Message. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_can_not_increase_quantity_message', function() { // Your code here }, 10 ); ``` [Search `cocart_can_not_increase_quantity_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_can_not_increase_quantity_message\&type=code) *** `cocart_can_not_update_item_message` Filters message about can not update item. Made available since v2.1.0 **Parameters** Message. **Usage** ```php theme={"system"} add_filter( 'cocart_can_not_update_item_message', function() { // Your code here }, 10 ); ``` [Search `cocart_can_not_update_item_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_can_not_update_item_message\&type=code) *** `cocart_cannot_add_product_type_to_cart_message` Filters message about product type that cannot be added to the cart. Made available since v2.1.0 **Parameters** Message. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_cannot_add_product_type_to_cart_message', function() { // Your code here }, 10 ); ``` [Search `cocart_cannot_add_product_type_to_cart_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cannot_add_product_type_to_cart_message\&type=code) *** `cocart_cart_item_required_stock_is_not_enough` Allows filter if product have enough stock to get added to the cart. Made available since v2.1.0 **Parameters** If have enough stock. The product object. Cart item values. **Usage** ```php theme={"system"} add_filter( 'cocart_cart_item_required_stock_is_not_enough', function() { // Your code here }, 10 ); ``` [Search `cocart_cart_item_required_stock_is_not_enough` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_item_required_stock_is_not_enough\&type=code) *** `cocart_invalid_variation_data_message` Filters message about invalid variation data. Made available since v2.1.0 **Parameters** Message. Attribute Label. Allowed values. **Usage** ```php theme={"system"} add_filter( 'cocart_invalid_variation_data_message', function() { // Your code here }, 10 ); ``` [Search `cocart_invalid_variation_data_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_invalid_variation_data_message\&type=code) *** `cocart_missing_variation_data_message` Filters message about missing variation data. Made available since v2.1.0 **Parameters** Message. Number of missing attributes. List of missing attributes. **Usage** ```php theme={"system"} add_filter( 'cocart_missing_variation_data_message', function() { // Your code here }, 10 ); ``` [Search `cocart_missing_variation_data_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_missing_variation_data_message\&type=code) *** `cocart_product_can_not_add_another_message` Filters message about product not being allowed to add another. Made available since v3.0.0 **Parameters** Message. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_product_can_not_add_another_message', function() { // Your code here }, 10 ); ``` [Search `cocart_product_can_not_add_another_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_product_can_not_add_another_message\&type=code) *** `cocart_product_cannot_add_to_cart_message` Filters message about product cannot be added to cart. Made available since v2.1.0 **Parameters** Message. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_product_cannot_add_to_cart_message', function() { // Your code here }, 10 ); ``` [Search `cocart_product_cannot_add_to_cart_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_product_cannot_add_to_cart_message\&type=code) *** `cocart_product_cannot_be_added_message` Filters message about product that cannot be added to cart. Made available since v3.0.0 **Parameters** Message. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_product_cannot_be_added_message', function() { // Your code here }, 10 ); ``` [Search `cocart_product_cannot_be_added_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_product_cannot_be_added_message\&type=code) *** `cocart_product_cannot_be_purchased_message` Filters message about product unable to be purchased. Made available since v2.1.0 **Parameters** Message. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_product_cannot_be_purchased_message', function() { // Your code here }, 10 ); ``` [Search `cocart_product_cannot_be_purchased_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_product_cannot_be_purchased_message\&type=code) *** `cocart_product_does_not_exist_message` Filters message about product does not exist. Made available since v2.1.0 **Parameters** Message. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_product_does_not_exist_message', function() { // Your code here }, 10 ); ``` [Search `cocart_product_does_not_exist_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_product_does_not_exist_message\&type=code) *** `cocart_product_failed_validation_message` Filters message about product failing validation. Made available since v1.0.0 **Parameters** Message. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_product_failed_validation_message', function() { // Your code here }, 10 ); ``` [Search `cocart_product_failed_validation_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_product_failed_validation_message\&type=code) *** `cocart_product_is_out_of_stock_message` Filters message about product is out of stock. Made available since v2.1.0 **Parameters** Message. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_product_is_out_of_stock_message', function() { // Your code here }, 10 ); ``` [Search `cocart_product_is_out_of_stock_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_product_is_out_of_stock_message\&type=code) *** `cocart_product_not_enough_stock_message` Filters message about product not having enough stock. Made available since v3.1.0 **Parameters** Message. The product object. Quantity remaining. **Usage** ```php theme={"system"} add_filter( 'cocart_product_not_enough_stock_message', function() { // Your code here }, 10 ); ``` [Search `cocart_product_not_enough_stock_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_product_not_enough_stock_message\&type=code) *** `cocart_quantity_maximum_allowed` Filters the products maximum quantity allowed to be purchased. Made available since v3.1.0 **Usage** ```php theme={"system"} add_filter( 'cocart_quantity_maximum_allowed', function() { // Your code here }); ``` [Search `cocart_quantity_maximum_allowed` in repository](https://github.com/co-cart/co-cart/search?q=cocart_quantity_maximum_allowed\&type=code) *** `cocart_quantity_minimum_requirement` Filters the minimum quantity requirement the product allows to be purchased. Made available since v3.1.0 **Usage** ```php theme={"system"} add_filter( 'cocart_quantity_minimum_requirement', function() { // Your code here }); ``` [Search `cocart_quantity_minimum_requirement` in repository](https://github.com/co-cart/co-cart/search?q=cocart_quantity_minimum_requirement\&type=code) *** `cocart_skip_woocommerce_item_validation` Filter the item to skip product validation as it is added to cart. Made available since v3.0.0 **Parameters** Whether to validate the product or not. Contains the product data of the product to add to cart. The product ID. **Usage** ```php theme={"system"} add_filter( 'cocart_skip_woocommerce_item_validation', function() { // Your code here }, 10 ); ``` [Search `cocart_skip_woocommerce_item_validation` in repository](https://github.com/co-cart/co-cart/search?q=cocart_skip_woocommerce_item_validation\&type=code) *** # Session & Customer Management This category contains filters for session handling, customer data, and cart loading behavior. `cocart_disable_load_cart` Filter checks if **Load Cart** feature is disabled. Made available since v3.0.0 **Returns**: `bool` **Usage** ```php theme={"system"} add_filter( 'cocart_disable_load_cart', function() { // Your code here }); ``` [Search `cocart_disable_load_cart` in repository](https://github.com/co-cart/co-cart/search?q=cocart_disable_load_cart\&type=code) *** `cocart_load_cart_query_name` Filter allows developers to add more white labelling when loading the cart via web. Made available since v2.8.2 **Parameters** Default is 'cocart-load-cart'. **Usage** ```php theme={"system"} add_filter( 'cocart_load_cart_query_name', function() { // Your code here }, 10 ); ``` [Search `cocart_load_cart_query_name` in repository](https://github.com/co-cart/co-cart/search?q=cocart_load_cart_query_name\&type=code) *** `cocart_requested_cart_key` Filter allows the cart key to be overridden. Developer Note: Really only here so I don't have to create a new session handler to inject a customer ID with the POS Support Add-on. Made available since v4.2.0 **Usage** ```php theme={"system"} add_filter( 'cocart_requested_cart_key', function() { // Your code here }); ``` [Search `cocart_requested_cart_key` in repository](https://github.com/co-cart/co-cart/search?q=cocart_requested_cart_key\&type=code) *** `cocart_set_customer_id` Filter allows to set the customer ID. Made available since v4.1.0 **Parameters** Current user ID. **Usage** ```php theme={"system"} add_filter( 'cocart_set_customer_id', function() { // Your code here }, 10 ); ``` [Search `cocart_set_customer_id` in repository](https://github.com/co-cart/co-cart/search?q=cocart_set_customer_id\&type=code) *** # Product Data & Display This category contains filters for product information display, pricing, metadata, and attributes. `cocart_prepare_money_disable_decimals` This filter allows you to disable the decimals. If set to "True" the decimals will be set to "Zero". Made available since v2.1.0 **Usage** ```php theme={"system"} add_filter( 'cocart_prepare_money_disable_decimals', function() { // Your code here }); ``` [Search `cocart_prepare_money_disable_decimals` in repository](https://github.com/co-cart/co-cart/search?q=cocart_prepare_money_disable_decimals\&type=code) *** `cocart_prepare_product_attribute` Filter a attribute item returned from the API. Allows modification of the product attribute data right before it is returned. Made available since v2.1.0 **Parameters** The response object. The original attribute object. The request object. **Usage** ```php theme={"system"} add_filter( 'cocart_prepare_product_attribute', function() { // Your code here }, 10 ); ``` [Search `cocart_prepare_product_attribute` in repository](https://github.com/co-cart/co-cart/search?q=cocart_prepare_product_attribute\&type=code) *** `cocart_prepare_product_object` Filter the data for a response. Made available since v2.1.0 **Parameters** The response object. The product object. The request object. **Usage** ```php theme={"system"} add_filter( 'cocart_prepare_product_object', function() { // Your code here }, 10 ); ``` [Search `cocart_prepare_product_object` in repository](https://github.com/co-cart/co-cart/search?q=cocart_prepare_product_object\&type=code) *** `cocart_price_no_html` Filters the string of price markup. Made available since v2.1.0 **Parameters** Price HTML markup. Formatted price. Pass on the args. Price as float to allow plugins custom formatting. Since 3.2.0. Original price as float, or empty string. Since 5.0.0. **Usage** ```php theme={"system"} add_filter( 'cocart_price_no_html', function() { // Your code here }, 10 ); ``` [Search `cocart_price_no_html` in repository](https://github.com/co-cart/co-cart/search?q=cocart_price_no_html\&type=code) *** `cocart_product_title` Filters the product title in cart. Made available since v2.1.0 **Parameters** Product title. The product object. Cart item. Item key. **Usage** ```php theme={"system"} add_filter( 'cocart_product_title', function() { // Your code here }, 10 ); ``` [Search `cocart_product_title` in repository](https://github.com/co-cart/co-cart/search?q=cocart_product_title\&type=code) *** `cocart_products_add_to_cart_rest_url` Filters the REST URL shortcut for adding the product to cart. Made available since v3.1.0 **Parameters** REST URL for adding product to the cart. The product object. Product type. Product ID. **Usage** ```php theme={"system"} add_filter( 'cocart_products_add_to_cart_rest_url', function() { // Your code here }, 10 ); ``` [Search `cocart_products_add_to_cart_rest_url` in repository](https://github.com/co-cart/co-cart/search?q=cocart_products_add_to_cart_rest_url\&type=code) *** `cocart_products_get_price_range` Filters the products price range. Made available since v3.1.0 **Parameters** The current product price range. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_products_get_price_range', function() { // Your code here }, 10 ); ``` [Search `cocart_products_get_price_range` in repository](https://github.com/co-cart/co-cart/search?q=cocart_products_get_price_range\&type=code) *** `cocart_products_get_safe_meta_data` Filter allows you to control what remaining product meta data is safe to return. Made available since v3.11.0 **Parameters** Safe meta. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_products_get_safe_meta_data', function() { // Your code here }, 10 ); ``` [Search `cocart_products_get_safe_meta_data` in repository](https://github.com/co-cart/co-cart/search?q=cocart_products_get_safe_meta_data\&type=code) *** `cocart_products_ignore_private_meta_keys` Filter allows you to ignore private meta data for the product to return. When filtering, only list the meta key! Made available since v3.11.0 **Parameters** Ignored meta keys. The product object. **Usage** ```php theme={"system"} add_filter( 'cocart_products_ignore_private_meta_keys', function() { // Your code here }, 10 ); ``` [Search `cocart_products_ignore_private_meta_keys` in repository](https://github.com/co-cart/co-cart/search?q=cocart_products_ignore_private_meta_keys\&type=code) *** `cocart_products_variable_empty_price` Filter the variable products empty prices. Made available since v3.1.0 **Parameters** Empty array. The project object. **Usage** ```php theme={"system"} add_filter( 'cocart_products_variable_empty_price', function() { // Your code here }, 10 ); ``` [Search `cocart_products_variable_empty_price` in repository](https://github.com/co-cart/co-cart/search?q=cocart_products_variable_empty_price\&type=code) *** # System Environment & Status This category contains filters for system environment detection, staging sites, and general status information. `cocart_does_product_allow_price_change` Filter which products that can be allowed to override the price if not all. Made available since v4.1.0 **Parameters** Allow price change. Cart item. The request object. **Usage** ```php theme={"system"} add_filter( 'cocart_does_product_allow_price_change', function() { // Your code here }, 10 ); ``` [Search `cocart_does_product_allow_price_change` in repository](https://github.com/co-cart/co-cart/search?q=cocart_does_product_allow_price_change\&type=code) *** `cocart_is_rest_api_request` Filters the REST API requested. Made available since v2.1.0 **Parameters** True if CoCart REST API is requested. **Usage** ```php theme={"system"} add_filter( 'cocart_is_rest_api_request', function() { // Your code here }, 10 ); ``` [Search `cocart_is_rest_api_request` in repository](https://github.com/co-cart/co-cart/search?q=cocart_is_rest_api_request\&type=code) *** `cocart_return_default_response` **See Also:** * `cocart_{$endpoint}_response` Filter decides if the responses return as default or use the modified response which is filtered by the rest base. Made available since v3.0.0 **Usage** ```php theme={"system"} add_filter( 'cocart_return_default_response', function() { // Your code here }); ``` [Search `cocart_return_default_response` in repository](https://github.com/co-cart/co-cart/search?q=cocart_return_default_response\&type=code) *** `cocart_totals_calculated_message` Filters message about cart totals have been calculated. Made available since v2.1.0 **Parameters** Message. **Usage** ```php theme={"system"} add_filter( 'cocart_totals_calculated_message', function() { // Your code here }, 10 ); ``` [Search `cocart_totals_calculated_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_totals_calculated_message\&type=code) *** # Admin & Plugin Management This category contains filters for plugin administration, updates, submenus, and overall plugin configuration. `cocart_enable_setup_wizard` See if we need the setup wizard or not. Made available since v3.1.0 **Usage** ```php theme={"system"} add_filter( 'cocart_enable_setup_wizard', function() { // Your code here }); ``` [Search `cocart_enable_setup_wizard` in repository](https://github.com/co-cart/co-cart/search?q=cocart_enable_setup_wizard\&type=code) *** `cocart_get_plugins_for_cocart` Filter allows you to get plugins which "maybe" are for CoCart. Made available since v4.3.0 **Parameters** Array of plugins that "maybe" are for CoCart. Array of plugins installed. **Usage** ```php theme={"system"} add_filter( 'cocart_get_plugins_for_cocart', function() { // Your code here }, 10 ); ``` [Search `cocart_get_plugins_for_cocart` in repository](https://github.com/co-cart/co-cart/search?q=cocart_get_plugins_for_cocart\&type=code) *** `cocart_get_plugins_with_header` Filter allows you to get the plugins that have a valid value for a specific header. Made available since v4.3.0 **Parameters** Array of plugins matched with header. Plugin header to search for. Array of plugins installed. **Usage** ```php theme={"system"} add_filter( 'cocart_get_plugins_with_header', function() { // Your code here }, 10 ); ``` [Search `cocart_get_plugins_with_header` in repository](https://github.com/co-cart/co-cart/search?q=cocart_get_plugins_with_header\&type=code) *** `cocart_in_plugin_update_message` Filter allows you to change the upgrade notice. Made available since v4.3.0 **Usage** ```php theme={"system"} add_filter( 'cocart_in_plugin_update_message', function() { // Your code here }); ``` [Search `cocart_in_plugin_update_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_in_plugin_update_message\&type=code) *** `cocart_register_submenu_page` Hook to register submenu\_pages class handlers The array element should be 'submenu\_page\_slug' => array( 'class\_name' => array(), 'data' => array() ) Made available since v3.10.0 **Parameters** Array of submenu pages. **Usage** ```php theme={"system"} add_filter( 'cocart_register_submenu_page', function() { // Your code here }, 10 ); ``` [Search `cocart_register_submenu_page` in repository](https://github.com/co-cart/co-cart/search?q=cocart_register_submenu_page\&type=code) *** `cocart_show_plugin_search` Filter if **CoCart Plugin Suggestions** should be active. Made available since v4.1.0 **Parameters** True if CoCart Plugin Suggestions is active. **Usage** ```php theme={"system"} add_filter( 'cocart_show_plugin_search', function() { return false; }); ``` [Search `cocart_show_plugin_search` in repository](https://github.com/co-cart/co-cart/search?q=cocart_show_plugin_search\&type=code) *** # API Schema & Parameters This category contains filters that control API schema definitions, query parameters, and how data is structured in API responses. `cocart_add_item_query_parameters` Filters the query parameters for adding item to cart. This filter allows you to extend the query parameters without removing any default parameters. Made available since v3.1.0 **Usage** ```php theme={"system"} add_filter( 'cocart_add_item_query_parameters', function() { // Your code here }); ``` [Search `cocart_add_item_query_parameters` in repository](https://github.com/co-cart/co-cart/search?q=cocart_add_item_query_parameters\&type=code) *** `cocart_add_items_query_parameters` Extends the query parameters. Dev Note: Nothing needs to pass so your safe if you think you will remove any default parameters. Made available since v3.1.0 **Usage** ```php theme={"system"} add_filter( 'cocart_add_items_query_parameters', function() { // Your code here }); ``` [Search `cocart_add_items_query_parameters` in repository](https://github.com/co-cart/co-cart/search?q=cocart_add_items_query_parameters\&type=code) *** `cocart_cart_items_schema` Extend the cart schema properties for items. This filter allows you to extend the cart schema properties for items without removing any default properties. Made available since v3.1.0 **Usage** ```php theme={"system"} add_filter( 'cocart_cart_items_schema', function() { // Your code here }); ``` [Search `cocart_cart_items_schema` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_items_schema\&type=code) *** `cocart_cart_query_parameters` Extend the query parameters for the cart. This filter allows you to extend the query parameters without removing any default parameters. Made available since v3.1.0 **Usage** ```php theme={"system"} add_filter( 'cocart_cart_query_parameters', function() { // Your code here }); ``` [Search `cocart_cart_query_parameters` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_query_parameters\&type=code) *** `cocart_prevent_wc_admin_note_created` Filter to prevent note from being created. Made available since v3.2.0 **Parameters** False by default. Arguments to create the note. **Usage** ```php theme={"system"} add_filter( 'cocart_prevent_wc_admin_note_created', function() { // Your code here }, 10 ); ``` [Search `cocart_prevent_wc_admin_note_created` in repository](https://github.com/co-cart/co-cart/search?q=cocart_prevent_wc_admin_note_created\&type=code) *** `cocart_store_index` Filters the API store index data. This contains the data describing the API. This includes information about the store, routes available on the API, and a small amount of data about the site. Made available since v2.1.0 **Parameters** Response data. **Usage** ```php theme={"system"} add_filter( 'cocart_store_index', function() { // Your code here }, 10 ); ``` [Search `cocart_store_index` in repository](https://github.com/co-cart/co-cart/search?q=cocart_store_index\&type=code) *** # Product Reviews This category contains filters for managing product reviews, their processing, and related queries. `cocart_pre_insert_product_review` Filters a review before it is inserted via the REST API. Allows modification of the review right before it is inserted via `wp_insert_comment()`. Returning a *WP\_Error* value from the filter will short circuit insertion and allow skipping further processing. Made available since v2.1.0 **Parameters** The prepared review data for `wp_insert_comment()`. Full details about the request. **Usage** ```php theme={"system"} add_filter( 'cocart_pre_insert_product_review', function() { // Your code here }, 10 ); ``` [Search `cocart_pre_insert_product_review` in repository](https://github.com/co-cart/co-cart/search?q=cocart_pre_insert_product_review\&type=code) *** `cocart_prepare_product_review` Filter product reviews object returned from the REST API. Made available since v2.1.0 **Parameters** The response object. Product review object used to create response. The request object. **Usage** ```php theme={"system"} add_filter( 'cocart_prepare_product_review', function() { // Your code here }, 10 ); ``` [Search `cocart_prepare_product_review` in repository](https://github.com/co-cart/co-cart/search?q=cocart_prepare_product_review\&type=code) *** `cocart_preprocess_product_review` Filters a review after it is prepared for the database. Allows modification of the review right after it is prepared for the database. Made available since v2.1.0 **Parameters** The prepared review data for `wp_insert_comment`. The request object. **Usage** ```php theme={"system"} add_filter( 'cocart_preprocess_product_review', function() { // Your code here }, 10 ); ``` [Search `cocart_preprocess_product_review` in repository](https://github.com/co-cart/co-cart/search?q=cocart_preprocess_product_review\&type=code) *** `cocart_product_review_collection_params` Filter collection parameters for the reviews controller. This filter registers the collection parameter, but does not map the collection parameter to an internal *WP\_Comment\_Query* parameter. Use the `cocart_product_review_query` filter to set *WP\_Comment\_Query* parameters. Made available since v2.1.0 **Parameters** JSON Schema-formatted collection parameters. **Usage** ```php theme={"system"} add_filter( 'cocart_product_review_collection_params', function() { // Your code here }, 10 ); ``` [Search `cocart_product_review_collection_params` in repository](https://github.com/co-cart/co-cart/search?q=cocart_product_review_collection_params\&type=code) *** `cocart_product_review_query` Filters arguments, before passing to WP\_Comment\_Query, when querying reviews via the REST API. Made available since v2.1.0 **Parameters** Array of arguments for *WP\_Comment\_Query*. The request object. **Usage** ```php theme={"system"} add_filter( 'cocart_product_review_query', function() { // Your code here }, 10 ); ``` [Search `cocart_product_review_query` in repository](https://github.com/co-cart/co-cart/search?q=cocart_product_review_query\&type=code) *** # Shipping & Packages This category contains filters for shipping packages, methods, and shipping-related calculations. `cocart_available_shipping_packages` Filter allows you to alter the shipping packages returned. Made available since v4.1.0 **Parameters** Available shipping packages. Chosen shipping method. **Usage** ```php theme={"system"} add_filter( 'cocart_available_shipping_packages', function() { // Your code here }, 10 ); ``` [Search `cocart_available_shipping_packages` in repository](https://github.com/co-cart/co-cart/search?q=cocart_available_shipping_packages\&type=code) *** `cocart_shipping_package_details_array` Filter allows you to change the package details. Made available since v3.0.0 **Parameters** Product names. Package details. **Usage** ```php theme={"system"} add_filter( 'cocart_shipping_package_details_array', function() { // Your code here }, 10 ); ``` [Search `cocart_shipping_package_details_array` in repository](https://github.com/co-cart/co-cart/search?q=cocart_shipping_package_details_array\&type=code) *** `cocart_shipping_package_name` Filters the package name for the shipping method. Made available since v3.0.0 **Parameters** Shipping name. **Usage** ```php theme={"system"} add_filter( 'cocart_shipping_package_name', function() { // Your code here }, 10 ); ``` [Search `cocart_shipping_package_name` in repository](https://github.com/co-cart/co-cart/search?q=cocart_shipping_package_name\&type=code) *** # Error Messages & Notifications This category contains filters for various error messages and user notifications throughout the cart system. `cocart_can_not_remove_item_message` Filters message about can not remove item. Made available since v2.1.0 **Parameters** Message. **Usage** ```php theme={"system"} add_filter( 'cocart_can_not_remove_item_message', function() { // Your code here }, 10 ); ``` [Search `cocart_can_not_remove_item_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_can_not_remove_item_message\&type=code) *** `cocart_can_not_restore_item_message` Filters message about can not restore item. Made available since v2.1.0 **Parameters** Message. **Usage** ```php theme={"system"} add_filter( 'cocart_can_not_restore_item_message', function() { // Your code here }, 10 ); ``` [Search `cocart_can_not_restore_item_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_can_not_restore_item_message\&type=code) *** `cocart_cart_item_key_required_message` Filters message about cart item key required. Made available since v2.1.0 **Parameters** Message. Status of which we are checking the item key. **Usage** ```php theme={"system"} add_filter( 'cocart_cart_item_key_required_message', function() { // Your code here }, 10 ); ``` [Search `cocart_cart_item_key_required_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_cart_item_key_required_message\&type=code) *** `cocart_item_not_in_cart_message` Filters message about cart item key required. Made available since v2.1.0 **Parameters** Message. Method. **Usage** ```php theme={"system"} add_filter( 'cocart_item_not_in_cart_message', function() { // Your code here }, 10 ); ``` [Search `cocart_item_not_in_cart_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_item_not_in_cart_message\&type=code) *** `cocart_no_items_in_cart_message` Filters message about no items in the cart. Made available since v2.1.0 **Parameters** Message. **Usage** ```php theme={"system"} add_filter( 'cocart_no_items_in_cart_message', function() { // Your code here }, 10 ); ``` [Search `cocart_no_items_in_cart_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_no_items_in_cart_message\&type=code) *** `cocart_no_items_message` Filters message about no items in cart. Made available since v2.1.0 **Parameters** Message. **Usage** ```php theme={"system"} add_filter( 'cocart_no_items_message', function() { // Your code here }, 10 ); ``` [Search `cocart_no_items_message` in repository](https://github.com/co-cart/co-cart/search?q=cocart_no_items_message\&type=code) *** # Functions available in the core of CoCart Source: https://docs.cocartapi.com/documentation/developers/functions Extend support for CoCart with these useful functions in your projects ## `cocart_maybe_show_results()` Checks if the session table exists before returning results. Helps prevents any fatal errors or crashes should debug mode be enabled. **Returns**: `boolean Returns true or false if the session table exists.` * **Since**: 4.2.0 Introduced. * **Defined in**: [`includes/cocart-core-functions.php`](https://github.com/co-cart/co-cart/blob/trunk/includes/cocart-core-functions.php#L90) *** ## `cocart_count_carts_expiring()` Counts how many carts are going to expire within the next 6 hours. **Returns**: `int Number of carts expiring.` * **Since**: 4.2.0 Introduced. * **Defined in**: [`includes/cocart-core-functions.php`](https://github.com/co-cart/co-cart/blob/trunk/includes/cocart-core-functions.php#L146) *** ## `cocart_count_carts_active()` Counts how many carts are active. **Returns**: `int Number of carts active.` * **Since**: 4.2.0 Introduced. * **Defined in**: [`includes/cocart-core-functions.php`](https://github.com/co-cart/co-cart/blob/trunk/includes/cocart-core-functions.php#L177) *** ## `cocart_count_carts_expired()` Counts how many carts have expired. **Returns**: `int Number of carts expired.` * **Since**: 4.2.0 Introduced. * **Defined in**: [`includes/cocart-core-functions.php`](https://github.com/co-cart/co-cart/blob/trunk/includes/cocart-core-functions.php#L207) *** ## `cocart_carts_source_web()` Counts how many carts were created via the web. **Returns**: `int Number of carts created via the web.` * **Since**: 4.2.0 Introduced. * **Defined in**: [`includes/cocart-core-functions.php`](https://github.com/co-cart/co-cart/blob/trunk/includes/cocart-core-functions.php#L237) *** ## `cocart_carts_source_headless()` Counts how many carts were created via CoCart API. **Returns**: `int Number of carts created via CoCart API.` * **Since**: 4.2.0 Introduced. * **Defined in**: [`includes/cocart-core-functions.php`](https://github.com/co-cart/co-cart/blob/trunk/includes/cocart-core-functions.php#L267) *** ## `cocart_carts_source_other()` Counts how many carts were the source is other or unknown. **Returns**: `int Number of carts created via other or unknown.` * **Since**: 4.2.0 Introduced. * **Defined in**: [`includes/cocart-core-functions.php`](https://github.com/co-cart/co-cart/blob/trunk/includes/cocart-core-functions.php#L297) *** ## `cocart_get_min_max_price_meta_query()` Get min/max price meta query args. | Parameter | Type | Description | | --------- | ------- | ---------------------------------- | | `$args` | `array` | Min price and max price arguments. | **Returns**: `array` * **Since**: 3.4.1 Introduced. * **Defined in**: [`includes/cocart-rest-functions.php`](https://github.com/co-cart/co-cart/blob/trunk/includes/cocart-rest-functions.php#L520) *** # Action hooks available in JWT Authentication Source: https://docs.cocartapi.com/documentation/developers/jwt/actions Trigger an action when these hooks are called Download the [JWT Authentication for CoCart](https://wordpress.org/plugins/cocart-jwt-authentication/) plugin to use these hooks. Each action hook is documented below with its description and usage example. ## Token Events ### `cocart_jwt_token_generated` Made available since v2.1.0 Fires when a new JWT token is generated after successful authentication. ```php theme={"system"} add_action( 'cocart_jwt_token_generated', function( $token, $user ) { // Log token generation error_log("New token generated for user: {$user->ID}"); }, 10, 2 ); ``` ### `cocart_jwt_auth_token_refreshed` Made available since v2.1.0 Fires when a token is refreshed using a refresh token. ```php theme={"system"} add_action( 'cocart_jwt_auth_token_refreshed', function( $token, $user ) { // Track token refresh events error_log("Token refreshed for user: {$user->ID}"); }, 10, 2 ); ``` ### `cocart_jwt_auth_token_validated` Made available since v2.1.0 Fires when a token is successfully validated. ```php theme={"system"} add_action( 'cocart_jwt_auth_token_validated', function( $decoded ) { // Access validated token data $user_id = $decoded->data->user->id; error_log("Token validated for user: {$user_id}"); } ); ``` ## Token Management ### `cocart_jwt_auth_token_deleted` Made available since v2.1.0 Fires when a token is deleted. ```php theme={"system"} add_action( 'cocart_jwt_auth_token_deleted', function( $user_id ) { $user = get_user_by( 'id', $user_id ); // Cleanup after token deletion error_log("Token for {$user->display_name} has been deleted"); }, 10, 2 ); ``` ## Authentication Events ### `cocart_jwt_auth_authenticated` Made available since v3.0.0 Fires when a user is authenticated via JWT token. ```php theme={"system"} add_action( 'cocart_jwt_auth_authenticated', function( $user ) { // Send admin notification for VIP customers if ( in_array( 'vip_customer', $user->roles ) ) { wp_mail( get_option( 'admin_email' ), 'VIP Customer Login', "VIP customer {$user->display_name} has logged in via API." ); } // Track API usage analytics $usage_count = get_user_meta( $user->ID, 'api_usage_count', true ); update_user_meta( $user->ID, 'api_usage_count', intval( $usage_count ) + 1 ); } ); ``` > All actions follow WordPress coding standards and can be used with the standard add\_action() function. The examples above show practical implementations for each action. # Filters available in JWT Authentication Source: https://docs.cocartapi.com/documentation/developers/jwt/filters Control how JWT Authentication operates when tokens are created Download the [JWT Authentication for CoCart](https://wordpress.org/plugins/cocart-jwt-authentication/) plugin to use these filters. Each filter is documented below with its description and usage example. ## Authentication filters ### `cocart_jwt_auth_issued_at` Made available since v2.0.0 Allows you to change the token issuance timestamp (iat claim) for token timing synchronization. ```php theme={"system"} add_filter( 'cocart_jwt_auth_issued_at', function( $timestamp ) { // Add a 5-minute buffer return $timestamp + (5 * MINUTE_IN_SECONDS); } ); ``` ### `cocart_jwt_auth_issuer` Made available since v2.0.0 Allows you to change the token issuer (iss claim) for multi-site setups or custom API endpoints. ```php theme={"system"} add_filter( 'cocart_jwt_auth_issuer', function( $issuer ) { return 'https://api.yoursite.com'; } ); ``` ### `cocart_jwt_auth_not_before` Made available since v2.0.0 Allows you to set when the token becomes valid (nbf claim) for token activation control. ```php theme={"system"} add_filter( 'cocart_jwt_auth_not_before', function( $time, $issued_at ) { // Token becomes valid 5 minutes after issuance return $issued_at + (5 * MINUTE_IN_SECONDS); }, 10, 2); ``` ### `cocart_jwt_auth_expire` Made available since v2.0.0 Allows you to customize when the token will expire (exp claim) based on roles or conditions. ```php theme={"system"} add_filter( 'cocart_jwt_auth_expire', function( $expiration, $issued_at ) { // Set expiration to 2 days return 2 * DAY_IN_SECONDS; }, 10, 2); ``` ### `cocart_jwt_auth_algorithm` Made available since v2.0.0 vAllows you to change the algorithm used for token signing. ```php theme={"system"} add_filter( 'cocart_jwt_auth_algorithm', function( $algorithm ) { return 'RS256'; // Use RSA SHA-256 instead of default HS256 }); ``` ### `cocart_jwt_auth_token_user_data` Made available since v2.2.0 Allows additional user data to be applied to the payload before the token is generated. ```php theme={"system"} add_filter( 'cocart_jwt_auth_token_user_data', function( $data, $user ) { return array_merge( $data, array( 'role' => $user->roles[0], 'display_name' => $user->display_name, 'email' => $user->user_email ) ); }, 10, 2); ``` ## Refresh Token Filters ### `cocart_jwt_auth_refresh_token_generation` Made available since v2.0.0 Allows you to change how refresh tokens are generated. ```php theme={"system"} add_filter( 'cocart_jwt_auth_refresh_token_generation', function( $token ) { return md5( uniqid() . time() ); // Use MD5 for token generation }); ``` ### `cocart_jwt_auth_refresh_token_expiration` Made available since v2.0.0 Allows you to customize refresh token lifetime based on roles or conditions. ```php theme={"system"} add_filter( 'cocart_jwt_auth_refresh_token_expiration', function( $expiration ) { return 60 * DAY_IN_SECONDS; // Set to 60 days }); ``` ## Token Management ### `cocart_jwt_auth_revoke_tokens_on_email_change` Made available since v2.3.0 Allows you to control token revocation on email changes. ```php theme={"system"} add_filter( 'cocart_jwt_auth_revoke_tokens_on_email_change', function( $should_revoke, $user_id ) { return true; // Always revoke tokens on email change. }, 10, 2); ``` ### `cocart_jwt_auth_revoke_tokens_on_password_change` Made available since v2.3.0 Allows you to control token revocation on password changes for security policies. ```php theme={"system"} add_filter( 'cocart_jwt_auth_revoke_tokens_on_password_change', function( $should_revoke, $user_id ) { return $user_id !== 1; // Don't revoke tokens for admin user }, 10, 2); ``` ### `cocart_jwt_auth_revoke_tokens_on_after_password_reset` Made available since v2.3.0 Allows you to control token revocation on password reset for security policies. ```php theme={"system"} add_filter( 'cocart_jwt_auth_revoke_tokens_on_after_password_reset', function( $should_revoke, $user_id ) { return true; // Always revoke tokens after password reset. }, 10, 2); ``` ### `cocart_jwt_auth_revoke_tokens_on_profile_update` Made available since v2.3.0 Allows you to control token revocation on profile update. ```php theme={"system"} add_filter( 'cocart_jwt_auth_revoke_tokens_on_profile_update', function( $should_revoke, $user_id ) { return true; // Always revoke tokens on profile change. }, 10, 2); ``` ### `cocart_jwt_auth_revoke_tokens_on_delete_user` Made available since v2.3.0 Allows you to control token revocation when a user is deleted. ```php theme={"system"} add_filter( 'cocart_jwt_auth_revoke_tokens_on_delete_user', function( $should_revoke, $user_id ) { return true; // Always revoke tokens when user is deleted. }, 10, 2); ``` ### `cocart_jwt_auth_revoke_tokens_on_wp_logout` Made available since v2.3.0 Allows you to control token revocation when a user logs out. ```php theme={"system"} add_filter( 'cocart_jwt_auth_revoke_tokens_on_wp_logout', function( $should_revoke, $user_id ) { return true; // Always revoke tokens on logout. }, 10, 2); ``` > All filters follow WordPress coding standards and can be used with the standard add\_filter() function. The examples above show practical implementations for each filter. ### `cocart_jwt_auth_token_prefix` Made available since v2.5.0 This prefix is used to identify the token type. It can be useful if you want to use different token types or to avoid conflicts with other JWT implementations. > It is **NOT required** to use a prefix, but it can help to distinguish tokens from different sources or implementations so use a unique prefix. ```php theme={"system"} add_filter( 'cocart_jwt_auth_token_prefix', function( $prefix ) { return 'cocart_'; }, 10, 2); ``` ### `cocart_jwt_auth_max_user_tokens` Made available since v3.0.0 Allows changing the maximum number of tokens a user can have. Default is 5 tokens. ```php theme={"system"} add_filter( 'cocart_jwt_auth_max_user_tokens', function( $max_tokens, $user ) { // Allow administrators to have more tokens if ( in_array( 'administrator', $user->roles ) ) { return 20; } // Limit regular users to 3 tokens return 3; }, 10, 2); ``` # API Permissions Source: https://docs.cocartapi.com/documentation/force-permissions Learn how to restrict access to certain CoCart routes. When using a REST-API, sometimes you don’t want all the routes to be accessible to everyone. Restricting access to certain routes can help you maintain better control over your operations. This guide, we help enforce permissions and restrict access to specific CoCart API routes. One clear example is that you maybe don’t want to support guest customers on your store, so you need to restrict all the public routes. Forcing API permissions doesn’t mean that only administrators or shop managers can access them. This means that the routes cannot be used unless the API is requested while being authenticated. Authentication is not forced by user role. ## How do you force API permission? It’s actually pretty easy. All you need to do is apply a filter based on the method of the routes you want to force permission on. There are no parameters required. Just return an array of the API routes you wish to force permission on. Filter name: `cocart_api_permission_check_{method}` Replace `{method}` with `get`, `post`, `put`, `delete` or `options`. ```php theme={"system"} add_filter( 'cocart_api_permission_check_get', function() { return array( 'v1/count-items', 'v2/cart/items/count', 'v2/cart/totals', 'v2/store' ); } ); ``` That’s it. # Guiding Principles Source: https://docs.cocartapi.com/documentation/guides/guiding-principles The following principles should be considered when extending, creating, or updating endpoints in CoCart ## Routes should be designed around resources with a single type of schema Routes should be designed around resources (nouns) rather than operations (verbs). Routes should also return only one type of data defined by their Schema. For example: | Route | Resource type | Expected data | | ---------------------- | ------------- | --------------------------- | | `cocart/v2/cart` | Cart | A cart object | | `cocart/v2/cart/items` | Cart Item | A list of cart item objects | | `cocart/v2/products` | Product | A list of product objects | | `cocart/v2/products/1` | Product | A product object | There are 2 notable exceptions to this rule in the CoCart API; *Errors* and *Cart Operations*. ### Error Handling Errors, including validation errors, should return an error response code (4xx or 5xx) and a [`WP_Error`](https://developer.wordpress.org/reference/classes/wp_error/) object. Error messages should be localized, but do not need to be written with language aimed at customers (clients should use the given error code to create customer-facing notices as needed). Error codes should have the prefix `cocart_`. ### Cart Operations Some endpoints are designed around operations to avoid clients needing to make multiple round trips to the API. This is purely for convenience. An example would be the `cocart/v2/cart/add-item` endpoint which accepts a quantity and product ID, but returns a full cart object, rather than just an updated list of items. ## Exposed data must belong to the current user or be non-sensitive Resources, including customer and order data, should reflect only the current session. Do not return data for other customers as this would be a breach of privacy and security issue. Store data such as settings (for example, store currency) is permitted in responses, but private or sensitive data must be avoided. Allowing more extensive access to data must be authenticated. Data returned from the API should not be [escaped](https://developer.wordpress.org/themes/theme-security/data-sanitization-escaping/) (this is left to the client rendering it), but it should be sanitized. For example, HTML should be run through [`wp_kses_post`](https://developer.wordpress.org/reference/functions/wp_kses_post/). It is the client’s responsibility to properly escape data that comes from the API, but we should try to avoid returning data that is potentially unsafe. ## Collections of resources should be paginated Large volumes of data should be paginated to avoid overwhelming the server. For example, returning a collection of products. * Use the response Headers `X-WP-Total`, `X-WP-TotalPages`, and `Link` to indicate available resources. * Use parameters `page` and `per_page` to retrieve certain pages. * The maximum allowed value for `per_page` is 100. ## API Responses should use standard HTTP status codes When returning content, use a valid HTTP response code such as: * `200 OK` for successful responses (this is the default response code). * `201 Created` when creating a resource, for example, adding a new cart item or applying a new coupon. * `204 No Content` for successful deletes. * `400 Bad Request` when a required parameter is not set. * `403 Forbidden` when a request is not allowed, for example, if the provided security nonce is invalid. * `404 Not Found` if a resource does not exist. * `409 Conflict` if a resource cannot be updated, for example, if something in the cart is invalid and removed during the request. A note on `DELETE` requests, a common pattern in the WordPress REST API is to return the deleted object. [A full list of HTTP status codes can be found here.](https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml) ## Breaking changes should be avoided where possible The CoCart API establishes a contract between itself and API consumers via the use of Schema. This contract should not be broken unless absolutely necessary. If a breaking change were necessary, a new version of the CoCart API would need to be released. A breaking change is anything that changes the format of existing Schema, removes a Schema property, removes an existing route, or makes a backwards-incompatible change to anything public that may already be in use by consumers. Breaking changes can be avoided by [deprecating existing properties](http://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.3) rather than removing them, or [deprecating routes](https://datatracker.ietf.org/doc/html/rfc8594) and replacing them with a different route if major changes are needed. Non-breaking changes are always permitted without the need to increase the API version. Some examples of these include: * Adding new properties to schema * Adding new routes, endpoints, methods * Adding optional request parameters * Re-ordering response fields The version will not increase for bug fixes unless the scope of the bug causes a backwards-incompatible change. Fixes would not be rolled back to past API versions with the exception of security issues that require backporting. # How to Update CoCart Source: https://docs.cocartapi.com/documentation/guides/updating-cocart Each release provides an improvement, new features, issues fixed, compatibility, even tighten security to make CoCart do what it needs to do for your headless store. ## Updating CoCart ### Automatic - one click update The CoCart plugin can be updated via the "Plugins" page found in your WordPress website admin area. Updates will appear when available and can be applied by simply clicking on the *update now* link. ### Manual update You may also apply plugin updates manually by copying and pasting the plugin files into your `wp-content/plugins` folder. You can download any free CoCart plugin files from the WordPress plugin directory and any premium CoCart plugin files from your customer portal. There is no loss or change to data whilst modifying the plugin’s files making it safe to delete and re-upload the plugin folder. ### Backups While running a headless website is not the same as a regular WordPress website, it is still important to backup the infrastructure that allows you to run it. #### Automatic backups The most efficient and reliable approach is to use an automated site backup service. There are many available that provide such a service. Some of the most popular ones include: * [UpdraftPlus](https://updraftplus.com/) * [BackupBuddy](https://ithemes.com/backupbuddy/) * [VaultPress](https://jetpack.com/support/backup/) * [WP Time Capsule](https://wptimecapsule.com/) * [BlogVault](https://blogvault.net/) #### Manual backups To do things manually, there are two parts to backing up your store: * Backup your database! There are multiple ways to do this, see the Codex for your options to back up your content. Both manual and plugin options exist. * Using SFTP head to your wp-content folder to backup your theme and plugin files. ### CoCart data update notice If you have configured CoCart to process database updates manually then you may be prompted with a notice to upgrade the database. The logic to check if a **database upgrade** is required will run in the admin area after a new version number is detected, therefore, it is fully compatible with both the update methods listed above. **Update CoCart Database** starts the process of updating your database to match the plugin version you installed or updated to. The database organizes, contains, and stores your customers cart in session. It is an essential process. Once the update process starts, you can view the progress which will take you to the **Scheduled Actions** section and show the pending actions for the update. Once it is completed, the next time you view an admin page you will see the dismissible update complete banner. # Load Cart Source: https://docs.cocartapi.com/documentation/load-cart Learn to load a guest cart session securely This feature is not part of the REST API. Do not treat it as such! This feature is designed to transfer the cart over to the web version of your store. It allows the guest customer to continue shopping or checkout what they already have in the cart added via your headless application. It's handy if you have not yet worked with payment gateway like *Stripe* to handle the headless checkout. You can choose to override the cart (if anything is set) or merge the cart items together. If a customer is logged in via the web version of your store then **WooCommerce** will then merge any items in the cart together with the items the guest customer has in cart. FYI: It does not matter if your customer is logged in or not already via the web version of your store. Only the cart data will be set. Customer details are **not transferred**. ## Query properties | Query | Type | Description | | ------------------ | ------ | ------------------------------------------------------------------------------------------------- | | `cocart-load-cart` | string | Set the cart key of the cart you wish to load. **mandatory** | | `notify` | bool | Set as true to notify customers once arrived on the web version of your store. *Default is false* | | `keep-cart` | bool | Set as false to merge cart data. *Default is true* | To load the cart from session on your web store, you must use the properties above to query your website. You can query any page you prefer your customer to land on as the cart is loaded in the background. `https://example-store.com/checkout/?cocart-load-cart=bbfa8e97ac9cff4c861d62a109e83bb6` If the same item already exists in cart and you are merging the two carts together, that item will not change. It will not increase or decrease the quantity if the cart item key are the same. ### FAQ Use the notice property to try loading the cart session again. This can be used also to debug why but normally this is because of two things. 1. The cart key was incorrect 2. The cart session has expired and is no longer in the database under that cart key. Use this filter to change the name. ```php theme={"system"} If you do not need or want to use WooCommerce native checkout then disable using this filter. ```php theme={"system"} # Rate Limiting Source: https://docs.cocartapi.com/documentation/rate-limiting Control and prevent abuse from excessive calls. Rate Limiting is only available with [CoCart Plus](https://cocartapi.com/pricing/). Popular stores can become the targets of malicious actors. One example of known abusive patterns is making many requests in a very short timeframe to try to overwhelm the store. Rate limiting is opt-in and is intended for advanced merchants and platforms. ## What it does? Rate limiting is to prevent abuse on endpoints from excessive calls and performance degradation on the machine running the store. Limiting is based on user ID for registered users (logged in) and IP address for guest users (unauthenticated requests). It also offers standard support for running behind a proxy, load balancer, etc. This is also optional and is disabled by default. The rate limiting uses a modified `wc_rate_limit` table with an additional remaining column for tracking the request count in any given request window. ## Limit information A default maximum of 25 requests can be made within a 10-second time frame. These can be changed through `cocart_api_rate_limit_options` filter. ## Methods restricted by Rate Limiting `POST`, `PUT`, `PATCH`, and `DELETE` ## Enable Rate Limiting Developers can enable rate limiting using the `cocart_api_rate_limit_options` filter. ```php theme={"system"} add_filter( 'cocart_api_rate_limit_options', function() { return [ 'enabled' => RateLimits::ENABLED, // enables/disables Rate Limiting. Default: false 'proxy_support' => RateLimits::PROXY_SUPPORT, // enables/disables Proxy support. Default: false 'limit' => RateLimits::LIMIT, // limit of request per timeframe. Default: 25 'seconds' => RateLimits::SECONDS, // timeframe in seconds. Default: 10 ]; } ); ``` ## Supporting Proxies Like any mechanism that restricts usage to counter potential abuse of an API, this is a sensitive feature that should be used carefully. In a scenario where a store is behind another service layer (a proxy, load balancer, etc.), the developer should enable standard proxy support through the Otherwise rate limiting might be wrongly triggered and group-limit requests. ## Proxy support For the `proxy_support` option to work properly, service layers (load balancer, cache service, CDNs, etc.) must be passing the originating IP supported through standard IP forwarding headers, namely: * `X_REAL_IP`|`CLIENT_IP` *Custom popular implementations that simplify obtaining the origin IP for the request* * `X_FORWARDED_FOR` *De-facto standard header for identifying the originating IP, [Documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For)* * `X_FORWARDED` *[Documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded), [RFC 7239](https://datatracker.ietf.org/doc/html/rfc7239)* This is disabled by default. ## Limit usage information observability Current limit information can be observed via custom response headers: * `RateLimit-Limit` *Maximum requests per time frame.* * `RateLimit-Remaining` *Requests available during current time frame.* * `RateLimit-Reset` *Unix timestamp of next time frame reset.* * `RateLimit-Retry-After` *Seconds until requests are unblocked again. Only shown when the limit is reached.* ### Response headers example ```http theme={"system"} RateLimit-Limit: 5 RateLimit-Remaining: 0 RateLimit-Reset: 1654880642 RateLimit-Retry-After: 28 ``` ## Tracking Abuses Developers can use the `cocart_api_rate_limit_exceeded` action to track and handle instances of API abuse: ```php theme={"system"} add_action( 'cocart_api_rate_limit_exceeded', function ( $offending_ip ) { /* Custom tracking implementation */ } ); ``` ## Testing Guide ### Without proxy support 1. Enable Rate Limiting by using the [options filter](#enable-rate-limiting). 2. In a short window, keep making API requests. 3. Check that RateLimit-xxx headers change on each request. 4. Check that once you've hit the limit, an error response is returned. You can modify the limits using the [options filter](#enable-rate-limiting) to make it easier to test. ### With proxy support, do the same as before and 1. Enable proxy support 2. Make your requests with one of the following request headers containing always the same IP address: * X-Real-IP or Client-IP * [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) * [Forwarded](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded) ### User Facing Testing 1. Enable Rate Limiting by using the [options filter](#enable-rate-limiting). 2. Try to apply a coupon or access `/wp-json/cocart/v2/coupon` beyond current limits (currently 25 requests under 10 seconds) 3. Ensure you get presented with an error "Too many requests. Please wait xx seconds before trying again." # Resources Source: https://docs.cocartapi.com/documentation/resources These resources may extend your capability of going headless with WordPress. ## CoCart for Developers We have over 200+ filters and action hooks in the core of CoCart alone. Find them logged under the "Developers" section on the side. Each filter and action hook is linked for further reference. ### Cart Enhanced This free add-on is not supported by the CoCart API reference. Enhances the cart response returned with additional product details and more. [Download here](https://wordpress.org/plugins/cocart-get-cart-enhanced/) ### JWT Authentication Authenticate via a simple JWT Token. This JWT authentication is designed for customer users and requires basic authentication used first. [Download here](https://wordpress.org/plugins/cocart-jwt-authentication/) ### Beta Tester Run bleeding edge versions of CoCart from the GitHub repository. This will replace your installed version of CoCart with the latest tagged pre-release on GitHub – use with caution, and not on production sites. You have been warned. [Download here](https://github.com/co-cart/cocart-beta-tester) ## WordPress REST-API If you are looking for any of WordPress core REST API routes, go to [https://developer.wordpress.org/rest-api/](https://developer.wordpress.org/rest-api/) for their API reference. ## Other Plugins The plugins below may be useful to you to extend the capability of going headless with WordPress. ### WP-REST-API V2 Menus This plugin extends the WordPress REST API with new routes for WordPress registered menus. [Download here](https://wordpress.org/plugins/wp-rest-api-v2-menus/) ### REST API Toolbox Allows tweaking of several REST API settings. [Download here](https://wordpress.org/plugins/rest-api-toolbox/) ### REST API Log Log all REST API requests and responses. Great for debugging. [Download here](https://wordpress.org/plugins/wp-rest-api-log/) ### Query Monitor A developer tools panel for WordPress. It enables debugging of database queries, PHP errors, hooks and actions, block editor blocks, enqueued scripts and stylesheets, HTTP API calls, and more. [Download here](https://wordpress.org/plugins/query-monitor/) ### Disable REST API Why recommend this? Because you may not want all REST API's registered on your WordPress site exposed or simply don't use them. The most comprehensive plugin for controlling access to the WordPress REST API. Useful to disable routes you are not using. [Download here](https://wordpress.org/plugins/disable-json-api/) We developed our own security plugin designed specifically for the REST API to provide a firewall from bad requests and protection for data exposed without authentication such as the index listing the routes available. **List of Features** * Hides all sensitive details from the `wp-json` index. * Deny access to any API route if the `user-agent` is not trust worthy or a bot. * Block use of any API route in an iFrame. * Rate limiting for any route. * Anonymous user data returned if accessed without authentication. * CORs support. * Permissions callback override for any route and method. [Get your API secure](#) # Security Source: https://docs.cocartapi.com/documentation/security Security is the most important part of creating a headless store. By default, CoCart cannot be found in WordPress REST API index under namespaces or routes. Don't be alarmed. This doesn't mean CoCart is not active on your site, we simply hide CoCart from any outsider trying to see if you are running it. Most developers don't like the index of the REST API exposing these details so we made sure at least CoCart is not shown automatically. We developed our own security plugin designed specifically for the REST API to provide a firewall from bad requests and protection for data exposed without authentication such as the index listing the routes available. **List of Features** * Hides all sensitive details from the `wp-json` index. * Deny access to any API route if the `user-agent` is not trust worthy or a bot. * Block use of any API route in an iFrame. * Rate limiting for any route. * Anonymous user data returned if accessed without authentication. * CORs support. * Permissions callback override for any route and method. [Get your API secure](#) ## Authentication header If you want to change the authorization header used for authenticating users with CoCart. Use filter `cocart_auth_header` to fetch the authorization value from it. ```php theme={"system"} add_filter( 'cocart_auth_header', function( $auth_header ) { $custom_header = isset( $_SERVER['HTTP_X_MY_CUSTOM_AUTH'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_MY_CUSTOM_AUTH'] ) ) : ''; return ! empty( $custom_header ) ? $custom_header : $auth_header; }, 10, 1); ``` # Tools Source: https://docs.cocartapi.com/documentation/tools Tools to help you develop. ## Local Environments When preparing the WordPress side of your headless store locally, using either one of these desktop applications will help you to create new WordPress sites on your computer with the click of a few buttons. They takes care of configuring *PHP*, *MySQL* and basic configuration of WordPress to connect to the database. Some may provides one-click support for enabling *XDebug*, allow access to your WordPress site using *WP-CLI*, and more. All you need out of the box. Quickly spin up a local environment from: * [LocalWP](https://localwp.com/) - **Recommend** * [DevKinsta](https://kinsta.com/devkinsta/) * [Lando](https://docs.lando.dev/plugins/wordpress/v/stable/) * [MAMP](https://codex.wordpress.org/Installing_WordPress_Locally_on_Your_Mac_With_MAMP) * [XAMP](https://www.apachefriends.org) * [Laravel Valet](https://laravel.com/docs/valet) When setting up your WordPress environment, please check that they match the [server requirements](https://woocommerce.com/document/server-requirements/) that WooCommerce ask for in order to run CoCart. ## Tools Some useful tools you can use to access the API include: * [Postman](https://www.getpostman.com/) - A multi platform REST API GUI client (using Google Chrome or installing the app on Mac OS X or Windows). * [Insomnia](https://insomnia.rest/) - Similar to Postman using an app on Mac OS X, Windows or Ubuntu. * [Bruno](https://www.usebruno.com/) - Bruno is a Git-integrated, fully offline, and open-source API client. * [Hoppscotch](https://hoppscotch.io/) - A fast and beautiful API request builder (web alternative to Postman). * [ExtendsClass](https://extendsclass.com/rest-client-online.html) - Another web HTTP client. * [CocoaRestClient](https://mmattozzi.github.io/cocoa-rest-client/) - A Mac OS X GUI client for interacting with the API. * [Paw HTTP Client](https://itunes.apple.com/us/app/paw-http-client/id584653203?mt=12) - Another HTTP client for Mac OS X. * [Hookbin](https://hookbin.com/) - Another tool to test web hooks. # WP-CLI for CoCart Source: https://docs.cocartapi.com/documentation/wp-cli CoCart offers the ability to manage the plugin via the command-line, using WP CLI. Before you make any changes, always take a backup of your site. This keeps your data safe if anything goes wrong. ## Core Commands WP-CLI commands where introduced since v3 All CoCart related commands are grouped into wp cocart command. | Command | Description | | ---------------------- | ------------------------------------------------- | | `wp cocart update` | Updates the CoCart database. | | `wp cocart version` | Returns the version of CoCart installed. | | `wp cocart db-version` | Returns the database version of CoCart installed. | ## Plus Commands | Command | Description | | ------------------------ | ------------------------------------------------------ | | `wp cocart plus version` | Returns the version of CoCart Plus you have installed. | ## Plugin Slugs Use the following slugs to manage CoCart plugins with WP-CLI. The slugs are used in the command line to identify the specific plugin you want to work with. | Plugin | Plugin Slug | | ------------------------- | ----------------------------- | | CoCart Core (Legacy) | cart-rest-api-for-woocommerce | | CoCart Core | cocart | | CoCart Plus | cocart-plus | | CoCart JWT Authentication | cocart-jwt-authentication | ## Frequently Asked Questions WP-CLI is a powerful set of command-line tools for managing WordPress installations in the terminal saving you time and effort. You can update plugins, configure multisite installations, and much more, all without using a web browser. To update a plugin using WP-CLI, first go to your WordPress directory in the terminal. Then type the command `wp plugin update `, replacing **plugin-slug** with the name of the plugin you want to update. This will update the plugin to its latest version. Not all CoCart plugins are available for installation via WP-CLI as they are not hosted on the WordPress plugin directory. Other plugins must be installed manually by downloading them. WP-CLI helps you manage plugins much faster by using simple commands in the terminal. You do not need to log in to the WordPress dashboard or click many buttons. It can save time, reduce mistakes, and make it easier to manage many sites. WP-CLI is useful for both beginners and advanced users. For more information about WP-CLI visit the official site [https://wp-cli.org/](https://wp-cli.org/) # Quick Start Source: https://docs.cocartapi.com/getting-started/core/quick-start Learn how to create a cart This tutorial uses a REST client for the examples, we will walk through the following steps in order to achieve placing items in the cart. The screenshots are from [Postman](https://www.postman.com/), but you can also use other REST clients like [Insomnia](https://insomnia.rest/) if you want. RESTful requests are a standardized way for applications to communicate with servers over the internet. These requests use different methods to perform specific actions: * **GET**: Fetch information from the server. * **POST**: Creates information to the server. * **PUT**: Updates existing information on the server. * **DELETE**: Deleting information from the server. **Let's get started** Normally you would need to decide if the cart we are managing is for a guest customer or a registered customer. For this tutorial we will focus on a guest customers. They have no identification on your store so it helps to start at the beginning. ## Fetch all available products Next, we need to know the ID of the product we want to order. For this example, I decided to go with the product named *Beanie with Logo*, one of the sample products in WooCommerce core. To list all available products, we make the following request: First, we need to know the ID of the product we want that can be used to add the item to the cart. I can get a list of products from `/wp-json/cocart/v2/products`. This returns products in JSON format and shows product IDs and pricing information: Requesting available products in store ## Add a product to the cart We can then pick which product we’d like to add to the cart, and go ahead and add it via the `/wp-json/cocart/v2/cart/add-item` route. This will either add the item to the cart, returning the new updated cart object, or return an error response if something went wrong. In comparison to the previous **GET** requests, adding a product to the cart requires a **POST** request. After making the request, we can see that the desired product had been added to the cart: Cart response along with the added item We can also see that the first shipping rate is selected by default. Of course, it’s possible placing multiple products as well as one product multiple times to the cart. To add multiple products to the cart, simply call the `/wp-json/cocart/v2/cart/add-item` endpoint with various products. To add one product multiple times to the cart, simply adjust the quantity parameter of the `/wp-json/cocart/v2/cart/add-item` endpoint. We recommend using the batch endpoint `/wp-json/cocart/batch` when possible to help with the performance of the API as well as provide one complete cart response. Once the item is added to the cart, a cart session is created and a new cart key (randomly generated) is assigned. This session stores the information about the cart items, shipping options, discounts applied, the totals and the customers information provided etc. ## Collecting and tracking the cart key There are two ways you can get the cart key. The first is via the cart response where you see `cart_key`. The second is via the returned response headers. There you will need to look for `CoCart-API-Cart-Key`. In this case the cart key is `{cart_key}`. This cart key is what we need to keep track of the cart session for the guest customer. The reason for that is because we don't rely on WooCommerce session cookie to store the cart key for us. Doing this allows more freedom for developers and control on how they want to build their headless store. Not using the same cart key for the guest customer will lead to several cart sessions being created with no way of getting the previous cart session back the next time you add a product or update the cart. Once you get the `cart_key`, you must store it somewhere in your application. It can be: * **Browser Storage** * using a cookie * LocalStorage (with encryption) * SessionStorage (for temporary sessions) * **Storage Libraries** * [localForage](https://www.npmjs.com/package/localforage) - Offline storage with fallbacks * [PouchDB](https://pouchdb.com/) - Offline-first database * **Native Storage** * [SQLite](https://www.sqlite.org/) - For mobile applications * [Hive](https://docs.hivedb.dev/) - For Flutter applications * Secure Keychain/Keystore for mobile platforms ## Adding customer information With the item now in the cart, we can attempt to add customer information using the `/wp-json/cocart/v2/cart/update?cart_key=&namespace=update-customer` endpoint. Notice that I placed the cart key as global parameter. You can apply the cart key via the headers to if you prefer. This endpoint requires a billing and shipping address. The payload we send looks something like this: ```json theme={"system"} { "first_name": "Anakin", "last_name": "Skywalker", "email": "thatisnomoon@space.com", "phone": "01908672354", "company": "Darth Vadar LTD", "address_1": "70 The Crescent", "address_2": "", // Only if needed. "city": "BELFAST", "state": "", // Only if needed. "country": "GB", "postcode": "BT90 2PU" } ``` Customers may want to provide a different address other than the billing address provided. Extend the fields with a `s_` prefix in front to identify the field is for shipping. Followed by setting the field `ship_to_different_address` as **true**. ```json theme={"system"} { "first_name": "Anakin", "last_name": "Skywalker", "email": "thatisnomoon@space.com", "phone": "01908672354", "company": "Darth Vadar LTD", "address_1": "70 The Crescent", "city": "BELFAST", "country": "GB", "postcode": "BT90 2PU", "s_first_name": "Sith", "s_last_name": "Lord", "s_address_1": "515 Cherry Drive", "s_city": "San Pablo", "s_state": "CA", "s_postcode": "94806", "s_country": "US", "s_company": "Galaxy Ruler LLC", "ship_to_different_address": true } ``` A different shipping address can only be applied if you have [CoCart Plus](https://cocartapi.com/pricing/) installed. We don't yet have the option to create an order via an API but we do provide the option to load the cart session to the native WooCommerce store to continue the checkout procedure there. We will have the checkout API available in the future. ## Load cart into store 123 ## Resources * Get Cart Info (/cocart/v2/cart) * Add Item to Cart (/cocart/v2/cart/add-item) * List Products (/cocart/v2/products) ## Further Reading * [Technical Documentation](/overview/standards) * [Guiding principles](/documentation/developers/guides/guiding-principles) ## Thoughts & feedback We hope you found this tutorial helpful! If you’ve got any questions or there’s another tutorial topic you’re keen to see, feel free to drop a comment or reach out in the [CoCart Community in Discord](https://cocartapi.com/community/?ref=mintlify). Your feedback helps us create content that better serves you. Thanks for reading! # Install CoCart Source: https://docs.cocartapi.com/getting-started/core/setup Follow one of many the ways to install CoCart ### Before you start It’s important that your [server requirements](https://woocommerce.com/document/server-requirements/) meet the minimum that WooCommerce ask for in order to run CoCart. If you already have WooCommerce installed and your store filled with products ready to sell. Congrats, you meet the requirements to install CoCart and can now start decoupling. ### Upload Install We don't host the latest core version of CoCart with WordPress.org for security reasons. Please download from us to make sure you are using an official copy. [Download CoCart Core](https://cocartapi.com/download/) Once you have the plugin downloaded, log in to your WordPress dashboard, navigate to the ‘Plugins’ menu and press ‘Add New’. Then press ‘Upload Plugin’. You will either be redirected to a new page or the upload field will simple appear at the top allowing you to upload the plugin. Once the file is selected, press ‘Install Now’. Once the plugin is installed. Press ‘Activate Plugin’. ### Install via FTP [Download CoCart Core](https://cocartapi.com/download/) Open your FTP program of choice and login to your FTP server. Access where your WordPress plugins folder is stored and upload the folder of the plugin that is in the zip file and put it in the plugins directory. Now log in to your WordPress dashboard, navigate to the ‘Plugins’ menu and press ‘Activate’ where CoCart is listed. ### Alternative Source: GitHub Versions of CoCart core below v5 will not have two versions, only a single zip file and will be labelled e.g. `cart-rest-api-for-woocommerce-v4.3.16.zip` Every release of CoCart core since v5 has two versions of the plugin compiled added as a release asset either as a `.zip` or `.tar.gz` format. ###### Examples * e.g. Regular zip - `cocart-core-v5.0.zip` * e.g. [GitHub Updater](https://github.com/afragen/git-updater) supported zip - `cocart-core-github-v5.0.zip` On the [releases page](https://github.com/co-cart/co-cart/releases), look under the “assets” section of the release you would like to install and download the compiled format that works best for you. Once you have downloaded the plugin, follow the installation instructions. ## Prerequisites Before using CoCart, ensure your WordPress permalinks are configured to any setting except "Plain". This configuration is essential for accessing the REST API using standard endpoint URIs (e.g. `cocart/v2/products`). Configure this under **Settings > Permalinks**. With these settings in place, you're ready to begin using CoCart. ## WooCommerce Dependency CoCart requires an active WooCommerce installation to function. If WooCommerce is not installed or is deactivated, CoCart will automatically disable itself during activation to prevent technical issues. You'll see a prompt to install or activate WooCommerce if needed. # Advanced Configuration Source: https://docs.cocartapi.com/getting-started/jwt/advanced-configuration Take security to the next level with JWT Authentication. ## Using RSA Keys (RS256) By default, CoCart JWT uses HS256 (HMAC SHA-256) for token signing. You can switch to RS256 (RSA SHA-256) for enhanced security, especially in distributed systems. **1. Generate RSA Keys** First, generate a private/public key pair: ```bash theme={"system"} # Generate private key openssl genpkey -algorithm RSA -out private.key -pkeyopt rsa_keygen_bits:2048 # Generate public key openssl rsa -pubout -in private.key -out public.key ``` **2. Configure Keys** Add these filters to a custom must-use plugin: ```php theme={"system"} // Set the algorithm to RS256 add_filter( 'cocart_jwt_auth_algorithm', function( $algorithm ) { return 'RS256'; }); // Set the private key for token signing. add_filter( 'cocart_jwt_auth_secret_private_key', function( $key ) { return file_get_contents( ABSPATH . 'path/to/private.key' ); }); // Set the public key for token validation. add_filter( 'cocart_jwt_auth_secret_public_key', function( $key ) { return file_get_contents( ABSPATH . 'path/to/public.key' ); }); ``` Store your keys securely and never commit them to version control. Consider using environment variables or WordPress constants in `wp-config.php` to store the key paths. **1. Key Storage Example** A secure way to configure keys using constants: ```php theme={"system"} // In wp-config.php define( 'COCART_JWT_AUTH_PRIVATE_KEY_PATH', '/secure/path/private.key' ); define( 'COCART_JWT_AUTH_PUBLIC_KEY_PATH', '/secure/path/public.key' ); // In your code add_filter( 'cocart_jwt_auth_secret_private_key', function( $key ) { return file_get_contents( COCART_JWT_AUTH_PRIVATE_KEY_PATH ); }); add_filter( 'cocart_jwt_auth_secret_public_key', function( $key ) { return file_get_contents( COCART_JWT_AUTH_PUBLIC_KEY_PATH ); }); ``` **4. Using Key Strings Directly** Alternatively, you can use the RSA key strings directly in your code: ```php theme={"system"} add_filter( 'cocart_jwt_auth_algorithm', function( $algorithm ) { return 'RS256'; }); add_filter( 'cocart_jwt_auth_secret_private_key', function( $key ) { return << While using key strings directly in code is possible, it’s recommended to store them in secure environment variables or files for better security and key management. ## Benefits of RS256 * **Asymmetric Encryption**: Different keys for signing and verification. * **Better Security**: Private key can be kept secret on the authentication server. * **Scalability**: Public key can be distributed to multiple verification servers. * **Standard Compliance**: Widely used in enterprise applications. # Core Concepts Source: https://docs.cocartapi.com/getting-started/jwt/concepts JSON Web Tokens are an open standard (RFC 7519) for securely transmitting information between parties as a JSON object. In WordPress REST API authentication: ## JSON Web Tokens (JWT) JWTs consist of three parts: Header, Payload, and Signature, each base64-encoded and separated by dots. Tokens carry all necessary information, reducing database queries and improving performance. Digital signatures ensure token integrity and authenticity using cryptographic algorithms. Can include custom claims for additional user data or permissions. ## Token Types CoCart JWT Authentication implements a dual-token system for enhanced security. The system uses two distinct types of tokens: ### Access Tokens Short-lived tokens used for API authentication. They: * Carry user identity and permissions * Are included in the Authorization header for API requests * Have configurable expiration times * Are validated on each request ### Refresh Tokens Long-lived tokens used to maintain user sessions. They: * Are used to obtain new access tokens * Are stored securely in the database * Implement secure token rotation * Help maintain persistent authentication ## Token Lifecycle Understanding how tokens are managed throughout their lifetime: Tokens are generated upon successful authentication with user credentials. Each API request validates the token’s signature, expiration, and claims. Access tokens are renewed using refresh tokens before expiration. Tokens can be invalidated for security events or user actions. ## Rate Limiting Rate limiting is a security feature that helps protect your API from abuse by limiting the number of requests. For JWT, we force enable this feature when refreshing a client's token and validating within a specific time window. Rate limiting is only supported if you have [CoCart Plus](https://cocartapi.com) installed. ### How It Works Each request is tracked based on the client’s IP address. Requests are counted within a configurable time window. (default: 1 minute) * For refresh token, limits are exceeded to `10` requests per minute per IP. * For validating token, limits are exceeded to `2` requests per minute per IP. Then requests are blocked with a 429 (Too Many Requests) response. After the time window expires, the request count resets automatically. ### Rate Limit Headers CoCart Plus includes standard rate limit headers in API responses: #### `X-RateLimit-Limit` integer Maximum number of requests allowed in the current time window. #### `X-RateLimit-Remaining` integer Number of requests remaining in the current time window. #### `X-RateLimit-Reset` timestamp Unix timestamp when the current time window expires. #### `Retry-After` integer Seconds to wait before making another request. (only present when rate limited) ### Default Limits Different endpoints have different rate limits to balance security and usability: * **Token Validation**: 10 requests per minute per token * * Higher limit for API operations * * Applies to protected endpoints * **Token Refresh**: 2 requests per minute per refresh token * * Moderate limit for token renewal * * Prevents refresh token abuse # Quick Start Source: https://docs.cocartapi.com/getting-started/jwt/quick-start This guide assumes you have already installed and configured CoCart JWT Authentication. If not, please follow the [setup guide](/getting-started/jwt/setup) first. In the following request examples below, you would replace ``, ``, `` and `` with your credentials before sending the request. ## Authentication Flow ### 1. Get a Token To authenticate a user and get a JWT token: ```bash cURL theme={"system"} curl -X POST \ https://your-store.com/wp-json/cocart/v2/login \ -H "Content-Type: application/json" \ -d '{"username": "", "password": ""}' ``` ```php PHP theme={"system"} 'https://your-store.com/wp-json/cocart/v2/login', CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_HTTPHEADER => [ 'Accept: application/json', 'Authorization: Basic ' . base64_encode( . ':' . ) ] ]); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); ``` ```javascript JavaScript theme={"system"} const auth = btoa(':'); fetch('https://your-store.com/wp-json/cocart/v2/login', { method: 'POST', headers: { 'Accept': 'application/json', 'Authorization': `Basic ${auth}` } }); ``` ```json theme={"system"} { "user_id": "123", "first_name": "John", "last_name": "Smith", "display_name": "john", "role": "Customer", "avatar_urls": {}, "email": "users@emailaddress.xyz", "extras": { "jwt_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOlwvXC9jb2NhcnRhcGkubG9jYWwiLCJpYXQiOjE3Mzk3NTEzNzIsIm5iZiI6MTczOTc1MTM3MiwiZXhwIjoxNzQwNjE1MzcyLCJkYXRhIjp7InVzZXIiOnsiaWQiOjEsInVzZXJuYW1lIjoic2ViYXN0aWVuIiwiaXAiOiIxMjcuMC4wLjEiLCJkZXZpY2UiOiJIVFRQX1hfVUNCUk9XU0VSX0RFVklDRV9VQSJ9LCJzZWNyZXRfa2V5IjoiYmFuYW5hIn19.aBuyRwAtvGb6SI4BB_MN4NYN01jqVZN4PPnd1jfW2UA", "jwt_refresh": "90efc95f1d85e465951d10c309897629524b7fc1b40dfab75ed68f7c8540468a05b8b26995685821f52cf736edb566f3317432288af4c6e4edc281f6ab7af371" }, "dev_note": "Don't forget to store the users login information in order to authenticate all other routes with CoCart." } ``` If you require to pass the user-agent header when making requests. Applying it when logging in must be done for the token to remain valid. If you decide to pass the user-agent header after, then the token will no longer be valid and you will have to request a new one. ### 2. Use the Token Make authenticated requests using the token. Here’s an example using Cart endpoint to get the current user’s cart: ```bash cURL theme={"system"} curl -X GET 'https://your-store.com/wp-json/cocart/v2/cart' \ -H 'Authorization: Bearer ' ``` ```php PHP theme={"system"} '; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => 'https://your-store.com/wp-json/cocart/v2/cart', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $token ] ]); $cart = curl_exec($ch); curl_close($ch); ``` ```javascript JavaScript theme={"system"} const token = await getToken(); const cart = await fetch('https://your-store.com/wp-json/cocart/v2/cart', { headers: { 'Authorization': `Bearer ${token}` } }); ``` ### 3. Refresh Token When the access token expires, use the refresh token to get a new one: ```bash cURL theme={"system"} curl -X POST \ https://your-site.com/wp-json/cocart/jwt/refresh-token \ -H "Content-Type: application/json" \ -d '{"refresh_token": ""}' ``` ```php PHP theme={"system"} '; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => 'https://your-store.com/wp-json/cocart/jwt/refresh-token', CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $token ] ]); $cart = curl_exec($ch); curl_close($ch); ``` ```javascript JavaScript theme={"system"} const token = await refreshToken(); const cart = await fetch('https://your-store.com/wp-json/cocart/jwt/refresh-token', { method: 'POST', headers: { 'Authorization': `Bearer ${token}` } }); ``` ```json theme={"system"} { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOlwvXC9jb2NhcnRhcGkubG9jYWwiLCJpYXQiOjE3NDA1MTE5NDgsIm5iZiI6MTc0MDUxMTk0OCwiZXhwIjoxNzQxMzc1OTQ4LCJkYXRhIjp7InVzZXIiOnsiaWQiOjEsInVzZXJuYW1lIjoic2ViYXN0aWVuIiwiaXAiOiIxMjcuMC4wLjEiLCJkZXZpY2UiOiJIVFRQX1hfVUNCUk9XU0VSX0RFVklDRV9VQSJ9LCJzZWNyZXRfa2V5IjoiYmFuYW5hIn19.zHEHjVLE0Rrr7yY4z51bjhnm5ndkbR6J1nDzJNOZTK0", "refresh_token": "7dfc00d346277468b975a22768f861702b056e20f7cd84675b4dd4c0eb1148f034ae2610c548458a55213d62ea6034006466919166841e5f6797caeac5bd5e27" } ``` Remember to never expose your JWT secret key or store tokens in plain text. Always use secure storage methods appropriate for your platform. ### 4. Validate Token To keep check of a valid token: ```bash cURL theme={"system"} curl -X POST \ https://your-site.com/wp-json/cocart/jwt/validate-token \ -H "Authorization: Bearer YOUR-JWT-TOKEN" ``` **Successful** ```json theme={"system"} { "message": "Token is valid." } ``` **Invalid Token** ```json theme={"system"} { "code": "cocart_authentication_error", "message": "Authentication failed.", "data": { "status": 401 } } ``` # Setup Source: https://docs.cocartapi.com/getting-started/jwt/setup Learn how to setup JWT Authentication for CoCart. Make sure you have downloaded the [JWT Authentication for CoCart](https://wordpress.org/plugins/cocart-jwt-authentication/) plugin and installed it. ## Secret Key Configuration Add the following code to your **wp-config.php** file: ```php theme={"system"} define( 'COCART_JWT_AUTH_SECRET_KEY', 'YOUR-UNIQUE-SECRET-KEY' ); ``` Never share or commit your secret key. Keep it secure and unique for each environment. ## Enable PHP HTTP Authorization Header ### Shared Hosts Most shared hosting providers have disabled the **HTTP Authorization Header** by default. To enable this option you'll need to edit your **.htaccess** file by adding the following: ```apache theme={"system"} RewriteEngine on RewriteCond %{HTTP:Authorization} ^(.*) RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1] ``` or ```apache theme={"system"} RewriteEngine On RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] ``` ### WPEngine To enable this option you'll need to edit your **.htaccess** file by adding the following outside of IfModule: ```apache theme={"system"} SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 ``` Example of what that looks like. ```apache theme={"system"} # BEGIN WordPress RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] RewriteCond %{HTTP:Authorization} ^(.*) RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1] SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 # END WordPress ``` ## How It Works CoCart JWT Authentication implements a secure OAuth 2.0 compliant authentication flow. Here's how the authentication process works in your WordPress application: Client authenticates the login endpoint via Authorization header using the basic method to obtain JWT tokens. Use the JWT token to authenticate any REST API requests via Authorization header using bearer method. Use refresh token to obtain new access tokens without re-authentication via the refresh-token endpoint. Validate the token in the background of your application from time to time to check the users authentication session is still valid. ## Security Best Practices CoCart JWT Authentication comes with built-in security features to protect your WordPress application. Here are the key security measures you should be aware of: Automatic token revocation on password/email changes. Automatic token revocation on user deletion. Automatic token revocation on user logout. Configurable token expiration times. Secure refresh token rotation. # License Activation Source: https://docs.cocartapi.com/getting-started/license-activation Enter your CoCart license key to activate your license. > Dev Note: Needs to be completed with some additional updates for new license system. Once CoCart is installed you should see a new menu item named **CoCart** in your WordPress dashboard, plus the following notification that prompts you to activate your license for CoCart: This notification will ask you to enter your license key. Go to **CoCart > Updates** or click the **Activate License** link. This should bring up the license activation screen: Here you enter your license key. Copy your CoCart license key provided and paste it into the license field. Click **Save Changes**. Your license should now be active: Confirmation that you have activated your license. That’s it! You will now automatically receive updates for CoCart when they become available. After purchasing, you will receive a unique license key via email and your [Polar account](https://polar.sh/cocartheadless/portal/request) with your purchase. No, local and staging installations do not count against your license limit. You can use CoCart on as many local or staging sites as you like without affecting your active site limit. The following URLs are considered local or staging sites and will not count against your active site limit. **Local URLs**: * 192.168.x.x * 127.0.0.1 * localhost (includes) * .local (top-level domain) * .test (top-level domain) * .wip (top-level domain) * .docksal (docksal) * .docksal.site (docksal) * .dev.cc (ServerPress) * .lndo.site (Lando) **Staging URLs**: * .staging.kinsta.com (Kinsta.com) * .kinsta.cloud (Kinsta.com) * .stage.site (Dreampress) * .newspackstaging.com (Newspack) * .pantheonsite.io (Pantheon) * .flywheelsites.com (Flywheel) * .flywheelstaging.com (Flywheel) * .cloudwaysapps.com (Cloudways) * .azurewebsites.net (Azure) * .wpserveur.net (WPServeur) * -liquidwebsites.com (Liquidweb) * .myftpupload.com (Go Daddy) * .sg-host.com (Singapore Web Hosting) * .platformsh.site (Platform.sh) * .wpstage.net (WP Stagecoach) You can also always deactivate the license key from your site from your WordPress dashboard under CoCart > Updates, and activate it on another site. # Install CoCart Plus Source: https://docs.cocartapi.com/getting-started/plus/setup You can purchase CoCart Plus via cocartapi.com/pricing/ ### Download Plugin Once you have purchased a license for CoCart Plus, you will find the plugin under your [Customer Account](https://polar.sh/cocartheadless/portal/request) where you purchased. ### Upload Install Once the plugin is downloaded, log in to your WordPress dashboard, navigate to the ‘Plugins’ menu and press ‘Add New’. Then press ‘Upload Plugin’. You will either be redirected to a new page or the upload field will simple appear at the top allowing you to upload the plugin. Once the file is selected, press ‘Install Now’. Once the plugin is installed. Press ‘Activate Plugin’. ### Install via FTP Open your FTP program of choice and login to your FTP server. Access where your WordPress plugins folder is stored and upload the folder of the plugin that is in the zip file and put it in the plugins directory. Now log in to your WordPress dashboard, navigate to the ‘Plugins’ menu and press ‘Activate’ where CoCart is listed. # WordPress Setup Source: https://docs.cocartapi.com/getting-started/wordpress-setup The best way to host your WordPress site for headless store. Deciding on the best way to host and configure your WordPress site for headless store can be a daunting task. There are many options available, and it can be difficult to know which one is right for you. This guide will help you understand the different options available and specify the best ones for your needs. ## The different types of hosting available There are many different types of hosting available, but the most common ones are: * Shared hosting * VPS hosting * Dedicated hosting * Managed WordPress hosting Each type of hosting has its own pros and cons, and the best one for you will depend on your needs. ## The pros and cons of each type of hosting ### Shared hosting Shared hosting is the most common type of hosting. It is also the cheapest option, making it a good choice for small businesses and personal websites. However, shared hosting has some drawbacks. Because you are sharing a server with other websites, your website may be slower and less reliable than if you were on a dedicated server. Additionally, you may have limited control over your server environment, which can make it difficult to customize your website. ### VPS hosting VPS (Virtual Private Server) hosting is a step up from shared hosting. With VPS hosting, you have your own virtual server that is isolated from other websites. This means that your website will be faster and more reliable than with shared hosting. However, VPS hosting is more expensive than shared hosting, and it requires more technical knowledge to set up and manage. If you are not comfortable managing your own server, VPS hosting may not be the best option for you. ### Dedicated hosting Dedicated hosting is the most expensive option, but it also offers the most control and flexibility. With dedicated hosting, you have your own physical server that is not shared with any other websites. This means that you can customize your server environment to meet your specific needs. However, dedicated hosting is also the most complex option, and it requires a lot of technical knowledge to set up and manage. If you are not comfortable managing your own server, dedicated hosting may not be the best option for you. ### Managed WordPress hosting Managed WordPress hosting is a specialized type of hosting that is designed specifically for WordPress websites. With managed WordPress hosting, your website is hosted on a server that is optimized for WordPress, and you have access to a team of experts who can help you with any issues you may have. This type of hosting is more expensive than shared hosting, but it can save you time and hassle in the long run. If you are not comfortable managing your own server, managed WordPress hosting may be the best option for you. ## Taking advantage of the WordPress Configuration File The WordPress configuration file **wp-config.php** is located at the root of WordPress and allows you to customize your WordPress installation. By taking advantage of the WordPress configuration file, you can improve the performance and reliability of your website, and make it easier to manage. For running a headless WordPress setup, we will be looking at a few options that will help improve the performance of your WordPress site and reduce the number of database calls when accessing the REST API. ### WP\_SITEURL **Site URL** is the address where your WordPress site is installed. It should include the **https\://** part and should not have a slash **/** at the end. **Recommend**: If you are using a subdirectory for your WordPress installation, you should set the site URL to the root of your site. This will allow you to access your site from the root URL without having to include the subdirectory in the URL. ```php theme={"system"} define( 'WP_HOME', 'https://example.com/wordpress' ); ``` [More information](https://developer.wordpress.org/advanced-administration/wordpress/wp-config/#wp-siteurl) ### WP\_HOME **Home** is the address where you want your visitors to access your site. It should include the **https\://** part and should not have a slash **/** at the end. **Recommend**: If you are using a subdirectory for your WordPress installation, you should set the home URL to the root of your site. This will allow you to access your site from the root URL without having to include the subdirectory in the URL. ```php theme={"system"} define( 'WP_HOME', 'https://example.com/wordpress' ); ``` [More information](https://developer.wordpress.org/advanced-administration/wordpress/wp-config/#blog-address-url) ### Memory Limit Having enough memory for WooCommerce is a must, even for smaller stores. We recommend setting the memory limit to at least **128M**. ```php theme={"system"} define( 'WP_MAX_MEMORY_LIMIT', '128M' ); ``` [More information](https://developer.wordpress.org/advanced-administration/wordpress/wp-config/#increasing-memory-allocated-to-php) ### Disable File Edits Once your site is live, you should disable the ability to edit files from the WordPress admin. This will prevent any unauthorized changes to your site. ```php theme={"system"} define( 'DISALLOW_FILE_EDIT', true ); ``` ### Disable Updates Having updates running in the background can cause issues with your site on production. For piece of mind, we recommend you disable updates. ```php theme={"system"} define( 'AUTOMATIC_UPDATER_DISABLED', true ); ``` [More information](https://developer.wordpress.org/advanced-administration/wordpress/wp-config/#disable-plugin-and-theme-update-and-installation) ### Debugging WordPress Debugging WordPress is essential for identifying and resolving issues. However, it is important to disable debugging on production sites to prevent exposing sensitive information. While working on your headless site, we recommend this simple configuration to enable debugging. It will log errors to a file instead of displaying them on the screen. This is especially useful where you may not have direct access to the server logs. ```php theme={"system"} define( 'WP_DEBUG', true ); if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { // Enable Debug logging to the /wp-content/debug.log file define( 'WP_DEBUG_LOG', true ); // Disable display of errors and warnings define( 'WP_DEBUG_DISPLAY', false ); @ini_set( 'display_errors', 0 ); } ``` [More information](https://developer.wordpress.org/advanced-administration/wordpress/wp-config/#wp-debug) ## Setting up CORS to allow the frontend to access the REST API When using CoCart with a decoupled frontend, you will encounter CORS (Cross-Origin Resource Sharing) issues. CORS is a security feature implemented by web browsers to prevent malicious websites from making requests to other domains. To resolve CORS issues, you need to configure your server to allow requests from your frontend domain. This is done by setting the **Access-Control-Allow-Origin** header in your server's response. Simply set this filter `cocart_disable_all_cors` to `false` to enable CORS. ```php theme={"system"} Please see the getting started section for [CoCart setup](/getting-started/core/setup). Being based on the WordPress REST-API, it’s extremely easy to get started. REST (Representational State Transfer) is an architectural style for building web services that communicate over HTTP, similar to how web browsers interact with servers. It provides a standardized way for applications to exchange data and perform operations. Recommend reading the [REST API handbook](https://developer.wordpress.org/rest-api/) for more information. CoCart reads the WooCommerce data and exposes it safely in the REST API. This allows the use of most WooCommerce hooks to provide a wider array of support for most WooCommerce extensions out of the box. A headless store allows you to separate the front-end and back-end of your eCommerce application. This means you can use any technology stack for the front-end while still leveraging WooCommerce's powerful capabilities. Benefits include: * Flexibility in choosing front-end technologies. * Improved performance and user experience. * Easier integration with third-party services. * Enhanced scalability and maintainability. While it is possible to use the same domain for both WordPress and the headless store. It is recommended to use a subdomain or a different domain for the headless store to avoid conflicts and ensure better performance. We have a [WordPress setup guide](/getting-started/wordpress-setup) that provides our recommendations for setting up a headless store with CoCart. Yes. Just install CoCart and activate it on the sites you want to use CoCart. The base URL to access the REST API will be based on your network configuration type. CoCart is designed to be completely open to customization via **filters** and **action hooks**. CoCart does it's best to work out of the box with [WooCommerce extensions](/plugins/woocommerce-extensions) but we know that is not going to be always the case. If there is a compatibility issue with a plugin that you would like to work with CoCart. We would be happy to hear about it. Take a look at our [tested and verified list](/plugins/woocommerce-extensions) for extensions that work with CoCart. We also have a list of [incompatible plugins](/plugins/incompatible) that don't work with CoCart. With over 50,000 plugins available in the WordPress directory, WooCommerce’s marketplace and others out there in the WordPress abyss, some conflicts may arise. In the unusual circumstance that such an issue occurs, we will always do our utmost to try and resolve those conflicts through our friendly support. ## Performance CoCart does not slow down your WordPress site. We take performance seriously. CoCart was designed so you can have faster stores in your framework of choice. No. CoCart only creates one database table to handle session management as we use our own session handler. If you're familiar with WooCommerce, you may be wondering why using a custom session handler at all instead of the WooCommerce default session handler? A number of reasons but the ones that really matter are. * The default session handler only supports cookies. * The default session handler has no support for concurrent requests. * The default session handler **does not support guest customers without cookies**. * The default session handler **does not store additional session data to help you**. * The default session handler **does not allow support for POS capability** (coming soon). * More consistent with modern web. ## Support A TypeScript SDK is currently in the works. If you have a specific language that you would like an SDK for, please [contact us](mailto:support@cocartapi.com) to let us know or simply [make a feature request](https://cocartapi.com/suggest-a-feature/?ref=mintlify). Yes. [View roadmap](https://cocartheadless.featurebase.app/roadmap/status). You can get help either [via email](mailto:support@cocartapi.com) or [via our Discord server](https://cocartapi.com/community/). Please read our [support policy](https://cocartapi.com/support-policy/) on what is and what is not supported. That would be found at [WooCommerce.com](https://woocommerce.com). Please read our [support policy](https://cocartapi.com/support-policy/) on what is and what is not supported. Like WordPress itself, CoCart is also under constant, active development. That means that as the API evolves, you’ll be able to utilise the improvements introduced without major disruptions to your store and your development processes. ## Contribute Absolutely. Visit our translation site, [register an account](http://translate.cocartapi.com/wp-login.php?action=register) if you haven't already. Select the project you want to help translate, pick the language and start translating. If the language you’d like to translate the plugin into isn’t available yet, please [ask via email](mailto:support@cocartapi.com) with the subject **Requesting Translation Set** and let us know which one so a translation set can be created. Please view [opening issues](/resources/opening-issues) section for more information. We have more available in our [support center](/knowledge-base/faq). # CoCart: Decoupling WooCommerce for the modern storefront Source: https://docs.cocartapi.com/overview/introduction CoCart is a developer-first REST API to decouple WooCommerce on the frontend. ## What is CoCart? CoCart is the REST-API extension for WooCommerce designed specifically for developers and designers who want the power of a top tier eCommerce platform without the limitations of traditional WordPress themes and plugins. Build the modern and scalable storefront of your dreams with confidence independent of WordPress using frameworks like **Astro**, **React**, **Vue**, or **Next.js**, gaining complete control over your customers experience no matter what your store sells. ### Problems We Solve Seamlessly separate your frontend from WordPress, allowing for greater flexibility and customization. Efficient handling of requests to ensure fast and reliable interactions, even under heavy load. Comprehensive documentation and a supportive community to assist you in building your ideal storefront. Get started with CoCart in minutes, by downloading and installing our plugin on your WordPress site. Learn about CoCart's core standards for the REST API ## Core Features CoCart utilizes WooCommerce’s Data Stores API and mirrors most WooCommerce hooks, ensuring broad compatibility with numerous extensions right from the start. No cookie blockage. Secure cart key solution for database-based session management designed for headless. No Admin API Keys required. Basic authentication for customers are handled depending on your store needs for preferred login: * Username and Password * Email and Password * Phone Number and Password. Can be followed by JWT authentication. Addressing CORS issues in decoupled setups, CoCart grants you control over the origin to address any CORS issues when decoupling. [View CORS section](/documentation/learn/cors) for more info. Search products by name, ID, or SKU; filter and retrieve necessary product data with or without authentication, allowing different results based on role type i.e. Membership, Wholesale and more. Our system minimizes the need for multiple requests to verify item and coupon validity in your cart. It efficiently checks stock, calculates totals and fees, ensuring real-time accuracy so your responses are consistently up-to-date. Empower your customers to set their price, encouraging support with flexible payment options that broaden your paying audience. Batch multiple cart requests at once for efficiency and faster responses. [View Bulk Requests section](/documentation/learn/batch-requests) for more info ## Integration options These SDKs are still in development so in the mean time please refer to our [API Reference](/reference/core) for direct API calls. ### Native SDKs For web and Node.js applications For WordPress, Laravel, and other PHP applications ## Why Choose CoCart? Focus on building your unique storefront with an API designed specifically for WooCommerce to be decoupled. CoCart offers a developer-first approach, ensuring you have the tools and flexibility needed to create a seamless shopping experience. ### Community and Support CoCart is built in the open with full transparency and a growing community of developers and contributors. Access comprehensive documentation to help you every step of the way. GPL 3.0 license with full transparency on GitHub Feature requests, roadmap, and issues - all in the open ### Future-Proof Your Store Stay ahead with a solution designed to evolve with the latest web technologies and eCommerce trends. ### Get Started Today Ready to take your WooCommerce store to the next level? [Install CoCart now](/getting-started/core/setup) and start building the modern storefront you've always envisioned. # Roadmap Source: https://docs.cocartapi.com/overview/roadmap Understand what is currently being prioritized and what we are planning to build in the near future. We use community feedback to plan our roadmap, and we also encourage contributors to submit their ideas on [Discord](https://cocartapi.com/community/?ref=mintlify) so that we can discuss them with the community. You are also welcome to [submit ideas on the feedback board](https://cocartheadless.featurebase.app/?createPost=true). Feel free to vote/comment on any of them listed if any of them are important to you. [View roadmap](https://cocartheadless.featurebase.app/roadmap/) # Security Policy Source: https://docs.cocartapi.com/overview/security-policy An overview of CoCart Security Policy Full details of the CoCart Security Policy can be found on [cocartapi.com/security-policy/](https://cocartapi.com/security-policy/). ## Supported Versions The CoCart Headless Security Team believes in Responsible Disclosure by alerting the security team immediately and privately of any potential vulnerabilities. If a critical vulnerability is found in any of the current versions of a CoCart plugin, we may opt to backport any patches to previous versions. ### Core | Version | Supported | | -------- | --------- | | 5.0.x | Yes | | 4.6.x | Yes | | 4.5.x | Yes | | 4.4.x | Yes | | 4.3.x | Yes | | 4.2.x | No | | 4.1.x | No | | 4.0.x | No | | \< 4.0.0 | No | ### Plus | Version | Supported | | -------- | --------- | | 2.0.x | Yes | | 1.6.x | Yes | | 1.5.x | Yes | | \< 1.4.x | No | ### JWT Authentication | Version | Supported | | -------- | --------- | | 2.5.x | Yes | | 2.4.x | Yes | | 2.3.x | Yes | | 2.2.x | Yes | | 2.1.x | Yes | | 2.0.x | Yes | | \< 1.0.x | No | ## Reporting a Vulnerability **For responsible disclosure of security issues, please submit your report based on instructions found on [cocartapi.com/security-policy/](https://cocartapi.com/security-policy/).** Our most critical targets are: * CoCart Core [repository](https://github.com/co-cart/co-cart) * CoCart Plus * CoCart JWT Authentication [repository](https://raw.githubusercontent.com/cocart-headless/cocart-jwt-authentication) * cocartapi.com -- the primary marketplace and marketing site. ## Guidelines We're committed to working with security researchers to resolve the vulnerabilities they discover. You can help us by following these guidelines: * Pen-testing Production: * Please **setup a local environment** instead whenever possible. Most of our code is open source (see above). * If that's not possible, **limit any data access/modification** to the bare minimum necessary to reproduce a PoC. * **Don't automate form submissions!** That's very annoying for us, because it adds extra work for the volunteers who manage those systems, and reduces the signal/noise ratio in our communication channels. * Be Patient - Give us a reasonable time to correct the issue before you disclose the vulnerability. # Standards Source: https://docs.cocartapi.com/overview/standards Learn about CoCart's core standards for the REST API CoCart API provides public Rest API endpoints for the development of customer-facing cart, ~~checkout~~, and product functionality. It follows many of the patterns used in the [WordPress REST API](https://developer.wordpress.org/rest-api/key-concepts/). Example of a valid API request using cURL: ```http theme={"system"} curl "https://example-store.com/wp-json/cocart/v2/products" ``` Possible uses of the CoCart API include: * Obtaining a list of products to display that can be searched or filtered * Adding products to the cart and returning an updated cart object for display * Obtaining shipping rates for a cart * Collecting a customers's addresses ## Versioning CoCart API will be safely versioned using root path versioning, in the format `/v{major}`. For example, `/cocart/v2/cart`. The current supported WordPress REST API integration for CoCart is version `v2`. ## CoCart API Namespace Resources in the CoCart API are all found within the `cocart/v2` namespace, and since this API extends the WordPress API, accessing it requires the `/wp-json/` base. Examples: ``` GET /wp-json/cocart/v2/products GET /wp-json/cocart/v2/cart ``` The API uses JSON to serialize data. You don’t need to specify .json at the end of an API URL. If you want to change the CoCart API Namespace, we have an add-on in the works that will do just that. Please show interest by contacting support to be on waitlist. ## Versioning Strategy The main principles of the strategy are: 1. All breaking changes will be bundled into a new version 2. Deprecations for existing versions whenever a new version is announced is 6 months 3. In order to provide quicker adoption of new changes, they will be released on on ongoing basis 4. All API responses will contain the version of CoCart core via the returned header `CoCart-Version` if you have `WP_DEBUG` enabled which will be set to the current version of the plugin you are using. Should there be any fundamental requirement changes that require an API breaking change, we will notify via a blog post. ## Breaking Changes Breaking changes are any changes that require developer resources to maintain existing functionality. This includes resources used for investigation into the changes that need to be made, determination of features/endpoints being deprecated and final implementation of all these changes. A list of breaking changes are things like: * Removing a param from the API request/response * Modifying the name for any params or endpoints * Adding/changing optional or required params (e.g., making a customers name a required field in the request) We won’t make breaking changes to existing API endpoints for API versions lower than `v2`. If breaking changes are necessary that changes the data in the response, we’ll release a new major version. We may deprecate APIs that have been replaced by a newer version. When doing so, we will expect developers to manage a transition to the new resources within the deprecation timeline of old ones. Changes we do not consider to be breaking: * Adding new endpoints * Adding optional query parameters to API endpoints * Adding new properties to existing API responses * Reordering properties in existing API responses It is important that clients are built to be robust to these changes. **Deprecation**: Deprecated versions will be unsupported and it is recommended that developers cease to use these APIs. **Sunset**: Once an API is sunset, the corresponding set of endpoints will no longer be accessible via the API. ## Requirements and limitations * This is an unauthenticated API. It does not require API keys or authentication tokens for access. * All API responses return JSON-formatted data. * Data returned from the API is reflective of the current user (customer). Sessions are token based. * CoCart API cannot be used to look up other customers and orders by ID; only data belonging to the current user. * Likewise, CoCart API cannot be used to write store data e.g. settings. For more extensive access, use the authenticated [WooCommerce REST API](https://woocommerce.github.io/woocommerce-rest-api-docs/#introduction). * Endpoints that do allow writes, for example, updating the current customer address, require a cart key or user ID by authentication. * CoCart API is render-target agnostic and should not make assumptions about where content will be displayed. For example, returning HTML would be discouraged unless the data type itself is HTML. ## Pagination If collections contain many results, they may be paginated. When listing resources you can pass the following parameters: | Parameter | Description | | --------- | ---------------------------------------------------------------------------------- | | page | Current page of the collection. Defaults to 1. | | per\_page | Maximum number of items to be returned in result set. Defaults to 10. Maximum 100. | Large queries can hurt site performance, so `per_page` is capped at **100 records**. If you wish to retrieve more than 100 records, for example to build a client-side list of all available categories, you may make multiple API requests and combine the results within your application. In the example below, we list 20 products per page and return page 2. ```http theme={"system"} curl "https://example-store.com/wp-json/cocart/v2/products?page=2&per_page=20" ``` Additional pagination headers are also sent back to help determine how much more data is available. | Header | Description | | --------------- | ------------------------------------------------------------------- | | X-WP-Total | The total number of items in the collection. | | X-WP-TotalPages | The total number of pages in the collection. | | Link | Contains links to other pages; next, prev, and up where applicable. | ## Status Codes The following table gives an overview of how the API functions generally behave. | Request type | Description | | ------------ | ----------------------------------------------------------------------------------------------------------- | | `GET` | Access one or more resources and return `200 OK` and the result as JSON. | | `POST` | Return `201 Created` if the resource is successfully created and return the newly created resource as JSON. | | `PUT` | Return `200 OK` if the resource is modified successfully. The modified result is returned as JSON. | | `DELETE` | Returns `204 No Content` if the resource was deleted successfully. | The following table shows the possible return codes for API requests. | Status Code | Description | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `200 OK` | The request was successful, the resource(s) itself is returned as JSON. | | `201 Created` | The POST request was successful and the resource is returned as JSON. | | `204 No Content` | The server has successfully fulfilled the request and that there is no additional content to send in the response payload body. | | `400 Bad Request` | A required attribute of the API request is missing. | | `401 Unauthorized` | Authentication or permission error, e.g. incorrect login. | | `403 Forbidden` | Not allowed to process this action or have permission. | | `404 Not Found` | A resource could not be accessed, for example it doesn't exist. | | `405 Method Not Allowed` | A request method is not supported for the requested resource. | | `406 Not Acceptable` | Indicates that the server could not produce a response. | | `500 Internal Server Error` | While handling the request something went wrong server-side. | ## Route Handling Typically, routes handle the following types of requests: * `GET` requests to read product, cart, or checkout data. * `POST` and `PUT` requests to update cart and checkout data. * `DELETE` requests to remove cart data. * `OPTIONS` requests to retrieve the JSON schema for the current route. Ideally, your server should be configured to accept these types of API requests (`POST`, `PUT` and `DELETE`), but if not you can use the [`_method`](https://developer.wordpress.org/rest-api/using-the-rest-api/global-parameters/#_method-or-x-http-method-override-header) property. ## Response Headers CoCart returns specific and required headers for the API to function and help manage data control. ### Global Headers If you have `WP_DEBUG` set to true, the version of the core of CoCart will return. In addition a timestamp header is also introduced. * `CoCart-Version: 4.6.3` * `CoCart-Timestamp: time()` ### Cart Headers For the Cart API, three important headers return for managing the cart session. Use them to help track the cart session. * Cart Key: `CoCart-API-Cart-Key: ` * Cart Expiring: `CoCart-API-Cart-Expiring: ` * Cart Expiration: `CoCart-API-Cart-Expiration: ` ### CORS Headers When CORS is enabled, the following headers will return. * `Access-Control-Allow-Methods: OPTIONS, GET, POST, PUT, PATCH, DELETE` * `Access-Control-Allow-Credentials: true` * `Vary: Origin` * `Access-Control-Max-Age: 600` - This caches the result of preflight requests (600 is the upper limit for Chromium). * `X-Robots-Tag: noindex` * `X-Content-Type-Options: nosniff` Allowed preflight requests and any allowed origins will return: * `Access-Control-Allow-Origin: *` ### Cache Control * `Expires: Thu, 01-Jan-70 00:00:01 GMT` * `Cache-Control: no-cache, must-revalidate, max-age=0, no-store` // If the API is authenticated it will extend by adding `private` at the end. * `Pragma: no-cache` The products API additionally returns the last modified header with the date of the product it was last updated. * `Last-Modified: Thu, 29-July-25 14:05:30 GMT` ## Dates Datetime fields in the APIs conform to the **[ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)** date and time format in UTC. For example: `2025-03-22T11:56:48.520641Z`. ## Country Codes Countries are identified in the APIs using **[ISO 3166-1 Alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)** codes. For example: `GB` and `US`. ## Currency Currency are identified in the APIs using **[ISO-4217](http://en.wikipedia.org/wiki/ISO_4217)** codes. This is a three-letter string like `USD` or `EUR`. The value of a currency is represented by your WooCommerce store settings on the **General** tab. Most currencies have a “precision” of two (like USD: \$1.23). * `AED`, `VEF`, `PKR`, `IDR`, `HKD`, `QAR`, `PHP`, `NZD`, `INR`, `EUR`, `ARS`, `THB`, `MXN`, `EGP`, `DZD`, `SAR`, `LBP`, `COP`, `TRY`, `SGD`, `MAD`, `AUD`, `USD`, `MYR`, `CAD`, `BRL`, `GBP`. The following currencies don’t use a decimal: * `VND`, `KRW`, `CLP`, `JPY` And these use three decimal places: * `KWD`, `IQD`, `BHD`, `TND` It is important that you set the currency correctly for the API to return price values correctly. # Backers Source: https://docs.cocartapi.com/resources/backers Development of CoCart is made possible thanks to these awesome backers! You can become a backer by becoming a CoCart Sponsor or support by [purchasing a CoCart license](https://cocartapi.com/pricing/?ref=mintlify). All sponsors will be listed in the [BACKERS.md](https://github.com/co-cart/co-cart/blob/development/BACKERS.md) file. CoCart helps you contract work and you'd love to support its development further. **Reward**: Your name will be in **BACKERS.md** file. You're a small team of developers and CoCart provides what you need. You'd love to support its development further so it can be more awesome. **Reward**: Your names will be in **BACKERS.md** file. CoCart saves you time and money for your clients. You'd love to keep it maintained and support its development further. **Reward**: Your company logo will be in CoCart's **README.md** and **CoCart's** website. CoCart saves you time and money for your major clients. You'd love to keep it maintained and support its development further. **Reward**: Your company logo will be placed higher in CoCart's **README.md** and **CoCart's** website. You will also get some stickers. **Reward**: Your company logo will be placed at the very top above all other sponsors in CoCart's [README](https://github.com/co-cart/co-cart/blob/development/README.md) and on [CoCart's website](https://cocartapi.com/). You will also get some shiny stickers. # Community Source: https://docs.cocartapi.com/resources/community CoCart community initiatives Join the community discussions on GitHub. Join the community on Discord to chat with us and fellow CoCart users. Current issues that are being worked on. Issues have a status label to identify it's progress. Create a bug report to help improve CoCart. Publish your headless store for others to see. **Contact us** with a link to the store. Share feature requests and integration requests. Learn about the latest features and updates from CoCart. Follow us on **X/Twitter** to get notified when we release new features # Opening Issues Source: https://docs.cocartapi.com/resources/opening-issues Opening issues is a crucial step in open-source, as issues keep projects stable and help maintainers understand the needs of the community. To help us maintain a stable project, please observe the following guidelines and general rules: ## Open issues for bugs only We ask that **issues are only opened for bugs**, and not for questions. Questions should be asked in [Discussions](https://github.com/co-cart/co-cart/discussions) or on [Discord](https://cocartapi.com/community/?ref=mintlify). While you may open a request for a feature. It would be best to ask in [Discussions](https://github.com/co-cart/co-cart/discussions) first to see if such a feature is possible. ## Include a proper reproduction To ensure your issue can be addressed, please **include a proper reproduction**. Please avoid: * Setting the link to the reproduction pointing to our repository * Providing a code snippet that does not sufficiently reproduce the issue Failing to include a proper reproduction may require extra back-and-forth between you and us, slow the process of fixing the issue for you and others, and make it harder to check if the issue has been fixed on a new release. ## Test the latest version before opening an issue Before opening an issue regarding a bug, please test with the latest stable version. If the bug is fixed, you can still open an issue, and we will tag it with Fixed under the trunk branch so others will know it has been fixed. If you do find that the bug was introduced in a specific version, and an older version didn’t have the issue then you should mention that this is a regression and in what versions it was introduced. ## Conclusion Now that you are ready, click below to open an issue! Thank you so much for contributing. Current issues that are being worked on. Issues have a status label to identify it's progress. Create a bug report to help improve CoCart. # Support Policy Source: https://docs.cocartapi.com/resources/support-policy # Mix and Match Products for WooCommerce Source: https://docs.cocartapi.com/api-reference/plugins/wc-mix-and-match-products Allows customers to create their own product bundles. Selling cases of wine? A dozen donuts? Fruit baskets? Six-packs of T-shirts? [Mix and Match Products](https://woocommerce.com/products/woocommerce-mix-and-match-products/) is ideal for offering similar products in bulk containers. Perfect for encouraging customers to buy in bulk without forcing them to buy items that don’t interest them. Mix and Match Products supports CoCart since v1.10.0 ## Add item to cart Add a container with the customers selected items and quantity. ```bash cURL theme={"system"} curl -X POST https://your-store.com/wp-json/cocart/v2/cart/add-item \ -H "Content-Type: application/json" \ -d '{ "id": "1102", "quantity": "2", "item_data": { "mnm_config": [ { "product_id": 987, "quantity": 1 }, { "product_id": 1001, "quantity": 2 }, { "product_id": 1003, "quantity": 3 } ] } }' ``` # Name Your Price for WooCommerce Source: https://docs.cocartapi.com/api-reference/plugins/wc-name-your-price Allow customers to define the product price. Also useful for accepting user-set donations. The [Name Your Price](https://woocommerce.com/products/name-your-price/) plugin extension lets you be flexible in what price you are willing to accept for selected products. You can use this plugin to accept donations or to take a new approach to selling products. You can suggest a price to your customers and optionally enforce a minimum acceptable price, or leave it entirely in the hands of the customer. Name Your Price supports CoCart since v3.1.0 ## Add item to cart Apply the customers requested price for the product when adding item to cart. ```bash cURL theme={"system"} curl -X POST https://your-store.com/wp-json/cocart/v2/cart/add-item \ -H "Content-Type: application/json" \ -d '{ "id": "129", "quantity": "1", "item_data": { "nyp": 24 } }' ``` # Remove item from cart Source: https://docs.cocartapi.com/api-reference/v2/cart/delete-item-by-key api-reference/v2/openapi-v2-stable.yaml delete /cart/item/{item_key} Removes a specific item from the customer's cart. By default returns the updated cart contents. Set return_status=true to get just a removal message. # Get Cart Items Count Source: https://docs.cocartapi.com/api-reference/v2/cart/get-items-count api-reference/v2/openapi-v2-stable.yaml get /cart/items/count Returns the count of items in the customer's cart. # Get Cart Totals Source: https://docs.cocartapi.com/api-reference/v2/cart/get-totals api-reference/v2/openapi-v2-stable.yaml get /cart/totals Get the carts totals. This endpoint will be deprecated in the future. Recommend getting the totals from the main **cart** endpoint. # Update cart Source: https://docs.cocartapi.com/api-reference/v2/cart/post-cart-update api-reference/v2/openapi-v2-stable.yaml post /cart/update Updates multiple cart items or properties at once. # Update Item in Cart Source: https://docs.cocartapi.com/api-reference/v2/cart/post-item-by-key api-reference/v2/openapi-v2-stable.yaml post /cart/item/{item_key} Updates the quantity or other properties of a specific item in the customer's cart. By default returns the updated cart contents. Set return_status=true to get a status message with quantity info. # Restore Item to Cart Source: https://docs.cocartapi.com/api-reference/v2/cart/put-item-by-key api-reference/v2/openapi-v2-stable.yaml put /cart/item/{item_key} Restores a previously removed item back to the customer's cart. By default returns the updated cart contents. Set return_item=true to get just the restored item details. # Get a Single Product Source: https://docs.cocartapi.com/api-reference/v2/products/get-product api-reference/v2/openapi-v2-stable.yaml get /products/{id} Gets a single product by ID or SKU. # Get a Product Attribute by ID Source: https://docs.cocartapi.com/api-reference/v2/products/get-product-attribute-by-id api-reference/v2/openapi-v2-stable.yaml get /products/attributes/{id} Gets a single product attribute by ID. # Get a Product Attribute Term by ID Source: https://docs.cocartapi.com/api-reference/v2/products/get-product-attribute-term api-reference/v2/openapi-v2-stable.yaml get /products/attributes/{attribute_id}/terms/{id} Gets a single term for a specific product attribute. # Get a Product Attributes Terms Source: https://docs.cocartapi.com/api-reference/v2/products/get-product-attribute-terms api-reference/v2/openapi-v2-stable.yaml get /products/attributes/{id}/terms Gets terms for a specific product attribute. # Get Product Attributes Source: https://docs.cocartapi.com/api-reference/v2/products/get-product-attributes api-reference/v2/openapi-v2-stable.yaml get /products/attributes Gets a list of product attributes. # Get Product Categories Source: https://docs.cocartapi.com/api-reference/v2/products/get-product-categories api-reference/v2/openapi-v2-stable.yaml get /products/categories Gets a list of product categories. # Get Product Category by ID Source: https://docs.cocartapi.com/api-reference/v2/products/get-product-category-by-id api-reference/v2/openapi-v2-stable.yaml get /products/categories/{id} Gets a single product category by ID. # Get a Product Review Source: https://docs.cocartapi.com/api-reference/v2/products/get-product-review api-reference/v2/openapi-v2-stable.yaml get /products/reviews/{id} # Get Product Reviews Source: https://docs.cocartapi.com/api-reference/v2/products/get-product-reviews api-reference/v2/openapi-v2-stable.yaml get /products/reviews Gets a list of product reviews. # Get Product Category by ID Source: https://docs.cocartapi.com/api-reference/v2/products/get-product-tag-by-id api-reference/v2/openapi-v2-stable.yaml get /products/categories/{id} Gets a single product category by ID. # Get Product Tags Source: https://docs.cocartapi.com/api-reference/v2/products/get-product-tags api-reference/v2/openapi-v2-stable.yaml get /products/tags Gets a list of product tags. # Get a Product Variation Source: https://docs.cocartapi.com/api-reference/v2/products/get-product-variation api-reference/v2/openapi-v2-stable.yaml get /products/{id}/variations/{variation_id} Gets a single variation for a variable product. # Get a Products Variations Source: https://docs.cocartapi.com/api-reference/v2/products/get-product-variations api-reference/v2/openapi-v2-stable.yaml get /products/{id}/variations Gets variations for a variable product. # Get Products Source: https://docs.cocartapi.com/api-reference/v2/products/get-products api-reference/v2/openapi-v2-stable.yaml get /products Gets a list of products with optional filtering and pagination. # Delete a Session Source: https://docs.cocartapi.com/api-reference/v2/sessions/delete-session api-reference/v2/openapi-v2-stable.yaml delete /sessions/{id} Deletes a specific cart session by session key. # Get a Session Source: https://docs.cocartapi.com/api-reference/v2/sessions/get-session api-reference/v2/openapi-v2-stable.yaml get /sessions/{id} Gets a specific cart session by session key. # Retrieve Sessions Source: https://docs.cocartapi.com/api-reference/v2/sessions/get-sessions api-reference/v2/openapi-v2-stable.yaml get /sessions Gets a list of cart sessions for administrative purposes. # Store Source: https://docs.cocartapi.com/api-reference/v2/store/get-store api-reference/v2/openapi-v2-stable.yaml get /store Gets general store information including routes and configuration. Both the version and routes only return when `WP_DEBUG` is set to `true`. # Login User Source: https://docs.cocartapi.com/api-reference/v2/user/post-login api-reference/v2/openapi-v2-stable.yaml post /login Logs in a user and creates a session. # Logout User Source: https://docs.cocartapi.com/api-reference/v2/user/post-logout api-reference/v2/openapi-v2-stable.yaml post /logout Logs out the current user and destroys the session. Originally this endpoint was used to log out a user and their cart session when relying on WooCommerce session cookie. While the endpoint is not needed to clear the users session anymore, you can still use it to clear any WordPress cookies that may have been set. # CoCart Core v4 Source: https://docs.cocartapi.com/breaking-changes/core-v4 These breaking changes affect how CoCart handles cart sessions. Since the cart key is provided in both the cart response and returned headers. Saving the cart key in your own cookie or local storage is recommended. CoCart core v4.2 introduced a significant architectural change to how cart sessions are managed. * **Cart keys** are now the primary method for identifying cart sessions for both guest and authenticated users. **No more WooCommerce session cookies when using the API**. * All session management handled by CoCart makes it more reliable for headless and decoupled WooCommerce stores. This change helps with the confusion of needing to pass along the session cookie or reading the cookie to extract the cart key and help with user switching much better. We got mixed feedback for before this change, so by removing the cookie the session handler relied on before, the developer has better control over it. **Developer Impact** * If you previously relied on WooCommerce’s session cookies with CoCart, you must now use the cart key returned. * All custom integrations, middleware, or client apps must store and send the cart key with every relevant API request. ## Versions not to install * `4.0.0` - Was missing a required class. `4.0.1` fixes that. * `4.2.0` - A deprecated function was causing a fatal error. Fixed with `4.2.1` * `4.3.1` - Hot fix in `4.3.2` corrected issues that affected CoCart since `4.2.0` and patches were applied to previous versions to prevent roll update issues for those who had not updated automatically. ## Deprecations We advise that you update on staging or local to check if you have used any of our experimental functions and filters that were added to the session handler to see if any have been deprecated. You can also see the list of deprecations below. * Removed the legacy API that CoCart started with. * Removed support for stores running lower than WooCommerce version 4.5 * User switching removed. Never worked 100%. Mainly added for internal debugging purposes. * No longer use `cocart_override_cart_item` filter. Recommend using `cocart_item_added_to_cart` action hook instead. * No longer user `cocart_cart_updated` hook. Replaced with `cocart_update_cart_before_totals` hook. * Removed the need to support web host "Pantheon" by filtering the cookie name. * Removed our session abstract `CoCart_Session` that extended `WC_Session`. Any remaining functions have moved to a refreshed session handler. * Function `CoCart_Session_Handler::destroy_cookie()` no longer used. * Function `CoCart_Session_Handler::cocart_setcookie()` no longer used. * Function `CoCart_Session_Handler::get_cart()` no longer used. * Filter `cocart_cookie` no longer used. Use `woocommerce_cookie` instead. * Filter `cocart_cookie_httponly` no longer used. * Filter `cocart_cookie_supported` no longer used. * Filter `cocart_set_cookie_options` no longer used. * Filter `cocart_cart_use_secure_cookie` no longer used. Use `wc_session_use_secure_cookie` instead. * Filter `cocart_is_cart_data_valid` no longer used. * Returned headers `X-CoCart-API-Timestamp` and `X-CoCart-API-Version` no longer used. # JWT Authentication Source: https://docs.cocartapi.com/cli-reference/cli-jwt These commands are strictly designed to help with your development. ## Clean up tokens Cleans up expired JWT tokens. ```bash theme={"system"} wp cocart jwt cleanup [--batch-size=] [--force] ``` ### Arguments Number of users to process per batch (default: 100) (Optional) Force cleanup of all tokens (Optional) **Examples:** ```bash theme={"system"} wp cocart jwt cleanup --batch-size=50 wp cocart jwt cleanup --force ``` ## View token details Displays details of a JWT token in a table. ```bash theme={"system"} wp cocart jwt view ``` ### Arguments The JWT token to view **Example:** ```bash theme={"system"} wp cocart jwt view eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOlwvXC9jb2NhcnRhcGkubG9jYWwiLCJpYXQiOjE3Mzk3NTEzNzIsIm5iZiI6MTczOTc1MTM3MiwiZXhwIjoxNzQwNjE1MzcyLCJkYXRhIjp7InVzZXIiOnsiaWQiOjEsInVzZXJuYW1lIjoic2ViYXN0aWVuIiwiaXAiOiIxMjcuMC4wLjEiLCJkZXZpY2UiOiJIVFRQX1hfVUNCUk9XU0VSX0RFVklDRV9VQSJ9LCJzZWNyZXRfa2V5IjoiYmFuYW5hIn19.aBuyRwAtvGb6SI4BB_MN4NYN01jqVZN4PPnd1jfW2UA ``` ## Lists tokens Lists all active JWT tokens. ```bash theme={"system"} wp cocart jwt list [--page=] [--per-page=] ``` ### Arguments Page number to display (default: 1) Number of tokens to display per page (default: 20) **Example:** ```bash theme={"system"} wp cocart jwt list --page=2 --per-page=10 ``` ## Create token Generates a new JWT token for a user. ```bash theme={"system"} wp cocart jwt create --user= [--user-agent=] ``` ### Arguments The user ID, email, or login to generate the token for The User Agent to override the server User Agent (optional) **Examples:** ```bash theme={"system"} wp cocart jwt create --user=123 wp cocart jwt create --user=admin@example.com --user-agent="Custom User Agent" ``` ## Destroy tokens Destroys JWT tokens for a specific user. ```bash theme={"system"} wp cocart jwt destroy [--pat=] [--force] ``` ### Arguments The user ID, email, or login to destroy tokens for Specific PAT token ID to destroy (optional) Force destroy without confirmation (optional) **Examples:** ```bash theme={"system"} wp cocart jwt destroy 1 wp cocart jwt destroy admin@example.com --force wp cocart jwt destroy username --pat=pat_abc123 ``` # Introduction Source: https://docs.cocartapi.com/cli-reference/introduction Welcome to the CLI Reference for CoCart. ## What is CoCart CLI? CoCart CLI (COCART-CLI) offers an efficient way to manage carts via the command line. This tool is an add-on and leverages the capabilities of the CoCart REST API. This means that most tasks achievable through the REST API can also be performed via the command line. ## Frequently Asked Questions CoCart CLI is an add-on that is part of CoCart Pro tier. You will find it as one of the benefits in your account. Simply download and install the plugin. CoCart CLI is a part of WP-CLI specifically designed for CoCart. While WP-CLI deals with general WordPress management, COCART-CLI focuses on CoCart-specific tasks. ## Troubleshooting This error often occurs if your user role doesn’t have the necessary permissions. Ensure you’re using an account with administrative privileges. Check for typos and verify the command syntax with –help. If the issue persists, consult the Command Reference or seek support from the CoCart community. # Code snippets added the right way Source: https://docs.cocartapi.com/knowledge-base/adding-code How to apply any CoCart filter or action hook the safe way The best way to apply changes to your WordPress site is to add them in parts/snippets without touching any files in a plugin or the theme your using. Editing other PHP file carries the risk of breaking the rest of the code in the file and also opens you to the potential that the code will be lost when you update. There are several functionality plugins available in the WordPress.org repository. The instructions below explain how to install and use a plugin called **[Code Snippets](https://wordpress.org/plugins/code-snippets/)**. 1. Go to Plugins → Add New, search **Code Snippets** and install and activate the plugin. This will add a Snippets item to your wp-admin dashboard menu. 2. Navigate to Snippets → Add New. 3. Enter a title. 4. Paste or type your code in the Code field. 5. Click "Save Changes and Activate". *** Install via **WP-CLI command**. ```bash theme={"system"} wp plugin install code-snippets --activate ``` If you have set a priority on the filter/hook. It is best that you set the **priority** at the same level. You also want to set/leave it on "Run snippet everywhere". # Cart Key Source: https://docs.cocartapi.com/knowledge-base/cart-key ## What is a Cart Key? A cart key is what identifies the cart stored in session along with it's cart data and expiration. The cart key by default, will be a random set of letters and numbers or if the Cart API request is authenticated, it will relate to the user ID of the authenticator instead. If you try to identify a registered user via the cart key then you will be asked to authenticate as that user instead. ## Finding the Cart Key You can find the cart key returned in the cart response called `cart_key` and via the returned headers called `CoCart-API-Cart-Key` once the first API request has been made. Once you have the cart key, you can then use it to set the `cart_key` as a global parameter with any of the Cart API routes to load that cart. Without the cart key set for other Cart API routes, any requests made will not be applied to the appropriate cart session. This is partially important when adding, updating or removing items to and from the cart as such. The same for coupons, fees and other cart related requests made. The cart\_key parameter is a global parameter so it must be queried rather than being added as part of the body data you send with the API request you make. Otherwise it will not update the appropriate cart. Should you fail to do so correctly will lead to adding items stored in their own individual cart session which you will not be able to recover from previous requests. ## Creating a Cart Key Manually You can create your own cart key but, it cannot be longer than **42 characters** as that is the limit for storing the key in the database. ### HTTP request /wp-json/cocart/v2/cart?cart\_key=mycartkey123 If you do create your own cart key, it is best that you do so when adding the first item to the cart in order to update the correct cart from the start. # Support Source: https://docs.cocartapi.com/knowledge-base/contact-us We love to support customers, quickly. Reach out anytime. Thank you for reaching out and helping us make CoCart & our docs better. We greatly appreciate it! Join the community discussions on GitHub. Join the community on Discord to chat with us and fellow CoCart users. Open a new issue for a bug report to help improve CoCart. Tell us about the feature you would like. ## Email You can reach us at [support@cocartapi.com](mailto:support@cocartapi.com) # Frequently Asked Questions Source: https://docs.cocartapi.com/knowledge-base/faq A collection of answers to your possible questions. At CoCart, we're here to help. You'll find instant answers to nearly every question by searching our knowledge base. If you still need help, please [contact us](mailto:support@cocartapi.com) for personal support. ## Pre-Sale Questions No. But you can try the latest version of CoCart [online for free by creating a sandbox](https://cocartapi.com/try-free-demo/) to see if it's right for you. Yes. But before you make a decision to purchase. We recommend that you [try creating a sandbox](https://cocartapi.com/try-free-demo/) first to try the product out at **no cost**. See [refund policy](https://cocartapi.com/refund-policy/) for more information. Yes you can. [Login to your Polar account](https://polar.sh/cocartheadless/portal/request) and you can manage which tier you wish to change to. Otherwise, [contact support](mailto:support@cocartapi.com) for assistance. We accept all major credit cards, Cash App Pay, U.S. Bank Account, Apple Pay and Google Pay. All payments are processed securely through [Polar](https://polar.sh). Yes. During checkout you can fill in your company details and an invoice is automatically generated and sent to you. Our order process is conducted securely by our online reseller [Polar](https://polar.sh). Polar is our Merchant of Record for all our orders and they will invoice and charge you. VAT is a required sales tax in some countries. Fill in your company details during checkout and the VAT will be deducted. Usually it's your bank issuing the decline, for a number of different reasons like insufficient funds, they think the transaction is fraudulent or you typed the wrong CCV. Unfortunately, banks rarely send along the real reason for declining a transaction and if it's none of the above, the only recourse is to contact your bank to figure out what the problem is. To keep giving you continued access to updates, yes. Subscriptions will renew automatically for you unless paused or cancelled. If you cancel your subscription at any time, you will lose access to updates and support once the billing period ends. No. It is up to you to keep track of your subscription. Once cancelled, your license remains active until the end of your current billing period. After that, the license status changes to “cancelled” you will no longer have access to updates and support. You can still use CoCart as before, you just won’t be able to receive updates. Please be aware that running outdated versions of any software brings an inherit security risk with it. Yes you can, but please know that when it comes to renewing your license, plugin updates past your subscription will not be available to you. We do not. Lifetime deals are really for products/services that don’t require much maintenance or any for that matter to keep working. As CoCart is an extension of WooCommerce, updates are important to keep up with changes they make which is why we do subscription only. All our WordPress plugins are multisite compatible. See Multisite questions below for more specifics. Yes. All our WordPress plugins are compatible with WordPress.com Business and eCommerce plans, which allows installation of plugins. Yes, we offer PPP for countries with significantly lower average income to make our prices fair for everyone. [Contact us](mailto:support@cocartapi.com) with proof of residence to receive a discount code. ## Multisite Questions To use one of our plugins on a WordPress multisite, you will need a license for each sub-site where you will be using it. For example: * If you want to use it on 5 sites in a multisite then you will need a license for 5 sites. * If your multisite contains 10 sites but you only want to use the plugin on 1 site, you will need a single site license. You should enter the license key on the plugin settings page for each site where you want to use the plugin. Yes, the plugin should be network activated even if you are only using it on 1 site within the multisite. This is needed in order to update the plugin. Yes, you can upgrade your license. If you need more than 20 sites, please get in touch. ## Support and Plugin Questions We offer support for all our products through our [Discord community](https://cocartapi.com/community). Support is available to all users with a valid license key. Plugin updates for the core plugin and any free add-ons will always get free updates. CoCart Plus and any premium add-on requires a valid license key to receive updates. CoCart can be updated either via one-click update or manually. When an update becomes available, you will receive a notification on your **Plugins** page. To update CoCart, simply click on the "Update Now" link in the notification on the Plugins page. If you prefer to update manually, you can download the new version of the plugin from the WordPress plugin repository. You can then safely delete the plugin directory on your server, and upload the new version via FTP. We can’t imagine why you’d want to, but you most certainly can uninstall. You’ll need to deactivate CoCart first by clicking on the "Deactivate" link on the Plugins page, followed by the "Delete" link. This will remove all of the plugin’s files from the WordPress plugins directory. It does not deactivate your license and you will need to repeat the process if you have any CoCart add-ons installed as well. Uninstalling CoCart will not affect any of your store data such as products or orders should you decide to not use CoCart. Please note, however, your headless store will no longer have access to any of CoCart's API endpoints and all current cart sessions will no longer exist. If you are using CoCart specific functions to access data in your plugin files, these functions will no longer exist, and your website will no longer function as expected. CoCart utilizes all WooCommerce functions and hooks so other plugins that rely on them are compatible. Some plugins expect certain behaviour when items are added to the cart so we do our best to cover those expectations in a guide should it be needed. There are over **50K plugins** available in the WordPress directory, WooCommerce’s marketplace and others out there in the WordPress abyss, some conflicts may arise. In the unusual circumstance that such an issue occurs, we will always do our utmost to try and resolve those conflicts through our friendly support. We do have a [list of WooCommerce extensions](/plugins/woocommerce-extensions.mdx) that have been tested and are known to work with CoCart. ## License Questions A license key, also known as an activation key, is a unique alphanumeric code used to authenticate and activate software. It serves as a form of digital rights management (DRM) to ensure that only legitimate users can access and use the software. It also enables us to control and monitor the number of installations and ensure that users comply with the terms of the software license agreement. After purchasing, you will receive a unique license key via email and your [Polar account](https://polar.sh/cocartheadless/portal/request) with your purchase. If you lose your license key, you can retrieve it from your [Polar account](https://polar.sh/cocartheadless/portal/request) or contact support for assistance. If you only purchased a license for one site, you first need to deactivate the license key from the CoCart updates page on the domain it was activated on. Then simply activate the license key on the domain you want. If you originally activated the license key on a staging/local site then it won't count as a site activation and you can simply go ahead and activate the license key on the production site. Absolutely! You can use your CoCart license on your own and your client’s websites. A client being someone you build a website for with CoCart. Reselling of the license itself is strictly against our terms. Yes, you can! However, all support requests will need to come through the license holder. Your clients will not have direct access to support. License keys are used to enable plugin updates. After purchase, you will receive a unique license key (alongside your CoCart plugin download). The key can be activated from your WordPress dashboard’s plugin page. License keys can be activated, deactivated and upgraded at any time. No, local and staging installations do not count against your license limit. You can use CoCart on as many local or staging sites as you like without affecting your active site limit. The following URLs are considered local or staging sites and will not count against your active site limit. **Local URLs**: * 192.168.x.x * 127.0.0.1 * localhost (includes) * .local (top-level domain) * .test (top-level domain) * .wip (top-level domain) * .docksal (docksal) * .docksal.site (docksal) * .dev.cc (ServerPress) * .lndo.site (Lando) **Staging URLs**: * .staging.kinsta.com (Kinsta.com) * .kinsta.cloud (Kinsta.com) * .stage.site (Dreampress) * .newspackstaging.com (Newspack) * .pantheonsite.io (Pantheon) * .flywheelsites.com (Flywheel) * .flywheelstaging.com (Flywheel) * .cloudwaysapps.com (Cloudways) * .azurewebsites.net (Azure) * .wpserveur.net (WPServeur) * -liquidwebsites.com (Liquidweb) * .myftpupload.com (Go Daddy) * .sg-host.com (Singapore Web Hosting) * .platformsh.site (Platform.sh) * .wpstage.net (WP Stagecoach) ## Troubleshoot Questions In some hosting environments, communication may not be possible between your server and the WordPress update server. If this happens to you, please note any error messages you find, and [contact support](mailto:support@cocartapi.com). This is possibly because you did not set the cart key as a global parameter on other Cart API requests. So all your seeing is the last item added to the cart. If you are using a caching plugin, you will need to exclude the cart API from being cached. The best way to do this is to exclude the entire `/cocart/v2/cart` endpoint from being cached. This will ensure that all cart-related requests are not cached. Currently CoCart already excludes from being cached in the following cache plugins: * [LiteSpeed](https://wordpress.org/plugins/litespeed-cache/) * [WP REST Cache](https://wordpress.org/plugins/wp-rest-cache/) * [WP REST API Cache](https://wordpress.org/plugins/wp-rest-api-cache/) * [WP Rocket](https://wp-rocket.me/) Unfortunately, no. This is because when you authenticate as the admin, you are logged in not the customer. Even if you specified the customers user ID as the cart key. It will not take affect. If you have **WP\_DEBUG** set to `true` in your [wp-config.php](#wp-config-php) file then you should be able to view all the logs recorded by CoCart under **WooCommerce -> System Status -> Logs** in your WordPress dashboard. URL Example: `https://example-store.com/wp-admin/admin.php?page=wc-status&tab=logs` You can also [change how the logs are presented](#filters-api-access-cocart-logging). # Don't Use Nulled Versions! Source: https://docs.cocartapi.com/knowledge-base/nulled-plugins Warning: Nulled plugins are bad for your website. We know money is short for all of us, and there aren’t many things more appealing than saving money when extending your website with that one crucial feature you need. Sooner or later, you will find copies of plugins offered for free or as part of a cheap yearly subscription. These copies are called nulled. They disable the licensing system of the plugin and offer it to you to save money. ## What are nulled plugins? You will get many results from websites offering a free license if you search for a specific plugin and add the term “nulled” at the end. They often do this by buying a single license and reselling it or downloading it from an active user by exploits (hacks). A bunch of examples could be: * CoCart Plus nulled * CoCart Pro nulled ## Should I use a nulled version? The short answer is no, but let me explain that a bit further to you. Here are a couple of reasons why you shouldn’t use a nulled version of one of our plugins: ### Malicious Code Nulled versions often include malicious code. This can be as simple as displaying ads on your website. Sometimes they even implement ways to steal all your user data (e-mails, passwords, names..). Installing and using nulled software always comes with a risk, and you shouldn’t be surprised if something wrong happens after using them. ### Updates Nulled versions aren’t regularly updated, and you can’t update them from your admin dashboard. Each time a new version is released, you need to return to the website, check if they have the updated version, and download and install them again. ### No support By using a nulled version, you don’t get access to support. If something breaks or doesn’t work as expected, you are left alone and can’t reach out to customer support to get help. We will do our best to warn you if a nulled version is detected on your site but there is no guarantee. ### SEO You may lose a bunch of rankings in Google using a nulled version of a plugin. Often these include hidden links to spam sites. Google will penalize your website by linking to those sites, and you will see a decrease in traffic to your website. ### Stealing money from the developer You may not care much about the developer behind the product, but imagine a developer stops working on the product because he doesn’t make enough money to justify the invested time for development. This may end up to the point that your website is completely broken because of missing updates, and there is no one to reach for help. ## What should I do? If you are looking for a way to save money, use our official coupon code to get a discount on our plugins. It's better to support the developers and get the official version of the plugin. # Plugin Suggestions Source: https://docs.cocartapi.com/knowledge-base/plugin-suggestions Discover other plugins we suggest FYI: Plugin suggestions only show to those who have CoCart Core v3.0 or above installed. Plugin Suggestions help you to discover other plugins that may provide features you are looking for from extending or supporting CoCart. These suggestions are added to the WordPress plugin search results page. The suggestions range from addons developed by CoCart or extensions developed by **WooCommerce** or **Third Party** developers that offer many useful features that users may not even realize are available, offering a functional solution to a particular problem. Plugin Suggestions works directly on a plugin search page when you’re looking for a feature that matches any specific key phrases. It adds a search result to the bottom of the listing that highlights the plugin matching the keywords you’re searching for with it’s name, author and possibly a link to learn more about it. Should you wish to just browse all available add-ons or supported extensions, you can just simply go to “CoCart” section under the plugin install page. Should the plugin be already installed on your site, the action link will be replaced with either “Activate” or “Installed & Active”. ## Using Plugin Suggestions \[CoCart Suggestion] 1. Start at Plugins → Add New in your WordPress dashboard. 2. Search for a plugin that CoCart may offer or be supported by. 3. You should see a plugin card appear among the search results at the bottom. 4. You will then be given an action link to learn more about it or purchase it. These suggestions are only shown on the first page as to not spam repetition. ## Disabling Plugin Suggestion To disable Plugin Suggestion entirely, you can add the following snippet to your theme’s functions.php file or a functionality plugin: ```php theme={"system"} add_filter( 'cocart_show_plugin_search', function() { return false; }); ``` We will be adding more plugins to the suggestion list as we continue to develop CoCart. And if you have any suggestions, please let us know. # Security Practices Source: https://docs.cocartapi.com/knowledge-base/security-practices Learn about security practices for token storage and server-side configuration. > Dev note: This page needs improving. ## Secure Storage **localStorage** is vulnerable to XSS attacks and should not be used for storing sensitive tokens in production applications. Here are recommended approaches for token storage, in order of security: 1. **HttpOnly Cookies** (Most Secure) * Protected from XSS attacks * Automatic CSRF protection when configured properly * Handled automatically by browsers 2. **Web Workers + IndexedDB** * Isolated from main thread * Protected from XSS * More complex implementation 3. **In-Memory Storage** * Cleared on page refresh * Protected from XSS * Requires state management solution ## Server-Side Configuration Your server should set cookies with secure options: ```javascript JavaScript theme={"system"} // Example server-side cookie configuration (Express.js) res.cookie('jwt_token', token, { httpOnly: true, // Prevents JavaScript access secure: true, // Requires HTTPS sameSite: 'strict', // CSRF protection maxAge: 3600000, // 1 hour path: '/' // Cookie path }); ``` ## Security Best Practices 1. **Always use HTTPS** for token transmission 2. **Set appropriate cookie flags:** * HttpOnly * Secure * SameSite=Strict 3. **Implement CSRF protection** 4. **Use short token expiration times** 5. **Rotate refresh tokens** # Authentication / Login Source: https://docs.cocartapi.com/knowledge-base/troubleshoot/authentication Trouble with authentication? You may need to add this to your **.htaccess** file in the parent folder where your WordPress installation is. Once added, restart the server and authentication should work. ```apache theme={"system"} RewriteEngine on RewriteCond %{HTTP:Authorization} ^(.*) RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1] ``` Basic authentication is recommended to be used on secure sites that have SSL enabled, so if you attempting to authenticate CoCart without it being secured. Then it will simply fail. If you are testing on a local or development environment, CoCart will allow you to authenticate via the basic method. CoCart supports all standard and additional support for identifying ways to login. * Username + Password * Email + Password * Billing Phone Number + Password How you choose to allow your customers to login is up to you. Should the customer forget the username they created or what was assigned when registering as a customer, using their email address instead is good alternative. ```bash cURL theme={"system"} curl --request POST \ --url https://localhost/wp-json/cocart/v2/login \ --header "Authorization: Basic " + btoa('username:password') --header "Content-Type: application/json" ``` If it is not be possible to authenticate the right way using the headers, you can authenticate the user via URL. ```bash theme={"system"} wp-json/cocart/v2/login?username=sebastien@domain.com&password=password ``` Please keep your sites secure! # JWT Authentication Source: https://docs.cocartapi.com/knowledge-base/troubleshoot/jwt-authentication Trouble with JWT authentication? You'll need to configure a secret key in your `wp-config.php` file and ensure your server has HTTP Authorization Header enabled. See the [Setup Guide](/getting-started/jwt/setup) for information. When you authenticate, you receive both an access token and a refresh token. The access token is used for API requests and expires after a configurable period (**default 10 days**). When it expires, you can use the refresh token (**valid for 30 days by default**) to obtain a new access token without re-authenticating with username and password. CORS is handled at the core level. Please see [CORS guide](/documentation/learn/cors) for more information. By default, all tokens are automatically revoked when a user changes their password or email. This behavior can be [customized using filters](/documentation/developers/jwt/filters). The plugin supports multiple signing algorithms including `HS256`, `HS384`, `HS512`, `RS256`, `RS384`, `RS512`, `ES256`, `ES384`, `ES512`, `PS256`, `PS384`, and `PS512`. You can choose and configure your preferred algorithm through the [filters](/documentation/developers/jwt/filters). If your having issues matching IP address due to server configuration, perhaps force the IP to the static IP address your server provides. ```php theme={"system"} add_filter( 'cocart_jwt_auth_token_before_sign', function( $payload ) { $payload['data']['user']['ip'] = '127.0.0.1'; // Replace IP address with static IP. return $payload; } ); ``` Perhaps filter the device to your specific user agent. That way it always matches. ```php theme={"system"} add_filter( 'cocart_jwt_auth_token_before_sign', function( $payload ) { $payload['data']['user']['device'] = 'My Custom User Agent'; // Replace with your user agent. return $payload; } ); ``` You can use the [filters](/documentation/developers/jwt/filters) to modify token claims, lifetime and data. There are are WP-CLI commands strictly designed to help with your development. See [Cli-Reference](/cli-reference/cli-jwt) for commands. In short: The most obvious would be that the user **IP address** has changed. Long answer: It is a common issue with JWT tokens and can be resolved by [**implementing a token validation and refresh flow**](/tutorials/jwt-token-checkup). When a user has either moved location or simply switched their networks at some point. Your site/app is going to experience authentication failure on the next request due to the fact the token is no longer valid. This is a security feature of JWT tokens to prevent replay attacks. # WordPress Configuration Source: https://docs.cocartapi.com/knowledge-base/wp-config Also known as the wp-config.php file. For more handling over CoCart for your store or a client, you will find that using the `wp-config.php` file is the best place to setup certain conditions. ## Uninstall To prevent any data loss when uninstalling CoCart from the backend and to ensure only the site owner can perform this action. You need to enable the ability to remove it. ```php theme={"system"} /** * Allows the full un-installation of CoCart. */ define( 'COCART_REMOVE_ALL_DATA', true ); ``` ## White Labelling If you are developing a headless store for a client and need to hide CoCart. Enabling white label mode comes in handy if that is something you would want. Enabling this hides CoCart completely from the backend including the admin menu, plugin row links, plugin notices, WooCommerce inbox notices and WooCommerce System Status information. ```php theme={"system"} /** * Hides CoCart from the WordPress dashboard. */ define( 'COCART_WHITE_LABEL', true ); ``` # Incompatible plugins Source: https://docs.cocartapi.com/plugins/incompatible Plugins that are not compatible with CoCart Most plugins that extend the frontend of WooCommerce should work out the box. However, those extensions that add or alter methods of applying data may not be 100% supported with CoCart. These plugins in particular are not compatible with CoCart. If installed, they will cause issues with getting a valid response when using the REST API. Next to each listed plugin is the reason for incompatibility. | Plugin Name | Product Page | Incompatible Reason | | ------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------ | | Smart Coupons For WooCommerce Coupons | [Link](https://wordpress.org/plugins/wt-smart-coupons-for-woocommerce/) | Prevents coupons from being applied to the cart. | # Our Plugin Suggestions Source: https://docs.cocartapi.com/plugins/suggestions The following plugins are our suggestions of plugins that may enhance your store. The list of plugins can also be seen in your WordPress dashboard if you have not disabled them. ## CoCart Add-ons All CoCart add-ons are developed by CoCart. ### JWT Authentication [CoCart JWT Authentication](https://wordpress.org/plugins/cocart-jwt-authentication/) is a plugin that allows you to authenticate your CoCart API requests using JSON Web Tokens (JWT). ### Cart API Enhanced [Cart API Enhanced](https://wordpress.org/plugins/cocart-get-cart-enhanced/) enhances the data returned for the cart and the items added to it. This addon is more of a proof of concept to using the filters that CoCart has to offer. ## Third-Party All third-party plugins are **not** developed by CoCart. ### Yoast SEO [Yoast SEO](https://wordpress.org/plugins/wordpress-seo/) is a powerful SEO plugin that helps you optimize your website for search engines. ### Atlas Content Modeler [Atlas Content Modeler](https://wordpress.org/plugins/atlas-content-modeler/) allows you to create and manage custom post types and fields in your store. ### WP Mail SMTP [WP Mail SMTP](https://wordpress.org/plugins/wp-mail-smtp/) allows you to send emails from your WordPress site. ### Imagify – Optimize Images & Convert WebP [Imagify](https://imagify.io/) allows you to optimize your images and convert them to WebP format. ### Redirection [Redirection](https://wordpress.org/plugins/redirection/) allows you to manage your redirects in your store. ### Safe SVG [Safe SVG](https://wordpress.org/plugins/safe-svg/) allows you to safely use SVG images in your store. ### Contact Form 7 [Contact Form 7](https://wordpress.org/plugins/contact-form-7/) allows you to create and manage contact forms in your store. ### Advanced Custom Fields (ACF) [Advanced Custom Fields (ACF)](https://wordpress.org/plugins/advanced-custom-fields/) allows you to create and manage custom fields in your store. We developed our own security plugin designed specifically for the REST API to provide a firewall from bad requests and protection for data exposed without authentication. **List of Features** * Hides all sensitive details from the `wp-json` index. * Deny access to any API route if the `user-agent` is not trust worthy or a bot. * Block use of any API route in an iFrame. * Rate limiting for any route. * Anonymous user data returned if accessed without authentication. * CORS support. [Get your API secure](https://apisecurity.pro) # WooCommerce Extensions Source: https://docs.cocartapi.com/plugins/woocommerce-extensions Tested and verified to work with CoCart. While other WooCommerce extensions may work, the extensions below are officially supported. Some extensions **may provide** specific documentation for use with CoCart API. While CoCart does have this feature built in, [Name Your Price](https://woocommerce.com/products/name-your-price/) allows customers to name their own price for products. [Documentation](../api-reference/plugins/wc-name-your-price) Allows you to create and manage coupons in your store. [View product page](https://woocommerce.com/products/smart-coupons/) Allows customers to create their own product bundles. [View product page](https://woocommerce.com/products/woocommerce-mix-and-match-products/) | [Documentation](../api-reference/plugins/wc-mix-and-match-products) Enables recurring payments and subscription products in your store. [View product page](https://woocommerce.com/products/woocommerce-subscriptions/) Allows you to restrict coupons to specific products, categories, and more. [View product page](https://woocommerce.com/products/coupon-restrictions/) Allows you to create and manage shipping packages in your store. [View product page](https://woocommerce.com/products/woocommerce-advanced-shipping-packages/) Allows you to offer free gift coupons to customers. [View product page](https://woocommerce.com/products/free-gift-coupons/) Allows you to create and manage table rate shipping methods in your store. [View product page](https://wordpress.org/plugins/flexible-shipping/) WooCommerce Automation blocks any tax calculations when using CoCart so we support [TaxJar](https://wordpress.org/plugins/taxjar-simplified-taxes-for-woocommerce/) instead to calculate sales tax for your store. Allows you to send follow up emails to customers. [View product page](https://woocommerce.com/products/follow-up-emails/) # Backers Source: https://docs.cocartapi.com/resources/backers Development of CoCart is made possible thanks to these awesome backers! You can become a backer by becoming a CoCart Sponsor or support by [purchasing a CoCart license](https://cocartapi.com/pricing/?ref=mintlify). All sponsors will be listed in the [BACKERS.md](https://github.com/co-cart/co-cart/blob/development/BACKERS.md) file. CoCart helps you contract work and you'd love to support its development further. **Reward**: Your name will be in **BACKERS.md** file. You're a small team of developers and CoCart provides what you need. You'd love to support its development further so it can be more awesome. **Reward**: Your names will be in **BACKERS.md** file. CoCart saves you time and money for your clients. You'd love to keep it maintained and support its development further. **Reward**: Your company logo will be in CoCart's **README.md** and **CoCart's** website. CoCart saves you time and money for your major clients. You'd love to keep it maintained and support its development further. **Reward**: Your company logo will be placed higher in CoCart's **README.md** and **CoCart's** website. You will also get some stickers. **Reward**: Your company logo will be placed at the very top above all other sponsors in CoCart's [README](https://github.com/co-cart/co-cart/blob/development/README.md) and on [CoCart's website](https://cocartapi.com/). You will also get some shiny stickers. # Community Source: https://docs.cocartapi.com/resources/community CoCart community initiatives Join the community discussions on GitHub. Join the community on Discord to chat with us and fellow CoCart users. Current issues that are being worked on. Issues have a status label to identify it's progress. Create a bug report to help improve CoCart. Publish your headless store for others to see. **Contact us** with a link to the store. Share feature requests and integration requests. Learn about the latest features and updates from CoCart. Follow us on **X/Twitter** to get notified when we release new features # Opening Issues Source: https://docs.cocartapi.com/resources/opening-issues Opening issues is a crucial step in open-source, as issues keep projects stable and help maintainers understand the needs of the community. To help us maintain a stable project, please observe the following guidelines and general rules: ## Open issues for bugs only We ask that **issues are only opened for bugs**, and not for questions. Questions should be asked in [Discussions](https://github.com/co-cart/co-cart/discussions) or on [Discord](https://cocartapi.com/community/?ref=mintlify). While you may open a request for a feature. It would be best to ask in [Discussions](https://github.com/co-cart/co-cart/discussions) first to see if such a feature is possible. ## Include a proper reproduction To ensure your issue can be addressed, please **include a proper reproduction**. Please avoid: * Setting the link to the reproduction pointing to our repository * Providing a code snippet that does not sufficiently reproduce the issue Failing to include a proper reproduction may require extra back-and-forth between you and us, slow the process of fixing the issue for you and others, and make it harder to check if the issue has been fixed on a new release. ## Test the latest version before opening an issue Before opening an issue regarding a bug, please test with the latest stable version. If the bug is fixed, you can still open an issue, and we will tag it with Fixed under the trunk branch so others will know it has been fixed. If you do find that the bug was introduced in a specific version, and an older version didn’t have the issue then you should mention that this is a regression and in what versions it was introduced. ## Conclusion Now that you are ready, click below to open an issue! Thank you so much for contributing. Current issues that are being worked on. Issues have a status label to identify it's progress. Create a bug report to help improve CoCart. # Support Policy Source: https://docs.cocartapi.com/resources/support-policy # Building product pages with OxbowUI Source: https://docs.cocartapi.com/tutorials/astro/oxbowui-product-list Learn how to integrate OxbowUI ecommerce components in Astro to display products This tutorial was written by [Claude Code (an AI)](https://claude.com/product/claude-code) and has not yet been reviewed. Follow along with caution. If the tutorial was helpful or a specific part was not clear/correct, please provide feedback at the bottom of the page. Thank you. # Introduction [OxbowUI](https://oxbowui.com) is an open-source component library featuring ready-to-use components built with Tailwind CSS and AlpineJS. In this tutorial, you'll learn how to use OxbowUI's ecommerce components with CoCart API to build dynamic product pages in Astro. ## What You'll Build * A responsive product grid for listing products * A detailed product page with image and description * Dynamic product data from CoCart/WooCommerce * Add to cart functionality with AlpineJS * Proper image handling and pricing display ## Prerequisites * An Astro project [set up with CoCart](./setup) * CoCart installed and activated on your WordPress site * Basic knowledge of Astro, Tailwind CSS, and AlpineJS * Tailwind CSS and AlpineJS installed in your project If you haven't set up your Astro project yet, follow the [Astro Setup Guide](./setup) first. ## Understanding OxbowUI Components We'll be working with three OxbowUI ecommerce components. You can interact with the demos below to see how they work: ### 1. Product Grid Component A responsive grid layout for displaying multiple products: The component structure: ```html theme={"system"}
#_

Nike Air Force 1´07 Fresh

$280.00

``` ### 2. Product Detail Component A detailed product view with image, price, and description: The component structure: ```html theme={"system"}
Product image

$190

Nike Air Max

Black

Hitting the field in the late '60s, adidas airmaxS quickly became soccer's "it" shoe.

``` We'll adapt these structures to work with CoCart product data. ## Creating the Product Grid Component Create `src/components/ProductGrid.astro`: ```astro theme={"system"} --- const { products } = Astro.props; /** * Format price with currency symbol */ function formatPrice(price, currencySymbol = '$') { return `${currencySymbol}${parseFloat(price).toFixed(2)}`; } ---
{products.map((product) => (
{product.images?.[0]?.alt

{product.name}

{formatPrice(product.prices.price, product.prices.currency_symbol)}

))}
``` ## Creating the Products Page Create `src/pages/products.astro`: ```astro theme={"system"} --- import Layout from '../layouts/Layout.astro'; import ProductGrid from '../components/ProductGrid.astro'; import { getProducts } from '../lib/cocart'; // Fetch products at build time const products = await getProducts({ per_page: 12 }); ---

Our Products

``` ## Creating the Product Detail Component Create `src/components/ProductDetail.astro`: ```astro theme={"system"} --- const { product } = Astro.props; function formatPrice(price, currencySymbol = '$') { return `${currencySymbol}${parseFloat(price).toFixed(2)}`; } ---
{product.images?.[0]?.alt

{formatPrice(product.prices.price, product.prices.currency_symbol)}

{product.name}

{product.attributes?.find(attr => attr.name === 'Color') && (

{product.attributes.find(attr => attr.name === 'Color').options[0]}

)}

``` ## Creating a Variable Product Component For products with variations (colors, sizes), we'll use an advanced component with interactive features: ### 3. Variable Product Component (Interactive Demo) Try selecting a color and size, then click "Add to Cart": Now let's create `src/components/VariableProduct.astro`: ```astro theme={"system"} --- const { product } = Astro.props; function formatPrice(price, currencySymbol = '$') { return `${currencySymbol}${parseFloat(price).toFixed(2)}`; } // Extract attributes for variations const colorAttribute = product.attributes?.find(attr => attr.name === 'Color' || attr.slug === 'pa_color'); const sizeAttribute = product.attributes?.find(attr => attr.name === 'Size' || attr.slug === 'pa_size'); ---
{product.name}

{product.name}

{formatPrice(product.prices.price, product.prices.currency_symbol)}

{colorAttribute && (

Color

)} {sizeAttribute && (

Size

)}

Free shipping over $50

Details

Shipping

We offer free standard shipping on all orders above $50. Express shipping options are available at checkout.

Returns

We accept returns within 30 days of purchase. Items must be in their original condition and packaging.

``` ## Creating the Product Detail Page Create `src/pages/product/[slug].astro`: ```astro theme={"system"} --- import Layout from '../../layouts/Layout.astro'; import ProductDetail from '../../components/ProductDetail.astro'; import VariableProduct from '../../components/VariableProduct.astro'; import { getProducts, getProduct } from '../../lib/cocart'; const { slug } = Astro.params; // Fetch the specific product const products = await getProducts({ slug }); const product = products[0]; if (!product) { return Astro.redirect('/404'); } // Check if product has variations const isVariable = product.type === 'variable'; ---
{isVariable ? ( ) : ( )}
``` ## Adding Interactive Cart Functionality To add items to cart with interactivity, create enhanced versions with AlpineJS. ### Interactive Product Grid Create `src/components/ProductGridInteractive.astro`: ```astro theme={"system"} --- const { products } = Astro.props; function formatPrice(price, currencySymbol = '$') { return `${currencySymbol}${parseFloat(price).toFixed(2)}`; } ---
{products.map((product) => (
{product.images?.[0]?.alt

{product.name}

{formatPrice(product.prices.price, product.prices.currency_symbol)}

))}
``` ### Interactive Product Detail Create `src/components/ProductDetailInteractive.astro`: ```astro theme={"system"} --- const { product } = Astro.props; function formatPrice(price, currencySymbol = '$') { return `${currencySymbol}${parseFloat(price).toFixed(2)}`; } ---
{product.images?.[0]?.alt

{formatPrice(product.prices.price, product.prices.currency_symbol)}

{product.name}

{product.attributes?.find(attr => attr.name === 'Color') && (

{product.attributes.find(attr => attr.name === 'Color').options[0]}

)}

``` ## Creating the Cart API Endpoint Create `src/pages/api/cart/add.js`: ```javascript theme={"system"} import { addToCart } from '../../../lib/cocart'; export async function POST({ request }) { try { const body = await request.json(); const { id, quantity = 1 } = body; const result = await addToCart(id, quantity); return new Response(JSON.stringify(result), { status: 200, headers: { 'Content-Type': 'application/json' } }); } catch (error) { return new Response(JSON.stringify({ error: error.message }), { status: 500, headers: { 'Content-Type': 'application/json' } }); } } ``` Make sure AlpineJS is installed and configured in your project. See the [Astro Setup Guide](./setup#adding-alpinejs-for-interactivity) for instructions. ## Working with Variable Products To add variable products to cart, you need to find the correct variation ID based on selected attributes. Update your CoCart API client in `src/lib/cocart.js`: ```javascript theme={"system"} /** * Get product variations * @param {string|number} productId - Product ID * @returns {Promise} Variations array */ export async function getProductVariations(productId) { try { const response = await fetch(`${API_BASE}/products/${productId}/variations`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error fetching variations:', error); return []; } } /** * Find variation ID based on selected attributes * @param {Array} variations - Product variations * @param {Object} selectedAttributes - Selected attributes {color: 'Red', size: 'L'} * @returns {number|null} Variation ID */ export function findVariationId(variations, selectedAttributes) { return variations.find(variation => { return Object.entries(selectedAttributes).every(([key, value]) => { const attr = variation.attributes.find(a => a.name.toLowerCase() === key.toLowerCase() ); return attr && attr.option.toLowerCase() === value.toLowerCase(); }); })?.id || null; } ``` Then create an interactive variable product component that uses these functions to add the correct variation to cart. ## Understanding the CoCart Response The CoCart Products API returns data in this structure: ```json theme={"system"} { "id": 123, "name": "Nike Air Force 1´07 Fresh", "slug": "nike-air-force-1-07-fresh", "prices": { "price": "28000", "regular_price": "28000", "sale_price": "", "currency_code": "USD", "currency_symbol": "$" }, "images": [ { "id": 456, "src": "https://yourstore.com/wp-content/uploads/product.jpg", "alt": "Nike Air Force 1" } ] } ``` ## Customization Options ### Filtering Products Add category or search filtering: ```javascript theme={"system"} // In cocart.js export async function getProductsByCategory(categoryId, params = {}) { return getProducts({ ...params, category: categoryId }); } ``` ### Different Grid Layouts Modify the grid classes in ProductGrid.astro: ```html theme={"system"}
``` ### Price Variations Handle sale prices: ```astro theme={"system"} {product.prices.sale_price && (
{formatPrice(product.prices.regular_price, product.prices.currency_symbol)} {formatPrice(product.prices.sale_price, product.prices.currency_symbol)}
)} ``` ## Component Usage Summary You now have six components to use in your Astro project: ### Product Listing Components 1. **ProductGrid.astro** - Static product grid (SEO-friendly, server-rendered) 2. **ProductGridInteractive.astro** - Interactive product grid with add to cart ### Simple Product Detail Components 3. **ProductDetail.astro** - Static product detail view 4. **ProductDetailInteractive.astro** - Interactive product detail with add to cart ### Variable Product Components 5. **VariableProduct.astro** - Advanced component with: * Image gallery with thumbnails * Color selector * Size selector * Accordion sections (Details, Shipping, Returns) * Multiple action buttons (Add to Cart, Buy Now) The page automatically detects if a product is variable and uses the appropriate component. Use the static versions for better SEO and performance, or the interactive versions when you need client-side cart functionality. ## Next Steps * Explore more [OxbowUI ecommerce components](https://oxbowui.com/playground/ecommerce) * Add product image gallery (multiple images) * Implement product variations (size, color selection) * Add product filtering and search * Build cart page using OxbowUI cart components * Create checkout flow with CoCart Checkout API * Add product quick view functionality ## Resources * [OxbowUI Documentation](https://oxbowui.com) * [CoCart Products API](../../api-reference/v2/products/get-products) * [CoCart Add to Cart](../../api-reference/v2/cart/post-add-item) * [Astro Documentation](https://docs.astro.build) * [Tailwind CSS](https://tailwindcss.com) * [AlpineJS](https://alpinejs.dev) # Setting Up Astro Source: https://docs.cocartapi.com/tutorials/astro/setup Learn how to set up an Astro project for your headless WooCommerce store This tutorial was written by [Claude Code (an AI)](https://claude.com/product/claude-code) and has not yet been reviewed. Follow along with caution. If the tutorial was helpful or a specific part was not clear/correct, please provide feedback at the bottom of the page. Thank you. # Introduction [Astro](https://astro.build) is a modern web framework that delivers fast, content-focused websites. It's perfect for building headless storefronts with CoCart because of its excellent performance, flexibility, and support for multiple frameworks. This guide will walk you through setting up an Astro project configured to work with CoCart API. ## Why Astro for Headless Commerce? * **Fast by default** - Ships zero JavaScript by default, loading JS only when needed * **Framework agnostic** - Use React, Vue, Svelte, or vanilla JavaScript * **SEO friendly** - Server-side rendering and static site generation * **Island architecture** - Interactive components only where needed * **Great DX** - Hot module replacement and TypeScript support ## Prerequisites * Node.js 18.17.1 or higher * A WordPress site with WooCommerce installed * CoCart plugin installed and activated * Basic knowledge of JavaScript and command line ## Creating a New Astro Project Create a new Astro project using the official CLI: ```bash theme={"system"} npm create astro@latest my-headless-store ``` When prompted, choose the following options: * **How would you like to start?** → Empty * **Install dependencies?** → Yes * **Initialize git repository?** → Yes (recommended) * **TypeScript?** → Yes (recommended) or No Navigate to your project: ```bash theme={"system"} cd my-headless-store ``` ## Installing Tailwind CSS Most UI component libraries (including OxbowUI) use Tailwind CSS. Install it using Astro's integration: ```bash theme={"system"} npx astro add tailwind ``` This will: * Install Tailwind CSS and its dependencies * Create a `tailwind.config.mjs` file * Update your Astro configuration * Add necessary imports ## Project Structure Your Astro project should have this structure: ``` my-headless-store/ ├── src/ │ ├── components/ # Reusable components │ ├── layouts/ # Page layouts │ ├── pages/ # Routes (file-based routing) │ ├── lib/ # Utility functions and API clients │ └── styles/ # Global styles ├── public/ # Static assets ├── astro.config.mjs # Astro configuration ├── tailwind.config.mjs # Tailwind configuration ├── package.json └── tsconfig.json # TypeScript config (if using TS) ``` Create the necessary folders: ```bash theme={"system"} mkdir -p src/components src/lib src/layouts ``` ## Creating the CoCart API Client Create a centralized API client to interact with CoCart. Create `src/lib/cocart.js`: We are currently building out this client, so for now just make standard fetch requests to the CoCart API endpoints as needed. ```javascript theme={"system"} const STORE_URL = import.meta.env.PUBLIC_STORE_URL || 'https://yourstore.com'; const API_BASE = `${STORE_URL}/wp-json/cocart/v2`; /** * Fetch products from CoCart API * @param {Object} params - Query parameters * @returns {Promise} Products array */ export async function getProducts(params = {}) { const queryParams = new URLSearchParams({ per_page: params.per_page || 12, page: params.page || 1, ...params }); try { const response = await fetch(`${API_BASE}/products?${queryParams}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return data; } catch (error) { console.error('Error fetching products:', error); return []; } } /** * Get a single product by ID * @param {string|number} productId - Product ID * @returns {Promise} Product object */ export async function getProduct(productId) { try { const response = await fetch(`${API_BASE}/products/${productId}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error fetching product:', error); return null; } } /** * Add item to cart * @param {string} productId - Product ID * @param {number} quantity - Quantity to add * @param {Object} options - Additional options (variation_id, cart_item_data, etc.) * @returns {Promise} Cart response */ export async function addToCart(productId, quantity = 1, options = {}) { try { const response = await fetch(`${API_BASE}/cart/add-item`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id: productId, quantity: quantity, ...options }) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error adding to cart:', error); throw error; } } /** * Get current cart * @param {string} cartKey - Optional cart key * @returns {Promise} Cart object */ export async function getCart(cartKey = null) { const url = cartKey ? `${API_BASE}/cart?cart_key=${cartKey}` : `${API_BASE}/cart`; try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error fetching cart:', error); return null; } } /** * Update cart item quantity * @param {string} itemKey - Cart item key * @param {number} quantity - New quantity * @returns {Promise} Updated cart */ export async function updateCartItem(itemKey, quantity) { try { const response = await fetch(`${API_BASE}/cart/item/${itemKey}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ quantity }) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error updating cart item:', error); throw error; } } /** * Remove item from cart * @param {string} itemKey - Cart item key * @returns {Promise} Updated cart */ export async function removeCartItem(itemKey) { try { const response = await fetch(`${API_BASE}/cart/item/${itemKey}`, { method: 'DELETE' }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error removing cart item:', error); throw error; } } ``` ## Environment Configuration Create a `.env` file in your project root: ```bash theme={"system"} PUBLIC_STORE_URL=https://yourstore.com ``` Variables prefixed with `PUBLIC_` are exposed to the client-side code. Be careful not to expose sensitive data. Add `.env` to your `.gitignore`: ```bash theme={"system"} echo ".env" >> .gitignore ``` Create a `.env.example` for your team: ```bash theme={"system"} # .env.example PUBLIC_STORE_URL=https://yourstore.com ``` ## Creating a Base Layout Create a base layout at `src/layouts/Layout.astro`: ```astro theme={"system"} --- interface Props { title: string; description?: string; } const { title, description = "Your headless WooCommerce store" } = Astro.props; --- {title} ``` ## Adding AlpineJS for Interactivity If you plan to use interactive components (like OxbowUI), install AlpineJS: ```bash theme={"system"} npm install alpinejs ``` You can initialize it globally in your layout or per-component. For global initialization, update your layout: ```astro theme={"system"} --- // src/layouts/Layout.astro interface Props { title: string; description?: string; } const { title, description = "Your headless WooCommerce store" } = Astro.props; --- {title} ``` Alternatively, you can use AlpineJS via CDN by adding this to your ``: ```html theme={"system"} ``` ## Creating API Endpoints Astro supports API routes for server-side operations. Create API endpoints for cart operations. Create `src/pages/api/cart/add.js`: ```javascript theme={"system"} import { addToCart } from '../../../lib/cocart'; export async function POST({ request }) { try { const body = await request.json(); const { id, quantity = 1, ...options } = body; const result = await addToCart(id, quantity, options); return new Response(JSON.stringify(result), { status: 200, headers: { 'Content-Type': 'application/json' } }); } catch (error) { return new Response(JSON.stringify({ error: error.message }), { status: 500, headers: { 'Content-Type': 'application/json' } }); } } ``` ## Testing Your Setup Create a test page at `src/pages/index.astro`: ```astro theme={"system"} --- import Layout from '../layouts/Layout.astro'; import { getProducts } from '../lib/cocart'; const products = await getProducts({ per_page: 3 }); ---

Welcome to Your Headless Store

{products.map((product) => (

{product.name}

{product.prices.currency_symbol}{product.prices.price}

))}
``` ## Running Your Project Start the development server: ```bash theme={"system"} npm run dev ``` Visit `http://localhost:4321` to see your store. ## Building for Production Build your site for production: ```bash theme={"system"} npm run build ``` Preview the production build: ```bash theme={"system"} npm run preview ``` ## Deployment Options Astro sites can be deployed to various platforms: * **Vercel** - Zero configuration deployment * **Netlify** - Easy deployment with built-in features * **Cloudflare Pages** - Global edge network * **GitHub Pages** - Free hosting for static sites * **Your own server** - Deploy the `dist` folder ## Next Steps Now that your Astro project is set up with CoCart: 1. [Build product listings with OxbowUI components](./oxbowui-product-list) 2. Add shopping cart functionality 3. Implement checkout flow 4. Add user authentication 5. Optimize for performance and SEO ## Troubleshooting ### CORS Errors If you encounter CORS errors, you may need to configure WordPress to allow cross-origin requests. See [CORS documentation](../../documentation/cors). ### API Connection Issues 1. Verify your `PUBLIC_STORE_URL` is correct 2. Ensure CoCart is installed and activated 3. Check that WooCommerce is configured properly 4. Test API endpoints directly in your browser or Postman ## Resources * [Astro Documentation](https://docs.astro.build) * [CoCart API Reference](../../api-reference/introduction) * [Tailwind CSS Documentation](https://tailwindcss.com) * [AlpineJS Documentation](https://alpinejs.dev) # Authentication Injection with CoCart Source: https://docs.cocartapi.com/tutorials/authentication-injection Learn how to intervene CoCart's authentication This guide only works if you have CoCart v4.8 and up installed. ## What is authentication injection? Authentication injection refers to the ability to insert custom authentication logic into the existing login process. This allows developers to implement additional security measures, such as custom validation rules, external system integration, role-based access control, or comprehensive logging mechanisms, without modifying the core authentication flow. ## Overview CoCart's authentication injection system is built around a series of hooks (filters and actions) that allow you to customize the login process. These hooks provide entry points to modify the behavior of authentication, enabling you to add layers of security or integrate with external systems. ## Available Hooks Each hook is documented below with its description, parameters, and practical usage examples. ### `cocart_login_permission_callback` Made available since v4.8.0 Allows you to modify the permission result after basic authentication. This is the primary hook for adding custom validation, external system checks, or role-based access control. ```php Basic Implementation theme={"system"} add_filter( 'cocart_login_permission_callback', function( $permission, $current_user, $request, $endpoint ) { // Your additional authentication logic here return $permission; // or return WP_Error to deny access }, 10, 4 ); ``` ```php Advanced Example theme={"system"} add_filter( 'cocart_login_permission_callback', 'my_advanced_auth_check', 10, 4 ); function my_advanced_auth_check( $permission, $current_user, $request, $endpoint ) { if ( true !== $permission ) { return $permission; } // Example: Check user capabilities if ( ! user_can( $current_user, 'access_api' ) ) { return new WP_Error( 'cocart_insufficient_permissions', 'User lacks required permissions for API access', array( 'status' => 403 ) ); } return $permission; } ``` Current permission status (true after basic auth) The authenticated user object The current REST API request The endpoint being accessed ('login') Allow login to proceed Deny login with specific error message and data ### `cocart_login_permission_granted` Made available since v4.8.0 Fires when login permission is successfully granted. Perfect for audit logging and post-authentication tasks. ```php Basic Logging theme={"system"} add_action( 'cocart_login_permission_granted', function( $current_user, $request, $endpoint ) { // Log successful authentication error_log("Login granted for user: {$current_user->ID}"); }, 10, 3 ); ``` ```php Advanced Audit Logging theme={"system"} add_action( 'cocart_login_permission_granted', 'comprehensive_audit_log', 10, 3 ); function comprehensive_audit_log( $current_user, $request, $endpoint ) { $ip_address = CoCart_Authentication::get_ip_address(); $user_agent = $request->get_header( 'user_agent' ); // Log to custom table or external service wp_insert_post( array( 'post_type' => 'auth_log', 'post_status' => 'private', 'post_title' => "Login: {$current_user->user_login}", 'meta_input' => array( 'user_id' => $current_user->ID, 'ip_address' => $ip_address, 'user_agent' => $user_agent, 'endpoint' => $endpoint, 'timestamp' => current_time( 'mysql' ) ) ) ); } ``` The authenticated user object The current REST API request The endpoint being accessed ('login') ### `cocart_login_secure_auth_methods` Made available since v4.8.0 Allows customizing which authentication methods skip additional checks (like custom validation or external system verification). ```php Add Custom Method theme={"system"} add_filter( 'cocart_login_secure_auth_methods', function( $secure_methods, $current_method ) { // Add custom secure authentication methods $secure_methods[] = 'custom_oauth'; return $secure_methods; }, 10, 2 ); ``` ```php Remove JWT Security theme={"system"} add_filter( 'cocart_login_secure_auth_methods', function( $secure_methods, $current_method ) { // Force additional checks even with JWT tokens $secure_methods = array_diff( $secure_methods, array( 'jwt' ) ); return $secure_methods; }, 10, 2 ); ``` Array of authentication methods considered secure (default: \['jwt', 'api\_key']) The current authentication method being used ### `cocart_login_collection_params` Made available since v4.8.0 Allows you to add additional parameters to the login endpoint for custom authentication data. ```php Add Custom Auth Parameters theme={"system"} add_filter( 'cocart_login_collection_params', function( $additional_params ) { $additional_params['department_code'] = array( 'description' => 'Employee department code', 'type' => 'string', 'required' => false, 'sanitize_callback' => 'sanitize_text_field', ); $additional_params['license_key'] = array( 'description' => 'Application license key', 'type' => 'string', 'pattern' => '^[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$', ); return $additional_params; } ); ``` ```php Add Custom Auth Fields theme={"system"} add_filter( 'cocart_login_collection_params', function( $additional_params ) { $additional_params['device_id'] = array( 'description' => 'Unique device identifier', 'type' => 'string', 'required' => false, ); $additional_params['app_version'] = array( 'description' => 'Application version', 'type' => 'string', 'pattern' => '^[0-9]+\.[0-9]+\.[0-9]+$', ); return $additional_params; } ); ``` Array of additional parameters to add to the login endpoint ## API Usage Examples ```bash theme={"system"} curl -X POST "https://yoursite.com/wp-json/cocart/v2/login" \ -H "Authorization: Basic $(echo -n 'username:password' | base64)" \ -H "Content-Type: application/json" ``` ```bash theme={"system"} curl -X POST "https://yoursite.com/wp-json/cocart/v2/login" \ -H "Authorization: Basic $(echo -n 'username:password' | base64)" \ -H "Content-Type: application/json" \ -H "X-Client-ID: mobile-app" \ -H "X-App-Version: 1.2.3" ``` ```bash theme={"system"} curl -X POST "https://yoursite.com/wp-json/cocart/v2/login" \ -H "Authorization: Basic $(echo -n 'username:password' | base64)" \ -H "Content-Type: application/json" \ -d '{ "device_id": "mobile-app-12345", "app_version": "2.1.0" }' ``` ```bash theme={"system"} curl -X POST "https://yoursite.com/wp-json/cocart/v2/login" \ -H "Authorization: Bearer your-jwt-token-here" \ -H "Content-Type: application/json" ``` ```php theme={"system"} $credentials = base64_encode('username:password'); $response = wp_remote_post( 'https://yoursite.com/wp-json/cocart/v2/login', array( 'headers' => array( 'Authorization' => 'Basic ' . $credentials, 'Content-Type' => 'application/json', ), 'timeout' => 30, ) ); if ( is_wp_error( $response ) ) { // Handle error echo 'Error: ' . $response->get_error_message(); } else { $body = wp_remote_retrieve_body( $response ); $data = json_decode( $body, true ); if ( isset( $data['jwt_token'] ) ) { // Store JWT token for future requests $jwt_token = $data['jwt_token']; } } ``` ```php theme={"system"} $credentials = base64_encode('username:password'); $response = wp_remote_post( 'https://yoursite.com/wp-json/cocart/v2/login', array( 'headers' => array( 'Authorization' => 'Basic ' . $credentials, 'Content-Type' => 'application/json', 'X-Client-ID' => 'mobile-app', 'X-App-Version' => '1.2.3', ), 'timeout' => 30, ) ); $body = wp_remote_retrieve_body( $response ); $data = json_decode( $body, true ); if ( isset( $data['code'] ) && $data['code'] === 'cocart_unsupported_version' ) { // Handle version requirement echo 'API version not supported. Please update your app.'; } elseif ( isset( $data['jwt_token'] ) ) { // Login successful $jwt_token = $data['jwt_token']; } ``` ```javascript theme={"system"} const credentials = btoa('username:password'); fetch('https://yoursite.com/wp-json/cocart/v2/login', { method: 'POST', headers: { 'Authorization': `Basic ${credentials}`, 'Content-Type': 'application/json', }, }) .then(response => response.json()) .then(data => { if (data.jwt_token) { // Store JWT token localStorage.setItem('cocart_token', data.jwt_token); console.log('Login successful'); } else if (data.code === 'cocart_unsupported_version') { // Handle version requirement handleVersionUpdate(data); } }) .catch(error => { console.error('Login error:', error); }); ``` ```javascript theme={"system"} const credentials = btoa('username:password'); fetch('https://yoursite.com/wp-json/cocart/v2/login', { method: 'POST', headers: { 'Authorization': `Basic ${credentials}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ 'device_id': 'mobile-app-12345', 'app_version': '2.1.0' }) }) .then(response => response.json()) .then(data => { if (data.jwt_token) { localStorage.setItem('cocart_token', data.jwt_token); console.log('Device login successful'); } else if (data.code === 'cocart_device_not_registered') { console.error('Device not registered for this account'); } }) .catch(error => { console.error('Device login error:', error); }); ``` ```javascript theme={"system"} const jwtToken = localStorage.getItem('cocart_token'); fetch('https://yoursite.com/wp-json/cocart/v2/login', { method: 'POST', headers: { 'Authorization': `Bearer ${jwtToken}`, 'Content-Type': 'application/json', }, }) .then(response => response.json()) .then(data => { if (data.jwt_token) { // Token is valid, login successful console.log('JWT login successful'); } }) .catch(error => { // Token might be expired, redirect to login console.error('JWT login error:', error); }); ``` ### Response Examples ```json theme={"system"} { "success": true, "data": { "jwt_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...", "refresh_token": "abc123def456...", "user_id": 123, "user_email": "user@example.com", "user_display_name": "John Doe" } } ``` ```json theme={"system"} { "code": "cocart_unsupported_version", "message": "Unsupported API version", "data": { "status": 400, "requested_version": "1.0", "supported_versions": ["2.0", "2.1", "2.2"] } } ``` ```json theme={"system"} { "code": "cocart_device_not_registered", "message": "This device is not registered for this account", "data": { "status": 403, "device_registration_required": true } } ``` ```json theme={"system"} { "code": "cocart_rate_limited", "message": "Too many login attempts. Please try again later.", "data": { "status": 429, "retry_after": 3600 } } ``` ## Authentication Flow User provides username/password via Basic Auth Basic authentication succeeds → user authenticated Permission callback runs → detects `basic_auth` method Custom filters execute → check for additional requirements (device, etc.) If additional data required → returns error with specific requirements User provides required data → validation succeeds Successful login response includes JWT token for future requests (if active) User provides JWT token via Bearer Authorization JWT authentication succeeds → user authenticated Permission callback runs → detects `jwt` method Custom filters SKIPPED → secure authentication method bypasses additional checks Login succeeds immediately → no additional validation required ## Advanced Configuration ### Customizing Secure Authentication Methods You can modify which authentication methods skip additional checks like custom validation: ```php theme={"system"} add_filter( 'cocart_login_secure_auth_methods', 'my_secure_auth_methods', 10, 2 ); function my_secure_auth_methods( $secure_methods, $current_method ) { // Add custom secure authentication methods $secure_methods[] = 'custom_oauth'; // Remove JWT from secure methods (force additional validation even with JWT) $secure_methods = array_diff( $secure_methods, array( 'jwt' ) ); return $secure_methods; } ``` ### Custom Authentication Provider Create a custom authentication provider that integrates with external systems: ```php theme={"system"} add_filter( 'cocart_login_permission_callback', 'custom_ldap_auth', 10, 4 ); function custom_ldap_auth( $permission, $current_user, $request, $endpoint ) { if ( true !== $permission ) { return $permission; } // Check if LDAP authentication is required for this user $require_ldap = get_user_meta( $current_user->ID, 'require_ldap_auth', true ); if ( $require_ldap ) { $ldap_token = $request->get_param( 'ldap_token' ); if ( empty( $ldap_token ) ) { return new WP_Error( 'cocart_ldap_required', 'LDAP authentication required', array( 'status' => 400, 'ldap_required' => true ) ); } // Validate with LDAP server if ( ! validate_ldap_token( $current_user->user_login, $ldap_token ) ) { return new WP_Error( 'cocart_ldap_invalid', 'Invalid LDAP credentials', array( 'status' => 401 ) ); } } return $permission; } ``` ## Implementation Guidelines 1. **Always check the current permission status first** - If it's already an error, don't override it 2. **Respect secure authentication methods** - Use the `cocart_login_secure_auth_methods` filter appropriately 3. **Provide clear error messages** - Include helpful information in error responses 4. **Use appropriate HTTP status codes** - 400 for missing required data, 401 for invalid credentials 5. **Include metadata in error responses** - Help clients understand what's needed 6. **Implement rate limiting** - Protect against brute force attacks 7. **Log security events** - Use the permission granted action for audit trails 8. **Validate all inputs** - Sanitize and validate all request parameters 9. **Follow WordPress coding standards** - Maintain consistency with WordPress conventions ## Security Best Practices Always validate user input and implement proper error handling when extending authentication. * **Validate all input parameters** - Use WordPress sanitization functions like `sanitize_text_field()` * **Always check the permission status first** - Return early if permission is already denied * **Use appropriate HTTP status codes** - 400 for bad requests, 401 for authentication failures, 403 for insufficient permissions * **Log security events** - Use the `cocart_login_permission_granted` action for audit trails ## Testing Your Implementation ### Simple Test Filter Test the authentication injection mechanism with a basic filter: ```php theme={"system"} // Simple test filter for development add_filter( 'cocart_login_permission_callback', 'test_auth_injection', 10, 4 ); function test_auth_injection( $permission, $user, $request, $endpoint ) { if ( true !== $permission ) { return $permission; } $test_param = $request->get_param( 'test_auth' ); if ( 'allow' !== $test_param ) { return new WP_Error( 'test_auth_required', 'Add test_auth=allow parameter for testing', array( 'status' => 400 ) ); } return true; } ``` ### Test with cURL ```bash theme={"system"} # This should fail curl -X POST "https://yoursite.com/wp-json/cocart/v2/login" \ -H "Authorization: Basic $(echo -n 'username:password' | base64)" \ -H "Content-Type: application/json" # This should succeed curl -X POST "https://yoursite.com/wp-json/cocart/v2/login" \ -H "Authorization: Basic $(echo -n 'username:password' | base64)" \ -H "Content-Type: application/json" \ -d '{"test_auth": "allow"}' ``` ## Common Use Cases These examples demonstrate practical implementations of authentication injection for common security requirements. Integrate with external SSO providers like SAML, OAuth, or LDAP for seamless authentication Add extra verification for specific user roles, capabilities, or department restrictions Require device registration and management for enhanced mobile security Restrict access based on geographic location with country-level controls Control access based on business hours, maintenance windows, or schedules Validate custom headers for API versioning, client identification, or feature flags ```php theme={"system"} add_filter( 'cocart_login_permission_callback', 'sso_integration', 10, 4 ); function sso_integration( $permission, $current_user, $request, $endpoint ) { if ( true !== $permission ) { return $permission; } $sso_token = $request->get_param( 'sso_token' ); if ( ! empty( $sso_token ) ) { // Validate SSO token with external provider $sso_valid = validate_sso_token( $sso_token, $current_user->user_email ); if ( ! $sso_valid ) { return new WP_Error( 'cocart_sso_invalid', 'Invalid SSO token', array( 'status' => 401 ) ); } } return $permission; } ``` ```php theme={"system"} add_filter( 'cocart_login_permission_callback', 'role_based_auth', 10, 4 ); function role_based_auth( $permission, $current_user, $request, $endpoint ) { if ( true !== $permission ) { return $permission; } // Require additional verification for admin users if ( in_array( 'administrator', $current_user->roles ) ) { $admin_code = $request->get_param( 'admin_verification_code' ); if ( empty( $admin_code ) ) { return new WP_Error( 'cocart_admin_verification_required', 'Additional verification required for admin users', array( 'status' => 400, 'admin_verification_required' => true ) ); } if ( ! verify_admin_code( $current_user->ID, $admin_code ) ) { return new WP_Error( 'cocart_admin_verification_invalid', 'Invalid admin verification code', array( 'status' => 401 ) ); } } return $permission; } ``` ```php theme={"system"} add_filter( 'cocart_login_permission_callback', 'device_registration_check', 10, 4 ); function device_registration_check( $permission, $current_user, $request, $endpoint ) { if ( true !== $permission ) { return $permission; } $device_id = $request->get_param( 'device_id' ); $user_agent = $request->get_header( 'user_agent' ); if ( empty( $device_id ) ) { return new WP_Error( 'cocart_device_id_required', 'Device ID is required for authentication', array( 'status' => 400 ) ); } // Check if device is registered for this user $registered_devices = get_user_meta( $current_user->ID, 'registered_devices', true ) ?: array(); if ( ! in_array( $device_id, $registered_devices ) ) { return new WP_Error( 'cocart_device_not_registered', 'This device is not registered for this account', array( 'status' => 403, 'device_registration_required' => true ) ); } return $permission; } ``` ```php theme={"system"} add_filter( 'cocart_login_permission_callback', 'geolocation_check', 10, 4 ); function geolocation_check( $permission, $current_user, $request, $endpoint ) { if ( true !== $permission ) { return $permission; } $ip_address = CoCart_Authentication::get_ip_address(); $country_code = get_country_from_ip( $ip_address ); // Block certain countries $blocked_countries = array( 'CN', 'RU', 'KP' ); $allowed_countries = get_option( 'allowed_countries', array( 'US', 'CA', 'GB', 'AU' ) ); if ( in_array( $country_code, $blocked_countries ) ) { return new WP_Error( 'cocart_geo_blocked', 'Access from your location is not permitted', array( 'status' => 403, 'country_code' => $country_code ) ); } // Optional: Only allow specific countries if ( ! empty( $allowed_countries ) && ! in_array( $country_code, $allowed_countries ) ) { return new WP_Error( 'cocart_geo_restricted', 'Access is restricted to approved regions only', array( 'status' => 403, 'country_code' => $country_code ) ); } return $permission; } ``` ```php theme={"system"} add_filter( 'cocart_login_permission_callback', 'time_based_access', 10, 4 ); function time_based_access( $permission, $current_user, $request, $endpoint ) { if ( true !== $permission ) { return $permission; } $current_time = current_time( 'H:i' ); $current_day = current_time( 'w' ); // 0 = Sunday, 6 = Saturday // Get user-specific access hours $access_schedule = get_user_meta( $current_user->ID, 'access_schedule', true ); if ( ! empty( $access_schedule ) ) { $allowed = false; // Check if current time falls within allowed schedule if ( isset( $access_schedule[ $current_day ] ) ) { $day_schedule = $access_schedule[ $current_day ]; foreach ( $day_schedule as $time_slot ) { if ( $current_time >= $time_slot['start'] && $current_time <= $time_slot['end'] ) { $allowed = true; break; } } } if ( ! $allowed ) { $next_available = get_next_available_time( $access_schedule ); return new WP_Error( 'cocart_time_restricted', 'Access is not permitted at this time', array( 'status' => 403, 'current_time' => $current_time, 'next_available' => $next_available ) ); } } return $permission; } ``` ```php theme={"system"} add_filter( 'cocart_login_permission_callback', 'validate_custom_headers', 10, 4 ); function validate_custom_headers( $permission, $current_user, $request, $endpoint ) { if ( true !== $permission ) { return $permission; } // Validate client identifier $client_id = $request->get_header( 'X-Client-ID' ); $app_version = $request->get_header( 'X-App-Version' ); if ( ! empty( $client_id ) ) { $client_config = get_client_configuration( $client_id ); if ( ! $client_config ) { return new WP_Error( 'cocart_unknown_client', 'Unknown client identifier.', array( 'status' => 400 ) ); } // Check minimum app version requirements if ( ! empty( $app_version ) && ! empty( $client_config['min_version'] ) ) { if ( version_compare( $app_version, $client_config['min_version'], '<' ) ) { return new WP_Error( 'cocart_outdated_client', 'Client version is outdated and no longer supported.', array( 'status' => 426, 'current_version' => $app_version, 'minimum_version' => $client_config['min_version'] ) ); } } // Store client info for logging update_user_meta( $current_user->ID, 'last_client_info', array( 'client_id' => $client_id, 'app_version' => $app_version, 'login_time' => current_time( 'mysql' ) ) ); } return $permission; } ``` All authentication extensions follow WordPress coding standards and integrate seamlessly with CoCart's existing authentication system. The examples above demonstrate practical implementations for common security requirements. # Convert Cart to Order Source: https://docs.cocartapi.com/tutorials/covert-cart-to-order Learn how to convert a cart session into an order In this tutorial, we'll walk through the process of converting a shopping cart into an order using the WooCommerce REST API. This is particularly useful when you need to programmatically create orders from cart sessions. CoCart will provide it's own checkout API in the future that will stream line the process. In the mean time, this is the best method. You will need WooCommerce API credentials (consumer key and secret) for this. ## Step 1: Retrieve the Cart Data First, we'll fetch the current cart data using the CoCart API: In the following request examples, you would replace ``, `` and `` before sending the request. ```bash cURL theme={"system"} curl -X GET \ https://your-store.com/wp-json/cocart/v2/cart?cart_key= \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -H 'User-Agent: CoCart API/v2' // Not a requirement. ``` ```php PHP theme={"system"} $curl = curl_init(); curl_setopt_array( $curl, array( CURLOPT_URL => "https://your-store.com/wp-json/cocart/v2/cart?cart_key=", CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 30, CURLOPT_HTTPHEADER => array( 'Accept: application/json', 'Content-Type: application/json;charset=utf-8' 'User-Agent: CoCart API/v2', // Not a requirement. ) ) ); $cart = curl_exec($curl); curl_close($curl); ``` ```javascript JavaScript theme={"system"} const getCart = async () => { const response = await fetch('https://your-store.com/wp-json/cocart/v2/cart?cart_key=', { method: 'GET', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'CoCart API/v2' // Not a requirement. } }); return await response.json(); }; ``` ```bash cURL theme={"system"} curl -X GET \ https://your-store.com/wp-json/cocart/v2/cart \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -H 'Authorization: Basic base64_encode(:)' -H 'User-Agent: CoCart API/v2' // Not a requirement. ``` ```php PHP theme={"system"} $curl = curl_init(); curl_setopt_array( $curl, array( CURLOPT_URL => "https://your-store.com/wp-json/cocart/v2/cart", CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 30, CURLOPT_HTTPHEADER => array( 'Accept: application/json', 'Content-Type: application/json;charset=utf-8' 'Authorization: Basic ' . base64_encode( . ':' . ) 'User-Agent: CoCart API/v2', // Not a requirement. ) ) ); $cart = curl_exec($curl); curl_close($curl); ``` ```javascript JavaScript theme={"system"} const auth = btoa(':'); const getCart = async () => { const response = await fetch('https://your-store.com/wp-json/cocart/v2/cart', { method: 'GET', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': `Basic ${auth}` 'User-Agent': 'CoCart API/v2' // Not a requirement. } }); return await response.json(); }; ``` ## Step 2: Prepare Order Data Next, we'll prepare the order data using the cart information. We'll need to: 1. Decode the cart JSON 2. Set up billing and shipping information 3. Configure payment details ```bash cURL theme={"system"} # First decode and store the cart response from Step 1 CART_DATA=$(cat cart-response.json) # Prepare the order data structure ORDER_DATA=$(jq -n \ --arg payment_method "bacs" \ --arg payment_title "Direct Bank Transfer" \ --argjson paid true \ --argjson cart "$CART_DATA" \ '{ payment_method: $payment_method, payment_method_title: $payment_title, set_paid: $paid, billing: { first_name: $cart.customer.billing_address.billing_first_name, last_name: $cart.customer.billing_address.billing_last_name, address_1: $cart.customer.billing_address.billing_address_1, address_2: $cart.customer.billing_address.billing_address_2, city: $cart.customer.billing_address.billing_city, state: $cart.customer.billing_address.billing_state, postcode: $cart.customer.billing_address.billing_postcode, country: $cart.customer.billing_address.billing_country, email: $cart.customer.billing_address.billing_email, phone: $cart.customer.billing_address.billing_phone }, shipping: { first_name: $cart.customer.shipping_address.shipping_first_name, last_name: $cart.customer.shipping_address.shipping_last_name, address_1: $cart.customer.shipping_address.shipping_address_1, address_2: $cart.customer.shipping_address.shipping_address_2, city: $cart.customer.shipping_address.shipping_city, state: $cart.customer.shipping_address.shipping_state, postcode: $cart.customer.shipping_address.shipping_postcode, country: $cart.customer.shipping_address.shipping_country } }') ``` ```javascript JavaScript theme={"system"} const cart = await getCart(); const orderData = { payment_method: 'bacs', payment_method_title: 'Direct Bank Transfer', set_paid: true, billing: { first_name: cart.customer.billing_address.billing_first_name, last_name: cart.customer.billing_address.billing_last_name, address_1: cart.customer.billing_address.billing_address_1, address_2: cart.customer.billing_address.billing_address_2, city: cart.customer.billing_address.billing_city, state: cart.customer.billing_address.billing_state, postcode: cart.customer.billing_address.billing_postcode, country: cart.customer.billing_address.billing_country, email: cart.customer.billing_address.billing_email, phone: cart.customer.billing_address.billing_phone }, shipping: { first_name: cart.customer.shipping_address.shipping_first_name, last_name: cart.customer.shipping_address.shipping_last_name, address_1: cart.customer.shipping_address.shipping_address_1, address_2: cart.customer.shipping_address.shipping_address_2, city: cart.customer.shipping_address.shipping_city, state: cart.customer.shipping_address.shipping_state, postcode: cart.customer.shipping_address.shipping_postcode, country: cart.customer.shipping_address.shipping_country }, line_items: [], shipping_lines: [] }; ``` ```php PHP theme={"system"} // Decode cart data $cart = json_decode($cart); // Prepare order data $order_data = array( 'payment_method' => 'bacs', 'payment_method_title' => 'Direct Bank Transfer', 'set_paid' => true, 'billing' => array( 'first_name' => $cart->customer->billing_address->billing_first_name, 'last_name' => $cart->customer->billing_address->billing_last_name, 'address_1' => $cart->customer->billing_address->billing_address_1, 'address_2' => $cart->customer->billing_address->billing_address_2, 'city' => $cart->customer->billing_address->billing_city, 'state' => $cart->customer->billing_address->billing_state, 'postcode' => $cart->customer->billing_address->billing_postcode, 'country' => $cart->customer->billing_address->billing_country, 'email' => $cart->customer->billing_address->billing_email, 'phone' => $cart->customer->billing_address->billing_phone ), 'shipping' => array( 'first_name' => $cart->customer->shipping_address->shipping_first_name, 'last_name' => $cart->customer->shipping_address->shipping_last_name, 'address_1' => $cart->customer->shipping_address->shipping_address_1, 'address_2' => $cart->customer->shipping_address->shipping_address_2, 'city' => $cart->customer->shipping_address->shipping_city, 'state' => $cart->customer->shipping_address->shipping_state, 'postcode' => $cart->customer->shipping_address->shipping_postcode, 'country' => $cart->customer->shipping_address->shipping_country ), 'line_items' => array(), 'shipping_lines' => array() ); ``` ## Step 3: Add Shipping Method If shipping is selected in the cart, we'll add it to the order: ```bash cURL theme={"system"} # Add shipping lines if shipping method exists if [[ $(echo "$CART_DATA" | jq -r '.shipping.packages.default.chosen_method') != "null" ]]; then CHOSEN_METHOD=$(echo "$CART_DATA" | jq -r '.shipping.packages.default.chosen_method') ORDER_DATA=$(echo "$ORDER_DATA" | jq \ --arg method_id "$(echo "$CART_DATA" | jq -r ".shipping.packages.default.rates.$CHOSEN_METHOD.method_id")" \ --arg title "$(echo "$CART_DATA" | jq -r ".shipping.packages.default.rates.$CHOSEN_METHOD.label")" \ --arg cost "$(echo "$CART_DATA" | jq -r ".shipping.packages.default.rates.$CHOSEN_METHOD.cost")" \ '. + {shipping_lines: [{method_id: $method_id, method_title: $title, total: $cost}]}') fi ``` ```javascript JavaScript theme={"system"} if (cart.shipping?.packages?.default?.chosen_method) { const chosenMethod = cart.shipping.packages.default.rates[cart.shipping.packages.default.chosen_method]; orderData.shipping_lines.push({ method_id: chosenMethod.method_id, method_title: chosenMethod.label, total: chosenMethod.cost }); } ``` ```php PHP theme={"system"} if (isset($cart->shipping->packages->default->chosen_method)) { $chosen_method = $cart->shipping->packages->default->rates->{$cart->shipping->packages->default->chosen_method}; $order_data['shipping_lines'][] = array( 'method_id' => $chosen_method->method_id, 'method_title' => $chosen_method->label, 'total' => $chosen_method->cost ); } ``` ## Step 4: Process Line Items We'll convert cart items into order line items: ```php PHP theme={"system"} foreach ($cart->items as $item) { $line_item = array( 'product_id' => $item->id, 'quantity' => $item->quantity->value, 'name' => $item->name, 'total' => $item->totals->total ); if (!empty($item->meta->product_type) && $item->meta->product_type === 'variation') { $line_item['variation_id'] = $item->id; $line_item['product_id'] = $item->parent_id; } $order_data['line_items'][] = $line_item; } ``` ```javascript JavaScript theme={"system"} orderData.line_items = cart.items.map(item => { const lineItem = { product_id: item.id, quantity: item.quantity.value, name: item.name, total: item.totals.total }; if (item.meta?.product_type === 'variation') { lineItem.variation_id = item.id; lineItem.product_id = item.parent_id; } return lineItem; }); ``` ```bash cURL theme={"system"} # Process line items ORDER_DATA=$(echo "$ORDER_DATA" | jq \ --argjson cart "$CART_DATA" \ '. + {line_items: ($cart.items | map({ product_id: .id, quantity: .quantity.value, name: .name, total: .totals.total, variation_id: (if .meta.product_type == "variation" then .id else null end), product_id: (if .meta.product_type == "variation" then .parent_id else .id end) }))}') ``` ## Step 5: Create the Order Finally, we'll send the prepared data to the WooCommerce API to create the order: ```bash cURL theme={"system"} ``` ```javascript JavaScript theme={"system"} const createOrder = async (orderData) => { const consumerKey = 'your_consumer_key'; const consumerSecret = 'your_consumer_secret'; const domain = 'https://example-store.com'; try { const response = await fetch(`${domain}/wp-json/wc/v3/orders`, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': `Basic ${btoa(`${consumerKey}:${consumerSecret}`)}` }, body: JSON.stringify(orderData) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const order = await response.json(); console.log(`Order created successfully. Order ID: ${order.id}`); return order; } catch (error) { console.error('Error creating order:', error); throw error; } }; // Usage try { const order = await createOrder(orderData); // Handle successful order creation } catch (error) { // Handle error } ``` ```php PHP theme={"system"} $consumer_key = 'your_consumer_key'; $consumer_secret = 'your_consumer_secret'; $domain = 'https://example-store.com'; $response = wp_remote_post($domain . "/wp-json/wc/v3/orders", array( 'headers' => array( 'Accept' => 'application/json', 'Content-Type' => 'application/json', 'Authorization' => 'Basic ' . base64_encode($consumer_key . ':' . $consumer_secret) ), 'body' => json_encode($order_data), 'timeout' => 30 )); if (is_wp_error($response)) { echo "Error: " . $response->get_error_message(); } else { $order = json_decode(wp_remote_retrieve_body($response)); echo "Order created successfully. Order ID: " . $order->id; } ``` ## Conclusion You've now successfully converted a CoCart cart into a WooCommerce order! The response will contain the newly created order details. Remember to: * Replace `example-store.com` with your actual domain * Insert your WooCommerce API credentials * Handle any potential errors in the response * Consider adding error checking and validation For more information about the available order parameters, consult the [WooCommerce REST API documentation](https://woocommerce.github.io/woocommerce-rest-api-docs/#orders). # Extending Cart: Creating a Callback Source: https://docs.cocartapi.com/tutorials/extending-cart-creating-callbacks Need to extend the cart to apply something unique? Cart callbacks allow you to extend CoCart's functionality by creating custom cart update operations. This tutorial shows you how to create, register, and use custom callbacks to add unique features to your cart. ## What are Cart Callbacks? Cart callbacks are custom PHP classes that execute when the cart is updated via the `/wp-json/cocart/v2/cart/update` endpoint. They allow you to: * Apply discounts or loyalty points * Update cart metadata * Integrate with third-party services * Implement custom cart validation rules * Add special promotions or fees ## Creating a Custom Callback Let's create a loyalty points callback as a practical example. We'll break this down into manageable steps: ### Step 1: Basic Class Structure First, create the basic callback class structure: ```php Basic Callback Structure theme={"system"} The `$name` property is crucial - it's used as the `namespace` parameter when calling your callback via the API. ### Step 2: Input Validation and Safety Checks Add the main callback method with proper validation: ```php Input Validation theme={"system"} public function callback( $request, $controller ) { try { // Safety check: Ensure cart has items if ( $controller->is_completely_empty() ) { throw new CoCart_Data_Exception( 'cocart_cart_empty', __( 'Cart is empty. Please add items to cart first.', 'cart-rest-api-for-woocommerce' ), 404 ); } // Extract custom data from request $data = isset( $request['data'] ) ? $request['data'] : array(); // Validate required parameters if ( empty( $data['points'] ) || ! is_numeric( $data['points'] ) ) { throw new CoCart_Data_Exception( 'cocart_invalid_points', __( 'Please provide a valid number of points to redeem.', 'cart-rest-api-for-woocommerce' ), 400 ); } // Continue with callback logic... } catch ( CoCart_Data_Exception $e ) { return CoCart_Response::get_error_response( $e->getErrorCode(), $e->getMessage(), $e->getCode(), $e->getAdditionalData() ); } } ``` ### Step 3: Implementing Your Custom Logic Add your specific functionality within the callback: ```php Custom Logic Implementation theme={"system"} // Inside the callback method, after validation... $points_to_redeem = intval( $data['points'] ); $current_user = wp_get_current_user(); $cart_updated = false; if ( $current_user->exists() ) { // Get user's available points $available_points = get_user_meta( $current_user->ID, 'loyalty_points', true ); $available_points = intval( $available_points ); // Check if user has enough points if ( $available_points >= $points_to_redeem ) { // Calculate discount (1 point = $0.10) $discount_amount = $points_to_redeem * 0.10; // Apply discount to cart WC()->cart->add_fee( sprintf( __( 'Loyalty Points Discount (%d points)', 'your-textdomain' ), $points_to_redeem ), -$discount_amount ); // Deduct points from user account $new_points_balance = $available_points - $points_to_redeem; update_user_meta( $current_user->ID, 'loyalty_points', $new_points_balance ); // Store redeemed points in session for reference WC()->session->set( 'redeemed_loyalty_points', $points_to_redeem ); $cart_updated = true; wc_add_notice( sprintf( __( 'Applied %d loyalty points for $%.2f discount. Remaining balance: %d points.', 'your-textdomain' ), $points_to_redeem, $discount_amount, $new_points_balance ), 'success' ); } else { throw new CoCart_Data_Exception( 'cocart_insufficient_points', sprintf( __( 'Insufficient points. You have %d points available.', 'your-textdomain' ), $available_points ), 400 ); } } else { throw new CoCart_Data_Exception( 'cocart_authentication_required', __( 'Please log in to redeem loyalty points.', 'your-textdomain' ), 401 ); } ``` ### Step 4: Finalize and Calculate Totals Complete the callback with proper totals calculation: ```php Finalize Callback theme={"system"} // After your custom logic... if ( $cart_updated ) { // Recalculate cart totals to include your changes $this->recalculate_totals( $request, $controller ); // Add success notice only if no errors occurred if ( 0 === wc_notice_count( 'error' ) ) { // Custom success message already added above } } return true; ``` ### Complete Callback Class Here's the complete loyalty points callback:
Complete Loyalty Points Callback ```php Complete Callback Class theme={"system"} is_completely_empty() ) { throw new CoCart_Data_Exception( 'cocart_cart_empty', __( 'Cart is empty. Please add items to cart first.', 'cart-rest-api-for-woocommerce' ), 404 ); } $data = isset( $request['data'] ) ? $request['data'] : array(); if ( empty( $data['points'] ) || ! is_numeric( $data['points'] ) ) { throw new CoCart_Data_Exception( 'cocart_invalid_points', __( 'Please provide a valid number of points to redeem.', 'cart-rest-api-for-woocommerce' ), 400 ); } $points_to_redeem = intval( $data['points'] ); $current_user = wp_get_current_user(); $cart_updated = false; if ( $current_user->exists() ) { $available_points = get_user_meta( $current_user->ID, 'loyalty_points', true ); $available_points = intval( $available_points ); if ( $available_points >= $points_to_redeem ) { $discount_amount = $points_to_redeem * 0.10; WC()->cart->add_fee( sprintf( __( 'Loyalty Points Discount (%d points)', 'your-textdomain' ), $points_to_redeem ), -$discount_amount ); $new_points_balance = $available_points - $points_to_redeem; update_user_meta( $current_user->ID, 'loyalty_points', $new_points_balance ); WC()->session->set( 'redeemed_loyalty_points', $points_to_redeem ); $cart_updated = true; wc_add_notice( sprintf( __( 'Applied %d loyalty points for $%.2f discount. Remaining balance: %d points.', 'your-textdomain' ), $points_to_redeem, $discount_amount, $new_points_balance ), 'success' ); } else { throw new CoCart_Data_Exception( 'cocart_insufficient_points', sprintf( __( 'Insufficient points. You have %d points available.', 'your-textdomain' ), $available_points ), 400 ); } } else { throw new CoCart_Data_Exception( 'cocart_authentication_required', __( 'Please log in to redeem loyalty points.', 'your-textdomain' ), 401 ); } if ( $cart_updated ) { $this->recalculate_totals( $request, $controller ); } return true; } catch ( CoCart_Data_Exception $e ) { return CoCart_Response::get_error_response( $e->getErrorCode(), $e->getMessage(), $e->getCode(), $e->getAdditionalData() ); } } } return new Loyalty_Points_CoCart_Callback(); ```
## Registering Your Callback Once you've created your callback class, you need to register it with CoCart. This tells CoCart that your callback is available for use. ### Registration Steps 1. **Save your callback class** to a PHP file (e.g., `loyalty-points-callback.php`) 2. **Include the file** in your theme or plugin 3. **Register the callback** using the CoCart action hook ```php Registration Code theme={"system"} add_action( 'cocart_register_extension_callback', 'register_loyalty_points_callback' ); function register_loyalty_points_callback( $callback ) { // Load your callback class file include_once( dirname( __FILE__) . '/callbacks/loyalty-points-callback.php' ); // Register the callback instance $callback->register( new Loyalty_Points_CoCart_Callback() ); } ``` ### Where to Place Registration Code You can place this registration code in: * **Your theme's functions.php file** * **A custom plugin file** * **Your site's wp-config.php file** (not recommended) If you place the code in your theme's functions.php, remember that changing themes will disable your callback. ## Using Your Callback Once registered, you can call your callback via the CoCart update endpoint. Here's how to use our loyalty points example: ### API Request Structure ```bash Basic Usage theme={"system"} curl --location --request POST 'https://example-store.com/wp-json/cocart/v2/cart/update' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_JWT_TOKEN' \ --data '{ "namespace": "apply-loyalty-points", "data": { "points": 50 } }' ``` ### JavaScript Usage ```javascript Frontend Integration theme={"system"} async function redeemLoyaltyPoints(points) { try { const response = await fetch('/wp-json/cocart/v2/cart/update', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${userToken}` }, body: JSON.stringify({ namespace: 'apply-loyalty-points', data: { points: points } }) }); const result = await response.json(); if (response.ok) { console.log('Points redeemed successfully:', result); // Update cart display with new totals updateCartDisplay(result); } else { console.error('Failed to redeem points:', result.message); showErrorMessage(result.message); } } catch (error) { console.error('Network error:', error); } } // Usage redeemLoyaltyPoints(25); // Redeem 25 points ``` ### Response Examples **Success Response:** ```json Success theme={"system"} { "cart_hash": "abc123def456", "cart_key": "user_cart_key", "currency": { "currency_code": "USD", "currency_symbol": "$" }, "totals": { "subtotal": "50.00", "discount_total": "2.50", "total": "47.50" }, "notices": [ { "notice": "Applied 25 loyalty points for $2.50 discount. Remaining balance: 75 points.", "type": "success" } ] } ``` **Error Response:** ```json Error - Insufficient Points theme={"system"} { "code": "cocart_insufficient_points", "message": "Insufficient points. You have 15 points available.", "data": { "status": 400 } } ``` ## Additional Callback Examples Here are some other practical callback ideas you can implement: ### Gift Card Redemption ```php Gift Card Example theme={"system"} protected $name = 'redeem-gift-card'; // In callback method: $gift_card_code = sanitize_text_field( $data['gift_card_code'] ); $gift_card = get_gift_card_by_code( $gift_card_code ); if ( $gift_card && $gift_card->is_valid() ) { $discount = min( $gift_card->get_balance(), WC()->cart->get_subtotal() ); WC()->cart->add_fee( 'Gift Card Discount', -$discount ); $gift_card->deduct_balance( $discount ); } ``` ### Shipping Insurance ```php Shipping Insurance Example theme={"system"} protected $name = 'add-shipping-insurance'; // In callback method: if ( isset( $data['add_insurance'] ) && $data['add_insurance'] ) { $insurance_cost = WC()->cart->get_subtotal() * 0.02; // 2% of subtotal WC()->cart->add_fee( 'Shipping Insurance', $insurance_cost ); WC()->session->set( 'has_shipping_insurance', true ); } ``` ### Custom Product Bundling ```php Product Bundle Example theme={"system"} protected $name = 'apply-bundle-discount'; // In callback method: $bundle_items = $data['bundle_items']; if ( count( $bundle_items ) >= 3 ) { $bundle_discount = WC()->cart->get_subtotal() * 0.15; // 15% bundle discount WC()->cart->add_fee( 'Bundle Discount (3+ items)', -$bundle_discount ); } ``` ## Best Practices 1. **Always validate input data** - Never trust user input 2. **Use proper error handling** - Throw CoCart\_Data\_Exception for consistent error responses 3. **Check authentication when needed** - Verify user permissions for sensitive operations 4. **Recalculate totals** - Always call `$this->recalculate_totals()` after making changes 5. **Provide clear feedback** - Use WooCommerce notices to inform users of what happened 6. **Test thoroughly** - Test all success and error scenarios ## Troubleshooting ### Common Issues 1. **Callback not found**: Check that your namespace matches the `$name` property 2. **Class not loaded**: Ensure your include path is correct 3. **Authentication errors**: Verify user login status for user-specific callbacks 4. **Totals not updating**: Make sure you're calling `recalculate_totals()` ### Debug Mode Enable debug mode to see detailed error messages: ```php Debug Mode theme={"system"} // Add to wp-config.php define( 'WP_DEBUG', true ); define( 'WP_DEBUG_LOG', true ); ``` # Generate Image Data URL Source: https://docs.cocartapi.com/tutorials/generate-image-dataurl > Dev Note: Needs to be completed! # Tutorials Overview Source: https://docs.cocartapi.com/tutorials/introduction Practical guides to help you get started with CoCart API Welcome to the CoCart tutorials section! These hands-on guides will help you implement common use cases and integrate CoCart with your applications. ## Getting Started If you're new to CoCart, we recommend starting with these foundational tutorials: Learn how to test and explore the CoCart API using Postman Verify and troubleshoot your JWT authentication tokens ## Common Use Cases These tutorials cover common scenarios you'll encounter when building headless WooCommerce applications: Learn how to convert a cart session into an order using the WooCommerce REST API Implement custom authentication methods in your application ## Extending CoCart Learn how to extend and customize CoCart to meet your specific needs: Add custom callbacks to respond to cart events ## Framework Integrations Step-by-step guides for integrating CoCart with popular JavaScript frameworks: Build fast, content-focused ecommerce sites with Astro and CoCart. * [Setup Guide](/tutorials/astro/setup) * [OxbowUI Product List](/tutorials/astro/oxbowui-product-list) Create server-rendered React applications with Next.js and CoCart. * [Setup Guide](/tutorials/nextjs/setup) Build native mobile apps with React Native and CoCart. * [Setup Guide](/tutorials/react-native/setup) ## Tips and Tricks Quick solutions for common tasks: * [Generate TypeScript Types](/tutorials/typescript-types-generation) - Automatically generate TypeScript types from CoCart OpenAPI specifications * [Generate Image Data URL](/tutorials/generate-image-dataurl) - Convert product images to base64 data URLs ## What You'll Need Before starting these tutorials, make sure you have: * A WordPress site with WooCommerce installed * CoCart plugin installed and activated * Basic understanding of REST APIs * Familiarity with your chosen programming language ## Getting Help If you run into issues while following these tutorials: * Check the [API Reference](/api-reference/introduction) for detailed endpoint documentation * Visit our [Support Centre](/knowledge-base/faq) for troubleshooting guides * Join our [Community](/resources/community) to ask questions and share knowledge ## Contributing Have a tutorial idea or found an issue? We welcome contributions! Check out our [Contributing to Documentation](/documentation/contributing-to-docs) guide to learn how you can help improve our documentation. # Understanding JWT Token Invalidation Source: https://docs.cocartapi.com/tutorials/jwt-token-checkup Learn how to validate and refresh JWT tokens. ## The Problem When implementing JWT authentication, you may encounter a common scenario: 1. A user logs into your store's mobile app while on WiFi 2. The JWT token is issued and includes their current IP address 3. Later, the user switches to cellular data or changes networks 4. Their next API request fails with a 401 error, despite having a valid token This happens because the JWT token includes IP validation as a security measure to prevent token theft and replay attacks. When the user's IP address changes, the security check fails. ## Common Scenarios That Trigger This * Switching between WiFi and cellular data * Moving between different WiFi networks * Using the app while commuting * VPN connections being enabled or disabled ## Solution Overview This guide demonstrates how to implement a robust token validation and refresh flow that: 1. Detects when a token becomes invalid 2. Automatically refreshes the token without disrupting the user experience 3. Falls back to re-authentication only when necessary ## How to setup? This guide shows how to implement secure token handling using HTTP-only cookies. Ensure your server is configured to set secure HttpOnly cookies with appropriate SameSite attributes. ### 1. Validate the token First, check if the current token is still valid using the validation endpoint: ```javascript JavaScript theme={"system"} async function validateToken() { const response = await fetch('https://your-store.com/wp-json/cocart/jwt/validate-token', { method: 'POST', credentials: 'include', // Important for sending cookies headers: { 'Content-Type': 'application/json' } }); return response.status === 200; } ``` ### 2. Implementation Token Refresh When validation fails, implement the refresh flow: ```javascript JavaScript theme={"system"} async function refreshAuthToken() { const response = await fetch('https://your-store.com/wp-json/cocart/jwt/refresh-token', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' } }); if (!response.ok) { throw new Error('Token refresh failed'); } return response.ok; // Cookies are handled automatically by the browser } ``` ### 3. Complete Error Handler ```javascript JavaScript theme={"system"} async function handleAuthError(error) { if (error.status === 401) { try { await refreshAuthToken(); return true; // Token refresh successful } catch (refreshError) { // Redirect to login if refresh fails window.location.href = '/login'; // This would be the page URL for your login page not the login endpoint. return false; } } throw error; } ``` ## Implementation Example ```javascript JavaScript theme={"system"} class AuthJWTManager { constructor() { this.validationAttempts = 0; this.refreshAttempts = 0; } async ensureValidToken() { try { if (await validateToken()) { return true; } } catch (error) { return await handleAuthError(error); } } } ``` ## Server-Side Configuration Your server should set cookies with secure options: ```javascript JavaScript theme={"system"} // Example server-side cookie configuration (Express.js) res.cookie('jwt_token', token, { httpOnly: true, // Prevents JavaScript access secure: true, // Requires HTTPS sameSite: 'strict', // CSRF protection maxAge: 3600000, // 1 hour path: '/' // Cookie path }); ``` ## Security Considerations * Cookies are automatically sent with requests to your domain * HttpOnly prevents XSS attacks from stealing tokens * SameSite=Strict prevents CSRF attacks * Secure flag ensures cookies only work over HTTPS * No client-side token storage needed ## Error Response The API returns a standardized error response: ```json theme={"system"} { "code": "cocart_authentication_error", "message": "Authentication failed.", "status": 401 } ``` # Setting Up Next.js Source: https://docs.cocartapi.com/tutorials/nextjs/setup Learn how to set up a Next.js project for your headless WooCommerce store This tutorial was written by [Claude Code (an AI)](https://claude.com/product/claude-code) and has not yet been reviewed. Follow along with caution. If the tutorial was helpful or a specific part was not clear/correct, please provide feedback at the bottom of the page. Thank you. # Introduction [Next.js](https://nextjs.org) is a powerful React framework that enables you to build fast, production-ready web applications. It's an excellent choice for headless storefronts with CoCart because of its server-side rendering, API routes, excellent performance, and built-in optimizations. This guide will walk you through setting up a Next.js project configured to work with CoCart API. ## Why Next.js for Headless Commerce? * **Hybrid rendering** - Use SSR, SSG, or ISR based on your needs * **Built-in API routes** - Create backend endpoints without a separate server * **Optimized performance** - Automatic code splitting and image optimization * **SEO friendly** - Server-side rendering for better search engine visibility * **Great DX** - Fast refresh, TypeScript support, and comprehensive documentation * **Vercel deployment** - Zero-config deployment with built-in CI/CD ## Prerequisites * Node.js 18.17 or higher * A WordPress site with WooCommerce installed * CoCart plugin installed and activated * Basic knowledge of React and JavaScript ## Creating a New Next.js Project Create a new Next.js project using the official CLI: ```bash theme={"system"} npx create-next-app@latest my-headless-store ``` When prompted, choose the following options: * **Would you like to use TypeScript?** → Yes (recommended) or No * **Would you like to use ESLint?** → Yes (recommended) * **Would you like to use Tailwind CSS?** → Yes (recommended) * **Would you like your code inside a `src/` directory?** → Yes (recommended) * **Would you like to use App Router?** → Yes (recommended) * **Would you like to use Turbopack for `next dev`?** → Yes (optional, for faster dev) * **Would you like to customize the import alias?** → No (unless you have preference) Navigate to your project: ```bash theme={"system"} cd my-headless-store ``` ## Project Structure Your Next.js project will have this structure: ``` my-headless-store/ ├── src/ │ ├── app/ # App Router pages and layouts │ │ ├── layout.tsx # Root layout │ │ ├── page.tsx # Home page │ │ └── api/ # API routes │ ├── components/ # Reusable React components │ ├── lib/ # Utility functions and API clients │ └── styles/ # Global styles ├── public/ # Static assets ├── next.config.js # Next.js configuration ├── tailwind.config.ts # Tailwind configuration ├── package.json └── tsconfig.json # TypeScript config (if using TS) ``` Create the necessary folders: ```bash theme={"system"} mkdir -p src/components src/lib ``` ## Environment Configuration Create a `.env.local` file in your project root: ```bash theme={"system"} NEXT_PUBLIC_STORE_URL=https://yourstore.com ``` Variables prefixed with `NEXT_PUBLIC_` are exposed to the browser. Server-only variables should not have this prefix. Add `.env.local` to your `.gitignore` (it should already be there by default): ```bash theme={"system"} # .gitignore already includes .env*.local ``` Create a `.env.example` for your team: ```bash theme={"system"} # .env.example NEXT_PUBLIC_STORE_URL=https://yourstore.com ``` ## Creating the CoCart API Client Create a centralized API client to interact with CoCart. Create `src/lib/cocart.ts` (or `.js` if not using TypeScript): We are currently building out this client, so for now just make standard fetch requests to the CoCart API endpoints as needed. ```typescript theme={"system"} const STORE_URL = process.env.NEXT_PUBLIC_STORE_URL || 'https://yourstore.com'; const API_BASE = `${STORE_URL}/wp-json/cocart/v2`; /** * Fetch products from CoCart API */ export async function getProducts(params: { per_page?: number; page?: number; [key: string]: any; } = {}) { const queryParams = new URLSearchParams({ per_page: String(params.per_page || 12), page: String(params.page || 1), ...params }); try { const response = await fetch(`${API_BASE}/products?${queryParams}`, { next: { revalidate: 3600 } // Cache for 1 hour }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return data; } catch (error) { console.error('Error fetching products:', error); return []; } } /** * Get a single product by ID */ export async function getProduct(productId: string | number) { try { const response = await fetch(`${API_BASE}/products/${productId}`, { next: { revalidate: 3600 } // Cache for 1 hour }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error fetching product:', error); return null; } } /** * Add item to cart */ export async function addToCart( productId: string, quantity: number = 1, options: Record = {} ) { try { const response = await fetch(`${API_BASE}/cart/add-item`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id: productId, quantity: quantity, ...options }), cache: 'no-store' }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error adding to cart:', error); throw error; } } /** * Get current cart */ export async function getCart(cartKey: string | null = null) { const url = cartKey ? `${API_BASE}/cart?cart_key=${cartKey}` : `${API_BASE}/cart`; try { const response = await fetch(url, { cache: 'no-store' }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error fetching cart:', error); return null; } } /** * Update cart item quantity */ export async function updateCartItem(itemKey: string, quantity: number) { try { const response = await fetch(`${API_BASE}/cart/item/${itemKey}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ quantity }), cache: 'no-store' }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error updating cart item:', error); throw error; } } /** * Remove item from cart */ export async function removeCartItem(itemKey: string) { try { const response = await fetch(`${API_BASE}/cart/item/${itemKey}`, { method: 'DELETE', cache: 'no-store' }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error removing cart item:', error); throw error; } } ``` ## Creating API Routes Next.js API routes allow you to create backend endpoints. Create an API route for cart operations. Create `src/app/api/cart/add/route.ts`: ```typescript theme={"system"} import { NextRequest, NextResponse } from 'next/server'; import { addToCart } from '@/lib/cocart'; export async function POST(request: NextRequest) { try { const body = await request.json(); const { id, quantity = 1, ...options } = body; const result = await addToCart(id, quantity, options); return NextResponse.json(result, { status: 200 }); } catch (error: any) { return NextResponse.json( { error: error.message }, { status: 500 } ); } } ``` ## Updating the Root Layout Update your root layout at `src/app/layout.tsx`: ```typescript theme={"system"} import type { Metadata } from "next"; import { Inter } from "next/font/google"; import "./globals.css"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { title: "My Headless Store", description: "Your headless WooCommerce store powered by CoCart", }; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( {children} ); } ``` ## Testing Your Setup Update the homepage at `src/app/page.tsx`: ```typescript theme={"system"} import { getProducts } from '@/lib/cocart'; export default async function Home() { const products = await getProducts({ per_page: 3 }); return (

Welcome to Your Headless Store

{products.map((product: any) => (

{product.name}

{product.prices.currency_symbol}{product.prices.price}

))}
); } ``` ## Running Your Project Start the development server: ```bash theme={"system"} npm run dev ``` Visit `http://localhost:3000` to see your store. ## Building for Production Build your site for production: ```bash theme={"system"} npm run build ``` Start the production server locally: ```bash theme={"system"} npm run start ``` ## Caching Strategies Next.js offers several caching strategies for optimal performance: ### Static Generation (SSG) For pages that can be pre-rendered at build time: ```typescript theme={"system"} export const revalidate = 3600; // Revalidate every hour export default async function ProductsPage() { const products = await getProducts(); // ... } ``` ### Incremental Static Regeneration (ISR) For pages that need periodic updates: ```typescript theme={"system"} export async function generateStaticParams() { const products = await getProducts({ per_page: 100 }); return products.map((product: any) => ({ id: String(product.id) })); } export default async function ProductPage({ params }: { params: { id: string } }) { const product = await getProduct(params.id); // ... } ``` ### Server-Side Rendering (SSR) For dynamic pages that need fresh data: ```typescript theme={"system"} export const dynamic = 'force-dynamic'; export default async function CartPage() { const cart = await getCart(); // ... } ``` ## Deployment Options Next.js sites can be deployed to various platforms: * **Vercel** - Zero configuration deployment (recommended) * **Netlify** - Easy deployment with built-in features * **AWS Amplify** - Full-stack deployment * **Docker** - Containerized deployment * **Your own server** - Node.js server required ### Deploying to Vercel 1. Push your code to GitHub, GitLab, or Bitbucket 2. Import your project on [Vercel](https://vercel.com) 3. Add your environment variables 4. Deploy! ## Next Steps Now that your Next.js project is set up with CoCart: 1. Add shopping cart functionality with React Context or Zustand 2. Implement checkout flow 3. Add user authentication with JWT 4. Optimize images with Next.js Image component 5. Add loading states and error boundaries ## Troubleshooting ### CORS Errors If you encounter CORS errors, you may need to configure WordPress to allow cross-origin requests. See [CORS documentation](../../documentation/cors). ### API Connection Issues 1. Verify your `NEXT_PUBLIC_STORE_URL` is correct in `.env.local` 2. Ensure CoCart is installed and activated 3. Check that WooCommerce is configured properly 4. Test API endpoints directly in your browser or Postman ### Hydration Errors If you see hydration mismatches: * Ensure you're not using browser-only APIs during SSR * Use `'use client'` directive for client-only components * Check that your data is consistent between server and client renders ## Resources * [Next.js Documentation](https://nextjs.org/docs) * [CoCart API Reference](../../api-reference/introduction) * [Next.js Deployment](https://nextjs.org/docs/deployment) * [React Documentation](https://react.dev) # Setting Up Nuxt Source: https://docs.cocartapi.com/tutorials/nuxt/setup Learn how to set up a Nuxt project for your headless WooCommerce store This tutorial was written by [Claude Code (an AI)](https://claude.com/product/claude-code) and has not yet been reviewed. Follow along with caution. If the tutorial was helpful or a specific part was not clear/correct, please provide feedback at the bottom of the page. Thank you. # Introduction [Nuxt](https://nuxt.com) is a powerful Vue framework that makes web development intuitive and performant. It's an excellent choice for building headless storefronts with CoCart because of its server-side rendering capabilities, excellent developer experience, and robust ecosystem. This guide will walk you through setting up a Nuxt project configured to work with CoCart API. Instructions are provided for both **Nuxt 3** (stable, widely supported) and **Nuxt 4** (latest release with new features). **Which version should you use?** * **Nuxt 3**: Recommended for production applications. Stable with extensive ecosystem support and long-term maintenance until January 2026. * **Nuxt 4**: Latest features and improvements. Good for new projects that want cutting-edge capabilities. Officially released in 2025. ## Why Nuxt for Headless Commerce? * **Hybrid rendering** - Choose between SSR, SSG, or CSR per route * **Auto imports** - Components, composables, and utilities are automatically imported * **File-based routing** - Intuitive routing system with dynamic routes * **Server routes** - Built-in API routes with full-stack capabilities * **Vue ecosystem** - Access to the entire Vue.js ecosystem and components * **SEO friendly** - Built-in SEO features and meta tag management ## Prerequisites * Node.js 16.10.0 or higher (18.0.0+ recommended) * A WordPress site with WooCommerce installed * CoCart plugin installed and activated * Basic knowledge of JavaScript and command line * Node.js 18.0.0 or higher * A WordPress site with WooCommerce installed * CoCart plugin installed and activated * Basic knowledge of JavaScript and command line ## Creating a New Nuxt Project Create a new Nuxt 3 project using the official CLI: ```bash theme={"system"} npx nuxi@latest init my-headless-store ``` When prompted, choose your preferred package manager (npm, yarn, or pnpm). Navigate to your project: ```bash theme={"system"} cd my-headless-store ``` Install dependencies: ```bash theme={"system"} npm install ``` Create a new Nuxt 4 project using the official CLI: ```bash theme={"system"} npx nuxi@latest init my-headless-store ``` When prompted, choose your preferred package manager (npm, yarn, or pnpm). Navigate to your project: ```bash theme={"system"} cd my-headless-store ``` Install dependencies: ```bash theme={"system"} npm install ``` Nuxt 4 uses the same initialization command as Nuxt 3. The latest version will be installed automatically. ## Installing Tailwind CSS Install Tailwind CSS using the Nuxt module: ```bash theme={"system"} npm install -D @nuxtjs/tailwindcss ``` Add the module to your `nuxt.config.ts`: ```javascript theme={"system"} export default defineNuxtConfig({ modules: ['@nuxtjs/tailwindcss'], devtools: { enabled: true } }) ``` ```javascript theme={"system"} export default defineNuxtConfig({ modules: ['@nuxtjs/tailwindcss'], compatibilityDate: '2024-11-01', devtools: { enabled: true } }) ``` Nuxt 4 introduces the `compatibilityDate` option for managing framework updates and breaking changes. Create a `tailwind.config.js` file (optional, for customization): ```javascript theme={"system"} /** @type {import('tailwindcss').Config} */ export default { content: [], theme: { extend: {}, }, plugins: [], } ``` ## Project Structure Your Nuxt project should have this structure: ``` my-headless-store/ ├── assets/ # Stylesheets, fonts, images ├── components/ # Vue components (auto-imported) ├── composables/ # Vue composables (auto-imported) ├── layouts/ # Layout components ├── pages/ # File-based routing ├── public/ # Static files served at root ├── server/ │ ├── api/ # API routes │ └── utils/ # Server utilities ├── utils/ # Auto-imported utilities ├── app.vue # Main app component ├── nuxt.config.ts # Nuxt configuration └── package.json ``` Nuxt automatically imports components from the `components/` directory and composables from the `composables/` directory. No need for manual imports! ## Environment Configuration Create a `.env` file in your project root: ```bash theme={"system"} NUXT_PUBLIC_STORE_URL=https://yourstore.com ``` Variables prefixed with `NUXT_PUBLIC_` are exposed to the client-side code. Keep sensitive data in server-only environment variables without the `NUXT_PUBLIC_` prefix. Add `.env` to your `.gitignore`: ```bash theme={"system"} echo ".env" >> .gitignore ``` Create a `.env.example` for your team: ```bash theme={"system"} # .env.example NUXT_PUBLIC_STORE_URL=https://yourstore.com ``` ## Creating the CoCart Composable Create a composable to interact with CoCart. Create `composables/useCoCart.js`: ```javascript theme={"system"} export const useCoCart = () => { const config = useRuntimeConfig() const STORE_URL = config.public.storeUrl const API_BASE = `${STORE_URL}/wp-json/cocart/v2` /** * Fetch products from CoCart API */ const getProducts = async (params = {}) => { const queryParams = { per_page: params.per_page || 12, page: params.page || 1, ...params } try { const { data, error } = await useFetch(`${API_BASE}/products`, { query: queryParams }) if (error.value) { console.error('Error fetching products:', error.value) return [] } return data.value || [] } catch (err) { console.error('Error fetching products:', err) return [] } } /** * Get a single product by ID */ const getProduct = async (productId) => { try { const { data, error } = await useFetch(`${API_BASE}/products/${productId}`) if (error.value) { console.error('Error fetching product:', error.value) return null } return data.value } catch (err) { console.error('Error fetching product:', err) return null } } /** * Add item to cart */ const addToCart = async (productId, quantity = 1, options = {}) => { try { const { data, error } = await useFetch(`${API_BASE}/cart/add-item`, { method: 'POST', body: { id: productId, quantity: quantity, ...options } }) if (error.value) { throw new Error(error.value.message || 'Failed to add item to cart') } return data.value } catch (err) { console.error('Error adding to cart:', err) throw err } } /** * Get current cart */ const getCart = async (cartKey = null) => { const url = cartKey ? `${API_BASE}/cart?cart_key=${cartKey}` : `${API_BASE}/cart` try { const { data, error } = await useFetch(url) if (error.value) { console.error('Error fetching cart:', error.value) return null } return data.value } catch (err) { console.error('Error fetching cart:', err) return null } } /** * Update cart item quantity */ const updateCartItem = async (itemKey, quantity) => { try { const { data, error } = await useFetch(`${API_BASE}/cart/item/${itemKey}`, { method: 'POST', body: { quantity } }) if (error.value) { throw new Error(error.value.message || 'Failed to update cart item') } return data.value } catch (err) { console.error('Error updating cart item:', err) throw err } } /** * Remove item from cart */ const removeCartItem = async (itemKey) => { try { const { data, error } = await useFetch(`${API_BASE}/cart/item/${itemKey}`, { method: 'DELETE' }) if (error.value) { throw new Error(error.value.message || 'Failed to remove cart item') } return data.value } catch (err) { console.error('Error removing cart item:', err) throw err } } return { getProducts, getProduct, addToCart, getCart, updateCartItem, removeCartItem } } ``` ```javascript theme={"system"} export const useCoCart = () => { const config = useRuntimeConfig() const STORE_URL = config.public.storeUrl const API_BASE = `${STORE_URL}/wp-json/cocart/v2` /** * Fetch products from CoCart API */ const getProducts = async (params = {}) => { const queryParams = { per_page: params.per_page || 12, page: params.page || 1, ...params } try { const { data, error } = await useFetch(`${API_BASE}/products`, { query: queryParams }) if (error.value) { console.error('Error fetching products:', error.value) return [] } return data.value || [] } catch (err) { console.error('Error fetching products:', err) return [] } } /** * Get a single product by ID */ const getProduct = async (productId) => { try { const { data, error } = await useFetch(`${API_BASE}/products/${productId}`) if (error.value) { console.error('Error fetching product:', error.value) return null } return data.value } catch (err) { console.error('Error fetching product:', err) return null } } /** * Add item to cart */ const addToCart = async (productId, quantity = 1, options = {}) => { try { const { data, error } = await useFetch(`${API_BASE}/cart/add-item`, { method: 'POST', body: { id: productId, quantity: quantity, ...options } }) if (error.value) { throw new Error(error.value.message || 'Failed to add item to cart') } return data.value } catch (err) { console.error('Error adding to cart:', err) throw err } } /** * Get current cart */ const getCart = async (cartKey = null) => { const url = cartKey ? `${API_BASE}/cart?cart_key=${cartKey}` : `${API_BASE}/cart` try { const { data, error } = await useFetch(url) if (error.value) { console.error('Error fetching cart:', error.value) return null } return data.value } catch (err) { console.error('Error fetching cart:', err) return null } } /** * Update cart item quantity */ const updateCartItem = async (itemKey, quantity) => { try { const { data, error } = await useFetch(`${API_BASE}/cart/item/${itemKey}`, { method: 'POST', body: { quantity } }) if (error.value) { throw new Error(error.value.message || 'Failed to update cart item') } return data.value } catch (err) { console.error('Error updating cart item:', err) throw err } } /** * Remove item from cart */ const removeCartItem = async (itemKey) => { try { const { data, error } = await useFetch(`${API_BASE}/cart/item/${itemKey}`, { method: 'DELETE' }) if (error.value) { throw new Error(error.value.message || 'Failed to remove cart item') } return data.value } catch (err) { console.error('Error removing cart item:', err) throw err } } return { getProducts, getProduct, addToCart, getCart, updateCartItem, removeCartItem } } ``` The composable code is identical for both Nuxt 3 and 4. Nuxt 4 maintains backward compatibility with Nuxt 3 APIs. This composable is automatically imported in all your components and pages. Just call `const { getProducts } = useCoCart()` to use it! ## Creating a Default Layout Create a default layout at `layouts/default.vue`: ```vue theme={"system"} ``` ## Creating Your First Page Create a home page at `pages/index.vue`: ```vue theme={"system"} ``` The `useAsyncData` composable automatically handles server-side rendering and client-side hydration. Data fetched on the server is serialized and sent to the client. ## Creating Server API Routes Nuxt supports server API routes for server-side operations. Create `server/api/cart/add.post.js`: ```javascript theme={"system"} export default defineEventHandler(async (event) => { try { const body = await readBody(event) const { id, quantity = 1, ...options } = body const config = useRuntimeConfig() const STORE_URL = config.public.storeUrl const API_BASE = `${STORE_URL}/wp-json/cocart/v2` const response = await $fetch(`${API_BASE}/cart/add-item`, { method: 'POST', body: { id, quantity, ...options } }) return response } catch (error) { throw createError({ statusCode: 500, message: error.message || 'Failed to add item to cart' }) } }) ``` Server routes are automatically prefixed with `/api`. This route will be accessible at `/api/cart/add`. ## Managing Cart State Create a cart composable for managing cart state at `composables/useCartState.js`: ```javascript theme={"system"} export const useCartState = () => { const cart = useState('cart', () => ({ items: [], itemCount: 0, total: '0' })) const addItem = (item) => { cart.value = { ...cart.value, items: [...cart.value.items, item], itemCount: cart.value.itemCount + item.quantity } } const removeItem = (itemKey) => { const newItems = cart.value.items.filter(item => item.key !== itemKey) const newCount = newItems.reduce((sum, item) => sum + item.quantity, 0) cart.value = { ...cart.value, items: newItems, itemCount: newCount } } const updateQuantity = (itemKey, quantity) => { const items = cart.value.items.map(item => item.key === itemKey ? { ...item, quantity } : item ) const itemCount = items.reduce((sum, item) => sum + item.quantity, 0) cart.value = { ...cart.value, items, itemCount } } const clearCart = () => { cart.value = { items: [], itemCount: 0, total: '0' } } return { cart, addItem, removeItem, updateQuantity, clearCart } } ``` Use the cart state in your components: ```vue theme={"system"} ``` ## SEO and Meta Tags Nuxt makes it easy to manage SEO with the `useSeoMeta` composable: ```vue theme={"system"} ``` ## Running Your Project Start the development server: ```bash theme={"system"} npm run dev ``` Visit `http://localhost:3000` to see your store. ## Building for Production Build your site for production: ```bash theme={"system"} npm run build ``` Preview the production build: ```bash theme={"system"} npm run preview ``` ## Deployment Options Nuxt can be deployed to various platforms: **Zero configuration deployment** ```bash theme={"system"} # Install Vercel CLI npm i -g vercel # Deploy vercel ``` Nuxt automatically detects Vercel and configures itself appropriately. **Easy deployment with built-in features** Create a `netlify.toml` file: ```toml theme={"system"} [build] command = "npm run build" publish = ".output/public" ``` Connect your repository to Netlify and deploy. **Global edge network deployment** 1. Connect your Git repository to Cloudflare Pages 2. Set build command: `npm run build` 3. Set build output directory: `.output/public` 4. Deploy Nuxt automatically detects Cloudflare Pages and configures itself. **Deploy to any Node.js hosting** After running `npm run build`, you can start the production server: ```bash theme={"system"} node .output/server/index.mjs ``` Or use PM2 for process management: ```bash theme={"system"} pm2 start .output/server/index.mjs --name "my-headless-store" ``` **Generate a static site** For fully static sites, you can use: ```bash theme={"system"} npm run generate ``` This creates a `.output/public` directory that can be deployed to any static hosting service like GitHub Pages, AWS S3, or Nginx. ## Version-Specific Features ### Nuxt 3 Specific Features * **Stable ecosystem**: All major modules and libraries are fully compatible * **Long-term support**: Maintenance until January 2026 * **Production-ready**: Battle-tested in thousands of applications * **Extensive documentation**: Comprehensive guides and community resources ### Recommended Modules for Nuxt 3 ```bash theme={"system"} # Image optimization npm install -D @nuxt/image # PWA support npm install -D @vite-pwa/nuxt # Icon support npm install -D @nuxt/icon ``` ### Nuxt 4 Specific Features * **Compatibility date**: Use `compatibilityDate` in config for controlled updates * **Performance improvements**: Enhanced build times and smaller bundle sizes * **New defaults**: Better defaults for modern web development * **Future-ready**: Latest features and improvements from the Nuxt team ### New in Nuxt 4 * **Shared `app/` directory**: New folder structure for better organization * **Normalized `useFetch` and `$fetch` defaults**: More consistent API behavior * **Future Nitro 3**: Upcoming server engine improvements ### Migration from Nuxt 3 to Nuxt 4 If you want to upgrade an existing Nuxt 3 project to Nuxt 4: ```bash theme={"system"} # Update package.json npm install nuxt@latest # Add compatibility date to nuxt.config.ts # compatibilityDate: '2024-11-01' ``` Review the [Nuxt 4 migration guide](https://nuxt.com/docs/getting-started/upgrade#nuxt-4) for breaking changes and necessary updates. ## Troubleshooting If you encounter CORS errors, you may need to configure WordPress to allow cross-origin requests. See [CORS documentation](/documentation/cors). You can also add CORS headers in your Nuxt config: ```javascript theme={"system"} export default defineNuxtConfig({ routeRules: { '/api/**': { cors: true, headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE', } } } }) ``` 1. Verify your `NUXT_PUBLIC_STORE_URL` is correct in `.env` 2. Ensure CoCart is installed and activated 3. Check that WooCommerce is configured properly 4. Test API endpoints directly in your browser or Postman **Debug tip**: Add logging to your composable: ```javascript theme={"system"} console.log('API_BASE:', API_BASE) console.log('Response:', data.value) ``` If you see hydration mismatch warnings: 1. Ensure data fetching is done with `useAsyncData` or `useFetch` 2. Check that your component structure matches between server and client 3. Avoid using browser-only APIs during SSR 4. Use `` for client-side only components: ```vue theme={"system"} ``` Some Nuxt modules may not yet support Nuxt 4. Check the module's documentation for compatibility. If a module isn't compatible yet: * Check for updates or beta versions * Look for alternative modules * Consider staying on Nuxt 3 until the module is updated * Report the issue to the module maintainer ## Next Steps Now that your Nuxt project is set up with CoCart: 1. Build product listing pages with dynamic routes 2. Create a shopping cart component with real-time updates 3. Implement checkout functionality 4. Add user authentication with JWT 5. Optimize images with Nuxt Image module 6. Add PWA capabilities with `@vite-pwa/nuxt` ## Resources * [Nuxt Documentation](https://nuxt.com) * [Nuxt 4 Announcement](https://nuxt.com/blog/v4) * [CoCart API Reference](/api-reference/introduction) * [Tailwind CSS Documentation](https://tailwindcss.com) * [Vue.js Documentation](https://vuejs.org) # Getting Started with Postman Source: https://docs.cocartapi.com/tutorials/postman Learn how to use Postman to interact with CoCart API # Introduction [Postman](https://www.postman.com/) is a popular API development tool that makes it easy to build, test, and modify API requests from a user-friendly graphical interface for sending HTTP requests and viewing responses, making it perfect for testing and exploring the CoCart API. We recommend using Postman with the CoCart API when you are troubleshooting issues with your application. ## Why Use Postman? * Easy-to-use graphical interface for making API requests * Save and organize your API requests for future use * Test different parameters and authentication methods quickly * View detailed response data in a structured format * Share API collections with your team ## Setting Up Postman 1. Download and install Postman from the [official website](https://www.postman.com/downloads/) 2. Create a free Postman account (optional but recommended) 3. Launch Postman on your computer ## Importing CoCart API Collection CoCart provides an OpenAPI document that follows the [OpenAPI Specification](https://swagger.io/specification/) that you can import to get started quickly: 1. Download the CoCart OpenAPI document: [CoCart OpenAPI Document](#) 2. In Postman, click the "Import" button in the top left 3. Drag and drop the downloaded the OpenAPI file or browse to select it 4. Click "Import" to add the collection to your workspace ## Configuring Environment Variables To use the CoCart API effectively with Postman, set up your environment variables: 1. Click the "Environments" tab in Postman 2. Create a new environment (e.g., "CoCart Local") 3. Add the following variables: * `url`: Your WordPress site URL (e.g., `http://localhost/wordpress`) * `consumer_key`: Your WooCommerce consumer key - for Session API ONLY * `consumer_secret`: Your WooCommerce consumer secret - for Session API ONLY ## Making Your First Request 1. Select the imported CoCart collection 2. Choose the environment you created 3. Open the "Products" request 4. Click "Send" to make your first API request The response will show your stores product data in JSON format. ## Authentication If you need customer authentication: 1. In the request's "Auth" tab, select "Basic Auth" 2. Enter your the customers username/email/phone number 3. Enter your the customers password [See Authentication](../api-reference/authentication) for more information. ## Next Steps * Explore the various endpoints in the CoCart collection * Try modifying request parameters to see different responses * Use the "Tests" tab to write test scripts for your requests * Save your frequently used requests for quick access For more information about using Postman, visit the [Postman Learning Center](https://learning.postman.com/). ## What’s next If you click on the right side in Postman that says “Code”, you can turn the request we just created into the language of your choosing such as PHP, Javascript, Python, Node or Ruby to help you get started. Postman has great documentation that might be helpful and an AI assistant. # Setting Up React Native Source: https://docs.cocartapi.com/tutorials/react-native/setup Learn how to set up a React Native project for your headless WooCommerce mobile store This tutorial was written by [Claude Code (an AI)](https://claude.com/product/claude-code) and has not yet been reviewed. Follow along with caution. If the tutorial was helpful or a specific part was not clear/correct, please provide feedback at the bottom of the page. Thank you. # Introduction [React Native](https://reactnative.dev) is a popular framework for building native mobile applications using React. It's an excellent choice for creating mobile storefronts with CoCart because it allows you to build iOS and Android apps from a single codebase while maintaining native performance and user experience. This guide will walk you through setting up a React Native project configured to work with CoCart API. ## Why React Native for Headless Commerce? * **Cross-platform** - Build for iOS and Android from one codebase * **Native performance** - Real native components, not webviews * **React ecosystem** - Use familiar React patterns and libraries * **Hot reloading** - Fast development with instant feedback * **Large community** - Extensive third-party packages and support * **Cost effective** - One team can build for multiple platforms ## Prerequisites * Node.js 18 or higher * A WordPress site with WooCommerce installed * CoCart plugin installed and activated * Basic knowledge of React and JavaScript * For iOS development: macOS with Xcode installed * For Android development: Android Studio installed ## Development Environment Setup Before creating your project, set up your development environment: ```bash macOS theme={"system"} # Install Homebrew (if not already installed) /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" # Install Node and Watchman brew install node brew install watchman # Install CocoaPods (for iOS dependencies) sudo gem install cocoapods ``` ```bash Windows theme={"system"} # Install Chocolatey (if not already installed) # Run PowerShell as Administrator, then: Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) # Install Node choco install -y nodejs-lts # Install OpenJDK for Android development choco install -y microsoft-openjdk11 ``` For detailed environment setup, refer to [React Native Environment Setup](https://reactnative.dev/docs/environment-setup). ## Creating a New React Native Project Create a new React Native project using the official CLI: ```bash theme={"system"} npx react-native@latest init MyHeadlessStore ``` Navigate to your project: ```bash theme={"system"} cd MyHeadlessStore ``` ## Project Structure Your React Native project will have this structure: ``` MyHeadlessStore/ ├── android/ # Android native code ├── ios/ # iOS native code ├── src/ # Your app code (create this) │ ├── api/ # API client │ ├── components/ # Reusable components │ ├── screens/ # Screen components │ ├── navigation/ # Navigation setup │ ├── context/ # Context providers │ ├── hooks/ # Custom hooks │ └── types/ # TypeScript types ├── App.tsx # Root component ├── package.json └── tsconfig.json ``` Create the source directory structure: ```bash theme={"system"} mkdir -p src/api src/components src/screens src/navigation src/context src/hooks src/types ``` ## Installing Essential Dependencies Install the necessary packages for a complete e-commerce app: ```bash theme={"system"} # Navigation npm install @react-navigation/native @react-navigation/native-stack @react-navigation/bottom-tabs # Navigation dependencies npm install react-native-screens react-native-safe-area-context # State management and data fetching npm install @tanstack/react-query zustand # Async storage for cart persistence npm install @react-native-async-storage/async-storage # Image handling npm install react-native-fast-image # Additional utilities npm install axios ``` For iOS, install pods: ```bash theme={"system"} cd ios && pod install && cd .. ``` ## Environment Configuration Install the config package: ```bash theme={"system"} npm install react-native-config ``` Create a `.env` file in your project root: ```bash theme={"system"} API_URL=https://yourstore.com/wp-json/cocart/v2 STORE_URL=https://yourstore.com ``` Add `.env` to your `.gitignore`: ```bash theme={"system"} echo ".env" >> .gitignore ``` Create a `.env.example`: ```bash theme={"system"} # .env.example API_URL=https://yourstore.com/wp-json/cocart/v2 STORE_URL=https://yourstore.com ``` ## Creating the CoCart API Client Create a centralized API client at `src/api/cocart.ts`: We are currently building out this client, so for now just make standard fetch/axios requests to the CoCart API endpoints as needed. ```typescript theme={"system"} import axios, { AxiosInstance } from 'axios'; import Config from 'react-native-config'; import AsyncStorage from '@react-native-async-storage/async-storage'; const API_BASE = Config.API_URL || 'https://yourstore.com/wp-json/cocart/v2'; // Create axios instance const api: AxiosInstance = axios.create({ baseURL: API_BASE, timeout: 10000, headers: { 'Content-Type': 'application/json', }, }); // Add cart key to requests api.interceptors.request.use( async (config) => { const cartKey = await AsyncStorage.getItem('cart_key'); if (cartKey && config.headers) { config.headers['Cart-Key'] = cartKey; } return config; }, (error) => Promise.reject(error) ); // Save cart key from responses api.interceptors.response.use( async (response) => { const cartKey = response.headers['cart-key']; if (cartKey) { await AsyncStorage.setItem('cart_key', cartKey); } return response; }, (error) => Promise.reject(error) ); /** * Fetch products from CoCart API */ export async function getProducts(params: { per_page?: number; page?: number; category?: string; search?: string; [key: string]: any; } = {}) { try { const response = await api.get('/products', { params }); return response.data; } catch (error) { console.error('Error fetching products:', error); throw error; } } /** * Get a single product by ID */ export async function getProduct(productId: string | number) { try { const response = await api.get(`/products/${productId}`); return response.data; } catch (error) { console.error('Error fetching product:', error); throw error; } } /** * Get current cart */ export async function getCart() { try { const response = await api.get('/cart'); return response.data; } catch (error) { console.error('Error fetching cart:', error); throw error; } } /** * Add item to cart */ export async function addToCart( productId: string, quantity: number = 1, options: Record = {} ) { try { const response = await api.post('/cart/add-item', { id: productId, quantity, ...options, }); return response.data; } catch (error) { console.error('Error adding to cart:', error); throw error; } } /** * Update cart item quantity */ export async function updateCartItem(itemKey: string, quantity: number) { try { const response = await api.post(`/cart/item/${itemKey}`, { quantity }); return response.data; } catch (error) { console.error('Error updating cart item:', error); throw error; } } /** * Remove item from cart */ export async function removeCartItem(itemKey: string) { try { const response = await api.delete(`/cart/item/${itemKey}`); return response.data; } catch (error) { console.error('Error removing cart item:', error); throw error; } } /** * Clear cart */ export async function clearCart() { try { const response = await api.post('/cart/clear'); await AsyncStorage.removeItem('cart_key'); return response.data; } catch (error) { console.error('Error clearing cart:', error); throw error; } } export default api; ``` ## Setting Up React Query Create a query client configuration at `src/api/queryClient.ts`: ```typescript theme={"system"} import { QueryClient } from '@tanstack/react-query'; export const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 1000 * 60 * 5, // 5 minutes cacheTime: 1000 * 60 * 10, // 10 minutes retry: 2, }, }, }); ``` ## Creating Custom Hooks Create a cart hook at `src/hooks/useCart.ts`: ```typescript theme={"system"} import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { getCart, addToCart, updateCartItem, removeCartItem, clearCart } from '../api/cocart'; import { Alert } from 'react-native'; export function useCart() { const queryClient = useQueryClient(); // Get cart query const { data: cart, isLoading, error } = useQuery({ queryKey: ['cart'], queryFn: getCart, }); // Add to cart mutation const addToCartMutation = useMutation({ mutationFn: ({ productId, quantity, options }: any) => addToCart(productId, quantity, options), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['cart'] }); Alert.alert('Success', 'Item added to cart'); }, onError: (error: any) => { Alert.alert('Error', error.message || 'Failed to add item to cart'); }, }); // Update cart item mutation const updateCartMutation = useMutation({ mutationFn: ({ itemKey, quantity }: any) => updateCartItem(itemKey, quantity), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['cart'] }); }, onError: (error: any) => { Alert.alert('Error', error.message || 'Failed to update cart'); }, }); // Remove cart item mutation const removeCartMutation = useMutation({ mutationFn: (itemKey: string) => removeCartItem(itemKey), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['cart'] }); }, onError: (error: any) => { Alert.alert('Error', error.message || 'Failed to remove item'); }, }); // Clear cart mutation const clearCartMutation = useMutation({ mutationFn: clearCart, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['cart'] }); }, onError: (error: any) => { Alert.alert('Error', error.message || 'Failed to clear cart'); }, }); return { cart, isLoading, error, addToCart: addToCartMutation.mutate, updateCartItem: updateCartMutation.mutate, removeCartItem: removeCartMutation.mutate, clearCart: clearCartMutation.mutate, isAddingToCart: addToCartMutation.isPending, }; } ``` Create a products hook at `src/hooks/useProducts.ts`: ```typescript theme={"system"} import { useQuery } from '@tanstack/react-query'; import { getProducts, getProduct } from '../api/cocart'; export function useProducts(params?: any) { return useQuery({ queryKey: ['products', params], queryFn: () => getProducts(params), }); } export function useProduct(productId: string | number) { return useQuery({ queryKey: ['product', productId], queryFn: () => getProduct(productId), enabled: !!productId, }); } ``` ## Setting Up Navigation Create the navigation structure at `src/navigation/AppNavigator.tsx`: ```typescript theme={"system"} import React from 'react'; import { NavigationContainer } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; // Import screens (we'll create these next) import HomeScreen from '../screens/HomeScreen'; import ProductDetailScreen from '../screens/ProductDetailScreen'; import CartScreen from '../screens/CartScreen'; import ProfileScreen from '../screens/ProfileScreen'; const Stack = createNativeStackNavigator(); const Tab = createBottomTabNavigator(); function HomeTabs() { return ( ); } export default function AppNavigator() { return ( ); } ``` ## Creating Example Screens Create a basic home screen at `src/screens/HomeScreen.tsx`: ```typescript theme={"system"} import React from 'react'; import { View, Text, FlatList, TouchableOpacity, StyleSheet, ActivityIndicator, Image, } from 'react-native'; import { useProducts } from '../hooks/useProducts'; import FastImage from 'react-native-fast-image'; export default function HomeScreen({ navigation }: any) { const { data: products, isLoading, error } = useProducts({ per_page: 20 }); if (isLoading) { return ( ); } if (error) { return ( Error loading products ); } const renderProduct = ({ item }: any) => ( navigation.navigate('ProductDetail', { productId: item.id })} > {item.images?.[0]?.src && ( )} {item.name} {item.prices.currency_symbol}{item.prices.price} ); return ( item.id.toString()} numColumns={2} contentContainerStyle={styles.list} /> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', }, centered: { flex: 1, justifyContent: 'center', alignItems: 'center', }, list: { padding: 8, }, productCard: { flex: 1, margin: 8, backgroundColor: '#fff', borderRadius: 12, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 3, overflow: 'hidden', }, productImage: { width: '100%', height: 150, backgroundColor: '#f5f5f5', }, productInfo: { padding: 12, }, productName: { fontSize: 14, fontWeight: '600', marginBottom: 4, color: '#333', }, productPrice: { fontSize: 16, fontWeight: 'bold', color: '#6a42d7', }, errorText: { fontSize: 16, color: '#ff0000', }, }); ``` Create a placeholder for the cart screen at `src/screens/CartScreen.tsx`: ```typescript theme={"system"} import React from 'react'; import { View, Text, StyleSheet, FlatList, ActivityIndicator } from 'react-native'; import { useCart } from '../hooks/useCart'; export default function CartScreen() { const { cart, isLoading } = useCart(); if (isLoading) { return ( ); } if (!cart || cart.items_count === 0) { return ( Your cart is empty ); } return ( Cart ({cart.items_count} items) Total: {cart.totals.currency_symbol}{cart.totals.total} ); } const styles = StyleSheet.create({ container: { flex: 1, padding: 16, backgroundColor: '#fff', }, centered: { flex: 1, justifyContent: 'center', alignItems: 'center', }, title: { fontSize: 24, fontWeight: 'bold', marginBottom: 16, }, total: { fontSize: 18, fontWeight: '600', color: '#6a42d7', }, emptyText: { fontSize: 16, color: '#999', }, }); ``` Create placeholder screens: ```typescript theme={"system"} // src/screens/ProductDetailScreen.tsx import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; export default function ProductDetailScreen() { return ( Product Detail Screen ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center' }, }); ``` ```typescript theme={"system"} // src/screens/ProfileScreen.tsx import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; export default function ProfileScreen() { return ( Profile Screen ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center' }, }); ``` ## Updating App.tsx Update your root `App.tsx` file: ```typescript theme={"system"} import React from 'react'; import { QueryClientProvider } from '@tanstack/react-query'; import { queryClient } from './src/api/queryClient'; import AppNavigator from './src/navigation/AppNavigator'; export default function App() { return ( ); } ``` ## Running Your App ```bash iOS theme={"system"} npm run ios # Or for a specific simulator npm run ios -- --simulator="iPhone 15" ``` ```bash Android theme={"system"} # Start Metro bundler (in one terminal) npm start # Run Android app (in another terminal) npm run android ``` ## Testing on Physical Devices ```text iOS theme={"system"} 1. Open ios/MyHeadlessStore.xcworkspace in Xcode 2. Select your device from the device menu 3. Click Run button ``` ```text Android theme={"system"} 1. Enable Developer Mode on your Android device 2. Enable USB Debugging in Developer Options 3. Connect device via USB 4. Run: npm run android ``` ## Building for Production ```bash iOS theme={"system"} cd ios pod install cd .. # Build for release npx react-native run-ios --configuration Release ``` ```bash Android theme={"system"} # Generate release APK cd android ./gradlew assembleRelease # Or generate AAB for Google Play Store ./gradlew bundleRelease ``` ### App Store Submission ```text iOS theme={"system"} 1. Open ios/MyHeadlessStore.xcworkspace in Xcode 2. Select "Any iOS Device" as target 3. Product → Archive 4. Upload to App Store Connect ``` ```text Android theme={"system"} APK location: android/app/build/outputs/apk/release/app-release.apk AAB location: android/app/build/outputs/bundle/release/app-release.aab Upload the AAB to Google Play Console ``` ## Performance Optimization ### Image Optimization * Use `react-native-fast-image` for better image performance * Cache images appropriately * Use appropriate image sizes ### List Optimization * Use `FlatList` with proper `keyExtractor` * Implement `getItemLayout` for fixed-height items * Use `maxToRenderPerBatch` and `windowSize` props ### Code Splitting ```bash theme={"system"} npm install @react-native-community/cli-plugin-metro ``` ## Troubleshooting ### Metro Bundler Issues ```bash theme={"system"} # Clear cache and restart npm start -- --reset-cache ``` ```bash iOS Build Issues theme={"system"} cd ios pod deintegrate pod install cd .. ``` ```bash Android Build Issues theme={"system"} cd android ./gradlew clean cd .. ``` ### CORS Errors If you encounter CORS errors, configure WordPress to allow cross-origin requests. See [CORS documentation](../../documentation/cors). ### Network Issues ```text iOS Simulator theme={"system"} Use localhost or 127.0.0.1 in your API_URL: API_URL=http://localhost:8000/wp-json/cocart/v2 ``` ```text Android Emulator theme={"system"} Use 10.0.2.2 instead of localhost: API_URL=http://10.0.2.2:8000/wp-json/cocart/v2 Or use your computer's IP address: API_URL=http://192.168.1.100:8000/wp-json/cocart/v2 ``` ## Next Steps Now that your React Native app is set up with CoCart: 1. Implement full product detail screens 2. Complete cart functionality (update quantities, remove items) 3. Add checkout flow 4. Implement user authentication with JWT 5. Add push notifications for order updates 6. Implement offline support with AsyncStorage 7. Add analytics and crash reporting ## Resources * [React Native Documentation](https://reactnative.dev/docs/getting-started) * [CoCart API Reference](../../api-reference/introduction) * [React Navigation](https://reactnavigation.org/docs/getting-started) * [React Query](https://tanstack.com/query/latest/docs/react/overview) * [Expo Documentation](https://docs.expo.dev/) (if using Expo) # Setting Up SvelteKit Source: https://docs.cocartapi.com/tutorials/sveltekit/setup Learn how to set up a SvelteKit project for your headless WooCommerce store This tutorial was written by [Claude Code (an AI)](https://claude.com/product/claude-code) and has not yet been reviewed. Follow along with caution. If the tutorial was helpful or a specific part was not clear/correct, please provide feedback at the bottom of the page. Thank you. # Introduction [SvelteKit](https://kit.svelte.dev) is a modern web framework for building high-performance applications with Svelte. It's an excellent choice for headless storefronts with CoCart because of its speed, developer experience, and flexible rendering options. This guide will walk you through setting up a SvelteKit project configured to work with CoCart API. ## Why SvelteKit for Headless Commerce? * **Fast and lightweight** - Minimal JavaScript bundle with reactive components * **Flexible rendering** - Choose between SSR, SSG, or CSR per route * **Built-in routing** - File-based routing with layouts and nested routes * **Server-side capabilities** - API routes and server-only code with `+server.ts` and `+page.server.ts` * **Great DX** - Hot module replacement, TypeScript support, and excellent tooling * **Progressive enhancement** - Works without JavaScript, enhanced when available ## Prerequisites * Node.js 18 or higher * A WordPress site with WooCommerce installed * CoCart plugin installed and activated * Basic knowledge of JavaScript and command line ## Creating a New SvelteKit Project Create a new SvelteKit project using the official CLI: ```bash theme={"system"} npm create svelte@latest my-headless-store ``` When prompted, choose the following options: * **Which Svelte app template?** → Skeleton project * **Add type checking with TypeScript?** → Yes, using TypeScript syntax (recommended) * **Select additional options** → * Add ESLint for code linting (recommended) * Add Prettier for code formatting (recommended) Navigate to your project: ```bash theme={"system"} cd my-headless-store ``` Install dependencies: ```bash theme={"system"} npm install ``` ## Installing Tailwind CSS Install Tailwind CSS using the SvelteKit integration: ```bash theme={"system"} npx svelte-add@latest tailwindcss npm install ``` This will: * Install Tailwind CSS and its dependencies * Create `tailwind.config.js` and `postcss.config.js` files * Add necessary imports to your app ## Project Structure Your SvelteKit project should have this structure: ``` my-headless-store/ ├── src/ │ ├── lib/ │ │ ├── server/ # Server-only code │ │ └── cocart.ts # CoCart API client │ ├── routes/ │ │ ├── +layout.svelte # Root layout │ │ ├── +page.svelte # Home page │ │ └── api/ # API routes │ └── app.html # HTML template ├── static/ # Static assets ├── svelte.config.js # SvelteKit configuration ├── tailwind.config.js # Tailwind configuration └── package.json ``` SvelteKit distinguishes between client and server code. Code in `src/lib/server` is only bundled for the server and never sent to the client. ## Environment Configuration Create a `.env` file in your project root: ```bash theme={"system"} PUBLIC_STORE_URL=https://yourstore.com ``` Variables prefixed with `PUBLIC_` are exposed to the client-side code. Keep sensitive data in server-only environment variables without the `PUBLIC_` prefix. Add `.env` to your `.gitignore`: ```bash theme={"system"} echo ".env" >> .gitignore ``` Create a `.env.example` for your team: ```bash theme={"system"} # .env.example PUBLIC_STORE_URL=https://yourstore.com ``` ## Creating the CoCart API Client Create a centralized API client to interact with CoCart. Create `src/lib/cocart.ts`: ```typescript theme={"system"} import { PUBLIC_STORE_URL } from '$env/static/public'; const STORE_URL = PUBLIC_STORE_URL || 'https://yourstore.com'; const API_BASE = `${STORE_URL}/wp-json/cocart/v2`; /** * Fetch products from CoCart API */ export async function getProducts(params: { per_page?: number; page?: number; [key: string]: any; } = {}) { const queryParams = new URLSearchParams({ per_page: String(params.per_page || 12), page: String(params.page || 1), ...Object.fromEntries( Object.entries(params).map(([k, v]) => [k, String(v)]) ) }); try { const response = await fetch(`${API_BASE}/products?${queryParams}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return data; } catch (error) { console.error('Error fetching products:', error); return []; } } /** * Get a single product by ID */ export async function getProduct(productId: string | number) { try { const response = await fetch(`${API_BASE}/products/${productId}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error fetching product:', error); return null; } } /** * Add item to cart */ export async function addToCart( productId: string | number, quantity: number = 1, options: Record = {} ) { try { const response = await fetch(`${API_BASE}/cart/add-item`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id: productId, quantity: quantity, ...options }) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error adding to cart:', error); throw error; } } /** * Get current cart */ export async function getCart(cartKey: string | null = null) { const url = cartKey ? `${API_BASE}/cart?cart_key=${cartKey}` : `${API_BASE}/cart`; try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error fetching cart:', error); return null; } } /** * Update cart item quantity */ export async function updateCartItem(itemKey: string, quantity: number) { try { const response = await fetch(`${API_BASE}/cart/item/${itemKey}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ quantity }) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error updating cart item:', error); throw error; } } /** * Remove item from cart */ export async function removeCartItem(itemKey: string) { try { const response = await fetch(`${API_BASE}/cart/item/${itemKey}`, { method: 'DELETE' }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('Error removing cart item:', error); throw error; } } ``` ## Creating a Root Layout Create a root layout at `src/routes/+layout.svelte`: ```svelte theme={"system"}
``` ## Loading Data with Server-Side Rendering SvelteKit uses `+page.server.ts` files to load data on the server before rendering. Create `src/routes/+page.server.ts`: ```typescript theme={"system"} import { getProducts } from '$lib/cocart'; import type { PageServerLoad } from './$types'; export const load: PageServerLoad = async () => { const products = await getProducts({ per_page: 12 }); return { products }; }; ``` Then create the page at `src/routes/+page.svelte`: ```svelte theme={"system"}

Welcome to Your Headless Store

{#each data.products as product}

{product.name}

{product.prices.currency_symbol}{product.prices.price}

{/each}
``` SvelteKit automatically generates TypeScript types for your route data. The `PageData` type is auto-generated based on your `load` function's return value. ## Creating API Routes SvelteKit supports API routes using `+server.ts` files. Create `src/routes/api/cart/add/+server.ts`: ```typescript theme={"system"} import { json } from '@sveltejs/kit'; import { addToCart } from '$lib/cocart'; import type { RequestHandler } from './$types'; export const POST: RequestHandler = async ({ request }) => { try { const body = await request.json(); const { id, quantity = 1, ...options } = body; const result = await addToCart(id, quantity, options); return json(result); } catch (error) { return json( { error: error instanceof Error ? error.message : 'Unknown error' }, { status: 500 } ); } }; ``` ## Managing Cart State with Stores SvelteKit works seamlessly with Svelte stores for client-side state management. Create `src/lib/stores/cart.ts`: ```typescript theme={"system"} import { writable } from 'svelte/store'; interface CartItem { key: string; id: number; quantity: number; name: string; price: string; } interface Cart { items: CartItem[]; itemCount: number; total: string; } function createCartStore() { const { subscribe, set, update } = writable({ items: [], itemCount: 0, total: '0' }); return { subscribe, set, addItem: (item: CartItem) => update(cart => ({ ...cart, items: [...cart.items, item], itemCount: cart.itemCount + item.quantity })), removeItem: (itemKey: string) => update(cart => { const newItems = cart.items.filter(item => item.key !== itemKey); const newCount = newItems.reduce((sum, item) => sum + item.quantity, 0); return { ...cart, items: newItems, itemCount: newCount }; }), clear: () => set({ items: [], itemCount: 0, total: '0' }) }; } export const cart = createCartStore(); ``` Use the store in your components: ```svelte theme={"system"}

Cart items: {$cart.itemCount}

``` ## Running Your Project Start the development server: ```bash theme={"system"} npm run dev ``` Visit `http://localhost:5173` to see your store. Use `npm run dev -- --open` to automatically open the browser. ## Building for Production Build your site for production: ```bash theme={"system"} npm run build ``` Preview the production build: ```bash theme={"system"} npm run preview ``` ## Deployment Options SvelteKit supports multiple adapters for different deployment platforms: Install the Vercel adapter: ```bash theme={"system"} npm i -D @sveltejs/adapter-vercel ``` Update `svelte.config.js`: ```javascript theme={"system"} import adapter from '@sveltejs/adapter-vercel'; export default { kit: { adapter: adapter() } }; ``` Install the Netlify adapter: ```bash theme={"system"} npm i -D @sveltejs/adapter-netlify ``` Update `svelte.config.js`: ```javascript theme={"system"} import adapter from '@sveltejs/adapter-netlify'; export default { kit: { adapter: adapter() } }; ``` Install the Cloudflare adapter: ```bash theme={"system"} npm i -D @sveltejs/adapter-cloudflare ``` Update `svelte.config.js`: ```javascript theme={"system"} import adapter from '@sveltejs/adapter-cloudflare'; export default { kit: { adapter: adapter() } }; ``` Install the Node adapter: ```bash theme={"system"} npm i -D @sveltejs/adapter-node ``` Update `svelte.config.js`: ```javascript theme={"system"} import adapter from '@sveltejs/adapter-node'; export default { kit: { adapter: adapter() } }; ``` ## Advanced Configuration ### Form Actions SvelteKit's form actions provide a way to handle form submissions with progressive enhancement: ```typescript theme={"system"} // src/routes/cart/+page.server.ts import type { Actions } from './$types'; import { addToCart } from '$lib/cocart'; export const actions = { addToCart: async ({ request }) => { const data = await request.formData(); const productId = data.get('productId'); const quantity = Number(data.get('quantity')); try { await addToCart(productId as string, quantity); return { success: true }; } catch (error) { return { success: false, error: 'Failed to add item' }; } } } satisfies Actions; ``` ### Hooks for Global Request Handling Use `src/hooks.server.ts` for global request handling like authentication: ```typescript theme={"system"} import type { Handle } from '@sveltejs/kit'; export const handle: Handle = async ({ event, resolve }) => { // Add custom headers, handle authentication, etc. const response = await resolve(event); return response; }; ``` ## Troubleshooting If you encounter CORS errors, you may need to configure WordPress to allow cross-origin requests. See the [CORS documentation](/documentation/cors). 1. Verify your `PUBLIC_STORE_URL` is correct in `.env` 2. Ensure CoCart is installed and activated 3. Check that WooCommerce is configured properly 4. Test API endpoints directly in your browser or Postman If you encounter build errors: 1. Clear the `.svelte-kit` directory: `rm -rf .svelte-kit` 2. Reinstall dependencies: `npm install` 3. Try building again: `npm run build` ## Next Steps Now that your SvelteKit project is set up with CoCart: 1. Build product listing pages with dynamic routes 2. Create a shopping cart page with real-time updates 3. Implement checkout functionality 4. Add user authentication with JWT 5. Optimize for performance with preloading and caching ## Resources * [SvelteKit Documentation](https://kit.svelte.dev) * [CoCart API Reference](/api-reference/introduction) * [Tailwind CSS Documentation](https://tailwindcss.com) * [Svelte Tutorial](https://svelte.dev/tutorial) # Generate TypeScript Types Source: https://docs.cocartapi.com/tutorials/typescript-types-generation Learn how to automatically generate TypeScript types from CoCart OpenAPI specifications for type-safe development This tutorial was written by [Claude Code (an AI)](https://claude.com/product/claude-code) and has not yet been reviewed. Follow along with caution. If the tutorial was helpful or a specific part was not clear/correct, please provide feedback at the bottom of the page. Thank you. # Introduction TypeScript provides strong typing that helps catch errors at compile time and improves developer experience with better autocompletion. CoCart provides OpenAPI specification files that can be used to automatically generate TypeScript types for all API endpoints, request bodies, and response schemas. This tutorial will show you how to generate and use TypeScript types from the CoCart OpenAPI specifications in your TypeScript projects. ## Why Use Generated Types? * **Type safety** - Catch errors at compile time instead of runtime * **Better IDE support** - Get accurate autocompletion and IntelliSense * **Automatic updates** - Regenerate types when the API changes * **Self-documenting** - Types serve as inline documentation * **Reduced errors** - Prevent typos and incorrect API usage ## Prerequisites * Node.js 18 or higher * A TypeScript project (Next.js, React, Node.js, etc.) * Basic knowledge of TypeScript * CoCart API endpoint URL ## Available OpenAPI Specifications CoCart provides several OpenAPI specification files depending on which API version you're using: | API Version | Specification File | Recommended For | | ------------------ | ----------------------------- | --------------------------- | | **v2 Stable** | `openapi-v2-stable.yaml` | Production applications | | **v2 Pre-release** | `openapi-v2-pre-release.yaml` | Testing upcoming features | | **v1 Cart** | `openapi-cart-v1.yaml` | Legacy v1 cart endpoints | | **v1 Products** | `openapi-products-v1.yaml` | Legacy v1 product endpoints | This tutorial focuses on the **v2 Stable API**, which is recommended for all new projects. ## Installation Install the `openapi-typescript` package as a development dependency: ```bash theme={"system"} npm install -D openapi-typescript ``` Or if you prefer Yarn: ```bash theme={"system"} yarn add -D openapi-typescript ``` ## Generating Types from Remote URL The easiest way to generate types is directly from the GitHub repository: ```bash theme={"system"} npx openapi-typescript https://raw.githubusercontent.com/cocart-headless/cocart-api-documentation/main/api-reference/v2/openapi-v2-stable.yaml -o src/types/cocart.ts ``` This command: * Fetches the OpenAPI spec from GitHub * Generates TypeScript types * Saves them to `src/types/cocart.ts` Add this command to your `package.json` scripts for easy regeneration: ```json theme={"system"} { "scripts": { "generate-types": "openapi-typescript https://raw.githubusercontent.com/cocart-headless/cocart-api-documentation/main/api-reference/v2/openapi-v2-stable.yaml -o src/types/cocart.ts" } } ``` Then run: `npm run generate-types` ## Generating Types from Local File If you have the OpenAPI specification file locally: 1. **Download the specification file** to your project: ```bash theme={"system"} curl -o openapi-v2-stable.yaml https://raw.githubusercontent.com/cocart-headless/cocart-api-documentation/main/api-reference/v2/openapi-v2-stable.yaml ``` 2. **Generate types from the local file**: ```bash theme={"system"} npx openapi-typescript ./openapi-v2-stable.yaml -o src/types/cocart.ts ``` ## Using Generated Types Once you've generated the types, you can use them in your TypeScript code. The generated types follow this structure: ```typescript theme={"system"} import type { paths, components } from './types/cocart'; // Extract types from paths type CartResponse = paths['/cart']['get']['responses']['200']['content']['application/json']; type AddItemRequest = paths['/cart/add-item']['post']['requestBody']['content']['application/json']; // Extract types from components/schemas type Product = components['schemas']['Product']; type Cart = components['schemas']['Cart']; ``` ### Example: Creating a Type-Safe API Client Create a type-safe API client using the generated types: ```typescript theme={"system"} import type { paths, components } from './types/cocart'; const API_BASE = 'https://yourstore.com/wp-json/cocart/v2'; // Type-safe function to get cart export async function getCart(): Promise { const response = await fetch(`${API_BASE}/cart`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); } // Type-safe function to add item to cart export async function addToCart( data: paths['/cart/add-item']['post']['requestBody']['content']['application/json'] ): Promise { const response = await fetch(`${API_BASE}/cart/add-item`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data), }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); } // Type-safe function to get products export async function getProducts( params?: paths['/products']['get']['parameters']['query'] ): Promise { const queryString = params ? new URLSearchParams(params as any).toString() : ''; const url = `${API_BASE}/products${queryString ? `?${queryString}` : ''}`; const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); } ``` ### Example: Using Types in React Components Use the generated types in your React components: ```typescript theme={"system"} import React, { useEffect, useState } from 'react'; import type { components } from './types/cocart'; import { getCart, addToCart } from './api/cocart'; type Cart = components['schemas']['Cart']; type Product = components['schemas']['Product']; export function ProductCard({ product }: { product: Product }) { const [isAdding, setIsAdding] = useState(false); const handleAddToCart = async () => { setIsAdding(true); try { await addToCart({ id: product.id.toString(), quantity: 1, }); alert('Added to cart!'); } catch (error) { console.error('Failed to add to cart:', error); } finally { setIsAdding(false); } }; return (

{product.name}

{product.prices.currency_symbol}{product.prices.price}

); } export function CartSummary() { const [cart, setCart] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { getCart() .then(setCart) .catch(console.error) .finally(() => setLoading(false)); }, []); if (loading) return
Loading cart...
; if (!cart) return
Failed to load cart
; return (

Cart ({cart.items_count} items)

Total: {cart.totals.currency_symbol}{cart.totals.total}

); } ``` ### Example: Using with Axios Create a type-safe Axios client: ```typescript theme={"system"} import axios, { AxiosInstance } from 'axios'; import type { paths, components } from './types/cocart'; const api: AxiosInstance = axios.create({ baseURL: 'https://yourstore.com/wp-json/cocart/v2', headers: { 'Content-Type': 'application/json', }, }); // Type-safe cart operations export const cartApi = { getCart: async (): Promise => { const response = await api.get('/cart'); return response.data; }, addItem: async ( data: paths['/cart/add-item']['post']['requestBody']['content']['application/json'] ): Promise => { const response = await api.post('/cart/add-item', data); return response.data; }, updateItem: async ( itemKey: string, data: paths['/cart/item/{item_key}']['post']['requestBody']['content']['application/json'] ): Promise => { const response = await api.post(`/cart/item/${itemKey}`, data); return response.data; }, removeItem: async (itemKey: string): Promise => { const response = await api.delete(`/cart/item/${itemKey}`); return response.data; }, }; // Type-safe product operations export const productApi = { getProducts: async ( params?: paths['/products']['get']['parameters']['query'] ): Promise => { const response = await api.get('/products', { params }); return response.data; }, getProduct: async (id: string): Promise => { const response = await api.get(`/products/${id}`); return response.data; }, }; ``` ### Example: Using with React Query Combine generated types with React Query for powerful data fetching: ```typescript theme={"system"} import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import type { components } from './types/cocart'; import { getCart, addToCart, getProducts } from './api/cocart'; type Cart = components['schemas']['Cart']; type Product = components['schemas']['Product']; // Hook for fetching cart export function useCart() { return useQuery({ queryKey: ['cart'], queryFn: getCart, }); } // Hook for adding to cart export function useAddToCart() { const queryClient = useQueryClient(); return useMutation({ mutationFn: addToCart, onSuccess: () => { // Invalidate cart query to refetch queryClient.invalidateQueries({ queryKey: ['cart'] }); }, }); } // Hook for fetching products export function useProducts(params?: { per_page?: number; page?: number }) { return useQuery({ queryKey: ['products', params], queryFn: () => getProducts(params), }); } ``` ## Advanced Configuration ### Custom Output Options The `openapi-typescript` CLI supports various options: ```bash theme={"system"} # Generate with additional options npx openapi-typescript https://raw.githubusercontent.com/cocart-headless/cocart-api-documentation/main/api-reference/v2/openapi-v2-stable.yaml \ -o src/types/cocart.ts \ --alphabetize \ --export-type ``` Available options: * `--alphabetize` - Sort types alphabetically * `--export-type` - Use `export type` instead of `export interface` * `--path-params-as-types` - Generate path parameters as types * `--additional-properties` - Allow additional properties in objects ### Generating Multiple API Versions If you need types for multiple API versions: ```json theme={"system"} { "scripts": { "generate-types:v2": "openapi-typescript https://raw.githubusercontent.com/cocart-headless/cocart-api-documentation/main/api-reference/v2/openapi-v2-stable.yaml -o src/types/cocart-v2.ts", "generate-types:v2-pre": "openapi-typescript https://raw.githubusercontent.com/cocart-headless/cocart-api-documentation/main/api-reference/v2/openapi-v2-pre-release.yaml -o src/types/cocart-v2-pre.ts", "generate-types:all": "npm run generate-types:v2 && npm run generate-types:v2-pre" } } ``` ### Using with Your Own WordPress Instance If you're using a custom CoCart installation with extended endpoints, you can generate types from your own OpenAPI spec: ```bash theme={"system"} # If your WordPress site exposes the OpenAPI spec npx openapi-typescript https://yourstore.com/wp-json/cocart/v2/openapi.json -o src/types/cocart.ts ``` ## Type Utilities Create utility types for common use cases: ```typescript theme={"system"} import type { paths, components } from './types/cocart'; // Extract all cart-related types export type Cart = components['schemas']['Cart']; export type CartItem = components['schemas']['CartItem']; export type CartTotals = components['schemas']['CartTotals']; // Extract all product-related types export type Product = components['schemas']['Product']; export type ProductVariation = components['schemas']['ProductVariation']; export type ProductCategory = components['schemas']['ProductCategory']; // Extract request/response types export type AddItemRequest = paths['/cart/add-item']['post']['requestBody']['content']['application/json']; export type AddItemResponse = paths['/cart/add-item']['post']['responses']['200']['content']['application/json']; export type UpdateItemRequest = paths['/cart/item/{item_key}']['post']['requestBody']['content']['application/json']; export type UpdateItemResponse = paths['/cart/item/{item_key}']['post']['responses']['200']['content']['application/json']; // Extract query parameter types export type ProductsQuery = paths['/products']['get']['parameters']['query']; export type CartQuery = paths['/cart']['get']['parameters']['query']; // Helper type for API errors export type ApiError = { code: string; message: string; data?: { status: number; [key: string]: any; }; }; ``` ## Best Practices Regenerate types regularly when: * CoCart releases a new version * You update your CoCart plugin * API endpoints change ```bash theme={"system"} npm run generate-types ``` Commit generated types to version control so all team members have access: ```bash theme={"system"} git add src/types/cocart.ts git commit -m "chore: update CoCart types" ``` Keep generated types separate from custom types: ``` src/ ├── types/ │ ├── cocart.ts # Generated types │ ├── cocart-utils.ts # Custom utility types │ └── index.ts # Type exports ``` Create type guards for runtime type checking: ```typescript theme={"system"} import type { Cart } from './types/cocart'; export function isCart(data: unknown): data is Cart { return ( typeof data === 'object' && data !== null && 'items_count' in data && 'totals' in data ); } ``` ## Troubleshooting ### Types Not Generating If type generation fails: 1. **Check your internet connection** (for remote URLs) 2. **Verify the OpenAPI spec URL** is correct 3. **Ensure openapi-typescript is installed**: ```bash theme={"system"} npm install -D openapi-typescript ``` 4. **Try with verbose output**: ```bash theme={"system"} npx openapi-typescript [url] -o types.ts --verbose ``` ### Type Errors in IDE If your IDE shows type errors: 1. **Restart your TypeScript server** in VS Code: `Cmd/Ctrl + Shift + P` → "TypeScript: Restart TS Server" 2. **Check tsconfig.json** includes the types directory: ```json theme={"system"} { "include": ["src/**/*"] } ``` 3. **Regenerate types** to ensure they're up-to-date ### Missing Types If some types are missing: * The OpenAPI spec may not include all schemas * Check if the endpoint exists in the specification file * You may need to create custom types for extended functionality ## Next Steps Now that you have TypeScript types set up: 1. [Implement cart functionality](/tutorials/nextjs/setup) with type safety 2. [Add user authentication](/api-reference/authentication) with typed requests 3. [Build a checkout flow](/api-reference/v2/cart/post-add-item) with full type coverage 4. [Explore the API Reference](/api-reference/introduction) to see all available endpoints ## Resources Official documentation for openapi-typescript Complete API documentation with all endpoints Learn more about TypeScript OpenAPI specification documentation # CoCart Core Updates Source: https://docs.cocartapi.com/updates/core Keep up with all the latest improvements, features, and fixes in CoCart Core. Stay up to date with the latest releases and improvements to CoCart Core. Each update brings new features, bug fixes, and performance enhancements to help you build better headless WooCommerce experiences. For complete technical details, visit the [full changelog on GitHub](https://github.com/co-cart/co-cart/blob/trunk/CHANGELOG.md). *** ## Enhanced Login Security & Proxy Support We've strengthened the authentication system with better security controls and improved proxy detection. This release introduces several new filter hooks that give you fine-grained control over the login endpoint's permission system. If you're running CoCart behind a proxy or load balancer, you'll appreciate the enhanced IP address detection that now supports trusted proxy configurations. We've also added helpful logging to make debugging authentication issues much easier. For developers, there are six new filters available to customize authentication behavior, including `cocart_login_permission_callback` for adding custom permission checks and `cocart_trusted_proxies` for configuring your proxy setup. **Compatibility:** WooCommerce v10.2 ## Plugin Renamed for WordPress Directory To comply with WordPress directory trademark guidelines, we've updated the plugin name from "Headless WooCommerce Made Easy with CoCart" to "Headless eCommerce API for Developers - CoCart". This is purely a branding change—everything else works exactly the same. We've also added support for authenticating via JSON request body on the API v2 login endpoint, making it easier to integrate with modern frontend frameworks that prefer JSON over form data. ## Session Management Improvements Fixed a critical issue where the "Load Cart from Session" feature was inadvertently destroying sessions after loading them, which was caused by session improvements in WooCommerce v10. If you experienced carts not persisting correctly, this update resolves that. We've also optimized the session handler to reduce duplicate database calls and improved how session timestamps are updated. These changes should result in better performance, especially on high-traffic stores. **Deprecated:** The `cocart_load_cart_override` action hook is no longer used. ## WooCommerce v10 Cart Persistence Fix This release fixes a frustrating bug where removing items from the cart wouldn't stick. WooCommerce v10 introduced changes to session data handling that created cache conflicts—we've resolved this with session handler optimizations. We've also added a 30-day maximum expiration limit for cart sessions to prevent your session table from growing too large and impacting performance. The cart cache now loads with WooCommerce instead of only during REST API requests, ensuring consistent pricing calculations whether you're using the API or WooCommerce's native cart. **Important:** WooCommerce v9 is now the minimum required version, though we recommend v10+ for best performance. **Compatibility:** WooCommerce v10.0.4 ## Empty Cart Error Fixes Quick fix for `undefined array key` errors that were appearing when the cart was empty. We've also resolved an issue where items couldn't be removed via the update endpoint due to quantity validation problems. **Compatibility:** WooCommerce v10.0.3 ## WooCommerce v10 Ready This release focuses on compatibility with WooCommerce v10. We've refreshed CoCart's branding and improved styling consistency across all admin pages to reduce conflicts with WordPress and WooCommerce. Authentication has been enhanced with better detection for basic auth and new debug logs to help troubleshoot authentication failures. We've also improved accessibility with a semantic markup overhaul for better screen reader support. WordPress.org users can now try CoCart instantly using the new Playground blueprint—perfect for testing before installing. **Compatibility:** WooCommerce v10.0 ## Product Filtering by Brand You can now filter products by brand names in the Products API. We've also added the missing option to order products randomly, which was requested by the community. This will likely be the last feature release on the WordPress plugin directory as we transition to a new distribution model. Future updates will focus on maintenance and compatibility. **Compatibility:** WooCommerce v9.9 ## Automatic Database Updates Database updates now run automatically when needed—no more manual intervention required. This is especially helpful if you're using site management tools like ManageWP, MainWP, or BlogVault. We've aligned cart session expirations with WooCommerce's defaults for better abandoned cart compatibility. Logged-in users now get persistent carts that renew daily and expire after a week, while guest carts follow WooCommerce's standard expiration. LiteSpeed Cache users will benefit from automatic exclusion of CoCart from caching, preventing stale cart data issues. **For developers:** The `cocart_cart_expiring` and `cocart_cart_expiration` filters now include the `is_user_logged_in()` parameter for better control. ## Variation Attribute Sanitization Product variation attributes are now properly sanitized, with labels automatically converted to their internal names (for example, "Size" becomes "pa\_size"). This ensures consistency across your API responses. **Compatibility:** WordPress v6.8 ## Shipping Settings Respect We've fixed an issue where package details weren't being returned properly and optimized cart fetching across all endpoints. Shipping methods now fully respect your WooCommerce shipping settings. If you've configured your store to require a shipping address before calculating shipping, the API will correctly return no methods until the customer provides their address. **Compatibility:** WooCommerce v9.8 ## Critical Error Fix & WordPress 6.3 Required Fixed a critical error that occurred when adding items to the cart while requesting item details to be returned. We've also corrected missing schema information for Cart API v1. **Important:** WordPress 6.3 is now the minimum required version. ## Guest Session Identification Guest carts now include a `t_` prefix before the cart key, matching WooCommerce's session handler convention. This helps third-party plugins and hosting configurations identify guest sessions more reliably. We've also improved authentication error handling by making error access public, preventing other authentication plugins from failing unnecessarily. **Compatibility:** WooCommerce v9.7 ## New Customer Field Filters We've improved how customer fields are handled with two powerful new filters. The `cocart_get_customer_{field}` filter now runs after value retrieval, allowing you to transform customer data (like converting country codes to country names). There's also a new `cocart_get_after_customer_{field-type}_fields` filter for modifying all billing or shipping fields at once. The cart and items endpoint schemas have been corrected for better API documentation. ## Cache Control for Guest Users Added `no-store` to the `Cache-Control` header for guest users, preventing browsers and proxies from caching sensitive cart data. ## Persistent Cart Fix for Registered Users Fixed the root cause of persistent cart issues affecting registered customers. If you experienced carts not saving properly for logged-in users, this update resolves that completely. ## Security Patch: Meta Data Exposure **Security Update:** We've patched an issue where hidden and private product meta data could be exposed through the API. CoCart now properly filters out any meta data that should remain private. As a bonus improvement, the `Last-Modified` header now returns the actual product modification date when a product ID is detected. ## Cache Header Improvements Removed conflicting cache headers and improved cache handling across the board. Cache headers now respect authentication status and are set at a better priority to prevent conflicts with cache plugins and preflight requests. The `Last-Modified` header now properly respects your WordPress timezone settings instead of always using UTC. **Compatibility:** WordPress v6.7, WooCommerce v9.4 ## Security Patch: Third Party Plugins **Security Update:** While not directly a CoCart vulnerability, we've added proactive protection against public information leaks from other WooCommerce plugins. Since CoCart is a public API, we're releasing security patches quickly to protect your store without waiting for third-party fixes. If you notice any security concerns with CoCart or plugins that connect to it, please [report them responsibly](https://cocartapi.com/security-policy/#Reporting-Security-Vulnerabilities). ## Cart Tax Display Fix Fixed a fatal error when adding items to the cart and corrected how cart item prices are displayed. Prices now properly reflect your cart's tax settings rather than your store's default settings. ## Cart Validation Improvements We've made several improvements to cart validation and item handling. The cart now validates earlier in the request lifecycle, and item keys are properly reset when re-adding items to prevent manipulation. The upgrade notice timing has been adjusted to show after 6 weeks instead of 4, and we've removed unnecessary Gravatar API calls from the dashboard. Translation contributors should note that our translation URL has moved to [translate.cocartapi.com](https://translate.cocartapi.com). ## Session API & CORS Fixes We've resolved several CORS-related issues and fixed the Sessions API not properly accessing the session handler. The `access-control-allow-origin` header is now correctly returned, and header sending priority has been adjusted for better compatibility. Cart merging from guest to authenticated users now works reliably. ## Price Consistency & Weight Format Product prices are now fully consistent in Cart API v2, even for stores configured without decimal places. We've also fixed how weight values are returned—they now come back as strings to preserve accuracy without rounding issues. Several autoload path issues have been corrected, improving overall plugin stability. ## Major Session Handler Refresh We've completely refreshed our session handler to extend WooCommerce's native session handler instead of forking it. This makes CoCart significantly more compatible with third-party plugins and WooCommerce's new cart and checkout blocks. **Important changes:** * Cookies are no longer used for headless carts—use the cart key returned in headers or response * Better user switching support * Improved cart migration from guest to authenticated users * Can now request a specific cart via the `cocart-api-cart-key` header This is a significant architectural improvement that sets the foundation for better compatibility going forward. We recommend testing on staging first, as several experimental functions and filters have been deprecated. **Compatibility:** WordPress v6.6, WooCommerce v9.0 ## Customer Details & Phone Authentication You can now set customer billing details directly through the cart API with a new callback. Basic Authentication has been enhanced to accept a customer's billing phone number as their username—useful for phone-based authentication flows. Authentication is now more robust, detecting authorization headers through multiple methods including `HTTP_AUTHORIZATION`, `REDIRECT_HTTP_AUTHORIZATION`, and `getallheaders()`. Stock details now properly return for product variations in the Products API v2. **Deprecated:** The legacy API (CoCart's original version) has been removed. The minimum WooCommerce version is now 4.5. ## Batch Support & Quantity Validation CoCart 4.0 introduces batch support for Cart API v2 endpoints, allowing you to perform multiple cart operations in a single request. You can now batch add items, clear cart, remove items, restore items, and update the cart—dramatically reducing API calls for complex cart operations. **Breaking change:** The quantity parameter must now be passed as a string (not integer) when adding or updating items. This ensures consistent data handling across all cart operations. We've fixed several important issues including CORS credentials being returned incorrectly and improved cart update resilience—updates now continue processing even if an item no longer exists. Product API schemas have been completed for v1 and corrected for v2, ensuring accurate API documentation. [Read the full release announcement](https://cocart.dev/cocart-4-0-released-now-with-cart-batch-support-and-more/) ## Products API Enhancements We've added powerful new capabilities to the Products API, including the ability to query product variations by attribute slugs and filter product meta data for better security. Product taxonomies are now fully accessible, and we've introduced filters to prevent sensitive meta data from being exposed through the API—important for protecting customer information that some plugins might inadvertently make public. Cart performance has been improved when returning items, and product queries now properly handle date ranges. **For developers:** New filters `cocart_products_ignore_private_meta_keys` and `cocart_products_get_safe_meta_data` give you control over what product meta is exposed. ## Performance & Compatibility This release focuses on performance improvements and better WordPress integration. CoCart now uses significantly less memory and sends headers more efficiently using WordPress's native `send_headers()` function. We've improved how plugin suggestions work in the WordPress dashboard and enhanced the Products API with support for excluding related products and better argument handling. **Compatibility:** PHP v8.3, WooCommerce v8.6 ## Support Page & Security Improvements We've added a new support page in the WordPress dashboard and introduced helpful tabs on all CoCart admin pages to make getting help easier. For enhanced security, CoCart namespaces and routes are now hidden from the WordPress REST API index unless debug mode is enabled—this helps prevent external scanning of your store's API setup. Several PHP 8.1+ compatibility issues have been resolved, and the Setup Wizard no longer blocks access to the WordPress dashboard during installation. **Compatibility:** WordPress v6.4, WooCommerce v8.4 **Requirements:** PHP 7.4 minimum (previously 7.0) ## WooCommerce HPOS Support Removed WooCommerce plugin headers to prevent incompatibility warnings when using the High-Performance Order Storage (HPOS) feature. This ensures smooth operation with WooCommerce's modern order management system. We've also fixed an issue where products without featured images couldn't determine the placeholder image. **Compatibility:** WooCommerce v7.9 ## Developer Hooks & Cart Loading Introduced the `cocart_cart_loaded` hook, allowing developers to trigger webhooks when a cart is loaded from session—perfect for tracking and analytics integrations. Authentication has been enhanced with better PHP 8.1+ compatibility and new filters for extending the login response. **Compatibility:** WooCommerce v7.4 ## Cart Cache & Item Validation Fixed critical issues with custom pricing not being applied when carts are loaded from session. The cart cache system now properly maintains custom prices across sessions. Item validation has been improved to catch issues earlier, preventing errors when products no longer exist. We've also resolved several edge cases with item quantity updates and removed item handling. **Compatibility:** WooCommerce v7.0 ## WooCommerce Detection & Yoast SEO CoCart installation now requires WooCommerce to be active first, preventing activation errors on fresh WordPress installs. The plugin will deactivate automatically if WooCommerce is not detected. Product queries can now use both category/tag slugs and IDs for more flexible filtering. Yoast SEO support has been adjusted—the `yoast_head` field is now available by default for better SEO integration. **Compatibility:** WordPress v6.0, WooCommerce v6.6 ## Cache Prevention & Plugin Suggestions Added support to prevent CoCart from being cached by WP Super Cache and specific web hosts like Pantheon. This ensures your cart API always returns fresh data. Plugin suggestions system has been completely rebuilt to fetch data from a cached JSON file, improving dashboard performance. Products API v2 now properly handles placeholder images when products don't have featured images. **For developers:** New filter `cocart_send_cache_control_patterns` lets you control which routes should not be cached. **Compatibility:** WooCommerce v6.4 ## Products API Pagination Products API v2 now returns proper pagination information as a separate object, making it easier to navigate through product listings. Pagination links automatically include your query arguments for seamless navigation. We've improved performance by unregistering Yoast SEO's duplicate `yoast_head` field while keeping `yoast_head_json` for better JSON response validation. **Breaking change:** Products array is now nested under a `products` object instead of being returned directly. This only affects the get all products endpoint in API v2. ## Major Feature Release This is one of the biggest releases in CoCart's history, introducing groundbreaking features: **Setup Wizard** - Helps new stores prepare for headless commerce **Custom Cart Callbacks** - Build your own cart update endpoints for unlimited flexibility **Products API Merged** - The Products add-on is now part of CoCart core with API v2 **Custom Pricing** - Set custom prices for items when adding to cart (simple products and variations) **Field Selection** - Request only the cart fields you need, like GraphQL, for incredible performance **Bulk Updates** - Update multiple item quantities at once **Email Capture** - Set billing email when adding items for abandoned cart tracking Cart responses are now faster with selective field loading, timestamp headers show request timing, and login responses include user avatars and email addresses. **Important:** If using CoCart Products add-on, update it before upgrading to prevent site crashes. **Requirements:** WordPress v5.6 minimum **Compatibility:** WordPress v5.9, WooCommerce v6.2 ## Validation Fixes Fixed item removal validation issues for specific edge cases and resolved an undefined function error with `get_current_screen()`. ## API v2 Launch CoCart 3.0 marked a major milestone with the introduction of API v2—a complete redesign of the cart response with improved structure, better performance, and enhanced developer experience. This release brought significant improvements to how cart data is organized and returned, making it easier to build modern frontend applications. The enhanced cart response provides clearer structure for items, totals, shipping, and customer data. While API v1 remains available for backward compatibility, v2 set the foundation for all future CoCart development with a more logical, developer-friendly architecture. This was the beginning of CoCart's evolution into the powerful headless commerce solution it is today. *** ## Earlier Versions For changelog entries prior to v3.0.0, please refer to the [complete changelog on GitHub](https://github.com/co-cart/co-cart/blob/trunk/CHANGELOG.md). *** ## Need Help? Found a bug? Let us know on GitHub Need help? Check our support policy Connect with other CoCart developers See what's coming next # Documentation Source: https://docs.cocartapi.com/updates/documentation Keep up with new additions or changes to the documentation ## ?? ??, 2025 * New release of documentation and user guides for all of CoCart. # CoCart JWT Authentication Updates Source: https://docs.cocartapi.com/updates/jwt Keep up with all the latest improvements, features, and fixes in CoCart JWT Authentication. Stay up to date with the latest releases and improvements to CoCart JWT Authentication. This plugin provides secure token-based authentication for your headless WooCommerce store. CoCart JWT Authentication is a separate plugin that works specifically for CoCart to provide token-based authentication. *** ## Multi-Token Sessions & Enhanced Security This is a major security and functionality update that introduces multi-device token management and improved tracking. **🔴 Breaking Change:** Previous tokens will be invalidated and users will need to re-authenticate. **Multi-Token Support** - Users can now have multiple active token sessions, each tracked separately for different devices or browsers. This enables proper token lifecycle management across all user devices. **Personal Access Token (PAT) Integration** - Tokens are now dual-secured with PAT IDs, preventing token proliferation when users are already authenticated. The system returns existing tokens instead of creating new ones. **Enhanced WP-CLI** - The CLI now accepts user ID, email, or login when creating tokens, and includes a new `destroy` command to remove tokens for specific users with confirmation prompts. **Setup Guide** - Added a WordPress dashboard setup guide with a built-in secret key generator for easier configuration. Tokens now log the last login timestamp as part of the PAT, and authorization fails if users have no tokens in session or if tokens aren't found—improving security across the board. **For developers:** New filter `cocart_jwt_auth_max_user_tokens` to set maximum tokens per user, and new action hook `cocart_jwt_auth_authenticated` that fires on authentication. **Compatibility:** CoCart v4.8 ## PHP 7.4 Compatibility Fix Fixed token generation compatibility issue with PHP v7.4, ensuring the plugin works reliably across all supported PHP versions. **Compatibility:** CoCart v4.7, WooCommerce v10.1 ## 🔥 Hot Patch: Guest User Support Critical fix for guest user authentication that was broken in the previous release. The authentication header validation now properly handles empty values, failing safely instead of returning errors. Thanks to @marianobitelo for reporting this issue quickly. ## Token Validation Improvements Enhanced token validation with improved pattern matching and more comprehensive debug logging to help troubleshoot authentication issues. We've corrected the plugin slug for the logger and improved how token values are checked against validation patterns. **For developers:** New filter `cocart_jwt_auth_token_prefix` lets you add a prefix to tokens to distinguish them from other authentication sources. **Compatibility:** CoCart v4.6, WooCommerce v9.9 ## Debug Logs & System Status Added comprehensive debug logging for authentication failures, making it much easier to identify where token validation is failing during development. The WooCommerce System Status page now includes JWT Authentication data, plus a handy button to manually clear expired tokens under Tools. ## Quick Error Fix Fixed an uncaught error that could occur in certain authentication scenarios. ## RSA-Based Configuration Support Added support for more advanced RSA-based token configuration, giving you greater control over token signing and validation. **New Developer Filters:** * `cocart_jwt_auth_token_before_sign` - Modify token data before signing * `cocart_jwt_auth_secret_private_key` - Set private key for token signing * `cocart_jwt_auth_secret_public_key` - Set public key for token validation * `cocart_jwt_auth_revoke_tokens_on_*` - Control token revocation on email changes, password changes, password resets, profile updates, user deletion, and logout **Filter Renamed:** `cocart_jwt_token_generated` → `cocart_jwt_auth_token_generated` for consistency (considered a typo correction) ## Token Validation & WP-CLI Commands Introduced a new REST API endpoint `cocart/jwt/validate-token` to check token validity without making authenticated requests. **WP-CLI Commands** - Comprehensive CLI support for token management: * List all tokens for users * View individual token details * Validate tokens * Clear expired tokens (or force clear all) * Create new tokens We've also improved how tokens are created, how users are identified, and optimized the cleanup of expired tokens to work in batches of 100 for better performance. **For developers:** New filter `cocart_jwt_auth_token_user_data` allows adding custom user data to the token payload before generation. ## Basic Auth & Action Hooks Added support for getting usernames during basic authentication via simple headers or URL parameters, making integration easier. Error responses now properly handle cases where a user account is deleted mid-request, preventing confusing error messages. **For developers:** Introduced a comprehensive set of action hooks that let you respond to various authentication events. Check the documentation for details on available hooks and usage examples. **Compatibility:** CoCart v4.3, WooCommerce v9.7 ## Token Refresh & Enhanced Security This major release introduces token refresh capabilities and significantly improved security features. **🔴 Breaking Change:** Previous tokens will be invalidated and users will need to re-authenticate. **Token Refresh Endpoint** - New `cocart/jwt/refresh-token` endpoint allows extending token lifetime without requiring re-authentication, improving user experience for long-lived sessions. **Device Binding** - Tokens are now bound to specific IP addresses or devices to mitigate token misuse and unauthorized access. **Flexible Algorithms** - You can now change the signing algorithm to any supported option per RFC 7518 specifications. **Longer Token Lifetime** - Tokens now expire after 10 days by default (previously 2 hours), reducing the need for frequent re-authentication. Authentication error messages have been simplified to make them harder to identify externally, improving security through obscurity. **For developers:** Six new filters for customizing token behavior: * `cocart_jwt_auth_issuer` - Change token issuer for multi-site setups * `cocart_jwt_auth_issued_at` - Adjust token timing * `cocart_jwt_auth_not_before` - Set earliest token usage time * `cocart_jwt_auth_algorithm` - Change signing algorithm * `cocart_jwt_auth_refresh_token_generation` - Customize refresh token creation * `cocart_jwt_refresh_token_expiration` - Control refresh token lifetime by role **Compatibility:** WordPress v6.7, WooCommerce v9.6 **Requires:** CoCart v4.3 minimum ## Enhanced Header Detection Authorization headers are now detectable using the `getallheaders()` function, improving compatibility with various server configurations. ## Compatibility Update Updated compatibility testing with the latest WordPress and WooCommerce versions. **Compatibility:** WordPress v6.5, WooCommerce v8.8 ## WooCommerce HPOS Support Removed WooCommerce plugin headers to prevent incompatibility warnings when using the High-Performance Order Storage (HPOS) feature. ## Initial Release The first public release of CoCart JWT Authentication, providing secure token-based authentication for headless WooCommerce stores. This plugin enables developers to authenticate API requests using JSON Web Tokens instead of traditional cookie-based authentication, perfect for modern JavaScript frameworks and mobile applications. *** ## Get JWT Authentication Download from GitHub or install from the WordPress plugin directory *** ## Need Help? Found a bug? Report it on GitHub Need help? Check our support policy Connect with other CoCart developers Learn how to set up JWT Authentication # Overview Source: https://docs.cocartapi.com/updates/overview Follow along with updates across CoCart. Keep up with new additions or changes to the documentation. Keep up with new additions or changes to the core plugin. Keep up with new additions or changes to CoCart Plus. Keep up with new additions or changes to the JWT Authentication. # CoCart Plus Updates Source: https://docs.cocartapi.com/updates/plus Keep up with all the latest improvements, features, and fixes in CoCart Plus. Stay up to date with the latest releases and improvements to CoCart Plus. Each update brings new features, bug fixes, and performance enhancements to extend CoCart's capabilities. CoCart Plus is a premium extension that adds advanced features like batch requests, rate limiting, and extended cart callbacks. *** ## Admin Notice & Totals Calculation Fix Fixed an issue with admin notice removal in the WordPress dashboard and ensured cart totals are properly calculated before handling any data operations. These fixes improve stability and prevent edge cases where cart data might be processed before totals are ready. ## Coupon Removal Fix Fixed a bug where removing coupons from the cart would silently return true without actually removing the coupon. Coupon removal now works reliably and provides proper feedback. ## Cloudflare Support & Staging Detection We've enhanced the rate limiter to properly detect Cloudflare's IP header, ensuring accurate rate limiting for sites behind Cloudflare's proxy. InstaWP domains are now automatically recognized as staging sites, making it easier to test CoCart Plus without license restrictions. Customer phone numbers and postcodes are now sanitized and formatted when validated, ensuring consistent data quality. **Important:** WooCommerce v7.0 is now the minimum required version, and CoCart v4.2+ will be required for future updates. **Compatibility:** WordPress v6.6 ## Quick Bug Fix Fixed an undefined index error for `ship_to_different_address` that could appear in certain checkout scenarios. ## Batch Requests & Shipping Details This release introduces powerful new capabilities for handling multiple cart operations efficiently. **Batch Endpoint** - Send multiple cart requests in a single API call and receive a unified cart response. This dramatically reduces API calls and improves performance for complex cart operations. (API v2 only) **Shipping Details Callback** - The cart callback has been extended to allow setting customer shipping details, complementing the existing billing details functionality. We've also improved session initialization to fail gracefully when sessions aren't available, preventing errors in edge cases. **Requires:** CoCart v4.1 ## Rate Limiting Introduced CoCart Plus now includes a comprehensive rate limiting system to protect your API from abuse and ensure fair usage across all clients. The rate limiter is fully configurable and includes detailed documentation to help you set appropriate limits for your store's needs. Check out our [Rate Limiting Guide](https://cocart.dev/guide/rate-limiting-guide/) for implementation details and testing strategies. We've also fixed the coupon endpoint REST base to ensure compatibility with CoCart v4.0 and adjusted error status codes to better reflect response types. **Compatibility:** CoCart v4.0, WooCommerce v8.9 ## Stylesheet Loading Fix Quick fix for the CoCart Updates page stylesheet not loading correctly in the WordPress dashboard. ## License Management & Subscription Support This release brings significant improvements to license management and adds WooCommerce Subscriptions support. **What's New:** * Subscription item details now included in Cart API v2 * License activation notifications in WordPress dashboard * Direct links to manage licenses via customer portal * Purchase license links for unlicensed installations * Recent updates feed on the CoCart Updates page **Security Improvements:** * Properly escaped dashboard values to prevent XSS * Updated to latest WordPress Coding Standards License activation messages for local and staging sites are now much clearer, and the activation status properly returns for these environments. **Compatibility:** WordPress v6.5, WooCommerce v8.8, PHP 8.3 ## Plugin Action Links Fix Fixed plugin action links appearing incorrectly for all plugins when CoCart Plus needed an update. ## Enhanced License Management We've significantly improved how CoCart Plus handles licenses and updates, making it easier to manage your license across different environments. **New Features:** * Force update check on WordPress updates page now clears cached plugin data * License expiration warnings on both Plugins and Updates pages * Site lock key to detect site migrations and prompt license reactivation * Better staging and local site detection during activation * License activation without domain protocol for seamless HTTP to HTTPS transitions We've also fixed a critical static method call error in the Totals Controller and resolved an issue where plugin information wouldn't return for existing licenses. ## License Activation Page Introduced a dedicated Updates page where you can enter and manage your license key. Once activated, you'll see your full license details and unlock automatic updates. We've also corrected default values for cart fees and fixed PHP deprecation warnings for float-to-int conversions. **Requirements:** * WordPress v5.6 minimum * PHP 7.4 minimum * CoCart v3.10 minimum **Compatibility:** WordPress v6.4.3, WooCommerce v8.5.2, PHP 8.2.10 *** ## Get CoCart Plus Unlock advanced features like batch requests, rate limiting, and priority support *** ## Need Help? Found a bug? Let us know on GitHub Need help? Check our support policy Connect with other CoCart developers See what's coming next