|
@@ -15,38 +15,52 @@ class Studiou_WC_FPP_Admin {
|
|
|
add_action('wp_ajax_studiou_wcfpp_update_status', array($this, 'ajax_update_status'));
|
|
add_action('wp_ajax_studiou_wcfpp_update_status', array($this, 'ajax_update_status'));
|
|
|
add_action('wp_ajax_studiou_wcfpp_delete_files', array($this, 'ajax_delete_files'));
|
|
add_action('wp_ajax_studiou_wcfpp_delete_files', array($this, 'ajax_delete_files'));
|
|
|
add_action('wp_ajax_studiou_wcfpp_download_zip', array($this, 'ajax_download_zip'));
|
|
add_action('wp_ajax_studiou_wcfpp_download_zip', array($this, 'ajax_download_zip'));
|
|
|
|
|
+ add_action('wp_ajax_studiou_wcfpp_download_csv', array($this, 'ajax_download_csv'));
|
|
|
add_action('wp_ajax_studiou_wcfpp_bulk_status', array($this, 'ajax_bulk_status'));
|
|
add_action('wp_ajax_studiou_wcfpp_bulk_status', array($this, 'ajax_bulk_status'));
|
|
|
|
|
|
|
|
- // Handle direct ZIP download and file download (marks as downloaded)
|
|
|
|
|
|
|
+ // Handle direct ZIP / CSV download and file download (marks as downloaded)
|
|
|
add_action('admin_init', array($this, 'handle_zip_download'));
|
|
add_action('admin_init', array($this, 'handle_zip_download'));
|
|
|
|
|
+ add_action('admin_init', array($this, 'handle_csv_download'));
|
|
|
add_action('admin_init', array($this, 'handle_file_download'));
|
|
add_action('admin_init', array($this, 'handle_file_download'));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public function render_summary_page() {
|
|
public function render_summary_page() {
|
|
|
// Process filters
|
|
// Process filters
|
|
|
- $current_status = isset($_GET['status']) ? sanitize_text_field($_GET['status']) : '';
|
|
|
|
|
|
|
+ $current_status = isset($_GET['status']) ? sanitize_text_field($_GET['status']) : '';
|
|
|
$current_product = isset($_GET['product_id']) ? absint($_GET['product_id']) : 0;
|
|
$current_product = isset($_GET['product_id']) ? absint($_GET['product_id']) : 0;
|
|
|
- $current_search = isset($_GET['s']) ? sanitize_text_field($_GET['s']) : '';
|
|
|
|
|
- $current_page = isset($_GET['paged']) ? max(1, absint($_GET['paged'])) : 1;
|
|
|
|
|
- $per_page = 30;
|
|
|
|
|
|
|
+ $current_order = isset($_GET['order_id']) ? absint($_GET['order_id']) : 0;
|
|
|
|
|
+ $current_search = isset($_GET['s']) ? sanitize_text_field($_GET['s']) : '';
|
|
|
|
|
+ $current_page = isset($_GET['paged']) ? max(1, absint($_GET['paged'])) : 1;
|
|
|
|
|
+ $per_page = 30;
|
|
|
|
|
+
|
|
|
|
|
+ $allowed_orderby = array('order_id', 'status', 'created_at');
|
|
|
|
|
+ $orderby_in = isset($_GET['orderby']) ? sanitize_text_field($_GET['orderby']) : 'created_at';
|
|
|
|
|
+ $orderby = in_array($orderby_in, $allowed_orderby, true) ? $orderby_in : 'created_at';
|
|
|
|
|
+ $order_in = isset($_GET['order']) ? strtoupper(sanitize_text_field($_GET['order'])) : 'DESC';
|
|
|
|
|
+ $order = ($order_in === 'ASC') ? 'ASC' : 'DESC';
|
|
|
|
|
|
|
|
$args = array(
|
|
$args = array(
|
|
|
- 'status' => $current_status,
|
|
|
|
|
|
|
+ 'status' => $current_status,
|
|
|
'product_id' => $current_product,
|
|
'product_id' => $current_product,
|
|
|
- 'search' => $current_search,
|
|
|
|
|
- 'limit' => $per_page,
|
|
|
|
|
- 'offset' => ($current_page - 1) * $per_page,
|
|
|
|
|
- 'orderby' => isset($_GET['orderby']) ? sanitize_text_field($_GET['orderby']) : 'created_at',
|
|
|
|
|
- 'order' => isset($_GET['order']) ? sanitize_text_field($_GET['order']) : 'DESC',
|
|
|
|
|
|
|
+ 'order_id' => $current_order,
|
|
|
|
|
+ 'search' => $current_search,
|
|
|
|
|
+ 'limit' => $per_page,
|
|
|
|
|
+ 'offset' => ($current_page - 1) * $per_page,
|
|
|
|
|
+ 'orderby' => $orderby,
|
|
|
|
|
+ 'order' => $order,
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
- $records = $this->db->get_file_records($args);
|
|
|
|
|
- $total = $this->db->count_file_records($args);
|
|
|
|
|
|
|
+ $records = $this->db->get_file_records($args);
|
|
|
|
|
+ $total = $this->db->count_file_records($args);
|
|
|
$total_pages = ceil($total / $per_page);
|
|
$total_pages = ceil($total / $per_page);
|
|
|
|
|
|
|
|
// Get products that have FPP enabled for filter dropdown
|
|
// Get products that have FPP enabled for filter dropdown
|
|
|
$fpp_products = $this->get_fpp_products();
|
|
$fpp_products = $this->get_fpp_products();
|
|
|
|
|
|
|
|
|
|
+ // Expose active sort to the view
|
|
|
|
|
+ $current_orderby = $orderby;
|
|
|
|
|
+ $current_order_dir = $order;
|
|
|
|
|
+
|
|
|
include STUDIOU_WCFPP_PLUGIN_DIR . 'views/admin-summary.php';
|
|
include STUDIOU_WCFPP_PLUGIN_DIR . 'views/admin-summary.php';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -255,6 +269,127 @@ class Studiou_WC_FPP_Admin {
|
|
|
exit;
|
|
exit;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ public function ajax_download_csv() {
|
|
|
|
|
+ check_ajax_referer('studiou-wcfpp-nonce', 'nonce');
|
|
|
|
|
+
|
|
|
|
|
+ if (!current_user_can('manage_woocommerce')) {
|
|
|
|
|
+ wp_send_json_error(array('message' => __('Insufficient permissions.', 'studiou-wc-free-photo-product')));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $file_ids = isset($_POST['file_ids']) ? array_map('absint', (array) $_POST['file_ids']) : array();
|
|
|
|
|
+ if (empty($file_ids)) {
|
|
|
|
|
+ wp_send_json_error(array('message' => __('No files selected.', 'studiou-wc-free-photo-product')));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $records = $this->db->get_file_records_by_ids($file_ids);
|
|
|
|
|
+ if (empty($records)) {
|
|
|
|
|
+ wp_send_json_error(array('message' => __('No files found.', 'studiou-wc-free-photo-product')));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $upload_dir = wp_upload_dir();
|
|
|
|
|
+ $csv_name = 'fpp-records-' . date('Y-m-d-His') . '.csv';
|
|
|
|
|
+ $csv_dir = $upload_dir['basedir'] . '/studiou-fpp-chunks';
|
|
|
|
|
+ if (!file_exists($csv_dir)) {
|
|
|
|
|
+ wp_mkdir_p($csv_dir);
|
|
|
|
|
+ }
|
|
|
|
|
+ $csv_path = $csv_dir . '/' . $csv_name;
|
|
|
|
|
+
|
|
|
|
|
+ $fh = fopen($csv_path, 'wb');
|
|
|
|
|
+ if (!$fh) {
|
|
|
|
|
+ wp_send_json_error(array('message' => __('Could not create CSV file.', 'studiou-wc-free-photo-product')));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // UTF-8 BOM so Excel opens the file with the correct encoding
|
|
|
|
|
+ fwrite($fh, "\xEF\xBB\xBF");
|
|
|
|
|
+
|
|
|
|
|
+ // Header row — column labels translated
|
|
|
|
|
+ fputcsv($fh, array(
|
|
|
|
|
+ __('ID', 'studiou-wc-free-photo-product'),
|
|
|
|
|
+ __('File Name', 'studiou-wc-free-photo-product'),
|
|
|
|
|
+ __('Product', 'studiou-wc-free-photo-product'),
|
|
|
|
|
+ __('Variation ID', 'studiou-wc-free-photo-product'),
|
|
|
|
|
+ __('Order', 'studiou-wc-free-photo-product'),
|
|
|
|
|
+ __('Customer', 'studiou-wc-free-photo-product'),
|
|
|
|
|
+ __('Status', 'studiou-wc-free-photo-product'),
|
|
|
|
|
+ __('Date', 'studiou-wc-free-photo-product'),
|
|
|
|
|
+ __('File URL', 'studiou-wc-free-photo-product'),
|
|
|
|
|
+ ));
|
|
|
|
|
+
|
|
|
|
|
+ foreach ($records as $record) {
|
|
|
|
|
+ $product_title = get_the_title($record->product_id);
|
|
|
|
|
+
|
|
|
|
|
+ if ((int) $record->customer_id > 0) {
|
|
|
|
|
+ $user = get_userdata((int) $record->customer_id);
|
|
|
|
|
+ $customer_name = $user ? $user->display_name : '#' . (int) $record->customer_id;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $customer_name = __('Guest', 'studiou-wc-free-photo-product');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $file_url = wp_get_attachment_url((int) $record->attachment_id);
|
|
|
|
|
+
|
|
|
|
|
+ fputcsv($fh, array(
|
|
|
|
|
+ (int) $record->id,
|
|
|
|
|
+ (string) $record->file_name,
|
|
|
|
|
+ (string) $product_title,
|
|
|
|
|
+ (int) $record->variation_id,
|
|
|
|
|
+ (int) $record->order_id ? '#' . (int) $record->order_id : '',
|
|
|
|
|
+ (string) $customer_name,
|
|
|
|
|
+ (string) self::get_status_label($record->status),
|
|
|
|
|
+ (string) $record->created_at,
|
|
|
|
|
+ (string) ($file_url ?: ''),
|
|
|
|
|
+ ));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fclose($fh);
|
|
|
|
|
+
|
|
|
|
|
+ $download_url = add_query_arg(array(
|
|
|
|
|
+ 'studiou_fpp_download_csv' => 1,
|
|
|
|
|
+ 'file' => $csv_name,
|
|
|
|
|
+ '_wpnonce' => wp_create_nonce('studiou-fpp-csv-download'),
|
|
|
|
|
+ ), admin_url('admin.php'));
|
|
|
|
|
+
|
|
|
|
|
+ wp_send_json_success(array(
|
|
|
|
|
+ 'download_url' => $download_url,
|
|
|
|
|
+ 'row_count' => count($records),
|
|
|
|
|
+ ));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function handle_csv_download() {
|
|
|
|
|
+ if (!isset($_GET['studiou_fpp_download_csv']) || !isset($_GET['file'])) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!wp_verify_nonce($_GET['_wpnonce'] ?? '', 'studiou-fpp-csv-download')) {
|
|
|
|
|
+ wp_die(__('Security check failed.', 'studiou-wc-free-photo-product'));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!current_user_can('manage_woocommerce')) {
|
|
|
|
|
+ wp_die(__('Insufficient permissions.', 'studiou-wc-free-photo-product'));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $file_name = sanitize_file_name($_GET['file']);
|
|
|
|
|
+ $upload_dir = wp_upload_dir();
|
|
|
|
|
+ $file_path = $upload_dir['basedir'] . '/studiou-fpp-chunks/' . $file_name;
|
|
|
|
|
+
|
|
|
|
|
+ if (!file_exists($file_path) || pathinfo($file_name, PATHINFO_EXTENSION) !== 'csv') {
|
|
|
|
|
+ wp_die(__('File not found.', 'studiou-wc-free-photo-product'));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ header('Content-Type: text/csv; charset=UTF-8');
|
|
|
|
|
+ header('Content-Disposition: attachment; filename="' . $file_name . '"');
|
|
|
|
|
+ header('Content-Length: ' . filesize($file_path));
|
|
|
|
|
+ header('Pragma: no-cache');
|
|
|
|
|
+
|
|
|
|
|
+ readfile($file_path);
|
|
|
|
|
+
|
|
|
|
|
+ unlink($file_path);
|
|
|
|
|
+ exit;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* Handle single file download — serves the file and marks status as "downloaded".
|
|
* Handle single file download — serves the file and marks status as "downloaded".
|
|
|
*/
|
|
*/
|