Skip to content

Powered by Grav CMS + Helios Theme

Twig functions and filters

KahunaCart registers Twig functions and filters that any theme can call, whether or not it uses the shipped templates. This page is the signature reference; worked examples and template override rules are on Storefront.

These are a theme's tool. To put a product grid or a buy button into an ordinary page's content, use the shortcodes instead — they render through these same functions and the same partials, and need neither security.twig_content nor a theme change.

Before you begin

  • KahunaCart installed and enabled.
  • A theme or a page template to call them from.

Everything here works in any storefront Twig template, including your own theme's. Nothing needs enabling.

Reference

text|kahunacart_markdownfilter

Merchant-written Markdown as HTML, with raw markup escaped and executable link targets defused

message|kahunacart_messagefilter

A storefront sentence as HTML: everything in it escaped, then its links and bold drawn

message|kahunacart_message_textfilter

The same storefront sentence as plain text, with its links and bold taken out, for an attribute, a title, or anywhere a link cannot go

minor|kahunacart_price(currency = null, with = null)filter

Formats minor units as money, localized to the active language, in the currency you pass or else the visitor's

kahunacart_account_profile_url()function

The credentials page, whose slug is configurable — a theme that hardcodes "/account/profile" breaks on any store that changed it

kahunacart_account_url()function

The customer account route, {base}/account, honouring your configured base

kahunacart_addons(product = null)function

A product's add-on options, priced, in the order the merchant put them

kahunacart_address_lines(address)function

An address as printable lines, laid out for its own country: postcode before the city in Germany, largest unit first in Japan, and the layout the partial always used everywhere else, with the country's name rather than its code on the last line

kahunacart_attribute(product, slug)function

One attribute's display string, or null when the product does not answer it, for the theme that wants a single fact in the hero rather than the whole table

kahunacart_attribute_url(product, slug)function

Where one attribute value's link goes: the shop narrowed to every product answering the same thing

kahunacart_attributes(product)function

A product's attributes, as the plugin's own product page has them: a list of {slug, label, type, value, display, unit, group, options, filter_url, values} in definition order, holding only the ones marked to show on the product and only where the product has an answer

kahunacart_avatar(size = 64)function

The signed-in customer's picture as a URL, at the pixel size you ask for

kahunacart_badges(product = null, labels = [])function

The badges over a product's picture, in the order they are drawn: sold out, pre-order, the sale, the merchant's own badge, download

kahunacart_base_route()function

The configured base route, normalized with a leading slash and no trailing one

kahunacart_buy_button_fields(product = null, variants = null)function

The form fields other plugins want inside this product's add-to-cart form, already rendered

kahunacart_buy_now(product = null)function

How a product's buy button behaves: {on, label}

kahunacart_cart_count()function

Total units in the current session's cart, or 0

kahunacart_cart_line_notes(order = null, items = null)function

What other plugins need the customer to read beside a cart or receipt line, keyed by line item id

kahunacart_cart_word()function

The storefront's word for the cart, cart, bag or basket (storefront.cart_word), for a theme that picks an icon or a class by it

kahunacart_categories()function

The whole category tree, nested

kahunacart_category_image(category = null, width = 160, height = null)function

A category's picture at the size you ask for, as {url, alt, width, height}, or null when the category has none

kahunacart_countries()function

Every ISO 3166-1 alpha-2 code with its English name, ordered by name, and the code checkout.default_country names (or '')

kahunacart_coupon_notice()function

The "you are holding a discount code" banner, rendered

kahunacart_currencies()function

The currencies a shopper can pick, for the switcher or a theme's own menu

kahunacart_currency_link(url)function

Keeps an explicit ?currency= choice on an existing site-navigation URL

kahunacart_currency_notice()function

What to tell a shopper whose cart is in one currency and who followed a link to another

kahunacart_current_currency()function

The currency this request is in, and the store's base currency, for the "Not available in EUR" partial or a theme's own line

kahunacart_custom_fields(entity, entityId)function

The custom field values on one row — a product, a variant, an order, an order line, a customer, an address — as a CustomFieldValues object

kahunacart_customer()function

The customer record the current visitor is, as an array, or null

kahunacart_date(at = null, form = StoreDate::LONG)function

A date the way the store's language writes one, in the store's timezone: "November 19, 2026" on a US English store, "19 November 2026" on a British one, "19

kahunacart_default_country()function

The country code checkout.default_country names, for preselecting an address form

kahunacart_downloads(limit = 0)function

The signed-in customer's downloads, newest first, for a theme's own library

kahunacart_express_buttons(zone = ExpressButtonRegistry::ZONE_CART)function

The express-pay region for the cart page ('cart.express', the default) or the checkout page ('checkout.express'): the wallet buttons every eligible provider registered on onKahunaCartRegisterExpressButtons, each drawn to the merchant's express.* style so they sit in one row at one height

kahunacart_image(image, width = 600, height = null)function

