Appearance
WooCommerce PDF Invoices in Laravel: keep numbers and settings
Invoices are the one part of a shop an accountant cares about. They have to be numbered without gaps, never twice, and an invoice sent last spring has to come out the same when the customer asks for it again. On a WooCommerce shop that is usually the job of PDF Invoices & Packing Slips by WP Overnight, and its data sits in the shop's database next to the orders.
Here is where the plugin keeps it:
- An order's invoice is in the order's meta:
_wcpdf_invoice_numberas printed (INV-2026-0042),_wcpdf_invoice_number_data(the number, its prefix, suffix and padding),_wcpdf_invoice_date, the settings it was made with in_wcpdf_invoice_settings, and what made it in_wcpdf_invoice_creation_trigger. - The numbering is a table of its own,
wcpdf_invoice_number, with last years' numbers inwcpdf_invoice_number_{year}when it starts again every January. - The settings are its options:
wpo_wcpdf_settings_generalfor the shop's details and the paper,wpo_wcpdf_documents_settings_invoiceand…_packing-slipfor each document.
A usual Laravel rebuild of a shop starts invoices from 1, or prints them from a template that has never seen the old ones. The accountant then has two numberings, and an old invoice comes out with today's address on it.
How kitloom reads it
kitloom runs on the WordPress database as it is, and its shop keeps WooCommerce's orders in WooCommerce's tables. kitloom/invoices reads the plugin's data where the plugin left it:
- Old invoices stay as they were. An order that had invoice
INV-2025-0317still has it, with its date, and is drawn with the shop details it was made with — the old address on the old invoice. - The numbering goes on. The next invoice takes the next number of the plugin's counter, under a lock: two orders paid at the same moment never get the same one. Prefix, suffix, padding and the yearly reset are read from the plugin's settings, placeholders included (
[invoice_year],[order_number],[invoice_date="ymd"]). - An invoice is made once, for good, as the plugin does it: when an email you chose goes out with the PDF, when the order reaches a status you chose, when you or the customer open it, or when you set its number by hand. A cancelled order keeps its number.
- The packing slip is there too: the shipping address and the lines with SKU and weight, no prices.
The documents speak the language the customer ordered in, as the shop's emails to them do.
What the admin shows
Invoice, Packing slip and Invoice number are on every order's row and page, in Filament and in Nova. Invoices → Settings holds what the plugin's settings held: the shop's details and logo, the emails that carry the invoice, the numbering, when the customer's account offers the invoice, the paper and whether the PDF opens or downloads. A new shop has no email ticked: nothing is numbered until you say how.
Whoever may edit the shop's orders opens both documents of any order. A customer opens their own order's invoice from their account, signed in, and nothing else: another order's address answers "not found".
What changes and what is not covered
- The move is one way. The plugin's options are read as WordPress left them and written as JSON from then on; the plugin on WordPress would not read them back.
- Two documents. The invoice and the packing slip, the plugin's free ones. Documents of its paid extensions — proforma invoices, credit notes — are not read.
- The look is kitloom's. The plugin's PHP templates do not run; the PDF is drawn by the module's Blade views, which you can publish and change. dompdf draws it in PHP, so nothing to install on the server, but it draws CSS 2.1 (tables, no flexbox) and does not join Arabic or Hebrew letters.
- PDFs are not stored. Each is drawn when it is opened or sent, from the order and its number.
The complete list of what is read is in the Invoices guide.
Ask an AI agent for an invoice
A customer writes "can you send me the invoice for my last order?". With kitloom/ai installed, an agent connected to the site finds the order and its invoice (invoices_get) — the number as printed, the date, and links to the PDFs that open without signing in for half an hour — and makes one when the order has none yet (invoices_create). You ask:
- "Send me the invoice links for order 1042."
- "Which of today's orders have no invoice yet?"
- "Make the invoice for order 1051 — the customer needs it for their company."
The agent acts as the user whose key it holds and needs that user's right to manage orders. It takes a number only when asked, since a number is taken for good, and it never changes an invoice already made. With kitloom/webhooks, the topic invoice.created hands every new invoice to a bookkeeping app. How to connect an agent: Run your site from Claude or Cursor.
Watch it
Two short lessons from the admin, narrated:
Check it on your own shop
Point kitloom at a read-only copy of the live database and open a few old orders: their invoices should come out with the numbers and dates the customers received. Making a new invoice writes the counter, so try that on a copy you load yourself — the steps are in Migrate from WordPress.
Try it
Open a sandbox in one click, with no sign-up: Filament or Nova. Invoices are one plugin among several; the same approach covers WooCommerce itself, Contact Form 7 and Rank Math.