---
title: Developers
description: How CartPops V2 is built, and the PHP hooks, browser events, REST routes and CSS you can rely on when you extend it.
sidebar:
  label: Overview
  order: 0
---

This section documents the extension points CartPops V2 supports. Everything listed here was checked against the plugin source. If something is not listed, treat it as internal.

:::note[The API can change]
CartPops follows the changelog, not a semantic-versioning promise. Read the [changelog](/changelog) before you update a site that depends on these hooks.
:::

## How V2 is built

- **Blocks.** The cart drawer and the cart launcher are two WordPress blocks, `cartpops/cart-drawer` and `cartpops/cart-launcher`. On themes that do not place them, CartPops renders them for you in `wp_footer`.
- **WordPress Interactivity API.** Cart state in the browser lives in one Interactivity store named `cartpops`. The store is internal. Classic scripts cannot import it, so use the [browser events](/developers/javascript) instead.
- **WooCommerce Store API.** The drawer reads and changes the cart through the WooCommerce Store API (`/wc/store/v1`). CartPops adds its own data under the `cartpops` extension namespace.
- **`cartpops/v1` REST routes.** A small set of routes that CartPops' own interface uses for coupons, recommendations, drawer data and settings. See [Store API and REST](/developers/store-api-and-rest).
- **Server-rendered drawer.** PHP renders the first state of the drawer. After that the browser updates it. The PHP actions around the drawer run once per server render, not on every cart change.

The drawer is not a template you can override. V2 has no theme template folder for it. Use the documented positions and filters instead.

## Free and Pro

Free and Pro expose the same hooks and the same names. Three hooks only do anything on a site with an active Pro license, because the feature they change exists only in Pro:

- `cartpops_pro_recommendation_button_presentation`
- `cartpops_secondary_btn_classes`
- `cartpops_elementor_widget_cart_is_hidden`

On a Free site these three are never called, so a callback is harmless but has no effect.

## What is covered

**[PHP actions](/developers/php-actions)**

`cartpops_loaded` and the 18 drawer positions where you can print markup.

**[PHP filters](/developers/php-filters)**

URLs, the open-on-add trigger, cart item presentation, launcher attributes, REST origins and more.

**[JavaScript](/developers/javascript)**

Open or close the drawer from your own code and keep a header counter in sync.

**[Store API and REST](/developers/store-api-and-rest)**

The `cartpops` Store API namespace, the add-to-cart fragment and the `cartpops/v1` routes.

**[CSS customization](/developers/css-customization)**

Custom properties, stable class names and where Custom CSS loads.

## Safety rules that apply everywhere

CartPops treats filter results as untrusted input. Most filters validate what you return and fall back to a safe value if it is wrong. A fallback is silent, so if a filter seems to be ignored, check the accepted values on its page. Several filters also catch exceptions thrown by your callback. The ones that do not are marked on their page.

:::note[Coming from V1?]
Most V1 hooks, the `window.CartPops` object and the template overrides are gone. See [Upgrading to V2: for developers](/upgrading-to-v2/developers).
:::
