Search code examples
phpjqueryajaxwordpressgravity-forms-plugin

How to initiate a file download after Gravity Forms AJAX submit


I have a Gravity Form where users have checkboxes set up to choose which files to download. For enhanced UX, the form is multi-page and uses AJAX.

Using the following PHP function and Gravity Forms Hook, I am able to loop through the selected checkboxes and add files into a ZIP Archive, but can't currently start the download.

add_filter( 'gform_after_submission_3', 'download_brochures_message', 10, 4 );
function download_brochures_message( $entry ) {

$confirmation = "Your download should begin shortly. \r\n";
$error = "Files not set \r\n";

$file1 = rgar( $entry, '1.1' );
$file2 = rgar( $entry, '1.2' );
$file3 = rgar( $entry, '1.3' );
$file4 = rgar( $entry, '1.4' );

$files = array(
        $file1,
        $file2,
        $file3,
        $file4
    );

print_r($files);

$zip = new ZipArchive();

$current_time = time();

$file_folder = wp_upload_dir();

$dir = $file_folder['path'];

$zip_file = tempnam( $dir, time() );

$zip->open( $zip_file, ZipArchive::CREATE );

foreach ($files as $file) {
    $zip->addFile($file);
}

$zip->close();

echo $zip_file;

header('Content-disposition: attachment; filename="'.$zip_name.'"');
header('Content-type: application/zip');
header('Content-Length: ' . filesize($zip_file));
header("Location: $zip_file");
readfile($zip_file);
}

Since the form submit's via AJAX, the page headers have already been sent and the PHP errors I receive are "Cannot modify header information - headers already sent". How could I modify this code to allow the zip to download?


Solution

  • To achieve a fully working solution to this required the PHP backend functions to handle creating the zip based on POST'ed form values and a small bit of JavaScript to initiate the download.

    PHP:

    /**
     * Function to force file download based on user selected checkboxes.
     */
    add_filter( 'gform_confirmation_{your-form-id}', 'get_chosen_brochures', 10, 4 );
    function get_chosen_brochures( $confirmation, $form, $entry, $ajax ) {
        $brochures = retrieve_brochure_data( $entry );
        $confirmation = start_brochures_download( $brochures );
        return $confirmation;
    }
    
    function retrieve_brochure_data( $entry ){
        $radio_value_1 = rgar( $entry, '1.1' );
        $radio_value_2 = rgar( $entry, '1.2' );
        $radio_value_3 = rgar( $entry, '1.3' );
        $radio_value_4 = rgar( $entry, '1.4' );
    
        return array(
                $radio_value_1,
                $radio_value_2,
                $radio_value_3,
                $radio_value_4
            );
    }
    
    function start_brochures_download( $brochures ) {
        $files = $brochures;
        $error = "Files not set";
        $success = "Thank you. Your download will being shortly.";
        if( $files ) {
    
            $zip = new ZipArchive();
    
            $current_time = time();
    
            $file_name = "Archive-Name-".$current_time.".zip";
    
            $file_folder = wp_upload_dir();
            $dir = $file_folder['path'];
            $url = $file_folder['url'];
            $zip_file = $dir.'/'.$file_name;
            $zip_url = $url.'/'.$file_name;
    
            $zip->open( $zip_file, ZipArchive::CREATE );
    
            foreach ($files as $key => $file) {
                if( !empty($file) ){
                    # download file
                    $download_file = file_get_contents($file);
    
                    #add it to the zip
                    $zip->addFromString(basename($file), $download_file);
                }
                $error .= "\n *File $key is empty";
            }
    
            $zip->close();
    
            return $success . " If your download doesn't begin automatically, you can click <a id='generated-download-link' href='{$zip_url}'>here to start the download</a>.";
    
        } else {
            return $error;
        }
    }
    

    JS:

    $(document).bind('gform_confirmation_loaded', function(event, formId){
        if( formId === 3 ){
            var download_url = $("#generated-download-link").attr('href');
            if(download_url) {
                var delay = 2000;
                setTimeout( function(){ window.location = download_url; }, delay );
            }
        }
    });
    

    The biggest part of my issue with the initial code was related to me not being able to alter page headers after the page was loaded. This was a limitation of using AJAX forms, however AJAX was a requirement due to some UX flows which are in place.

    To reuse this code, you will need to set the radio button or checkbox value to the URL of the file you wish to download.