> ## Documentation Index
> Fetch the complete documentation index at: https://docs.joinerywp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Hooks and functions

> The public PHP API of Joinery Core.

## Actions

**joinery\_core\_init** `action`

Fires once the core is ready, with the `Joinery\Core\Plugin` instance. Register conditions and actions here.

**joinery\_admin\_enqueue** `action`

Fires on the Joinery admin page after the admin app is enqueued, with its script handle (`joinery-admin`). Enqueue scripts that add tabs here, with that handle as a dependency.

## Filters

**joinery\_apply\_rules\_to\_item** `filter`

`( bool $apply, array $cart_item )`. Return `false` to keep a cart line out of pricing: rules won't change its price, and it doesn't count toward the cart's quantity or subtotal. Gift Cards uses it so a €50 card always costs €50.

**joinery\_b2b\_apply\_trade\_price** `filter`

`( bool $apply, WC_Product $product )`, from B2B & Wholesale. Return `false` to keep a product at its normal price for trade customers. Gift Cards uses it so cards sell at face value.

**joinery\_po\_addon\_price** `filter`

`( float $amount, WC_Product $product )`, from Product Options. The fixed part of a cart line's add-ons, before it's added to the item price. B2B & Wholesale uses it to take a trade tier's discount off add-ons. Percentage add-ons follow the base price already, so they don't pass through it.

**joinery\_po\_apply\_to\_product** `filter`

`( bool $apply, WC_Product $product )`, from Product Options. Return `false` and the product shows no options, not even from option sets for all products. Gift Cards uses it so a card always costs its value.

**joinery\_returning\_customer\_statuses** `filter`

`( string[] $statuses )`. Order statuses that make a customer a returning customer, for `Context::$returning`. Default: paid statuses (`processing`, `completed`) plus `on-hold`.

**joinery\_apply\_rules\_to\_order\_item** `filter`

`( bool $apply, WC_Order_Item_Product $item )`. The same for rules that run after an order (event actions): return `false` and the line neither counts toward the rule's conditions nor earns a reward.

## Admin app (JavaScript)

**window\.joinery.registerTab( \{ id, label, render } )** `function`

Adds a tab to Joinery's admin page. `render` returns a React element (use `wp.element`). The tab opens at `admin.php?page=joinery#<id>`, so you can link straight to it.

**window\.joinery.ui** `object`

Shared components, `Card`, `PageIntro` and `Tag`, so your tab matches the rest of Joinery without bundling its own copy.

## Functions

**joinery\_register\_condition( Condition \$condition )** `function`

Adds a condition to the rules editor and the engine.

**joinery\_register\_action( Action \$action )** `function`

Adds an action. Implement `ItemPriceAction`, `CartDiscountAction` or `EventAction`.

**joinery\_wallet()** `function`

The customer wallet (`Joinery\Core\Wallet\Ledger`): `credit( $customer_id, $amount, $source, $order_id, $expires_at, $note )`, `debit( … )`, `balance( $customer_id )` and `entries( $customer_id )`. Spending uses up the credit that expires soonest; `debit()` returns 0 rather than overspend.

**joinery\_core\_version()** `function`

The installed core version, for checking compatibility: `version_compare( joinery_core_version(), '1.2.0', '>=' )`.

## Interfaces

| Interface | Purpose |
| - | - |
| `Joinery\Core\Rules\Condition` | `matches( $settings, Context $context ): bool` |
| `Joinery\Core\Rules\ItemPriceAction` | `adjust_price( float $price, $settings, Context $context ): float` |
| `Joinery\Core\Rules\CartDiscountAction` | `discount( $settings, Context $context ): float` |
| `Joinery\Core\Rules\LineDiscountAction` | `line_discounts( $settings, Context $context ): array` (amount off per line key) and `discount_label( $settings ): string` |
| `Joinery\Core\Rules\EventAction` | `events(): string[]` and `handle( $event, $payload, $settings )`, run after an order is paid or completed |
| `Joinery\Core\Rules\QuantityBreaks` | `quantity_breaks( $settings ): int[]`, for headless price tables |

`Context` is read-only data: `customer_id`, `roles`, `cart_quantity`, `cart_subtotal` (undiscounted), `now`, `returning` (whether the customer has ordered before: by account or billing email, counting paid and on-hold orders; `null` for a guest who hasn't entered an email yet), for line-scope checks, `item` (`product_id`, `category_ids`, `quantity`, `price`), and for cart-level actions, `lines`: every cart line rules apply to (`key`, `product_id`, `category_ids`, `quantity`, and `price` after item-price rules).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.