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_New_User.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_New_User.php
550 lines
1 <?php
2
3 /**
4 * SBR_New_User.
5 *
6 * @since 1.2
7 */
8
9 namespace SmashBalloon\Reviews\Common\Admin;
10
11 // Exit if accessed directly
12 if (! defined('ABSPATH')) {
13 exit;
14 }
15
16 class SBR_New_User extends SBR_Notifications {
17 /**
18 * Source of notifications content.
19 *
20 * @since 1.2
21 *
22 * @var string
23 */
24 const SOURCE_URL = 'https://plugin.smashballoon.com/newuser.json';
25
26 /**
27 * @var string
28 */
29 const OPTION_NAME = 'sbr_newuser_notifications';
30
31 /**
32 * Register hooks.
33 *
34 * @since 1.2
35 */
36 public function hooks()
37 {
38 add_action('admin_init', array( $this, 'dismiss' ));
39 add_action('wp_ajax_sbr_review_notice_consent_update', array( $this, 'review_notice_consent' ));
40 }
41
42 public function option_name()
43 {
44 return self::OPTION_NAME;
45 }
46
47 public function source_url()
48 {
49 return self::SOURCE_URL;
50 }
51
52 /**
53 * Verify notification data before it is saved.
54 *
55 * @param array $notifications Array of notifications items to verify.
56 *
57 * @return array
58 *
59 * @since 1.2
60 */
61 public function verify($notifications)
62 {
63 $data = array();
64
65 if (! is_array($notifications) || empty($notifications)) {
66 return $data;
67 }
68
69 $option = $this->get_option();
70
71 foreach ($notifications as $key => $notification) {
72 // The message should never be empty, if they are, ignore.
73 if (empty($notification['content'])) {
74 continue;
75 }
76
77 // Ignore if notification has already been dismissed.
78 if (! empty($option['dismissed']) && in_array($notification['id'], $option['dismissed'])) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
79 continue;
80 }
81
82 $data[ $key ] = $notification;
83 }
84
85 return $data;
86 }
87
88 /**
89 * Verify saved notification data for active notifications.
90 *
91 * @since 1.2
92 *
93 * @param array $notifications Array of notifications items to verify.
94 *
95 * @return array
96 */
97 public function verify_active($notifications)
98 {
99 if (! is_array($notifications) || empty($notifications)) {
100 return array();
101 }
102
103 $sbr_statuses_option = get_option('sbr_statuses', array());
104 $current_time = sbr_get_current_time();
105
106 // rating notice logic
107 $sbr_rating_notice_option = get_option('sbr_rating_notice', false);
108 $sbr_rating_notice_waiting = get_transient('reviews_feed_rating_notice_waiting');
109 $should_show_rating_notice = ( $sbr_rating_notice_waiting !== 'waiting' && $sbr_rating_notice_option !== 'dismissed' );
110
111 // new user discount logic
112 $in_new_user_month_range = true;
113 $should_show_new_user_discount = false;
114 $has_been_one_month_since_rating_dismissal = isset($sbr_statuses_option['rating_notice_dismissed']) ? ( (int) $sbr_statuses_option['rating_notice_dismissed'] + ( (int) $notifications['review']['wait'] * DAY_IN_SECONDS ) ) < $current_time + 1 : true;
115
116 if (isset($sbr_statuses_option['first_install']) && $sbr_statuses_option['first_install'] === 'from_update') {
117 global $current_user;
118 $user_id = $current_user->ID;
119 $ignore_new_user_sale_notice_meta = get_user_meta($user_id, 'sbr_ignore_new_user_sale_notice');
120 $ignore_new_user_sale_notice_meta = isset($ignore_new_user_sale_notice_meta[0]) ? $ignore_new_user_sale_notice_meta[0] : '';
121 if ($ignore_new_user_sale_notice_meta !== 'always') {
122 $should_show_new_user_discount = true;
123 }
124 } elseif ($in_new_user_month_range && $has_been_one_month_since_rating_dismissal && $sbr_rating_notice_waiting !== 'waiting') {
125 global $current_user;
126 $user_id = $current_user->ID;
127 $ignore_new_user_sale_notice_meta = get_user_meta($user_id, 'sbr_ignore_new_user_sale_notice');
128 $ignore_new_user_sale_notice_meta = isset($ignore_new_user_sale_notice_meta[0]) ? $ignore_new_user_sale_notice_meta[0] : '';
129
130 if (
131 $ignore_new_user_sale_notice_meta !== 'always'
132 && isset($sbr_statuses_option['first_install'])
133 && $current_time > (int) $sbr_statuses_option['first_install'] + ( (int) $notifications['discount']['wait'] * DAY_IN_SECONDS )
134 ) {
135 $should_show_new_user_discount = true;
136 }
137 }
138
139 if (\SmashBalloon\Reviews\Common\Util::sbr_is_pro()) {
140 $should_show_new_user_discount = false;
141 }
142
143 if (isset($notifications['review']) && $should_show_rating_notice) {
144 return array( $notifications['review'] );
145 } elseif (isset($notifications['discount']) && $should_show_new_user_discount) {
146 return array( $notifications['discount'] );
147 }
148
149 return array();
150 }
151
152 /**
153 * Get notification data.
154 *
155 * @since 1.2
156 *
157 * @return array
158 */
159 public function get()
160 {
161 if (! $this->has_access()) {
162 return array();
163 }
164
165 $option = $this->get_option();
166
167 // Only update if does not exist.
168 if (empty($option['update'])) {
169 $this->update();
170 }
171
172 $events = ! empty($option['events']) ? $this->verify_active($option['events']) : array();
173 $feed = ! empty($option['feed']) ? $this->verify_active($option['feed']) : array();
174
175 return array_merge($events, $feed);
176 }
177
178 /**
179 * Add a manual notification event.
180 *
181 * @since 1.2
182 *
183 * @param array $notification Notification data.
184 */
185 public function add($notification)
186 {
187 if (empty($notification['id'])) {
188 return;
189 }
190
191 $option = $this->get_option();
192
193 if (in_array($notification['id'], $option['dismissed'])) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
194 return;
195 }
196
197 foreach ($option['events'] as $item) {
198 if ($item['id'] === $notification['id']) {
199 return;
200 }
201 }
202
203 $notification = $this->verify(array( $notification ));
204
205 update_option(
206 $this->option_name(),
207 array(
208 'update' => $option['update'],
209 'feed' => $option['feed'],
210 'events' => array_merge($notification, $option['events']),
211 'dismissed' => $option['dismissed'],
212 )
213 );
214 }
215
216 /**
217 * Update notification data from feed.
218 *
219 * @since 1.2
220 */
221 public function update()
222 {
223 $feed = $this->fetch_feed();
224 $option = $this->get_option();
225
226 update_option(
227 $this->option_name(),
228 array(
229 'update' => time(),
230 'feed' => $feed,
231 'events' => $option['events'],
232 'dismissed' => $option['dismissed'],
233 )
234 );
235 }
236
237 /**
238 * Do not enqueue anything extra.
239 *
240 * @since 1.2
241 */
242 public function enqueues()
243 {
244 }
245
246 public function review_notice_consent()
247 {
248 // Security Checks
249 check_ajax_referer('sbr-admin', 'sbr_nonce');
250 if (! sbr_current_user_can('manage_reviews_feed_options')) {
251 wp_send_json_error(); // This auto-dies.
252 }
253
254 $consent = isset($_POST['consent']) ? sanitize_text_field($_POST['consent']) : '';
255
256 update_option('sbr_review_consent', $consent);
257
258 if ($consent == 'no') {
259 $sbr_statuses_option = get_option('sbr_statuses', array());
260 update_option('sbr_rating_notice', 'dismissed', false);
261 $sbr_statuses_option['rating_notice_dismissed'] = sbr_get_current_time();
262 update_option('sbr_statuses', $sbr_statuses_option, false);
263 }
264 wp_die();
265 }
266
267 /**
268 * Output notifications on Form Overview admin area.
269 *
270 * @since 1.2
271 */
272 public function output()
273 {
274 $notifications = $this->get();
275 if (empty($notifications)) {
276 return;
277 }
278 // new user notices included in regular settings page notifications so this
279 // checks to see if user is one of those pages
280 if (
281 ! empty($_GET['page'])
282 && strpos($_GET['page'], 'sbr') !== false
283 ) {
284 return;
285 }
286
287 $content_allowed_tags = array(
288 'em' => array(),
289 'strong' => array(),
290 'span' => array(
291 'style' => array(),
292 ),
293 'a' => array(
294 'href' => array(),
295 'target' => array(),
296 'rel' => array(),
297 ),
298 );
299 $image_overlay = '';
300
301 foreach ($notifications as $notification) {
302 $img_src = SBR_PLUGIN_URL . 'assets/images/' . sanitize_text_field(str_replace('sbi', 'sbr', $notification['image']));
303 $type = sanitize_text_field($notification['id']);
304 // check if this is a review notice
305 if ($type == 'review') {
306 $review_consent = get_option('sbr_review_consent');
307 $sbr_open_feedback_url = 'https://smashballoon.com/feedback/?plugin=reviews-pro&utm_campaign=reviews-pro&utm_source=notifications&utm_medium=feedback';
308 // step #1 for the review notice
309 if (! $review_consent) {
310 ?>
311 <div class="sbr_notice sbr_review_notice_step_1">
312 <div class="sbr_thumb">
313 <img src="<?php echo esc_url($img_src); ?>" alt="notice">
314 </div>
315 <div class="sbr-notice-text">
316 <p class="sbr-notice-text-p"><?php echo esc_html__('Are you enjoying the Reviews Feed Plugin?', 'reviews-feed'); ?></p>
317 </div>
318 <div class="sbr-notice-consent-btns">
319 <?php
320 printf(
321 '<button class="sbr-btn-link" id="sbr_review_consent_yes">%s</button>',
322 esc_html__('Yes', 'reviews-feed')
323 );
324
325 printf(
326 '<a href="%s" target="_blank" class="sbr-btn-link" id="sbr_review_consent_no">%s</a>',
327 esc_url($sbr_open_feedback_url),
328 esc_html__('No', 'reviews-feed')
329 );
330 ?>
331 </div>
332 </div>
333 <?php
334 }
335 }
336 $close_href = wp_nonce_url(add_query_arg(array( 'sbr_dismiss' => $type )), 'sbr-' . $type, 'sbr_nonce');
337
338 $title = $this->get_notice_title($notification);
339 $content = $this->get_notice_content($notification, $content_allowed_tags);
340
341 $buttons = array();
342 if (! empty($notification['btns']) && is_array($notification['btns'])) {
343 foreach ($notification['btns'] as $btn_type => $btn) {
344 if (! is_array($btn['url'])) {
345 $buttons[ $btn_type ]['url'] = $this->replace_merge_fields($btn['url'], $notification);
346 } elseif (is_array($btn['url'])) {
347 $buttons[ $btn_type ]['url'] = wp_nonce_url(add_query_arg($btn['url']), 'sbr-' . $type, 'sbr_nonce');
348 $close_href = $buttons[ $btn_type ]['url'];
349 }
350
351 $buttons[ $btn_type ]['attr'] = '';
352 if (! empty($btn['attr'])) {
353 $buttons[ $btn_type ]['attr'] = ' target="_blank" rel="noopener noreferrer"';
354 }
355
356 $buttons[ $btn_type ]['class'] = '';
357 if (! empty($btn['class'])) {
358 $buttons[ $btn_type ]['class'] = ' ' . $btn['class'];
359 }
360
361 $buttons[ $btn_type ]['text'] = '';
362 if (! empty($btn['text'])) {
363 $buttons[ $btn_type ]['text'] = wp_kses($btn['text'], $content_allowed_tags);
364 }
365 }
366 }
367 }
368
369 $review_consent = get_option('sbr_review_consent');
370 $review_step2_style = '';
371 if ($type == 'review' && ! $review_consent) {
372 $review_step2_style = 'style="display: none;"';
373 }
374 ?>
375
376 <div class="sbr_notice_op sbr_notice sbr_<?php echo esc_attr($type); ?>_notice" <?php echo ! empty($review_step2_style) ? esc_attr($review_step2_style) : ''; ?>>
377 <div class="sbr_thumb">
378 <img src="<?php echo esc_url($img_src); ?>" alt="notice">
379 <?php echo wp_kses_post($image_overlay); ?>
380 </div>
381 <div class="sbr-notice-text">
382 <div class="sbr-notice-text-inner">
383 <h3 class="sbr-notice-text-header"><?php echo wp_kses_post($title); ?></h3>
384 <p class="sbr-notice-text-p"><?php echo wp_kses_post($content); ?></p>
385 </div>
386 <div class="sbr-notice-btns-wrap">
387 <p class="sbr-notice-links">
388 <?php
389 foreach ($buttons as $type => $button) :
390 $btn_classes = array( 'sbr-btn' );
391 $btn_classes[] = esc_attr($button['class']);
392 if ($type == 'primary') {
393 $btn_classes[] = 'sbr-btn-blue';
394 } else {
395 $btn_classes[] = 'sbr-btn-grey';
396 }
397 ?>
398 <a class="<?php echo esc_attr(implode(' ', $btn_classes)); ?>" href="<?php echo esc_url($button['url']); ?>"<?php echo esc_attr($button['attr']); ?>><?php echo wp_kses_post($button['text']); ?></a>
399 <?php endforeach; ?>
400 </p>
401 </div>
402 </div>
403 <div class="sbr-notice-dismiss">
404 <a href="<?php echo esc_url($close_href); ?>">
405 <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
406 <path d="M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z" fill="#141B38"></path>
407 </svg>
408 </a>
409 </div>
410 </div>
411 <?php
412 }
413
414 /**
415 * SBR Get Notice Title depending on the notice type
416 *
417 * @since 1.1
418 *
419 * @param array $notification
420 *
421 * @return string $title
422 */
423 public function get_notice_title($notification)
424 {
425 $type = $notification['id'];
426 $title = '';
427
428 // Notice title depending on notice type
429 if ($type == 'review') {
430 $title = __('Glad to hear you are enjoying it. Would you consider leaving a positive review?', 'reviews-feed');
431 } elseif ($type == 'discount') {
432 $title = __('Exclusive Offer! 60% OFF', 'reviews-feed');
433 } else {
434 $title = $this->replace_merge_fields($notification['title'], $notification);
435 }
436
437 return $title;
438 }
439
440 /**
441 * SBR Get Notice Content depending on the notice type
442 *
443 * @since 1.1
444 *
445 * @param array $notification
446 * @param array $content_allowed_tags
447 *
448 * @return string $content
449 */
450 public function get_notice_content($notification, $content_allowed_tags)
451 {
452 $type = $notification['id'];
453 $content = '';
454
455 // Notice content depending on notice type
456 if ($type == 'review') {
457 $content = __('It really helps to support the plugin and help others to discover it too!', 'reviews-feed');
458 } elseif ($type == 'discount') {
459 $content = __('We don’t run promotions very often, but for a limited time we’re offering 60% Off our Pro version to all users of our free Reviews Feed.', 'reviews-feed');
460 } else {
461 if (! empty($notification['content'])) {
462 $content = wp_kses($this->replace_merge_fields($notification['content'], $notification), $content_allowed_tags);
463 }
464 }
465 return $content;
466 }
467
468 /**
469 * Hide messages permanently or some can be dismissed temporarily
470 *
471 * @since 1.2
472 */
473 // phpcs:disable Generic.Metrics.CyclomaticComplexity.MaxExceeded -- Legacy method with multiple notice handlers
474 public function dismiss()
475 {
476 global $current_user;
477 $user_id = $current_user->ID;
478 $sbr_statuses_option = get_option('sbr_statuses', array());
479
480 if (isset($_GET['sbr_ignore_rating_notice_nag'])) {
481 $rating_ignore = false;
482 if (isset($_GET['sbr_nonce']) && wp_verify_nonce($_GET['sbr_nonce'], 'sbr-review')) {
483 $rating_ignore = isset($_GET['sbr_ignore_rating_notice_nag']) ? sanitize_text_field($_GET['sbr_ignore_rating_notice_nag']) : false;
484 }
485 if (1 === (int) $rating_ignore) {
486 update_option('sbr_rating_notice', 'dismissed', false);
487 $sbr_statuses_option['rating_notice_dismissed'] = sbr_get_current_time();
488 update_option('sbr_statuses', $sbr_statuses_option, false);
489 } elseif ('later' === $rating_ignore) {
490 set_transient('reviews_feed_rating_notice_waiting', 'waiting', 2 * WEEK_IN_SECONDS);
491 delete_option('sbr_review_consent');
492 update_option('sbr_rating_notice', 'pending', false);
493 }
494 }
495
496 if (isset($_GET['sbr_ignore_new_user_sale_notice'])) {
497 $new_user_ignore = false;
498 if (isset($_GET['sbr_nonce']) && wp_verify_nonce($_GET['sbr_nonce'], 'sbr-discount')) {
499 $new_user_ignore = isset($_GET['sbr_ignore_new_user_sale_notice']) ? sanitize_text_field($_GET['sbr_ignore_new_user_sale_notice']) : false;
500 }
501 if ('always' === $new_user_ignore) {
502 update_user_meta($user_id, 'sbr_ignore_new_user_sale_notice', 'always');
503
504 $current_month_number = (int) date('n', sbr_get_current_time());
505 $not_early_in_the_year = ( $current_month_number > 5 );
506
507 if ($not_early_in_the_year) {
508 update_user_meta($user_id, 'sbr_ignore_bfcm_sale_notice', date('Y', sbr_get_current_time()));
509 }
510 }
511 }
512
513 if (isset($_GET['sbr_ignore_bfcm_sale_notice'])) {
514 $bfcm_ignore = false;
515 if (isset($_GET['sbr_nonce']) && wp_verify_nonce($_GET['sbr_nonce'], 'sbr-bfcm')) {
516 $bfcm_ignore = isset($_GET['sbr_ignore_bfcm_sale_notice']) ? sanitize_text_field($_GET['sbr_ignore_bfcm_sale_notice']) : false;
517 }
518 if ('always' === $bfcm_ignore) {
519 update_user_meta($user_id, 'sbr_ignore_bfcm_sale_notice', 'always');
520 } elseif (date('Y', sbr_get_current_time()) === $bfcm_ignore) {
521 update_user_meta($user_id, 'sbr_ignore_bfcm_sale_notice', date('Y', sbr_get_current_time()));
522 }
523 update_user_meta($user_id, 'sbr_ignore_new_user_sale_notice', 'always');
524 }
525
526 if (isset($_GET['sbr_dismiss'])) {
527 $notice_dismiss = false;
528 if (isset($_GET['sbr_nonce']) && wp_verify_nonce($_GET['sbr_nonce'], 'sbr-notice-dismiss')) {
529 $notice_dismiss = sanitize_text_field($_GET['sbr_dismiss']);
530 }
531 if ('review' === $notice_dismiss) {
532 update_option('sbr_rating_notice', 'dismissed', false);
533 $sbr_statuses_option['rating_notice_dismissed'] = sbr_get_current_time();
534 update_option('sbr_statuses', $sbr_statuses_option, false);
535
536 update_user_meta($user_id, 'sbr_ignore_new_user_sale_notice', 'always');
537 } elseif ('discount' === $notice_dismiss) {
538 $current_month_number = (int) date('n', sbr_get_current_time());
539 $not_early_in_the_year = ( $current_month_number > 5 );
540
541 if ($not_early_in_the_year) {
542 update_user_meta($user_id, 'sbr_ignore_bfcm_sale_notice', date('Y', sbr_get_current_time()));
543 }
544
545 update_user_meta($user_id, 'sbr_ignore_new_user_sale_notice', 'always');
546 }
547 }
548 }
549 // phpcs:enable Generic.Metrics.CyclomaticComplexity.MaxExceeded
550 }