FFL Funnels Sync
WooCommerce → FFL Funnels dashboard sync (signed HTTPS webhook, HPOS-compatible)
Install
Upload it under Plugins → Add New Plugin → Upload Plugin, then activate.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/aaruca/ffl-funnels-sync/releases/download/v1.0.0/ffl-funnels-sync-1.0.0.zipWordPress plugin: sends WooCommerce order events to the FFL Funnels ads dashboard using a signed HTTPS webhook. Delivery is event-driven through WooCommerce hooks, with Action Scheduler used when available and one-off retries scheduled when a delivery fails.
Versioning and releases
- The plugin header
Version, the PHP constantFFL_FS_VERSION, and the annotated tag (for examplev1.0.0) must match on each public release. GitHub Actions will refuse to build a release asset if they diverge. - Git tags use SemVer:
vMAJOR.MINOR.PATCH. Pushing a tag of the formv*.*.*runs the Release workflow and publishesffl-funnels-sync-MAJOR.MINOR.PATCH.zipon the Releases page. That zip is created withgit archiveand excludes.github/and other repo-only files so the package matches what you would upload to a site. - Schema migrations use a separate option,
ffl_fs_schema_version(integer), not the marketing version string. Bump that only when the stored option shape or encryption layout changes.
See CHANGELOG.md for release history.
Requirements
- WordPress 6.2+
- WooCommerce 7.0+
- PHP 7.4+
Security
- Direct access: Every PHP file under
includes/starts withdefined('ABSPATH') || exit. Root andincludes/also ship an emptyindex.phpso misconfigured servers do not list directory contents. - Settings: Saving options requires
manage_woocommerce. Unauthorized saves keep the previous stored values. - Secret at rest: The shared secret entered in wp-admin is stored encrypted in
wp_options(AES-256-GCM) using keys derived from WordPressAUTH_KEY/ salts (includes/Crypto.php). ConstantsFFL_FUNNELS_SYNC_SECRET/FFL_WEBHOOK_SECRETstill bypass DB entirely if you define them. - Outbound webhooks: HTTPS only, TLS verification on, HMAC signature on every request. Optional host allowlist via filter
ffl_fs_allowed_webhook_hosts(seeincludes/Security.php). - Logs: When debug logging is enabled, messages are passed through
Security::redact_log_message()(strips HTML and masks email-like strings).
Install (from a release zip, recommended)
- Open Releases and download the latest
ffl-funnels-sync-x.y.z.zip(not "Source code", unless you are developing the plugin). - In WordPress: Plugins -> Add New -> Upload Plugin and choose the file, or unzip so that
wp-content/plugins/ffl-funnels-sync/containsffl-funnels-sync.phpand theincludes/directory. - Activate FFL Funnels Sync, then go to WooCommerce -> FFL Funnels Sync and set the webhook URL and shared secret.
Note: A plain clone or "Download ZIP" of the whole repository is fine for development, but the installable build for production is the release asset (smaller, no .github/ or git metadata in the tree).
Install (manual copy from source)
- Copy the
ffl-funnels-syncfolder intowp-content/plugins/. - Activate FFL Funnels Sync in wp-admin.
- Open WooCommerce -> FFL Funnels Sync and enter the webhook URL and shared secret for this site.
Use Test connection now on that screen (after saving, if needed) to POST a signed connection_test event; success means HTTPS, host allowlist (if used), secret, and signature headers were accepted with HTTP 2xx. Your dashboard must treat that payload like other webhooks (verify HMAC); if it returns an error status for unknown event types, the test may fail while real order events still work.
The plugin does not ship a default endpoint or secret. Orders start syncing once the admin fills those in, or once they are defined in wp-config.php:
define('FFL_FUNNELS_SYNC_ENDPOINT', 'https://ads-dashboard.fflfunnels.com/api/webhooks/woocommerce');
define('FFL_FUNNELS_SYNC_SECRET', 'use-a-long-random-string');
FFL_WEBHOOK_URL and FFL_WEBHOOK_SECRET are accepted as aliases for the two constants above. When either pair is defined, the corresponding setting is managed outside the database and the admin field becomes read-only.
Events
The plugin sends distinct events for:
- paid orders (
order_paid) - completed orders (
order_completed) - partial refunds (
order_partially_refunded) - full refunds (
order_fully_refunded)
Each event is tracked independently per order so later lifecycle events are not blocked by earlier successful deliveries.
Security (dashboard side)
Each request includes:
X-FFL-Timestamp- Unix timestamp (string).X-FFL-Signature-sha256=+hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret).
Verify using the raw request body (before JSON decode). Reject stale timestamps (for example older than 5 minutes) to limit replay attacks.
Filters
ffl_fs_connection_test_payload- adjust the JSON body for Test connection now (default event nameconnection_test).ffl_fs_payload- adjust the outbound array before signing. Receives the payload,WC_Order, event name, and refund ID.ffl_fs_force_resend- returntrueto allow sending a previously delivered event again. Receives the legacy boolean,WC_Order, event key, event name, and refund ID.ffl_fs_allowed_webhook_hosts- return an array of allowed hostname strings (for example['ads-dashboard.fflfunnels.com']) to block requests to any other host. Defaultnullmeans no extra host restriction (HTTPS + valid URL still required).ffl_fs_default_endpoint- optionally prefill the dashboard URL for new installs. Default is empty.
Uninstall
Deactivating unschedules pending background deliveries. Uninstalling deletes ffl_funnels_sync_options, ffl_fs_schema_version, queued dispatch jobs, and plugin-specific order meta.
License
GPL-2.0-or-later. See LICENSE.
Releases
1 release. Each count is every asset in that release; expand a row for the breakdown.