PluginProbe ʕ •ᴥ•ʔ
Reviews Feed – Add Testimonials and Customer Reviews From Google Reviews, Yelp, TripAdvisor, and More / 2.11.0
Reviews Feed – Add Testimonials and Customer Reviews From Google Reviews, Yelp, TripAdvisor, and More v2.11.0
2.11.0 2.10.0 2.9.0 2.8.0 2.7.0 2.6.7 2.6.8 2.6.5 2.6.4 2.6.3 2.6.2 2.6.0 2.5.5 2.5.4 2.5.3 2.5.2 trunk 1.0 1.0.1 1.0.2 1.0.3 1.1 1.1.1 1.1.2 1.2.0 2.0 2.1.0 2.1.1 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.5.0 2.5.1
reviews-feed / class / Common / Admin / SBR_Notifications.php
reviews-feed / class / Common / Admin Last commit date
Blocks 1 week ago MenuService.php 1 week ago SBR_About_Builder.php 1 week ago SBR_Admin_Notice.php 1 week ago SBR_Collections_Builder.php 1 week ago SBR_New_User.php 1 week ago SBR_Notifications.php 1 week ago SBR_Plugin_Insltaller.php 1 week ago SBR_Support_Builder.php 1 week ago SBR_Support_Tool.php 1 week ago
SBR_Notifications.php
808 lines
1 <?php
2
3 // phpcs:disable Generic.Metrics.CyclomaticComplexity.MaxExceeded
4 // Note: Legacy file with complex notification handling. Refactoring planned.
5
6 /**
7 * SBR_Notifications.
8 *
9 * @since 1.1
10 */
11
12 namespace SmashBalloon\Reviews\Common\Admin;
13
14 use Smashballoon\Stubs\Services\ServiceProvider;
15
16 // Exit if accessed directly
17 if (! defined('ABSPATH')) {
18 exit;
19 }
20
21 class SBR_Notifications extends ServiceProvider
22 {
23 /**
24 * Source of notifications content.
25 *
26 * @var string
27 */
28 const SOURCE_URL = 'https://plugin.smashballoon.com/notifications.json';
29
30 /**
31 * @var string
32 */
33 const OPTION_NAME = 'sbr_notifications';
34
35 /**
36 * JSON data contains notices for all plugins. This is used
37 * to select messages only meant for this plugin
38 *
39 * @var string
40 */
41 const PLUGIN = 'reviews';
42
43 /**
44 * Option value.
45 *
46 * @since 1.2
47 *
48 * @var bool|array
49 */
50 public $option = false;
51
52
53 public function register()
54 {
55 $this->init();
56 }
57
58 /**
59 * Initialize class.
60 *
61 * @since 1.2
62 */
63 public function init()
64 {
65 $this->hooks();
66 }
67
68 /**
69 * Use this function to get the option name to allow
70 * inheritance for the New_User class
71 *
72 * @return string
73 */
74 public function option_name()
75 {
76 return self::OPTION_NAME;
77 }
78
79 /**
80 * Use this function to get the source URL to allow
81 * inheritance for the New_User class
82 *
83 * @return string
84 */
85 public function source_url()
86 {
87 return self::SOURCE_URL;
88 }
89
90 /**
91 * Register hooks.
92 *
93 * @since 1.2
94 */
95 public function hooks()
96 {
97 add_action('admin_enqueue_scripts', array( $this, 'enqueues' ));
98
99 add_action('sbr_admin_notices', array( $this, 'output' ));
100 add_filter('sbr_admin_notices_filter', array( $this, 'output' ));
101
102 // on cron. Once a week?
103 add_action('sbr_notification_update', array( $this, 'update' ));
104
105 add_action('wp_ajax_sbr_dashboard_notification_dismiss', array( $this, 'dismiss' ));
106 }
107
108
109 /**
110 * Check if user has access and is enabled.
111 *
112 * @since 1.2
113 *
114 * @return bool
115 */
116 public function has_access()
117 {
118 $access = false;
119
120 if (sbr_current_user_can('manage_reviews_feed_options')) {
121 $access = true;
122 }
123
124 return apply_filters('sbr_admin_notifications_has_access', $access);
125 }
126
127 /**
128 * Get option value.
129 *
130 * @since 1.2
131 *
132 * @param bool $cache Reference property cache if available.
133 *
134 * @return array
135 */
136 public function get_option($cache = true)
137 {
138 if ($this->option && $cache) {
139 return $this->option;
140 }
141 $option = get_option($this->option_name(), array());
142 $this->option = array(
143 'update' => ! empty($option['update']) ? $option['update'] : 0,
144 'events' => ! empty($option['events']) ? $option['events'] : array(),
145 'feed' => ! empty($option['feed']) ? $option['feed'] : array(),
146 'dismissed' => ! empty($option['dismissed']) ? $option['dismissed'] : array(),
147 );
148
149 return $this->option;
150 }
151
152 /**
153 * Fetch notifications from feed.
154 *
155 * @since 1.2
156 *
157 * @return array
158 */
159 public function fetch_feed()
160 {
161 $res = wp_remote_get($this->source_url());
162
163 if (is_wp_error($res)) {
164 return array();
165 }
166
167 $body = wp_remote_retrieve_body($res);
168
169 if (empty($body)) {
170 return array();
171 }
172 $body = str_replace(array( 'sbi_', 'sbi-' ), array( 'sbr_', 'sbr-' ), $body);
173
174 return $this->verify(json_decode($body, true));
175 }
176
177 /**
178 * Verify notification data before it is saved.
179 *
180 * @since 1.2
181 *
182 * @param array $notifications Array of notifications items to verify.
183 *
184 * @return array
185 */
186 public function verify($notifications) // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
187 {
188 $data = array();
189
190 if (! is_array($notifications) || empty($notifications)) {
191 return $data;
192 }
193
194 $option = $this->get_option();
195
196 foreach ($notifications as $notification) {
197 // Ignore if not a targeted plugin
198 if (! empty($notification['plugin']) && is_array($notification['plugin']) && ! in_array(self::PLUGIN, $notification['plugin'], true)) {
199 continue;
200 }
201
202 // Ignore if max wp version detected
203 if (! empty($notification['maxwpver']) && version_compare(get_bloginfo('version'), $notification['maxwpver'], '>')) {
204 continue;
205 }
206
207 // Ignore if max version has been reached
208 if (! empty($notification['maxver']) && version_compare($notification['maxver'], SBRVER) < 0) {
209 continue;
210 }
211
212 // Ignore if min version has not been reached
213 if (! empty($notification['minver']) && version_compare($notification['minver'], SBRVER) > 0) {
214 continue;
215 }
216
217 // Ignore if a specific sbr_status is empty or false
218 if (! empty($notification['statuscheck'])) {
219 $status_key = sanitize_key($notification['statuscheck']);
220 $sbr_statuses_option = get_option('sbr_statuses', array());
221
222 if (empty($sbr_statuses_option[ $status_key ])) {
223 continue;
224 }
225 }
226
227 // The message and license should never be empty, if they are, ignore.
228 if (empty($notification['content']) || empty($notification['type'])) {
229 continue;
230 }
231
232 // Ignore if license type does not match.
233 $license = \SmashBalloon\Reviews\Common\Util::sbr_is_pro() ? 'pro' : 'free';
234
235 if (! in_array($license, $notification['type'], true)) {
236 continue;
237 }
238
239 // Ignore if expired.
240 if (! empty($notification['end']) && sbr_get_current_time() > strtotime($notification['end'])) {
241 continue;
242 }
243
244 // Ignore if notification has already been dismissed.
245 if (! empty($option['dismissed']) && in_array($notification['id'], $option['dismissed'])) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
246 continue;
247 }
248
249 // TODO: Ignore if notification existed before installing SBR.
250 // Prevents bombarding the user with notifications after activation.
251 $activated = false;
252 if (
253 ! empty($activated)
254 && ! empty($notification['start'])
255 && $activated > strtotime($notification['start'])
256 ) {
257 continue;
258 }
259
260 $data[] = $notification;
261 }
262
263 return $data;
264 }
265
266 /**
267 * Verify saved notification data for active notifications.
268 *
269 * @since 1.2
270 *
271 * @param array $notifications Array of notifications items to verify.
272 *
273 * @return array
274 */
275 public function verify_active($notifications)
276 {
277 if (! is_array($notifications) || empty($notifications)) {
278 return array();
279 }
280
281 // Remove notfications that are not active.
282 foreach ($notifications as $key => $notification) {
283 if (
284 ( ! empty($notification['start']) && sbr_get_current_time() < strtotime($notification['start']) )
285 || ( ! empty($notification['end']) && sbr_get_current_time() > strtotime($notification['end']) )
286 ) {
287 unset($notifications[ $key ]);
288 }
289
290 if (empty($notification['recent_install_override']) && $this->recently_installed()) {
291 unset($notifications[ $key ]);
292 }
293
294 // Ignore if max version has been reached
295 if (! empty($notification['maxver']) && version_compare($notification['maxver'], SBRVER) < 0) {
296 unset($notifications[ $key ]);
297 }
298
299 // Ignore if max wp version detected
300 if (! empty($notification['maxwpver']) && version_compare(get_bloginfo('version'), $notification['maxwpver'], '>')) {
301 unset($notifications[ $key ]);
302 }
303
304 // Ignore if min version has not been reached
305 if (! empty($notification['minver']) && version_compare($notification['minver'], SBRVER) > 0) {
306 unset($notifications[ $key ]);
307 }
308
309 // Ignore if a specific sbr_status is empty or false
310 if (! empty($notification['statuscheck'])) {
311 $status_key = sanitize_key($notification['statuscheck']);
312 $sbr_statuses_option = get_option('sbr_statuses', array());
313
314 if (empty($sbr_statuses_option[ $status_key ])) {
315 unset($notifications[ $key ]);
316 }
317 }
318 }
319
320 return $notifications;
321 }
322
323 /**
324 * @return bool
325 *
326 * @since 1.4.5/1.4.2
327 */
328 public function recently_installed()
329 {
330 $sbr_statuses_option = get_option('sbr_statuses', array());
331
332 if (! isset($sbr_statuses_option['first_install'])) {
333 return false;
334 }
335
336 // Plugin was installed less than a week ago
337 if ((int) $sbr_statuses_option['first_install'] > time() - WEEK_IN_SECONDS) {
338 return true;
339 }
340
341 return false;
342 }
343
344 /**
345 * Get notification data.
346 *
347 * @since 1.2
348 *
349 * @return array
350 */
351 public function get()
352 {
353 if (! $this->has_access()) {
354 return array();
355 }
356
357
358 $option = $this->get_option();
359
360 // Update notifications using async task.
361 if (empty($option['update']) || sbr_get_current_time() > $option['update'] + DAY_IN_SECONDS) {
362 $this->update();
363 }
364
365 $events = ! empty($option['events']) ? $this->verify_active($option['events']) : array();
366 $feed = ! empty($option['feed']) ? $this->verify_active($option['feed']) : array();
367
368 // If there is a new user notification, add it to the beginning of the notification list
369 $sbr_newuser = new SBR_New_User();
370 $newuser_notifications = $sbr_newuser->get();
371
372 if (! empty($newuser_notifications)) {
373 $events = array_merge($newuser_notifications, $events);
374 }
375
376 return array_merge($events, $feed);
377 }
378
379 /**
380 * Get notification count.
381 *
382 * @since 1.2
383 *
384 * @return int
385 */
386 public function get_count()
387 {
388 return count($this->get());
389 }
390
391 /**
392 * Add a manual notification event.
393 *
394 * @since 1.2
395 *
396 * @param array $notification Notification data.
397 */
398 public function add($notification)
399 {
400 if (empty($notification['id'])) {
401 return;
402 }
403
404 $option = $this->get_option();
405
406 if (in_array($notification['id'], $option['dismissed'])) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
407 return;
408 }
409
410 foreach ($option['events'] as $item) {
411 if ($item['id'] === $notification['id']) {
412 return;
413 }
414 }
415
416 $notification = $this->verify(array( $notification ));
417
418 update_option(
419 'sbr_notifications',
420 array(
421 'update' => $option['update'],
422 'feed' => $option['feed'],
423 'events' => array_merge($notification, $option['events']),
424 'dismissed' => $option['dismissed'],
425 )
426 );
427 }
428
429 /**
430 * Update notification data from feed.
431 *
432 * @since 1.2
433 */
434 public function update()
435 {
436 $feed = $this->fetch_feed();
437 $option = $this->get_option();
438 update_option(
439 'sbr_notifications',
440 array(
441 'update' => sbr_get_current_time(),
442 'feed' => $feed,
443 'events' => $option['events'],
444 'dismissed' => $option['dismissed'],
445 )
446 );
447 }
448
449 /**
450 * Admin area Form Overview enqueues.
451 *
452 * @since 1.2
453 */
454 public function enqueues()
455 {
456 if (! $this->has_access()) {
457 return;
458 }
459
460 $notifications = $this->get();
461
462 if (empty($notifications)) {
463 return;
464 }
465
466 $min = '';
467
468 wp_enqueue_style(
469 'sbr-admin-notifications',
470 SBR_PLUGIN_URL . "assets/css/admin-notifications{$min}.css",
471 array(),
472 SBRVER
473 );
474
475 wp_enqueue_script(
476 'sbr-admin-notifications',
477 SBR_PLUGIN_URL . "assets/js/admin-notifications{$min}.js",
478 array( 'jquery' ),
479 SBRVER,
480 true
481 );
482
483 wp_localize_script('sbr-admin-notifications', 'sbrA', array(
484 'ajax_url' => admin_url('admin-ajax.php'),
485 'sbr_nonce' => wp_create_nonce('sbr-admin')
486 ));
487 }
488
489 /**
490 * Fields from the remote source contain placeholders to allow
491 * some messages to be used for multiple plugins.
492 *
493 * @param $content string
494 * @param $notification array
495 *
496 * @return string
497 *
498 * @since 1.2
499 */
500 public function replace_merge_fields($content, $notification)
501 {
502 $merge_fields = array(
503 '{plugin}' => 'Reviews Feed',
504 '{amount}' => isset($notification['amount']) ? $notification['amount'] : '',
505 '{platform}' => 'Reviews',
506 '{lowerplatform}' => 'reviews',
507 '{review-url}' => 'https://wordpress.org/support/plugin/reviews-feed/reviews/',
508 '{slug}' => 'reviews-feed',
509 '{campaign}' => 'reviews-free'
510 );
511
512 if (\SmashBalloon\Reviews\Common\Util::sbr_is_pro()) {
513 $merge_fields['{campaign}'] = 'reviews-pro';
514 $merge_fields['{plugin}'] = 'Reviews Feed Pro';
515 }
516
517 foreach ($merge_fields as $find => $replace) {
518 $content = str_replace($find, $replace, $content);
519 }
520
521 return $content;
522 }
523
524
525
526 public function get_notifcation_info_json()
527 {
528 if (isset($_GET['feed_id'])) {
529 return [];
530 }
531
532 $notifications = $this->get();
533
534 if (empty($notifications)) {
535 return [];
536 }
537
538 $is_review_notice = ! empty($notifications[0]) && ! empty($notifications[0]['id']);
539
540 // CUSTOM MODIFICATION: Allow all notifications, not just review notices
541 // Original code only displayed if first notification was a review notice
542 // Commented out to allow custom notifications to display
543 // if ( ! $is_review_notice || ! empty( $_GET['feed_id'] ) ) {
544 // return null;
545 // }
546 }
547
548
549
550 /**
551 * Output notifications on Reviews Feed admin area.
552 *
553 * @since 1.2
554 */
555 public function output()
556 {
557 if (isset($_GET['feed_id'])) {
558 return null;
559 }
560
561 $notifications = $this->get();
562 if (empty($notifications)) {
563 return null;
564 }
565
566 $is_review_notice = ! empty($notifications[0]) && ! empty($notifications[0]['id']) && $notifications[0]['id'] === 'review';
567
568 if (! $is_review_notice || ! empty($_GET['feed_id'])) {
569 return null;
570 }
571
572 $notifications_html = '';
573 $current_class = ' current';
574 $content_allowed_tags = array(
575 'em' => array(),
576 'strong' => array(),
577 'span' => array(
578 'style' => array(),
579 ),
580 'a' => array(
581 'href' => array(),
582 'target' => array(),
583 'rel' => array(),
584 ),
585 );
586
587 foreach ($notifications as $notification) {
588 $type = $notification['id'];
589
590 // Buttons HTML.
591 $buttons_html = '';
592 if (! empty($notification['btns']) && is_array($notification['btns'])) {
593 foreach ($notification['btns'] as $btn_type => $btn) {
594 if ($type == 'review' || $type == 'discount') {
595 $btn_class = $btn_type === 'primary' ? 'sbr-btn-blue' : 'sbr-btn-grey';
596 } else {
597 $btn_class = $btn_type === 'primary' ? 'sbr-btn-orange' : 'sbr-btn-grey';
598 }
599 if (is_array($btn['url'])) {
600 $args = array();
601 foreach ($btn['url'] as $key => $value) {
602 $args[ sanitize_key($key) ] = sanitize_key($value);
603 }
604 $btn['url'] = wp_nonce_url(add_query_arg($args), 'sbr-' . $type, 'sbr_nonce');
605 }
606 if (! empty($btn['attr'])) {
607 $btn['target'] = '_blank';
608 }
609 if (empty($btn['class'])) {
610 $btn['class'] = '';
611 }
612 $buttons_html .= sprintf(
613 '<a href="%1$s" class="sbr-btn %2$s %3$s"%4$s>%5$s</a>',
614 ! empty($btn['url']) ? esc_url($this->replace_merge_fields($btn['url'], $notification)) : '',
615 esc_attr($btn['class']),
616 esc_attr($btn_class),
617 ! empty($btn['target']) && $btn['target'] === '_blank' ? ' target="_blank" rel="noopener noreferrer"' : '',
618 ! empty($btn['text']) ? sanitize_text_field($btn['text']) : ''
619 );
620 }
621 $buttons_html = ! empty($buttons_html) ? '<div class="buttons">' . $buttons_html . '</div>' : '';
622 }
623 if (empty($notification['image'])) {
624 $image_html = '<div class="bell">';
625
626 $image_html .= '<svg xmlns="http://www.w3.org/2000/svg" width="42" height="48" viewBox="0 0 42 48"><defs><style>.a{fill:#777;}.b{fill:#ca4a1f;}</style></defs><path class="a" d="M23-79a6.005,6.005,0,0,1-6-6h10.06a12.066,12.066,0,0,0,1.791,1.308,6.021,6.021,0,0,1-2.077,3.352A6.008,6.008,0,0,1,23-79Zm1.605-9H5.009a2.955,2.955,0,0,1-2.173-.923A3.088,3.088,0,0,1,2-91a2.919,2.919,0,0,1,.807-2.036c.111-.12.229-.243.351-.371a14.936,14.936,0,0,0,3.126-4.409A23.283,23.283,0,0,0,8.007-107.5a14.846,14.846,0,0,1,.906-5.145,14.5,14.5,0,0,1,2.509-4.324A15.279,15.279,0,0,1,20-122.046V-124a3,3,0,0,1,3-3,3,3,0,0,1,3,3v1.954a15.28,15.28,0,0,1,8.58,5.078,14.5,14.5,0,0,1,2.509,4.324,14.846,14.846,0,0,1,.906,5.145c0,.645.016,1.281.047,1.888A12.036,12.036,0,0,0,35-106a11.921,11.921,0,0,0-8.485,3.515A11.923,11.923,0,0,0,23-94a12,12,0,0,0,1.6,6Z" transform="translate(-2 127)"/><circle class="b" cx="9" cy="9" r="9" transform="translate(24 24)"/></svg>';
627 $image_html .= '</div>';
628 } else {
629 if ($notification['image'] === 'balloon') {
630 $image_html = sprintf(
631 '<div class="bell"><img src="%s" alt="notice">',
632 SBR_PLUGIN_URL . 'assets/images/balloon.svg'
633 );
634 } elseif ($notification['image'] === 'review' || $notification['image'] === 'discount') {
635 $image_html = sprintf(
636 '<div class="bell"><img src="%s" alt="notice">',
637 SBR_PLUGIN_URL . 'assets/images/' . sanitize_text_field(str_replace('sbi', 'sbr', $notification['image']))
638 );
639 } else {
640 $image_html = '<div class="thumb">';
641 $img_src = SBR_PLUGIN_URL . 'assets/images/' . sanitize_text_field(str_replace('sbi', 'sbr', $notification['image']));
642 $image_html .= '<img src="' . esc_url($img_src) . '" alt="notice">';
643
644 if (isset($notification['image_overlay'])) {
645 $image_html .= '<div class="img-overlay">' . esc_html(str_replace('%', '%%', $notification['image_overlay'])) . '</div>';
646 }
647 }
648 $image_html .= '</div>';
649 }
650
651 // Check if it's review notice then show step #1
652 if ($type == 'review') {
653 $step1_img = SBR_PLUGIN_URL . 'assets/images/' . sanitize_text_field(str_replace('sbi', 'sbr', $notification['image']));
654 $step1_img_html = sprintf('<div class="bell"><img src="%s" alt="notice"></div>', $step1_img);
655
656 $review_consent = get_option('sbr_review_consent');
657 $sbr_open_feedback_url = 'https://smashballoon.com/feedback/?plugin=reviews-lite&utm_campaign=reviews-free&utm_source=notifications&utm_medium=feedback';
658 // step #1 for the review notice
659 if (! $review_consent) {
660 $step1_btns = sprintf(
661 '<button class="sbr-btn-link" id="sbr_review_consent_yes">%s</button>',
662 __('Yes', 'reviews-feed')
663 );
664 $step1_btns .= sprintf(
665 '<a href="%s" target="_blank" class="sbr-btn-link" id="sbr_review_consent_no">%s</a>',
666 $sbr_open_feedback_url,
667 __('No', 'reviews-feed')
668 );
669 $notifications_html .= sprintf(
670 '<div class="sbr_review_step1_notice" data-message-id="%3$s">' . $step1_img_html . '
671 <h3 class="title">%1$s</h3>
672 <div class="review-step-1-btns">%2$s</div>
673 </div>',
674 __('Are you enjoying the Reviews Feed Plugin?', 'reviews-feed'),
675 $step1_btns,
676 ! empty($notification['id']) ? esc_attr(sanitize_text_field($notification['id'])) : 0
677 );
678 }
679 }
680
681 $review_consent = get_option('sbr_review_consent');
682 $review_step2_style = '';
683 if ($type == 'review' && ! $review_consent) {
684 $review_step2_style = 'style="display: none;"';
685 }
686
687 // Build the notification HTML for review notice
688 if ($type == 'review') {
689 $notifications_html .= sprintf(
690 '<div class="message%5$s %7$s" data-message-id="%4$s" %6$s>' . $image_html . '
691 <h3 class="title">%1$s</h3>
692 <p class="content">%2$s</p>
693 %3$s
694 </div>',
695 __('Glad to hear you are enjoying it. Would you consider leaving a positive review?', 'reviews-feed'),
696 __('It really helps to support the plugin and help others to discover it too!', 'reviews-feed'),
697 $buttons_html,
698 ! empty($notification['id']) ? esc_attr(sanitize_text_field($notification['id'])) : 0,
699 $current_class,
700 ( $notification['id'] == 'review' && ! empty($review_step2_style) ) ? $review_step2_style : '',
701 ( $type == 'review' ) ? 'rn_step_2' : ''
702 );
703 } elseif ($type == 'discount') {
704 } else {
705 // Notification HTML for other notices
706 $notifications_html .= sprintf(
707 '<div class="message%5$s" data-message-id="%4$s" %6$s>' . $image_html . '
708 <h3 class="title">%1$s</h3>
709 <p class="content">%2$s</p>
710 %3$s
711 </div>',
712 ! empty($notification['title']) ? $this->replace_merge_fields(sanitize_text_field($notification['title']), $notification) : '',
713 ! empty($notification['content']) ? wp_kses($this->replace_merge_fields($notification['content'], $notification), $content_allowed_tags) : '',
714 $buttons_html,
715 ! empty($notification['id']) ? esc_attr(sanitize_text_field($notification['id'])) : 0,
716 $current_class,
717 ( $notification['id'] == 'review' && ! empty($review_step2_style) ) ? $review_step2_style : ''
718 );
719 }
720
721 // Only first notification is current.
722 $current_class = '';
723 }
724
725 $close_href = wp_nonce_url(add_query_arg(array( 'sbr_dismiss' => $type )), 'sbr-' . $type, 'sbr_nonce');
726 $type_class = '';
727 if ($type === 'review' || $type === 'discount') {
728 $type_class = $type === 'review' ? 'sbr_review_notice' : 'sbr_discount_notice';
729 }
730 $href = ( $type === 'review' || $type === 'discount' ) ? ' href=" ' . esc_attr($close_href) . '" ' : '';
731
732 $return = '<div id="sbr-notifications" class="' . esc_attr($type_class) . '" ' . $href . '>';
733 $return .= '<button type="button" class="dismiss" aria-label="' . esc_attr__('Dismiss this message', 'reviews-feed') . '">';
734 $return .= '<svg aria-hidden="true" focusable="false" width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M9.66683 1.27325L8.72683 0.333252L5.00016 4.05992L1.2735 0.333252L0.333496 1.27325L4.06016 4.99992L0.333496 8.72659L1.2735 9.66659L5.00016 5.93992L8.72683 9.66659L9.66683 8.72659L5.94016 4.99992L9.66683 1.27325Z" fill="white"/></svg>';
735 $return .= '</button>';
736
737 if (count($notifications) > 1) :
738 $return .= '<div class="navigation">';
739 $return .= '<button type="button" class="prev disabled" aria-label="' . esc_attr__('Previous message', 'reviews-feed') . '" disabled><svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="chevron-left" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" class="svg-inline--fa fa-chevron-left fa-w-10"><path fill="currentColor" d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z" class=""></path></svg></button>';
740 $return .= '<button type="button" class="next disabled" aria-label="' . esc_attr__('Next message', 'reviews-feed') . '" disabled><svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="chevron-right" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" class="svg-inline--fa fa-chevron-right fa-w-10"><path fill="currentColor" d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z" class=""></path></svg></button>';
741 $return .= '</div>';
742 endif;
743
744 $return .= '<div class="messages">';
745 $return .= $notifications_html;
746 $return .= '</div>';
747 $return .= '</div>';
748
749 return $return;
750 }
751
752 /**
753 * Dismiss notification via AJAX. If it's a new user message, also dismiss it
754 * on all admin pages.
755 *
756 * @since 1.2
757 */
758 public function dismiss()
759 {
760 // Run a security check.
761 check_ajax_referer('sbr-admin', 'nonce');
762
763 // Check for access and required param.
764 if (! $this->has_access() || empty($_POST['id'])) {
765 wp_send_json_error();
766 }
767
768 $id = sanitize_text_field(wp_unslash($_POST['id']));
769
770 if ($id === 'review') {
771 $sbr_statuses_option = get_option('sbr_statuses', array());
772
773 update_option('sbr_rating_notice', 'dismissed', false);
774 $sbr_statuses_option['rating_notice_dismissed'] = sbr_get_current_time();
775 update_option('sbr_statuses', $sbr_statuses_option, false);
776 } elseif ($id === 'discount') {
777 update_user_meta(get_current_user_id(), 'sbr_ignore_new_user_sale_notice', 'always');
778
779 $current_month_number = (int)date('n', sbr_get_current_time());
780 $not_early_in_the_year = ($current_month_number > 5);
781
782 if ($not_early_in_the_year) {
783 update_user_meta(get_current_user_id(), 'sbr_ignore_bfcm_sale_notice', date('Y', sbr_get_current_time()));
784 }
785 }
786
787 $option = $this->get_option();
788 $type = is_numeric($id) ? 'feed' : 'events';
789
790 $option['dismissed'][] = $id;
791 $option['dismissed'] = array_unique($option['dismissed']);
792
793 // Remove notification.
794 if (is_array($option[ $type ]) && ! empty($option[ $type ])) {
795 foreach ($option[ $type ] as $key => $notification) {
796 if ($notification['id'] == $id) { // phpcs:ignore WordPress.PHP.StrictComparisons
797 unset($option[ $type ][ $key ]);
798 break;
799 }
800 }
801 }
802
803 update_option('sbr_notifications', $option);
804
805 wp_send_json_success();
806 }
807 }
808