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.
<?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.
<?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.
<?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
<?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.
<a download href="<?= $page->invoice() ?>">Download Invoice</a>
Previous Orders
<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

