PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / 3.3.3
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar v3.3.3
3.3.3 3.3.2 3.3.1 3.3.0 3.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 trunk 0.2.5.5 0.2.5.6 0.2.5.7 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 All 158 releases
← All changes | includes/Core/Rest/Popup.php +16 -1 3.2.10 → 3.3.3 View file →
@@ -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) {