WordPress Admin: export CSV from custom table

I’m trying to export some data from a custom table to CSV. Ideally it would download the file immediately when clicking a button.

By searching the web I came up with a lot of pieces of code, but whatever I do, it doesn’t work. The main problem is: I get the desired output, but it just gets echoed within the admin area instead of creating a CSV file that can be downloaded.

Read More

I guess it is because my script runs inside WP admin and the WP headers get sent before the CSV header.

The only thing that comes to my mind now to prevent this: write the script in an external file and run this in a blank browser window. But then I’m in trouble getting WordPress user emails and names to be included (based on an ID from my custom table).

Right now I’m running this code in my custom plugin’s main file:

class export_table_to_csv{

private $db;
private $table_name;
private $separator;

function __construct($table_n, $sep, $filename, $eventid){

    global $wpdb;                                               
    $this->db = $wpdb;                                          
    $this->table_name = $table_n;                               
    $this->separator = $sep;
    $this->eventid = $eventid;

    $generatedDate = date('d-m-Y His');                         

    $csvFile = $this->generate_csv();                           
    header("Pragma: public");
    header("Expires: 0");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header("Cache-Control: private", false);                    
    header('Content-Type: application/csv; charset=UTF-8'); 

    header("Content-Disposition: attachment; filename="" . $filename . " " . $generatedDate . ".csv";" );
    header("Content-Transfer-Encoding: binary");
    header("Content-length: " . filesize($csvFile));

    echo $csvFile;                                             
    exit;
}


function generate_csv(){

    $csv_output = '';                                           
    $table = $this->db->prefix . $this->table_name;             

    $csv_output = $csv_output . "Name". $this->separator ."Email". $this->separator. "Value1". $this->separator ."Value2";
    $csv_output .= "n";


    $values = $this->db->get_results("SELECT userid,value1,value2 FROM " . $table . " WHERE eventid=".$this->eventid);       

    foreach ($values as $rowr) {

        $fields = array_values((array) $rowr);                  

        $UserID = $fields[0];
        $V1 = $fields[1];
        $V2 = $fields[2];

        $user_info = get_userdata($UserID);
        $first_name = $user_info->first_name;
        $last_name = $user_info->last_name;
        $Eml = $user_info->user_email;
        $Fullname = $first_name." ".$last_name;


        $csv_output = $csv_output.$Fullname.$this->separator.$Eml.$this->separator.$V1.$this->separator.$V2;
        $csv_output .= "n";  

    }

   return $csv_output; 

   }

}

EDIT:
Based on Nick’s code I tried another approach now.

Im calling the following as a separate file:

<?php 

$EventID = $_REQUEST["event"];

$location = $_SERVER['DOCUMENT_ROOT'];

include ($location . '/wp/wp-config.php');
include ($location . '/wp/wp-load.php');
include ($location . '/wp/wp-includes/pluggable.php');


// Name for File
$Loc = get_post_meta($EventID, 'tloc', true);
$Dat = get_post_meta($EventID, 'tdat', true); 

$y = substr($Dat, 2, 2);
$m = substr($Dat, 4, 2);
$d = substr($Dat, 6, 2);

$TheDate = $d.$m.$y;

header("Content-type: text/csv");
header("Content-Disposition: attachment;     filename=Res_".$Loc."_".$TheDate.".csv");
header("Pragma: no-cache");
header("Expires: 0");

$file = fopen('php://output', 'w'); 

$csv_header .= "Name; Email; Value1; Value2";
$csv_header  = "n";
fputcsv($file, $csv_header);


global $wpdb;
$csv_output = "";
$table_name = $wpdb->prefix . "nameoftable";    
$Res = $wpdb->get_results("SELECT userid, value1, value2 FROM $table_name WHERE eventid=$EventID"); 

