PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.0
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.0
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
← All changes | back/Classes/FieldClass.php +483 -251 10.1.4 → 11.1.0 View file →
@@ -2,8 +2,9 @@
2 2
3 3 namespace AcyMailing\Classes;
4 4
5 5 use AcyMailing\Core\AcymClass;
6 +use AcyMailing\Helpers\SecurityHelper;
6 7
7 8 class FieldClass extends AcymClass
8 9 {
9 10 const LANGUAGE_FIELD_ID_KEY = 'language_field_id';
@@ -41,15 +42,17 @@
41 42 'total' => acym_loadResult($queryCount),
42 43 ];
43 44 }
44 45
45 - public function getFieldsByID($ids)
46 + public function getFieldsByID(array $ids): array
46 47 {
48 + if (empty($ids)) {
49 + return [];
50 + }
51 +
47 52 acym_arrayToInteger($ids);
48 - if (empty($ids)) return [];
49 - $query = 'SELECT * FROM #__acym_field WHERE `id` IN('.implode(',', $ids).') ORDER BY `ordering` ASC';
50 53
51 - return acym_loadObjectList($query);
54 + return acym_loadObjectList('SELECT * FROM #__acym_field WHERE `id` IN('.implode(',', $ids).') ORDER BY `ordering` ASC');
52 55 }
53 56
54 57 public function getFieldsByNameKey(array $nameKeys): array
55 58 {
@@ -61,12 +64,14 @@
61 64
62 65 return acym_loadObjectList('SELECT * FROM #__acym_field WHERE `namekey` IN('.implode(',', $nameKeys).') ORDER BY `ordering` ASC', 'id');
63 66 }
64 67
65 - public function getFieldsByType($types)
68 + public function getFieldsByType(array $types): array
66 69 {
67 - if (empty($types)) return [];
68 - if (!is_array($types)) $types = [$types];
70 + if (empty($types)) {
71 + return [];
72 + }
73 +
69 74 $types = array_map('acym_escapeDB', $types);
70 75 $query = 'SELECT * FROM #__acym_field WHERE `type` IN('.implode(',', $types).') ORDER BY `ordering` ASC';
71 76
72 77 return acym_loadObjectList($query);
@@ -71,21 +76,19 @@
71 76
72 77 return acym_loadObjectList($query);
73 78 }
74 79
75 - public function getOrdering()
80 + public function getOrdering(): int
76 81 {
77 - return acym_loadResult('SELECT COUNT(id) FROM #__acym_field');
82 + return (int)acym_loadResult('SELECT COUNT(*) FROM #__acym_field');
78 83 }
79 84
80 - public function getAllFieldsForUser()
85 + public function getAllFieldsForUser(): array
81 86 {
82 - $query = 'SELECT * FROM #__acym_field WHERE id NOT IN (1, 2) ORDER BY `ordering` ASC';
83 -
84 - return acym_loadObjectList($query, 'id');
87 + return acym_loadObjectList('SELECT * FROM #__acym_field WHERE id NOT IN (1, 2) ORDER BY `ordering` ASC', 'id');
85 88 }
86 89
87 - public function getAllFieldsForModuleFront()
90 + public function getAllFieldsForModuleFront(): array
88 91 {
89 92 return acym_loadObjectList(
90 93 'SELECT *
91 94 FROM #__acym_field
@@ -95,21 +98,19 @@
95 98 'id'
96 99 );
97 100 }
98 101
99 - public function getFieldsValueByUserId($userId)
102 + public function getFieldsValueByUserId(int $userId): array
100 103 {
101 - $query = 'SELECT * FROM #__acym_user_has_field WHERE user_id = '.intval($userId);
102 -
103 - return acym_loadObjectList($query, 'field_id');
104 + return acym_loadObjectList('SELECT * FROM #__acym_user_has_field WHERE user_id = '.intval($userId), 'field_id');
104 105 }
105 106
106 - public function getFieldsValueByFieldId($fieldId)
107 + public function getFieldsValueByFieldId(int $fieldId): array
107 108 {
108 109 return acym_loadObjectList('SELECT * FROM #__acym_user_has_field WHERE field_id = '.intval($fieldId));
109 110 }
110 111
111 - public function generateNamekey($name, $namekey = '')
112 + public function generateNamekey(string $name, string $namekey = ''): string
112 113 {
113 114 $fieldsNamekey = acym_loadResultArray('SELECT namekey FROM #__acym_field');
114 115 $columnsUser = acym_getColumns('user');
115 116 $namekeyForbidden = array_merge($fieldsNamekey, $columnsUser);
@@ -125,42 +126,51 @@
125 126
126 127 return $namekey;
127 128 }
128 129
129 - public function getValueFromDB($fieldDB)
130 + public function getValueFromDB(object $fieldDB): array
130 131 {
131 132 $query = 'SELECT '.acym_secureDBColumn($fieldDB->value).' AS value, '.acym_secureDBColumn($fieldDB->title).' AS title
132 133 FROM `'.acym_secureDBColumn($fieldDB->database).'`.`'.acym_secureDBColumn($fieldDB->table).'`';
133 - $query .= isset($fieldDB->where_value) && strlen($fieldDB->where_value) > 0 ? ' WHERE `'.acym_secureDBColumn($fieldDB->where).'` '.$fieldDB->where_sign.' '.acym_escapeDB(
134 - $fieldDB->where_value
135 - ) : '';
134 + if (isset($fieldDB->where_value) && strlen($fieldDB->where_value) > 0) {
135 + $allowedSigns = ['=', '!=', '>', '<', '>=', '<=', 'BEGINS', 'END', 'CONTAINS', 'NOTCONTAINS', 'LIKE', 'NOT LIKE', 'REGEXP', 'NOT REGEXP', 'IS NULL', 'IS NOT NULL'];
136 + $whereSign = in_array($fieldDB->where_sign ?? '', $allowedSigns, true) ? $fieldDB->where_sign : '=';
137 + $query .= ' WHERE `'.acym_secureDBColumn($fieldDB->where).'` '.$whereSign.' '.acym_escapeDB($fieldDB->where_value);
138 + }
136 139 if (!empty($fieldDB->order_by)) $query .= ' ORDER BY '.acym_secureDBColumn($fieldDB->order_by).' '.acym_secureDBColumn($fieldDB->sort_order);
137 140
138 141 return acym_loadObjectList($query);
139 142 }
140 143
141 - public function store($userID, $fields, $ajax = false)
144 + public function store(int $userID, array $fields, bool $ajax = false): void
142 145 {
143 - if (!empty($_FILES['customField'])) {
146 + $uploadedFileFields = [];
147 + $customField = acym_getVar('array', 'customField', [], 'FILES');
148 + if (!empty($customField['tmp_name'])) {
144 149 $uploadFolder = trim(acym_cleanPath(html_entity_decode(acym_getFilesFolder(true))), DS.' ').DS;
145 - $uploadPath = acym_cleanPath(ACYM_ROOT.$uploadFolder.'userfiles'.DS);
150 + $uploadPath = acym_cleanPath(ACYM_ROOT.$uploadFolder.'userfiles'.DS.$userID.DS);
151 + if (!file_exists($uploadPath)) {
152 + acym_createDir($uploadPath);
153 + }
146 154 $allowedExtensions = explode(',', $this->config->get('allowed_files'));
147 155
148 - foreach ($_FILES['customField']['tmp_name'] as $key => $value) {
156 + foreach ($customField['tmp_name'] as $key => $value) {
149 157 if (is_array($value) && isset($value[0])) $value = $value[0];
150 158 if (empty($value)) continue;
151 159
152 - $fileName = $_FILES['customField']['name'][$key];
160 + // Get the uploaded file name
161 + $fileName = $customField['name'][$key];
153 162 while (is_array($fileName) && isset($fileName[0])) {
154 163 $fileName = $fileName[0];
155 164 }
165 + $fileName = basename($fileName);
156 166
157 - if (!preg_match('#\.('.implode('|', $allowedExtensions).')$#Ui', $fileName)) {
167 + if (!acym_fileNameValid($fileName) || !preg_match('#\.('.implode('|', array_map('preg_quote', $allowedExtensions)).')$#i', $fileName)) {
158 168 $ext = substr($fileName, strrpos($fileName, '.') + 1);
159 169 if ($ajax) {
160 170 $this->errors[] = acym_translationSprintf(
161 171 'ACYM_ACCEPTED_TYPE',
162 - acym_escape($ext),
172 + esc_html($ext),
163 173 implode(', ', $allowedExtensions)
164 174 );
165 175 } else {
166 176 acym_enqueueMessage(
@@ -165,9 +175,9 @@
165 175 } else {
166 176 acym_enqueueMessage(
167 177 acym_translationSprintf(
168 178 'ACYM_ACCEPTED_TYPE',
169 - acym_escape($ext),
179 + esc_html($ext),
170 180 implode(', ', $allowedExtensions)
171 181 ),
172 182 'error',
173 183 5000
@@ -176,9 +186,9 @@
176 186
177 187 continue;
178 188 }
179 189
180 - if (!acym_uploadFile($value, $uploadPath.$fileName)) {
190 + if (!acym_isPathWithinDirectory($uploadPath, $uploadPath.$fileName) || !acym_uploadFile($value, $uploadPath.$fileName)) {
181 191 if ($ajax) {
182 192 $this->errors[] = acym_translation('ACYM_ERROR_SAVING');
183 193 } else {
184 194 acym_enqueueMessage(acym_translation('ACYM_ERROR_SAVING'), 'error');
@@ -185,9 +195,10 @@
185 195 }
186 196
187 197 continue;
188 198 }
189 - $fields[$key] = $_FILES['customField']['name'][$key];
199 + $fields[$key] = $fileName;
200 + $uploadedFileFields[$key] = true;
190 201 }
191 202 }
192 203
193 204 if (empty($fields)) return;
@@ -240,11 +251,43 @@
240 251 if (in_array($field->type, ['text', 'textarea']) && !empty($fieldOptions->max_characters)) {
241 252 $value = substr($value, 0, $fieldOptions->max_characters);
242 253 }
243 254
255 + // A file field value can only be set through an actual upload, never through a plain posted string
256 + if ($field->type === 'file' && strlen($value) !== 0 && empty($uploadedFileFields[$id])) {
257 + continue;
258 + }
259 +
260 + // If deleting a file field, also delete the physical file
261 + if ($field->type === 'file' && strlen($value) === 0) {
262 + $oldValue = acym_loadResult(
263 + 'SELECT `value` FROM #__acym_user_has_field WHERE `user_id` = '.intval($userID).' AND `field_id` = '.intval($id)
264 + );
265 + if (!empty($oldValue)) {
266 + $fileName = @json_decode($oldValue, true);
267 + if (is_array($fileName)) $fileName = $fileName[0];
268 + if (empty($fileName)) $fileName = $oldValue;
269 +
270 + $fileName = basename($fileName);
271 + if (acym_fileNameValid($fileName)) {
272 + $uploadFolder = trim(acym_cleanPath(html_entity_decode(acym_getFilesFolder(true))), DS.' ').DS;
273 + $userfilesBase = acym_cleanPath(ACYM_ROOT.$uploadFolder.'userfiles'.DS);
274 + // Try new path (with user folder) first, then legacy path (without user folder)
275 + $filePath = acym_cleanPath($userfilesBase.$userID.DS.$fileName);
276 + if (!file_exists($filePath)) {
277 + $filePath = acym_cleanPath($userfilesBase.$fileName);
278 + }
279 + if (acym_isPathWithinDirectory($userfilesBase, $filePath)) {
280 + acym_deleteFile($filePath);
281 + }
282 + }
283 + }
284 + }
285 +
286 + // The user removed a value, don't add an empty line and remove any previous value from the bd
244 287 if (strlen($value) === 0) {
245 - $query = 'DELETE FROM `#__acym_user_has_field`
246 - WHERE `user_id` = '.intval($userID).'
288 + $query = 'DELETE FROM `#__acym_user_has_field`
289 + WHERE `user_id` = '.intval($userID).'
247 290 AND `field_id` = '.intval($id);
248 291 } else {
249 292 $query = 'INSERT INTO #__acym_user_has_field (`user_id`, `field_id`, `value`) VALUES ('.intval($userID).', '.intval($id).', '.acym_escapeDB($value).')';
250 293 $query .= ' ON DUPLICATE KEY UPDATE `value`= VALUES(`value`)';
@@ -253,9 +296,9 @@
253 296 acym_query($query);
254 297 }
255 298 }
256 299
257 - public function getAllFieldsByUserIds($userIds)
300 + public function getAllFieldsByUserIds(array $userIds): array
258 301 {
259 302 acym_arrayToInteger($userIds);
260 303 if (empty($userIds)) return [];
261 304
@@ -265,10 +308,16 @@
265 308
266 309 return acym_loadObjectList($query);
267 310 }
268 311
269 - public function getAllFieldsListingByUserIds($userIds, $fieldIds, $listing = ''): array
312 + public function getAllFieldsListingByUserIds(array $userIds, array $fieldIds, string $listing = ''): array
270 313 {
314 + acym_arrayToInteger($userIds);
315 + if (empty($userIds)) return [];
316 +
317 + acym_arrayToInteger($fieldIds);
318 + if (empty($fieldIds)) return [];
319 +
271 320 $query = 'SELECT field.type AS `type`, field.value AS `value`, field.name AS field_name, user_field.user_id AS user_id, user_field.field_id AS field_id, user_field.value AS field_value, field.active, field.option
272 321 FROM #__acym_user_has_field AS user_field
273 322 JOIN #__acym_field AS field ON user_field.field_id = field.id';
274 323
@@ -273,18 +322,12 @@
273 322 JOIN #__acym_field AS field ON user_field.field_id = field.id';
274 323
275 324 $conditions = [];
276 325
277 - if (!empty($listing)) $conditions[] = $listing;
326 + if (!empty($listing)) {
327 + $conditions[] = $listing;
328 + }
278 329
279 - if (!is_array($userIds)) $userIds = [$userIds];
280 - acym_arrayToInteger($userIds);
281 - if (empty($userIds)) return [];
282 -
283 - if (!is_array($fieldIds)) $fieldIds = [$fieldIds];
284 - acym_arrayToInteger($fieldIds);
285 - if (empty($fieldIds)) return [];
286 -
287 330 $conditions[] = 'user_field.user_id IN ('.implode(',', $userIds).')';
288 331 $conditions[] = 'user_field.field_id IN ('.implode(',', $fieldIds).')';
289 332
290 333 if (!empty($conditions)) {
@@ -330,8 +373,9 @@
330 373 return !empty($fieldOption['value']) || !empty($fieldOption['title']);
331 374 });
332 375
333 376 if (empty($defaultValues)) {
377 + // Options from database
334 378 if (!empty($one->field_value)) {
335 379 $fieldOptions = json_decode($one->option, true);
336 380 if (!empty($fieldOptions['fieldDB'])) {
337 381 $dbOptions = json_decode($fieldOptions['fieldDB'], true);
@@ -343,8 +387,9 @@
343 387 }
344 388 }
345 389 }
346 390 } else {
391 + // Classic options
347 392 foreach ($defaultValues as $oneValue) {
348 393 if (!in_array($oneValue['value'], explode(',', $one->field_value))) continue;
349 394 $fieldValues[$key][] = $oneValue['title'];
350 395 }
@@ -358,9 +403,9 @@
358 403
359 404 return $fieldValues;
360 405 }
361 406
362 - public function getAllFieldsBackendListing()
407 + public function getAllFieldsBackendListing(): array
363 408 {
364 409 $whereLanguage = '(backend_listing = 1 OR `type` = "language")';
365 410 $query = 'SELECT id, name FROM #__acym_field WHERE '.$whereLanguage.' AND active = 1 AND id NOT IN (1, 2) ORDER BY ordering';
366 411
@@ -376,11 +421,11 @@
376 421
377 422 return $return;
378 423 }
379 424
380 - public function getAllFieldsFrontendListing()
425 + public function getAllFieldsFrontendListing(): array
381 426 {
382 - $query = 'SELECT id, name FROM #__acym_field WHERE frontend_listing = 1 AND active = 1 AND id NOT IN (1, 2)';
427 + $fields = acym_loadObjectList('SELECT id, name FROM #__acym_field WHERE frontend_listing = 1 AND active = 1 AND id NOT IN (1, 2)');
383 428
384 429 $return = [
385 430 'names' => [],
386 431 'ids' => [],
@@ -385,21 +430,20 @@
385 430 'names' => [],
386 431 'ids' => [],
387 432 ];
388 433
389 - foreach (acym_loadObjectList($query) as $one) {
390 - $return['names'][] = $one->name;
391 - $return['ids'][] = $one->id;
434 + foreach ($fields as $oneField) {
435 + $return['names'][] = $oneField->name;
436 + $return['ids'][] = $oneField->id;
392 437 }
393 438
394 439 return $return;
395 440 }
396 441
397 - public function delete($elements)
442 + public function delete(array $elements): int
398 443 {
399 444 if (empty($elements)) return 0;
400 445
401 - if (!is_array($elements)) $elements = [$elements];
402 446 acym_arrayToInteger($elements);
403 447
404 448 acym_trigger('specialActionOnDelete', ['field', $elements]);
405 449
@@ -407,39 +451,42 @@
407 451
408 452 return parent::delete($elements);
409 453 }
410 454
455 + /**
456 + * @param mixed $defaultValue
457 + */
411 458 public function displayField(
412 - $field,
459 + object $field,
413 460 $defaultValue,
414 - $size,
415 - $valuesArray,
416 - $displayOutside = true,
417 - $displayFront = false,
418 - $user = null,
419 - $display = 1,
420 - $displayIf = '',
421 - $userClasses = []
422 - ) {
423 - $allClasses = !empty($userClasses['all']) ? $userClasses['all'] : '';
424 - $textClasses = !empty($userClasses['text']) ? $userClasses['text'] : '';
425 - $emailClasses = !empty($userClasses['email']) ? $userClasses['email'] : '';
426 - $radioClasses = !empty($userClasses['radio']) ? $userClasses['radio'] : '';
427 - $checkboxClasses = !empty($userClasses['checkbox']) ? $userClasses['checkbox'] : '';
428 - $dateClasses = !empty($userClasses['date']) ? $userClasses['date'] : '';
429 - $phoneClasses = !empty($userClasses['phone']) ? $userClasses['phone'] : '';
430 - $multipleDropdownClasses = !empty($userClasses['multiple_dropdown']) ? $userClasses['multiple_dropdown'] : '';
461 + array $valuesArray,
462 + bool $displayOutside = true,
463 + bool $displayFront = false,
464 + ?object $user = null,
465 + bool $showField = true
466 + ): void {
467 + if (intval($field->active) === 0 && intval($field->core) !== 1) {
468 + return;
469 + }
431 470
432 471 $extraErrors = $this->config->get('extra_errors', '0');
433 472 $isCoreField = $field->core == 1;
434 473
435 - if (!$isCoreField && !acym_level(ACYM_ENTERPRISE)) return '';
474 + if (!$isCoreField && !acym_level(ACYM_ENTERPRISE)) {
475 + return;
476 + }
436 477
437 - if ($display == 0 && acym_isAdmin() && acym_level(ACYM_ENTERPRISE) && !$isCoreField) return '';
478 + if (!$showField) {
479 + if (!acym_isAdmin()) {
480 + return;
481 + }
438 482
439 - if ($display == 0 && !acym_isAdmin()) return '';
483 + if (acym_isAdmin() && acym_level(ACYM_ENTERPRISE) && !$isCoreField) {
484 + return;
485 + }
486 + }
440 487
441 - $return = '';
488 + $data = [];
442 489
443 490 $cmsUser = false;
444 491 if ($displayFront && !empty($user->id)) {
445 492 $cmsUser = !empty($user->cms_id);
@@ -475,8 +522,9 @@
475 522 }
476 523 $valuesArray = $valuesArrayTmp;
477 524 }
478 525
526 + // Translate text of the options
479 527 if (is_array($valuesArray)) {
480 528 foreach ($valuesArray as $key => $oneValue) {
481 529 if (is_object($oneValue) && !empty($valuesArray[$key]->text)) {
482 530 $valuesArray[$key]->text = acym_translation($valuesArray[$key]->text);
@@ -494,44 +542,78 @@
494 542 }
495 543
496 544 $field->name = acym_translation($field->name);
497 545
498 - if (empty((array)$field->option) || !isset($field->option->authorized_content)) {
499 - $authorizedContent = '';
500 - } else {
546 + if (!empty((array)$field->option) && isset($field->option->authorized_content)) {
501 547 if (empty($field->option->error_message_invalid)) {
502 548 $field->option->authorized_content->message = acym_translationSprintf('ACYM_INCORRECT_FIELD_VALUE', $field->name);
503 549 } else {
504 550 $field->option->authorized_content->message = $field->option->error_message_invalid;
505 551 }
506 - $authorizedContent = ' data-authorized-content="'.acym_escape($field->option->authorized_content, false).'"';
552 + $data['authorizedContent'] = json_encode($field->option->authorized_content);
507 553 }
508 554
509 555 $attributesSelectField = [];
510 - $maxCharacters = empty($field->option->max_characters) ? '' : ' maxlength="'.$field->option->max_characters.'"';
511 - $style = '';
512 - if (!empty($size)) {
513 - $attributesSelectField['style'] = $size;
514 - $style = ' style="'.$size.'"';
556 + if (!empty($field->option->max_characters)) {
557 + $data['maxCharacters'] = $field->option->max_characters;
515 558 }
559 + if (!empty($field->option->size)) {
560 + $attributesSelectField['style'] = 'width:'.$field->option->size.'px';
561 + $data['style'] = 'width:'.$field->option->size.'px';
562 + }
516 563
517 - $placeholder = '';
518 - if (!$displayOutside) $placeholder = ' placeholder="'.acym_escape($field->name).'"';
564 + if (!$displayOutside) {
565 + $data['placeholder'] = $field->name;
566 + }
519 567
520 568 $name = 'customField['.intval($field->id).']';
521 - $nameAttribute = ' name="'.$name.'"';
522 569 if ($field->type === 'text') {
523 - $value = ' value="'.acym_escape($defaultValue).'"';
570 + $data['value'] = empty($defaultValue)
571 + ? ''
572 + : (
573 + is_scalar($defaultValue)
574 + ? $defaultValue
575 + : json_encode($defaultValue)
576 + );
524 577 }
525 578
526 - if (($displayOutside && (in_array($field->id, [1, 2]) || in_array(
527 - $field->type,
528 - ['text', 'textarea', 'single_dropdown', 'multiple_dropdown', 'custom_text', 'file', 'language']
529 - )))) {
530 - $return .= '<label '.$displayIf.' class="cell margin-top-1"><span class="acym__users__creation__fields__title">'.$field->name.'</span>';
579 + $allowedFieldNameTags = array_merge(SecurityHelper::ALLOWED_HTML_FIELD_NAME, [
580 + 'a' => [
581 + 'href' => true,
582 + 'target' => true,
583 + 'title' => true,
584 + 'class' => true,
585 + 'rel' => true,
586 + 'aria-label' => true,
587 + ],
588 + ]);
589 +
590 + $labelTypes = ['text', 'textarea', 'single_dropdown', 'multiple_dropdown', 'custom_text', 'language'];
591 + $titleTypes = ['date', 'radio', 'checkbox', 'file'];
592 +
593 + $useLabel = $displayOutside && (in_array($field->id, [1, 2]) || in_array($field->type, $labelTypes));
594 + $useTitle = $displayOutside && in_array($field->type, $titleTypes);
595 +
596 + if ($useLabel) {
597 + echo '<label class="cell margin-top-1"><span class="acym__users__creation__fields__title">'.wp_kses(
598 + $field->name,
599 + SecurityHelper::ALLOWED_HTML_FIELD_NAME
600 + ).'</span>';
531 601 }
532 - if ($displayOutside && in_array($field->type, ['date', 'radio', 'checkbox'])) {
533 - $return .= '<div '.$displayIf.' class="cell margin-top-1"><div class="acym__users__creation__fields__title">'.$field->name.'</div>';
602 + if ($useTitle) {
603 + if (in_array($field->type, ['date', 'radio', 'checkbox'])) {
604 + $groupLabelId = 'acym__field__label__'.intval($field->id).'_'.acym_rand(1000, 9999);
605 + echo '<div class="cell margin-top-1" role="group" aria-labelledby="'.esc_attr($groupLabelId).'"'.($field->required ? ' aria-required="true"' : '').'>';
606 + echo '<div id="'.esc_attr($groupLabelId).'" class="acym__users__creation__fields__title">'.wp_kses(
607 + $field->name,
608 + $allowedFieldNameTags
609 + ).'</div>';
610 + } else {
611 + echo '<div class="cell margin-top-1"><div class="acym__users__creation__fields__title">'.wp_kses(
612 + $field->name,
613 + $allowedFieldNameTags
614 + ).'</div>';
615 + }
534 616 }
535 617
536 618 $messageRequired = empty($field->option->error_message) ? '' : acym_translation($field->option->error_message);
537 619 $requiredJson = json_encode(['type' => $field->type, 'message' => $messageRequired]);
@@ -536,91 +618,130 @@
536 618 $messageRequired = empty($field->option->error_message) ? '' : acym_translation($field->option->error_message);
537 619 $requiredJson = json_encode(['type' => $field->type, 'message' => $messageRequired]);
538 620 $required = '';
539 621 if ($field->required) {
540 - $required = ' data-required="'.acym_escape($requiredJson).'"';
622 + $data['data-required'] = $requiredJson;
623 + $data['aria-required'] = 'true';
624 + $required = ' data-required="'.esc_attr($requiredJson).'"';
541 625 $attributesSelectField['data-required'] = $requiredJson;
626 + $attributesSelectField['aria-required'] = 'true';
542 627 }
543 628
544 629 $readonly = '';
545 - if ($display == 0 && acym_isAdmin() && acym_level(ACYM_ENTERPRISE) && $isCoreField) {
630 + if (!$showField && acym_isAdmin() && acym_level(ACYM_ENTERPRISE) && $isCoreField) {
546 631 $attributesSelectField['disabled'] = true;
547 632 unset($attributesSelectField['data-required']);
548 633 $readonly = ' disabled ';
549 634 $required = '';
635 + $data['disabled'] = true;
636 + unset($data['data-required']);
550 637 }
551 638
639 + $defaultValue = $this->prepareDefaultValue($defaultValue, $field->type, $user);
640 +
552 641 if ($field->id == 1) {
553 - $nameAttribute = ' name="user[name]"';
554 - $inputTmp = '<input '.$nameAttribute.$placeholder.$required.$value.$authorizedContent.$style.$maxCharacters.$readonly.' type="text" class="cell '.$allClasses.' '.$textClasses.'"'.'>';
555 - if (!empty($readonly)) {
556 - $inputTmp = acym_tooltip(
642 + $data['type'] = 'text';
643 + $data['name'] = 'user[name]';
644 + $data['autocomplete'] = 'name';
645 + $data['class'] = 'cell';
646 +
647 + if (empty($readonly)) {
648 + include acym_getPartial('fields', 'input');
649 + } else {
650 + ob_start();
651 + include acym_getPartial('fields', 'input');
652 + $input = ob_get_clean();
653 +
654 + acym_tooltip(
557 655 [
558 - 'hoveredText' => $inputTmp,
656 + 'hoveredText' => $input,
559 657 'textShownInTooltip' => acym_translation('ACYM_CF_EDITION_BLOCKED'),
560 658 ]
561 659 );
562 660 }
563 - $return .= $inputTmp;
564 661 } elseif ($field->id == 2) {
565 - $nameAttribute = ' name="user[email]"';
566 - $uniqueId = 'email_field_'.rand(100, 900);
567 - $inputTmp = '<input id="'.$uniqueId.'" '.$nameAttribute.$placeholder.$value.$authorizedContent.$style.$maxCharacters.$readonly.' required type="email" class="cell acym__user__edit__email '.$allClasses.' '.$emailClasses.'"'.($displayFront && $cmsUser
568 - ? 'disabled' : '').'>';
569 - if (!empty($readonly)) {
570 - $inputTmp = acym_tooltip(
662 + $uniqueId = 'email_field_'.acym_rand(100, 900);
663 +
664 + unset($data['data-required']);
665 + $data['type'] = 'email';
666 + $data['name'] = 'user[email]';
667 + $data['autocomplete'] = 'email';
668 + $data['id'] = $uniqueId;
669 + $data['class'] = 'cell acym__user__edit__email';
670 + $data['required'] = true;
671 + $data['readonly'] = $cmsUser;
672 +
673 + if (empty($readonly)) {
674 + include acym_getPartial('fields', 'input');
675 + } else {
676 + ob_start();
677 + include acym_getPartial('fields', 'input');
678 + $input = ob_get_clean();
679 +
680 + acym_tooltip(
571 681 [
572 - 'hoveredText' => $inputTmp,
682 + 'hoveredText' => $input,
573 683 'textShownInTooltip' => acym_translation('ACYM_CF_EDITION_BLOCKED'),
574 684 ]
575 685 );
576 686 }
577 - $return .= $inputTmp;
687 +
578 688 if ($displayFront && !$cmsUser && !empty($this->config->get('email_spellcheck'))) {
579 - $return .= '<ul acym-data-field="'.$uniqueId.'" class="acym_email_suggestions" style="display: none;"></ul>';
689 + echo '<ul acym-data-field="'.esc_attr($uniqueId).'" class="acym_email_suggestions" style="display: none;"></ul>';
580 690 }
581 691 } elseif ($field->type === 'language') {
582 - if (empty($defaultValue) && !empty($user->language)) {
583 - $defaultValue = $user->language;
584 - }
585 -
586 - $attributesSelectField['class'] = 'acym__select '.$allClasses;
587 - if (!empty($userClasses['language'])) {
588 - $attributesSelectField['class'] .= ' '.$userClasses['language'];
589 - }
590 - $selectTmp = acym_select(
591 - $this->getLanguagesForDropdown(),
592 - 'user[language]',
593 - empty($defaultValue) ? acym_getLanguageTag() : $defaultValue,
594 - $attributesSelectField
595 - );
596 -
597 - if (!empty($readonly)) {
598 - $selectTmp = acym_tooltip(
692 + $attributesSelectField['class'] = 'acym__select';
693 + if (empty($readonly)) {
694 + acym_select(
695 + $this->getLanguagesForDropdown(),
696 + 'user[language]',
697 + $defaultValue,
698 + $attributesSelectField,
699 + 'value',
700 + 'text',
701 + null,
702 + false,
703 + true
704 + );
705 + } else {
706 + acym_tooltip(
599 707 [
600 - 'hoveredText' => $selectTmp,
708 + 'hoveredText' => acym_select(
709 + $this->getLanguagesForDropdown(),
710 + 'user[language]',
711 + $defaultValue,
712 + $attributesSelectField
713 + ),
601 714 'textShownInTooltip' => acym_translation('ACYM_CF_EDITION_BLOCKED'),
602 715 ]
603 716 );
604 717 }
605 - $return .= $selectTmp;
606 718 } elseif ($field->type === 'text') {
607 - $return .= '<input '.$nameAttribute.$placeholder.$required.$value.$authorizedContent.$style.$maxCharacters.' type="text">';
719 + $data['type'] = 'text';
720 + $data['name'] = $name;
721 + include acym_getPartial('fields', 'input');
608 722 } elseif ($field->type === 'textarea') {
609 - $return .= '<textarea '.$nameAttribute.$required.$maxCharacters.' rows="'.intval($field->option->rows).'" cols="'.intval(
610 - $field->option->columns
611 - ).'">'.(empty($defaultValue) ? '' : $defaultValue).'</textarea>';
723 + echo '<textarea name="'.esc_attr($name).'"';
724 + if (!empty($data['data-required'])) {
725 + echo ' data-required="'.esc_attr($data['data-required']).'"';
726 + }
727 + if (!empty($data['aria-required'])) {
728 + echo ' aria-required="true"';
729 + }
730 + if (isset($data['maxCharacters'])) {
731 + echo ' maxlength="'.esc_attr($data['maxCharacters']).'"';
732 + }
733 + echo ' rows="'.intval($field->option->rows).'" cols="'.intval($field->option->columns).'">';
734 + echo esc_html(is_scalar($defaultValue) ? $defaultValue : '');
735 + echo '</textarea>';
612 736 } elseif ($field->type === 'radio') {
613 - $defaultValue = strlen($defaultValue) === 0 ? null : $defaultValue;
614 737 if ($displayFront) {
615 - foreach ($valuesArray as $key => $oneValue) {
616 - $isCkecked = $defaultValue == $key ? 'checked' : '';
617 - $return .= '<label><input '.$nameAttribute.$required.' type="radio" value="'.acym_escape(
618 - $key
619 - ).'" '.$isCkecked.((!empty($allClasses) || !empty($radioClasses)) ? ' class="'.$allClasses.' '.$radioClasses.'"' : '').'> '.$oneValue.'</label>';
620 - }
738 + $data['name'] = $name;
739 + $data['values'] = $valuesArray;
740 + $data['value'] = $defaultValue;
741 + include acym_getPartial('fields', 'radio');
621 742 } else {
622 - $return .= acym_radio(
743 + acym_radio(
623 744 $valuesArray,
624 745 $name.'[]',
625 746 $defaultValue,
626 747 $field->required ? ['data-required' => $requiredJson] : []
@@ -626,129 +747,224 @@
626 747 $field->required ? ['data-required' => $requiredJson] : []
627 748 );
628 749 }
629 750 } elseif ($field->type === 'checkbox') {
630 - if ($displayFront) {
631 - $defaultValue = empty($defaultValue) ? null : (explode(',', $defaultValue));
632 - foreach ($valuesArray as $key => $oneValue) {
633 - $checked = !empty($defaultValue) && in_array($key, $defaultValue) ? 'checked' : '';
634 - $return .= '<label><input '.$required.' type="checkbox" name="'.$name.'['.acym_escape($key).']" value="'.acym_escape(
635 - $key
636 - ).'" '.$checked.((!empty($allClasses) || !empty($checkboxClasses)) ? ' class="'.$allClasses.' '.$checkboxClasses.'"' : '').'> '.$oneValue.'</label>';
637 - }
638 - } else {
639 - if (!empty($defaultValue) && !is_object($defaultValue)) {
640 - $defaultValue = explode(',', $defaultValue);
641 - $temporaryObject = new \stdClass();
642 - foreach ($defaultValue as $oneValue) {
643 - $temporaryObject->$oneValue = 'on';
644 - }
645 - $defaultValue = $temporaryObject;
646 - }
647 - $defaultValue = is_object($defaultValue) ? $defaultValue : new \stdClass();
648 - foreach ($valuesArray as $key => $oneValue) {
649 - if (empty($defaultValue->$key)) {
650 - $labelClass = 'class="cell margin-top-1"';
651 - $attributes = '';
652 - } else {
653 - $labelClass = '';
654 - $attributes = 'checked '.$required;
655 - }
656 - $return .= '<label '.$labelClass.'>';
657 - $return .= '<input '.$attributes.' type="checkbox" name="'.$name.'['.acym_escape(
658 - $key
659 - ).']" class="acym__users__creation__fields__checkbox">'.$oneValue.'</label>';
660 - }
661 - }
751 + $data['name'] = $name;
752 + $data['values'] = $valuesArray;
753 + $data['value'] = $defaultValue;
754 + $data['displayFront'] = $displayFront;
755 + include acym_getPartial('fields', 'checkbox');
662 756 } elseif ($field->type === 'single_dropdown') {
663 - $attributesSelectField['class'] = 'acym__custom__fields__select__form acym__select '.$allClasses;
664 - if (!empty($userClasses['single_dropdown'])) {
665 - $attributesSelectField['class'] .= ' '.$userClasses['single_dropdown'];
666 - }
667 - $return .= acym_select(
757 + $attributesSelectField['class'] = 'acym__custom__fields__select__form acym__select';
758 + acym_select(
668 759 $valuesArray,
669 760 $name,
670 - empty($defaultValue) ? '' : $defaultValue,
671 - $attributesSelectField
761 + $defaultValue,
762 + $attributesSelectField,
763 + 'value',
764 + 'text',
765 + null,
766 + false,
767 + true
672 768 );
673 769 } elseif ($field->type === 'multiple_dropdown') {
674 - $defaultValue = is_array($defaultValue) ? $defaultValue : explode(',', $defaultValue);
675 -
676 770 $attributes = [
677 - 'class' => 'acym__custom__fields__select__multiple__form acym__select '.$allClasses.' '.$multipleDropdownClasses,
678 - 'style' => $size,
771 + 'class' => 'acym__custom__fields__select__multiple__form acym__select',
772 + 'style' => empty($field->option->size) ? '' : 'width:'.$field->option->size.'px',
679 773 ];
680 - if ($field->required) $attributes['data-required'] = $displayFront ? acym_escape($requiredJson) : $requiredJson;
774 + if ($field->required) {
775 + $attributes['data-required'] = $displayFront ? esc_attr($requiredJson) : $requiredJson;
776 + $attributes['aria-required'] = 'true';
777 + }
681 778
682 - $return .= acym_selectMultiple($valuesArray, $name, empty($defaultValue) ? [] : $defaultValue, $attributes);
779 + acym_selectMultiple(
780 + $valuesArray,
781 + $name,
782 + $defaultValue,
783 + $attributes,
784 + 'value',
785 + 'text',
786 + true
787 + );
683 788 } elseif ($field->type === 'date') {
684 789 $attributes = [
685 - 'class' => 'acym__custom__fields__select__form acym__select '.$allClasses.' '.$dateClasses,
790 + 'class' => 'acym__custom__fields__select__form acym__select',
686 791 'acym-field-type' => 'date',
687 792 ];
688 793 if (!empty($required)) {
689 794 $attributes['data-required'] = $requiredJson;
690 795 }
691 - $return .= acym_displayDateFormat(
692 - $field->option->format,
693 - $name.'[]',
694 - $defaultValue,
695 - $attributes
796 +
797 + echo wp_kses(
798 + acym_displayDateFormat(
799 + $field->option->format,
800 + $name.'[]',
801 + $defaultValue,
802 + $attributes
803 + ),
804 + array_merge_recursive(
805 + SecurityHelper::ALLOWED_HTML_SELECT,
806 + [
807 + 'select' => [
808 + 'data-required' => true,
809 + 'acym-field-type' => true,
810 + 'aria-label' => true,
811 + ],
812 + 'div' => [
813 + 'class' => true,
814 + ],
815 + ]
816 + )
696 817 );
697 818 } elseif ($field->type === 'file') {
698 - $defaultValue = is_array($defaultValue) ? $defaultValue[0] : $defaultValue;
699 819 if ($displayFront) {
700 - $return .= '<input '.$nameAttribute.$required.' type="file">';
820 + unset($data['placeholder'], $data['value'], $data['authorizedContent'], $data['style'], $data['maxCharacters']);
821 + $data['type'] = 'file';
822 + $data['name'] = $name;
823 + include acym_getPartial('fields', 'input');
701 824 } else {
702 - $return .= acym_inputFile($name.'[]', $defaultValue, '', '', $required);
825 + $downloadUrl = '';
826 + if (!empty($defaultValue) && !empty($user->id)) {
827 + $fileName = is_array($defaultValue) ? $defaultValue[0] : $defaultValue;
828 + $fileName = basename($fileName);
829 + if (!empty($fileName) && acym_fileNameValid($fileName)) {
830 + $uploadFolder = trim(acym_cleanPath(html_entity_decode(acym_getFilesFolder(true))), DS.' ').DS;
831 + $userFilePath = $uploadFolder.'userfiles'.DS.$user->id.DS.$fileName;
832 + $legacyFilePath = $uploadFolder.'userfiles'.DS.$fileName;
833 +
834 + if (file_exists(acym_cleanPath(ACYM_ROOT.$userFilePath))) {
835 + $downloadUrl = ACYM_LIVE.str_replace(DS, '/', $userFilePath);
836 + } elseif (file_exists(acym_cleanPath(ACYM_ROOT.$legacyFilePath))) {
837 + $downloadUrl = ACYM_LIVE.str_replace(DS, '/', $legacyFilePath);
838 + }
839 + }
840 + }
841 + $attributes = [];
842 + if (!empty($required)) {
843 + $attributes['data-required'] = $requiredJson;
844 + }
845 + acym_inputFile($name.'[]', $defaultValue, '', $attributes, $downloadUrl);
703 846 }
704 847 } elseif ($field->type === 'phone') {
705 - $defaultValue = !empty($defaultValue) ? explode(',', $defaultValue) : '';
706 848 $indicator = !empty($defaultValue[0]) ? $defaultValue[0] : '';
707 849 $number = !empty($defaultValue[1]) ? $defaultValue[1] : '';
708 850
709 - if ($displayOutside) $return .= '<div '.$displayIf.' class="cell margin-top-1 grid-x"><div class="acym__users__creation__fields__title cell">'.$field->name.'</div>';
710 - $return .= '<div class="cell large-5 medium-4 padding-right-1">';
711 - $return .= acym_generateCountryNumber($name.'[code]', $indicator);
712 - $return .= '</div>';
713 - $return .= '<input '.$placeholder.$required.$style.$maxCharacters.' class="cell large-7 medium-8 '.$allClasses.' '.$phoneClasses.'"'.' type="tel" name="'.$name.'[phone]" value="'.acym_escape(
714 - $number
715 - ).'">';
716 - if ($displayOutside) $return .= '</div>';
851 + if ($displayOutside) {
852 + $phoneLabelId = 'acym__field__label__'.intval($field->id).'_'.acym_rand(1000, 9999);
853 + echo '<div class="cell margin-top-1 grid-x" role="group" aria-labelledby="'.esc_attr($phoneLabelId).'"'.($field->required ? ' aria-required="true"' : '').'>';
854 + echo '<div id="'.esc_attr($phoneLabelId).'" class="acym__users__creation__fields__title cell">'.wp_kses(
855 + $field->name,
856 + SecurityHelper::ALLOWED_HTML_FIELD_NAME
857 + ).'</div>';
858 + }
859 + echo '<div class="cell large-5 medium-4 padding-next-1">';
860 + acym_generateCountryNumber($name.'[code]', $indicator);
861 + echo '</div>';
862 +
863 + unset($data['authorizedContent']);
864 + $data['type'] = 'tel';
865 + $data['name'] = $name.'[phone]';
866 + $data['autocomplete'] = 'tel-national';
867 + $data['class'] = 'cell large-7 medium-8';
868 + $data['value'] = $number;
869 + if ($displayOutside) {
870 + $data['aria-label'] = acym_translation('ACYM_PHONE_NUMBER');
871 + }
872 + include acym_getPartial('fields', 'input');
873 +
874 + if ($displayOutside) {
875 + echo '</div>';
876 + }
717 877 } elseif ($field->type === 'custom_text') {
718 - $return .= $field->option->custom_text;
878 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Admin-defined custom HTML content, intentionally rendered as-is.
879 + echo $field->option->custom_text;
719 880 }
720 881
721 - $labelTypes = ['text', 'textarea', 'single_dropdown', 'multiple_dropdown', 'custom_text', 'file', 'language'];
722 - if ($displayOutside && (in_array($field->id, [1, 2]) || in_array($field->type, $labelTypes))) {
723 - $return .= '</label>';
882 + if ($useLabel) {
883 + echo '</label>';
724 884 }
725 - if ($displayOutside && in_array($field->type, ['date', 'radio', 'checkbox'])) {
726 - $return .= '</div>';
885 + if ($useTitle) {
886 + echo '</div>';
727 887 }
728 888
729 - $return .= '<div class="acym__field__error__block" data-acym-field-id="'.intval($field->id).'"></div>';
889 + echo '<div class="acym__field__error__block" data-acym-field-id="'.intval($field->id).'" aria-live="assertive"></div>';
730 890 if ($displayFront && $extraErrors && !acym_isAdmin()) {
731 - $return .= '<div class="acym__message__invalid__field acym__color__error" style="display: none;">';
732 - $return .= '<i class="acymicon-times-circle acym__cross__invalid acym__color__error"></i>'.acym_translation('ACYM_THANKS_TO_FILL_IN_THIS_FIELD').'</div>';
891 + echo '<div class="acym__message__invalid__field acym__color__error" style="display: none;">';
892 + echo '<i class="acymicon-times-circle acym__cross__invalid acym__color__error"></i>'.esc_html(acym_translation('ACYM_THANKS_TO_FILL_IN_THIS_FIELD')).'</div>';
733 893 }
894 + }
734 895
735 - return $return;
896 + /**
897 + * @param mixed $defaultValue
898 + *
899 + * @return mixed
900 + */
901 + private function prepareDefaultValue($defaultValue, string $fieldType, ?object $user)
902 + {
903 + if ($fieldType === 'language') {
904 + if (empty($defaultValue) && !empty($user->language)) {
905 + $defaultValue = $user->language;
906 + }
907 +
908 + return empty($defaultValue) ? acym_getLanguageTag() : $defaultValue;
909 + }
910 +
911 + if ($fieldType === 'phone') {
912 + return !empty($defaultValue) ? explode(',', $defaultValue) : '';
913 + }
914 +
915 + if ($fieldType === 'file') {
916 + return is_array($defaultValue) ? $defaultValue[0] : $defaultValue;
917 + }
918 +
919 + if (in_array($fieldType, ['single_dropdown', 'textarea'])) {
920 + return empty($defaultValue) ? '' : $defaultValue;
921 + }
922 +
923 + if ($fieldType === 'radio') {
924 + return strlen($defaultValue) === 0 ? null : $defaultValue;
925 + }
926 +
927 + if (in_array($fieldType, ['checkbox', 'multiple_dropdown'])) {
928 + if (empty($defaultValue)) {
929 + return [];
930 + }
931 +
932 + if (is_string($defaultValue)) {
933 + return explode(',', $defaultValue);
934 + }
935 +
936 + if (is_object($defaultValue)) {
937 + $defaultValues = [];
938 + foreach ($defaultValue as $oneKey => $oneValue) {
939 + if (!empty($oneValue)) {
940 + $defaultValues[] = $oneKey;
941 + }
942 + }
943 +
944 + return $defaultValues;
945 + }
946 +
947 + return is_array($defaultValue) ? $defaultValue : [];
948 + }
949 +
950 + return $defaultValue;
736 951 }
737 952
738 - public function getFieldTypeById($id)
953 + public function getFieldTypeById(int $id): string
739 954 {
740 - $query = 'SELECT type FROM #__acym_field WHERE id = '.intval($id);
741 -
742 - return acym_loadResult($query);
955 + return acym_loadResult('SELECT type FROM #__acym_field WHERE id = '.intval($id));
743 956 }
744 957
745 - public function setInactive($elements)
958 + public function setInactive(array $elements): void
746 959 {
747 - if (!is_array($elements)) $elements = [$elements];
748 - if (empty($elements)) return 0;
960 + if (empty($elements)) {
961 + return;
962 + }
963 +
749 964 acym_arrayToInteger($elements);
750 965
966 + // Core fields can't be disabled
751 967 $excludedFields = acym_loadResultArray('SELECT `id` FROM #__acym_field WHERE `core` = 1');
752 968 acym_arrayToInteger($excludedFields);
753 969
754 970 $elements = array_diff($elements, $excludedFields);
@@ -755,12 +971,12 @@
755 971
756 972 parent::setInactive($elements);
757 973 }
758 974
759 - public function insertLanguageField()
975 + public function insertLanguageField(): void
760 976 {
761 - if ($this->getLanguageFieldId() !== false) {
762 - return false;
977 + if (!empty($this->getLanguageFieldId())) {
978 + return;
763 979 }
764 980
765 981 $field = new \stdClass();
766 982 $field->name = 'ACYM_LANGUAGE';
@@ -776,21 +992,23 @@
776 992 $field->namekey = 'acym_language';
777 993
778 994 $rowId = acym_insertObject('#__acym_field', $field);
779 995
780 - if (empty($rowId)) return false;
996 + if (empty($rowId)) {
997 + return;
998 + }
781 999
782 - return $this->config->save([self::LANGUAGE_FIELD_ID_KEY => $rowId]);
1000 + $this->config->saveConfig([self::LANGUAGE_FIELD_ID_KEY => $rowId]);
783 1001 }
784 1002
785 - public function getLanguageFieldId()
1003 + public function getLanguageFieldId(): int
786 1004 {
787 1005 $languageFieldId = acym_loadResult('SELECT `id` FROM `#__acym_field` WHERE `namekey` = "acym_language"');
788 1006
789 - return empty($languageFieldId) ? false : $languageFieldId;
1007 + return empty($languageFieldId) ? 0 : $languageFieldId;
790 1008 }
791 1009
792 - public function getLanguagesForDropdown()
1010 + public function getLanguagesForDropdown(): array
793 1011 {
794 1012 $languages = acym_getLanguages(false, true);
795 1013 $dataLanguages = [];
796 1014
@@ -810,32 +1028,46 @@
810 1028
811 1029 return $dataLanguages;
812 1030 }
813 1031
814 - public function setEmailConfirmationField($displayOutside, $size, $container = 'div', $displayInline = false)
1032 + public function setEmailConfirmationField(bool $displayOutside, object $field, string $container = 'div', bool $displayInline = false): void
815 1033 {
816 - $uniqueId = 'email_confirmation_field_'.rand(100, 900);
817 - $name = acym_translation('ACYM_EMAIL_CONFIRMATION');
1034 + $uniqueId = 'email_confirmation_field_'.acym_rand(100, 900);
1035 +
1036 + echo '<'.esc_attr($container).' class="onefield acym_email_confirmation_field acyfield_text">';
1037 + if ($displayOutside) {
1038 + echo '<label class="cell margin-top-1">';
1039 + echo '<span class="acym__users__creation__fields__title">'.esc_html(acym_translation('ACYM_EMAIL_CONFIRMATION')).'</span>';
1040 + }
1041 +
818 1042 $placeholder = !$displayOutside ? acym_translation('ACYM_EMAIL_CONFIRMATION') : '';
819 - $style = empty($size) ? '' : ' style="'.$size.'"';
1043 + echo '<input id="'.esc_attr($uniqueId).'"
1044 + '.(empty($field->option->size) ? '' : ' style="width:'.intval($field->option->size).'px"').'
1045 + required
1046 + type="email"
1047 + class="cell acym__user__edit__email"
1048 + name="user[email_confirmation]"';
1049 + if (!$displayOutside) {
1050 + echo ' aria-label="'.esc_attr(acym_translation('ACYM_EMAIL_CONFIRMATION')).'"';
1051 + }
1052 + echo ' placeholder="'.esc_attr($placeholder).'" />';
1053 + echo '<span class="acym__field__error__block" aria-live="assertive"></span>';
1054 +
820 1055 $extraErrors = $this->config->get('extra_errors', '0');
821 -
822 -
823 - $return = '<'.$container.' class="onefield acym_email_confirmation_field acyfield_text">';
824 - if ($displayOutside) $return .= '<label class="cell margin-top-1"><span class="acym__users__creation__fields__title">'.$name.'</span>';
825 - $return .= '<input id="'.$uniqueId.'" '.$style.' required type="email" class="cell acym__user__edit__email" name="user[email_confirmation]" placeholder="'.$placeholder.'">';
826 - $return .= '<span class="acym__field__error__block"></span>';
827 1056 if ($extraErrors && !acym_isAdmin()) {
828 - $return .= '<span class="acym__message__invalid__field acym__color__error" style="display: none;">';
829 - $return .= '<i class="acymicon-times-circle acym__cross__invalid acym__color__error"></i>'.acym_translation('ACYM_THANKS_TO_FILL_IN_THIS_FIELD').'</span>';
1057 + echo '<span class="acym__message__invalid__field acym__color__error" style="display: none;">';
1058 + echo '<i class="acymicon-times-circle acym__cross__invalid acym__color__error"></i>';
1059 + echo esc_html(acym_translation('ACYM_THANKS_TO_FILL_IN_THIS_FIELD'));
1060 + echo '</span>';
830 1061 }
831 - if ($displayOutside) $return .= '</label>';
832 - $return .= '</'.$container.'>';
833 1062
834 - if ($container == 'td' && !$displayInline) {
835 - $return .= '</tr>';
1063 + if ($displayOutside) {
1064 + echo '</label>';
836 1065 }
1066 + echo '</'.esc_attr($container).'>';
837 1067
838 - return $return;
1068 + if ($container === 'td' && !$displayInline) {
1069 + //TODO either open tr here, or close it where setEmailConfirmationField is called
1070 + echo '</tr>';
1071 + }
839 1072 }
840 1073 }
841 -