WAIT: Form Actions Process Flow

Currently the form action looping like this

foreach ( $this->form_settings['actions'] as $form_action ) {
	// Skip if not a valid built-in action and no custom action handler exists (@since 1.12.2)
	if ( ! array_key_exists( $form_action, $available_actions ) && ! has_action( "bricks/form/action/{$form_action}" ) ) {
		continue;
	}

	$action_class = 'Bricks\Integrations\Form\Actions\\' . str_replace( ' ', '_', ucwords( str_replace( '-', ' ', $form_action ) ) );

	// If class exists, run the action
	if ( class_exists( $action_class ) ) {
		$action = new $action_class( $form_action );

		if ( ! method_exists( $action_class, 'run' ) ) {
			continue;
		}

		$action->run( $this );
	}
	// Handle custom actions registered via controls filter (@since 1.12.2)
	else {
		/**
		 * Fire custom form action
		 *
		 * @param \Bricks\Integrations\Form\Init $form Current form instance
		 *
		 * @since 1.12.2
		 */
		do_action( "bricks/form/action/{$form_action}", $this );
	}

	// Halts execution if an action reported an error
	$this->maybe_stop_processing();
}

Assume the form actions are executed in this order:
0 → Email
1 → Webhook
2 → Custom
3 → Submission
4 → Custom
5 → Redirect

Actions 0 to 3 run successfully, but action 4 throws an error and stops the process.

The issue is that the form process isn’t fully completed, yet the email has already been sent and a record has been saved to the database. When the user tries to resubmit the form, it leads to duplicate entries and multiple emails being sent — creating unnecessary confusion and a poor user experience.

The logic should ensure that emails are sent and submissions are stored only after all actions have successfully completed.
(Correct me if I’m wrong.)

1 Like

HI @bricksonemore,

if you set the “Email” action as the last one, it should be better, right?

Matej

Of course, it solved the problem. However, it’s also very easy to implement in init.php.

The existing code at lines 407–412 already handles this for the redirect action and pushes it to the end of the execution order.
It would only take a few additional lines to apply the same logic to the email and submission actions — benefiting all users.

if ( in_array( 'redirect', $this->form_settings['actions'], true ) ) {
	// Remove 'redirect' from actions
	$this->form_settings['actions'] = array_diff( $this->form_settings['actions'], [ 'redirect' ] );
	// Add 'redirect' as last action
	$this->form_settings['actions'][] = 'redirect';
}

Sure, that would be an easy change, but maybe someone doesn’t want the email action to be the last one.
Let’s wait and see what other users think about it.

Matej

Just wanted to create an issue for this under bugs and saw this is already a feature request. I think ordering it yourself is fine, as long as all actions run no matter if another action throws an error. I know this is also not that trivial, because you would need to adjust the Error-Message or decide how to let either the admin or customer know, if one or more actions failed.

It would be a start if the description mentioned that the order is relevant or the UI had an indicator so you could drag and drop elements, to change the ordering.

Yeah, this is not a bug. It’s how it works now. I’ll bring this topic up internally, but my opinion is that it’s not as simple as implementing it this way.
Some users might rely on the fact that the next action will not run if the previous fails, so we need to implement a toggle or settings for this, if we decide to implement it.

I’ll keep you updated.
Matej