PluginProbe ʕ •ᴥ•ʔ
Robin Image Optimizer – Unlimited Image Optimization, WebP & AVIF / 2.0.6
Robin Image Optimizer – Unlimited Image Optimization, WebP & AVIF v2.0.6
2.0.7 2.0.6 2.0.5 trunk 1.3.7 1.4.0 1.4.1 1.4.2 1.4.6 1.5.0 1.5.3 1.5.6 1.5.8 1.6.5 1.6.6 1.6.9 1.7.0 1.7.4 1.8.1 1.8.2 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4
robin-image-optimizer / vendor / codeinwp / themeisle-sdk / src / Modules / Notification.php
robin-image-optimizer / vendor / codeinwp / themeisle-sdk / src / Modules Last commit date
About_us.php 1 month ago Abstract_Migration.php 4 months ago Announcements.php 4 months ago Compatibilities.php 10 months ago Crash_reporter.php 1 month ago Dashboard_widget.php 1 month ago Featured_plugins.php 1 month ago Float_widget.php 10 months ago Licenser.php 4 months ago Logger.php 1 month ago Migrator.php 1 month ago Notification.php 10 months ago Promotions.php 1 month ago Recommendation.php 10 months ago Review.php 10 months ago Rollback.php 10 months ago Script_loader.php 10 months ago Translate.php 10 months ago Translations.php 10 months ago Uninstall_feedback.php 1 month ago Welcome.php 10 months ago
Notification.php
516 lines
1 <?php
2 /**
3 * The notification model class for ThemeIsle SDK
4 *
5 * @package ThemeIsleSDK
6 * @subpackage Modules
7 * @copyright Copyright (c) 2017, Marius Cristea
8 * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9 * @since 1.0.0
10 */
11
12 namespace ThemeisleSDK\Modules;
13
14 use ThemeisleSDK\Common\Abstract_Module;
15 use ThemeisleSDK\Product;
16
17 // Exit if accessed directly.
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit;
20 }
21
22 /**
23 * Notification module for ThemeIsle SDK.
24 */
25 class Notification extends Abstract_Module {
26 /**
27 * Show notifications only after the user has the product installed after this amount of time, in hours.
28 */
29 const MIN_INSTALL_TIME = 100;
30 /**
31 * How much time should we show the notification, in days.
32 */
33 const MAX_TIME_TO_LIVE = 7;
34
35 /**
36 * Number of days between notifications.
37 */
38 const TIME_BETWEEN_NOTIFICATIONS = 5;
39
40 /**
41 * Holds a possible notification list.
42 *
43 * @var array Notifications list.
44 */
45 private static $notifications = [];
46
47 /**
48 * Show notification data.
49 */
50 public static function show_notification() {
51
52 $current_notification = self::get_last_notification();
53
54 $notification_details = [];
55 // Check if the saved notification is still present among the possible ones.
56 if ( ! empty( $current_notification ) ) {
57 $notification_details = self::get_notification_details( $current_notification );
58 if ( empty( $notification_details ) ) {
59 $current_notification = [];
60 }
61 }
62 // Check if the notificatin is expired.
63 if ( ! empty( $current_notification ) && self::is_notification_expired( $current_notification ) ) {
64 update_option( $current_notification['id'], 'no' );
65 self::set_last_active_notification_timestamp();
66 $current_notification = [];
67 }
68 // If we don't have any saved notification, get a new one.
69 if ( empty( $current_notification ) ) {
70 $notification_details = self::get_random_notification();
71 if ( empty( $notification_details ) ) {
72 return;
73 }
74 self::set_active_notification(
75 [
76 'id' => $notification_details['id'],
77 'display_at' => time(),
78 ]
79 );
80 }
81 if ( empty( $notification_details ) ) {
82 return;
83 }
84 $notification_html = self::get_notification_html( $notification_details );
85 do_action( $notification_details['id'] . '_before_render' );
86
87 echo $notification_html; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped, already escaped internally.
88
89 do_action( $notification_details['id'] . '_after_render' );
90 self::render_snippets();
91 }
92
93 /**
94 * Get last notification details.
95 *
96 * @return array Last notification details.
97 */
98 private static function get_last_notification() {
99 $notification = self::get_notifications_metadata();
100
101 return isset( $notification['last_notification'] ) ? $notification['last_notification'] : [];
102 }
103
104 /**
105 * Get notification center details.
106 *
107 * @return array Notification center details.
108 */
109 private static function get_notifications_metadata() {
110
111 $data = get_option(
112 'themeisle_sdk_notifications',
113 [
114 'last_notification' => [],
115 'last_notification_active' => 0,
116 ]
117 );
118
119 return $data;
120
121 }
122
123 /**
124 * Check if the notification is still possible.
125 *
126 * @param array $notification Notification to check.
127 *
128 * @return array Either is still active or not.
129 */
130 private static function get_notification_details( $notification ) {
131 $notifications = array_filter(
132 self::$notifications,
133 function ( $value ) use ( $notification ) {
134 if ( isset( $value['id'] ) && isset( $notification['id'] ) && $value['id'] === $notification['id'] ) {
135 return true;
136 }
137
138 return false;
139 }
140 );
141
142 return ! empty( $notifications ) ? reset( $notifications ) : [];
143 }
144
145 /**
146 * Check if the notification is expired.
147 *
148 * @param array $notification Notification to check.
149 *
150 * @return bool Either the notification is due.
151 */
152 private static function is_notification_expired( $notification ) {
153 if ( ! isset( $notification['display_at'] ) ) {
154 return true;
155 }
156
157 $notifications = array_filter(
158 self::$notifications,
159 function ( $value ) use ( $notification ) {
160 if ( isset( $value['id'] ) && isset( $notification['id'] ) && $value['id'] === $notification['id'] ) {
161 return true;
162 }
163
164 return false;
165 }
166 );
167
168 if ( empty( $notifications ) ) {
169 return true;
170 }
171 $notification_definition = reset( $notifications );
172
173 $when_to_expire = isset( $notification_definition['expires_at'] )
174 ? $notification_definition['expires_at'] :
175 ( isset( $notification_definition['expires'] )
176 ? ( $notification['display_at'] + $notification_definition['expires'] ) :
177 ( $notification['display_at'] + self::MAX_TIME_TO_LIVE * DAY_IN_SECONDS )
178 );
179
180 return ( $when_to_expire - time() ) < 0;
181 }
182
183 /**
184 * Set last notification details.
185 */
186 private static function set_last_active_notification_timestamp() {
187 $metadata = self::get_notifications_metadata();
188 $metadata['last_notification_active'] = time();
189 update_option( 'themeisle_sdk_notifications', $metadata );
190 }
191
192 /**
193 * Return notification to show.
194 *
195 * @return array Notification data.
196 */
197 public static function get_random_notification() {
198 if ( ( time() - self::get_last_active_notification_timestamp() ) < self::TIME_BETWEEN_NOTIFICATIONS * DAY_IN_SECONDS ) {
199 return [];
200 }
201
202 $notifications = self::$notifications;
203 $notifications = array_filter(
204 $notifications,
205 function ( $value ) {
206 if ( isset( $value['sticky'] ) && true === $value['sticky'] ) {
207 return true;
208 }
209
210 return false;
211 }
212 );
213 // No priority notifications, use all.
214 if ( empty( $notifications ) ) {
215 $notifications = self::$notifications;
216 }
217 if ( empty( $notifications ) ) {
218 return [];
219 }
220 $notifications = array_values( $notifications );
221
222 return $notifications[ array_rand( $notifications, 1 ) ];
223
224 }
225
226 /**
227 * Get last notification details.
228 *
229 * @return int Last notification details.
230 */
231 private static function get_last_active_notification_timestamp() {
232 $notification = self::get_notifications_metadata();
233
234 return isset( $notification['last_notification_active'] ) ? $notification['last_notification_active'] : 0;
235 }
236
237 /**
238 * Get last notification details.
239 *
240 * @param array $notification Notification data.
241 */
242 private static function set_active_notification( $notification ) {
243 $metadata = self::get_notifications_metadata();
244 $metadata['last_notification'] = $notification;
245 update_option( 'themeisle_sdk_notifications', $metadata );
246 }
247
248 /**
249 * Get notification html.
250 *
251 * @param array $notification_details Notification details.
252 *
253 * @return string Html for notice.
254 */
255 public static function get_notification_html( $notification_details ) {
256 $default = [
257 'id' => '',
258 'heading' => '',
259 'img_src' => '',
260 'message' => '',
261 'ctas' => [
262 'confirm' => [
263 'link' => '#',
264 'text' => '',
265 ],
266 'cancel' => [
267 'link' => '#',
268 'text' => '',
269 ],
270 ],
271 'type' => 'success',
272 ];
273 $notification_details = wp_parse_args( $notification_details, $default );
274 global $pagenow;
275 $type = in_array( $notification_details['type'], [ 'success', 'info', 'warning', 'error' ], true ) ? $notification_details['type'] : 'success';
276 $notification_details['ctas']['cancel']['link'] = wp_nonce_url( add_query_arg( [ 'nid' => $notification_details['id'] ], admin_url( $pagenow ) ), $notification_details['id'], 'tsdk_dismiss_nonce' );
277 $notification_html = '<div class="notice notice-' . $type . ' is-dismissible themeisle-sdk-notice" data-notification-id="' . esc_attr( $notification_details['id'] ) . '" id="' . esc_attr( $notification_details['id'] ) . '-notification"> <div class="themeisle-sdk-notification-box">';
278
279 if ( ! empty( $notification_details['heading'] ) ) {
280 $notification_html .= sprintf( '<h4>%s</h4>', wp_kses_post( $notification_details['heading'] ) );
281 }
282 if ( ! empty( $notification_details['img_src'] ) ) {
283 $notification_html .= '<div class="wrap-flex">';
284 $notification_html .= sprintf( '<img src="%s" alt="%s" />', esc_attr( $notification_details['img_src'] ), esc_attr( $notification_details['heading'] ) );
285 }
286 if ( ! empty( $notification_details['message'] ) ) {
287 $notification_html .= wp_kses_post( $notification_details['message'] );
288 if ( ! empty( $notification_details['img_src'] ) ) {
289 $notification_html .= '</div>';
290 }
291 }
292 $notification_html .= '<div class="actions">';
293
294 if ( ! empty( $notification_details['ctas']['confirm']['text'] ) ) {
295 $notification_html .= sprintf(
296 '<a href="%s" target="_blank" class=" button button-primary %s" data-confirm="yes" >%s</a>',
297 esc_url( $notification_details['ctas']['confirm']['link'] ),
298 esc_attr( $notification_details['id'] . '_confirm' ),
299 wp_kses_post( $notification_details['ctas']['confirm']['text'] )
300 );
301 }
302
303 if ( ! empty( $notification_details['ctas']['cancel']['text'] ) ) {
304 $notification_html .= sprintf(
305 '<a href="%s" class=" button %s" data-confirm="no">%s</a>',
306 esc_url( $notification_details['ctas']['cancel']['link'] ),
307 esc_attr( $notification_details['id'] ) . '_cancel',
308 wp_kses_post( $notification_details['ctas']['cancel']['text'] )
309 );
310 }
311
312 $notification_html .= '</div>';
313 $notification_html .= ' </div>';
314 $notification_html .= ' </div>';
315
316 return $notification_html;
317 }
318
319 /**
320 * Adds js snippet for hiding the notice.
321 */
322 public static function render_snippets() {
323
324 ?>
325 <style type="text/css">
326 .themeisle-sdk-notification-box {
327 padding: 3px;
328 }
329
330 .themeisle-sdk-notification-box .wrap-flex {
331 display: flex;
332 align-items: center;
333 justify-content: start;
334 gap: 12px;
335 }
336
337 .themeisle-sdk-notification-box .wrap-flex img {
338 width: 42px;
339 object-fit: cover;
340 }
341
342 .themeisle-sdk-notification-box .actions {
343 margin-top: 6px;
344 margin-bottom: 4px;
345 }
346
347 .themeisle-sdk-notification-box .button {
348 margin-right: 5px;
349 }
350 </style>
351 <script type="text/javascript">
352 (function ($) {
353 $(document).ready(function () {
354 $('#wpbody-content').on('click', ".themeisle-sdk-notice a.button, .themeisle-sdk-notice .notice-dismiss", function (e) {
355
356 var container = $('.themeisle-sdk-notice');
357 var link = $(this);
358 var notification_id = container.attr('data-notification-id');
359 var confirm = link.attr('data-confirm');
360 if (typeof confirm === "undefined") {
361 confirm = 'no';
362 }
363 $.post(
364 ajaxurl,
365 {
366 'nonce': '<?php echo esc_attr( wp_create_nonce( (string) __CLASS__ ) ); ?>',
367 'action': 'themeisle_sdk_dismiss_notice',
368 'id': notification_id,
369 'confirm': confirm,
370 },
371 ).fail(function() {
372 location.href = encodeURI(link.attr('href'));
373 });
374 if (confirm === 'yes') {
375 $(this).trigger('themeisle-sdk:confirmed');
376 } else {
377 $(this).trigger('themeisle-sdk:canceled');
378 }
379 container.hide();
380 if (confirm === 'no' || link.attr('href') === '#') {
381 return false;
382 }
383 });
384 });
385 })(jQuery);
386 </script>
387 <?php
388 }
389
390 /**
391 * Dismiss the notification.
392 */
393 public static function dismiss() {
394 check_ajax_referer( (string) __CLASS__, 'nonce' );
395
396 $id = isset( $_POST['id'] ) ? sanitize_text_field( $_POST['id'] ) : '';
397 $confirm = isset( $_POST['confirm'] ) ? sanitize_text_field( $_POST['confirm'] ) : 'no';
398
399 if ( empty( $id ) ) {
400 wp_send_json( [] );
401 }
402 self::setup_notifications();
403 $ids = wp_list_pluck( self::$notifications, 'id' );
404 if ( ! in_array( $id, $ids, true ) ) {
405 wp_send_json( [] );
406 }
407 self::set_last_active_notification_timestamp();
408 update_option( $id, $confirm );
409 do_action( $id . '_process_confirm', $confirm );
410 wp_send_json( [] );
411 }
412 /**
413 * Dismiss the notification.
414 */
415 public static function dismiss_get() {
416 $is_nonce_dismiss = sanitize_text_field( isset( $_GET['tsdk_dismiss_nonce'] ) ? $_GET['tsdk_dismiss_nonce'] : '' );
417 if ( strlen( $is_nonce_dismiss ) < 5 ) {
418 return;
419 }
420 $id = sanitize_text_field( isset( $_GET['nid'] ) ? $_GET['nid'] : '' );
421 if ( empty( $id ) ) {
422 return;
423 }
424 $nonce = wp_verify_nonce( sanitize_text_field( $_GET['tsdk_dismiss_nonce'] ), $id );
425 if ( $nonce !== 1 ) {
426 return;
427 }
428 $ids = wp_list_pluck( self::$notifications, 'id' );
429 if ( ! in_array( $id, $ids, true ) ) {
430 return;
431 }
432 $confirm = 'no';
433 self::set_last_active_notification_timestamp();
434 update_option( $id, $confirm );
435 do_action( $id . '_process_confirm', $confirm );
436 }
437
438 /**
439 * Check if we should load the notification module.
440 *
441 * @param Product $product Product to check.
442 *
443 * @return bool Should we load this?
444 */
445 public function can_load( $product ) {
446
447 if ( $this->is_from_partner( $product ) ) {
448 return false;
449 }
450 if ( ! current_user_can( 'manage_options' ) ) {
451 return false;
452 }
453 if ( ( time() - $product->get_install_time() ) < ( self::MIN_INSTALL_TIME * HOUR_IN_SECONDS ) ) {
454 return false;
455 }
456
457 return true;
458 }
459
460 /**
461 * Setup notifications queue.
462 */
463 public static function setup_notifications() {
464 $notifications = apply_filters( 'themeisle_sdk_registered_notifications', [] );
465 $notifications = array_filter(
466 $notifications,
467 function ( $value ) {
468 if ( ! isset( $value['id'] ) ) {
469 return false;
470 }
471 if ( get_option( $value['id'], '' ) !== '' ) {
472 return false;
473 }
474
475 return apply_filters( $value['id'] . '_should_show', true );
476 }
477 );
478 self::$notifications = $notifications;
479 }
480 /**
481 * Load the module logic.
482 *
483 * @param Product $product Product to load the module for.
484 *
485 * @return Notification Module instance.
486 */
487 public function load( $product ) {
488 if ( apply_filters( 'themeisle_sdk_hide_notifications', false ) ) {
489 return;
490 }
491 $this->product = $product;
492
493 $notifications = apply_filters( 'themeisle_sdk_registered_notifications', [] );
494 $notifications = array_filter(
495 $notifications,
496 function ( $value ) {
497 if ( ! isset( $value['id'] ) ) {
498 return false;
499 }
500 if ( get_option( $value['id'], '' ) !== '' ) {
501 return false;
502 }
503
504 return apply_filters( $value['id'] . '_should_show', true );
505 }
506 );
507 self::$notifications = $notifications;
508 add_action( 'admin_notices', array( __CLASS__, 'show_notification' ) );
509 add_action( 'wp_ajax_themeisle_sdk_dismiss_notice', array( __CLASS__, 'dismiss' ) );
510 add_action( 'admin_head', array( __CLASS__, 'dismiss_get' ) );
511 add_action( 'admin_head', array( __CLASS__, 'setup_notifications' ) );
512
513 return $this;
514 }
515 }
516