Product support

Visit this product's website for support.


Dynamic PDF Plugin

Demo URL: https://october-demo.renatio.com/backend/backend/auth/signin

Login: dynamicpdf

Password: dynamicpdf

This plugin allows developers to create and edit PDF templates with a simple user interface.

HTML to PDF converter uses dompdf library.

Plugin uses dompdf wrapper for Laravel barryvdh/laravel-dompdf.

Like this plugin?

If you like this plugin, give this plugin a Like or Make donation with PayPal.

My other plugins

Please check my other plugins.


Please use GitHub Issues Page to report any issues with plugin.

Reviews should not be used for getting support or reporting bugs, if you need support please use the Plugin support link.

Icon made by Darius Dan from www.flaticon.com.

PDF Templates list


There are couple ways to install this plugin.

  1. Use php artisan plugin:install Renatio.DynamicPDF command.
  2. Use composer require renatio/dynamicpdf-plugin in project root. When you use this option you must run php artisan october:migrate after installation.

PDF content

PDF can be created in October using either PDF views or PDF templates. A PDF view is supplied by plugin in the file system in the /views directory. Whereas a PDF template is managed using the back-end interface via Settings > PDF > PDF Templates. All PDFs templates support using Twig for markup.

PDF views must be registered in the Plugin registration file with the registerPDFTemplates and registerPDFLayouts method. This will automatically generate a PDF template and layout and allows them to be customized using the back-end interface.

PDF layouts views

PDF layouts views reside in the file system and the code used represents the path to the view file. For example PDF layout with the code author.plugin::pdf.layouts.default would use the content in following file:

plugins/                 <=== Plugins directory
  author/                <=== "author" segment
    plugin/              <=== "plugin" segment
      views/             <=== View directory
        pdf/             <=== "pdf" segment
          layouts/       <=== "layouts" segment
            default.htm  <=== "default" segment

The content inside a PDF view file can include up to 3 sections: configuration, CSS/LESS, and HTML markup. Sections are separated with the == sequence. For example:

