: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$multiple = ! empty( $field['multiple'] ) ? ' multiple' : '';
$placeholder = ! empty( $field['placeholder'] ) ? $field['placeholder'] : '';
'<select class="%s"%s readonly>',
wpforms_sanitize_classes( $list_class, true ),
if ( ! empty( $placeholder ) ) {
'<option value="" class="placeholder">%s</option>',
// Build the select options.
foreach ( $values as $key => $value ) {
$default = isset( $value['default'] ) ? (bool) $value['default'] : false;
$selected = ! empty( $placeholder ) && empty( $multiple ) ? '' : selected( true, $default, false );
$label = $this->get_choices_label( $value['label'] ?? '', $key + 1, $field );
$label .= ! empty( $field['show_price_after_labels'] ) && isset( $value['value'] ) ? ' - ' . wpforms_format_amount( wpforms_sanitize_amount( $value['value'] ), true ) : '';
'<option value="%2$s" %1$s>%2$s</option>',
// Normal checkbox/radio-based fields.
'<ul class="%s" style="%s">',
wpforms_sanitize_classes( $list_class, true ),
esc_attr( $inline_style )
foreach ( $values as $key => $value ) {
$default = isset( $value['default'] ) ? $value['default'] : '';
$selected = checked( '1', $default, false );
if ( ! empty( $value['default'] ) ) {
$item_class[] = 'wpforms-selected';
$item_class[] = 'wpforms-image-choices-item';
$item_class[] = 'wpforms-icon-choices-item';
wpforms_sanitize_classes( $item_class, true )
$label = $this->get_choices_label( $value['label'] ?? '', $key + 1, $field );
$label .= ! empty( $field['show_price_after_labels'] ) && isset( $value['value'] ) ? ' - ' . wpforms_format_amount( wpforms_sanitize_amount( $value['value'] ), true ) : '';
if ( in_array( $field['choices_images_style'], [ 'modern', 'classic' ], true ) ) {
$input_class[] = 'wpforms-screen-reader-element';
'<span class="wpforms-image-choices-image"><img src="%s" alt="%s"%s></span>',
! empty( $value['image'] ) ? esc_url( $value['image'] ) : WPFORMS_PLUGIN_URL . 'assets/images/builder/placeholder-200x125.svg',
! empty( $value['label'] ) ? ' title="' . esc_attr( $value['label'] ) . '"' : ''
if ( $field['choices_images_style'] === 'none' ) {
'<input type="%s" class="%s" %s readonly>',
wpforms_sanitize_classes( $input_class, true ),
$output .= '<span class="wpforms-image-choices-label">' . wp_kses( $label, $allowed_tags ) . '</span>';
} elseif ( $with_icons ) {
$icon = isset( $value['icon'] ) && ! wpforms_is_empty_string( $value['icon'] ) ? $value['icon'] : IconChoices::DEFAULT_ICON;
$icon_style = ! empty( $value['icon_style'] ) ? $value['icon_style'] : IconChoices::DEFAULT_ICON_STYLE;
if ( in_array( $field['choices_icons_style'], [ 'default', 'modern', 'classic' ], true ) ) {
$input_class[] = 'wpforms-screen-reader-element';
'<span class="wpforms-icon-choices-icon">
<i class="ic-fa-%s ic-fa-%s"></i>
<span class="wpforms-icon-choices-icon-bg"></span>
'<input type="%1$s" class="%2$s" %3$s readonly>',
wpforms_sanitize_classes( $input_class, true ),
$output .= '<span class="wpforms-icon-choices-label">' . wp_kses( $label, $allowed_tags ) . '</span>';
'<input type="%s" %s readonly> %s',
wp_kses( $label, $allowed_tags )
* Contains more than 20/250 items, include a note about a limited subset of results displayed.
if ( $total > $slice_size ) {
$output .= '<div class="wpforms-alert-dynamic wpforms-alert wpforms-alert-warning">';
wp_kses( /* translators: %s - total amount of choices. */
__( 'Showing the first %1$s choices.<br> All %2$s choices will be displayed when viewing the form.', 'wpforms-lite' ),
$first_item = ! empty( $field['min_quantity'] ) ? $field['min_quantity'] : 0;
$class .= $this->is_payment_quantities_enabled( $field ) ? '' : ' wpforms-hidden';
'<select class="quantity-input %1$s" readonly>',
echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
* Create a new field in the admin AJAX editor.
public function field_new() {
if ( ! check_ajax_referer( 'wpforms-builder', 'nonce', false ) ) {
wp_send_json_error( esc_html__( 'Your session expired. Please reload the builder.', 'wpforms-lite' ) );
// Check for permissions.
if ( ! wpforms_current_user_can( 'edit_forms' ) ) {
wp_send_json_error( esc_html__( 'You are not allowed to perform this action.', 'wpforms-lite' ) );
if ( empty( $_POST['id'] ) ) {
wp_send_json_error( esc_html__( 'No form ID found', 'wpforms-lite' ) );
// Check for field type to add.
if ( empty( $_POST['type'] ) ) {
wp_send_json_error( esc_html__( 'No field type found', 'wpforms-lite' ) );
$field_args = ! empty( $_POST['defaults'] ) && is_array( $_POST['defaults'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['defaults'] ) ) : [];
$field_type = sanitize_key( $_POST['type'] );
$field_id = wpforms()->get( 'form' )->next_field_id( absint( $_POST['id'] ) );
$field = wp_parse_args( $field_args, $field );
$field = apply_filters( 'wpforms_field_new_default', $field );
$field_required = apply_filters( 'wpforms_field_new_required', '', $field );
$field_class = apply_filters( 'wpforms_field_new_class', '', $field );
$field_helper_hide = ! empty( $_COOKIE['wpforms_field_helper_hide'] );
// Field types that default to required.
if ( ! empty( $field_required ) ) {
$field_required = 'required';
$field['required'] = '1';
$this->field_preview( $field );
'<div class="wpforms-field wpforms-field-%1$s %2$s %3$s" id="wpforms-field-%4$s" data-field-id="%4$s" data-field-type="%5$s">',
esc_attr( $field_required ),
esc_attr( $field_class ),
wpforms_validate_field_id( $field['id'] ),
if ( apply_filters( 'wpforms_field_new_display_duplicate_button', true, $field ) ) {
$preview .= sprintf( '<a href="#" class="wpforms-field-duplicate" title="%s"><i class="fa fa-files-o" aria-hidden="true"></i></a>', esc_attr__( 'Duplicate Field', 'wpforms-lite' ) );
$preview .= sprintf( '<a href="#" class="wpforms-field-delete" title="%s"><i class="fa fa-trash-o"></i></a>', esc_attr__( 'Delete Field', 'wpforms-lite' ) );
if ( ! $field_helper_hide ) {
'<div class="wpforms-field-helper">
<span class="wpforms-field-helper-edit">%s</span>
<span class="wpforms-field-helper-drag">%s</span>
<span class="wpforms-field-helper-hide" title="%s">
<i class="fa fa-times-circle" aria-hidden="true"></i>
esc_html__( 'Click to Edit', 'wpforms-lite' ),
esc_html__( 'Drag to Reorder', 'wpforms-lite' ),
esc_html__( 'Hide Helper', 'wpforms-lite' )
$class = apply_filters( 'wpforms_builder_field_option_class', '', $field );
'<div class="wpforms-field-option wpforms-field-option-%1$s %2$s" id="wpforms-field-option-%3$s" data-field-id="%3$s">',
sanitize_html_class( $field['type'] ),
wpforms_sanitize_classes( $class ),
wpforms_validate_field_id( $field['id'] )
'<input type="hidden" name="fields[%1$s][id]" value="%1$s" class="wpforms-field-option-hidden-id">',
wpforms_validate_field_id( $field['id'] )
'<input type="hidden" name="fields[%s][type]" value="%s" class="wpforms-field-option-hidden-type">',
wpforms_validate_field_id( $field['id'] ),
esc_attr( $field['type'] )
$this->field_options( $field );
$options .= ob_get_clean();
// Prepare to return compiled results.
'form_id' => absint( $_POST['id'] ),
* Display the field input elements on the frontend
* according to the render engine setting.
* @param array $field Field data and settings.
* @param array $field_atts Field attributes (deprecated).
* @param array $form_data Form data and settings.
* @noinspection PhpUnusedParameterInspection
public function field_display_proxy( $field, $field_atts, $form_data ) {
$render_engine = wpforms_get_render_engine();
$method = "field_display_{$render_engine}";
if ( ! method_exists( $this, $method ) ) {
// Something is wrong, this should never occur.
// Let's display classic field in this case.
$method = 'fields_display_classic';
$this->$method( $field, $form_data );
* Display the field using classic rendering.
* @since 1.5.0 Converted to abstract method, as it's required for all fields.
* @param array $field Field data and settings.
* @param array $field_atts Field attributes (deprecated).
* @param array $form_data Form data and settings.
abstract public function field_display( $field, $field_atts, $form_data );
* Display the field using classic rendering.
* @param array $field Field data and settings.
* @param array $form_data Form data and settings.
protected function field_display_classic( $field, $form_data ) {
// The classic view is the same good old `field_display`.
$this->field_display( $field, [], $form_data );
* Display the field using modern rendering.
* @param array $field Field data and settings.
* @param array $form_data Form data and settings.
protected function field_display_modern( $field, $form_data ) {
// Maybe call the method from the field's modern frontend class.
if ( ! empty( $this->frontend_obj ) && method_exists( $this->frontend_obj, 'field_display_modern' ) ) {
$this->frontend_obj->field_display_modern( $field, $form_data );
// By default, the modern view is the same as the classic.
// In this way, we will implement modern only for the fields,
$this->field_display_classic( $field, $form_data );
* Display field input errors if present.
* @param string $key Input key.
* @param array $field Field data and settings.
public function field_display_error( $key, $field ) {
if ( empty( $field['properties']['error']['value'][ $key ] ) ) {
'<label class="wpforms-error" for="%s">%s</label>',
esc_attr( $field['properties']['inputs'][ $key ]['id'] ),
esc_html( $field['properties']['error']['value'][ $key ] )
* Display field input sublabel if present.
* @since 1.8.9 Ability to skip for attribute.
* @param string $key Input key.
* @param string $position Sublabel position.
* @param array $field Field data and settings.
public function field_display_sublabel( $key, $position, $field ) {
// Need a sublabel value.
if ( empty( $field['properties']['inputs'][ $key ]['sublabel']['value'] ) ) {
$field_position = ! empty( $field['properties']['inputs'][ $key ]['sublabel']['position'] ) ? $field['properties']['inputs'][ $key ]['sublabel']['position'] : 'after';
// Used to prevent from displaying sublabel twice.
if ( $field_position !== $position ) {
'wpforms-field-sublabel',
if ( ! empty( $field['properties']['inputs'][ $key ]['sublabel']['hidden'] ) ) {
$classes[] = 'wpforms-sublabel-hide';
* Allow to skip the `for` attribute inside the label.
* @param bool $skip Whether to skip the `for` attribute.
* @param string $key Input key.
* @param array $field Field data and settings.
$skip_for = (bool) apply_filters( 'wpforms_field_display_sublabel_skip_for', false, $key, $field );
* Allow to set custom for attribute to the label.
* @param string $value Actual for attribute value.
* @param string $key Input key.
* @param array $field Field data and settings.
$for = apply_filters( 'wpforms_field_display_sublabel_for', $field['properties']['inputs'][ $key ]['id'], $key, $field );
'<label %1$s class="%2$s">%3$s</label>',
! $skip_for ? sprintf( 'for="%s"', esc_attr( $for ) ) : '',
wpforms_sanitize_classes( $classes, true ),
esc_html( $field['properties']['inputs'][ $key ]['sublabel']['value'] )
* Validate field on form submit.
* @param int $field_id Field ID.
* @param mixed $field_submit Submitted field value (raw data).
* @param array $form_data Form data and settings.
public function validate( $field_id, $field_submit, $form_data ) {
// Basic required check - If field is marked as required, check for entry data.
if ( ! empty( $form_data['fields'][ $field_id ]['required'] ) && empty( $field_submit ) && '0' !== (string) $field_submit ) {
wpforms()->get( 'process' )->errors[ $form_data['id'] ][ $field_id ] = wpforms_get_required_label();
* Format and sanitize field.
* @param int $field_id Field ID.
* @param mixed $field_submit Field value that was submitted.
* @param array $form_data Form data and settings.
public function format( $field_id, $field_submit, $form_data ) {