WooCommerce Delivery Notes Developer Customization Guide (Template Overrides, Hooks & Filters)
1. Overriding Template Files
↑ Back to topTemplate overrides allow you to customize the document structure and design without modifying the plugin files directly.
Supported documents:
- Invoice
- Receipt
- Delivery Note
- Packing Slip
- Credit Note
Step 1: Open Your Active Theme Folder
↑ Back to topNavigate to:
wp-content/themes/your-theme/
Step 2: Create the Override Folder
↑ Back to topCreate a new folder:
woocommerce-delivery-notes
Final structure:
wp-content/themes/your-theme/woocommerce-delivery-notes/
Step 3: Locate Plugin Templates
↑ Back to topFind the template files inside:
wp-content/plugins/woocommerce-delivery-notes/templates/
Step 4: Copy the Template File
↑ Back to topCopy the template you want to customize into your theme override folder.
Example:
From:
wp-content/plugins/woocommerce-delivery-notes/templates/invoice.php
To:
wp-content/themes/your-theme/woocommerce-delivery-notes/invoice.php
For your reference, here is a screenshot:
Step 5: Edit the Copied Template
↑ Back to topModify the copied template file inside your theme.
The plugin will automatically load your custom template instead of the default plugin template.
Available Template Files
↑ Back to top| Template File | Description |
| invoice.php | Invoice document |
| receipt.php | Receipt document |
| deliverynote.php | Delivery note document |
| packingslip.php | Packing slip document |
| creditnote.php | Credit note document |
| base.php | Shared base layout used by all documents |
2. Hooks: Action and Filter Reference
The Print Invoice & Delivery Notes for WooCommerce plugin includes a wide range of WordPress hooks and filters that allow developers to customize invoice layouts, delivery notes, receipts, packing slips, PDF documents, email print views, and order data without modifying the core plugin files.
Using these WooCommerce invoice hooks and filters, you can:
- Add custom content to invoices and packing slips
- Modify billing and shipping information
- Customize PDF invoice layouts
- Add product images, QR codes, notes, and branding
- Change order item data and totals
- Customize print buttons and email print links
- Extend WooCommerce print invoice functionality safely
All hooks use the wcdn_ prefix and can be added to your custom plugin or the functions.php file of your active theme.
This document provides step-by-step examples for customizing WooCommerce invoice templates, delivery notes, receipts, and PDF documents using plugin actions and filters.
Before You Begin
You can add custom hook and filter code using:
- Your active theme’s functions.php
- A child theme
- A custom plugin
- The Code Snippets plugin
We recommend using a child theme or custom plugin instead of editing plugin files directly.
2.1. Document Layout Actions
↑ Back to topDocument Layout Actions allow developers to inject custom HTML into specific sections of WooCommerce invoices, packing slips, delivery notes, receipts, and credit notes without editing template files.
These hooks fire inside the shared base.php template during document rendering.
Callback Structure
Most document layout hooks use the following callback structure:
function my_callback( array $order, string $template ) { }
Parameters
| Parameter | Description |
| $order | Formatted WooCommerce order data including products, addresses, totals, payment details, and customer notes |
| $template | Current document type (invoice, receipt, deliverynote, packingslip, or creditnote) |
Available Template Types
↑ Back to top| Template Key | Document |
| invoice | Invoice |
| receipt | Receipt |
| deliverynote | Delivery Note |
| packingslip | Packing Slip |
| creditnote | Credit Note |
wcdn_before_document
↑ Back to topFires at the very start of the document inside .wcdn-document before any visible content is rendered.
Example Code
add_action( 'wcdn_before_document', function( $order, $template ) {
if ( 'invoice' === $template ) {
echo '<p style="color:red;font-weight:bold;">DRAFT</p>';
}
}, 10, 2 );
Expected Result
A “DRAFT” label appears at the top of the invoice before the document content begins.
wcdn_before_logo / wcdn_after_logo
↑ Back to topThese hooks fire before and after the shop logo block.
Both hooks run regardless of whether the logo is enabled in plugin settings.
Example Code
// Add a banner image above the logo.
add_action( 'wcdn_before_logo', function( $order, $template ) {
echo '<img src="' . esc_url( get_site_url() . '/banner.png' ) . '" style="width:100%;" />';
}, 10, 2 );
Note: Upload the banner image to your site’s root directory (e.g., https://example.com/banner.png) or update the image URL to match the location of your banner image in the Media Library.
Expected Output:
A full-width banner image is displayed above the shop logo on the printed document.
Example Code
// Add a tagline below the logo.
add_action( 'wcdn_after_logo', function( $order, $template ) {
echo '<p style="text-align:center;font-style:italic;">Your Trusted Partner</p>';
}, 10, 2 );
Expected Result
The text “Your Trusted Partner” is displayed below the shop logo in italic style and centered alignment.
wcdn_before_title / wcdn_after_title
↑ Back to topThese hooks fire before and after the document title heading (<h1>).
Example Code
// Show a "COPY" label on duplicate invoices.
add_action( 'wcdn_before_title', function( $order, $template ) {
if ( 'invoice' === $template && get_post_meta( $order['id'], '_is_copy', true ) ) {
echo '<p style="text-align:center;">[COPY]</p>';
}
}, 10, 2 );
Note
This snippet displays the [COPY] label only when:
- The current document type is an invoice.
- The order contains a custom meta field named _is_copy with a value that evaluates to true (for example, 1).
Expected Output
The text [COPY] is displayed above the invoice title for orders marked with the _is_copy meta field.
Example Code
// Add a subtitle under the title.
add_action( 'wcdn_after_title', function( $order, $template ) {
echo '<p style="text-align:center;font-size:0.85em;color:#888;">Tax Invoice</p>';
}, 10, 2 );
Expected Result
The text “Tax Invoice” is displayed below the document title.
wcdn_before_branding / wcdn_after_branding
↑ Back to topThese hooks fire around the branding section that contains:
- Store name
- Address
- Phone number
- Email address
wcdn_after_branding only fires when at least one branding field is visible.
Example Code
// Append a company registration number below the shop details.
add_action( 'wcdn_after_branding', function( $order, $template ) {
echo '<p style="font-size:0.8em;">Reg No: 12345678 | VAT No: GB123456789</p>';
}, 10, 2 );
Expected Result
The company registration number and VAT number are displayed below the shop details section.
wcdn_before_addresses / wcdn_after_addresses
↑ Back to topThese hooks fire around the billing/shipping address grid and order meta section.
wcdn_after_addresses fires only when at least one address or order meta field is visible.
Example Code
// Insert a delivery instructions field between branding and addresses.
add_action( 'wcdn_before_addresses', function( $order, $template ) {
$instructions = get_post_meta( $order['id'], '_delivery_instructions', true );
if ( $instructions ) {
echo '<p><strong>Delivery Instructions:</strong> ' . esc_html( $instructions ) . '</p>';
}
}, 10, 2 );
Note: This snippet displays delivery instructions only when the order contains a custom meta field named _delivery_instructions.
Expected Output
The delivery instructions are displayed before the billing and shipping address section. If no addresses are present, the instructions are displayed before the next available content block in the document.
wcdn_before_items / wcdn_after_items
↑ Back to topThese hooks fire before and after the line-items table.
Both hooks only fire when the order contains line items.
Example Code
// Add a section heading above the items table.
add_action( 'wcdn_before_items', function( $order, $template ) {
echo '<p style="font-weight:600;margin-top:10px;">Items Ordered</p>';
}, 10, 2 );
Expected Output
The text “Items Ordered” is displayed above the product/items table in the document.
Example Code
// Add a note below the items table.
add_action( 'wcdn_after_items', function( $order, $template ) {
echo '<p style="font-size:0.8em;font-style:italic;">All prices include VAT.</p>';
}, 10, 2 );
Expected Output
The text “All prices include VAT.” is displayed below the products/items table.
wcdn_order_item_before / wcdn_order_item_after
↑ Back to topThese hooks fire before and after the product cell content for each order item. In simple words, it allows you to add extra information before or after each product line in the invoice or packing slip.
Callback Structure
↑ Back to topfunction my_callback( array $item, array $order, string $template ) { }
Item Data Available
↑ Back to topThe $item array contains commonly available product and order item data. Some fields may vary depending on the product type or plugin configuration:
- name
- sku
- price
- quantity
- total
- product_id
- order_item_id
- meta
- addon
- image_url
- image_path
Example Code
add_action( 'wcdn_order_item_after', function( $item, $order, $template ) {
$product_id = 0;
if ( is_array( $item ) && isset( $item['product_id'] ) ) {
$product_id = $item['product_id'];
}
if ( ! $product_id && is_object( $item ) && method_exists( $item, 'get_product' ) ) {
$product = $item->get_product();
if ( $product ) {
$product_id = $product->get_id();
}
}
if ( ! $product_id ) {
return;
}
$status = get_post_meta(
$product_id,
'_fulfilment_status',
true
);
if ( ! empty( $status ) ) {
echo '<span style="font-size:0.75em;color:#888;">'
. esc_html( $status ) .
'</span>';
}
}, 10, 3 );
Expected Output
A fulfilment status label, such as “In Stock”, “Backordered”, or “Ready to Ship”, is displayed below the corresponding product name in the items table.
wcdn_before_totals / wcdn_after_totals
↑ Back to topThese hooks fire around the totals section.
Both hooks always fire.
Example Code
// Add a note before the totals section.
add_action( 'wcdn_before_totals', function( $order, $template ) {
echo '<p style="font-size:0.8em;">Payment due within 30 days.</p>';
}, 10, 2 );
Expected Output
The text “Payment due within 30 days.” is displayed immediately before the totals section.
Example Code
// Append a custom totals row (e.g. loyalty points earned).
add_action( 'wcdn_after_totals', function( $order, $template ) {
$points = get_post_meta( $order['id'], '_loyalty_points_earned', true );
if ( $points ) {
echo '<p style="text-align:right;font-size:0.85em;">Loyalty points earned: <strong>' . esc_html( $points ) . '</strong></p>';
}
}, 10, 2 );
Note
This snippet displays loyalty points only when the order contains a custom meta field named _loyalty_points_earned.
Expected Output
The loyalty points value stored in the _loyalty_points_earned order meta field is displayed below the totals section.
wcdn_before_pay_button / wcdn_after_pay_button
↑ Back to topThese hooks fire around the Pay Now button.
Both hooks always fire.
Example Code
// Add a QR code below the pay-now button.
add_action( 'wcdn_after_pay_button', function( $order, $template ) {
if ( ! empty( $order['payment_url'] ) ) {
$qr_url = 'https://api.qrserver.com/v1/create-qr-code/?size=80x80&data=' . urlencode( $order['payment_url'] );
echo '<p style="text-align:center;"><img src="' . esc_url( $qr_url ) . '" width="80" height="80" /></p>';
}
}, 10, 2 );
Expected Output
A QR code appears below the payment button linking customers directly to the payment page.
wcdn_before_notes / wcdn_after_notes
↑ Back to topThese hooks fire around the customer note section.
wcdn_after_notes only fires when customer notes are enabled and not empty.
Example Code
// Add a label before the customer note section.
add_action( 'wcdn_before_notes', function( $order, $template ) {
if ( ! empty( $order['customer_note'] ) ) {
echo '<p style="font-weight:600;">Customer Note</p>';
}
}, 10, 2 );
Expected Output
↑ Back to topA “Customer Note” heading appears before the customer note content.
wcdn_before_policies / wcdn_after_policies
↑ Back to topThese hooks fire around the policies section.
Both hooks always fire.
Example Code
// Append a returns policy link below the policies section.
add_action( 'wcdn_after_policies', function( $order, $template ) {
echo '<p style="font-size:0.8em;">Full returns policy: <a href="https://example.com/returns">example.com/returns</a></p>';
}, 10, 2 );
Expected Output
↑ Back to topA returns policy link appears below the policies section.
wcdn_before_complimentary_close / wcdn_after_complimentary_close
↑ Back to topThese hooks fire around the complimentary closing section.
Example Code
// Inject a signature image above the complimentary close.
add_action( 'wcdn_before_complimentary_close', function( $order, $template ) {
echo '<img src="' . esc_url( get_site_url() . '/signature.png' ) . '" style="height:40px;" />';
}, 10, 2 );
Expected Output
↑ Back to topA signature image appears above the complimentary closing message.
wcdn_before_footer / wcdn_after_footer
↑ Back to topThese hooks fire around the footer section.
Example Code
// Add a page number note at the very bottom.
add_action( 'wcdn_after_footer', function( $order, $template ) {
echo '<p style="text-align:center;font-size:0.75em;color:#aaa;">Generated by Example Store</p>';
}, 10, 2 );
Expected Output
↑ Back to topA footer note appears at the bottom of the document.
wcdn_after_document
↑ Back to topFires at the very end of the document before the closing .wcdn-document wrapper.
Example Code
add_action( 'wcdn_after_document', function( $order, $template ) {
echo '<p style="font-size:0.7em;color:#ccc;">Order ID: ' . esc_html( $order['id'] ) . '</p>';
}, 10, 2 );
Expected Output
↑ Back to topThe document displays the WooCommerce Order ID at the bottom.
2.2 Per-Template Actions
↑ Back to topEach document type fires actions before and after loading the shared base.php template.
Use these hooks when you want to customize only one document type and need access to the full raw $data array.
Callback Structure
↑ Back to topfunction my_callback( array $data ) { }
Available Data
↑ Back to topThe $data array contains:
- order
- shop
- document
- settings
- template
Available Per-Template Actions
↑ Back to top| Action | Fires |
| wcdn_before_invoice_template | Before the invoice base template |
| wcdn_after_invoice_template | After the invoice base template |
| wcdn_before_receipt_template | Before the receipt base template |
| wcdn_after_receipt_template | After the receipt base template |
| wcdn_before_deliverynote_template | Before the delivery note base template |
| wcdn_after_deliverynote_template | After the delivery note base template |
| wcdn_before_packingslip_template | Before the packing slip base template |
| wcdn_after_packingslip_template | After the packing slip base template |
| wcdn_before_creditnote_template | Before the credit note base template |
| wcdn_after_creditnote_template | After the credit note base template |
Example Code
// Add raw HTML only to packing slips, outside the normal document wrapper.
add_action( 'wcdn_after_packingslip_template', function( $data ) {
echo '<div style="page-break-before:always;"></div>';
} );
Expected Output
↑ Back to topPacking slips include a forced page break after rendering.
2.3 PDF Actions
↑ Back to topwcdn_after_pdf_generated
↑ Back to topFires after a PDF file has been generated and written to disk.
Parameters
↑ Back to top| Parameter | Description |
| $file | Absolute path to the generated PDF |
| $order_id | WooCommerce order ID |
| $template | Document template type |
Example Code
// Copy each generated PDF to a remote storage bucket.
add_action( 'wcdn_after_pdf_generated', function( $file, $order_id, $template ) {
my_upload_to_s3( $file, "invoices/{$order_id}/{$template}.pdf" );
}, 10, 3 );
Expected Output
Generated PDFs are automatically uploaded to external storage after creation.
2.4. Order Data Filters (Data Layer Customization)
↑ Back to topOrder Data Filters allow developers to modify WooCommerce order data before it is rendered in the document templates. These filters do not change the template structure — instead, they change what data the template receives.
Use these filters when you need to:
- Modify product names, quantities, or prices
- Add or remove order items
- Change totals or meta information
- Inject additional fields into items or orders
wcdn_order_items
↑ Back to topFilters the complete line items array before rendering.
Example Use Case: Sort products or remove unwanted items from invoices.
Example Code
add_filter( 'wcdn_order_items', function( $items, $order, $template ) {
usort( $items, fn( $a, $b ) => strcmp( $a['name'], $b['name'] ) );
return $items;
}, 10, 3 );
Expected Output
↑ Back to topOrder items appear sorted alphabetically by product name.
Example Use Case: Sort products by SKU instead of product name for structured invoices or warehouse-friendly packing slips.
Example Code
add_filter( 'wcdn_order_items', function( $items, $order, $template ) {
usort( $items, fn( $a, $b ) => strcmp( $a['sku'], $b['sku'] ) );
return $items;
}, 10, 3 );
Expected Output
↑ Back to topOrder items appear sorted based on SKU in ascending alphabetical order, making it easier for warehouse staff to pick and pack products in a structured sequence.
Example Use Case: Remove specific product categories (such as digital products) from packing slips so only physical items are included for shipping.
Example Code
add_filter( 'wcdn_order_items', function( $items, $order, $template ) {
if ( 'packingslip' !== $template ) {
return $items;
}
return array_filter( $items, function( $item ) {
return ! has_term( 'digital', 'product_cat', $item['product_id'] );
} );
}, 10, 3 );
Expected Output
↑ Back to topDigital products are excluded from packing slips, and only physical shippable items appear in the document.
wcdn_order_item_product
↑ Back to topReplaces or modifies the WC_Product object resolved for each order line item before rendering.
Use this filter when you need to override how product data is interpreted in documents, such as treating variations as parent products or modifying product-level logic for invoices and packing slips.
Return null to indicate that the item should be treated as having no associated product.
Parameters: WC_Product|null $product, WC_Order_Item $item
Example Code
add_filter( 'wcdn_order_item_product', function( $product, $item ) {
if ( $product && $product->is_type( 'variation' ) ) {
return wc_get_product( $product->get_parent_id() );
}
return $product;
}, 10, 2 );
Expected Output
↑ Back to topVariation products are replaced with their parent product objects before rendering. Any subsequent template logic, hooks, or customizations that use the product object will receive the parent product instead of the variation.
wcdn_order_item_name
↑ Back to topModifies the product display name during document rendering.
Use this filter when you want to append, prepend, or change how product names appear in invoices, packing slips, delivery notes, or receipts without changing the actual WooCommerce product or order data.
This only affects the rendered document output.
Parameters:
string $name, WC_Order_Item $item
Example Code
add_filter( 'wcdn_order_item_name', function( $name, $item ) {
return $name . ' (Verified Product)';
}, 10, 2 );
Expected Output
↑ Back to topProduct names in WooCommerce delivery documents are modified at render time to include the suffix “(Verified Product)”. The original product name in WooCommerce orders and database remains unchanged.
wcdn_order_item_quantity
Modifies the quantity displayed for each order line item in documents like invoices, packing slips, delivery notes, and receipts.
Use this filter when you need to control how product quantities appear in printed or PDF documents without changing the actual WooCommerce order data. Common use cases include rounding fractional quantities, enforcing whole numbers for display, or applying custom business rules for printed documents.
Parameters:
float $quantity, WC_Order_Item $item
Example Code
// Always show whole numbers even for fractional quantities.
add_filter( 'wcdn_order_item_quantity', function( $quantity, $item ) {
return ceil( $quantity );
}, 10, 2 );
Expected Output
↑ Back to topAll line item quantities in the document are rounded up to the nearest whole number before display. For example, a quantity of 2.3 will appear as 3 in invoices, packing slips, and other generated documents.
wcdn_formatted_item_price
↑ Back to topModifies the formatted unit price string displayed for each line item in WooCommerce documents such as invoices, packing slips, delivery notes, and receipts.
Use this filter when you need to customize how product prices are displayed in printed or PDF documents without changing actual WooCommerce order pricing data. Common use cases include replacing zero prices with labels like “FREE”, adding custom currency labels, or applying formatting rules for specific business conditions.
Parameters: string $price, WC_Order_Item $item, WC_Order $order
Example Code
// Show "FREE" instead of £0.00 for zero-price items.
add_filter( 'wcdn_formatted_item_price', function( $price, $item, $order ) {
if ( (float) $item->get_subtotal() === 0.0 ) {
return 'FREE';
}
return $price;
}, 10, 3 );
Expected Output
If a product line item has a subtotal of 0, the unit price in the document will be displayed as FREE instead of the default formatted price (e.g., £0.00, $0.00, etc.).
All non-zero priced items will continue to display their original formatted prices unchanged.
wcdn_product_meta_data
↑ Back to topFilters the raw WooCommerce item meta data before it is converted into readable label/value pairs in documents like invoices, packing slips, delivery notes, and receipts.
Use this filter when you need to control which product-level metadata appears in printed or PDF documents. It is commonly used to remove sensitive or irrelevant meta fields (like gift messages, internal notes, or custom checkout fields) from being displayed in customer-facing documents.
Parameters: array $meta_data (array of WC_Meta_Data objects), WC_Order_Item $item
Example Code
// Remove a specific meta key from all documents.
add_filter( 'wcdn_product_meta_data', function( $meta_data, $item ) {
return array_filter( $meta_data, fn( $m ) => $m->key !== '_gift_message' );
}, 10, 2 );
Expected Output
↑ Back to topAny line item meta with the key _gift_message will be excluded from all WooCommerce Delivery Notes documents. All other meta data will continue to appear normally after formatting.
wcdn_order_item_fields
↑ Back to topAppends additional label/value rows to the product meta section of each order item in WooCommerce documents such as invoices, packing slips, delivery notes, and receipts.
Use this filter when you need to display extra product-specific information in printed or PDF documents without modifying the core template structure. It is commonly used for adding custom attributes like barcodes, batch numbers, supplier codes, warranty details, or internal tracking fields.
This filter runs after the system has prepared the default item fields, so anything you return here will appear alongside existing product meta in the document output.
Parameters: array $fields, WC_Product $product, WC_Order $order, WC_Order_Item $item
Example Code
// Add a barcode row to each item.
add_filter( 'wcdn_order_item_fields', function( $fields, $product, $order, $item ) {
$barcode = get_post_meta( $product->get_id(), '_barcode', true );
if ( $barcode ) {
$fields[] = array(
'label' => 'Barcode',
'value' => $barcode,
);
}
return $fields;
}, 10, 4 );
Expected Output
↑ Back to topEach product line item in the document will display an additional row labeled “Barcode” beneath the product details (or within the item meta section), showing the value stored in the product meta field _barcode. If no barcode exists for a product, no additional row is added.
wcdn_order_totals
↑ Back to topAllows you to add, remove, reorder, or modify rows in the totals section of WooCommerce documents such as invoices, packing slips, delivery notes, and receipts.
Each entry in the $totals array represents a row in the totals table. The array key acts as the row identifier, while the value contains the formatted amount displayed in the document.
Use this filter when you need to add custom charges, remove existing totals rows, or adjust how totals are displayed in generated documents without changing the actual WooCommerce order totals.
This filter only affects the rendered document output and does not modify order data stored in WooCommerce.
Parameters:
- array $totals — Existing totals rows.
- WC_Order $order — The current WooCommerce order object.
- string $template — The document type being generated.
Standard keys: subtotal, discount, tax, tax_lines, shipping, fee_lines, total, has_refund, refunded, net_total
Example Code
// Add an environmental levy row after shipping.
add_filter( 'wcdn_order_totals', function( $totals, $order, $template ) {
$levy = get_post_meta( $order->get_id(), '_eco_levy', true );
if ( $levy ) {
$totals['eco_levy'] = wc_price(
$levy,
array( 'currency' => $order->get_currency() )
);
}
return $totals;
}, 10, 3 );
Expected Result
↑ Back to topIf the order contains a custom meta field named _eco_levy, an additional amount is added to the totals section of the generated document. The value is formatted using the order currency.
This filter affects only the displayed document totals and does not change the actual WooCommerce order total.
wcdn_order_info_fields
↑ Back to topModifies the order information section displayed in invoices, packing slips, delivery notes, receipts, and other generated documents. This section typically contains details such as the invoice number, invoice date, payment method, shipping method, and other order-related information.
Use this filter when you need to add custom order metadata to the order information table without modifying the document templates directly. Common use cases include displaying Purchase Order (PO) numbers, internal reference numbers, customer account IDs, ERP order references, or other business-specific information.
Parameters:
array $fields, WC_Order $order
Each field should be added in the following format:
array(
‘label’ => ‘Field Label’,
‘value’ => ‘Field Value’,
)
Example Code
// Add a Purchase Order number row.
add_filter( 'wcdn_order_info_fields', function( $fields, $order ) {
$po = get_post_meta( $order->get_id(), '_purchase_order_number', true );
if ( $po ) {
$fields['po_number'] = array(
'label' => 'PO Number',
'value' => $po,
);
}
return $fields;
}, 10, 2 );
Expected Result:
If the order contains a custom meta field named _purchase_order_number, a new row labeled “PO Number” is added to the order information section of the document. The value stored in the custom meta field is displayed alongside the label.
The PO Number is displayed as an additional row alongside the existing order information without affecting any other document data.
wcdn_order_meta_fields
↑ Back to topModifies the complete list of order information rows displayed in the document’s order data section, such as Invoice Number, Invoice Date, Payment Method, Shipping Method, Phone, and Email.
Unlike wcdn_order_info_fields, which only allows you to add new rows, this filter gives you full control over the existing order information fields. You can reorder, modify, hide, or remove rows before they are rendered in invoices, packing slips, delivery notes, receipts, and other generated documents.
Use this filter when you need to customize the layout or presentation of the order information section to match your business requirements.
Parameters:
array $fields, array $order, array $settings, string $template
Each field is an array in the following format:
array(
‘key’ => ‘paymentMethod’,
‘label’ => ‘Payment Method:’,
‘value’ => ‘Direct bank transfer’,
‘show’ => true,
)
Example Code
// Move the payment method row to the top.
add_filter( 'wcdn_order_meta_fields', function( $fields, $order, $settings, $template ) {
usort( $fields, function( $a, $b ) {
if ( 'paymentMethod' === $a['key'] ) {
return -1;
}
if ( 'paymentMethod' === $b['key'] ) {
return 1;
}
return 0;
} );
return $fields;
}, 10, 4 );
Expected Result:
The Payment Method row is moved to the top of the order information section and appears before other fields such as Invoice Number, Invoice Date, Shipping Method, Phone, and Email.
Only the display order of the rows is changed. The order data itself remains unchanged.
wcdn_order_meta_fields
↑ Back to topFilter the full list of order meta field rows shown in the document’s order data block.
Use this to reorder, remove, or modify existing rows such as invoice number, date, payment method, etc.
This hook is useful when you need full control over the order info table structure, not just adding new fields.
Parameters: array $fields, array $order, array $settings, string $template
Each field contains:
[ ‘key’, ‘label’, ‘value’, ‘show’ ]
Example Code
// Remove the invoice number row from delivery notes.
add_filter( 'wcdn_order_meta_fields', function( $fields, $order, $settings, $template ) {
if ( 'deliverynote' === $template ) {
return array_filter( $fields, fn( $f ) => 'invoiceNumber' !== $f['key'] );
}
return $fields;
}, 10, 4 );
Expected Result:
↑ Back to topThe “Invoice Number” row is removed from delivery note documents, while remaining unchanged in other document types.
wcdn_billing_address
↑ Back to topFilter the formatted billing address lines before rendering in the document.
Use this to append or modify billing address content without changing WooCommerce order data.
Parameters: array $lines, WC_Order $order
Each element is a single address line string.
Example Code
// Append a custom billing note as a final address line.
add_filter( 'wcdn_billing_address', function( $lines, $order ) {
$note = get_post_meta( $order->get_id(), '_billing_note', true );
if ( $note ) {
$lines[] = $note;
}
return $lines;
}, 10, 2 );
Expected Result:
↑ Back to topIf _billing_note exists, it appears as an additional line in the billing address block.
wcdn_shipping_address
↑ Back to topFilter the formatted shipping address lines before rendering.
Use this to append delivery-specific instructions or modify shipping address display.
Parameters: array $lines, WC_Order $order
// Append a delivery zone note to shipping address.
Example Code
add_filter( 'wcdn_shipping_address', function( $lines, $order ) {
$zone = get_post_meta( $order->get_id(), '_shipping_zone', true );
if ( $zone ) {
$lines[] = 'Zone: ' . $zone;
}
return $lines;
}, 10, 2 );
Expected Result:
↑ Back to topThe shipping address includes an additional line such as Zone: South-East.
wcdn_order_invoice_number
↑ Back to topModify the formatted invoice number before it is displayed in documents.
Use this to add prefixes, suffixes, or custom formatting for business identification.
Parameters: string $invoice_number
Example Code
// Prefix invoice number with current year.
add_filter( 'wcdn_order_invoice_number', function( $invoice_number ) {
return date( 'Y' ) . '-' . $invoice_number;
} );
Expected Result: Invoice numbers appear in format like 2026-INV-1023.
wcdn_order_invoice_date
↑ Back to topModify the formatted invoice date string before rendering.
Use this to change date formatting or localization.
Parameters: string $formatted_date, int $timestamp
Example Code
// Use a full readable date format.
add_filter( 'wcdn_order_invoice_date', function( $formatted_date, $timestamp ) {
return date_i18n( 'l, F j, Y', $timestamp );
}, 10, 2 );
Expected Result:
↑ Back to topInvoice date appears as: Monday, June 23, 2026.
2.5 Shop & Document Data Filters
↑ Back to topwcdn_shop_data
↑ Back to topFilter the shop/store data before it is passed into templates.
Use this to override store identity information dynamically without changing plugin settings.
Parameters: array $shop
Keys:
name, logo, logo_path, address, phone, email
Example Code
// Override store branding dynamically.
add_filter( 'wcdn_shop_data', function( $shop ) {
$shop['name'] = 'Sub-Brand Ltd';
$shop['address'] = '99 Example Street, London';
return $shop;
} );
Expected Result:
↑ Back to topAll generated documents show modified store name and address.
wcdn_document_data
↑ Back to topFilter document-level content such as footer, policies, and closing text.
Parameters: array $document
Keys:
footer, policies, complimentaryClose, isRTL
Example Code
// Append seasonal message in footer.
add_filter( 'wcdn_document_data', function( $document ) {
$document['footer'] .= '<br>Thank you for your order!';
return $document;
} );
Expected Result:
↑ Back to topFooter includes additional custom message.
wcdn_document_title
↑ Back to topModify document title labels shown in admin and print views.
Parameters: string $title, string $template_type
Example Code
// Rename receipt title.
add_filter( 'wcdn_document_title', function( $title, $template_type ) {
if ( 'receipt' === $template_type ) {
return 'Payment Confirmation';
}
return $title;
}, 10, 2 );
Expected Result:
↑ Back to topReceipt documents display as “Payment Confirmation”.
wcdn_watermark_text
↑ Back to topModify watermark text based on order conditions.
Parameters: string $text, array $order, string $template
Example Code
// Show PAID or UNPAID watermark.
add_filter( 'wcdn_watermark_text', function( $text, $order, $template ) {
if ( 'completed' === $order['status'] ) {
return 'PAID';
}
if ( in_array( $order['status'], array( 'pending', 'on-hold' ), true ) ) {
return 'UNPAID';
}
return $text;
}, 10, 3 );
Expected Result:
↑ Back to top
Watermark dynamically changes based on order status.
2.6 Template Rendering Filters
↑ Back to topwcdn_template_data
↑ Back to topModify the full data array passed into templates.
Parameters: array $data, string $template, string $type
Example Code
add_filter( 'wcdn_template_data', function( $data ) {
$data['my_var'] = 'hello';
return $data;
} );
Expected Result:
↑ Back to topCustom variables become available inside template overrides.
wcdn_template_css
↑ Back to topModify final combined CSS for rendered documents.
Parameters: string $css, string $context, array $data
Example Code
add_filter( 'wcdn_template_css', function( $css, $context, $data ) {
if ( 'html' === $context ) {
$css .= 'body { font-family: Lato, sans-serif; }';
}
return $css;
}, 10, 3 );
Expected Result:
Custom styles apply to HTML print preview.
wcdn_dynamic_css
↑ Back to topModify CSS generated from plugin settings.
Parameters: string $css, array $settings
Example Code
add_filter( 'wcdn_dynamic_css', function( $css ) {
$css .= '.wcdn-totals { color: #000 !important; }';
return $css;
}, 10, 2 );
Expected Result:
↑ Back to topTotals section always appears in black.
wcdn_locate_template
↑ Back to topOverride template file location.
Parameters: string|false $path, string $template, string $type, string $source
Example Code
add_filter( 'wcdn_locate_template', function( $path, $template ) {
if ( 'invoice' === $template ) {
return get_stylesheet_directory() . '/my-invoice.php';
}
return $path;
}, 10, 4 );
Expected Result:
↑ Back to topCustom invoice template is loaded instead of plugin default.
wcdn_allowed_statuses_{template}
↑ Back to topControl which order statuses enable a document.
Example Code
// Only allow packing slips for processing/on-hold orders.
add_filter( 'wcdn_allowed_statuses_packingslip', function( $statuses ) {
return array( 'processing', 'on-hold' );
} );
Expected Result:
↑ Back to topPacking slips hidden for other statuses.
2.7 Print View Filters
↑ Back to topwcdn_print_document_title
↑ Back to topModify browser tab title in print preview.
Parameters: string $title, array $order_ids, string $template
Example Code
add_filter( 'wcdn_print_document_title', function( $title, $order_ids, $template ) {
return 'My Store — ' . ucfirst( $template );
}, 10, 3 );
Expected Result:
↑ Back to topCustom title appears in print tab.
wcdn_format_phone_number
↑ Back to topFormat the billing phone number before it is rendered in documents.
Use this filter when you need to standardize, mask, or enhance phone number display in invoices, packing slips, delivery notes, or receipts. Common use cases include adding country codes, formatting numbers for international readability, or enforcing consistent display formats without changing stored order data.
Parameters: string $phone, string $country (ISO 3166-1 alpha-2 country code)
Example Code
// Add country dial code prefix for US orders.
add_filter( 'wcdn_format_phone_number', function( $phone, $country ) {
if ( 'US' === $country && ! str_starts_with( $phone, '+1' ) ) {
return '+1 ' . $phone;
}
return $phone;
}, 10, 2 );
Expected Result:
The billing phone number displayed in documents will be modified based on country rules.
wcdn_template_types_from_order
↑ Back to topControl which documents are available per order.
Parameters: array $types, WC_Order $order
Example Code
add_filter( 'wcdn_template_types_from_order', function( $types, $order ) {
$vat = get_post_meta( $order->get_id(), '_billing_vat', true );
if ( ! $vat ) {
return array_diff( $types, array( 'invoice' ) );
}
return $types;
}, 10, 2 );
Expected Result:
↑ Back to topInvoice option hidden if VAT is missing.
2.8 Email Filters
↑ Back to topwcdn_administrator_emails
↑ Back to topOverride the list of admin email addresses used when sending documents to administrators.
Parameters: array $emails
Example Code
add_filter( 'wcdn_administrator_emails', function( $emails ) {
$emails[] = 'accounts@example.com';
return $emails;
} );
Expected Result:
↑ Back to topAny document emails sent to admins will now also include accounts@example.com as a recipient.
wcdn_custom_email_message_body
↑ Back to topOverride the HTML email body when sending documents as standalone emails.
Parameters: string $message, WC_Order $order, string $template
Example Code
add_filter( 'wcdn_custom_email_message_body', function( $message, $order, $template ) {
return str_replace( 'Your order', 'Order #' . $order->get_order_number(), $message );
}, 10, 3 );
Expected Result:
↑ Back to topEmail body text replaces “Your order” with “Order #XXXX”.
wcdn_custom_email_recipients
↑ Back to topOverride recipients for document emails.
Parameters: array $emails, WC_Order $order, string $template
Example Code
add_filter( 'wcdn_custom_email_recipients', function( $emails, $order, $template ) {
if ( 'invoice' === $template ) {
$emails[] = 'sales@example.com';
}
return $emails;
}, 10, 3 );
Expected Result:
↑ Back to topInvoice emails also go to sales@example.com.
wcdn_print_view_in_browser_text_in_email
↑ Back to topChange the “Print” link text inside WooCommerce emails.
Parameters: string $text
Example Code
add_filter( 'wcdn_print_view_in_browser_text_in_email', function( $text ) {
return 'View & Print Your Invoice';
} );
Expected Result:
Email shows updated link text instead of default “Print”.
2.9 PDF Generation Filters
↑ Back to topwcdn_pdf_paper_size
↑ Back to topOverride PDF paper size.
Parameters: string $size, int $order_id
Example Code
add_filter( 'wcdn_pdf_paper_size', function( $size, $order_id ) {
$order = wc_get_order( $order_id );
if ( $order && 'US' === $order->get_shipping_country() ) {
return 'Letter';
}
return $size;
}, 10, 2 );
Expected Result:
US orders generate PDFs in Letter size; others use default A4.
wcdn_pdf_orientation
↑ Back to topOverride PDF orientation.
Example Code
add_filter( 'wcdn_pdf_orientation', function( $orientation, $order_id ) {
return 'landscape';
}, 10, 2 );
Expected Result:
All PDFs are generated in landscape mode.
wcdn_pdf_dpi
↑ Back to topOverride PDF rendering DPI.
Example Code
add_filter( 'wcdn_pdf_dpi', function( $dpi ) {
return 200;
} );
Expected Result:
Higher resolution PDF output (sharper images, larger file size).
wcdn_pdf_filename
↑ Back to topOverride PDF file name.
Example Code
add_filter( 'wcdn_pdf_filename', function( $filename, $order_id, $template ) {
$order = wc_get_order( $order_id );
return $template . '-' . $order->get_order_number() . '.pdf';
}, 10, 3 );
Expected Result:
Downloaded file name becomes like invoice-1023.pdf.
wcdn_pdf_generated_file
↑ Back to topTriggered when PDF is generated (returns file path).
Example Code
add_filter( 'wcdn_pdf_generated_file', function( $file, $order_id, $template ) {
error_log( "WCDN PDF generated: {$template} for order {$order_id} → {$file}" );
return $file;
}, 10, 3 );
Expected Result:
Log entry appears in debug log for each PDF generation.
wcdn_pdf_zoom_mode
↑ Back to topControl PDF zoom mode.
Example Code
add_filter( 'wcdn_pdf_zoom_mode', function( $mode ) {
return 'text';
} );
Expected Result:
PDF zoom focuses on text scaling.
2.10 PDF Locale Font Filters
↑ Back to topwcdn_pdf_locale_font_config
↑ Back to topOverride font config per locale.
Example Code
add_filter( 'wcdn_pdf_locale_font_config', function( $config, $locale ) {
if ( 'ja' === substr( $locale, 0, 2 ) ) {
return array(
'name' => 'NotoSansJP',
'google_name' => 'Noto+Sans+JP',
'display_name' => 'Noto Sans JP',
);
}
return $config;
}, 10, 2 );
Expected Result:
Japanese PDFs use Noto Sans JP font.
wcdn_pdf_locale_font_path
↑ Back to topProvide local font file.
Example Code
add_filter( 'wcdn_pdf_locale_font_path', function( $path, $locale ) {
if ( str_starts_with( $locale, 'zh_' ) ) {
return WP_CONTENT_DIR . '/fonts/NotoSansSC-Regular.ttf';
}
return $path;
}, 10, 2 );
Expected Result:
Chinese PDFs use local font file.
wcdn_pdf_locale_font_url
↑ Back to topProvide remote font URL.
Example Code
add_filter( 'wcdn_pdf_locale_font_url', function( $url, $locale ) {
if ( str_starts_with( $locale, 'ko' ) ) {
return 'https://fonts.example.com/NotoSansKR-Regular.ttf';
}
return $url;
}, 10, 2 );
Expected Result:
↑ Back to topKorean PDFs load external font.
wcdn_pdf_use_google_fonts_for_locale
↑ Back to topDisable Google Fonts fallback.
Example Code
add_filter( 'wcdn_pdf_use_google_fonts_for_locale', '__return_false' );
Expected Result:
System does NOT fetch Google Fonts; only local/URL fonts used.