PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 2.3.0
Subscriptions for WooCommerce with Stripe Recurring Payments v2.3.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
subscription / templates / myaccount / single.php

single.php in Subscriptions for WooCommerce with Stripe Recurring Payments 2.3.0, at templates/myaccount/single.php

477 lines 17.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // Exit if accessed directly.
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit;
5 }
6 /**
7 * Single subscription page
8 *
9 * @var WC_Order $order
10 * @var WC_Order_Item $order_item
11 * @var array $related_orders
12 * @var string $start_date
13 * @var string $next_date
14 * @var string|null $trial
15 * @var string|null $trial_mode
16 * @var string $status
17 * @var array $action_buttons
18 * @var bool $is_grace_period
19 * @var int $grace_remaining
20 * @var float $price Renewal total, after any discount that recurs.
21 * @var float $price_excl_tax Renewal subtotal before discount and tax.
22 * @var float $tax Tax on the discounted renewal amount.
23 * @var float $discount Discount that applies to each renewal. 0 when none recurs.
24 *
25 * This template can be overridden by copying it to <your_theme>/subscription/myaccount/single.php
26 *
27 * @package SpringDevs\Subscription
28 */
29
30 use SpringDevs\Subscription\Illuminate\Helper;
31
32 if ( ! isset( $id ) ) {
33 return;
34 }
35
36 if ( ! get_the_title( $id ) ) {
37 return;
38 }
39
40 do_action( 'before_single_subscrpt_content', $id );
41 ?>
42 <style>
43 .auto-renew-on,
44 .subscription_renewal_early,
45 .auto-renew-off {
46 margin-bottom: 10px;
47 }
48 .subscrpt_action_buttons {
49 display: flex;
50 flex-wrap: wrap;
51 gap: 10px;
52 }
53 .product-name .subscrpt-plan-term {
54 display: block;
55 margin-top: 4px;
56 font-size: 13px;
57 color: #6b7280;
58 }
59 </style>
60 <table class="woocommerce-table woocommerce-table--order-details shop_table order_details subscription_details">
61 <tbody>
62 <tr>
63 <td><?php esc_html_e( 'Order', 'subscription' ); ?></td>
64 <td><a href="<?php echo esc_html( wc_get_endpoint_url( 'view-order', $order->get_id(), wc_get_page_permalink( 'myaccount' ) ) ); ?>" target="_blank"># <?php echo esc_html( $order->get_id() ); ?></a></td>
65 </tr>
66 <tr>
67 <td><?php esc_html_e( 'Status', 'subscription' ); ?></td>
68 <td>
69 <?php if ( $is_grace_period && $grace_remaining > 0 ) : ?>
70 <span class="subscrpt-legacy-status subscrpt-legacy-status--active grace-active">
71 Active
72
73 <?php
74 $grace_remaining_text = sprintf(
75 // translators: Number of days remaining in grace period.
76 __( '%d days remaining!', 'subscription' ),
77 $grace_remaining
78 );
79 ?>
80 <span class="grace-icon" data-tooltip="<?php echo esc_attr( $grace_remaining_text ); ?>">
81 <span class="dashicons dashicons-warning"></span>
82 </span>
83 </span>
84 <?php else : ?>
85 <span class="subscrpt-legacy-status subscrpt-legacy-status--<?php echo esc_attr( strtolower( $status ) ); ?>">
86 <?php echo esc_html( $verbose_status ); ?>
87 </span>
88 <?php endif; ?>
89 </td>
90 </tr>
91
92 <?php if ( $is_grace_period && $grace_remaining > 0 ) : ?>
93 <tr>
94 <td><?php esc_html_e( 'Grace Period Ends On', 'subscription' ); ?></td>
95 <td><?php echo esc_html( $grace_end_date ); ?></td>
96 </tr>
97 <?php endif; ?>
98
99 <?php if ( null != $trial && 'off' !== $trial ) : ?>
100 <tr>
101 <td><?php esc_html_e( 'Trial', 'subscription' ); ?></td>
102 <td><?php echo esc_html( $trial ); ?></td>
103 </tr>
104 <?php endif; ?>
105 <tr>
106 <td>
107 <?php
108 if ( 'null' == $trial || 'off' === $trial_mode ) {
109 esc_html_e( 'Start date', 'subscription' );
110 } elseif ( 'extended' === $trial_mode ) {
111 esc_html_e( 'Trial End & Subscription Start', 'subscription' );
112 } elseif ( ! Helper::has_next_payment( $status ) ) {
113 esc_html_e( 'Trial End', 'subscription' );
114 } else {
115 esc_html_e( 'Trial End & First Billing', 'subscription' );
116 }
117 ?>
118 </td>
119 <td><?php echo esc_html( $start_date ); ?></td>
120 </tr>
121 <?php if ( ( null == $trial || in_array( $trial_mode, array( 'off', 'extended' ), true ) ) && get_post_meta( $id, '_subscrpt_next_date', true ) && Helper::has_next_payment( $status ) ) : ?>
122 <tr>
123 <td>
124 <?php
125 esc_html_e( 'Next payment date', 'subscription' );
126 ?>
127 </td>
128 <td>
129 <?php echo esc_html( $next_date ); ?>
130 </td>
131 </tr>
132 <?php endif; ?>
133
134 <!-- get the max_no_payment info using Helper -->
135 <?php $remaining_payments = subscrpt_get_remaining_payments( $id ); ?>
136 <?php $payments_made = subscrpt_count_payments_made( $id ); ?>
137 <?php
138 // Get maximum payments using helper function (handles variations properly)
139 $product_id = get_post_meta( $id, '_subscrpt_product_id', true );
140 $max_payments = subscrpt_get_max_payments( $id );
141
142 // Get Payment Type and Access Duration Information
143 $payment_type = $product_id ? get_post_meta( $product_id, '_subscrpt_payment_type', true ) : 'recurring';
144 $payment_type = $payment_type ?: 'recurring'; // Default to recurring if empty
145
146 // Also check subscription's own meta data
147 $subscription_payment_type = get_post_meta( $id, '_subscrpt_payment_type', true );
148 $subscription_max_payments = get_post_meta( $id, '_subscrpt_max_no_payment', true );
149
150 // Also check if this subscription has variation data
151 $variation_id = get_post_meta( $id, '_subscrpt_variation_id', true );
152 if ( $variation_id ) {
153 $variation_payment_type = get_post_meta( $variation_id, '_subscrpt_payment_type', true );
154 $variation_max_payments = get_post_meta( $variation_id, '_subscrpt_max_no_payment', true );
155
156 // Use variation data if product data is not available
157 if ( empty( $payment_type ) || 'recurring' === $payment_type ) {
158 if ( ! empty( $variation_payment_type ) ) {
159 $payment_type = $variation_payment_type;
160 }
161 }
162 if ( empty( $max_payments ) && ! empty( $variation_max_payments ) ) {
163 $max_payments = $variation_max_payments;
164 }
165 }
166
167 // Use subscription's own data if available and more specific
168 if ( ! empty( $subscription_payment_type ) ) {
169 $payment_type = $subscription_payment_type;
170 }
171 if ( ! empty( $subscription_max_payments ) ) {
172 $max_payments = $subscription_max_payments;
173 }
174
175 // Final fallback: Infer payment type from max_payments if not explicitly set
176 if ( ( empty( $payment_type ) || 'recurring' === $payment_type ) && $max_payments > 0 ) {
177 $payment_type = 'split_payment';
178 }
179
180 // Ensure max_payments is properly set for display
181 $max_payments = (int) $max_payments;
182 ?>
183
184 <!-- show payment progress if max_payments is set and not unlimited -->
185 <?php if ( ( $remaining_payments !== 'unlimited' && $max_payments > 0 ) || ( 'split_payment' === $payment_type && $max_payments > 0 ) ) : ?>
186 <tr>
187 <td><?php esc_html_e( 'Total Payments', 'subscription' ); ?></td>
188 <td><?php echo esc_html( $payments_made ) . ' / ' . esc_html( $max_payments ); ?></td>
189 </tr>
190 <?php endif; ?>
191
192 <tr>
193 <td><?php esc_html_e( 'Payment Type', 'subscription' ); ?></td>
194 <td>
195 <?php
196 if ( 'split_payment' === $payment_type ) {
197 esc_html_e( 'Split Payment', 'subscription' );
198 } else {
199 esc_html_e( 'Recurring', 'subscription' );
200 }
201 ?>
202 <!-- DEBUG: Show raw values -->
203 <!-- <small style="color: #666; font-size: 11px; display: block;">
204 Debug: Product ID: <?php echo esc_html( $product_id ); ?>,
205 Variation ID: <?php echo esc_html( $variation_id ?: 'None' ); ?>,
206 Type: <?php echo esc_html( $payment_type ); ?>,
207 Max: <?php echo esc_html( $max_payments ); ?>
208 </small> -->
209 </td>
210 </tr>
211
212 <!-- Access Duration Information for Split Payments -->
213 <?php if ( 'split_payment' === $payment_type && $max_payments > 0 ) : ?>
214 <?php
215 // Plan subscriptions store access-ends on the subscription; classic ones on
216 // the product. Prefer the subscription meta, fall back to the product.
217 $access_ends_timing = get_post_meta( $id, '_subscrpt_access_ends_timing', true );
218 $access_ends_timing = $access_ends_timing ? $access_ends_timing : ( get_post_meta( $product_id, '_subscrpt_access_ends_timing', true ) ?: 'after_full_duration' );
219 $custom_duration_time = get_post_meta( $id, '_subscrpt_custom_access_duration_time', true ) ?: ( get_post_meta( $product_id, '_subscrpt_custom_access_duration_time', true ) ?: 1 );
220 $custom_duration_type = get_post_meta( $id, '_subscrpt_custom_access_duration_type', true ) ?: ( get_post_meta( $product_id, '_subscrpt_custom_access_duration_type', true ) ?: 'months' );
221
222 // Calculate access end date if Pro version is available
223 $access_end_date_string = null;
224 if ( function_exists( 'subscrpt_pro_activated' ) && subscrpt_pro_activated() ) {
225 if ( class_exists( '\SpringDevs\SubscriptionPro\Illuminate\SplitPaymentHandler' ) ) {
226 $access_end_date_string = \SpringDevs\SubscriptionPro\Illuminate\SplitPaymentHandler::get_access_end_date_string( $id );
227 }
228 }
229 ?>
230 <tr>
231 <td><?php esc_html_e( 'Access Duration', 'subscription' ); ?></td>
232 <td>
233 <?php
234 switch ( $access_ends_timing ) {
235 case 'lifetime':
236 esc_html_e( 'Lifetime access after completion', 'subscription' );
237 break;
238 case 'after_full_duration':
239 esc_html_e( 'Full subscription duration', 'subscription' );
240 break;
241 case 'custom_duration':
242 printf(
243 /* translators: %1$s: duration time, %2$s: duration type */
244 esc_html__( '%1$s %2$s after first payment', 'subscription' ),
245 esc_html( $custom_duration_time ),
246 esc_html( ucfirst( Helper::get_typos( $custom_duration_time, $custom_duration_type, true ) ) )
247 );
248 break;
249 default:
250 esc_html_e( 'Full subscription duration', 'subscription' );
251 break;
252 }
253 ?>
254 </td>
255 </tr>
256
257 <!-- Show calculated access end date if available -->
258 <?php if ( $access_end_date_string ) : ?>
259 <tr>
260 <td><?php esc_html_e( 'Access Ends On', 'subscription' ); ?></td>
261 <td><?php echo esc_html( $access_end_date_string ); ?></td>
262 </tr>
263 <?php endif; ?>
264 <?php endif; ?>
265
266 <?php if ( ! empty( $order->get_payment_method_title() ) ) : ?>
267 <tr>
268 <td><?php esc_html_e( 'Payment', 'subscription' ); ?></td>
269 <td>
270 <span data-is_manual="yes" class="subscription-payment-method"><?php echo esc_html( $order->get_payment_method_title() ); ?></span>
271 </td>
272 </tr>
273 <?php endif; ?>
274 <?php if ( 0 < count( $action_buttons ) ) : ?>
275 <tr>
276 <td><?php echo esc_html_e( 'Actions', 'subscription' ); ?></td>
277 <td class="subscrpt_action_buttons">
278 <?php foreach ( $action_buttons as $action_button ) : ?>
279 <a href="<?php echo esc_attr( $action_button['url'] ); ?>" class="button
280 <?php
281 if ( isset( $action_button['class'] ) ) {
282 echo esc_attr( $action_button['class'] );}
283 ?>
284 <?php echo esc_attr( $wp_button_class ); ?>"><?php echo esc_html( $action_button['label'] ); ?></a>
285 <?php endforeach; ?>
286 </td>
287 </tr>
288 <?php endif; ?>
289 </tbody>
290 </table>
291
292 <?php do_action( 'subscrpt_before_subscription_totals', (int) $id ); ?>
293
294 <h2><?php echo esc_html_e( 'Subscription Totals', 'subscription' ); ?></h2>
295 <table class="woocommerce-table woocommerce-table--order-details shop_table order_details">
296 <thead>
297 <tr>
298 <th class="product-name"><?php echo esc_html_e( 'Product', 'subscription' ); ?></th>
299 <th class="product-total"><?php echo esc_html_e( 'Total', 'subscription' ); ?></th>
300 </tr>
301 </thead>
302 <tbody>
303 <?php
304 $product_name = $order_item->get_name();
305 $product_link = get_permalink( $order_item->get_variation_id() !== 0 ? $order_item->get_variation_id() : $order_item->get_product_id() );
306 $order_item_meta = $order_item->get_meta( '_subscrpt_meta', true );
307 $time = '1' === $order_item_meta['time'] ? null : $order_item_meta['time'];
308 $type = subscrpt_get_typos( $order_item_meta['time'], $order_item_meta['type'] );
309 $product_price_html = Helper::format_price_with_order_item( $price, $order_item->get_id() );
310 ?>
311 <tr class="order_item">
312 <td class="product-name">
313 <a href="<?php echo esc_html( $product_link ); ?>"><?php echo esc_html( $product_name ); ?></a>
314 <strong class="product-quantity">× <?php echo esc_html( $order_item->get_quantity() ); ?></strong>
315 <?php
316 $plan_label = function_exists( 'subscrpt_get_subscription_plan_label' ) ? subscrpt_get_subscription_plan_label( $id ) : '';
317 if ( $plan_label ) :
318 ?>
319 <span class="subscrpt-plan-term"><?php printf( /* translators: %s: plan name. */ esc_html__( 'Plan: %s', 'subscription' ), esc_html( $plan_label ) ); ?></span>
320 <?php endif; ?>
321 </td>
322 <td class="product-total">
323 <span class="woocommerce-Price-amount amount">
324 <?php
325 $unit_price = (float) get_post_meta( $id, '_subscrpt_price', true );
326 $display_price = $unit_price * max( 1, (int) $order_item->get_quantity() );
327 echo wp_kses_post( Helper::format_price_with_order_item( $display_price, $order_item->get_id() ) );
328 ?>
329 </span>
330 </td>
331 </tr>
332 </tbody>
333 <tfoot>
334 <tr>
335 <th scope="row"><?php esc_html_e( 'Subtotal', 'subscription' ); ?>:</th>
336 <td>
337 <span class="woocommerce-Price-amount amount">
338 <?php echo wp_kses_post( wc_price( $price_excl_tax, array( 'currency' => $order->get_currency() ) ) ); ?>
339 </span>
340 </td>
341 </tr>
342
343 <?php if ( ! empty( $discount ) && $discount > 0 ) : ?>
344 <tr class="subscrpt-recurring-discount">
345 <th scope="row"><?php esc_html_e( 'Discount', 'subscription' ); ?>:</th>
346 <td>
347 <span class="woocommerce-Price-amount amount">
348 <?php
349 printf(
350 '-%s',
351 wp_kses_post( wc_price( $discount, array( 'currency' => $order->get_currency() ) ) )
352 );
353 ?>
354 </span>
355 </td>
356 </tr>
357 <?php endif; ?>
358
359 <?php if ( $tax > 0 ) : ?>
360 <tr>
361 <th scope="row"><?php esc_html_e( 'Tax', 'subscription' ); ?>:</th>
362 <td>
363 <span class="woocommerce-Price-amount amount">
364 <?php echo wp_kses_post( wc_price( $tax, array( 'currency' => $order->get_currency() ) ) ); ?>
365 </span>
366 </td>
367 </tr>
368 <?php endif; ?>
369
370 <tr>
371 <th scope="row"><?php esc_html_e( 'Renew', 'subscription' ); ?>:</th>
372 <td>
373 <span class="woocommerce-Price-amount amount">
374 <?php echo wp_kses_post( $product_price_html ); ?>
375 </span>
376 </td>
377 </tr>
378 </tfoot>
379 </table>
380
381 <?php do_action( 'subscrpt_after_subscription_totals', (int) $id ); ?>
382
383 <!-- Show related subscription orders -->
384 <?php
385 /*
386 * Sequence number within this subscription: 1 = first (parent) order, then each
387 * renewal in order. Helper::get_related_orders() returns newest-first, so the
388 * map is built from the reversed list. Relations whose order no longer exists
389 * are skipped here as well, keeping the numbering gapless with the rendered rows.
390 */
391 $related_order_seq = [];
392 foreach ( array_reverse( $related_orders ) as $subscrpt_relation ) {
393 if ( isset( $related_order_seq[ $subscrpt_relation->order_id ] ) || ! wc_get_order( $subscrpt_relation->order_id ) ) {
394 continue;
395 }
396 $related_order_seq[ $subscrpt_relation->order_id ] = count( $related_order_seq ) + 1;
397 }
398 ?>
399 <h2><?php echo esc_html_e( 'Related Orders', 'subscription' ); ?></h2>
400 <table class="woocommerce-table woocommerce-table--order-details shop_table order_details">
401 <thead>
402 <tr>
403 <th class="order-number"><?php echo esc_html_e( '#', 'subscription' ); ?></th>
404 <th class="order-type"><?php echo esc_html_e( 'Type', 'subscription' ); ?></th>
405 <th class="order-date"><?php echo esc_html_e( 'Date', 'subscription' ); ?></th>
406 <th class="order-status"><?php echo esc_html_e( 'Status', 'subscription' ); ?></th>
407 <th class="order-total"><?php echo esc_html_e( 'Total', 'subscription' ); ?></th>
408 </tr>
409 </thead>
410 <tbody>
411 <?php if ( empty( $related_orders ) ) : ?>
412 <tr class="order_item">
413 <td colspan="5" class="no-orders">
414 <?php echo esc_html_e( 'No related orders found.', 'subscription' ); ?>
415 </td>
416 </tr>
417 <?php endif; ?>
418
419 <?php foreach ( $related_orders as $related_order ) : ?>
420 <?php
421 $order_id = $related_order->order_id;
422 $order = wc_get_order( $order_id );
423 if ( ! $order ) {
424 continue;
425 }
426
427 $order_type = $related_order->type;
428 $order_type_label = wps_subscription_order_relation_type_cast( $order_type );
429
430 $order_created_date = $order->get_date_created()->date_i18n( get_option( 'date_format' ) );
431
432 $order_status = $order->get_status();
433 $order_status_name = wc_get_order_status_name( $order_status );
434
435 $order_total = $order->get_total();
436 $formatted_order_total = wc_price( $order_total, array( 'currency' => $order->get_currency() ) );
437 ?>
438
439 <tr class="order_item">
440 <td class="order-number">
441 <?php
442 // translators: %s: WooCommerce order number.
443 $order_number_label = sprintf( __( 'Order #%s', 'subscription' ), $order->get_order_number() );
444 ?>
445 <a href="<?php echo esc_url( wc_get_endpoint_url( 'view-order', $order_id, wc_get_page_permalink( 'myaccount' ) ) ); ?>" title="<?php echo esc_attr( $order_number_label ); ?>" aria-label="<?php echo esc_attr( $order_number_label ); ?>">
446 <?php echo esc_html( number_format_i18n( $related_order_seq[ $order_id ] ?? 0 ) ); ?>
447 </a>
448 </td>
449 <td class="order-type">
450 <?php echo esc_html( $order_type_label ); ?>
451 </td>
452 <td class="order-date">
453 <?php echo esc_html( $order_created_date ); ?>
454 </td>
455 <td class="order-status">
456 <span class="order-status-<?php echo esc_attr( $order_status ); ?>">
457 <?php echo esc_html( $order_status_name ); ?>
458 </span>
459 </td>
460 <td class="order-total">
461 <?php echo wp_kses_post( $formatted_order_total ); ?>
462 </td>
463 </tr>
464 <?php endforeach; ?>
465 </tbody>
466 </table>
467
468 <section class="woocommerce-customer-details">
469 <h2 class="woocommerce-column__title"><?php esc_html_e( 'Billing address', 'subscription' ); ?></h2>
470 <address>
471 <?php echo wp_kses_post( $order->get_formatted_billing_address() ); ?>
472 <p class="woocommerce-customer-details--phone"><?php echo esc_html( $order->get_billing_phone() ); ?></p>
473 <p class="woocommerce-customer-details--email"><?php echo esc_html( $order->get_billing_email() ); ?></p>
474 </address>
475 </section>
476 <div class="clear"></div>
477