PluginProbe
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management / 1.1.0
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management v1.1.0
1.6.0 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 / donation-amount-markup.php

donation-amount-markup.php in SureDonation – Donation Forms, Fundraising Campaigns & Donor Management 1.1.0, at inc/fields/donation-amount-markup.php

296 lines 11.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * SureDonation Donation Amount Markup Class.
4 *
5 * @package SureDonation
6 * @since 0.0.1
7 */
8
9 namespace SureDonation\Inc\Fields;
10
11 use SureDonation\Inc\Helper;
12 use SureDonation\Inc\Payments\Payment_Helper;
13
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit; // Exit if accessed directly.
16 }
17
18 /**
19 * Donation Amount Markup Class.
20 *
21 * @since 0.0.1
22 */
23 class Donation_Amount_Markup extends Base {
24 /**
25 * Choice type (radio or checkbox).
26 *
27 * @var string
28 * @since 0.0.1
29 */
30 protected $choice_type;
31
32 /**
33 * Layout (horizontal or vertical).
34 *
35 * @var string
36 * @since 0.0.1
37 */
38 protected $layout;
39
40 /**
41 * Choice width (width of each option in horizontal layout).
42 *
43 * @var string
44 * @since 0.0.1
45 */
46 protected $choice_width;
47
48 /**
49 * Whether the optional custom amount input is shown after the presets.
50 *
51 * @var bool
52 * @since 1.0.0
53 */
54 protected $allow_custom_amount;
55
56 /**
57 * Minimum allowed value for the custom amount input. 0 means no min.
58 *
59 * @var float
60 * @since 1.0.0
61 */
62 protected $custom_amount_min;
63
64 /**
65 * Maximum allowed value for the custom amount input. 0 means no max.
66 *
67 * @var float
68 * @since 1.0.0
69 */
70 protected $custom_amount_max;
71
72 /**
73 * Initialize the properties based on block attributes.
74 *
75 * @param array<string, mixed> $attributes Block attributes.
76 * @since 0.0.1
77 */
78 public function __construct( $attributes ) {
79 $this->slug = 'donation-amount';
80 $this->choice_type = isset( $attributes['choiceType'] ) ? Helper::get_string_value( $attributes['choiceType'] ) : 'radio';
81 $this->layout = isset( $attributes['layout'] ) ? Helper::get_string_value( $attributes['layout'] ) : 'horizontal';
82 $this->choice_width = isset( $attributes['choiceWidth'] ) ? Helper::get_string_value( $attributes['choiceWidth'] ) : '50';
83 $this->allow_custom_amount = ! isset( $attributes['allowCustomAmount'] ) || (bool) $attributes['allowCustomAmount'];
84 $this->custom_amount_min = isset( $attributes['customAmountMin'] ) && is_numeric( $attributes['customAmountMin'] )
85 ? (float) $attributes['customAmountMin']
86 : 0.0;
87 $this->custom_amount_max = isset( $attributes['customAmountMax'] ) && is_numeric( $attributes['customAmountMax'] )
88 ? (float) $attributes['customAmountMax']
89 : 0.0;
90
91 $this->set_properties( $attributes );
92 $this->set_unique_slug();
93 $this->set_markup_properties();
94 }
95
96 /**
97 * Render donation-amount markup
98 *
99 * @since 0.0.1
100 * @return string
101 */
102 public function markup() {
103 $classes = $this->get_field_classes( [ 'sd-' . $this->choice_type . '-mode' ] );
104 $vertical_class = 'vertical' === $this->layout ? ' sd-vertical-layout' : '';
105 $choice_width_class = ' sd-choice-width-' . str_replace( '.', '-', $this->choice_width );
106 $wrap_class = 'sd-block-wrap sd-donation-amount-wrap' . $choice_width_class . $vertical_class;
107 $svg_type = 'radio' === $this->choice_type ? 'circle' : 'square';
108 $checked_svg = $this->get_svg_icon( $svg_type . '-checked', 'sd-donation-amount-icon' );
109 $unchecked_svg = $this->get_svg_icon( $svg_type . '-unchecked', 'sd-donation-amount-icon-unchecked' );
110 $input_name = 'checkbox' === $this->choice_type ? $this->field_name . '[]' : $this->field_name;
111
112 // Get the default value for the hidden input (preselected option).
113 $hidden_value = '';
114 if ( ! empty( $this->default ) && ! empty( $this->options ) && is_array( $this->options ) ) {
115 foreach ( $this->options as $option ) {
116 $option_value = $option['value'] ?? ( $option['label'] ?? '' );
117 if ( $this->default === $option_value ) {
118 $hidden_value = $option_value;
119 break;
120 }
121 }
122 }
123
124 ob_start();
125 ?>
126 <div data-block-id="<?php echo esc_attr( $this->block_id ); ?>" class="<?php echo esc_attr( $classes ); ?>">
127 <fieldset>
128 <!-- Hidden input to store the selected value for use by payment block and form submission -->
129 <input
130 type="hidden"
131 class="sd-input-donation-amount-hidden sd-input-common"
132 name="<?php echo esc_attr( $this->field_name ); ?>-value"
133 data-slug="<?php echo esc_attr( $this->block_slug ? $this->block_slug : $this->unique_slug ); ?>"
134 data-required="<?php echo esc_attr( $this->data_require_attr ); ?>"
135 value="<?php echo esc_attr( $hidden_value ); ?>"
136 />
137 <legend class="sd-block-legend">
138 <?php echo wp_kses_post( $this->label_markup ); ?>
139 </legend>
140 <?php echo wp_kses_post( $this->help_markup ); ?>
141 <?php
142 $show_custom_amount = $this->allow_custom_amount && 'radio' === $this->choice_type;
143 ?>
144 <?php if ( ! empty( $this->options ) && is_array( $this->options ) ) { ?>
145 <div class="<?php echo esc_attr( $wrap_class ); ?>" role="group" aria-labelledby="sd-label-<?php echo esc_attr( $this->block_id ); ?>">
146 <?php foreach ( $this->options as $index => $option ) { ?>
147 <?php
148 $option_label = $option['label'] ?? '';
149 $option_value = $option['value'] ?? $option_label;
150 $option_id = $this->unique_slug . '-' . $index;
151 $is_checked = $this->default === $option_value;
152 $checked_attr = $is_checked ? 'checked' : '';
153 ?>
154 <div class="sd-donation-amount-single">
155 <input
156 type="<?php echo esc_attr( $this->choice_type ); ?>"
157 id="<?php echo esc_attr( $option_id ); ?>"
158 name="<?php echo esc_attr( $input_name ); ?>"
159 value="<?php echo esc_attr( $option_value ); ?>"
160 class="sd-input-<?php echo esc_attr( $this->choice_type ); ?>"
161 data-required="<?php echo esc_attr( $this->data_require_attr ); ?>"
162 <?php echo esc_attr( $checked_attr ); ?>
163 />
164 <div class="sd-block-content-wrap">
165 <div class="sd-option-container">
166 <label for="<?php echo esc_attr( $option_id ); ?>"><?php echo esc_html( $this->format_option_label( $option_label ) ); ?></label>
167 </div>
168 <div class="sd-icon-container">
169 <?php
170 $allowed_svg = [
171 'svg' => [
172 'class' => true,
173 'width' => true,
174 'height' => true,
175 'viewbox' => true,
176 'fill' => true,
177 'xmlns' => true,
178 'aria-hidden' => true,
179 ],
180 'circle' => [
181 'cx' => true,
182 'cy' => true,
183 'r' => true,
184 'stroke' => true,
185 'stroke-width' => true,
186 'fill' => true,
187 ],
188 'rect' => [
189 'x' => true,
190 'y' => true,
191 'width' => true,
192 'height' => true,
193 'rx' => true,
194 'stroke' => true,
195 'stroke-width' => true,
196 ],
197 'path' => [
198 'd' => true,
199 'stroke' => true,
200 'stroke-width' => true,
201 'stroke-linecap' => true,
202 'stroke-linejoin' => true,
203 ],
204 ];
205 echo wp_kses( $checked_svg, $allowed_svg );
206 echo wp_kses( $unchecked_svg, $allowed_svg );
207 ?>
208 </div>
209 </div>
210 </div>
211 <?php } ?>
212 <?php if ( $show_custom_amount ) { ?>
213 <div class="sd-donation-amount-single sd-donation-amount-custom">
214 <input
215 type="number"
216 id="sd-custom-amount-<?php echo esc_attr( $this->block_id ); ?>"
217 class="sd-input-common sd-donation-amount-custom-input"
218 data-slug="<?php echo esc_attr( $this->block_slug ? $this->block_slug : $this->unique_slug ); ?>"
219 step="0.01"
220 <?php if ( $this->custom_amount_min > 0 ) { ?>
221 min="<?php echo esc_attr( (string) $this->custom_amount_min ); ?>"
222 <?php } ?>
223 <?php if ( $this->custom_amount_max > 0 ) { ?>
224 max="<?php echo esc_attr( (string) $this->custom_amount_max ); ?>"
225 <?php } ?>
226 placeholder="<?php esc_attr_e( 'Enter custom amount', 'suredonation' ); ?>"
227 aria-label="<?php esc_attr_e( 'Enter custom amount', 'suredonation' ); ?>"
228 />
229 </div>
230 <?php } ?>
231 </div>
232 <?php } ?>
233 <div class="sd-error-wrap"><?php echo wp_kses_post( $this->error_msg_markup ); ?></div>
234 </fieldset>
235 </div>
236 <?php
237 return (string) ob_get_clean();
238 }
239
240 /**
241 * Get SVG icon for radio/checkbox
242 *
243 * @param string $type Icon type (circle-checked, circle-unchecked, square-checked, square-unchecked).
244 * @param string $classes CSS class.
245 * @return string SVG markup.
246 * @since 0.0.1
247 */
248 private function get_svg_icon( $type, $classes = '' ) {
249 $class_attr = $classes ? ' class="' . esc_attr( $classes ) . '"' : '';
250
251 switch ( $type ) {
252 case 'circle-checked':
253 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">
254 <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"/>
255 <path d="M15.1667 2.6665L8.5 9.33984L6.5 7.33984" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
256 </svg>';
257 case 'circle-unchecked':
258 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">
259 <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"/>
260 </svg>';
261 case 'square-checked':
262 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">
263 <path d="M6.5 7.33366L8.5 9.33366L15.1667 2.66699" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
264 <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"/>
265 </svg>';
266 case 'square-unchecked':
267 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">
268 <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"/>
269 </svg>';
270 default:
271 return '';
272 }
273 }
274
275 /**
276 * Format an option label — if the label is purely numeric, prepend the
277 * configured currency symbol. Custom (non-numeric) labels render as-is.
278 *
279 * @param string $label Raw option label.
280 * @return string Display label.
281 * @since 1.0.0
282 */
283 private function format_option_label( $label ) {
284 $trimmed = trim( $label );
285
286 if ( '' === $trimmed || ! is_numeric( $trimmed ) ) {
287 return $label;
288 }
289
290 $currency = Payment_Helper::get_global_setting( 'currency', 'USD' );
291 $symbol = Payment_Helper::get_currency_symbol( is_string( $currency ) ? $currency : 'USD' );
292
293 return $symbol . $trimmed;
294 }
295 }
296