For the past few months we have been working on a big update for WooCommerce PDF Invoices & Packing Slips. We have redesigned both the settings interface and the code powering the plugin, focussing on usability for both developers and end-users and making it more stable and future proof.

If you:
… love to try out the exciting new features before anyone else
… have a staging site/test environment

We’d love your input & feedback!

We have made the beta of the main plugin available for download on github, where you can download the latest version:
WooCommerce PDF Invoices & Packing Slips beta

If you have an active license for any of the paid PDF invoice extensions, you can download the accompanying updates for those from your account (scroll to the bottom of the page and click on “View Details and Downloads”).

Important note! This is still in beta and although we have extensively tested this in our own environment and with some early testers, this is a big update with many changes. There can always be conflicts with other plugins/themes/specific server configurations that we haven’t found in our own tests.
We recommend testing this on a staging site/test environment first and always keep a backup in in case something goes wrong and you need to revert.


Here’s what’s new/different:

Separate document settings

Document specific settings are now neatly organized on their own pages under the “Documents” settings tab:

WooCommerce PDF Invoices & Packing Slips Document Settings
WooCommerce PDF Invoices & Packing Slips Document Settings

WooCommerce PDF Invoice settings

Settings that are applied to all documents (such as the template, page size, shop address, shop name, footer text etc.) are now under the General settings tab.

The Order Document class

Before 2.0, PDF invoices were created from a central ‘export’ class that was filled with all the data and held all the methods for handling various parts of the invoice creation process. This was limiting flexibility and extendability of the plugin and also wasn’t a very clear structure for the plugin. Various parts of that old ‘export’ class are now divided over different classes that each have a clear purpose, which makes maintaining the code much easier. Each document (Invoice, Packing Slips) now has it’s own ‘Order Document’ class/object, which is instanced for each PDF for an order. This object then contains only data and methods relevant for that particular document, which makes room for more advanced filters and also extendability with new document types. Creating an invoice is now as simple as:

$invoice = wcpdf_get_invoice( $order );
$pdf = $invoice->get_pdf();

Developers will find this much easier to work with than previous versions and it’s also a lot more reliable this way.

More robust invoice numbering

One of the most important aspects of invoicing is to have a reliable invoice numbering system that is flexible at the same time. The previous system had proven to be quite reliable over the years, although sometimes issues with server side caching would come up. Sites with very heavy traffic or peak flurries of orders (multiple orders per second) sometimes ended up with duplicate invoice numbers (due to what developers call a race condition in the code). All of the above issues were mainly caused by how the invoice number was stored, which was in the ‘wp_options’ table from WordPress.
In 2.0 we have moved invoice numbers (and all other document number sequences for that matter) into separate, dedicated tables. This is much faster and very reliable, also with extremely high order volumes/peaks. Editing the ‘next invoice number’ is still done from the settings page, but has it’s own edit (and save) button:
Edit WooCommerce PDF Invoice number
The pdf invoice number is stored in the order with all the formatting data so that when the shop owner makes changes to this, existing orders will not unexpectedly change as well. This comes with a slight change to the meta keys in which the invoice number is stored in the order:
_wcpdf_formatted_invoice_number is now stored as _wcpdf_invoice_number
all data from the invoice number (raw number, prefix, suffix, padding) is stored as _wcpdf_invoice_number_data.

No more global variables

A lot of functions in previous versions were called via a global variable $wpo_wcpdf. This didn’t make sense with the new document object anymore, and the use of globals in PHP is generally not recommended so we decided to ditch the global. All document related functions are now inside the Order Document class. From within templates, these are available under $this, and from within filters/actions, they are available in the $document object.

Two examples to show this:

Template function in 1.6.5:


Template function in 2.0:


Action hook in 1.6.5:

add_action( 'wpo_wcpdf_after_order_data', 'wpo_wcpdf_delivery_date', 10, 2 );
function wpo_wcpdf_delivery_date ($template_type, $order) {
    global $wpo_wcpdf;
    <tr class="delivery-date">
        <th>Delivery Date:</th>
        <td><?php $wpo_wcpdf->custom_field('delivery_date'); ?></td>

Action hook in 2.0:

add_action( 'wpo_wcpdf_after_order_data', 'wpo_wcpdf_delivery_date', 10, 2 );
function wpo_wcpdf_delivery_date ($template_type, $order) {
    $document = wcpdf_get_document( $template_type, $order );
    <tr class="delivery-date">
        <th>Delivery Date:</th>
        <td><?php $document->custom_field('delivery_date'); ?></td>

Better PHP 7.0 & 7.1 compatibility

DOMPDF, the library that converts HTML from the templates to PDF has been updated to 0.8. This version solves some issues with PHP 7.0 and 7.1 and is also a lot more reliable than the version that was bundled with 1.6.5 (0.6).
We have also made the PDF library pluggable, which means that if you prefer to use another conversion library (they all have their strengths & weaknesses), you can do that without modifying plugin files.

We hope you enjoy these changes & improvements as much as we do!

If you find any issues, please report them on github – if you have any questions, don’t hesitate to contact us!


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.