Solution to create PDF or CSV from kirby data

Hi everybody,

that’s just an example I thought about and I would like to hear your opinions regarding a solution.

If for example we have a something like an event signup, where users fill out a form with their data and that data is stored in automatic created subpages, what would be the best workaround, to export the data to a pdf or a csv file (or whatever file format we would like to have)?

Using the kirby api? Creating a virtual document that can be downloaded? Create and update a file inside the event pages content folder?

At the moment, the guide and cookbook is extremely good to show examples, how we can migrate data to kirby, but not in the indirect way.

What do you think?

Exporting data is no problem at all using Kirby’s API, depending on the export format you probably need a third party library (PDF, for example).

1 Like

Hi,
is this question still actually?
I have build a K2 site with both exports. CSV as a conference registration and the pdf generation as automatic invoice generating.

Cheers

hey @Christian,

Im currently trying to achieve pdf export per page with MPDF.

havent got much time to work on it on this lately but maybe you could take a look at it if is helpful!

depending on your use case, creating content representations of your pages could be an idea. I often do that for pdf files with MPDF and it works quite nicely.

For example, let’s assume your registration is saved as a page with template “ticket”. In the templates folder create a “ticket.pdf.php” file containing this:

<?php

use Mpdf\Mpdf;
use Mpdf\Config\ConfigVariables;
use Mpdf\Config\FontVariables;
use Mpdf\Output\Destination;


//load custom fonts
$assets = kirby()->roots()->assets();
$defaultConfig = (new ConfigVariables())->getDefaults();
$fontDirs = $defaultConfig['fontDir'];
$myFontDirs = array_filter(glob("$assets/fonts/*"), 'is_dir');

$defaultFontConfig = (new FontVariables())->getDefaults();
$fontData = $defaultFontConfig['fontdata'];

//init a pdf document
$pdf = new Mpdf([
  'mode' => 'utf-8', 
  'format' => 'A4', //adjust paper format here
  'fontDir' => array_merge($fontDirs, $myFontDirs),
  'fontdata' => $fontData + [
    //here you can define custom fonts from your assets folder (afaik, must be ttf)
    'niveaugrotesk' => [ 
      'R' => 'ng-light.ttf', //regular
      'I' => 'ng-light-italic.ttf', //italic
      'B' => 'ng-bold.ttf', //bold
      'BI' => 'ng-bold-italic.ttf', //bold italic
    ]
  ]
]);


//define some CSS for your ticket layout
$css = <<<CSS

@page {
  margin: 1cm;
}

body {
  font-family: niveaugrotesk;
  font-size: 10pt;
  color: cmyk(0,0,0,100); /* you can use CMYK colors like this */
}

CSS;


// capture some html to be written on the ticket
// do it like normal kirby templates
ob_start(); ?>

<h1>Ticket for <?= $page->name() ?></h1>
<p>Your ticket is valid for the event: <?= $page->parent()->title()->html()  ?></p>

<?php 
$html = ob_get_clean(); //save the captured html to this variable

//give the document a title and an author name
$pdf->SetTitle($site->title() . ' - ' . $page->title());
$pdf->SetAuthor($site->title());

//write the css to the file
$pdf->WriteHTML($css, 1);

//write content to the file
$pdf->WriteHTML($html);
//you can also write the HTML to a fixed box 
// $pdf->WriteFixedPosHTML($html, 10, 10, 100, 100); //the numbers are the bounds of the box in mm

//respond with the pdf file 
$pdf->Output($page->uid() . '.pdf', Destination::INLINE);

When people normally see their registration at “https://example.com/path/to/my/ticket”, they can now download a pdf representation of it by going to “https://example.com/path/to/my/ticket.pdf

1 Like

Hello @rasteiner, this looks like a very nice solution for downloading pages as pdf files.

I installed mpdf via composer require mpdf/mpdf — see: GitHub - mpdf/mpdf: PHP library generating PDF files from UTF-8 encoded HTML — in my fresh Kirby 3 plainkit.

Then I added the pdf code you posted to site/templates/default.pdf.php with slight changes to the font file names, css, and kirby elements to be printed (basically the same code as in default.php).

Is there anything more I’d need to do to make this work? Because now simply adding .pdf to my URL results in bringing up the Error page.

Thank you very much!

Having the template there should be enough: Content Representations | Kirby

What happens if you remove everything from the “.pdf.php” template and just have it say “hello world” or something? This just to make sure it’s not something in the template code that causes the error.

Do you use some kind of customized routes?

With only <p>hello world</p> in site/templates/default.pdf.php, the Error page is shown, too.

Do you use some kind of customized routes?

No; pretty stock plainkit with just mpdf added via composer and some css and template/snippet changes, nothing else.

