Install the free PDF Invoice for WooCommerce plugin, choose the order statuses and emails in its settings, and each chosen order email carries a PDF invoice. Packing slips are download only.
Contents10 sections
To attach a PDF invoice to WooCommerce order emails, install the free PDF Invoice for WooCommerce plugin, enter your company details and choose the order statuses and emails under WooCommerce → Settings → PDF Invoice. It builds each invoice on your own server and attaches it to the order emails you select. One thing to change first: with the defaults, only Processing is a Mark as Paid status, so the copy on the Completed order email shows no PAID badge and the full amount due until you add Completed to Mark as Paid. Packing slips are downloads for your staff, not email attachments.
What the plugin does, and what it does not
An invoice is made when an order reaches a status you choose, and made again whenever it is attached to an email or downloaded, so it always shows the order as it is now. Read these limits before you start:
- It does not record payments. “Paid” and “Amount Due” follow the order status you pick, and refunds do not change the amount due.
- There is one design, Template 1 on A4 paper, though you can override its markup in your theme.
- Invoice numbers carry no prefix such as INV-. A filter can add one (see Invoice numbers).
- The invoice prints the billing address only. The shipping address is on the packing slip.
- It keeps no archive. PDFs are a cache, deleted after 7 days and made again when needed.
- It has no estimates, reminders, recurring invoices, shortcodes or WP-CLI commands. According to its documentation, Advance Invoices for WordPress & WooCommerce is the separate paid plugin for invoices that customers pay online with Stripe or PayPal.
What you need
- WordPress 6.5 or later and PHP 7.4 or later.
- WooCommerce 10.0 or later, active. WordPress will not activate the plugin without it, and if WooCommerce is deactivated later the plugin does nothing and shows no message.
- The PHP extensions
dom,mbstringandiconvfor the bundled PDF library (Dompdf), andgdif your logo is a PNG. The plugin does not check for them, so a missing one appears as a PHP error. - An uploads folder that PHP can write to, because PDFs are saved in
wp-content/uploads/wphub-invoice, and a working mail setup.
Step-by-step setup
- Make sure WooCommerce is active, then open Plugins → Add Plugin, search for “PDF Invoice for Woocommerce”, and click Install Now and Activate.
- Open WooCommerce → Settings → PDF Invoice. The Settings link on the Plugins screen goes to the same place.
- Fill in Company Name, Company Address, Company Email and Company Phone.
- Upload your logo under Media → Library, copy its file URL and paste it into Company Logo. PNG, JPG and SVG work.
- Under Generate Invoice, choose the statuses at which an invoice is made when an order moves to them. The default is Processing. Email attachments are made whatever this list says.
- Under Mark as Paid, choose the statuses at which the invoice shows a green PAID badge and an amount due of zero. The default is Processing, so add Completed here. This also keeps the customer’s Download Invoice button after completion.
- Under Attach to Emails, choose the emails that carry the invoice. The defaults are New order, Processing order, Order details and Completed order.
- Decide on numbering before you issue invoices you want to count: tick Sequential Invoice Numbers and set Starting Invoice Number (default 1000, use 1 or higher), or leave it off to use the WooCommerce order ID.
- Optional: tick VAT Number Field, edit Footer Note and Copyright Text, or untick Packing Slip Button to hide the packing slip icon in the Orders list.
- Click Save changes, then Preview Template next to the Invoice Template list. A sample invoice opens in a new tab. It uses the saved settings, so save first.
- Test it: place a test order, or move an existing one to a status you selected. With sequential numbers on, it uses up a number. Check that the email carries the PDF, then open WooCommerce → Orders and click the Invoice icon on that order.
When the invoice is made and which emails get it
- Status change: when an order moves to a Generate Invoice or Mark as Paid status, the plugin makes the PDF.
- Email attachment: when WooCommerce prepares a selected email, the invoice is made again for the order’s current state and attached, so an email never carries an old PAID or amount due.
- Download: every download makes it again.
All of this happens inside the request that triggers it, with no background queue. The plugin attaches only to emails WooCommerce actually sends, so a selected email must also be enabled under WooCommerce → Settings → Emails. Some details are easy to miss:
- Only emails that belong to an order get the invoice. Account emails such as a password reset never do, even if you select them.
- Selecting an email does not check the order’s status. An invoice is attached to a Cancelled order or Failed order email in whatever state the order is in, and with sequential numbers on it uses up a number.
- Refunded order covers full refunds only. For a partial refund WooCommerce sends its email under another ID,
customer_partially_refunded_order, which the plugin does not match. - If the PDF cannot be written, the email goes out without it and nothing is reported.
- Orders placed before you installed the plugin get their PDF the first time an email is sent for them or the invoice is downloaded.
Invoice numbers
With Sequential Invoice Numbers off, the invoice number is the WooCommerce order ID. With it on, each order gets one number the first time an invoice is made for it, stored on the order and never changed. The first invoice gets exactly the Starting Invoice Number and each new one the next number. Raising the starting number later takes effect with the next invoice, and lowering it never re-uses a number.
Switch sequential numbers on before you send invoices you want to count. An order you already invoiced under its order ID gets a new number the next time its invoice is made, and it differs from the one you sent. To print INV-1001 instead of 1001, add this to a small custom plugin or your child theme’s functions.php:
add_filter( 'wphub_invoice_number', function ( $number, $order_id, $settings ) {
return 'INV-' . $number;
}, 10, 3 );The filter changes the number that is printed and used in file names, not the number stored on the order.
What the invoice and packing slip show
- Header and Bill to: your logo, company name, address, phone and email, then the customer’s name, company, billing address, phone, email and VAT number.
- Details: Invoice No, Order Number, Invoice Date (the date the order was created, as d/m/Y), the PAID badge when it applies, and Amount Due.
- Items: #, Item, Qty, Unit Price and Total. Each line shows the name, the SKU if any, and item details such as variation attributes and add-ons. Unit Price is the line subtotal divided by the quantity, before discounts. Fees appear in the totals, not in this table.
- Totals and footer: the rows WooCommerce gives for the order’s totals, Amount Due, your Footer Note, your Copyright Text and Page X of Y.
To change the layout, copy templates/template-1.php or templates/packing-slip.php from the plugin into yourtheme/invoice-for-wc/ and edit the copy. For US Letter paper, use the wphub_invoice_paper_size filter.
The packing slip
A packing slip has no prices. It shows your company details, Bill To, Ship To (only when the order has a shipping address), the order number and date, a table of Item and Qty with SKUs and item details, the shipping method (only when the order has one), the payment method and your Copyright Text. The Footer Note is not printed on it. It is made fresh at each download and never saved.
VAT number
With VAT Number Field ticked, checkout gets an optional VAT Number field: in the billing section of the classic checkout, and in the Contact information step of the Checkout block. The value is printed as “VAT NO:” on the invoice and the packing slip.
Who can download a PDF
- Staff: in WooCommerce → Orders, an Invoice icon (Download Invoice) appears on every order whatever its status, and a Packing Slip icon (Download Packing Slip) appears unless Packing Slip Button is off. Both need permission to edit orders. The single order edit screen has no button.
- Customers: a Download Invoice button under the order table on the View order and Order received pages, and an Invoice action in My Account → Orders. Guests use the button on the order page they reach through their order link.
Customers see the button only when the order’s status is in Generate Invoice or Mark as Paid, or the order already has a sequential invoice number. The links contain a WordPress nonce, so a copied link stops working after the nonce lifetime (12 to 24 hours by default) and the customer opens the order page again.
Where the PDFs are stored
Invoices are saved in wp-content/uploads/wphub-invoice under file names that cannot be guessed, and downloads go only through permission-checked links. The folder gets an .htaccess file that denies direct access on Apache and LiteSpeed. nginx ignores .htaccess, so add a deny rule for that folder in your server configuration. A daily WP-Cron event deletes PDFs older than 7 days. Deleting the plugin removes the folder but keeps your settings, the invoice counter and the numbers on orders.
Good to know and troubleshooting
- No PAID badge and the full amount due: the order’s status is not under Mark as Paid. With the defaults that includes Completed. Refunds never reduce the amount due.
- Customers lose the Download Invoice button after completion: add Completed to Generate Invoice or Mark as Paid, turn on sequential numbers, or use the
wphub_invoice_customer_can_downloadfilter. - No PDF on the email: the email is not selected under Attach to Emails, it has no order, WooCommerce is not sending it, the uploads folder is not writable, or the PDF library failed. Check the PHP error log.
- “Invoice could not be generated.”: the PDF could not be written, the library failed, or your host’s file system API asks for FTP credentials.
- “Security check failed.” or “You are not allowed to do this.”: the link is older than its nonce or was copied into another browser session (open the order page again), or the visitor does not own the order, the order is not eligible, or a staff member lacks permission to edit orders.
- The logo does not appear: the field is empty, the address is wrong, or an external address did not answer with HTTP 200 within 15 seconds. Use a Media Library file.
- Numbers jumped: a number is taken whenever an invoice is first made, including a staff download from the Orders list or an email attached for a status such as Cancelled.
- Checkout feels slow: the PDF is made inside the request. A logo on another site is downloaded when it is not cached, and one over about half a megabyte is never cached, so use a small Media Library file.
The full documentation covers every setting, filter, placeholder and what is stored.
Links
Plugin page: PDF Invoice for WooCommerce. Settings reference: PDF Invoice for WooCommerce documentation. More tools: Browse all plugins.