Skip to content

Instantly share code, notes, and snippets.

@mircobabini
Last active August 3, 2022 16:17
Show Gist options
  • Save mircobabini/13c083d7a2b312848f97496126d2aff2 to your computer and use it in GitHub Desktop.
Save mircobabini/13c083d7a2b312848f97496126d2aff2 to your computer and use it in GitHub Desktop.
PMPro fallback: Try to fix the wp_insert_user failure that is about to happen because PayPal Express gateway lost the session for any reason
<?php
/**
* Test:
* - Go to checkout page
* - Click on proceed (with PayPal Express)
* - Copy the paypal.com link and complete the checkout in anonymous mode (session is empty for sure)
* - Check the CREATED USER! :)
*
* Added a cookie fallback for session lost, when payment completed after a long time.
* Doesn't cover the case above though.
*
* Just with some notices in logs.
* @see https://github.com/strangerstudios/paid-memberships-pro/issues/1341
*
* DISCUSSION ABOUT THIS:
* @see https://github.com/strangerstudios/paid-memberships-pro/issues/1338
*/
/*
add_action('init', function(){
$new_user_array = [
'user_login' => '',
'user_email' => '',
'user_pass' => '',
'first_name' => '',
'first_name' => '',
];
$new_user_array = apply_filters( 'pmpro_checkout_new_user_array', $new_user_array );
var_dump( $new_user_array );
});
*/
/**
* Save paypalexpress session user data to cookie as well.
* Should last more than sessions, at least until the browser is closed.
*/
add_action( 'pmpro_paypalexpress_session_vars', function(){
global $current_user;
if( ! $current_user->ID ){
// without expiration, the cookie will expire at the end of the session
// so when the browser closes. should last more than the session though
setcookie( "pmpro_signup_username", $_SESSION['pmpro_signup_username'] );
setcookie( "pmpro_signup_password", $_SESSION['pmpro_signup_password'] );
setcookie( "pmpro_signup_email", $_SESSION['pmpro_signup_email'] );
/* to simulate issue with session */
if( $simulate_issue_with_session = false ){
$_SESSION['pmpro_signup_username'] = '';
$_SESSION['pmpro_signup_password'] = '';
$_SESSION['pmpro_signup_email'] = '';
}
}
}, 10 );
/**
* Try to fix the wp_insert_user failure that is about to happen
* because PayPal Express gateway lost the session for any reason
* @see https://github.com/strangerstudios/paid-memberships-pro/issues/1338
*/
add_filter( 'pmpro_checkout_new_user_array', function( $new_user_array ){
global $current_user;
$send_debug_email = false;
$before_new_user_array = $new_user_array;
// if we are reviewing an order
if( isset( $_REQUEST['review'] ) ) {
$order_code = $_REQUEST['review'];
$order = new MemberOrder( $order_code );
}
// check: if we are using paypalexpress for this order (not needed I think)
// because paypal express is the only one acting this way, isn't it?
// if( $order->gateway === 'paypalexpress' )
// check: if we dont already have a user for this order AND the user is not logged in
if( $order->user_id == 0 && ! $current_user->ID ){
/**
* FALLBACK IF USER_LOGIN IS MISSING
*/
// if we will not be able to create user
if( empty( $new_user_array['user_login'] ) ){
// debug = true
$send_debug_email = true;
// try to fetch fallback from cookies
if( isset( $_COOKIE['pmpro_signup_username'] ) ){
$fallback_username = $_COOKIE['pmpro_signup_username'];
$fallback_password = $_COOKIE['pmpro_signup_password'];
$fallback_email = $_COOKIE['pmpro_signup_email'];
// now get rid of insecure cookies
unset( $_COOKIE['pmpro_signup_username'] ); setcookie( 'pmpro_signup_username', '', time() - 3600, '/' );
unset( $_COOKIE['pmpro_signup_password'] ); setcookie( 'pmpro_signup_password', '', time() - 3600, '/' );
unset( $_COOKIE['pmpro_signup_email'] ); setcookie( 'pmpro_signup_email', '', time() - 3600, '/' );
}else{
// generate a fallbacks
$fallback_username = wp_help__generate_unique_username( "$order->FirstName $order->LastName", 'pmpro' );
$fallback_password = wp_generate_password();
$fallback_email = "mirco+$fallback_username@sedweb.it";
}
/** avoid other warning, @see https://github.com/strangerstudios/paid-memberships-pro/issues/1341 */
$_SESSION['pmpro_signup_username'] = $fallback_username;
$_SESSION['pmpro_signup_password'] = $fallback_password;
$_SESSION['pmpro_signup_email'] = $fallback_email;
/** fix the new_user_array data */
$new_user_array['user_login'] = $fallback_username;
$new_user_array['user_email'] = $fallback_email;
$new_user_array['user_pass'] = $fallback_password;
}
/**
* FALLBACK IF USER_LOGIN IS INVALID (incomplete)
*/
// if the username is longer then 60 chars
if( $new_user_array['user_login'] > 60 ){
// !! can be moved to PMPro checks BEFORE checkout
// hard force, user never get noticed... tricky.
$new_user_array['user_login'] = wp_help__generate_unique_username( substr( $new_user_array['user_login'], 0, 15 ) );
}
// if the username is listed in illegals
$illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
if( in_array( strtolower( $new_user_array['user_login'] ), array_map( 'strtolower', $illegal_logins ) ) ){
// !! can be moved to PMPro checks BEFORE checkout
// hard force, user never get noticed... tricky.
$new_user_array['user_login'] = wp_help__generate_unique_username( '');
}
// if the username already exists
if( username_exists( $new_user_array['user_login'] ) ){
// !! can be moved to PMPro checks BEFORE checkout
// hard force, user never get noticed... tricky.
$new_user_array['user_login'] = wp_help__generate_unique_username( '' );
}
/**
* Complete user profiles from order data
*/
// if first_name not assigned automatically from order
if( empty( $new_user_array['first_name'] ) ){
$new_user_array['first_name'] = $order->FirstName;
}
// if last_name not assigned automatically from order
if( empty( $new_user_array['last_name'] ) ){
$new_user_array['last_name'] = $order->LastName;
}
}
// log
if( $send_debug_email && function_exists( 'debug__extended' ) ){
debug__extended( [
'where' => str_replace( ABSPATH, '', __FILE__ ) . ':' . __LINE__,
'user_array_1' => $before_new_user_array,
'user_array_2' => $new_user_array,
] );
}
return $new_user_array;
}, 11 );
/**
* Generate a unique username based on the string passed.
* If the string is empty, uses the fallback_usrename_base plus a suffix (-1, -2...)
*
* @param $string_name
* @param string $fallback_username_base
* @return string
*/
function wp_help__generate_unique_username( $string_name, $fallback_username_base = 'pmpro-user' ){
// any string to a valid username
$username_base = sanitize_user( $string_name, true );
// only lower chars, numbers and hyphens
$username_base = sanitize_title( $username_base );
// ensure it's still valid (may be empty)
if( ! validate_username( $username_base ) ){
$username_base = $fallback_username_base;
}
// append a suffix until it's valid
$suffix = 1;
while( $suffix < 100000 ){ // dont like infinite loops, avoid using while( true )
$username = "$username_base-$suffix";
if( ! username_exists( $username ) ){
return $username;
}
$suffix++;
}
// since I dont like infinite loops and used a limited loops above,
// it may be unable to generate a new unique username... amen.
return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment