Skip to content

Instantly share code, notes, and snippets.

@maxkostinevich
Last active February 11, 2023 20:03
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save maxkostinevich/dbcb07f36ad4276c1010 to your computer and use it in GitHub Desktop.
Save maxkostinevich/dbcb07f36ad4276c1010 to your computer and use it in GitHub Desktop.
WordPress: Export custom data to CSV
<?php
/**
* Export Data to CSV file
* Could be used in WordPress plugin or theme
*/
// A sample link to Download CSV, could be placed somewhere in plugin settings page
?>
<a href="<?php echo admin_url( 'admin.php?page=myplugin-settings-page' ) ?>&action=download_csv&_wpnonce=<?php echo wp_create_nonce( 'download_csv' )?>" class="page-title-action"><?php _e('Export to CSV','my-plugin-slug');?></a>
<?php
// Add action hook only if action=download_csv
if ( isset($_GET['action'] ) && $_GET['action'] == 'download_csv' ) {
// Handle CSV Export
add_action( 'admin_init', 'csv_export' ;
}
function csv_export() {
// Check for current user privileges
if( !current_user_can( 'manage_options' ) ){ return false; }
// Check if we are in WP-Admin
if( !is_admin() ){ return false; }
// Nonce Check
$nonce = isset( $_GET['_wpnonce'] ) ? $_GET['_wpnonce'] : '';
if ( ! wp_verify_nonce( $nonce, 'download_csv' ) ) {
die( 'Security check error' );
}
ob_start();
$domain = $_SERVER['SERVER_NAME'];
$filename = 'users-' . $domain . '-' . time() . '.csv';
$header_row = array(
'Email',
'Name'
);
$data_rows = array();
global $wpdb;
$sql = 'SELECT * FROM ' . $wpdb->users;
$users = $wpdb->get_results( $sql, 'ARRAY_A' );
foreach ( $users as $user ) {
$row = array(
$user['user_email'],
$user['user_name']
);
$data_rows[] = $row;
}
$fh = @fopen( 'php://output', 'w' );
fprintf( $fh, chr(0xEF) . chr(0xBB) . chr(0xBF) );
header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' );
header( 'Content-Description: File Transfer' );
header( 'Content-type: text/csv' );
header( "Content-Disposition: attachment; filename={$filename}" );
header( 'Expires: 0' );
header( 'Pragma: public' );
fputcsv( $fh, $header_row );
foreach ( $data_rows as $data_row ) {
fputcsv( $fh, $data_row );
}
fclose( $fh );
ob_end_flush();
die();
}
@codenameEli
Copy link

Heads up on line 15 you are missing the ending paren,
add_action( 'admin_init', 'csv_export' ; -> add_action( 'admin_init', 'csv_export');

@elshazer
Copy link

elshazer commented Nov 1, 2018

// Add action hook only if action=download_csv

if ( isset($_GET['action'] ) && $_GET['action'] == 'download_csv' )  {
	// Handle CSV Export
	add_action( 'admin_init', 'csv_export' ;
}

Not functioned

@hiteshvpra
Copy link

hiteshvpra commented Feb 26, 2019

Hello Friends i have tested this code on my plugins, but when i export the csv then some errors occurred in the file.

  1. In the line number 15 closing parenthesis is missing.
    add_action( 'admin_init', 'csv_export' );

  2. For prevent unwanted html code in csv file just remove ob_start(); function from the line number 32.

Copy link

ghost commented Apr 25, 2019

I consistently get this error:
[25-Apr-2019 16:18:27 UTC] PHP Warning: Cannot modify header information - headers already sent by (output started at /home/content/p3pnexwpnas02_data02/43/42443143/html/wp-includes/class.wp-styles.php:242) in /home/content/p3pnexwpnas02_data02/43/42443143/html/wp-content/themes/modern-quince/inc/template-functions.php on line 556

And the page simply displays the contents of the would-be csv file. It does not export anything.

I have slightly modified the code to use as a regular function in my functions.php file as follows:

`function csv_export($data) {

ob_start();
$domain = $_SERVER['SERVER_NAME'];
$filename = 'export.csv';

$fh = @fopen( 'php://output', 'w' );
fprintf( $fh, chr(0xEF) . chr(0xBB) . chr(0xBF) );
header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' );
header( 'Content-Description: File Transfer' );
header( 'Content-type: text/csv' );
header( "Content-Disposition: attachment; filename={$filename}" );
header( 'Expires: 0' );
header( 'Pragma: public' );
foreach ( $data as $data_row ) {
    fputcsv( $fh, $data_row );
}
fclose( $fh );

ob_end_flush();

return;   

}`

When I made the final line exit or die it made the entire page stop loading. I am using this on the frontend of the site.

When a user clicks a "download this table" button, the page reloads with a query string.

Something like this (simplified for posting here):

if ($_GET['download']=='download') csv_export($data);

The $data variable is set to an array-of-arrays in an earlier call.

Please advise if you can. Thank you!

@darthmikeyd
Copy link

darthmikeyd commented May 8, 2019

I tried the following code, but it is adding the pages html code to the csv file. I tried removing the ob_start(); as suggested above, but that didn't work. Any help is appreciated.

ob_start();
global $wpdb;
$domain = $_SERVER['SERVER_NAME'];
$table = $wpdb->prefix . "qi_project_requests";
$filename = "export.csv";
$sql = $wpdb->get_results("select * from $table");		
$header_row = array(
	'Date Submitted',
	'Requestor Name'
);
$data_rows = array();
foreach ($sql as $data) {
	$row = array(
		$data->date,
		$data->rname
	);
        $data_rows[] = $row;
}
$fh = @fopen( 'php://output', 'w' ); 
fprintf( $fh, chr(0xEF) . chr(0xBB) . chr(0xBF) ); 
header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' ); 
header( 'Content-Description: File Transfer' ); 
header( 'Content-type: text/csv' ); 
header( "Content-Disposition: attachment; filename=$filename" ); 
header( 'Expires: 0' ); 
header( 'Pragma: public' ); 
fputcsv( $fh, $header_row ); 
foreach ( $data_rows as $data_row ) { 
	fputcsv( $fh, $data_row ); 
} 
fclose( $fh ); 
ob_end_flush(); 
die(); 

@Tsioriantenaina
Copy link

Hello. You have to add ob_end_clean() before $fh = @fopen( 'php://output', 'w' );
fclose($fh); exit();

@rajrn
Copy link

rajrn commented Jul 9, 2019

This is coreect code of file export in proper way please try it!

if (isset($_POST["export"]))
{

       $filename = 'Student_Table_' . time() . '.csv';
        $header_row = array(
            'S NO.',
            'First Name',
            'Last Name',
            'Email',
            'parent Name',
            'Address'
        );
       $data_rows = array();


        $users = $wpdb->get_results("SELECT * FROM ".$table_prefix."student ","ARRAY_A");
        foreach ( $users as $user ) 
        {
            $row = array(
            $user['id'],
            $user['f_name'],
            $user['l_name'],
            $user['email'],
            $user['p_name'],
            $user['address']
            );
            $data_rows[] = $row;
        }
        ob_end_clean ();
        $fh = @fopen( 'php://output', 'w' );
        header( "Content-Disposition: attachment; filename={$filename}" );
        fputcsv( $fh, $header_row );
        foreach ( $data_rows as $data_row ) 
        {
            fputcsv( $fh, $data_row );
        }
    
        
        exit();
    }

@apos37
Copy link

apos37 commented Dec 3, 2019

I have made the corrections that others mentioned in the comments, and it works fine for me in the admin area on my plugin settings page. Awesome! Thank you.

How do I make this work on the front end? I have made the following changes and I'm still having issues with the link, which takes me to a Page Not Found when I click on it:

add_action( 'init', 'csv_export_storelist');
if( is_admin() ){ return false; }

<a href="<?php echo $_GET['uri'] ?>&action=download_csv_bc&_wpnonce=<?php echo wp_create_nonce( 'download_csv' )?>" class="export_mapdatafile">Export to CSV</a>

Any suggestions?

@djcowan
Copy link

djcowan commented Apr 29, 2020

Thanks @maxkostinevich:
public function perfect( "first-time" ) : WP_Nice_One { return $this->is_much_appreciated(); }

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