Skip to main content
Adzbyte
CRM Lifecycle EngineeringCRM IntegrationPlugin DevelopmentWordPress

One lead record, even when form events race

Salesforce Extended for Gravity Forms

A lifecycle layer for Gravity Forms and Salesforce that captures useful partial submissions without duplicating or downgrading the completed CRM record.

Role

WordPress Integration Developer

Timeline

October 2025–present

Status

Released

Client

Multi-step lead workflow

Diagram showing partial heartbeat, abandonment scan, manual send, and final submission passing through locks and validation to one authoritative Salesforce record ID.

01 / The problem

A workflow that needed stronger engineering boundaries

Multi-step forms can contain valuable lead data before final submission, but synchronizing partial entries creates concurrency and identity risks. Heartbeats may overlap, an abandonment scan may run beside a live submission, and a queued partial save may arrive after a final entry is complete. If each event independently searches by mutable values such as phone or email, the CRM can receive duplicates or stale updates.

  • Losing usable leads when a visitor abandons a multi-page form
  • Creating duplicate CRM records from partial and complete events
  • Late heartbeats recreating or downgrading completed entries
  • Multiple Salesforce feeds updating the wrong object or account
  • A transient API error falling through to another create-capable feed
  • Concurrency between real-time, scheduled, manual, and full-submit paths

02 / The approach

Design the workflow around explicit invariants

Treat CRM identity as an explicit lifecycle invariant. The first successful write records the Salesforce ID, object, and feed on the Gravity Forms entry. Every later path either reuses that exact ID for the same object or leaves unrelated object feeds untouched. Cross-request locks and completion state serialize competing events, while validation and fail-closed feed processing stop incomplete or ambiguous writes.

  • Capture only useful partials: Mapped or configured required fields and the feed's primary key determine when an entry is ready to sync.
  • Preserve authoritative identity: The first successful Salesforce response establishes the record ID; later updates inject that ID only for the matching object.
  • Coordinate every event source: Immediate partial saves, scheduled abandonment, native/manual sends, and full submissions share lifecycle metadata and locks.
  • Fail closed: Hard API or validation errors stop feed fall-through, while update-only and conditional-feed rules remain intact.

03 / Architecture

Gravity Forms add-on plus dedicated synchronization, abandonment, Salesforce-record lifecycle, and partial-entry lifecycle services

The implementation separates WordPress integration points from the domain services and operational controls that carry the workflow.

  • WordPress and Gravity Forms bootstrap
  • Per-form settings and feed-aware mapping UI
  • Partial-entry sync handler
  • Scheduled abandonment scanner
  • Authoritative Salesforce record lifecycle coordinator
  • Heartbeat/final-submission concurrency coordinator
  • Entry-note and debug logging

04 / System surface

Capabilities organized around the operator journey

The case study focuses on the verified engineering surface rather than unmeasured business claims.

  • Partial lead capture: Sync after all mapped fields are filled, regardless of form page
  • Partial lead capture: Configurable required-field subset for abandonment capture
  • Lifecycle identity: Stores the first Salesforce ID, object, and feed as the authoritative relationship
  • Lifecycle identity: Forces later same-object writes to the stored ID
  • Concurrency and duplicate prevention: Atomic per-entry lock across partial, abandonment, and managed full submission
  • Concurrency and duplicate prevention: Per-form partial UUID and browser lifecycle locks
  • Operations: Entry notes and debug logging
  • Operations: Five-minute abandonment scan with timeout and query controls

05 / Engineering decisions

Tradeoffs made explicit

The design choices below address compatibility, identity, safety, and maintainability constraints found in the audited implementation.

  • Make Salesforce ID the lifecycle identity after the first successful write: Email, phone, and names may change or produce ambiguous searches; the returned CRM ID is stable.
  • Scope forced IDs to the authoritative object: A form can create several object types, so a Lead ID must never be injected into Contact, Assessment, or another feed.
  • Serialize cross-request writes with WordPress option locks: Atomic `add_option()` provides a shared boundary for concurrent PHP requests without introducing a separate queue service.
  • Correlate first-save requests with a browser lifecycle ID: Before Partial Entries assigns a UUID, the browser ID closes the pending-window gap between heartbeat and final submission.
  • Stop on hard Salesforce errors: Trying another create-capable feed after a hard failure could turn a transient error into a duplicate.
  • Inherit connection and feed configuration from the parent plugin: Partial and complete submissions use the same account, object, primary key, conditional logic, and update-only rules.

06 / Verified outcome

A defensible result grounded in inspected evidence

Repository and interface evidence establish the engineering outcome. Production volume, time savings, and business impact remain unclaimed unless separately confirmed.

  • Release v1.6.1 resolves to the current default-branch commit dc941679744e1fd7500f1ef7816109af5ea065c0.
  • The inspected history contains 50 commits, all attributed to Adrian T. Saycon.
  • The release contains 24 PHP files, 1 JavaScript file, and 1 CSS file, with 3,067 application PHP lines and 3,236 test/support PHP lines.
  • The repository contains 61 test methods in 15 PHP test/support files.
  • GitHub Actions completed the v1.6.1 PHP 7.4-8.3 test matrix successfully.
  • CRM record identity remains explicit across partial and final lifecycle stages.
  • Concurrency behavior is designed and tested rather than left to request timing.
  • The extension adds partial capture without replacing the parent plugin's authentication or feed model.

Project gallery

Diagram showing partial heartbeat, abandonment scan, manual send, and final submission passing through locks and validation to one authoritative Salesforce record ID.
Every event source converges on one authoritative Salesforce record lifecycle.
Sanitized Salesforce Extended settings showing partial-entry and abandonment controls with feed labels blurred.
Per-form settings make partial-entry timing, abandonment, feed selection, and required-field policy explicit.

Latest Articles

From the Blog

View all articles