| @@ -230,16 +230,20 @@ | ||
| 230 | 230 | $where_clause = implode(' AND ', $where_conditions); |
| 231 | 231 | |
| 232 | 232 | // Get total count for pagination |
| 233 | 233 | $total_query = $wpdb->prepare( |
| 234 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16. | |
| 234 | 235 | "SELECT COUNT(*) FROM {$table_name} e WHERE {$where_clause}", |
| 235 | 236 | ...$where_values |
| 236 | 237 | ); |
| 238 | + // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16. | |
| 237 | 239 | $total_items = (int) $wpdb->get_var($total_query); |
| 238 | 240 | |
| 239 | 241 | // Get paginated entries with notification information |
| 240 | 242 | $posts_table = $wpdb->prefix . 'nx_posts'; |
| 243 | + // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16. | |
| 241 | 244 | $entries_query = $wpdb->prepare( |
| 245 | + // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16. | |
| 242 | 246 | "SELECT e.*, p.title as notification_name, p.nx_id as notification_id |
| 243 | 247 | FROM {$table_name} e |
| 244 | 248 | LEFT JOIN {$posts_table} p ON e.nx_id = p.nx_id |
| 245 | 249 | WHERE {$where_clause} |
| @@ -246,8 +250,10 @@ | ||
| 246 | 250 | ORDER BY e.created_at DESC |
| 247 | 251 | LIMIT %d OFFSET %d", |
| 248 | 252 | ...array_merge($where_values, [$per_page, $offset]) |
| 249 | 253 | ); |
| 254 | + // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared | |
| 255 | + // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16. | |
| 250 | 256 | $entries = $wpdb->get_results($entries_query, ARRAY_A); |
| 251 | 257 | |
| 252 | 258 | $formatted_entries = []; |
| 253 | 259 | foreach ($entries as $entry) { |
| @@ -290,11 +296,13 @@ | ||
| 290 | 296 | |
| 291 | 297 | $sources = $this->form_sources(); |
| 292 | 298 | $src_placeholders = implode(',', array_fill(0, count($sources), '%s')); |
| 293 | 299 | $delete_query = $wpdb->prepare( |
| 300 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16. | |
| 294 | 301 | "DELETE FROM {$table_name} WHERE entry_id = %d AND source IN ({$src_placeholders})", |
| 295 | 302 | array_merge([$entry_id], $sources) |
| 296 | 303 | ); |
| 304 | + // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16. | |
| 297 | 305 | $result = $wpdb->query($delete_query); |
| 298 | 306 | |
| 299 | 307 | if ($result === false) { |
| 300 | 308 | return new \WP_REST_Response([ |
| @@ -345,12 +353,14 @@ | ||
| 345 | 353 | $src_placeholders = implode(',', array_fill(0, count($sources), '%s')); |
| 346 | 354 | |
| 347 | 355 | // Prepare the query with source filter |
| 348 | 356 | $query = $wpdb->prepare( |
| 357 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16. | |
| 349 | 358 | "DELETE FROM {$table_name} WHERE entry_id IN ({$placeholders}) AND source IN ({$src_placeholders})", |
| 350 | 359 | array_merge($entry_ids, $sources) |
| 351 | 360 | ); |
| 352 | 361 | |
| 362 | + // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16. | |
| 353 | 363 | $result = $wpdb->query($query); |
| 354 | 364 | |
| 355 | 365 | if ($result === false) { |
| 356 | 366 | return new \WP_REST_Response([ |
| @@ -407,8 +417,9 @@ | ||
| 407 | 417 | |
| 408 | 418 | // Get all entries for export (no pagination) |
| 409 | 419 | $posts_table = $wpdb->prefix . 'nx_posts'; |
| 410 | 420 | $query = $wpdb->prepare( |
| 421 | + // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16. | |
| 411 | 422 | "SELECT e.entry_id, e.nx_id, e.data, e.created_at, p.title as notification_name |
| 412 | 423 | FROM {$table_name} e |
| 413 | 424 | LEFT JOIN {$posts_table} p ON e.nx_id = p.nx_id |
| 414 | 425 | WHERE {$where_clause} |
| @@ -415,9 +426,11 @@ | ||
| 415 | 426 | ORDER BY e.created_at DESC", |
| 416 | 427 | ...$where_values |
| 417 | 428 | ); |
| 418 | 429 | |
| 430 | + // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16. | |
| 419 | 431 | $entries = $wpdb->get_results($query, ARRAY_A); |
| 432 | + // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare | |
| 420 | 433 | |
| 421 | 434 | if (empty($entries)) { |
| 422 | 435 | return new \WP_REST_Response([ |
| 423 | 436 | 'success' => false, |
| @@ -428,9 +441,9 @@ | ||
| 428 | 441 | // Generate CSV content |
| 429 | 442 | $csv_data = $this->generate_csv_data($entries); |
| 430 | 443 | |
| 431 | 444 | // Generate filename |
| 432 | - $filename = 'notificationx-feedback-entries-' . date('Y-m-d-H-i-s') . '.csv'; | |
| 445 | + $filename = 'notificationx-feedback-entries-' . gmdate('Y-m-d-H-i-s') . '.csv'; | |
| 433 | 446 | |
| 434 | 447 | return new \WP_REST_Response([ |
| 435 | 448 | 'success' => true, |
| 436 | 449 | 'csv_content' => $csv_data, |
| @@ -435,8 +448,9 @@ | ||
| 435 | 448 | 'success' => true, |
| 436 | 449 | 'csv_content' => $csv_data, |
| 437 | 450 | 'filename' => $filename, |
| 438 | 451 | 'total_entries' => count($entries), |
| 452 | + /* translators: %d: number of entries prepared for export */ | |
| 439 | 453 | 'message' => sprintf(__('Successfully prepared %d entries for export', 'notificationx'), count($entries)) |
| 440 | 454 | ], 200); |
| 441 | 455 | } |
| 442 | 456 | |
| @@ -474,8 +488,9 @@ | ||
| 474 | 488 | |
| 475 | 489 | $row = [ |
| 476 | 490 | $counter++, |
| 477 | 491 | $date->format('F j, Y'), |
| 492 | + /* translators: %d: notification ID */ | |
| 478 | 493 | $entry['notification_name'] ?: sprintf(__('Notification #%d', 'notificationx'), $entry['nx_id']), |
| 479 | 494 | ]; |
| 480 | 495 | |
| 481 | 496 | if ($is_pro) { |