Correctly show error message next to the field when the same form is rendered multiple times

Every form block now has unique ID (even the same block in two different form has different ID) used for rendering error messages. Before this, when the same form was rendered on a page multiple times, error messages of custom fields were always shown on the last rendered form, even if the first one was submitted.

[MAILPOET-6182]
This commit is contained in:
 Ján Mikláš
2024-08-07 10:52:35 +02:00
committed by Aschepikov
parent ccc1786614
commit 4a54033d1e
9 changed files with 39 additions and 15 deletions

View File

@@ -27,7 +27,9 @@ class BlockRendererHelper {
} }
public function getInputValidation(array $block, array $extraRules = [], ?int $formId = null): string { public function getInputValidation(array $block, array $extraRules = [], ?int $formId = null): string {
$rules = []; $rules = [
'errors-container' => '.' . $this->getErrorsContainerClass($block, $formId),
];
$blockId = $this->wp->escAttr($block['id']); $blockId = $this->wp->escAttr($block['id']);
if ($blockId === 'email') { if ($blockId === 'email') {
@@ -52,13 +54,11 @@ class BlockRendererHelper {
$rules['required'] = true; $rules['required'] = true;
$rules['mincheck'] = 1; $rules['mincheck'] = 1;
$rules['group'] = $blockId; $rules['group'] = $blockId;
$rules['errors-container'] = '.mailpoet_error_' . $blockId . '_' . $formId;
$rules['required-message'] = __('Please select a list.', 'mailpoet'); $rules['required-message'] = __('Please select a list.', 'mailpoet');
} }
if (!empty($block['params']['required'])) { if (!empty($block['params']['required'])) {
$rules['required'] = true; $rules['required'] = true;
$rules['errors-container'] = '.mailpoet_error_' . $blockId . '_' . $formId;
$rules['required-message'] = __('This field is required.', 'mailpoet'); $rules['required-message'] = __('This field is required.', 'mailpoet');
} }
@@ -74,13 +74,11 @@ class BlockRendererHelper {
if (in_array($block['type'], ['radio', 'checkbox'])) { if (in_array($block['type'], ['radio', 'checkbox'])) {
$rules['group'] = 'custom_field_' . $blockId; $rules['group'] = 'custom_field_' . $blockId;
$rules['errors-container'] = '.mailpoet_error_' . $blockId . ($formId ? '_' . $formId : '');
$rules['required-message'] = __('This field is required.', 'mailpoet'); $rules['required-message'] = __('This field is required.', 'mailpoet');
} }
if ($block['type'] === 'date') { if ($block['type'] === 'date') {
$rules['group'] = 'custom_field_' . $blockId; $rules['group'] = 'custom_field_' . $blockId;
$rules['errors-container'] = '.mailpoet_error_' . $blockId . ($formId ? '_' . $formId : '');
} }
$validation = []; $validation = [];
@@ -267,6 +265,22 @@ class BlockRendererHelper {
}, $value); }, $value);
} }
public function renderErrorsContainer(array $block = [], ?int $formId = null): string {
$errorContainerClass = $this->getErrorsContainerClass($block, $formId);
return '<span class="' . $errorContainerClass . '"></span>';
}
private function getErrorsContainerClass(array $block = [], ?int $formId = null): string {
$validationId = $block['validation_id'] ?? null;
if (!$validationId) {
$validationId = $this->wp->escAttr($block['id']);
if ($formId) {
$validationId .= '_' . $formId;
}
}
return 'mailpoet_error_' . $validationId;
}
private function translateValidationErrorMessage(string $validate): string { private function translateValidationErrorMessage(string $validate): string {
switch ($validate) { switch ($validate) {
case 'email': case 'email':

View File

@@ -74,7 +74,7 @@ class Checkbox {
$html .= '</fieldset>'; $html .= '</fieldset>';
$html .= '<span class="mailpoet_error_' . $this->wp->escAttr($block['id']) . ($formId ? '_' . $formId : '') . '"></span>'; $html .= $this->rendererHelper->renderErrorsContainer($block, $formId);
return $this->wrapper->render($block, $html); return $this->wrapper->render($block, $html);
} }

View File

@@ -92,7 +92,7 @@ class Date {
} }
} }
$html .= '<span class="mailpoet_error_' . $this->wp->escAttr($block['id']) . ($formId ? '_' . $formId : '') . '"></span>'; $html .= $this->rendererHelper->renderErrorsContainer($block, $formId);
return $html; return $html;
} }

View File

@@ -76,7 +76,7 @@ class Radio {
$html .= '</fieldset>'; $html .= '</fieldset>';
$html .= '<span class="mailpoet_error_' . $block['id'] . ($formId ? '_' . $formId : '') . '"></span>'; $html .= $this->rendererHelper->renderErrorsContainer($block, $formId);
return $this->wrapper->render($block, $html); return $this->wrapper->render($block, $html);
} }

View File

