PageRenderTime 58ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/www/wp-content/plugins/ithemes-exchange/core-addons/transaction-methods/paypal-standard/init.php

https://github.com/ArzuA/gitwordpress
PHP | 1104 lines | 615 code | 176 blank | 313 comment | 94 complexity | 048603196a957669498c747ba02d0fc3 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * Hooks for PayPal Standard (insecure) add-on
  4. *
  5. * @package IT_Exchange
  6. * @since 0.2.0
  7. */
  8. if ( !defined( 'PAYPAL_LIVE_URL' ) )
  9. define( 'PAYPAL_LIVE_URL', 'https://www.paypal.com/' );
  10. if ( !defined( 'PAYPAL_PAYMENT_URL' ) )
  11. define( 'PAYPAL_PAYMENT_URL', 'https://www.paypal.com/cgi-bin/webscr' );
  12. /**
  13. * Mark this transaction method as okay to manually change transactions
  14. *
  15. * @since 1.9.2
  16. */
  17. add_filter( 'it_exchange_paypal-standard_transaction_status_can_be_manually_changed', '__return_true' );
  18. /**
  19. * Returns status options
  20. *
  21. * @since 1.9.2
  22. * @return array
  23. */
  24. function it_exchange_paypal_standard_get_default_status_options() {
  25. $options = array(
  26. 'Pending' => _x( 'Pending', 'Transaction Status', 'it-l10n-ithemes-exchange' ),
  27. 'Completed' => _x( 'Paid', 'Transaction Status', 'it-l10n-ithemes-exchange' ),
  28. 'Reversed' => _x( 'Reversed', 'Transaction Status', 'it-l10n-ithemes-exchange' ),
  29. 'Refunded' => _x( 'Refunded', 'Transaction Status', 'it-l10n-ithemes-exchange' ),
  30. 'Voided' => _x( 'Voided', 'Transaction Status', 'it-l10n-ithemes-exchange' ),
  31. );
  32. return $options;
  33. }
  34. add_filter( 'it_exchange_get_status_options_for_paypal-standard_transaction', 'it_exchange_paypal_standard_get_default_status_options' );
  35. /**
  36. * Outputs wizard settings for PayPal
  37. *
  38. * @since 0.4.0
  39. * @todo make this better, probably
  40. * @param object $form Current IT Form object
  41. * @return void
  42. */
  43. function it_exchange_print_paypal_standard_wizard_settings( $form ) {
  44. $IT_Exchange_PayPal_Standard_Add_On = new IT_Exchange_PayPal_Standard_Add_On();
  45. $settings = it_exchange_get_option( 'addon_paypal_standard', true );
  46. $form_values = ITUtility::merge_defaults( ITForm::get_post_data(), $settings );
  47. // Alter setting keys for wizard
  48. foreach( $form_values as $key => $value ) {
  49. $form_values['paypal-standard-' . $key] = $value;
  50. unset( $form_values[$key] );
  51. }
  52. $hide_if_js = it_exchange_is_addon_enabled( 'paypal-standard' ) ? '' : 'hide-if-js';
  53. ?>
  54. <div class="field paypal-standard-wizard <?php echo $hide_if_js; ?>">
  55. <?php if ( empty( $hide_if_js ) ) { ?>
  56. <input class="enable-paypal-standard" type="hidden" name="it-exchange-transaction-methods[]" value="paypal-standard" />
  57. <?php } ?>
  58. <?php $IT_Exchange_PayPal_Standard_Add_On->get_paypal_standard_payment_form_table( $form, $form_values ); ?>
  59. </div>
  60. <?php
  61. }
  62. add_action( 'it_exchange_print_paypal-standard_wizard_settings', 'it_exchange_print_paypal_standard_wizard_settings' );
  63. /**
  64. * Stripe URL to perform refunds
  65. *
  66. * @since 0.4.0
  67. *
  68. * @param string $url passed by WP filter.
  69. * @param string $url transaction URL
  70. */
  71. function it_exchange_refund_url_for_paypal_standard( $url ) {
  72. return 'https://paypal.com/';
  73. }
  74. add_filter( 'it_exchange_refund_url_for_paypal-standard', 'it_exchange_refund_url_for_paypal_standard' );
  75. /**
  76. * This proccesses a paypal transaction.
  77. *
  78. * @since 0.4.0
  79. *
  80. * @param string $status passed by WP filter.
  81. * @param object $transaction_object The transaction object
  82. */
  83. function it_exchange_process_paypal_standard_addon_transaction( $status, $transaction_object ) {
  84. if ( $status ) //if this has been modified as true already, return.
  85. return $status;
  86. if ( !empty( $_REQUEST['it-exchange-transaction-method'] ) && 'paypal-standard' === $_REQUEST['it-exchange-transaction-method'] ) {
  87. if ( !empty( $_REQUEST['tx'] ) ) //if PDT is enabled
  88. $transaction_id = $_REQUEST['tx'];
  89. else if ( !empty( $_REQUEST['txn_id'] ) ) //if PDT is not enabled
  90. $transaction_id = $_REQUEST['txn_id'];
  91. else
  92. $transaction_id = NULL;
  93. if ( !empty( $_REQUEST['cm'] ) )
  94. $transient_transaction_id = $_REQUEST['cm'];
  95. else
  96. $transient_transaction_id = NULL;
  97. if ( !empty( $_REQUEST['amt'] ) ) //if PDT is enabled
  98. $transaction_amount = $_REQUEST['amt'];
  99. else if ( !empty( $_REQUEST['mc_gross'] ) ) //if PDT is not enabled
  100. $transaction_amount = $_REQUEST['mc_gross'];
  101. else
  102. $transaction_amount = NULL;
  103. if ( !empty( $_REQUEST['st'] ) ) //if PDT is enabled
  104. $transaction_status = $_REQUEST['st'];
  105. else if ( !empty( $_REQUEST['payment_status'] ) ) //if PDT is not enabled
  106. $transaction_status = $_REQUEST['payment_status'];
  107. else
  108. $transaction_status = NULL;
  109. if ( !empty( $transaction_id ) && !empty( $transient_transaction_id ) && !empty( $transaction_amount ) && !empty( $transaction_status ) ) {
  110. try {
  111. $general_settings = it_exchange_get_option( 'settings_general' );
  112. $paypal_settings = it_exchange_get_option( 'addon_paypal_standard' );
  113. $it_exchange_customer = it_exchange_get_current_customer();
  114. if ( number_format( $transaction_amount, '2', '', '' ) != number_format( $transaction_object->total, '2', '', '' ) )
  115. throw new Exception( __( 'Error: Amount charged is not the same as the cart total!', 'it-l10n-ithemes-exchange' ) );
  116. //If the transient still exists, delete it and add the official transaction
  117. if ( it_exchange_get_transient_transaction( 'paypal-standard', $transient_transaction_id ) ) {
  118. it_exchange_delete_transient_transaction( 'paypal-standard', $transient_transaction_id );
  119. $ite_transaction_id = it_exchange_add_transaction( 'paypal-standard', $transaction_id, $transaction_status, $it_exchange_customer->id, $transaction_object );
  120. return $ite_transaction_id;
  121. }
  122. }
  123. catch ( Exception $e ) {
  124. it_exchange_add_message( 'error', $e->getMessage() );
  125. return false;
  126. }
  127. return it_exchange_paypal_standard_addon_get_ite_transaction_id( $transaction_id );
  128. }
  129. it_exchange_add_message( 'error', __( 'Unknown error while processing with PayPal. Please try again later.', 'it-l10n-ithemes-exchange' ) );
  130. }
  131. return false;
  132. }
  133. add_action( 'it_exchange_do_transaction_paypal-standard', 'it_exchange_process_paypal_standard_addon_transaction', 10, 2 );
  134. /**
  135. * Grab the paypal customer ID for a WP user
  136. *
  137. * @since 0.4.0
  138. *
  139. * @param integer $customer_id the WP customer ID
  140. * @return string
  141. */
  142. function it_exchange_get_paypal_standard_addon_customer_id( $customer_id ) {
  143. return get_user_meta( $customer_id, '_it_exchange_paypal_standard_id', true );
  144. }
  145. /**
  146. * Add the paypal customer email as user meta on a WP user
  147. *
  148. * @since 0.4.0
  149. *
  150. * @param integer $customer_id the WP user ID
  151. * @param integer $paypal_standard_id the paypal customer ID
  152. * @return boolean
  153. */
  154. function it_exchange_set_paypal_standard_addon_customer_id( $customer_id, $paypal_standard_id ) {
  155. return update_user_meta( $customer_id, '_it_exchange_paypal_standard_id', $paypal_standard_id );
  156. }
  157. /**
  158. * Grab the paypal customer email for a WP user
  159. *
  160. * @since 0.4.0
  161. *
  162. * @param integer $customer_id the WP customer ID
  163. * @return string
  164. */
  165. function it_exchange_get_paypal_standard_addon_customer_email( $customer_id ) {
  166. return get_user_meta( $customer_id, '_it_exchange_paypal_standard_email', true );
  167. }
  168. /**
  169. * Add the paypal customer email as user meta on a WP user
  170. *
  171. * @since 0.4.0
  172. *
  173. * @param integer $customer_id the WP user ID
  174. * @param string $paypal_standard_email the paypal customer email
  175. * @return boolean
  176. */
  177. function it_exchange_set_paypal_standard_addon_customer_email( $customer_id, $paypal_standard_email ) {
  178. return update_user_meta( $customer_id, '_it_exchange_paypal_standard_email', $paypal_standard_email );
  179. }
  180. /**
  181. * This is the function registered in the options array when it_exchange_register_addon was called for paypal
  182. *
  183. * It tells Exchange where to find the settings page
  184. *
  185. * @return void
  186. */
  187. function it_exchange_paypal_standard_settings_callback() {
  188. $IT_Exchange_PayPal_Standard_Add_On = new IT_Exchange_PayPal_Standard_Add_On();
  189. $IT_Exchange_PayPal_Standard_Add_On->print_settings_page();
  190. }
  191. /**
  192. * This is the function prints the payment form on the Wizard Settings screen
  193. *
  194. * @return void
  195. */
  196. function paypal_standard_print_wizard_settings( $form ) {
  197. $IT_Exchange_PayPal_Standard_Add_On = new IT_Exchange_PayPal_Standard_Add_On();
  198. $settings = it_exchange_get_option( 'addon_paypal_standard', true );
  199. ?>
  200. <div class="field paypal_standard-wizard hide-if-js">
  201. <?php $IT_Exchange_PayPal_Standard_Add_On->get_paypal_standard_payment_form_table( $form, $settings ); ?>
  202. </div>
  203. <?php
  204. }
  205. /**
  206. * Saves paypal settings when the Wizard is saved
  207. *
  208. * @since 0.4.0
  209. *
  210. * @return void
  211. */
  212. function it_exchange_save_paypal_standard_wizard_settings( $errors ) {
  213. if ( ! empty( $errors ) )
  214. return $errors;
  215. $IT_Exchange_PayPal_Standard_Add_On = new IT_Exchange_PayPal_Standard_Add_On();
  216. return $IT_Exchange_PayPal_Standard_Add_On->paypal_standard_save_wizard_settings();
  217. }
  218. add_action( 'it_exchange_save_paypal-standard_wizard_settings', 'it_exchange_save_paypal_standard_wizard_settings' );
  219. /**
  220. * Default settings for paypal_standard
  221. *
  222. * @since 0.4.0
  223. *
  224. * @param array $values
  225. * @return array
  226. */
  227. function it_exchange_paypal_standard_addon_default_settings( $values ) {
  228. $defaults = array(
  229. 'live-email-address' => '',
  230. 'purchase-button-label' => __( 'Pay with PayPal', 'it-l10n-ithemes-exchange' ),
  231. );
  232. $values = ITUtility::merge_defaults( $values, $defaults );
  233. return $values;
  234. }
  235. add_filter( 'it_storage_get_defaults_exchange_addon_paypal_standard', 'it_exchange_paypal_standard_addon_default_settings' );
  236. /**
  237. * Returns the button for making the PayPal faux payment button
  238. *
  239. * @since 0.4.19
  240. *
  241. * @param array $options
  242. * @return string HTML button
  243. */
  244. function it_exchange_paypal_standard_addon_make_payment_button( $options ) {
  245. if ( 0 >= it_exchange_get_cart_total( false ) )
  246. return;
  247. $general_settings = it_exchange_get_option( 'settings_general' );
  248. $paypal_settings = it_exchange_get_option( 'addon_paypal_standard' );
  249. $payment_form = '';
  250. if ( $paypal_email = $paypal_settings['live-email-address'] ) {
  251. $it_exchange_customer = it_exchange_get_current_customer();
  252. $payment_form .= '<form action="" method="post">';
  253. $payment_form .= '<input type="submit" class="it-exchange-paypal-standard-button" name="paypal_standard_purchase" value="' . $paypal_settings['purchase-button-label'] .'" />';
  254. $payment_form .= '</form>';
  255. }
  256. return $payment_form;
  257. }
  258. add_filter( 'it_exchange_get_paypal-standard_make_payment_button', 'it_exchange_paypal_standard_addon_make_payment_button', 10, 2 );
  259. /**
  260. * Process the faux PayPal Standard form
  261. *
  262. * @since 0.4.19
  263. *
  264. * @param array $options
  265. * @return string HTML button
  266. */
  267. function it_exchange_process_paypal_standard_form() {
  268. $paypal_settings = it_exchange_get_option( 'addon_paypal_standard' );
  269. if ( ! empty( $_REQUEST['paypal_standard_purchase'] ) ) {
  270. if ( $paypal_email = $paypal_settings['live-email-address'] ) {
  271. $it_exchange_customer = it_exchange_get_current_customer();
  272. $temp_id = it_exchange_create_unique_hash();
  273. $transaction_object = it_exchange_generate_transaction_object();
  274. it_exchange_add_transient_transaction( 'paypal-standard', $temp_id, $it_exchange_customer->id, $transaction_object );
  275. wp_redirect( it_exchange_paypal_standard_addon_get_payment_url( $temp_id ) );
  276. } else {
  277. it_exchange_add_message( 'error', __( 'Error processing PayPal form. Missing valid PayPal account.', 'it-l10n-ithemes-exchange' ) );
  278. wp_redirect( it_exchange_get_page_url( 'checkout' ) );
  279. }
  280. }
  281. }
  282. add_action( 'template_redirect', 'it_exchange_process_paypal_standard_form', 11 );
  283. /**
  284. * Returns the button for making the PayPal real payment button
  285. *
  286. * @since 0.4.19
  287. *
  288. * @param string $temp_id Temporary ID we reference late with IPN
  289. * @return string HTML button
  290. */
  291. function it_exchange_paypal_standard_addon_get_payment_url( $temp_id ) {
  292. if ( 0 >= it_exchange_get_cart_total( false ) )
  293. return;
  294. $general_settings = it_exchange_get_option( 'settings_general' );
  295. $paypal_settings = it_exchange_get_option( 'addon_paypal_standard' );
  296. $paypal_payment_url = '';
  297. if ( $paypal_email = $paypal_settings['live-email-address'] ) {
  298. $subscription = false;
  299. $it_exchange_customer = it_exchange_get_current_customer();
  300. remove_filter( 'the_title', 'wptexturize' ); // remove this because it screws up the product titles in PayPal
  301. if ( 1 === it_exchange_get_cart_products_count() ) {
  302. $cart = it_exchange_get_cart_products();
  303. foreach( $cart as $product ) {
  304. if ( it_exchange_product_supports_feature( $product['product_id'], 'recurring-payments', array( 'setting' => 'auto-renew' ) ) ) {
  305. if ( it_exchange_product_has_feature( $product['product_id'], 'recurring-payments', array( 'setting' => 'auto-renew' ) ) ) {
  306. $time = it_exchange_get_product_feature( $product['product_id'], 'recurring-payments', array( 'setting' => 'time' ) );
  307. switch( $time ) {
  308. case 'yearly':
  309. $unit = 'Y';
  310. break;
  311. case 'monthly':
  312. default:
  313. $unit = 'M';
  314. break;
  315. }
  316. $unit = apply_filters( 'it_exchange_paypal-standard_subscription_unit', $unit, $time );
  317. $duration = apply_filters( 'it_exchange_paypal-standard_subscription_duration', 1, $time );
  318. $subscription = true;
  319. }
  320. }
  321. }
  322. }
  323. if ( $subscription ) {
  324. //https://developer.paypal.com/webapps/developer/docs/classic/paypal-payments-standard/integration-guide/Appx_websitestandard_htmlvariables/#id08A6HI00JQU
  325. //a1, t1, p1 are for the first trial periods which is not supported with the Recurring Payments add-on
  326. //a2, t2, p2 are for the second trial period, which is not supported with the Recurring Payments add-on
  327. //a3, t3, p3 are required for the actual subscription details
  328. $paypal_args = array(
  329. 'cmd' => '_xclick-subscriptions',
  330. 'a3' => number_format( it_exchange_get_cart_total( false ), 2, '.', '' ), //Regular subscription price.
  331. 'p3' => $duration, //Subscription duration. Specify an integer value in the allowable range for the units of duration that you specify with t3.
  332. 't3' => $unit, //Regular subscription units of duration. (D, W, M, Y) -- we only use M,Y by default
  333. 'src' => 1, //Recurring payments.
  334. );
  335. } else {
  336. $paypal_args = array (
  337. 'cmd' => '_xclick',
  338. 'amount' => number_format( it_exchange_get_cart_total( false ), 2, '.', '' ),
  339. 'quantity' => '1',
  340. );
  341. }
  342. $query = array(
  343. 'business' => $paypal_email,
  344. 'item_name' => strip_tags( it_exchange_get_cart_description() ),
  345. 'return' => add_query_arg( 'it-exchange-transaction-method', 'paypal-standard', it_exchange_get_page_url( 'transaction' ) ),
  346. 'currency_code' => $general_settings['default-currency'],
  347. 'notify_url' => get_site_url() . '/?' . it_exchange_get_webhook( 'paypal-standard' ) . '=1',
  348. 'no_note' => '1',
  349. 'no_shipping' => '1',
  350. 'shipping' => '0',
  351. 'email' => $it_exchange_customer->data->user_email,
  352. 'rm' => '2',
  353. 'cancel_return' => it_exchange_get_page_url( 'cart' ),
  354. 'custom' => $temp_id,
  355. );
  356. $query = array_merge( $paypal_args, $query );
  357. $query = apply_filters( 'it_exchange_paypal_standad_query', $query );
  358. $paypal_payment_url = PAYPAL_PAYMENT_URL . '?' . http_build_query( $query );
  359. } else {
  360. it_exchange_add_message( 'error', __( 'ERROR: Invalid PayPal Setup' ) );
  361. $paypal_payment_url = it_exchange_get_page_url( 'cart' );
  362. }
  363. return $paypal_payment_url;
  364. }
  365. /**
  366. * Adds the paypal webhook to the global array of keys to listen for
  367. *
  368. * @since 0.4.0
  369. *
  370. * @param array $webhooks existing
  371. * @return array
  372. */
  373. function it_exchange_paypal_standard_addon_register_webhook() {
  374. $key = 'paypal-standard';
  375. $param = apply_filters( 'it_exchange_paypal-standard_webhook', 'it_exchange_paypal-standard' );
  376. it_exchange_register_webhook( $key, $param );
  377. }
  378. add_filter( 'init', 'it_exchange_paypal_standard_addon_register_webhook' );
  379. /**
  380. * Processes webhooks for PayPal Web Standard
  381. *
  382. * @since 0.4.0
  383. * @todo actually handle the exceptions
  384. *
  385. * @param array $request really just passing $_REQUEST
  386. */
  387. function it_exchange_paypal_standard_addon_process_webhook( $request ) {
  388. $general_settings = it_exchange_get_option( 'settings_general' );
  389. $settings = it_exchange_get_option( 'addon_paypal_standard' );
  390. $subscriber_id = !empty( $request['subscr_id'] ) ? $request['subscr_id'] : false;
  391. $subscriber_id = !empty( $request['recurring_payment_id'] ) ? $request['recurring_payment_id'] : $subscriber_id;
  392. if ( !empty( $request['txn_type'] ) ) {
  393. if ( !empty( $request['transaction_subject'] ) && $transient_data = it_exchange_get_transient_transaction( 'paypal-standard', $request['transaction_subject'] ) ) {
  394. it_exchange_delete_transient_transaction( 'paypal-standard', $request['transaction_subject'] );
  395. $ite_transaction_id = it_exchange_add_transaction( 'paypal-standard', $request['txn_id'], $request['payment_status'], $transient_data['customer_id'], $transient_data['transaction_object'] );
  396. return $ite_transaction_id;
  397. }
  398. switch( $request['txn_type'] ) {
  399. case 'web_accept':
  400. switch( strtolower( $request['payment_status'] ) ) {
  401. case 'completed' :
  402. it_exchange_paypal_standard_addon_update_transaction_status( $request['txn_id'], $request['payment_status'] );
  403. break;
  404. case 'reversed' :
  405. it_exchange_paypal_standard_addon_update_transaction_status( $request['parent_txn_id'], $request['reason_code'] );
  406. break;
  407. }
  408. break;
  409. case 'subscr_payment':
  410. switch( strtolower( $request['payment_status'] ) ) {
  411. case 'completed' :
  412. if ( !it_exchange_paypal_standard_addon_update_transaction_status( $request['txn_id'], $request['payment_status'] ) ) {
  413. //If the transaction isn't found, we've got a new payment
  414. it_exchange_paypal_standard_addon_add_child_transaction( $request['txn_id'], $request['payment_status'], $subscriber_id, $request['mc_gross'] );
  415. } else {
  416. //If it is found, make sure the subscriber ID is attached to it
  417. it_exchange_paypal_standard_addon_update_subscriber_id( $request['txn_id'], $subscriber_id );
  418. }
  419. it_exchange_paypal_standard_addon_update_subscriber_status( $subscriber_id, 'active' );
  420. break;
  421. }
  422. break;
  423. case 'subscr_signup':
  424. it_exchange_paypal_standard_addon_update_subscriber_status( $subscriber_id, 'active' );
  425. break;
  426. case 'recurring_payment_suspended':
  427. it_exchange_paypal_standard_addon_update_subscriber_status( $subscriber_id, 'suspended' );
  428. break;
  429. case 'subscr_cancel':
  430. it_exchange_paypal_standard_addon_update_subscriber_status( $subscriber_id, 'cancelled' );
  431. break;
  432. case 'subscr_eot':
  433. it_exchange_paypal_standard_addon_update_subscriber_status( $subscriber_id, 'deactivated' );
  434. break;
  435. }
  436. } else {
  437. //These IPNs don't have txn_types, why PayPal!? WHY!?
  438. if ( !empty( $request['reason_code'] ) ) {
  439. switch( $request['reason_code'] ) {
  440. case 'refund' :
  441. it_exchange_paypal_standard_addon_update_transaction_status( $request['parent_txn_id'], $request['payment_status'] );
  442. it_exchange_paypal_standard_addon_add_refund_to_transaction( $request['parent_txn_id'], $request['mc_gross'] );
  443. if ( $subscriber_id )
  444. it_exchange_paypal_standard_addon_update_subscriber_status( $subscriber_id, 'refunded' );
  445. break;
  446. }
  447. }
  448. }
  449. }
  450. add_action( 'it_exchange_webhook_it_exchange_paypal-standard', 'it_exchange_paypal_standard_addon_process_webhook' );
  451. /**
  452. * Gets iThemes Exchange's Transaction ID from PayPal Standard's Transaction ID
  453. *
  454. * @since 0.4.19
  455. *
  456. * @param integer $paypal_standard_id id of paypal transaction
  457. * @return integer iTheme Exchange's Transaction ID
  458. */
  459. function it_exchange_paypal_standard_addon_get_ite_transaction_id( $paypal_standard_id ) {
  460. $transactions = it_exchange_paypal_standard_addon_get_transaction_id( $paypal_standard_id );
  461. foreach( $transactions as $transaction ) { //really only one
  462. return $transaction->ID;
  463. }
  464. }
  465. /**
  466. * Grab a transaction from the paypal transaction ID
  467. *
  468. * @since 0.4.0
  469. *
  470. * @param integer $paypal_standard_id id of paypal transaction
  471. * @return transaction object
  472. */
  473. function it_exchange_paypal_standard_addon_get_transaction_id( $paypal_standard_id ) {
  474. $args = array(
  475. 'meta_key' => '_it_exchange_transaction_method_id',
  476. 'meta_value' => $paypal_standard_id,
  477. 'numberposts' => 1, //we should only have one, so limit to 1
  478. );
  479. return it_exchange_get_transactions( $args );
  480. }
  481. /**
  482. * Grab a transaction from the paypal transaction ID
  483. *
  484. * @since 0.4.0
  485. *
  486. * @param integer $paypal_standard_id id of paypal transaction
  487. * @return transaction object
  488. */
  489. function it_exchange_paypal_standard_addon_get_transaction_id_by_subscriber_id( $subscriber_id ) {
  490. $args = array(
  491. 'meta_key' => '_it_exchange_transaction_subscriber_id',
  492. 'meta_value' => $subscriber_id,
  493. 'numberposts' => 1, //we should only have one, so limit to 1
  494. );
  495. return it_exchange_get_transactions( $args );
  496. }
  497. /**
  498. * Updates a paypals transaction status based on paypal ID
  499. *
  500. * @since 0.4.0
  501. *
  502. * @param integer $paypal_standard_id id of paypal transaction
  503. * @param string $new_status new status
  504. * @return bool
  505. */
  506. function it_exchange_paypal_standard_addon_update_transaction_status( $paypal_standard_id, $new_status ) {
  507. $transactions = it_exchange_paypal_standard_addon_get_transaction_id( $paypal_standard_id );
  508. foreach( $transactions as $transaction ) { //really only one
  509. $current_status = it_exchange_get_transaction_status( $transaction );
  510. if ( $new_status !== $current_status )
  511. it_exchange_update_transaction_status( $transaction, $new_status );
  512. return true;
  513. }
  514. return false;
  515. }
  516. /**
  517. * Add a new transaction, really only used for subscription payments.
  518. * If a subscription pays again, we want to create another transaction in Exchange
  519. * This transaction needs to be linked to the parent transaction.
  520. *
  521. * @since 1.3.0
  522. *
  523. * @param integer $paypal_standard_id id of paypal transaction
  524. * @param string $payment_status new status
  525. * @param string $subscriber_id from PayPal (optional)
  526. * @return bool
  527. */
  528. function it_exchange_paypal_standard_addon_add_child_transaction( $paypal_standard_id, $payment_status, $subscriber_id=false, $amount ) {
  529. $transactions = it_exchange_paypal_standard_addon_get_transaction_id( $paypal_standard_id );
  530. if ( !empty( $transactions ) ) {
  531. //this transaction DOES exist, don't try to create a new one, just update the status
  532. it_exchange_paypal_standard_addon_update_transaction_status( $paypal_standard_id, $payment_status );
  533. } else {
  534. if ( !empty( $subscriber_id ) ) {
  535. $transactions = it_exchange_paypal_standard_addon_get_transaction_id_by_subscriber_id( $subscriber_id );
  536. foreach( $transactions as $transaction ) { //really only one
  537. $parent_tx_id = $transaction->ID;
  538. $customer_id = get_post_meta( $transaction->ID, '_it_exchange_customer_id', true );
  539. }
  540. } else {
  541. $parent_tx_id = false;
  542. $customer_id = false;
  543. }
  544. if ( $parent_tx_id && $customer_id ) {
  545. $transaction_object = new stdClass;
  546. $transaction_object->total = $amount;
  547. it_exchange_add_child_transaction( 'paypal-standard', $paypal_standard_id, $payment_status, $customer_id, $parent_tx_id, $transaction_object );
  548. return true;
  549. }
  550. }
  551. return false;
  552. }
  553. /**
  554. * Adds a refund to post_meta for a stripe transaction
  555. *
  556. * @since 0.4.0
  557. * @param string $paypal_standard_id PayPal Transaction ID
  558. * @param string $refund Refund Amount
  559. */
  560. function it_exchange_paypal_standard_addon_add_refund_to_transaction( $paypal_standard_id, $refund ) {
  561. $transactions = it_exchange_paypal_standard_addon_get_transaction_id( $paypal_standard_id );
  562. foreach( $transactions as $transaction ) { //really only one
  563. it_exchange_add_refund_to_transaction( $transaction, number_format( abs( $refund ), '2', '.', '' ) );
  564. }
  565. }
  566. /**
  567. * Updates a subscription ID to post_meta for a paypal transaction
  568. *
  569. * @since 1.3.0
  570. * @param string $paypal_standard_id PayPal Transaction ID
  571. * @param string $subscriber_id PayPal Subscriber ID
  572. */
  573. function it_exchange_paypal_standard_addon_update_subscriber_id( $paypal_standard_id, $subscriber_id ) {
  574. $transactions = it_exchange_paypal_standard_addon_get_transaction_id( $paypal_standard_id );
  575. foreach( $transactions as $transaction ) { //really only one
  576. do_action( 'it_exchange_update_transaction_subscription_id', $transaction, $subscriber_id );
  577. }
  578. }
  579. /**
  580. * Updates a subscription status to post_meta for a paypal transaction
  581. *
  582. * @since 1.3.0
  583. * @param string $subscriber_id PayPal Subscriber ID
  584. * @param string $status Status of Subscription
  585. */
  586. function it_exchange_paypal_standard_addon_update_subscriber_status( $subscriber_id, $status ) {
  587. $transactions = it_exchange_paypal_standard_addon_get_transaction_id_by_subscriber_id( $subscriber_id );
  588. foreach( $transactions as $transaction ) { //really only one
  589. // If the subscription has been cancelled/suspended and fully refunded, they need to be deactivated
  590. if ( !in_array( $status, array( 'active', 'deactivated' ) ) ) {
  591. if ( $transaction->has_refunds() && 0 === it_exchange_get_transaction_total( $transaction, false ) )
  592. $status = 'deactivated';
  593. if ( $transaction->has_children() ) {
  594. //Get the last child and make sure it hasn't been fully refunded
  595. $args = array(
  596. 'numberposts' => 1,
  597. 'order' => 'ASC',
  598. );
  599. $last_child_transaction = $transaction->get_children( $args );
  600. foreach( $last_child_transaction as $last_transaction ) { //really only one
  601. $last_transaction = it_exchange_get_transaction( $last_transaction );
  602. if ( $last_transaction->has_refunds() && 0 === it_exchange_get_transaction_total( $last_transaction, false ) )
  603. $status = 'deactivated';
  604. }
  605. }
  606. }
  607. do_action( 'it_exchange_update_transaction_subscription_status', $transaction, $subscriber_id, $status );
  608. }
  609. }
  610. /**
  611. * Gets the interpretted transaction status from valid paypal transaction statuses
  612. *
  613. * @since 0.4.0
  614. *
  615. * @param string $status the string of the paypal transaction
  616. * @return string translaction transaction status
  617. */
  618. function it_exchange_paypal_standard_addon_transaction_status_label( $status ) {
  619. switch ( strtolower( $status ) ) {
  620. case 'completed':
  621. case 'success':
  622. case 'canceled_reversal':
  623. case 'processed' :
  624. return __( 'Paid', 'it-l10n-ithemes-exchange' );
  625. case 'refunded':
  626. case 'refund':
  627. return __( 'Refund', 'it-l10n-ithemes-exchange' );
  628. case 'reversed':
  629. return __( 'Reversed', 'it-l10n-ithemes-exchange' );
  630. case 'buyer_complaint':
  631. return __( 'Buyer Complaint', 'it-l10n-ithemes-exchange' );
  632. case 'denied' :
  633. return __( 'Denied', 'it-l10n-ithemes-exchange' );
  634. case 'expired' :
  635. return __( 'Expired', 'it-l10n-ithemes-exchange' );
  636. case 'failed' :
  637. return __( 'Failed', 'it-l10n-ithemes-exchange' );
  638. case 'pending' :
  639. return __( 'Pending', 'it-l10n-ithemes-exchange' );
  640. case 'voided' :
  641. return __( 'Voided', 'it-l10n-ithemes-exchange' );
  642. default:
  643. return __( 'Unknown', 'it-l10n-ithemes-exchange' );
  644. }
  645. }
  646. add_filter( 'it_exchange_transaction_status_label_paypal-standard', 'it_exchange_paypal_standard_addon_transaction_status_label' );
  647. /**
  648. * Returns a boolean. Is this transaction a status that warrants delivery of any products attached to it?
  649. *
  650. * @since 0.4.2
  651. *
  652. * @param boolean $cleared passed in through WP filter. Ignored here.
  653. * @param object $transaction
  654. * @return boolean
  655. */
  656. function it_exchange_paypal_standard_transaction_is_cleared_for_delivery( $cleared, $transaction ) {
  657. $valid_stati = array(
  658. 'completed',
  659. 'success',
  660. 'canceled_reversal',
  661. 'processed',
  662. );
  663. return in_array( strtolower( it_exchange_get_transaction_status( $transaction ) ), $valid_stati );
  664. }
  665. add_filter( 'it_exchange_paypal-standard_transaction_is_cleared_for_delivery', 'it_exchange_paypal_standard_transaction_is_cleared_for_delivery', 10, 2 );
  666. /*
  667. * Returns the unsubscribe action for PayPal autorenewing payments
  668. *
  669. * @since 1.3.0
  670. *
  671. * @param string $output Should be an empty string
  672. * @param array $options Array of options passed from Recurring Payments add-on
  673. * @return string $output Unsubscribe action
  674. */
  675. function it_exchange_paypal_standard_unsubscribe_action( $output, $options ) {
  676. $paypal_settings = it_exchange_get_option( 'addon_paypal_standard' );
  677. $paypal_url = PAYPAL_PAYMENT_URL;
  678. $paypal_email = $paypal_settings['live-email-address'];
  679. $output = '<a class="button" href="' . $paypal_url . '?cmd=_subscr-find&alias=' . urlencode( $paypal_email ) . '">';
  680. $output .= $options['label'];
  681. $output .= '</a>';
  682. return $output;
  683. }
  684. add_filter( 'it_exchange_paypal-standard_unsubscribe_action', 'it_exchange_paypal_standard_unsubscribe_action', 10, 2 );
  685. /**
  686. * Output the Cancel URL for the Payments screen
  687. *
  688. * @since 1.3.1
  689. *
  690. * @param object $transaction iThemes Transaction object
  691. * @return void
  692. */
  693. function it_exchange_paypal_standard_after_payment_details_cancel_url( $transaction ) {
  694. $cart_object = get_post_meta( $transaction->ID, '_it_exchange_cart_object', true );
  695. foreach ( $cart_object->products as $product ) {
  696. $autorenews = $transaction->get_transaction_meta( 'subscription_autorenew_' . $product['product_id'], true );
  697. if ( $autorenews ) {
  698. $subscriber_id = $transaction->get_transaction_meta( 'subscriber_id', true );
  699. $status = $transaction->get_transaction_meta( 'subscriber_status', true );
  700. switch( $status ) {
  701. case 'deactivated':
  702. $output = __( 'Recurring payment has been deactivated', 'it-l10n-ithemes-exchange' );
  703. break;
  704. case 'cancelled':
  705. $output = __( 'Recurring payment has been cancelled', 'it-l10n-ithemes-exchange' );
  706. break;
  707. case 'suspended':
  708. $output = __( 'Recurring payment has been suspended', 'it-l10n-ithemes-exchange' );
  709. break;
  710. case 'active':
  711. default:
  712. $output = '<a href="' . PAYPAL_LIVE_URL . '">' . __( 'Cancel Recurring Payment', 'it-l10n-ithemes-exchange' ) . ' (' . __( 'Profile ID', 'it-l10n-ithemes-exchange' ) . ': ' . $subscriber_id . ')</a>';
  713. break;
  714. }
  715. ?>
  716. <div class="transaction-autorenews clearfix spacing-wrapper">
  717. <div class="recurring-payment-cancel-options left">
  718. <div class="recurring-payment-status-name"><?php echo $output; ?></div>
  719. </div>
  720. </div>
  721. <?php
  722. continue;
  723. }
  724. }
  725. }
  726. add_action( 'it_exchange_after_payment_details_cancel_url_for_paypal-standard', 'it_exchange_paypal_standard_after_payment_details_cancel_url' );
  727. /**
  728. * Convert old option keys to new option keys
  729. *
  730. * Our original option keys for this plugin were generating form field names 80+ chars in length
  731. *
  732. * @since 1.6.2
  733. *
  734. * @param array $options options as pulled from the DB
  735. * @param string $key the key for the options
  736. * @param boolean $break_cache was the flag to break cache passed?
  737. * @param boolean $merge_defaults was the flag to merge defaults passed?
  738. * @return array
  739. */
  740. function it_exchange_paypal_standard_convert_option_keys( $options, $key, $break_cache, $merge_defaults ) {
  741. if ( 'addon_paypal_standard' != $key )
  742. return $options;
  743. foreach( $options as $key => $value ) {
  744. if ( 'paypal-standard-' == substr( $key, 0, 16 ) && empty( $opitons[substr( $key, 16 )] ) ) {
  745. $options[substr( $key, 16 )] = $value;
  746. unset( $options[$key] );
  747. }
  748. }
  749. return $options;
  750. }
  751. add_filter( 'it_exchange_get_option', 'it_exchange_paypal_standard_convert_option_keys', 10, 4 );
  752. /**
  753. * Class for Stripe
  754. * @since 0.4.0
  755. */
  756. class IT_Exchange_PayPal_Standard_Add_On {
  757. /**
  758. * @var boolean $_is_admin true or false
  759. * @since 0.4.0
  760. */
  761. var $_is_admin;
  762. /**
  763. * @var string $_current_page Current $_GET['page'] value
  764. * @since 0.4.0
  765. */
  766. var $_current_page;
  767. /**
  768. * @var string $_current_add_on Current $_GET['add-on-settings'] value
  769. * @since 0.4.0
  770. */
  771. var $_current_add_on;
  772. /**
  773. * @var string $status_message will be displayed if not empty
  774. * @since 0.4.0
  775. */
  776. var $status_message;
  777. /**
  778. * @var string $error_message will be displayed if not empty
  779. * @since 0.4.0
  780. */
  781. var $error_message;
  782. /**
  783. * Class constructor
  784. *
  785. * Sets up the class.
  786. * @since 0.4.0
  787. * @return void
  788. */
  789. function IT_Exchange_PayPal_Standard_Add_On() {
  790. $this->_is_admin = is_admin();
  791. $this->_current_page = empty( $_GET['page'] ) ? false : $_GET['page'];
  792. $this->_current_add_on = empty( $_GET['add-on-settings'] ) ? false : $_GET['add-on-settings'];
  793. if ( ! empty( $_POST ) && $this->_is_admin && 'it-exchange-addons' == $this->_current_page && 'paypal-standard' == $this->_current_add_on ) {
  794. $this->save_settings();
  795. }
  796. }
  797. function print_settings_page() {
  798. $settings = it_exchange_get_option( 'addon_paypal_standard', true );
  799. $form_values = empty( $this->error_message ) ? $settings : ITForm::get_post_data();
  800. $form_options = array(
  801. 'id' => apply_filters( 'it_exchange_add_on_paypal-standard', 'it-exchange-add-on-paypal-standard-settings' ),
  802. 'enctype' => apply_filters( 'it_exchange_add_on_paypal-standard_settings_form_enctype', false ),
  803. 'action' => 'admin.php?page=it-exchange-addons&add-on-settings=paypal-standard',
  804. );
  805. $form = new ITForm( $form_values, array( 'prefix' => 'it-exchange-add-on-paypal_standard' ) );
  806. if ( ! empty ( $this->status_message ) )
  807. ITUtility::show_status_message( $this->status_message );
  808. if ( ! empty( $this->error_message ) )
  809. ITUtility::show_error_message( $this->error_message );
  810. ?>
  811. <div class="wrap">
  812. <?php ITUtility::screen_icon( 'it-exchange' ); ?>
  813. <h2><?php _e( 'PayPal Standard Settings - Basic', 'it-l10n-ithemes-exchange' ); ?></h2>
  814. <?php do_action( 'it_exchange_paypal-standard_settings_page_top' ); ?>
  815. <?php do_action( 'it_exchange_addon_settings_page_top' ); ?>
  816. <?php $form->start_form( $form_options, 'it-exchange-paypal-standard-settings' ); ?>
  817. <?php do_action( 'it_exchange_paypal-standard_settings_form_top' ); ?>
  818. <?php $this->get_paypal_standard_payment_form_table( $form, $form_values ); ?>
  819. <?php do_action( 'it_exchange_paypal-standard_settings_form_bottom' ); ?>
  820. <p class="submit">
  821. <?php $form->add_submit( 'submit', array( 'value' => __( 'Save Changes', 'it-l10n-ithemes-exchange' ), 'class' => 'button button-primary button-large' ) ); ?>
  822. </p>
  823. <?php $form->end_form(); ?>
  824. <?php do_action( 'it_exchange_paypal-standard_settings_page_bottom' ); ?>
  825. <?php do_action( 'it_exchange_addon_settings_page_bottom' ); ?>
  826. </div>
  827. <?php
  828. }
  829. function get_paypal_standard_payment_form_table( $form, $settings = array() ) {
  830. $general_settings = it_exchange_get_option( 'settings_general' );
  831. if ( ! empty( $_GET['page'] ) && 'it-exchange-setup' == $_GET['page'] ) : ?>
  832. <h3><?php _e( 'PayPal Standard - Basic (Fastest Setup)', 'it-l10n-ithemes-exchange' ); ?></h3>
  833. <?php endif;
  834. if ( !empty( $settings ) )
  835. foreach ( $settings as $key => $var )
  836. $form->set_option( $key, $var );
  837. ?>
  838. <div class="it-exchange-addon-settings it-exchange-paypal-addon-settings">
  839. <p>
  840. <?php _e( 'This is the simple and fast version to get PayPal setup for your store. You might use this version just to get your store going, but we highly suggest you switch to the PayPal Standard Secure option. To get PayPal set up for use with Exchange, you\'ll need to add the following information from your PayPal account.', 'it-l10n-ithemes-exchange' ); ?><br /><br />
  841. <?php _e( 'Video:', 'it-l10n-ithemes-exchange' ); ?>&nbsp;<a href="http://ithemes.com/tutorials/setting-up-paypal-standard-basic/" target="_blank"><?php _e( 'Setting Up PayPal Standard Basic', 'it-l10n-ithemes-exchange' ); ?></a>
  842. </p>
  843. <p><?php _e( 'Don\'t have a PayPal account yet?', 'it-l10n-ithemes-exchange' ); ?> <a href="http://paypal.com" target="_blank"><?php _e( 'Go set one up here', 'it-l10n-ithemes-exchange' ); ?></a>.</p>
  844. <h4><?php _e( 'What is your PayPal email address?', 'it-l10n-ithemes-exchange' ); ?></h4>
  845. <p>
  846. <label for="live-email-address"><?php _e( 'PayPal Email Address', 'it-l10n-ithemes-exchange' ); ?> <span class="tip" title="<?php _e( 'We need this to tie payments to your account.', 'it-l10n-ithemes-exchange' ); ?>">i</span></label>
  847. <?php
  848. if ( ! empty( $_GET['page'] ) && 'it-exchange-setup' == $_GET['page'] )
  849. $form->add_text_box( 'paypal-standard-live-email-address' );
  850. else
  851. $form->add_text_box( 'live-email-address' );
  852. ?>
  853. </p>
  854. <p>
  855. <label for="purchase-button-label"><?php _e( 'Purchase Button Label', 'it-l10n-ithemes-exchange' ); ?> <span class="tip" title="<?php _e( 'This is the text inside the button your customers will press to purchase with PayPal Standard', 'it-l10n-ithemes-exchange' ); ?>">i</span></label>
  856. <?php
  857. if ( ! empty( $_GET['page'] ) && 'it-exchange-setup' == $_GET['page'] )
  858. $form->add_text_box( 'paypal-standard-purchase-button-label' );
  859. else
  860. $form->add_text_box( 'purchase-button-label' );
  861. ?>
  862. </p>
  863. </div>
  864. <?php
  865. }
  866. /**
  867. * Save settings
  868. *
  869. * @since 0.4.0
  870. * @return void
  871. */
  872. function save_settings() {
  873. $defaults = it_exchange_get_option( 'addon_paypal_standard' );
  874. $new_values = wp_parse_args( ITForm::get_post_data(), $defaults );
  875. // Check nonce
  876. if ( ! wp_verify_nonce( $_POST['_wpnonce'], 'it-exchange-paypal-standard-settings' ) ) {
  877. $this->error_message = __( 'Error. Please try again', 'it-l10n-ithemes-exchange' );
  878. return;
  879. }
  880. $errors = apply_filters( 'it_exchange_add_on_paypal_standard_validate_settings', $this->get_form_errors( $new_values ), $new_values );
  881. if ( ! $errors && it_exchange_save_option( 'addon_paypal_standard', $new_values ) ) {
  882. ITUtility::show_status_message( __( 'Settings saved.', 'it-l10n-ithemes-exchange' ) );
  883. } else if ( $errors ) {
  884. $errors = implode( '<br />', $errors );
  885. $this->error_message = $errors;
  886. } else {
  887. $this->status_message = __( 'Settings not saved.', 'it-l10n-ithemes-exchange' );
  888. }
  889. do_action( 'it_exchange_save_add_on_settings_paypal-standard' );
  890. }
  891. function paypal_standard_save_wizard_settings() {
  892. if ( empty( $_REQUEST['it_exchange_settings-wizard-submitted'] ) )
  893. return;
  894. $paypal_standard_settings = array();
  895. $fields = array(
  896. 'live-email-address',
  897. 'purchase-button-label',
  898. );
  899. $default_wizard_paypal_standard_settings = apply_filters( 'default_wizard_paypal-standard_settings', $fields );
  900. foreach( $default_wizard_paypal_standard_settings as $var ) {
  901. if ( isset( $_REQUEST['it_exchange_settings-paypal-standard-' . $var] ) ) {
  902. $paypal_standard_settings[$var] = $_REQUEST['it_exchange_settings-paypal-standard-' . $var];
  903. }
  904. }
  905. $settings = wp_parse_args( $paypal_standard_settings, it_exchange_get_option( 'addon_paypal_standard' ) );
  906. if ( $error_msg = $this->get_form_errors( $settings ) ) {
  907. return $error_msg;
  908. } else {
  909. it_exchange_save_option( 'addon_paypal_standard', $settings );
  910. $this->status_message = __( 'Settings Saved.', 'it-l10n-ithemes-exchange' );
  911. }
  912. return;
  913. }
  914. /**
  915. * Validates for values
  916. *
  917. * Returns string of errors if anything is invalid
  918. *
  919. * @since 0.4.0
  920. * @return void
  921. */
  922. function get_form_errors( $values ) {
  923. $errors = array();
  924. if ( empty( $values['live-email-address'] ) )
  925. $errors[] = __( 'Please include your PayPal Email Address', 'it-l10n-ithemes-exchange' );
  926. return $errors;
  927. }
  928. }