Customizing the WooCommerce Shipping packing slips is possible, though a bit limited. Due to a frightening series of interdependent internal classes without public instances, you can’t get information about an order’s shipments when customizing the packing slip. But there’s still a lot you can do without that.
A heads-up, our examples use PHP 8.4’s new \Dom\HTMLDocument class, which makes dealing with modern HTML in PHP much simpler. This code could be probably be adapted for the old DOMDocument class, or symfony/css-selector.
All of the examples can go in a plugin where you keep your functionality-related WordPress hooks. You wouldn’t put functionality customization in a theme, would you?
Add your site logo
To add our site logo, we’re going to replace the generic “Packing Slip” heading. I think that’s implied.
<?php
add_filter('wcshipping_packing_list', function($packing_slip_html, $order_id, $label_id) {
$document = \Dom\HTMLDocument::createFromString($packing_slip_html);
$heading = $this->document->querySelector('h1');
if($heading) {
$img = $document->createElement('img');
$img->setAttribute('src', get_site_icon_url());
$img->setAttribute('style', 'max-width:.5in; height: auto; display: block;margin-bottom:.25in;');
$heading->replaceWith($img);
}
return $document->saveHtml();
}, 10, 3);Code language: PHP (php)
Print the packing slip to a 4×6 label
Some eCommerce folks print their packing slips on the same 4×6 labels they print their shipping labels on. This seems expensive, but perhaps logistically simpler.
We can add some CSS that suggests to the browser that we’d like to print to a 4×6 label. I’ve also made some tweaks to get the slip to fit better in a 4×6 environment.
<?php
add_filter('wcshipping_packing_list', function($packing_slip_html, $order_id, $label_id) {
$document = \Dom\HTMLDocument::createFromString($packing_slip_html);
$style = $document->querySelector('style');
if($style) {
$style->textContent .= '
@page {
size: 4in 6in;
margin: 0;
}
body {
font-size:10px;
}
th, td {
padding:.05in;
}
';
}
/**
* This removes the item image/name, weight, and dimensions from the items table.
* Saves space. Customize to your needs.
* CSS or a different selector here could be used to hide/remove the image and keep the name.
*/
foreach($document->querySelectorAll('table th:first-child, table td:first-child, table th:nth-child(5), table td:nth-child(5), table th:nth-child(6), table td:nth-child(6)') as $cell) {
$cell->remove();
}
return $document->saveHtml();
}, 10, 3);Code language: HTML, XML (xml)
That @page CSS selector is pretty nifty, but it doesn’t seem to reliably hint the paper size to the print dialog, so you may still need to select the right paper size. Let us know if you’ve got a better solution for hinting that.
Manipulating the existing HTML is pretty easy, but if you need to know about the shipment and associated label to create new markup, you’re out of luck.
Say you wanted to add an informational product care card to shipments that include a particular product. You don’t want this to appear everywhere the order items are listed, so you don’t want to filter the order items. You just want to filter what’s shown on the packing slip so that your packers remember to add it to the right box. There’s no way to get the shipment information without access to internal WooCommerce Shipping classes. You can only get the full order object (with wc_get_order( $order_id ) ). The best you can do is search the HTML for the trigger product SKU and, if found, insert a new child row into the existing table.
What creative ways have you found to customize the WooCommerce Shipping packing slips? Where have you found them lacking that this kind of customization might come in handy?

Leave a Reply