Can Posted July 16, 2014 Share Posted July 16, 2014 (edited) Hey guys, got asked to share how to set up mpdf with processwire so it's time to make a little tutorial Disclaimer: ( ) This is my first tutorial and I'm not a real coder yet so every tips and hints are highly appreciated Grab a copy of mPDF unzip it and put it in a nice place outside of your Processwire folder(s) - (as far as I remember is has to be outside or within a module to work, but I could be wrong?!) Open the template from which you want to create the PDF from In my case I have a "course.php" which is showing a page with a weekly schedule table and I wanted to provide this schedule as pdf next to the website version. I turned on urlSegments for "course" template, because I find it nicer than a get variable Then in my course.php template file after the normal website output I added the following It's probably better to have this logic at the very top of the template file to prevent unnecessary code execution right?? Aha, now I remember why it's at the bottom. I have some more logic above it which I wanted to share for browser output and pdf creation and this was the easiest way, probably I'll rearrange everything to make it faster At least the if( file_exists logic could go at the very top <?php // In case you don't have other urlSegments it's better to throw a 404 when someone types a non existing url, // could be managed better but at the moment it's easier if($input->urlSegment1 && $sanitizer->pageName($input->urlSegment1) != 'pdf') throw new Wire404Exception(); // if urlSegment /pdf/ output course table as PDF file if($sanitizer->pageName($input->urlSegment1) === 'pdf') { // $config->paths->files = PWs /assets/files/ folder, page ID and the title of the page could be any field or anything else // maybe you want to add the date $pdfPath = $config->paths->files . $page->id . "/" . $page->title.'.pdf'; // Options for wireSendFile because they're needed more then once $wireSendOptions = array('exit' => true, 'forceDownload' => true, 'downloadFilename' => ''); // If file already exists force download it and stop further execution which is handled $wireSendOptions 'exit' => true if(file_exists( $pdfPath )) wireSendFile($config->paths->files . $page->id . "/" . $headline.'.pdf', $wireSendOptions ); // include mPDF.php conditionally for localhost and productive website, you probably don't need it if structure is the same // included it at this point because we don't need it to provide an existing file // you could even include it after your output logic just before PDF creation.. if($config->httpHost == 'localhost') { include("../../../../classes/MPDF57/mpdf.php") } else { include("../../../classes/MPDF57/mpdf.php"); } // at this point you create the logic for your output // I'm not sure wether mPDF understands single 'quotes' properly // TCPDF doesn't really liked them so I stick to double "quotes" for now // just a little example how it might look you can of course have a loop populate everything from $page or somewhere else ;-) $pdfOutput = '<table class="data"> <tr> <th>Entry Header 1</th> <th>Entry Header 2</th> <th>Entry Header 3</th> <th>Entry Header 4</th> </tr> <tr> <td>Entry First Line 1</td> <td>Entry First Line 2</td> <td>Entry First Line 3</td> <td>Entry First Line 4</td> </tr> <tr> <td>Entry Line 1</td> <td>Entry Line 2</td> <td>Entry Line 3</td> <td>Entry Line 4</td> </tr> <tr> <td>Entry Last Line 1</td> <td>Entry Last Line 2</td> <td>Entry Last Line 3</td> <td>Entry Last Line 4</td> </tr> </table>'; // now the best part // the next comment explains the mPDF() parameters as in the manual http://mpdf1.com/manual/index.php?tid=184 // mode, format, default_font_size, default_font, margin_left, margin_right, // margin_top, margin_bottom, margin_header, margin_footer, orientation $mpdf = new mPDF('utf-8','A4-L', 0, '', 5, 5, 16, 6, 5, 5, 'L'); // The header is repeated on all pages, it's possibly to have different headers (even/odd) and other fancy stuff // You can have images as well, just have a look at the documentation it's pretty good $mpdf->SetHTMLHeader("<h2>{$page->title}</h2>"); // this one puts your table, created above, into the file $mpdf->WriteHTML($pdfOutput); // I'm saving the PDF file to the disc first as set in line 9 // 'D' would output the file inline in the browser window but then we're not able to store it for faster serving $mpdf->Output($pdfPath,'F'); // Thanks to Ryan and his nice functions we can use wireSendFile (as above) to get the created file and force download it wireSendFile($pdfPath, $wireSendOptions ); } // End if /pdf/ If you want to create the file everytime it's called and don't want the it to get stored just strip line 12, 15 and 67 and change the 'F' in line 64 to 'D' If you want to have a newly created file each time you change the page you have to install a little module to hookAfter page save It's just one file, I called it like hooks.module because maybe I will add some hooks later and there is no need to have each hook in a separate module. <?php class Hooks extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'Custom Hooks', 'summary' => 'Hooks, PDF deletion on page save for example', 'version' => 1, 'autoload' => true, // You want it to autoload, otherwise it would never get called ); } public function init() { $this->pages->addHookAfter('save', $this, 'deletePDF'); //initialise the hook } // Most of it is just copied from Pages2PDF module from Wanze, a little 'simplified' though^^ public function deletePDF(HookEvent $event) { $page = $event->arguments[0]; $pdf = wire('config')->paths->files . $page->id . "/" . $page->title.'.pdf'; if (file_exists($pdf) && is_file($pdf)) { $name = $page->title.'.pdf'; if (@unlink($pdf)) { $this->message($this->_(sprintf("The following file got deleted '%s'", $name))); } else { $this->error($this->_(sprintf("Failed to delete '%s'", $name))); } } } } Hope you can follow the steps. Please let me know if not and why Any improvements are welcome because I would love to learn more as well Edited July 16, 2014 by Can 5 Link to comment Share on other sites More sharing options...
gebeer Posted July 16, 2014 Share Posted July 16, 2014 This is great and very useful. Thanks a lot Can! May have spotted an error. In line 33 you define the HTML table as $pdfOutput. And the in line 71 you go $mpdf->WriteHTML($table); I think it should read $mpdf->WriteHTML($pdfOutput); I will most likely put this to use. Only waiting for the customer to finally confirm that they want this feature. I will add the cart logic as discussed in the other thread and publish my code here. Will take another month more or so. Cheers Gerhard 2 Link to comment Share on other sites More sharing options...
Can Posted July 16, 2014 Author Share Posted July 16, 2014 Thank you Gerhard, really fast As I mentioned I changed it a bit for this tut and missed this one, thanks to you it's corrected I would like to know how it works for you in the end, so hopefully your customer likes the feature Link to comment Share on other sites More sharing options...
muzzer Posted July 19, 2014 Share Posted July 19, 2014 Dude! I've always wanted to do on-the-fly PDF brochures of some pages on a site I have, but have always put it off as thinking I don't have enough spare time to justify it, and don;t really want to fight stupid PDF libraries to get a decent result.. Well, after reading your tut I decided it looked easier than I have previously thought. In about 2 hours this morning I've nailed this with some outstanding results, sooo easy! I thought there would be issues getting PDF data to display right etc (these things are never straight-forward) but no, mpdf is the bomb! So thanks for the enticing post that got me going with this, and guys, if you like me think PDF generation will be more trouble than it's worth, I encourage you to give it a go. 3 Link to comment Share on other sites More sharing options...
Can Posted July 20, 2014 Author Share Posted July 20, 2014 I'm really glad it helped you muzzer Link to comment Share on other sites More sharing options...
muzzer Posted July 20, 2014 Share Posted July 20, 2014 Yeah thanks Can. Only thing I'm coming unwound on is wrapping text around a right-floated image. Looks like this is something that cannot be done with mpdf. If anyone has an solution to this I'd love to know. Cheers Link to comment Share on other sites More sharing options...
Can Posted July 20, 2014 Author Share Posted July 20, 2014 Don't needed images so far, so can't help you with this one. But have you checked out this one http://mpdf1.com/manual/index.php?tid=245 scroll a bit down to Float and Text wrapping. maybe it helps Link to comment Share on other sites More sharing options...
muzzer Posted July 20, 2014 Share Posted July 20, 2014 Thanks for that Can, You're right, images do seem to float, unfortunately when I replace the image with a div it fails. Looks like all pdf classes have similar issues and this is obviously not an easy thing to get working reliably <div> <div style="float:right;width:100px;height:100px"> <p>Small div text</p> </div> <p>text in here should wrap floated internal div. When internal div is replaced with a floated image it works, but as a div it fails. Bummer</p> </div> Link to comment Share on other sites More sharing options...
gebeer Posted July 20, 2014 Share Posted July 20, 2014 I'm still not sure exactly which way to go with PDF creation. There is also a client side JS library: https://github.com/MrRio/jsPDF We'll have to check this out more thoroughly. Maybe it will make things like floating images possible? 1 Link to comment Share on other sites More sharing options...
gebeer Posted July 20, 2014 Share Posted July 20, 2014 @muzzer jsPDF library can handle floating divs and images pretty well. I set up a quick and dirty test page at http://jspdf.webseiten-fuer-alle.de/ Underneath "Choose examples" select the last one "** NEW addHTML()" and you'll instantly see the result. For floating divs with mpdf have a read here: http://mpdf1.com/manual/index.php?tid=385 As far as I understand it in your example the text wrapping the div also needs to be wrapped with float and width (but then it won't wrap the div anymore). 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now