1

I have a button in my WordPress page. when user clicks it, I make an Ajax request to functions.php and it should create a file and send it to user as a downloaded file.

here are the parts of codes:

userProfile.php:

<?php
echo "<input id='getUsersButton' type='button' class='actionButton' value='Download Users Email'/>";
?>

<script>
    jQuery(document).ready(function ($) {
        $('#getUsersButton').on('click', function (e) {
            e.preventDefault();

            var ajax_url = ajax_params.ajax_url;
            var data = {
                'action': 'them_getUsersEmail',
            };
            $.post(ajax_url, data, function (response) {
                if (JSON.parse(response) == true) {
                    window.alert("Sending your request...");
                } else {
                    window.alert("Error Handling Request");
                }
            });
        });
    });
</script>

functions.php:

<?php
function them_getUsersEmail() {
    $file = "test.txt";
    $txt = fopen($file, "w") or die("Unable to open file!");
    fwrite($txt, "test data");
    fclose($txt);

    header('Content-Description: File Transfer');
    header('Content-Disposition: attachment; filename='.basename($file));
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    header("Content-Type: text/plain");
    header("Content-Type: application/download");
    ob_clean();
    flush();
    readfile($file);
    echo json_encode(true);
    exit();
}

add_action('wp_ajax_them_getUsersEmail', 'them_getUsersEmail');
add_action('wp_ajax_nopriv_them_getUsersEmail', 'them_getUsersEmail');
?>

my problem is that I expect to receive a file after executing of them_getUsersEmail but instead, I will receive test.txt content(test data) as response variable in ajax callback in userProfile.php.

I also changed Ajax request as bellow but nothing changed and no file will be downloaded:

$.post(ajax_url, data);

I am new to php so my question is that if I am using the correct approach for implementation and if I am correct, how can I fix the problem?

thank you.

P.S: I would like to inform user that his request is accepted or rejected so I considered related window.alerts.

farzad
  • 368
  • 1
  • 3
  • 15
  • is the information protected? – Nick Maroulis Aug 21 '22 at 11:23
  • I have not implemented it yet but it will query the database and should return the result as a file – farzad Aug 21 '22 at 11:25
  • 1
    Are you trying to have AJAX “do work” and then have the browser present a native file download window? If so, see this: https://stackoverflow.com/a/9970672/231316 – Chris Haas Aug 21 '22 at 15:07
  • Your solution worked. but my question is if i am using the right approach? Using the link suggested approach, `them_getUsersEmail` now returns the raw data and i will create downloaded file by js. is this ok or is there better approach? @chris-hass – farzad Aug 22 '22 at 04:03
  • 3
    AJAX means a _background_ request, and you can not directly make the response cause a "frontend action", such as prompting for a download - so if you keep using AJAX, you will need to undertake this extra step. And alternative would be to submit a normal form instead (if you even need to send values via POST, otherwise a link with GET parameters might also do) - only then it should not go to the AJAX endpoint, but you should rather set up a custom REST API endpoint then, https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/ – CBroe Aug 22 '22 at 08:29

1 Answers1

0

Based on https://stackoverflow.com/a/9970672/231316 that is suggested by @chris-hass, I managed to temporarily fix the problem by creating download file by JS:

userProfile:

jQuery(document).ready(function ($) {
    $('#getUsersButton').on('click', function (e) {
        e.preventDefault();

        var ajax_url = ajax_params.ajax_url;
        var data = {
            'action': 'them_getUsersEmail',
        };
        $.post(ajax_url, data, function (response) {
            const url = window.URL.createObjectURL(new Blob([response], {type: "text/plain"}));
            const a = document.createElement('a');
            a.style.display = 'none';
            a.href = url;
            a.download = 'usersEmail.txt';
            document.body.appendChild(a);
            a.click();
            window.URL.revokeObjectURL(url);
            alert('your file has downloaded!'); // or you know, something with better UX...
        });
    });
});

functions.php

function them_getUsersEmail()
{
    echo json_encode("test");
    exit();
}

however I wonder that I am using the best approach for this requirement?

farzad
  • 368
  • 1
  • 3
  • 15