Reputation: 47
I'm trying to make some reports for my wordpress plugin. This reports must be downloadable as excel. Basically what I did was creating a button and when that button were pressed, I will query the database and make an excel from the results.
Now I need to modify the header to return the results as excel file. This is how I did it:
header('Content-Disposition: attachment; filename='.$filename.'.xls');
header('Content-type: application/force-download');
header('Content-Transfer-Encoding: binary');
header('Pragma: public');
print "\xEF\xBB\xBF"; // UTF-8 BOM
The problem is it returns the following error:
Warning: Cannot modify header information - headers already sent by (output started at .....\wp-admin\menu-header.php:137)
I probably need ob_start() for this, but isn't that ob_start() must be placed BEFORE the first header (which is from the core files of Wordpress). I prefer not to modify the core files if possible.
Or maybe Wordpress' own hook 'send_headers'? but I can't get it to work, it's still generate the same error.
So what do I need to solve this problem? Is there exist another way to grenerate an excel file from wordpress plugin?
Any help appreciated!
Upvotes: 3
Views: 2214
Reputation: 3
This is a complete example i used following Danijel idea:
first the link to download:
<form action="" method="post">
<a class="btn btn-outline-success" href="<?php echo admin_url( '?download-excel' ); ?>">Descargar a Excel</a>
</form>
then the add action which leads to another file VerAliados.php:
add_action( 'plugins_loaded', function() {
if ( isset( $_GET['download-excel'] ) ) {
// here you can create .xls file
include ("Aliados/VerAliados.php");
//include ("Aliados/prueba.php");
global $Canal;
if ($Canal=="WFU"){
//echo "aca-aliado0";
$resp=descarga_aliados();
//echo $resp;
}
header('Content-Disposition: attachment; filename=resultados.xlsx');
header('Content-type: application/force-download');
header('Content-Transfer-Encoding: binary');
header('Pragma: public');
die();
}
});
VerAliados.php contains this function using the plugin CBXPHPSPREADSHEET:
function descarga_aliados() {
if ( defined('CBXPHPSPREADSHEET_PLUGIN_NAME') && file_exists( CBXPHPSPREADSHEET_ROOT_PATH . 'lib/vendor/autoload.php' ) ) {
require_once( CBXPHPSPREADSHEET_ROOT_PATH . 'lib/vendor/autoload.php' );
$objPHPExcel = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$sheet = $objPHPExcel->getActiveSheet();
$args = array(
'orderby' => 'id',
'user_registered' => 'ASC',
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'custom_field',
'value' => 'aliado',
)
)
);
$user_query = new WP_User_Query( $args );
$sheet->setCellValue('A1', 'ID');
$sheet->setCellValue('B1', 'Fecha_Registro_usuario');
$sheet->setCellValue('C1', 'Estado');
$sheet->setCellValue('D1', 'Email');
$sheet->setCellValue('E1', 'Nombre');
$row_num = 2;
foreach ( $user_query->get_results() as $user ) {
$sheet->setCellValue('A' . $row_num, $user->id);
$sheet->setCellValue('B' . $row_num, $user->user_registered);
$sheet->setCellValue('C' . $row_num, $user->afreg_new_user_status);
$sheet->setCellValue('D' . $row_num, $user->user_email);
$sheet->setCellValue('E' . $row_num, $user->afreg_additional_68083);
$row_num++;
}
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($objPHPExcel, "Xlsx");
$writer->save('resultados.xlsx');
$writer->save('php://output');
}
}
Upvotes: 0
Reputation: 12709
You send a header too late since header() is already sent in menu-header.php. From the code provided i can't see at which point you are sending header, but a good place would be in plugins_loaded action since that action hook is called when all plugins have been loaded, and before any output is sent.
The link for download can look like this:
<a href="<?php echo admin_url( '?download' ); ?>">download</a>
And, plugins_loaded action:
add_action( 'plugins_loaded', function() {
if ( isset( $_GET['download'] ) ) {
// here you can create .xls file
header('Content-Disposition: attachment; filename='.$filename.'.xls');
header('Content-type: application/force-download');
header('Content-Transfer-Encoding: binary');
header('Pragma: public');
die();
}
});
Upvotes: 4