PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.26.1
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.26.1
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / models / FrmInbox.php

FrmInbox.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.26.1, at classes/models/FrmInbox.php

603 lines 12.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 /**
7 * @since 4.05
8 */
9 class FrmInbox extends FrmFormApi {
10
11 protected $cache_key;
12
13 /**
14 * @var string
15 */
16 private $option = 'frm_inbox';
17
18 /**
19 * @var array|false
20 */
21 private static $messages = false;
22
23 /**
24 * @var array
25 */
26 private static $banner_messages;
27
28 public function __construct() {
29 $this->set_cache_key();
30
31 if ( false === self::$messages ) {
32 $this->set_messages();
33 }
34 }
35
36 /**
37 * @since 4.05
38 *
39 * @return void
40 */
41 protected function set_cache_key() {
42 $this->cache_key = 'frm_inbox_cache';
43 }
44
45 /**
46 * @since 4.05
47 *
48 * @return string
49 */
50 protected function api_url() {
51 return 'https://formidableforms.com/wp-json/inbox/v1/message/';
52 }
53
54 /**
55 * @since 4.05
56 *
57 * @param array|false $filter
58 *
59 * @return array
60 */
61 public function get_messages( $filter = false ) {
62 $messages = self::$messages;
63
64 if ( $filter === 'filter' ) {
65 $this->filter_messages( $messages );
66 }
67 return $messages;
68 }
69
70 /**
71 * @since 4.05
72 *
73 * @return void
74 */
75 public function set_messages() {
76 self::$messages = get_option( $this->option );
77
78 if ( ! is_array( self::$messages ) ) {
79 self::$messages = array();
80 }
81
82 $this->add_api_messages();
83
84 /**
85 * Messages are in an array.
86 */
87 self::$messages = apply_filters( 'frm_inbox', self::$messages );
88 }
89
90 /**
91 * @since 4.05
92 *
93 * @return void
94 */
95 private function add_api_messages() {
96 $api = $this->get_api_info();
97
98 if ( empty( $api ) ) {
99 return;
100 }
101
102 foreach ( $api as $message ) {
103 $this->add_message( $message );
104 }
105 }
106
107 /**
108 * @param array|string $message
109 *
110 * @return void
111 */
112 public function add_message( $message ) {
113 if ( ! is_array( $message ) || ! isset( $message['key'] ) ) {
114 // if the API response is invalid, $message may not be an array.
115 // if there are no messages from the API, it is returning a "No Entries Found" item with no key, so check for a key as well.
116 return;
117 }
118
119 if ( isset( self::$messages[ $message['key'] ] ) && ! isset( $message['force'] ) ) {
120 // Don't replace messages unless required.
121 return;
122 }
123
124 if ( ! $this->within_valid_timeframe( $message ) ) {
125 return;
126 }
127
128 if ( isset( self::$messages[ $message['key'] ] ) ) {
129 // Move up and mark as new.
130 unset( self::$messages[ $message['key'] ] );
131 }
132
133 $this->fill_message( $message );
134 self::$messages[ $message['key'] ] = $message;
135
136 $this->update_list();
137
138 $this->clean_messages();
139 }
140
141 /**
142 * @param array $message
143 *
144 * @return void
145 */
146 private function fill_message( &$message ) {
147 $defaults = array(
148 'time' => time(),
149 'message' => '',
150 'subject' => '',
151 'icon' => 'frm_tooltip_icon',
152 'cta' => '',
153 'expires' => false,
154 // Use 'free', 'personal', 'business', 'elite', 'grandfathered'.
155 'who' => 'all',
156 'type' => '',
157 );
158
159 $message = array_merge( $defaults, $message );
160
161 $message['created'] = $message['time'];
162 unset( $message['time'] );
163 }
164
165 /**
166 * @return void
167 */
168 private function clean_messages() {
169 $removed = false;
170
171 foreach ( self::$messages as $t => $message ) {
172 $read = ! empty( $message['read'] ) && isset( $message['read'][ get_current_user_id() ] ) && $message['read'][ get_current_user_id() ] < strtotime( '-1 month' );
173 $dismissed = ! empty( $message['dismissed'] ) && isset( $message['dismissed'][ get_current_user_id() ] ) && $message['dismissed'][ get_current_user_id() ] < strtotime( '-1 week' );
174
175 if ( $read || $dismissed || ! $this->within_valid_timeframe( $message ) ) {
176 unset( self::$messages[ $t ] );
177 $removed = true;
178 }
179 }
180
181 if ( $removed ) {
182 $this->update_list();
183 }
184 }
185
186 /**
187 * @param array $messages
188 * @param string $type
189 *
190 * @return void
191 */
192 public function filter_messages( &$messages, $type = 'unread' ) {
193 $user_id = get_current_user_id();
194
195 foreach ( $messages as $k => $message ) {
196 $dismissed = isset( $message['dismissed'] ) && isset( $message['dismissed'][ $user_id ] );
197
198 if ( empty( $k ) || ! $this->within_valid_timeframe( $message ) || ( $type === 'dismissed' ) !== $dismissed ) {
199 unset( $messages[ $k ] );
200 } elseif ( ! $this->is_for_user( $message ) ) {
201 unset( $messages[ $k ] );
202 }
203 }
204
205 $messages = apply_filters( 'frm_filter_inbox', $messages );
206 }
207
208 /**
209 * Check if a message has started and is not expired.
210 *
211 * @since 6.25
212 *
213 * @param array $message
214 *
215 * @return bool
216 */
217 private function within_valid_timeframe( $message ) {
218 return $this->has_started( $message ) && ! $this->is_expired( $message );
219 }
220
221 /**
222 * Check if a message has actually started, so we can prevent showing something that is queued up early.
223 *
224 * @since 6.25
225 *
226 * @param array $message
227 *
228 * @return bool
229 */
230 private function has_started( $message ) {
231 if ( empty( $message['starts'] ) ) {
232 return true;
233 }
234
235 return $message['starts'] <= time();
236 }
237
238 /**
239 * @param array $message
240 *
241 * @return bool
242 */
243 private function is_expired( $message ) {
244 return ! empty( $message['expires'] ) && $message['expires'] < time();
245 }
246
247 /**
248 * Show different messages for different accounts.
249 *
250 * @param array $message
251 *
252 * @return bool
253 */
254 private function is_for_user( $message ) {
255 if ( FrmApiHelper::is_for_user( $message ) ) {
256 return true;
257 }
258
259 $who = (array) $message['who'];
260
261 /**
262 * Allow for other special inbox cases in other add-ons.
263 *
264 * @since 6.8.1
265 *
266 * @param bool $is_for_user
267 * @param array $who
268 * @param array $message
269 */
270 return (bool) apply_filters( 'frm_inbox_message_is_for_user', false, $who, $message );
271 }
272
273 /**
274 * @param string $key
275 *
276 * @return void
277 */
278 public function mark_read( $key ) {
279 if ( ! $key || ! isset( self::$messages[ $key ] ) ) {
280 return;
281 }
282
283 if ( ! isset( self::$messages[ $key ]['read'] ) ) {
284 self::$messages[ $key ]['read'] = array();
285 }
286 self::$messages[ $key ]['read'][ get_current_user_id() ] = time();
287
288 $this->update_list();
289 }
290
291 /**
292 * @since 4.05.02
293 *
294 * @param string $key
295 *
296 * @return void
297 */
298 public function mark_unread( $key ) {
299 $is_read = isset( self::$messages[ $key ] ) && isset( self::$messages[ $key ]['read'] ) && isset( self::$messages[ $key ]['read'][ get_current_user_id() ] );
300
301 if ( $is_read ) {
302 unset( self::$messages[ $key ]['read'][ get_current_user_id() ] );
303 $this->update_list();
304 }
305 }
306
307 /**
308 * @param string $key
309 *
310 * @return void
311 */
312 public function dismiss( $key ) {
313 if ( $key === 'all' ) {
314 $this->dismiss_all();
315 return;
316 }
317
318 if ( ! isset( self::$messages[ $key ] ) ) {
319 return;
320 }
321
322 if ( ! isset( self::$messages[ $key ]['dismissed'] ) ) {
323 self::$messages[ $key ]['dismissed'] = array();
324 }
325 self::$messages[ $key ]['dismissed'][ get_current_user_id() ] = time();
326
327 $this->update_list();
328 }
329
330 /**
331 * @since 4.06
332 *
333 * @return void
334 */
335 private function dismiss_all() {
336 $user_id = get_current_user_id();
337
338 foreach ( self::$messages as $key => $message ) {
339 if ( ! isset( $message['dismissed'] ) ) {
340 self::$messages[ $key ]['dismissed'] = array();
341 }
342
343 if ( ! isset( $message['dismissed'][ $user_id ] ) ) {
344 self::$messages[ $key ]['dismissed'][ $user_id ] = time();
345 }
346 }
347 $this->update_list();
348 }
349
350 /**
351 * @return array
352 */
353 public function unread() {
354 $messages = $this->get_messages( 'filter' );
355 $user_id = get_current_user_id();
356
357 foreach ( $messages as $t => $message ) {
358 if ( isset( $message['read'] ) && isset( $message['read'][ $user_id ] ) ) {
359 unset( $messages[ $t ] );
360 }
361 }
362 return $messages;
363 }
364
365 /**
366 * @since 6.8.4 The $filtered parameter was added.
367 *
368 * @param bool $filtered
369 *
370 * @return string
371 */
372 public function unread_html( $filtered = true ) {
373 $count = count( $this->unread() );
374
375 if ( ! $count ) {
376 return '';
377 }
378
379 $html = ' <span class="update-plugins frm_inbox_count"><span class="plugin-count">' . absint( $count ) . '</span></span>';
380
381 if ( ! $filtered ) {
382 return $html;
383 }
384
385 /**
386 * @since 4.06.01
387 *
388 * @param string $html
389 */
390 return (string) apply_filters( 'frm_inbox_badge', $html );
391 }
392
393 /**
394 * @since 4.05.02
395 *
396 * @param string $key
397 *
398 * @return void
399 */
400 public function remove( $key ) {
401 if ( isset( self::$messages[ $key ] ) ) {
402 unset( self::$messages[ $key ] );
403 $this->update_list();
404 }
405 }
406
407 /**
408 * @return void
409 */
410 private function update_list() {
411 update_option( $this->option, self::$messages, 'no' );
412 }
413
414 /**
415 * Show a banner message if one is available.
416 *
417 * @return bool True if a banner is available and shown.
418 */
419 public static function maybe_show_banner() {
420 if ( empty( self::$banner_messages ) ) {
421 return false;
422 }
423
424 $message = end( self::$banner_messages );
425 $cta = self::get_prepared_banner_cta( $message['cta'] );
426
427 require FrmAppHelper::plugin_path() . '/classes/views/inbox/banner.php';
428 return true;
429 }
430
431 /**
432 * Make sure that the CTA uses utm_medium=banner.
433 *
434 * @since 6.8.4
435 *
436 * @param string $cta
437 *
438 * @return string
439 */
440 private static function get_prepared_banner_cta( $cta ) {
441 $cta = str_replace( 'button-secondary', 'button-primary', $cta );
442 return preg_replace_callback(
443 '/href=("|\')(.*?)("|\')/',
444 /**
445 * Replace a single href attribute in the CTA.
446 *
447 * @param array $matches The regex results for a single match.
448 *
449 * @return string
450 */
451 function ( $matches ) {
452 $url = $matches[2];
453 $parts = parse_url( $url );
454
455 if ( '#' === $url ) {
456 return 'href="#"';
457 }
458
459 $query = array();
460
461 if ( isset( $parts['query'] ) ) {
462 parse_str( $parts['query'], $query );
463 }
464 $query['utm_medium'] = 'banner';
465 $parts['query'] = http_build_query( $query );
466 return 'href="' . $parts['scheme'] . '://' . $parts['host'] . $parts['path'] . '?' . $parts['query'] . '"';
467 },
468 $cta
469 );
470 }
471
472 /**
473 * @return void
474 */
475 public static function maybe_disable_screen_options() {
476 self::$banner_messages = self::get_banner_messages();
477
478 if ( self::$banner_messages ) {
479 // disable screen options tab when displaying banner messages because it gets in the way of the banner.
480 add_filter( 'screen_options_show_screen', '__return_false' );
481 }
482 }
483
484 /**
485 * Get all message with a "banner" message key defined.
486 *
487 * @return array
488 */
489 private static function get_banner_messages() {
490 return self::get_messages_with_key( 'banner' );
491 }
492
493 /**
494 * Get all messages with a "slidein" message key defined.
495 *
496 * @since 6.8.4
497 *
498 * @return array
499 */
500 private static function get_slidein_messages() {
501 return self::get_messages_with_key( 'slidein' );
502 }
503
504 /**
505 * Get all messages with a $key message key defined.
506 *
507 * @since 6.8.4
508 *
509 * @param string $key The key we are checking for (ie. banner or slidein).
510 *
511 * @return array
512 */
513 private static function get_messages_with_key( $key ) {
514 $inbox = new self();
515 return array_filter(
516 $inbox->get_messages( 'filter' ),
517 function ( $message ) use ( $key ) {
518 return ! empty( $message[ $key ] );
519 }
520 );
521 }
522
523 /**
524 * Check if there is at least one slidein message.
525 *
526 * @since 6.8.4
527 *
528 * @return bool
529 */
530 public static function has_a_slidein_message() {
531 return (bool) self::get_slidein_messages();
532 }
533
534 /**
535 * Get the array used for frmGlobal.inboxSlideIn
536 *
537 * @since 6.8.4
538 *
539 * @return array|false
540 */
541 public static function get_inbox_slide_in_value_for_js() {
542 $messages = self::get_slidein_messages();
543
544 if ( ! $messages ) {
545 return false;
546 }
547
548 $message = reset( $messages );
549
550 /**
551 * Extend the keys in the global JS object.
552 * This is used in Pro to include images.
553 *
554 * @since 6.8.4
555 *
556 * @param array $keys
557 */
558 $keys_to_return = apply_filters(
559 'frm_inbox_slidein_js_vars',
560 array( 'key', 'slidein', 'subject', 'cta' )
561 );
562
563 return array_reduce(
564 $keys_to_return,
565 function ( $total, $key ) use ( $message ) {
566 $total[ $key ] = $message[ $key ] ?? '';
567 return $total;
568 },
569 array()
570 );
571 }
572
573 /**
574 * Clear the inbox cache by deleting the associated option from the database.
575 *
576 * @since 6.17
577 *
578 * @return void
579 */
580 public static function clear_cache() {
581 delete_option( 'frm_inbox' );
582 }
583
584 /**
585 * Check inbox for an "error" type. This is displayed on the form list page if one exists.
586 *
587 * @since 6.19
588 *
589 * @return array|false
590 */
591 public static function check_for_error() {
592 $inbox = new self();
593 $messages = $inbox->get_messages( 'filter' );
594
595 foreach ( $messages as $message ) {
596 if ( is_array( $message ) && isset( $message['type'] ) && 'error' === $message['type'] ) {
597 return $message;
598 }
599 }
600 return false;
601 }
602 }
603