PS: Oh, I set up multi-language-support …

PPS: And it seems to not work with the home route. So now I get:

Does the default.php template still exist? Where did you install mpdf? Did you install the complete plainkit with composer?

Hello @texnixe.

Does the default.php template still exist?

Yes.

Where did you install mpdf?

At the top most level of the plainkit I simply executed composer require mpdf/mpdf

Did you install the complete plainkit with composer?

Yes, I did so yesterday via composer create-project getkirby/plainkit <folder_name>

Ok, one issue is that in the Plainkit there is no parent page, so you would have to change the line of code where the parent is called to avoid the PHP error:

<p>Your ticket is valid for the event: <?= $page->parent()->title()->html()  ?></p>

If you then add a new test page, it should work, however, for some reason it doesn’t work on the homepage.

Make sure that in multilanguage support, your text files have the language code extension (which is added automatically if you set up languages via the Panel, but not if you do it manually).


On a side note: If your main project doesn’t have Kirby set up with composer, make sure to install mpdf in a plugin, not through the main composer file to avoid duplicate Kirby folders.

Huh, Firefox just crashed and then all of macOS … weird.

I’m not using that line. My file looks like … see below.

So now, after that forced reboot, typing en/concept-paper.pdf in my address bar results in a loading time of ~three minutes and then the following error:

I tried removing the color values from the CSS block in site/templates/default.pdf.php, but the same error is thrown, so that’s probably not the problem.

Seems like some problem with mpdf itself? Maybe I have to return to simply using <button onClick="window.print()">Save as PDF</button>:eyes:


<?php

use Mpdf\Mpdf;
use Mpdf\Config\ConfigVariables;
use Mpdf\Config\FontVariables;
use Mpdf\Output\Destination;

// load custom fonts
$assets = kirby()->roots()->assets();
$defaultConfig = (new ConfigVariables())->getDefaults();
$fontDirs = $defaultConfig['fontDir'];
$myFontDirs = array_filter(glob("$assets/fonts/*"), 'is_dir');

$defaultFontConfig = (new FontVariables())->getDefaults();
$fontData = $defaultFontConfig['fontdata'];

// init a pdf document
$pdf = new Mpdf([
  'mode' => 'utf-8',
  'format' => 'A4',
  'fontDir' => array_merge($fontDirs, $myFontDirs),
  'fontdata' => $fontData + [
    'Inter' => [
      'R' => 'Inter-Medium.otf',
      'I' => 'Inter-MediumItalic.otf',
      'B' => 'Inter-Bold.otf',
      'BI' => 'Inter-BoldItalic.otf',
    ]
  ]
]);

// define some CSS for your ticket layout
$css = <<<CSS

:root {
  --color-fg: cmyk(0,0,0,100);
  --color-bg: cmyk(0,0,0,0);
  --color-hi: cmyk(0,0,0,100);
  --color-lo: cmyk(0,0,0,40);
  --margin: 1rem;
  --width: 64ch;
}

html {
  font-family: Inter;
  font-size: 10pt;
}

header > nav,
body > footer {
  display: none;
}

main article h2 {
  break-after: avoid;
}

main article h2 + p {
  break-before: avoid;
}

main article p,
main article ul,
main article img {
  break-inside: avoid;
}

main blockquote footer {
  font-size: 10pt;
}

@page {
  margin-left: 2.6cm;
  margin-top: 2cm;
  margin-right: 2cm;
  margin-bottom: 2.6cm;
}

CSS;

// capture some html to be written on the ticket
ob_start(); ?>

<?php snippet('header') ?>
<?php snippet('nav') ?>
    <main>
      <article>
        <?= $page->text()->toBlocks() ?>

      </article>
      <aside id="credits">
        <div>
          <?= $page->authors()->toBlocks() ?>

        </div>
        <div>
          <?= $page->translators()->toBlocks() ?>

        </div>
      </aside>
    </main>
<?php snippet('footer') ?>

<?php
// save the captured html to this variable
$html = ob_get_clean();

// give the document a title and an author name
$pdf->SetTitle($site->title() . ' - ' . $page->title());
$pdf->SetAuthor($site->title());

// write the css to the file
$pdf->WriteHTML($css, 1);

// write content to the file
$pdf->WriteHTML($html);
// you can also write the HTML to a fixed box
// the numbers are the bounds of the box in mm
// $pdf->WriteFixedPosHTML($html, 10, 10, 100, 100);

// respond with the pdf file
$pdf->Output($page->uid() . '.pdf', Destination::INLINE);

@texnixe Might be a somewhat stupid question, but is there any way to completely remove mpdf via compose from my plainkit instance? :thinking:

Maybe it’s simply composer remove mpdf/mpdf

Yep.

1 Like