Magento 2 Extensions:PDF Customizer

From XTENTO Support Wiki
Jump to: navigation, search
This is a guide for Magento 2. This extension is a Magento 2 only extension, we don't offer a version for Magento 1 at this point.




Customizing all your order/invoice/shipment/credit memo as well as product PDFs has never been easier. Easily set up custom PDFs for packing slips or invoices. Export your product catalog into beautifully styled PDFs. Adjust invoices to your local regulations and make sure they match your corporate identity. All using the PDF Customizer extension by XTENTO.

Interested in this Magento 2 Extension?

Head over to our store to purchase this extension: PDF Customizer (Magento 2)

Got questions? Feel free to contact us! Contact Form

Setting up the extension

cat composer.json | grep -q 'magento/project-community-edition' && (composer require mpdf/mpdf "^8.0" ; composer require mpdf/qrcode "^1.0" ; composer dump-autoload) || echo 'composer.json seems to be broken! cannot install.'

The extensions configuration section is located at System > XTENTO > PDF Customizer. After installing the extension, make sure to enable the module there.

At System > XTENTO > PDF Customizer you will also be able to enable/disable order/invoice/shipment/credit memo PDFs and specify whether they should be attached to emails sent to your customers.

Managing PDF Templates

To set up custom PDF Templates or set up one of our beautiful ready-to-use PDFs, please go to Stores > Manage PDF Templates.

You will have the ability to add new templates there for each of the following entities:

Once you click "Add New Template" you can select the entity (for example "Orders") to add a new PDF Template for.

You will then be presented with an onboarding screen that shows you our ready-to-use PDF Templates that can be loaded with the click of a button. We would suggest selecting one of the templates that looks good to you, load it, and if required, customize it, or use it as it is.

After clicking "Load Template" you will be see four tabs to configure the PDF Template, which are explained as following:

- Template Name: Specify the template name
- Enable / Disable Template
- Default Template: Whether this is the default template (for example for Orders - if "Default Template" is set to yes, then this means it's the template attached to order emails sent to the customer)
- Store View(s): Which store views should use this template? Set up different templates for different stores/countries

- PDF Filename: Specify the file name to use when this PDF is generated. You can use variables there such as {{var increment_id}} or any other variable you find in the "PDF Template" tab
- Paper Orientation / Format / Margins: Specify the general PDF layout. Most of the time you can use the default values that the "default template" specified there.
- Additional PDFs: Enter template IDs (comma-separated) of additional "attachment" PDFs (such as terms and conditions) you would like to generate and attach to emails when this PDF is triggered, for example on order placement.

Described below, this is the section of the template where you specify the exact PDF contents and layout.

This is a helpful utility - simply click the "Preview PDF" tab and you will instantly see a preview of the changes you've applied in the "PDF Template" tab.

Creating a custom PDF Template

Creating custom PDFs is super easy using the extension. The extension uses the popular "mPDF" library internally to generate PDFs. This is done by converting HTML/CSS into PDF.

You don't need to know HTML or CSS to use the extension. Simply use one of the ready-to-use & beautiful PDF Templates that comes with the extension out of the box.

To customize your PDF Templates you will only need to change text and HTML/CSS. Use one of our ready-to-use templates as the foundation.

mPDF supports many HTML tags:

CSS is supported as well:

The mPDF documentation can be very helpful sometimes if you hit a roadblock. Check out this topic on "images" for example:

Template Layout

Go to Stores > Manage PDF Templates and add or edit one of the existing templates. The actual PDF is generated via the HTML/CSS specified in the "PDF Template" tab when editing a PDF profile.

The general layout of a PDF Template is as following, simply look at one of our ready-to-use templates to see it: ##header_start##
...header HTML here...
...body HTML here...
...footer HTML here...

There are three sections:

Theoretically you can leave the header and footer empty, however, the body should be there. Also, the template structure (##header_start##...##header_end##...##body_start##... etc.) must always be present.

Between each of the sections you can use almost any HTML Tag. Use that to build your PDF Template using divs/tables/etc., and be sure to use our sample templates as a foundation to see how to get started.

Outputting Items

Within the body, if you want to output order/invoice/... items, you will need to put the data that is output "for each item" in the following block: ##items_start##
...item data here, this data is output N times for each item in an order/invoice/...

Additional Item Filters

Within the items_start and items_end section, you can specify "item settings" to tell the module that only specific product types (just visible items, or just configurable items, or items without parent items) should be shown in the PDF: <!--item_configuration:mode=visible--> or <!--item_configuration:hidden_types=virtual,downloadable--> or <!--item_configuration:hide_parent_items=true--> or <!--item_configuration:hide_child_items=true--> or combine them <!--item_configuration:mode=visible;hidden_types=virtual,downloadable-->

Sorting Products

It is also possible to sort products on orders/invoices/... PDF using the extension. You can sort by any product attribute: <!--item_configuration:sort_by=name;sort_order=ASC--> Natural sorting is used to determine the order. You can inverse it by setting sort_order to DESC

Product Options

Since module version 2.6.4, outputting product options (such as Size: S, Color: Blue) of configurable products, etc., is possible like this:

{{var item.product_options_formatted}}

Outputting custom options is possible as well:

{{var item.item_options}}
Accessing parent/child attributes

Accessing attributes of parent/child products is also possible. The following nodes exist for that: child_item, child_order_item, child_order_item_product, parent_item, parent_order_item, parent_order_item_product

Accessing the parents "ean" attribute: {{var parent_order_item_product.ean}}

Accessing the child product "color" attribute: {{var child_order_item_product.attribute}}

For bundle items, getting the options/bundle name: {{var item.bundle_name}}

Sample to get the child item name, if it's a child product:

{{if child_order_item.item_id}}
Rendering totals

Since module version 2.8.7 we support outputting total renderers to render the totals (subtotal, grand total, etc.), just like Magento does out of the box in their built-in PDFs. This allows you to output totals of third party extensions as well.

You won't need to do anything if you are a new user (starting from version 2.8.7) but if you installed the extension before, and have troubles with totals not showing up, you will need to adjust your template and remove all the totals from the PDF Template and instead simply put something like this there, to have the iterating totals_start/totals_end sections (see our sample templates!):

    <td colspan="3"></td>
    <td colspan="2" class="label">
        {{depend total.is_grand_total}}<strong>{{/depend}}{{var total.label }} {{depend total.is_tax}}({{var total.tax_percent}}){{/depend}}{{depend total.is_grand_total}}</strong>{{/depend}}
    <td class="value {{depend total.is_grand_total}}final{{/depend}}">
        <strong>{{var total_formatted.amount}}</strong>


Hundreds of different variables can be used to add dynamic content into your PDFs. In the "PDF Template" tab, simply click one of the variable buttons to see the available variables. By clicking on a variable, it will be inserted at the current cursor position.

Easily add variables such as order, invoice, shipment, credit memo and item information as well as product attributes to your PDF Template. For product exports, you can also access all product-related information as well.

Example how to output the customer email: {{var order.customer_email}}

You can easily see all available variables by clicking the buttons in the "PDF Template" tab.

It is also possible to apply modifiers to variables, for example to convert new lines to <br/> html tags: {{var order.some_field|nl2br}}

Prefix your field with "formatted_" to get a localized version, for example of date or currency values: {{var formatted_order.created_at}}

Getting the grand total formatted, i.e. in a localized version including the currency symbol: {{var formatted_order.grand_total}}

Accessing the "base grand total", that is the grand total in the base currency, and the base currency symbol: {{var formatted_order.base_grand_total}}

Also possible for item variables to get localized/currency versions: {{var formatted_item.row_total}}

Outputting the product image thumbnail can be done like this (as a reminder, all variables can be found via the "Show variables" buttons easily): {{var order_item_product.thumbnail_image_html}}

Getting the shipping country name: {{var shipping.country_name}}

Accessing a product attribute: {{var order_item_product.color}}

Accessing the order gift message: {{var giftmessage.message}} / {{var giftmessage.sender}} / {{var giftmessage.recipient}}

Accessing the customer note: {{var comment}}

Outputting the billing firstname: {{var billing.firstname}}

Outputting a custom "customer" attribute, so only there if the buyer is a registered customer: {{var customer.some_field}}

For a list of all fields, simply use the "Variable" buttons in the "PDF Template" tab and you can see which fields are there and how they are called exactly.

Adding custom variables

Have data that is stored in custom database tables? Or, need to populate some variables based on complex conditionals such as "if order weight > 5, text is X, otherwise Y"?

You can hook into an event in our module where variables are built. The event is called as following: xtento_pdfcustomizer_build_transport_after (Check out the file "\Xtento\PdfCustomizer\Helper\Variable\Processors\Pdf.php" for more details)

A sample observer which adds custom variables to our module can be downloaded here.


The extension supports dozens of different barcode types that can be output into PDFs:

Outputting barcodes couldn't be simpler. Let's say you currently output the invoice# like this:

{{var invoice.increment_id}}

To output the invoice# as a c128 barcode simply add "barcode_c128_" in front of the variable name:

{{var barcode_c128a_invoice.increment_id}}

Supported for: order, invoice, shipment, creditmemo and customer prefixes. Another example:

{{var barcode_qr_order.entity_id}}

This works for almost any of the variables that can be output.

You can also output "custom" barcodes using combined values, or in different sizes using the barcode tag:

<barcode code="{{var order.increment_id}}" type="c39" size="0.8" class="barcode" text="1" /> <!-- Value goes into code attribute -->


In general, most of the directives ({{...}}, can be described as "functions") that you are familiar with from the Magento "email template" system can be used. See here for more details about directives.


Used to translate text in the PDF templates: {{trans "Once your package ships we will send you a tracking number."}} or {{trans "Thank you for your order from %store_name." store_name=$store.getFrontendName()}}

It is recommended to output all the text in your PDF Template like this, to make sure localization works once you add, for example, another store view in another language.

{{depend}}, {{if}}, {{else}}

If-then-else or just if constructs can be set up using the depend, if and else directives.

Example, for an "if without else", just append "_if" to the variable you are trying to access, before the "dot":

{{depend customer_if.telephone}}
...output something if customer telephone is not empty...

Or another example for an if-then-else if the "order field some_field" evaluates to 1:

{{if order_if.some_field}}
...output something...
...output something else...

Sections that can be used for "depends": billing_if, shipping_if, customer_if, order_if, invoice_if (for invoice templates), shipment_if (for shipment templates), creditmemo_if (for credit memo templates), store_information_if

You cannot use logical expressions (if X is 123) in depend and if directives. Instead, you will need to set up a variable that evaluates to 0 or 1 and use it with depends/if. Contact us if you need help.


Get a value from the Magento "System" configuration. Example:

{{config path="web/unsecure/base_url"}}

Allowed "path" values:

Example to get the store city: {{config path="general/store_information/city"}}


The store directive is used to retrieve the stores URL: {{store url=""}}


Output a custom variable (maintained at System > Custom Variables):

{{customVar code="..."}}

Adding images in PDFs

You can either upload images to a webserver and embed it in the PDF Template like this: <img src=""/>

where you simply place the full link to the image in the "src" tag. This, however, only works if your Magento server is able to connect to "itself" via http/https, which sometimes isn't the case. In that case, simply host the image elsewhere or use an absolute path such as /var/www/folder/media/image.jpg to embed the image.

Or in case you want to upload the logo in the Magento backend, you can simply use the following logo variable which takes the image you upload at "Stores > Configuration > Sales > Sales > Invoice and Packing Slip Design > Logo for PDF Print-outs": <img src="{{logo_url}}"/> Be sure to upload a square/quadratic image, i.e. where width is same as height, for best look.

It is also possible to dynamically retrieve the path to an image (stored in the "media" folder of Magento) using the {{media}} directive: <img src="{{media url="some_folder/some_image.png"}}" alt="" /> <!-- Looks for image in folder media/some_folder/ -->

Using PHP in PDF Templates

Need more complicated if/then/else statements or need to use PHP code? Simply embed your code in a template.phtml file and write your logic in there, then embed it as a block.

A sample phtml template can be found here: PdfCustomizer/view/adminhtml/templates/custom_block/sample.phtml

Make sure to place it in a custom module, in the same folder structure detailed above: view/adminhtml/templates/YOUR_FOLDER/FILE.phtml

You can then call it from your PDF Template like this: {{block class="Magento\Backend\Block\Template" template="Xtento_PdfCustomizer::custom_block/sample.phtml" area="adminhtml" order=$order}}

Just adjust the path to your custom module/phtml template and it will be output. Do not change "class" or "area" values. Inside this template, you have access to all PHP functions, can access the $order object, etc. So for example, something like this would be no problem (just to showcase - any PHP function is possible):

$shipMethod = $order->getShippingDescription(); echo substr($shipMethod, 0, 10);

For an invoice template, you could even add the $invoice as a variable that you can then access using $this->getInvoice() in your phtml template: {{block class="Magento\Backend\Block\Template" template="Xtento_PdfCustomizer::custom_block/sample.phtml" area="adminhtml" order=$order invoice=$invoice}}

To access the $item variable, do this (this must be used within ##items_start## and ##items_end##): {{block class="Magento\Backend\Block\Template" template="Xtento_PdfCustomizer::custom_block/sample.phtml" area="adminhtml" order=$order item=$item}}

On a side note, it is also possible to embed CMS blocks into PDFs: {{block id="some_cms_block_id"}}

Using the extension

The PDFs you set up that have "Default Template" set to "Yes" will be used when printing invoices/shipments etc. from within an order/invoice/shipment/credit memo.

To print your custom PDFs, simply go to, for example, the Sales > Orders grid and select the "Print PDF: ..." action from the "Actions" dropdown. Be sure not to confuse them with the default-Magento print options, as those will still return the old PDFs!

Printing products/the catalog is possible from the Catalog > Products grid using the "PDF Catalog" mass action as well as from within a product using the "Print PDF" button.

Troubleshooting / Hints

Printing invoice/shipment before invoicing/shipping order

You can use our extension to print an invoice/packing slip before the order has been invoiced/shipped.

To do so, just create a new "Order" PDF template and a "Shipment" PDF Template. Then, copy the template HTML/CSS from the "Shipment" template into the "Order" PDF Template and replace "var shipment" and "var formatted_shipment" with "var order" and "var formatted_order". So now you will have an order PDF Template, that looks like a packing slip/shipment PDF Template. (Same steps for invoice template; just replace shipment with invoice)

Header: First page of document only

Don't want the header of the page to repeat on every page, provided your page is so big / has so many items that it is split across multiple pages? Simply move everything from the ###header### section to the ###body### section - now the header will be output once only, for the first page of your invoice/packing slip/...

Footer: Output on every page of long documents

Have orders/invoices/... that have lots of items and want the footer to be output on every page? Since module version 2.6.3 that is possible. Somewhere between the body_start and body_end section of your PDF Template, simply paste this:

<!-- configuration: outputFooterOnEveryPage="true" -->

PDF Preview not working

Trying to use the PDF preview functionality in your PDF Template but it doesn't display the PDF but your browser rather wants to download it (but that fails)? Make sure you have enabled a PDF plugin in your browser, in Chrome make sure Chrome PDF viewer plugin and/or the Adobe Reader plugin are NOT disabled. Also, it can help to go into your browsers settings and enable "Preview in Browser".

setasign/fpdi suggests installing [...]

Shows up during composer installation or when installing mpdf via composer. You can ignore this message -- it's just a recommendation and you don't need to install those packages.

Cannot download PDF in frontend/backend

Using Cloudflare and HTTP2? That may be the culprit:

Wrong filename when printing PDFs

When printing from the grid a generic filename is used, as multiple documents could be printed. Go into the individual order/invoice/shipment and press "Print" to get the file with your customized filename.

Customizing MPDF config; adding custom fonts

To customize MPDF configuration or add custom fonts, you will want to install our "sample helper module" to do so, that way you don't need to modify our modules code and can keep upgrading PdfCustomizer just fine.

You can get the sample module here.

Install it in Magento using bin/magento module:enable Xtento_PdfConfig and also run setup:upgrade and flush the cache.

Then, in the file app\code\Xtento\PdfConfig\Observer\GetMpdfConfig.php you can modify the MPDF configuration, as well as add a custom font directory and specify the fonts.

You need PdfCustomier version 2.6.4 or newer for this to work.

Important notes:

Outputting tracking numbers of shipments on orders/invoices/shipments/...

Since module version 2.6.6 tracking numbers can be accessed and output in your PDF Templates:

Tracking Number: {{var track.track_number}} ({{var track.carrier_code}} / {{var track.title}})<br/>

This will output one row for each tracking number. Adjust & style as required.

Programmatically creating PDFs using our extension

Writing a custom module and want to generate, for example, the invoice PDF using our extension? That's possible, easily.

Sample code (better use dependency injection, just a sample for understanding):

// $collection should be an order/invoice/shipment/collection (\Magento\Sales\Model\ResourceModel\Order\Invoice\CollectionFactory etc.) with filters that contain the objects you want to print
// $templateId can be null if you want the default template to be used, or can be set to a specific PDF Template ID you have configured in our extension
$pdf = $this->objectManager->create('\Xtento\PdfCustomizer\Helper\GeneratePdf')->generatePdfForCollection($collection, $templateId);

$pdf will be an array then, containing two keys: "output" and "filename". Output is a string, the PDF data, and filename the filename that was generated by the extension.

It's also possible to generate the PDF for one specific object (such as an order, or invoice, identified using it's entity_id):

// $entity - Can be a repository or just the entity, for example "order" or "invoice"
// $sourceId - Can be the entity_id of the object or an actual object such as an order/invoice/product
// $templateId - Provide PDF Template ID to generate or provide non and have the extension pick the default template
$pdf = $this->objectManager->create('\Xtento\PdfCustomizer\Helper\GeneratePdf')->generatePdfForObject($entity, $sourceId, $templateId);

Unable to load theme by specified key:

Your database/configuration is broken. In the core_config_data table, an entry for "design/theme/theme_id" is missing for your store(s). The theme ID can be found as following: vendor/magento/framework/View/Design/Theme/FlyweightFactory.php, look for: throw new \LogicException("Unable to load theme by specified key: '{$themeKey}'"); BEFORE this line add: var_dump(array_shift($this->themes)->getThemeId());

Empty email body / broken emails

Emails such as the new order email are "empty", meaning, there is the email subject, but the body is empty. This is caused by a misbuilt "attachment" feature of certain email extensions, we are aware of several extensions doing this:
- MageSuite_EmailAttachments: They change how the "Magento\Framework\Mail\Message" works and add their "$this->parts" array which is not compatible with other extensions that want to add attachments. Disable this extension.
- MagePlaza_EmailAttachments: Issue unknown but they also tamper with email parts. Any extension adding attachments would fail, just like ours do. Disable this extension. is empty

If the current order/invoice/... is a guest order, this field will be empty, because no customer exists then. Better to use order.customer_email which is always populated as it comes from the order directly.

Product item variable for product variables are empty

Example, you want to access the color of a product, and use the field "order_item_product.color" to do so. That field accesses the product that was ordered. If the product was deleted in the meantime, the attribute value cannot be retrieved. Or this is a child/parent item, then use "child_order_item_product.color" or "parent_order_item_product.color"

Crash / White Page

Possible reasons:

Doesn't help? Enable display_errors and set error_reporting to E_ALL and see what's the exact error.

"Old" PDFs (from testing store) are printed instead of "new" orders after going live

This only applies if you enabled "Read PDF from backup folder" in your PDF template.

The module internally keeps track of printed items (orders/invoices/shipments/credit memos) if you enable the "Save PDF in backup folder" feature in your PDF template. This, especially when "Read PDF from backup folder" is enabled as well, can lead to issues when you switch from "testing" to "live". Because the "Read PDF from backup folder" makes sure that PDFs never change, i.e., once an order has been printed, it will ALWAYS show the originally created PDF for that order, in that case, with old customers data from your testing store.

Now, when going live and deleting your test orders, the entity_id of orders is reset to 1 again, which makes sense. But if you remember, you also printed (some) test orders using our module, for example the entity_ids 101, 102, and 103. So now when the entity_id on your live site reaches 101, our module thinks these orders *have* been printed already, and the module returns the "old" testing PDFs. (Which is okay - it can't know you deleted orders)

To fix this, open the var/xtento_pdf/ folder and delete all the PDFs you find in there. You'll be fine then.

Remember: Whenever you delete orders/invoices/shipments/credit memos, and the entity_id is reset (often when deleting test orders for example), be sure to wipe out the PDFs in the var/xtento_pdf folder as well.

Outputting a page break / forcing a new page

This is pretty simple. In your template, insert:


See here for more details and variants:

Changing the billing/shipping address layout

The layout/fields of the billing/shipping address output in your PDFs can be updated here: Stores > Configuration > Customers > Customer Configuration > Address Templates > PDF

Checkout success page: Print receipt link

Want your custom PDF to be printed if a customer clicks the "Print receipt" link on the checkout success page? Open your template: app\code\Magento\Checkout\view\frontend\templates\button.phtml (in your theme folder)

At the top of the file add:

$printUrl = $block->getPrintUrl();
$orderEntityId = substr($printUrl, strpos($printUrl, 'order_id/') + 9);
if (strpos($orderEntityId, '/') !== false) {
    $orderEntityId = substr($orderEntityId, 0, strpos($orderEntityId, '/'));

Then, look for:


Replace with:

$block->getUrl('xtento_pdf/pdfPrint/sales', ['template_id' => null, 'order_id' => $orderEntityId, 'entity_id' => $orderEntityId])

Disable line wrapping (value/amount split on two lines)

If you see issues such as this in your PDF files, where the value in a table/cell is split across multiple lines:
Anmerkung 2019-11-10 200841.png
In the template CSS (tab "PDF Template"), add the following CSS option to the respective area in the td: white-space: nowrap;


.summary table tbody td.value { white-space: nowrap; background: #e5f6f2; color: #00ab84; border-top: 1px solid #00ab84; border-bottom: 1px solid #00ab84; }

Outputting prices without currency symbols

If you want prices to be output without a currency symbol for whatever reason, simply place this in the "Template HTML" somewhere:

<!-- hideCurrencySymbol=true -->

Very long words lead to text being very small

This happens in tables especially. Simply add the following style attribute to your table HTML element:


So for example, it could look like this (exact html attributes depend on your PDF template, just make sure to add the style attribute):

<table width="100%" borderspace="0" cellpadding="0" cellspacing="0" style="overflow:wrap;">

Outputting a page counter / page number

Put this into your footer or header (does not work in body) to output the current page# as well as the total number of pages (for the current document):

{{trans "Page"}}: {PAGENO} / {nb}

No/wrong PDF email attachments for invoice email

Don't see our (for example, invoice) PDF attached to your invoice email? Did you make sure that the "Attach to email" option is enabled at System > XTENTO > PDF Customizer? If yes, you may have a module installed in Magento which tries to attach attachments but shouldn't, such as the Mageplaza_EmailAttachments extension. You don't need it if you have our PDF Customizer extension, so disable it.

Certain barcodes are not displayed / fail to generate

This is probably because the value in the field you are trying to display as a barcode contains a character that is not supported by this barcode type. Try using a QR barcode instead if you have strange/special characters you need to represent. With c128a for example, you cannot use special characters such as umlauts, etc.

Background PDF functionality: Limitations

You can upload a PDF file in the PDF Template that will be used as the background of the document. However, this will be output on the first page only.

You can alternatively look into using an image as the page background:

Personal tools
General Information
Magento 2 Guides
Magento 2 Extensions
Magento 1 Guides
Magento 1 Extensions
Magento Integration Suite
Product Feed Guides