title: Wordpress admin widget that exports data
body: <p>I've been coding in PHP for a long time, but I'm currently writing my first Wordpress plugin. The plugin's goals are:</p>
  
  <ul>
  <li>Display a form on a public-facing page to collect simple data from
  site visitors (first/last name, etc)</li>
  <li>Provide a way for admins export the data</li>
  </ul>
  
  <p>I've got a plugin that successfully creates a table on activation and a shortcode that provides a form which successfully stores the submitted data in the database.</p>
  
  <p>On the back-end, I have a dashboard widget that currently displays some stats about the submissions, and my last task is to provide a button to export those stats to CSV, and that's where I'm stumped.  I'm not sure how to handle this in WP world...in the past, I would have had the button open a new window to a page that does the exporting and echos a CSV string to the page along with headers that indicate it's a binary file so it's downloaded.  In WP, how do I accomplish this? Do I put a PHP script in my plugin directory and have my widget open that page? If so, how does that page gain access to $wpdb to handle the data access?</p>
  
  <p>Here is my code (just for the dashboard widget part) as it stands now:</p>
  
  <pre><code>&lt;?php
  /*
  Plugin meta details
   */
  add_action('init', 'myplugin_buffer_start');
  add_action('wp_footer', 'myplugin_buffer_end');
  
  function myplugin_ob_callback($buffer) {
      // You can modify buffer here, and then return the updated code
      return $buffer;
  }
  
  /**
   * Action: init
   * Runs after WP has finished loading but before any headers are sent, user is already authenticated at this point
   * Good for intercepting $_POST/$_GET
   */
  function myplugin_buffer_start() 
  { 
      ob_start("myplugin_ob_callback"); 
  }
  
  /**
   * Action wp_footer
   * Triggered near the &lt;/body&gt; tag of the user's template by the wp_footer() function.
   */
  function myplugin_buffer_end() 
  { 
      ob_end_flush(); 
  }
  
  
  /****************************************************************
   *  Stats Dashboard Widgets
   ***************************************************************/
  function myplugin_displaytestFormWidget_process()
  {
      $errors = array();
  
      if ( 'POST' == $_SERVER['REQUEST_METHOD'] &amp;&amp; isset ( $_POST['myplugin_export_button'] ))
      {
          ob_end_clean(); // erase the output buffer and turn off buffering...blow away all the markup/content from the buffer up to this point
  
          global $wpdb;
          $tableName = $wpdb-&gt;prefix . "myplugin_test_form";
          $qry = "select Name, Date from $tableName order by Date desc";
  
          //ob_start();  when I uncomment this, it works!
          $result = $wpdb-&gt;get_results($qry, ARRAY_A);
          if ($wpdb-&gt;num_rows)
          {
              $date = new DateTime();
              $ts = $date-&gt;format("Y-m-d-G-i-s");
              $filename = "myCsvFile-$ts.csv";
              header( 'Content-Type: text/csv' );
              header( 'Content-Disposition: attachment;filename='.$filename);
  
              $fp = fopen('php://output', 'w');
              //$headrow = $result[0];
              //fputcsv($fp, array_keys($headrow));
              foreach ($result as $data) {
                  fputcsv($fp, $data);
              }
              fclose($fp);
  
              //when I uncomment these lines along with adding ob_start above, it works
              //$contLength = ob_get_length();
              //header( 'Content-Length: '.$contLength);
          }
      }
  
      return myplugin_displaytestFormWidget();
  }   
  
  function myplugin_displaytestFormWidget()
  {
      global $wpdb;
      $tableName = $wpdb-&gt;prefix . "myplugin_test_form";
  
      $submissionCount = $wpdb-&gt;get_var("select count(Id) from $tableName");
  ?&gt;
      &lt;div&gt;&lt;strong&gt;Last entry: &lt;/strong&gt;John Q. test (May 5, 2013)&lt;/div&gt;
      &lt;div&gt;&lt;strong&gt;Total submissions: &lt;/strong&gt; &lt;?php echo $submissionCount ?&gt;&lt;/div&gt;
  
      &lt;form id="myplugin_test_export_widget" method="post" action=""&gt;
          &lt;input type="submit" name="myplugin_export_button" value="Export All" /&gt;
      &lt;/form&gt;
  &lt;?php
  }
  
  function myplugin_addDashboardWidgets()
  {
      // widget_id, widget_name, callback, control_callback
      wp_add_dashboard_widget(
          'test-form-widget', 
          'test Form Submissions', 
          'myplugin_displaytestFormWidget_process'
      );  
  }
  
  /****************************************************************
   *  Hooks
   ***************************************************************/
  //add_action('widgets_init', 'simple_widget_init');
  add_action('wp_dashboard_setup', 'myplugin_addDashboardWidgets' ); 
  
  // This shortcode will inject the form onto a page
  add_shortcode('test-form', 'myplugin_displaytestForm_process');
  
  register_activation_hook(__FILE__, 'myplugin_test_form_activate');
  </code></pre>
  
  <p>You can see in the <strong>myplugin_displayTestFormWidget</strong> function I'm displaying the form, I just don't know what to do with the button to make it all jive.</p>
  
  <p><img src="https://i.stack.imgur.com/1Jr36.png" alt="Screenshot of widget output"></p>
  
  <p>Can anyone assist?</p>