Developed by CoolTRONIC.pl sp. z o.o. and Pawel Potacki, this plugin allows you to create PDF files from Craft CMS entries using a Twig template. It supports the creation and download of multiple PDF files from entries within a specific channel section on a website running Craft CMS 3 or 4. Example implementations can be found within this README file.
Please note that MPDF for PHP8.x and Craft 4 may require a GD extension.
- Installation
- Usage
pdf
method Parameters- Parameters
pdfAsset
method - Securely Displaying PDF Documents in the Browser Without Saving to the /web Folder
- Variables within a Template
- Overriding Default Options
- Custom fonts
- Return values
- Loop example
- Twig template example
- Adding PDFs to Assets
- Advanced
pdfAsset
Method Options - Including Images in PDF
- Thumbnail of Generated PDF on Frontend
- Generating on backend and Displaying Thumbnails by PDF Generator by
assetThumb
option to add into Assets onpdfAsset
method - Generating on backend and Displaying Dumb Thumbnails by PDF Generator by
dumbThumb
option to defaultpdf
method - Generating on backend and Displaying Thumbnails of PDF Assets by external PDF Transform plugin
- What if I cannot generate Thumbnails with enabled ImageMagick?
- Custom Title of PDF Document
- Custom Variables
- Custom Page Break in PDF Document
- Page and Total Page Numbers
- Generate PDF File Only When Entry Data is Changed
- Filename Characters
- Browser Caching Issues of PDF Files on Some Servers and Hosting
- Downloading Multiple PDF Files with JavaScript on Any Page
- RTL Text Direction
- Add Watermark
- Generate PDF Table of Contents
- Generate PDF Bookmarks
- Requirements
- Support
- Credits
- License
You can install the PDF Generator plugin from the Craft Plugin Store or through Composer.
Go to the Craft CMS Plugin Store in your project’s Control Panel and search for "PDF Generator". Then click on the "Install" button in its modal window.
Open your terminal and go to your Craft project:
cd /path/to/project
Then tell Composer to require the plugin:
composer require cooltronic/document-helper
The pdf method generates a PDF file from a Twig template and returns a URL to the file. The method accepts an array of parameters:
-
template
- This is the location of the template file for the PDF, which should be located in the /templates directory. -
destination
- This indicates where the PDF file will be generated. It can be one of four options:file
,inline
,download
, orstring
. To download multiple files, refer to the JavaScript example provided in the README.md file. -
filename
- This is the name of the generated PDF file. -
entry
- This represents the data that will be inputted into the template to generate the PDF. This data is contained within an 'entry' array. -
pdfOptions
- This parameter allows you to customize the generation of the PDF. The available options are described in the section on overriding default options.
Method returns string with filename for anchors or string content for PDF files to send content as attachment.
{{craft.documentHelper.pdf("template.twig", "file", "document.pdf", entry, pdfOptions)}}
<a href="{{alias('@web')}}/
{{craft.documentHelper.pdf("_pdf/document.twig", "file", 'pdf/' ~ entry.id ~ '.pdf', entry, pdfOptions)}}"
download>
</a>
The pdfAsset
method generates a PDF file from a Twig template, saves it as an asset, and returns an Asset model. The method accepts an array of parameters:
-
template
- This is the location of the template file for the PDF, which should be located in the /templates directory. -
filename
- This is the name of temporary or / and final of generated PDF file. -
entry
- This represents the data that will be inputted into the template to generate the PDF. This data is contained within an 'entry' array. -
pdfOptions
- This parameter allows you to customize the generation of the PDF. The available options are described in the section on overriding default options. -
volumeHandle
- This parameter should contains volume handle name on which we need to add PDF as Craft CMS asset from system. The volume handle must have aBase URL
in your test:@web\pdffiles
in Craft CMS Filesystems, Assets settings.
{% set asset = craft.documentHelper.pdfAsset('_pdf/document.twig', alias('@root')~'/example.pdf', entry, pdfOptions, 'pdffiles') %}
{% if asset %}
<a href="{{asset.url()}}?v={{asset.dateModified|date('U')}}">Download your PDF</a>
{% else %}
File was not generated.
{% endif %}
You can securely display PDF documents in the browser without saving them to the /web folder as follows:
{% set pdfOptions = {
date: entry.dateUpdated|date('U'),
header: "_pdf/header.twig",
footer: "_pdf/footer.twig"
} %}
{% header "Content-Type: application/pdf" %}
{{craft.documentHelper.pdf('_pdf/document.twig', 'inline', '../book_example' ~ '.pdf', entry, pdfOptions)}}
Within the PDF Twig template, you can access the passed entry
in a generated twig template array:
{{entry.VAR}}
The title of the current entry can be accessed via:
{{title}}
You can override the default options with pdfOptions
as shown above. Here are the available options:
date
- This is disabled by default. If you provide a date (in timestamp format) that is older than the creation date of the file, the existing file will be overwritten.header
- This is the header Twig template, which is disabled by default.footer
- This is the footer Twig template, also disabled by default.margin_top
- The top margin defaults to 30.margin_bottom
- The bottom margin defaults to 30.margin_left
- The left margin defaults to 15.margin_right
- The right margin defaults to 15.mirrorMargins
- This defaults to 0 but can be set to 1.pageNumbers
- This adds page numbers in the footer.title
- This replaces the default title of the generated PDF document.custom
- This allows you to add custom variable or variables.password
- This can be used to add password protection to your PDF. The password should be provided as a string.no_auto_page_break
- This disables automatic system page breaks. This can be useful if you need to manually add page breaks. For example, you can add a custom page to documents with more than one page break using . This may fix page break issues in some cases, but not all.author
- This sets the author metadata. It should be provided as a string.keywords
- This sets the keyword metadata. It should be provided as a string in the following format: "keyword1, longer keyword2, keyword3".fonts
:fontdata
, andfontDir
- These allow you to set custom fonts described above.
tempDir
- This sets the path to the temporary directory used for generating PDFs. We have tested this with the main /tmp directory on the server with success. This could potentially improve performance when generating multiple PDFs.landscape
- If this is set, the PDF will be generated in landscape mode.portrait
- If this is set, the PDF will be generated in portrait mode.format
This sets the paper size for the PDF. The default is "A4", but you can set other sizes compatible with MPDF. Other popular formats include:- A3
- A4 (default)
- A5
- Letter (8,5 x 11 in)
- Legal (8,5 x 14 in)
- Executive (7,25 x 10,5 in)
- B4
- B5
watermarkImage
- This option creates a watermark using the image file specified by the provided path.watermarkText
- This option creates a watermark using the text provided.autoToC
- This option automatically generates a Table of Contents using the H1-H6 tags in your document.autoBookmarks
- This option automatically generates bookmarks using the H1-H6 tags in your document.assetTitle
- This option allows you to set a custom title for the Asset in the Craft CMS system when using thepdfAsset
method.assetFilename
- This option allows you to change the target filename of the file in the Craft CMS Asset when using thepdfAsset
method.assetDelete
- This option enables the deletion of the internally generated file in the@root
path. Please note that this operation is irreversible and may consume more resources. This is because the Asset is updated and the PDF is generated on every load when using thepdfAsset
method.assetSiteId
- This option allows you to assign a customsiteId
to the Asset ofpdfAsset
method. ThesiteId
should be passed as a number, representing the ID of the site to which the generated asset should belong.assetThumb
: This option generates a thumbnail image of a Craft CMS image Asset using thepdfAsset
method (requires ImageMagick). It can be accessed in the Twig template asasset.assetThumb
.assetThumbVolumeHandle
: This is an optional parameter that specifies the Volume Handle for the thumbnail. If not provided, the PDF Volume Handle is used. The volume handle must have aBase URL
in your test:@web\pdffiles
in Craft CMS Filesystems, Assets settings.
dumbThumb
: This option generates a basic thumbnail image (without an Asset) using thepdf
method (requires ImageMagick).
Both assetThumb
and dumbThumb
support the following optional customizations:
thumbType
: This parameter allows you to choose the format of the thumbnail. Options includejpg
,gif
,webp
,avif
, andpng
. The default format isjpg
.thumbWidth
: This parameter specifies the width of the thumbnail in pixels. The default width is210
.thumbHeight
: This parameter specifies the height of the thumbnail in pixels. The default height is297
.thumbPage
: This parameter specifies the page to generate the thumbnail from. The default is the first page, which is numbered from0
.thumbBgColor
: This parameter specifies the background color of the thumbnail. Options includeblack
,rgb(33,66,99)
, and#123456
. The default color iswhite
.thumbTrim
: This parameter, when set totrue
, trims your page and centers the content. The default value isfalse
.thumbTrimFrameColor
: This parameter changes the color of the trim frame. Colors can be specified asblack
or in RGB format (e.g.,rgb(12,1,2)
) or in HEX format (e.g.,#662266
).
This is an example of how to use custom fonts, specifically Roboto-Regular.ttf
and Roboto-Italic.ttf
, which should be placed in the config folder:
fontdata: { 'roboto' : {
'R' : 'Roboto-Regular.ttf',
'I' : 'Roboto-Italic.ttf'
}},
fontDir: "{{craft.app.path.configPath}}/",
After the update of MPDF, which is used by our PDF Generator, we have resolved an issue with passed paths. Now, you must provide an absolute path on the server to the config directory. Alternatively, you can pass the main folder. For instance, on ISP Config 3.2 host, you can use: fontDir
: /var/www/clients/client0/web21/private/config/
.
If you're running a single site, it should be an absolute path to the /config
folder, like: fontDir: /path_to/config/
.
For XAMPP in Windows hosts, the confirmed format is working fontDir
: file:///C:/xampp/htdocs/craft4/config/
.
- If the destination is
inline
orstring
, the plugin returns a string. - If the destination is
download
orfile
, it returns the filename in the /web folder. - If an error occurs during the PDF generation, the methods will return
false
.
You can generate multiple PDF files in a loop. For example, you can generate a PDF file for each entry in a section:
{% for item in craft.entries.section('xxx').orderBy('title asc').all() %}
{% set pdfOptions = {
date: entry.dateUpdated|date('U'),
} %}
<a href="
{{alias('@web')}}/
{{craft.documentHelper.pdf("_pdf/document.twig", "file", 'pdf/' ~ item.id ~ '.pdf' ,item, pdfOptions)}}
" download>
DOWNLOAD {{item.title}}
</a>
{% endfor %}
Here is an example of a Twig template that can be used to generate a PDF document:
<!DOCTYPE html>
<html>
<head>
<title>{{ entry.title }}</title>
<style>
body {
font-family: 'DejaVu Sans', sans-serif;
}
</style>
</head>
<body>
<h1>{{ entry.title }}</h1>
<p>{{ entry.variable }}</p>
</body>
</html>
...
You can add generated PDF files to your Craft assets. To do this you need to specify the filename using the @root
path. The following example demonstrates its usage with a volume that has the handle pdffiles
:
{% set pdfOptions = { date: entry.dateUpdated|date('U') } %}
{% set asset = craft.documentHelper.pdfAsset('_pdf/document.twig', alias('@root')~'/example.pdf', entry, pdfOptions, 'pdffiles') %}
{% if asset %}
<a href="{{asset.url()}}?v={{asset.dateModified|date('U')}}">Download PDF</a>
{% else %}
File was not generated.
{% endif %}
In this example, a timestamp is added to the file URL to ensure the file is refreshed when it changes, beneficial for various caching solutions like Varnish Cache & Preload, Blitz, or CDNs like Cloudflare.
By default, the title of the PDF is based on the filename. However, you can override this along with other settings using pdfOptions:
{% set pdfOptions = {
...
assetTitle: "My Awesome Title",
assetFilename: "MyAwesome_Filename.pdf",
assetDelete: true,
assetSiteId: 2,
}
%}
In this example:
- assetTitle sets a custom title.
- assetFilename sets a custom filename.
- assetDelete when set to true, the file in @root path is deleted and regenerated every time this code runs.
- assetSiteId sets the site ID of the generated PDF to site with 2 id. You can also use string variables for assetTitle and assetFilename, such as the entry title:
{% set pdfOptions = {
...
assetTitle: entry.title,
assetFilename: entry.title~".pdf",
}
%}
These options give you greater flexibility in customizing the generated PDF assets.
There are two ways to include images in the PDF template.
If you're using the Image Toolbox plugin, you can include images like this:
{% set image = entry.photoFromCMS.one() %}
{% set transformSettings = {
width: 100,
height: 200,
mode: 'stretch'
} %}
{% set options = {
class: '',
alt: '',
} %}
...
{{craft.images.picture(image, transformSettings, options)}}
You can also include an image in a PDF document without a plugin, like this:
{% set image = entry.photoFromCMS.first() %}
{% if image is not null %}
<img src="{{image.url}}" alt="">
{% endif %}
You can use PDF Thumbnails by @scandel for client-side generation of PDF thumbnails. This requires the files pdfThumbnails.js, pdf.js, and pdf.worker.js to be loaded in the /web folder. The pdf.js and pdf.worker.js files from PDF.js can be found here.
Here's an example:
<script src="{{alias('@web')}}/pdfThumbnails.js" data-pdfjs-src="{{alias('@web')}}/pdf_js/build/"></script>
<script src="{{alias('@web')}}/pdf_js/build/pdf.js"></script>
<script src="{{alias('@web')}}/pdf_js/build/pdf.worker.js"></script>
{% header "Cache-Control: no-cache" %}
<a href="{{alias('@web')}}{{version("/" ~ craft.documentHelper.pdf('_pdf/document.twig', 'file', 'pdf/example.pdf' , entry, pdfOptions))}}">
<img class="img-responsive" data-pdf-thumbnail-file="{{alias('@web')}}/pdf/example.pdf" src="{{alias('@web')}}/pdfjs_placeholder.png">
Generating on backend and Displaying Thumbnails by PDF Generator by assetThumb
option to add into Assets on pdfAsset
method
To display Image Thumbnail added into Craft CMS Twig template you may use following options:
{% set pdfOptionsAsset = {
assetThumb: true
}
%}
{% set asset = craft.documentHelper.pdfAsset('_pdf/document.twig', alias('@root')~'/test.pdf', entry, pdfOptionsAsset, 'pdfFiles') %}
{% if asset %}
{% set assetThumb = asset.assetThumb %}
<a href="{{asset.url()}}?v={{asset.dateModified|date('U')}}">
{% if assetThumb %}
<img src="{{ assetThumb.url() }}?v={{ assetThumb.dateModified|date('U') }}" />
{% else %}
Thumbnail is not available
{% endif %}
</a>
{% else %}
If you want add image into another Volume than PDF file you may override PDF options with option assetThumbVolumeHandle
, in this example this will be set into pdfimages
volume handle:
{% set pdfOptionsAsset = {
assetThumb: true,
assetThumbVolumeHandle: "pdfimages"
}
%}
Generating on backend and Displaying Dumb Thumbnails by PDF Generator by dumbThumb
option to default pdf
method
To add thumbnails generated with old pdf
method you may use following code:
{% set pdfOptionsDumb = {
date: entry.dateUpdated|date('U'),
dumbThumb: true,
}
%}
<a href="{{alias('@web')}}/{{craft.documentHelper.pdf('_pdf/document.twig', 'file', 'pdf/example.pdf' , entry, pdfOptionsDumb)}}">
<img src="{{alias('@web')}}{{ '/pdf/example.jpg' }}" />
</a>
To generate an image thumbnail of a PDF asset, you can use the PDF Transform plugin. Please note, this feature requires ImageMagick.
Here's an example of how to generate and display a thumbnail:
{% set pdfOptions = { date: entry.dateUpdated|date('U') } %}
{% set asset = craft.documentHelper.pdfAsset('_pdf/document.twig', alias('@root')~'/example.pdf', entry, pdfOptions, 'pdffiles') %}
{% if asset %}
<a href="{{asset.url()}}?v={{asset.dateModified|date('U')}}">
{% set transformedPdf = craft.pdfTransform.render(asset) %}
<img src="{{ transformedPdf.url }}?v={{transformedPdf.dateModified|date('U')}}" />
</a>
{% endif %}
If you encounter the following error with PDF Transform:
attempt to perform an operation not allowed by the security policy `PDF' @ error/constitute.c/IsCoderAuthorized/421
On our plugin error is in your Craft CMS in /runtime/logs/web.log
and image is not generated in pdf
or pdfAsset
:
Imagick Error: attempt to perform an operation not allowed by the security policy `PDF' @ error/constitute.c/IsCoderAuthorized/421
This means ImageMagick's security policy is preventing operations on PDF files. To fix this, you'll need to modify the policy.xml file located at /etc/ImageMagick-6/policy.xml
or /etc/ImageMagick-7/policy.xml
, depending on your ImageMagick version.
Find and modify the policy related to PDFs to allow the desired operation. Be cautious, as changing this file can have security implications. Make sure you understand the risks and consequences. Here's an example of how to change a policy from disallowing all operations to allowing read and write operations:
<!-- Before -->
<policymap>
<policymap domain="coder" rights="none" pattern="PDF" />
</policymap>
<!-- After -->
<policymap>
<policymap domain="coder" rights="read | write" pattern="PDF" />
</policymap>
Then restart your PHP FPM service if you are using. If you're unsure about modifying this file, consider reaching out to your hosting provider's support team for assistance.
To set a custom title for your PDF, use the title
option in the pdfOptions
as follows:
{% set pdfOptions = {
...,
title: "My awesome Title"
} %}
You can use custom
variables in your Twig template. To do this, add an associative array or variable to the custom
parameter in the pdfOptions array. The keys of this array or passed variable will be available as variables in your Twig template.
To pass a string or number to the PDF template, set it as a custom
variable in the pdfOptions
:
{% set pdfOptions = {
...,
custom: variable
} %}
Then, in your PDF template, you can call upon this custom variable:
{{custom}}
If you want to pass an array to the PDF template, define the array in the custom
variable in the pdfOptions
:
{% set pdfOptions = {
...,
custom: {
slug: entry.slug,
created: entry.dateCreated,
...
}
} %}
You can then access the array variables in your PDF template:
{{custom.slug}}
{{custom.created.format('d/m/Y')}}
You can add a page break in your PDF document by using the <pagebreak>
tag in your Twig template.
<p>Content before the page break.</p>
<pagebreak />
<p>Content after the page break.</p>
You can add page numbers and the total number of pages to your PDF document by using the {PAGENO}
and {nbpg}
placeholders in your Twig template, header or footer.
<p>Page {PAGENO} of {nbpg}</p>
You can set the PDF Generator plugin to only generate a new PDF file when the data of an entry is changed. To do this, use the following pdfOptions
to ensure that a PDF is only generated when the data in an entry has been updated:
{% set pdfOptions = {
date: entry.dateUpdated|date('U'),
} %}
The filename of the generated PDF file can only contain alphanumeric characters, underscores, and hyphens. When selecting a filename for your PDF, ensure that you only use safe characters. The following characters are not allowed in Windows filenames: ":", "/", "?", "|", "<", ">" or "/".
Some servers and hosting environments may cache PDF files, which can cause issues when you're trying to view the latest version of a generated PDF file. To prevent this, you can add a unique query string to the URL of the PDF file.
If you are experiencing issues with your server or hosting caching PDF files, you can use the Static Files Autoversioning plugin. This plugin adds a timestamp to your PDF, helping to avoid caching issues.
<a href="{{alias('@web')}}{{version("/" ~ craft.documentHelper.pdf('_pdf/document.twig', 'file', 'pdf/book' ~ '.pdf' ,entry, pdfOptions))}}">LINK </a>
With this plugin, your PDF will have a timestamp and any caching policy problems with your hosting will be resolved. The following is an example of what the PDF link will look like:
<a href="http://some-domain.com/pdf/book.pdf?v=1668157143">LINK </a>
You can download multiple PDF files with JavaScript on any page. To do this, you can use this example with pdf
method to specify entries for which you want to generate PDF files.
<script>
{% set pdfOptions = {
date: entry.dateUpdated|date('U')
} %}
var files = [
"{{ alias('@web') }}/{{craft.documentHelper.pdf('_pdf/document.twig', 'file', 'pdf/' ~ entry.dateCreated|date('Y-m-d') ~ random(10) ~ '.pdf', entry, pdfOptions)}}",
"{{ alias('@web') }}/{{craft.documentHelper.pdf('_pdf/document.twig', 'file', 'pdf/' ~ entry.dateCreated|date('Y-m-d') ~ random(10) ~ '.pdf', entry, pdfOptions)}}"
];
for (var i = files.length - 1; i >= 0; i--) {
var a = document.createElement("a");
a.target = "_blank";
a.download = "download";
a.href = files[i];
a.click();
};
</script>
Example with a loop on channel section xxx
for items on array:
{% set pdfOptions = {
date: entry.dateUpdated|date('U')
} %}
<script>
var files = [
{% for item in craft.entries.section('xxx').orderBy('title asc').all() %}
"{{alias('@web')}}/{{craft.documentHelper.pdf('_pdf/document.twig', 'file', 'pdf/' ~ item.id ~ '.pdf', item, pdfOptions)}}"
{% if loop.last %}{% else %}, {% endif %}
{% endfor %}
];
for (var i = files.length - 1; i >= 0; i--) {
var a = document.createElement("a");
a.target = "_blank";
a.download = "download";
a.href = files[i];
a.click();
};
</script>
You can download multiple PDF files with JavaScript on any page. To do this, you can use the pdfs
parameter looped through pdfAsset
method to specify an array of entries, in this example items of channel section xxx
for which you want to generate PDF files.
{% set pdfs = [] %}
{% for item in craft.entries.section('xxx').orderBy('title asc').all() %}
{% set pdf = craft.documentHelper.pdfAsset('_pdf/document.twig', 'file', 'pdf/' ~ item.id ~ '.pdf', item, pdfOptions) %}
{% set pdfs = pdfs|merge([pdf]) %}
{% endfor %}
In your JavaScript code pass pdfs
from Craft CMS, you can then loop over the passed pdfs
array and trigger the download of each PDF file.
<script>
var pdfs = JSON.parse('{{ pdfs|json_encode|raw }}');
pdfs.forEach(function(pdf) {
window.open(pdf.url, '_blank');
});
</script>
he PDF Generator plugin supports right-to-left (RTL) text direction. To enable RTL text direction set HTML dir
attribute in your HTML Twig template markup. For example:
<div dir="rtl">This is some text in a right-to-left language.</div>
To specify a language in mPDF, you can use the lang
attribute in your HTML. For example:
<div lang="ar">هذا نص باللغة العربية</div>
In order for mPDF to display the correct characters, you'll also need to use a font that supports the characters of the language you're using. mPDF comes with several fonts that support a wide range of characters. You can set the font using the CSS font-family property. For example, to use the Arial
font:
div {
font-family: 'Arial';
}
Full example on arabic text:
<div dir="rtl" lang="ar" style="font-family: Arial;">هذا نص باللغة العربية</div>
Watermarks can be added to your PDFs using mPDF parameters. This can be either in the form of an image or text.
You can include a PNG or JPG image as a watermark in your PDF. Specify the path and file extension of your image in the watermarkImage
parameter.
For example:
{% set pdfOptions = {
'watermarkImage': 'path/to/your/image.ext'
} %}
Replace path/to/your/image.ext
with the actual path and file extension of your image.
You can also add a text watermark to your PDF. Simply specify your desired text in the watermarkText
parameter.
For example:
{% set pdfOptions = {
'watermarkText': 'My text watermark example'
} %}
Replace 'My text watermark example' with the actual text you want to use as a watermark.
You have the ability to create your own Table of Contents as per the guidelines in the mPDF ToC documentantion.
Additionally, we can enable automatic generation of a Table of Contents from H1-H6 tags present in your PDF document. You can activate this feature by setting the autoToC
option to true.
For instance:
{% set pdfOptions = {
'autoToC': true
} %}
Manually adding bookmarks can be done with the bookmark tag <bookmark content="Text" />
. The content attribute is used to set the text of the bookmark. You can also use the optional level
attribute to set the nesting level of the bookmark.
Additionally, we can enable automatic generation of a Bookmarks from H1-H6 tags present in your PDF document. You can activate this feature by setting the autoBookmarks
option to true. For do that set:
{% set pdfOptions = {
'autoBookmarks': true
} %}
Craft CMS >= 3.0.0 for 0.x branch Craft CMS >= 4.0.0 for 1.x branch
For inquiries regarding custom PDF work, such as generating templates or modifying plugins, please reach out to us via our contact page.
Special thanks to the developers and testers who have contributed to this project and helped identify and fix bugs:
This project is licensed under the Craft License. See the LICENSE.md file for details.