PluginProbe
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More / 2.2.0
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More v2.2.0
2.3.0 2.2.0 2.1.1 2.1.0 2.0.0 1.10.0 1.9.1 1.9.0 1.2.1 1.2.2 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.5.0 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.0 All 59 releases
storeengine / includes / api / me-subscriptions.php

me-subscriptions.php in StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More 2.2.0, at includes/api/me-subscriptions.php

204 lines 6.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Current-user-scoped subscriptions endpoints for the headless customer dashboard.
4 *
5 * @package StoreEngine\API
6 */
7
8 namespace StoreEngine\API;
9
10 use StoreEngine\Addons\Subscription\Classes\Subscription;
11 use StoreEngine\Addons\Subscription\Classes\SubscriptionCollection;
12 use StoreEngine\Classes\Exceptions\StoreEngineException;
13 use StoreEngine\Utils\Helper;
14 use WP_Error;
15 use WP_REST_Request;
16 use WP_REST_Response;
17 use WP_REST_Server;
18
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit;
21 }
22
23 class MeSubscriptions extends AbstractRestApiController {
24
25 protected $rest_base = 'me/subscriptions';
26
27 public static function init() {
28 if ( ! class_exists( SubscriptionCollection::class ) ) {
29 return;
30 }
31
32 $self = new self();
33 add_action( 'rest_api_init', [ $self, 'register_routes' ] );
34 add_filter( 'storeengine/rest/me/menu_items', [ $self, 'add_menu_item' ] );
35 }
36
37 public function register_routes() {
38 register_rest_route( $this->namespace, '/' . $this->rest_base, [
39 'methods' => WP_REST_Server::READABLE,
40 'callback' => [ $this, 'list_subscriptions' ],
41 'permission_callback' => [ $this, 'permission_check' ],
42 'args' => [
43 'page' => [ 'type' => 'integer', 'default' => 1 ],
44 'per_page' => [ 'type' => 'integer', 'default' => 10 ],
45 'status' => [ 'type' => 'string' ],
46 ],
47 ] );
48
49 register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', [
50 'args' => [ 'id' => [ 'type' => 'integer' ] ],
51 'methods' => WP_REST_Server::READABLE,
52 'callback' => [ $this, 'get_subscription' ],
53 'permission_callback' => [ $this, 'permission_check' ],
54 ] );
55
56 foreach ( [ 'cancel', 'pause', 'resume' ] as $action ) {
57 register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)/' . $action, [
58 'args' => [ 'id' => [ 'type' => 'integer' ] ],
59 'methods' => WP_REST_Server::CREATABLE,
60 'callback' => [ $this, $action . '_subscription' ],
61 'permission_callback' => [ $this, 'permission_check' ],
62 ] );
63 }
64 }
65
66 public function permission_check() {
67 if ( ! is_user_logged_in() ) {
68 return new WP_Error( 'storeengine_rest_not_logged_in', __( 'You must be logged in.', 'storeengine' ), [ 'status' => 401 ] );
69 }
70
71 return true;
72 }
73
74 public function add_menu_item( array $items ): array {
75 $items[] = [
76 'slug' => 'subscriptions',
77 'route' => 'subscriptions',
78 'label' => __( 'Subscriptions', 'storeengine' ),
79 'icon' => 'refresh',
80 'order' => 15,
81 ];
82
83 return $items;
84 }
85
86 public function list_subscriptions( WP_REST_Request $request ) {
87 $user_id = get_current_user_id();
88 $page = max( 1, (int) $request->get_param( 'page' ) );
89 $per_page = min( 100, max( 1, (int) $request->get_param( 'per_page' ) ) );
90 $status = $request->get_param( 'status' );
91
92 $where = [
93 'relation' => 'AND',
94 [ 'key' => 'type', 'value' => 'subscription' ],
95 [ 'key' => 'customer_id', 'value' => $user_id, 'type' => 'NUMERIC' ],
96 ];
97
98 if ( $status ) {
99 $where[] = [ 'key' => 'status', 'value' => $status ];
100 }
101
102 $query = new SubscriptionCollection( [
103 'per_page' => $per_page,
104 'page' => $page,
105 'where' => $where,
106 ] );
107
108 $data = [];
109 foreach ( $query->get_results() as $sub ) {
110 $data[] = $this->format_subscription( $sub );
111 }
112
113 return $this->prepare_query_response( $data, $query, $request );
114 }
115
116 public function get_subscription( WP_REST_Request $request ) {
117 $sub = $this->load_owned( (int) $request->get_param( 'id' ) );
118 if ( is_wp_error( $sub ) ) {
119 return $sub;
120 }
121
122 return rest_ensure_response( $this->format_subscription( $sub, true ) );
123 }
124
125 public function cancel_subscription( WP_REST_Request $request ) {
126 return $this->change_status( $request, 'pending_cancel', __( 'Cancelled by customer.', 'storeengine' ) );
127 }
128
129 public function pause_subscription( WP_REST_Request $request ) {
130 return $this->change_status( $request, 'on_hold', __( 'Paused by customer.', 'storeengine' ) );
131 }
132
133 public function resume_subscription( WP_REST_Request $request ) {
134 return $this->change_status( $request, 'active', __( 'Resumed by customer.', 'storeengine' ) );
135 }
136
137 protected function change_status( WP_REST_Request $request, string $new_status, string $note ) {
138 $sub = $this->load_owned( (int) $request->get_param( 'id' ) );
139 if ( is_wp_error( $sub ) ) {
140 return $sub;
141 }
142
143 try {
144 $sub->update_status( $new_status, $note );
145 } catch ( StoreEngineException $e ) {
146 return new WP_Error( 'storeengine_rest_status_failed', $e->getMessage(), [ 'status' => 500 ] );
147 }
148
149 return rest_ensure_response( $this->format_subscription( $sub, true ) );
150 }
151
152 /**
153 * @return Subscription|WP_Error
154 */
155 protected function load_owned( int $id ) {
156 if ( $id <= 0 ) {
157 return new WP_Error( 'storeengine_rest_invalid_id', __( 'Invalid subscription id.', 'storeengine' ), [ 'status' => 400 ] );
158 }
159
160 try {
161 $sub = new Subscription( $id );
162 } catch ( \Throwable $e ) {
163 return new WP_Error( 'storeengine_rest_subscription_not_found', __( 'Subscription not found.', 'storeengine' ), [ 'status' => 404 ] );
164 }
165
166 if ( ! $sub->get_id() || (int) $sub->get_customer_id() !== get_current_user_id() ) {
167 return new WP_Error( 'storeengine_rest_subscription_not_found', __( 'Subscription not found.', 'storeengine' ), [ 'status' => 404 ] );
168 }
169
170 return $sub;
171 }
172
173 protected function format_subscription( Subscription $sub, bool $detailed = false ): array {
174 $data = [
175 'id' => $sub->get_id(),
176 'status' => $sub->get_status(),
177 'total' => (float) $sub->get_total_amount(),
178 'currency' => $sub->get_currency(),
179 'billing_period' => $sub->get_payment_duration_type(),
180 'billing_interval' => (int) $sub->get_payment_duration(),
181 'start_date' => $this->date_as_string( $sub->get_start_date() ),
182 'next_payment_date' => $this->date_as_string( $sub->get_next_payment_date() ),
183 'last_payment_date' => $this->date_as_string( $sub->get_last_payment_date() ),
184 'end_date' => $this->date_as_string( $sub->get_end_date() ),
185 'trial' => (bool) $sub->get_trial(),
186 'trial_end_date' => $this->date_as_string( $sub->get_trial_end_date() ),
187 'payment_method' => $sub->get_payment_method_to_display(),
188 'parent_order_id' => $sub->get_initial_order_id(),
189 ];
190
191 if ( $detailed ) {
192 $data['related_order_ids'] = $sub->get_related_order_ids( 'any' );
193 $data['suspension_count'] = (int) $sub->get_suspension_count();
194 $billing = $sub->get_address( 'billing' );
195 $shipping = $sub->get_address( 'shipping' );
196 unset( $billing['address_type'], $shipping['address_type'] );
197 $data['billing_address'] = $billing;
198 $data['shipping_address'] = $shipping;
199 }
200
201 return $data;
202 }
203 }
204