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

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