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

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