Skip to content

Instantly share code, notes, and snippets.

@tommcfarlin
Last active December 6, 2022 04:16
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save tommcfarlin/5ed11e21332503deb90f to your computer and use it in GitHub Desktop.
Save tommcfarlin/5ed11e21332503deb90f to your computer and use it in GitHub Desktop.
[WordPress] Import a CSV file, break it into parts, and then import the data all the while providing the user with feedback.
<?php
/**
* Note that this file is for demonstration purposes only. It should be treated
* more like pseudo-code than code ready for production.
*
* The idea of the code below is how to break up a large CSV file into parts
* and then write the individual files to disk.
*/
// Read the contents of the file
$csv = file_get_contents( $file );
/* Separate each file into an index of an array and store the total
* number of rows that exist in the array. This assumes that
* each row of the CSV file is on a new line.
*/
$csv_rows = explode( "\n", $csv );
$total_rows = count( $csv_rows );
// Store the title row. This will be written at the top of every file.
$title_row = $csv_rows[ 0 ];
/* Calculate the number of rows that will consist of 10, and then calculate
* the number of rows for the final file.
*
* We use floor() so we don't round up by one.
*/
$rows_of_ten = floor( $total_rows / 10 );
$remaining_row = ( $rows_of_ten % 10 );
// Prepare to write out the files. This could just as easily be a for loop.
$file_counter = 0;
while( 0 < $rows_of_ten ) {
/* Create the output file that will contain a title row and a set of ten rows.
* The filename is generated based on which file we're importing.
*/
$output_file = fopen( dirname( __FILE__ ). '/acme_csv_' . $file_counter . '.csv', 'w' );
// Write out the title and then a batch of 10 rows into a string.
for( $i = 0; $i <= 10; $i++ ) {
/* Read the value from the array and then remove it from
* the array so it's not read again.
*/
$csv_data .= $csv_rows[ $i ] . "\n";
unset( $csv_rows[ $i ] );
}
/* Write out the file and then close the handle since we'll be opening
* a new one on the next iteration.
*/
fwrite( $output_file, $csv_data );
fclose( $output_file );
/* Increase the file counter by one and decrement the rows of 10,
* reset the keys for the rows of the array, and then reset the
* string of data to the title row
*/
$file_counter++;
$rows_of_ten--;
$csv_rows = array_values( $csv_rows );
$csv_data = $title_row;
}
<?php
/* $number_of_files can be calculated during the import process
* previously discussed.
*/
update_option( 'acme-number-of-files', $number_of_files );
/* An alternative way to do this is to read all of the CSV files
* that have been created after the process of creating the files
* has completed.
*/
$files = glob( dirname( __FILE__ ) . '/acme_csv_*.csv' );
update_option( 'acme-number-of-files', count( $files ) );
<?php
/* Setup the hook for the Ajax request.
* This may be done in the constructor or somewhere else in your
* plugin.
*/
add_action( 'wp_ajax_import_files', array( $this, 'import_files' ) );
/**
* Begins importing the files. Only comments below because the
* way in which you go about retrieving your files will vary
* based on your overall implementation.
*/
public function import_files() {
/*
* 1. Read the most recent file that has not been read
* 2. Insert the information from the file into the database
* 3. Delete (or unlink()) the file that was just created
* 4. Update the option of how many files have been processed.
*/
// Step 4 may look something like this:
if ( NULL === ( $parsed_files = get_option( 'acme-parsed-files' ) ) ) {
$parsed_files = 0;
}
update_option( 'acme-parsed-files', $parsed_files );
}
<?php
// Define the hook for getting the status somewhere in your plugin
add_action( 'wp_ajax_get_import_status', array( $this, 'get_import_status' ) );
public function get_import_status() {
/* Notice that in the above code that we use die() with
* a value - this is how the value is returned to
* the client requesting a value from this function.
*
* $progress indicates how far we are during the import,
* -1 indicates that we're done and we can eventually stop
* the timer.
*/
if ( FALSE !== get_option( 'acme-parsed-files' ) ) {
$parsed_files = floatval( get_option( 'acme-parsed-files' ) );
$total_files = floatval( get_option( 'acme-number-of-files' ) );
$progress = $parsed_files / $total_files;
die( $progress );
} else {
die( '-1' );
}
}
(function( $ ) {
'use strict';
$(function() {
/* Use the global WordPress 'ajaxurl' to send the request to WordPress
* and tell it to fire the import_files function.
*
* Use the response returned from the server for how to update the display
* when the operation has completely finished.
*/
$.post( ajaxurl, {
action: 'import_files'
}, function( response ) {
/* You can control the response from the server. In this case,
* I'm sending a '0' whenever all of the files have been imported.
*/
if ( '0' === response ) {
// Update the progress to 100%, display an 'import complete' message
}
});
});
})( jQuery );
(function( $ ) {
'use strict';
$(function() {
var importTimer;
/* Every second, we're going to poll the server to request for the
* value of the progress being made. This is using the get_import_status
* function on the server-side.
*
* If the response is -1, then the operation is done and we can stop the
* timer; otherwise, we can update the progressbar.
*/
importTimer = setInterval(function() {
// Get the current status of the update
$.get( ajaxurl, {
action: 'get_import_status'
}, function( response ) {
if ( '-1' === response ) {
// Set the progress bar equal to 100 and clear the timer
} else {
// Update the progress bar with (100 * response)
}
});
}, 1000 );
});
})( jQuery );
(function( $ ) {
'use strict';
$(function() {
var importTimer;
/* Every second, we're going to poll the server to request for the
* value of the progress being made. This is using the get_import_status
* function on the server-side.
*
* If the response is -1, then the operation is done and we can stop the
* timer; otherwise, we can update the progressbar.
*/
importTimer = setInterval(function() {
// Get the current status of the update
$.get( ajaxurl, {
action: 'get_import_status'
}, function( response ) {
if ( '-1' === response ) {
// Set the progress bar equal to 100 and clear the timer
} else {
// Update the progress bar with (100 * response)
}
});
}, 1000 );
/* Use the global WordPress 'ajaxurl' to send the request to WordPress
* and tell it to fire the import_files function.
*
* Use the response returned from the server for how to update the display
* when the operation has completely finished.
*/
$.post( ajaxurl, {
action: 'import_files'
}, function( response ) {
/* You can control the response from the server. In this case,
* I'm sending a '0' whenever all of the files have been imported.
*/
if ( '0' === response ) {
// Update the progress to 100%, display an 'import complete' message
}
});
});
})( jQuery );
@gianghl1983
Copy link

It seems you did not treat $remaining_row in 1/ :D

@Ozzy182
Copy link

Ozzy182 commented Dec 6, 2022

for "$remaining_row" i did:
if($remaining_row){
$rows_of_ten++;
}
just one increment cuz it wont be more than 9 when divided by 10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment