PluginProbe ʕ •ᴥ•ʔ
Paid Membership Plugin, Ecommerce, User Registration Form, Login Form, User Profile & Restrict Content – ProfilePress / trunk
Paid Membership Plugin, Ecommerce, User Registration Form, Login Form, User Profile & Restrict Content – ProfilePress vtrunk
4.16.18 4.16.17 4.16.16 trunk 1.0 1.0.1 1.0.2 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.5a 1.1.6 1.1.7 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.4 1.4.1 1.4.2 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.7 1.7.1 1.7.2 1.8 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.1.9 2.2.10 2.2.11 2.2.12 2.2.13 2.2.14 2.2.15 2.2.16 2.2.2 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 3.0 3.1 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 3.1.19 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.10 3.2.11 3.2.12 3.2.13 3.2.14 3.2.15 3.2.16 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 4.0.0 4.0.1 4.0.2 4.0.3 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.10.0 4.10.1 4.10.2 4.10.3 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.13.3 4.13.4 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.15.0 4.15.1 4.15.10 4.15.11 4.15.12 4.15.13 4.15.14 4.15.15 4.15.16 4.15.17 4.15.18 4.15.19 4.15.2 4.15.20 4.15.20.1 4.15.21 4.15.22 4.15.23 4.15.24 4.15.25 4.15.3 4.15.4 4.15.5 4.15.6 4.15.7 4.15.8 4.15.9 4.16.0 4.16.1 4.16.10 4.16.11 4.16.12 4.16.13 4.16.14 4.16.15 4.16.2 4.16.3 4.16.4 4.16.5 4.16.6 4.16.7 4.16.8 4.16.9 4.2.0 4.3.0 4.3.1 4.3.2 4.4.0 4.4.1 4.5.0 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.7.0 4.8.0 4.9.0
wp-user-avatar / src / Membership / Services / OrderService.php
wp-user-avatar / src / Membership / Services Last commit date
EUVATChecker 3 years ago Calculator.php 3 years ago CouponService.php 3 years ago CustomerService.php 3 years ago OrderService.php 4 months ago SubscriptionService.php 4 months ago TaxService.php 3 years ago index.php 3 years ago
OrderService.php
601 lines
1 <?php
2
3 namespace ProfilePress\Core\Membership\Services;
4
5 use ProfilePress\Core\Base;
6 use ProfilePress\Core\Membership\Controllers\CheckoutSessionData;
7 use ProfilePress\Core\Membership\Models\Coupon\CouponFactory;
8 use ProfilePress\Core\Membership\Models\Coupon\CouponUnit;
9 use ProfilePress\Core\Membership\Models\Customer\CustomerFactory;
10 use ProfilePress\Core\Membership\Models\Order\CartEntity;
11 use ProfilePress\Core\Membership\Models\Order\OrderEntity as OrderEntity;
12 use ProfilePress\Core\Membership\Models\Order\OrderFactory;
13 use ProfilePress\Core\Membership\Models\Order\OrderStatus;
14 use ProfilePress\Core\Membership\Models\Order\OrderType;
15 use ProfilePress\Core\Membership\Models\Plan\PlanFactory;
16 use ProfilePress\Core\Membership\Models\Subscription\SubscriptionEntity;
17 use ProfilePress\Core\Membership\Models\Subscription\SubscriptionFactory;
18 use ProfilePress\Core\Membership\Models\Subscription\SubscriptionStatus;
19 use ProfilePress\Core\Membership\Models\Subscription\SubscriptionTrialPeriod;
20 use ProfilePress\Core\Membership\Repositories\OrderRepository;
21 use ProfilePress\Core\Membership\Repositories\SubscriptionRepository;
22 use ProfilePress\Core\ShortcodeParser\MyAccount\MyAccountTag;
23 use ProfilePressVendor\Carbon\CarbonImmutable;
24
25 class OrderService
26 {
27 const ORDER_NOTE_META_KEY = 'order_notes';
28
29 /**
30 * @param CartEntity $cart_vars
31 *
32 * @return bool
33 */
34 public function is_free_checkout($cart_vars)
35 {
36 return Calculator::init($cart_vars->total)->isNegativeOrZero() && (
37 ! PlanFactory::fromId($cart_vars->plan_id)->is_auto_renew() ||
38 Calculator::init($cart_vars->recurring_amount)->isNegativeOrZero() ||
39 $this->is_disable_payment_for_zero_initial_subscription_payment($cart_vars)
40 );
41 }
42
43 /**
44 * Should payment form be displayed when initial payment of a subscription zero amount?
45 *
46 * @param CartEntity $cart_vars
47 *
48 * @return bool
49 */
50 public function is_disable_payment_for_zero_initial_subscription_payment($cart_vars)
51 {
52 if (PlanFactory::fromId($cart_vars->plan_id)->is_recurring()) {
53 return apply_filters('ppress_checkout_disable_payment_for_zero_initial_payment', false, $cart_vars);
54 }
55
56 return false;
57 }
58
59 public function customer_has_trialled($plan_id = '')
60 {
61 if (ppress_settings_by_key('one_time_trial') == 'true' && is_user_logged_in()) {
62
63 $customer = CustomerFactory::fromUserId(get_current_user_id());
64
65 if ($customer->exists()) {
66
67 $cache_key = sprintf('ppress_has_trialled_%s_%s', $customer->id, $plan_id);
68
69 $trials_count = wp_cache_get($cache_key);
70
71 if (false === $trials_count) {
72
73 global $wpdb;
74
75 $table = Base::subscriptions_db_table();
76
77 if (apply_filters('ppress_checkout_global_onetime_free_trial', false, $customer, $plan_id)) {
78
79 $trials_count = $wpdb->get_var(
80 $wpdb->prepare(
81 "SELECT COUNT(*) FROM $table WHERE status != %s AND customer_id = %d AND trial_period != %s",
82 SubscriptionStatus::PENDING,
83 $customer->id,
84 SubscriptionTrialPeriod::DISABLED
85 )
86 );
87
88 } else {
89
90 $trials_count = $wpdb->get_var(
91 $wpdb->prepare(
92 "SELECT COUNT(*) FROM $table WHERE status != %s AND customer_id = %d AND plan_id = %d AND trial_period != %s",
93 SubscriptionStatus::PENDING,
94 $customer->id,
95 absint($plan_id),
96 SubscriptionTrialPeriod::DISABLED
97 )
98 );
99 }
100
101 wp_cache_set($cache_key, $trials_count, '', MINUTE_IN_SECONDS);
102 }
103
104 if (absint($trials_count) > 0) return true;
105 }
106 }
107
108 return false;
109 }
110
111 /**
112 * Handle calculating a percentage/fraction (proration) we should charge the
113 * user for based on the current day of the month before their next bill cycle.
114 * To use yourself, implement a getSubscription method which returns an object
115 * containing current_period_start and current_period_end DateTime objects.
116 *
117 * @param string|\Datetime $currentPeriodStart
118 * @param string|\Datetime $currentPeriodEnd
119 *
120 * @return float
121 */
122 protected function prorateUpcomingBillingCycle($currentPeriodStart, $currentPeriodEnd)
123 {
124 $now = CarbonImmutable::now('UTC')->toDateTime();
125
126 if (is_string($currentPeriodStart)) {
127 $currentPeriodStart = CarbonImmutable::parse($currentPeriodStart, 'UTC')->toDateTime();
128 }
129
130 if (is_string($currentPeriodEnd)) {
131 $currentPeriodEnd = CarbonImmutable::parse($currentPeriodEnd, 'UTC')->toDateTime();
132 }
133
134 // get the number of second difference between the cycle start and end date
135 $currentPeriodStartEpoch = (int)$currentPeriodStart->format('U');
136 $currentPeriodEndEpoch = (int)$currentPeriodEnd->format('U');
137 $nowEpoch = (int)$now->format('U');
138
139 // if we aren't between the start and end of the subscription period, we have a problem
140 // hence we return 0.
141 if ($nowEpoch < $currentPeriodStartEpoch || $nowEpoch > $currentPeriodEndEpoch) {
142 return 0;
143 }
144
145 // get the difference of the start and end time in seconds
146 $epochDifference = $currentPeriodEndEpoch - $currentPeriodStartEpoch;
147
148 // get the prorated number of seconds till the end of the subscription period
149 $remainingSecondsInPeriod = $currentPeriodEndEpoch - $nowEpoch;
150
151 // return fraction of the total seconds in the current billing period
152 return $remainingSecondsInPeriod / $epochDifference;
153 }
154
155 /**
156 * @param int $from_sub_id Subscription ID being upgraded from
157 * @param int $to_plan_id Plan ID being upgraded to
158 * @param string $old_price
159 * @param string $new_price
160 *
161 * @return mixed|string|null
162 *
163 * @see https://gist.github.com/cballou/774c5a15f9771314f0d1
164 *
165 */
166 protected function get_time_based_pro_rated_upgrade_cost($from_sub_id, $to_plan_id, $old_price, $new_price)
167 {
168 $fromSub = SubscriptionFactory::fromId($from_sub_id);
169 $toPlan = ppress_get_plan($to_plan_id);
170
171 // If the subscription being upgraded is lifetime, we cannot use time based pro-ration, so fall back to cost based.
172 if ($fromSub->is_lifetime()) {
173 return Calculator::init($new_price)->minus($old_price)->val();
174 }
175
176 $subscription_length_seconds = CarbonImmutable::parse($fromSub->created_date, 'UTC')->diffInSeconds(CarbonImmutable::parse($fromSub->expiration_date, 'UTC'));
177 $seconds_until_expires = CarbonImmutable::parse($fromSub->expiration_date, 'UTC')->diffInSeconds(CarbonImmutable::now('UTC'));
178 $seconds_used = Calculator::init($subscription_length_seconds)->minus($seconds_until_expires)->val();
179
180 // If the subscription has been purchased within the minimum time fall back on cost-based
181 if (apply_filters('ppress_get_time_based_pro_rated_minimum_time', DAY_IN_SECONDS) >= $seconds_used) {
182 return Calculator::init($new_price)->minus($old_price)->val();
183 }
184
185 $credit = 0;
186
187 if ($fromSub->is_active()) {
188 // "Unused" price of current subscription
189 $credit = Calculator::init($old_price)->multipliedBy(
190 $this->prorateUpcomingBillingCycle($fromSub->created_date, $fromSub->expiration_date)
191 )->val();
192 }
193
194 // Lifetime upgrades are calculated differently because the amount of time left is unlimited.
195 $prorated = Calculator::init($new_price)->minus($credit)->val();
196
197 return apply_filters('ppress_get_time_based_pro_rated_upgrade_cost', $prorated, $from_sub_id, $to_plan_id);
198 }
199
200 /**
201 * Calculate the prorated cost to upgrade a subscription
202 *
203 * Calculations are based on the time remaining on a subscription instead of a price comparison.
204 *
205 * @param int $from_sub_id
206 * @param int $to_plan_id
207 *
208 * @return string The prorated cost to upgrade the subscription
209 */
210 public function get_pro_rated_upgrade_cost($from_sub_id, $to_plan_id)
211 {
212 $proration_method = ppress_settings_by_key('proration_method', 'cost-based', true);
213
214 $fromSub = SubscriptionFactory::fromId($from_sub_id);
215 $toPlan = ppress_get_plan($to_plan_id);
216
217 $old_price = Calculator::init($fromSub->get_initial_amount())->minus($fromSub->get_initial_tax())->val();
218 $new_price = $toPlan->get_price();
219
220 $order_type = Calculator::init($old_price)->isGreaterThan($new_price) ? OrderType::DOWNGRADE : OrderType::UPGRADE;
221
222 ppress_session()->set(CheckoutSessionData::ORDER_TYPE, [
223 'plan_id' => $to_plan_id,
224 'order_type' => $order_type,
225 ]);
226
227 if ($proration_method == 'cost-based') {
228 $prorated = Calculator::init($new_price)->minus($old_price)->val();
229 } else {
230 $prorated = $this->get_time_based_pro_rated_upgrade_cost($from_sub_id, $to_plan_id, $old_price, $new_price);
231 }
232
233 return Calculator::init($prorated)->isNegativeOrZero() ? '0' : $prorated;
234 }
235
236 /**
237 * @param $args
238 *
239 * @return CartEntity
240 */
241 public function checkout_order_calculation($args)
242 {
243 $defaults = [
244 'plan_id' => 0,
245 'coupon_code' => '',
246 'tax_rate' => '0',
247 'change_plan_sub_id' => '0'
248 ];
249
250 $args = wp_parse_args($args, $defaults);
251
252 $tax_rate = $args['tax_rate'];
253
254 $coupon_code = ! empty($args['coupon_code']) ? $args['coupon_code'] : '';
255
256 $planObj = ppress_get_plan(absint($args['plan_id']));
257
258 $change_plan_sub_id = intval($args['change_plan_sub_id']);
259
260 $prorated_price_flag = false;
261 $prorated_price = '0';
262
263 if (
264 $change_plan_sub_id > 0 &&
265 SubscriptionFactory::fromId($change_plan_sub_id)->exists()
266 ) {
267 $prorated_price_flag = true;
268 $prorated_price = $this->get_pro_rated_upgrade_cost($change_plan_sub_id, absint($args['plan_id']));
269 }
270
271 $sub_total = $planObj->has_free_trial() ? '0' : (true === $prorated_price_flag ? $prorated_price : $planObj->price);
272
273 if ($planObj->is_recurring() && ! empty($planObj->signup_fee) && Calculator::init($planObj->signup_fee)->isGreaterThan('0')) {
274 $sub_total = Calculator::init($sub_total)->plus($planObj->signup_fee)->val();
275 }
276
277 $recurring_amount = $planObj->is_recurring() ? $planObj->price : '0';
278
279 $discount_percentage = '';
280 $tax_amount = '0';
281 $recurring_tax_amount = '0';
282 $discount_amount = '0';
283 $tax_rate_decimal = '0';
284
285 $couponObj = CouponFactory::fromCode($coupon_code);
286
287 if ($couponObj->exists()) {
288
289 $discount_amount = $couponObj->amount;
290
291 $recurring_discount_amount = $discount_amount;
292
293 if ($couponObj->unit == CouponUnit::PERCENTAGE) {
294
295 $discount_percentage = $couponObj->amount;
296
297 $discount_amount = Calculator::init($discount_amount)
298 ->dividedBy('100')
299 ->multipliedBy($sub_total)
300 ->val();
301
302 $recurring_discount_amount = Calculator::init($recurring_discount_amount)
303 ->dividedBy('100')
304 ->multipliedBy($recurring_amount)
305 ->val();
306 }
307
308 if ($planObj->is_recurring() && $couponObj->is_recurring()) {
309 $recurring_amount = Calculator::init($recurring_amount)->minus($recurring_discount_amount)->val();
310 }
311 }
312
313 if (
314 apply_filters('ppress_checkout_is_tax_enabled', TaxService::init()->is_tax_enabled(), $args) &&
315 ! empty($tax_rate) &&
316 ! Calculator::init($tax_rate)->isNegativeOrZero()
317 ) {
318
319 $tax_rate_decimal = Calculator::init($tax_rate)->dividedBy('100')->val();
320
321 if (TaxService::init()->is_price_inclusive_tax() === true) {
322
323 $gross_amount = Calculator::init($sub_total)->minus($discount_amount)->val();
324
325 $tax_calculation_base_total = Calculator::init($gross_amount)->dividedBy(
326 Calculator::init('1')->plus($tax_rate_decimal)->val()
327 )->val();
328
329 $tax_amount = Calculator::init($gross_amount)->minus($tax_calculation_base_total)->val();
330
331 $sub_total = Calculator::init($tax_calculation_base_total)->plus($discount_amount)->val();
332
333 if ($planObj->is_recurring()) {
334
335 $old_recurring_amount = $recurring_amount;
336
337 $recurring_amount = Calculator::init($recurring_amount)->dividedBy(
338 Calculator::init('1')->plus($tax_rate_decimal)->val()
339 )->val();
340
341 $recurring_tax_amount = Calculator::init($old_recurring_amount)->minus($recurring_amount)->val();
342 }
343
344 } else {
345
346 $tax_amount = Calculator::init($sub_total)->minus($discount_amount)->multipliedBy($tax_rate_decimal)->val();
347
348 $recurring_tax_amount = Calculator::init($recurring_amount)->multipliedBy($tax_rate_decimal)->val();
349 }
350 }
351
352 $total = Calculator::init($sub_total)->minus($discount_amount)->plus($tax_amount)->val();
353
354 $recurring_amount = Calculator::init($recurring_tax_amount)->plus($recurring_amount)->val();
355
356 $cart = new CartEntity();
357 $cart->prorated_price = $prorated_price;
358 $cart->plan_id = $planObj->id;
359 $cart->change_plan_sub_id = $change_plan_sub_id;
360 $cart->sub_total = $sub_total;
361 $cart->coupon_code = $coupon_code;
362 $cart->discount_amount = $discount_amount;
363 $cart->discount_percentage = $discount_percentage;
364 $cart->tax_rate = $tax_rate;
365 $cart->tax_rate_decimal = $tax_rate_decimal;
366 $cart->tax_amount = $tax_amount;
367 $cart->total = $total;
368
369 // recurring vars
370 $cart->initial_amount = $total;
371 $cart->initial_tax = $tax_amount;
372 $cart->initial_tax_rate = $tax_rate;
373 $cart->recurring_tax_rate = $tax_rate;
374 $cart->recurring_amount = $recurring_amount;
375 $cart->recurring_tax = $recurring_tax_amount;
376 $cart->expiration_date = SubscriptionService::init()->get_plan_expiration_datetime($planObj->id);
377
378 return $cart;
379 }
380
381 public function get_customer_orders_url($customer_id, $order_status = false)
382 {
383 $args = ['by_ci' => $customer_id];
384 if ($order_status) $args['status'] = $order_status;
385
386 return add_query_arg($args, PPRESS_MEMBERSHIP_ORDERS_SETTINGS_PAGE);
387 }
388
389 /**
390 * Generate an order key
391 *
392 * @return string The order key.
393 */
394 public function generate_order_key()
395 {
396 $key = strtolower(md5(uniqid('ppress', true)));
397
398 return apply_filters('ppress_generate_order_key', $key);
399 }
400
401 /**
402 * @param $order_id
403 *
404 * @return false|int
405 */
406 public function delete_order($order_id)
407 {
408 $result = OrderRepository::init()->delete($order_id);
409
410 if ($result) {
411 OrderRepository::init()->delete_all_meta_data($order_id);
412 }
413
414 do_action('ppress_order_deleted', $order_id);
415
416 return $result;
417 }
418
419 /**
420 * @param $order_id
421 *
422 * @return array
423 */
424 public function get_order_notes($order_id)
425 {
426 global $wpdb;
427
428 $table = Base::order_meta_db_table();
429
430 return $wpdb->get_results(
431 $wpdb->prepare(
432 "SELECT meta_id, meta_value FROM $table WHERE meta_key = %s AND ppress_order_id = %d",
433 self::ORDER_NOTE_META_KEY,
434 $order_id
435 ),
436 ARRAY_A
437 );
438 }
439
440 public function add_order_note($order_id, $note)
441 {
442 $note = ppress_format_date_time(time()) . '|' . $note;
443
444 return OrderRepository::init()->add_meta_data(
445 $order_id,
446 self::ORDER_NOTE_META_KEY,
447 $note
448 );
449 }
450
451 /**
452 * @param int $meta_id Note meta ID
453 *
454 * @return bool
455 */
456 public function delete_order_note_by_id($meta_id)
457 {
458 return delete_metadata_by_mid('ppress_order', $meta_id);
459 }
460
461 public function delete_all_order_notes($order_id)
462 {
463 return OrderRepository::init()->delete_meta_data(
464 $order_id,
465 self::ORDER_NOTE_META_KEY
466 );
467 }
468
469 /**
470 * @param array $args
471 * @param SubscriptionEntity $subscription
472 *
473 * @return false|int
474 */
475 public function record_subscription_renewal_order($args, $subscription)
476 {
477 $args = wp_parse_args($args, [
478 'total_amount' => '', // This is the full amount that was charged at the gateway, INCLUDING tax.
479 'transaction_id' => '',
480 'payment_method' => '',
481 ]);
482
483 $orders = OrderRepository::init()->retrieveBy([
484 'transaction_id' => $args['transaction_id'],
485 'number' => 1
486 ]);
487
488 if ( ! empty($orders)) return false;
489
490 $parent_order = OrderFactory::fromId($subscription->parent_order_id);
491
492 $new_order = new OrderEntity();
493 $new_order->subscription_id = $subscription->id;
494 $new_order->customer_id = $subscription->customer_id;
495 $new_order->plan_id = $parent_order->plan_id;
496 $new_order->billing_address = $parent_order->billing_address;
497 $new_order->billing_city = $parent_order->billing_city;
498 $new_order->billing_state = $parent_order->billing_state;
499 $new_order->billing_country = $parent_order->billing_country;
500 $new_order->billing_postcode = $parent_order->billing_postcode;
501 $new_order->billing_phone = $parent_order->billing_phone;
502 $new_order->order_key = OrderService::init()->generate_order_key();
503 $new_order->order_type = OrderType::RENEWAL_ORDER;
504 $new_order->transaction_id = $args['transaction_id'];
505 $new_order->payment_method = ! empty($args['payment_method']) ? $args['payment_method'] : $parent_order->payment_method;
506 $new_order->status = OrderStatus::COMPLETED;
507 $new_order->mode = $parent_order->mode;
508 $new_order->date_completed = current_time('mysql', true);
509 $new_order->currency = $parent_order->currency;
510
511 // Force the renewal to have no discount codes.
512 $new_order->discount = '0';
513 $new_order->coupon_code = '';
514
515 if ( ! empty($subscription->recurring_tax)) {
516 $new_order->tax = $subscription->recurring_tax;
517 }
518
519 if ( ! empty($subscription->recurring_tax_rate)) {
520 $new_order->tax_rate = $subscription->recurring_tax_rate;
521 }
522
523 $new_order->subtotal = ppress_sanitize_amount(Calculator::init($args['total_amount'])->minus($new_order->tax)->val());
524 $new_order->total = ppress_sanitize_amount($args['total_amount']);
525
526 $order_id = $new_order->save();
527
528 $new_order->id = $order_id;
529
530 // ensures after completed order actions are triggered
531 $new_order->complete_order();
532
533 do_action('ppress_subscription_renewed', $subscription->id, $order_id);
534
535 return $order_id;
536 }
537
538 /**
539 * @param $order_id
540 *
541 * @return bool
542 */
543 public function process_order_refund($order_id)
544 {
545 $order = OrderRepository::init()->retrieve($order_id);
546
547 if ($order->exists() && $order->is_refundable()) {
548
549 $payment_method = ppress_get_payment_method($order->payment_method);
550
551 if (is_object($payment_method) && method_exists($payment_method, 'process_refund')) {
552
553 $response = $payment_method->process_refund(
554 $order->get_id(),
555 $order->get_total()
556 );
557
558 if ($response === true) {
559 $order->refund_order();
560 SubscriptionRepository::init()->retrieve($order->subscription_id)->cancel(true);
561
562 return true;
563 }
564 }
565 }
566
567 return false;
568 }
569
570 public function frontend_view_order_url($order_key)
571 {
572 return add_query_arg(['order_key' => $order_key], MyAccountTag::get_endpoint_url('list-orders'));
573 }
574
575 public function admin_view_order_url($order_id_or_key)
576 {
577 $order_id = $order_id_or_key;
578 if ( ! is_numeric($order_id_or_key)) {
579 $order_id = OrderFactory::fromOrderKey($order_id_or_key)->id;
580 }
581
582 return add_query_arg([
583 'ppress_order_action' => 'edit',
584 'id' => $order_id
585 ], PPRESS_MEMBERSHIP_ORDERS_SETTINGS_PAGE);
586 }
587
588 /**
589 * @return self
590 */
591 public static function init()
592 {
593 static $instance = null;
594
595 if (is_null($instance)) {
596 $instance = new self();
597 }
598
599 return $instance;
600 }
601 }