One image at a size of your choosing, as {url, alt, width, height}

kahunacart_kit_items(product = null)function

What a grouped product or a kit contains

kahunacart_lightbox()function

The lightbox's <dialog>, the first time a page asks for it, and nothing after that, so every template that draws an opener can call it

kahunacart_line_fixed_qty(item = null)function

Whether a cart line's quantity is the add-on's rather than the customer's

kahunacart_login_url()function

The Login plugin's own sign-in route, and its logout task on the current page with the nonce that task expects — built exactly the way its own login-status partial builds it

kahunacart_logout_url()function

The Login plugin's own sign-in route, and its logout task on the current page with the nonce that task expects — built exactly the way its own login-status partial builds it

kahunacart_notices(notices, filters = [])function

Narrows a list of order notices to the ones a template is about to draw

kahunacart_order_fields(order)function

What the customer answered on one order's checkout fields, in the order the form asked them

kahunacart_order_reference(order)function

What an order is called: the reference the order_reference object template stamped on it at completion, or #<number> for an order placed before references existed

kahunacart_order_status_axes(order)function

Which of an order's statuses the customer is shown, as a list of axis names in the order the account draws them

kahunacart_pay_what_you_want(product = null, variants = null)function

What a shopper may pay for a pay-what-you-want product, ready for the price box, or null for a product sold at its price

kahunacart_paywall(page)function

What this visitor gets of a page, for a theme or a listing template that wants to decide for itself

kahunacart_preorder(product = null)function

Whether a product is a pre-order, and how to say when it comes out

kahunacart_price(minor, currency = null, with = null)function

Formats minor units as money, localized to the active language, in the currency you pass or else the visitor's

kahunacart_price_set(vars = [], units = null)function

Every amount a cart or order summary prints, as one list for the with of kahunacart_price(), so the summary is printed alike: if any amount in it has cents all of them keep them, and if every one is whole none show cents

kahunacart_product(slug)function

One published product, or null

kahunacart_product_images(product)function

Every picture on a product, in gallery order — gallery images and nothing else, which is what this function has always returned and what a theme drawing an <img> with it wants

kahunacart_product_labels(product)function

A product's labels as the storefront draws them, in order: its EU energy labels and its label images

kahunacart_product_media(product, role = null, kind = null)function

Everything attached to a product, gallery first and then the samples

kahunacart_product_safety(product)function

The Product safety block for a product, as the product route hands it to partials/kahunacart-product-safety.html.twig: {manufacturer, responsible_person, safety_info}, or null when the product has no manufacturer (its own or the store default) and no safety information

kahunacart_product_type(product = null)function

—

kahunacart_products(limit = 50, offset = 0)function

Published products in the store's listing order

kahunacart_quantity_limits(product = null, variant = null)function

How many of one thing this shopper may put in the box, ready for the box: {min, max, step, sold_individually, hint}

kahunacart_quick_add(product = null)function

The variant a product card's Add button can post, or null when the card should link to the product instead

kahunacart_related(product, kind = RelationKind::RELATED)function

One product's curated block, for a theme rendering it somewhere the shipped partials do not

kahunacart_releases(product = null, limit = ReleaseFeed::DEFAULT_LIMIT)function

A product's releases, newest first, or the latest across the store: a changelog, a "what's new" strip or a ticker of what shipped lately

kahunacart_sale(variant, product = null)function

The sale covering one variant, or null at the ordinary price

kahunacart_search_url(query = null)function

The search route, {base}/search

kahunacart_sections()function

The store's sectioned listing, resolved: the blocks catalog.sections declares, each already holding its products, for a theme that wants to draw them its own way rather than through the shipped partials

kahunacart_set_price(product = null)function

What a grouped product or a kit costs, in the visitor's currency

kahunacart_sign_in_url(returnTo = null)function

A sign-in link that brings the shopper back to a storefront page afterwards: this page when no page is named, or the one you name as a path under the shop ('/product/' ~ product.slug, '/cart') or as a whole kahunacart_url()

kahunacart_status_label(status, axis = StatusAxis::STATUS)function

What a customer is told a status is

kahunacart_stock(product = null, variant = null)function

A product's stock, as a card, a stock line or a buy button draws it: {tracked, qty, sold_out, backorder, low, preorder, in_stock, digital, reason, label}

kahunacart_store_status()function

Whether the store is open, and whether this visitor may buy: the one thing a theme asks instead of reading the configuration

kahunacart_subdivision(country, value)function

A stored region as the option value to preselect

kahunacart_subdivisions(country)function

One country's states or provinces, code => English name, for a <select>

kahunacart_subdivisions_json()function

Every subdivision list as JSON, once per response

kahunacart_tags()function

Every tag in the store, each with its label, its slug, how many published products wear it, and the listing URL that filters on it

kahunacart_tax_note(product = null, variant = null)function

The small line under a price that says whether it includes tax ("incl. VAT", "excl. VAT"), or empty when the store is not asked to say so or charges no tax

