PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 1.10.2
Subscriptions for WooCommerce with Stripe Recurring Payments v1.10.2
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 1.4.1 1.4.2 1.5.0 1.5.1 All 61 releases
subscription / includes / Admin / Subscriptions.php

Subscriptions.php in Subscriptions for WooCommerce with Stripe Recurring Payments 1.10.2, at includes/Admin/Subscriptions.php

1,035 lines 34.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace SpringDevs\Subscription\Admin;
4
5 use SpringDevs\Subscription\Illuminate\Action;
6 use SpringDevs\Subscription\Illuminate\Helper;
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, 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
13 /**
14 * Subscriptions class
15 *
16 * @package SpringDevs\Subscription\Admin
17 */
18 class Subscriptions {
19
20
21 /**
22 * Initialize the class.
23 */
24 public function __construct() {
25 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
26 add_filter( 'post_row_actions', array( $this, 'post_row_actions' ) );
27 add_filter( 'manage_subscrpt_order_posts_columns', array( $this, 'add_custom_columns' ) );
28 add_action( 'manage_subscrpt_order_posts_custom_column', array( $this, 'add_custom_columns_data' ), 10, 2 );
29 add_action( 'add_meta_boxes', array( $this, 'create_meta_boxes' ) );
30 add_action( 'admin_head-post.php', array( $this, 'some_styles' ) );
31 add_action( 'admin_head-post-new.php', array( $this, 'some_styles' ) );
32 add_action( 'admin_footer-post.php', array( $this, 'some_scripts' ) );
33 add_action( 'admin_footer-post-new.php', array( $this, 'some_scripts' ) );
34 add_action( 'save_post', array( $this, 'save_subscrpt_order' ) );
35 add_filter( 'woocommerce_order_item_get_formatted_meta_data', array( $this, 'remove_order_meta' ), 10, 1 );
36 add_filter( 'bulk_actions-edit-subscrpt_order', array( $this, 'remove_bulk_actions' ) );
37 add_action( 'restrict_manage_posts', array( $this, 'add_subscription_filter_select' ) );
38 add_action( 'admin_menu', array( $this, 'add_overview_submenu' ), 40 );
39 add_action( 'edit_form_after_title', array( $this, 'display_subscription_details_section' ) );
40
41 add_action( 'admin_head-post.php', [ $this, 'add_back_to_list_button' ] );
42 }
43
44 /**
45 * Remove 'Edit` and 'Trash' from bulk actions.
46 *
47 * @param array $actions Action list.
48 *
49 * @return array
50 */
51 public function remove_bulk_actions( $actions ) {
52 unset( $actions['edit'] );
53 unset( $actions['trash'] );
54
55 return $actions;
56 }
57
58 /**
59 * Hide order meta key from custom fields.
60 *
61 * @param array $formatted_meta Data with key-value.
62 *
63 * @return array
64 */
65 public function remove_order_meta( $formatted_meta ): array {
66 $temp_metas = array();
67 foreach ( $formatted_meta as $key => $meta ) {
68 if ( isset( $meta->key ) && '_renew_subscrpt' !== $meta->key ) {
69 $temp_metas[ $key ] = $meta;
70 }
71 }
72
73 return $temp_metas;
74 }
75
76 /**
77 * Enqueue admin assets.
78 *
79 * @return void
80 */
81 public function enqueue_scripts() {
82 wp_enqueue_style( 'subscrpt_admin_css' );
83 wp_enqueue_style( 'subscrpt_status_css' );
84 }
85
86 /**
87 * Remove default post actions.
88 *
89 * @param array $actions Actions.
90 *
91 * @return array
92 */
93 public function post_row_actions( $actions ) {
94 global $current_screen;
95 if ( 'subscrpt_order' !== $current_screen->post_type ) {
96 return $actions;
97 }
98 unset( $actions['inline hide-if-no-js'] );
99 unset( $actions['view'] );
100 unset( $actions['trash'] );
101 unset( $actions['edit'] );
102
103 return $actions;
104 }
105
106 /**
107 * Register custom columns.
108 *
109 * @param array $columns Columns.
110 *
111 * @return array
112 */
113 public function add_custom_columns( $columns ) {
114 $columns['subscrpt_start_date'] = __( 'Start Date', 'subscription' );
115 $columns['subscrpt_customer'] = __( 'Customer', 'subscription' );
116 $columns['subscrpt_next_date'] = __( 'Next Date', 'subscription' );
117 $columns['subscrpt_status'] = __( 'Status', 'subscription' );
118 unset( $columns['date'] );
119 unset( $columns['cb'] );
120
121 return $columns;
122 }
123
124 /**
125 * Display column data.
126 *
127 * @param string $column Column.
128 * @param int $post_id Post Id.
129 *
130 * @return void
131 */
132 public function add_custom_columns_data( $column, $post_id ) {
133 // HPOS: Safe. Only retrieves WooCommerce order via CRUD, and subscription meta via post meta.
134 $order_id = get_post_meta( $post_id, '_subscrpt_order_id', true ); // HPOS: Only subscription meta, not order meta.
135 $order = wc_get_order( $order_id ); // HPOS: Safe, uses WooCommerce CRUD.
136 if ( $order ) {
137 if ( 'subscrpt_start_date' === $column ) {
138 $start_date = get_post_meta( $post_id, '_subscrpt_start_date', true );
139 echo ! empty( $start_date ) ? esc_html( wp_date( 'F d, Y', $start_date ) ) : '-';
140 } elseif ( 'subscrpt_customer' === $column ) {
141 ?>
142 <?php echo wp_kses_post( $order->get_formatted_billing_full_name() ); ?>
143 <br />
144 <a href="mailto:<?php echo wp_kses_post( $order->get_billing_email() ); ?>"><?php echo wp_kses_post( $order->get_billing_email() ); ?></a>
145 <br />
146 <?php if ( ! empty( $order->get_billing_phone() ) ) : ?>
147 Phone : <a
148 href="tel:<?php echo esc_js( $order->get_billing_phone() ); ?>"><?php echo esc_js( $order->get_billing_phone() ); ?></a>
149 <?php endif; ?>
150 <?php
151 } elseif ( 'subscrpt_next_date' === $column ) {
152 $next_date = get_post_meta( $post_id, '_subscrpt_next_date', true );
153 echo ! empty( $next_date ) ? esc_html( wp_date( 'F d, Y', $next_date ) ) : '-';
154 } elseif ( 'subscrpt_status' === $column ) {
155 $status_obj = get_post_status_object( get_post_status( $post_id ) );
156 ?>
157 <span
158 class="subscrpt-<?php echo esc_html( $status_obj->name ); ?>"><?php echo esc_html( $status_obj->label ); ?></span>
159 <?php
160 }
161 } else {
162 esc_html_e( 'Order not found !!', 'subscription' );
163 }
164 }
165
166 /**
167 * Create meta boxes for admin subscriptions.
168 */
169 public function create_meta_boxes() {
170 remove_meta_box( 'submitdiv', 'subscrpt_order', 'side' );
171 add_meta_box(
172 'subscrpt_order_save_post',
173 __( 'Subscription Action', 'subscription' ),
174 array( $this, 'subscrpt_order_save_post' ),
175 'subscrpt_order',
176 'side',
177 'default'
178 );
179
180 add_meta_box(
181 'subscrpt_customer_info',
182 __( 'Customer Details', 'subscription' ),
183 array( $this, 'customer_info' ),
184 'subscrpt_order',
185 'side',
186 'default'
187 );
188
189 // Removed the redundant subscription info meta box as it's now shown prominently above
190
191 add_meta_box(
192 'subscrpt_order_history',
193 __( 'Related Orders', 'subscription' ),
194 array( $this, 'order_histories' ),
195 'subscrpt_order',
196 'normal',
197 'default'
198 );
199
200 add_meta_box(
201 'subscrpt_order_activities',
202 __( 'Subscription Activities', 'subscription' ),
203 array( $this, 'order_activities' ),
204 'subscrpt_order',
205 'normal',
206 'default'
207 );
208 }
209
210 /**
211 * Display Order Histories.
212 *
213 * @param \WP_Post $post Post Object.
214 *
215 * @return void
216 */
217 public function order_histories( $post ) {
218 $subscription_id = $post->ID;
219 global $wpdb;
220 $table_name = $wpdb->prefix . 'subscrpt_order_relation';
221
222 // @phpcs:ignore
223 $order_histories = $wpdb->get_results(
224 $wpdb->prepare(
225 'SELECT * FROM %i WHERE subscription_id=%d ORDER BY id DESC',
226 array(
227 $table_name,
228 $subscription_id,
229 )
230 )
231 );
232
233 include 'views/order-history.php';
234 }
235
236 /**
237 * Display Order Activities
238 *
239 * @param \WP_Post $post Post Object.
240 *
241 * @return void
242 */
243 public function order_activities( $post ) {
244 if ( function_exists( 'subscrpt_pro_activated' ) ) :
245 if ( subscrpt_pro_activated() ) :
246 do_action( 'subscrpt_order_activities', $post->ID );
247 else :
248 ?>
249 <div class="wp-subscription-admin-box wp-subscription-upgrade-pro-banner" style="margin-bottom:18px;display:flex;align-items:center;gap:18px;justify-content:space-between;background:linear-gradient(90deg,#38bdf8 0%,#6366f1 100%);border-radius:10px;padding:22px 28px;box-shadow:0 2px 12px rgba(56,189,248,0.08);color:#fff;">
250 <div style="flex:1;">
251 <div style="display:flex;align-items:center;gap:14px;">
252 <span style="font-size:2.2em;line-height:1;">🚀</span>
253 <span style="font-family:Georgia,serif;font-size:1.25em;font-weight:bold;">Upgrade to WPSubscription Pro</span>
254 </div>
255 <div style="margin-top:8px;font-size:1.08em;max-width:500px;opacity:0.95;">
256 Unlock advanced features, automation, and priority support. Take your subscription business to the next level!
257 </div>
258 </div>
259 <div style="flex-shrink:0;">
260 <a href="https://wpsubscription.co/" target="_blank" class="button button-primary" style="background:#fff;color:#6366f1;font-weight:600;font-size:1.08em;padding:12px 28px;border:none;box-shadow:0 2px 8px rgba(99,102,241,0.10);border-radius:6px;">Upgrade to Pro</a>
261 </div>
262 </div>
263 <?php
264 endif;
265 endif;
266 }
267
268 /**
269 * Save subscription HTML.
270 */
271 public function subscrpt_order_save_post() {
272 $actions_data = array(
273 'active' => array(
274 'label' => __( 'Activate Subscription', 'subscription' ),
275 'value' => 'active',
276 ),
277 'pending' => array(
278 'label' => __( 'Pending Subscription', 'subscription' ),
279 'value' => 'pending',
280 ),
281 'expire' => array(
282 'label' => __( 'Expire Subscription', 'subscription' ),
283 'value' => 'expired',
284 ),
285 'pe_cancelled' => array(
286 'label' => __( 'Pending Cancel Subscription', 'subscription' ),
287 'value' => 'pe_cancelled',
288 ),
289 'cancelled' => array(
290 'label' => __( 'Cancel Subscription', 'subscription' ),
291 'value' => 'cancelled',
292 ),
293 );
294
295 $map_actions = array(
296 'pending' => array( 'active', 'cancelled' ),
297 'active' => array( 'pe_cancelled', 'cancelled' ),
298 'pe_cancelled' => array( 'active', 'cancelled' ),
299 'cancelled' => array( 'active' ),
300 'expired' => array(),
301 );
302
303 $status = get_post_status( get_the_ID() );
304 $actions = $map_actions[ $status ];
305
306 include 'views/subscription-save-meta.php';
307 }
308
309 /**
310 * Display Customer Info
311 *
312 * @param \WP_Post $post Post Object.
313 *
314 * @return void
315 */
316 public function customer_info( $post ) {
317 $order_id = get_post_meta( $post->ID, '_subscrpt_order_id', true );
318 $order = wc_get_order( $order_id );
319 if ( ! $order ) {
320 return;
321 }
322 include 'views/subscription-customer.php';
323 }
324
325 /**
326 * Display subscription info.
327 *
328 * @return void
329 */
330 public function subscrpt_order_info() {
331 $order_id = get_post_meta( get_the_ID(), '_subscrpt_order_id', true );
332 $order_item_id = get_post_meta( get_the_ID(), '_subscrpt_order_item_id', true );
333 $trial = get_post_meta( get_the_ID(), '_subscrpt_trial', true );
334 $start_date = get_post_meta( get_the_ID(), '_subscrpt_start_date', true );
335 $next_date = get_post_meta( get_the_ID(), '_subscrpt_next_date', true );
336 $trial_start_date = get_post_meta( get_the_ID(), '_subscrpt_trial_started', true );
337 $trial_end_date = get_post_meta( get_the_ID(), '_subscrpt_trial_ended', true );
338 $trial_mode = get_post_meta( get_the_ID(), '_subscrpt_trial_mode', true );
339 $order = wc_get_order( $order_id );
340 if ( ! $order ) {
341 return;
342 }
343 $order_item = $order->get_item( $order_item_id );
344
345 $product_name = $order_item->get_name();
346 $product_link = get_the_permalink( $order_item->get_product_id() );
347
348 // Get payment information
349 $product_id = $order_item->get_product_id(); // get_post_meta( get_the_ID(), '_subscrpt_product_id', true );
350 $max_payments = subscrpt_get_max_payments( get_the_ID() ) ?: 0;
351 $payments_made = subscrpt_count_payments_made( get_the_ID() );
352
353 $rows = array(
354 'product' => array(
355 'label' => __( 'Product', 'subscription' ),
356 'value' => '<a href="' . esc_html( $product_link ) . '" target="_blank">' . esc_html( $product_name ) . '</a>',
357 ),
358 'cost' => array(
359 'label' => __( 'Cost', 'subscription' ),
360 'value' => Helper::format_price_with_order_item( get_post_meta( get_the_ID(), '_subscrpt_price', true ), $order_item->get_id() ),
361 ),
362 'quantity' => array(
363 'label' => __( 'Qty', 'subscription' ),
364 'value' => "x{$order_item->get_quantity()}",
365 ),
366 );
367
368 // Add payment information if max_payments is set and not unlimited
369 if ( ! empty( $max_payments ) && $max_payments > 0 ) {
370 $rows['total_payments'] = array(
371 'label' => __( 'Total Payments', 'subscription' ),
372 'value' => esc_html( $payments_made ) . ' / ' . esc_html( $max_payments ),
373 );
374 }
375
376 $rows += array(
377 'start_date' => array(
378 'label' => __( 'Started date', 'subscription' ),
379 'value' => ! empty( $start_date ) ? wp_date( 'F d, Y', $trial && $trial_start_date ? $trial_start_date : $start_date ) : '-',
380 ),
381 'next_date' => array(
382 'label' => __( 'Payment due date', 'subscription' ),
383 'value' => ! empty( $next_date ) ? wp_date( 'F d, Y', $trial && $trial_end_date && 'on' === $trial_mode ? $trial_end_date : ( $next_date ?? '-' ) ) : '-',
384 ),
385 'status' => array(
386 'label' => __( 'Status', 'subscription' ),
387 'value' => '<span class="subscrpt-' . get_post_status() . '">' . get_post_status_object( get_post_status() )->label . '</span>',
388 ),
389 'payment_method' => array(
390 'label' => __( 'Payment Method', 'subscription' ),
391 'value' => empty( $order->get_payment_method_title() ) ? '-' : $order->get_payment_method_title(),
392 ),
393 'billing_address' => array(
394 'label' => __( 'Billing', 'subscription' ),
395 'value' => $order->get_formatted_billing_address() ? $order->get_formatted_billing_address() : __( 'No billing address set.', 'subscription' ),
396 ),
397 'shipping_address' => array(
398 'label' => __( 'Shipping', 'subscription' ),
399 'value' => $order->get_formatted_shipping_address() ? $order->get_formatted_shipping_address() : __( 'No shipping address set.', 'subscription' ),
400 ),
401 );
402 if ( $trial ) {
403 $rows = array_slice( $rows, 0, 3, true ) + array(
404 'trial' => array(
405 'label' => __( 'Trial', 'subscription' ),
406 'value' => $trial,
407 ),
408 'trial_period' => array(
409 'label' => __( 'Trial Period', 'subscription' ),
410 'value' => ( $trial_start_date && $trial_end_date ? ' [ ' . wp_date( 'F d, Y', $trial_start_date ) . ' - ' . wp_date( 'F d, Y', $trial_end_date ) . ' ] ' : __( 'Trial isn\'t activated yet! ', 'subscription' ) ),
411 ),
412 ) + array_slice( $rows, 3, count( $rows ) - 1, true );
413 }
414
415 if ( class_exists( 'WC_Stripe' ) && 'stripe' === $order->get_payment_method() ) {
416 $is_auto_renew = get_post_meta( get_the_ID(), '_subscrpt_auto_renew', true );
417 $new_rows = array();
418 foreach ( $rows as $key => $value ) {
419 $new_rows[ $key ] = $value;
420 if ( 'payment_method' === $key ) {
421 $new_rows['stripe_auto_renewal'] = array(
422 'label' => __( 'Stripe Auto Renewal', 'subscription' ),
423 'value' => '0' !== $is_auto_renew ? 'On' : 'Off',
424 );
425 }
426 }
427
428 $rows = $new_rows;
429 }
430
431 $rows = apply_filters( 'subscrpt_admin_info_rows', $rows, get_the_ID(), $order );
432
433 include 'views/subscription-info.php';
434 }
435
436 /**
437 * Display a prominent subscription details section.
438 *
439 * @param \WP_Post $post The post object.
440 *
441 * @return void
442 */
443 public function display_subscription_details_section( $post ) {
444 // Only display for subscription post type
445 if ( 'subscrpt_order' !== $post->post_type ) {
446 return;
447 }
448
449 $subscription_id = $post->ID;
450 $subscription_data = Helper::get_subscription_data( $subscription_id );
451
452 $order_id = $subscription_data['order']['order_id'] ?? 0;
453 $order = $order_id ? wc_get_order( $order_id ) : null;
454
455 $order_item_id = $subscription_data['order']['order_item_id'] ?? 0;
456 $order_item = $order ? $order->get_item( $order_item_id ) : null;
457
458 if ( ! $order || ! $order_item ) {
459 return;
460 }
461
462 $product_id = $subscription_data['product']['product_id'] ?? 0;
463 $max_payments = ! empty( subscrpt_get_max_payments( $subscription_id ) ) ? subscrpt_get_max_payments( $subscription_id ) : 0;
464 $payments_made = subscrpt_count_payments_made( $subscription_id );
465
466 // Get subscription details
467 $product = wc_get_product( $product_id );
468 $subscrpt_type = $subscription_data['schedule']['timing_option'] ?? '';
469 $subscrpt_time = $subscription_data['schedule']['timing_per'] ?? '';
470
471 $trial_type = $subscription_data['trial']['timing_option'] ?? 'days';
472 $trial_time = $subscription_data['trial']['timing_per'] ?? 0;
473
474 $signup_fee = $subscription_data['signup_fee'] ?? '';
475
476 $quantity = (int) $order_item->get_quantity();
477 $cost = (float) ( $subscription_data['price'] ?? 0 ) * max( 1, $quantity );
478 $cost = empty( $cost ) ? (float) $order_item->get_total() : $cost;
479
480 $price_excl_tax = (float) $order_item->get_total();
481 $tax_amount = (float) $order_item->get_total_tax();
482 if ( $tax_amount > 0 ) {
483 $cost = $price_excl_tax + $tax_amount;
484 $cost = number_format( (float) $cost, 2, '.', '' );
485 }
486
487 $subscrpt_status = $subscription_data['status'] ?? '';
488 $verbose_status = Helper::get_verbose_status( $subscrpt_status );
489
490 $started_date = $subscription_data['start_date'] ?? '';
491 $started_date = ! empty( $started_date ) ? wp_date( 'F j, Y - g:i A', strtotime( $started_date ) ) : '-';
492
493 $next_payment_date = $subscription_data['next_date'] ?? '';
494 $next_payment_date = ! empty( $next_payment_date ) ? wp_date( 'F j, Y - g:i A', strtotime( $next_payment_date ) ) : '-';
495
496 $is_grace_period = isset( $subscription_data['grace_period'] );
497 $grace_remaining = $subscription_data['grace_period']['remaining_days'] ?? 0;
498 $grace_end_date = $subscription_data['grace_period']['end_date'] ?? '';
499 $grace_end_date = ! empty( $grace_end_date ) ? wp_date( 'F j, Y - g:i A', strtotime( $grace_end_date ) ) : '';
500
501 ?>
502 <div class="wp-subscription-details-section">
503 <h2 style="margin: 0 0 20px 0; padding: 0; border-bottom: 1px solid #ddd; padding-bottom: 12px;">
504 <?php
505 $text = sprintf(
506 // translators: Subscription ID.
507 __( 'Subscription #%d details', 'subscription' ),
508 $post->ID
509 );
510 echo esc_html( $text );
511 ?>
512 </h2>
513
514 <div class="subscription-details-grid">
515 <!-- Primary Information -->
516 <div class="details-group primary">
517 <h3><?php esc_html_e( 'General', 'subscription' ); ?></h3>
518 <table>
519 <tr>
520 <th><?php esc_html_e( 'Status', 'subscription' ); ?></th>
521 <td>
522 <?php if ( $is_grace_period && $grace_remaining > 0 ) : ?>
523 <span class="subscrpt-active grace-active">
524 Active
525
526 <?php
527 $grace_remaining_text = sprintf(
528 // translators: Number of days remaining in grace period.
529 __( '%d days remaining!', 'subscription' ),
530 $grace_remaining
531 );
532 ?>
533 <span class="grace-icon" data-tooltip="<?php echo esc_attr( $grace_remaining_text ); ?>">
534 <span class="dashicons dashicons-warning"></span>
535 </span>
536 </span>
537 <?php else : ?>
538 <span class="subscrpt-<?php echo esc_attr( strtolower( $subscrpt_status ) ); ?>">
539 <?php echo esc_html( $verbose_status ); ?>
540 </span>
541 <?php endif; ?>
542 </td>
543 </tr>
544 <tr>
545 <th><?php esc_html_e( 'Product', 'subscription' ); ?></th>
546 <td><a href="<?php echo esc_url( get_the_permalink( $order_item->get_product_id() ) ); ?>" target="_blank"><?php echo esc_html( $order_item->get_name() ); ?></a></td>
547 </tr>
548 </table>
549 </div>
550
551 <!-- Subscription Terms -->
552 <div class="details-group">
553 <h3><?php esc_html_e( 'Subscription Terms', 'subscription' ); ?></h3>
554 <table>
555 <tr>
556 <th><?php esc_html_e( 'Billing', 'subscription' ); ?></th>
557 <td>
558 <?php echo wp_kses_post( wc_price( $cost ) ); ?> /
559 <?php
560 echo esc_html( $subscrpt_time > 1 ? $subscrpt_time . '-' : '' );
561 ?>
562 <?php
563 echo esc_html( $subscrpt_type );
564 ?>
565 </td>
566 </tr>
567
568 <?php if ( $signup_fee ) : ?>
569 <tr>
570 <th><?php esc_html_e( 'Signup Fee', 'subscription' ); ?></th>
571 <td><?php echo wp_kses_post( wc_price( $signup_fee ) ); ?></td>
572 </tr>
573 <?php endif; ?>
574
575 <?php if ( $trial_time ) : ?>
576 <tr>
577 <th><?php esc_html_e( 'Free Trial', 'subscription' ); ?></th>
578 <td><?php echo esc_html( $trial_time . ' ' . $trial_type ); ?></td>
579 </tr>
580 <?php endif; ?>
581
582 <?php if ( ! empty( $max_payments ) && $max_payments > 0 ) : ?>
583 <tr>
584 <th><?php esc_html_e( 'Total Payments', 'subscription' ); ?></th>
585 <td><strong><?php echo esc_html( $payments_made . ' / ' . $max_payments ); ?></strong></td>
586 </tr>
587 <?php endif; ?>
588 </table>
589 </div>
590
591 <!-- Schedule Dates -->
592 <div class="details-group">
593 <h3><?php esc_html_e( 'Schedule Dates', 'subscription' ); ?></h3>
594 <table>
595 <tr>
596 <th><?php esc_html_e( 'Started', 'subscription' ); ?></th>
597 <td><?php echo esc_html( $started_date ); ?></td>
598 </tr>
599 <tr>
600 <th><?php esc_html_e( 'Next Payment', 'subscription' ); ?></th>
601 <td><?php echo esc_html( $next_payment_date ); ?></td>
602 </tr>
603 </table>
604 </div>
605
606 <!-- Grace Period Info -->
607 <?php if ( $is_grace_period ) : ?>
608 <div class="details-group">
609 <h3><?php esc_html_e( 'Grace Period', 'subscription' ); ?></h3>
610 <table>
611 <tr>
612 <th><?php esc_html_e( 'Remaining', 'subscription' ); ?></th>
613 <td><?php echo esc_html( $grace_remaining . ' days' ); ?></td>
614 </tr>
615 <tr>
616 <th><?php esc_html_e( 'End Date', 'subscription' ); ?></th>
617 <td><?php echo esc_html( $grace_end_date ); ?></td>
618 </tr>
619 </table>
620 </div>
621 <?php endif; ?>
622 </div>
623 </div>
624 <?php
625 }
626
627 /**
628 * Include some styles.
629 *
630 * @return void
631 */
632 public function some_styles() {
633 global $post;
634 if ( 'subscrpt_order' === $post->post_type ) :
635 ?>
636 <style>
637 .submitbox {
638 display: flex;
639 justify-content: space-around;
640 }
641
642 .subscrpt_sub_box {
643 display: grid;
644 line-height: 2;
645 }
646
647 /* Hide WordPress title area margin */
648 #poststuff #post-body.columns-2 {
649 margin-right: 300px;
650 }
651
652 /* Clean, minimal details section */
653 .wp-subscription-details-section {
654 margin: 20px 0 30px 0;
655 padding: 20px;
656 border: 1px solid #ddd;
657 background: #fff;
658 }
659
660 /* Grid layout for organized sections */
661 .subscription-details-grid {
662 display: grid;
663 grid-template-columns: 1fr 1fr;
664 gap: 30px;
665 margin-top: 20px;
666 }
667
668 @media (max-width: 782px) {
669 .subscription-details-grid {
670 grid-template-columns: 1fr;
671 }
672 }
673
674 /* Details group styling */
675 .details-group h3 {
676 margin: 0 0 12px 0;
677 padding: 0 0 8px 0;
678 border-bottom: 1px solid #eee;
679 font-size: 14px;
680 font-weight: 600;
681 color: #555;
682 text-transform: uppercase;
683 letter-spacing: 0.5px;
684 }
685
686 .details-group.primary h3 {
687 color: #333;
688 }
689
690 .details-group table {
691 width: 100%;
692 border-collapse: collapse;
693 }
694
695 .details-group table th {
696 text-align: left;
697 padding: 8px 12px 8px 0;
698 font-weight: 500;
699 color: #666;
700 width: 40%;
701 vertical-align: top;
702 font-size: 13px;
703 }
704
705 .details-group table td {
706 padding: 8px 0;
707 color: #333;
708 font-size: 13px;
709 line-height: 1.4;
710 }
711
712 .details-group table tr {
713 border-bottom: 1px solid #f5f5f5;
714 }
715
716 .details-group table tr:last-child {
717 border-bottom: none;
718 }
719
720 /* Simple status badge */
721 .status-badge {
722 display: inline-block;
723 padding: 2px 8px;
724 border-radius: 3px;
725 font-size: 12px;
726 font-weight: 500;
727 text-transform: capitalize;
728 background: #f5f5f5;
729 color: #666;
730 border: 1px solid #ddd;
731 }
732
733 /* Clean links */
734 .details-group a {
735 color: #0073aa;
736 text-decoration: none;
737 }
738
739 .details-group a:hover {
740 text-decoration: underline;
741 }
742
743 /* Meta box styling improvements */
744 .postbox {
745 border: 1px solid #ddd;
746 }
747
748 .postbox .hndle {
749 border-bottom: 1px solid #eee;
750 background: #fafafa;
751 }
752
753 #subscrpt_order_history .inside table,
754 #subscrpt_order_activities .inside table {
755 border: none;
756 }
757 </style>
758 <?php
759 endif;
760 }
761
762 /**
763 * Disable changes popup.
764 *
765 * @return void
766 */
767 public function some_scripts() {
768 global $post;
769 if ( 'subscrpt_order' === $post->post_type ) :
770 ?>
771 <script>
772 jQuery(document).ready(function() {
773 jQuery(window).off('beforeunload', null);
774 });
775 </script>
776 <?php
777 endif;
778 }
779
780 public function save_subscrpt_order( $post_id ) {
781 if ( wp_is_post_revision( $post_id ) || ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || ! isset( $_POST['subscrpt_order_action'] ) ) {
782 return;
783 }
784
785 // Verify nonce for security.
786 if ( ! isset( $_POST['subscrpt_order_action_nonce_field'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['subscrpt_order_action_nonce_field'] ) ), 'subscrpt_order_action_nonce' ) ) {
787 return;
788 }
789
790 // Check permissions.
791 if ( ! current_user_can( 'edit_post', $post_id ) ) {
792 return;
793 }
794 remove_all_actions( 'save_post' );
795
796 $action = sanitize_text_field( wp_unslash( $_POST['subscrpt_order_action'] ) );
797 $old_status = get_post_status( $post_id );
798
799 wp_update_post(
800 array(
801 'ID' => $post_id,
802 'post_status' => $action,
803 )
804 );
805
806 if ( $old_status !== $action ) {
807 $old_status_object = get_post_status_object( $old_status );
808 $new_status_object = get_post_status_object( $action );
809 WC()->mailer();
810 do_action( 'subscrpt_status_changed_admin_email_notification', $post_id, $old_status_object->label, $new_status_object->label );
811 }
812
813 $order_id = get_post_meta( $post_id, '_subscrpt_order_id', true );
814 if ( 'active' === $action ) {
815 $order = wc_get_order( $order_id );
816 $order->update_status( 'completed' );
817 Action::status( $action, $post_id );
818 } else {
819 Action::status( $action, $post_id );
820 }
821 }
822
823 public function add_subscription_filter_select() {
824 // Implementation of add_subscription_filter_select method
825 }
826
827 public function add_overview_submenu() {
828 // Remove and re-add submenu to ensure Overview is first
829 remove_submenu_page( 'edit.php?post_type=subscrpt_order', 'edit.php?post_type=subscrpt_order' );
830 add_submenu_page(
831 'edit.php?post_type=subscrpt_order',
832 __( 'Overview', 'subscription' ),
833 __( 'Overview', 'subscription' ),
834 'manage_options',
835 'subscription_overview',
836 array( $this, 'render_overview_page' ),
837 0
838 );
839 add_submenu_page(
840 'edit.php?post_type=subscrpt_order',
841 __( 'All Subscriptions', 'subscription' ),
842 __( 'All Subscriptions', 'subscription' ),
843 'manage_options',
844 'edit.php?post_type=subscrpt_order',
845 '',
846 1
847 );
848 if ( ! class_exists( 'Sdevs_Wc_Subscription_Pro' ) ) {
849 add_submenu_page(
850 'edit.php?post_type=subscrpt_order',
851 __( 'Go Pro', 'subscription' ),
852 __( 'Go Pro', 'subscription' ),
853 'manage_options',
854 'wp_subscription_go_pro',
855 array( $this, 'render_go_pro_page' ),
856 99
857 );
858 }
859 }
860
861 public function render_overview_page() {
862 ?>
863 <div class="wrap wpsubscription-overview" style="max-width:1100px;margin:40px auto 0 auto;">
864 <div class="wpsubscription-overview-card" style="background:#fff;border-radius:12px;box-shadow:0 2px 12px rgba(0,0,0,0.06);padding:40px 32px 32px 32px;">
865 <div class="wpsubscription-overview-top" style="display:grid;grid-template-columns:1fr 1fr;gap:40px;align-items:start;margin-bottom:40px;">
866 <div class="wpsubscription-overview-info" style="display:flex;flex-direction:column;gap:18px;">
867 <h1 style="margin-bottom:0.2em;"><?php esc_html_e( 'WPSubscription Overview', 'subscription' ); ?></h1>
868 <p class="product-desc" style="font-size:1.15em;line-height:1.6;max-width:500px;">
869 <?php esc_html_e( 'WPSubscription is the most seamless and reliable WooCommerce subscription solution for store owners looking to grow recurring revenue. Easily manage recurring payments, automate renewals, and delight your customers with flexible plans.', 'subscription' ); ?>
870 </p>
871 <div class="wpsubscription-links" style="display:flex;gap:12px;flex-wrap:wrap;">
872 <a href="https://docs.converslabs.com/en" target="_blank" class="button button-secondary"><?php esc_html_e( 'Documentation', 'subscription' ); ?></a>
873 <a href="https://wpsubscription.co/" target="_blank" class="button button-secondary"><?php esc_html_e( 'Website', 'subscription' ); ?></a>
874 </div>
875 </div>
876 <div class="promo-video" style="text-align:center;">
877 <iframe width="420" height="236" src="https://www.youtube.com/embed/2e6o5p0M7L4" title="WPSubscription Promo" frameborder="0" allowfullscreen style="max-width:100%;border-radius:8px;"></iframe>
878 </div>
879 </div>
880
881 <div class="wpsubscription-what-section" style="margin-bottom:40px;">
882 <h2><?php esc_html_e( 'What does Subscriptions for WooCommerce do?', 'subscription' ); ?></h2>
883 <p style="font-size:1.08em;max-width:900px;line-height:1.7;">
884 <?php esc_html_e( 'Subscriptions for WooCommerce enables you to create and manage recurring payment products and services with ease. Automate renewals, offer flexible billing schedules, and provide your customers with a seamless subscription experience. Whether you sell digital content, physical goods, or memberships, WPSubscription gives you the tools to grow your recurring revenue.', 'subscription' ); ?>
885 </p>
886 </div>
887
888 <h2 style="margin-top:2em;"><?php esc_html_e( 'Highlights', 'subscription' ); ?></h2>
889 <div class="wpsubscription-features-grid">
890 <div class="feature-box"><span class="dashicons dashicons-admin-generic"></span><h3>Easy Setup</h3><p>Get started in minutes with our intuitive onboarding wizard.</p></div>
891 <div class="feature-box"><span class="dashicons dashicons-money"></span><h3>Multiple Gateways</h3><p>Support for Stripe, PayPal, and Paddle out of the box.</p></div>
892 <div class="feature-box"><span class="dashicons dashicons-schedule"></span><h3>Flexible Plans</h3><p>Create and manage various subscription types and delivery schedules.</p></div>
893 <div class="feature-box"><span class="dashicons dashicons-chart-line"></span><h3>Comprehensive Dashboard</h3><p>Monitor and manage all subscriptions in one place.</p></div>
894 </div>
895 </div>
896 </div>
897 <style>
898 .wpsubscription-overview .promo-video { text-align:center; }
899 .wpsubscription-features-grid {
900 display: grid;
901 grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
902 gap: 24px;
903 margin-top: 32px;
904 }
905 .feature-box {
906 background: #fff;
907 border-radius: 10px;
908 box-shadow: 0 2px 8px rgba(0,0,0,0.06);
909 padding: 24px 18px 18px 18px;
910 text-align: center;
911 transition: transform 0.2s, box-shadow 0.2s;
912 will-change: transform;
913 }
914 .feature-box:hover {
915 transform: translateY(-6px) scale(1.03);
916 box-shadow: 0 6px 24px rgba(0,0,0,0.10);
917 }
918 .feature-box .dashicons {
919 font-size: 2.2em;
920 color: #7f54b3;
921 margin-bottom: 10px;
922 display: block;
923 }
924 .feature-box h3 {
925 margin: 12px 0 8px 0;
926 font-size: 1.15em;
927 }
928 .feature-box p {
929 color: #555;
930 font-size: 1em;
931 margin: 0;
932 }
933 </style>
934 <?php
935 }
936
937 public function render_go_pro_page() {
938 if ( class_exists( 'Sdevs_Wc_Subscription_Pro' ) ) {
939 echo '<div class="notice notice-info" style="margin:40px auto;max-width:700px;text-align:center;font-size:1.2em;">Pro is already active.</div>';
940 return;
941 }
942 ?>
943 <div class="wrap wpsubscription-go-pro" style="max-width:900px;margin:40px auto 0 auto;">
944 <div class="wpsubscription-go-pro-card" style="background:#fff;border-radius:12px;box-shadow:0 2px 12px rgba(0,0,0,0.06);padding:40px 32px 32px 32px;">
945 <h1 style="margin-bottom:0.5em;"><?php esc_html_e( 'Upgrade to WPSubscription Pro', 'subscription' ); ?></h1>
946 <p style="font-size:1.12em;max-width:600px;line-height:1.6;">
947 <?php esc_html_e( 'Unlock the full power of subscriptions for WooCommerce. Get advanced features, priority support, and more ways to grow your recurring revenue.', 'subscription' ); ?>
948 </p>
949 <table class="wpsubscription-compare-table" style="width:100%;margin:32px 0 40px 0;border-collapse:separate;border-spacing:0;box-shadow:0 1px 4px rgba(0,0,0,0.04);background:#fafbfc;border-radius:8px;overflow:hidden;">
950 <thead>
951 <tr style="background:#f8f9fa;">
952 <th style="padding:18px 12px 18px 24px;font-size:1.08em;text-align:left;border:none;"></th>
953 <th style="padding:18px 12px;font-size:1.08em;text-align:center;border:none;">Free</th>
954 <th style="padding:18px 12px;font-size:1.08em;text-align:center;border:none;color:#7f54b3;">Pro</th>
955 </tr>
956 </thead>
957 <tbody>
958 <tr>
959 <td style="padding:16px 12px 16px 24px;">Simple subscription products</td>
960 <td style="text-align:center;">✔️</td>
961 <td style="text-align:center;">✔️</td>
962 </tr>
963 <tr style="background:#f6f7f7;">
964 <td style="padding:16px 12px 16px 24px;">Automated recurring billing</td>
965 <td style="text-align:center;">✔️</td>
966 <td style="text-align:center;">✔️</td>
967 </tr>
968 <tr>
969 <td style="padding:16px 12px 16px 24px;">Multiple payment gateways</td>
970 <td style="text-align:center;">✔️</td>
971 <td style="text-align:center;">✔️</td>
972 </tr>
973 <tr style="background:#f6f7f7;">
974 <td style="padding:16px 12px 16px 24px;">Customer self-service portal</td>
975 <td style="text-align:center;">✔️</td>
976 <td style="text-align:center;">✔️</td>
977 </tr>
978 <tr>
979 <td style="padding:16px 12px 16px 24px;">Priority support</td>
980 <td style="text-align:center;"></td>
981 <td style="text-align:center;">✔️</td>
982 </tr>
983 <tr style="background:#f6f7f7;">
984 <td style="padding:16px 12px 16px 24px;">Advanced reporting & analytics</td>
985 <td style="text-align:center;"></td>
986 <td style="text-align:center;">✔️</td>
987 </tr>
988 <tr>
989 <td style="padding:16px 12px 16px 24px;">Variable product support</td>
990 <td style="text-align:center;"></td>
991 <td style="text-align:center;font-weight:600;color:#43a047;">✔️</td>
992 </tr>
993 </tbody>
994 </table>
995 <div style="text-align:center;margin-top:24px;">
996 <a href="https://wpsubscription.co/" target="_blank" class="button button-primary button-hero" style="font-size:1.2em;padding:16px 40px 16px 40px;background:#7f54b3;border:none;box-shadow:0 2px 8px rgba(127,84,179,0.10);">
997 <?php esc_html_e( 'Upgrade to Pro', 'subscription' ); ?>
998 </a>
999 </div>
1000 </div>
1001 </div>
1002 <?php
1003 }
1004
1005 /**
1006 * Add "Back to list" button next to the post title.
1007 */
1008 public function add_back_to_list_button() {
1009 global $post;
1010
1011 // Only apply on edit subscription screen
1012 if ( ! isset( $post ) || $post->post_type !== 'subscrpt_order' ) {
1013 return;
1014 }
1015
1016 $list_url = admin_url( 'admin.php?page=wp-subscription' );
1017 ?>
1018 <script type="text/javascript">
1019 document.addEventListener('DOMContentLoaded', function() {
1020 const heading = document.querySelector('.wrap .wp-heading-inline');
1021 if (heading) {
1022 const iconLink = document.createElement('a');
1023 iconLink.href = '<?php echo esc_url( $list_url ); ?>';
1024 iconLink.innerHTML = '<span class="dashicons dashicons-arrow-left-alt2" style="font-size:28px;height:28px;width:28px;"></span>';
1025 iconLink.style.cssText = "text-decoration:none;color:#555;display:inline-flex;align-items:center;margin-right:2px;transform:translateY(20%);box-shadow:none;";
1026 iconLink.title = '<?php echo esc_html_e( 'Back to subscriptions list.', 'subscription' ); ?>';
1027
1028 heading.insertAdjacentElement('beforebegin', iconLink);
1029 }
1030 });
1031 </script>
1032 <?php
1033 }
1034 }
1035