- WordPress core y plugins - Tema Twenty Twenty-Four configurado - Plugin allow-unfiltered-html.php simplificado - .gitignore configurado para excluir wp-config.php y uploads 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
537 lines
16 KiB
PHP
537 lines
16 KiB
PHP
<?php
|
|
/**
|
|
* 2Checkout Payment Gateway
|
|
*
|
|
* @package Restrict Content Pro
|
|
* @subpackage Classes/Gateways/2Checkout
|
|
* @copyright Copyright (c) 2017, Pippin Williamson
|
|
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
|
* @since 2.3
|
|
*/
|
|
|
|
class RCP_Payment_Gateway_2Checkout extends RCP_Payment_Gateway {
|
|
|
|
private $secret_word;
|
|
private $secret_key;
|
|
private $publishable_key;
|
|
private $seller_id;
|
|
private $environment;
|
|
|
|
/**
|
|
* Get things going
|
|
*
|
|
* @access public
|
|
* @since 2.3
|
|
* @return void
|
|
*/
|
|
public function init() {
|
|
global $rcp_options;
|
|
|
|
$this->supports[] = 'one-time';
|
|
$this->supports[] = 'recurring';
|
|
$this->supports[] = 'fees';
|
|
$this->supports[] = 'gateway-submits-form';
|
|
|
|
$this->secret_word = isset( $rcp_options['twocheckout_secret_word'] ) ? trim( $rcp_options['twocheckout_secret_word'] ) : '';
|
|
|
|
if( $this->test_mode ) {
|
|
|
|
$this->secret_key = isset( $rcp_options['twocheckout_test_private'] ) ? trim( $rcp_options['twocheckout_test_private'] ) : '';
|
|
$this->publishable_key = isset( $rcp_options['twocheckout_test_publishable'] ) ? trim( $rcp_options['twocheckout_test_publishable'] ) : '';
|
|
$this->seller_id = isset( $rcp_options['twocheckout_test_seller_id'] ) ? trim( $rcp_options['twocheckout_test_seller_id'] ) : '';
|
|
$this->environment = 'sandbox';
|
|
|
|
} else {
|
|
|
|
$this->secret_key = isset( $rcp_options['twocheckout_live_private'] ) ? trim( $rcp_options['twocheckout_live_private'] ) : '';
|
|
$this->publishable_key = isset( $rcp_options['twocheckout_live_publishable'] ) ? trim( $rcp_options['twocheckout_live_publishable'] ) : '';
|
|
$this->seller_id = isset( $rcp_options['twocheckout_live_seller_id'] ) ? trim( $rcp_options['twocheckout_live_seller_id'] ) : '';
|
|
$this->environment = 'production';
|
|
|
|
}
|
|
|
|
if( ! class_exists( 'Twocheckout' ) ) {
|
|
require_once RCP_PLUGIN_DIR . 'pro/includes/libraries/twocheckout/Twocheckout.php';
|
|
}
|
|
|
|
} // end init
|
|
|
|
/**
|
|
* Process registration
|
|
*
|
|
* @access public
|
|
* @since 2.3
|
|
* @return void
|
|
*/
|
|
public function process_signup() {
|
|
|
|
Twocheckout::privateKey( $this->secret_key );
|
|
Twocheckout::sellerId( $this->seller_id );
|
|
Twocheckout::sandbox( $this->test_mode );
|
|
|
|
/**
|
|
* @var RCP_Payments $rcp_payments_db
|
|
*/
|
|
global $rcp_payments_db;
|
|
|
|
$member = new RCP_Member( $this->user_id ); // for backwards compatibility only
|
|
|
|
if( empty( $_POST['twoCheckoutToken'] ) ) {
|
|
rcp_errors()->add( 'missing_card_token', __( 'Missing 2Checkout token, please try again or contact support if the issue persists.', 'rcp' ), 'register' );
|
|
return;
|
|
}
|
|
|
|
$paid = false;
|
|
|
|
if ( $this->auto_renew ) {
|
|
|
|
$payment_type = 'Credit Card';
|
|
$line_items = array( array(
|
|
"recurrence" => $this->length . ' ' . ucfirst( $this->length_unit ),
|
|
"type" => 'product',
|
|
"price" => $this->amount,
|
|
"productId" => $this->subscription_id,
|
|
"name" => $this->subscription_name,
|
|
"quantity" => '1',
|
|
"tangible" => 'N',
|
|
"startupFee" => $this->initial_amount - $this->amount
|
|
) );
|
|
|
|
} else {
|
|
|
|
$payment_type = 'Credit Card One Time';
|
|
$line_items = array( array(
|
|
"recurrence" => 0,
|
|
"type" => 'product',
|
|
"price" => $this->initial_amount,
|
|
"productId" => $this->subscription_id,
|
|
"name" => $this->subscription_name,
|
|
"quantity" => '1',
|
|
"tangible" => 'N'
|
|
) );
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
$charge = Twocheckout_Charge::auth( array(
|
|
'merchantOrderId' => $this->subscription_key,
|
|
'token' => $_POST['twoCheckoutToken'],
|
|
'currency' => strtolower( $this->currency ),
|
|
'billingAddr' => array(
|
|
'name' => sanitize_text_field( $_POST['rcp_card_name'] ),
|
|
'addrLine1' => sanitize_text_field( $_POST['rcp_card_address'] ),
|
|
'city' => sanitize_text_field( $_POST['rcp_card_city'] ),
|
|
'state' => sanitize_text_field( $_POST['rcp_card_state'] ),
|
|
'zipCode' => sanitize_text_field( $_POST['rcp_card_zip'] ),
|
|
'country' => sanitize_text_field( $_POST['rcp_card_country'] ),
|
|
'email' => $this->email,
|
|
),
|
|
"lineItems" => $line_items,
|
|
));
|
|
|
|
if( $charge['response']['responseCode'] == 'APPROVED' ) {
|
|
|
|
// This activates the user's account.
|
|
$rcp_payments_db->update( $this->payment->id, array(
|
|
'date' => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ),
|
|
'payment_type' => $payment_type,
|
|
'transaction_id' => $charge['response']['orderNumber'],
|
|
'status' => 'complete'
|
|
) );
|
|
|
|
do_action( 'rcp_gateway_payment_processed', $member, $this->payment->id, $this );
|
|
|
|
$paid = true;
|
|
}
|
|
|
|
} catch ( Twocheckout_Error $e ) {
|
|
|
|
$this->error_message = $e->getMessage();
|
|
do_action( 'rcp_registration_failed', $this );
|
|
wp_die( $e->getMessage(), __( 'Error', 'rcp' ), array( 'response' => '401' ) );
|
|
|
|
}
|
|
|
|
if ( $paid ) {
|
|
|
|
$this->membership->add_note( __( 'Subscription started in 2Checkout', 'rcp' ) );
|
|
$this->membership->set_gateway_subscription_id( '2co_' . $charge['response']['orderNumber'] );
|
|
|
|
do_action( 'rcp_2co_signup', $this->user_id, $this );
|
|
|
|
}
|
|
|
|
// redirect to the success page, or error page if something went wrong
|
|
wp_redirect( $this->return_url ); exit;
|
|
}
|
|
|
|
/**
|
|
* Proccess webhooks
|
|
*
|
|
* @access public
|
|
* @since 2.3
|
|
* @return void
|
|
*/
|
|
public function process_webhooks() {
|
|
|
|
if ( isset( $_GET['listener'] ) && $_GET['listener'] == '2checkout' ) {
|
|
|
|
rcp_log( 'Starting to process 2Checkout webhook.' );
|
|
|
|
global $wpdb;
|
|
|
|
$hash = strtoupper( md5( $_POST['sale_id'] . $this->seller_id . $_POST['invoice_id'] . $this->secret_word ) );
|
|
|
|
if ( ! hash_equals( $hash, $_POST['md5_hash'] ) ) {
|
|
rcp_log( 'Exiting 2Checkout webhook - invalid MD5 hash.', true );
|
|
|
|
die('-1');
|
|
}
|
|
|
|
if ( empty( $_POST['message_type'] ) ) {
|
|
rcp_log( 'Exiting 2Checkout webhook - empty message_type.', true );
|
|
|
|
die( '-2' );
|
|
}
|
|
|
|
if ( empty( $_POST['vendor_id'] ) ) {
|
|
rcp_log( 'Exiting 2Checkout webhook - empty vendor_id.', true );
|
|
|
|
die( '-3' );
|
|
}
|
|
|
|
$subscription_key = sanitize_text_field( $_POST['vendor_order_id'] );
|
|
$this->membership = rcp_get_membership_by( 'subscription_key', $subscription_key );
|
|
|
|
if ( empty( $this->membership ) ) {
|
|
rcp_log( sprintf( 'Exiting 2Checkout webhook - membership not found from order ID %s.', $subscription_key ), true );
|
|
|
|
die( '-4' );
|
|
}
|
|
|
|
$member = new RCP_Member( $this->membership->get_user_id() ); // for backwards compatibility
|
|
|
|
if( 'twocheckout' != $this->membership->get_gateway() ) {
|
|
rcp_log( 'Exiting 2Checkout webhook - membership is not a 2Checkout subscription.' );
|
|
|
|
return;
|
|
}
|
|
|
|
rcp_log( sprintf( 'Processing webhook for membership #%d.', $this->membership->get_id() ) );
|
|
|
|
$payments = new RCP_Payments();
|
|
|
|
switch( strtoupper( $_POST['message_type'] ) ) {
|
|
|
|
case 'ORDER_CREATED' :
|
|
rcp_log( 'Processing 2Checkout ORDER_CREATED webhook.' );
|
|
|
|
break;
|
|
|
|
case 'REFUND_ISSUED' :
|
|
|
|
rcp_log( sprintf( 'Processing 2Checkout REFUND_ISSUED webhook for invoice ID %s.', $_POST['invoice_id'] ) );
|
|
|
|
$payment = $payments->get_payment_by( 'transaction_id', $_POST['invoice_id'] );
|
|
$payments->update( $payment->id, array( 'status' => 'refunded' ) );
|
|
|
|
if( ! empty( $_POST['recurring'] ) ) {
|
|
|
|
$this->membership->cancel();
|
|
$this->membership->add_note( __( 'Membership cancelled via refund 2Checkout', 'rcp' ) );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'RECURRING_INSTALLMENT_SUCCESS' :
|
|
|
|
rcp_log( sprintf( 'Processing 2Checkout RECURRING_INSTALLMENT_SUCCESS webhook for membership #%d.', $this->membership->get_id() ) );
|
|
|
|
$payment_data = array(
|
|
'date' => date( 'Y-m-d H:i:s', strtotime( $_POST['timestamp'], current_time( 'timestamp' ) ) ),
|
|
'subscription' => $this->membership->get_membership_level_name(),
|
|
'payment_type' => sanitize_text_field( $_POST['payment_type'] ),
|
|
'transaction_type' => 'renewal',
|
|
'subscription_key' => $subscription_key,
|
|
'amount' => sanitize_text_field( $_POST['item_list_amount_1'] ), // don't have a total from this call, but this should be safe
|
|
'subtotal' => sanitize_text_field( $_POST['item_list_amount_1'] ),
|
|
'user_id' => $this->membership->get_user_id(),
|
|
'customer_id' => $this->membership->get_customer()->get_id(),
|
|
'membership_id' => $this->membership->get_id(),
|
|
'transaction_id' => sanitize_text_field( $_POST['invoice_id'] ),
|
|
'gateway' => 'twocheckout'
|
|
);
|
|
|
|
$recurring = ! empty( $_POST['recurring'] );
|
|
$this->membership->renew( $recurring );
|
|
$payment_id = $payments->insert( $payment_data );
|
|
$this->membership->add_note( __( 'Membership renewed in 2Checkout', 'rcp' ) );
|
|
|
|
do_action( 'rcp_webhook_recurring_payment_processed', $member, $payment_id, $this );
|
|
do_action( 'rcp_gateway_payment_processed', $member, $payment_id, $this );
|
|
|
|
break;
|
|
|
|
case 'RECURRING_INSTALLMENT_FAILED' :
|
|
|
|
rcp_log( 'Processing 2Checkout RECURRING_INSTALLMENT_FAILED webhook.' );
|
|
|
|
if ( ! empty( $_POST['sale_id'] ) ) {
|
|
$this->webhook_event_id = sanitize_text_field( $_POST['sale_id'] );
|
|
}
|
|
|
|
do_action( 'rcp_recurring_payment_failed', $member, $this );
|
|
|
|
break;
|
|
|
|
case 'RECURRING_STOPPED' :
|
|
|
|
rcp_log( 'Processing 2Checkout RECURRING_STOPPED webhook.' );
|
|
|
|
if ( $this->membership->has_payment_plan() && $this->membership->at_maximum_renewals() ) {
|
|
rcp_log( sprintf( 'Membership #%d has completed its payment plan - not cancelling.', $this->membership->get_id() ) );
|
|
} else {
|
|
if ( $this->membership->is_active() ) {
|
|
$this->membership->cancel();
|
|
$this->membership->add_note( __( 'Membership cancelled via 2Checkout webhook.', 'rcp' ) );
|
|
} else {
|
|
rcp_log( sprintf( 'Membership #%d is not active - not cancelling.', $this->membership->get_id() ) );
|
|
}
|
|
|
|
do_action( 'rcp_webhook_cancel', $member, $this );
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
case 'RECURRING_COMPLETE' :
|
|
|
|
rcp_log( 'Processing 2Checkout RECURRING_COMPLETE webhook.' );
|
|
|
|
break;
|
|
|
|
case 'RECURRING_RESTARTED' :
|
|
|
|
rcp_log( 'Processing 2Checkout RECURRING_RESTARTED webhook.' );
|
|
|
|
$this->membership->set_status( 'active' );
|
|
$this->membership->add_note( __( 'Subscription restarted in 2Checkout', 'rcp' ) );
|
|
|
|
do_action( 'rcp_webhook_recurring_payment_profile_created', $member, $this );
|
|
|
|
break;
|
|
|
|
|
|
case 'FRAUD_STATUS_CHANGED' :
|
|
|
|
rcp_log( sprintf( 'Processing 2Checkout FRAUD_STATUS_CHANGED webhook. Status: %s', $_POST['fraud_status'] ) );
|
|
|
|
switch ( $_POST['fraud_status'] ) {
|
|
case 'pass':
|
|
break;
|
|
case 'fail':
|
|
|
|
$this->membership->set_status( 'pending' );
|
|
$this->membership->add_note( __( 'Payment flagged as fraudulent in 2Checkout', 'rcp' ) );
|
|
|
|
break;
|
|
case 'wait':
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
do_action( 'rcp_2co_' . strtolower( $_POST['message_type'] ) . '_ins', $member );
|
|
die( 'success');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Display fields and add extra JavaScript
|
|
*
|
|
* @access public
|
|
* @since 2.3
|
|
* @return void
|
|
*/
|
|
public function fields() {
|
|
ob_start();
|
|
?>
|
|
<script type="text/javascript">
|
|
// Called when token created successfully.
|
|
var successCallback = function(data) {
|
|
// re-enable the submit button
|
|
jQuery('#rcp_registration_form #rcp_submit').attr("disabled", false);
|
|
// Remove loding overlay
|
|
jQuery('#rcp_ajax_loading').hide();
|
|
|
|
var form$ = jQuery('#rcp_registration_form');
|
|
// token contains id, last4, and card type
|
|
var token = data.response.token.token;
|
|
// insert the token into the form so it gets submitted to the server
|
|
form$.append("<input type='hidden' name='twoCheckoutToken' value='" + token + "' />");
|
|
|
|
form$.get(0).submit();
|
|
};
|
|
// Called when token creation fails.
|
|
var errorCallback = function(data) {
|
|
if (data.errorCode === 200) {
|
|
tokenRequest();
|
|
} else {
|
|
|
|
jQuery('#rcp_registration_form').unblock();
|
|
jQuery('#rcp_submit').before( '<div class="rcp_message error"><p class="rcp_error"><span>' + data.errorMsg + '</span></p></div>' );
|
|
jQuery('#rcp_submit').val( rcp_script_options.register );
|
|
|
|
}
|
|
};
|
|
var tokenRequest = function() {
|
|
// Setup token request arguments
|
|
var args = {
|
|
sellerId: '<?php echo $this->seller_id; ?>',
|
|
publishableKey: '<?php echo $this->publishable_key; ?>',
|
|
ccNo: jQuery('.rcp_card_number').val(),
|
|
cvv: jQuery('.rcp_card_cvc').val(),
|
|
expMonth: jQuery('.rcp_card_exp_month').val(),
|
|
expYear: jQuery('.rcp_card_exp_year').val()
|
|
};
|
|
// Make the token request
|
|
TCO.requestToken(successCallback, errorCallback, args);
|
|
};
|
|
jQuery(document).ready(function($) {
|
|
// Pull in the public encryption key for our environment
|
|
TCO.loadPubKey('<?php echo $this->environment; ?>');
|
|
|
|
jQuery('body').on('rcp_register_form_submission', function rcp_2co_register_form_submission_handler(event, response, form_id) {
|
|
|
|
if ( response.gateway.slug !== 'twocheckout' ) {
|
|
return;
|
|
}
|
|
|
|
event.preventDefault();
|
|
|
|
/*
|
|
* Create token if the amount due today is greater than $0, or if the recurring
|
|
* amount is greater than $0 and auto renew is enabled.
|
|
*/
|
|
if( response.total > 0 || ( response.recurring_total > 0 && true == response.auto_renew ) ) {
|
|
|
|
|
|
// Call our token request function
|
|
tokenRequest();
|
|
|
|
// Prevent form from submitting
|
|
return false;
|
|
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
<?php
|
|
rcp_get_template_part( 'card-form', 'full' );
|
|
return ob_get_clean();
|
|
}
|
|
|
|
/**
|
|
* Validate additional fields during registration submission
|
|
*
|
|
* @access public
|
|
* @since 2.3
|
|
* @return void
|
|
*/
|
|
public function validate_fields() {
|
|
|
|
if( empty( $_POST['rcp_card_cvc'] ) ) {
|
|
rcp_errors()->add( 'missing_card_code', __( 'The security code you have entered is invalid', 'rcp' ), 'register' );
|
|
}
|
|
|
|
if( empty( $_POST['rcp_card_address'] ) ) {
|
|
rcp_errors()->add( 'missing_card_address', __( 'The address you have entered is invalid', 'rcp' ), 'register' );
|
|
}
|
|
|
|
if( empty( $_POST['rcp_card_city'] ) ) {
|
|
rcp_errors()->add( 'missing_card_city', __( 'The city you have entered is invalid', 'rcp' ), 'register' );
|
|
}
|
|
|
|
if( empty( $_POST['rcp_card_state'] ) && $this->card_needs_state_and_zip() ) {
|
|
rcp_errors()->add( 'missing_card_state', __( 'The state you have entered is invalid', 'rcp' ), 'register' );
|
|
}
|
|
|
|
if( empty( $_POST['rcp_card_country'] ) ) {
|
|
rcp_errors()->add( 'missing_card_country', __( 'The country you have entered is invalid', 'rcp' ), 'register' );
|
|
}
|
|
|
|
if( empty( $_POST['rcp_card_zip'] ) && $this->card_needs_state_and_zip() ) {
|
|
rcp_errors()->add( 'missing_card_zip', __( 'The zip / postal code you have entered is invalid', 'rcp' ), 'register' );
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Load 2Checkout JS
|
|
*
|
|
* @access public
|
|
* @since 2.3
|
|
* @return void
|
|
*/
|
|
public function scripts() {
|
|
wp_enqueue_script( 'twocheckout', 'https://www.2checkout.com/checkout/api/2co.min.js', array( 'jquery' ) );
|
|
}
|
|
|
|
/**
|
|
* Determine if zip / state are required
|
|
*
|
|
* @access private
|
|
* @since 2.3
|
|
* @return bool
|
|
*/
|
|
private function card_needs_state_and_zip() {
|
|
|
|
$ret = true;
|
|
|
|
if( ! empty( $_POST['rcp_card_country'] ) ) {
|
|
|
|
$needs_zip = array(
|
|
'AR',
|
|
'AU',
|
|
'BG',
|
|
'CA',
|
|
'CH',
|
|
'CY',
|
|
'EG',
|
|
'FR',
|
|
'IN',
|
|
'ID',
|
|
'IT',
|
|
'JP',
|
|
'MY',
|
|
'ME',
|
|
'NL',
|
|
'PA',
|
|
'PH',
|
|
'PO',
|
|
'RO',
|
|
'RU',
|
|
'SR',
|
|
'SG',
|
|
'ZA',
|
|
'ES',
|
|
'SW',
|
|
'TH',
|
|
'TU',
|
|
'GB',
|
|
'US'
|
|
);
|
|
|
|
if( ! in_array( $_POST['rcp_card_country'], $needs_zip ) ) {
|
|
$ret = false;
|
|
}
|
|
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
}
|