kahunacart_url(path = '', currency = null)function

A storefront URL, ready for an href or a form action

kahunacart_whole_amounts()function

Whether the store prints whole amounts without their cents (storefront.whole_amounts)

kahunacart_zone(zone, context = [])function

A storefront extension zone, rendered: every widget an add-on mounted there, in the merchant's order, inside one element naming the zone

A filter takes the value on its left as its first argument, so each filter card shows it there. text|kahunacart_markdown is a line you can paste:

TWIG
{{ product.description|kahunacart_markdown }}

kahunacart_price is registered twice, as a function and as a filter, so both of these work:

TWIG
{{ kahunacart_price(item.total_minor) }}
{{ item.total_minor|kahunacart_price }}

The kit items function

kahunacart_kit_items(product) lists the parts of a grouped product or a kit, in the order you set them, for a theme that draws its own buy form. Each row has id, child_product_id, child_title, child_slug, child_status, required_quantity, resolved_variant_id and shopper_picks.

A part the shopper picks also carries the variants to choose from:

Key What it holds
choices One entry per variant of the part: id, label, available, sold_out, backorder, note (the sold-out or backorder wording, or the "not sold in this currency" note) and price_minor in the visitor's currency, or null when the variant has no price there
choice_prices_differ True when the choices don't all cost the same

Draw a <select name="parts[<row id>]" required> with one <option value="<choice id>"> per choice and a first empty option, and disable the choices that aren't available. Leave out a part with fewer than two choices, because there is nothing to pick and the cart uses its one variant. partials/kahunacart-kit.html.twig does all of this, and shows the price beside each choice only when the set isn't sold as a set and choice_prices_differ is true. See Which variant a part sells.

The set price function

kahunacart_set_price(product) answers what a grouped product or a kit costs in the visitor's currency, for a theme that draws its own price line. It returns {parts_minor, price_minor, saving_minor, sells_as_set}, or null for any other product.

Key What it holds
parts_minor One set of the parts at their own prices, or null when a part has no price in the visitor's currency
price_minor The bundle price when the product is sold as a set, else null
saving_minor What the set saves, 0 when it saves nothing
sells_as_set Whether Sell as a set is on

A grouped product never shows its own price, so print price_minor with parts_minor struck through when saving_minor is above 0, and parts_minor alone when it isn't, both through kahunacart_price. Or include partials/kahunacart-set-price.html.twig, which does that and draws nothing when there is nothing to show. See Storefront for the partial's variables.

The newsletter signup function

The Newsletters add-on registers one function of its own, for drawing a signup form anywhere in a theme. See Subscribers, lists and tags for its arguments.

kahunacart_newsletter_form(list = null, options = [])function

The signup form for a list, as HTML a theme can print anywhere

The booking functions

The Bookings add-on's functions draw a booking picker, a customer's own booking page and a class list. See Developers.

kahunacart_booking(product = null, options = null)function

The booking picker for a product, by its slug, anywhere in a template. with pins it to one bookable

kahunacart_booking_manage()function

The page a customer's booking link opens, where they can see, move or cancel their own booking. The token is read from the address, never written into the page

kahunacart_bookings_board(options = null)function

Which products are free on which days, for a week-at-a-glance board

kahunacart_bookings_counts(options = null)function

Openings left today, resources free right now and a class's places

kahunacart_bookings_day(options = null)function

One day, lane by lane: each person and each tub with what is booked on it, what is free and what is shut

kahunacart_bookings_lengths(product = null)function

The lengths a product is sold in, each with its price and start times

kahunacart_bookings_next_free(product = null)function

The next day from tomorrow with something free, or null

kahunacart_bookings_services(options = null)function

The appointments a shopper can book, flat or grouped by category

kahunacart_bookings_sizes(product = null, options = null)function

The sizes of a product and how many of each are free on a day

kahunacart_bookings_staff(options = null)function

The people who do the work, each with a link that books them

kahunacart_sessions_data(days = 60, category = '')function

The same list as data

The availability function

The Rentals add-on's function answers a property's calendar. See Developers.

kahunacart_availability(product = null, options = null)function

A property's availability calendar, by its product slug. months is how many it draws, 1 to 12

kahunacart_rentals_house(product = null)function

The house rules and the next night to arrive on, or null on anything wrong

kahunacart_rentals_rates(product = null)function

The rate bands still to come, in date order

Rules that apply to all of them

Money is minor units. Every *_minor field is an integer in the store's smallest unit. Pass it to kahunacart_price rather than dividing it yourself. See Money conventions.

URLs honour the base route. kahunacart_url, kahunacart_account_url, kahunacart_search_url and the rest build on the configured storefront base and the active language prefix. Do not hardcode /shop/cart; it breaks on a store that changed the base.

A failure is contained. If one of these throws, the call returns an empty value and logs instead of breaking the page.

Nothing here is cached. A listing call runs a query each time. Assign it to a variable when you need it twice in one template.