PluginProbe
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management / trunk
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management vtrunk
1.5.1 1.5.0 1.4.0 1.3.0 trunk 0.0.1 1.0.0 1.1.0 1.1.1 1.1.2 1.2.0
suredonation / inc / fields / base.php

base.php in SureDonation – Donation Forms, Fundraising Campaigns & Donor Management trunk, at inc/fields/base.php

502 lines 14.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Form Field Base Class.
4 *
5 * This file defines the base class for form field markup in the SureDonation package.
6 *
7 * @package SureDonation
8 * @since 0.0.1
9 */
10
11 namespace SureDonation\Inc\Fields;
12
13 use SureDonation\Inc\Helper;
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit; // Exit if accessed directly.
17 }
18
19 /**
20 * Field Base Class
21 *
22 * Defines the base class for form field markup generation.
23 *
24 * @since 0.0.1
25 */
26 class Base {
27 /**
28 * Stores the attributes of the block.
29 *
30 * @var array<string, mixed> $attributes Block attributes.
31 * @since 0.0.1
32 */
33 protected $attributes = [];
34
35 /**
36 * Flag indicating if the field is required.
37 *
38 * @var bool
39 * @since 0.0.1
40 */
41 protected $required = false;
42
43 /**
44 * Width of the field (percentage).
45 *
46 * @var string
47 * @since 0.0.1
48 */
49 protected $field_width = '';
50
51 /**
52 * Stores the label for the field.
53 *
54 * @var string $label Label used for the input field.
55 * @since 0.0.1
56 */
57 protected $label = '';
58
59 /**
60 * Stores the help text.
61 *
62 * @var string $help
63 * @since 0.0.1
64 */
65 protected $help = '';
66
67 /**
68 * Validation error message for the field.
69 *
70 * @var string $error_msg Input field validation error message.
71 * @since 0.0.1
72 */
73 protected $error_msg = '';
74
75 /**
76 * Unique identifier for the block.
77 *
78 * @var string $block_id Unique identifier representing the block.
79 * @since 0.0.1
80 */
81 protected $block_id = '';
82
83 /**
84 * Stores the ID of the form.
85 *
86 * @var string $form_id Form ID.
87 * @since 0.0.1
88 */
89 protected $form_id = '';
90
91 /**
92 * Stores the block slug.
93 *
94 * @var string
95 * @since 0.0.1
96 */
97 protected $block_slug = '';
98
99 /**
100 * Stores the slug type (e.g., 'input', 'email').
101 *
102 * @var string $slug slug value.
103 * @since 0.0.1
104 */
105 protected $slug = '';
106
107 /**
108 * Data-required attribute value.
109 *
110 * @var string $data_require_attr Value of the data-required attribute.
111 * @since 0.0.1
112 */
113 protected $data_require_attr = 'false';
114
115 /**
116 * CSS class for block width.
117 *
118 * @var string $block_width The CSS class for block width.
119 * @since 0.0.1
120 */
121 protected $block_width = '';
122
123 /**
124 * Stores custom class names.
125 *
126 * @var string $class_name The value of the class name attribute.
127 * @since 0.0.1
128 */
129 protected $class_name = '';
130
131 /**
132 * Stores the placeholder text.
133 *
134 * @var string $placeholder HTML field placeholder.
135 * @since 0.0.1
136 */
137 protected $placeholder = '';
138
139 /**
140 * Stores the HTML placeholder attribute.
141 *
142 * @var string $placeholder_attr HTML field placeholder attribute.
143 * @since 0.0.1
144 */
145 protected $placeholder_attr = '';
146
147 /**
148 * Default value for the field.
149 *
150 * @var string
151 * @since 0.0.1
152 */
153 protected $default = '';
154
155 /**
156 * HTML attribute string for the default value.
157 *
158 * @var string
159 * @since 0.0.1
160 */
161 protected $default_value_attr = '';
162
163 /**
164 * Unique slug combining slug and block ID.
165 *
166 * @var string
167 * @since 0.0.1
168 */
169 protected $unique_slug = '';
170
171 /**
172 * Stores the field name for form submission.
173 *
174 * @var string $field_name HTML field name.
175 * @since 0.0.1
176 */
177 protected $field_name = '';
178
179 /**
180 * Options for select/checkbox/radio fields.
181 *
182 * @var array<mixed>
183 * @since 0.0.1
184 */
185 protected $options = [];
186
187 /**
188 * Checked state for the field.
189 *
190 * @var string
191 * @since 0.0.1
192 */
193 protected $checked = '';
194
195 /**
196 * HTML attribute string for the checked state.
197 *
198 * @var string
199 * @since 0.0.1
200 */
201 protected $checked_attr = '';
202
203 /**
204 * Stores the help text markup.
205 *
206 * @var string
207 * @since 0.0.1
208 */
209 protected $help_markup = '';
210
211 /**
212 * Stores the error message markup.
213 *
214 * @var string
215 * @since 0.0.1
216 */
217 protected $error_msg_markup = '';
218
219 /**
220 * Stores the HTML label markup.
221 *
222 * @var string
223 * @since 0.0.1
224 */
225 protected $label_markup = '';
226
227 /**
228 * Render the field markup.
229 *
230 * @return string
231 * @since 0.0.1
232 */
233 public function markup() {
234 return '';
235 }
236
237 /**
238 * Get CSS classes for the field wrapper.
239 *
240 * @param array<string> $extra_classes Extra classes to be added.
241 * @since 0.0.1
242 * @return string
243 */
244 public function get_field_classes( $extra_classes = [] ) {
245 $common_classes = [
246 'sd-block-single',
247 'sd-block',
248 "sd-{$this->slug}-block",
249 "sd-{$this->slug}-{$this->block_id}-block",
250 $this->block_width,
251 $this->class_name,
252 ];
253
254 if ( $this->block_slug ) {
255 $common_classes[] = "sd-slug-{$this->block_slug}";
256 }
257
258 if ( ! empty( $extra_classes ) && is_array( $extra_classes ) ) {
259 $common_classes = array_merge( $common_classes, $extra_classes );
260 }
261
262 return Helper::join_strings( $common_classes );
263 }
264
265 /**
266 * Setter for the properties of class based on block attributes.
267 *
268 * @param array<string, mixed> $attributes Block attributes.
269 * @since 0.0.1
270 * @return void
271 */
272 protected function set_properties( $attributes ) {
273 $this->attributes = $attributes;
274 $this->required = ! empty( $attributes['required'] );
275 $this->field_width = isset( $attributes['fieldWidth'] ) ? Helper::get_string_value( $attributes['fieldWidth'] ) : '';
276 $this->label = isset( $attributes['label'] ) ? Helper::get_string_value( $attributes['label'] ) : '';
277 $this->help = isset( $attributes['help'] ) ? Helper::get_string_value( $attributes['help'] ) : '';
278 $this->error_msg = isset( $attributes['errorMsg'] ) ? Helper::get_string_value( $attributes['errorMsg'] ) : '';
279 $this->block_id = isset( $attributes['block_id'] ) ? Helper::get_string_value( $attributes['block_id'] ) : '';
280 $this->form_id = isset( $attributes['formId'] ) ? Helper::get_string_value( $attributes['formId'] ) : '';
281 $this->block_slug = isset( $attributes['slug'] ) ? Helper::get_string_value( $attributes['slug'] ) : '';
282 $this->placeholder = isset( $attributes['placeholder'] ) ? Helper::get_string_value( $attributes['placeholder'] ) : '';
283 $this->default = isset( $attributes['defaultValue'] ) ? Helper::get_string_value( $attributes['defaultValue'] ) : '';
284 $this->checked = isset( $attributes['checked'] ) ? Helper::get_string_value( $attributes['checked'] ) : '';
285 $this->options = isset( $attributes['options'] ) && is_array( $attributes['options'] ) ? $attributes['options'] : [];
286 $this->class_name = isset( $attributes['className'] ) && is_string( $attributes['className'] ) ? ' ' . $attributes['className'] : '';
287 $this->data_require_attr = $this->required ? 'true' : 'false';
288 $this->block_width = $this->field_width ? ' sd-block-width-' . str_replace( '.', '-', $this->field_width ) : '';
289 $this->placeholder_attr = '' !== $this->placeholder ? ' placeholder="' . esc_attr( $this->placeholder ) . '" ' : '';
290 $this->default_value_attr = '' !== $this->default ? ' value="' . esc_attr( $this->default ) . '" ' : '';
291 $this->checked_attr = $this->checked ? 'checked' : '';
292 }
293
294 /**
295 * Set the unique slug for the field.
296 *
297 * @since 0.0.1
298 * @return void
299 */
300 protected function set_unique_slug() {
301 $this->unique_slug = 'sd-' . $this->slug . '-' . $this->block_id;
302 $this->field_name = $this->unique_slug;
303 }
304
305 /**
306 * Set markup properties (label, help, error).
307 *
308 * @since 0.0.1
309 * @return void
310 */
311 protected function set_markup_properties() {
312 $this->label_markup = $this->generate_label_markup();
313 $this->help_markup = $this->generate_help_markup();
314 $this->error_msg_markup = $this->generate_error_markup();
315 }
316
317 /**
318 * Generate label markup.
319 *
320 * @since 0.0.1
321 * @return string
322 */
323 protected function generate_label_markup() {
324 if ( empty( $this->label ) ) {
325 return '';
326 }
327
328 $required_mark = $this->required ? '<span class="sd-required" aria-hidden="true">*</span>' : '';
329
330 return sprintf(
331 '<label for="%s" class="sd-label">%s%s</label>',
332 esc_attr( $this->unique_slug ),
333 esc_html( $this->label ),
334 $required_mark
335 );
336 }
337
338 /**
339 * Generate help text markup.
340 *
341 * @since 0.0.1
342 * @return string
343 */
344 protected function generate_help_markup() {
345 if ( empty( $this->help ) ) {
346 return '';
347 }
348
349 return sprintf(
350 '<p id="sd-help-%s" class="sd-help">%s</p>',
351 esc_attr( $this->block_id ),
352 esc_html( $this->help )
353 );
354 }
355
356 /**
357 * Generate error message markup.
358 *
359 * @since 0.0.1
360 * @return string
361 */
362 protected function generate_error_markup() {
363 $error_text = $this->error_msg ? $this->error_msg : $this->default_required_message();
364
365 return sprintf(
366 '<p id="sd-error-%s" class="sd-error" role="alert" style="display: none;">%s</p>',
367 esc_attr( $this->block_id ),
368 esc_html( $error_text )
369 );
370 }
371
372 /**
373 * Resolve the default required-field message for this field type.
374 *
375 * Mirrors the server-side resolution so the pre-rendered message matches
376 * what the server would return: the admin-configured global default (Global
377 * Settings → Form Validation) for the field type, falling back to a generic
378 * message for field types without a configurable default.
379 *
380 * @since 1.1.0
381 * @return string
382 */
383 protected function default_required_message() {
384 // Derive the key via the same helper the server uses, so the key is
385 // normalized identically (e.g. hyphenated field types) and the editor /
386 // markup / server never resolve different keys for the same field.
387 $message = \SureDonation\Inc\Field_Validation::get_validation_message(
388 \SureDonation\Inc\Field_Validation::required_message_key( 'suredonation/' . $this->slug )
389 );
390
391 return '' !== $message ? $message : __( 'This field is required.', 'suredonation' );
392 }
393
394 /**
395 * Get aria-describedby attribute value.
396 *
397 * @since 0.0.1
398 * @return string
399 */
400 protected function get_aria_describedby() {
401 $describedby = [];
402
403 if ( ! empty( $this->help ) ) {
404 $describedby[] = 'sd-help-' . $this->block_id;
405 }
406
407 $describedby[] = 'sd-error-' . $this->block_id;
408
409 return implode( ' ', $describedby );
410 }
411
412 /**
413 * Darken a hex color by a percentage.
414 *
415 * @param string $hex Hex color code.
416 * @param int $percent Percentage to darken (0-100).
417 * @return string Darkened hex color.
418 * @since 0.0.1
419 */
420 protected function darken_color( $hex, $percent = 15 ) {
421 $hex = ltrim( $hex, '#' );
422
423 if ( strlen( $hex ) === 3 ) {
424 $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
425 }
426
427 $r = hexdec( substr( $hex, 0, 2 ) );
428 $g = hexdec( substr( $hex, 2, 2 ) );
429 $b = hexdec( substr( $hex, 4, 2 ) );
430
431 $r = max( 0, $r - ( $r * $percent / 100 ) );
432 $g = max( 0, $g - ( $g * $percent / 100 ) );
433 $b = max( 0, $b - ( $b * $percent / 100 ) );
434
435 return sprintf( '#%02x%02x%02x', $r, $g, $b );
436 }
437
438 /**
439 * Lighten a hex color by a percentage.
440 *
441 * @param string $hex Hex color code.
442 * @param int $percent Percentage to lighten (0-100).
443 * @return string Lightened hex color.
444 * @since 0.0.1
445 */
446 protected function lighten_color( $hex, $percent = 90 ) {
447 $hex = ltrim( $hex, '#' );
448
449 if ( strlen( $hex ) === 3 ) {
450 $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
451 }
452
453 $r = hexdec( substr( $hex, 0, 2 ) );
454 $g = hexdec( substr( $hex, 2, 2 ) );
455 $b = hexdec( substr( $hex, 4, 2 ) );
456
457 $r = min( 255, $r + ( ( 255 - $r ) * $percent / 100 ) );
458 $g = min( 255, $g + ( ( 255 - $g ) * $percent / 100 ) );
459 $b = min( 255, $b + ( ( 255 - $b ) * $percent / 100 ) );
460
461 return sprintf( '#%02x%02x%02x', $r, $g, $b );
462 }
463
464 /**
465 * Get the checked/unchecked SVG icon for a radio or checkbox option.
466 *
467 * Shared by every field that renders the option-pill markup (the donation
468 * amount choices and the payment-type chooser), so the two cannot drift apart.
469 *
470 * @param string $type Icon type (circle-checked, circle-unchecked, square-checked, square-unchecked).
471 * @param string $classes CSS class.
472 * @return string SVG markup.
473 * @since 1.5.1
474 */
475 protected function get_svg_icon( $type, $classes = '' ) {
476 $class_attr = $classes ? ' class="' . esc_attr( $classes ) . '"' : '';
477
478 switch ( $type ) {
479 case 'circle-checked':
480 return '<svg' . $class_attr . ' width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
481 <path d="M15.1663 7.38674V8.00007C15.1655 9.43769 14.7 10.8365 13.8392 11.988C12.9785 13.1394 11.7685 13.9817 10.3899 14.3893C9.0113 14.797 7.53785 14.748 6.18932 14.2498C4.8408 13.7516 3.68944 12.8308 2.90698 11.6248C2.12452 10.4188 1.75287 8.99211 1.84746 7.55761C1.94205 6.12312 2.49781 4.75762 3.43186 3.66479C4.36591 2.57195 5.6282 1.81033 7.03047 1.4935C8.43274 1.17668 9.89985 1.32163 11.213 1.90674" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
482 <path d="M15.1667 2.6665L8.5 9.33984L6.5 7.33984" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
483 </svg>';
484 case 'circle-unchecked':
485 return '<svg' . $class_attr . ' width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
486 <path d="M7.99967 14.6668C11.6816 14.6668 14.6663 11.6821 14.6663 8.00016C14.6663 4.31826 11.6816 1.3335 7.99967 1.3335C4.31778 1.3335 1.33301 4.31826 1.33301 8.00016C1.33301 11.6821 4.31778 14.6668 7.99967 14.6668Z" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
487 </svg>';
488 case 'square-checked':
489 return '<svg' . $class_attr . ' width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
490 <path d="M6.5 7.33366L8.5 9.33366L15.1667 2.66699" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
491 <path d="M14.5 8V12.6667C14.5 13.0203 14.3595 13.3594 14.1095 13.6095C13.8594 13.8595 13.5203 14 13.1667 14H3.83333C3.47971 14 3.14057 13.8595 2.89052 13.6095C2.64048 13.3594 2.5 13.0203 2.5 12.6667V3.33333C2.5 2.97971 2.64048 2.64057 2.89052 2.39052C3.14057 2.14048 3.47971 2 3.83333 2H11.1667" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
492 </svg>';
493 case 'square-unchecked':
494 return '<svg' . $class_attr . ' width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
495 <path d="M12.6667 2H3.33333C2.59695 2 2 2.59695 2 3.33333V12.6667C2 13.403 2.59695 14 3.33333 14H12.6667C13.403 14 14 13.403 14 12.6667V3.33333C14 2.59695 13.403 2 12.6667 2Z" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
496 </svg>';
497 default:
498 return '';
499 }
500 }
501 }
502