PluginProbe ʕ •ᴥ•ʔ
Appointment Booking Plugin – LatePoint | Calendar & Scheduling for WordPress / 5.6.0
Appointment Booking Plugin – LatePoint | Calendar & Scheduling for WordPress v5.6.0
5.6.9 5.6.8 5.6.7 5.6.6 5.6.5 5.6.4 5.6.3 5.6.2 5.6.1 5.6.0 5.5.2 5.5.1 5.5.0 5.4.2 trunk 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.1.91 5.1.92 5.1.93 5.1.94 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1
latepoint / lib / kit / astra-notices / class-astra-notices.php
latepoint / lib / kit / astra-notices Last commit date
class-astra-notices.php 3 months ago notices.css 4 months ago notices.js 4 months ago
class-astra-notices.php
418 lines
1 <?php
2 /**
3 * Astra Notices
4 *
5 * An easy to use PHP Library to add dismissible admin notices in the WordPress admin.
6 *
7 * @package Astra Notices
8 * @since 1.0.0
9 */
10
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit; // Exit if accessed directly.
13 }
14
15 if ( ! class_exists( 'Astra_Notices' ) ) :
16
17 /**
18 * Astra_Notices
19 *
20 * @since 1.0.0
21 */
22 class Astra_Notices {
23
24 /**
25 * Notices
26 *
27 * @access private
28 * @var array Notices.
29 * @since 1.0.0
30 */
31 private static $version = '1.1.16';
32
33 /**
34 * Notices
35 *
36 * @access private
37 * @var array Notices.
38 * @since 1.0.0
39 */
40 private static $notices = array();
41
42 /**
43 * Instance
44 *
45 * @access private
46 * @var object Class object.
47 * @since 1.0.0
48 */
49 private static $instance;
50
51 /**
52 * Initiator
53 *
54 * @since 1.0.0
55 * @return object initialized object of class.
56 */
57 public static function get_instance() {
58 if ( ! isset( self::$instance ) ) {
59 self::$instance = new self();
60 }
61 return self::$instance;
62 }
63
64 /**
65 * Constructor
66 *
67 * @since 1.0.0
68 */
69 public function __construct() {
70 add_action( 'admin_notices', array( $this, 'show_notices' ), 30 );
71 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
72 add_action( 'wp_ajax_astra-notice-dismiss', array( $this, 'dismiss_notice' ) );
73 add_filter( 'wp_kses_allowed_html', array( $this, 'add_data_attributes' ), 10, 2 );
74 }
75
76 /**
77 * Filters and Returns a list of allowed tags and attributes for a given context.
78 *
79 * @param array $allowedposttags array of allowed tags.
80 * @param string $context Context type (explicit).
81 * @since 1.0.0
82 * @return array
83 */
84 public function add_data_attributes( $allowedposttags, $context ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
85 $allowedposttags['a']['data-repeat-notice-after'] = true;
86
87 return $allowedposttags;
88 }
89
90 /**
91 * Add Notice.
92 *
93 * @since 1.0.0
94 * @param array $args Notice arguments.
95 * @return void
96 */
97 public static function add_notice( $args = array() ) {
98 self::$notices[] = $args;
99
100 if ( ! isset( $args['id'] ) ) {
101 return;
102 }
103
104 $notice_id = sanitize_key( $args['id'] ); // Notice ID.
105 $notices = get_option( 'allowed_astra_notices', array() );
106 if ( ! in_array( $notice_id, $notices, true ) ) {
107 $notices[] = $notice_id; // Add notice id to the array.
108 update_option( 'allowed_astra_notices', $notices ); // Update the option.
109 }
110 }
111
112 /**
113 * Dismiss Notice.
114 *
115 * @since 1.0.0
116 * @return void
117 */
118 public function dismiss_notice() {
119 check_ajax_referer( 'astra-notices', 'nonce' );
120
121 $notice_id = ( isset( $_POST['notice_id'] ) ) ? sanitize_key( wp_unslash( $_POST['notice_id'] ) ) : '';
122 $repeat_notice_after = ( isset( $_POST['repeat_notice_after'] ) ) ? absint( $_POST['repeat_notice_after'] ) : '';
123 $notice = $this->get_notice_by_id( $notice_id );
124 $capability = isset( $notice['capability'] ) ? $notice['capability'] : 'manage_options';
125
126 if ( ! apply_filters( 'astra_notices_user_cap_check', current_user_can( $capability ) ) ) {
127 return;
128 }
129
130 $allowed_notices = get_option( 'allowed_astra_notices', array() ); // Get allowed notices.
131
132 // Define restricted user meta keys.
133 $wp_default_meta_keys = array(
134 'wp_capabilities',
135 'wp_user_level',
136 'wp_user-settings',
137 'account_status',
138 'session_tokens',
139 );
140
141 // if $notice_id does not start with astra-notices-id and notice_id is not from the allowed notices, then return.
142 if ( strpos( $notice_id, 'astra-notices-id-' ) !== 0 && ( ! in_array( $notice_id, $allowed_notices, true ) ) ) {
143 return;
144 }
145
146 // Valid inputs?
147 if ( ! empty( $notice_id ) ) {
148
149 if ( in_array( $notice_id, $wp_default_meta_keys, true ) ) {
150 wp_send_json_error( esc_html__( 'Invalid notice ID.', 'astra-notices' ) );
151 }
152
153 if ( ! empty( $repeat_notice_after ) ) {
154 set_transient( $notice_id, true, $repeat_notice_after );
155 } else {
156 update_user_meta( get_current_user_id(), $notice_id, 'notice-dismissed' );
157 }
158
159 wp_send_json_success();
160 }
161
162 wp_send_json_error();
163 }
164
165 /**
166 * Enqueue Scripts.
167 *
168 * @since 1.0.0
169 * @return void
170 */
171 public function enqueue_scripts() {
172 wp_register_style( 'astra-notices', self::get_url() . 'notices.css', array(), self::$version );
173 wp_register_script( 'astra-notices', self::get_url() . 'notices.js', array( 'jquery' ), self::$version, true );
174 wp_localize_script(
175 'astra-notices',
176 'astraNotices',
177 array(
178 '_notice_nonce' => wp_create_nonce( 'astra-notices' ),
179 )
180 );
181 }
182
183 /**
184 * Sort the notices based on the given priority of the notice.
185 * This function is called from usort()
186 *
187 * @since 1.5.2
188 * @param array $notice_1 First notice.
189 * @param array $notice_2 Second Notice.
190 * @return array
191 */
192 public function sort_notices( $notice_1, $notice_2 ) {
193 if ( ! isset( $notice_1['priority'] ) ) {
194 $notice_1['priority'] = 10;
195 }
196 if ( ! isset( $notice_2['priority'] ) ) {
197 $notice_2['priority'] = 10;
198 }
199
200 return $notice_1['priority'] - $notice_2['priority'];
201 }
202
203 /**
204 * Get all registered notices.
205 * Since v1.1.8 it is recommended to register the notices on
206 *
207 * @return array|null
208 */
209 private function get_notices() {
210 usort( self::$notices, array( $this, 'sort_notices' ) );
211
212 return self::$notices;
213 }
214
215 /**
216 * Get notice by notice_id
217 *
218 * @param string $notice_id Notice id.
219 *
220 * @return array notice based on the notice id.
221 */
222 private function get_notice_by_id( $notice_id ) {
223 if ( empty( $notice_id ) ) {
224 return array();
225 }
226
227 $notices = $this->get_notices();
228 $notice = wp_list_filter(
229 $notices,
230 array(
231 'id' => $notice_id,
232 )
233 );
234
235 return ( ! empty( $notice ) && isset( $notice[0] ) ) ? $notice[0] : array();
236 }
237
238 /**
239 * Display the notices in the WordPress admin.
240 *
241 * @since 1.0.0
242 * @return void
243 */
244 public function show_notices() {
245 $defaults = array(
246 'id' => '', // Optional, Notice ID. If empty it set `astra-notices-id-<$array-index>`.
247 'type' => 'info', // Optional, Notice type. Default `info`. Expected [info, warning, notice, error].
248 'message' => '', // Optional, Message.
249 'show_if' => true, // Optional, Show notice on custom condition. E.g. 'show_if' => if( is_admin() ) ? true, false, .
250 'repeat-notice-after' => '', // Optional, Dismiss-able notice time. It'll auto show after given time.
251 'display-notice-after' => false, // Optional, Dismiss-able notice time. It'll auto show after given time.
252 'class' => '', // Optional, Additional notice wrapper class.
253 'priority' => 10, // Priority of the notice.
254 'display-with-other-notices' => true, // Should the notice be displayed if other notices are being displayed from Astra_Notices.
255 'is_dismissible' => true,
256 'capability' => 'manage_options', // User capability - This capability is required for the current user to see this notice.
257 );
258
259 // Count for the notices that are rendered.
260 $notices_displayed = 0;
261 $notices = $this->get_notices();
262
263 foreach ( $notices as $key => $notice ) {
264 $notice = wp_parse_args( $notice, $defaults );
265
266 // Show notices only for users with `manage_options` cap.
267 if ( ! current_user_can( $notice['capability'] ) ) {
268 continue;
269 }
270
271 $notice['id'] = self::get_notice_id( $notice, $key );
272 $notice['classes'] = self::get_wrap_classes( $notice );
273
274 // Notices visible after transient expire.
275 if ( isset( $notice['show_if'] ) && true === $notice['show_if'] ) {
276
277 // don't display the notice if it is not supposed to be displayed with other notices.
278 if ( 0 !== $notices_displayed && false === $notice['display-with-other-notices'] ) {
279 continue;
280 }
281
282 if ( self::is_expired( $notice ) ) {
283
284 self::markup( $notice );
285 ++$notices_displayed;
286 }
287 }
288 }
289 }
290
291 /**
292 * Render a notice.
293 *
294 * @since 1.0.0
295 * @param array $notice Notice markup.
296 * @return void
297 */
298 public static function markup( $notice = array() ) {
299 wp_enqueue_script( 'astra-notices' );
300 wp_enqueue_style( 'astra-notices' );
301
302 do_action( 'astra_notice_before_markup' );
303
304 do_action( "astra_notice_before_markup_{$notice['id']}" );
305
306 ?>
307 <div id="<?php echo esc_attr( $notice['id'] ); ?>" class="<?php echo 'astra-notice-wrapper ' . esc_attr( $notice['classes'] ); ?>" data-repeat-notice-after="<?php echo esc_attr( $notice['repeat-notice-after'] ); ?>">
308 <div class="astra-notice-container">
309 <?php do_action( "astra_notice_inside_markup_{$notice['id']}" ); ?>
310 <?php echo wp_kses_post( $notice['message'] ); ?>
311 </div>
312 </div>
313 <?php
314
315 do_action( "astra_notice_after_markup_{$notice['id']}" );
316
317 do_action( 'astra_notice_after_markup' );
318 }
319
320 /**
321 * Get wrapper classes for a notice.
322 *
323 * @since 1.0.0
324 *
325 * @param array $notice Notice arguments.
326 * @return array Notice wrapper classes.
327 */
328 private static function get_wrap_classes( $notice ) {
329 $classes = array( 'astra-notice', 'notice' );
330
331 if ( $notice['is_dismissible'] ) {
332 $classes[] = 'is-dismissible';
333 }
334
335 $classes[] = $notice['class'];
336 if ( isset( $notice['type'] ) && '' !== $notice['type'] ) {
337 $classes[] = 'notice-' . $notice['type'];
338 }
339
340 return esc_attr( implode( ' ', $classes ) );
341 }
342
343 /**
344 * Get HTML ID for a given notice.
345 *
346 * @since 1.0.0
347 *
348 * @param array $notice Notice arguments.
349 * @param int $key Notice array index.
350 * @return string HTML if for the notice.
351 */
352 private static function get_notice_id( $notice, $key ) {
353 if ( isset( $notice['id'] ) && ! empty( $notice['id'] ) ) {
354 return $notice['id'];
355 }
356
357 return 'astra-notices-id-' . $key;
358 }
359
360 /**
361 * Check if the notice is expires.
362 *
363 * @since 1.0.0
364 *
365 * @param array $notice Notice arguments.
366 * @return boolean
367 */
368 private static function is_expired( $notice ) {
369 $transient_status = get_transient( $notice['id'] );
370
371 if ( false === $transient_status ) {
372
373 if ( isset( $notice['display-notice-after'] ) && false !== $notice['display-notice-after'] ) {
374
375 if ( 'delayed-notice' !== get_user_meta( get_current_user_id(), $notice['id'], true ) &&
376 'notice-dismissed' !== get_user_meta( get_current_user_id(), $notice['id'], true ) ) {
377 set_transient( $notice['id'], 'delayed-notice', $notice['display-notice-after'] );
378 update_user_meta( get_current_user_id(), $notice['id'], 'delayed-notice' );
379
380 return false;
381 }
382 }
383
384 // Check the user meta status if current notice is dismissed or delay completed.
385 $meta_status = get_user_meta( get_current_user_id(), $notice['id'], true );
386
387 if ( empty( $meta_status ) || 'delayed-notice' === $meta_status ) {
388 return true;
389 }
390 }
391
392 return false;
393 }
394
395 /**
396 * Get base URL for the astra-notices.
397 *
398 * @return mixed URL.
399 */
400 public static function get_url() {
401 $path = wp_normalize_path( dirname( __FILE__ ) ); // phpcs:ignore Modernize.FunctionCalls.Dirname.FileConstant
402 $theme_dir = wp_normalize_path( get_template_directory() );
403
404 if ( strpos( $path, $theme_dir ) !== false ) {
405 return trailingslashit( get_template_directory_uri() . str_replace( $theme_dir, '', $path ) );
406 } else {
407 return plugin_dir_url( __FILE__ );
408 }
409 }
410 }
411
412 /**
413 * Kicking this off by calling 'get_instance()' method
414 */
415 Astra_Notices::get_instance();
416
417 endif;
418