DOMPDF and WordPress
Making PDFs by filling in a simple form is pretty cool. Loads of possible applications. I’ll leave it to your imagination. In this blog post though, i’m going to go through one possible method.
DOMPDF is an HTML to PDF rendering engine, written in PHP. Another I’ve used (a few years ago now) is MPDF57. If memory serves, MPDF57 felt bloated and limited in capabilities. However, that is the nature of such rendering engines, as I was reminded with DOMPDF. However, this time at least, DOMPDF felt a lot more intuitive and capable, so don’t be scared! I should also mention, another popular HTML to PDF engine is WKHTMLtoPDF. Which is from what I hear comparable to DOMPDF and possibly even better.
So I recently had my second project requiring on-demand PDF creation. The idea is we have a “designed” multi-page template that we can fill in using a web form and that will flex to varying amounts of content. Having done a very simple version of this previously, I concluded it could be done simply in WordPress and that perhaps the tech had evolved to a superior process.
In deed, a look at the WP plugin repository revealed a small handful of plugins seemingly capable of doing the job. That is to say, plugins I could at least mod to my needs. WordPress PDF Templates seemed to offer everything I needed. It will convert any post from any post type and has DOMPDF in-built. So no need to build a bespoke plugin.
Once the plugin is installed, we want to add some bits to our wp-config file:
ini_set("memory_limit", "999M"); ini_set("max_execution_time", "999"); define( 'DISABLE_PDF_CACHE', true ); define('DOMPDF_PAPER_SIZE', 'A4'); define('DOMPDF_PAPER_ORIENTATION', 'landscape'); define('DOMPDF_DPI', 144);
The ini_set commands are probably only needed if, like me in this case, you need to produce a rather big document with a large amount of content. My template for example takes about 30 or 40 images, which seems to slow down the PDF processing time. Without ini_set, I would often get a 500 error on my local dev environment anyway.
The “define” commands should be straightforward to understand. I’ve used 144 dpi as I don”t want things to look terrible in print, but file size is a factor. For this job, 144 will suffice for me anyway.
OK. Now, set up your custom post type with all the fields you need. I usually use WP Pods for this because it’s easy and powerful.
Now we want to make sure our PDF Plugin works for our CPT. Got to your function.php and add this (replace “invites” with the name of your CPT):
// add pdf print support to post type ‘invites’ if(function_exists('set_pdf_print_support')) { set_pdf_print_support(array('post', 'page', 'invites')); }
Awesome, now copy index-pdf.php from the WP PDF Templates plugin folder to your theme directory. If you want rename it to single-[your-cpt-name]-pdf.php which will be necessary anyway if you want to use multiple post types and templates.
First of all, to make sure all my php is working correctly in outputting my data, I just use a standard single-[your-cpt-name].php. You don’t need to do this, but refreshing a PDF, especially with a lot of data in it, is slow.
MARKUP
My template starts off really basic.
<?php /** * Filename: single-invites-pdf.php */ ?> <!DOCTYPE html> <html> <head> <title><?php wp_title(); ?></title> <?php wp_head(); ?> <style> /* STYLES GO HERE */ </style> </head> <body> <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?> <!-- CONTENT GOES HERE --> <?php endwhile; endif; ?> </body> </html>
CSS
As the CSS is going to be unique to the PDF, I don’t see a performance issue with an additional HTTP request, so you can put it in a separate file to your styles.css. Or as include your styles in the actual template as I’ve done here.
DOMPDF uses CSS 2.1, but not entirely, frequently you will have to use work arounds in your markup to get the desired effect. For example, I wanted to use a box-shadow. No such luck. Gradients are also out. Further, “background-size” does not work. Which is annoying when wanting to set background images to “cover”. This means using alternative methods to create the same effect. So instead of using the background-image property, I set an image tag, outside the container, with position set to absolute. Maybe play with the z-index. (Using PNGs with transparency can also help you achieve the desired graphic effect with box shadows or gradients.)
You can use custom fonts by including them in your theme directory and calling them in the styles.
UNIQUE CODE
Now, onto the meat. DOMPDF has some very useful code you arguably need to know.
First of all is @page in your styles. This is where you set the main content area and margins. A bit like when you create a new document in Adobe inDesign if you’ve used that.
@page { margin: 2cm 0 1cm !important ; size: 27.7cm 19cm;}
As this is a multipage template, it’s interesting to look at page numbering with DOMPDF. First of all you will need a position:fixed div to use as either a header or a footer on each page of the pdf. Then add content using :before or :after as so:
.page-header {position: fixed;height: 1.3cm;width: 100%;top:-2cm;left: 2cm;right: 2cm;border-bottom: 1px solid #999;}
.page-header:after { content: counter(page); position: absolute;top: 0.66cm;right: 0.05cm;}
You can see content: counter(page) is where the magic happens.
Another issue with multi-page PDFs, is page breaking. I have sections which are single pages, and pages which cascade the content. When alternating between sections, I need to make sure new sections don’t start on the same page as the previous section. DOMPDF has a useful tool for this. After the end of a section, add this:
<div style="page-break-after: always;"></div>
Elegant no?