PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.28
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.28
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.28, at classes/models/FrmInbox.php

607 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'] ) ? true : $message['starts'] <= time();
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 unset( self::$messages[ $key ] );
405 $this->update_list();
406 }
407 }
408
409 /**
410 * @return void
411 */
412 private function update_list() {
413 update_option( $this->option, self::$messages, false );
414 }
415
416 /**
417 * Show a banner message if one is available.
418 *
419 * @return bool True if a banner is available and shown.
420 */
421 public static function maybe_show_banner() {
422 if ( empty( self::$banner_messages ) ) {
423 return false;
424 }
425
426 $message = end( self::$banner_messages );
427 $cta = self::get_prepared_banner_cta( $message['cta'] );
428
429 require FrmAppHelper::plugin_path() . '/classes/views/inbox/banner.php';
430 return true;
431 }
432
433 /**
434 * Make sure that the CTA uses utm_medium=banner.
435 *
436 * @since 6.8.4
437 *
438 * @param string $cta
439 *
440 * @return string
441 */
442 private static function get_prepared_banner_cta( $cta ) {
443 $cta = str_replace( 'button-secondary', 'button-primary', $cta );
444 return preg_replace_callback(
445 '/href=("|\')(.*?)("|\')/',
446 /**
447 * Replace a single href attribute in the CTA.
448 *
449 * @param array $matches The regex results for a single match.
450 *
451 * @return string
452 */
453 function ( $matches ) {
454 $url = $matches[2];
455
456 if ( '#' === $url ) {
457 return 'href="#"';
458 }
459
460 $parts = parse_url( $url );
461 $query = array();
462
463 if ( isset( $parts['query'] ) ) {
464 parse_str( $parts['query'], $query );
465 }
466
467 $query['utm_medium'] = 'banner';
468 $parts['query'] = http_build_query( $query );
469 return 'href="' . $parts['scheme'] . '://' . $parts['host'] . $parts['path'] . '?' . $parts['query'] . '"';
470 },
471 $cta
472 );
473 }
474
475 /**
476 * @return void
477 */
478 public static function maybe_disable_screen_options() {
479 self::$banner_messages = self::get_banner_messages();
480
481 if ( self::$banner_messages ) {
482 // Disable screen options tab when displaying banner messages because it gets in the way of the banner.
483 add_filter( 'screen_options_show_screen', '__return_false' );
484 }
485 }
486
487 /**
488 * Get all message with a "banner" message key defined.
489 *
490 * @return array
491 */
492 private static function get_banner_messages() {
493 return self::get_messages_with_key( 'banner' );
494 }
495
496 /**
497 * Get all messages with a "slidein" message key defined.
498 *
499 * @since 6.8.4
500 *
501 * @return array
502 */
503 private static function get_slidein_messages() {
504 return self::get_messages_with_key( 'slidein' );
505 }
506
507 /**
508 * Get all messages with a $key message key defined.
509 *
510 * @since 6.8.4
511 *
512 * @param string $key The key we are checking for (ie. banner or slidein).
513 *
514 * @return array
515 */
516 private static function get_messages_with_key( $key ) {
517 $inbox = new self();
518 return array_filter(
519 $inbox->get_messages( 'filter' ),
520 function ( $message ) use ( $key ) {
521 return ! empty( $message[ $key ] );
522 }
523 );
524 }
525
526 /**
527 * Check if there is at least one slidein message.
528 *
529 * @since 6.8.4
530 *
531 * @return bool
532 */
533 public static function has_a_slidein_message() {
534 return (bool) self::get_slidein_messages();
535 }
536
537 /**
538 * Get the array used for frmGlobal.inboxSlideIn
539 *
540 * @since 6.8.4
541 *
542 * @return array|false
543 */
544 public static function get_inbox_slide_in_value_for_js() {
545 $messages = self::get_slidein_messages();
546
547 if ( ! $messages ) {
548 return false;
549 }
550
551 $message = reset( $messages );
552
553 /**
554 * Extend the keys in the global JS object.
555 * This is used in Pro to include images.
556 *
557 * @since 6.8.4
558 *
559 * @param array $keys
560 */
561 $keys_to_return = apply_filters(
562 'frm_inbox_slidein_js_vars',
563 array( 'key', 'slidein', 'subject', 'cta' )
564 );
565
566 return array_reduce(
567 $keys_to_return,
568 function ( $total, $key ) use ( $message ) {
569 $total[ $key ] = $message[ $key ] ?? '';
570 return $total;
571 },
572 array()
573 );
574 }
575
576 /**
577 * Clear the inbox cache by deleting the associated option from the database.
578 *
579 * @since 6.17
580 *
581 * @return void
582 */
583 public static function clear_cache() {
584 delete_option( 'frm_inbox' );
585 }
586
587 /**
588 * Check inbox for an "error" type. This is displayed on the form list page if one exists.
589 *
590 * @since 6.19
591 *
592 * @return array|false
593 */
594 public static function check_for_error() {
595 $inbox = new self();
596 $messages = $inbox->get_messages( 'filter' );
597
598 foreach ( $messages as $message ) {
599 if ( is_array( $message ) && isset( $message['type'] ) && 'error' === $message['type'] ) {
600 return $message;
601 }
602 }
603
604 return false;
605 }
606 }
607