PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 1.10.2
Subscriptions for WooCommerce with Stripe Recurring Payments v1.10.2
2.0.0 1.11.2 1.11.1 1.11.0 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.6 1.9.5 trunk 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 All 61 releases
subscription / includes / Admin / SettingsHelper.php

SettingsHelper.php in Subscriptions for WooCommerce with Stripe Recurring Payments 1.10.2, at includes/Admin/SettingsHelper.php

537 lines 16.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Settings Helper File
4 *
5 * @package SpringDevs\Subscription\Admin
6 */
7
8 namespace SpringDevs\Subscription\Admin;
9
10 /**
11 * Settings Helper Class
12 *
13 * @package SpringDevs\Subscription\Admin
14 */
15 class SettingsHelper {
16 /**
17 * Singleton instance
18 *
19 * @var SettingsHelper|null
20 */
21 private static $instance = null;
22
23 /**
24 * Get singleton instance
25 *
26 * @return SettingsHelper
27 */
28 public static function get_instance() {
29 if ( null === self::$instance ) {
30 self::$instance = new self();
31 }
32 return self::$instance;
33 }
34
35 /**
36 * Initialize the class.
37 */
38 private function __construct() {
39 add_filter( 'process_subscrpt_settings_fields', [ $this, 'process_settings_fields' ], 100, 1 );
40 }
41
42 /**
43 * Process settings fields.
44 *
45 * @param array $fields Settings fields.
46 * @return array Processed settings fields.
47 */
48 public function process_settings_fields( $fields ) {
49 // Group settings fields.
50 $fields = $this->group_settings_fields( $fields );
51
52 // Sort fields by priority (groups & fields).
53 $fields = $this->sort_settings_fields( $fields );
54
55 return $fields;
56 }
57
58 /**
59 * Group settings fields.
60 *
61 * @param array $fields Settings fields.
62 * @return array Processed settings fields.
63 */
64 public function group_settings_fields( $fields ) {
65 $tmp_fields = [];
66 foreach ( $fields as $field ) {
67 $field_group = $field['group'] ?? 'main';
68
69 if ( $field['type'] === 'heading' ) {
70 $group_priority = $field['priority'] ?? 0;
71 $tmp_fields[ $field_group ]['priority'] = $group_priority;
72 $field['priority'] = -1;
73 }
74
75 $tmp_fields[ $field_group ]['fields'][] = $field;
76 }
77 return $tmp_fields;
78 }
79
80 /**
81 * Sort settings fields.
82 *
83 * @param array $fields Settings fields.
84 * @return array Processed settings fields.
85 */
86 public function sort_settings_fields( $fields ) {
87 // Sort groups by priority.
88 uasort(
89 $fields,
90 function ( $a, $b ) {
91 $priority_a = $a['priority'] ?? 0;
92 $priority_b = $b['priority'] ?? 0;
93 return $priority_a <=> $priority_b;
94 }
95 );
96
97 // Sort fields within each group by priority.
98 foreach ( $fields as $group_key => $group_data ) {
99 uasort(
100 $group_data['fields'],
101 function ( $a, $b ) {
102 $priority_a = $a['priority'] ?? 0;
103 $priority_b = $b['priority'] ?? 0;
104 return $priority_a <=> $priority_b;
105 }
106 );
107 $fields[ $group_key ]['fields'] = $group_data['fields'];
108 }
109 return $fields;
110 }
111
112 /**
113 * Render specified settings field.
114 *
115 * @param string $field Field type.
116 * @param array $args Field arguments.
117 * @param bool $should_print Whether to print the field or return as HTML string.
118 */
119 public static function render_settings_field( $field, $args, $should_print = true ) {
120 if ( empty( $field ) ) {
121 $field = 'input'; // Default field type.
122 subscrpt_write_debug_log( "[SettingsHelper] Field type not specified. Defaulting to 'input'." );
123 }
124
125 switch ( $field ) {
126 case 'heading':
127 return self::render_heading( $args, $should_print );
128 case 'switch':
129 case 'toggle':
130 return self::render_switch_field( $args, $should_print );
131 case 'select':
132 return self::render_select_field( $args, $should_print );
133 case 'multi_select':
134 return self::render_multiselect_field( $args, $should_print );
135 case 'join':
136 return self::render_joined_field( $args, $should_print );
137 case 'input':
138 default:
139 return self::render_input_field( $args, $should_print );
140 }
141 }
142
143
144 /**
145 * Text Element HTML.
146 *
147 * @param array $args Same as 'render_text_field'.
148 * @param bool $join_item Whether to return element for 'join' container or not.
149 */
150 public static function inp_element( $args = [], $join_item = false ) {
151 $id = $args['id'];
152 $value = $args['value'] ?? '';
153 $placeholder = $args['placeholder'] ?? '';
154 $type = $args['type'] ?? 'text';
155
156 $disabled_attr = isset( $args['disabled'] ) && $args['disabled'] ? 'disabled' : '';
157
158 $style_attr = '';
159 if ( isset( $args['style'] ) ) {
160 $style_attr = $args['style'];
161 }
162
163 $other_attrs_html = '';
164 foreach ( ( $args['attributes'] ?? [] ) as $attr_key => $attr_value ) {
165 $other_attrs_html .= sprintf( ' %s="%s" ', esc_attr( $attr_key ), esc_attr( $attr_value ) );
166 }
167
168 ob_start();
169 ?>
170 <input
171 id="<?php echo esc_attr( $id ); ?>"
172 name="<?php echo esc_attr( $id ); ?>"
173 class="wpsubs-input"
174 <?php
175 if ( $style_attr ) :
176 ?>
177 style="<?php echo esc_attr( $style_attr ); ?>"<?php endif; ?>
178 type="<?php echo esc_attr( $type ); ?>"
179 placeholder="<?php echo esc_attr( $placeholder ); ?>"
180 value="<?php echo esc_attr( $value ); ?>"
181 <?php echo esc_attr( $disabled_attr ); ?>
182 <?php echo wp_kses_post( $other_attrs_html ); ?>
183 />
184 <?php
185 return ob_get_clean();
186 }
187
188 /**
189 * Select Element HTML.
190 *
191 * @param array $args Same as 'render_select_field'.
192 * @param bool $join_item Whether to return element for 'join' container or not.
193 */
194 public static function select_element( $args = [], $join_item = false ) {
195 $id = $args['id'];
196
197 // Enhanced / multiselect → wpsubs-tag-select (pill input with filter).
198 if ( isset( $args['enhanced'] ) && $args['enhanced'] ) {
199 $multiple = isset( $args['attributes']['multiple'] ) && $args['attributes']['multiple'];
200 $adv_options = array();
201 foreach ( ( $args['options'] ?? [] ) as $opt_value => $opt_label ) {
202 $adv_options[] = array(
203 'value' => (string) $opt_value,
204 'label' => $opt_label,
205 );
206 }
207
208 ob_start();
209 wpsubs_render_tag_select(
210 array(
211 'name' => $id,
212 'value' => $args['selected'] ?? ( $multiple ? array() : '' ),
213 'options' => $adv_options,
214 'multiple' => $multiple,
215 )
216 );
217 return ob_get_clean();
218 }
219
220 // Regular select → wpsubs-adv-select (button-based custom dropdown).
221 $selected = (string) ( $args['selected'] ?? '' );
222 $adv_options = array();
223 foreach ( ( $args['options'] ?? [] ) as $opt_value => $opt_label ) {
224 $adv_options[] = array(
225 'value' => (string) $opt_value,
226 'label' => $opt_label,
227 'disabled' => isset( $args['disabled'] ) && ( is_array( $args['disabled'] )
228 ? in_array( $opt_value, $args['disabled'], true )
229 : $args['disabled'] === $opt_value ),
230 );
231 }
232
233 ob_start();
234 wpsubs_render_adv_select(
235 array(
236 'name' => $id,
237 'value' => $selected,
238 'options' => $adv_options,
239 'align' => 'left',
240 )
241 );
242 return ob_get_clean();
243 }
244
245 /**
246 * Render Field Heading.
247 *
248 * - Args:
249 * - title (string) - Field title.
250 * - description (string) - Field description (optional).
251 *
252 * @param array $args Field arguments.
253 * @param bool $should_print Whether to print the field or return as HTML string.
254 */
255 public static function render_heading( $args = [], $should_print = true ) {
256 $title = $args['title'] ?? '';
257 $description = $args['description'] ?? '';
258
259 ob_start();
260 ?>
261 <div class="wpsubs-settings-heading">
262 <h3 class="wpsubs-settings-heading__title"><?php echo esc_html( $title ); ?></h3>
263 <?php if ( ! empty( $description ) ) : ?>
264 <p class="wpsubs-settings-heading__desc"><?php echo wp_kses_post( $description ); ?></p>
265 <?php endif; ?>
266 </div>
267 <?php
268 $html_content = ob_get_clean();
269
270 // Output not escaped intentionally. Breaks the HTML structure when escaped.
271 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
272 return $should_print ? print( $html_content ) : $html_content;
273 }
274
275 /**
276 * Render Text field.
277 *
278 * - Args:
279 * - id (string) - Field ID.
280 * - title (string) - Field title.
281 * - description (string) - Field description (optional).
282 * - value (string) - Default value.
283 * - placeholder (string) - Default placeholder.
284 * - disabled (bool) - Disabled status.
285 * - type (string) - Input type [text, email, number, date, time, etc.].
286 *
287 * @param array $args Field arguments.
288 * @param bool $should_print Whether to print the field or return as HTML string.
289 */
290 public static function render_input_field( $args = [], $should_print = true ) {
291 $title = $args['title'] ?? '';
292 $description = $args['description'] ?? '';
293
294 // Return error if ID is not provided.
295 if ( empty( $args['id'] ?? '' ) ) {
296 $field_hint = empty( $title ) ? 'Error' : $title;
297 $no_id_msg = '<p><strong>' . $field_hint . ':</strong> ' . __( 'Field ID is required.', 'subscription' ) . '</p>';
298 return $should_print ? print wp_kses_post( $no_id_msg ) : $no_id_msg;
299 }
300
301 // Input HTML.
302 $text_el_html = self::inp_element( $args );
303
304 ob_start();
305 ?>
306 <div class="wpsubs-settings-field">
307 <div class="wpsubs-settings-field__label"><?php echo esc_html( $title ); ?></div>
308 <div class="wpsubs-settings-field__control">
309 <?php
310 // Output intentionally not escaped as element is already escaped during generation & re-escaping breaks the HTML structure.
311 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
312 echo $text_el_html;
313 ?>
314 <?php if ( ! empty( $description ) ) : ?>
315 <p class="wpsubs-settings-field__hint"><?php echo wp_kses_post( $description ); ?></p>
316 <?php endif; ?>
317 </div>
318 </div>
319 <?php
320 $html_content = ob_get_clean();
321
322 // Output not escaped intentionally. Breaks the HTML structure when escaped.
323 // All form elements inside $html_content are pre-escaped during generation (esc_attr, esc_html).
324 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
325 return $should_print ? print( $html_content ) : $html_content;
326 }
327
328 /**
329 * Render Switch field.
330 *
331 * - Args:
332 * - id (string) - Field ID.
333 * - title (string) - Field title.
334 * - label (string) - Checkbox label.
335 * - description (string) - Field description (optional).
336 * - value (string) - Checked value.
337 * - checked (bool) - Checked status.
338 * - disabled (bool) - Disabled status.
339 *
340 * @param array $args Field arguments.
341 * @param bool $should_print Whether to print the field or return as HTML string.
342 */
343 public static function render_switch_field( $args = [], $should_print = true ) {
344 $id = $args['id'];
345 $title = $args['title'] ?? '';
346 $label = $args['label'] ?? '';
347 $description = $args['description'] ?? '';
348 $value = $args['value'] ?? '0';
349
350 // Return error if ID is not provided.
351 if ( empty( $args['id'] ?? '' ) ) {
352 $field_hint = empty( $title ) ? 'Error' : $title;
353 $no_id_msg = '<p><strong>' . $field_hint . ':</strong> ' . __( 'Field ID is required.', 'subscription' ) . '</p>';
354 return $should_print ? print wp_kses_post( $no_id_msg ) : $no_id_msg;
355 }
356
357 $description_html = '';
358 if ( ! empty( $description ) ) {
359 $description_html = sprintf(
360 '<p class="wpsubs-settings-field__hint">%s</p>',
361 wp_kses_post( $description )
362 );
363 }
364
365 $style_attr = '';
366 if ( isset( $args['style'] ) ) {
367 $style_attr .= ' ' . $args['style'];
368 }
369
370 $other_attrs_html = '';
371 foreach ( ( $args['attributes'] ?? [] ) as $attr_key => $attr_value ) {
372 $other_attrs_html .= sprintf( ' %s="%s" ', esc_attr( $attr_key ), esc_attr( $attr_value ) );
373 }
374
375 $checked_attr = isset( $args['checked'] ) && (bool) $args['checked'] ? 'checked' : '';
376 $disabled_attr = isset( $args['disabled'] ) && (bool) $args['disabled'] ? 'disabled' : '';
377
378 ob_start();
379 ?>
380 <div class="wpsubs-settings-field">
381 <div class="wpsubs-settings-field__label"><?php echo esc_html( $title ); ?></div>
382 <div class="wpsubs-settings-field__control">
383 <label class="wpsubs-settings-toggle-label" for="<?php echo esc_attr( $id ); ?>">
384 <input
385 id="<?php echo esc_attr( $id ); ?>"
386 name="<?php echo esc_attr( $id ); ?>"
387 class="wpsubs-toggle"
388 type="checkbox"
389 value="<?php echo esc_attr( $value ); ?>"
390 <?php echo esc_attr( $checked_attr ); ?>
391 <?php echo esc_attr( $disabled_attr ); ?>
392 <?php
393 // Output intentionally not escaped as element is already escaped during generation & re-escaping breaks the HTML structure.
394 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
395 echo $other_attrs_html;
396 ?>
397 />
398 <span class="wpsubs-toggle-ui" aria-hidden="true"></span>
399 <?php if ( ! empty( $label ) ) : ?>
400 <span class="wpsubs-settings-toggle-label__text"><?php echo esc_html( $label ); ?></span>
401 <?php endif; ?>
402 </label>
403 <?php echo wp_kses_post( $description_html ); ?>
404 </div>
405 </div>
406 <?php
407 $html_content = ob_get_clean();
408
409 // Output not escaped intentionally. Breaks the HTML structure when escaped.
410 // All form elements inside $html_content are pre-escaped during generation (esc_attr, esc_html).
411 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
412 return $should_print ? print( $html_content ) : $html_content;
413 }
414
415 /**
416 * Render Select field.
417 *
418 * - Args:
419 * - id (string) - Field ID.
420 * - title (string) - Field title.
421 * - description (string) - Field description (optional).
422 * - options (array) - Field options [value => label].
423 * - selected (string) - Selected option value.
424 * - disabled (string|array) - Disabled option value(s).
425 *
426 * @param array $args Field arguments.
427 * @param bool $should_print Whether to print the field or return as HTML string.
428 */
429 public static function render_select_field( $args = [], $should_print = true ) {
430 $title = $args['title'] ?? '';
431 $description = $args['description'] ?? '';
432
433 // Return error if ID is not provided.
434 if ( empty( $args['id'] ?? '' ) ) {
435 $field_hint = empty( $title ) ? 'Error' : $title;
436 $no_id_msg = '<p><strong>' . $field_hint . ':</strong> ' . __( 'Field ID is required.', 'subscription' ) . '</p>';
437 return $should_print ? print wp_kses_post( $no_id_msg ) : $no_id_msg;
438 }
439
440 // Select HTML.
441 $select_el_html = self::select_element( $args );
442
443 ob_start();
444 ?>
445 <div class="wpsubs-settings-field">
446 <div class="wpsubs-settings-field__label"><?php echo esc_html( $title ); ?></div>
447 <div class="wpsubs-settings-field__control">
448 <?php
449 // Output intentionally not escaped as element is already escaped during generation & re-escaping breaks the HTML structure.
450 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
451 echo $select_el_html;
452 ?>
453 <?php if ( ! empty( $description ) ) : ?>
454 <p class="wpsubs-settings-field__hint"><?php echo wp_kses_post( $description ); ?></p>
455 <?php endif; ?>
456 </div>
457 </div>
458 <?php
459 $html_content = ob_get_clean();
460
461 // Output not escaped intentionally. Breaks the HTML structure when escaped.
462 // All form elements inside $html_content are pre-escaped during generation (esc_attr, esc_html).
463 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
464 return $should_print ? print( $html_content ) : $html_content;
465 }
466
467 /**
468 * Render Multiselect field.
469 * Just a wrapper over 'render_select_field' with multiple attribute.
470 *
471 * @param array $args Field arguments.
472 * @param bool $should_print Whether to print the field or return as HTML string.
473 */
474 public static function render_multiselect_field( $args = [], $should_print = true ) {
475 $default_multiselect_args = [
476 'attributes' => [
477 'multiple' => 'multiple',
478 ],
479 'enhanced' => true,
480 ];
481
482 $args = wp_parse_args( $args, $default_multiselect_args );
483
484 return self::render_select_field( $args, $should_print );
485 }
486
487 /**
488 * Render Joined field with multiple elements.
489 *
490 * - Args:
491 * - title (string) - Field title.
492 * - description (string) - Field description (optional).
493 * - vertical (bool) - Whether to show items vertically or not.
494 * - elements ([...string]) - Array of HTML elements to join.
495 *
496 * @param array $args Field arguments.
497 * @param bool $should_print Whether to print the field or return as HTML string.
498 */
499 public static function render_joined_field( $args = [], $should_print = true ) {
500 $title = $args['title'] ?? '';
501 $description = $args['description'] ?? '';
502
503 $vertical_style = ( $args['vertical'] ?? false ) ? 'flex-direction:column;' : '';
504
505 ob_start();
506 ?>
507 <div class="wpsubs-settings-field">
508 <div class="wpsubs-settings-field__label"><?php echo esc_html( $title ); ?></div>
509 <div class="wpsubs-settings-field__control">
510 <div class="wpsubs-input-group"
511 <?php
512 if ( $vertical_style ) :
513 ?>
514 style="<?php echo esc_attr( $vertical_style ); ?>"<?php endif; ?>>
515 <?php
516 foreach ( ( $args['elements'] ?? [] ) as $element_html ) {
517 // Output intentionally not escaped as element is already escaped during generation & re-escaping breaks the HTML structure.
518 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
519 echo $element_html;
520 }
521 ?>
522 </div>
523 <?php if ( ! empty( $description ) ) : ?>
524 <p class="wpsubs-settings-field__hint"><?php echo wp_kses_post( $description ); ?></p>
525 <?php endif; ?>
526 </div>
527 </div>
528 <?php
529 $html_content = ob_get_clean();
530
531 // Output not escaped intentionally. Breaks the HTML structure when escaped.
532 // All form elements inside $html_content are pre-escaped during generation (esc_attr, esc_html).
533 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
534 return $should_print ? print( $html_content ) : $html_content;
535 }
536 }
537