PluginProbe
The Innovative Form Builder – IvyForms / 1.5.1
The Innovative Form Builder – IvyForms v1.5.1
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / backend / src / Common / Helpers / Import / WsFormOptionsExtractor.php

WsFormOptionsExtractor.php in The Innovative Form Builder – IvyForms 1.5.1, at backend/src/Common/Helpers/Import/WsFormOptionsExtractor.php

211 lines 6.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace IvyForms\Common\Helpers\Import;
4
5 /**
6 * Extract IvyForms field options from WS Form data grids.
7 *
8 * Splitting option extraction out of WsFormImportConverter keeps each class
9 * focused and within complexity limits.
10 */
11 class WsFormOptionsExtractor
12 {
13 /**
14 * Extract field options from a WS Form data grid stored in field meta.
15 *
16 * @param array<string, mixed> $meta
17 * @param string $wsType
18 * @return array<int, array<string, mixed>>
19 */
20 public static function extract(array $meta, string $wsType): array
21 {
22 $grid = $meta['data_grid_' . $wsType] ?? null;
23 if (!is_array($grid)) {
24 return [];
25 }
26
27 $columns = is_array($grid['columns'] ?? null) ? $grid['columns'] : [];
28 [$valueIndex, $labelIndex] = self::resolveColumnIndexes($columns);
29
30 $options = [];
31 foreach (self::collectGridRows($grid) as $row) {
32 $option = self::buildOption($row, $valueIndex, $labelIndex, count($options) + 1);
33 if ($option !== null) {
34 $options[] = $option;
35 }
36 }
37
38 return $options;
39 }
40
41 /**
42 * Extract consent agreement text when a checkbox is a single required option.
43 *
44 * WS Form has no GDPR field type; consent is modelled as a checkbox with one
45 * required row. Returns null when the grid does not match that shape so the
46 * field stays a regular checkbox.
47 *
48 * @param array<string, mixed> $meta
49 * @return string|null
50 */
51 public static function extractConsentText(array $meta): ?string
52 {
53 $grid = $meta['data_grid_checkbox'] ?? null;
54 if (!is_array($grid)) {
55 return null;
56 }
57
58 $rows = self::collectGridRows($grid);
59 $columns = is_array($grid['columns'] ?? null) ? $grid['columns'] : [];
60 [, $labelIndex] = self::resolveColumnIndexes($columns);
61 $consentRows = [];
62
63 foreach ($rows as $row) {
64 $label = self::extractConsentLabel($row, $labelIndex);
65 if ($label !== '') {
66 $consentRows[] = ['row' => $row, 'label' => $label];
67 }
68 }
69
70 if (count($consentRows) !== 1) {
71 return null;
72 }
73
74 $row = $consentRows[0]['row'];
75 $fieldRequired = self::isEnabled($meta['required'] ?? false);
76 $rowRequired = self::isEnabled($row['required'] ?? false);
77 if (!$fieldRequired && !$rowRequired) {
78 return null;
79 }
80
81 return $consentRows[0]['label'];
82 }
83
84 /**
85 * Extract sanitized consent copy from a WS Form grid row.
86 *
87 * @param array<string, mixed> $row
88 * @param int $labelIndex
89 * @return string
90 */
91 private static function extractConsentLabel(array $row, int $labelIndex): string
92 {
93 $rowData = is_array($row['data'] ?? null) ? $row['data'] : [];
94 $label = (string) ($rowData[$labelIndex] ?? $rowData[0] ?? '');
95
96 return wp_kses_post(self::expandWsFormTokens($label));
97 }
98
99 /**
100 * Normalize WS Form toggle values from saved metadata and JSON exports.
101 *
102 * @param mixed $value
103 * @return bool
104 */
105 private static function isEnabled($value): bool
106 {
107 return in_array($value, [true, 1, '1', 'on', 'true'], true);
108 }
109
110 /**
111 * Expand common WS Form tokens that appear in consent copy.
112 *
113 * @param string $text
114 * @return string
115 */
116 private static function expandWsFormTokens(string $text): string
117 {
118 return str_replace(
119 ['#blog_name', '#blog_admin_email'],
120 [get_bloginfo('name'), get_bloginfo('admin_email')],
121 $text
122 );
123 }
124
125 /**
126 * Flatten all rows across every group of a WS Form data grid.
127 *
128 * @param array<string, mixed> $grid
129 * @return array<int, array<string, mixed>>
130 */
131 private static function collectGridRows(array $grid): array
132 {
133 $rows = [];
134 foreach (($grid['groups'] ?? []) as $optionGroup) {
135 if (!is_array($optionGroup)) {
136 continue;
137 }
138 foreach (($optionGroup['rows'] ?? []) as $row) {
139 if (is_array($row)) {
140 $rows[] = $row;
141 }
142 }
143 }
144
145 return $rows;
146 }
147
148 /**
149 * Build a single option array from a WS Form data grid row.
150 *
151 * @param array<string, mixed> $row
152 * @param int|null $valueIndex
153 * @param int $labelIndex
154 * @param int $position
155 * @return array<string, mixed>|null
156 */
157 private static function buildOption(array $row, ?int $valueIndex, int $labelIndex, int $position): ?array
158 {
159 $rowData = is_array($row['data'] ?? null) ? $row['data'] : [];
160 if (empty($rowData)) {
161 return null;
162 }
163
164 $label = sanitize_text_field((string) ($rowData[$labelIndex] ?? $rowData[0] ?? ''));
165 $value = $label;
166 if ($valueIndex !== null && isset($rowData[$valueIndex])) {
167 $value = sanitize_text_field((string) $rowData[$valueIndex]);
168 }
169
170 if ($label === '' && $value === '') {
171 return null;
172 }
173
174 return [
175 'id' => $position,
176 'label' => $label !== '' ? $label : $value,
177 'value' => $value !== '' ? $value : $label,
178 'isDefault' => !empty($row['default']),
179 'position' => $position,
180 ];
181 }
182
183 /**
184 * Resolve the value/label column indexes for a WS Form data grid.
185 *
186 * @param array<int, mixed> $columns
187 * @return array{0: int|null, 1: int}
188 */
189 private static function resolveColumnIndexes(array $columns): array
190 {
191 $valueIndex = null;
192 $labelIndex = 0;
193
194 foreach ($columns as $index => $column) {
195 if (!is_array($column)) {
196 continue;
197 }
198 $columnId = isset($column['id']) ? (int) $column['id'] : (int) $index;
199 $columnLabel = strtolower((string) ($column['label'] ?? ''));
200 if ($columnLabel === 'value') {
201 $valueIndex = $columnId;
202 }
203 if ($columnLabel === 'label') {
204 $labelIndex = $columnId;
205 }
206 }
207
208 return [$valueIndex, $labelIndex];
209 }
210 }
211