Passed
Push — develop ( 947370...c7f45f )
by Reüel
04:28
created

Extension::subscription_source_url()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 2
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * Extension
4
 *
5
 * @author    Pronamic <[email protected]>
6
 * @copyright 2005-2018 Pronamic
7
 * @license   GPL-3.0-or-later
8
 * @package   Pronamic\WordPress\Pay\Extensions\MemberPress
9
 */
10
11
namespace Pronamic\WordPress\Pay\Extensions\MemberPress;
12
13
use MeprOptions;
14
use MeprProduct;
15
use MeprTransaction;
16
use MeprSubscription;
17
use Pronamic\WordPress\Pay\Core\Statuses;
18
use Pronamic\WordPress\Pay\Payments\Payment;
19
use Pronamic\WordPress\Pay\Subscriptions\Subscription;
20
21
/**
22
 * WordPress pay MemberPress extension
23
 *
24
 * @author  Remco Tolsma
25
 * @version 2.0.0
26
 * @since   1.0.0
27
 */
28
class Extension {
29
	/**
30
	 * The slug of this addon
31
	 *
32
	 * @var string
33
	 */
34
	const SLUG = 'memberpress';
35
36
	/**
37
	 * Bootstrap
38
	 */
39
	public static function bootstrap() {
40
		new self();
41
	}
42
43
	/**
44
	 * Constructs and initializes the MemberPress extension.
45
	 */
46
	public function __construct() {
47
		// @see https://gitlab.com/pronamic/memberpress/blob/1.2.4/app/lib/MeprGatewayFactory.php#L48-50
48
		add_filter( 'mepr-gateway-paths', array( $this, 'gateway_paths' ) );
49
50
		add_filter( 'pronamic_payment_redirect_url_' . self::SLUG, array( __CLASS__, 'redirect_url' ), 10, 2 );
51
		add_action( 'pronamic_payment_status_update_' . self::SLUG, array( __CLASS__, 'status_update' ), 10, 1 );
52
53
		add_filter( 'pronamic_payment_source_text_' . self::SLUG, array( __CLASS__, 'source_text' ), 10, 2 );
54
		add_filter( 'pronamic_payment_source_description_' . self::SLUG, array( __CLASS__, 'source_description' ), 10, 2 );
55
		add_filter( 'pronamic_payment_source_url_' . self::SLUG, array( __CLASS__, 'source_url' ), 10, 2 );
56
		add_filter( 'pronamic_subscription_source_text_' . self::SLUG, array( __CLASS__, 'subscription_source_text' ), 10, 2 );
57
		add_filter( 'pronamic_subscription_source_description_' . self::SLUG, array( __CLASS__, 'subscription_source_description' ), 10, 2 );
58
		add_filter( 'pronamic_subscription_source_url_' . self::SLUG, array( __CLASS__, 'subscription_source_url' ), 10, 2 );
59
60
		add_action( 'mepr_subscription_pre_delete', array( $this, 'subscription_pre_delete' ), 10, 1 );
61
62
		add_action( 'mepr_subscription_transition_status', array( $this, 'memberpress_subscription_transition_status' ), 10, 3 );
63
	}
64
65
	/**
66
	 * Gateway paths.
67
	 *
68
	 * @see https://gitlab.com/pronamic/memberpress/blob/1.2.4/app/lib/MeprGatewayFactory.php#L48-50
69
	 *
70
	 * @param array $paths Array with gateway paths.
71
	 * @return array
72
	 */
73
	public function gateway_paths( $paths ) {
74
		$paths[] = dirname( __FILE__ ) . '/../gateways/';
75
76
		return $paths;
77
	}
78
79
	/**
80
	 * Payment redirect URL filter.
81
	 *
82
	 * @since 1.0.1
83
	 *
84
	 * @param string  $url     Payment redirect URL.
85
	 * @param Payment $payment Payment to redirect for.
86
	 *
87
	 * @return string
88
	 */
89
	public static function redirect_url( $url, Payment $payment ) {
90
		global $transaction;
91
92
		$transaction_id = $payment->get_source_id();
93
94
		$transaction = new MeprTransaction( $transaction_id );
95
96
		switch ( $payment->get_status() ) {
97
			case Statuses::CANCELLED:
98
			case Statuses::EXPIRED:
99
			case Statuses::FAILURE:
100
				$product = $transaction->product();
101
102
				$url = add_query_arg(
103
					array(
104
						'action'   => 'payment_form',
105
						'txn'      => $transaction->trans_num,
106
						'_wpnonce' => wp_create_nonce( 'mepr_payment_form' ),
107
					),
108
					$product->url()
109
				);
110
111
				break;
112
			case Statuses::SUCCESS:
113
				// @see https://gitlab.com/pronamic/memberpress/blob/1.2.4/app/models/MeprOptions.php#L768-782
114
				$mepr_options = MeprOptions::fetch();
115
116
				$product         = new MeprProduct( $transaction->product_id );
117
				$sanitized_title = sanitize_title( $product->post_title );
118
119
				$args = array(
120
					'membership_id' => $product->ID,
121
					'membership'    => $sanitized_title,
122
					'trans_num'     => $transaction->trans_num,
123
				);
124
125
				$url = $mepr_options->thankyou_page_url( http_build_query( $args ) );
126
127
				break;
128
			case Statuses::OPEN:
129
			default:
130
				break;
131
		}
132
133
		return $url;
134
	}
135
136
	/**
137
	 * Update lead status of the specified payment.
138
	 *
139
	 * @see https://github.com/Charitable/Charitable/blob/1.1.4/includes/gateways/class-charitable-gateway-paypal.php#L229-L357
140
	 *
141
	 * @param Payment $payment The payment whose status is updated.
142
	 */
143
	public static function status_update( Payment $payment ) {
144
		$transaction_id = $payment->get_source_id();
145
146
		$transaction = new MeprTransaction( $transaction_id );
147
148
		if ( $payment->get_recurring() ) {
149
			$subscription = $transaction->subscription();
150
151
			if ( empty( $subscription ) || empty( $subscription->id ) ) {
152
				$subscription_id = $payment->get_subscription()->get_source_id();
153
154
				$subscription = new MeprSubscription( $subscription_id );
155
			}
156
157
			// Same source ID and first transaction ID for recurring payment means we need to add a new transaction.
158
			if ( $payment->get_source_id() === $subscription->id ) {
159
				// First transaction.
160
				$first_txn = $subscription->first_txn();
161
162
				if ( false === $first_txn || ! ( $first_txn instanceof MeprTransaction ) ) {
163
					$first_txn             = new MeprTransaction();
164
					$first_txn->user_id    = $subscription->user_id;
165
					$first_txn->product_id = $subscription->product_id;
166
					$first_txn->coupon_id  = $subscription->coupon_id;
167
					$first_txn->gateway    = null;
1 ignored issue
show
Bug Best Practice introduced by
The property gateway does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
168
				}
169
170
				// Transaction number.
171
				$trans_num = $payment->get_transaction_id();
172
173
				if ( empty( $trans_num ) ) {
174
					$trans_num = uniqid();
175
				}
176
177
				// New transaction.
178
				$transaction                  = new MeprTransaction();
179
				$transaction->created_at      = $payment->post->post_date_gmt;
1 ignored issue
show
Bug Best Practice introduced by
The property created_at does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
180
				$transaction->user_id         = $first_txn->user_id;
181
				$transaction->product_id      = $first_txn->product_id;
182
				$transaction->coupon_id       = $first_txn->coupon_id;
183
				$transaction->gateway         = $first_txn->gateway;
184
				$transaction->trans_num       = $trans_num;
1 ignored issue
show
Bug Best Practice introduced by
The property trans_num does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
185
				$transaction->txn_type        = MeprTransaction::$payment_str;
1 ignored issue
show
Bug Best Practice introduced by
The property txn_type does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
186
				$transaction->status          = MeprTransaction::$pending_str;
1 ignored issue
show
Bug Best Practice introduced by
The property status does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
187
				$transaction->subscription_id = $subscription->id;
1 ignored issue
show
Bug Best Practice introduced by
The property subscription_id does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
188
189
				$transaction->set_gross( $payment->get_amount()->get_amount() );
190
191
				$transaction->store();
192
193
				// Set source ID.
194
				$payment->set_meta( 'source_id', $transaction->id );
195
196
				$payment->source_id = $transaction->id;
197
			}
198
		}
199
200
		$should_update = ! MemberPress::transaction_has_status( $transaction, array(
201
			MeprTransaction::$failed_str,
202
			MeprTransaction::$complete_str,
203
		) );
204
205
		if ( $should_update ) {
206
			$gateway = new Gateway();
207
208
			$gateway->mp_txn = $transaction;
209
210
			switch ( $payment->get_status() ) {
211
				case Statuses::CANCELLED:
212
				case Statuses::EXPIRED:
213
				case Statuses::FAILURE:
214
					$gateway->record_payment_failure();
215
216
					break;
217
				case Statuses::SUCCESS:
218
					if ( $payment->get_recurring() ) {
219
						$gateway->record_subscription_payment();
220
					} else {
221
						$gateway->record_payment();
222
					}
223
224
					break;
225
				case Statuses::OPEN:
226
				default:
227
					break;
228
			}
229
		}
230
	}
231
232
	/**
233
	 * Subscription deleted.
234
	 *
235
	 * @param int $subscription_id MemberPress subscription id.
236
	 */
237
	public function subscription_pre_delete( $subscription_id ) {
238
		$subscription = get_pronamic_subscription_by_meta( '_pronamic_subscription_source_id', $subscription_id );
239
240
		if ( ! $subscription ) {
241
			return;
242
		}
243
244
		// Add note.
245
		$note = sprintf(
246
			/* translators: %s: MemberPress */
247
			__( '%s subscription deleted.', 'pronamic_ideal' ),
248
			__( 'MemberPress', 'pronamic_ideal' )
249
		);
250
251
		$subscription->add_note( $note );
252
253
		// The status of canceled or completed subscriptions will not be changed automatically.
254
		if ( ! in_array( $subscription->get_status(), array( Statuses::CANCELLED, Statuses::COMPLETED ), true ) ) {
255
			$subscription->set_status( Statuses::CANCELLED );
256
257
			$subscription->save();
258
		}
259
	}
260
261
	/**
262
	 * Source text.
263
	 *
264
	 * @param string  $text    Source text.
265
	 * @param Payment $payment Payment to create the source text for.
266
	 *
267
	 * @return string
268
	 */
269
	public static function source_text( $text, Payment $payment ) {
270
		$text = __( 'MemberPress', 'pronamic_ideal' ) . '<br />';
271
272
		$text .= sprintf(
273
			'<a href="%s">%s</a>',
274
			add_query_arg( array(
275
				'page'   => 'memberpress-trans',
276
				'action' => 'edit',
277
				'id'     => $payment->source_id,
278
			), admin_url( 'admin.php' ) ),
279
			/* translators: %s: payment source id */
280
			sprintf( __( 'Transaction %s', 'pronamic_ideal' ), $payment->source_id )
281
		);
282
283
		return $text;
284
	}
285
286
	/**
287
	 * Subscription source text.
288
	 *
289
	 * @param string       $text         Source text.
290
	 * @param Subscription $subscription Subscription to create the source text for.
291
	 *
292
	 * @return string
293
	 */
294
	public static function subscription_source_text( $text, Subscription $subscription ) {
295
		$text = __( 'MemberPress', 'pronamic_ideal' ) . '<br />';
296
297
		$text .= sprintf(
298
			'<a href="%s">%s</a>',
299
			add_query_arg( array(
300
				'page'         => 'memberpress-subscriptions',
301
				'subscription' => $subscription->source_id,
302
			), admin_url( 'admin.php' ) ),
303
			/* translators: %s: payment source id */
304
			sprintf( __( 'Subscription %s', 'pronamic_ideal' ), $subscription->source_id )
305
		);
306
307
		return $text;
308
	}
309
310
	/**
311
	 * Source description.
312
	 *
313
	 * @param string  $description Description.
314
	 * @param Payment $payment     Payment to create the description for.
315
	 *
316
	 * @return string
317
	 */
318
	public static function source_description( $description, Payment $payment ) {
319
		return __( 'MemberPress Transaction', 'pronamic_ideal' );
320
	}
321
322
	/**
323
	 * Subscription source description.
324
	 *
325
	 * @param string       $description  Description.
326
	 * @param Subscription $subscription Subscription to create the description for.
327
	 *
328
	 * @return string
329
	 */
330
	public static function subscription_source_description( $description, Subscription $subscription ) {
331
		return __( 'MemberPress Subscription', 'pronamic_ideal' );
332
	}
333
334
	/**
335
	 * Source URL.
336
	 *
337
	 * @param string  $url     URL.
338
	 * @param Payment $payment The payment to create the source URL for.
339
	 *
340
	 * @return string
341
	 */
342
	public static function source_url( $url, Payment $payment ) {
343
		$url = add_query_arg( array(
344
			'page'   => 'memberpress-trans',
345
			'action' => 'edit',
346
			'id'     => $payment->source_id,
347
		), admin_url( 'admin.php' ) );
348
349
		return $url;
350
	}
351
352
	/**
353
	 * Subscription source URL.
354
	 *
355
	 * @param string       $url          URL.
356
	 * @param Subscription $subscription Subscription.
357
	 *
358
	 * @return string
359
	 */
360
	public static function subscription_source_url( $url, Subscription $subscription ) {
361
		$url = add_query_arg( array(
362
			'page'         => 'memberpress-subscriptions',
363
			'subscription' => $subscription->source_id,
364
		), admin_url( 'admin.php' ) );
365
366
		return $url;
367
	}
368
369
	/**
370
	 * MemberPress update subscription.
371
	 *
372
	 * @link https://github.com/wp-premium/memberpress-basic/blob/1.3.18/app/controllers/MeprSubscriptionsCtrl.php#L92-L111
373
	 * @link https://github.com/wp-premium/memberpress-basic/blob/1.3.18/app/models/MeprSubscription.php#L100-L123
374
	 * @link https://github.com/wp-premium/memberpress-basic/blob/1.3.18/app/models/MeprSubscription.php#L112
375
	 *
376
	 * @param string           $status_old               Old status identifier.
377
	 * @param string           $status_new               New status identifier.
378
	 * @param MeprSubscription $memberpress_subscription MemberPress subscription object.
379
	 */
380
	public function memberpress_subscription_transition_status( $status_old, $status_new, $memberpress_subscription ) {
381
		$subscription = get_pronamic_subscription_by_meta( '_pronamic_subscription_source_id', $memberpress_subscription->id );
382
383
		if ( empty( $subscription ) ) {
384
			return;
385
		}
386
387
		$status = SubscriptionStatuses::transform( $status_new );
388
389
		$subscription->set_status( $status );
390
391
		$subscription->save();
392
	}
393
}
394