PluginProbe
WP Directory Kit / 1.1.0
WP Directory Kit v1.1.0
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 1.4.0 1.4.1 All 35 releases
wpdirectorykit / includes / class-wpdirectorykit-review-request.php

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

534 lines 15.0 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 $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' );
254 $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' );
255
256 $triggers = apply_filters( 'wpdirectorykit_reviews_triggers', array(
257 'time_installed' => array(
258 'triggers' => array(
259 'one_week' => array(
260 'message' => sprintf( $time_message, __( '1 week', 'wpdirectorykit' ) ),
261 'conditions' => array(
262 strtotime( self::installed_on() . ' +1 week' ) < time(),
263 ),
264 'link' => 'https://wordpress.org/support/plugin/wpdirectorykit/reviews/?rate=5#rate-response',
265 'pri' => 10,
266 ),
267 'one_month' => array(
268 'message' => sprintf( $time_message, __( '1 month', 'wpdirectorykit' ) ),
269 'conditions' => array(
270 strtotime( self::installed_on() . ' +1 month' ) < time(),
271 ),
272 'link' => 'https://wordpress.org/support/plugin/wpdirectorykit/reviews/?rate=5#rate-response',
273 'pri' => 20,
274 ),
275 'three_months' => array(
276 'message' => sprintf( $time_message, __( '3 months', 'wpdirectorykit' ) ),
277 'conditions' => array(
278 strtotime( self::installed_on() . ' +3 months' ) < time(),
279 ),
280 'link' => 'https://wordpress.org/support/plugin/wpdirectorykit/reviews/?rate=5#rate-response',
281 'pri' => 30,
282 ),
283
284 ),
285 'pri' => 10,
286 ),
287 'open_count' => array(
288 'triggers' => array(
289 '50_opens' => array(
290 'message' => sprintf( $open_message, 50 ),
291 'conditions' => array(
292 get_option( 'wpdirectorykit_total_open_count', 0 ) > 50,
293 ),
294 'link' => 'https://wordpress.org/support/plugin/wpdirectorykit/reviews/?rate=5#rate-response',
295 'pri' => 10,
296 ),
297 '100_opens' => array(
298 'message' => sprintf( $open_message, 100 ),
299 'conditions' => array(
300 get_option( 'wpdirectorykit_total_open_count', 0 ) > 100,
301
302 ),
303 'link' => 'https://wordpress.org/support/plugin/wpdirectorykit/reviews/?rate=5#rate-response',
304 'pri' => 20,
305 ),
306 '500_opens' => array(
307 'message' => sprintf( $open_message, 500 ),
308 'conditions' => array(
309 get_option( 'wpdirectorykit_total_open_count', 0 ) > 500,
310 ),
311 'link' => 'https://wordpress.org/support/plugin/wpdirectorykit/reviews/?rate=5#rate-response',
312 'pri' => 30,
313 ),
314
315 ),
316 'pri' => 50,
317 ),
318 ) );
319
320 // Sort Groups
321 uasort( $triggers, array( __CLASS__, 'rsort_by_priority' ) );
322
323 // Sort each groups triggers.
324 foreach ( $triggers as $k => $v ) {
325 uasort( $triggers[ $k ]['triggers'], array( __CLASS__, 'rsort_by_priority' ) );
326 }
327 }
328
329 if ( isset( $group ) ) {
330 if ( ! isset( $triggers[ $group ] ) ) {
331 return false;
332 }
333
334 return ! isset( $code ) ? $triggers[ $group ] : (isset( $triggers[ $group ]['triggers'][ $code ] ) ? $triggers[ $group ]['triggers'][ $code ] : false);
335 }
336
337 return $triggers;
338 }
339
340 /**
341 * Render admin notices if available.
342 */
343 public static function admin_notices() {
344 if ( self::hide_notices() ) {
345 return;
346 }
347
348 $group = self::get_trigger_group();
349 $code = self::get_trigger_code();
350 $pri = self::get_current_trigger( 'pri' );
351 $tigger = self::get_current_trigger();
352
353 // Used to anonymously distinguish unique site+user combinations in terms of effectiveness of each trigger.
354 $uuid = wp_hash( home_url() . '-' . get_current_user_id() );
355
356 ?>
357
358 <script type="text/javascript">
359 (function ($) {
360 var trigger = {
361 group: '<?php echo esc_js($group); ?>',
362 code: '<?php echo esc_js($code); ?>',
363 pri: '<?php echo esc_js($pri); ?>'
364 };
365
366 function dismiss(reason) {
367 $.ajax({
368 method: "POST",
369 dataType: "json",
370 url: ajaxurl,
371 data: {
372 action: 'wpdirectorykit_review_action',
373 nonce: '<?php echo wp_create_nonce( 'wpdirectorykit_review_action' ); ?>',
374 group: trigger.group,
375 code: trigger.code,
376 pri: trigger.pri,
377 reason: reason
378 }
379 });
380
381 <?php if ( ! empty( self::$api_url ) ) : ?>
382 $.ajax({
383 method: "POST",
384 dataType: "json",
385 url: '<?php echo esc_url(self::$api_url); ?>',
386 data: {
387 trigger_group: trigger.group,
388 trigger_code: trigger.code,
389 reason: reason,
390 uuid: '<?php echo esc_js($uuid); ?>'
391 }
392 });
393 <?php endif; ?>
394 }
395
396 $(document)
397 .on('click', '.wpdirectorykit-notice .wpdirectorykit-dismiss', function (event) {
398 var $this = $(this),
399 reason = $this.data('reason'),
400 notice = $this.parents('.wpdirectorykit-notice');
401
402 notice.fadeTo(100, 0, function () {
403 notice.slideUp(100, function () {
404 notice.remove();
405 });
406 });
407
408 dismiss(reason);
409 })
410 .ready(function () {
411 setTimeout(function () {
412 $('.wpdirectorykit-notice button.notice-dismiss').click(function (event) {
413 dismiss('maybe_later');
414 });
415 }, 1000);
416 });
417 }(jQuery));
418 </script>
419 <style>
420 .wpdirectorykit-notice p {
421 margin-bottom: 0;
422 }
423
424 .wpdirectorykit-notice img.logo {
425 float: right;
426 margin-left: 10px;
427 width: 75px;
428 padding: 0.25em;
429 border: 1px solid #ccc;
430 }
431 </style>
432
433
434 <div class="notice notice-success is-dismissible wpdirectorykit-notice">
435
436 <p>
437 <img class="logo" src="<?php echo WPDIRECTORYKIT_URL; ?>admin/img/icon-256x256.jpg" />
438 <strong>
439 <?php echo esc_html($tigger['message']); ?>
440 <br />
441 ~ WP Directory Kit
442 </strong>
443 </p>
444 <ul>
445 <li>
446 <a class="wpdirectorykit-dismiss" target="_blank" href="https://wordpress.org/support/plugin/wpdirectorykit/reviews/?rate=5#rate-response" data-reason="am_now">
447 <strong><?php _e( 'Ok, I will help you with 5 star rating', 'wpdirectorykit' ); ?></strong>
448 </a>
449 </li>
450 <li>
451 <a href="https://wpdirectorykit.com/contact.html" target="_blank"class="wpdirectorykit-dismiss" data-reason="improve_suggestion">
452 <?php _e( 'No, you doesn\'t deserver 5 stars and I will tell you why!', 'wpdirectorykit' ); ?>
453 </a>
454 </li>
455 <li>
456 <a href="#" class="wpdirectorykit-dismiss" data-reason="maybe_later">
457 <?php _e( 'Nope, maybe later', 'wpdirectorykit' ); ?>
458 </a>
459 </li>
460 <li>
461 <a href="#" class="wpdirectorykit-dismiss" data-reason="already_did">
462 <?php _e( 'I already did', 'wpdirectorykit' ); ?>
463 </a>
464 </li>
465 </ul>
466
467 </div>
468
469 <?php
470 }
471
472 /**
473 * Checks if notices should be shown.
474 *
475 * @return bool
476 */
477 public static function hide_notices() {
478 $conditions = array(
479 self::already_did(),
480 self::last_dismissed() && strtotime( self::last_dismissed() . ' +2 weeks' ) > time(),
481 empty( self::get_trigger_code() ),
482 );
483
484 return in_array( true, $conditions );
485 }
486
487 /**
488 * Gets the last dismissed date.
489 *
490 * @return false|string
491 */
492 public static function last_dismissed() {
493 $user_id = get_current_user_id();
494
495 return get_user_meta( $user_id, '_wpdirectorykit_reviews_last_dismissed', true );
496 }
497
498 /**
499 * Sort array by priority value
500 *
501 * @param $a
502 * @param $b
503 *
504 * @return int
505 */
506 public static function sort_by_priority( $a, $b ) {
507 if ( ! isset( $a['pri'] ) || ! isset( $b['pri'] ) || $a['pri'] === $b['pri'] ) {
508 return 0;
509 }
510
511 return ( $a['pri'] < $b['pri'] ) ? - 1 : 1;
512 }
513
514 /**
515 * Sort array in reverse by priority value
516 *
517 * @param $a
518 * @param $b
519 *
520 * @return int
521 */
522 public static function rsort_by_priority( $a, $b ) {
523 if ( ! isset( $a['pri'] ) || ! isset( $b['pri'] ) || $a['pri'] === $b['pri'] ) {
524 return 0;
525 }
526
527 return ( $a['pri'] < $b['pri'] ) ? 1 : - 1;
528 }
529
530 }
531
532 wpdirectorykit_Modules_Reviews::init();
533
534 ?>