phpwordpresssavejspdfhtml2pdf

When saving/email PDF to WordPress, it keeps saving/emailing a blank corrupt PDF (jsPDF & html2pdf)


I have based from my code from https://github.com/eKoopmans/html2pdf.js/issues/181 (odedta) comment and also tried the second users comment below theirs.

I have a script using html2pdf bundle. Which works well. It create a multi page PDF with images. The content of the PDF is data which is pulled from a WordPress category (using a wp Query) and results in 3-6 Posts being put into a PDF.

HTML for example:

<script type="text/javascript" charset="utf8" src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>


<div id="PDFcontent">
<h1> PDF tile </h1>
<img src="https://styles.redditmedia.com/t5_2r5i1/styles/communityIcon_x4lqmqzu1hi81.jpg?width=256&s=fc15e67e2b431bbd2e93e980be3090306b78be55"> 
<div class="html2pdf__page-break"></div>
<h2 class="exhibitied-title"> Page 2 title<h2>
Some text
<div class="html2pdf__page-break"></div>
<h2> Page 3 title<h2>
Some text
</div>

I have my Jquery at the bottom of the page

jQuery(function($) {
            window.onload = function() {
                let el = document.getElementById('PDFcontent');
                var title = $('.exhibitied-title').text();
                let opt = {
                    margin: 0.2,
                    filename: title + '.pdf',
                    image: {
                        type: 'jpeg',
                        quality: 0.99
                    },
                    html2canvas: {
                        scale: 2,
                        logging: true,
                        dpi: 192,
                        letterRendering: true,
                        /* useCORS: true*/
                    },
                    jsPDF: {
                        unit: 'mm',
                        format: 'a4',
                        orientation: 'portrait'
                    }
                };
                html2pdf().set(opt).from(el).toPdf().output('datauristring').save().then(function(pdfAsString) {
                    title = $('.exhibitied-title').text();
                    filetitle = title + '.pdf';
                    let data = {
                        'action': 'send_email_with_pdf',
                        'fileDataURI': pdfAsString,
                        'filetitle': filetitle,
                    }
                    $.post(myAjax.ajaxurl, data, function(response) {
                        console.log(response);
                    });
                });
            }
        });

.save works perfectly, the PDF is formatted exactly how I want it.

But when it comes to saving or emailing the PDF I am having problems. The email is does send and a PDF is created. However the pdf in the email is 115bytes and just says "Failed to load PDF document." when you try opening it, and the pdf which is saved in my WP uploads folder is 0 bytes and also "Failed to load PDF document." shows.

Inside my functions.php I have

function send_email_with_pdf() {
    $pdfdoc     = $_POST['fileDataURI'];
    $b64file        = trim( str_replace( 'data:application/pdf;base64,', '', $pdfdoc ) );
    $b64file        = str_replace( ' ', '+', $b64file );
    $decoded_pdf    = base64_decode( $b64file );
    //file_put_contents( $attachment, $decodPdf );
    
    
     $upload_dir = wp_upload_dir();
     $image_data = file_get_contents( $decoded_pdf );
    $filename = $_POST['filetitle'];
    if ( wp_mkdir_p( $upload_dir['path'] ) ) {
                  $file = $upload_dir['path'] . '/' . $filename;
                }
                else {
                  $file = $upload_dir['basedir'] . '/' . $filename;
                }
    file_put_contents( $file, $image_data );
    $mail = new PHPMailer;
    $mail->setFrom( 'me@myemail.com', 'My name' );
    $mail->addAddress( 'you@youremail.com', 'your name' );
    $mail->Subject  = 'Subject';
    
    $mail->Body     = $filename;
    
    $mail->addStringAttachment($decoded_pdf, $filename);
    $mail->isHTML( false );
    if( !$mail->send() ) {
        $response = 'Message was not sent.';
        $response .= 'Mailer error: ' . $mail->ErrorInfo;
    }
    else {
        $response = 'Message has been sent.';
    }

    wp_send_json( $response );
}
add_action( 'wp_ajax_send_email_with_pdf', 'send_email_with_pdf' );
add_action( 'wp_ajax_nopriv_send_email_with_pdf', 'send_email_with_pdf' );

Is anyone able to point me in the right direction please, or has anyone come across this issue before?

I have posted as much information as I can, but please let me know if you need more information.