name = "Default PDF layout"
body {
    font-size: 16px;
<!DOCTYPE html>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <style type="text/css" media="screen">
            {{ css|raw }}
        {{ content_html|raw }}

Note: Basic Twig tags and expressions are supported in PDF views.

The CSS/LESS section is optional and a view can contain only the configuration and HTML markup sections.

name = "Default PDF layout"
<!DOCTYPE html>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <style type="text/css" media="screen">
            {{ css|raw }}
        {{ content_html|raw }}

Configuration section

The configuration section sets the PDF view parameters. The following configuration parameters are supported:

Parameter Description
name the layout name, required.

Using PDF layouts

PDF layouts reside in the database and can be created by selecting Settings > PDF > PDF Templates and clicking the Layouts tab. These behave just like CMS layouts, they contain the scaffold for the PDF. PDF views and templates support the use of PDF layouts. The code specified in the layout is a unique identifier and cannot be changed once created.

PDF templates views

PDF templates reside in the file system and the code used represents the path to the view file. For example PDF template with the code author.plugin::pdf.invoice would use the content in following file:

plugins/                 <=== Plugins directory
  author/                <=== "author" segment
    plugin/              <=== "plugin" segment
      views/             <=== View directory
        pdf/             <=== "pdf" segment
          invoice.htm    <=== "invoice" segment

The content inside a PDF view file can include up to 2 sections: configuration and HTML markup. Sections are separated with the == sequence. For example:

title = "Invoice"
layout = "renatio.demo::pdf.layouts.default"
description = "Invoice template"
size = "a4"
orientation = "portrait"

Note: Basic Twig tags and expressions are supported in PDF views.

Configuration section

The configuration section sets the PDF view parameters. The following configuration parameters are supported:

Parameter Description
title the template title, required.
layout the layout code, optional.
description the template description, optional.
size the template paper size, optional, default a4.
orientation the template paper orientation, optional, default portrait.

Using PDF templates

PDF templates reside in the database and can be created in the back-end area via Settings > PDF > PDF Templates. The code specified in the template is a unique identifier and cannot be changed once created.

Note: If the PDF template does not exist in the system, this code will attempt to find a PDF view with the same code.

Registering PDF templates and layouts

PDF views can be registered as templates that are automatically generated in the back-end ready for customization. PDF templates can be customized via the Settings > PDF Templates menu. The templates can be registered by adding the registerPDFTemplates method of the Plugin registration class (Plugin.php).

public function registerPDFTemplates()
    return [

The method should return an array of pdf view names.

Like templates, PDF layouts can be registered by adding the registerPDFLayouts method of the Plugin registration class (Plugin.php).

public function registerPDFLayouts()
    return [

The method should return an array of pdf view names.


PDF templates and layouts can be accessed in the back-end area via Settings > PDF > PDF Templates.

Layouts define the PDF scaffold, that is everything that repeats on a PDF, such as a header and footer. Each layout has unique code, optional background image, HTML content and CSS/LESS content. Not all CSS properties are supported, so check CSSCompatibility.

Templates define the actual PDF content parsed from HTML.


The default configuration settings are set in config/dompdf.php. Copy this file to your own config directory to modify the values. You can publish the config using this command:

php artisan vendor:publish --provider="Barryvdh\DomPDF\ServiceProvider"

You can still alter the dompdf options in your code before generating the PDF using dynamic methods for all options like so:


or you can use setOption method before generating the pdf using this command:

    ->setOption(['dpi' => 300, 'defaultFont' => 'sans-serif'])

Available options and their defaults:

  • rootDir: "{app_directory}/vendor/dompdf/dompdf"
  • tempDir: "/tmp" (available in config/dompdf.php)
  • fontDir: "{appdirectory}/storage/fonts/" (available in config/dompdf.php)_
  • fontCache: "{appdirectory}/storage/fonts/" (available in config/dompdf.php)_
  • chroot: "{appdirectory}" (available in config/dompdf.php)_
  • logOutputFile: "/tmp/log.htm"
  • defaultMediaType: "screen" (available in config/dompdf.php)
  • defaultPaperSize: "a4" (available in config/dompdf.php)
  • defaultFont: "serif" (available in config/dompdf.php)
  • dpi: 96 (available in config/dompdf.php)
  • fontHeightRatio: 1.1 (available in config/dompdf.php)
  • isPhpEnabled: false (available in config/dompdf.php)
  • isRemoteEnabled: true (available in config/dompdf.php)
  • isJavascriptEnabled: true (available in config/dompdf.php)
  • isHtml5ParserEnabled: false (available in config/dompdf.php)
  • isFontSubsettingEnabled: false (available in config/dompdf.php)
  • debugPng: false
  • debugKeepTemp: false
  • debugCss: false
  • debugLayout: false
  • debugLayoutLines: true
  • debugLayoutBlocks: true
  • debugLayoutInline: true
  • debugLayoutPaddingBox: true
  • pdfBackend: "CPDF" (available in config/dompdf.php)
  • pdflibLicense: ""
  • adminUsername: "user"
  • adminPassword: "password"

See Dompdf\Options for a list of available options.


Method Description
loadTemplate($code, array $data = [], $encoding = null) Load backend template
loadLayout($code, array $data = [], $encoding = null) Load backend layout
loadHTML($string, $encoding = null) Load HTML string
loadFile($file) Load HTML string from a file
parseTemplate(Template $template, array $data = []) Parse backend template using Twig
parseLayout(Layout $layout, array $mergeData = []) Parse backend layout using Twig
getDomPDF() Get the DomPDF instance
setPaper($paper, $orientation = 'portrait') Set the paper size and orientation (default A4/portrait)
setWarnings($warnings) Show or hide warnings
output() Output the PDF as a string
save($filename) Save the PDF to a file
download($filename = 'document.pdf') Make the PDF downloadable by the user
stream($filename = 'document.pdf') Return a response with the PDF to show in the browser

All methods are available through Facade class Renatio\DynamicPDF\Classes\PDF.


Background image

To display background image added in layout use following code:

<body style="background: url({{ background_img }}) top left no-repeat;">

Background image should be at least 96 DPI size (793 x 1121 px).

If you want to use better quality image like 300 DPI (2480 x 3508 px) than you need to change template options like so:

return PDF::loadTemplate($model->code)

UTF-8 support

In your layout, set the UTF-8 meta tag in head section:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

If you have problems with foreign characters than try to use DejaVu Sans font family.

Page breaks

You can use the CSS page-break-before/page-break-after properties to create a new page.

.page-break {
    page-break-after: always;
<h1>Page 1</h1>
<div class="page-break"></div>
<h1>Page 2</h1>

Open basedir restriction error

On some hosting providers there were reports about open_basedir restriction problems with log file. You can change default log file destination like so:

return PDF::loadTemplate('renatio::invoice')

Embed image inside PDF template

You can use absolute path for image eg. https://app.dev/path_to_your_image.

For this to work you must set isRemoteEnabled option.

return PDF::loadTemplate('renatio::invoice', ['file' => $file])

I assume that $file is instance of October\Rain\Database\Attach\File.

Then in the template you can use following example code:

{{ file.getPath }}

{{ file.getLocalPath }}

{{ file.getThumb(200, 200, {'crop' => true}) }}

For retrieving stylesheets or images via http following PHP setting must be enabled allow_url_fopen.

When allow_url_fopen is disabled on server try to use relative path. You can use October getLocalPath function on the file object to retrieve it.

Download PDF via Ajax response

OctoberCMS ajax framework cannot handle this type of response.

Recommended approach is to save PDF file locally and return redirect to PDF file.

Page numbers

Page numbers can be generated using PHP. Inline PHP is disabled by default, because it can be a security risk. You can enable inline PHP using setIsPhpEnabled method.

return PDF::loadTemplate('renatio::invoice')

After that you must place following code before closing &lt;/body&gt; tag of the layout file.

<script type="text/php">
    if (isset($pdf)) {
        $size = 9;
        $color = [0,0,0];

        $font = $fontMetrics->getFont('Open Sans');
        $textHeight = $fontMetrics->getFontHeight($font, $size);
        $width = $fontMetrics->getTextWidth('Page 1 of 2', $font, $size);

        $foot = $pdf->open_object();

        $w = $pdf->get_width();
        $h = $pdf->get_height();

        $y = $h - $textHeight - 13;

        $pdf->add_object($foot, 'all');

        $text = "Page {PAGE_NUM} of {PAGE_COUNT}";

        // Center the text
        $pdf->page_text($w / 2 - $width / 2, $y, $text, $font, $size, $color);


Demo examples

There is a console command that will enable demo templates and layouts.

php artisan dynamicpdf:demo

To disable demo run following command:

php artisan dynamicpdf:demo --disable

The first example shows invoice with custom font and image embed.

The second example shows usage of header & footer, page break, page numbers and full background image.

Render PDF in browser

use Renatio\DynamicPDF\Classes\PDF; // import facade

public function pdf()
    $templateCode = 'renatio::invoice'; // unique code of the template
    $data = ['name' => 'John Doe']; // optional data used in template

    return PDF::loadTemplate($templateCode, $data)->stream('download.pdf');

Where $templateCode is an unique code specified when creating the template, $data is optional array of twig fields which will be replaced in template.

In HTML template you can use {{ name }} to output John Doe.

Download PDF

use Renatio\DynamicPDF\Classes\PDF;

public function pdf()
    return PDF::loadTemplate('renatio::invoice')->download('download.pdf');

Fluent interface

You can chain the methods:

return PDF::loadTemplate('renatio::invoice')

Change paper size and orientation

return PDF::loadTemplate('renatio::invoice')
    ->setPaper('a4', 'landscape')

Available paper sizes.

PDF on CMS page

To display PDF on CMS page you can use PHP section of the page like so:

use Renatio\DynamicPDF\Classes\PDF;

function onStart()
    return PDF::loadTemplate('renatio::invoice')->stream();

Header and footer on every page

    @page { margin: 100px 25px; }
    header { position: fixed; top: -60px; left: 0px; right: 0px; background-color: lightblue; height: 50px; }
    footer { position: fixed; bottom: -60px; left: 0px; right: 0px; background-color: lightblue; height: 50px; }
    p { page-break-after: always; }
    p:last-child { page-break-after: never; }
  <header>header on each page</header>
  <footer>footer on each page</footer>

Using custom fonts

Plugin provides "Open Sans" font, which can be imported in Layout CSS section.

@font-face {
    font-family: 'Open Sans';
    src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-Regular.ttf'|app }});

@font-face {
    font-family: 'Open Sans';
    font-weight: bold;
    src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-Bold.ttf'|app }});

@font-face {
    font-family: 'Open Sans';
    font-style: italic;
    src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-Italic.ttf'|app }});

@font-face {
    font-family: 'Open Sans';
    font-style: italic;
    font-weight: bold;
    src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-BoldItalic.ttf'|app }});

body {
    font-family: 'Open Sans', sans-serif;
    font-size: 16px;
  • Found the plugin useful on 23 Feb, 2023

    A million times, thank you for this!

    The amount of time you must have spent on this is incredible. Within 2 hours I went from knowing nothing to a bootstrap 5 styled dynamic invoice converted to PDF.

    My only question would be how to include local CSS/LESS files rather than having to use a CDN link.

    The time you have saved me Renatio is invaluable. Lets buy this man some coffee and energy drinks to help keep this up!=D

  • Found the plugin useful on 29 Sep, 2020

    Awesome plugin!

  • Found the plugin useful on 5 Mar, 2020

    Great plugin for working with PDF's.

    I was pleasantly surprised by how many features are provided for a free plugin, and the code is bug free.

    Author is still actively adding updates which is quite nice.

    Thanks for saving me having to create my own PDF implementation for OctoberCMS

  • Found the plugin useful on 10 May, 2019

    Hey Renatio, thanks for a good plugin. I've used it before without issue. However, the project I'm working on now does not use the CMS module, which is disabled and there is no theme installed. After installing this plugin with composer, I am getting a cms active theme not set error. I made an issue in the repo and would appreciate any assistance in getting it working without the CMS module loaded. Thanks!

  • Found the plugin useful on 11 May, 2018

    Well Done Mate! Good Job!!!

    I used DOMPDF Lib in codeigniter couple of years ago.it was really a headache.

    in this plugin i see all the problems have been sorted out which i faced previously.

    Thanks For Sharing!

  • Found the plugin useful on 7 May, 2018

    Awesome plugin! Just faced the issue with encoding. Couldn't get cyrillic letters to show properly just like in Kenny Heisher review comment. Problem is that dompdf vendor got too little font collection. But for those who want cyrillic symbols you can use font-family: DejaVu Sans; that solved my problem

  • Found the plugin useful on 22 Mar, 2018

    Useful App Converted to a Comment System

    I spent time building a system that can run as a comment form because I was tired of looking for one outside of the forum topic. Thanks!

    • 1.Create a page for the form
    • 2.Create a partial that is going to load the back-end data
    • 3.Set the where() method to specify what data is being queried
    • 4.Add the ajax handler to refresh partial after submission to the component
    • 5.Add the php call to the onRefreshTime()

    1. Page Markup: Summarized

    <div id="magicForms">{% partial 'testing/magicform' %}</div> <form data-request="{{ genericForm2 }}::onFormSubmit">...</form>

    2. Partial Markup: Summarized

    <ul> {% for record in records %} <li><strong>{{ record.form_data_arr.name }}:</strong> {{ record.form_data_arr.comment }}</li> {% endfor %} </ul>

    3. Parital Code: This is where the the collection methods get handy. Using the where() method I can query for the specific group. Here I am searching for the forms with 'group' and 'testing-comments'; the reverse is to put the newest comment on top.

    use \Martin\Forms\Models\Record as FormsRecords; function onStart() { $comments = FormsRecords::all(); $this['records'] = $comments->where('group', 'testing-comments')->reverse(); }

    4. Generic AJAX Form Component: Add this in More Settings -> JS on Success

    jQuery(document).ready(function($) { setInterval(function () { $.request('onRefreshTime', { update: { 'testing/magicform' : '#magicForms' } }) }, 300); });

    5. Page Code: This is needed for the javascript to call the onRefreshTime.

    function onRefreshTime() { return [ '#magicForms' => $this->renderPartial('testing/magicform') ]; }

  • Found the plugin useful on 27 Jul, 2017

    well... the worst plugin EVER!!! (joke) THANK YOU MAN :D

  • Found the plugin not useful on 14 Jul, 2017

    Not working with rainlab translate

  • author

    Replied on 17 Jul, 2017


    I'm so sorry it doesn't support external plugin like RainLab.Translate, but tell me why it should?

    Don't you think this is a new feature than can be added on request?

    You added request on GitHub and 10 minutes later you gave this plugin a negative review, because it doesn't meet all your requirements. I don't see that I wrote in documentation that it supports Translate plugin. It's open source project and you're welcome to make pull request for new features. If you don't have skill to make it, than just leave it to me.

    There is one simple rule here: if you don't like this plugin or it doesn't suit your task, then don't use it. It's free plugin and I spent my free time to make it and support.

    This plugin has many positive reviews from people that thinks it was usefull for them, so your review doesn't make a difference here. Imagine situation when fresh October developer make his first plugin and share it with you. Plugin works fine, have no bugs and make a job done. Then you use it and it looks like it doesn't support RainLab.Translate plugin and you write first negative review. This can make a huge impact on newcomer and discourage him from creating new plugins at all. Please think what you're doing and appreciate someone else work.


  • Found the plugin useful on 14 Jun, 2017

    Work like a charm. Thanks for the great job

  • Found the plugin useful on 5 May, 2017

    Thank you for the Plugin!

  • Found the plugin useful on 14 Apr, 2017

    Does the job! Thumbs up

  • Found the plugin useful on 28 Feb, 2017

    Thanks for Great plugin. But I am stucked with using UTF-8 font.

    Some people said I should run "php load_font.php FontName /path/to/font.ttf" (http://stackoverflow.com/questions/8968627/how-to-make-dompdf-support-unicode-font-step-by-step) But I cannot find the file "load_font.php" in this plugin. Please help me.

  • Found the plugin useful on 25 Sep, 2016

    Very useful!! Easy to use and did precisely what I needed it for!

  • Found the plugin useful on 12 Jul, 2016

    Nice plugin :-)

    I'm using window 7 and I had full permission but when I use preview button on templates backend it so message.

    unlink(C:\Users\lvthu\AppData\Local\Temp/04b854edea2a8e08d8007d212360ace1): Permission denied

    please help me.

  • author

    Replied on 12 Jul, 2016

    Thanks for the review :)

    This is not the place for support topic. Please use support area for this: https://github.com/mplodowski/DynamicPDF/issues

  • Found the plugin useful on 13 Jun, 2016

    Great plugin and outstanding support! Thank you very much!

  • Found the plugin useful on 8 May, 2016

    Nice plugin :-)

    If the demo template throws this error : DOMNode::cloneNode(): ID header already defined, it can be fixed by changing all id's in the template and layout into class, and changing the css accordingly.

  • author

    Replied on 9 May, 2016

    Thanks for the review :) This is now fixed in version 1.1.5.

  • Found the plugin useful on 11 Dec, 2015


  • Found the plugin useful on 18 Sep, 2015

    Thanks! I find this really useful

  • Found the plugin useful on 20 Aug, 2015

    Perfect plugin. The best side is it supports Turkish characters :)

    Thank you!

  • Found the plugin useful on 3 Jul, 2015

    You plugin is amazing.. From html to pdf... It gives you the power for reporting generation directly from OctoberCMS... It's a must-have plugin!!!

  • Found the plugin useful on 12 May, 2015

    I Love you ! Just perfect and great idea !


Allow self signed certificates on development environment.

Oct 27, 2023


Minor fix.

Oct 09, 2023


Fix creating public directory.

May 31, 2023


Fix page numbers demo.

Oct 13, 2022


Update to Laravel Dompdf v2.0.

Oct 13, 2022


Minor update.

Jun 16, 2022


Require October CMS 3.0.

Jun 07, 2022


Brazilian portuguese language. Thanks to @gcairesdev.

Dec 21, 2021


Fix preview pdf layout.

Nov 24, 2021


Update documentation.

Nov 24, 2021


Add demo console command.

Nov 24, 2021


Support October v2.0 and upgrade to DOMPDF 1.0.

Aug 13, 2021


Allow to set dompdf option with dynamic method.

Dec 07, 2020


Add Polish translation.

Nov 22, 2020


Allow to reset view template to default.

Nov 22, 2020


Fix custom template error.

Nov 20, 2020


Fix composer installation.

May 14, 2020


Fix custom templates error.

Feb 21, 2020


Allow to register mail templates and layouts.

Feb 17, 2020


Fix error when active theme is not set.

Feb 07, 2020


!!! Require PHP 7.1. Please see upgrade guide before update.

Feb 07, 2020


Support LESS in PDF layouts.

Feb 07, 2020


Add paper size and orientation configuration.

Feb 07, 2020


Allow to use CMS partials and filters.

May 06, 2018


Fix creating fonts directory

Dec 13, 2017


Add support for RainLab.Translate plugin

Sep 08, 2017


!!! Add support for Laravel 5.5.

Sep 07, 2017


Allow Laravel 5.5.

Jul 30, 2017


Fix open_basedir restriction on some hostings. Set isRemoteEnabled flag to allow absolute paths.

May 14, 2017


German language. Thanks to @TimFoerster.

May 14, 2017


Upgrade to DomPDF 0.8.

Mar 26, 2017


Database maintenance. Updated all timestamp columns to be nullable.

Mar 11, 2017


Upgrade to DomPDF 0.7.

Sep 10, 2016


!!! This is an important update that contains breaking changes.

Sep 10, 2016


Add preview HTML buttons.

Jun 12, 2016


!!! This is an important update that contains breaking changes.

May 28, 2016


UI improvements. Thanks to @kocholes.

May 09, 2016


Add Spanish and Spanish-Argentina locale. Thanks to @kocholes.

Apr 10, 2016


Add stream parameters and Czech locale. Thanks to @vojtasvoboda.

Apr 10, 2016


Minor changes.

Oct 05, 2015


Use Twig::parse() facade. Only update for October build 300 and above.

Oct 05, 2015


!!! Important update

Oct 05, 2015


Minor changes.

Sep 26, 2015


Initialize plugin.

May 10, 2015

Upgrading To 1.1.0

Plugin requires October build 300+.

Upgrading To 2.0.0

PDFTemplate::render() method was removed. Please switch to Renatio\DynamicPDF\Classes\PDF facade.

Upgrading To 2.1.0

Method setOrientation was removed. Use setPaper instead.

Upgrading To 2.1.1

Plugin requires Stable version of October and PHP >=5.5.9.

Upgrading To 3.0.0

Plugin requires OctoberCMS build 420+ with Laravel 5.5 and PHP >=7.0.

Upgrading To 4.0.0

Plugin requires PHP >=7.1 to work with the latest version of dompdf library.

For October composer based installation you must manually update project composer.json file to use at least PHP 7.1:

"config": {
    "preferred-install": "dist",
    "platform": {
        "php": "7.1"

After this change run composer update command.

Upgrading To 4.0.8

This is the latest version with support for October 1.x.

Using setOptions method to change dompdf options is no longer recommended. This will cause to override all laravel dompdf configuration and use only specified by method argument and dompdf defaults for rest options not set by a developer.

Instead of using this method, please use dynamic method call for option you would like to change. Please read more in documentation.

Upgrading To 5.0.1

Plugin requires OctoberCMS v2.1.x with Laravel 6 and PHP >=7.2.

Upgrading To 6.0.0

Plugin requires October CMS version 3.0 or higher, Laravel 9.0 or higher and PHP >=8.0.

Drop support for October CMS version 2.x.