PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.14
Booktics – Appointment Booking Calendar for Service Businesses v1.0.14
1.0.29 1.0.28 1.0.27 1.0.26 1.0.25 1.0.24 1.0.23 1.0.22 1.0.21 1.0.20 1.0.19 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.2 1.0.3 All 31 releases
booktics / vendor / arraytics / plugin-notice-sdk / src / Rating.php

Rating.php in Booktics – Appointment Booking Calendar for Service Businesses 1.0.14, at vendor/arraytics/plugin-notice-sdk/src/Rating.php

484 lines 13.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Arraytics\PluginNotice;
3
4 class Rating
5 {
6 /**
7 * Singleton instance of the Rating class.
8 *
9 * @var self|null
10 */
11 private static $instance;
12
13 /**
14 * Plugin slug or name.
15 *
16 * @var string
17 */
18 private $plugin_name;
19
20 /**
21 * Priority for hooking into WordPress actions.
22 *
23 * @var int
24 */
25 private $priority = 10;
26
27 /**
28 * Days after installation to show rating.
29 *
30 * @var int
31 */
32 private $days;
33
34 /**
35 * URL for plugin rating page.
36 *
37 * @var string
38 */
39 private $rating_url;
40
41 /**
42 * URL for plugin support page.
43 *
44 * @var string
45 */
46 private $support_url;
47
48 /**
49 * Plugin version, dynamically fetched.
50 *
51 * @var string
52 */
53 private $version;
54
55 /**
56 * Whether conditions to show rating are met.
57 *
58 * @var bool
59 */
60 private $condition_status = true;
61
62 /**
63 * Text domain for the plugin.
64 *
65 * @var string
66 */
67 private $text_domain;
68
69 /**
70 * URL of the plugin logo.
71 *
72 * @var string
73 */
74 private $plugin_logo;
75
76 /**
77 * Allowed admin screens to show rating.
78 *
79 * @var array
80 */
81 private $plugin_screens = [];
82
83 /**
84 * Whether duplicate rating notice is allowed.
85 *
86 * @var bool
87 */
88 private $duplication = false;
89
90 /**
91 * Flag to mark never-show triggered state.
92 *
93 * @var bool
94 */
95 private $never_show_triggered = false;
96
97 /**
98 * Interval (in days) to show rating again after "ask me later".
99 *
100 * @var int
101 */
102 private $rating_show_interval = 30;
103
104 /**
105 * API URL for fetching rating data.
106 *
107 * @var string
108 */
109 private $api_url;
110
111 /**
112 * Get singleton instance.
113 *
114 * @param string|null $text_domain
115 * @param string|null $unique_id
116 * @return self|false
117 */
118 public static function instance($text_domain = null, $unique_id = null)
119 {
120 if ($text_domain === null) {
121 return false;
122 }
123 if (!isset(self::$instance)) {
124 self::$instance = new self();
125 }
126
127 self::$instance->config($text_domain, $unique_id ?? uniqid());
128
129 return self::$instance;
130 }
131
132 /**
133 * Configure plugin-specific settings.
134 *
135 * @param string $text_domain
136 * @param string $unique_id
137 * @return self
138 */
139 public function config($text_domain, $unique_id)
140 {
141 $this->text_domain = $text_domain;
142 return $this;
143 }
144
145 public function update_settings()
146 {
147 $settings = get_transient($this->text_domain . '_rating_settings');
148 if ($settings) {
149 return;
150 }
151
152 $response = wp_remote_get($this->api_url . '/wp-json/plugin-banner/v1/rating');
153
154 if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
155 return;
156 }
157
158 $data = json_decode(wp_remote_retrieve_body($response), true);
159
160 $rating_settings = isset($data[$this->text_domain]) ? $data[$this->text_domain] : '';
161
162 set_transient($this->text_domain . '_rating_settings', $rating_settings, 12 * HOUR_IN_SECONDS);
163 }
164
165 public function set_plugin($plugin_name, $plugin_url)
166 {
167 $this->plugin_name = $plugin_name;
168 $this->rating_url = $plugin_url;
169 return $this;
170 }
171
172 public function set_api_url($url)
173 {
174 $this->api_url = rtrim($url, '/') . '/';
175 return $this;
176 }
177
178 public function set_priority($priority)
179 {
180 $this->priority = $priority;
181 return $this;
182 }
183
184 public function set_first_appear_day($days = 7)
185 {
186 $this->days = $days;
187 return $this;
188 }
189
190 public function set_rating_url($url)
191 {
192 $this->rating_url = $url;
193 return $this;
194 }
195
196 public function set_support_url($url)
197 {
198 $this->support_url = $url;
199 return $this;
200 }
201
202 public function set_plugin_logo($logo_url)
203 {
204 $this->plugin_logo = $logo_url;
205 return $this;
206 }
207
208 public function set_allowed_screens($screen)
209 {
210 $this->plugin_screens[] = $screen;
211 return $this;
212 }
213
214 public function set_condition($result)
215 {
216 if (is_bool($result)) {
217 $this->condition_status = $result;
218 } elseif (is_callable($result)) {
219 $this->condition_status = (bool) call_user_func($result);
220 } else {
221 $this->condition_status = false;
222 }
223 return $this;
224 }
225
226 public static function init()
227 {
228 add_action('wp_ajax_wpmet_rating_never_show_message', [__CLASS__, 'never_show_message']);
229 add_action('wp_ajax_wpmet_rating_ask_me_later_message', [__CLASS__, 'ask_me_later_message']);
230
231 if (self::$instance instanceof self) {
232 self::$instance->update_settings();
233 }
234 }
235
236 protected function is_current_screen_allowed($current_screen_id)
237 {
238 $allowed = array_merge($this->plugin_screens, ['dashboard', 'plugins']);
239 return in_array($current_screen_id, $allowed, true);
240 }
241
242 public function call()
243 {
244 self::init();
245 add_action('admin_head', [$this, 'fire'], $this->priority);
246 }
247
248 public function fire()
249 {
250 if (!current_user_can('update_plugins')) {
251 return;
252 }
253
254 $current_screen = get_current_screen();
255
256 if (!$this->is_current_screen_allowed($current_screen->id)) {
257 return;
258 }
259
260 if ($this->condition_status === false) {
261 return;
262 }
263
264 add_action('admin_footer', [$this, 'scripts'], 9999);
265
266 if (!$this->action_on_fire()) {
267 return;
268 }
269
270 if (!$this->is_installation_date_exists()) {
271 $this->set_installation_date();
272 }
273
274 if (get_option($this->text_domain . '_never_show') === 'yes') {
275 return;
276 }
277
278 if (get_option($this->text_domain . '_ask_me_later') === 'yes') {
279 $this->days = $this->rating_show_interval;
280 $this->duplication = true;
281 $this->never_show_triggered = true;
282 if ($this->get_remaining_days() >= $this->days) {
283 $this->duplication = false;
284 }
285 }
286
287 $this->display_message_box();
288 }
289
290 protected function action_on_fire()
291 {
292 return true;
293 }
294
295 public function set_installation_date()
296 {
297 add_option($this->text_domain . '_install_date', current_time('mysql'));
298 }
299
300 public function is_installation_date_exists()
301 {
302 return (bool) get_option($this->text_domain . '_install_date');
303 }
304
305 public function get_installation_date()
306 {
307 return get_option($this->text_domain . '_install_date');
308 }
309
310 public function set_first_action_date()
311 {
312 add_option($this->text_domain . '_first_action_Date', current_time('mysql'));
313 add_option($this->text_domain . '_first_action', 'yes');
314 }
315
316 public function get_days(\DateTime $from_date, \DateTime $to_date)
317 {
318 return (int) round(($to_date->format('U') - $from_date->format('U')) / (60 * 60 * 24));
319 }
320
321 public function get_remaining_days()
322 {
323 $install_date = $this->get_installation_date();
324 if (!$install_date) {
325 return 0;
326 }
327 $datetime1 = new \DateTime($install_date);
328 $datetime2 = new \DateTime(current_time('mysql'));
329 return abs($this->get_days($datetime1, $datetime2));
330 }
331
332 public static function never_show_message()
333 {
334 if (
335 empty($_POST['nonce']) ||
336 !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'wpmet_rating')
337 ) {
338 wp_send_json_error();
339 return;
340 }
341
342 $plugin_name = sanitize_key(isset($_POST['plugin_name']) ? $_POST['plugin_name'] : '');
343 if (!empty($plugin_name)) {
344 add_option($plugin_name . '_never_show', 'yes');
345 }
346 wp_send_json_success();
347 }
348
349 public static function ask_me_later_message()
350 {
351 if (
352 empty($_POST['nonce']) ||
353 !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'wpmet_rating')
354 ) {
355 wp_send_json_error();
356 return;
357 }
358
359 $plugin_name = sanitize_key(isset($_POST['plugin_name']) ? $_POST['plugin_name'] : '');
360 if (!empty($plugin_name)) {
361 if (get_option($plugin_name . '_ask_me_later') === false) {
362 add_option($plugin_name . '_ask_me_later', 'yes');
363 } else {
364 add_option($plugin_name . '_never_show', 'yes');
365 }
366 }
367 wp_send_json_success();
368 }
369
370 public function display_message_box()
371 {
372 $settings = get_transient($this->text_domain . '_rating_settings');
373 if ($settings !== 'yes') {
374 return;
375 }
376
377 global $wpmet_libs_execution_container;
378
379 if (!$this->duplication) {
380 if (isset($wpmet_libs_execution_container['rating'])) {
381 return;
382 }
383 }
384 $wpmet_libs_execution_container['rating'] = __FILE__;
385
386 if ($this->get_remaining_days() >= $this->days) {
387 $not_good_enough_btn_id = $this->never_show_triggered ? '_btn_never_show' : '_btn_not_good';
388 $message = "Hello! Seems like you have used {$this->plugin_name} to build this website — Thanks a lot! <br>
389 Could you please do us a <b>big favor</b> and give it a <b>5-star</b> rating on WordPress?
390 This would boost our motivation and help other users make a comfortable decision while choosing the {$this->plugin_name}";
391
392 Notice::instance($this->text_domain, '_plugin_rating_msg_used_in_day')
393 ->set_message($message)
394 ->set_button([
395 'url' => $this->rating_url,
396 'text' => 'Ok, you deserved it',
397 'class' => 'button-primary',
398 'id' => $this->text_domain . '_btn_deserved',
399 ])
400 ->set_button([
401 'url' => get_current_screen()->id === 'toplevel_page_getgenie' ? '#write-for-me' : '#',
402 'text' => 'I already did',
403 'class' => 'button-default',
404 'id' => $this->text_domain . '_btn_already_did',
405 'icon' => 'dashicons-before dashicons-smiley',
406 ])
407 ->set_button([
408 'url' => $this->support_url,
409 'text' => 'I need support',
410 'class' => 'button-default',
411 'id' => '#',
412 'icon' => 'dashicons-before dashicons-sos',
413 ])
414 ->set_button([
415 'url' => '#',
416 'text' => 'Never ask again',
417 'class' => 'button-default',
418 'id' => $this->text_domain . '_btn_never_show',
419 'icon' => 'dashicons-before dashicons-welcome-comments',
420 ])
421 ->set_button([
422 'url' => get_current_screen()->id === 'toplevel_page_getgenie' ? '#write-for-me' : '#',
423 'text' => 'No, not good enough',
424 'class' => 'button-default',
425 'id' => $this->text_domain . $not_good_enough_btn_id,
426 'icon' => 'dashicons-before dashicons-thumbs-down',
427 ])
428 ->call();
429 }
430 }
431
432 public function scripts()
433 {
434 $domain_js = esc_js($this->text_domain);
435 $nonce_js = esc_js(wp_create_nonce('wpmet_rating'));
436
437 echo <<<EOT
438 <script>
439 jQuery(document).ready(function (\$) {
440 \$('#{$domain_js}_btn_already_did').on('click', function() {
441 \$.post(ajaxurl, {
442 action: 'wpmet_rating_never_show_message',
443 plugin_name: '{$domain_js}',
444 nonce: '{$nonce_js}'
445 }, function() {
446 \$('#{$domain_js}-_plugin_rating_msg_used_in_day').remove();
447 });
448 });
449
450 \$('#{$domain_js}_btn_deserved').click(function() {
451 \$.post(ajaxurl, {
452 action: 'wpmet_rating_never_show_message',
453 plugin_name: '{$domain_js}',
454 nonce: '{$nonce_js}'
455 }, function() {
456 \$('#{$domain_js}-_plugin_rating_msg_used_in_day').remove();
457 });
458 });
459
460 \$('#{$domain_js}_btn_not_good').click(function() {
461 \$.post(ajaxurl, {
462 action: 'wpmet_rating_ask_me_later_message',
463 plugin_name: '{$domain_js}',
464 nonce: '{$nonce_js}'
465 }, function() {
466 \$('#{$domain_js}-_plugin_rating_msg_used_in_day').remove();
467 });
468 });
469
470 \$('#{$domain_js}_btn_never_show').click(function() {
471 \$.post(ajaxurl, {
472 action: 'wpmet_rating_never_show_message',
473 plugin_name: '{$domain_js}',
474 nonce: '{$nonce_js}'
475 }, function() {
476 \$('#{$domain_js}-_plugin_rating_msg_used_in_day').remove();
477 });
478 });
479 });
480 </script>
481 EOT;
482 }
483 }
484