2

I am trying to get an ajax request to update the response as it goes through a loop, similar to a progress bar.

A bit of background on this snippet. Here is the JS Ajax request:

// ------------initiate ajax call to generate database entries------------
var ajax_data = {};
ajax_data.action = 'database_generate';
// ------------run ajax call and return response------------
jQuery.ajax({
  method: 'post',
  url: '/wp-admin/admin-ajax.php',
  data: ajax_data,
  success: function(response){
    response_container.innerText = response;
  }
});

The javascript is pretty straightforward "success" response. I suspect that this may be part of the issue as to why it wont return until the loop finishes. I don't know how to call it differently to update.

Here is the PHP Snippet:

// ------------loop through grouped CSV data------------
foreach ($return_arrary as $current_post) {
  // ------------check if current state exists in database------------
  if (!$post_exists($current_post['State'])) {
    // ------------create post data------------
    $post_array = array(
      'post_title' => $current_post['State'],
      'post_type' => 'jed_map_states',
      'post_status' => 'publish'
    );
    // ------------insert post into database------------
    wp_insert_post($post_array);
    $counter++;
  }
}
echo $counter." States added to database.";

The php is needs a tad more context. $return_array is a list of state names that are grabbed from a csv file. $post_exists is $wpdb call to check if a post with the same title has been created. $counter is initialized earlier in the script. If I place the echo inside of the foreach loop it only sends a huge response of each iteration after the loop finishes ie:

0 States Added
1 States Added
2 States Added
...etc etc

I suspect that it takes a bit since it has to make the $wpdb call every time on loop. I would be great if there was a real-time update as its working.

Any help would be greatly appreciated!

2
  • 1
    If you want to do the operation piecemeal you'll have to send the data a piece at a time, it's either going to be one large request or multiple smaller ones. The ajax action in WP won't produce anything until the callback ends or ideally exits/dies (i don't see any in your code but i appreciate it's probably just a portion of the code), what you echo/print inside the callback is what makes up the received response. Is there a reason you need to import the CSV data specifically in this manner? (there's a reasonable amount of existing import from CSV approaches out there already).
    – t31os
    Commented Nov 19, 2022 at 23:38
  • @t31os The plugin I am writing essentially is an svg map with US state data attached to it using custom post types. So essentially the CSV is just a way to create states in the beginning of install and later down the line if a state is accidentally deleted. I would have to make a js loop instead of a php loop then? I'm thinking I could send the counter bewteen the too but idk if thats the most efficient way or if it would update accurately
    – sallycakes
    Commented Nov 21, 2022 at 9:11

1 Answer 1

1

To update the response as the loop progresses, you can try the following:

1- Modify the PHP script to output the current loop count after each iteration, rather than waiting until the end of the loop to output the final count. This will allow the success callback in the Ajax request to update the response as the loop progresses.

2- In the success callback, you can use the response_container.innerText property to update the response with each iteration of the loop.

For example:

// ------------loop through grouped CSV data------------
foreach ($return_arrary as $current_post) {
// ------------check if current state exists in database------------
if (!$post_exists($current_post['State'])) {
// ------------create post data------------
$post_array = array(
'post_title' => $current_post['State'],
'post_type' => 'jed_map_states',
'post_status' => 'publish'
);
// ------------insert post into database------------
wp_insert_post($post_array);
$counter++;
// ------------output current loop count------------
echo $counter." States added to database.";
// ------------flush output buffer------------
ob_flush();
flush();
}
}

// ------------initiate ajax call to generate database entries------------
var ajax_data = {};
ajax_data.action = 'database_generate';
// ------------run ajax call and return response------------
jQuery.ajax({
method: 'post',
url: '/wp-admin/admin-ajax.php',
data: ajax_data,
success: function(response){
// ------------update response with each iteration of the loop------------
response_container.innerText = response;
}
});

Note: You may also need to add ignore_user_abort(true); at the beginning of the PHP script to prevent the script from being terminated when the user navigates away from the page.

Another option is to use JavaScript's setInterval function to periodically send an Ajax request to check the progress of the loop. In this case, you can modify the PHP script to store the current loop count in a session variable or in a temporary file, and the success callback in the Ajax request can read this value and update the response accordingly.

For example:

// ------------initiate ajax call to generate database entries------------
function checkProgress() {
// ------------run ajax call and return response------------
jQuery.ajax({
method: 'post',
url: '/wp-admin/admin-ajax.php',
data: {
action: 'check_progress'
},
success: function(response){
// ------------update response with current loop count------------
response_container.innerText = response;
// ------------stop interval if loop has finished------------
if (response === 'Done') {
clearInterval(intervalId);
}
}
});
}

// ------------check progress every 1000 milliseconds (1 second)------------
var intervalId = setInterval(checkProgress, 1000);

In the PHP script, you can use a session variable or a temporary file to store the current loop count and return it in the response:

// ------------start session------------
if (session_status() === PHP_SESSION_NONE) {
session_start);
}

// ------------loop through grouped CSV data------------
foreach ($return_arrary as $current_post) {
// ------------check if current state exists in database------------
if (!$post_exists($current_post['State'])) {
// ------------create post data------------
$post_array = array(
'post_title' => $current_post['State'],
'post_type' => 'jed_map_states',
'post_status' => 'publish'
);
// ------------insert post into database------------
wp_insert_post($post_array);
$counter++;
// ------------store current loop count in session variable------------
$_SESSION['counter'] = $counter;
}
}

// ------------action to check progress------------
function check_progress_action() {
// ------------return current loop count------------
echo $_SESSION['counter']." States added to database.";
exit;
}
add_action('wp_ajax_check_progress', 'check_progress_action');
add_action('wp_ajax_nopriv_check_progress', 'check_progress_action');

Note: Don't forget to end the session at the end of the PHP script by calling session_write_close().

I hope this helps! Let me know if you have any questions or need further assistance.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.