sanitize_key( $plugin ), 'form_id' => mb_substr( sanitize_text_field( (string) $form_id ), 0, 64 ), 'form_name' => mb_substr( sanitize_text_field( (string) $form_name ), 0, 191 ), 'fields' => wp_json_encode( $fields ), 'currency' => Settings::get( 'currency' ), 'clarity' => Clarity::from_request(), ), array_intersect_key( $extra, array_flip( array( 'status', 'value', 'currency', 'won_at', 'note' ) ) ) ); // A postcode or a town in the form places the lead more exactly than its connection. $place = Lead_Place::from_fields( $fields, (string) ( $data['country'] ?? '' ) ); if ( $place ) { $data = array_merge( $data, $place ); } /** * Filters lead data before it is saved. * * @param array $data Column values. * @param array $fields Normalized fields. * @param array $attribution First and last touch, or null when not tracked. */ $data = apply_filters( 'dealroot_lead_data', $data, $fields, $attribution ); // The same person writing again while their enquiry is open: a message of that lead. $open = Messages::open_lead( $data ); if ( $open ) { Messages::received( $open, $data, $fields ); self::$created[ $plugin ] = (int) $open->id; return (int) $open->id; } $lead_id = Leads::insert( $data ); if ( $lead_id ) { self::$created[ $plugin ] = $lead_id; /** * Fires after a lead is stored. * * @param int $lead_id Lead ID. * @param array $data Stored column values. */ do_action( 'dealroot_lead_created', $lead_id, $data ); } return $lead_id; } /** * ID of the lead created for a form plugin during this request. * * @param string $plugin Form plugin key. * @return int */ public static function created_in_request( $plugin ) { return self::$created[ $plugin ] ?? 0; } /** * Name, email address and phone number in fields, e.g. of a checkout. * * @param array $fields Fields with label, name, type and value. * @return array{name: string, email: string, phone: string} */ public static function contact_of( array $fields ) { return self::contact_details( self::normalize_fields( $fields ) ); } /** * Cleans field values and drops empty or sensitive ones. * * @param array $fields Raw fields. * @return array */ private static function normalize_fields( array $fields ) { $clean = array(); foreach ( $fields as $field ) { $type = sanitize_key( $field['type'] ?? '' ); $value = $field['value'] ?? ''; if ( in_array( $type, array( 'password', 'captcha', 'recaptcha', 'hcaptcha', 'turnstile', 'honeypot', 'submit', 'html', 'step', 'section', 'page' ), true ) ) { continue; } if ( is_array( $value ) ) { $value = implode( ', ', array_filter( array_map( 'strval', array_filter( $value, 'is_scalar' ) ), 'strlen' ) ); } $value = trim( sanitize_textarea_field( (string) $value ) ); if ( '' === $value ) { continue; } $name = sanitize_text_field( (string) ( $field['name'] ?? '' ) ); $label = sanitize_text_field( (string) ( $field['label'] ?? '' ) ); if ( 0 === strpos( $name, '_' ) || preg_match( '/^(g-recaptcha|cf-turnstile|h-captcha|dealroot_)/', $name ) ) { continue; } $clean[] = array( 'label' => '' !== $label ? $label : $name, 'name' => $name, 'type' => $type, 'value' => mb_substr( $value, 0, self::MAX_FIELD_LENGTH ), ); } return $clean; } /** * Picks name, email and phone from the fields. * * @param array $fields Normalized fields. * @return array */ private static function contact_details( array $fields ) { $email = ''; $phone = ''; $first = ''; $last = ''; $full = ''; foreach ( $fields as $field ) { $key = strtolower( $field['name'] . ' ' . $field['label'] ); $value = $field['value']; if ( '' === $email && ( 'email' === $field['type'] || is_email( $value ) ) ) { $email = sanitize_email( $value ); continue; } if ( '' === $phone && ( in_array( $field['type'], array( 'tel', 'phone' ), true ) || preg_match( '/phone|tel|mobil|handy|телефон|номер|móvil|téléphone|telefono|numer/u', $key ) ) ) { $phone = mb_substr( $value, 0, 64 ); continue; } if ( preg_match( '/company|firma|unternehmen|компан|empresa|société|azienda|user/u', $key ) ) { continue; } if ( '' === $first && preg_match( '/first|vorname|fname|имя|ім.я|prénom|nombre|nome|imię|voornaam/u', $key ) && ! preg_match( '/last|nach|фамил|прізв/u', $key ) ) { $first = $value; continue; } if ( '' === $last && preg_match( '/last|nachname|surname|lname|фамил|прізвище|apellido|cognome|nazwisko|achternaam|nom de famille/u', $key ) ) { $last = $value; continue; } if ( '' === $full && ( 'name' === $field['type'] || preg_match( '/name|имя|ім.я|nom|nombre|nome|imię|naam/u', $key ) ) ) { $full = $value; } } $name = trim( $first . ' ' . $last ); if ( '' === $name ) { $name = $full; } $e164 = Phone::to_e164( $phone ); return array( 'name' => mb_substr( $name, 0, 191 ), 'email' => mb_substr( $email, 0, 191 ), 'phone' => '' !== $e164 ? $e164 : $phone, ); } }