PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / 3.2.7
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar v3.2.7
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 1.2.0 1.2.1 All 156 releases
notificationx / includes / Core / Rest / Popup.php

Popup.php in NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar 3.2.7, at includes/Core/Rest/Popup.php

488 lines 16.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace NotificationX\Core\Rest;
4
5 use NotificationX\GetInstance;
6 use NotificationX\Core\PopupNotification;
7 use NotificationX\Extensions\Popup\PopupNotification as PopupPopupNotification;
8 use NotificationX\NotificationX;
9 use WP_REST_Server;
10
11 /**
12 * @method static Popup get_instance($args = null)
13 */
14 class Popup {
15 /**
16 * Instance of Popup
17 *
18 * @var Popup
19 */
20 use GetInstance;
21 public $namespace;
22 public $rest_base;
23 public $id = 'popup_notification';
24
25 /**
26 * Sources that share the popup-submit form pipeline.
27 * Entries from these sources are listed/managed together in the Feedback Entries screen.
28 */
29 private function form_sources() {
30 return [ 'popup_notification', 'exit_intent_custom' ];
31 }
32
33 /**
34 * Constructor.
35 *
36 * @since 4.7.0
37 *
38 * @param string $post_type Post type.
39 */
40 public function __construct() {
41 $this->namespace = 'notificationx/v1';
42 $this->rest_base = 'popup-submit';
43 add_action('rest_api_init', [$this, 'register_routes']);
44 }
45
46
47 /**
48 * Registers the routes for the objects of the controller.
49 *
50 * @since 3.1.12
51 *
52 * @see register_rest_route()
53 */
54 public function register_routes() {
55 register_rest_route('notificationx/v1', '/popup-submit', [
56 'methods' => 'POST',
57 'callback' => [ $this , 'handle_popup_submission' ],
58 'permission_callback' => '__return_true',
59 'args' => [
60 'nx_id' => [
61 'required' => true,
62 'type' => 'string',
63 ],
64 'email' => [
65 'type' => 'string',
66 'sanitize_callback' => 'sanitize_email',
67 ],
68 'message' => [
69 'type' => 'string',
70 'sanitize_callback' => 'sanitize_textarea_field',
71 ],
72 'name' => [
73 'type' => 'string',
74 'sanitize_callback' => 'sanitize_textarea_field',
75 ],
76 'timestamp' => [
77 'type' => 'integer',
78 ],
79 ],
80 ]);
81
82 // Feedback entries endpoint
83 register_rest_route('notificationx/v1', '/feedback-entries', [
84 'methods' => 'GET',
85 'callback' => [$this, 'get_feedback_entries'],
86 'permission_callback' => function() {
87 return current_user_can('read_notificationx');
88 },
89 'args' => [
90 'page' => [
91 'default' => 1,
92 'type' => 'integer',
93 'minimum' => 1,
94 ],
95 'per_page' => [
96 'default' => 20,
97 'type' => 'integer',
98 'minimum' => 1,
99 'maximum' => 200,
100 ],
101 's' => [
102 'default' => '',
103 'type' => 'string',
104 'sanitize_callback' => 'sanitize_text_field',
105 ],
106 'notification_id' => [
107 'default' => '',
108 'type' => 'string',
109 'sanitize_callback' => 'sanitize_text_field',
110 ],
111 ],
112 ]);
113
114 // Delete feedback entry endpoint
115 register_rest_route('notificationx/v1', '/feedback-entries/(?P<id>\d+)', [
116 'methods' => 'DELETE',
117 'callback' => [$this, 'delete_feedback_entry'],
118 'permission_callback' => function() {
119 return current_user_can('edit_notificationx');
120 },
121 'args' => [
122 'id' => [
123 'required' => true,
124 'type' => 'integer',
125 ],
126 ],
127 ]);
128
129 // Bulk delete feedback entries endpoint
130 register_rest_route('notificationx/v1', '/feedback-entries/bulk-delete', [
131 'methods' => 'POST',
132 'callback' => [$this, 'bulk_delete_feedback_entries'],
133 'permission_callback' => function() {
134 return current_user_can('edit_notificationx');
135 },
136 'args' => [
137 'ids' => [
138 'required' => true,
139 'type' => 'array',
140 'items' => [
141 'type' => 'integer',
142 ],
143 ],
144 ],
145 ]);
146
147 // Export feedback entries endpoint
148 register_rest_route('notificationx/v1', '/feedback-entries/export', [
149 'methods' => 'POST',
150 'callback' => [$this, 'export_feedback_entries'],
151 'permission_callback' => function() {
152 return current_user_can('read_notificationx');
153 },
154 'args' => [
155 's' => [
156 'required' => false,
157 'type' => 'string',
158 ],
159 'notification_id' => [
160 'required' => false,
161 'type' => 'string',
162 ],
163 ],
164 ]);
165 }
166
167 /**
168 * Handle popup form submission
169 *
170 * @param WP_REST_Request $request
171 * @return WP_REST_Response
172 */
173 public function handle_popup_submission($request) {
174 $popup = PopupPopupNotification::get_instance();
175 return $popup->handle_popup_submission($request);
176 }
177
178
179 /**
180 * Get feedback entries
181 *
182 * @param WP_REST_Request $request
183 * @return WP_REST_Response
184 */
185 public function get_feedback_entries($request) {
186 global $wpdb;
187
188 $table_name = $wpdb->prefix . 'nx_entries';
189
190 // Get pagination parameters
191 $page = $request->get_param('page') ?: 1;
192 $per_page = $request->get_param('per_page') ?: 20;
193 $search = $request->get_param('s') ?: '';
194 $notification_id = $request->get_param('notification_id') ?: '';
195 $offset = ($page - 1) * $per_page;
196
197 // Build WHERE clause — include both popup and exit-intent submissions
198 $sources = $this->form_sources();
199 $src_placeholders = implode(',', array_fill(0, count($sources), '%s'));
200 $where_conditions = ["e.source IN ({$src_placeholders})"];
201 $where_values = $sources;
202
203 // Add notification filter
204 if (!empty($notification_id)) {
205 $where_conditions[] = "e.nx_id = %d";
206 $where_values[] = intval($notification_id);
207 }
208
209 // Add search functionality
210 if (!empty($search)) {
211 $where_conditions[] = "(e.data LIKE %s OR e.created_at LIKE %s)";
212 $search_term = '%' . $wpdb->esc_like($search) . '%';
213 $where_values[] = $search_term;
214 $where_values[] = $search_term;
215 }
216
217 $where_clause = implode(' AND ', $where_conditions);
218
219 // Get total count for pagination
220 $total_query = $wpdb->prepare(
221 "SELECT COUNT(*) FROM {$table_name} e WHERE {$where_clause}",
222 ...$where_values
223 );
224 $total_items = (int) $wpdb->get_var($total_query);
225
226 // Get paginated entries with notification information
227 $posts_table = $wpdb->prefix . 'nx_posts';
228 $entries_query = $wpdb->prepare(
229 "SELECT e.*, p.title as notification_name, p.nx_id as notification_id
230 FROM {$table_name} e
231 LEFT JOIN {$posts_table} p ON e.nx_id = p.nx_id
232 WHERE {$where_clause}
233 ORDER BY e.created_at DESC
234 LIMIT %d OFFSET %d",
235 ...array_merge($where_values, [$per_page, $offset])
236 );
237 $entries = $wpdb->get_results($entries_query, ARRAY_A);
238
239 $formatted_entries = [];
240 foreach ($entries as $entry) {
241 $data = maybe_unserialize($entry['data']);
242 $formatted_entries[] = [
243 'id' => $entry['entry_id'],
244 'date' => $entry['created_at'],
245 'name' => $data['name'] ?? '',
246 'email' => $data['email'] ?? '',
247 'message' => $data['message'] ?? '',
248 'title' => $data['title'] ?? '',
249 'theme' => $data['theme'] ?? '',
250 'ip' => $data['ip'] ?? '',
251 'notification_name' => $entry['notification_name'] ?? '',
252 'notification_id' => $entry['notification_id'] ?? 0,
253 'nx_id' => $entry['nx_id'] ?? 0,
254 ];
255 }
256
257 return new \WP_REST_Response([
258 'entries' => $formatted_entries,
259 'total' => $total_items,
260 'page' => $page,
261 'per_page' => $per_page,
262 'total_pages' => ceil($total_items / $per_page),
263 ], 200);
264 }
265
266 /**
267 * Delete feedback entry
268 *
269 * @param WP_REST_Request $request
270 * @return WP_REST_Response
271 */
272 public function delete_feedback_entry($request) {
273 global $wpdb;
274
275 $entry_id = $request->get_param('id');
276 $table_name = $wpdb->prefix . 'nx_entries';
277
278 $sources = $this->form_sources();
279 $src_placeholders = implode(',', array_fill(0, count($sources), '%s'));
280 $delete_query = $wpdb->prepare(
281 "DELETE FROM {$table_name} WHERE entry_id = %d AND source IN ({$src_placeholders})",
282 array_merge([$entry_id], $sources)
283 );
284 $result = $wpdb->query($delete_query);
285
286 if ($result === false) {
287 return new \WP_REST_Response([
288 'success' => false,
289 'message' => __('Failed to delete entry', 'notificationx'),
290 ], 500);
291 }
292
293 return new \WP_REST_Response([
294 'success' => true,
295 'message' => __('Entry deleted successfully', 'notificationx'),
296 ], 200);
297 }
298
299 /**
300 * Bulk delete feedback entries
301 *
302 * @param WP_REST_Request $request
303 * @return WP_REST_Response
304 */
305 public function bulk_delete_feedback_entries($request) {
306 global $wpdb;
307
308 $entry_ids = $request->get_param('ids');
309 $table_name = $wpdb->prefix . 'nx_entries';
310
311 if (empty($entry_ids) || !is_array($entry_ids)) {
312 return new \WP_REST_Response([
313 'success' => false,
314 'message' => __('No entries selected for deletion', 'notificationx'),
315 ], 400);
316 }
317
318 // Sanitize entry IDs
319 $entry_ids = array_map('absint', $entry_ids);
320 $entry_ids = array_filter($entry_ids); // Remove any zero values
321
322 if (empty($entry_ids)) {
323 return new \WP_REST_Response([
324 'success' => false,
325 'message' => __('Invalid entry IDs provided', 'notificationx'),
326 ], 400);
327 }
328
329 // Create placeholders for the IN clauses
330 $placeholders = implode(',', array_fill(0, count($entry_ids), '%d'));
331 $sources = $this->form_sources();
332 $src_placeholders = implode(',', array_fill(0, count($sources), '%s'));
333
334 // Prepare the query with source filter
335 $query = $wpdb->prepare(
336 "DELETE FROM {$table_name} WHERE entry_id IN ({$placeholders}) AND source IN ({$src_placeholders})",
337 array_merge($entry_ids, $sources)
338 );
339
340 $result = $wpdb->query($query);
341
342 if ($result === false) {
343 return new \WP_REST_Response([
344 'success' => false,
345 'message' => __('Failed to delete entries', 'notificationx'),
346 ], 500);
347 }
348
349 return new \WP_REST_Response([
350 'success' => true,
351 'message' => sprintf(
352 /* translators: %d: Number of entries deleted */
353 _n('%d entry deleted successfully', '%d entries deleted successfully', $result, 'notificationx'),
354 $result
355 ),
356 'deleted_count' => $result,
357 ], 200);
358 }
359
360 /**
361 * Export feedback entries
362 *
363 * @param WP_REST_Request $request
364 * @return WP_REST_Response
365 */
366 public function export_feedback_entries($request) {
367 global $wpdb;
368
369 $table_name = $wpdb->prefix . 'nx_entries';
370 $search = $request->get_param('s') ?: '';
371 $notification_id = $request->get_param('notification_id') ?: '';
372
373 // Build WHERE clause — include both popup and exit-intent submissions
374 $sources = $this->form_sources();
375 $src_placeholders = implode(',', array_fill(0, count($sources), '%s'));
376 $where_conditions = ["e.source IN ({$src_placeholders})"];
377 $where_values = $sources;
378
379 // Add notification filter if provided
380 if (!empty($notification_id)) {
381 $where_conditions[] = "e.nx_id = %d";
382 $where_values[] = intval($notification_id);
383 }
384
385 // Add search functionality if provided
386 if (!empty($search)) {
387 $where_conditions[] = "(e.data LIKE %s OR e.created_at LIKE %s)";
388 $search_term = '%' . $wpdb->esc_like($search) . '%';
389 $where_values[] = $search_term;
390 $where_values[] = $search_term;
391 }
392
393 $where_clause = implode(' AND ', $where_conditions);
394
395 // Get all entries for export (no pagination)
396 $posts_table = $wpdb->prefix . 'nx_posts';
397 $query = $wpdb->prepare(
398 "SELECT e.entry_id, e.nx_id, e.data, e.created_at, p.title as notification_name
399 FROM {$table_name} e
400 LEFT JOIN {$posts_table} p ON e.nx_id = p.nx_id
401 WHERE {$where_clause}
402 ORDER BY e.created_at DESC",
403 ...$where_values
404 );
405
406 $entries = $wpdb->get_results($query, ARRAY_A);
407
408 if (empty($entries)) {
409 return new \WP_REST_Response([
410 'success' => false,
411 'message' => __('No entries found to export', 'notificationx'),
412 ], 404);
413 }
414
415 // Generate CSV content
416 $csv_data = $this->generate_csv_data($entries);
417
418 // Generate filename
419 $filename = 'notificationx-feedback-entries-' . date('Y-m-d-H-i-s') . '.csv';
420
421 return new \WP_REST_Response([
422 'success' => true,
423 'csv_content' => $csv_data,
424 'filename' => $filename,
425 'total_entries' => count($entries),
426 'message' => sprintf(__('Successfully prepared %d entries for export', 'notificationx'), count($entries))
427 ], 200);
428 }
429
430 /**
431 * Generate CSV data from entries
432 *
433 * @param array $entries
434 * @return string
435 */
436 private function generate_csv_data($entries) {
437 $csv_data = [];
438 $is_pro = NotificationX::is_pro();
439
440 // CSV Headers
441 $csv_headers = [
442 __('No', 'notificationx'),
443 __('Date', 'notificationx'),
444 __('NotificationX Title', 'notificationx'),
445 ];
446
447 if ($is_pro) {
448 $csv_headers[] = __('Name', 'notificationx');
449 $csv_headers[] = __('Email Address', 'notificationx');
450 }
451
452 $csv_headers[] = __('Message', 'notificationx');
453
454 $csv_data[] = $csv_headers;
455
456 // Add data rows
457 $counter = 1;
458 foreach ($entries as $entry) {
459 $data = maybe_unserialize($entry['data']);
460 $date = new \DateTime($entry['created_at']);
461
462 $row = [
463 $counter++,
464 $date->format('F j, Y'),
465 $entry['notification_name'] ?: sprintf(__('Notification #%d', 'notificationx'), $entry['nx_id']),
466 ];
467
468 if ($is_pro) {
469 $row[] = $data['name'] ?? '';
470 $row[] = $data['email'] ?? '';
471 }
472
473 $row[] = $data['message'] ?? '';
474
475 $csv_data[] = $row;
476 }
477
478 // Convert array to CSV string
479 $csv_content = '';
480 foreach ($csv_data as $row) {
481 $csv_content .= '"' . implode('","', array_map(function($field) {
482 return str_replace('"', '""', $field); // Escape quotes
483 }, $row)) . '"' . "\n";
484 }
485
486 return $csv_content;
487 }
488 }