PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.8.2
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.8.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 / helpers / FrmEmailSummaryHelper.php

FrmEmailSummaryHelper.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.8.2, at classes/helpers/FrmEmailSummaryHelper.php

555 lines 14.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * In-plugin summary emails helper
4 *
5 * @since 6.7
6 * @package Formidable
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 die( 'You are not allowed to call this page directly.' );
11 }
12
13 /**
14 * Class FrmEmailSummaryHelper
15 */
16 class FrmEmailSummaryHelper {
17
18 const MONTHLY = 'monthly';
19
20 const YEARLY = 'yearly';
21
22 /**
23 * Number of days to send the next monthly email.
24 */
25 const MONTHLY_PERIOD = 30;
26
27 /**
28 * Number of days to send the next yearly email.
29 */
30 const YEARLY_PERIOD = 365;
31
32 /**
33 * Number of days before renewal date to send yearly email.
34 */
35 const BEFORE_RENEWAL_PERIOD = 45;
36
37 /**
38 * Number of days before sending the first summary email after upgrade plugin.
39 */
40 const DELAY_AFTER_UPGRADE = 15;
41
42 /**
43 * Summary emails option name.
44 *
45 * @var string
46 */
47 public static $option_name = 'frm_summary_emails_options';
48
49 /**
50 * Checks if summary emails are enabled.
51 *
52 * @return bool
53 */
54 public static function is_enabled() {
55 $frm_settings = FrmAppHelper::get_settings();
56 return ! empty( $frm_settings->summary_emails ) && ! empty( $frm_settings->summary_emails_recipients );
57 }
58
59 /**
60 * Gets summary emails options.
61 *
62 * @return array
63 */
64 private static function get_options() {
65 $options = get_option( self::$option_name );
66 if ( ! $options ) {
67 $default_options = array(
68 // Do not send email within 15 days after updating.
69 'last_' . self::MONTHLY => self::get_date_from_today( '-' . self::DELAY_AFTER_UPGRADE . ' days' ),
70 'last_' . self::YEARLY => '',
71 'renewal_date' => '',
72 );
73
74 self::save_options( $default_options );
75 return $default_options;
76 }
77
78 return $options;
79 }
80
81 /**
82 * Saves summary emails options.
83 *
84 * @param array $options Options data.
85 */
86 private static function save_options( $options ) {
87 update_option( self::$option_name, $options );
88 }
89
90 /**
91 * Checks if should send summary emails.
92 *
93 * @return array|false Return array of emails should be sent, or `false` if not send any emails.
94 */
95 public static function should_send_emails() {
96 if ( ! self::is_enabled() ) {
97 return false;
98 }
99
100 $emails = array();
101 $current_date = self::get_date_from_today();
102
103 // Check for monthly or yearly email.
104 $last_monthly = self::get_last_sent_date( 'monthly' );
105 $last_yearly = self::get_last_sent_date( 'yearly' );
106 $last_stats = max( $last_monthly, $last_yearly );
107
108 // Do not send any email if it isn't enough 30 days from the last stats email.
109 if ( $last_stats && self::MONTHLY_PERIOD > self::get_date_diff( $current_date, $last_stats ) ) {
110 return $emails;
111 }
112
113 if ( $last_yearly ) {
114 // If this isn't the first yearly email, send the new one after 1 year.
115 if ( $last_yearly && self::YEARLY_PERIOD <= self::get_date_diff( $current_date, $last_yearly ) ) {
116 $emails[] = self::YEARLY;
117 return $emails;
118 }
119 } else {
120 // If no yearly email has been sent, send it if it's less than 45 days until the renewal date.
121 $renewal_date = self::get_renewal_date();
122 if ( $renewal_date && self::BEFORE_RENEWAL_PERIOD >= self::get_date_diff( $current_date, $renewal_date ) ) {
123 $emails[] = self::YEARLY;
124 return $emails;
125 }
126 }
127
128 // If it isn't time for yearly email, it's time for monthly email.
129 $emails[] = self::MONTHLY;
130
131 return $emails;
132 }
133
134 /**
135 * Sends monthly email.
136 */
137 public static function send_monthly() {
138 $monthly_email = new FrmEmailMonthly();
139
140 if ( $monthly_email->send() ) {
141 self::set_last_sent_date( self::MONTHLY );
142 }
143 }
144
145 /**
146 * Sends yearly email.
147 */
148 public static function send_yearly() {
149 $yearly_email = new FrmEmailYearly();
150
151 if ( $yearly_email->send() ) {
152 self::set_last_sent_date( self::YEARLY );
153 }
154 }
155
156 /**
157 * Gets the renewal date and save to options. If it doesn't exist, get the created date of the lowest ID form then plus 1 year.
158 *
159 * @return string
160 */
161 private static function get_renewal_date() {
162 $options = self::get_options();
163
164 // Get cached value from options.
165 if ( ! empty( $options['renewal_date'] ) ) {
166 return $options['renewal_date'];
167 }
168
169 // Return the actual renewal date if it exists.
170 $license_info = FrmAddonsController::get_primary_license_info();
171 if ( ! empty( $license_info['expires'] ) ) {
172 $renewal_date = gmdate( 'Y-m-d', $license_info['expires'] );
173
174 $options['renewal_date'] = $renewal_date;
175 self::save_options( $options );
176 return $renewal_date;
177 }
178
179 // If renewal date doesn't exist, get from the first form creation date.
180 $first_form_date = self::get_earliest_form_created_date();
181 if ( $first_form_date ) {
182 $renewal_date = gmdate( 'Y-m-d', strtotime( $first_form_date . '+' . self::YEARLY_PERIOD . ' days' ) );
183
184 // If the first form is more than 1 year in the past, set renewal date to the next 45 days.
185 if ( $renewal_date < self::get_date_from_today() ) {
186 $renewal_date = self::get_date_from_today( '+' . self::BEFORE_RENEWAL_PERIOD . ' days' );
187 }
188
189 $options['renewal_date'] = $renewal_date;
190 self::save_options( $options );
191 return $renewal_date;
192 }
193
194 return false;
195 }
196
197 /**
198 * Gets date object.
199 *
200 * @param string|DateTime $date Date string or object.
201 * @return DateTime|false
202 */
203 private static function get_date_obj( $date ) {
204 if ( $date instanceof DateTime ) {
205 return $date;
206 }
207
208 return date_create( $date );
209 }
210
211 /**
212 * Gets the days different between 2 dates.
213 *
214 * @param string|DateTime $date1 Date 1.
215 * @param string|DateTime $date2 Date 2.
216 * @return int|false
217 */
218 private static function get_date_diff( $date1, $date2 ) {
219 $date1 = self::get_date_obj( $date1 );
220 if ( ! $date1 ) {
221 return false;
222 }
223
224 $date2 = self::get_date_obj( $date2 );
225 if ( ! $date2 ) {
226 return false;
227 }
228
229 return date_diff( $date1, $date2 )->days;
230 }
231
232 /**
233 * Gets sent date of the last monthly or yearly email.
234 *
235 * @param string $type Accepts `monthly`, `yearly`.
236 * @return string|false
237 */
238 public static function get_last_sent_date( $type ) {
239 $options = self::get_options();
240 if ( empty( $options[ 'last_' . $type ] ) ) {
241 return false;
242 }
243
244 return $options[ 'last_' . $type ];
245 }
246
247 /**
248 * Sets the last sent date of an email type.
249 *
250 * @param string $type Email type.
251 * @param mixed $value Set custom value. If this is null, set the current date.
252 */
253 public static function set_last_sent_date( $type, $value = null ) {
254 $options = self::get_options();
255
256 $options[ 'last_' . $type ] = null === $value ? self::get_date_from_today() : '';
257 self::save_options( $options );
258 }
259
260 /**
261 * Gets the created date of earliest form.
262 *
263 * @return string
264 */
265 private static function get_earliest_form_created_date() {
266 return FrmDb::get_var(
267 'frm_forms',
268 array(),
269 'created_at',
270 array( 'order_by' => 'id ASC' )
271 );
272 }
273
274 /**
275 * Gets payments data.
276 *
277 * @param string $from_date From date.
278 * @param string $to_date To date.
279 * @return array Contains `count` and `total`.
280 */
281 public static function get_payments_data( $from_date, $to_date ) {
282 $payment = new FrmTransLitePayment();
283 return $payment->get_payments_stats( $from_date, $to_date );
284 }
285
286 /**
287 * Gets entries count in a date range.
288 *
289 * @param string $from_date From date.
290 * @param string $to_date To date.
291 * @return int
292 */
293 public static function get_entries_count( $from_date, $to_date ) {
294 return FrmDb::get_count(
295 'frm_items',
296 array(
297 // The `=` is added after `>` in the query.
298 'created_at >' => $from_date,
299 'created_at <' => $to_date . ' 23:59:59',
300 'is_draft' => 0,
301 )
302 );
303 }
304
305 /**
306 * Gets top forms in a date range.
307 *
308 * @param string $from_date From date.
309 * @param string $to_date To date.
310 * @param int $limit Limit the result. Default is 5.
311 * @return array Contains `form_id`, `form_name`, and `items_count`.
312 */
313 public static function get_top_forms( $from_date, $to_date, $limit = 5 ) {
314 global $wpdb;
315
316 $result = $wpdb->get_results(
317 $wpdb->prepare(
318 "SELECT fr.id AS form_id, fr.name AS form_name, COUNT(*) as items_count
319 FROM {$wpdb->prefix}frm_items AS it INNER JOIN {$wpdb->prefix}frm_forms AS fr ON it.form_id = fr.id
320 WHERE it.created_at BETWEEN %s AND %s AND it.is_draft = 0
321 GROUP BY form_id ORDER BY items_count DESC LIMIT %d",
322 $from_date,
323 $to_date . ' 23:59:59',
324 intval( $limit )
325 )
326 );
327
328 // Remove slashes from form name.
329 foreach ( $result as &$value ) {
330 $value->form_name = wp_unslash( $value->form_name );
331 }
332
333 return $result;
334 }
335
336 /**
337 * Shows the comparison HTML in the email.
338 *
339 * @param float $diff Percentage of difference.
340 */
341 public static function show_comparison( $diff ) {
342 if ( ! $diff ) {
343 return;
344 }
345
346 if ( $diff > 0 ) {
347 $arrow = '&uarr;';
348 $color = '#12b76a';
349 } else {
350 $arrow = '&darr;';
351 $color = '#f04438';
352 }
353
354 $displayed_value = round( $diff * 100 );
355 if ( ! $displayed_value ) {
356 // Do not show 0 value.
357 $displayed_value = $diff > 0 ? 1 : -1;
358 }
359
360 printf(
361 '<span style="color: %1$s; font-size: 0.75em; font-weight: 700;">
362 %2$s<span style="display: inline-block; line-height: 1.33;">%3$s</span>
363 </span>',
364 esc_attr( $color ),
365 esc_html( $arrow ),
366 intval( $displayed_value ) . '%'
367 );
368 }
369
370 /**
371 * Gets section CSS in the email.
372 *
373 * @param string $border_pos Border position. Default is `top`. Set to empty if no border.
374 * @return string
375 */
376 public static function get_section_style( $border_pos = 'top' ) {
377 if ( $border_pos ) {
378 $border = 'border-' . $border_pos . ': 1px solid #eaecf0;';
379 } else {
380 $border = '';
381 }
382 return 'padding: 3em 4.375em;' . $border;
383 }
384
385 /**
386 * Gets h2 CSS in the email.
387 *
388 * @return string
389 */
390 public static function get_heading2_style() {
391 return 'font-size: 1.125em; line-height: 1.33em; margin: 0 0 1.33em;';
392 }
393
394 /**
395 * Gets CSS for button.
396 *
397 * @return string
398 */
399 public static function get_button_style( $display_block = false ) {
400 return 'display: ' . ( $display_block ? 'block' : 'inline-block' ) . '; font-size: 0.875em; line-height: 2.4; border-radius: 1.2em; border: 1px solid #d0d5dd; font-weight: 600; text-align: center; margin-top: 2.6em; color: #1d2939; text-decoration: none; padding-left: 1em; padding-right: 1em;';
401 }
402
403 /**
404 * Shows the section heading with icon.
405 *
406 * @param string $icon Icon file name, without file path and extension. Use .png image.
407 * @param string $text Heading text.
408 */
409 public static function section_heading_with_icon( $icon, $text ) {
410 ?>
411 <h2 style="<?php echo esc_attr( self::get_heading2_style() ); ?>">
412 <img style="vertical-align: bottom; height: 24px; width: auto;" src="<?php echo esc_url( FrmAppHelper::plugin_url() . '/images/' . $icon . '.png' ); ?>" alt="<?php echo esc_attr( $icon ); ?>" />
413 <span style="display: inline-block; vertical-align: text-bottom;"><?php echo esc_html( $text ); ?></span>
414 </h2>
415 <?php
416 }
417
418 /**
419 * Gets Formidable URL with tracking params.
420 *
421 * @param string $url The URL.
422 * @param string|array $args Custom tracking args if is array, or `utm_content` if is string.
423 * @return string
424 */
425 public static function get_frm_url( $url, $args = array() ) {
426 if ( is_array( $args ) ) {
427 $args = wp_parse_args(
428 $args,
429 array(
430 'medium' => 'summary-email',
431 'content' => 'link',
432 )
433 );
434 } else {
435 $args = array(
436 'medium' => 'summary-email',
437 'content' => $args,
438 );
439 }
440
441 return FrmAppHelper::admin_upgrade_link( $args, $url );
442 }
443
444 /**
445 * Gets the latest inbox message.
446 *
447 * @return array|false
448 */
449 public static function get_latest_inbox_message() {
450 $inbox = new FrmInbox();
451 $messages = $inbox->get_messages( 'filter' );
452 if ( ! $messages || ! is_array( $messages ) ) {
453 return false;
454 }
455
456 $messages = array_reverse( $messages );
457 foreach ( $messages as $message ) {
458 if ( 'news' !== $message['type'] ) {
459 continue;
460 }
461
462 return $message;
463 }
464
465 return false;
466 }
467
468 /**
469 * Gets out of date plugin names.
470 *
471 * @return array
472 */
473 public static function get_out_of_date_plugins() {
474 $update_data = FrmAddonsController::check_update( '' );
475 if ( ! $update_data || ! is_object( $update_data ) || empty( $update_data->response ) ) {
476 return array();
477 }
478
479 $plugins = array();
480 foreach ( $update_data->response as $plugin_data ) {
481 $plugins[] = $plugin_data->display_name;
482 }
483
484 return $plugins;
485 }
486
487 /**
488 * Processes inbox CTA button before showing in email.
489 *
490 * @param string $button_html Button HTML. This usually contains 1 button and 1 dismiss button.
491 * @return string
492 */
493 public static function process_inbox_cta_button( $button_html ) {
494 // Remove dismiss button.
495 $button_html = preg_replace( '/<a[^>]*class="[^"]*\bfrm_inbox_dismiss\b[^"]*"[^>]*>[^<]*<\/a>/', '', $button_html );
496
497 // Replace link utm.
498 $button_html = str_replace( 'utm_medium=inbox', 'utm_medium=summary-email', $button_html );
499
500 if ( strpos( $button_html, 'style="' ) ) {
501 // Maybe this button contains inline style.
502 return $button_html;
503 }
504
505 // Add inline CSS for specific button types.
506 if ( strpos( $button_html, 'frm-button-primary' ) ) {
507 $button_html = str_replace( '<a', '<a style="' . self::get_button_style() . '"', $button_html );
508 }
509
510 return $button_html;
511 }
512
513 /**
514 * Gets the localized date with the date diff from today.
515 *
516 * @param string $date_diff Date diff string. By default, this is empty, the result will be the current date.
517 * @return string
518 */
519 public static function get_date_from_today( $date_diff = '' ) {
520 if ( ! $date_diff ) {
521 return FrmAppHelper::get_localized_date( 'Y-m-d', gmdate( 'Y-m-d H:i:s' ) );
522 }
523 return FrmAppHelper::get_localized_date( 'Y-m-d', gmdate( 'Y-m-d H:i:s', strtotime( $date_diff ) ) );
524 }
525
526 /**
527 * Maybe remove recipients from setting from API.
528 *
529 * @since 6.8
530 *
531 * @param array $recipients Recipients.
532 */
533 public static function maybe_remove_recipients_from_api( &$recipients ) {
534 $api = new FrmFormApi();
535 $addons = $api->get_api_info();
536 if ( empty( $addons['no_emails'] ) ) {
537 return;
538 }
539
540 $skip_emails = is_string( $addons['no_emails'] ) ? explode( ',', $addons['no_emails'] ) : (array) $addons['no_emails'];
541 $recipients = array_diff( $recipients, $skip_emails );
542 }
543
544 /**
545 * Echos string in plain text email.
546 *
547 * @since 6.8
548 *
549 * @param string $string string.
550 */
551 public static function plain_text_echo( $string ) {
552 echo wp_strip_all_tags( $string ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
553 }
554 }
555