Products

Sync from provider

The central concept of the Kirby Kart plugin is that you can manage your products and their prices in the cloud using your payment provider, such as PayPal or Stripe. This approach offers significant advantages, as all subsequent events related to orders and customers are linked to these products and prices. This connection enables improved statistics and features like tax reports.

Once you enter your API credentials in the configuration settings, your products and prices will be retrieved from the cloud, and product pages will be created in the Kirby CMS content folder. You can manually trigger a sync from within the Panel.

The sync will be repeated automatically every n minutes based on the bnomei.kart.expire config setting, which defaults to 0. By default, the synchronisation must be triggered manually, which seems reasonable since changes only need to be made when updates are applied at the providers as well.
Therefore, if you change products or prices at the provider, you will need to log into the Kirby Panel and manually trigger the sync.
Ideally, you should confirm that your intended changes have been applied after doing this.

Each product has a hashed version of your provider's product ID as its page UUID prefixed with pr-. This behaviour can be adjusted with the bnomei.kart.products.product.uuid config setting. But you must use the product ID, or the sync will not work.

Adding images and downloads

After creating the product content pages, you can add additional elements such as images, downloadable files, or any necessary custom fields (see extending the blueprint below).

Panel

Available data

The following Kirby CMS fields are present on a product page:

  • $product->categories()
  • $product->created()
  • $product->description()
  • $product->details()
  • $product->downloads()
  • $product->featured()
  • $product->gallery()
  • $product->maxapo()
  • $product->price()
  • $product->raw()
  • $product->rrprice()
  • $product->tags()

As well as the following page methods:

  • $product->add()
  • $product->addToCart()
  • $product->addToWishlist()
  • $product->buy()
  • $product->buyNow
  • $product->firstGalleryImage()
  • $product->firstGalleryImageUrl()
  • $product->forget()
  • $product->formattedPrice()
  • $product->hasVariant($variant)
  • $product->inStock()
  • $product->later()
  • $product->maxAmountPerOrder()
  • $product->moveFromCartToWishlist()
  • $product->moveFromWishlistToCart()
  • $product->now()
  • $product->ownedByUser($user)
  • $product->priceWithVariant($variant)
  • $product->remove()
  • $product->removeFromCart()
  • $product->removeFromWishlist()
  • $product->rrpp()
  • $product->salesCount()
  • $product->setAmountInCart()
  • $product->stock($withHold, $variant)
  • $product->stockUrl()
  • $product->updateStock($quantity, $set)
  • $product->variantData($resolveImages)
  • $product->variantGroups()
  • $product->wish()

Related field methods:

  • $field->toCategories()
  • $field->toFormattedCurrency()
  • $field->toFormattedNumber()
  • $field->toTags()

Related pages collection methods:

  • $collection->interval($field, $from, $until)
  • $collection->sum($field)
  • $collection->sumField($field)
  • $collection->trend($field, $compare)
  • $collection->trendPercent($field, $compare)
  • $collection->trendTheme($field, $compare)

Extending the blueprint

Create a site/blueprints/tabs/products.yml, and any columns/sections/fields you add there will be shown on the second tab of the product's blueprint. This allows me to push improvements to the blueprints without disrupting your custom setup.

The alternative would be to copy all the YAML files from the plugin into your project's site/blueprints/pages and site/blueprints/users-folders. While this option allows full adjustment of the panel views, you will miss out on my updates.

Tax

The Kirby Kart plugin does not provide a preview of tax calculations because it does not have access to your customers' locations or shipping and billing addresses. However, once your customer proceeds to checkout and reaches the payment processing stage with your provider, they can enter this information and see the correct tax rate applied, or you roll out a custom solution.

JSON-LD

Putting a <script> element with JSON formatted in a specific schema allows search engines to understand the current content page better. The Kirby Kart plugin has a built-in snippet to output such data for product pages.

<?php snippet('kart/product-json-ld') ?>

Most SEO plugins for Kirby output similar snippets for breadcrumbs and content summaries.

Product Variants

You can create product variations in the setting tags. Each combination consists of a tag with GROUP:OPTION, separated by a space; You can use uppercase letters, whitespaces and skip possible combinations if you want. Like for a T-Shirt:

  • color:Red, size:S
  • color:Red, size:M
  • color:Red, size:L
  • color:Sky Blue, size:S
  • color:Sky Blue, size:M
  • color:Sky Blue, size:L (SKIP)

By default, each product variant uses its parent product's price and recommended retail price (RRP). You can enforce a custom price per product variant and link one or more images.

The product model has a few methods related to product variants that will allow you to fetch the variants grouped, ready to build HTML <select> elements and to retrieve the data of a specific product variant.

<form method="POST" action="<?= $product->add() ?>">
    <?php foreach($product->variantGroups() as $name => $options) { ?>
        <label>
            <?= t($name, $name) ?>
            <select name="<?= $name ?>">
                <?php foreach($options as $option) { ?>
                    <option name="<?= $option ?>" <?= get($name) === $option ? 'selected' : '' ?>><?= t($option, $option) ?></option>
                <?php } ?>
            </select>
        </label>
    <?php } ?>
    <input type="hidden" name="redirect" value="<?= $redirect ?? $page->url() ?>">
    <button type="submit" onclick="this.disabled=true;this.form.submit();">Add to cart</button>
</form>

You must forward the variant as a comma-separated string or individual fields whenever acting upon that variant, like when adding or removing it from the cart or wishlist.

<?php foreach (kart()->wishlist()->lines() as $line) {
    /** @var \Bnomei\Kart\CartLine $line */
    /** @var ProductPage $product */
    $product = $line->product(); ?>
    <div>
        <form method="POST" onclick="this.disabled=true;this.form.submit();" action="<?= $product->now() ?>">
            <input type="hidden" name="variant" value="<?= $line->variant() ?>">
            <button type="submit">⊼</button>
        </form>
        <form method="POST" action="<?= $product->forget() ?>">
            <input type="hidden" name="size" value="M">
            <input type="hidden" name="color" value="Red">
            <button type="submit" onclick="this.disabled=true;this.form.submit();">⊗</button>
        </form>
    </div>
<?php } ?>
Kirby Kart is not affiliated with the developers of Kirby CMS. We are merely standing on the shoulder of giants.
© 2025 Bruno Meilick All rights reserved.