'choices', 'type' => 'choices', 'label' => __( 'Options', '2ranq-forms' ), 'help' => __( 'One option per row. Drag to reorder.', '2ranq-forms' ), ), ) ); return $settings; } /** * The choices of the field, cleaned. * * @param array $field The field settings. * * @return array An array with the keys `value` and `label`. */ protected function get_choices( $field ) { $choices = isset( $field['choices'] ) && is_array( $field['choices'] ) ? $field['choices'] : array(); $clean = array(); foreach ( $choices as $choice ) { if ( ! is_array( $choice ) ) { continue; } $value = isset( $choice['value'] ) ? (string) $choice['value'] : ''; $label = isset( $choice['label'] ) ? (string) $choice['label'] : $value; if ( '' === $value && '' === $label ) { continue; } $clean[] = array( 'value' => '' === $value ? $label : $value, 'label' => '' === $label ? $value : $label, 'default' => ! empty( $choice['default'] ), ); } return $clean; } /** * The list of allowed values. * * @param array $field The field settings. * * @return array */ protected function allowed_values( $field ) { return wp_list_pluck( $this->get_choices( $field ), 'value' ); } /** * Whether one choice renders as picked. * * While the form is fresh the owner's defaults decide. The moment a send has * failed, what the visitor picked wins, even when they picked nothing, because * putting the defaults back would quietly change their answer under them. * * @param array $choice One choice, as get_choices() returns it. * @param mixed $sticky What sticky_value() gave for the whole field. * * @return bool */ protected function choice_on( $choice, $sticky ) { if ( null === $sticky ) { return ! empty( $choice['default'] ); } $picked = array_map( 'strval', array_filter( is_array( $sticky ) ? $sticky : array( $sticky ), 'is_scalar' ) ); return in_array( (string) $choice['value'], $picked, true ); } /** * The value prepared for display, as the label the visitor actually saw. * * What is stored is the value of the choice, which is a key like * `i-am-already-a-customer`. The person reading the entry, the notification, * the export or the webhook picked `I am already a customer`, so that is what * they are shown. A value that is no longer among the choices is shown as it * was stored, because an old entry has to stay readable after the form is * changed. * * @param mixed $value The cleaned value. * @param array $field The field settings. * * @return string */ public function format_value( $value, $field ) { $labels = array(); foreach ( $this->get_choices( $field ) as $choice ) { $labels[ $choice['value'] ] = $choice['label']; } $selected = is_array( $value ) ? $value : array( $value ); $out = array(); foreach ( $selected as $single ) { if ( ! is_scalar( $single ) ) { continue; } $single = (string) $single; if ( '' === $single ) { continue; } $out[] = isset( $labels[ $single ] ) ? $labels[ $single ] : $single; } return implode( ', ', $out ); } /** * Cleaning. * * @param mixed $value The raw value. * @param array $field The field settings. * * @return mixed */ public function sanitize( $value, $field ) { unset( $field ); if ( is_array( $value ) ) { return array_values( array_map( 'sanitize_text_field', array_filter( $value, 'is_scalar' ) ) ); } return sanitize_text_field( is_scalar( $value ) ? (string) $value : '' ); } /** * Validation. * * The value has to be one of the offered ones. This matters: without this * check anyone can send anything in a select field, because the list of * choices is visible in the HTML. * * @param mixed $value The value. * @param array $field The field settings. * * @return string */ public function validate( $value, $field ) { $empty = is_array( $value ) ? array() === $value : '' === trim( (string) $value ); if ( ! empty( $field['required'] ) && $empty ) { return $this->required_message( $field ); } if ( $empty ) { return ''; } $allowed = $this->allowed_values( $field ); $selected = is_array( $value ) ? $value : array( $value ); foreach ( $selected as $single ) { if ( ! in_array( (string) $single, $allowed, true ) ) { return __( 'Please choose one of the available options.', '2ranq-forms' ); } } if ( ! $this->is_multiple() && count( $selected ) > 1 ) { return __( 'Please choose one of the available options.', '2ranq-forms' ); } return ''; } }