PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.29
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.29
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 / controllers / FrmEmailStylesController.php

FrmEmailStylesController.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.29, at classes/controllers/FrmEmailStylesController.php

499 lines 13.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Controller for email styles
4 *
5 * @since 6.25
6 *
7 * @package Formidable
8 */
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 die( 'You are not allowed to call this page directly.' );
12 }
13
14 /**
15 * Class FrmEmailStylesController
16 */
17 class FrmEmailStylesController {
18
19 /**
20 * Gets email styles.
21 *
22 * @return array[]
23 */
24 public static function get_email_styles() {
25 $icon_dir_url = FrmAppHelper::plugin_url() . '/images/email-styles/';
26
27 $email_styles = array(
28 'classic' => array(
29 'name' => __( 'Classic', 'formidable' ),
30 'selectable' => true,
31 'icon_url' => $icon_dir_url . 'classic.svg',
32 'is_plain_text' => false,
33 ),
34 'plain' => array(
35 'name' => __( 'Plain Text', 'formidable' ),
36 'selectable' => true,
37 'icon_url' => $icon_dir_url . 'plain.svg',
38 'is_plain_text' => true,
39 ),
40 'modern' => array(
41 'name' => __( 'Modern', 'formidable' ),
42 'selectable' => false,
43 'icon_url' => $icon_dir_url . 'modern.svg',
44 'is_plain_text' => false,
45 ),
46 'sleek' => array(
47 'name' => __( 'Sleek', 'formidable' ),
48 'selectable' => false,
49 'icon_url' => $icon_dir_url . 'sleek.svg',
50 'is_plain_text' => false,
51 ),
52 'compact' => array(
53 'name' => __( 'Compact', 'formidable' ),
54 'selectable' => false,
55 'icon_url' => $icon_dir_url . 'compact.svg',
56 'is_plain_text' => false,
57 ),
58 );
59
60 /**
61 * Filter the email styles.
62 *
63 * @since 6.25
64 *
65 * @param array[] $email_styles The email styles.
66 *
67 * @return array
68 */
69 return apply_filters( 'frm_email_styles', $email_styles );
70 }
71
72 /**
73 * Gets email style preview URL.
74 *
75 * @param string $style_key Style key.
76 *
77 * @return string
78 */
79 public static function get_email_style_preview_url( $style_key ) {
80 return wp_nonce_url( admin_url( 'admin-ajax.php?action=frm_email_style_preview&style_key=' . $style_key ), 'frm_email_style_preview' );
81 }
82
83 /**
84 * Gets the email style set in the Global settings.
85 *
86 * @return string
87 */
88 public static function get_default_email_style() {
89 $frm_settings = FrmAppHelper::get_settings();
90
91 if ( empty( $frm_settings->email_style ) ) {
92 return 'classic';
93 }
94
95 // Check if the selected style is available and selectable.
96 $styles = self::get_email_styles();
97 $style = $frm_settings->email_style;
98
99 if ( isset( $styles[ $style ] ) && ! empty( $styles[ $style ]['selectable'] ) ) {
100 return $style;
101 }
102
103 return 'classic';
104 }
105
106 /**
107 * Gets the test email content.
108 *
109 * @param false|string $style_key Default is `false`, using the one in settings.
110 *
111 * @return string
112 */
113 private static function get_test_email_content( $style_key = false ) {
114 if ( ! $style_key ) {
115 $style_key = self::get_default_email_style();
116 }
117
118 $table_rows = array(
119 array(
120 'label' => 'Name',
121 'value' => 'John Doe',
122 ),
123 array(
124 'label' => 'Email address',
125 'value' => 'john@doe.com',
126 ),
127 array(
128 'label' => 'Subject',
129 'value' => 'Contact subject',
130 ),
131 array(
132 'label' => 'Message',
133 'value' => 'Lorem ipsum dolor sit amet, <a href="#">consectetur adipiscing elit</a>.
134 Praesent in risus velit. Donec molestie tincidunt ex sed consequat. Ut ornare fringilla fringilla.',
135 ),
136 );
137
138 if ( 'plain' === $style_key ) {
139 $content = '';
140
141 foreach ( $table_rows as $row ) {
142 $content .= $row['label'] . ': ' . $row['value'] . "\r\n";
143 }
144 } else {
145 $content = self::get_test_rich_text_email_content( $style_key, $table_rows );
146 }//end if
147
148 return $content;
149 }
150
151 /**
152 * Gets the test email content.
153 *
154 * @param string $style_key Style key.
155 * @param array $table_rows Table rows.
156 *
157 * @return string
158 */
159 private static function get_test_rich_text_email_content( $style_key, $table_rows ) {
160 $style_settings = self::get_email_style_settings();
161
162 // Sleek table style doesn't have any border.
163 $should_remove_border = 'sleek' === $style_key;
164
165 // Modern and Compact table styles don't have top and bottom border.
166 $should_remove_top_bottom_border = 'classic' !== $style_key;
167 $table_generator = self::get_table_generator( $style_key );
168 $content = $table_generator->generate_table_header();
169
170 // By default, table has the bottom border and table cells have top border.
171 if ( $should_remove_top_bottom_border ) {
172 $content = $table_generator->remove_border( $content, 'bottom' );
173 }
174
175 foreach ( $table_rows as $index => $row ) {
176 if ( 'compact' === $style_key ) {
177 // Add some spaces after the label. Maybe change it to the left in RTL.
178 $row['label'] = '<div style="padding-right:10px;">' . $row['label'] . '</div>';
179
180 // Compact table has two columns layout.
181 $table_row = $table_generator->generate_two_cell_table_row( $row['label'], $row['value'] );
182 } else {
183 // Other table styles have one column layout.
184 $table_row = $table_generator->generate_single_cell_table_row( self::get_content_for_one_column_cell( $row['label'], $row['value'] ) );
185 }
186
187 if ( ! $index && $should_remove_top_bottom_border ) {
188 $table_row = $table_generator->remove_border( $table_row );
189 }
190
191 $content .= $table_row;
192 }
193
194 $content .= $table_generator->generate_table_footer();
195
196 if ( $should_remove_border ) {
197 $content = $table_generator->remove_border( $content, 'top' );
198 }
199
200 if ( 'classic' !== $style_key ) {
201 $content = self::wrap_email_message( $content );
202 }
203
204 $wrapped_content = '<html><head><meta charset="utf-8" /></head>';
205
206 if ( 'classic' !== $style_key ) {
207 // This works in previewing and as a fallback for email content.
208 $wrapped_content .= '<style>
209 body {background-color:' . esc_attr( $style_settings['bg_color'] ) . ';}
210 a {color:' . esc_attr( $style_settings['link_color'] ) . ';}
211 </style>';
212 }
213
214 return $wrapped_content . ( '</head><body>' . $content . '</body></html>' );
215 }
216
217 /**
218 * Gets content for the cell of one column table.
219 *
220 * @param string $label Field label.
221 * @param string $value Prepared field value.
222 *
223 * @return string
224 */
225 public static function get_content_for_one_column_cell( $label, $value ) {
226 return '<div style="font-weight:600;">' . $label . '</div>' . $value;
227 }
228
229 /**
230 * Gets table generator object for an email style.
231 *
232 * @param false|string $email_style Email style. Default is `false`: using the one in global settings.
233 *
234 * @return FrmTableHTMLGenerator
235 */
236 public static function get_table_generator( $email_style = false ) {
237 if ( false === $email_style ) {
238 $email_style = self::get_default_email_style();
239 }
240
241 $style_settings = self::get_email_style_settings();
242
243 $atts = array(
244 'inline_style' => true,
245 'email_style' => $email_style,
246 );
247
248 if ( 'classic' !== $email_style ) {
249 $atts['width'] = '100%';
250 $atts['border_color'] = $style_settings['border_color'];
251 $atts['cell_padding'] = '16px 0';
252 $atts['bg_color'] = $style_settings['container_bg_color'];
253 $atts['alt_bg_color'] = $style_settings['container_bg_color'];
254 $atts['text_color'] = $style_settings['text_color'];
255 }
256
257 return new FrmTableHTMLGenerator( 'entry', $atts );
258 }
259
260 /**
261 * AJAX handler for previewing email style.
262 */
263 public static function ajax_preview() {
264 // Check permission and nonce.
265 FrmAppHelper::permission_check( 'frm_change_settings' );
266 check_ajax_referer( 'frm_email_style_preview' );
267
268 $style_key = FrmAppHelper::get_param( 'style_key', '', 'get', 'sanitize_text_field' );
269 $not_exist_msg = __( "This email style doesn't exist", 'formidable' );
270
271 if ( ! $style_key ) {
272 die( esc_html( $not_exist_msg ) );
273 }
274
275 $styles = self::get_email_styles();
276
277 if ( ! isset( $styles[ $style_key ] ) ) {
278 die( esc_html( $not_exist_msg ) );
279 }
280
281 $style_key = FrmAppHelper::get_param( 'style_key', '', 'sanitize_text_field' );
282 $content = self::get_test_email_content( $style_key );
283
284 header( self::get_content_type_header( $style_key ) );
285
286 echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
287
288 die();
289 }
290
291 /**
292 * AJAX handler for sending a test email.
293 */
294 public static function ajax_send_test_email() {
295 // Check permission and nonce.
296 FrmAppHelper::permission_check( 'frm_change_settings' );
297 check_ajax_referer( 'frm_ajax', 'nonce' );
298
299 $emails_str = FrmAppHelper::get_post_param( 'emails_str', '', 'sanitize_text_field' );
300 $emails = explode( ',', $emails_str );
301 $valid_emails = array();
302
303 foreach ( $emails as $email ) {
304 $email = trim( $email );
305
306 if ( ! $email || ! is_email( $email ) ) {
307 continue;
308 }
309
310 $valid_emails[] = $email;
311 }
312
313 if ( ! $valid_emails ) {
314 wp_send_json_error( __( 'Invalid email address', 'formidable' ) );
315 }
316
317 $email_style = self::get_default_email_style();
318 $subject = __( 'Formidable Test Email', 'formidable' );
319 $content = self::get_test_email_content();
320 $headers = array(
321 self::get_content_type_header( $email_style ),
322 );
323
324 FrmUsageController::update_flows_data( 'send_test_email', $email_style );
325
326 $result = wp_mail( $valid_emails, $subject, $content, $headers );
327
328 if ( $result ) {
329 wp_send_json_success( __( 'Test email sent successfully!', 'formidable' ) );
330 }
331
332 wp_send_json_error( __( 'Failed to send test email!', 'formidable' ) );
333 }
334
335 /**
336 * Gets Content-Type header.
337 *
338 * @param string $email_style Email style.
339 *
340 * @return string
341 */
342 private static function get_content_type_header( $email_style ) {
343 $content_type = 'plain' === $email_style ? 'text/plain' : 'text/html';
344 return 'Content-Type: ' . $content_type . '; charset=utf-8';
345 }
346
347 /**
348 * Shows placeholder Pro settings.
349 *
350 * @return void
351 */
352 public static function show_upsell_settings() {
353 include FrmAppHelper::plugin_path() . '/classes/views/frm-settings/email/settings.php';
354 }
355
356 /**
357 * Gets email style settings value.
358 *
359 * @return array
360 */
361 public static function get_email_style_settings() {
362 /**
363 * Filter the email style settings value.
364 *
365 * @since 6.25
366 *
367 * @param array $settings The settings value.
368 */
369 return apply_filters(
370 'frm_email_style_settings',
371 array(
372 // Placeholder image.
373 'img' => FrmAppHelper::plugin_url() . '/images/email-styles/placeholder.png',
374 'img_size' => '',
375 'img_align' => '',
376 'img_location' => '',
377 'bg_color' => '#EAECF0',
378 'container_bg_color' => '#ffffff',
379 'text_color' => '#475467',
380 'link_color' => '#4199FD',
381 'border_color' => '#dddddd',
382 'font' => '',
383 )
384 );
385 }
386
387 /**
388 * Wraps email message with new settings.
389 *
390 * @param string $message Email message.
391 *
392 * @return string
393 */
394 public static function wrap_email_message( $message ) {
395 $style_settings = self::get_email_style_settings();
396 $header_img = '';
397
398 if ( $style_settings['img'] ) {
399 $img_align = $style_settings['img_align'] ? $style_settings['img_align'] : 'center';
400 $img_size = $style_settings['img_size'] ? $style_settings['img_size'] : 'thumbnail';
401 $img_url = is_numeric( $style_settings['img'] ) ? wp_get_attachment_image_url( $style_settings['img'], $img_size ) : $style_settings['img'];
402
403 $header_img .= sprintf(
404 '<div style="text-align:%s;margin-bottom:32px;">',
405 esc_attr( $img_align )
406 );
407
408 $header_img .= sprintf(
409 '<img src="%s" alt="" style="max-width:100%%;height:auto;" />',
410 esc_url( $img_url )
411 );
412
413 $header_img .= '</div>';
414 }
415
416 // Wrapper.
417 $font_family = $style_settings['font'] ? $style_settings['font'] : 'Inter,sans-serif';
418 $new_message = sprintf(
419 '<div style="background-color:%1$s;color:%2$s;font-family:%3$s;padding:40px 10px;">',
420 esc_attr( $style_settings['bg_color'] ),
421 esc_attr( $style_settings['text_color'] ),
422 esc_attr( $font_family )
423 );
424
425 // Container.
426 $new_message .= '<div style="max-width:640px;margin:auto;">';
427
428 // Header image if outside.
429 if ( $style_settings['img'] && 'inside' !== $style_settings['img_location'] ) {
430 $new_message .= $header_img;
431 }
432
433 // Main container.
434 $new_message .= sprintf(
435 '<div style="background-color:%s;border-radius:8px;padding:32px;">',
436 esc_attr( $style_settings['container_bg_color'] )
437 );
438
439 // Header image if inside.
440 if ( $style_settings['img'] && 'inside' === $style_settings['img_location'] ) {
441 $new_message .= $header_img;
442 }
443
444 // The message.
445 $new_message .= self::add_inline_css( 'a', 'color:' . $style_settings['link_color'] . ';', $message );
446
447 return $new_message . '</div></div></div>';
448 }
449
450 /**
451 * Adds inline CSS to a tag in the content.
452 *
453 * @param string $tag Tag name.
454 * @param string $css CSS code.
455 * @param string $content The content.
456 *
457 * @return string
458 */
459 private static function add_inline_css( $tag, $css, $content ) {
460 $regex = '/<' . $tag . '.*?>/msi';
461 preg_match_all( $regex, $content, $matches, PREG_SET_ORDER );
462
463 if ( ! $matches ) {
464 return $content;
465 }
466
467 $searches = array();
468 $replaces = array();
469
470 foreach ( $matches as $match ) {
471 $searches[] = $match[0];
472 $replaces[] = self::add_css_to_style_attr( $tag, $css, $match[0] );
473 }
474
475 return str_replace( $searches, $replaces, $content );
476 }
477
478 /**
479 * Adds inline CSS to a single HTML tag.
480 *
481 * @param string $tag Tag name.
482 * @param string $css CSS code.
483 * @param string $html The HTML tag.
484 *
485 * @return string
486 */
487 private static function add_css_to_style_attr( $tag, $css, $html ) {
488 $regex = '/\sstyle=("|\')/mi';
489
490 if ( preg_match( $regex, $html, $matches ) ) {
491 $search = $matches[0];
492 $replace = $search . $css;
493 return preg_replace( $regex, $replace, $html );
494 }
495
496 return str_replace( '<' . $tag, '<' . $tag . ' style="' . $css . '"', $html );
497 }
498 }
499