PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
5.34.3 5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / lib / Form / Block / BlockRendererHelper.php
mailpoet / lib / Form / Block Last commit date
BlockRendererHelper.php 3 weeks ago Checkbox.php 1 year ago Close.php 2 weeks ago Column.php 2 months ago Columns.php 2 months ago Date.php 1 year ago Divider.php 3 years ago Heading.php 2 months ago Html.php 1 year ago Image.php 10 months ago Paragraph.php 3 weeks ago Radio.php 1 year ago Segment.php 2 months ago Select.php 2 months ago Submit.php 1 year ago Text.php 1 year ago Textarea.php 1 year ago index.php 3 years ago
BlockRendererHelper.php
310 lines
1 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
2
3 namespace MailPoet\Form\Block;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\Form\Util\FieldNameObfuscator;
9 use MailPoet\Services\Validator;
10 use MailPoet\WP\Functions as WPFunctions;
11
12 /**
13 * This class still covers several responsibilities and could be further refactored
14 * @package MailPoet\Form\Block
15 */
16 class BlockRendererHelper {
17
18 /** @var FieldNameObfuscator */
19 private $fieldNameObfuscator;
20
21 /** @var WPFunctions */
22 protected $wp;
23
24 public function __construct(
25 FieldNameObfuscator $fieldNameObfuscator,
26 WPFunctions $wp
27 ) {
28 $this->fieldNameObfuscator = $fieldNameObfuscator;
29 $this->wp = $wp;
30 }
31
32 public function getInputValidation(array $block, array $extraRules = [], ?int $formId = null): string {
33 $rules = [
34 'errors-container' => '.' . $this->getErrorsContainerClass($block, $formId),
35 ];
36 $blockId = $this->wp->escAttr($block['id']);
37
38 if ($blockId === 'email') {
39 $rules['required'] = true;
40 $rules['minlength'] = Validator::EMAIL_MIN_LENGTH;
41 $rules['maxlength'] = Validator::EMAIL_MAX_LENGTH;
42 $rules['type-message'] = __('This value should be a valid email.', 'mailpoet');
43 }
44
45 if (($blockId === 'first_name') || ($blockId === 'last_name')) {
46 $errorMessages = [
47 __('Please specify a valid name.', 'mailpoet'),
48 __('Addresses in names are not permitted, please add your name instead.', 'mailpoet'),
49 ];
50 $rules['names'] = '[' . implode(',', array_map(function (string $errorMessage): string {
51 return $this->wp->escAttr('"' . $errorMessage . '"');
52 }, $errorMessages)) . ']';
53 }
54
55 // Segments should be required only when form ID is not empty. That allows save form on subscription management site when any segment is not checked.
56 if ($blockId === 'segments' && $formId) {
57 $rules['required'] = true;
58 $rules['mincheck'] = 1;
59 $rules['group'] = $blockId;
60 $rules['required-message'] = __('Please select a list.', 'mailpoet');
61 }
62
63 if (static::getFieldIsRequired($block)) {
64 $rules['required'] = true;
65 $rules['required-message'] = __('This field is required.', 'mailpoet');
66 }
67
68 if (!empty($block['params']['validate'])) {
69 if ($block['params']['validate'] === 'phone') {
70 $rules['pattern'] = "^[\d\+\-\.\(\)\/\s]*$";
71 $rules['error-message'] = __('Please specify a valid phone number.', 'mailpoet');
72 } else {
73 $rules['type'] = $this->wp->escAttr($block['params']['validate']);
74 $rules['error-message'] = $this->translateValidationErrorMessage($block['params']['validate']);
75 }
76 }
77
78 if (in_array($block['type'], ['radio', 'checkbox', 'date'])) {
79 $rules['group'] = 'custom_field_' . $blockId;
80 }
81
82 $rules = array_merge($rules, $extraRules);
83
84 if (empty($rules)) {
85 return '';
86 }
87
88 $validation = [];
89 $rules = array_unique($rules);
90 foreach ($rules as $rule => $value) {
91 if (is_bool($value)) {
92 $value = ($value) ? 'true' : 'false';
93 }
94 // We need to use single quotes because we need to pass array of strings as a parameter for custom validation
95 if ($rule === 'names') {
96 $validation[] = 'data-parsley-' . $rule . '=\'' . $this->wp->wpKsesPost($value) . '\''; // The value has been escaped above.
97 } else {
98 $validation[] = 'data-parsley-' . $this->wp->escAttr($rule) . '="' . $this->wp->escAttr($this->wp->wpKsesPost($value)) . '"';
99 if ($rule === 'required') {
100 $validation[] = 'required aria-required="true"';
101 }
102 }
103 }
104 return join(' ', $validation);
105 }
106
107 public function renderLabel(array $block, array $formSettings): string {
108 $html = '';
109 $forId = '';
110
111 if (
112 isset($block['params']['hide_label'])
113 && $block['params']['hide_label']
114 ) {
115 return $html;
116 }
117
118 // If the label is displayed within the field,
119 // we'll use aria-label instead of a label element
120 if (
121 isset($block['params']['label_within'])
122 && $block['params']['label_within']
123 ) {
124 return $html;
125 }
126
127 $automationId = null;
128 if (in_array($block['id'], ['email', 'last_name', 'first_name'], true)) {
129 $automationId = 'data-automation-id="form_' . $block['id'] . '_label" ';
130 }
131
132 if (!empty($block['params']['input_id']) && is_scalar($block['params']['input_id'])) {
133 $forId = 'for="' . $this->wp->escAttr((string)$block['params']['input_id']) . '" ';
134 } elseif (isset($formSettings['id'])) {
135 $forId = 'for="' . $this->wp->escAttr('form_' . (string)$block['id'] . '_' . (string)$formSettings['id']) . '" ';
136 }
137
138 if (
139 isset($block['params']['label'])
140 && strlen(trim($block['params']['label'])) > 0
141 ) {
142 $labelClass = 'class="mailpoet_' . $block['type'] . '_label" ';
143
144 $html .= '<label '
145 . $forId
146 . $labelClass
147 . $this->renderFontStyle($formSettings, $block['styles'] ?? [])
148 . ($automationId ? " $automationId" : '')
149 . '>';
150 $html .= static::getFieldLabel($block);
151
152 if (static::getFieldIsRequired($block)) {
153 $html .= '&nbsp;<span class="mailpoet_required" aria-hidden="true">*</span>';
154 }
155
156 $html .= '</label>';
157 }
158 return $html;
159 }
160
161 public function renderLegend(array $block, array $formSettings): string {
162 $html = '';
163
164 if (
165 isset($block['params']['hide_label'])
166 && $block['params']['hide_label']
167 ) {
168 return $html;
169 }
170
171 if (
172 isset($block['params']['label'])
173 && strlen(trim($block['params']['label'])) > 0
174 ) {
175 // Use _label suffix for backward compatibility
176 $labelClass = 'class="mailpoet_' . $block['type'] . '_label" ';
177 $html .= '<legend '
178 . $labelClass
179 . $this->renderFontStyle($formSettings, $block['styles'] ?? [])
180 . '>';
181 $html .= static::getFieldLabel($block);
182
183 if (static::getFieldIsRequired($block)) {
184 $html .= '&nbsp;<span class="mailpoet_required" aria-hidden="true">*</span>';
185 }
186
187 $html .= '</legend>';
188 }
189 return $html;
190 }
191
192 public function renderFontStyle(array $formSettings, array $styles = []) {
193 $rules = [];
194 if (isset($formSettings['fontSize'])) {
195 $rules[] = 'font-size: ' . $formSettings['fontSize'] . (is_numeric($formSettings['fontSize']) ? "px;" : ";");
196 $rules[] = 'line-height: 1.2;';
197 }
198 if (isset($styles['bold']) && $styles['bold']) {
199 $rules[] = 'font-weight: bold;';
200 }
201 return $rules ? 'style="' . $this->wp->escAttr(implode("", $rules)) . '"' : '';
202 }
203
204 public function renderInputPlaceholder(array $block): string {
205 $html = '';
206 // if the label is displayed as a placeholder,
207 if (
208 isset($block['params']['label_within'])
209 && $block['params']['label_within']
210 ) {
211 $label = $this->wp->escAttr(static::getFieldLabel($block));
212 if (static::getFieldIsRequired($block)) {
213 $label .= ' *';
214 }
215 // Some screen readers don't read placeholders, so we need to add aria-label
216 // but to prevent reading it twice, they need to be the same (including *)
217 $html .= ' placeholder="' . $label . '"';
218 $html .= ' aria-label="' . $label . '" ';
219 }
220 return $html;
221 }
222
223 // return field name depending on block data
224 public function getFieldName(array $block = []): string {
225 $blockId = $this->wp->escAttr($block['id']);
226 if ((int)$blockId > 0) {
227 return 'cf_' . $blockId;
228 } elseif (isset($block['params']['obfuscate']) && !$block['params']['obfuscate']) {
229 return $blockId;
230 } else {
231 return $this->fieldNameObfuscator->obfuscate($block['id']);//obfuscate field name for spambots
232 }
233 }
234
235 public function getFieldLabel(array $block = []): string {
236 return (isset($block['params']['label'])
237 && strlen(trim($block['params']['label'])) > 0)
238 ? $this->wp->escHtml(trim($block['params']['label'])) : '';
239 }
240
241 public function getFieldValue($block = []) {
242 return (isset($block['params']['value'])
243 && strlen(trim($block['params']['value'])) > 0)
244 ? $this->wp->escAttr(trim($block['params']['value'])) : '';
245 }
246
247 public function getFieldIsRequired($block = []): bool {
248 return (isset($block['params']['required'])
249 && strlen(trim($block['params']['required'])) > 0)
250 ? !empty($block['params']['required']) : false;
251 }
252
253 public function getInputModifiers(array $block = []): string {
254 $modifiers = [];
255
256 if (isset($block['params']['readonly']) && $block['params']['readonly']) {
257 $modifiers[] = 'readonly';
258 }
259
260 if (isset($block['params']['disabled']) && $block['params']['disabled']) {
261 $modifiers[] = 'disabled';
262 }
263 return join(' ', $modifiers);
264 }
265
266 public function escapeShortCodes(?string $value): ?string {
267 if ($value === null) {
268 return null;
269 }
270 return preg_replace_callback('/' . $this->wp->getShortcodeRegex() . '/s', function ($matches) {
271 return str_replace(['[', ']'], ['&#91;', '&#93;'], $matches[0]);
272 }, $value);
273 }
274
275 public function renderErrorsContainer(array $block = [], ?int $formId = null): string {
276 $errorContainerClass = $this->getErrorsContainerClass($block, $formId);
277 return '<span class="' . $errorContainerClass . '"></span>';
278 }
279
280 private function getErrorsContainerClass(array $block = [], ?int $formId = null): string {
281 $validationId = $block['validation_id'] ?? null;
282 if (!$validationId) {
283 $validationId = $this->wp->escAttr($block['id']);
284 if ($formId) {
285 $validationId .= '_' . $formId;
286 }
287 }
288 return 'mailpoet_error_' . $validationId;
289 }
290
291 private function translateValidationErrorMessage(string $validate): string {
292 switch ($validate) {
293 case 'email':
294 return __('This value should be a valid email.', 'mailpoet');
295 case 'url':
296 return __('This value should be a valid url.', 'mailpoet');
297 case 'number':
298 return __('This value should be a valid number.', 'mailpoet');
299 case 'integer':
300 return __('This value should be a valid integer.', 'mailpoet');
301 case 'digits':
302 return __('This value should be digits.', 'mailpoet');
303 case 'alphanum':
304 return __('This value should be alphanumeric.', 'mailpoet');
305 default:
306 return __('This value seems to be invalid.', 'mailpoet');
307 }
308 }
309 }
310