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

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