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

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