__( 'is', '2ranq-forms' ), 'is_not' => __( 'is not', '2ranq-forms' ), 'empty' => __( 'is empty', '2ranq-forms' ), 'filled' => __( 'is filled in', '2ranq-forms' ), 'contains' => __( 'contains', '2ranq-forms' ), 'gt' => __( 'is greater than', '2ranq-forms' ), 'lt' => __( 'is less than', '2ranq-forms' ), ); } /** * Cleans the rules of one field. * * @param mixed $raw The raw value out of the builder. * * @return array An empty array means the field has no conditions. */ public static function sanitize( $raw ) { if ( ! is_array( $raw ) ) { return array(); } $action = isset( $raw['action'] ) ? sanitize_key( $raw['action'] ) : ''; if ( ! in_array( $action, array( 'show', 'hide' ), true ) ) { return array(); } $match = isset( $raw['match'] ) && 'any' === sanitize_key( $raw['match'] ) ? 'any' : 'all'; $rules = array(); if ( isset( $raw['rules'] ) && is_array( $raw['rules'] ) ) { foreach ( $raw['rules'] as $rule ) { if ( ! is_array( $rule ) ) { continue; } $field = isset( $rule['field'] ) ? sanitize_key( $rule['field'] ) : ''; $op = isset( $rule['op'] ) ? sanitize_key( $rule['op'] ) : 'is'; if ( '' === $field || ! isset( self::operators()[ $op ] ) ) { continue; } $rules[] = array( 'field' => $field, 'op' => $op, 'value' => isset( $rule['value'] ) && is_scalar( $rule['value'] ) ? sanitize_text_field( (string) $rule['value'] ) : '', ); } } // A rule without a single condition means nothing, so the whole thing is dropped. if ( ! $rules ) { return array(); } return array( 'action' => $action, 'match' => $match, 'rules' => $rules, ); } /** * Whether the field is shown at all, given what the person filled in. * * @param array $field The field settings. * @param array $values The values of the other fields, by key. * * @return bool */ public static function is_visible( $field, $values ) { $logic = isset( $field['conditional'] ) ? $field['conditional'] : array(); if ( empty( $logic['rules'] ) ) { return true; } $results = array(); foreach ( $logic['rules'] as $rule ) { $results[] = self::test( $rule, isset( $values[ $rule['field'] ] ) ? $values[ $rule['field'] ] : '' ); } $met = 'any' === $logic['match'] ? in_array( true, $results, true ) : ! in_array( false, $results, true ); return 'show' === $logic['action'] ? $met : ! $met; } /** * Checks one rule. * * @param array $rule The rule. * @param mixed $value The value of the field the rule points at. * * @return bool */ private static function test( $rule, $value ) { // A field with several choices is compared as a list, not as one string. $list = is_array( $value ) ? array_map( 'strval', $value ) : array( (string) $value ); $flat = implode( ' ', $list ); $want = (string) $rule['value']; switch ( $rule['op'] ) { case 'is': return in_array( $want, $list, true ); case 'is_not': return ! in_array( $want, $list, true ); case 'empty': return '' === trim( $flat ); case 'filled': return '' !== trim( $flat ); case 'contains': return '' !== $want && false !== stripos( $flat, $want ); case 'gt': return is_numeric( $flat ) && is_numeric( $want ) && (float) $flat > (float) $want; case 'lt': return is_numeric( $flat ) && is_numeric( $want ) && (float) $flat < (float) $want; } return false; } /** * The rules in the shape that goes into the attribute, for the script to * read. * * @param array $field The field settings. * * @return string An empty string when the field has no conditions. */ public static function attribute( $field ) { $logic = isset( $field['conditional'] ) ? $field['conditional'] : array(); if ( empty( $logic['rules'] ) ) { return ''; } return (string) wp_json_encode( $logic ); } }