Web to print with Pimcore and Wkhtmltopdf

Pimcore is definitely a fantastic CMS and PIM platform, so wouldn’t it be wonderful if there was an easy way to render your pages or products into downloadable PDFs? Well, there is!

The Pimcore team presented a very user-friendly, straight-forward way themselves a while back:

The official docs for how to implement this leaves some parts for your imagination, and recently the SVN links went broken, so here’s a tutorial how to do it:

First, you need to install the wkhtmltopdf binary. If you are on debian/ubuntu, there is an wkhtmltopdf APT package available to be easily installed with apt-get. This package does not work out of the box unfortunately, since it rely on X server – which is something you usually won’t be using on a webserver.

Instead, download and install the static binary from Google docs (I chose wkhtmltopdf-0.9.9-static-i386.tar.bz2 at the time I wrote this blog post, for Ubuntu 10.04 LTS on a i386 VPS):

wget http://wkhtmltopdf.googlecode.com/files/wkhtmltopdf-0.9.9-static-i386.tar.bz2
tar -jxf wkhtmltopdf-0.9.9-static-i386.tar.bz2
sudo mv wkhtmltopdf-i386 /usr/bin/wkhtmltopdf
sudo chown root.root /usr/bin/wkhtmltopdf
sudo chmod a+x /usr/bin/wkhtmltopdf

Now test the binary to see that you got the correct binary for your configuration and that all is well:

wkhtmltopdf www.google.com test.pdf

Next, add the (at this time missing) Pimcore labs code to your installation, by creating the file /website/lib/Website/Controller/Plugin/Wkhtmltopdf.php:

<?php
/**
 * Pimcore
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.pimcore.org/license
 *
 * @copyright  Copyright (c) 2009-2010 elements.at New Media Solutions GmbH (http://www.elements.at)
 * @license    http://www.pimcore.org/license     New BSD License
 */
 
require_once 'Zend/Controller/Plugin/Abstract.php';
 
class Website_Controller_Plugin_Wkhtmltopdf extends Zend_Controller_Plugin_Abstract {
 
    protected $config = array();
 
    public function __construct ($config = array()) {
        if($config) {
            $this->config = $config;
        }
    }
 
    public function dispatchLoopShutdown() {
 
        if(!Pimcore_Tool::isHtmlResponse($this->getResponse())) {
            return;
        }
 
        $body = $this->getResponse()->getBody();
        header("Content-Type: application/pdf");
        echo Website_Tool_Pdf_Wkhtmltopdf::fromString($body, $this->config);
 
        exit;
    }
}

And /website/lib/Website/Tool/Pdf/Wkhtmltopdf.php:

<?php
/**
 * Pimcore
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.pimcore.org/license
 *
 * @copyright  Copyright (c) 2009-2010 elements.at New Media Solutions GmbH (http://www.elements.at)
 * @license    http://www.pimcore.org/license     New BSD License
 */
 
class Website_Tool_Pdf_Wkhtmltopdf {
 
    public function fromUrl ($url, $config = array()) {
        return self::convert($url, $config);
    }
 
    public function fromString ($string, $config = array()) {
 
        $tmpHtmlFile = PIMCORE_TEMPORARY_DIRECTORY . "/" . uniqid() . ".htm";
        file_put_contents($tmpHtmlFile, $string);
        $httpSource = $_SERVER["HTTP_SCHEME"] . "://" . $_SERVER["HTTP_HOST"] . str_replace($_SERVER["DOCUMENT_ROOT"],"",$tmpHtmlFile);
 
        $pdfContent = self::convert($httpSource, $config);
 
        @unlink($tmpHtmlFile);
 
        return $pdfContent;
    }
 
    protected function convert ($httpSource, $config = array()) {
 
        $tmpPdfFile = PIMCORE_SYSTEM_TEMP_DIRECTORY . "/" . uniqid() . ".pdf";
        $options = " ";
        $optionConfig = array();
 
        if(is_array($config["options"])) {
            foreach ($config["options"] as $argument => $value) {
                // there is no value only the option
                if(is_numeric($argument)) {
                    $optionConfig[] = $value;
                } else {
                    $optionConfig[] = $argument . " " . $value;
                }
            }
 
            $options .= implode(" ", $optionConfig);
        }
 
        $wkhtmltopdfBinary = "/usr/bin/wkhtmltopdf";
        if($config["bin"]) {
            $wkhtmltopdfBinary = $config["bin"];
        }
 
        exec($wkhtmltopdfBinary.$options." " . $httpSource . " " . $tmpPdfFile);
 
        $pdfContent = file_get_contents($tmpPdfFile);
 
        // remove temps
        @unlink($tmpPdfFile);
 
        return $pdfContent;
    }
 
}

Now, create a controller/action/view by choice, and add the following code in the controller (for example pdfAction):

public function pdfAction () {
        if(!$this->editmode) {
            $front = Zend_Controller_Front::getInstance();
            $front->registerPlugin(new Website_Controller_Plugin_Wkhtmltopdf(array(
                "options" => array( // configuration for wkhtmltopdf ( see http://madalgo.au.dk/~jakobt/wkhtmltopdf-0.9.9-doc.html )
                    "--disable-smart-shrinking",
                    "--print-media-type",
                    "--margin-left" => "0",
                    "--margin-top" => "0",
                    "--margin-bottom" => "0",
                    "--margin-right" => "0"
                ),
                "bin" => "/usr/bin/wkhtmltopdf" // path to the wkhtmltopdf binary (default is /usr/bin/wkhtmltopdf)
            )), 700);
        }
}

Now, when you create a document in Pimcore and select the controller/action that you just created, you will be able to create a page in the regular WYSIWYG manner (depending on what layout you have defined, and editables and layout in your view file).

Publish your document and point your browser to it – et voilà! You should get a PDF with the same appearance as the web page.

This entry was posted in Pimcore and tagged , , , , . Bookmark the permalink.