PluginProbe
The Innovative Form Builder – IvyForms / 1.5
The Innovative Form Builder – IvyForms v1.5
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 / GravityFormsImportConverter.php

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

302 lines 9.7 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 * Convert a Gravity Forms JSON export into the IvyForms import payload structure.
7 */
8 class GravityFormsImportConverter
9 {
10 /**
11 * Gravity Forms field types that have IvyForms equivalents.
12 *
13 * CAPTCHA maps to reCAPTCHA because Gravity's math/simple/Google widgets
14 * have no matching IvyForms UI; the native security field is used instead.
15 *
16 * @var array<string, string>
17 */
18 private const TYPE_MAP = [
19 'text' => 'text',
20 'username' => 'text',
21 'textarea' => 'textarea',
22 'email' => 'email',
23 'number' => 'number',
24 'select' => 'select',
25 'multiselect' => 'multi-select',
26 'radio' => 'radio',
27 'multi_choice' => 'radio',
28 'image_choice' => 'radio',
29 'checkbox' => 'checkbox',
30 'consent' => 'gdpr',
31 'phone' => 'phone',
32 'website' => 'website',
33 'date' => 'date',
34 'time' => 'time',
35 'fileupload' => 'file-upload',
36 'html' => 'html',
37 'captcha' => 'recaptcha',
38 'section' => 'section',
39 'product' => 'product',
40 'quantity' => 'quantity',
41 'total' => 'total',
42 ];
43
44 /**
45 * Convert one or more exported Gravity Forms forms.
46 *
47 * @param array<string|int, mixed> $rawData
48 * @return array<string, mixed>
49 */
50 public static function convert(array $rawData): array
51 {
52 $forms = [];
53 foreach (self::normalizeToList($rawData) as $formRaw) {
54 if (is_array($formRaw)) {
55 $forms[] = self::convertSingleForm($formRaw);
56 }
57 }
58
59 return ['forms' => $forms];
60 }
61
62 /**
63 * @param array<string|int, mixed> $rawData
64 * @return array<int, mixed>
65 */
66 private static function normalizeToList(array $rawData): array
67 {
68 if (isset($rawData['title'])) {
69 return [$rawData];
70 }
71
72 unset($rawData['version']);
73
74 return array_values($rawData);
75 }
76
77 /**
78 * @param array<string, mixed> $formRaw
79 * @return array<string, mixed>
80 */
81 private static function convertSingleForm(array $formRaw): array
82 {
83 $description = sanitize_textarea_field((string) ($formRaw['description'] ?? ''));
84
85 return [
86 'form' => [
87 'name' => sanitize_text_field((string) ($formRaw['title'] ?? '')),
88 'description' => $description,
89 'published' => true,
90 'showTitle' => true,
91 'showDescription' => ($description !== ''),
92 'storeEntries' => true,
93 'formActionButtons' => [
94 'submitButtonSettings' => [
95 'label' => GravityFormsSubmitLabelMapper::extract($formRaw),
96 'position' => 'default',
97 ],
98 ],
99 ],
100 'fields' => self::extractFields($formRaw),
101 'notifications' => [],
102 'confirmation' => self::extractConfirmation($formRaw),
103 ];
104 }
105
106 /**
107 * @param array<string, mixed> $formRaw
108 * @return array<int, array<string, mixed>>
109 */
110 private static function extractFields(array $formRaw): array
111 {
112 $context = ['id' => 1, 'fieldIndex' => 1, 'position' => 1, 'rowIndex' => 0];
113 $fields = [];
114
115 foreach (($formRaw['fields'] ?? []) as $rawField) {
116 if (!is_array($rawField)) {
117 continue;
118 }
119
120 if (($rawField['type'] ?? '') === 'name') {
121 GravityFormsNameFieldMapper::append($rawField, $fields, $context);
122 continue;
123 }
124 if (($rawField['type'] ?? '') === 'address') {
125 GravityFormsAddressFieldMapper::append($rawField, $fields, $context);
126 continue;
127 }
128
129 $field = self::convertField($rawField, $context);
130 if ($field !== null) {
131 $fields[] = $field;
132 }
133 }
134
135 return $fields;
136 }
137
138 /**
139 * @param array<string, mixed> $rawField
140 * @param array<string, int> $context
141 * @return array<string, mixed>|null
142 */
143 private static function convertField(array $rawField, array &$context): ?array
144 {
145 $gravityType = (string) ($rawField['type'] ?? '');
146 $ivyType = self::TYPE_MAP[$gravityType] ?? null;
147 if ($ivyType === null) {
148 return null;
149 }
150 $ivyType = GravityFormsFieldSettingsMapper::resolveType($gravityType, $ivyType, $rawField);
151
152 $htmlContent = $ivyType === 'html'
153 ? wp_kses_post((string) ($rawField['content'] ?? ''))
154 : '';
155 if ($ivyType === 'html' && $htmlContent === '') {
156 return null;
157 }
158
159 $field = self::buildFieldBase($rawField, $ivyType, $context);
160 if ($ivyType === 'html') {
161 $field['htmlContent'] = $htmlContent;
162 }
163
164 $field['confirmFieldEnabled'] = !empty($rawField['emailConfirmEnabled']);
165
166 $options = self::extractOptions($rawField);
167 if (!empty($options)) {
168 $field['fieldOptions'] = $options;
169 }
170 GravityFormsFieldSettingsMapper::apply($field, $rawField, $gravityType, $ivyType, $options);
171
172 return $field;
173 }
174
175 /**
176 * @param array<string, mixed> $rawField
177 * @param string $ivyType
178 * @param array<string, int> $context
179 * @return array<string, mixed>
180 */
181 private static function buildFieldBase(array $rawField, string $ivyType, array &$context): array
182 {
183 $defaultValue = $rawField['defaultValue'] ?? '';
184
185 return [
186 'id' => $context['id']++,
187 'fieldIndex' => $context['fieldIndex']++,
188 'type' => $ivyType,
189 'label' => sanitize_text_field((string) ($rawField['label'] ?? '')),
190 'placeholder' => sanitize_text_field((string) ($rawField['placeholder'] ?? '')),
191 'description' => sanitize_text_field((string) ($rawField['description'] ?? '')),
192 'required' => !empty($rawField['isRequired']),
193 'requiredMessage' => sanitize_text_field((string) ($rawField['errorMessage'] ?? '')),
194 'defaultValue' => is_scalar($defaultValue) ? sanitize_text_field((string) $defaultValue) : '',
195 'hideLabel' => (($rawField['labelPlacement'] ?? '') === 'hidden_label'),
196 'parentId' => null,
197 'position' => $context['position']++,
198 'rowIndex' => $context['rowIndex']++,
199 'columnIndex' => 0,
200 'width' => 100,
201 ];
202 }
203
204 /**
205 * @param array<string, mixed> $rawField
206 * @return array<int, array<string, mixed>>
207 */
208 private static function extractOptions(array $rawField): array
209 {
210 $rawOptions = $rawField['choices'] ?? [];
211 if (!is_array($rawOptions)) {
212 return [];
213 }
214
215 $options = [];
216 foreach ($rawOptions as $rawOption) {
217 if (!is_array($rawOption)) {
218 continue;
219 }
220
221 $label = sanitize_text_field((string) ($rawOption['text'] ?? ''));
222 $value = sanitize_text_field((string) ($rawOption['value'] ?? $label));
223 if ($label === '' && $value === '') {
224 continue;
225 }
226
227 $position = count($options) + 1;
228 $options[] = [
229 'id' => $position,
230 'label' => $label !== '' ? $label : $value,
231 'value' => $value !== '' ? $value : $label,
232 'isDefault' => !empty($rawOption['isSelected']),
233 'position' => $position,
234 ];
235 }
236
237 return $options;
238 }
239
240 /**
241 * @param array<string, mixed> $formRaw
242 * @return array<string, mixed>
243 */
244 private static function extractConfirmation(array $formRaw): array
245 {
246 $confirmations = $formRaw['confirmations'] ?? [];
247 if (!is_array($confirmations)) {
248 return [];
249 }
250
251 $confirmation = GravityFormsFieldSettingsMapper::findDefaultConfirmation($confirmations);
252 if ($confirmation === null) {
253 return [];
254 }
255
256 $type = (string) ($confirmation['type'] ?? 'message');
257 if ($type === 'redirect' && !empty($confirmation['url'])) {
258 return self::redirectConfirmation(
259 'redirectToCustomUrl',
260 'url',
261 esc_url_raw((string) $confirmation['url'])
262 );
263 }
264
265 if ($type === 'page' && !empty($confirmation['pageId'])) {
266 return self::redirectConfirmation('redirectToPage', 'page', (string) $confirmation['pageId']);
267 }
268
269 $message = (string) ($confirmation['message'] ?? '');
270
271 return $message === '' ? [] : [
272 'type' => 'successMessage',
273 'enabled' => true,
274 'showForm' => false,
275 'message' => wp_kses_post($message),
276 'url' => '',
277 'page' => '',
278 ];
279 }
280
281 /**
282 * @param string $type
283 * @param string $targetKey
284 * @param string $targetValue
285 * @return array<string, mixed>
286 */
287 private static function redirectConfirmation(string $type, string $targetKey, string $targetValue): array
288 {
289 return array_merge(
290 [
291 'type' => $type,
292 'enabled' => true,
293 'showForm' => false,
294 'message' => '',
295 'url' => '',
296 'page' => '',
297 ],
298 [$targetKey => $targetValue]
299 );
300 }
301 }
302