Developers

Developer Reference: Filters & Actions

Last updated July 7, 2026

Super Speedy Emails exposes a set of WordPress filters and actions so you can extend its behaviour from your own plugin, mu-plugin, or theme without modifying the plugin. This page is the complete reference for those hooks. For the database schema, PHP classes, and the sse_send() API, see the main Developer Reference.

Quick reference

HookTypePurpose
sse_send()functionQueue a single email from your own code.
sse_should_send_support_emailfilterPer-product: is there news to send? (default true)
sse_support_email_subjectfilterOverride the support email subject (optional).
sse_support_email_contentfilterThe body of a support email (returns { body, name }).
sse_support_email_should_send_to_userfilterPer-owner: should this person receive it?
sse_support_email_sentactionFires per queued support email (real sends only).
sse_changelog_product_mapfilter(Companion plugin) map product IDs to plugin slugs.
sse_support_assets_dirfilter(Companion plugin) where the changelog reader looks for files.
sse_templates_registryfilterAdd or override email templates.
sse_confirmation_ttl_daysfilterDouble opt-in link lifetime.
sse_automation_triggersfilterRegister custom automation trigger types.

The sse_send() function

The public entry point for sending a single email from another plugin. It runs the suppression gate, creates a log entry, and queues the message for delivery.

$result = sse_send( array(
    'email'            => 'customer@example.com',
    'subject'          => 'Your licence expires soon',
    'body_text'        => "Hi {{first_name}},
Your licence expires in 7 days...",
    'category'         => 'product_marketing',   // governs the suppression rules
    'unsubscribe_url'  => $your_unsubscribe_url,  // optional; sets List-Unsubscribe
    'source_plugin'    => 'my-renewals-plugin',
    'source_reference' => 'renewal:order:12345',  // your own tag for dedup/audit
) );
if ( is_wp_error( $result ) ) {
    // Blocked by a suppression, or an invalid address.
} else {
    // $result is the email log row ID.
}

It returns the log row ID on success, or a WP_Error if the address is invalid or suppressed for that category. Full argument documentation is in the Developer Reference. The hooks below are mostly about the automated support-email system, which is the main extension surface.

Support-email hooks

These power the Automated Support & Changelog Emails feature. The engine is generic; these hooks supply the policy. Every callback receives the running value plus a single SSE_Support_Context $context — see the Developer Guide for the full object. $context->product_id is always set; $context->subscriber is null in the per-product probe and set per recipient at send; $context->is_preview is true during the admin Preview (your filters must be side-effect-free then).

There is no sse_support_email_product_ids filter — the products a support email covers are the admin’s checklist on the Support Email record.

sse_should_send_support_email (filter) — per product

Runs once per product, before owners are loaded. Return true if there’s news worth sending. Default true. Guard any state write with $context->is_preview.

add_filter( 'sse_should_send_support_email', function ( $should, $context ) {
    // $context->product_id set; $context->is_preview true during Preview
    return $should;   // false → skip this product (no owners loaded)
}, 10, 2 );

sse_support_email_subject (filter) — optional

Runs per product (and per recipient at send). Return a string to override the GUI subject. Most implementations skip this and set the subject in the GUI with a {product_name} token.

add_filter( 'sse_support_email_subject', function ( $subject, $context ) {
    return $subject;
}, 10, 2 );

sse_support_email_content (filter) — per product

Runs per product (and per recipient at send). Return { body, name }. The incoming $content holds the GUI defaults — return it to keep them; an empty body sends nothing for that product.

add_filter( 'sse_support_email_content', function ( $content, $context ) {
    return array(
        'body' => "Hi {first_name},
Here's what changed...
- Faster cache warmup",
        'name' => 'Scalability Pro', // human name for the footer
    );
}, 10, 2 );

Per-recipient tokens ({first_name}, {unsubscribe_url}, {manage_url}, {product_name}, {email}, {site_name}, {site_url}) are filled by the engine (double-brace {{...}} is also accepted for back-compat). A subject key here is honoured only as a fallback. There is no reference key — repeat behaviour is handled by the per-day guard (below).

sse_support_email_should_send_to_user (filter) — per owner

Runs once per owner, after the per-day guard, the suppression gate and the admin’s recency rules. Return false to skip this individual. Default true. $context->subscriber, ->matching_product and ->all_products are set.

add_filter( 'sse_support_email_should_send_to_user', function ( $send, $context ) {
    // e.g. skip bundle-only owners:
    if ( $context->matching_product && ! $context->matching_product->direct ) {
        return false;
    }
    return $send;
}, 10, 2 );

People excluded here appear under Will NOT receive in the Preview. You don’t check unsubscribes/bounces here — the gate already removed them.

sse_support_email_sent (action)

Fires once per successfully-queued support email, on real sends only (never during Preview). The changelog companion uses it to advance its stored “last sent version” — after a successful send, never inside the decision filter, so a failure can’t skip a release.

add_action( 'sse_support_email_sent', function ( $context ) {
    // $context->product_id, $context->subscriber, $context->name, ...
} );

Repeat behaviour (no reference in core)

There is no version/reference dedup in core. Repeats are governed by two things: the per-day guard (at most one email per support-email + product + customer per calendar day) and your sse_should_send_support_email filter (which decides when there’s news). “Send again tomorrow because the version changed” = your filter returns true again on a new day.

Changelog-reader hooks

These belong to the companion plugin (Super Speedy Plugins — Changelog Emails), the worked-example consumer of the support-email filters above. They are not part of the core plugin.

sse_changelog_product_map (filter)

Maps a WooCommerce product ID to a plugin slug, so the reader knows which readme.txt / metadata to read for that product. Ships pre-filled with the Super Speedy Plugins catalogue.

add_filter( 'sse_changelog_product_map', function ( $map ) {
    $map[12345] = 'my-plugin-slug';
    return $map;
} );

sse_support_assets_dir (filter)

Overrides the local directory the changelog reader looks in for each plugin’s readme.txt and metadata file. Useful in development, or if your assets live somewhere non-standard.

add_filter( 'sse_support_assets_dir', function ( $dir ) {
    return '/path/to/your/plugin/assets';
} );

Template hooks

sse_templates_registry (filter)

Adds new editable email templates, or overrides the defaults of existing ones. The registry defines each template’s label, default subject/body, and the list of supported {{tokens}}. See Editing Email Templates.

add_filter( 'sse_templates_registry', function ( $registry ) {
    $registry['my_template'] = array(
        'label'        => 'My custom email',
        'has_subject'  => true,
        'subject'      => 'Hello {{first_name}}',
        'body'         => "Hi {{first_name}},
...",
        'placeholders' => array(
            '{{first_name}}' => "Recipient's first name",
        ),
    );
    return $registry;
} );

Render a registered template in your own code with SSE_Templates::subject( $key, $vars ) and SSE_Templates::body( $key, $vars ) — only the tokens you pass are replaced, so unknown tokens are left intact for a later pass.

Other hooks

sse_confirmation_ttl_days (filter)

How long a double opt-in confirmation link stays valid, in days (default 7). See Double Opt-in.

add_filter( 'sse_confirmation_ttl_days', function ( $days ) {
    return 14;
} );

sse_automation_triggers (filter)

Registers additional automation trigger types beyond the built-in ones, so your code can start an automation sequence from a custom event. See Automations & Drips.

add_filter( 'sse_automation_triggers', function ( $triggers ) {
    $triggers['my_custom_event'] = array(
        'label' => 'My custom event',
    );
    return $triggers;
} );

Where to put this code

Hook code belongs in a small plugin or mu-plugin (recommended, so it’s version-controlled and survives theme changes), or your theme’s functions.php. For the support-email filters specifically, a dedicated mu-plugin keeps your sending policy in one auditable place.

Leave a Reply

Your email address will not be published. Required fields are marked *

×
1/1