FED Group Klaviyo Subscriptions
Pushes subscription events from WooCommerce to Klaviyo.
by FED Group · github.com/jes-wd/fed-group-klaviyo-subscriptions
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/jes-wd/fed-group-klaviyo-subscriptions/archive/refs/heads/main.zipWordPress plugin that sends selected WooCommerce Subscriptions lifecycle signals to Klaviyo: failed payments, final cancellation, skip-week actions, day-before-payment Meals Predicted, and ongoing subscription_status on the Klaviyo profile. It is built so checkout and subscription flows are never blocked by Klaviyo; failures are logged only.
Requirements
- WordPress 6.0 or newer
- PHP 7.4 or newer
- WooCommerce
- WooCommerce Subscriptions (
wcs_get_subscriptionmust exist) - A Klaviyo private API key on the live site (see below)
Installation
- Copy the
fed-group-klaviyo-subscriptionsfolder intowp-content/plugins/. - Activate FED Group Klaviyo Subscriptions in the Plugins screen.
- On the live store, define the API key (recommended in
wp-config.php, beforeABSPATHis irrelevant but before the plugin runs is fine if the constant is defined early):
define( 'FGKS_KLAVIYO_API_KEY', 'your-private-api-key' );
If the key is missing on a live host, administrators see a dashboard notice explaining how to set it.
Production-only behaviour
By default the plugin does nothing unless the current site hostname is exactly the live apex host (fedgroup.com.au). Host detection uses home_url() (with a fallback to HTTP_HOST when needed). Subdomains such as staging.fedgroup.com.au are not treated as live.
Staging, local, and preview URLs therefore load the plugin file but do not register WooCommerce hooks, do not call Klaviyo, and do not show the missing-key notice.
Overrides
| Mechanism | Purpose |
|---|---|
FGKS_KLAVIYO_ALLOW_NON_LIVE |
Define and set truthy to allow Klaviyo traffic from non-live hosts (for example local integration testing). Use with care. |
Filter fgks_is_live_klaviyo_environment |
Return true or false to force live or non-live behaviour regardless of hostname. |
Configuration filters
| Filter | Arguments | Description |
|---|---|---|
fgks_klaviyo_api_key |
(string) $api_key |
Supply or replace the Klaviyo private key without hard-coding it in the repo. |
fgks_klaviyo_store_name |
(string) $name |
Default display name in event properties is Get Fed; change it here if needed. |
fgks_is_live_klaviyo_environment |
null |
Return a boolean to override live detection (see above). |
fgks_skip_klaviyo_delay_seconds |
(int) 60 |
Seconds to wait after skip before sending Subscription Skipped (so skip reason can be saved). |
fgks_skip_reason_text |
(string) $reason, (int) $subscription_id, (string) $meal_delivery_unique_id |
Adjust resolved skip reason before the Klaviyo event. |
fgks_skip_dedupe_enabled |
(bool) true |
Set to false to allow multiple Subscription Skipped events per subscription per day (testing only). |
fgks_meals_predicted_dedupe_enabled |
(bool) true |
Set to false to allow duplicate Meals Predicted events for the same subscription/delivery/week (testing only). |
fgks_meals_predicted_properties |
(array) $properties, (array) $payload, WC_Subscription $subscription |
Adjust Meals Predicted event properties before send. |
Constants you may define before the plugin’s defaults:
FGKS_KLAVIYO_API_KEY— private key (empty string is the default).FGKS_KLAVIYO_REVISION— Klaviyo API revision header; default is pinned in the main plugin file.FGKS_KLAVIYO_ALLOW_NON_LIVE— allow sending from non-live environments.
Klaviyo usage
- Events API —
POST https://a.klaviyo.com/api/eventsfor metrics Payment Failed, Subscription Cancelled, and Subscription Skipped. - Profiles API —
POST https://a.klaviyo.com/api/profile-importwhen a subscription’s status changes, to keepsubscription_statusaligned (active,on_hold,pending_cancel, orcancelled).
Headers follow Klaviyo’s JSON:API expectations, including the pinned revision value.
WooCommerce hooks
| Hook | Effect |
|---|---|
woocommerce_subscription_payment_failed |
Sends Payment Failed with recovery URL, Stripe-style decline details when present, amount, currency, and is_first_order. |
woocommerce_subscription_status_cancelled |
Sends Subscription Cancelled once per subscription (after a successful API response). Includes previous_status when it was captured on the way into cancelled. |
woocommerce_subscription_status_updated |
Upserts the Klaviyo profile with normalised subscription_status only (no extra metric per status). |
woocommerce_subscription_pre_update_status |
Internal: records the prior status when the new status is cancelled, because the dedicated cancelled hook runs before the generic “updated” hook. |
The following hook is intentionally not used: woocommerce_subscription_renewal_payment_failed (the generic payment-failed hook is used instead).
Skip week (theme integration)
After a customer’s skip is persisted, the theme should fire:
do_action( 'getfed_subscription_skipped', $subscription_id, $customer_email, $skip_reason, $meal_delivery_unique_id );
The FED Group theme calls this from the meal-selection AJAX handler when the user chooses skip for a week. The plugin waits 60 seconds (filterable) before sending Subscription Skipped, then resolves skip_reason from the optional hint, the skipping-reason CPT, or fgks_skip_reason_text.
Meals Predicted (theme integration)
On the Melbourne day before payment day (03:00), the theme cron fed_predict_weekly_meals freezes each eligible box. By default it only logs what would be sent (JSON lines in wp-content/uploads/fed-meals-predicted.log) and does not call Klaviyo.
Enable the live event from wp-config.php (or a filter) when ready:
define( 'FED_MEALS_PREDICTED_KLAVIYO_ENABLED', true );
// or: add_filter( 'fed_meals_predicted_klaviyo_enabled', '__return_true' );
When enabled, the theme fires:
do_action( 'getfed_meals_predicted', $payload );
$payload includes subscription_id, user_id, meals (flat product ID list), delivery_date, payment_date, week, year, meal_delivery_id, and related fields.
The plugin sends metric Meals Predicted with a Placed Order–style shape (ItemNames, Items / extra.Items / $extra.Items, categories, quantity, $value). After a successful send it fires fgks_meals_predicted_sent so the theme marks that week as sent (no re-fire on late meal edits).
Skips and company week-off never emit this event. Eligibility is enforced in the theme (next payment tomorrow, or last order is the paid processing parent).
Deduplication and meta keys
Deduplication metadata is written only after Klaviyo returns success, so a failed HTTP call can be retried on a later hook.
| Scenario | Meta key | Notes |
|---|---|---|
| Payment failed | _fgks_last_payment_failed_hash on the order |
Hash from subscription id, order id, failure code (or empty), and order modified time. |
| Cancelled | _fgks_cancelled_sent on the subscription |
Flag after a successful cancelled event. |
| Cancelled (internal) | _fgks_cancel_previous_status on the subscription |
Cleared after a successful cancelled event. |
| Skip | _fgks_last_skip_dedup_key on the subscription |
One successful skip event per subscription per site-local calendar day (wp_date). |
| Skip (pending) | _fgks_pending_skip_delivery_id, _fgks_pending_skip_reason_hint on the subscription |
Set when a skip is scheduled; cleared when the delayed send runs. |
| Meals Predicted | _fgks_last_meals_predicted_key on the subscription |
Hash of subscription id, meal delivery id, ISO week, and year after a successful send. |
Logging
HTTP and transport errors are logged with WooCommerce’s logger when available, using the log source fed-group-klaviyo-subscriptions. If WooCommerce logging is unavailable, error_log is used as a fallback.
Support and safety
- The plugin does not run raw SQL against WooCommerce tables; it uses WooCommerce APIs and subscription objects.
- Klaviyo errors must not break checkout: the client catches failures and logs them without throwing.
Version
See the plugin header in fed-group-klaviyo-subscriptions.php for the current version string.