Solution

  • I got this working, for anyone else needing it.

    I have added notes in the code for explanation

    First add this to the top of your page

    <script type="text/javascript" charset="utf8" src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
    

    HTML / Wordpress content loop part

    <div id="PDFcontent">
    <h1 class="mypdftitle"> PDF tile </h1>
    <img src="https://styles.redditmedia.com/t5_2r5i1/styles/communityIcon_x4lqmqzu1hi81.jpg?width=256&s=fc15e67e2b431bbd2e93e980be3090306b78be55"> 
    <div class="html2pdf__page-break"></div>
    <h2> Page 2 title<h2>
    Some text
    <div class="html2pdf__page-break"></div>
    <h2> Page 3 title<h2>
    Some text
    </div>
    

    JQuery - goes at the bottom on the page above the footer

    jQuery(function($) {
        window.onload = function() {
            let el = document.getElementById('PDFcontent');
            var title = $('.exhibitied-title').text();
            let opt = { //Create/design the pdf
                margin: 0.2,
                filename: title + '.pdf',
                image: {
                    type: 'jpeg',
                    quality: 0.99
                },
                html2canvas: {
                    scale: 2,
                    logging: true,
                    dpi: 192,
                    letterRendering: true,
                },
                jsPDF: {
                    unit: 'mm',
                    format: 'a4',
                    orientation: 'portrait'
                }
            };
            html2pdf().from(el).set(opt).toPdf() /*add .save() if you need it to download locally too*/.output('datauristring').then(function(res) {
                this.blobString = res;
                title = $('mypdftitle').text(); //Get the title from h1 html
                filetitle = title; //set the title to be send in the ajax
                let data = {
                    'action': 'send_email_with_pdf', //Name of function in functions.php
                    'fileDataURI': this.blobString,
                    'filetitle': filetitle, //name of pdf - you set this above
                }
                $.post(myAjax.ajaxurl, data, function(response) { //myAjax.ajaxurl see the bottom code comment
                    console.log(response);
                    console.log(filetitle);
                });
                console.log(this.blobString);
            });
        }
    });
    ```
    

    Now in functions.php

        function send_email_with_pdf() {
            if (isset($_POST['fileDataURI'])) {
        
                /*** Prepare and decode the uri string ***/
                    $pdfdoc     = $_POST['fileDataURI']; // This looks like data:application/pdf;filename=generated.pdf;base64,JVBERi0xLjMKJbrfrOAKMyAwIG9iago8PC9UeXB....
                           $b64file        = str_replace( 'data:application/pdf;filename=generated.pdf;base64,', '', $pdfdoc ) ; //remove data:application/pdf;filename=generated.pdf;base64,
                         $decoded_pdf    = base64_decode(  $b64file  ); //decode it
        
        
        
                /**** Unique naming ****/   
                   $date = date("d-m-y"); // Today date day month year
                       $time = date("h:i"); // The time 
                 //Adding date and time to the pdf, will make sure each pdf generated is unique 
                 $ext = ".pdf"; //file extension
                     $thename = $_POST['filetitle']; //The title sent by ajax from the extension page
                     $name        = str_replace( ' ', '-', $thename ) ; //remove spaces - makes urls better
                $filename =  $name . '-' . $date . '-' . $time . $ext; // combine the file name
                //If you dont want date and time, then do the following $filename = $thename . $ext;
        
        
        
                /**** Upload directory *****/
                $upload_dir = wp_upload_dir();
                if (wp_mkdir_p($upload_dir['path'])) { // Puts the file in wp-content/uploads/year/month
                    $file = $upload_dir['path'].
                    '/'.$filename;
                } else {
                    $file = $upload_dir['basedir'].
                    '/'.$filename;
                }
        
        
                /*** Upload it ****/
                file_put_contents($file, $decoded_pdf);
        
        
        
                /*** Send the email ****/
                $mail = new PHPMailer;
                        $mail->setFrom( 'me@myemail.com', 'My name' );
                        $mail->addAddress( 'you@youremail.com', 'your name' );
                $mail - > Subject = $filename;
                $mail - > Body = $filename; //email text goes here, I have made it the file name for example
                $mail - > addStringAttachment($decoded_pdf, $filename);
                $mail - > isHTML(false);
                if (!$mail - > send()) {
                    $response = 'Message was not sent.';
                    $response. = 'Mailer error: '.$mail - > ErrorInfo;
                } else {
                    $response = 'Message has been sent.';
                    $response = $image_data;
                }
                wp_send_json($response);
            }
        }
        add_action('wp_ajax_send_email_with_pdf', 'send_email_with_pdf');
        add_action('wp_ajax_nopriv_send_email_with_pdf', 'send_email_with_pdf');
    

    For those who are unsure about the myAjax.ajaxurl in the JQuery part, Add this to the top of your functions.php in your WordPress theme, and then when ever you want to call Ajax on your site you can use the myAjax.ajaxurl

    add_action( 'init', 'script_enqueuer' );
    
    function script_enqueuer() {
       wp_register_script( "liker_script", get_stylesheet_directory_uri().'/js/functionality.js', array('jquery') );
       wp_localize_script( 'liker_script', 'myAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' )));        
        wp_enqueue_script( 'jquery' );
       wp_enqueue_script( 'liker_script' );
    }