: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
// The required constraint in HTML5 form validation does not work with checkbox groups, so omit in AMP.
$required_attr = wpforms_is_amp() && count( $choices ) > 1 ? '' : $choice['required'];
if ( $using_image_choices ) {
// Make sure the image choices are keyboard-accessible.
$choice['label']['attr']['tabindex'] = 0;
if ( wpforms_is_amp() ) {
$choice['label']['attr']['on'] = sprintf(
'tap:AMP.setState({ %s: { %s: ! %s[%s] } })',
wp_json_encode( $amp_state_id ),
wp_json_encode( $choice['id'] ),
wp_json_encode( $choice['id'] )
$choice['label']['attr']['role'] = 'button';
if ( is_array( $choice['label']['class'] ) && wpforms_is_empty_string( $label ) ) {
$choice['label']['class'][] = 'wpforms-field-label-inline-empty';
wpforms_html_attributes( $choice['label']['id'], $choice['label']['class'], $choice['label']['data'], $choice['label']['attr'] )
echo '<span class="wpforms-image-choices-image">';
if ( ! empty( $choice['image'] ) ) {
'<img src="%s" alt="%s"%s>',
esc_url( $choice['image'] ),
! empty( $label ) ? ' title="' . esc_attr( $label ) . '"' : ''
if ( $field['choices_images_style'] === 'none' ) {
$choice['attr']['tabindex'] = '-1';
if ( wpforms_is_amp() ) {
$choice['attr']['[checked]'] = sprintf(
wp_json_encode( $choice['id'] )
'<input type="checkbox" %s %s %s>',
wpforms_html_attributes( $choice['id'], $choice['class'], $choice['data'], $choice['attr'] ),
esc_attr( $required_attr ),
checked( '1', $choice['default'], false )
echo '<span class="wpforms-image-choices-label">' . wp_kses_post( $label ) . '</span>';
} elseif ( $using_icon_choices ) {
if ( wpforms_is_amp() ) {
$choice['label']['attr']['on'] = sprintf(
'tap:AMP.setState({ %s: { %s: ! %s[%s] } })',
wp_json_encode( $amp_state_id ),
wp_json_encode( $choice['id'] ),
wp_json_encode( $choice['id'] )
$choice['label']['attr']['role'] = 'button';
$choice['attr']['autocomplete'] = 'off';
wpforms()->get( 'icon_choices' )->field_display( $field, $choice, 'checkbox' );
'<input type="checkbox" %s %s %s>',
wpforms_html_attributes( $choice['id'], $choice['class'], $choice['data'], $choice['attr'] ),
esc_attr( $required_attr ),
checked( '1', $choice['default'], false )
'<label %s>%s%s</label>',
wpforms_html_attributes( $choice['label']['id'], $choice['label']['class'], $choice['label']['data'], $choice['label']['attr'] ),
* Validate field on form submit.
* @param int $field_id Field ID.
* @param array $field_submit Submitted field value (raw data).
* @param array $form_data Form data.
public function validate( $field_id, $field_submit, $form_data ) {
$field = $form_data['fields'][ $field_id ];
// Skip validation if field is dynamic and choices are empty.
if ( $this->is_dynamic_choices_empty( $field, $form_data ) ) {
$field_submit = (array) $field_submit;
$choice_limit = empty( $form_data['fields'][ $field_id ]['choice_limit'] ) ? 0 : (int) $form_data['fields'][ $field_id ]['choice_limit'];
$count_choices = count( $field_submit );
if ( $choice_limit > 0 && $count_choices > $choice_limit ) {
$error = wpforms_setting( 'validation-check-limit', esc_html__( 'You have exceeded the number of allowed selections: {#}.', 'wpforms-lite' ) );
$error = str_replace( '{#}', $choice_limit, $error );
// Basic required check - If field is marked as required, check for entry data.
! empty( $form_data['fields'][ $field_id ]['required'] ) &&
empty( $field_submit ) ||
count( $field_submit ) === 1 &&
( ! isset( $field_submit[0] ) || (string) $field_submit[0] === '' )
$error = wpforms_get_required_label();
if ( ! empty( $error ) ) {
wpforms()->get( 'process' )->errors[ $form_data['id'] ][ $field_id ] = $error;
* Format and sanitize field.
* @param int $field_id Field ID.
* @param array $field_submit Submitted form data.
* @param array $form_data Form data and settings.
public function format( $field_id, $field_submit, $form_data ) {
$field_submit = (array) $field_submit;
$field = $form_data['fields'][ $field_id ];
$dynamic = ! empty( $field['dynamic_choices'] ) ? $field['dynamic_choices'] : false;
$name = sanitize_text_field( $field['label'] );
$value_raw = wpforms_sanitize_array_combine( $field_submit );
'value_raw' => $value_raw,
'id' => wpforms_validate_field_id( $field_id ),
if ( 'post_type' === $dynamic && ! empty( $field['dynamic_post_type'] ) ) {
// Dynamic population is enabled using post type.
$value_raw = implode( ',', array_map( 'absint', $field_submit ) );
$data['value_raw'] = $value_raw;
$data['dynamic'] = 'post_type';
$data['dynamic_items'] = $value_raw;
$data['dynamic_post_type'] = $field['dynamic_post_type'];
foreach ( $field_submit as $id ) {
if ( ! is_wp_error( $post ) && ! empty( $post ) && $data['dynamic_post_type'] === $post->post_type ) {
$posts[] = esc_html( wpforms_get_post_title( $post ) );
$data['value'] = ! empty( $posts ) ? wpforms_sanitize_array_combine( $posts ) : '';
elseif ( 'taxonomy' === $dynamic && ! empty( $field['dynamic_taxonomy'] ) ) {
// Dynamic population is enabled using taxonomy.
$value_raw = implode( ',', array_map( 'absint', $field_submit ) );
$data['value_raw'] = $value_raw;
$data['dynamic'] = 'taxonomy';
$data['dynamic_items'] = $value_raw;
$data['dynamic_taxonomy'] = $field['dynamic_taxonomy'];
foreach ( $field_submit as $id ) {
$term = get_term( $id, $field['dynamic_taxonomy'] );
if ( ! is_wp_error( $term ) && ! empty( $term ) ) {
$terms[] = esc_html( wpforms_get_term_name( $term ) );
$data['value'] = ! empty( $terms ) ? wpforms_sanitize_array_combine( $terms ) : '';
// Normal processing, dynamic population is off.
// If show_values is true, that means values posted are the raw values
// and not the labels. So we need to set label values. Also store
if ( ! empty( $field['show_values'] ) && (int) $field['show_values'] === 1 ) {
foreach ( $field_submit as $item ) {
foreach ( $field['choices'] as $key => $choice ) {
// Check if the submitted value is the same as the choice value or if the value is empty and the key matches.
// Skip if the submitted value is empty.
if ( ( ! empty( $item ) && $item === $choice['value'] ) || ( empty( $choice['value'] ) && (int) str_replace( 'Choice ', '', $item ) === $key ) ) {
$value[] = $choice['label'];
$data['value'] = ! empty( $value ) ? wpforms_sanitize_array_combine( $value ) : '';
$data['value'] = $value_raw;
// Determine choices keys, this is needed for image choices.
foreach ( $field_submit as $item ) {
foreach ( $field['choices'] as $key => $choice ) {
/* translators: %s - choice number. */
if ( $item === $choice['label'] || $item === sprintf( esc_html__( 'Choice %s', 'wpforms-lite' ), $key ) ) {
// Images choices are enabled, lookup and store image URLs.
if ( ! empty( $choice_keys ) && ! empty( $field['choices_images'] ) ) {
foreach ( $choice_keys as $key ) {
$data['images'][] = ! empty( $field['choices'][ $key ]['image'] ) ? esc_url_raw( $field['choices'][ $key ]['image'] ) : '';
// Push field details to be saved.
wpforms()->get( 'process' )->fields[ $field_id ] = $data;
new WPForms_Field_Checkbox();