PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.12
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.12
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.12, at classes/helpers/FrmStylesCardHelper.php

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