PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.26.1
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.26.1
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 / FrmStylesCardHelper.php

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

524 lines 13.2 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 6.0
8 */
9 class FrmStylesCardHelper {
10
11 const PAGE_SIZE = 3;
12
13 /**
14 * @var string
15 */
16 private $view_file_path;
17
18 /**
19 * @var stdClass|WP_Post
20 */
21 private $active_style;
22
23 /**
24 * @var WP_Post
25 */
26 private $default_style;
27
28 /**
29 * @var int
30 */
31 private $form_id;
32
33 /**
34 * @var bool
35 */
36 private $enabled;
37
38 /**
39 * @var bool If this is true, a lock will be rendered with the style name when self::echo_style_card is called.
40 */
41 private $locked;
42
43 /**
44 * @var bool If this is true, a "NEW" pill is included beside the style name.
45 */
46 private $is_new_template;
47
48 /**
49 * @param stdClass|WP_Post $active_style
50 * @param WP_Post $default_style
51 * @param int|string $form_id
52 * @param bool $enabled
53 */
54 public function __construct( $active_style, $default_style, $form_id, $enabled ) {
55 $this->view_file_path = FrmAppHelper::plugin_path() . '/classes/views/styles/_style-card.php';
56 $this->active_style = $active_style;
57 $this->default_style = $default_style;
58 $this->form_id = (int) $form_id;
59 $this->enabled = $enabled;
60 $this->locked = false;
61 $this->is_new_template = false;
62 }
63
64 /**
65 * Echo a style card for a specific target Style Post object.
66 *
67 * @since 6.0
68 *
69 * @param stdClass|WP_Post $style
70 * @param bool $hidden Used for pagination.
71 *
72 * @return void
73 */
74 private function echo_style_card( $style, $hidden = false ) {
75 $params = $this->get_params_for_style_card( $style, $hidden );
76 $is_locked = $this->locked;
77 $is_new_template = $this->is_new_template;
78 $is_active_style = $style->ID === $this->active_style->ID;
79
80 include $this->view_file_path;
81 }
82
83 /**
84 * Get params to use in the style card HTML element used in the style list.
85 *
86 * @since 6.0
87 *
88 * @param stdClass|WP_Post $style
89 * @param bool $hidden
90 *
91 * @return array
92 */
93 private function get_params_for_style_card( $style, $hidden = false ) {
94 if ( ! empty( $style->post_content['position'] ) ) {
95 $label_position = $style->post_content['position'];
96 } else {
97 $frm_style = new FrmStyle();
98 $defaults = $frm_style->get_defaults();
99 $label_position = $defaults['position'];
100 }
101
102 $class_name = 'frm_style_' . $style->post_name;
103 $params = array(
104 'class' => 'frm-style-card frm-transition-ease',
105 'style' => self::get_style_param_for_card( $style ),
106 'data-classname' => $class_name,
107 'data-style-id' => $style->ID,
108 'data-edit-url' => esc_url( FrmStylesHelper::get_edit_url( $style, $this->form_id ) ),
109 'data-label-position' => $label_position,
110 );
111
112 $is_active_style = $style->ID === $this->active_style->ID;
113
114 if ( $is_active_style ) {
115 $params['class'] .= ' frm-active-style-card frm-currently-set-style-card';
116 }
117
118 if ( $hidden ) {
119 $params['class'] .= ' frm_hidden';
120 }
121
122 if ( self::has_dark_background( $style ) ) {
123 $params['class'] .= ' frm-dark-style';
124 }
125
126 /**
127 * Filter params so Pro can add additional params, like data-delete-url.
128 *
129 * @since 6.0
130 *
131 * @param array $params
132 * @param array $args {
133 *
134 * @type WP_Post $style
135 * }
136 */
137 return apply_filters( 'frm_style_card_params', $params, compact( 'style' ) );
138 }
139
140 /**
141 * @param stdClass|WP_Post $style
142 *
143 * @return bool
144 */
145 private static function has_dark_background( $style ) {
146 $key = 'fieldset_bg_color';
147
148 if ( empty( $style->post_content[ $key ] ) ) {
149 return false;
150 }
151
152 $color = $style->post_content[ $key ];
153
154 if ( 0 === strpos( $color, 'rgba' ) ) {
155 preg_match_all( '/([\\d.]+)/', $color, $matches );
156
157 if ( isset( $matches[1][3] ) && is_numeric( $matches[1][3] ) ) {
158 // Consider a faded out rgba value as light even when the color is dark.
159 $color_opacity = floatval( $matches[1][3] );
160
161 if ( $color_opacity < 0.5 ) {
162 return false;
163 }
164 }
165 }
166
167 $brightness = FrmStylesHelper::get_color_brightness( $color );
168 return $brightness < 155;
169 }
170
171 /**
172 * @since 6.0
173 *
174 * @param array $style {
175 * API style data.
176 *
177 * @type array $settings
178 * @type string $name
179 * @type string $slug
180 * }
181 *
182 * @param bool $hidden
183 *
184 * @return bool True if the template was valid and echoed.
185 */
186 private function echo_card_template( $style, $hidden = false ) {
187 if ( empty( $style['settings'] ) || ! is_array( $style['settings'] ) ) {
188 return false;
189 }
190
191 // Use a better name than my sample form.
192 $style_object = new stdClass();
193 $style_object->ID = 0;
194 $style_object->post_title = $style['name'];
195 $style_object->post_content = $style['settings'];
196
197 // An unlocked template uses a static "frm_style_template" in Pro.
198 // A locked template however uses a slug to match the sandbox CSS.
199 $style_object->post_name = isset( $style['url'] ) ? 'frm_style_template' : $style['slug'];
200
201 $this->locked = empty( $style['url'] );
202
203 if ( $this->locked ) {
204 /**
205 * Set up a locked style card for the upgrade modal.
206 *
207 * @param array $params
208 * @param array $args {
209 *
210 * @type stdClass|WP_Post $style
211 * }
212 *
213 * @param stdClass $style_object
214 * @param array $style
215 */
216 $param_filter = function ( $params, $args ) use ( $style_object, $style ) {
217 if ( $args['style'] !== $style_object ) {
218 return $params;
219 }
220
221 $params['class'] .= ' frm-locked-style';
222 $params['data-upgrade-url'] = FrmAppHelper::admin_upgrade_link(
223 array(
224 'content' => 'upgrade',
225 'medium' => 'styler-card',
226 ),
227 '/style-templates/' . $style['slug']
228 );
229 $params['data-requires'] = FrmFormsHelper::get_plan_required( $style );
230 return $params;
231 };
232 } else {
233 /**
234 * Include the template key for the preview in Pro.
235 *
236 * @param array $params
237 * @param array $style
238 *
239 * @return array
240 */
241 $param_filter = function ( $params ) use ( $style ) {
242 $params['data-template-key'] = $style['slug'];
243 return $params;
244 };
245 }//end if
246
247 $this->is_new_template = ! empty( $style['is_new'] );
248
249 add_filter( 'frm_style_card_params', $param_filter, 10, $this->locked ? 2 : 1 );
250
251 $this->echo_style_card( $style_object, $hidden );
252 return true;
253 }
254
255 /**
256 * Get the string to populate the style card's style attribute with.
257 * This is used to reset some style variables like font size, label padding, and field height, so the cards all look more similar in comparison.
258 * It's kept static as it only requires a $style as input and also gets called when resetting a style.
259 *
260 * @since 6.0
261 *
262 * @param stdClass|WP_Post $style A new style (including duplicated styles) is not a WP_Post object.
263 * Template cards also use an stdClss instead of a WP_Post object.
264 *
265 * @return string
266 */
267 public static function get_style_param_for_card( $style ) {
268 $styles = array();
269
270 // Add the background color setting for fieldsets to the card.
271 if ( empty( $style->post_content['fieldset_bg_color'] ) ) {
272 $background_color = '#fff';
273 } else {
274 $background_color = ( 0 === strpos( $style->post_content['fieldset_bg_color'], 'rgb' ) ? $style->post_content['fieldset_bg_color'] : '#' . $style->post_content['fieldset_bg_color'] );
275 }
276 $styles[] = '--preview-background-color: ' . $background_color;
277
278 if ( empty( $style->post_content['submit_border_color'] ) ) {
279 $style->post_content['submit_border_color'] = 'transparent';
280 }
281
282 // Apply additional styles from the style.
283 $rules_to_apply = self::get_style_keys_for_card();
284
285 $frm_style = new FrmStyle();
286 $color_settings = $frm_style->get_color_settings();
287
288 foreach ( $rules_to_apply as $key ) {
289 if ( ! array_key_exists( $key, $style->post_content ) ) {
290 // A template from the API may not include every style key. If something is missing, skip it.
291 continue;
292 }
293
294 $value = $style->post_content[ $key ];
295
296 $is_hex = in_array( $key, $color_settings, true ) && $value && '#' !== $value[0] && false === strpos( $value, 'rgb' ) && $value !== 'transparent';
297
298 if ( $is_hex ) {
299 $value = '#' . $value;
300 }
301
302 $styles[] = '--' . str_replace( '_', '-', $key ) . ':' . $value;
303 }
304
305 return implode( ';', $styles );
306 }
307
308 /**
309 * Get the keys we want to use from the style to use in the card.
310 * We don't use every style as we want the cards to look consistent, so size settings are left out.
311 * The card previews also only include a labelled text input and submit button so we don't need styles for other elements.
312 *
313 * @since 6.0
314 *
315 * @return array<string>
316 */
317 private static function get_style_keys_for_card() {
318 return array(
319 'field_border_width',
320 'field_border_style',
321 'border_color',
322 'border_radius',
323 'submit_bg_color',
324 'submit_border_color',
325 'submit_border_width',
326 'submit_border_radius',
327 'submit_text_color',
328 'label_color',
329 'text_color',
330 'bg_color',
331 );
332 }
333
334 /**
335 * Echo a card wrapper and its children style cards.
336 *
337 * @since 6.0
338 *
339 * @param string $id The ID of the card wrapper element.
340 * @param array $styles
341 *
342 * @return void
343 */
344 public function echo_card_wrapper( $id, $styles ) {
345 $wrapper_style = $this->get_style_attribute_value_for_wrapper();
346
347 // Begin card wrapper
348 $card_wrapper_params = array(
349 'id' => $id,
350 'class' => 'frm-style-card-wrapper with_frm_style',
351 'style' => $wrapper_style,
352 );
353
354 if ( $this->enabled ) {
355 $card_wrapper_params['class'] .= ' frm-styles-enabled';
356 }
357
358 $first_style = reset( $styles );
359 $is_template_wrapper = is_array( $first_style );
360 ?>
361 <div <?php FrmAppHelper::array_to_html_params( $card_wrapper_params, true ); ?>>
362 <?php
363 if ( $is_template_wrapper ) {
364 $this->echo_template_cards( $styles );
365 } else {
366 $this->echo_custom_cards( $styles );
367 }
368 ?>
369 </div>
370 <?php
371 }
372
373 /**
374 * Overwrite some styles. We want to make sure the sizes are normalized for the cards.
375 * The cards use some rules from the default style because of the with_frm_style class on the card wrapper.
376 * As these can be customized, apply some default values for the card previews instead.
377 * This is used in the card wrapper so it doesn't need to get added to each card.
378 *
379 * @since 6.0
380 *
381 * @return string
382 */
383 private function get_style_attribute_value_for_wrapper() {
384 $frm_style = new FrmStyle();
385 $defaults = $frm_style->get_defaults();
386
387 $styles = array();
388 $styles[] = '--field-font-size: ' . $defaults['field_font_size'];
389 $styles[] = '--field-height: ' . $defaults['field_height'];
390 $styles[] = '--field-pad: ' . $defaults['field_pad'];
391 $styles[] = '--font-size: ' . $defaults['font_size'];
392 $styles[] = '--label-padding: ' . $defaults['label_padding'];
393 $styles[] = '--form-align: ' . $defaults['form_align'];
394
395 return implode( ';', $styles );
396 }
397
398 /**
399 * @since 6.0
400 *
401 * @param array<array> $styles
402 *
403 * @return void
404 */
405 private function echo_template_cards( $styles ) {
406 array_walk(
407 $styles,
408 /**
409 * Echo a style card for a single template from API data.
410 *
411 * @param array|string $style
412 * @param string $key The key for the API data. It may be a numeric ID, or a key like "active_sub" or "expires".
413 * @param int $count Used for pagination.
414 *
415 * @return void
416 */
417 function ( $style, $key ) {
418 if ( ! is_numeric( $key ) ) {
419 // Skip active_sub/expires keys.
420 return;
421 }
422
423 $this->echo_card_template( $style );
424 }
425 );
426 }
427
428 /**
429 * @param array<WP_Post> $styles
430 *
431 * @return void
432 */
433 private function echo_custom_cards( $styles ) {
434 $count = 0;
435 $this->locked = false;
436 array_walk(
437 $styles,
438 /**
439 * Echo a style card for a single style in the $styles array.
440 *
441 * @param WP_Post $style
442 * @param int $count Used for pagination.
443 *
444 * @return void
445 */
446 function ( $style ) use ( &$count ) {
447 $hidden = $count > self::PAGE_SIZE - 1;
448 $this->echo_style_card( $style, $hidden );
449 ++$count;
450 }
451 );
452
453 $this->maybe_echo_card_pagination( $count );
454 }
455
456 /**
457 * @since 6.0
458 *
459 * @param int $count
460 *
461 * @return void
462 */
463 private function maybe_echo_card_pagination( $count ) {
464 if ( $count <= self::PAGE_SIZE ) {
465 // Not enough cards to require pagination.
466 return;
467 }
468 ?>
469 <div class="frm-style-card-pagination frm_wrap">
470 <a href="#" class="frm-show-all-styles">
471 <?php
472 printf(
473 /* translators: %d: The number of styles */
474 esc_html__( 'Show all (%d)', 'formidable' ),
475 esc_html( $count - self::PAGE_SIZE )
476 );
477 ?>
478 </a>
479 </div>
480 <?php
481 }
482
483 /**
484 * @since 6.0
485 *
486 * @return array
487 */
488 public function get_styles() {
489 if ( is_callable( 'FrmProStylesController::get_styles_for_styler' ) ) {
490 return FrmProStylesController::get_styles_for_styler( $this->active_style );
491 }
492 return array( $this->default_style );
493 }
494
495 /**
496 * Remove the default style from an array of styles.
497 *
498 * @param array $styles
499 *
500 * @return array
501 */
502 public function filter_custom_styles( $styles ) {
503 return array_filter(
504 $styles,
505 /**
506 * @param WP_Post $style
507 *
508 * @return bool
509 */
510 function ( $style ) {
511 return $this->default_style->ID !== $style->ID;
512 }
513 );
514 }
515
516 /**
517 * @return array
518 */
519 public function get_template_info() {
520 $style_api = new FrmStyleApi();
521 return $style_api->get_api_info();
522 }
523 }
524