foreach ($Res as $rowr) {

    $fields = array_values((array) $rowr); 

    $UserID = $fields[0];
    $V1 = $fields[1];
    $V2 = $fields[2];

    $user_info = get_userdata($UserID);
    $Eml = $user_info->user_email;
    $first_name = $user_info->first_name;
    $last_name = $user_info->last_name;
    $Fullname = $first_name." ".$last_name;

    $csv_output .= $Fullname;
    $csv_output .= "; ";
    $csv_output .= $Eml;
    $csv_output .= "; ";
    $csv_output .= $V1;
    $csv_output .= "; ";
    $csv_output .= $V2;
    $csv_output .= "n";  

    fputcsv($file, $csv_output); 
    $csv_output = "";

}    

exit();

?>

Now, a correctly named CSV file gets downloaded, but it is empty. If I delete the header stuff and use “echo” instead of “fputcsv” the data is there. What am I doing wrong?

Related posts

Leave a Reply

1 comment

  1. I think you do not need to echo csvfile. I had similar approach for generating user list as csv and here is a code which works.The thing is that I have it on a separate php file and the link on dashboard is pointing that separate php file. When clicked, it generates a csv and download starts. You could also create custom page and then in functions.php or somewhere else, write this functions and pre-check if is_page(‘target_page’) then run this function and then redirect back to where you are.

    <?php 
    // Include WP files so our generator can actually work with WP
    
    $location = $_SERVER['DOCUMENT_ROOT'];
    
    include ($location . '/wp-config.php');
    include ($location . '/wp-load.php');
    include ($location . '/wp-includes/pluggable.php');
    
    global $wpdb;
    
    function generatecsv() {
      global $wpdb;
    
         header("Content-type: text/csv");
          header("Content-Disposition: attachment; filename=Daily-Recruiter-CSV.csv");
          header("Pragma: no-cache");
          header("Expires: 0");
    
          //Functions for gethering data
    
    
    function how_many_recruiters_do_i_have() {
      global  $wp_query;
    
      $recruiters = count( get_users( array( 'meta_key' => 'user_role', 'meta_value' => 'recruiter' ) ) );
    
      $both = count( get_users( array( 'meta_key' => 'user_role', 'meta_value' => 'both' ) ) );
    
      return $recruiters + $both;
    }
    
    
    function how_many_recruiters_joined_yesterday($date='') {
    
        global $wpdb;
    
        if( empty($date) )
    
        $date = date('Y-m-d');
    
        $morning = new DateTime($date . ' 00:00:00');
    
        $night = new DateTime($date . ' 23:59:59'); 
    
    
        $m = $morning->format('Y-m-d H:i:s');
    
        $n = $night->format('Y-m-d H:i:s');
    
    
        $sql = $wpdb->prepare("SELECT og_users.* FROM og_users WHERE 1=1 AND CAST(user_registered AS DATE) BETWEEN %s AND %s ORDER BY user_login ASC",$m,$n);
    
        $users = $wpdb->get_results($sql);
    
        $recruiter_counter = 0;
    
        foreach ($users as $user) {
    
          if ( (get_user_meta($user->ID, 'user_role', true) == 'recruiter') || (get_user_meta($user->ID, 'user_role', true) == 'both') ) {
    
          $recruiter_counter++;
        }
    
        }
    return $recruiter_counter;
    
    }
    
    function how_many_times_did_recruiters_search() {
    
      global  $wp_query;
    
      $recruiters = array();
    
      $both = array();
    
      $recruiters = get_users( array( 'meta_key' => 'user_role', 'meta_value' => 'recruiter' ) ) ;
    
      $both = get_users( array( 'meta_key' => 'user_role', 'meta_value' => 'both' ) ) ;
    
      $merged_recruiters_array = array_merge($recruiters, $both);
    
        $search_counter = 0;
    
      foreach ($merged_recruiters_array as $user_object) {
    
        $search_counter = $search_counter + get_user_meta($user_object->ID, "search_number", true);
    
      }
    
    return $search_counter;
    
    }
    
    function how_many_times_recruiter_sent_email() {
    
      global  $wp_query;
    
      $recruiters = array();
    
      $both = array();
    
      $recruiters = get_users( array( 'meta_key' => 'user_role', 'meta_value' => 'recruiter' ) ) ;
    
      $both = get_users( array( 'meta_key' => 'user_role', 'meta_value' => 'both' ) ) ;
    
      $merged_recruiters_array = array_merge($recruiters, $both);
    
      $mail_counter = 0;
    
      foreach ($merged_recruiters_array as $user_object) {
    
        if(strip_tags( get_field( "sent_email_to", 'user_'.$user_object->ID )))
              { 
                  $emailsreceived = preg_replace( "/r|n/", "", strip_tags( get_field( "sent_email_to", 'user_'.$user_object->ID )));
                  $emailreceivedarray = explode(",", $emailsreceived);
                  $emailsnumber = count($emailreceivedarray);
                  $mail_counter = $mail_counter + ($emailsnumber-1);
              }
        }
    
        return $mail_counter;
      }
    
    
    function how_many_times_anyone_sent_email() {
    
      global  $wp_query;
    
      $recruiters = array();
    
      $both = array();
    
      $talent = array();
    
      $recruiters = get_users( array( 'meta_key' => 'user_role', 'meta_value' => 'recruiter' ) ) ;
    
      $both = get_users( array( 'meta_key' => 'user_role', 'meta_value' => 'both' ) ) ;
    
      $talent = get_users( array( 'meta_key' => 'user_role', 'meta_value' => 'talent' ) ) ;
    
      $merged_recruiters_array = array_merge($recruiters, $both, $talent);
    
      $mail_counter = 0;
    
      foreach ($merged_recruiters_array as $user_object) {
    
        if(strip_tags( get_field( "sent_email_to", 'user_'.$user_object->ID )))
              { 
                  $emailsreceived = preg_replace( "/r|n/", "", strip_tags( get_field( "sent_email_to", 'user_'.$user_object->ID )));
                  $emailreceivedarray = explode(",", $emailsreceived);
                  $emailsnumber = count($emailreceivedarray);
                  $mail_counter = $mail_counter + ($emailsnumber-1);
              }
        }
    
        return $mail_counter;
      }
    
    function how_many_recruiters_logged_in_this_day($date='') {
    
    
      global  $wp_query;
    
      $recruiters = array();
    
      $both = array();
    
      $recruiters = get_users( array( 'meta_key' => 'user_role', 'meta_value' => 'recruiter' ) ) ;
    
      $both = get_users( array( 'meta_key' => 'user_role', 'meta_value' => 'both' ) ) ;
    
      $merged_recruiters_array = array_merge($recruiters, $both);
    
      $counter = 0;
    
      foreach ($merged_recruiters_array as $user_object) {
    
        if(get_user_meta($user_object->ID, "user_log", true)) {
    
          if ( strpos(get_user_meta($user_object->ID, "user_log", true), $date)  !== false) {
            $counter++;
          }
        }
      }
    
    return $counter;
    }
    
    
          //open stream  
          $file = fopen('php://output', 'w');  
    
          // Add Headers                            
          fputcsv($file, array(
            'Date',
            'How many recruiters I have',
            'How many new recruiters joined today',
            'How many searches the recruiters did',
            'How many times recruiters contacted talent',
            'How many anyone contacted talent',
            'How many recruiters logged into the system'
    
            )); 
    
    $data = array();
    
    $offset = 30;
    
    $counter = 0;
          while ($counter < $offset ) {
            $counter++;
    
            $profileRow = array(
                date('d.m.Y',strtotime("-".$counter." days")),
                how_many_recruiters_do_i_have(),
                how_many_recruiters_joined_yesterday( date('Y-m-d',strtotime("-".$counter." days"))),
                how_many_times_did_recruiters_search(),
                how_many_times_recruiter_sent_email(),
                how_many_times_anyone_sent_email(),
                how_many_recruiters_logged_in_this_day(date('d.m.Y',strtotime("-".$counter." days")))
    
    
    
              );
            array_push($data, $profileRow);
          }
    
    
         foreach ($data as $row) {
    
                fputcsv($file, $row);   
    
         }
    
    
          exit(); 
    }
    
    generatecsv();
    
    ?>