$layout Defaults to FormLayout::current(). * @return list|WP_Error The error names the field as `fields[id]`. */ public static function check( mixed $given, bool $staff = false, ?array $layout = null ): array|WP_Error { $given = is_array( $given ) ? $given : []; $out = []; foreach ( $layout ?? FormLayout::current() as $entry ) { if ( ! $entry['custom'] || FormLayout::HIDDEN === $entry['answer'] ) { continue; } $raw = $given[ $entry['id'] ] ?? ''; $value = self::value( $entry, is_scalar( $raw ) ? trim( (string) $raw ) : '' ); if ( $value instanceof WP_Error ) { return $value; } if ( '' === $value ) { if ( ! $staff && FormLayout::REQUIRED === $entry['answer'] ) { return self::refuse( $entry['id'], 'checkbox' === $entry['type'] ? __( 'Please tick this box.', 'flexatech-table-reservations' ) : __( 'Please fill in this field.', 'flexatech-table-reservations' ) ); } continue; } $out[] = [ 'id' => $entry['id'], 'label' => FormLayout::label( $entry ), 'value' => $value, 'email' => $entry['email'], ]; } return $out; } /** * Answers read back from the reservation's JSON column. * * @return list */ public static function decode( mixed $json ): array { $list = is_string( $json ) && '' !== $json ? json_decode( $json, true ) : null; $out = []; foreach ( is_array( $list ) ? $list : [] as $answer ) { if ( ! is_array( $answer ) || ! is_string( $answer['label'] ?? null ) || ! is_string( $answer['value'] ?? null ) ) { continue; } $out[] = [ 'id' => (string) ( $answer['id'] ?? '' ), 'label' => $answer['label'], 'value' => $answer['value'], 'email' => ! empty( $answer['email'] ), ]; } return $out; } /** * The text kept for one answer, '' for none. * * @param Entry $entry */ private static function value( array $entry, string $raw ): string|WP_Error { if ( '' === $raw ) { return ''; } switch ( $entry['type'] ) { case 'checkbox': return '0' === $raw ? '' : __( 'Yes', 'flexatech-table-reservations' ); case 'select': case 'radio': foreach ( $entry['options'] as $choice ) { if ( $choice['value'] === $raw ) { return $choice['label']; } } return self::refuse( $entry['id'], __( 'Choose one of the options.', 'flexatech-table-reservations' ) ); case 'number': return is_numeric( $raw ) && strlen( $raw ) <= 32 ? $raw : self::refuse( $entry['id'], __( 'Enter a number.', 'flexatech-table-reservations' ) ); case 'date': return Planner::is_date( $raw ) ? Emails::format_date( $raw ) : self::refuse( $entry['id'], __( 'Choose a date.', 'flexatech-table-reservations' ) ); case 'email': return is_email( $raw ) ? sanitize_email( $raw ) : self::refuse( $entry['id'], __( 'Enter a valid email address, like name@example.com.', 'flexatech-table-reservations' ) ); case 'tel': return Contact::phone_ok( $raw ) ? $raw : self::refuse( $entry['id'], __( 'Enter a valid phone number.', 'flexatech-table-reservations' ) ); case 'textarea': $text = trim( sanitize_textarea_field( $raw ) ); /* translators: %d: the most characters the answer may have. */ return mb_strlen( $text ) <= self::LONG_MAX ? $text : self::refuse( $entry['id'], sprintf( __( 'Keep it to %d characters.', 'flexatech-table-reservations' ), self::LONG_MAX ) ); default: $text = trim( sanitize_text_field( $raw ) ); /* translators: %d: the most characters the answer may have. */ return mb_strlen( $text ) <= self::TEXT_MAX ? $text : self::refuse( $entry['id'], sprintf( __( 'Keep it to %d characters.', 'flexatech-table-reservations' ), self::TEXT_MAX ) ); } } private static function refuse( string $id, string $message ): WP_Error { return new WP_Error( 'fxtr_invalid', $message, [ 'status' => 400, 'fields' => [ 'fields[' . $id . ']' => $message ], ] ); } }