Orders

Available Data

Fields:

  • $order->customer()
  • $order->invnumber()
  • $order->invoiceurl()
  • $order->items()
  • $order->notes()
  • $order->paidDate()
  • $order->paymentComplete()
  • $order->paymentMethod()

Page Methods:

  • $order->createZipWithFiles($files, $filename)
  • $order->discount()
  • $order->download()
  • $order->downloads()
  • $order->formattedDiscount()
  • $order->formattedSubtotal()
  • $order->formattedSum()
  • $order->formattedTax()
  • $order->formattedTotal()
  • $order->hasProduct($product, $variant)
  • $order->invoice()
  • $order->invoiceNumber()
  • $order->isPayed()
  • $order->itemsSum($fieldname)
  • $order->orderLines()
  • $order->productsCount($product)
  • $order->subtotal()
  • $order->sum()
  • $order->sumTax()
  • $order->sumtax()
  • $order->tax()
  • $order->total()
  • $order->urlWithSignature()

Invoice Number

The Kirby Kart plugin has an autoincrementing, left-padded with 0, five-character length invoice number, like 00123 or 07654. This behaviour is NOT configurable.

You can change the last used invoice number on the Orders page at any time. This is useful if you need to continue at a certain invoice number.

Each order also has a seven-letter non-ambiguous UUID prefixed with or-. This UUID will also be used as the title and slug of the order page. You can adjust this behaviour with the bnomei.kart.orders.order.uuid config setting.

Url with Signature

Each order includes a method called $order->urlWithSignature(), which generates a URL with a signature appended to it. This signature, along with a verification check at the beginning of the site/templates/order.php file, helps prevent unauthorised access to orders by obstructing attempts to "guess" the unique name of an order. Use that signed URL instead of the plain $order->url() whenever possible.

site/templates/order.php
<?php

kart()->validateSignatureOrGo();

// rest of the template...

Downloads

The Kirby Kart plugin simplifies things by including downloadable files with your orders. Add the files you wish to include to each product to get started. The Kart will automatically check all products in the order, retrieve the files marked for download, and compile them into a ZIP file.

If the order consists of a single product and that product has a ZIP file designated for download, the system will use that file directly. If multiple products are in the order, all downloadable files will be grouped into a new ZIP file.

Please note that the actual filename of the created ZIP file will not be shared publicly; it will be hidden behind a generic download URL. This setup also allows you to regenerate the ZIP file in the background or requires users to log in before accessing the download. You can share that generic URL in emails without worrying about updates to a ZIP breaking the link.

Download URLs are signed URLs as explained above, and the same check should be applied to the template.

If you need more manual control, you could use the Panel to upload/replace the ZIP file attached to an order at any point. You could even add a ZIP to an order that did not generate one from its purchased products.

You can try the downloads in the online demo.

site/templates/order.php
<?php if ($page->download()) { ?>
<a download href="<?= $page->download() ?>">Download Files</a>
<?php } ?>

In the templates/order.zip.php file, you can customise the download further by adding a counter (see hooks kart.order.download) or limiting the number of downloads per order.

Emails

The Kirby Kart plugin does not send any emails regarding orders. You can listen to the fulfilment hook and use core Kirby CMS features to send emails. The Kirby Kart documentation also has a guide on emails.

Licenses

Each line in an order will receive a unique license key. If you sell digital products, you can use that key combined with a maxapo = 1 on the product and the API provided by the Kirby Kart plugin to build your licensing logic.

The Kirby Kart plugin only gives you the license key, endpoint to trigger changes and hooks to listen for events. You'll need to add your logic for managing the state of each license using the three callbacks for activation/deactivation/validation as config options. Check the Bnomei\Kart\Licenses-class on which data is expected to be returned.

site/config/config.php
<?php

return [
    'bnomei.kart.licenses.activate' => function (string $check, ?string $found = null, ?OrderPage $order = null, ?User $user = null) {
        // TIP: check current state, manipulate if needed and return state
        return [
            'activated' => $wasItActivated,
        ];
    },
    'bnomei.kart.licenses.deactivate' => function (string $check, ?string $found = null, ?OrderPage $order = null, ?User $user = null) {
        return [
            'deactivated' => $wasItDeactivated,
        ];
    },
    'bnomei.kart.licenses.validate' => function (string $check, ?string $found = null, ?OrderPage $order = null, ?User $user = null) {
        return [
             'valid' => $isItValid,
        ];
    },
    // other options
];

Even if you do not plan to use licenses, you can utilise the license key as a unique identifier for each line in orders. This can be useful when referencing items in other parts of your business logic. You can use the following helper to get the order and customer for which the key was used. The lookup has a cache to stay performant even with many orders.

<?php

$order = kart()->licenses()->order($licenseKey);
$customer = kart()->licenses()->customer($licenseKey);

Fulfilment Hook

site/config/config.php
<?php

use Kirby\Cms\User;

return [
    'hooks' => [
        'kart.cart.completed' => function (?User $user = null, ?OrderPage $order = null): void {
            // do stuff here
        },
    ],
    // other options
];

Invoices

The Kirby Kart plugin does not generate or send invoices by itself. While you could implement such functionality using a custom fulfilment hook, I recommend utilising the invoices provided by your payment provider whenever possible.

If the provider sends a URL for an invoice along with the data from the completed checkout, that URL will be stored and accessible to you at $order->invoice().

Additionally, with some providers like Stripe, generating invoices may incur extra fees, and this feature is not enabled by default in Kirby Kart. Please consult your provider's API documentation for guidance on how to activate this feature. Within Kart the provider's config settings allow changes to the checkout session.

If you want to create your own logic, the Kirby Kart plugin has you covered. It includes prefab content representation templates/order.pdf.php and matching snippets/kart/order.pdf.php to generate PDFs from order pages using MPDF (not installed by default).

While attaching a PDF to an email is convenient for the customer is also not super easy to do. The prefab from Kirby Kart is intended to be used as a URL, like https://www.example.com/orders/or-1234567.pdf, which is the pattern used as fallback for $order->invoice() as well.

Invoice URLs are signed URLs as explained above, and the same check should be applied in the template.

You can try the invoices in the online demo.

site/templates/order.php
<a download href="<?= $page->invoice() ?>">Download Invoice</a>

Previous Orders

site/templates/order.php
<h2>Previous Orders</h2>
<?php
$user = kirby()->user();
if ($user && $user === $page->customer()->toUser()) { ?>
    <ol>
        <?php foreach ($user->orders()->not($page) as $order) { ?>
            <li><a href="<?= $order->urlWithSignature() ?>"><?= $order->paidDate()->toDate('Y-m-d H:i') ?> <?= $order->title() ?></a></li>
        <?php } ?>
    </ol>
<?php } else { ?>
    <p><mark>Please <a href="<?= url('kart/login') ?>">log in</a> to see previous orders.</mark></p>
<?php } ?>
<?php if ($user?->orders()->count() > 0) { ?>
    <a href="<?= $user->orders()->first()->urlWithSignature() ?>">
        Your most recent order
    </a>
<?php } ?>

Success page

If you do not want your customers to be redirected to the order page, you can set the bnomei.kart.successPage to the id (like order-thank-you) of a generic success page.

Creating orders programmatically

If you ever need to create orders with code the following should get you started.

$newOrder = page('orders')->createOrder($data, $user);

Screenshots

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.