PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 2.4.0
Subscriptions for WooCommerce with Stripe Recurring Payments v2.4.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 +181 -67 1.4.0 → 2.4.0 View file →
@@ -1,8 +1,11 @@
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 +
5 8 // HPOS: This file is compatible with WooCommerce High-Performance Order Storage (HPOS).
6 9 // All WooCommerce order data is accessed via WooCommerce CRUD methods (wc_get_order, wc_get_order_item_meta, etc.).
7 10 // All direct post meta access is for subscription data only, not WooCommerce order data.
8 11 // If you add new order data access, use WooCommerce CRUD for HPOS compatibility.
@@ -12,21 +15,48 @@
12 15 *
13 16 * @package SpringDevs\Subscription\Frontend
14 17 */
15 18 class MyAccount {
19 + /**
20 + * Subscriptions endpoint slug.
21 + *
22 + * @var string
23 + */
24 + private $subscriptions_endpoint = 'subscriptions';
16 25
26 + /**
27 + * View Subscriptions endpoint slug.
28 + *
29 + * @var string
30 + */
31 + private $view_subscriptions_endpoint = 'view-subscription';
17 32
33 +
18 34 /**
19 35 * Initialize the class
20 36 */
21 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.
22 43 add_action( 'init', array( $this, 'flush_rewrite_rules' ) );
23 - add_filter( 'woocommerce_account_menu_items', array( $this, 'custom_my_account_menu_items' ) );
24 - add_filter( 'woocommerce_endpoint_view-subscription_title', array( $this, 'change_single_title' ) );
25 - 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.
26 49 add_filter( 'woocommerce_get_query_vars', array( $this, 'custom_query_vars' ) );
27 - add_action( 'woocommerce_account_view-subscription_endpoint', array( $this, 'view_subscrpt_content' ) );
28 - 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 +
29 59 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_styles' ) );
30 60 }
31 61
32 62 /**
@@ -36,9 +66,11 @@
36 66 *
37 67 * @return array
38 68 */
39 69 public function custom_query_vars( array $query_vars ): array {
40 - $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 +
41 73 return $query_vars;
42 74 }
43 75
44 76 /**
@@ -43,96 +75,175 @@
43 75
44 76 /**
45 77 * Display Subscription Content.
46 78 *
47 - * @param Int $id Post ID.
79 + * @param int $id Post ID.
48 80 */
49 - public function view_subscrpt_content( int $id ) {
50 - $order_id = get_post_meta( $id, '_subscrpt_order_id', true );
51 - $order_item_id = get_post_meta( $id, '_subscrpt_order_item_id', true );
52 - 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 ) {
53 90 return wp_safe_redirect( '/404' );
54 91 }
55 - $order = wc_get_order( $order_id );
56 - $order_item = $order->get_item( $order_item_id );
57 - $status = get_post_status( $id );
58 - $user_cancel = get_post_meta( $id, '_subscrpt_user_cancel', true );
59 - $start_date = get_post_meta( $id, '_subscrpt_start_date', true );
60 - $next_date = get_post_meta( $id, '_subscrpt_next_date', true );
61 - $trial = get_post_meta( $id, '_subscrpt_trial', true );
62 - $trial_mode = get_post_meta( $id, '_subscrpt_trial_mode', true );
63 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 ) && Helper::has_next_payment( $status ) ? 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 +
64 134 $subscrpt_nonce = wp_create_nonce( 'subscrpt_nonce' );
65 135 $action_buttons = array();
66 136
67 137 if ( 'cancelled' !== $status ) {
68 - 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 +
69 142 $action_buttons['cancel'] = array(
70 143 'url' => subscrpt_get_action_url( 'cancelled', $subscrpt_nonce, $id ),
71 - 'label' => __( 'Cancel', 'sdevs_subscrpt' ),
144 + 'label' => $label,
72 145 'class' => 'cancel',
73 146 );
74 147 } elseif ( trim( $status ) === trim( 'pe_cancelled' ) ) {
75 - $action_buttons['reactive'] = array(
76 - 'url' => subscrpt_get_action_url( 'reactive', $subscrpt_nonce, $id ),
77 - '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,
78 154 );
79 155 } elseif ( 'expired' === $status && 'pending' !== $order->get_status() ) {
80 - $action_buttons['renew'] = array(
81 - 'url' => subscrpt_get_action_url( 'renew', $subscrpt_nonce, $id ),
82 - 'label' => __( 'Renew', 'sdevs_subscrpt' ),
83 - );
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 + }
84 166 }
85 167
86 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 +
87 172 $action_buttons['pay_now'] = array(
88 173 'url' => $order->get_checkout_payment_url(),
89 - 'label' => __( 'Pay now', 'sdevs_subscrpt' ),
174 + 'label' => $label,
90 175 );
91 176 }
92 177 }
93 178
94 - $is_auto_renew = get_post_meta( $id, '_subscrpt_auto_renew', true );
95 - $renewal_setting = get_option( 'subscrpt_auto_renewal_toggle', '1' );
96 - if ( '' === $is_auto_renew && '1' === $renewal_setting ) {
97 - update_post_meta( $id, '_subscrpt_auto_renew', 1 );
98 - }
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 +
99 182 $saved_methods = wc_get_customer_saved_methods_list( get_current_user_id() );
100 183 $has_methods = isset( $saved_methods['cc'] );
101 - if ( $has_methods && '1' === $renewal_setting && class_exists( 'WC_Stripe' ) && $order && 'stripe' === $order->get_payment_method() ) {
102 - if ( '0' === $is_auto_renew ) {
103 - $action_buttons['auto-renew-on'] = array(
104 - 'url' => subscrpt_get_action_url( 'renew-on', $subscrpt_nonce, $id ),
105 - 'label' => __( 'Turn on Auto Renewal', 'sdevs_subscrpt' ),
106 - );
107 - } else {
108 - $action_buttons['auto-renew-off'] = array(
109 - 'url' => subscrpt_get_action_url( 'renew-off', $subscrpt_nonce, $id ),
110 - 'label' => __( 'Turn off Auto Renewal', 'sdevs_subscrpt' ),
111 - );
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 + }
112 204 }
113 205 }
114 206
115 - $post_status_object = get_post_status_object( $status );
116 - $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 + }
117 212
213 + $action_buttons = apply_filters( 'subscrpt_single_action_buttons', $action_buttons, $id, $subscrpt_nonce, $status );
214 +
215 + // Nothing renews once a subscription has ended, so drop the auto-renewal toggle — Pro adds it through the filter too.
216 + if ( ! Helper::has_next_payment( $status ) ) {
217 + unset( $action_buttons['auto-renew-on'], $action_buttons['auto-renew-off'] );
218 + }
219 +
118 220 wc_get_template(
119 221 'myaccount/single.php',
120 222 array(
121 223 'id' => $id,
224 + 'status' => $status,
225 + 'verbose_status' => $verbose_status,
122 226 'start_date' => $start_date,
123 227 'next_date' => $next_date,
228 + 'is_grace_period' => $is_grace_period,
229 + 'grace_remaining' => $grace_remaining,
230 + 'grace_end_date' => $grace_end_date,
124 231 'trial' => $trial,
125 232 'trial_mode' => empty( $trial_mode ) ? 'off' : $trial_mode,
126 233 'order' => $order,
127 234 'order_item' => $order_item,
128 - 'status' => $post_status_object,
235 + 'related_orders' => $related_orders,
236 + 'price' => $price,
237 + 'price_excl_tax' => $price_excl_tax,
238 + 'tax' => $tax_amount,
239 + 'discount' => $discount,
129 240 'user_cancel' => $user_cancel,
130 241 'action_buttons' => $action_buttons,
131 242 'wp_button_class' => wc_wp_theme_get_element_class_name( 'button' ) ? ' ' . wc_wp_theme_get_element_class_name( 'button' ) : '',
132 243 ),
133 244 'subscription',
134 - WP_SUBSCRIPTION_TEMPLATES
245 + SUBSCRPT_TEMPLATES
135 246 );
136 247 }
137 248
138 249 /**
@@ -138,37 +249,36 @@
138 249 /**
139 250 * Re-write flush
140 251 */
141 252 public function flush_rewrite_rules() {
142 - add_rewrite_endpoint( 'subscriptions', EP_ROOT | EP_PAGES );
253 + add_rewrite_endpoint( $this->subscriptions_endpoint, EP_ROOT | EP_PAGES );
143 254 flush_rewrite_rules();
144 255 }
145 256
146 257 /**
147 - * Change View Subscription Title
258 + * Change All Subscriptions Title
148 259 *
149 260 * @param string $title Title.
150 261 *
151 262 * @return string
152 263 */
153 - public function change_single_title( string $title ): string {
154 - /* translators: %s: Subscription ID */
155 - return sprintf( __( 'Subscription #%s', 'sdevs_subscrpt' ), get_query_var( 'view-subscription' ) );
264 + public function change_subscriptions_title( string $title ): string {
265 + $title = __( 'My Subscriptions', 'subscription' );
266 + return $title;
156 267 }
157 268
158 269 /**
159 - * Change Subscription Lists Title
270 + * Change View Subscription Title
160 271 *
161 272 * @param string $title Title.
162 273 *
163 274 * @return string
164 275 */
165 - public function change_lists_title( string $title ): string {
166 - global $wp_query;
167 - $is_endpoint = isset( $wp_query->query_vars['subscriptions'] );
168 - if ( $is_endpoint && ! is_admin() && is_account_page() ) {
169 - $title = __( 'My Subscriptions', 'sdevs_subscrpt' );
170 - }
276 + public function change_single_subscription_title( string $title ): string {
277 + $subs_id = get_query_var( $this->view_subscriptions_endpoint, 0 );
278 +
279 + /* translators: %s: Subscription ID */
280 + $title = sprintf( __( 'Subscription #%s', 'subscription' ), $subs_id );
171 281 return $title;
172 282 }
173 283
174 284 /**
@@ -177,12 +287,16 @@
177 287 * @param array $items MyAccount menu items.
178 288 * @return array
179 289 */
180 290 public function custom_my_account_menu_items( array $items ): array {
181 - $logout = $items['customer-logout'];
182 - unset( $items['customer-logout'] );
183 - $items['subscriptions'] = __( 'Subscriptions', 'sdevs_subscrpt' );
184 - $items['customer-logout'] = $logout;
291 + // Check if subscriptions menu item already exists to prevent duplicates
292 + if ( ! isset( $items[ $this->subscriptions_endpoint ] ) ) {
293 + $logout = $items['customer-logout'];
294 + unset( $items['customer-logout'] );
295 +
296 + $items[ $this->subscriptions_endpoint ] = __( 'Subscriptions', 'subscription' );
297 + $items['customer-logout'] = $logout;
298 + }
185 299 return $items;
186 300 }
187 301
188 302 /**
@@ -196,9 +310,9 @@
196 310 'author' => get_current_user_id(),
197 311 'posts_per_page' => 10,
198 312 'paged' => $current_page,
199 313 'post_type' => 'subscrpt_order',
200 - 'post_status' => array( 'pending', 'active', 'on_hold', 'cancelled', 'expired', 'pe_cancelled' ),
314 + 'post_status' => array( 'pending', 'active', 'on_hold', 'cancelled', 'expired', 'pe_cancelled', 'completed' ),
201 315 );
202 316
203 317 $postslist = new \WP_Query( $args );
204 318 wc_get_template(
@@ -208,9 +322,9 @@
208 322 'postslist' => $postslist,
209 323 'current_page' => $current_page,
210 324 ),
211 325 'subscription',
212 - WP_SUBSCRIPTION_TEMPLATES
326 + SUBSCRPT_TEMPLATES
213 327 );
214 328 }
215 329
216 330 /**