items as $item ) { $label = (string) ( $item['label'] ?? '' ); $value = (string) ( $item['value'] ?? '' ); $fields[ $label ] = $value; // Uploaded files are private: the payload carries the file name, never a link. } return array( 'event' => 'entry_created', 'form_id' => (int) $form['id'], 'form_title' => $form['title'], 'entry_id' => (int) $entry->id, 'created_at' => (string) ( $entry->created_at ?? '' ), 'fields' => $fields, ); } /** * Post a payload to one webhook. Extracted so the request itself can be asserted in tests. */ function pubforms_send_webhook( $url, $payload ) { // wp_safe_remote_post() refuses loopback, private-network and unusual-port targets. return wp_safe_remote_post( $url, array( 'headers' => array( 'Content-Type' => 'application/json', 'X-PubForms-Event' => 'entry_created', ), 'body' => (string) wp_json_encode( $payload ), 'timeout' => 5, ) ); } /** * Deliver a confirmed entry to every webhook configured on its form. Best-effort: a failed delivery * never fails the submission. */ function pubforms_deliver_webhooks( $form, $entry ) { if ( ! $form || ! $entry ) { return; } $payload = pubforms_webhook_payload( $form, $entry ); foreach ( pubforms_webhook_urls( $form ) as $url ) { pubforms_send_webhook( $url, $payload ); } }