PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 2.2.0
Subscriptions for WooCommerce with Stripe Recurring Payments v2.2.0
2.4.0 2.3.0 2.2.0 2.1.0 2.0.0 1.11.2 1.11.1 1.11.0 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.6 1.9.5 trunk 1.3.0 1.3.1 1.3.2 1.4.0 All 65 releases
← All changes | includes/Frontend/MyAccount.php +179 -65 1.3.2 → 2.2.0 View file →
@@ -1,8 +1,16 @@
1 1 <?php
2 2
3 3 namespace SpringDevs\Subscription\Frontend;
4 4
5 +use SpringDevs\Subscription\Illuminate\Helper;
6 +use SpringDevs\Subscription\Illuminate\Subscription\Subscription;
7 +
8 +// HPOS: This file is compatible with WooCommerce High-Performance Order Storage (HPOS).
9 +// All WooCommerce order data is accessed via WooCommerce CRUD methods (wc_get_order, wc_get_order_item_meta, etc.).
10 +// All direct post meta access is for subscription data only, not WooCommerce order data.
11 +// If you add new order data access, use WooCommerce CRUD for HPOS compatibility.
12 +
5 13 /**
6 14 * Class MyAccount
7 15 *
8 16 * @package SpringDevs\Subscription\Frontend
@@ -7,21 +15,48 @@
7 15 *
8 16 * @package SpringDevs\Subscription\Frontend
9 17 */
10 18 class MyAccount {
19 + /**
20 + * Subscriptions endpoint slug.
21 + *
22 + * @var string
23 + */
24 + private $subscriptions_endpoint = 'subscriptions';
11 25
26 + /**
27 + * View Subscriptions endpoint slug.
28 + *
29 + * @var string
30 + */
31 + private $view_subscriptions_endpoint = 'view-subscription';
12 32
33 +
13 34 /**
14 35 * Initialize the class
15 36 */
16 37 public function __construct() {
38 + // Assign endpoint slug from settings.
39 + $this->subscriptions_endpoint = Subscription::get_user_endpoint( 'subs_list' );
40 + $this->view_subscriptions_endpoint = Subscription::get_user_endpoint( 'view_subs' );
41 +
42 + // Flush rewrite rules on init.
17 43 add_action( 'init', array( $this, 'flush_rewrite_rules' ) );
18 - add_filter( 'woocommerce_account_menu_items', array( $this, 'custom_my_account_menu_items' ) );
19 - add_filter( 'woocommerce_endpoint_view-subscription_title', array( $this, 'change_single_title' ) );
20 - add_filter( 'the_title', array( $this, 'change_lists_title' ), 10 );
44 +
45 + // Add My Subscriptions menu item.
46 + add_filter( 'woocommerce_account_menu_items', array( $this, 'custom_my_account_menu_items' ), 200 );
47 +
48 + // Add subscription url endpoints to query vars.
21 49 add_filter( 'woocommerce_get_query_vars', array( $this, 'custom_query_vars' ) );
22 - add_action( 'woocommerce_account_view-subscription_endpoint', array( $this, 'view_subscrpt_content' ) );
23 - add_action( 'woocommerce_account_subscriptions_endpoint', array( $this, 'subscrpt_endpoint_content' ) );
50 +
51 + // Subscription EndPoint Content.
52 + add_action( "woocommerce_account_{$this->subscriptions_endpoint}_endpoint", array( $this, 'subscrpt_endpoint_content' ) );
53 + add_action( "woocommerce_account_{$this->view_subscriptions_endpoint}_endpoint", array( $this, 'view_subscrpt_content' ) );
54 +
55 + // Subscription page titles
56 + add_filter( "woocommerce_endpoint_{$this->subscriptions_endpoint}_title", array( $this, 'change_subscriptions_title' ) );
57 + add_filter( "woocommerce_endpoint_{$this->view_subscriptions_endpoint}_title", array( $this, 'change_single_subscription_title' ) );
58 +
24 59 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_styles' ) );
25 60 }
26 61
27 62 /**
@@ -31,9 +66,11 @@
31 66 *
32 67 * @return array
33 68 */
34 69 public function custom_query_vars( array $query_vars ): array {
35 - $query_vars['view-subscription'] = 'view-subscription';
70 + $query_vars[ $this->subscriptions_endpoint ] = $this->subscriptions_endpoint;
71 + $query_vars[ $this->view_subscriptions_endpoint ] = $this->view_subscriptions_endpoint;
72 +
36 73 return $query_vars;
37 74 }
38 75
39 76 /**
@@ -38,90 +75,164 @@
38 75
39 76 /**
40 77 * Display Subscription Content.
41 78 *
42 - * @param Int $id Post ID.
79 + * @param int $id Post ID.
43 80 */
44 - public function view_subscrpt_content( int $id ) {
45 - $order_id = get_post_meta( $id, '_subscrpt_order_id', true );
46 - $order_item_id = get_post_meta( $id, '_subscrpt_order_item_id', true );
47 - if ( ! $order_id || ! $order_item_id ) {
81 + public function view_subscrpt_content( $id ) {
82 + $id = absint( $id ); // typecast to int.
83 +
84 + $subs_post = get_post( $id );
85 + $author_id = $subs_post ? (int) $subs_post->post_author : 0;
86 + $current_user_id = get_current_user_id();
87 + $user_is_admin = current_user_can( 'manage_options' );
88 +
89 + if ( ! $user_is_admin && (int) $author_id !== (int) $current_user_id ) {
48 90 return wp_safe_redirect( '/404' );
49 91 }
50 - $order = wc_get_order( $order_id );
51 - $order_item = $order->get_item( $order_item_id );
52 - $status = get_post_status( $id );
53 - $user_cancel = get_post_meta( $id, '_subscrpt_user_cancel', true );
54 - $start_date = get_post_meta( $id, '_subscrpt_start_date', true );
55 - $next_date = get_post_meta( $id, '_subscrpt_next_date', true );
56 - $trial = get_post_meta( $id, '_subscrpt_trial', true );
57 - $trial_mode = get_post_meta( $id, '_subscrpt_trial_mode', true );
58 92
93 + $subscription_id = $id;
94 + $subscription_data = Helper::get_subscription_data( $subscription_id );
95 + $related_orders = Helper::get_related_orders( $subscription_id );
96 +
97 + $status = $subscription_data['status'] ?? '';
98 + $verbose_status = Helper::get_verbose_status( $status );
99 +
100 + $order_id = $subscription_data['order']['order_id'] ?? 0;
101 + $order_item_id = $subscription_data['order']['order_item_id'] ?? 0;
102 +
103 + $order = wc_get_order( $order_id );
104 + $order_item = $order ? $order->get_item( $order_item_id ) : null;
105 +
106 + if ( ! $order || ! $order_item ) {
107 + return wp_safe_redirect( '/404' );
108 + }
109 +
110 + $user_cancel = $subscription_data['can_user_cancel'] ?? false;
111 +
112 + $start_date = $subscription_data['start_date'] ?? '';
113 + $start_date = ! empty( $start_date ) ? wp_date( 'F j, Y', strtotime( $start_date ) ) : '-';
114 +
115 + $next_date = $subscription_data['next_date'] ?? '';
116 + $next_date = ! empty( $next_date ) ? wp_date( 'F j, Y', strtotime( $next_date ) ) : '-';
117 +
118 + $trial = get_post_meta( $id, '_subscrpt_trial', true );
119 + $trial_mode = get_post_meta( $id, '_subscrpt_trial_mode', true );
120 +
121 + // Undiscounted subtotal, the discount that recurs, tax on the discounted amount, and the renewal total.
122 + $display_totals = Helper::get_subscription_display_totals( $id, $order_item );
123 +
124 + $price = $display_totals['total'];
125 + $price_excl_tax = $display_totals['full_excl'];
126 + $tax_amount = $display_totals['tax'];
127 + $discount = $display_totals['discount'];
128 +
129 + $is_grace_period = isset( $subscription_data['grace_period'] );
130 + $grace_remaining = $subscription_data['grace_period']['remaining_days'] ?? 0;
131 + $grace_end_date = $subscription_data['grace_period']['end_date'] ?? '';
132 + $grace_end_date = ! empty( $grace_end_date ) ? wp_date( 'F j, Y', strtotime( $grace_end_date ) ) : '';
133 +
59 134 $subscrpt_nonce = wp_create_nonce( 'subscrpt_nonce' );
60 135 $action_buttons = array();
61 136
62 137 if ( 'cancelled' !== $status ) {
63 - if ( in_array( $status, array( 'pending', 'active', 'on_hold' ), true ) && 'yes' === $user_cancel ) {
138 + if ( in_array( $status, array( 'pending', 'active', 'on_hold' ), true ) && $user_cancel ) {
139 + $label = __( 'Cancel', 'subscription' );
140 + $label = apply_filters( 'subscrpt_split_payment_button_text', $label, 'cancel', $id, $status );
141 +
64 142 $action_buttons['cancel'] = array(
65 143 'url' => subscrpt_get_action_url( 'cancelled', $subscrpt_nonce, $id ),
66 - 'label' => __( 'Cancel', 'sdevs_subscrpt' ),
144 + 'label' => $label,
67 145 'class' => 'cancel',
68 146 );
69 147 } elseif ( trim( $status ) === trim( 'pe_cancelled' ) ) {
70 - $action_buttons['reactive'] = array(
71 - 'url' => subscrpt_get_action_url( 'reactive', $subscrpt_nonce, $id ),
72 - 'label' => __( 'Reactive', 'sdevs_subscrpt' ),
148 + $label = __( 'Reactivate', 'subscription' );
149 + $label = apply_filters( 'subscrpt_split_payment_button_text', $label, 'reactivate', $id, $status );
150 +
151 + $action_buttons['reactivate'] = array(
152 + 'url' => subscrpt_get_action_url( 'reactivate', $subscrpt_nonce, $id ),
153 + 'label' => $label,
73 154 );
74 155 } elseif ( 'expired' === $status && 'pending' !== $order->get_status() ) {
75 - $action_buttons['renew'] = array(
76 - 'url' => subscrpt_get_action_url( 'renew', $subscrpt_nonce, $id ),
77 - 'label' => __( 'Renew', 'sdevs_subscrpt' ),
78 - );
156 + // Check if maximum payments reached before showing renew button
157 + if ( ! subscrpt_is_max_payments_reached( $id ) ) {
158 + $label = __( 'Renew', 'subscription' );
159 + $label = apply_filters( 'subscrpt_split_payment_button_text', $label, 'renew', $id, $status );
160 +
161 + $action_buttons['renew'] = array(
162 + 'url' => subscrpt_get_action_url( 'renew', $subscrpt_nonce, $id ),
163 + 'label' => $label,
164 + );
165 + }
79 166 }
80 167
81 168 if ( 'pending' === $order->get_status() ) {
169 + $label = __( 'Pay now', 'subscription' );
170 + $label = apply_filters( 'subscrpt_split_payment_button_text', $label, 'pay_now', $id, $status );
171 +
82 172 $action_buttons['pay_now'] = array(
83 173 'url' => $order->get_checkout_payment_url(),
84 - 'label' => __( 'Pay now', 'sdevs_subscrpt' ),
174 + 'label' => $label,
85 175 );
86 176 }
87 177 }
88 178
89 - $is_auto_renew = get_post_meta( $id, '_subscrpt_auto_renew', true );
90 - $renewal_setting = get_option( 'subscrpt_auto_renewal_toggle', '1' );
91 - if ( '' === $is_auto_renew && '1' === $renewal_setting ) {
92 - update_post_meta( $id, '_subscrpt_auto_renew', 1 );
93 - }
179 + $is_auto_renew = $subscription_data['is_auto_renew'];
180 + $renewal_setting = in_array( get_option( 'wp_subscription_auto_renewal_toggle', '1' ), [ 1, '1', 'true', 'yes' ], true );
181 +
94 182 $saved_methods = wc_get_customer_saved_methods_list( get_current_user_id() );
95 183 $has_methods = isset( $saved_methods['cc'] );
96 - if ( $has_methods && '1' === $renewal_setting && class_exists( 'WC_Stripe' ) && $order && 'stripe' === $order->get_payment_method() ) {
97 - if ( '0' === $is_auto_renew ) {
98 - $action_buttons['auto-renew-on'] = array(
99 - 'url' => subscrpt_get_action_url( 'renew-on', $subscrpt_nonce, $id ),
100 - 'label' => __( 'Turn on Auto Renewal', 'sdevs_subscrpt' ),
101 - );
102 - } else {
103 - $action_buttons['auto-renew-off'] = array(
104 - 'url' => subscrpt_get_action_url( 'renew-off', $subscrpt_nonce, $id ),
105 - 'label' => __( 'Turn off Auto Renewal', 'sdevs_subscrpt' ),
106 - );
184 + if ( $has_methods && $renewal_setting && class_exists( 'WC_Stripe' ) && $order && 'stripe' === $order->get_payment_method() ) {
185 + // Check maximum payment limit for auto-renewal buttons too
186 + if ( ! subscrpt_is_max_payments_reached( $id ) ) {
187 + if ( ! $is_auto_renew ) {
188 + $label = __( 'Turn on Auto Renewal', 'subscription' );
189 + $label = apply_filters( 'subscrpt_split_payment_button_text', $label, 'auto-renew-on', $id, $status );
190 +
191 + $action_buttons['auto-renew-on'] = array(
192 + 'url' => subscrpt_get_action_url( 'renew-on', $subscrpt_nonce, $id ),
193 + 'label' => $label,
194 + );
195 + } else {
196 + $label = __( 'Turn off Auto Renewal', 'subscription' );
197 + $label = apply_filters( 'subscrpt_split_payment_button_text', $label, 'auto-renew-off', $id, $status );
198 +
199 + $action_buttons['auto-renew-off'] = array(
200 + 'url' => subscrpt_get_action_url( 'renew-off', $subscrpt_nonce, $id ),
201 + 'label' => $label,
202 + );
203 + }
107 204 }
108 205 }
109 206
110 - $post_status_object = get_post_status_object( $status );
111 - $action_buttons = apply_filters( 'subscrpt_single_action_buttons', $action_buttons, $id, $subscrpt_nonce, $status );
207 + // Allow programmatically disabling cancel button
208 + $disable_cancel = apply_filters( 'subscrpt_split_payment_disable_cancel', false, $id, $status );
209 + if ( $disable_cancel && isset( $action_buttons['cancel'] ) ) {
210 + unset( $action_buttons['cancel'] );
211 + }
112 212
213 + $action_buttons = apply_filters( 'subscrpt_single_action_buttons', $action_buttons, $id, $subscrpt_nonce, $status );
214 +
113 215 wc_get_template(
114 216 'myaccount/single.php',
115 217 array(
116 218 'id' => $id,
219 + 'status' => $status,
220 + 'verbose_status' => $verbose_status,
117 221 'start_date' => $start_date,
118 222 'next_date' => $next_date,
223 + 'is_grace_period' => $is_grace_period,
224 + 'grace_remaining' => $grace_remaining,
225 + 'grace_end_date' => $grace_end_date,
119 226 'trial' => $trial,
120 227 'trial_mode' => empty( $trial_mode ) ? 'off' : $trial_mode,
121 228 'order' => $order,
122 229 'order_item' => $order_item,
123 - 'status' => $post_status_object,
230 + 'related_orders' => $related_orders,
231 + 'price' => $price,
232 + 'price_excl_tax' => $price_excl_tax,
233 + 'tax' => $tax_amount,
234 + 'discount' => $discount,
124 235 'user_cancel' => $user_cancel,
125 236 'action_buttons' => $action_buttons,
126 237 'wp_button_class' => wc_wp_theme_get_element_class_name( 'button' ) ? ' ' . wc_wp_theme_get_element_class_name( 'button' ) : '',
127 238 ),
@@ -133,37 +244,36 @@
133 244 /**
134 245 * Re-write flush
135 246 */
136 247 public function flush_rewrite_rules() {
137 - add_rewrite_endpoint( 'subscriptions', EP_ROOT | EP_PAGES );
248 + add_rewrite_endpoint( $this->subscriptions_endpoint, EP_ROOT | EP_PAGES );
138 249 flush_rewrite_rules();
139 250 }
140 251
141 252 /**
142 - * Change View Subscription Title
253 + * Change All Subscriptions Title
143 254 *
144 255 * @param string $title Title.
145 256 *
146 257 * @return string
147 258 */
148 - public function change_single_title( string $title ): string {
149 - /* translators: %s: Subscription ID */
150 - return sprintf( __( 'Subscription #%s', 'sdevs_subscrpt' ), get_query_var( 'view-subscription' ) );
259 + public function change_subscriptions_title( string $title ): string {
260 + $title = __( 'My Subscriptions', 'subscription' );
261 + return $title;
151 262 }
152 263
153 264 /**
154 - * Change Subscription Lists Title
265 + * Change View Subscription Title
155 266 *
156 267 * @param string $title Title.
157 268 *
158 269 * @return string
159 270 */
160 - public function change_lists_title( string $title ): string {
161 - global $wp_query;
162 - $is_endpoint = isset( $wp_query->query_vars['subscriptions'] );
163 - if ( $is_endpoint && ! is_admin() && is_account_page() ) {
164 - $title = __( 'My Subscriptions', 'sdevs_subscrpt' );
165 - }
271 + public function change_single_subscription_title( string $title ): string {
272 + $subs_id = get_query_var( $this->view_subscriptions_endpoint, 0 );
273 +
274 + /* translators: %s: Subscription ID */
275 + $title = sprintf( __( 'Subscription #%s', 'subscription' ), $subs_id );
166 276 return $title;
167 277 }
168 278
169 279 /**
@@ -172,12 +282,16 @@
172 282 * @param array $items MyAccount menu items.
173 283 * @return array
174 284 */
175 285 public function custom_my_account_menu_items( array $items ): array {
176 - $logout = $items['customer-logout'];
177 - unset( $items['customer-logout'] );
178 - $items['subscriptions'] = __( 'Subscriptions', 'sdevs_subscrpt' );
179 - $items['customer-logout'] = $logout;
286 + // Check if subscriptions menu item already exists to prevent duplicates
287 + if ( ! isset( $items[ $this->subscriptions_endpoint ] ) ) {
288 + $logout = $items['customer-logout'];
289 + unset( $items['customer-logout'] );
290 +
291 + $items[ $this->subscriptions_endpoint ] = __( 'Subscriptions', 'subscription' );
292 + $items['customer-logout'] = $logout;
293 + }
180 294 return $items;
181 295 }
182 296
183 297 /**
@@ -191,9 +305,9 @@
191 305 'author' => get_current_user_id(),
192 306 'posts_per_page' => 10,
193 307 'paged' => $current_page,
194 308 'post_type' => 'subscrpt_order',
195 - 'post_status' => array( 'pending', 'active', 'on_hold', 'cancelled', 'expired', 'pe_cancelled' ),
309 + 'post_status' => array( 'pending', 'active', 'on_hold', 'cancelled', 'expired', 'pe_cancelled', 'completed' ),
196 310 );
197 311
198 312 $postslist = new \WP_Query( $args );
199 313 wc_get_template(