I am currently manually creating a pdf file of my products but, I would like to display my page as a pdf file for download when I click a button, as they are the same content.
I would like to control how it displays, can I create page-item.pdf.twig template so that if a user visits www.example.com/page-item.pdf it will display a pdf.
if this is not supported by Grav I was thinking of using TCPDF
how can I add this to Grav?
As per the documentation
Grav is a flexible platform however, and can actually serve up any content type you could wish for (xml, rss, json, pdf, etc.), you just have to provide a way to render it appropriately.
If you were to request a route with a .xml extension, for example: /blog.xml, instead of using the regular blog.html.twig template to render it, Grav looks for a template called blog.xml.twig. You would need to ensure that template outputs the appropriate XML structure.
And then in some custom plugin with outputPDF($page) Twig function render the PDF using TCPDF
Or maybe this outputPDF() even could render your actual my-page.html.twig output. I used TCPDF years ago, but IIRC it can accept HTML and make a PDF. I believe it used to distort the layout then, but maybe worth trying
In your described case, it is enough to optimize your print-stylesheet - as all modern browsers are able to generate PDF files as well.
If you want to generate a completely individual looking PDF-file with specific data from your page (lets say you have built a real estate page and want the user to be able to download an expose for a building in your corporate style) I would recommend jsPDF.
But be aware that coding a PDF-template is as much fun as creating a responsive newsletter-template with tables…
ok, so I am having a go at designing a custom plugin. It works well locally, but I am having issues on the live site.
When I upload the plugin, the whole site doesn’t display, it just shows “this page isn’t working”.
If I edit out code, it seems to be the “class MYPDF extends TCPDF” section; due to if I remove it, the site displays again.
I have installed tcpdf via composer in the plugin root folder. is there something I am missing or doing wrong?
Here is an abbreviated version of the code
<?php
namespace Grav\Plugin;
use Composer\Autoload\ClassLoader;
use Grav\Common\Plugin;
use TCPDF;
class MYPDF extends TCPDF {
public $logoPath;
public $product;
public $dxfIconPath;
public $dxfFilePath;
public function Header() {
// Code
}
public function Footer() {
// Code
}
}
/**
* Class ProductPDFPlugin
* @package Grav\Plugin
*/
class ProductPDFPlugin extends Plugin
{
/**
* @return array
*
* The getSubscribedEvents() gives the core a list of events
* that the plugin wants to listen to. The key of each
* array section is the event that the plugin listens to
* and the value (in the form of an array) contains the
* callable (or function) as well as the priority. The
* higher the number the higher the priority.
*/
public static function getSubscribedEvents(): array
{
return [
'onPluginsInitialized' => [
['onPluginsInitialized', 0]
]
];
}
/**
* Composer autoload
*
* @return ClassLoader
*/
public function autoload(): ClassLoader
{
return require __DIR__ . '/vendor/autoload.php';
}
/**
* Initialize the plugin
*/
public function onPluginsInitialized(): void
{
// Don't proceed if we are in the admin plugin
if ($this->isAdmin()) {
return;
}
// Enable the main events we are interested in
$this->enable([
'onPageInitialized' => ['onPageInitialized', 0]
]);
}
/**
* Handle the page initialization event
*/
public function onPageInitialized(): void
{
// Check if the current route is for generating a PDF
$uri = $this->grav['uri'];
$path = $uri->path();
if (preg_match('/^\/products\/.+\.pdf$/', $path)) {
$this->generatePDF($path);
}
}
/**
* Generate and display a PDF using TCPDF
*/
private function generatePDF(string $path): void
{
// Extract product name from path
$productName = basename($path, '.pdf');
// Remove the .pdf extension to find the original page
$originalPath = preg_replace('/\.pdf$/', '', $path);
// Retrieve the original page
$page = $this->grav['pages']->dispatch($originalPath, true);
// Get product data from page frontmatter
$product = $page->header()->product;
// Create new PDF document
$pdf = new MYPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
// Set document information
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('Your Name');
$pdf->SetTitle($product['code'] . '[' . $product['name'] . ']');
$pdf->SetSubject('Product PDF Document');
$pdf->SetKeywords('TCPDF, PDF, product, guide');
//HTML PDF CODE
// Output PDF document
$pdf->Output( $product['code'] . '[' . $product['name'] . ']'.'.pdf', 'I');
// Stop Grav from further processing
exit();
}
}
Further to this, it seems locally i have got tcpdf installed in the root composer, when removed it acts the same. so my question is how do i make sure it uses TCPDF from the plugin composer?
@dean_007, Yes, it may have solved the error, but it is a bit crude…
I would do the following to better align with PHP PSR-1 codestyle, Composer autoloading and Grav itself:
Create a plugin using $ bin/plugin devtools newplugin and name it ProductPDF
Judging from your code, it seems you’ve used this utility.
$ cd user/plugins/product-pdf
$ composer require tecnickcom/tcpdf
Note require instead of required
Create file /user/plugins/product-pdf/classes/MyPDF.pdf, with the following content:
<?php
namespace Grav\Plugin\ProductPDF;
use TCPDF;
class MyPDF extends TCPDF {
public $logoPath;
public $product;
public $dxfIconPath;
public $dxfFilePath;
public function Header() {
// Code
}
public function Footer() {
// Code
}
}
Note the CamelCase naming convention for both the file and class.
Make the following changes in file /user/plugins/product-pdf/product-pdf.php:
Add use Grav\Plugin\ProductPDF\MyPDF;
Don’t use require __DIR__ . '/vendor/autoload.php'; public function autoload() will be called by Grav when plugin is initialized.
Remove use TCPDF;
Remove entire class MYPDF
Replace $pdf = new MYPDF(...) with $pdf = new MyPDF(...)