add( 'invalid_nonce', __( 'An authentication error occurred. Please try again.', 'rcp' ), 'register' ); wp_send_json_error( array( 'success' => false, 'errors' => rcp_get_error_messages_html( 'register' ), 'nonce' => wp_create_nonce( 'rcp-register-nonce' ), ) ); } global $rcp_options; $membership_level = rcp_get_membership_level( rcp_get_registration()->get_membership_level_id() ); // We are already sanitizing, but PHPCS keep complaining about the isset function. // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $discount = isset( $_POST['rcp_discount'] ) ? sanitize_text_field( strtolower( wp_unslash( $_POST['rcp_discount'] ) ) ) : ''; $price = number_format( $membership_level->get_price(), 2, '.', '' ); $initial_amount = rcp_get_registration()->get_total(); $auto_renew = rcp_registration_is_recurring(); // if both today's total and the recurring total are 0, the there is a full discount // if this is not a recurring membership only check today's total $full_discount = ( $auto_renew ) ? ( rcp_get_registration()->get_total() == 0 && rcp_get_registration()->get_recurring_total() == 0 ) : ( rcp_get_registration()->get_total() == 0 ); $customer = rcp_get_customer_by_user_id(); $has_trialed = ! empty( $customer ) ? $customer->has_trialed() : false; $registration_type = rcp_get_registration()->get_registration_type(); // Whether this is a `new` membership, `renewal`, `upgrade`, or `downgrade`. $recovered_payment = rcp_get_registration()->get_recovered_payment(); // get the selected payment method/gateway if ( ! isset( $_POST['rcp_gateway'] ) ) { $gateway = 'paypal'; } else { $gateway = sanitize_text_field( wp_unslash( $_POST['rcp_gateway'] ) ); } // Change gateway to "free" if this membership doesn't require payment. if ( empty( $initial_amount ) && ! $auto_renew ) { $gateway = 'free'; } rcp_log( sprintf( 'Started new registration for membership level #%d via %s.', $membership_level->get_id(), $gateway ) ); /*********************** * validate the form */ do_action( 'rcp_before_form_errors', $_POST, $customer ); $validate_only = isset( $_POST['validate_only'] ); $user_data = rcp_validate_user_data(); if ( ! rcp_is_registration() ) { // no membership level was chosen rcp_errors()->add( 'no_level', __( 'Please choose a membership level', 'rcp' ), 'register' ); } if ( $membership_level->is_free() && ! $membership_level->is_lifetime() && $has_trialed ) { // this ensures that users only sign up for a free trial once rcp_errors()->add( 'free_trial_used', __( 'You may only sign up for a free trial once', 'rcp' ), 'register' ); } if ( ! empty( $discount ) ) { // make sure we have a valid discount if ( rcp_validate_discount( $discount, $membership_level->get_id() ) ) { // check if the user has already used this discount if ( $price > 0 && ! $user_data['need_new'] && rcp_user_has_used_discount( $user_data['id'], $discount ) && apply_filters( 'rcp_discounts_once_per_user', false, $discount, $membership_level->get_id() ) ) { rcp_errors()->add( 'discount_already_used', __( 'You can only use the discount code once', 'rcp' ), 'register' ); } } else { // the entered discount code is incorrect rcp_errors()->add( 'invalid_discount', __( 'The discount you entered is invalid', 'rcp' ), 'register' ); } } // Validate extra fields in gateways with the 2.1+ gateway API if ( ! has_action( 'rcp_gateway_' . $gateway ) && $price > 0 && ! $full_discount ) { $gateways = new RCP_Payment_Gateways(); $gateway_var = $gateways->get_gateway( $gateway ); $gateway_obj = new $gateway_var['class'](); $gateway_obj->validate_fields(); } // If enabled, terms agreement must be checked. if ( ! empty( $rcp_options['enable_terms'] ) && ! isset( $_POST['rcp_agree_to_terms'] ) ) { rcp_errors()->add( 'terms_not_agreed', __( 'You must agree to the terms and conditions', 'rcp' ), 'register' ); } // If enabled, privacy policy agreement must be checked. if ( ! empty( $rcp_options['enable_privacy_policy'] ) && ! isset( $_POST['rcp_agree_to_privacy_policy'] ) ) { rcp_errors()->add( 'privacy_policy_not_agreed', __( 'You must agree to the privacy policy', 'rcp' ), 'register' ); } do_action( 'rcp_form_errors', $_POST, $customer ); // retrieve all error messages, if any $errors = rcp_errors()->get_error_messages(); if ( ! empty( $errors ) ) { rcp_log( sprintf( 'Registration cancelled with the following errors: %s.', implode( ', ', $errors ) ) ); wp_send_json_error( array( 'success' => false, 'errors' => rcp_get_error_messages_html( 'register' ), 'nonce' => wp_create_nonce( 'rcp-register-nonce' ), 'gateway' => array( 'slug' => $gateway, 'supports' => ! empty( $gateway_obj->supports ) ? $gateway_obj->supports : false, ), ) ); } elseif ( $validate_only ) { wp_send_json_success( array( 'success' => true, 'nonce' => wp_create_nonce( 'rcp-register-nonce' ), 'total' => rcp_get_registration()->get_total(), 'total_formatted' => rcp_currency_filter( rcp_get_registration()->get_total() ), 'recurring_total' => rcp_get_registration()->get_recurring_total(), 'auto_renew' => $auto_renew, 'gateway' => array( 'slug' => $gateway, 'supports' => ! empty( $gateway_obj->supports ) ? $gateway_obj->supports : false, ), 'level' => array( 'id' => $membership_level->get_id(), 'name' => $membership_level->get_name(), 'description' => $membership_level->get_description(), 'trial' => $membership_level->has_trial(), ), ) ); } if ( $user_data['need_new'] ) { $display_name = trim( $user_data['first_name'] . ' ' . $user_data['last_name'] ); $user_data['id'] = wp_insert_user( array( 'user_login' => $user_data['login'], 'user_pass' => $user_data['password'], 'user_email' => $user_data['email'], 'first_name' => $user_data['first_name'], 'last_name' => $user_data['last_name'], 'display_name' => ! empty( $display_name ) ? $display_name : $user_data['login'], 'user_registered' => date( 'Y-m-d H:i:s' ), ) ); if ( ! is_wp_error( $user_data['id'] ) ) { wp_set_auth_cookie( $user_data['id'] ); wp_set_current_user( $user_data['id'] ); if ( ! isset( $rcp_options['disable_new_user_notices'] ) ) { // Send an email to the admin alerting them of the registration. wp_new_user_notification( absint( $user_data['id'] ) ); } } } if ( is_wp_error( $user_data['id'] ) ) { rcp_errors()->add( $user_data['id']->get_error_code(), $user_data['id']->get_error_message(), 'register' ); } elseif ( ! empty( $user_data['id'] ) && ! is_wp_error( $user_data['id'] ) && empty( $customer ) ) { // Create the customer record if it doesn't already exist. $customer_id = rcp_add_customer( array( 'user_id' => absint( $user_data['id'] ) ) ); $customer = ! empty( $customer_id ) ? rcp_get_customer( $customer_id ) : false; if ( empty( $customer ) ) { rcp_errors()->add( 'customer_creation_failed', __( 'Failed to create customer record', 'rcp' ), 'register' ); } } // Refresh error messages to account for any user creation errors. $errors = rcp_errors()->get_error_messages(); if ( ! empty( $errors ) ) { rcp_log( sprintf( 'Registration cancelled with the following errors: %s.', implode( ', ', $errors ) ) ); wp_send_json_error( array( 'success' => false, 'errors' => rcp_get_error_messages_html( 'register' ), 'nonce' => wp_create_nonce( 'rcp-register-nonce' ), 'gateway' => array( 'slug' => $gateway, 'supports' => ! empty( $gateway_obj->supports ) ? $gateway_obj->supports : false, ), ) ); } $user_id = $user_data['id']; // Save agreement to terms and privacy policy. if ( ! empty( $_POST['rcp_agree_to_terms'] ) ) { $terms_agreed = get_user_meta( $user_id, 'rcp_terms_agreed', true ); if ( ! is_array( $terms_agreed ) ) { $terms_agreed = array(); } $terms_agreed[] = current_time( 'timestamp' ); update_user_meta( $user_id, 'rcp_terms_agreed', $terms_agreed ); } if ( ! empty( $_POST['rcp_agree_to_privacy_policy'] ) ) { $privacy_policy_agreed = get_user_meta( $user_id, 'rcp_privacy_policy_agreed', true ); if ( ! is_array( $privacy_policy_agreed ) ) { $privacy_policy_agreed = array(); } $privacy_policy_agreed[] = current_time( 'timestamp' ); update_user_meta( $user_id, 'rcp_privacy_policy_agreed', $privacy_policy_agreed ); } update_user_meta( $user_id, '_rcp_new_subscription', '1' ); $subscription_key = rcp_generate_subscription_key(); // If we're recovering a payment, then let's recover the associated membership as well. if ( ! empty( $recovered_payment ) && ! empty( $recovered_payment->membership_id ) && $recovered_payment->object_id == $membership_level->get_id() ) { $previous_membership = rcp_get_membership( $recovered_payment->membership_id ); // Re-enable this membership if it's been disabled. if ( $previous_membership->is_disabled() ) { $previous_membership->enable(); } rcp_log( sprintf( 'Using recovered membership #%d for registration.', $previous_membership->get_id() ) ); } else { $previous_membership = rcp_get_registration()->get_membership(); } $previous_membership_level = ! empty( $previous_membership ) ? rcp_get_membership_level( $previous_membership->get_object_id() ) : false; if ( $previous_membership instanceof Membership_Level ) { // Backwards compat. update_user_meta( $user_id, '_rcp_old_subscription_id', $previous_membership->get_object_id() ); // If the current user isn't the "owner" of the previous membership, something is wrong... if ( $previous_membership->get_user_id() != get_current_user_id() ) { wp_die( __( 'You do not have permission to perform this action.', 'rcp' ), __( 'Error', 'rcp' ), array( 'response' => 403 ) ); } // If this is an upgrade/downgrade but the membership isn't allowed to be changed, something is wrong... if ( in_array( $registration_type, array( 'upgrade', 'downgrade' ) ) && ! $previous_membership->upgrade_possible() ) { wp_die( __( 'You do not have permission to perform this action.', 'rcp' ), __( 'Error', 'rcp' ), array( 'response' => 403 ) ); } // If this is a renewal, but the membership isn't allowed to be renewed, something is wrong... if ( 'renewal' == $registration_type && ! $previous_membership->can_renew() ) { wp_die( __( 'You do not have permission to perform this action.', 'rcp' ), __( 'Error', 'rcp' ), array( 'response' => 403 ) ); } } rcp_log( sprintf( 'Registration type: %s.', $registration_type ) ); // Delete pending payment ID. A new one may be created for paid membership. delete_user_meta( $user_id, 'rcp_pending_payment_id' ); // Delete old pending data that may have been added in previous versions. delete_user_meta( $user_id, 'rcp_pending_expiration_date' ); delete_user_meta( $user_id, 'rcp_pending_subscription_key' ); // Backwards compatibility pre-2.9: set pending subscription key. update_user_meta( $user_id, 'rcp_pending_subscription_key', $subscription_key ); // Backwards compatibility: we still need to set this for Hard-set Expiration dates. update_user_meta( $user_id, 'rcp_pending_subscription_level', $membership_level->get_id() ); $amount = ( $membership_level->has_trial() && ! $has_trialed ) ? 0.00 : rcp_get_registration()->get_total(); /** * Create a pending membership if this is not a manual renewal. */ if ( 'renewal' != $registration_type && empty( $recovered_payment ) ) { $membership_data = array( 'customer_id' => $customer->get_id(), 'object_id' => $membership_level->get_id(), 'object_type' => 'membership', 'initial_amount' => $amount, 'recurring_amount' => $membership_level->is_lifetime() ? 0.00 : rcp_get_registration()->get_recurring_total( true, true ), 'auto_renew' => $auto_renew, 'maximum_renewals' => $membership_level->get_maximum_renewals(), 'status' => 'pending', 'gateway' => $gateway, 'subscription_key' => $subscription_key, ); if ( in_array( $registration_type, array( 'upgrade', 'downgrade' ) ) && ! empty( $previous_membership ) ) { $membership_data['upgraded_from'] = $previous_membership->get_id(); } $membership_id = $customer->add_membership( $membership_data ); if ( in_array( $registration_type, array( 'upgrade', 'downgrade' ) ) ) { $membership = rcp_get_membership( $membership_id ); $membership->add_note( sprintf( __( 'Upgraded from %1$s (membership #%2$d).', 'rcp' ), $previous_membership_level->get_name(), $previous_membership->get_id() ) ); } } elseif ( ! empty( $previous_membership ) ) { /** * Use the existing membership record if this is a renewal and we have a previous membership to work with. */ $membership_id = $previous_membership->get_id(); $new_membership_data = array( 'auto_renew' => $auto_renew, 'gateway' => $gateway, 'recurring_amount' => $membership_level->is_lifetime() ? 0.00 : rcp_get_registration()->get_recurring_total( true, true ), ); if ( $auto_renew || ! $previous_membership->get_subscription_key() ) { // Use new generated subscription key if auto renewing, or if the existing subscription key is blank. $new_membership_data['subscription_key'] = $subscription_key; } else { // Keep the same subscription key if not auto renew. $subscription_key = $previous_membership->get_subscription_key(); } if ( ! $previous_membership->is_active() ) { $new_membership_data['status'] = 'pending'; $new_membership_data['expiration_date'] = $previous_membership->calculate_expiration( true, ! $has_trialed ); // Maybe re-calculate trialing period. if ( $membership_level->has_trial() && ! $has_trialed ) { $new_membership_data['trial_end_date'] = $new_membership_data['expiration_date']; } } rcp_update_membership( $membership_id, $new_membership_data ); rcp_log( sprintf( 'Using existing membership #%d for payment.', $membership_id ) ); } if ( rcp_get_registration()->get_total() == 0 && rcp_get_registration()->get_recurring_total() == 0 && ! empty( $discount ) && '2' != rcp_get_auto_renew_behavior() ) { rcp_update_membership( $membership_id, array( 'expiration_date' => null ) ); } // Create a pending payment $credits = ! empty( $previous_membership ) && in_array( $registration_type, array( 'upgrade', 'downgrade' ) ) ? $previous_membership->get_prorate_credit_amount() : 0; $payment_data = array( 'date' => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ), 'subscription' => $membership_level->get_name(), 'object_id' => $membership_level->get_id(), 'object_type' => 'subscription', 'gateway' => $gateway, 'subscription_key' => $subscription_key, 'amount' => $amount, 'user_id' => $user_id, 'customer_id' => $customer->get_id(), 'membership_id' => $membership_id, 'status' => 'pending', 'subtotal' => $membership_level->get_price(), 'credits' => $credits, 'fees' => rcp_get_registration()->get_total_fees() + $credits, 'discount_amount' => rcp_get_registration()->get_total_discounts(), 'discount_code' => $discount, 'transaction_type' => $registration_type, ); $rcp_payments = new RCP_Payments(); if ( ! empty( $recovered_payment ) ) { // Update the recovered payment. rcp_log( sprintf( 'Updating recovered payment #%d with new data.', $recovered_payment->id ) ); $rcp_payments->update( $recovered_payment->id, $payment_data ); $payment_id = $recovered_payment->id; } else { // Insert a new payment record. $payment_id = $rcp_payments->insert( $payment_data ); } // Store the pending payment ID. This is so we know which payment is responsible for activating the membership. rcp_update_membership_meta( $membership_id, 'pending_payment_id', $payment_id ); // This is for backwards compatibility only. We now use membership meta (see above). update_user_meta( $user_data['id'], 'rcp_pending_payment_id', $payment_id ); if ( in_array( $registration_type, array( 'upgrade', 'downgrade' ) ) ) { // Flag the member as having just upgraded update_user_meta( $user_id, '_rcp_just_upgraded', current_time( 'timestamp' ) ); } /** * Triggers after all the form data has been processed, but before the user is sent to the payment gateway. * The user's membership is pending at this point. * * @param array $_POST Posted data. * @param int $user_id ID of the user registering. * @param float $price Price of the membership. * @param int $payment_id ID of the pending payment associated with this registration. * @param RCP_Customer $customer Customer object. * @param int $membership_id ID of the new pending membership. * @param RCP_Membership|false $previous_membership Previous membership object, or false if none. * @param string $registration_type Type of registration: 'new', 'renewal', or 'upgrade'. */ do_action( 'rcp_form_processing', $_POST, $user_id, $price, $payment_id, $customer, $membership_id, $previous_membership, $registration_type ); $success_data = array( 'success' => true, 'nonce' => wp_create_nonce( 'rcp-register-nonce' ), 'total' => rcp_get_registration()->get_total(), 'recurring_total' => rcp_get_registration()->get_recurring_total(), 'auto_renew' => $auto_renew, 'gateway' => array( 'slug' => $gateway, 'supports' => ! empty( $gateway_obj->supports ) ? $gateway_obj->supports : false, ), 'level' => array( 'trial' => $membership_level->has_trial(), ), 'payment_id' => $payment_id, ); // Handle gateway ajax processing. if ( 'free' != $gateway && rcp_gateway_supports( $gateway, 'ajax-payment' ) ) { // send all of the membership data off for processing by the gateway $result = rcp_handle_gateway_ajax_processing( $gateway, rcp_get_payment_registration_details( $payment_id ) ); if ( is_wp_error( $result ) ) { rcp_errors()->add( $result->get_error_code(), $result->get_error_message(), 'register' ); wp_send_json_error( array( 'success' => false, 'errors' => rcp_get_error_messages_html( 'register' ), 'nonce' => wp_create_nonce( 'rcp-register-nonce' ), 'gateway' => array( 'slug' => $gateway, 'supports' => ! empty( $gateway_obj->supports ) ? $gateway_obj->supports : false, ), ) ); } elseif ( is_array( $result ) ) { $success_data['gateway']['data'] = $result; } } wp_send_json_success( $success_data ); exit; } add_action( 'wp_ajax_rcp_process_register_form', 'rcp_process_registration', 100 ); add_action( 'wp_ajax_nopriv_rcp_process_register_form', 'rcp_process_registration', 100 ); /** * Generate a new nonce for registration * * We have to do this via ajax after the form processing step because we log in new users, which means * nonce generations done in the same request after log in will fail (due to the new logged in cookies not * being properly set in PHP yet). We have to do a whole new request to get a properly validated nonce. * * Annoying, but it's the price we pay for not doing a full page refresh. * * @since 3.2 * @return void */ function rcp_generate_registration_nonce() { wp_send_json_success( wp_create_nonce( 'rcp-register-nonce' ) ); } add_action( 'wp_ajax_rcp_generate_registration_nonce', 'rcp_generate_registration_nonce', 100 ); add_action( 'wp_ajax_nopriv_rcp_generate_registration_nonce', 'rcp_generate_registration_nonce', 100 ); /** * Send registration payment to the gateway for processing. * * @since 3.2 * @return void */ function rcp_send_registration_to_gateway() { // Don't listen if we're doing ajax processes. if ( ! empty( $_POST['rcp_ajax'] ) ) { return; } // Check nonce if ( ! ( isset( $_POST['rcp_register_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['rcp_register_nonce'] ) ), 'rcp-register-nonce' ) ) ) { return; } if ( empty( $_POST['rcp_registration_payment_id'] ) ) { rcp_errors()->add( 'missing_payment_id', __( 'Missing payment ID.', 'rcp' ), 'register' ); return; } /** * @var RCP_Payments $rcp_payments_db */ global $rcp_payments_db; $payment = $rcp_payments_db->get_payment( absint( sanitize_text_field( wp_unslash( $_POST['rcp_registration_payment_id'] ) ) ) ); if ( empty( $payment ) ) { rcp_errors()->add( 'invalid_payment', __( 'Invalid payment. Please try again.', 'rcp' ), 'register' ); return; } // Process a paid membership. if ( 'free' != $payment->gateway ) { // Send all of the membership data off for processing by the gateway. rcp_send_to_gateway( $payment->gateway, rcp_get_payment_registration_details( $payment->id ) ); } else { // Process a free or trial membership. // Complete payment. This also activates the membership. $rcp_payments_db->update( $payment->id, array( 'status' => 'complete' ) ); rcp_log( sprintf( 'Completed free registration to membership level #%d for customer #%d.', $payment->object_id, $payment->customer_id ) ); // send the newly created user to the redirect page after logging them in wp_redirect( rcp_get_return_url( absint( $payment->user_id ) ) ); exit; } } add_action( 'init', 'rcp_send_registration_to_gateway', 100 ); /** * Get all the registration information associated with a payment. This is used when sending the * payment to the gateway for processing. * * @param int $payment_id * * @since 3.2 * @return array */ function rcp_get_payment_registration_details( $payment_id ) { /** * @var RCP_Payments $rcp_payments_db */ global $rcp_payments_db; $payment = $rcp_payments_db->get_payment( absint( $payment_id ) ); if ( empty( $payment ) ) { return array(); } $user = get_userdata( absint( $payment->user_id ) ); $membership_level = rcp_get_membership_level( $payment->object_id ); $customer = rcp_get_customer( $payment->customer_id ); /* * At this point we can't know for sure if this was a brand new user, so we will assume they were if their account was created today. */ $new_user = date( 'Y-m-d', strtotime( $user->user_registered, current_time( 'timestamp' ) ) ) === date( 'Y-m-d', current_time( 'timestamp' ) ); $registration_data = array( 'price' => rcp_get_registration()->get_total( true, false ), // get total without the fee 'initial_price' => rcp_get_registration()->get_total( true, true ), 'recurring_price' => rcp_get_registration()->get_recurring_total( true, true ), 'discount' => rcp_get_registration()->get_total_discounts(), 'discount_code' => ! empty( $payment->discount_code ) ? $payment->discount_code : '', 'fee' => rcp_get_registration()->get_total_fees(), 'length' => $membership_level instanceof Membership_Level ? $membership_level->get_duration() : 0, 'length_unit' => $membership_level instanceof Membership_Level ? strtolower( $membership_level->get_duration_unit() ) : 'day', 'subscription_id' => $membership_level instanceof Membership_Level ? $membership_level->get_id() : 0, 'subscription_name' => $membership_level instanceof Membership_Level ? $membership_level->get_name() : '', 'key' => $payment->subscription_key, 'user_id' => $user->ID, 'user_name' => $user->user_login, 'user_email' => $user->user_email, 'currency' => rcp_get_currency(), 'auto_renew' => rcp_registration_is_recurring(), 'return_url' => rcp_get_return_url( $user->ID ), 'new_user' => $new_user, 'trial_duration' => $membership_level instanceof Membership_Level ? $membership_level->get_trial_duration() : 0, 'trial_duration_unit' => $membership_level instanceof Membership_Level ? $membership_level->get_trial_duration_unit() : 'day', 'trial_eligible' => ! $customer->has_trialed(), 'post_data' => $_POST, 'payment_id' => $payment_id, 'membership_id' => absint( $payment->membership_id ), 'customer' => $customer, 'subscription_start_date' => '', // Empty means it starts today. ); // if giving the user a credit, make sure the credit does not exceed the first payment if ( $registration_data['fee'] < 0 && abs( $registration_data['fee'] ) > $registration_data['price'] ) { $registration_data['fee'] = -1 * $registration_data['price']; } /* * Delay the subscription start date if this is a free trial OR the amount due today is $0, * the recurring amount is greater than $0, and auto renew is enabled. */ if ( $registration_data['trial_eligible'] && ! empty( $registration_data['trial_duration'] ) ) { // Subscription start date is the end of the trial. $registration_data['subscription_start_date'] = date( 'Y-m-d H:i:s', strtotime( $registration_data['trial_duration'] . ' ' . $registration_data['trial_duration_unit'], current_time( 'timestamp' ) ) ); // Set the amount due today to $0. $registration_data['price'] = 0; $registration_data['fee'] = 0; } elseif ( empty( $registration_data['price'] + $registration_data['fee'] ) && ! empty( $registration_data['recurring_price'] ) && rcp_registration_is_recurring() ) { // Start date is delayed due to discounts, negative signup fees, or credits. $registration_data['subscription_start_date'] = date( 'Y-m-d H:i:s', strtotime( $registration_data['length'] . ' ' . $registration_data['length_unit'], current_time( 'timestamp' ) ) ); } update_user_meta( $user->ID, 'rcp_pending_subscription_amount', round( $registration_data['price'] + $registration_data['fee'], 2 ) ); /** * Filters the registration data. * * @param array $registration_data */ return apply_filters( 'rcp_subscription_data', $registration_data ); } /** * Provide the default registration values when checking out with Stripe Checkout. * * @return void */ function rcp_handle_stripe_checkout() { if ( empty( $_POST['rcp_stripe_checkout'] ) || empty( $_POST['rcp_gateway'] ) || empty( $_POST['rcp_user_email'] ) || 'stripe' !== $_POST['rcp_gateway'] ) { return; } if ( empty( $_POST['rcp_user_login'] ) ) { $_POST['rcp_user_login'] = sanitize_text_field( wp_unslash( $_POST['rcp_user_email'] ) ); } if ( empty( $_POST['rcp_user_first'] ) ) { $user_email = explode( '@', sanitize_text_field( wp_unslash( $_POST['rcp_user_email'] ) ) ); $_POST['rcp_user_first'] = $user_email[0]; } if ( empty( $_POST['rcp_user_last'] ) ) { $_POST['rcp_user_last'] = ''; } if ( empty( $_POST['rcp_user_pass'] ) ) { $_POST['rcp_user_pass'] = wp_generate_password(); } if ( empty( $_POST['rcp_user_pass_confirm'] ) ) { $_POST['rcp_user_pass_confirm'] = sanitize_text_field( wp_unslash( $_POST['rcp_user_pass'] ) ); } } add_action( 'rcp_before_form_errors', 'rcp_handle_stripe_checkout' ); /** * Validate and set up the user data for registration * * @access public * @since 1.5 * @return array */ function rcp_validate_user_data() { $user = array(); if ( ! is_user_logged_in() ) { $user['id'] = 0; $user['login'] = sanitize_text_field( wp_unslash( isset( $_POST['rcp_user_login'] ) ? $_POST['rcp_user_login'] : '' ) ); $user['email'] = sanitize_text_field( wp_unslash( isset( $_POST['rcp_user_email'] ) ? $_POST['rcp_user_email'] : '' ) ); $user['first_name'] = sanitize_text_field( wp_unslash( isset( $_POST['rcp_user_first'] ) ? $_POST['rcp_user_first'] : '' ) ); $user['last_name'] = sanitize_text_field( wp_unslash( isset( $_POST['rcp_user_last'] ) ? $_POST['rcp_user_last'] : '' ) ); $user['password'] = sanitize_text_field( wp_unslash( isset( $_POST['rcp_user_pass'] ) ? $_POST['rcp_user_pass'] : '' ) ); $user['password_confirm'] = sanitize_text_field( wp_unslash( isset( $_POST['rcp_user_pass_confirm'] ) ? $_POST['rcp_user_pass_confirm'] : '' ) ); $user['need_new'] = true; } else { $userdata = get_userdata( get_current_user_id() ); $user['id'] = $userdata->ID; $user['login'] = $userdata->user_login; $user['email'] = $userdata->user_email; $user['need_new'] = false; } if ( $user['need_new'] ) { if ( username_exists( $user['login'] ) ) { // Username already registered rcp_errors()->add( 'username_unavailable', sprintf( __( 'This username is already in use. If this is your username, please log in and try again.', 'rcp' ), esc_url( rcp_get_login_url() ) ), 'register' ); } if ( ! rcp_validate_username( $user['login'] ) ) { // invalid username rcp_errors()->add( 'username_invalid', __( 'Invalid username', 'rcp' ), 'register' ); } if ( empty( $user['login'] ) ) { // empty username rcp_errors()->add( 'username_empty', __( 'Please enter a username', 'rcp' ), 'register' ); } if ( ! is_email( $user['email'] ) ) { // invalid email rcp_errors()->add( 'email_invalid', __( 'Invalid email', 'rcp' ), 'register' ); } if ( email_exists( $user['email'] ) ) { // Email address already registered rcp_errors()->add( 'email_used', sprintf( __( 'This email address is already in use. If this is your email address, please log in and try again.', 'rcp' ), esc_url( rcp_get_login_url() ) ), 'register' ); } if ( empty( $user['password'] ) ) { // passwords do not match rcp_errors()->add( 'password_empty', __( 'Please enter a password', 'rcp' ), 'register' ); } if ( $user['password'] !== $user['password_confirm'] ) { // passwords do not match rcp_errors()->add( 'password_mismatch', __( 'Passwords do not match', 'rcp' ), 'register' ); } } return apply_filters( 'rcp_user_registration_data', $user ); } /** * Get the registration success/return URL * * @param $user_id int The user ID we have just registered * * @access public * @since 1.5 * @since 3.5.8 Looking inside the $_POST for the content_upgrade_redirect block * @return string */ function rcp_get_return_url( $user_id = 0 ) { if ( empty( $user_id ) ) { $user_id = get_current_user_id(); } // Redirect coming from Content Upgrade Redirect block if ( ! empty( $_POST['rcp_redirect'] ) ) { $validated_rcp_redirect = wp_validate_redirect( sanitize_text_field( wp_unslash( $_POST['rcp_redirect'] ) ) ); if ( ! empty( $validated_rcp_redirect ) ) { return apply_filters( 'rcp_return_url', $validated_rcp_redirect, $user_id ); } } global $rcp_options; if ( isset( $rcp_options['redirect'] ) ) { $redirect = get_permalink( $rcp_options['redirect'] ); } else { $redirect = home_url(); } return apply_filters( 'rcp_return_url', $redirect, $user_id ); } /** * Determine if the current page is a registration page * * @access public * @since 2.0 * @return bool */ function rcp_is_registration_page() { global $rcp_options, $post; $ret = false; if ( isset( $rcp_options['registration_page'] ) ) { $ret = is_page( $rcp_options['registration_page'] ); } if ( ! empty( $post ) && has_shortcode( $post->post_content, 'register_form' ) ) { $ret = true; } return apply_filters( 'rcp_is_registration_page', $ret ); } /** * Get the auto renew behavior * * 1 == All memberships auto renew * 2 == No memberships auto renew * 3 == Customer chooses whether to auto renew * * @access public * @since 2.0 * @return int */ function rcp_get_auto_renew_behavior() { global $rcp_options, $rcp_level; // Check for old disable auto renew option if ( isset( $rcp_options['disable_auto_renew'] ) ) { $rcp_options['auto_renew'] = '2'; unset( $rcp_options['disable_auto_renew'] ); update_option( 'rcp_settings', $rcp_options ); } $behavior = isset( $rcp_options['auto_renew'] ) ? $rcp_options['auto_renew'] : '3'; if ( $rcp_level ) { $level = rcp_get_membership_level( $rcp_level ); if ( $level instanceof Membership_Level && $level->is_free() ) { $behavior = '2'; } } return apply_filters( 'rcp_auto_renew_behavior', $behavior ); } /** * When new memberships are registered, a flag is set * * This removes the flag as late as possible so other systems can hook into * rcp_set_status and perform actions on new memberships * * @deprecated 3.0 Still here for backwards compatibility. * * @param string $status User's membership status. * @param int $user_id ID of the member. * * @access public * @since 2.3.6 * @return void */ function rcp_remove_new_subscription_flag( $status, $user_id ) { if ( ! in_array( $status, array( 'active', 'free' ) ) ) { return; } delete_user_meta( $user_id, '_rcp_old_subscription_id' ); delete_user_meta( $user_id, '_rcp_new_subscription' ); } add_action( 'rcp_set_status', 'rcp_remove_new_subscription_flag', 9999999, 2 ); /** * When upgrading memberships, the new level / key are stored as pending. Once payment is received, the pending * values are set as the permanent values. * * See https://github.com/restrictcontentpro/restrict-content-pro/issues/294 * * @deprecated 3.0 Still here for backwards compatibility. * * @param string $status User's membership status. * @param int $user_id ID of the user. * @param string $old_status Previous membership status. * @param RCP_Member $member Member object. * * @access public * @since 2.4.3 * @return void */ function rcp_set_pending_subscription_on_upgrade( $status, $user_id, $old_status, $member ) { if ( 'active' !== $status ) { return; } $subscription_id = get_user_meta( $user_id, 'rcp_pending_subscription_level', true ); $subscription_key = get_user_meta( $user_id, 'rcp_pending_subscription_key', true ); if ( ! empty( $subscription_id ) && ! empty( $subscription_key ) ) { delete_user_meta( $user_id, 'rcp_pending_subscription_level' ); delete_user_meta( $user_id, 'rcp_pending_subscription_key' ); } } add_action( 'rcp_set_status', 'rcp_set_pending_subscription_on_upgrade', 10, 4 ); /** * Determine if this registration is recurring * * @since 2.5 * @return bool */ function rcp_registration_is_recurring() { $auto_renew = false; if ( '3' == rcp_get_auto_renew_behavior() ) { $auto_renew = ! empty( $_POST['rcp_auto_renew'] ); } if ( '1' == rcp_get_auto_renew_behavior() ) { $auto_renew = true; } // make sure this gateway supports recurring payments if ( $auto_renew && ! empty( $_POST['rcp_gateway'] ) ) { $auto_renew = rcp_gateway_supports( sanitize_text_field( wp_unslash( $_POST['rcp_gateway'] ) ), 'recurring' ); } if ( $auto_renew && ! empty( $_POST['rcp_level'] ) ) { $membership_level = rcp_get_membership_level( sanitize_text_field( wp_unslash( $_POST['rcp_level'] ) ) ); if ( $membership_level instanceof Membership_Level ) { // check if this is an unlimited or free membership if ( $membership_level->is_lifetime() || $membership_level->is_free() ) { $auto_renew = false; } // Disable auto renew if this is a free trial but the gateway doesn't support them built into subscriptions. if ( $auto_renew && $membership_level->has_trial() ) { $customer = rcp_get_customer(); $trial_eligible = empty( $customer ) || ( ! empty( $customer ) && ! $customer->has_trialed() ); if ( $trial_eligible && ! rcp_gateway_supports( sanitize_text_field( wp_unslash( $_POST['rcp_gateway'] ) ), 'trial' ) ) { $auto_renew = false; } } } } if ( ! rcp_get_registration_recurring_total() > 0 ) { $auto_renew = false; } return apply_filters( 'rcp_registration_is_recurring', $auto_renew ); } /** * Add the registration total before the gateway fields * * @since 2.5 * @return void */ function rcp_registration_total_field() { ?>
get_membership_level_id() ); if ( $level instanceof Membership_Level && $level->has_trial() && ! rcp_customer_has_trialed() ) { $total = sprintf( __( 'Free trial - %s', 'rcp' ), $level->get_trial_duration() . ' ' . rcp_filter_duration_unit( $level->get_trial_duration_unit(), $level->get_trial_duration() ) ); } $total = apply_filters( 'rcp_registration_total', $total ); if ( $echo ) { echo $total; } return $total; } /** * Get the total for this registration * * @since 2.5 * @return float|false */ function rcp_get_registration_total() { if ( ! rcp_is_registration() ) { return false; } return rcp_get_registration()->get_total(); } /** * Get formatted recurring total for this registration * * @param bool $echo Whether or not to echo the value. * * @since 2.5 * @return string|bool */ function rcp_registration_recurring_total( $echo = true ) { $total = rcp_get_registration_recurring_total(); // the registration has not been setup yet if ( false === $total ) { return false; } if ( 0 < $total ) { $total = rcp_currency_filter( $total ); $membership_level = rcp_get_membership_level( rcp_get_registration()->get_membership_level_id() ); if ( $membership_level instanceof Membership_Level ) { if ( $membership_level->get_duration() == 1 ) { $total .= '/' . rcp_filter_duration_unit( $membership_level->get_duration_unit(), 1 ); } else { $total .= sprintf( __( ' every %1$s %2$s', 'rcp' ), $membership_level->get_duration(), rcp_filter_duration_unit( $membership_level->get_duration_unit(), $membership_level->get_duration() ) ); } } } else { $total = __( 'free', 'rcp' ); } $total = apply_filters( 'rcp_registration_recurring_total', $total ); if ( $echo ) { echo $total; } return $total; } /** * Get the recurring total payment * * @since 2.5 * @return bool|int */ function rcp_get_registration_recurring_total() { if ( ! rcp_is_registration() ) { return false; } return rcp_get_registration()->get_recurring_total(); } /** * Is the registration object setup? * * @since 2.5 * @return bool */ function rcp_is_registration() { return (bool) rcp_get_registration()->get_membership_level_id(); } /** * Get the registration object. If it hasn't been setup, setup an empty * registration object. * * @return RCP_Registration */ function rcp_get_registration() { global $rcp_registration; // setup empty registration object if one doesn't exist if ( ! is_a( $rcp_registration, 'RCP_Registration' ) ) { rcp_setup_registration(); } return $rcp_registration; } /** * Setup the registration object * * Auto setup cart on page load if $_POST parameters are found * * @param int|null $level_id ID of the membership level for this registration. * @param string|null $discount Discount code to apply to this registration. * * @since 2.5 * @return void */ function rcp_setup_registration( $level_id = null, $discount = null ) { global $rcp_registration; $rcp_registration = new RCP_Registration( $level_id, $discount ); do_action( 'rcp_setup_registration', $level_id, $discount ); } /** * Automatically setup the registration object * * @uses rcp_setup_registration() * * @return void */ function rcp_setup_registration_init() { if ( empty( $_POST['rcp_level'] ) ) { return; } $level_id = abs( sanitize_text_field( wp_unslash( $_POST['rcp_level'] ) ) ); $discount = ! empty( $_REQUEST['discount'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['discount'] ) ) : null; $discount = ! empty( $_POST['rcp_discount'] ) ? sanitize_text_field( wp_unslash( $_POST['rcp_discount'] ) ) : $discount; rcp_setup_registration( $level_id, $discount ); } add_action( 'init', 'rcp_setup_registration_init' ); /** * Filter levels to only show valid upgrade levels * * @param array $levels Array of membership levels. * * @since 2.5 * @return array Array of membership levels. */ function rcp_filter_registration_upgrade_levels( $levels = array() ) { global $rcp_payments_db; remove_filter( 'rcp_get_levels', 'rcp_filter_registration_upgrade_levels' ); // Filter available levels based on query args. $type = rcp_get_registration()->get_registration_type(); $membership = rcp_get_registration()->get_membership(); $payment_id = ! empty( $_GET['rcp_registration_payment_id'] ) ? absint( $_GET['rcp_registration_payment_id'] ) : 0; if ( ! empty( $payment_id ) && $payment = $rcp_payments_db->get_payment( $payment_id ) ) { // We're recovering a payment -- only show the level associated with that payment. $levels = array( rcp_get_membership_level( $payment->object_id ) ); } else { // Renewals / upgrades / normal. if ( 'renewal' == $type && ! empty( $membership ) ) { $level_id = $membership->get_object_id(); $levels = $membership->can_renew() ? array( rcp_get_membership_level( $level_id ) ) : array(); } elseif ( in_array( $type, array( 'upgrade', 'downgrade' ) ) && ! empty( $membership ) ) { $levels = $membership->upgrade_possible() ? $membership->get_upgrade_paths() : array(); } elseif ( 'new' == $type && ! rcp_multiple_memberships_enabled() ) { $levels = rcp_get_upgrade_paths(); } } add_filter( 'rcp_get_levels', 'rcp_filter_registration_upgrade_levels' ); return $levels; } /** * Hook into registration page and filter upgrade path */ add_action( 'rcp_before_subscription_form_fields', 'rcp_filter_registration_upgrade_levels' ); /** * Display "new membership" message. * * Adds a notice to the registration form if a user is signing up for a new membership but they * already have existing memberships that could be renewed or upgraded instead. This is to help * avoid confusion if someone thinks they're renewing a membership but actually they're signing * up for a second one instead. * * This message is not displayed if multiple memberships is disabled. * * @since 3.1 * @return void */ function rcp_display_new_membership_message() { // Bail if multiple memberships aren't enabled. if ( ! rcp_multiple_memberships_enabled() ) { return; } // Bail if we're already renewing or upgrading. if ( 'new' != rcp_get_registration()->get_registration_type() ) { return; } $customer = rcp_get_customer(); // current customer // Bail if this user isn't already a customer. if ( empty( $customer ) ) { return; } // Bail if this customer doesn't have any memberships. $memberships = $customer->get_memberships( array( 'status__in' => array( 'active', 'cancelled', 'expired' ), ) ); // Final array of filtered memberships. $membership_array = array(); /** * @var RCP_Membership $membership */ foreach ( $memberships as $membership ) { if ( ! $membership->can_renew() && ! $membership->upgrade_possible() ) { continue; } $actions = array(); if ( $membership->can_renew() ) { $actions[] = '' . __( 'Renew', 'rcp' ) . ''; } if ( $membership->upgrade_possible() ) { $actions[] = '' . __( 'Change', 'rcp' ) . ''; } $membership_array[ $membership->get_id() ] = array( 'name' => sprintf( '%s (%s)', $membership->get_membership_level_name(), $membership->get_status() ), 'actions' => implode( sprintf( ' %s ', __( 'or', 'rcp' ) ), $actions ), ); } if ( empty( $membership_array ) ) { return; } ?>

%s', __( 'You are signing up for a new membership.', 'rcp' ), __( 'Click here to renew or change an existing membership instead.', 'rcp' ) ); ?>

get_registration_type(), array( 'upgrade', 'downgrade' ) ) ) { return; } $membership = rcp_get_registration()->get_membership(); if ( empty( $membership ) ) { return; } ?>

