Export users information as CSV file from a panel widget

Hi,

I try to export user information (firstname, lastname, email) in a CSV file from a panel widget.
It works but my CSV file begin with HTML content I would like to remove. My datas are at the bottom of the CSV file.

This is how I generate the CSV file:

…/plugins/export-users-csv/widgets/export-users-csv/export-users-csv.html.php

...
  // generate the CSV file
  if ( !empty( $exportonclick ) ) :

    $delimiter = ",";

    ob_end_clean();

    header('Pragma: no-cache');
    header('Expires: 0');
    header('Content-Type: text/csv');
    header('Content-Disposition: attachment; filename="export_users.csv"');

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

    fputcsv( $file, array( 'First name', 'Last name', 'Email' ) );

    foreach ( $export_users as $key_export_user => $export_user ) :

      $datas = array( 
        site()->user( $export_user->username() )->firstName(),
        site()->user( $export_user->username() )->lastName(), 
        site()->user( $export_user->username() )->email(),
      );

      fputcsv( $file, $datas );

    endforeach;

    fclose( $file );
    ob_flush();
    exit();

  endif;
...

Here a screenshot from my CSV:

What I am doing wrong? How to export just my datas whitout all this html content?
Any ideas?

Thanks

What is there in your file above the quoted code bit?

This is the entire code of …/plugins/export-users-csv/widgets/export-users-csv/export-users-csv.html.php

<?php


  $adminvalue = '';
  $organizersvalue = '';
  $evaluatorsvalue = '';
  $speakersvalue = '';
  $exportonclick = '';

  // get values from the checkbox
  $adminvalue = strip_tags( esc( get('admin') ) );
  $organizersvalue = strip_tags( esc( get('organizers') ) );
  $evaluatorsvalue = strip_tags( esc( get('evaluators') ) );
  $speakersvalue = strip_tags( esc( get('speakers') ) );
  $exportonclick = strip_tags( esc( get('export') ) );

  $adminusers = array();
  $organizersusers = array(); 
  $evaluatorsusers = array();
  $speakersusers = array();
  $datas = array();

  
  // get users from datas
  if ( !empty( $adminvalue ) ) :
    $adminusers = panel()->site()->users()->filterBy('role', 'admin')->toArray();
  endif;

  if ( !empty( $organizersvalue ) ) :
    $organizersusers = panel()->site()->users()->filterBy('role', 'organizer')->toArray();
  endif;

  if ( !empty( $evaluatorsvalue ) ) :
    $evaluatorsusers = panel()->site()->users()->filterBy('role', 'evaluator')->toArray();
  endif;

  if ( !empty( $speakersvalue ) ) :
    $speakersusers = panel()->site()->users()->filterBy('role', 'speaker')->toArray() ;
  endif;

  // merge all users
  $export_users = array_merge( $adminusers,  $evaluatorsusers, $organizersusers, $speakersusers );

  // generate the CSV file
  if ( !empty( $exportonclick ) ) :

    $delimiter = ",";

    ob_end_clean();

    header('Pragma: no-cache');
    header('Expires: 0');
    header('Content-Type: text/csv');
    header('Content-Disposition: attachment; filename="export_users.csv"');

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

    fputcsv( $file, array( 'First name', 'Last name', 'Email' ) );

    foreach ( $export_users as $key_export_user => $export_user ) :

      $datas = array( 
        site()->user( $export_user->username() )->firstName(),
        site()->user( $export_user->username() )->lastName(), 
        site()->user( $export_user->username() )->email(),
      );

      fputcsv( $file, $datas );

    endforeach;

    fclose( $file );
    ob_flush();
    exit();

  endif;



?>


<style>

/* widget css */

.button-container {
	margin-bottom: 20px;
}

.button-container-last {
	margin-bottom: 5px;
}

.button {
  padding: 0 5px;
}

</style>

<?= export_translation('export_help_text'); ?>

<br><br>

<div class="button-container-last">
  
  <form class="" action="<?= panel()->urls()->index . '/' ?>">
    <input type="checkbox" name="admin" value="admin">&nbsp;&nbsp;<?= export_translation('export_users_admin'); ?><br>
    <input type="checkbox" name="organizers" value="organizers">&nbsp;&nbsp;<?= export_translation('export_users_organizers'); ?><br>
    <input type="checkbox" name="evaluators" value="evaluators">&nbsp;&nbsp;<?= export_translation('export_users_evaluators'); ?><br>
    <input type="checkbox" name="speakers" value="speakers">&nbsp;&nbsp;<?= export_translation('export_users_speakers'); ?><br><br>
    <input type="hidden" name="export" value="yes">
    <button class="button" type="submit" name="exportusers" value="exportusers" ><?= export_translation('export_users_button'); ?></button>
  </form>
</div>


and here the widget:

But this HTML file is probably included in a main php file where you echo something before you send the headers. I think a cleaner way would be to call a route that does the cvs generating stuff.

Thanks for the route suggestion.

May I define the route in my plugin or do I have to define it in the config file?

You can define your route in your plugin file.