PluginProbe
wpForo Forum / 2.4.2
wpForo Forum v2.4.2
3.1.5 3.1.4 3.1.2 3.1.1 3.1.0 3.0.9 3.0.8 3.0.7 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 1.4.13 1.4.2 All 137 releases
wpforo / classes / Forms.php

Forms.php in wpForo Forum 2.4.2, at classes/Forms.php

1,628 lines 64.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace wpforo\classes;
4
5 // Exit if accessed directly
6 if( ! defined( 'ABSPATH' ) ) exit;
7
8 class Forms {
9 public $default;
10 public $field_dir;
11 public $current;
12
13 public function __construct() {
14 $this->init_defaults();
15 }
16
17 private function init_defaults() {
18 $this->field_dir = '/wpforo/users/fields/';
19 $this->default = [
20 'label' => '',
21 'title' => '',
22 'name' => '',
23 'value' => '',
24 'values' => '',
25 'type' => 'text',
26 'placeholder' => '',
27 'description' => '',
28 'id' => '',
29 'class' => '',
30 'attributes' => '',
31 'isDefault' => 0,
32 'isWrapItem' => '',
33 'isLabelFirst' => '',
34 'isDisabled' => 0,
35 'isEditable' => 1,
36 'isRequired' => 0,
37 'isMultiChoice' => 0,
38 'isAllowedCustomValues' => 0,
39 'UGroupIdsFrontAddNewDefaultValues' => [],
40 'isOnlyForGuests' => 0,
41 'isRemovable' => 1,
42 'isSearchable' => 0,
43 'allowedGroupIds' => [],
44 'fileExtensions' => '',
45 'fileSize' => 1,
46 'minLength' => 0,
47 'maxLength' => 0,
48 'faIcon' => '',
49 'html' => '',
50 'varname' => '',
51 'template' => '',
52 'cantBeInactive' => [],
53 'canEdit' => [ 1 ],
54 'canView' => [ 1, 2, 3, 5 ],
55 'can' => '',
56 'isDisplayDefaultValues' => 0,
57 ];
58 }
59
60 public function fix_field( $field ) {
61 return wpforo_array_args_cast_and_merge( (array) $field, $this->default );
62 }
63
64 /**
65 * Form builder
66 * for form layout and field building
67 *
68 * @param array $fields associative multi-level array
69 *
70 * @return string form HTML
71 */
72 public function build( $fields ) {
73 if( empty( $fields ) ) return '';
74 $html = '';
75 foreach( $fields as $row_key => $row ) {
76 $row_class = "row-$row_key " . apply_filters( 'wpforo_row_classes', '', $row_key );
77 $html .= '<div class="wpf-tr ' . esc_attr( $row_class ) . '">';
78 foreach( $row as $col_key => $col ) {
79 $col_class_field = '';
80 foreach( $col as $field ) {
81 $col_class_field .= ' wpf-row-' . wpfval( $field, 'name' );
82 }
83 reset( $col );
84 $col_class = "row_$row_key-col_$col_key " . $col_class_field . ' ' . apply_filters( 'wpforo_col_classes', '', $row_key, $col_key );
85 $html .= '<div class="wpf-td wpfw-' . count( $row ) . ' ' . esc_attr( $col_class ) . '">';
86 foreach( $col as $field ) {
87 if( ! empty( $field ) ) $html .= $this->build_field( $field );
88 }
89 $html .= '</div>';
90 }
91 $html .= '<div class="wpf-cl"></div></div>';
92 }
93
94 return $html;
95 }
96
97 /**
98 * Builds field with input HTML and wrapper divs
99 *
100 * @param array $args field arguments
101 *
102 * @return string field HTML
103 */
104 public function build_field( $args ) {
105 if( is_string( $args ) ) $args = WPF()->member->get_field( $args );
106
107 $html = '';
108 if( ! is_array( $args ) || empty( $args ) ) return '';
109 $f = wpforo_parse_args( $args, $this->default );
110 $f = $this->prepare_args( $f );
111
112 //Get field input tag
113 $field_html = $this->field( $f );
114
115 //Wrapping field input
116 if( $f['template'] === 'register' ) {
117 if( $this->can_add( $f ) ) {
118 $html = $this->field_wrap_register( $field_html, $f );
119 }
120 } elseif( $f['template'] === 'account' ) {
121 if( $this->can_edit( $f ) ) {
122 $html = $this->field_wrap_account( $field_html, $f );
123 }
124 } elseif( $f['template'] === 'profile' ) {
125 if( $this->can_view( $f ) && $this->can_show_value( $f ) ) {
126 $f = $this->esc_field( $f );
127 $html = $this->field_wrap_profile( $field_html, $f );
128 }
129 } elseif( $f['template'] === 'members' ) {
130 if( $this->can_show_value( $f ) ) $html = $this->field_wrap_members( $field_html, $f );
131 } else {
132 $html = $this->field_wrap_default( $field_html, $f );
133 }
134
135 return $html;
136 }
137
138 /**
139 * Field input HTML builder
140 *
141 * @param array $f field arguments
142 *
143 * @return string field input HTML
144 */
145 public function field( $f ) {
146 $f = $this->prepare_field_args( $f );
147
148 $f = apply_filters( 'wpforo_form_field', $f );
149
150 switch( $f['type'] ) {
151 case 'url':
152 $field_html = $this->field_url( $f );
153 break;
154 case 'file':
155 $field_html = $this->field_file( $f );
156 break;
157 case 'html':
158 $field_html = $this->field_html( $f );
159 break;
160 case 'radio':
161 $field_html = $this->field_radio( $f );
162 break;
163 case 'select':
164 $field_html = $this->field_select( $f );
165 break;
166 case 'avatar':
167 $field_html = $this->field_avatar( $f );
168 break;
169 case 'textarea':
170 $field_html = $this->field_textarea( $f );
171 break;
172 case 'tinymce':
173 $field_html = $this->field_tinymce( $f );
174 break;
175 case 'password':
176 $field_html = $this->field_password( $f );
177 break;
178 case 'checkbox':
179 $field_html = $this->field_checkbox( $f );
180 break;
181 case 'usergroup':
182 $field_html = $this->field_usergroup( $f );
183 break;
184 case 'secondary_groups':
185 $field_html = $this->field_secondary_groups( $f );
186 break;
187 case 'user_nicename':
188 $field_html = $this->field_nicename( $f );
189 break;
190 case 'tel':
191 $field_html = $this->field_tel( $f );
192 break;
193 case 'autocomplete':
194 $field_html = $this->field_autocomplete( $f );
195 break;
196 default:
197 $field_html = $this->field_text( $f );
198 }
199
200 return apply_filters( 'wpforo_form_field_html', $field_html, $f );
201 }
202
203 /**
204 * Wraps input HTML for Registration form
205 *
206 * @param string $field_html input HTML
207 * @param array $f field arguments
208 *
209 * @return string wrapped field input HTML
210 */
211 public function field_wrap_register( $field_html, $f ) {
212 $html = '<div class="wpf-field wpf-field-type-' . esc_attr( $f['type'] ) . ' wpf-field-name-' . esc_attr( $f['field_class'] ) . ' ' . esc_attr( $f['required_class'] ) . '" title="' . esc_attr(
213 $f['title']
214 ) . '">';
215 if( $f['type'] !== 'html' ) {
216 if( $f['label'] || $f['description'] ) {
217 $html .= '<div class="wpf-label-wrap">';
218 if( $f['label'] ) {
219 $html .= '<p class="wpf-label wpfcl-1">' . $f['label'] . $f['required_indicator'] . '</p>';
220 }
221 if( $f['description'] ) {
222 $html .= '<div class="wpf-desc wpfcl-2">' . $f['description'] . '</div>';
223 }
224 $html .= '</div>';
225 }
226 $html .= '<div class="wpf-field-wrap">';
227 if( $f['faIcon'] ) {
228 $html .= '<i class="' . esc_attr( $f['faIcon'] ) . ' wpf-field-icon"></i>';
229 }
230 $html .= $field_html;
231 $html .= '</div>';
232 } else {
233 $html .= $field_html;
234 }
235 $html .= '<div class="wpf-field-cl"></div></div>';
236
237 return $html;
238 }
239
240 /**
241 * Wraps input HTML for Account form
242 *
243 * @param string $field_html input HTML
244 * @param array $f field arguments
245 *
246 * @return string wrapped field input HTML
247 */
248 public function field_wrap_account( $field_html, $f ) {
249 $html = '<div class="wpf-field wpf-field-type-' . esc_attr( $f['type'] ) . ' wpf-field-name-' . esc_attr( $f['field_class'] ) . ' ' . esc_attr( $f['required_class'] ) . '" title="' . esc_attr(
250 $f['title']
251 ) . '">';
252 if( $f['type'] === 'html' ) {
253 $html .= $field_html;
254 } elseif( $f['name'] === 'user_login' ) {
255 $html .= '<div class="wpf-label-wrap">';
256 $html .= '<p class="wpf-label wpfcl-1">' . stripslashes( (string) $f['label'] ) . '</p>';
257 $html .= '</div>';
258 $html .= '<div class="wpf-field-wrap">';
259 $html .= '<span class="wpf-username">' . $f['value'] . '</span>';
260 $html .= '</div>';
261 } elseif( $f['type'] !== 'password' && ! $f['isEditable'] && ! $this->can_moderate( $f ) && WPF()->current_user_groupid !== 1 ) {
262 $f = $this->esc_field( $f );
263 $html .= '<div class="wpf-label-wrap">';
264 $html .= '<p class="wpf-label wpfcl-1">' . stripslashes( (string) $f['label'] ) . '</p>';
265 $html .= '</div>';
266 $html .= '<div class="wpf-field-wrap">';
267 $html .= '<span class="wpf-filed-value"><i class="' . esc_attr( $f['faIcon'] ) . '"></i> ' . $f['value'] . '</span>';
268 $html .= '</div>';
269 } else {
270 if( $f['label'] || $f['description'] ) {
271 $html .= '<div class="wpf-label-wrap">';
272 if( $f['label'] ) {
273 $html .= '<p class="wpf-label wpfcl-1">' . stripslashes( (string) $f['label'] ) . $f['required_indicator'] . '</p>';
274 }
275 if( $f['description'] ) {
276 $html .= '<div class="wpf-desc wpfcl-2">' . $f['description'] . '</div>';
277 }
278 $html .= '</div>';
279 }
280 $html .= '<div class="wpf-field-wrap">';
281 if( $f['faIcon'] ) {
282 $html .= '<i class="' . esc_attr( $f['faIcon'] ) . ' wpf-field-icon"></i>';
283 }
284 $html .= $field_html;
285 $html .= '</div>';
286 }
287 $html .= '<div class="wpf-field-cl"></div></div>';
288
289 return $html;
290 }
291
292 /**
293 * Wraps input HTML for Profile page
294 *
295 * @param string $field_html input HTML
296 * @param array $f field arguments
297 *
298 * @return string wrapped field input HTML
299 */
300 public function field_wrap_profile( $field_html, $f ) {
301
302 if( ! in_array( $f['type'], [ 'html', 'avatar' ] ) && ! ( $f['isRequired'] && $f['isDisplayDefaultValues'] ) && ( ! isset( $f['value'] ) || ( ! is_numeric(
303 $f['value']
304 ) && empty( $f['value'] ) ) ) ) {
305 return false;
306 }
307
308 $html = '<div class="wpf-field wpf-field-type-' . esc_attr( $f['type'] ) . ' wpf-field-name-' . esc_attr( $f['field_class'] ) . ' ' . esc_attr( $f['required_class'] ) . '" title="' . esc_attr(
309 $f['title']
310 ) . '">';
311 if( $f['type'] !== 'html' ) {
312 if( ! $f['faIcon'] ) {
313 $f['faIcon'] = 'fas fa-address-card';
314 }
315 if( $f['label'] ) {
316 $html .= '<div class="wpf-label-wrap"><p class="wpf-label wpfcl-1"><i class="' . esc_attr( $f['faIcon'] ) . ' wpf-field-icon"></i> ' . $f['label'] . '</p></div>';
317 }
318 if( $f['type'] === 'avatar' || ( isset( $f['value'] ) && ! empty( $f['value'] ) ) ) {
319 if( is_array( $f['value'] ) ) {
320 $html .= esc_html( implode( ', ', $f['value'] ) );
321 } else {
322 $f = $this->prepare_values( $f, WPF()->current_object['userid'] );
323 $html .= '<div class="wpf-field-wrap">';
324 $html .= $f['value'];
325 $html .= '</div>';
326 }
327 } else {
328 if( $default_values = wpforo_preg_grep_recursive( '#^\[.+?]$#isu', $f['values'] ) ) {
329 $_html = '';
330 foreach( $default_values as $default_key => $default_value ) {
331 if( ! is_array( $default_value ) ) {
332 $item = $this->build_item_value_lable( $default_value );
333 $_html .= $item['label'] . ', ';
334 } else {
335 $csv = '';
336 foreach( $default_value as $_default_value ) {
337 if( ! is_array( $_default_value ) ) {
338 $item = $this->build_item_value_lable( $_default_value );
339 $csv .= $item['label'] . ', ';
340 }
341 }
342 $_html .= trim( (string) $default_key ) . '( ' . trim( (string) $csv, ', ' ) . ' ), ';
343 }
344 }
345 $html .= sprintf( '<div class="wpf-field-wrap">%1$s</div>', trim( (string) $_html, ', ' ) );
346 } else {
347 return false;
348 }
349 }
350 } else {
351 $html .= $field_html;
352 }
353 $html .= '<div class="wpf-field-cl"></div></div>';
354
355 return $html;
356 }
357
358 /**
359 * Wraps input HTML for Members Search form
360 *
361 * @param string $field_html input HTML
362 * @param array $f field arguments
363 *
364 * @return string wrapped field input HTML
365 */
366 public function field_wrap_members( $field_html, $f ) {
367 $html = '<div class="wpf-field wpf-field-type-' . esc_attr( $f['type'] ) . ' wpf-field-name-' . esc_attr( $f['field_class'] ) . ' ' . esc_attr( $f['required_class'] ) . '" title="' . esc_attr(
368 $f['title']
369 ) . '">';
370 if( $f['type'] === 'html' ) {
371 $html .= $field_html;
372 } else {
373 if( $f['label'] || $f['description'] ) {
374 $html .= '<div class="wpf-label-wrap">';
375 if( $f['label'] ) {
376 $html .= '<p class="wpf-label wpfcl-1">' . stripslashes( (string) $f['label'] ) . $f['required_indicator'] . '</p>';
377 }
378 if( $f['description'] ) {
379 $html .= '<div class="wpf-desc wpfcl-2">' . $f['description'] . '</div>';
380 }
381 $html .= '</div>';
382 }
383 $html .= '<div class="wpf-field-wrap">';
384 if( $f['faIcon'] ) {
385 $html .= '<i class="' . esc_attr( $f['faIcon'] ) . ' wpf-field-icon"></i>';
386 }
387 $html .= $field_html;
388 $html .= '</div>';
389 }
390 $html .= '<div class="wpf-field-cl"></div></div>';
391
392 return $html;
393 }
394
395 /**
396 * Default wrapper of input HTML
397 *
398 * @param string $field_html input HTML
399 * @param array $f field arguments
400 *
401 * @return string wrapped field input HTML
402 */
403 public function field_wrap_default( $field_html, $f ) {
404 $html = '<div class="wpf-field wpf-field-type-' . esc_attr( $f['type'] ) . ' wpf-field-name-' . esc_attr( $f['field_class'] ) . ' ' . esc_attr( $f['required_class'] ) . '">';
405 if( $f['type'] === 'html' ) {
406 $html .= $field_html;
407 } else {
408 if( $f['label'] || $f['description'] ) {
409 $html .= '<div class="wpf-label-wrap" style="float: none; width: 100%;">';
410 if( $f['faIcon'] ) $html .= '<i class="' . esc_attr( $f['faIcon'] ) . '"></i>';
411 if( $f['label'] ) {
412 $html .= '<p class="wpf-label wpfcl-1" style="display: inline-block; margin-left: 5px;">' . stripslashes( (string) $f['label'] ) . $f['required_indicator'] . '</p>';
413 }
414
415 if( wpfval( $f, 'type' ) === 'file' && ( $file_size = wpfval( $f, 'fileSize' ) ) ) {
416 $html .= '<em style="opacity: 0.8;"> (' . wpforo_phrase( 'max allowed file size', false, 'lower' ) . ' ' . $file_size . 'MB)</em>';
417 }
418
419 if( $f['description'] ) {
420 $html .= '<div class="wpf-desc wpfcl-2" style="display: inline-block; margin-left: 5px;">' . $f['description'] . '</div>';
421 }
422 $html .= '</div>';
423 } else {
424 if( $f['faIcon'] ) $html .= '<i class="' . esc_attr( $f['faIcon'] ) . '"></i>';
425 }
426 $html .= '<div class="wpf-field-wrap" style="width: 100%">';
427 $html .= $field_html;
428 $html .= '</div>';
429 }
430 $html .= '<div class="wpf-field-cl"></div></div>';
431
432 return $html;
433 }
434
435 /**
436 * File - Field builder
437 *
438 * @param array $f field arguments
439 *
440 * @return string field HTML
441 */
442 public function field_file( $f ) {
443 $field_html = '';
444 $extensions = '';
445 if( $f['fileExtensions'] ) {
446 foreach( $f['fileExtensions'] as $key => $ext ) {
447 if( strpos( (string) $ext, '.' ) === false ) {
448 $f['fileExtensions'][ $key ] = '.' . $ext;
449 }
450 }
451 $f['fileExtensions'] = implode( ', ', $f['fileExtensions'] );
452 if( $f['fileExtensions'] ) $extensions = ' accept="' . esc_attr( $f['fileExtensions'] ) . '" ';
453 }
454 if( $f['value'] ) {
455 $f['isRequired'] = '';
456 if( is_array( $f['value'] ) ) {
457 $file_name = (string) wpfval( $f['value'], 'filename' );
458 $f['value'] = (string) wpfval( $f['value'], 'fileurl' );
459 } else {
460 $file_name = basename( (string) $f['value'] );
461 }
462 $extension = pathinfo( $f['value'], PATHINFO_EXTENSION );
463 $f['value'] = wpforo_fix_upload_url( $f['value'] );
464
465 if( wpfval( WPF()->current_object['user'], 'userid' ) ) {
466 $delete = '?wpfaction=ucf_file_delete&foro_f=' . $f['name'] . '&foro_u=' . WPF()->current_object['user']['userid'];
467 $delete_url = wp_nonce_url( $delete, 'wpforo_delete_profile_field', 'foro_n' );
468 $delete_html = ' &nbsp;|&nbsp; <a href="' . $delete_url . '" title="' . wpforo_phrase( 'Delete this file', false ) . '" onclick="return confirm(\'' . wpforo_phrase(
469 'Are you sure you want to delete this file?',
470 false
471 ) . '\')"><i class="fas fa-times" style="color:#e86666; font-size:14px; line-height:14px;"></i></a>';
472 } else {
473 $delete_html = ' &nbsp;|&nbsp; <span data-fieldkey="' . $f['fieldKey'] . '" style="cursor: pointer;" class="wpforo-delete-custom-file" title="' . wpforo_phrase(
474 'Delete this file',
475 false
476 ) . '"><i class="fas fa-times" style="color:#e86666; font-size:14px; line-height:14px;"></i></span>';
477 }
478
479 if( $extension && wpforo_is_image( $extension ) ) {
480 $field_html .= '<div class="wpf-field-file-wrap" style="margin-bottom: 10px;">
481 <img src="' . esc_url_raw( $f['value'] ) . '" alt="' . esc_attr( $file_name ) . '" title="' . esc_attr( $file_name ) . '" style="max-width:100px; max-height:100px"/>
482 <div class="wpf-field-file-name">
483 <i class="fas fa-paperclip"></i>
484 <a href="' . esc_url_raw( $f['value'] ) . '" title="' . esc_attr( $file_name ) . '" target="_blank">' . esc_attr( $file_name ) . '</a>' . $delete_html . '
485 </div>
486 </div>';
487 } else {
488 $field_html .= '<div class="wpf-field-file-wrap" style="margin-bottom: 10px;">
489 <div class="wpf-field-file-name">
490 <i class="fas fa-paperclip"></i>
491 <a href="' . esc_url_raw( $f['value'] ) . '" title="' . esc_attr( $file_name ) . '" target="_blank">' . esc_attr( $file_name ) . '</a>' . $delete_html . '
492 </div>
493 </div>';
494 }
495 }
496 $field_html .= '<input type="file" name="' . esc_attr( $f['fieldName'] ) . '" value=""
497 id="' . esc_attr( $f['fieldId'] ) . '" class="' . esc_attr( $f['fieldId'] ) . '"
498 ' . $f['isRequired'] . ' ' . $f['isDisabled'] . ' ' . $f['attributes'] . ' ' . $extensions . ' />';
499
500 return $field_html;
501 }
502
503 private function form_extra( $f ) {
504 $form_type = wpfval( $f, 'form_type' );
505 switch( $form_type ) {
506 case 'topic':
507 if( $forum = wpfval( $f, 'meta', 'forum' ) ) {
508 wpforo_topic_form_extra( (int) wpfval( $forum, 'forumid' ), (array) wpfval( $f, 'meta', 'values' ) );
509 }
510 break;
511 case 'post':
512 if( $topic = wpfval( $f, 'meta', 'topic' ) ) {
513 wpforo_reply_form_extra( $topic, (array) wpfval( $f, 'meta', 'values' ) );
514 }
515 break;
516 }
517 }
518
519 /**
520 * Textarea - Field builder
521 *
522 * @param array $f field arguments
523 *
524 * @return string field HTML
525 */
526 public function field_textarea( $f ) {
527 $field_html = '<textarea name="' . esc_attr( $f['fieldName'] ) . '"
528 id="' . esc_attr( $f['fieldId'] ) . '"
529 class="' . esc_attr( $f['fieldId'] ) . '"
530 placeholder="' . esc_attr( $f['placeholder'] ) . '"
531 ' . $f['isRequired'] . ' ' . $f['isDisabled'] . ' ' . $f['attributes'] . '
532 ' . $f['minmax'] . ' data-isbody="' . intval( $f['fieldKey'] === 'body' ) . '">' . esc_textarea( (string) $f['value'] ) . '</textarea>';
533 if( $f['fieldKey'] === 'body' ) {
534 ob_start();
535 $this->form_extra( $f );
536 $field_html .= ob_get_clean();
537 }
538
539 return $field_html;
540 }
541
542 /**
543 * Textarea - Field builder
544 *
545 * @param array $f field arguments
546 *
547 * @return string field HTML
548 */
549 public function field_tinymce( $f ) {
550 WPF()->current_object['load_tinymce'] = true;
551 $f['isRequired'] = '';
552 $f['attributes'] .= ' data-wpforoeditor="tinymce" ';
553 if( empty( $f['wp_editor_settings'] ) ) $f['wp_editor_settings'] = WPF()->tpl->editor_buttons();
554 $f['wp_editor_settings'] = apply_filters( 'wpforo_form_field_tinymce_editor_settings', $f['wp_editor_settings'], $f );
555 wp_localize_script( 'wpforo-frontend-js', 'wpforo_editor_settings_' . esc_attr( $f['fieldId'] ), $f['wp_editor_settings'] );
556
557 return $this->field_textarea( $f );
558 }
559
560 /**
561 * Password - Field builder
562 *
563 * @param array $f field arguments
564 *
565 * @return string field HTML
566 */
567 public function field_password( $f ) {
568 $field_html = '';
569 if( $f['template'] === 'account' ) {
570 $f['isRequired'] = 0;
571 $f['label'] = wpforo_phrase( 'Old password', false );
572 $f['description'] = '';
573 $field_html .= '<input type="password"
574 name="' . esc_attr( $f['varname'] ) . '[old_pass]"
575 value="" id="' . esc_attr( $f['fieldId'] ) . '-old"
576 class="' . esc_attr( $f['fieldId'] ) . '"
577 placeholder="' . esc_attr( wpforo_phrase( 'Old password', false ) ) . '"
578 ' . $f['isDisabled'] . ' ' . $f['attributes'] . '/>
579 <i class="fas fa-eye-slash wpf-show-password"></i>';
580 }
581 $p1 = '1';
582 $p2 = '2';
583 if( ! empty( $f['varname'] ) ) {
584 $f['fieldName'] = $f['varname'] . '[' . $f['name'] . $p1 . ']';
585 } else {
586 $f['fieldName'] = $f['name'] . $p1;
587 }
588 if( $f['template'] === 'account' ) {
589 $f['label'] = wpforo_phrase( 'New', false ) . ' ' . wpforo_phrase( $f['label'], false, 'lower' );
590 $f['placeholder'] = wpforo_phrase( 'New', false ) . ' ' . wpforo_phrase( $f['placeholder'], false, 'lower' );
591 }
592 if( in_array( $f['template'], [ 'account', 'register' ], true ) ) {
593 if( $f['template'] === 'account' ) $field_html .= '<div style="position:relative"><i class="' . esc_attr( $f['faIcon'] ) . ' wpf-field-icon"></i>';
594 $field_html .= '<input type="password"
595 name="' . esc_attr( $f['fieldName'] ) . '"
596 value="" id="' . esc_attr( $f['fieldId'] ) . '-new1"
597 class="' . esc_attr( $f['fieldId'] ) . '"
598 placeholder="' . esc_attr( $f['placeholder'] ) . '"
599 ' . $f['isDisabled'] . ' ' . $f['attributes'] . ' ' . $f['minmax'] . '/>';
600 if( $f['template'] === 'register' ) {
601 $field_html .= '<i class="fas fa-eye-slash wpf-show-password"></i>';
602 }
603 if( $f['template'] === 'account' ) {
604 $field_html .= '</div>';
605 }
606 $f['label'] = wpforo_phrase( 'Confirm Password', false );
607 $f['placeholder'] = wpforo_phrase( 'Confirm Password', false );
608 $f['description'] = '';
609 $f['fieldName'] = ( ! empty( $f['varname'] ) ? $f['varname'] . '[' . $f['name'] . $p2 . ']' : $f['name'] . $p2 );
610 $field_html .= '<div style="position:relative"><i class="' . esc_attr( $f['faIcon'] ) . ' wpf-field-icon"></i>';
611 $field_html .= '<input type="password"
612 name="' . esc_attr( $f['fieldName'] ) . '"
613 value="" id="' . esc_attr( $f['fieldId'] ) . '-new2"
614 class="' . esc_attr( $f['fieldId'] ) . '"
615 placeholder="' . esc_attr( $f['placeholder'] ) . '"
616 ' . $f['isDisabled'] . ' ' . $f['attributes'] . ' ' . $f['minmax'] . '/>';
617 $field_html .= '</div>';
618 }
619
620 return $field_html;
621 }
622
623 /**
624 * Checkbox - Field builder
625 *
626 * @param array $f field arguments
627 *
628 * @return string field HTML
629 */
630 public function field_checkbox( $f ) {
631 $i = 0;
632 $field_html = '';
633 $f['value'] = $this->build_array_value( $f['value'], "\n" );
634 $f['values'] = $this->build_array_using_string_rows( $f['values'] );
635 if( ! empty( $f['values'] ) ) {
636 $item_field_name = $f['fieldName'] . '[]';
637 $use_default_selected = ( trim( (string) $f['isRequired'] ) && ! $f['value'] );
638 $f['isRequired'] = ( count( $f['values'] ) == 1 ) ? $f['isRequired'] : '';
639 $field_html .= '<input type="hidden" name="' . esc_attr( $f['fieldName'] ) . '" value="">';
640 foreach( $f['values'] as $row ) {
641 $item = $this->build_item_value_lable( $row );
642 $id = $f['fieldId'] . '_' . ++ $i;
643 $field_html .= '<div class="wpf-field-item">';
644 $item_html = '<input type="checkbox" ' . ( $use_default_selected ? ( $item['default_selected'] ? ' checked ' : '' ) : $this->check( $item['value'], $f['value'] ) ) . '
645 name="' . esc_attr( $item_field_name ) . '"
646 value="' . esc_attr( $item['value'] ) . '"
647 id="' . esc_attr( $id ) . '"
648 class="wpf-input-checkbox ' . esc_attr( $f['class'] ) . '"
649 ' . $f['isDisabled'] . ' ' . $f['isRequired'] . ' ' . $f['attributes'] . '>';
650 $field_html .= $this->build_label( $item['label'], $item_html, $f, $id );
651 $field_html .= '</div>';
652 }
653 }
654
655 return $field_html;
656 }
657
658 /**
659 * Radio - Field builder
660 *
661 * @param array $f field arguments
662 *
663 * @return string field HTML
664 */
665 public function field_radio( $f ) {
666 $i = 0;
667 $field_html = '';
668 $f['value'] = $this->build_array_value( $f['value'], "\n" );
669 $f['values'] = $this->build_array_using_string_rows( $f['values'] );
670 $use_default_selected = ( trim( (string) $f['isRequired'] ) && ! $f['value'] );
671 if( ! empty( $f['values'] ) ) {
672 foreach( $f['values'] as $row ) {
673 $item = $this->build_item_value_lable( $row );
674 $id = $f['fieldId'] . '_' . ++ $i;
675 $field_html .= '<div class="wpf-field-item">';
676 $item_html = '<input type="radio" ' . ( $use_default_selected ? ( $item['default_selected'] ? ' checked ' : '' ) : $this->check( $item['value'], $f['value'] ) ) . '
677 name="' . esc_attr( $f['fieldName'] ) . '"
678 value="' . esc_attr( $item['value'] ) . '"
679 id="' . esc_attr( $id ) . '"
680 class="wpf-input-radio ' . esc_attr( $f['class'] ) . '"
681 ' . $f['isDisabled'] . ' ' . $f['isRequired'] . ' ' . $f['attributes'] . ' />';
682 $field_html .= $this->build_label( $item['label'], $item_html, $f, $id );
683 $field_html .= '</div>';
684 }
685 }
686
687 return $field_html;
688 }
689
690 /**
691 * Radio - Field builder
692 *
693 * @param array $f field arguments
694 *
695 * @return string field HTML
696 */
697 public function field_select( $f ) {
698 $field_html = '';
699 $f['value'] = $this->build_array_value( $f['value'], "\n" );
700 $f['values'] = $this->build_array_using_string_rows( $f['values'] );
701 $use_default_selected = ( trim( (string) $f['isRequired'] ) && ! $f['value'] );
702 if( ! empty( $f['values'] ) ) {
703 $field_html .= '<select name="' . esc_attr( $f['fieldName'] ) . '"
704 id="' . esc_attr( $f['fieldId'] ) . '"
705 class="' . esc_attr( $f['class'] ) . '"
706 ' . $f['isMultiChoice'] . ' ' . $f['isDisabled'] . '
707 ' . $f['isRequired'] . ' ' . $f['attributes'] . '>';
708 if( ! $f['isRequired'] ) {
709 $field_html .= apply_filters( 'wpforo_form_field_select_first_option', '<option value="">' . wpforo_phrase( '--- Choose ---', false ) . '</option>', $f );
710 }
711 foreach( $f['values'] as $optgroup => $row ) {
712 if( is_array( $row ) && ! empty( $row ) ) {
713 $field_html .= '<optgroup label="' . esc_attr( $optgroup ) . '">';
714 foreach( $row as $sub_row ) {
715 $item = $this->build_item_value_lable( $sub_row );
716 $item['value'] = ( $f['name'] === 'timezone' ) ? str_replace( ' ', '_', $item['value'] ) : $item['value'];
717 $field_html .= '<option value="' . esc_attr( $item['value'] ) . '" ' . ( $use_default_selected ? ( $item['default_selected'] ? ' selected ' : '' ) : $this->select(
718 $item['value'],
719 $f['value']
720 ) ) . '>' . esc_html( $item['label'] ) . '</option>';
721 }
722 $field_html .= '</optgroup>';
723 } else {
724 $item = $this->build_item_value_lable( $row );
725 $item['value'] = ( $f['name'] === 'timezone' ) ? str_replace( ' ', '_', $item['value'] ) : $item['value'];
726 $field_html .= '<option value="' . esc_attr( $item['value'] ) . '" ' . ( $use_default_selected ? ( $item['default_selected'] ? ' selected ' : '' ) : $this->select(
727 $item['value'],
728 $f['value']
729 ) ) . '>' . esc_html( $item['label'] ) . '</option>';
730 }
731 }
732 $field_html .= '</select>';
733 }
734
735 return $field_html;
736 }
737
738 public function generate_multi_item( $val, $dvalues = [], $save_button = false ) {
739 return sprintf(
740 '<div class="wpf-multi-item wpf-multi-item-known-%1$d"><span class="wpf-multi-item-value">%2$s</span>%3$s<span class="wpf-multi-item-action wpf-del" title="%4$s"><i class="fa-solid fa-xmark" title="%4$s"></i></span></div>',
741 (int) in_array( $val, $dvalues, true ),
742 $val,
743 ( $save_button ? sprintf(
744 '<span class="wpf-multi-item-action wpf-save-variant" title="%1$s"><i class="fa-regular fa-floppy-disk" title="%1$s"></i></span>',
745 wpforo_phrase( 'Add to pre-defined values', false )
746 ) : '' ),
747 wpforo_phrase( 'remove', false )
748 );
749 }
750
751 /**
752 * Radio - Field builder
753 *
754 * @param array $f field arguments
755 *
756 * @return string field HTML
757 */
758 public function field_autocomplete( $f ) {
759 $f['value'] = $this->build_array_value( $f['value'], "\n" );
760 $f['values'] = $this->build_array_using_string_rows( $f['values'] );
761 $save_button = (int) wpfval( $f, 'formid' ) > 0 && array_intersect( WPF()->current_user_groupids, (array) wpfval( $f, 'UGroupIdsFrontAddNewDefaultValues' ) );
762
763 return sprintf(
764 '<%1$s data-dbvariants="%16$s" data-formid="%2$d" data-fieldkey="%3$s">%4$s<input type="text" name="%5$s" list="%6$s" class="%7$s" value="%8$s" autocomplete="off" %9$s %10$s %11$s %12$s><span class="wpf-invalid-msg wpf-required">%13$s</span><span class="wpf-invalid-msg wpf-not-allowed-value">%14$s</span>%15$s</%1$s>',
765 ( $f['isMultiChoice'] ? 'wpf-multi-input' : 'wpf-autocomplete-input' ),
766 (int) wpfval( $f, 'formid' ),
767 $f['fieldKey'],
768 ( $f['isMultiChoice'] ? sprintf( '<template id="wpf-multi-item-template">%1$s</template>', $this->generate_multi_item( '', [], $save_button ) ) . implode(
769 '',
770 array_map( function( $val ) use ( $f, $save_button ) { return $this->generate_multi_item( $val, $f['values'], $save_button ); }, array_filter( $f['value'] ) )
771 ) : '' ),
772 esc_attr( $f['fieldName'] ),
773 esc_attr( $f['fieldId'] ),
774 esc_attr( $f['class'] ),
775 ( ! $f['isMultiChoice'] ? current( $f['value'] ) : '' ),
776 $f['isDisabled'],
777 $f['isRequired'],
778 $f['attributes'],
779 ( (int) $f['isAllowedCustomValues'] || $save_button ? 'allow-custom-values' : '' ),
780 wpforo_phrase( 'This Field is Required', false ),
781 wpforo_phrase( 'Wrong Value (This Field Allows Only Predefined Values)', false ),
782 ( ( $values = (array) wpfval( $f, 'values' ) ) ? sprintf(
783 '<datalist id="%1$s">%2$s</datalist>',
784 esc_attr( $f['fieldId'] ),
785 implode(
786 '',
787 array_map(
788 function( $value ) {
789 return sprintf( '<option value="%1$s"></option>', esc_attr( $value ) );
790 },
791 array_diff( $values, $f['value'] )
792 )
793 )
794 ) : '' ),
795 esc_attr( json_encode( $f['values'] ) )
796 );
797 }
798
799 /**
800 * Usergroup - Field builder
801 *
802 * @param array $f field arguments
803 *
804 * @return string field HTML
805 */
806 public function field_usergroup( $f ) {
807 $field_html = '';
808 if( ! empty( $f['allowedGroupIds'] ) ) {
809 $field_html .= '<select name="' . esc_attr( $f['fieldName'] ) . '"
810 id="' . esc_attr( $f['fieldId'] ) . '"
811 class="' . esc_attr( $f['class'] ) . '"
812 ' . $f['isDisabled'] . ' ' . $f['isRequired'] . ' ' . $f['attributes'] . '>';
813
814 $field_html .= '<option value="">' . wpforo_phrase( '--- Choose ---', false ) . '</option>';
815 foreach( $f['allowedGroupIds'] as $groupid ) {
816 if( $f['value'] != 4 && $groupid == 4 ) continue;
817 if( $group = WPF()->usergroup->get_usergroup( $groupid ) ) {
818 $field_html .= '<option value="' . esc_attr( $groupid ) . '" ' . $this->select( $groupid, $f['value'] ) . '>' . $group['name'] . '</option>';
819 }
820 }
821 $field_html .= '</select>';
822 }
823
824 return $field_html;
825 }
826
827 public function field_secondary_groups( $f ) {
828 $field_html = '';
829 if( $groups = WPF()->usergroup->get_secondary_groups() ) {
830 $allowed_groupids = (array) wpfval( $f, 'allowedGroupIds' );
831 $i = 0;
832 $field_html .= '<input type="hidden" name="' . esc_attr( $f['fieldName'] ) . '" value="">';
833 foreach( $groups as $group ) {
834 if( in_array( $group['groupid'], [ 1, 2, 4 ] ) || ( $allowed_groupids && ! in_array( $group['groupid'], $allowed_groupids ) ) ) continue;
835 $id = $f['fieldId'] . '_' . ++ $i;
836 $field_html .= '<div class="wpf-field-item">';
837 $item_html = '<input type="checkbox" ' . $this->check( $group['groupid'], $f['value'] ) . '
838 name="' . esc_attr( $f['fieldName'] . '[]' ) . '"
839 value="' . esc_attr( $group['groupid'] ) . '"
840 id="' . esc_attr( $id ) . '"
841 class="wpf-input-checkbox ' . esc_attr( $f['class'] ) . '"
842 ' . $f['isDisabled'] . ' ' . $f['attributes'] . '>';
843 $field_html .= $this->build_label( $group['name'], $item_html, $f, $id );
844 $field_html .= '</div>';
845 }
846 }
847
848 return $field_html;
849 }
850
851 /**
852 * Avatar - Field builder
853 *
854 * @param array $f field arguments
855 *
856 * @return string field HTML
857 */
858 public function field_avatar( $f ) {
859 $protocol = is_ssl() ? 'https://' : 'http://';
860 $remote_url = ( $f['value'] && strpos( (string) $f['value'], 'wpforo/avatars' ) === false ) ? $f['value'] : '';
861 $field_html = '<ul>
862 <li>
863 <input ' . $f['isRequired'] . ' name="' . esc_attr(
864 $f['varname']
865 ) . '[avatar_type]" id="wpfat_gravatar" value="gravatar" ' . ( $f['value'] == '' || $f['value'] == null ? 'checked="checked"' : '' ) . ' type="radio" />&nbsp;
866 <label for="wpfat_gravatar">' . wpforo_phrase( 'Default avatar', false ) . '</label>
867 </li>
868 <li>
869 <input name="' . esc_attr( $f['varname'] ) . '[avatar_type]" id="wpfat_remote" value="remote" ' . ( $f['value'] && strpos(
870 (string) $f['value'],
871 'wpforo/avatars'
872 ) === false ? 'checked="checked"' : '' ) . ' type="radio" />&nbsp;
873 <label for="wpfat_remote">' . wpforo_phrase( 'Specify avatar by URL:', false ) . '</label>
874 <input autocomplete="off" name="' . esc_attr( $f['varname'] ) . '[avatar_url]" value="' . esc_url( preg_replace( '|^//|is', $protocol, (string) $remote_url ) ) . '" maxlength="990" data-wpfucf-minmaxlength="1,990" type="url" />
875 </li>';
876 if( ( wpfval( WPF()->current_object, 'template' ) && WPF()->current_object['template'] === 'register' ) || WPF()->usergroup->can( 'upa' ) ) {
877 if( strpos( (string) $f['value'], 'gravatar.com' ) === false && strpos( $f['value'], 'facebook.com' ) === false ) {
878 $url = $f['value'] . '?lm=' . time();
879 } else {
880 $url = '';
881 }
882 $field_html .= '<li>
883 <input name="' . esc_attr( $f['varname'] ) . '[avatar_type]" id="wpfat_custom" value="custom" type="radio" ' . ( ( strpos( $url, 'wpforo/avatars' ) !== false ) ? 'checked' : '' ) . ' />&nbsp;
884 <label for="wpfat_custom"> ' . wpforo_phrase( 'Upload an avatar', false ) . '</label>' . ( strpos( $url, 'wpforo/avatars' ) !== false ? '<br />
885 <img src="' . esc_url( (string) $url ) . '" class="wpf-custom-avatar-img" alt="avatar">' : '' ) . '&nbsp;
886 <input class="wpf-custom-avatar" name="avatar" type="file" />&nbsp;</li>';
887 }
888 $field_html .= '</ul> <script type="text/javascript">jQuery(document).ready(function($){$( "input[name=\'' . esc_attr(
889 $f['varname']
890 ) . '\[avatar_url\]\']" ).on("click", function(){$( "#wpfat_remote" ).prop(\'checked\', true);}); $( "input[name=\'avatar\']" ).on("click", function(){$( "#wpfat_custom" ).prop(\'checked\', true);});});</script>';
891
892 return $field_html;
893 }
894
895 /**
896 * HTML - Field builder
897 *
898 * @param array $f field arguments
899 *
900 * @return string field HTML
901 */
902 public function field_html( $f ) {
903 return stripslashes( do_shortcode( wpforo_apply_ucf_shortcode( (string) $f['html'] ) ) );
904 }
905
906 /**
907 * URL - Field builder
908 *
909 * @param array $f field arguments
910 *
911 * @return string field HTML
912 */
913 public function field_url( $f ) {
914 return '<input type="url" value="' . esc_url_raw( $f['value'] ) . '"
915 name="' . esc_attr( $f['fieldName'] ) . '"
916 id="' . esc_attr( $f['fieldId'] ) . '"
917 class="' . esc_attr( $f['class'] ) . '"
918 placeholder="' . esc_attr( $f['placeholder'] ) . '"
919 ' . $f['isRequired'] . ' ' . $f['isDisabled'] . ' ' . $f['attributes'] . ' ' . $f['minmax'] . '/>';
920 }
921
922 /**
923 * Nickname - Field builder
924 *
925 * @param array $f field arguments
926 *
927 * @return string field HTML
928 */
929 public function field_nicename( $f ) {
930 return '<input type="text" value="' . esc_attr( urldecode( (string) $f['value'] ) ) . '"
931 name="' . esc_attr( $f['fieldName'] ) . '"
932 id="' . esc_attr( $f['fieldId'] ) . '"
933 class="' . esc_attr( $f['class'] ) . '"
934 placeholder="' . esc_attr( $f['placeholder'] ) . '"
935 ' . $f['isRequired'] . ' ' . $f['isDisabled'] . ' ' . $f['attributes'] . ' ' . $f['minmax'] . '/>';
936 }
937
938 /**
939 * Text - Field builder
940 *
941 * @param array $f field arguments
942 *
943 * @return string field HTML
944 */
945 public function field_text( $f ) {
946 return '<input type="' . esc_attr( $f['type'] ) . '"
947 value="' . esc_attr( $f['value'] ) . '"
948 name="' . esc_attr( $f['fieldName'] ) . '"
949 id="' . esc_attr( $f['fieldId'] ) . '"
950 class="' . esc_attr( $f['class'] ) . '"
951 placeholder="' . esc_attr( $f['placeholder'] ) . '"
952 ' . $f['isRequired'] . ' ' . $f['isDisabled'] . ' ' . $f['attributes'] . ' ' . $f['minmax'] . '/>';
953 }
954
955 public function field_tel( $f ) {
956 return '<input type="' . esc_attr( $f['type'] ) . '"
957 value="' . esc_attr( $f['value'] ) . '"
958 name="' . esc_attr( $f['fieldName'] ) . '"
959 id="' . esc_attr( $f['fieldId'] ) . '"
960 class="' . esc_attr( $f['class'] ) . '"
961 placeholder="' . esc_attr( $f['placeholder'] ) . '"
962 ' . $f['isRequired'] . ' ' . $f['isDisabled'] . ' ' . $f['attributes'] . ' ' . $f['minmax'] . '
963 pattern="' . ( ! empty( $f['pattern'] ) ? $f['pattern'] : '[0-9]*' ) . '">';
964 }
965
966 /**
967 * Prepares displayed values for Profile fields
968 *
969 * @param array $f field arguments
970 * @param int $userid
971 *
972 * @return array prepared values
973 */
974 public function prepare_values( $f, $userid = 0 ) {
975 switch( $f['type'] ) {
976 case 'textarea':
977 $f['value'] = wpforo_kses( wpforo_decode( $f['value'] ) );
978 break;
979 case 'date':
980 // $f['value'] = wpforo_date($f['value'], 'date', false);
981 break;
982 case 'datetime':
983 $f['value'] = wpforo_date( $f['value'], 'datetime', false );
984 break;
985 case 'url':
986 $f['value'] = sprintf( '<a href="%1$s" target="_blank" rel="nofollow">%2$s</a>', $f['value'], $f['value'] );
987 break;
988 case 'email':
989 $f['value'] = sprintf( '<a href="mailto:%1$s" rel="nofollow">%2$s</a>', $f['value'], $f['value'] );
990 break;
991 case 'tel':
992 $f['value'] = sprintf( '<a href="tel:%1$s" rel="nofollow">%2$s</a>', $f['value'], $f['value'] );
993 break;
994 case 'file':
995 if( ! empty( $f['value'] ) ) {
996 if( is_array( $f['value'] ) ) {
997 $file_name = (string) wpfval( $f['value'], 'filename' );
998 $f['value'] = (string) wpfval( $f['value'], 'fileurl' );
999 } else {
1000 $file_name = basename( (string) $f['value'] );
1001 }
1002 $f['value'] = wpforo_fix_upload_url( $f['value'] );
1003 $file_url = esc_url_raw( $f['value'] );
1004 $file_name = esc_attr( $file_name );
1005 $extension = pathinfo( $f['value'], PATHINFO_EXTENSION );
1006 if( wpforo_is_image( $extension ) ) {
1007 $f['value'] = sprintf(
1008 '<a href="%1$s" target="_blank" title="%2$s"><img src="%1$s" alt="%2$s" class="wpf-field-file-img" style="max-width:120px; max-height:120px"></a>',
1009 $file_url,
1010 $file_name
1011 );
1012 } elseif( wpforo_is_audio( $extension ) ) {
1013 $f['value'] = sprintf( '<audio src="%1$s" controls title="%2$s"></audio>', $file_url, $file_name );
1014 } elseif( wpforo_is_video( $extension ) ) {
1015 $f['value'] = sprintf( '<video src="%1$s" controls title="%2$s"></video>', $file_url, $file_name );
1016 } else {
1017 $f['value'] = sprintf( '<a href="%s" target="_blank">%s</a>', $file_url, $file_name );
1018 }
1019 }
1020 break;
1021 case 'avatar':
1022 $f['value'] = ( WPF()->usergroup->can( 'va' ) && wpforo_setting( 'profiles', 'avatars' ) ) ? WPF()->member->get_avatar_html( $f['value'], $userid ) : '';
1023 break;
1024 case 'color':
1025 if( $f['value'] ) {
1026 $f['value'] = '<input type="color" value="' . $f['value'] . '" disabled title="' . $f['value'] . '" style="min-width: 100px; min-height: 25px;">';
1027 }
1028 break;
1029 }
1030 switch( $f['name'] ) {
1031 case 'skype':
1032 $f['value'] = sprintf( '<a href="skype:%s?userinfo" rel="nofollow">%s</a>', $f['value'], $f['value'] );
1033 break;
1034 case 'location':
1035 $f['value'] = sprintf( '<a href="//maps.google.com/?q=%s" target="_blank" rel="nofollow">%s</a>', $f['value'], $f['value'] );
1036 break;
1037 case 'signature':
1038 $f['value'] = wpforo_signature( $f['value'], [ 'echo' => 0 ] );
1039 break;
1040 case 'about':
1041 $f['value'] = wpforo_nofollow_tag( $f['value'] );
1042 break;
1043 }
1044
1045 return apply_filters( 'wpforo_form_prepare_values', $f );
1046 }
1047
1048 /**
1049 * Prepares arguments
1050 *
1051 * @param array $f field arguments
1052 *
1053 * @return array prepared values
1054 */
1055 public function prepare_args( $f ) {
1056
1057 $is_owner = $this->owner();
1058
1059 //field_class
1060 $f['field_class'] = sanitize_text_field( $f['name'] );
1061
1062 //varname
1063 $f['varname'] = $f['isDefault'] ? (string) wpfval( $this->current, 'varname' ) : 'data';
1064
1065 //template
1066 $f['template'] = ( isset( $this->current['template'] ) ) ? $this->current['template'] : WPF()->current_object['template'];
1067
1068 //value
1069 $f['value'] = ( isset( $this->current['value'][ $f['name'] ] ) ) ? $this->current['value'][ $f['name'] ] : $f['value'];
1070 if( ! $f['isDefault'] && $f['varname'] ) {
1071 $f['value'] = ( isset( $this->current['value'][ $f['varname'] ][ $f['name'] ] ) ) ? $this->current['value'][ $f['varname'] ][ $f['name'] ] : $f['value'];
1072 }
1073 $f['value'] = wpforo_unslashe( $f['value'] );
1074 $f['value'] = wpforo_decode( $f['value'] );
1075
1076 if( $f['name'] === 'user_nicename' ) {
1077 $f['value'] = urldecode( (string) $f['value'] );
1078 }
1079
1080 //allowedGroupIds
1081 $groups = [];
1082 if( ! empty( $f['allowedGroupIds'] ) ) $groups = $this->build_array_value( $f['allowedGroupIds'] );
1083 if( $f['type'] === 'usergroup' ) {
1084 if( ! $is_owner && wpforo_current_user_is( 'admin' ) ) {
1085 $groups = WPF()->usergroup->get_usergroups( 'groupid' );
1086 } elseif( $is_owner && ! in_array( WPF()->current_user_groupid, $f['allowedGroupIds'] ) ) {
1087 $groups = [];
1088 }
1089 }
1090 $f['allowedGroupIds'] = array_filter( $groups );
1091
1092 //isRequired
1093 if( $f['isRequired'] ) {
1094 $f['required_class'] = ' wpf-field-required ';
1095 $f['required_indicator'] = ' <span class="wpf-field-required-icon" title="' . esc_attr( wpforo_phrase( 'Required field', false ) ) . '">*</span>';
1096 } else {
1097 $f['required_class'] = '';
1098 $f['required_indicator'] = '';
1099 }
1100
1101 return $f;
1102 }
1103
1104 /**
1105 * @param array $f field arguments
1106 *
1107 * @return array prepared values
1108 */
1109 public function prepare_field_args( $f ) {
1110 //faIcon
1111 $f['faIcon'] = trim( (string) $f['faIcon'] );
1112 if( strpos( $f['faIcon'], ' ' ) === false ) $f['faIcon'] = 'fas ' . $f['faIcon'];
1113
1114 //isRequired
1115 $f['isRequired'] = ( $f['isRequired'] ) ? ' required="required" ' : '';
1116
1117 //isDisabled
1118 $f['isDisabled'] = ( $f['isDisabled'] ) ? ' disabled="disabled" ' : '';
1119
1120 //fieldName | new key in args
1121 $f['fieldName'] = ( ! empty( $f['varname'] ) ? $f['varname'] . '[' . $f['name'] . ']' : $f['name'] );
1122
1123 //isMultiChoice
1124 if( $f['isMultiChoice'] ) {
1125 $f['fieldName'] .= '[]';
1126 $f['isMultiChoice'] = ' multiple="multiple" ';
1127 } else {
1128 $f['isMultiChoice'] = '';
1129 }
1130
1131 //fieldId | new key in args
1132 $f['fieldId'] = ( $f['varname'] ? $f['varname'] . '_' : '' ) . ( $f['id'] ?: $f['name'] );
1133 $f['fieldId'] = uniqid( $f['fieldId'] . '_' );
1134
1135 //minLength & maxLength
1136 $f['minLength'] = ( $f['minLength'] ) ? intval( $f['minLength'] ) : '';
1137 $f['maxLength'] = ( $f['maxLength'] ) ? intval( $f['maxLength'] ) : '';
1138 if( $f['minLength'] ) {
1139 $minLength_attr = ( $f['type'] === 'date' || $f['type'] === 'number' || $f['type'] === 'range' ) ? ' min="' . $f['minLength'] . '" ' : ' minlength="' . $f['minLength'] . '" ';
1140 }
1141 if( $f['maxLength'] ) {
1142 $maxLength_attr = ( $f['type'] === 'date' || $f['type'] === 'number' || $f['type'] === 'range' ) ? ' max="' . $f['maxLength'] . '" ' : ' maxlength="' . $f['maxLength'] . '" ';
1143 }
1144 $f['minmax'] = isset( $minLength_attr ) ? $minLength_attr : '';
1145 $f['minmax'] .= isset( $maxLength_attr ) ? ' ' . $maxLength_attr : '';
1146
1147 //attributes
1148 $f['attributes'] .= ' autocomplete="off"';
1149
1150 if( wpfkey( $f, 'fileExtensions' ) ) {
1151 if( is_scalar( $f['fileExtensions'] ) ) $f['fileExtensions'] = explode( ',', $f['fileExtensions'] );
1152 $f['fileExtensions'] = array_filter( $f['fileExtensions'] );
1153 }
1154
1155 return $f;
1156 }
1157
1158 /**
1159 * @param array $file_data
1160 * @param int $userid
1161 *
1162 * @return array
1163 */
1164 public function prepare_file_args( $file_data, $userid = 1 ) {
1165 $file = [ 'files' => [], 'fields' => [] ];
1166 $userid = $userid ?: WPF()->current_userid;
1167
1168 if( ! empty( $file_data ) ) {
1169 foreach( $file_data as $file_field_name => $file_name ) {
1170 $field_name_folder = substr( (string) $file_field_name, 6 );
1171 $file_upload_dir = wpforo_fix_dir_sep(
1172 WPF()->folders['wp_upload']['dir'] . $this->field_dir . $userid . DIRECTORY_SEPARATOR . $field_name_folder
1173 ) . DIRECTORY_SEPARATOR;
1174 $file_path = $file_upload_dir . $file_name;
1175 $file['files'][ $file_field_name ] = $file_path;
1176 $file['fields'][ $file_field_name ] = $this->field_dir . $userid . '/' . $field_name_folder . '/' . $file_name;
1177 wp_mkdir_p( $file_upload_dir );
1178 }
1179 }
1180
1181 return $file;
1182 }
1183
1184 public function check( $needle, $haystack ) {
1185 if( is_scalar( $haystack ) ) $haystack = explode( ',', $haystack );
1186
1187 return in_array( $needle, (array) $haystack ) ? 'checked' : '';
1188 }
1189
1190 public function select( $needle, $haystack ) {
1191 return in_array( $needle, (array) $haystack ) ? 'selected' : '';
1192 }
1193
1194 public function build_label( $item_label, $item_html, $f, $for = '' ) {
1195 $label = '<label for="' . $for . '" class="wpf-' . $f['type'] . '-label">' . stripslashes( (string) $item_label ) . '</label>';
1196 $field_html = $f['isLabelFirst'] ? $label . '&nbsp;' . $item_html : $item_html . '&nbsp;' . $label;
1197 if( $f['isWrapItem'] ) $field_html = '<label for="' . $for . '">' . $field_html . '</label>';
1198
1199 return $field_html;
1200 }
1201
1202 public function build_item_value_lable( $string, $sep = '=>' ) {
1203 $string = trim( (string) $string );
1204 $count = 0;
1205 $string = preg_replace( '#^\[(.+?)]$#isu', '$1', (string) $string, 1, $count );
1206 $default_selected = (bool) $count;
1207 $data = explode( $sep, $string );
1208 $value = wpfkey( $data, 0 ) ? trim( (string) $data[0] ) : 'no_value';
1209 $label = wpfkey( $data, 1 ) ? trim( (string) $data[1] ) : $value;
1210
1211 return compact( 'value', 'label', 'default_selected' );
1212 }
1213
1214 public function build_array_value( $var, $sep = ',' ) {
1215 if( is_scalar( $var ) ) {
1216 $var = trim( (string) $var );
1217 if( ! strlen( (string) $var ) ) return [];
1218 }
1219 if( is_serialized( $var ) ) {
1220 $var = unserialize( $var );
1221 } elseif( is_scalar( $var ) && strpos( (string) $var, $sep ) !== false ) {
1222 $var = explode( $sep, $var );
1223 }
1224
1225 return array_map( 'trim', (array) $var );
1226 }
1227
1228 public function build_array_using_string_rows( $string, $regexp = '' ) {
1229 if( is_scalar( $string ) ) {
1230 if( ! $regexp ) $regexp = '#' . preg_quote( PHP_EOL ) . '#isu';
1231
1232 return array_filter( preg_split( $regexp, $string ) );
1233 }
1234
1235 return $string;
1236 }
1237
1238 public function sanitize( $data, $fields ) {
1239 $types = $this->field_types( $fields );
1240 if( ! empty( $data ) && ! empty( $types ) ) {
1241 foreach( $data as $name => $value ) {
1242 if( wpfval( $types, $name ) ) {
1243 $data[ $name ] = $this->sanitize_field( $value, $types[ $name ], $name );
1244 }
1245 }
1246 }
1247
1248 return $data;
1249 }
1250
1251 public function sanitize_field( $value, $type = 'text', $name = '' ) {
1252 if( ! is_null( $value ) ) {
1253 if( $type === 'text' ) {
1254 $value = sanitize_text_field( $value );
1255 if( $name === 'user_nicename' ) {
1256 $value = sanitize_title( sanitize_user( $value, true ) );
1257 }
1258 } elseif( $type === 'url' ) {
1259 $value = esc_url_raw( $value );
1260 } elseif( $type === 'date' ) {
1261 $value = sanitize_text_field( $value );
1262 } elseif( $type === 'textarea' ) {
1263 $value = stripslashes( wpforo_kses( trim( (string) $value ), 'user_description' ) );
1264 } elseif( $type === 'email' ) {
1265 $value = sanitize_email( $value );
1266 } elseif( $type === 'password' ) {
1267 $value = trim( (string) $value );
1268 } elseif( $type === 'usergroup' ) {
1269 $value = intval( $value );
1270 } elseif( $type === 'radio' ) {
1271 $value = sanitize_text_field( $value );
1272 } elseif( $type === 'checkbox' ) {
1273 if( $name === 'secondary_groupids' ) {
1274 $value = wpforo_sanitize_int( $value );
1275 } else {
1276 $value = wpforo_sanitize_text( $value );
1277 }
1278 } elseif( $type === 'select' ) {
1279 $value = sanitize_text_field( $value );
1280 } elseif( $type === 'color' ) {
1281 $value = sanitize_text_field( $value );
1282 } elseif( $type === 'number' ) {
1283 $value = intval( $value );
1284 } elseif( $type === 'tel' ) {
1285 $value = sanitize_text_field( $value );
1286 } elseif( $type === 'html' ) {
1287 $value = preg_replace( '#<script(.*?)>(.*?)</script>#is', '', (string) $value );
1288 }
1289
1290 if( is_string( $value ) ) {
1291 $value = stripslashes( (string) $value );
1292 }
1293 }
1294
1295 return $value;
1296 }
1297
1298 public function esc_field( $f ) {
1299 if( wpfkey( $f, 'value' ) ) {
1300 $f['value'] = wpforo_trim( $f['value'] );
1301 if( in_array( wpfval( $f, 'type' ), [ 'textarea', 'tinymce' ], true ) ) {
1302 $f['value'] = wpautop( wpforo_kses( stripslashes( (string) $f['value'] ) ) );
1303 } elseif( wpfval( $f, 'type' ) === 'file' ) {
1304 $f['value'] = wpfval( $f['value'], 'fileurl' ) ?: $f['value'];
1305 } elseif( $f['name'] === 'timezone' ) {
1306 $f['value'] = str_replace( '_', ' ', $f['value'] );
1307 } elseif( $f['fieldKey'] === 'secondary_groupids' ) {
1308 $f['value'] = WPF()->usergroup->get_secondary_group_names( $f['value'] );
1309 $f['value'] = implode( ', ', $f['value'] );
1310 } elseif( $f['type'] === 'usergroup' && $f['fieldKey'] === 'groupid' && ( $f['value'] = intval( $f['value'] ) ) ) {
1311 if( $group = WPF()->usergroup->get_usergroup( $f['value'] ) ) $f['value'] = wpfval( $group, 'name' );
1312 } elseif( is_array( $f['value'] ) ) {
1313 $f['value'] = array_filter( $f['value'] );
1314 $f['value'] = implode( ', ', $f['value'] );
1315 }
1316 }
1317 $f['value'] = apply_filters( 'wpforo_display_field_value', $f['value'], $f );
1318
1319 return $f;
1320 }
1321
1322 public function validate( &$data, &$fields ) {
1323 $type = '';
1324 $label = '';
1325 $userid = '';
1326 $error = [];
1327 $return = [];
1328 $is_owner = $this->owner();
1329 $template = ( isset( $this->current['template'] ) ) ? $this->current['template'] : WPF()->current_object['template'];
1330 if( empty( $data ) ) $error[] = 'No data submitted';
1331 if( empty( $fields ) ) $error[] = 'User profile fields not found';
1332 if( empty( $error ) ) {
1333 foreach( $fields as $r_key => $rows ) {
1334 foreach( $rows as $c_key => $cols ) {
1335 foreach( $cols as $key => $field ) {
1336 if( wpfval( $field, 'name' ) ) {
1337 $name = $field['name'];
1338 if( ! $template && wpfval( $field, 'template' ) ) $template = $field['template'];
1339 if( wpfval( $field, 'label' ) ) $label = esc_html( $field['label'] );
1340 if( wpfval( $field, 'type' ) ) $type = $field['type'];
1341 if( wpfval( $data, 'userid' ) ) $userid = $data['userid'];
1342 if( $template && $template !== 'register' ) {
1343 if( $template === 'account' && $field['type'] === 'password' ) $field['isRequired'] = 0;
1344 if( ! $this->can_edit( $field ) ) {
1345 unset( $cols[ $key ] );
1346 unset( $data[ $name ] );
1347 unset( $fields[ $r_key ][ $c_key ][ $key ] );
1348 }
1349 }
1350 if( wpfkey( $cols, $key ) && wpfkey( $data, $name ) ) {
1351 $value = $data[ $name ];
1352 if( is_string( $value ) ) {
1353 $value = trim( $value );
1354 $value = htmlspecialchars_decode( $value );
1355 }
1356 if( wpfval( $field, 'isRequired' ) && ! $value ) {
1357 $error[] = $label . ' ' . wpforo_phrase( 'field is required', false, false );
1358 }
1359 if( $value ) {
1360 if( $type === 'number' ) {
1361 if( wpfval( $field, 'minLength' ) ) {
1362 if( (int) $value < $field['minLength'] ) {
1363 $error[] = $label . ' ' . sprintf( wpforo_phrase( 'field value must be at least %d', false, false ), intval( $field['minLength'] ) );
1364 }
1365 }
1366 if( wpfval( $field, 'maxLength' ) ) {
1367 if( (int) $value > $field['maxLength'] ) {
1368 $error[] = $label . ' ' . sprintf( wpforo_phrase( 'field value cannot be greater than %d', false, false ), intval( $field['maxLength'] ) );
1369 }
1370 }
1371 } else {
1372 if( wpfval( $field, 'minLength' ) ) {
1373 if( wpforo_strlen( $value ) < $field['minLength'] ) {
1374 $error[] = $label . ' ' . sprintf( wpforo_phrase( 'field length must be at least %d characters', false, false ), intval( $field['minLength'] ) );
1375 }
1376 }
1377 if( wpfval( $field, 'maxLength' ) ) {
1378 if( wpforo_strlen( $value ) > $field['maxLength'] ) {
1379 $error[] = $label . ' ' . sprintf( wpforo_phrase( 'field length cannot be greater than %d characters', false, false ), intval( $field['maxLength'] ) );
1380 }
1381 }
1382 }
1383 if( $type === 'url' && filter_var( $value, FILTER_VALIDATE_URL ) === false ) {
1384 $error[] = $label . ' ' . wpforo_phrase( 'field value is not a valid URL', false, false );
1385 }
1386 if( $type === 'email' ) {
1387 if( ! is_email( $value ) ) {
1388 $error[] = $label . ' ' . wpforo_phrase( 'Invalid Email address', false, false );
1389 }
1390 if( $name === 'user_email' ) {
1391 $email_owner = email_exists( $value );
1392 if( $email_owner && $email_owner != $userid ) {
1393 $error[] = $label . ' ' . wpforo_phrase( 'This email address is already registered. Please insert another', false, false );
1394 }
1395 }
1396 }
1397 if( $type === 'file' ) {
1398 $extension = pathinfo( $value, PATHINFO_EXTENSION );
1399 $extension = ( function_exists( 'mb_strtolower' ) ) ? mb_strtolower( (string) $extension ) : strtolower( (string) $extension );
1400 if( wpfval( $field, 'fileExtensions' ) ) {
1401 if( $extension ) {
1402 if( ! in_array( $extension, $field['fileExtensions'] ) ) {
1403 $error[] = $label . ' ' . wpforo_phrase( 'file type is not allowed', false, false );
1404 $error[] = sprintf( 'Allowed file types: %s', implode( ', ', $field['fileExtensions'] ) );
1405 }
1406 } else {
1407 $error[] = $label . ' ' . wpforo_phrase( 'file type is not detected', false, false );
1408 }
1409 } else {
1410 $mime_types = get_allowed_mime_types();
1411 $mime_types = array_flip( $mime_types );
1412 if( ! empty( $mime_types ) ) {
1413 $implode_types = implode( '|', $mime_types );
1414 $explode_types = explode( '|', $implode_types );
1415 if( ! in_array( $extension, $explode_types ) ) {
1416 $error[] = $label . ' ' . sprintf( wpforo_phrase( 'file type %s is not allowed', false, false ), $extension );
1417 }
1418 if( ! WPF()->perm->can_attach_file_type( $extension ) ) {
1419 $error[] = 'You are not allowed to attach this file type';
1420 }
1421 }
1422 }
1423 if( wpfval( $field, 'fileSize' ) ) {
1424 if( wpfval( $_FILES, 'data', 'size', $name ) && $_FILES['data']['size'][ $name ] > ( $field['fileSize'] * 1024 * 1024 ) ) {
1425 $error[] = $label . ' ' . wpforo_phrase( 'file is too large', false, false );
1426 $error[] = sprintf( 'Maximum allowed file size is %s MB', $field['fileSize'] );
1427 }
1428 }
1429 }
1430 if( $name === 'user_nicename' ) {
1431 $value = sanitize_text_field( $value );
1432 $user_nicename = sanitize_title( sanitize_user( $value, true ) );
1433 if( ! $user_nicename ) {
1434 $error[] = 'Nickname validation failed';
1435 }
1436 $sql = "SELECT `ID` FROM `" . WPF()->db->users . "` WHERE `ID` != " . intval( $userid ) . " AND `user_nicename` LIKE '" . esc_sql( $user_nicename ) . "'";
1437 if( WPF()->db->get_var( $sql ) ) {
1438 $error[] = 'This nickname is already in use. Please insert another.';
1439 }
1440 }
1441 if( $name === 'groupid' ) {
1442 if( $template !== 'register' ) {
1443 if( $is_owner || ! wpforo_current_user_is( 'admin' ) ) {
1444 $error[] = 'You have no permission to edit Usergroup field';
1445 }
1446 } else {
1447 if( in_array( $value, [ 1, 2, 4 ] ) ) {
1448 $error[] = 'Admin and Moderator Usergroups are not permitted';
1449 } else {
1450 if( wpfval( $field, 'allowedGroupIds' ) ) {
1451 $allowedGroupIds = wpforo_parse_args( $field['allowedGroupIds'] );
1452 if( ! in_array( $value, $allowedGroupIds ) ) {
1453 $error[] = 'The selected Usergroup cannot be set';
1454 }
1455 } else {
1456 $error[] = 'The selected Usergroup is not found in allowed list';
1457 }
1458 }
1459 }
1460 }
1461 if( $name === 'secondary_groupids' ) {
1462 if( $template === 'register' || ( $is_owner && $field['isEditable'] ) || ( ! $is_owner && in_array(
1463 WPF()->current_user_groupid,
1464 (array) $field['canEdit']
1465 ) ) || wpforo_current_user_is( 'admin' ) ) {
1466 if( ! empty( $value ) && is_array( $value ) ) {
1467 $secondary_groupids = WPF()->usergroup->get_secondary_groupids();
1468 foreach( $value as $secondary_groupid ) {
1469 if( in_array( $secondary_groupid, [ 1, 2, 4 ] ) ) {
1470 $error[] = 'Admin and Moderator Usergroups are not permitted';
1471 }
1472 if( $secondary_groupid && ! in_array( $secondary_groupid, $secondary_groupids ) ) {
1473 $error[] = 'One of the selected Usergroups cannot be set as Secondary';
1474 }
1475 }
1476 }
1477 } else {
1478 $error[] = 'You have no permission to edit Usergroup field';
1479 }
1480 }
1481 }
1482 }
1483 }
1484 }
1485 }
1486 }
1487 }
1488 if( ! empty( $error ) ) {
1489 $return['error'] = $error;
1490
1491 return $return;
1492 } else {
1493 return true;
1494 }
1495 }
1496
1497 public function validate_password( $data ) {
1498 $error = [];
1499 $return = [ 'error' => false ];
1500 if( wpfval( $data, 'old_pass' ) && wpfval( $data, 'user_pass1' ) && wpfval( $data, 'user_pass2' ) ) {
1501 if( $data['user_pass1'] !== $data['user_pass2'] ) {
1502 $error[] = 'New Passwords do not match';
1503 } else {
1504 return true;
1505 }
1506 }
1507 if( ! empty( $error ) ) {
1508 $return['error'] = $error;
1509
1510 return $return;
1511 }
1512
1513 return false;
1514 }
1515
1516 public function field_types( $fields ) {
1517 $name_type_fields = [];
1518 if( ! empty( $fields ) ) {
1519 foreach( $fields as $rows ) {
1520 foreach( $rows as $cols ) {
1521 foreach( $cols as $field ) {
1522 if( wpfval( $field, 'name' ) && wpfval( $field, 'type' ) ) {
1523 $name_type_fields[ $field['name'] ] = $field['type'];
1524 }
1525 }
1526 }
1527 }
1528 }
1529
1530 return $name_type_fields;
1531 }
1532
1533 public function owner( $object_userid = false ): bool {
1534 if( ! $object_userid ) {
1535 if( wpfval( WPF()->current_object, 'user', 'userid' ) ) {
1536 return wpforo_is_owner( WPF()->current_object['user']['userid'] );
1537 } else {
1538 return false;
1539 }
1540 } else {
1541 return wpforo_is_owner( $object_userid );
1542 }
1543 }
1544
1545 /**
1546 * @param array $f
1547 *
1548 * @return bool
1549 */
1550 public function can_add( $f ) {
1551 if( wpfval( $f, 'name' ) ) {
1552 if( $f['name'] === 'signature' && ! wpforo_setting( 'profiles', 'signature' ) ) {
1553 return false;
1554 }
1555 if( $f['name'] === 'avatar' && ( ! wpforo_setting( 'profiles', 'custom_avatars' ) || ! wpforo_setting( 'profiles', 'avatars' ) ) ) {
1556 return false;
1557 }
1558 }
1559
1560 return true;
1561 }
1562
1563 /**
1564 * @param array $f
1565 *
1566 * @return bool
1567 */
1568 public function can_view( $f ) {
1569 return wpforo_current_user_is( 'admin' ) || ! ( ! $this->owner() && ! in_array( WPF()->current_user_groupid, (array) $f['canView'] ) );
1570 }
1571
1572 /**
1573 * @param array $f
1574 *
1575 * @return bool
1576 */
1577 public function can_edit( $f ) {
1578 if( wpfval( WPF()->current_object, 'user', 'userid' ) ) {
1579 $is_owner = $this->owner();
1580 $value = wpfkey( $f, 'value' ) ? $f['value'] : false;
1581 $can_edit = wpfkey( $f, 'isEditable' ) ? $f['isEditable'] : false;
1582 $can_moderate = $this->can_moderate( $f );
1583 if( ! $is_owner && ! $can_moderate && WPF()->current_user_groupid !== 1 ) {
1584 return false;
1585 }
1586 if( ! $can_edit && ! $can_moderate && WPF()->current_user_groupid !== 1 && ! $value ) {
1587 return false;
1588 }
1589 if( wpfkey( $f, 'name' ) ) {
1590 if( $f['name'] === 'signature' && ( ! WPF()->usergroup->can( 'ups' ) || ! wpforo_setting( 'profiles', 'signature' ) ) ) {
1591 return false;
1592 }
1593 if( $f['name'] === 'avatar' && ( ! wpforo_setting( 'profiles', 'custom_avatars' ) || ! wpforo_setting( 'profiles', 'avatars' ) ) ) {
1594 return false;
1595 }
1596 if( $f['name'] === 'groupid' && ( WPF()->current_user_groupid != 1 || $is_owner || ! current_user_can( 'administrator' ) ) ) {
1597 return false;
1598 }
1599 }
1600
1601 return true;
1602 } else {
1603 return false;
1604 }
1605 }
1606
1607 /**
1608 * @param array $f
1609 *
1610 * @return bool
1611 */
1612 public function can_moderate( $f ) {
1613 if( empty( $f ) ) return false;
1614 $usergroups_who_can_edit = ! empty( $f['canEdit'] ) ? (array) $f['canEdit'] : [ 1 ];
1615
1616 return in_array( WPF()->current_user_groupid, $usergroups_who_can_edit );
1617 }
1618
1619 public function can_show_value( $f ) {
1620 $return = true;
1621 if( is_string( $f ) ) $f = WPF()->member->get_field( $f );
1622 $f = wpforo_parse_args( $f, $this->default );
1623 if( $f['type'] === 'password' ) $return = false;
1624
1625 return apply_filters( 'wpforo_form_can_show_value', $return, $f );
1626 }
1627 }
1628