schedule( $lead_id, 'lead.created' ); } /** * Queues the lead.status_changed event. * * @param int $lead_id Lead ID. */ public function on_status_changed( $lead_id ) { $this->schedule( $lead_id, 'lead.status_changed' ); } /** * Queues delivery so visitors and admins never wait for the endpoint. * * @param int $lead_id Lead ID. * @param string $event Event name. */ private function schedule( $lead_id, $event ) { if ( '' === Settings::get( 'webhook_url' ) ) { return; } wp_schedule_single_event( time(), self::HOOK, array( (int) $lead_id, $event ) ); } /** * Sends a queued event. * * @param int $lead_id Lead ID. * @param string $event Event name. */ public function deliver( $lead_id, $event ) { $lead = Leads::get( $lead_id ); if ( ! $lead ) { return; } if ( 'lead.created' === $event && 'spam' === $lead->status ) { return; } self::send( $event, self::payload( $lead ) ); } /** * Posts an event. * * @param string $event Event name. * @param array $lead Lead payload. * @return true|\WP_Error */ public static function send( $event, array $lead ) { $url = Settings::get( 'webhook_url' ); if ( '' === $url ) { return new \WP_Error( 'dealroot_webhook', __( 'No webhook URL is set.', 'dealroot' ) ); } $body = wp_json_encode( array( 'event' => $event, 'sent_at' => gmdate( 'c' ), 'site' => array( 'name' => wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ), 'url' => home_url( '/' ), ), 'lead' => $lead, ) ); $headers = array( 'Content-Type' => 'application/json; charset=utf-8', 'X-Dealroot-Event' => $event, ); $secret = Settings::get( 'webhook_secret' ); if ( '' !== $secret ) { $headers['X-Dealroot-Signature'] = 'sha256=' . hash_hmac( 'sha256', $body, $secret ); } $response = wp_safe_remote_post( $url, array( 'timeout' => 10, 'headers' => $headers, 'body' => $body, ) ); if ( is_wp_error( $response ) ) { return $response; } $code = (int) wp_remote_retrieve_response_code( $response ); if ( $code < 200 || $code >= 300 ) { /* translators: %d: HTTP status code. */ return new \WP_Error( 'dealroot_webhook', sprintf( __( 'The endpoint answered with HTTP %d.', 'dealroot' ), $code ) ); } return true; } /** * Lead data as sent to the endpoint. * * @param object $lead Lead row. * @return array */ public static function payload( $lead ) { $statuses = Leads::status_labels(); $payload = array( 'id' => (int) $lead->id, 'created_at' => gmdate( 'c', strtotime( $lead->created_at . ' UTC' ) ), 'name' => $lead->name, 'email' => $lead->email, 'phone' => $lead->phone, 'whatsapp_url' => Phone::whatsapp_url( 0 === strpos( $lead->phone, '+' ) ? $lead->phone : '' ), 'form' => array( 'plugin' => $lead->form_plugin, 'id' => $lead->form_id, 'name' => $lead->form_name, ), 'status' => $lead->status, 'status_label' => $statuses[ $lead->status ] ?? $lead->status, 'value' => null === $lead->value ? null : (float) $lead->value, 'currency' => $lead->currency, 'won_at' => $lead->won_at ? gmdate( 'c', strtotime( $lead->won_at . ' UTC' ) ) : null, 'channel' => $lead->channel, 'channel_label' => Attribution::channel_label( $lead->channel ), 'source' => $lead->source, 'medium' => $lead->medium, 'campaign' => $lead->campaign, 'last_channel' => $lead->last_channel, 'landing_page' => $lead->landing_page, 'gclid' => $lead->gclid, 'gbraid' => $lead->gbraid, 'wbraid' => $lead->wbraid, 'fbclid' => $lead->fbclid, 'msclkid' => $lead->msclkid, 'fields' => (array) json_decode( (string) $lead->fields, true ), 'attribution' => json_decode( (string) $lead->attribution, true ), 'recording_url' => '' !== Clarity::url( $lead ) ? Clarity::url( $lead ) : null, 'admin_url' => admin_url( 'admin.php?page=dealroot&lead=' . (int) $lead->id ), ); /** * Filters the webhook payload. * * @param array $payload Payload. * @param object $lead Lead row. */ return apply_filters( 'dealroot_webhook_payload', $payload, $lead ); } }