order_no, externalorder, externalorderdate' ); ?>

order_no' ); ?>

array( 'file_field' => 'inprint_csv', 'nonce' => 'import_inprint_protocol_nonce', 'handler' => array('Studiou_DB_Manager', 'import_inprint_protocol'), ), 'import_delivered_protocol' => array( 'file_field' => 'delivered_csv', 'nonce' => 'import_delivered_protocol_nonce', 'handler' => array('Studiou_DB_Manager', 'import_delivered_protocol'), ), ); } public function handle_import_inprint_protocol() { $this->run_import('import_inprint_protocol'); } public function handle_import_delivered_protocol() { $this->run_import('import_delivered_protocol'); } /** * Common pipeline: capability check → nonce → file validation → parse → dispatch → redirect. * Every non-success branch returns immediately via redirect_back() so static * analysis can prove that subsequent code is only reached on the happy path. */ private function run_import($action) { $dispatch = $this->protocol_dispatch(); if (!isset($dispatch[$action])) { return $this->redirect_back(); } $cfg = $dispatch[$action]; if (!current_user_can('edit_shop_orders')) { wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'studiou-wc-ord-print-statuses')); } check_admin_referer($action, $cfg['nonce']); $file = $this->validated_upload($cfg['file_field']); if ($file === null) { return $this->redirect_back(); } $csv_data = Studiou_DB_Manager::parse_csv($file['tmp_name']); if (empty($csv_data)) { UtilsLog::message( __('CSV file could not be parsed or contained no data rows.', 'studiou-wc-ord-print-statuses'), 'error' ); return $this->redirect_back(); } $handler = $cfg['handler']; $result = $handler($csv_data); $this->emit_import_summary($result); return $this->redirect_back(); } /** * Validate the file upload superglobal entry. Emits a notice and returns null on failure. * * @return array|null */ private function validated_upload($field) { if (!isset($_FILES[$field]) || !is_array($_FILES[$field])) { UtilsLog::message(__('No file uploaded.', 'studiou-wc-ord-print-statuses'), 'error'); return null; } $file = $_FILES[$field]; if (isset($file['error']) && $file['error'] !== UPLOAD_ERR_OK) { UtilsLog::message( sprintf( /* translators: %d is the PHP upload error code. */ __('File upload failed (error code %d).', 'studiou-wc-ord-print-statuses'), (int) $file['error'] ), 'error' ); return null; } if (empty($file['tmp_name']) || !is_uploaded_file($file['tmp_name'])) { UtilsLog::message(__('Uploaded file is not accessible.', 'studiou-wc-ord-print-statuses'), 'error'); return null; } // Defense-in-depth: the HTML `accept` attribute is a client-side hint // and can be bypassed. Verify the uploaded file is named *.csv. $name = isset($file['name']) ? (string) $file['name'] : ''; $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); if ($ext !== 'csv') { UtilsLog::message(__('Only .csv files are accepted.', 'studiou-wc-ord-print-statuses'), 'error'); return null; } return $file; } private function emit_import_summary($result) { $updated = isset($result['updated_count']) ? (int) $result['updated_count'] : 0; $errors = isset($result['errors']) && is_array($result['errors']) ? $result['errors'] : array(); // Skip the "0 orders updated" notice when nothing actually changed — // the per-error notice below is more informative on its own and // matches the pattern Bulk_Actions_Manager::notify_moved_count uses. if ($updated > 0) { UtilsLog::message( sprintf( _n( '%d order updated successfully.', '%d orders updated successfully.', $updated, 'studiou-wc-ord-print-statuses' ), $updated ), 'success' ); } elseif (empty($errors)) { // Both counters zero: the CSV parsed and had rows, but // dedupe_by_order_no filtered everything out — every row had // an empty order_no column. Surface this so the operator // isn't left wondering whether the import ran. UtilsLog::message( __('The CSV file contained no actionable rows (empty order_no column).', 'studiou-wc-ord-print-statuses'), 'info' ); } if (!empty($errors)) { // Dedupe repeated error strings (e.g., "Invalid row format in // CSV." 100×) so the notice stays readable. The count is the // total number of errors, not the number of unique messages. $total = count($errors); $unique = array_values(array_unique($errors)); UtilsLog::message( sprintf( /* translators: 1: error count, 2: comma-separated error messages. */ __('%1$d errors occurred: %2$s', 'studiou-wc-ord-print-statuses'), $total, esc_html(implode(', ', $unique)) ), 'error' ); } } private function redirect_back() { wp_safe_redirect(admin_url('admin.php?page=studiou-import-protocols')); exit; } }