Developer Documentation

Hooks and Filters


Fatal Error Notify provides several hooks and filters that allow you to customize error handling behavior, modify notification contents, and integrate with your own plugins or themes.

Error Handling Filters

fen_ignore_error

Allows you to completely ignore specific errors before they are processed.

/**
 * Filter whether to ignore an error.
 *
 * @param bool  $ignore Whether to ignore the error.
 * @param array $error  The error data array.
 */
add_filter( 'fen_ignore_error', function( $ignore, $error ) {
    // Ignore all warnings from a specific plugin
    if ( isset( $error['file'] ) && strpos( $error['file'], 'problematic-plugin' ) !== false ) {
        return true;
    }
    return $ignore;
}, 10, 2 );
fen_is_error_type_enabled

Filter whether an error type is enabled for notifications on a specific channel.

/**
 * Filter whether an error type is enabled for notifications.
 *
 * @param bool   $enabled Whether the error type is enabled.
 * @param array  $error   The error data array containing 'type' and other details.
 * @param string $channel The notification channel (email, slack, twilio, echodash) or false for any channel.
 */
add_filter( 'fen_is_error_type_enabled', function( $enabled, $error, $channel ) {
    // Only send critical WooCommerce errors to Slack
    if ( $channel === 'slack' && strpos( $error['type'], 'woocommerce_' ) === 0 ) {
        return in_array( $error['type'], [ 'woocommerce_emergency', 'woocommerce_critical' ] );
    }
    return $enabled;
}, 10, 3 );
fen_is_error_paused

Filter whether an error notification is paused.

/**
 * Filter whether an error notification is paused.
 *
 * @param bool  $paused Whether the error notification is paused.
 * @param array $error  The error data array.
 */
add_filter( 'fen_is_error_paused', function( $paused, $error ) {
    // Pause all errors during maintenance mode
    if ( wp_maintenance_mode() ) {
        return true;
    }
    return $paused;
}, 10, 2 );
fen_is_rate_limited

Filter whether an error notification is rate limited.

/**
 * Filter whether an error notification is rate limited.
 *
 * @param bool  $rate_limited Whether the error is currently rate limited.
 * @param array $error        The error data array.
 */
add_filter( 'fen_is_rate_limited', function( $rate_limited, $error ) {
    // Never rate limit critical errors
    if ( isset( $error['type'] ) && $error['type'] === E_ERROR ) {
        return false;
    }
    return $rate_limited;
}, 10, 2 );

Rate Limiting Customization

fen_rate_limit_time

Customize the rate limiting time period (default is 1 hour).

/**
 * Change rate limiting to 30 minutes instead of 1 hour.
 */
add_filter( 'fen_rate_limit_time', function( $time ) {
    return 30 * MINUTE_IN_SECONDS;
} );
fen_rate_limit_data

Customize what data is used to generate the rate limiting hash.

/**
 * Include user ID in rate limiting to separate errors by user.
 *
 * @param array $rate_limit_data The data to use for rate limiting.
 * @param array $error           The full error data array.
 */
add_filter( 'fen_rate_limit_data', function( $rate_limit_data, $error ) {
    if ( isset( $error['user'] ) ) {
        $rate_limit_data['user'] = $error['user'];
    }
    return $rate_limit_data;
}, 10, 2 );

Notification Content Filters

fen_error

Filter the error data before sending notifications.

/**
 * Filter the error data before sending notifications.
 *
 * @param array $error The error data array.
 */
add_filter( 'fen_error', function( $error ) {
    // Add custom context to error messages
    if ( isset( $error['message'] ) ) {
        $error['message'] = '[Site: ' . get_bloginfo( 'name' ) . '] ' . $error['message'];
    }
    return $error;
} );
fen_email_notification_output

Filter the email notification output.

/**
 * Filter the email notification output.
 *
 * @param string $output The email notification output.
 * @param array  $error  The error data array.
 */
