$values Stored values keyed by field key. * * @return array The payload. */ public function build( Form $form, int $submission_id, array $values ): array { $payload = array( 'event' => 'submission.created', 'sent_at' => gmdate( 'c' ), 'site' => array( 'name' => wp_specialchars_decode( (string) get_bloginfo( 'name' ), ENT_QUOTES ), 'url' => home_url( '/' ), ), 'form' => array( 'id' => $form->id(), 'title' => $form->title(), 'slug' => $form->slug(), ), 'submission' => array( 'id' => $submission_id, 'fields' => $this->fields( $form, $values ), ), ); /** * Filters the payload sent to the webhooks of a form. * * @since 1.0.0 * * @param array $payload Payload about to be encoded. * @param Form $form Form that was submitted. * @param int $submission_id Stored submission ID. * @param array $values Stored values keyed by field key. */ return (array) apply_filters( 'formpilot_webhook_payload', $payload, $form, $submission_id, $values ); } /** * Builds a payload with made up values, for a test delivery. * * @param Form $form Form the test belongs to. * * @return array The payload. */ public function sample( Form $form ): array { $payload = $this->build( $form, 0, array() ); $payload['event'] = 'webhook.test'; $payload['test'] = true; return $payload; } /** * Builds the field list. * * Every field of the form appears, including the ones with no answer, so the * receiving end sees a stable shape rather than a payload whose keys change * with what the visitor happened to fill in. * * @param Form $form Form that was submitted. * @param array $values Stored values keyed by field key. * * @return array> The fields. */ private function fields( Form $form, array $values ): array { $fields = array(); foreach ( $this->fields->for_form( $form->id() ) as $field ) { $key = $field->field_key(); if ( ! array_key_exists( $key, $values ) ) { // A page break carries no answer and neither does a field added // after this submission was stored. continue; } $fields[] = array( 'key' => $key, 'label' => $field->label(), 'type' => $field->type(), 'value' => $this->outbound( $this->formatter->decode( (string) $this->stringify( $values[ $key ] ) ) ), ); } return $fields; } /** * Removes what only this server can use from a value before it leaves. * * A stored upload records the absolute path it was written to, and the * payload used to carry it verbatim - so every file field told a third-party * endpoint where this site lives on disk, which no receiver can do anything * with except learn the server's layout. The URL, name, type and size stay. * * @param mixed $value Decoded value. * * @return mixed The value, without a server path. */ private function outbound( mixed $value ): mixed { if ( $this->formatter->is_file_payload( $value ) ) { unset( $value['file'] ); } return $value; } /** * Returns a stored value as the string the formatter expects. * * @param mixed $value Stored value. */ private function stringify( mixed $value ): string { if ( is_scalar( $value ) ) { return (string) $value; } return (string) wp_json_encode( $value ); } }