Click here to sign up for an additional membership instead.', 'rcp' ), $membership->get_membership_level_name(), esc_url( rcp_get_registration_page_url() ) ); ?>

get_registration_type(), array( 'upgrade', 'downgrade' ) ) ) { return; } if ( $membership = $registration->get_membership() ) { $amount = $membership->get_prorate_credit_amount(); } else { $amount = rcp_get_member_prorate_credit(); } if ( empty( $amount ) ) { return; } $registration->add_fee( -1 * $amount, __( 'Proration Credit', 'rcp' ), false, true ); rcp_log( sprintf( 'Adding %.2f proration credits to registration for user #%d.', $amount, get_current_user_id() ) ); } add_action( 'rcp_registration_init', 'rcp_add_prorate_fee' ); /** * Add message to checkout specifying proration credit * * @since 2.5 * @return void */ function rcp_add_prorate_message() { // If this isn't an upgrade, don't show the message. if ( ! in_array( rcp_get_registration()->get_registration_type(), array( 'upgrade', 'downgrade' ) ) ) { return; } $upgrade_paths = rcp_get_upgrade_paths( get_current_user_id() ); $has_upgrade = false; /* * The proration message should only be shown if the user has at least one upgrade * option available where the price is greater than $0. */ if ( ! empty( $upgrade_paths ) ) { foreach ( $upgrade_paths as $subscription_level ) { if ( ( $subscription_level->price > 0 || $subscription_level->fee > 0 ) ) { $has_upgrade = true; break; } } } if ( $membership = rcp_get_registration()->get_membership() ) { $amount = $membership->get_prorate_credit_amount(); } else { $amount = rcp_get_member_prorate_credit(); } if ( empty( $amount ) || ( ! $has_upgrade ) ) { return; } $prorate_message = sprintf( '

%s

', __( 'If you upgrade or downgrade your account, the new membership will be prorated up to %s for the first payment. Prorated prices are shown below.', 'rcp' ) ); printf( apply_filters( 'rcp_registration_prorate_message', $prorate_message ), esc_html( rcp_currency_filter( $amount ) ) ); } add_action( 'rcp_before_subscription_form_fields', 'rcp_add_prorate_message' ); /** * Add the registration type to the form. * * @since 3.1 * @return void */ function rcp_add_registration_type_field() { $reg_type = ! empty( $_GET['registration_type'] ) ? sanitize_text_field( wp_unslash( $_GET['registration_type'] ) ) : ''; $membership_id = ! empty( $_GET['membership_id'] ) ? sanitize_text_field( wp_unslash( $_GET['membership_id'] ) ) : 0; $payment_id = ! empty( $_GET['rcp_registration_payment_id'] ) ? sanitize_text_field( wp_unslash( $_GET['rcp_registration_payment_id'] ) ) : 0; ?> prepare( "DELETE FROM {$wpdb->usermeta} WHERE user_id = %d AND meta_key LIKE %s", $user_id, '_rcp_reminder_sent_' . absint( $member->get_subscription_id() ) . '_%' ); $wpdb->query( $query ); } // add_action( 'rcp_set_status', 'rcp_remove_expiring_soon_email_sent_flag', 10, 4 ); /** * Trigger email verification during registration. * * @uses rcp_send_email_verification() * * @param array $posted Posted form data. * @param int $user_id ID of the user making this registration. * @param float $price Price of the membership level. * @param int $payment_id ID of the pending payment associated with this registration. * @param RCP_Customer $customer Customer object. * @param int $membership_id ID of the new pending membership. * @param RCP_Membership|false $previous_membership Previous membership object, or false if none. * @param string $registration_type Type of registration: 'new', 'renewal', or 'upgrade'. * * @return void */ function rcp_set_email_verification_flag( $posted, $user_id, $price, $payment_id, $customer, $membership_id, $previous_membership, $registration_type ) { global $rcp_options; $require_verification = isset( $rcp_options['email_verification'] ) ? $rcp_options['email_verification'] : 'off'; $required = in_array( $require_verification, array( 'free', 'all' ) ); // Not required if this is a paid registration and email verification is required for free only. if ( $price > 0 && 'free' == $require_verification ) { $required = false; } // Not required if they've already had a membership level. // This prevents email verification from popping up for old users on upgrades/downgrades/renewals. if ( $previous_membership ) { $required = false; } // Bail if verification not required. if ( ! apply_filters( 'rcp_require_email_verification', $required, $posted, $user_id, $price ) ) { return; } // Email verification already completed. if ( 'verified' === $customer->get_email_verification_status() ) { return; } // Add meta flag to indicate they're pending email verification. This also sends the email. $customer->update( array( 'email_verification' => 'pending', ) ); } add_action( 'rcp_form_processing', 'rcp_set_email_verification_flag', 10, 8 ); /** * Remove membership data if registration payment fails. Includes: * * - Update pending payment status to "Failed" * - If this is a brand new registration, disable the associated membership. @todo Maybe this could be improved. * * @param RCP_Payment_Gateway $gateway * * @since 2.8 * @return void */ function rcp_remove_subscription_data_on_failure( $gateway ) { if ( ! empty( $gateway->user_id ) && is_object( $gateway->payment ) ) { /** * @var RCP_Payments $rcp_payments_db */ global $rcp_payments_db; // Mark the pending payment as failed. $rcp_payments_db->update( $gateway->payment->id, array( 'status' => 'failed' ) ); // Disable the membership. $transaction_type = ! empty( $gateway->payment->transaction_type ) ? $gateway->payment->transaction_type : 'new'; if ( is_object( $gateway->membership ) && ! $gateway->membership->is_active() && 'renewal' != $transaction_type ) { $gateway->membership->disable(); } if ( is_object( $gateway->membership ) ) { $pending_payment_id = rcp_get_membership_meta( $gateway->membership->get_id(), 'pending_payment_id', true ); if ( $pending_payment_id == $gateway->payment->id ) { rcp_delete_membership_meta( $gateway->membership->get_id(), 'pending_payment_id' ); } } // Delete the pending payment ID meta value if that matches this payment. // This is for backwards compatibility only; we now use membership meta. $customer = rcp_get_customer_by_user_id( $gateway->user_id ); if ( ! empty( $customer ) ) { $pending_payment_id = $customer->get_pending_payment_id(); if ( $pending_payment_id == $gateway->payment->id ) { delete_user_meta( $customer->get_user_id(), 'rcp_pending_payment_id' ); } } } // Log error. rcp_log( sprintf( '%s registration failed for user #%d. Error message: %s', rcp_get_gateway_name_from_object( $gateway ), $gateway->user_id, $gateway->error_message ), true ); } add_action( 'rcp_registration_failed', 'rcp_remove_subscription_data_on_failure' ); /** * Complete a registration when a payment is completed by updating the following: * * - Add discount code to member's profile (if applicable). * - Increase discount code usage (if applicable). * - Mark as trialing (if applicable). * - Remove the role granted by the previous membership level and apply new one. * * @param int $payment_id ID of the payment being completed. * * @since 2.9 * @return void */ function rcp_complete_registration( $payment_id ) { /** * @var RCP_Payments $rcp_payments_db */ global $rcp_payments_db; $payment = $rcp_payments_db->get_payment( $payment_id ); if ( ! empty( $payment->customer_id ) ) { $customer = rcp_get_customer( $payment->customer_id ); } else { $customer = false; } // No customer - bail. if ( empty( $customer ) ) { return; } $membership_id = ! empty( $payment->membership_id ) ? $payment->membership_id : 0; $membership = ! empty( $membership_id ) ? rcp_get_membership( $membership_id ) : false; if ( empty( $membership ) ) { return; } $pending_payment_id = rcp_get_membership_meta( $membership_id, 'pending_payment_id', true ); // If this payment doesn't correspond to the initial signup ID, bail. if ( empty( $pending_payment_id ) || $pending_payment_id != $payment_id ) { return; } rcp_log( sprintf( 'Completing registration for customer #%d via payment #%d.', $customer->get_id(), $pending_payment_id ) ); if ( ! empty( $payment->transaction_type ) && 'renewal' != $payment->transaction_type ) { // If this is a brand new membership, activate it. $membership->activate(); } else { // Otherwise this is a manual renewal, so let's renew it. $expiration = ''; if ( 'pending' == $membership->get_status() ) { // If membership is pending, use existing expiration date. This would have been set during registration. $expiration = $membership->get_expiration_date( false ); } $membership->renew( $membership->is_recurring(), 'active', $expiration ); } // Increase the number of uses for this discount code. if ( ! empty( $payment->discount_code ) ) { $discount = rcp_get_discount_by( 'code', $payment->discount_code ); if ( ! empty( $discount ) ) { rcp_log( sprintf( 'Recording usage of discount code #%d.', $discount->get_id() ) ); // Record the usage of this discount code $discount->store_for_user( $customer->get_user_id() ); // Increase the usage count for the code $discount->increment_use_count(); } } // Delete the pending payment record. rcp_delete_membership_meta( $membership_id, 'pending_payment_id' ); // Backwards compatibility. if ( ! empty( $payment->user_id ) ) { delete_user_meta( $payment->user_id, 'rcp_pending_payment_id' ); } $member = new RCP_Member( $customer->get_user_id() ); // for backwards compatibility in the below action /** * Registration successful! Hook into this action if you need to execute code * after a successful registration, but not during an automatic renewal. * * @var RCP_Member $member * @var RCP_Customer $customer * @var RCP_Membership $membership * @since 2.9 */ do_action( 'rcp_successful_registration', $member, $customer, $membership ); } add_action( 'rcp_update_payment_status_complete', 'rcp_complete_registration' ); /** * Register a user account as an RCP member, assign a membership level, * calculate the expiration date, etc. * * @deprecated 3.0 Use `RCP_Customer::add_membership()` instead. * @see RCP_Customer::add_membership() * * @param int $user_id ID of the user to add the membership to. * @param array $args { * Array of membership arguments. Only `subscription_id` is required. * * @type string $status Optional. Status to set: free, active, cancelled, or expired. If omitted, set * to free or active. * @type int $subscription_id Required. ID number of the membership level to give the user. * @type string $expiration Optional. Expiration date to give the user in MySQL format. If omitted, * calculated automatically. * @type string $discount_code Optional. Name of a discount code to add to the user's profile and increment * usage count. * @type string $subscription_key Optional. Subscription key to add to the user's profile. * @type int|bool $trial_duration Optional. Only supply this to give the user a free trial. * @type string $trial_duration_unit Optional. `day`, `month`, or `year`. * @type bool $recurring Optional. Whether or not the membership is automatically recurring. Default is * `false`. * @type string $payment_profile_id Optional. Payment profile ID to add to the user's profile. * } * * @since 2.9 * @return bool */ function rcp_add_user_to_subscription( $user_id, $args = array() ) { $defaults = array( 'status' => '', 'subscription_id' => 0, 'expiration' => '', // Calculated automatically if not provided. 'discount_code' => '', // To add to their profile and increase usage. 'subscription_key' => '', 'trial_duration' => false, // To set as trialing. 'trial_duration_unit' => 'day', 'recurring' => false, 'payment_profile_id' => '', ); $args = wp_parse_args( $args, $defaults ); // Membership level ID is required. if ( empty( $args['subscription_id'] ) ) { return false; } // Check to see if a customer exists, and if not, create one. $customer = rcp_get_customer_by_user_id( $user_id ); if ( empty( $customer ) ) { $customer_id = rcp_add_customer( array( 'user_id' => $user_id, ) ); if ( empty( $customer_id ) ) { return false; } $customer = rcp_get_customer( $customer_id ); } $member = new RCP_Member( $user_id ); $previous_membership = rcp_get_customer_single_membership( $customer->get_id() ); $old_membership_id = ! empty( $previous_membership ) ? $previous_membership->get_object_id() : false; $membership_level = rcp_get_membership_level( $args['subscription_id'] ); // Invalid membership level - bail. if ( ! $membership_level instanceof Membership_Level ) { return false; } if ( ! empty( $previous_membership ) && $previous_membership->get_object_id() == $args['subscription_id'] ) { /** * If the previous membership is the same as this new one, renew it instead of adding a new one. */ $expiration = ! empty( $args['expiration'] ) ? $args['expiration'] : ''; $previous_membership->renew( false, 'active', $expiration ); if ( ! empty( $args['subscription_key'] ) ) { $previous_membership->set_subscription_key( $args['subscription_key'] ); } if ( ! empty( $args['payment_profile_id'] ) ) { $previous_membership->set_gateway_customer_id( $args['payment_profile_id'] ); } } else { /** * Gather all the membership data for a brand new membership. */ $membership_data = array( 'object_id' => $membership_level->get_id(), ); if ( ! empty( $args['subscription_key'] ) ) { $membership_data['subscription_key'] = $args['subscription_key']; } /* * Initial and recurring amounts. */ $membership_data['initial_amount'] = $membership_level->get_price() + $membership_level->get_fee(); $membership_data['recurring_amount'] = $membership_level->get_price(); /* * Expiration date * Calculate it if not provided. */ $expiration = $args['expiration']; if ( empty( $expiration ) ) { $expiration = rcp_calculate_subscription_expiration( $membership_level->get_id(), ! $member->has_trialed() ); } $membership_data['expiration_date'] = $expiration; /* * Discount code * Increase the number of uses. */ if ( ! empty( $args['discount_code'] ) ) { $discount = rcp_get_discount_by( 'code', $args['discount_code'] ); if ( ! empty( $discount ) ) { // Record the usage of this discount code $discount->store_for_user( $user_id ); // Increase the usage count for the code $discount->increment_use_count(); } } /* * Set the status */ $status = $args['status']; if ( empty( $status ) || 'free' == $status ) { $status = 'active'; } $membership_data['status'] = $status; // Recurring $membership_data['auto_renew'] = ! empty( $args['recurring'] ) ? 1 : 0; // Payment profile ID if ( ! empty( $args['payment_profile_id'] ) ) { $membership_data['gateway_subscription_id'] = $args['payment_profile_id']; } /** * Now actually insert or update the membership. */ $membership_id = $customer->add_membership( $membership_data ); if ( empty( $membership_id ) ) { return false; } } /** * Registration successful! Hook into this action if you need to execute code * after a successful registration, but not during an automatic renewal. * * @var RCP_Member $member * @since 2.9 */ do_action( 'rcp_successful_registration', $member ); return true; } /** * Automatically add new users to a membership level if enabled * * @param int $user_id ID of the newly created user. * * @since 2.9 * @return void */ function rcp_user_register_add_subscription_level( $user_id ) { global $rcp_options; if ( empty( $rcp_options['auto_add_users'] ) ) { return; } $level_id = absint( $rcp_options['auto_add_users_level'] ); if ( empty( $level_id ) ) { return; } // Don't run if we're on the registration form. if ( did_action( 'rcp_form_errors' ) ) { return; } rcp_log( sprintf( 'Auto adding membership level to user #%d.', $user_id ) ); $customer = rcp_get_customer_by_user_id( $user_id ); if ( empty( $customer ) ) { $customer_id = rcp_add_customer( array( 'user_id' => $user_id ) ); if ( empty( $customer_id ) ) { rcp_log( sprintf( 'Error creating customer record for user #%d.', $user_id ) ); return; } $customer = rcp_get_customer( $customer_id ); } if ( empty( $customer ) ) { rcp_log( sprintf( 'Error retrieving customer record for user #%d.', $user_id ) ); return; } $customer->add_membership( array( 'object_id' => $level_id, 'status' => 'active', // Note: this bypasses RCP_Membership::activate(). Not sure if desired. 'signup_method' => 'manual', ) ); } add_action( 'user_register', 'rcp_user_register_add_subscription_level' ); /** * Returns the URL to the designated registration page. * * @since 3.1 * @return string */ function rcp_get_registration_page_url() { global $rcp_options; $url = get_permalink( $rcp_options['registration_page'] ); /** * Filters the registration page URL. * * @param string $url * * @since 3.3.5 */ return apply_filters( 'rcp_registration_page_url', $url ); } /** * Adds the membership "Next Renewal Due" date to the registration "Total Details" table. * * @since 3.3 * @return void */ function rcp_add_membership_renewal_date_to_total_details() { $renewal_date = false; $registration = rcp_get_registration(); $membership = $registration->get_membership(); $membership_level_id = $registration->get_membership_level_id(); // Bail if we have a discount code and the initial & recurring amounts are 0. if ( $registration->get_total() == 0 && $registration->get_recurring_total() == 0 && $registration->get_discounts() && '2' != rcp_get_auto_renew_behavior() ) { return; } if ( ! empty( $membership ) && 'renewal' == $registration->get_registration_type() ) { /* * @link https://github.com/restrictcontentpro/restrict-content-pro/issues/1259 * * Not all gateways currently support extending the expiration date another full billing cycle during * renewals while auto renew is selected. */ $from_today = false; if ( ! empty( $_POST['rcp_gateway'] ) ) { $from_today = rcp_gateway_supports( sanitize_text_field( wp_unslash( $_POST['rcp_gateway'] ) ), 'expiration-extension-on-renewals' ) ? false : rcp_registration_is_recurring(); } $renewal_date = $membership->calculate_expiration( $from_today ); } if ( empty( $renewal_date ) && ! empty( $membership_level_id ) ) { $membership_level = rcp_get_membership_level( $membership_level_id ); // Bail if duration is `0` or price is `0`. if ( ! $membership_level instanceof Membership_Level || $membership_level->is_free() || $membership_level->is_lifetime() ) { return; } $renewal_date = rcp_calculate_subscription_expiration( $membership_level_id, $registration->is_trial() ); } if ( empty( $renewal_date ) || 'none' == $renewal_date ) { return; } ?>