add_filter( 'fen_email_notification_output', function( $output, $error ) {
    // Add custom footer to email notifications
    $output .= '

Need help? Contact support at [email protected]

'; return $output; }, 10, 2 );
fen_email_notification_subject

Filter the email notification subject.

/**
 * Filter the email notification subject.
 *
 * @param string $subject The email notification subject.
 * @param array  $error   The error data array.
 */
add_filter( 'fen_email_notification_subject', function( $subject, $error ) {
    // Add priority indicator for fatal errors
    if ( isset( $error['type'] ) && $error['type'] === E_ERROR ) {
        $subject = '[URGENT] ' . $subject;
    }
    return $subject;
}, 10, 2 );
fen_full_request_url

Filter the full request URL included in notifications.

/**
 * Filter the full request URL.
 *
 * @param string $url   The full request URL.
 * @param array  $error The error data array.
 */
add_filter( 'fen_full_request_url', function( $url, $error ) {
    // Add UTM parameters for tracking
    return add_query_arg( 'utm_source', 'error_notification', $url );
}, 10, 2 );

WordPress Mail Integration

fen_use_wp_mail

Control whether to use WordPress’s wp_mail() function or PHP’s mail() function.

/**
 * Force use of PHP mail() instead of wp_mail().
 */
add_filter( 'fen_use_wp_mail', '__return_false' );

Action Hooks


Error Processing Actions

fen_handle_error

Fired when an error is being handled, before notifications are sent.

/**
 * Log all errors to a custom log file.
 *
 * @param array $error The error data array.
 */
add_action( 'fen_handle_error', function( $error ) {
    error_log( 
        '[' . date( 'Y-m-d H:i:s' ) . '] FEN Error: ' . print_r( $error, true ),
        3,
        WP_CONTENT_DIR . '/custom-error.log'
    );
} );
fen_handle_error_{type}

Fired for specific error types (e.g., fen_handle_error_1 for E_ERROR).

/**
 * Send critical errors to external monitoring service.
 */
add_action( 'fen_handle_error_1', function( $error ) { // E_ERROR = 1
    // Send to external monitoring service
    wp_remote_post( 'https://monitoring.example.com/api/errors', [
        'body' => json_encode( $error ),
        'headers' => [ 'Content-Type' => 'application/json' ]
    ] );
} );

Settings Management


Getting Settings

Access Fatal Error Notify settings programmatically:

// Get all settings
$settings = fatal_error_notify()->admin->get_all();

// Get a specific setting
$email = fatal_error_notify()->admin->get( 'notification_email' );

// Get setting with default value
$slack_channel = fatal_error_notify()->admin->get( 'slack_channel_id', '#general' );

Setting Filters

fen_get_setting_{key}

Filter individual setting values when they’re retrieved.

/**
 * Override license key from wp-config.php constant.
 */
add_filter( 'fen_get_setting_license_key', function( $license_key ) {
    if ( defined( 'FATAL_ERROR_NOTIFY_LICENSE_KEY' ) ) {
        return FATAL_ERROR_NOTIFY_LICENSE_KEY;
    }
    return $license_key;
} );

Creating Custom Integrations


Fatal Error Notify supports custom plugin integrations through an extensible architecture. You can create integrations for your own plugins or third-party plugins.

Integration Class Structure

Create a class that extends FEN_Integration:

class FEN_My_Plugin extends FEN_Integration {

    public $slug = 'my-plugin';
    public $title = 'My Plugin';

    /**
     * Initialize hooks specific to this integration.
     */
    public function init() {
        add_action( 'my_plugin_error', array( $this, 'handle_plugin_error' ) );
        add_filter( 'my_plugin_setting', array( $this, 'enable_error_logging' ) );
    }

    /**
     * Get registered error types for this integration.
     *
     * @return array Types
     */
    public function get_error_types() {
        return array(
            'api_error'      => __( 'API Connection Error', 'my-plugin' ),
            'validation'     => __( 'Data Validation Error', 'my-plugin' ),
            'payment_failed' => __( 'Payment Processing Error', 'my-plugin' ),
        );
    }

    /**
     * Handle errors from our plugin.
     */
    public function handle_plugin_error( $error_data ) {
        $error = array(
            'type'    => $error_data['type'], // Should match a key from get_error_types()
            'message' => $error_data['message'],
            'user'    => get_current_user_id(),
        );

        // Add additional context if available
        if ( isset( $error_data['context'] ) ) {
            $error['message'] .= "\n\nContext: " . print_r( $error_data['context'], true );
        }

        $this->handle_error( $error );
    }

    /**
     * Enable error logging in our plugin.
     */
    public function enable_error_logging( $value ) {
        // Force enable logging if FEN integration is active
        if ( $this->is_enabled() ) {
            return true;
        }
        return $value;
    }
}

// Initialize the integration
new FEN_My_Plugin();

Integration Registration

Register your integration with Fatal Error Notify using the fen_integrations filter:

/**
 * Register custom integrations.
 *
 * @param array $integrations Existing integrations.
 * @return array Modified integrations.
 */
add_filter( 'fen_integrations', function( $integrations ) {
    $integrations['my-plugin'] = 'My_Plugin_Main_Class';
    return $integrations;
} );

Integration Helper Methods

The FEN_Integration base class provides several helper methods:

// Check if integration is enabled for any notification channel
if ( $this->is_enabled() ) {
    // Integration is active
}

// Get enabled notification channels
$channels = $this->get_enabled_channels(); // Returns array like ['email', 'slack']

// Get enabled error types
$types = $this->get_enabled_types(); // Returns array like ['api_error' => true]

Manual Error Triggering


You can manually trigger error notifications from your code:

Trigger PHP Error Notification

$error = array(
    'type'    => E_WARNING,
    'message' => 'Custom error message from my plugin',
    'file'    => __FILE__,
    'line'    => __LINE__,
    'user'    => get_current_user_id(),
);

fatal_error_notify()->public->handle_error( $error );

Trigger Custom Integration Error

// Assuming you have a custom integration class instance
$integration = fatal_error_notify()->integrations->{'my-plugin'};

$error = array(
    'type'    => 'api_error', // Must match a type from get_error_types()
    'message' => 'API connection failed: timeout after 30 seconds',
    'user'    => get_current_user_id(),
);

$integration->handle_error( $error );

WP-CLI Commands


Fatal Error Notify includes WP-CLI support for managing settings programmatically.

Available Commands

Get All Options
wp fatal-error-notify get_options
Get Specific Option
wp fatal-error-notify get_option notification_email
wp fatal-error-notify get_option levels
Update Option
# Simple value
wp fatal-error-notify update_option notification_email [email protected]

# Array value (JSON format)
wp fatal-error-notify update_option levels '{"1":true,"2":false,"4":true}'
Bulk Updates
# Update email on all sites in multisite
wp site list --field=url | xargs -n1 -I {} sh -c 'wp --url={} fatal-error-notify update_option notification_email [email protected]'

Error Data Structure


Understanding the error data structure helps when working with hooks and filters.

PHP Error Structure

array(
    'type'    => 1,              // PHP error constant (E_ERROR, E_WARNING, etc.)
    'message' => 'Error message',
    'file'    => 'path/to/file.php',
    'line'    => 123,
    'user'    => 1,              // WordPress user ID (if available)
)

Plugin Integration Error Structure

array(
    'type'    => 'plugin_error_type', // Integration slug + underscore + error type
    'message' => 'Error message',
    'user'    => 1,                   // WordPress user ID (if available)
    'url'     => 'https://...',       // Optional: relevant URL
    'file'    => 'path/to/file.php',  // Optional: relevant file
    'line'    => 123,                 // Optional: relevant line number
)

HTTP Error Structure

array(
    'type'    => 'http_error',
    'message' => 'HTTP API error: timeout',
    'url'     => 'https://api.example.com/endpoint',
    'user'    => 1,
)

JavaScript Error Structure

array(
    'type'    => 'js_fatal',
    'message' => 'Uncaught TypeError: Cannot read property...',
    'url'     => 'https://yoursite.com/page',
    'file'    => 'script.js',
    'line'    => 42,
    'user'    => 1,
)

Best Practices


Performance Considerations

  • Rate Limiting: Always respect rate limiting to avoid notification spam
  • Conditional Loading: Only load integration code when the target plugin is active
  • Non-blocking: Use non-blocking HTTP requests for external notifications
  • Memory Management: Be mindful of memory usage in error handlers

Security

  • Sanitize Data: Always sanitize error data before processing
  • Capability Checks: Verify user capabilities before allowing configuration changes
  • Nonce Verification: Use nonces for AJAX requests and form submissions
  • Data Validation: Validate all input data, especially from external sources

Error Handling

  • Graceful Degradation: Ensure your code doesn’t break if Fatal Error Notify is deactivated
  • Avoid Recursion: Be careful not to trigger errors within error handlers
  • Logging: Use WordPress’s built-in logging functions when possible
  • Testing: Test error scenarios thoroughly, including edge cases

Troubleshooting


Common Issues

Integration Not Appearing in Settings
  • Ensure the target plugin class exists and is loaded
  • Check that your integration is registered with the fen_integrations filter
  • Verify the integration file is being included properly
Notifications Not Sending
  • Check if the error type is enabled in the plugin settings
  • Verify rate limiting isn’t preventing notifications
  • Ensure the error isn’t being filtered out by custom hooks
  • Check notification channel settings (email, Slack, etc.)
Custom Error Types Not Working
  • Ensure error types are returned by get_error_types()
  • Check that the error type matches exactly (case-sensitive)
  • Verify the integration prefix is being added correctly

Debugging

Enable WordPress debug logging to troubleshoot issues:

// Add to wp-config.php
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );

// Add debug logging to your integration
error_log( 'FEN Debug: ' . print_r( $error_data, true ) );

Examples


Custom Error Logger

/**
 * Log all Fatal Error Notify errors to a custom table.
 */
add_action( 'fen_handle_error', function( $error ) {
    global $wpdb;
    
    $wpdb->insert(
        $wpdb->prefix . 'custom_error_log',
        array(
            'error_type' => $error['type'],
            'message'    => $error['message'],
            'file'       => isset( $error['file'] ) ? $error['file'] : '',
            'line'       => isset( $error['line'] ) ? $error['line'] : 0,
            'user_id'    => isset( $error['user'] ) ? $error['user'] : 0,
            'url'        => isset( $error['url'] ) ? $error['url'] : '',
            'timestamp'  => current_time( 'mysql' ),
        ),
        array( '%s', '%s', '%s', '%d', '%d', '%s', '%s' )
    );
} );

Conditional Notifications

/**
 * Only send notifications during business hours.
 */
add_filter( 'fen_ignore_error', function( $ignore, $error ) {
    $current_hour = (int) current_time( 'H' );
    
    // Business hours: 9 AM to 5 PM
    if ( $current_hour < 9 || $current_hour >= 17 ) {
        // Still log critical errors, but don't send notifications
        if ( isset( $error['type'] ) && $error['type'] !== E_ERROR ) {
            return true;
        }
    }
    
    return $ignore;
}, 10, 2 );

Enhanced Error Context

/**
 * Add additional context to all error notifications.
 */
add_filter( 'fen_error', function( $error ) {
    // Add server information
    $error['message'] .= "\n\n--- Server Info ---\n";
    $error['message'] .= "PHP Version: " . PHP_VERSION . "\n";
    $error['message'] .= "WordPress Version: " . get_bloginfo( 'version' ) . "\n";
    $error['message'] .= "Memory Usage: " . size_format( memory_get_usage( true ) ) . "\n";
    $error['message'] .= "Peak Memory: " . size_format( memory_get_peak_usage( true ) ) . "\n";
    
    // Add active plugins
    if ( function_exists( 'get_plugins' ) ) {
        $active_plugins = get_option( 'active_plugins', array() );
        $error['message'] .= "Active Plugins: " . count( $active_plugins ) . "\n";
    }
    
    return $error;
} );