View Categories

Hooks and Filters

The plugin’s public extension surface, grouped by what you’d want to do with it.


Ground Rules #

Before writing a callback:

  1. Filters must return their filtered value on every path, including early bails. Returning nothing replaces the value with null for every later callback.
  2. Be defensive. Don’t assume a parameter’s type; validate at the top of the callback.
  3. Never log field values or full entry data. The plugin’s own records are redacted deliberately — don’t undo that in an extension.

Tuning Intervals #

Filter Default Purpose
rfsfgf_worker_interval 900 Seconds between worker runs. One-minute floor. The health threshold (two intervals) follows it automatically.
rfsfgf_failed_check_interval 43200 Seconds between maintenance scans.
rfsfgf_failed_check_first_run UTC timestamp anchoring the maintenance event’s first run, so it lands at a preferred time of day.
rfsfgf_missed_run_grace 2 × worker interval How late an occurrence must be before a skipping feed treats it as missed. Never below one worker interval.
// Poll every five minutes. Only worth doing if the host invokes WordPress that often.
add_filter( 'rfsfgf_worker_interval', function ( $seconds ) {
    return 300;
} );

Interval changes are detected during registration, and an event registered at the wrong interval is repaired — with the previous timestamp and interval recorded.


Shaping Schedules #

Filter Receives Purpose
rfsfgf_schedule_created $schedule, $meta, $entry Adjust the normalized schedule as a series is created.
rfsfgf_next_occurrence $target, $schedule, $after Adjust a calculated target before it is stored.

rfsfgf_next_occurrence is the hook for calendar rules the settings don’t cover — a blackout window, a business-day offset, an organisation-specific holiday list.

add_filter( 'rfsfgf_next_occurrence', function ( $target, $schedule, $after ) {
    if ( ! is_int( $target ) ) {
        return $target;
    }
    // Push a target landing on a company holiday to the next day.
    return my_is_holiday( $target ) ? $target + DAY_IN_SECONDS : $target;
}, 10, 3 );

Return a valid future timestamp. A filter that returns something unusable will produce a schedule you can’t explain from the UI.


Processing Events #

Action Receives Fires
rfsfgf_attempt_started $attempt, $id, $context As an attempt begins.
rfsfgf_attempt_completed $result, $context When an attempt resolves. The context is redacted.
rfsfgf_lock_recovered $series_id When a stale claim is recovered.

Use these for structured monitoring — a metrics pipeline, an audit trail, a dashboard.

add_action( 'rfsfgf_attempt_completed', function ( $result, $context ) {
    if ( ! is_array( $result ) ) {
        return;
    }
    my_metrics_counter( 'rfsfgf.attempt.' . rgar( $result, 'outcome', 'unknown' ) );
}, 10, 2 );

Lifecycle and Transition Events #

Action Receives Fires
rfsfgf_series_pause $series A series is paused.
rfsfgf_series_resume $series A series is resumed.
rfsfgf_series_cancel $series A series is canceled.
rfsfgf_series_first_failure $series The first failure in a new sequence.
rfsfgf_series_failed $series The failure threshold was reached.
rfsfgf_series_recovered $series A success resolved the issue.
rfsfgf_parent_series_canceled $entry_id, $count, $reason A parent was trashed or deleted, cancelling its series. $reason distinguishes trashed from deleted.

These are the right hooks for routing alerts somewhere other than the Admin Email — Slack, a helpdesk, a log.

add_action( 'rfsfgf_series_failed', function ( $series ) {
    if ( ! is_array( $series ) ) {
        return;
    }
    my_alerting_channel( sprintf(
        'Recurring series #%d stopped after %d consecutive failures.',
        (int) rgar( $series, 'id' ),
        (int) rgar( $series, 'consecutive_failures' )
    ) );
} );

The historical rfsfgf_auto_form_submissions_failed_entries report filter is superseded by these events. Periodic full-history email generation has been removed.


Schedule Propagation #

Action Receives Fires
rfsfgf_schedule_applied $series_id, $schedule, $source A schedule was applied to one series.
rfsfgf_feed_schedule_applied $feed_id, $saved, $skipped A bulk feed application finished, with counts of applied and skipped series.
rfsfgf_next_submission_changed $series_id, $target, $schedule A series’ next target was moved.

Useful for auditing who changed what, and for reconciling a bulk application that skipped locked series.


Diagnostics #

Filter Receives Purpose
rfsfgf_diagnostic_context $context Adjust the diagnostic context before the report is produced.

The plugin applies its own bounded allowlist after this filter, so you cannot use it to leak values into a report. Adding non-sensitive environment detail is the intended use.


Shortcode Visibility #

Filter Receives Purpose
rfsfgf_shortcode_can_view $can_view, $context, $args Decide whether a shortcode renders, before anything is output.

$context is overview or entry_widget. For the entry widget, $args holds the entry and form.

add_filter( 'rfsfgf_shortcode_can_view', function ( $can_view, $context, $args ) {
    if ( 'entry_widget' === $context && ! $can_view ) {
        return get_current_user_id() && (int) rgar( $args['entry'], 'created_by' ) === get_current_user_id();
    }
    return $can_view;
}, 10, 3 );

Widening the read does not widen the write. The buttons and the handler behind them still require recurring_form_submissions_manage_resubmissions.


Capability #

recurring_form_submissions_manage_resubmissions

Granted to administrators automatically. Every operational surface and handler checks it; every request also verifies its nonce and that the parent, form and feed belong together.


Gravity Forms Integration Points #

The plugin registers ordinary Gravity Forms extension points you can use as usual:

Point Names
Notification events auto_submit_success, auto_submit_fail, auto_submits_complete
Merge tags {resubmission_progress}, {is_auto_submission}, {rfsfgf_is_parent_submission}, {total_resubmissions}, {rfsfgf_feed_label}
Entry meta Feed Label, Is Parent Submission, Is Auto Submission, Total Resubmissions, Resubmissions Progress

Child entries are created through normal Gravity Forms processing, so gform_after_submission and friends fire on them exactly as they would for a human submission. Use {is_auto_submission} or the entry meta to tell them apart.