@@ -69,7 +69,7 @@ class Segment {
$html .= '</label>'; $html .= '</label>';
} }
$html .= '<span class="mailpoet_error_' . $block['id'] . ($formId ? '_' . $formId : '') . '"></span>'; $html .= $this->rendererHelper->renderErrorsContainer($block, $formId);
// End fieldset around checkboxes // End fieldset around checkboxes
$html .= '</fieldset>'; $html .= '</fieldset>';

View File

@@ -32,7 +32,7 @@ class Select {
$this->blockStylesRenderer = $blockStylesRenderer; $this->blockStylesRenderer = $blockStylesRenderer;
} }
public function render(array $block, array $formSettings): string { public function render(array $block, array $formSettings, ?int $formId = null): string {
$html = ''; $html = '';
$fieldName = 'data[' . $this->rendererHelper->getFieldName($block) . ']'; $fieldName = 'data[' . $this->rendererHelper->getFieldName($block) . ']';
@@ -94,6 +94,8 @@ class Select {
} }
$html .= '</select>'; $html .= '</select>';
$html .= $this->rendererHelper->renderErrorsContainer($block, $formId);
return $this->wrapper->render($block, $html); return $this->wrapper->render($block, $html);
} }
} }

View File

@@ -31,7 +31,7 @@ class Text {
$this->wp = $wp; $this->wp = $wp;
} }
public function render(array $block, array $formSettings): string { public function render(array $block, array $formSettings, ?int $formId = null): string {
$type = 'text'; $type = 'text';
$automationId = ' '; $automationId = ' ';
$id = ''; $id = '';
@@ -86,6 +86,8 @@ class Text {
$html .= '/>'; $html .= '/>';
$html .= $this->rendererHelper->renderErrorsContainer($block, $formId);
return $this->wrapper->render($block, $html); return $this->wrapper->render($block, $html);
} }
} }

View File

@@ -31,7 +31,7 @@ class Textarea {
$this->wp = $wp; $this->wp = $wp;
} }
public function render(array $block, array $formSettings): string { public function render(array $block, array $formSettings, ?int $formId = null): string {
$html = ''; $html = '';
$name = $this->rendererHelper->getFieldName($block); $name = $this->rendererHelper->getFieldName($block);
$styles = $this->inputStylesRenderer->renderForTextInput($block['styles'] ?? [], $formSettings); $styles = $this->inputStylesRenderer->renderForTextInput($block['styles'] ?? [], $formSettings);
@@ -57,6 +57,8 @@ class Textarea {
$html .= '>' . $this->rendererHelper->escapeShortCodes($this->rendererHelper->getFieldValue($block)) . '</textarea>'; $html .= '>' . $this->rendererHelper->escapeShortCodes($this->rendererHelper->getFieldValue($block)) . '</textarea>';
$html .= $this->rendererHelper->renderErrorsContainer($block, $formId);
return $this->wrapper->render($block, $html); return $this->wrapper->render($block, $html);
} }
} }

View File

@@ -18,6 +18,7 @@ use MailPoet\Form\Block\Select;
use MailPoet\Form\Block\Submit; use MailPoet\Form\Block\Submit;
use MailPoet\Form\Block\Text; use MailPoet\Form\Block\Text;
use MailPoet\Form\Block\Textarea; use MailPoet\Form\Block\Textarea;
use MailPoet\Util\Security;
class BlocksRenderer { class BlocksRenderer {
/** @var Checkbox */ /** @var Checkbox */
@@ -104,6 +105,9 @@ class BlocksRenderer {
if ($formId) { if ($formId) {
$formSettings['id'] = $formId; $formSettings['id'] = $formId;
} }
// This is used to properly show validation message when
// the same form is rendered on a page multiple times
$block['validation_id'] = Security::generateRandomString();
switch ($block['type']) { switch ($block['type']) {
case FormEntity::HTML_BLOCK_TYPE: case FormEntity::HTML_BLOCK_TYPE:
$html .= $this->html->render($block, $formSettings); $html .= $this->html->render($block, $formSettings);
@@ -142,15 +146,15 @@ class BlocksRenderer {
break; break;
case FormEntity::SELECT_BLOCK_TYPE: case FormEntity::SELECT_BLOCK_TYPE:
$html .= $this->select->render($block, $formSettings); $html .= $this->select->render($block, $formSettings, $formId);
break; break;
case FormEntity::TEXT_BLOCK_TYPE: case FormEntity::TEXT_BLOCK_TYPE:
$html .= $this->text->render($block, $formSettings); $html .= $this->text->render($block, $formSettings, $formId);
break; break;
case FormEntity::TEXTAREA_BLOCK_TYPE: case FormEntity::TEXTAREA_BLOCK_TYPE:
$html .= $this->textarea->render($block, $formSettings); $html .= $this->textarea->render($block, $formSettings, $formId);
break; break;
case FormEntity::SUBMIT_BLOCK_TYPE: case FormEntity::SUBMIT_BLOCK_TYPE: