PDF template action hooks

The template engine for PDF Invoices & Packing Slips is built for flexibility, and includes several action hooks where you can output custom content:

HookPositionArguments
wpo_wcpdf_before_documentBefore all content on the document$document_type, $order
wpo_wcpdf_after_documentAfter all content on the document (after the footer) $document_type, $order
wpo_wcpdf_after_document_labelAfter the document label (Invoice, Packing Slip etc.) $document_type, $order
wpo_wcpdf_before_billing_addressBefore the billing address $document_type, $order
wpo_wcpdf_after_billing_addressAfter the billing address $document_type, $order
wpo_wcpdf_before_shipping_addressBefore the shipping address $document_type, $order
wpo_wcpdf_after_shipping_addressAfter the shipping address $document_type, $order
wpo_wcpdf_before_order_dataBefore the order data (invoice number, order date, etc.)
note that this is inside a table, and you should output the data as an html table row/cells
$document_type, $order
wpo_wcpdf_after_order_dataAfter the order data
note that this is inside a table, and you should output the data as an html table row/cells
$document_type, $order
wpo_wcpdf_before_order_detailsBefore the order details table with all items $document_type, $order
wpo_wcpdf_after_order_detailsAfter the order details table $document_type, $order
wpo_wcpdf_before_item_metaBefore the item meta (for each item in the order details table)$document_type, $item, $order
wpo_wcpdf_after_item_metaAfter the item meta (for each item in the order details table)$document_type, $item, $order
wpo_wcpdf_before_customer_notesBefore the customer/shipping notes (left of the order totals) $document_type, $order
wpo_wcpdf_after_customer_notesAfter the customer/shipping notes (left of the order totals) $document_type, $order

Using the template action hooks #

If you have never used WordPress action hooks before, this may sound like abracadabra. Luckily it’s not that difficult, although some basic PHP knowledge does help a lot if you’re doing this.

There are two places where you can put the code from the examples below. You can either insert the code into your theme functions / functions.php (read this if you have never edited that file before!) or if you have already created a custom PDF template, you can put it in the template-functions.php file inside your custom template folder.

Example 1: Print a delivery date on the packing slip #

This will print a custom field (for example, delivery_date) below the regular order data on the packing slip. If you don’t know the name of your custom field, follow this guide: Finding WooCommerce Custom Fields

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

Some plugins save the delivery date as a UNIX timestamp, which is a big number, like 1483228800. In this case, you will need to convert this to human readable format first.

add_action( 'wpo_wcpdf_after_order_data', 'wpo_wcpdf_delivery_date', 10, 2 );
function wpo_wcpdf_delivery_date ($document_type, $order) {
    if ($document_type == 'packing-slip') {
        // get the delivery date from the order
        $delivery_date = $order->get_meta('delivery_date');
        // convert the delivery date to a human readable format (using the WooCommerce/WordPress date format settings)
        $formatted_delivery_date = date_i18n( wc_date_format(), $delivery_date );
        ?>
        <tr class="delivery-date">
            <th>Delivery Date:</th>
            <td><?php echo $formatted_delivery_date; ?></td>
        </tr>
        <?php
    }
}

Example 2: Print a custom text after the order details table #

This will print a simple text below the order details table on all PDF documents.

add_action( 'wpo_wcpdf_after_order_details', 'wpo_wcpdf_custom_text', 10, 2 );
function wpo_wcpdf_custom_text ($document_type, $order) {
    ?>
    <div class="custom-text">
    If you have any questions about your order, don't hesitate to contact us!
    </div>
    <?php
}

Or restricted to the PDF invoice and BACS payment method:

add_action( 'wpo_wcpdf_after_order_details', 'wpo_wcpdf_custom_text', 10, 2 );
function wpo_wcpdf_custom_text ($document_type, $order) {
    $payment_method = $order->get_payment_method();
    if ($document_type == 'invoice' && $payment_method == 'bacs') {
        ?>
        <div class="custom-text">
        Thank you for your order. Please send the full amount to our bank account: 123-456-789.
        After we have received your payment, you will receive a notification and we will send you the goods.
        </div>
        <?php
    }
}

Or a text about intra-community supply, restricted to invoices (& proforma invoices & credit notes) without tax:

add_action( 'wpo_wcpdf_after_order_details', 'wpo_wcpdf_tax_exempt', 10, 2 );
function wpo_wcpdf_tax_exempt( $document_type, $order ) {
    // only in financial documents
    if ( !in_array( $document_type, array('invoice', 'proforma', 'credit-note') ) ) {
        return;
    }
     
    // get shop location
    $shop_base_location = wc_get_base_location();
     
    // get billing country
    if ( $order->get_type() == 'shop_order_refund' ) { // get data from parent order for refunds
        $order = wc_get_order( $order->get_parent_id() );
    }
    $billing_country = $order->get_billing_country();
 
    // check if any tax was charged and if billing country is outside of shop base country
    if ( $order->get_total_tax() == 0 && $order->get_total() > 0 && $billing_country != $shop_base_location['country'] ) {
        ?>
        <div class="tax-exempt">
        Tax free under intra-community supply.
        </div>
        <?php
    }
}

Example 3: Print a list of categories under each product name #

This example prints a comma separated list of categories for each product under the product name (after the item meta).

add_action( 'wpo_wcpdf_after_item_meta', 'wpo_wcpdf_show_product_categories', 10, 3 );
function wpo_wcpdf_show_product_categories ( $document_type, $item, $order ) {
    // get a comma separated list of categories (category links stripped)
    if (isset($item['product'])) {
        echo '<div class="product-categories">Categories: '.strip_tags( wc_get_product_category_list( $item['product']->get_id() ) ).'</div>';
    }
}

Example 4: Print a due date on the invoice #

Calculate a due date 14 days after the invoice date (see the + 14 days bit and strtotime() for reference)

add_action( 'wpo_wcpdf_after_order_data', 'wpo_wcpdf_due_date', 10, 2 );
function wpo_wcpdf_due_date ($document_type, $order) {
    if ($document_type == 'invoice') { // put due date only on invoice
        $invoice = wcpdf_get_invoice( $order );
        if ( $invoice_date = $invoice->get_date() ) {
            $due_date = date_i18n( get_option( 'date_format' ), strtotime( $invoice_date->date_i18n('Y-m-d H:i:s') . ' + 14 days') );
            ?>
            <tr class="due-date">
                <th>Due Date:</th>
                <td><?php echo $due_date; ?></td>
            </tr>
            <?php
        }
    }
}

Example 5: Printing payment instructions on the Proforma Invoice #

You may want to add some custom styles to make this look a bit better.

add_action( 'wpo_wcpdf_after_order_details', 'wpo_wcpdf_payment_instructions', 10, 2 );
function wpo_wcpdf_payment_instructions ($document_type, $order) {
    if ($document_type == 'proforma') { // change 'proforma' to 'invoice' if you want to put this on the invoice
        WC()->payment_gateways();
        $order_id = $order->get_id();
        $payment_method = $order->get_payment_method();
        do_action( 'woocommerce_thankyou_' . $payment_method, $order_id );
    }
}