PluginProbe
WP Directory Kit / 1.5.9
WP Directory Kit v1.5.9
1.5.9 1.5.7 1.5.6 1.5.5 1.5.4 1.5.3 trunk 1.1.0 1.1.6 1.1.8 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.8 All 37 releases
wpdirectorykit / includes / class-wpdirectorykit-review-request.php

class-wpdirectorykit-review-request.php in WP Directory Kit 1.5.9, at includes/class-wpdirectorykit-review-request.php

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