💻 DéveloppementIntermédiaire PS 1.7 PS 8.x

Générer un PDF dans un module PrestaShop : guide complet

Découvrez comment générer des PDF personnalisés dans un module PrestaShop : contrôleur dédié, classe PDF, erreurs AJAX courantes et bonnes pratiques.

En bref : Pour générer un PDF dans PrestaShop, évitez AJAX et utilisez une URL directe vers un contrôleur dédié qui envoie le fichier avec les bons en-têtes HTTP. Créez un ModuleFrontController qui récupère l'ID commande via Tools::getValue(), vérifie les droits d'accès, puis appelle la classe PDF native ou TCPDF pour le rendu.

Publié le 21 mars 2026 6 min de lecture Alexandre Carette

Générer un PDF dans un module PrestaShop : guide complet

La génération de documents PDF — factures personnalisées, bons de livraison, attestations ou tout autre document métier — est un besoin récurrent dans l'écosystème PrestaShop. Pourtant, de nombreux développeurs se heurtent à des PDF qui ne se génèrent tout simplement pas, souvent à cause d'un mauvais choix d'architecture pour déclencher la génération.

Cet article détaille les bonnes pratiques pour créer un système de génération PDF fiable dans un module PrestaShop, en évitant les pièges classiques liés à AJAX et aux en-têtes HTTP.

Pourquoi la génération PDF échoue souvent via AJAX

L'erreur la plus fréquente consiste à vouloir générer un PDF via une requête AJAX. Le problème est fondamental : un PDF est un fichier binaire que le navigateur doit recevoir avec les bons en-têtes HTTP (Content-Type: application/pdf, Content-Disposition) pour déclencher le téléchargement ou l'affichage.

Or, une requête AJAX intercepte la réponse en JavaScript. Le navigateur ne sait pas qu'il doit ouvrir un fichier — il reçoit du binaire brut dans un callback JS, ce qui produit :

  • Un fichier corrompu si on tente de le reconstruire côté client
  • Une page blanche si la réponse n'est pas traitée
  • Des erreurs `json_decode` si le contrôleur attend du JSON mais reçoit du binaire

La solution : une requête HTTP classique

Pour générer un PDF, il suffit de passer par une URL directe ou un formulaire HTML classique. Le navigateur reçoit alors les en-têtes corrects et propose le téléchargement nativement.


// ❌ Mauvaise approche : AJAX
$.ajax({
    url: baseUrl + 'module/monmodule/generatepdf',
    data: { id_order: orderId },
    success: function(response) {
        // Le PDF binaire arrive ici... inutilisable
    }
});

// ✅ Bonne approche : redirection directe
window.location.href = baseUrl + 'module/monmodule/generatepdf?id_order=' + orderId;

Créer un contrôleur dédié à la génération PDF

La méthode recommandée est de créer un ModuleFrontController (ou ModuleAdminController) qui reçoit l'identifiant de la commande via l'URL et génère le PDF.

Structure du module


monmodule/
├── monmodule.php
├── controllers/
│   └── front/
│       └── generatepdf.php
└── classes/
    └── MonModulePDFGenerator.php

Le contrôleur front (PrestaShop 1.7 / 8.x)


<?php
/**
 * Contrôleur de génération PDF
 */
class MonModuleGeneratepdfModuleFrontController extends ModuleFrontController
{
    public function initContent()
    {
        parent::initContent();

        // Récupérer l'ID commande depuis l'URL
        $id_order = (int) Tools::getValue('id_order');

        if (!$id_order) {
            Tools::redirect('index.php?controller=history');
        }

        // Vérifier que la commande appartient au client connecté
        $order = new Order($id_order);
        if (!Validate::isLoadedObject($order)
            || $order->id_customer !== (int) $this->context->customer->id
        ) {
            Tools::redirect('index.php?controller=history');
        }

        // Générer le PDF
        $this->generateOrderPDF($order);
    }

    protected function generateOrderPDF(Order $order)
    {
        // Utiliser la classe PDF native de PrestaShop
        $pdf = new PDF($order, PDF::TEMPLATE_INVOICE, $this->context->smarty);
        $pdf->render();
        exit; // Important : stopper l'exécution après l'envoi du PDF
    }
}

Appel depuis un template Smarty


<a href="{$link->getModuleLink('monmodule', 'generatepdf', ['id_order' => $order.id_order])}" 
   class="btn btn-primary" 
   target="_blank">
    Télécharger le PDF
</a>

Alternativement, un formulaire HTML classique fonctionne tout aussi bien :


<form method="GET" action="{$link->getModuleLink('monmodule', 'generatepdf')}" target="_blank">
    <input type="hidden" name="id_order" value="{$order.id_order}">
    <button type="submit" class="btn btn-primary">Générer le PDF</button>
</form>

Créer un PDF personnalisé avec TCPDF

PrestaShop embarque TCPDF. Pour des documents sur mesure (attestation, certificat, bon de garantie), on peut s'en servir directement.


