Creating A Custom Background Processor

Sending data to external services, generating reports, or performing complex calculations can pose a challenge when working with form submissions in real time. This guide will walk you through creating a custom background processor in Gravity Forms by extending the GF_Background_Process class.

What Is A Background Processor

A background processor lets you offload time consuming processes to run in the background, ensuring that form submissions remain fast and responsive. This approach improves site performance and user experience while handling all necessary post-submission operations.

Creating a Custom Background Processor

The example implementation covers the following:

  • Automatically queuing tasks triggered by form submissions.
  • Processing queued tasks asynchronously using custom logic.
  • Managing scheduled events and queues during plugin uninstallation.
  • Handling edge cases, such as skipped or invalid entries.

Let’s explore the code and learn how to implement this solution.

if ( ! class_exists( 'GF_Background_Process' ) ) {
	require_once GF_PLUGIN_DIR_PATH . 'includes/libraries/gf-background-process.php';
}

// Rename the class to something unique and more meaningful to your use case.
class My_Custom_GF_Background_Processor extends GF_Background_Process {

	// Rename the action to something unique and more meaningful to your use case.
	protected $action = 'my_custom_gf_background_processor';

	/**
	 * Null or the current instance of the class.
	 *
	 * @var null|self
	 */
	private static $_instance;

	/**
	 * Returns the current instance of the class.
	 */
	public static function get_instance() {
		if ( null === self::$_instance ) {
			self::$_instance = new self;
		}

		return self::$_instance;
	}

	/**
	 * Initializes the background processor.
	 */
	public function __construct() {
		parent::__construct();
		add_action( 'init', array( $this, 'init' ), 11 );
	}

	/**
	 * Add any hooks.
	 *
	 * @return void
	 */
	public function init() {
		add_action( 'gform_after_submission', array( $this, 'after_submission' ), 10, 2 );
		add_action( 'gform_uninstalling', array( $this, 'uninstalling' ) );
	}

	/**
	 * Adds the entry to the background processing queue.
	 *
	 * @param array $entry The entry that was created by the submission.
	 * @param array $form  The form that was submitted.
	 *
	 * @return void
	 */
	public function after_submission( $entry, $form ) {
		if ( rgar( $entry, 'status' ) === 'spam' ) {
			return;
		}

		$entry_id = absint( rgar( $entry, 'id' ) );
		GFCommon::log_debug( __METHOD__ . sprintf( '(): Adding entry #%d to the async processing queue.', $entry_id ) );

		$this->push_to_queue( array(
			'entry_id' => $entry_id,
			'form_id'  => absint( rgar( $form, 'id' ) ),
		) );
		$this->save()->dispatch();
	}

	/**
	 * Performs some cleanup tasks when the plugin is uninstalled.
	 *
	 * @return void
	 */
	public function uninstalling() {
		$this->clear_scheduled_events();
		$this->clear_queue( true );
		$this->unlock_process();
	}

	/**
	 * Processes the background task.
	 *
	 * @param array $item The task arguments.
	 *
	 * @return bool|array
	 */
	protected function task( $item ) {
		$entry = GFAPI::get_entry( rgar( $item, 'entry_id' ) );
		if ( is_wp_error( $entry ) ) {
			GFCommon::log_debug( __METHOD__ . sprintf( '(): Aborting; Entry #%d not found.', rgar( $item, 'entry_id' ) ) );

			return false;
		}

		$form = GFAPI::get_form( rgar( $item, 'form_id' ) );
		if ( empty( $form ) ) {
			GFCommon::log_debug( __METHOD__ . sprintf( '(): Aborting; Form #%d not found.', rgar( $item, 'form_id' ) ) );

			return false;
		}

		// Allow the form to be hydrated by add-ons e.g. populating the field inputs/choices properties.
		$form = $this->filter_form( $form, $entry );

		GFCommon::log_debug( __METHOD__ . '(): Processing => ' . print_r( $item, true ) );

		// process the $entry here
		// return false to remove the item from the queue
		// return $item to keep it in the queue for another attempt

		return false;
	}

}

// Update the class name to match your new class name above.
My_Custom_GF_Background_Processor::get_instance();