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

595 lines 12.9 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( $for_parent = null ) {
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->is_expired( $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 $expired = $this->is_expired( $message );
163 if ( $read || $expired || $dismissed ) {
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->is_expired( $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 * @param array $message
194 *
195 * @return bool
196 */
197 private function is_expired( $message ) {
198 return ! empty( $message['expires'] ) && $message['expires'] < time();
199 }
200
201 /**
202 * Show different messages for different accounts.
203 *
204 * @param array $message
205 * @return bool
206 */
207 private function is_for_user( $message ) {
208 if ( ! isset( $message['who'] ) || $message['who'] === 'all' ) {
209 return true;
210 }
211 $who = (array) $message['who'];
212 if ( $this->is_for_everyone( $who ) ) {
213 return true;
214 }
215 if ( $this->is_user_type( $who ) ) {
216 return true;
217 }
218 if ( in_array( 'free_first_30', $who, true ) && $this->is_free_first_30() ) {
219 return true;
220 }
221 if ( in_array( 'free_not_first_30', $who, true ) && $this->is_free_not_first_30() ) {
222 return true;
223 }
224 /**
225 * Allow for other special inbox cases in other add-ons.
226 *
227 * @since 6.8.1
228 *
229 * @param bool $is_for_user
230 * @param array $who
231 * @param array $message
232 */
233 return (bool) apply_filters( 'frm_inbox_message_is_for_user', false, $who, $message );
234 }
235
236 /**
237 * @since 6.16.3
238 *
239 * @param array $who
240 * @return bool
241 */
242 private function is_for_everyone( $who ) {
243 return in_array( 'all', $who, true ) || in_array( 'everyone', $who, true );
244 }
245
246 /**
247 * @since 6.16.3
248 *
249 * @param array $who
250 * @return bool
251 */
252 private function is_user_type( $who ) {
253 return in_array( $this->get_user_type(), $who, true );
254 }
255
256 private function get_user_type() {
257 if ( ! FrmAppHelper::pro_is_installed() ) {
258 return 'free';
259 }
260
261 return FrmAddonsController::license_type();
262 }
263
264 /**
265 * @param string $key
266 *
267 * @return void
268 */
269 public function mark_read( $key ) {
270 if ( ! $key || ! isset( self::$messages[ $key ] ) ) {
271 return;
272 }
273
274 if ( ! isset( self::$messages[ $key ]['read'] ) ) {
275 self::$messages[ $key ]['read'] = array();
276 }
277 self::$messages[ $key ]['read'][ get_current_user_id() ] = time();
278
279 $this->update_list();
280 }
281
282 /**
283 * @since 4.05.02
284 *
285 * @param string $key
286 * @return void
287 */
288 public function mark_unread( $key ) {
289 $is_read = isset( self::$messages[ $key ] ) && isset( self::$messages[ $key ]['read'] ) && isset( self::$messages[ $key ]['read'][ get_current_user_id() ] );
290 if ( $is_read ) {
291 unset( self::$messages[ $key ]['read'][ get_current_user_id() ] );
292 $this->update_list();
293 }
294 }
295
296 /**
297 * @param string $key
298 *
299 * @return void
300 */
301 public function dismiss( $key ) {
302 if ( $key === 'all' ) {
303 $this->dismiss_all();
304 return;
305 }
306
307 if ( ! isset( self::$messages[ $key ] ) ) {
308 return;
309 }
310
311 if ( ! isset( self::$messages[ $key ]['dismissed'] ) ) {
312 self::$messages[ $key ]['dismissed'] = array();
313 }
314 self::$messages[ $key ]['dismissed'][ get_current_user_id() ] = time();
315
316 $this->update_list();
317 }
318
319 /**
320 * @since 4.06
321 *
322 * @return void
323 */
324 private function dismiss_all() {
325 $user_id = get_current_user_id();
326 foreach ( self::$messages as $key => $message ) {
327 if ( ! isset( $message['dismissed'] ) ) {
328 self::$messages[ $key ]['dismissed'] = array();
329 }
330
331 if ( ! isset( $message['dismissed'][ $user_id ] ) ) {
332 self::$messages[ $key ]['dismissed'][ $user_id ] = time();
333 }
334 }
335 $this->update_list();
336 }
337
338 public function unread() {
339 $messages = $this->get_messages( 'filter' );
340 $user_id = get_current_user_id();
341 foreach ( $messages as $t => $message ) {
342 if ( isset( $message['read'] ) && isset( $message['read'][ $user_id ] ) ) {
343 unset( $messages[ $t ] );
344 }
345 }
346 return $messages;
347 }
348
349 /**
350 * @since 6.8.4 The $filtered parameter was added.
351 *
352 * @param bool $filtered
353 * @return string
354 */
355 public function unread_html( $filtered = true ) {
356 $count = count( $this->unread() );
357 if ( ! $count ) {
358 return '';
359 }
360
361 $html = ' <span class="update-plugins frm_inbox_count"><span class="plugin-count">' . absint( $count ) . '</span></span>';
362
363 if ( ! $filtered ) {
364 return $html;
365 }
366
367 /**
368 * @since 4.06.01
369 *
370 * @param string $html
371 */
372 return (string) apply_filters( 'frm_inbox_badge', $html );
373 }
374
375 /**
376 * @since 4.05.02
377 *
378 * @param string $key
379 * @return void
380 */
381 public function remove( $key ) {
382 if ( isset( self::$messages[ $key ] ) ) {
383 unset( self::$messages[ $key ] );
384 $this->update_list();
385 }
386 }
387
388 /**
389 * @return void
390 */
391 private function update_list() {
392 update_option( $this->option, self::$messages, 'no' );
393 }
394
395 /**
396 * Check if user is still using the Lite version only, and within
397 * the first 30 days of activation.
398 *
399 * @since 6.16
400 *
401 * @return bool
402 */
403 private function is_free_first_30() {
404 return $this->is_free() && $this->is_first_30();
405 }
406
407 /**
408 * @since 6.16.3
409 *
410 * @return bool
411 */
412 private function is_first_30() {
413 $activation_timestamp = get_option( 'frm_first_activation' );
414 if ( false === $activation_timestamp ) {
415 // If the option does not exist, assume that it is
416 // because the user was active before this option was introduced.
417 return false;
418 }
419 $cutoff = strtotime( '-30 days' );
420 return $activation_timestamp > $cutoff;
421 }
422
423 /**
424 * @since 6.16.3
425 *
426 * @return bool
427 */
428 private function is_free_not_first_30() {
429 return $this->is_free() && ! $this->is_first_30();
430 }
431
432 /**
433 * Check if the Pro plugin is active. If not, consider the user to be on the free version.
434 *
435 * @since 6.16.3
436 *
437 * @return bool
438 */
439 private function is_free() {
440 return ! FrmAppHelper::pro_is_included();
441 }
442
443 /**
444 * Show a banner message if one is available.
445 *
446 * @return bool True if a banner is available and shown.
447 */
448 public static function maybe_show_banner() {
449 if ( empty( self::$banner_messages ) ) {
450 return false;
451 }
452 $message = end( self::$banner_messages );
453 $cta = self::get_prepared_banner_cta( $message['cta'] );
454
455 require FrmAppHelper::plugin_path() . '/classes/views/inbox/banner.php';
456 return true;
457 }
458
459 /**
460 * Make sure that the CTA uses utm_medium=banner.
461 *
462 * @since 6.8.4
463 *
464 * @param string $cta
465 * @return string
466 */
467 private static function get_prepared_banner_cta( $cta ) {
468 $cta = str_replace( 'button-secondary', 'button-primary', $cta );
469 return preg_replace_callback(
470 '/href=("|\')(.*?)("|\')/',
471 /**
472 * Replace a single href attribute in the CTA.
473 *
474 * @param array $matches The regex results for a single match.
475 * @return string
476 */
477 function ( $matches ) {
478 $url = $matches[2];
479 $parts = parse_url( $url );
480
481 if ( '#' === $url ) {
482 return 'href="#"';
483 }
484
485 $query = array();
486 if ( isset( $parts['query'] ) ) {
487 parse_str( $parts['query'], $query );
488 }
489 $query['utm_medium'] = 'banner';
490 $parts['query'] = http_build_query( $query );
491 return 'href="' . $parts['scheme'] . '://' . $parts['host'] . $parts['path'] . '?' . $parts['query'] . '"';
492 },
493 $cta
494 );
495 }
496
497 /**
498 * @return void
499 */
500 public static function maybe_disable_screen_options() {
501 self::$banner_messages = self::get_banner_messages();
502 if ( self::$banner_messages ) {
503 // disable screen options tab when displaying banner messages because it gets in the way of the banner.
504 add_filter( 'screen_options_show_screen', '__return_false' );
505 }
506 }
507
508 /**
509 * Get all message with a "banner" message key defined.
510 *
511 * @return array
512 */
513 private static function get_banner_messages() {
514 return self::get_messages_with_key( 'banner' );
515 }
516
517 /**
518 * Get all messages with a "slidein" message key defined.
519 *
520 * @since 6.8.4
521 *
522 * @return array
523 */
524 private static function get_slidein_messages() {
525 return self::get_messages_with_key( 'slidein' );
526 }
527
528 /**
529 * Get all messages with a $key message key defined.
530 *
531 * @since 6.8.4
532 *
533 * @param string $key The key we are checking for (ie. banner or slidein).
534 * @return array
535 */
536 private static function get_messages_with_key( $key ) {
537 $inbox = new self();
538 return array_filter(
539 $inbox->get_messages( 'filter' ),
540 function ( $message ) use ( $key ) {
541 return ! empty( $message[ $key ] );
542 }
543 );
544 }
545
546 /**
547 * Check if there is at least one slidein message.
548 *
549 * @since 6.8.4
550 *
551 * @return bool
552 */
553 public static function has_a_slidein_message() {
554 return (bool) self::get_slidein_messages();
555 }
556
557 /**
558 * Get the array used for frmGlobal.inboxSlideIn
559 *
560 * @since 6.8.4
561 *
562 * @return array|false
563 */
564 public static function get_inbox_slide_in_value_for_js() {
565 $messages = self::get_slidein_messages();
566 if ( ! $messages ) {
567 return false;
568 }
569
570 $message = reset( $messages );
571
572 /**
573 * Extend the keys in the global JS object.
574 * This is used in Pro to include images.
575 *
576 * @since 6.8.4
577 *
578 * @param array $keys
579 */
580 $keys_to_return = apply_filters(
581 'frm_inbox_slidein_js_vars',
582 array( 'key', 'slidein', 'subject', 'cta' )
583 );
584
585 return array_reduce(
586 $keys_to_return,
587 function ( $total, $key ) use ( $message ) {
588 $total[ $key ] = isset( $message[ $key ] ) ? $message[ $key ] : '';
589 return $total;
590 },
591 array()
592 );
593 }
594 }
595