prefix . 'tt24_entries'; $table_entry_fields = $wpdb->prefix . 'tt24_entry_fields'; $table_forms = $wpdb->prefix . 'tt24_forms'; // 4. SMART FILTERS: Build the dynamic WHERE clause $where_clauses = array("1=1"); $query_args = array(); // Filter by Form ID if ( isset( $_GET['filter_form_id'] ) && absint( $_GET['filter_form_id'] ) > 0 ) { $where_clauses[] = "e.form_id = %d"; $query_args[] = absint( $_GET['filter_form_id'] ); } // Filter by Start Date if ( ! empty( $_GET['start_date'] ) ) { $where_clauses[] = "e.created_at >= %s"; $query_args[] = sanitize_text_field( $_GET['start_date'] ) . ' 00:00:00'; } // Filter by End Date if ( ! empty( $_GET['end_date'] ) ) { $where_clauses[] = "e.created_at <= %s"; $query_args[] = sanitize_text_field( $_GET['end_date'] ) . ' 23:59:59'; } $where_sql = implode(' AND ', $where_clauses); // 5. Fetch the Parent Entries (now pulling form_settings for translation) $sql = " SELECT e.id, e.form_id, e.ip_address, e.created_at, f.title as form_name, f.form_settings FROM {$table_entries} e LEFT JOIN {$table_forms} f ON e.form_id = f.id WHERE {$where_sql} ORDER BY e.created_at DESC "; // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching if ( ! empty( $query_args ) ) { $entries = $wpdb->get_results( $wpdb->prepare( $sql, ...$query_args ), ARRAY_A ); } else { $entries = $wpdb->get_results( $sql, ARRAY_A ); } // phpcs:enable if ( empty( $entries ) ) { wp_safe_redirect( admin_url( 'admin.php?page=tt24-forms-entries&error=no_data' ) ); exit; } // 6. Build the Translation Dictionary from the fetched entries $field_dictionary = array(); $entry_ids = array(); foreach ( $entries as $entry ) { $entry_ids[] = $entry['id']; // Collect IDs for the child query if ( ! empty( $entry['form_settings'] ) ) { $parsed = json_decode( $entry['form_settings'], true ); $layout = array(); if ( is_array( $parsed ) ) { $layout = isset( $parsed['layout'] ) ? (is_array( $parsed['layout']) ? $parsed['layout'] : array()) : $parsed; } foreach ( $layout as $field ) { if ( isset( $field['name'] ) && isset( $field['label'] ) ) { $field_dictionary[ $field['name'] ] = $field['label']; } } } } // 7. Fetch Child Field Data ONLY for the filtered entries $in_ids = implode( ',', array_map( 'absint', $entry_ids ) ); // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching $fields_data = $wpdb->get_results( "SELECT entry_id, field_name, field_value FROM {$table_entry_fields} WHERE entry_id IN ({$in_ids})", ARRAY_A ); // phpcs:enable $mapped_fields = array(); $unique_headers = array(); foreach ( $fields_data as $field ) { $e_id = $field['entry_id']; $f_name = $field['field_name']; $mapped_fields[ $e_id ][ $f_name ] = $field['field_value']; if ( ! in_array( $f_name, $unique_headers, true ) ) { $unique_headers[] = $f_name; } } // 8. Prepare the HTTP Headers for Download $site_name = sanitize_title( get_bloginfo( 'name' ) ); $filename = sprintf( '24tt-export-%s-%s.csv', $site_name, gmdate( 'Y-m-d' ) ); if ( ob_get_length() ) { ob_clean(); } header( 'Content-Type: text/csv; charset=UTF-8' ); header( 'Content-Disposition: attachment; filename="' . $filename . '"' ); header( 'Pragma: no-cache' ); header( 'Expires: 0' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen $output = fopen( 'php://output', 'w' ); // Add UTF-8 BOM so Excel reads special characters correctly // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fputs fputs( $output, "\xEF\xBB\xBF" ); // 9. Write the CSV Column Headers (WITH TRANSLATION) $csv_headers = array( 'Entry ID', 'Form Name', 'Date Submitted', 'IP Address' ); foreach ( $unique_headers as $header ) { if ( isset( $field_dictionary[ $header ] ) ) { $csv_headers[] = $field_dictionary[ $header ]; // Use beautiful label! } else { $csv_headers[] = ucwords( str_replace( array( '_', '-' ), ' ', $header ) ); // Smart fallback } } fputcsv( $output, $csv_headers ); // 10. Write the Rows of Data foreach ( $entries as $entry ) { $row = array( $entry['id'], $entry['form_name'], $entry['created_at'], $entry['ip_address'] ); foreach ( $unique_headers as $header ) { if ( isset( $mapped_fields[ $entry['id'] ][ $header ] ) ) { $row[] = $mapped_fields[ $entry['id'] ][ $header ]; } else { $row[] = ''; } } fputcsv( $output, $row ); } // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose fclose( $output ); exit; } } // Instantiate and initialize the export class securely $tt24_export = new TT24_Export(); $tt24_export->init();