PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.34
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.34
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 6.5.4 All 140 releases
formidable / classes / models / FrmInbox.php

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

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