<?php
class MonModulePDFGenerator
{
    public static function generate(Order $order)
    {
        // TCPDF est chargé par PrestaShop
        $pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8');
        $pdf->SetCreator('Ma Boutique');
        $pdf->SetAuthor('Ma Boutique');
        $pdf->SetTitle('Document #' . $order->reference);

        // Supprimer en-tête/pied par défaut
        $pdf->setPrintHeader(false);
        $pdf->setPrintFooter(false);

        $pdf->AddPage();
        $pdf->SetFont('helvetica', 'B', 16);
        $pdf->Cell(0, 15, 'Document personnalisé', 0, 1, 'C');

        $pdf->SetFont('helvetica', '', 12);
        $pdf->Cell(0, 10, 'Commande : ' . $order->reference, 0, 1);
        $pdf->Cell(0, 10, 'Date : ' . Tools::displayDate($order->date_add), 0, 1);

        // Contenu HTML si besoin
        $html = '<table border="1" cellpadding="5">';
        $html .= '<tr><th>Produit</th><th>Quantité</th><th>Prix</th></tr>';

        $products = $order->getProducts();
        foreach ($products as $product) {
            $html .= '<tr>';
            $html .= '<td>' . htmlspecialchars($product['product_name']) . '</td>';
            $html .= '<td>' . (int) $product['product_quantity'] . '</td>';
            $html .= '<td>' . Tools::displayPrice($product['total_price_tax_incl']) . '</td>';
            $html .= '</tr>';
        }
        $html .= '</table>';

        $pdf->writeHTML($html, true, false, true, false, '');

        // Envoyer le PDF au navigateur
        $pdf->Output('document-' . $order->reference . '.pdf', 'D');
    }
}

Côté back-office : AdminController

Pour la génération depuis le back-office, le principe est identique. On utilise un ModuleAdminController avec un token CSRF vérifié automatiquement par PrestaShop :


<?php
class AdminMonModulePdfController extends ModuleAdminController
{
    public function postProcess()
    {
        if (Tools::isSubmit('generateCustomPdf')) {
            $id_order = (int) Tools::getValue('id_order');
            $order = new Order($id_order);

            if (Validate::isLoadedObject($order)) {
                MonModulePDFGenerator::generate($order);
                exit;
            }

            $this->errors[] = $this->l('Commande introuvable.');
        }
    }
}

Gérer le cas où AJAX est incontournable

Si votre UX impose vraiment une requête AJAX (par exemple pour afficher un loader pendant la génération), la solution consiste à séparer la logique en deux étapes :

  1. **Requête AJAX** : prépare le PDF et le stocke temporairement sur le serveur
  2. **Redirection** : redirige vers une URL de téléchargement
  3. 
    // Étape 1 : préparer le PDF via AJAX
    fetch(baseUrl + 'module/monmodule/preparepdf', {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: 'id_order=' + orderId + '&ajax=1'
    })
    .then(response => response.json())
    .then(data => {
        if (data.success && data.download_url) {
            // Étape 2 : télécharger le PDF préparé
            window.location.href = data.download_url;
        }
    });
    

    Côté PHP, le contrôleur de préparation génère le fichier, le stocke dans un dossier temporaire, et renvoie l'URL :

    
    public function displayAjaxPreparePdf()
    {
        $id_order = (int) Tools::getValue('id_order');
        $order = new Order($id_order);
    
        // Générer et stocker le PDF
        $filename = 'doc_' . $order->reference . '_' . time() . '.pdf';
        $filepath = _PS_MODULE_DIR_ . 'monmodule/tmp/' . $filename;
    
        // ... logique de génération avec TCPDF ::Output($filepath, 'F') ...
    
        $download_url = $this->context->link->getModuleLink(
            'monmodule', 'downloadpdf', ['file' => $filename, 'token' => $this->generateSecureToken($filename)]
        );
    
        die(json_encode([
            'success' => true,
            'download_url' => $download_url
        ]));
    }
    

    Sécurité : ne jamais exposer directement le chemin du fichier. Utilisez un token temporaire pour valider le téléchargement et supprimez le fichier après un délai raisonnable via un cron.

    Checklist de débogage PDF

    Si votre PDF ne se génère pas, vérifiez ces points dans l'ordre :

    VérificationCommande / Action Erreurs PHP masquéesActiver le mode debug : `define('_PS_MODE_DEV_', true);` Sortie parasite avant le PDFVérifier qu'aucun `echo`, `var_dump` ou BOM UTF-8 ne précède la sortie Droits d'écriture`chmod 755` sur le dossier temporaire du module Mémoire PHP suffisante`memory_limit` ≥ 256M pour les PDF volumineux AJAX vs requête directeTester l'URL du PDF directement dans le navigateur Objet Order valideVérifier `Validate::isLoadedObject($order)` avant la génération
#pdf #module prestashop #tcpdf #génération documents #controleur admin

Questions fréquentes

Tout ce que vous devez savoir sur ce sujet.

Un projet PrestaShop ?

Discutons-en directement.

★★★★★

193 projets livrés

Gratuit & sans engagement — réponse sous 24h

Alexandre Carette

Alexandre Carette

Expert PrestaShop & Architecture E-commerce

Développeur PrestaShop depuis 2014, 193 projets livrés. Je conçois des architectures headless Nuxt + PrestaShop et des outils d'automatisation IA pour les e-commerçants.