How to Create a Custom Invoice Template in Magento 2

Why Custom Invoice Templates Matter in Magento 2
If you're running a Magento 2 store, you know that invoices aren't just boring paperwork – they're part of your brand experience. The default invoice template gets the job done, but it looks... well, default. Creating a custom invoice template lets you:
- Match your brand colors and logo
- Add custom fields like PO numbers or special instructions
- Improve readability for your customers
- Include promotional messages or loyalty program details
The good news? Magento 2 makes this customization surprisingly straightforward once you know where to look. Let's walk through the process step by step.
Understanding Magento 2's Invoice Structure
Before we start coding, it helps to understand how Magento handles invoices:
- Layout files define the structure (XML)
- Templates handle the HTML/PHP rendering
- CSS styles control the appearance
All invoice-related files live in the vendor/magento/module-sales
module, but we'll create our own version in our theme to override the defaults.
Step 1: Create Your Custom Theme (If You Haven't Already)
First, make sure you have a custom theme set up. If you're already using one, skip to Step 2.
In your Magento installation:
app/design/frontend/<Vendor>/<Theme>/
├── registration.php
├── theme.xml
└── web/
├── css/
├── images/
└── js/
Your registration.php
should look like:
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::THEME,
'frontend/<Vendor>/<Theme>',
__DIR__
);
And theme.xml
:
<theme xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Config/etc/theme.xsd">
<title>Your Theme Name</title>
<parent>Magento/blank</parent>
</theme>
Step 2: Override the Invoice Template
Now we'll create our custom invoice template by copying and modifying the default one.
Create this directory structure in your theme:
app/design/frontend/<Vendor>/<Theme>/Magento_Sales/templates/order/email/invoice/
Copy the default items.phtml
file from:
vendor/magento/module-sales/view/frontend/templates/order/email/invoice/items.phtml
Paste it into your new directory. This is the file we'll modify to customize our invoice appearance.
Step 3: Customize the Invoice HTML
Open your copied items.phtml
file. Here's a simple example of how you might modify it:
<?php
/**
* Custom invoice template
*/
?>
<table class="email-items" style="width:100%; font-family: Arial, sans-serif;">
<thead>
<tr>
<th class="item-info" style="text-align:left; padding:10px; background:#f5f5f5;">
<?= $block->escapeHtml(__('Product')) ?>
</th>
<th class="item-qty" style="text-align:left; padding:10px; background:#f5f5f5;">
<?= $block->escapeHtml(__('Qty')) ?>
</th>
<th class="item-price" style="text-align:left; padding:10px; background:#f5f5f5;">
<?= $block->escapeHtml(__('Price')) ?>
</th>
</tr>
</thead>
<tbody>
<?php foreach ($_items as $_item): ?>
<?php if (!$_item->getOrderItem()->getParentItem()) : ?>
<tr>
<td class="item-info" style="padding:10px; border-bottom:1px solid #eee;">
<p class="product-name"><?= $block->escapeHtml($_item->getName()) ?></p>
<?php if ($_options = $block->getItemOptions($_item)): ?>
<dl class="item-options">
<?php foreach ($_options as $_option) : ?>
<dt><?= $block->escapeHtml($_option['label']) ?></dt>
<?php if (!$block->getPrintStatus()): ?>
<?php $_formatedOptionValue = $block->getFormatedOptionValue($_option) ?>
<dd>
<?php if (isset($_formatedOptionValue['full_view'])): ?>
<?= $_formatedOptionValue['full_view'] ?>
<?php else: ?>
<?= $_formatedOptionValue['value'] ?>
<?php endif; ?>
</dd>
<?php endif; ?>
<?php endforeach; ?>
</dl>
<?php endif; ?>
</td>
<td class="item-qty" style="padding:10px; border-bottom:1px solid #eee;">
<?= (float)$_item->getQty() ?>
</td>
<td class="item-price" style="padding:10px; border-bottom:1px solid #eee;">
<?= /* @noEscape */ $block->getItemPrice($_item) ?>
</td>
</tr>
<?php endif; ?>
<?php endforeach; ?>
</tbody>
<tfoot>
<?= $block->getChildHtml('invoice_totals') ?>
</tfoot>
</table>
Step 4: Customize the Invoice Layout
To make sure our template is used, we need to override the layout file. Create this file:
app/design/frontend/<Vendor>/<Theme>/Magento_Sales/layout/sales_email_order_invoice_items.xml
With this content:
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="items">
<action method="setTemplate">
<argument name="template" xsi:type="string">Magento_Sales::order/email/invoice/items.phtml</argument>
</action>
</referenceBlock>
</body>
</page>
Step 5: Add Custom CSS
For more advanced styling, create a custom CSS file at:
app/design/frontend/<Vendor>/<Theme>/web/css/source/_email-invoice.less
Add your styles there. For example:
.email-invoice {
.logo {
text-align: center;
margin-bottom: 20px;
img {
max-width: 200px;
}
}
.invoice-details {
background: #f9f9f9;
padding: 15px;
margin-bottom: 20px;
.invoice-title {
color: @primary__color;
font-size: 18px;
margin-bottom: 10px;
}
}
.order-details {
margin-bottom: 30px;
}
}
Step 6: Add Your Company Logo
To add your logo to invoices, go to:
- Admin Panel → Stores → Configuration
- Sales → Sales Emails
- Upload your logo under "Logo for HTML Email"
- Set the width to an appropriate size (usually 200px)
Step 7: Adding Custom Fields
Need to add custom fields like PO numbers or special instructions? Here's how:
First, create a plugin to add your custom data to the invoice email. Create this file:
app/code/<Vendor>/<Module>/Plugin/Sales/Order/Invoice.php
With this content:
<?php
namespace <Vendor>\<Module>\Plugin\Sales\Order;
class Invoice
{
public function beforeGetEmailCustomVariables(
\Magento\Sales\Model\Order\Invoice $subject,
$result
) {
$order = $subject->getOrder();
// Add your custom data here
$result['custom_field'] = $order->getData('your_custom_field');
return [$result];
}
}
Then reference this data in your template:
<?php if (isset($custom_field) && $custom_field): ?>
<div class="custom-field">
<strong><?= __('Custom Field') ?>:</strong>
<span><?= $custom_field ?></span>
</div>
<?php endif; ?>
Step 8: Testing Your Custom Invoice
After making all these changes, it's crucial to test:
- Create a test order
- Generate an invoice for it
- Send the invoice email to yourself
- Check both HTML and plain text versions
To manually trigger an invoice email from the admin:
- Go to Sales → Invoices
- Find your test invoice
- Click "Send Email"
Advanced Customization: PDF Invoices
If you want your customizations to also appear on PDF invoices, you'll need to override the PDF renderer. Create this file:
app/code/<Vendor>/<Module>/Model/Order/Pdf/Invoice.php
Extend the core class and override the methods you need. The most important one is getPdf()
which generates the PDF content.
Common Issues and Troubleshooting
Problem: Changes aren't appearing
Solution: Clear cache and static content: php bin/magento cache:flush
and php bin/magento setup:static-content:deploy
Problem: Emails not sending
Solution: Check your email configuration under Stores → Configuration → Sales → Sales Emails
Problem: Layout breaks in email clients
Solution: Stick to simple table-based layouts and inline CSS for maximum compatibility
Final Thoughts
Customizing your Magento 2 invoice templates is a great way to reinforce your brand and improve customer experience. While the process might seem technical at first, breaking it down into these steps makes it manageable.
Remember that invoices are legal documents, so always include all required information. Beyond that, let your brand personality shine through!
Need more advanced customizations? Check out our Magento 2 extensions that can help streamline your invoicing process even further.