PluginProbe
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms / trunk
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms vtrunk
3.53.0 3.52.0 3.51.0 3.50.0 3.45.0 3.38.0 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.40.0 3.40.1 3.41.0 3.42.0 3.43.0 3.44.0 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 All 177 releases
simple-tags / review-request / review.php

review.php in Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms trunk, at review-request/review.php

561 lines 19.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * This class can be customized to quickly add a review request system.
5 *
6 * It includes:
7 * - Multiple trigger groups which can be ordered by priority.
8 * - Multiple triggers per group.
9 * - Customizable messaging per trigger.
10 * - Link to review page.
11 * - Request reviews on a per user basis rather than per site.
12 * - Allows each user to dismiss it until later or permanently seamlessly via AJAX.
13 * - Integrates with attached tracking server to keep anonymous records of each triggers effectiveness.
14 * - Tracking Server API: https://gist.github.com/danieliser/0d997532e023c46d38e1bdfd50f38801
15 *
16 * To use this please include the following credit block as well as completing the following TODOS.
17 *
18 * Original Author: danieliser
19 * Original Author URL: https://danieliser.com
20 *
21 * TODO Search & Replace taxopress_ with your prefix
22 * TODO Search & Replace Taxopress_ with your prefix
23 * TODO Search & Replace 'simple-tags' with your 'simple-tags'
24 * TODO Change the $api_url if your using the accompanying tracking server. Leave it blank to disable this feature.
25 * TODO Modify the ::triggers function array with your custom triggers & text.
26 * TODO Keep in mind highest priority group/code combination that has all passing conditions will be chosen.
27 */
28
29 if (!defined('ABSPATH')) {
30 exit;
31 }
32
33 if (!class_exists('Taxopress_Modules_Reviews')) {
34 /**
35 * Class Taxopress_Modules_Reviews
36 *
37 * This class adds a review request system for your plugin or theme to the WP dashboard.
38 */
39 class Taxopress_Modules_Reviews
40 {
41 /**
42 * Tracking API Endpoint.
43 *
44 * @var string
45 */
46 public static $api_url = '';
47
48 /**
49 *
50 */
51 public static function init()
52 {
53 add_action('init', [__CLASS__, 'hooks']);
54 add_action('wp_ajax_taxopress_review_action', [__CLASS__, 'ajax_handler']);
55 }
56
57 /**
58 * Hook into relevant WP actions.
59 */
60 public static function hooks()
61 {
62 if (is_admin() && current_user_can('edit_posts')) {
63 self::installed_on();
64 add_action('admin_notices', [__CLASS__, 'admin_notices']);
65 add_action('network_admin_notices', [__CLASS__, 'admin_notices']);
66 add_action('user_admin_notices', [__CLASS__, 'admin_notices']);
67 //moved assets to footer due to a plugin stripping out assets in admin notice (https://wordpress.org/plugins/disable-admin-notices/)
68 add_action('admin_footer', [__CLASS__, 'admin_footer']);
69 }
70 }
71
72 /**
73 * Get the install date for comparisons. Sets the date to now if none is found.
74 *
75 * @return false|string
76 */
77 public static function installed_on()
78 {
79 $installed_on = get_option('taxopress_reviews_installed_on', false);
80
81 if (!$installed_on) {
82 $installed_on = current_time('mysql');
83 update_option('taxopress_reviews_installed_on', $installed_on);
84 }
85
86 return $installed_on;
87 }
88
89 /**
90 *
91 */
92 public static function ajax_handler()
93 {
94 $nonce = isset($_REQUEST['nonce']) ? sanitize_text_field(wp_unslash($_REQUEST['nonce'])) : '';
95 if (empty($nonce) || !wp_verify_nonce($nonce, 'taxopress_review_action')) {
96 wp_send_json_error();
97 }
98
99 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
100 $args = wp_parse_args($_REQUEST, [
101 'group' => self::get_trigger_group(),
102 'code' => self::get_trigger_code(),
103 'pri' => self::get_current_trigger('pri'),
104 'reason' => 'maybe_later',
105 ]);
106
107 try {
108 $user_id = get_current_user_id();
109
110 $dismissed_triggers = self::dismissed_triggers();
111 $dismissed_triggers[$args['group']] = $args['pri'];
112 update_user_meta($user_id, '_taxopress_reviews_dismissed_triggers', $dismissed_triggers);
113 update_user_meta($user_id, '_taxopress_reviews_last_dismissed', current_time('mysql'));
114
115 switch ($args['reason']) {
116 case 'maybe_later':
117 update_user_meta($user_id, '_taxopress_reviews_last_dismissed', current_time('mysql'));
118 break;
119 case 'am_now':
120 case 'already_did':
121 self::already_did(true);
122 break;
123 }
124
125 wp_send_json_success();
126 } catch (Exception $e) {
127 wp_send_json_error($e);
128 }
129 }
130
131 /**
132 * @return int|string
133 */
134 public static function get_trigger_group()
135 {
136 static $selected;
137
138 if (!isset($selected)) {
139 $dismissed_triggers = self::dismissed_triggers();
140
141 $triggers = self::triggers();
142
143 foreach ($triggers as $g => $group) {
144 foreach ($group['triggers'] as $t => $trigger) {
145 if (
146 !in_array(
147 false,
148 $trigger['conditions']
149 ) && (empty($dismissed_triggers[$g]) || $dismissed_triggers[$g] < $trigger['pri'])
150 ) {
151 $selected = $g;
152 break;
153 }
154 }
155
156 if (isset($selected)) {
157 break;
158 }
159 }
160 }
161
162 return $selected;
163 }
164
165 /**
166 * @return int|string
167 */
168 public static function get_trigger_code()
169 {
170 static $selected;
171
172 if (!isset($selected)) {
173 $dismissed_triggers = self::dismissed_triggers();
174
175 foreach (self::triggers() as $g => $group) {
176 foreach ($group['triggers'] as $t => $trigger) {
177 if (
178 !in_array(
179 false,
180 $trigger['conditions']
181 ) && (empty($dismissed_triggers[$g]) || $dismissed_triggers[$g] < $trigger['pri'])
182 ) {
183 $selected = $t;
184 break;
185 }
186 }
187
188 if (isset($selected)) {
189 break;
190 }
191 }
192 }
193
194 return $selected;
195 }
196
197 /**
198 * @param null $key
199 *
200 * @return bool|mixed|void
201 */
202 public static function get_current_trigger($key = null)
203 {
204 $group = self::get_trigger_group();
205 $code = self::get_trigger_code();
206
207 if (!$group || !$code) {
208 return false;
209 }
210
211 $trigger = self::triggers($group, $code);
212
213 if (empty($key)) {
214 $return = $trigger;
215 } elseif (isset($trigger[$key])) {
216 $return = $trigger[$key];
217 } else {
218 $return = false;
219 }
220
221 return $return;
222 }
223
224 /**
225 * Returns an array of dismissed trigger groups.
226 *
227 * Array contains the group key and highest priority trigger that has been shown previously for each group.
228 *
229 * $return = array(
230 * 'group1' => 20
231 * );
232 *
233 * @return array|mixed
234 */
235 public static function dismissed_triggers()
236 {
237 $user_id = get_current_user_id();
238
239 $dismissed_triggers = get_user_meta($user_id, '_taxopress_reviews_dismissed_triggers', true);
240
241 if (!$dismissed_triggers) {
242 $dismissed_triggers = [];
243 }
244
245 return $dismissed_triggers;
246 }
247
248 /**
249 * Returns true if the user has opted to never see this again. Or sets the option.
250 *
251 * @param bool $set If set this will mark the user as having opted to never see this again.
252 *
253 * @return bool
254 */
255 public static function already_did($set = false)
256 {
257 $user_id = get_current_user_id();
258
259 if ($set) {
260 update_user_meta($user_id, '_taxopress_reviews_already_did', true);
261
262 return true;
263 }
264
265 return (bool)get_user_meta($user_id, '_taxopress_reviews_already_did', true);
266 }
267
268 /**
269 * Gets a list of triggers.
270 *
271 * @param null $group
272 * @param null $code
273 *
274 * @return bool|mixed|void
275 */
276 public static function triggers($group = null, $code = null)
277 {
278 static $triggers;
279
280 if (!isset($triggers)) {
281 $time_message = __(
282 "Hey, you've been using TaxoPress for %s on your site. We hope the plugin has been useful. Please could you quickly leave a 5-star rating on WordPress.org? It really does help to keep TaxoPress growing.",
283 'simple-tags'
284 );
285
286 $triggers = apply_filters('taxopress_reviews_triggers', [
287 'time_installed' => [
288 'triggers' => [
289 'one_week' => [
290 'message' => sprintf($time_message, __('1 week', 'simple-tags')),
291 'conditions' => [
292 strtotime(self::installed_on() . ' +1 week') < time(),
293 ],
294 'link' => 'https://wordpress.org/support/plugin/simple-tags/reviews/?rate=5#rate-response',
295 'pri' => 10,
296 ],
297 'one_month' => [
298 'message' => sprintf($time_message, __('1 month', 'simple-tags')),
299 'conditions' => [
300 strtotime(self::installed_on() . ' +1 month') < time(),
301 ],
302 'link' => 'https://wordpress.org/support/plugin/simple-tags/reviews/?rate=5#rate-response',
303 'pri' => 20,
304 ],
305 'three_months' => [
306 'message' => sprintf($time_message, __('3 months', 'simple-tags')),
307 'conditions' => [
308 strtotime(self::installed_on() . ' +3 months') < time(),
309 ],
310 'link' => 'https://wordpress.org/support/plugin/simple-tags/reviews/?rate=5#rate-response',
311 'pri' => 30,
312 ],
313
314 ],
315 'pri' => 10,
316 ]
317 ]);
318
319 // Sort Groups
320 uasort($triggers, [__CLASS__, 'rsort_by_priority']);
321
322 // Sort each groups triggers.
323 foreach ($triggers as $k => $v) {
324 uasort($triggers[$k]['triggers'], [__CLASS__, 'rsort_by_priority']);
325 }
326 }
327
328 if (isset($group)) {
329 if (!isset($triggers[$group])) {
330 return false;
331 }
332
333
334 if (!isset($code)) {
335 $return = $triggers[$group];
336 } elseif (isset($triggers[$group]['triggers'][$code])) {
337 $return = $triggers[$group]['triggers'][$code];
338 } else {
339 $return = false;
340 }
341
342 return $return;
343 }
344
345 return $triggers;
346 }
347
348 /**
349 * Render admin notices if available.
350 */
351 public static function admin_notices()
352 {
353
354 if (self::hide_notices()) {
355 return;
356 }
357 $tigger = self::get_current_trigger();
358
359 ?>
360
361 <div class="notice notice-success is-dismissible taxopress-notice">
362
363 <img src="<?php echo esc_url(STAGS_URL . '/assets/images/logo-notice.png'); ?>" class="logo" alt=""/>
364 <p>
365 <?php echo esc_html($tigger['message']); ?>
366 </p>
367 <p>
368 <a class="button button-primary taxopress-dismiss" target="_blank"
369 href="https://wordpress.org/support/plugin/simple-tags/reviews/?rate=5#rate-response"
370 data-reason="am_now">
371 <strong><?php _e('Click here to add your rating for TaxoPress', 'simple-tags'); ?></strong>
372 </a> <a href="#" class="button taxopress-dismiss" data-reason="maybe_later">
373 <?php _e('Maybe later', 'simple-tags'); ?>
374 </a> <a href="#" class="button taxopress-dismiss" data-reason="already_did">
375 <?php _e('I already did', 'simple-tags'); ?>
376 </a>
377 </p>
378
379 </div>
380
381 <?php
382 }
383
384 /**
385 * Render admin notice assets if available.
386 */
387 public static function admin_footer()
388 {
389
390 if (self::hide_notices()) {
391 return;
392 }
393
394 $group = self::get_trigger_group();
395 $code = self::get_trigger_code();
396 $pri = self::get_current_trigger('pri');
397 $tigger = self::get_current_trigger();
398
399 // Used to anonymously distinguish unique site+user combinations in terms of effectiveness of each trigger.
400 $uuid = wp_hash(home_url() . '-' . get_current_user_id());
401
402 ?>
403
404 <script type="text/javascript">
405 (function($) {
406 var trigger = {
407 group: '<?php echo esc_js($group); ?>',
408 code: '<?php echo esc_js($code); ?>',
409 pri: '<?php echo esc_js($pri); ?>'
410 }
411
412 function dismiss(reason) {
413 $.ajax({
414 method: "POST",
415 dataType: "json",
416 url: ajaxurl,
417 data: {
418 action: 'taxopress_review_action',
419 nonce: '<?php echo esc_js(wp_create_nonce('taxopress_review_action')); ?>',
420 group: trigger.group,
421 code: trigger.code,
422 pri: trigger.pri,
423 reason: reason
424 }
425 })
426
427 <?php if (!empty(self::$api_url)) : ?>
428 $.ajax({
429 method: "POST",
430 dataType: "json",
431 url: '<?php echo esc_js(self::$api_url); ?>',
432 data: {
433 trigger_group: trigger.group,
434 trigger_code: trigger.code,
435 reason: reason,
436 uuid: '<?php echo esc_js($uuid); ?>'
437 }
438 })
439 <?php endif; ?>
440 }
441
442 $(document)
443 .on('click', '.taxopress-notice .taxopress-dismiss', function(event) {
444 var $this = $(this),
445 reason = $this.data('reason'),
446 notice = $this.parents('.taxopress-notice')
447
448 notice.fadeTo(100, 0, function() {
449 notice.slideUp(100, function() {
450 notice.remove()
451 })
452 })
453
454 dismiss(reason)
455 })
456 .ready(function() {
457 setTimeout(function() {
458 $('.taxopress-notice button.notice-dismiss').click(function(event) {
459 dismiss('maybe_later')
460 })
461 }, 1000)
462 })
463 }(jQuery))
464 </script>
465 <style>
466 .taxopress-notice {
467 min-height: 100px;
468 }
469 .taxopress-notice img.logo {
470 float: right;
471 width: 75px;
472 padding: 10px 0 10px 20px;
473 }
474 .taxopress-notice p,
475 .taxopress-notice .button {
476 font-size: 15px;
477 }
478 .taxopress-notice .button:not(.button-primary),
479 .taxopress-notice .button:not(.button-primary):hover,
480 .taxopress-notice .button:not(.button-primary):active,
481 .taxopress-notice .button:not(.button-primary):focus {
482 border-color: #1F48AC !important;
483 color: #1F48AC !important;
484 }
485 .taxopress-notice .button-primary,
486 .taxopress-notice .button-primary:hover,
487 .taxopress-notice .button-primary:active,
488 .taxopress-notice .button-primary:focus {
489 border-color: #1F48AC !important;
490 background: #1F48AC !important;
491 }
492 </style>
493 <?php
494 }
495
496 /**
497 * Checks if notices should be shown.
498 *
499 * @return bool
500 */
501 public static function hide_notices()
502 {
503 $conditions = [
504 self::already_did(),
505 self::last_dismissed() && strtotime(self::last_dismissed() . ' +2 weeks') > time(),
506 empty(self::get_trigger_code()),
507 ];
508
509 return in_array(true, $conditions);
510 }
511
512 /**
513 * Gets the last dismissed date.
514 *
515 * @return false|string
516 */
517 public static function last_dismissed()
518 {
519 $user_id = get_current_user_id();
520
521 return get_user_meta($user_id, '_taxopress_reviews_last_dismissed', true);
522 }
523
524 /**
525 * Sort array by priority value
526 *
527 * @param $a
528 * @param $b
529 *
530 * @return int
531 */
532 public static function sort_by_priority($a, $b)
533 {
534 if (!isset($a['pri']) || !isset($b['pri']) || $a['pri'] === $b['pri']) {
535 return 0;
536 }
537
538 return ($a['pri'] < $b['pri']) ? -1 : 1;
539 }
540
541 /**
542 * Sort array in reverse by priority value
543 *
544 * @param $a
545 * @param $b
546 *
547 * @return int
548 */
549 public static function rsort_by_priority($a, $b)
550 {
551 if (!isset($a['pri']) || !isset($b['pri']) || $a['pri'] === $b['pri']) {
552 return 0;
553 }
554
555 return ($a['pri'] < $b['pri']) ? 1 : -1;
556 }
557 }
558 }
559
560 Taxopress_Modules_Reviews::init();
561