Stock
Unlimited quantity by default
Unless you have disabled the management of Stocks using the bnomei.kart.stocks.enabled
configuration settings, the Kirby Kart plugin will create a content page to manage stocks. It also expects a subpage for each Stock-to-Product relationship.
The plugin assumes unlimited availability for each product without an explicitly defined stock amount and does not track stock changes.
Product Variants
You can also define stock for product variants. The stock for variants coexists with the product's main stock. If a variant has no stock definition, the plugin will fall back to the product's main stock when fulfilling an order. The product page has a method to retrieve the stock for each variant.
Cart and checkout
Your customers can add items in or out of stock to their carts.
Items that go out of stock while in their cart are not removed.
You can check if all items in the cart have stock available before starting the checkout flow with kart()->cart()->canCheckout()
like this...
<form method="POST" action="<?= kart()->urls()->cart_checkout() ?>">
<?php // TODO: You should add an invisible CAPTCHA here, like... ?>
<?php // snippet('kart/turnstile-form')?>
<input type="hidden" name="redirect" value="<?= $page?->url() ?>">
<button type="submit" onclick="this.disabled=true;this.form.submit();" <?= kart()->cart()->canCheckout() === false ? 'disabled' : '' ?>>Checkout</button>
</form>
Wishlist
Your customers can add items in or out of stock to their wishlists.
Items that go out of stock while on their wishlist are not removed.
Stock management in Panel
Within the Kirby CMS Panel, you can create new Stock-to-Product relationships (aka stock pages) and update the stock of existing ones. It will also show when each stock page was last updated. This timestamp might not perfectly correlate to the timestamp of an order since, by default, the Kirby Kart plugin uses a locking queue.
Orders will NOT put stock in hold by default
You can check for enough stock when starting the checkout flow, see above.
Since all successful orders eventually update the stock, even if there is insufficient stock, a successful order processed after that time might still cause the stock to drop below 0
. You can enable reserving stock with the bnomei.kart.stocks.hold = 10
config setting, with a number in minutes or false
. The Kirby Kart plugin will reserve/hold product quantities when the checkout process begins in 10 minutes
or until the order is cancelled/completed. The hold is only enabled for registered and logged-in users.
The hold is not a perfect solution; it just prevents the worst-case scenarios and enables "flash sales" on a first-come, first-served basis.
DANGER: Unless you enforce a maximum quantity per product in the cart, someone could hold all your stock hostage! Kart defaults tobnomei.kart.orders.order.maxapo = 10
, and you can set a value per product. Most providers have an additional limit for the number of line items in an order, which is reflected in the Kirby Kart plugin withbnomei.kart.orders.order.maxlpo = 10
.
Updating stock with Locking Queue
Kirby is a flat-file CMS. Within each HTTP request, the required content files are read, and in the case of the stock pages, possibly updated as a result of completing an order. This imposes a challenge when handling concurrent HTTP requests.
Concurrent requests occur when a later request starts while another request has not yet finished. This is usually a very, very short amount of time, but depending on the amount of traffic your website is experiencing and how performant it is in general, it could be anything between a few milliseconds and multiple seconds.
In the case of Kirby, this will not lead to race conditions or processes waiting on each other, but simply to the later-processed request overwriting the result of the earlier one.
Let's see this in action:
- Product A has a stock amount of
7
.Customer #1 adds2x
Product A to the cart, starts the checkout and fills out their credentials. - Customer #2 clicks a "Buy Now" button for
1x
Product A and is sent to the provider checkout and fills out their credentials. - Both Customer #1 and #2 complete the payment at roughly the same time. The provider sends two HTTP requests which both are processed by the Kart plugin and they want to change the stock of Product A.
- Request #1 reads the stock amount for Product A as
7
and wants to write7-2
. - Request #2 reads the stock amount for Product A as
7
and wants to write7-1
. - Let's assume #1 finishes before #2 it will write
5
but that will get overwritten soon after with the result of #2's6
. Or the other way round with #2 first6
and #1 later resulting in a stock of5
.
As you can see, neither result is correct; it should have been 7-2-1=4
. The only solution for handling truly concurrent requests is to put the changes in a locking queue and process them independently of the original requests while strictly enforcing that each job in the queue can only be read and processed synchronously.
The implementation of the Kirby Kart plugin ensures the stocks get updated correctly even under a very high server load.
ATTENTION: The locking queue tracks stock in high-traffic HTTP request scenarios, not between order initiation and completion.
Performance
The Kirby Kart plugin caches the stock of all products and their variants for quick retrieval. This cache gets flushed when any stock gets updated.
Screenshots

