Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ninja Forms notification unintentionally delayed #4

Closed
remcotolsma opened this issue Jan 18, 2022 · 4 comments
Closed

Ninja Forms notification unintentionally delayed #4

remcotolsma opened this issue Jan 18, 2022 · 4 comments
Assignees
Labels
bug Something isn't working

Comments

@remcotolsma
Copy link
Member

I use Pronamic Pay (7.0.2) together with Ninja Forms (3.6.7) for payment forms.
When i started using this solution, the administrator emails where send even if the payment failed. But some time ago this stopped working and e-mails where only send when the payment succeeded.

After some research i’m suspecting that an update of Pronamic Pay (6.7.0) with support for delayed actions caused this change in behavior. Now there’s a toggle in Ninja Forms to choose if you want to delay this notification e-mail to be send after the payment, or not.

Great functionality! But i would like to receive an e-mail immediately after the form has submitted, even if the payment failed, so i’ve set this toggle to OFF to disable this delay.

Unfortunately e-mails are only send when the payment succeeds.

Is it possible there’s a bug in this functionality? Or maybe i’m misunderstanding how this is supposed to work?

Thanks!

Source: https://wordpress.org/support/topic/receive-ninja-form-email-even-when-the-payment-failed/

@rvdsteege

I was able to reproduce your issue and can confirm there is indeed something going wrong. The e-mail should not be delayed in your case.

I’ve found the culprit and will let you know once this has been resolved.

Source: https://wordpress.org/support/topic/receive-ninja-form-email-even-when-the-payment-failed/#post-15124596

According to @rvdsteege caused by:

@remcotolsma remcotolsma added the bug Something isn't working label Jan 18, 2022
@remcotolsma
Copy link
Member Author

remcotolsma commented Jan 18, 2022

@rvdsteege
Copy link
Member

do you remember (or find out) if we copied the 2e299dd implementation from something?

The Ninja Forms PayPal Express plugin uses the halt mechanism.

@remcotolsma
Copy link
Member Author

do you remember (or find out) if we copied the 2e299dd implementation from something?

The Ninja Forms PayPal Express plugin uses the halt mechanism.

👍 https://github.com/pronamic/ninja-forms-paypal-express/blob/a5079486c59d925fcb9dedf23781cdac18857c7d/includes/PaymentGateway.php#L181

// Save session cookie in payment meta for processing delayed actions.
\Ninja_Forms()->session()->set( 'pronamic_payment_id', $payment->get_id() );
$headers = headers_list();
foreach ( $headers as $header ) {
if ( 'set-cookie' !== substr( strtolower( $header ), 0, 10 ) ) {
continue;
}
$cookie = \explode( ';', $header );
$cookie = trim( \substr( $cookie[0], 12 ) );
$cookie = \explode( '=', $cookie );
$payment->set_meta( 'ninjaforms_session_cookie', $cookie[1] );
}

I don't quite understand the cookie and session code yet, they don't seem to use that in https://github.com/pronamic/ninja-forms-paypal-express/.

@rvdsteege
Copy link
Member

The PayPal Express add-on also uses the halt/resume mechanism:

However, the mechanism provided by Ninja Forms to resume processing of form actions uses the current session (managed by Ninja Forms). That would mean 'order fulfilment' will only work if the user returns immediately after payment, within the current session. From experience, we know that that is not always the case and it could also be initiated by a webhook request. The PayPal Express add-on does not support PayPal IPN, so they didn't have to cope with the issue of resuming a specific session.

Therefore, we're storing the Ninja Forms session cookie to be able to restore that specific session and then resume processing of form actions:

/**
* Fulfill order.
*
* @param Payment $payment Payment.
*/
public function fulfill_order( $payment ) {
// Check if already fulfilled.
$is_fulfilled = (int) $payment->get_meta( 'ninjaforms_fulfilled' );
if ( 1 === $is_fulfilled ) {
return;
}
// Check session cookie.
$session_cookie = $payment->get_meta( 'ninjaforms_session_cookie' );
if ( empty( $session_cookie ) ) {
return;
}
$session_cookie = \urldecode( $session_cookie );
// Check form ID.
$form_id = $payment->get_meta( 'ninjaforms_payment_form_id' );
if ( empty( $form_id ) ) {
return;
}
// Init Ninja Forms session.
$wp_session_cookie = 'nf_wp_session';
if ( defined( '\WP_SESSION_COOKIE' ) ) {
$wp_session_cookie = \WP_SESSION_COOKIE;
}
$session_cookie_temp = null;
if ( \array_key_exists( $wp_session_cookie, $_COOKIE ) ) {
$session_cookie_temp = filter_var( \wp_unslash( $_COOKIE[ $wp_session_cookie ] ), \FILTER_SANITIZE_STRING );
}
$_COOKIE[ $wp_session_cookie ] = $session_cookie;
\Ninja_Forms()->session();
// Set up fields merge tags to prevent empty default email.
try {
$fields = \Ninja_Forms()->merge_tags['fields'];
$fields_reflection = new ReflectionClass( $fields );
$merge_tags_prop = $fields_reflection->getProperty( 'merge_tags' );
$merge_tags_prop->setAccessible( true );
$merge_tags = array_merge(
$merge_tags_prop->getValue( $fields ),
\Ninja_Forms()->config( 'MergeTagsFieldsAJAX' )
);
$merge_tags_prop->setValue( $fields, $merge_tags );
} catch ( \Exception $e ) {
// Nothing to do.
}
// Set `nf_resume` for Ninja Forms to continue processing form actions.
$_POST['nf_resume'] = $form_id;
define( 'PRONAMIC_PAY_NINJA_FORMS_RESUME', true );
// Prevent `wp_die()` in Ninja Forms response to exit script execution.
\add_filter(
'wp_die_handler',
function( $handler ) {
return '__return_true';
}
);
// Resume processing form actions.
ob_start();
\Ninja_Forms()->controllers['submission']->resume();
\ob_end_clean();
// Delete session.
\Ninja_Forms()->session()->delete();
// Unset/restore session cookie.
unset( $_COOKIE[ $wp_session_cookie ] );
if ( null !== $session_cookie_temp ) {
$_COOKIE[ $wp_session_cookie ] = $session_cookie_temp;
}
$payment->set_meta( 'ninjaforms_fulfilled', true );
}

I agree that e.g. getting the cookie from the headers is quite ugly, but I don't think there is (or at least was) any other way to get to the same end result.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants