Generate highly customized PDFs with wkhtmltopdf and eZ Publish
By: Thiago Campos Viana | May 4, 2015 | eZ Publish add-ons, Web solutions, wkhtmltopdf, and pdf
One of our customer websites sells research reports where all of the content is built and managed in the eZ Publish content management system. These reports are served via HTML through a gated website portal. They wanted to add a dynamic PDF report generation feature (based on content in the CMS); the PDF template was highly customized with nice layouts and styles, cover and back pages, custom page breaks, and much more. Over the years we've had good experiences with the ParadoxPDF extension. However due to its lack of HTML5 + CSS3 support and relatively high server load, we decided to look for an alternative solution. We found that wkhtmltopdf does a great job at producing highly styled PDFs, and we were able to integrate it nicely with eZ Publish.
Among the downsides of ParadoxPDF are that it is based on the Java application flying-saucer, which has not been updated since 2011. It only supports CSS2, and doesn't support page breaks using CSS for example. wkhtmltopdf uses qtwebkit, which supports HTML5 and CSS3, and is actively maintained.
Is your website accessible to people with disabilities?
Get our beginner's guide to website accessibility
Download your FREE copyWe also ran some performance tests and found that wkhtmltopdf can generate PDFs up to twice as fast as ParadoxPDF.
Here is some example code on how to use wkhtmltopdf to generate PDFs in eZ Publish. It includes a cover page, a back page, and a table of contents.
// Initialize the PDF using this library: https://github.com/mikehaertl/phpwkhtmltopdf $pdf = new Pdf(); // specify wkhtmltopdf options; see: http://wkhtmltopdf.org/usage/wkhtmltopdf.txt $options = array( 'page-width' => '216mm', 'page-height' => '279mm', 'dpi' => 96, 'image-quality' => 100, //'margin-top' => '16mm', 'margin-right' => '14mm', 'margin-bottom' => '25mm', 'margin-left' => '14mm', 'header-spacing' => 15, 'footer-spacing' => 5, 'disable-smart-shrinking', 'no-outline', 'user-style-sheet' => 'extension/myextension/design/standard/stylesheets/pdf.css', 'footer-html' => 'extension/myextension/design/standard/templates/pdf/footer.html', 'header-html' => 'extension/myextension/design/standard/templates/pdf/header.html' ); $pdf->setOptions( $options ); // uses eZ Template to build the cover and frontpage $tpl = eZTemplate::factory(); $tpl->setVariable( 'object', $object ); $pdf->addPage( $tpl->fetch( 'design:pdf/cover.tpl' ) ); $pdf->addPage( $tpl->fetch( 'design:pdf/frontpage.tpl' ) ); // Adds a Table of Contents $pdf->addToc(array('user-style-sheet' => 'extension/myextension/design/standard/stylesheets/pdf.css','xsl-style-sheet' => 'extension/myextension/design/standard/stylesheets/toc.xsl')); // Fill the body of the PDF $pdf->addPage( $tpl->fetch( 'design:pdf/main_body.tpl' ) ); // Adds the backpage $pdf->addPage( $tpl->fetch( 'design:pdf/backpage.tpl' ) ); // Downloads the PDF $pdf->send( $node->attribute('name') . '_Report.pdf');
header.html
<!doctype html> <html> <head> <meta name="csrf-param" content="_token" /> <meta name="csrf-token" id="_token_js" title="ee27aab32db95f302d92f14ced4b96ec9b99674e" content="ee27aab32db95f302d92f14ced4b96ec9b99674e" /> <meta name="csrf-token-x" id="ezxform_token_js" title="ee27aab32db95f302d92f14ced4b96ec9b99674e" content="ee27aab32db95f302d92f14ced4b96ec9b99674e" /> <meta charset="utf-8"> <link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700,600,800,400italic,600italic,700italic,800italic,300,300italic' rel='stylesheet' type='text/css'> </head> <body id="pdf-header"> <header> <span class="report-name"> SOME NAME HERE {pdf_name} </span> <span class="report-date">{pdf_date}</span> </header> </body> </html>
footer.html
<!doctype html> <html> <head> <meta name="csrf-param" content="_token" /> <meta name="csrf-token" id="_token_js" title="ee27aab32db95f302d92f14ced4b96ec9b99674e" content="ee27aab32db95f302d92f14ced4b96ec9b99674e" /> <meta name="csrf-token-x" id="ezxform_token_js" title="ee27aab32db95f302d92f14ced4b96ec9b99674e" content="ee27aab32db95f302d92f14ced4b96ec9b99674e" /> <meta charset="utf-8"> <link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700,600,800,400italic,600italic,700italic,800italic,300,300italic' rel='stylesheet' type='text/css'> <script> function pagination() { var vars = {}; var x = document.location.search.substring(1).split('&'); for (var i in x) { var z = x[i].split('=', 2); vars[z[0]] = unescape(z[1]); } var x = ['frompage','topage','page','webpage','section','subsection','subsubsection']; for (var i in x) { var y = document.getElementsByClassName(x[i]); for (var j = 0; j < y.length; ++j) { y[j].textContent = vars[x[i]]; } } } </script> </head> <body id="pdf-footer" onload="pagination()"> <span class="copyright"> © Copyright MySite. All rights reserved. </span> <span class="page"></span> </body> </html>
To help other eZ Publish developers get started with wkhtmltopdf, we have created a very simple extension, mugo_wkhtmltopdf, to illustrate an initial integration. You can check the file node.php and see that we are using the phpwkhtmltopdf library. That library includes other examples to show how to create more complex PDFs.
To use wkhtmltopdf you also need to install the tool itself! In our sample extension's readme file, we explain how to install it on CentOS. There is also public documentation on how to install wkhtmltopdf on Ubuntu; for Mac and Windows you can run the installer.
One alternative solution for generating PDFs from your CMS is to use a third-party service -- you would interact with an API, sending the HTML and receiving the PDF back. This is worth considering if you do not have a requirement (such as a privacy one) to self-host everything.