PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 2.1.0
Subscriptions for WooCommerce with Stripe Recurring Payments v2.1.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/Admin/Subscriptions.php +66 -586 1.9.6 → 2.1.0 View file →
@@ -25,21 +25,30 @@
25 25 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
26 26 add_filter( 'post_row_actions', array( $this, 'post_row_actions' ) );
27 27 add_filter( 'manage_subscrpt_order_posts_columns', array( $this, 'add_custom_columns' ) );
28 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' ) );
29 + add_action( 'load-post.php', array( $this, 'redirect_legacy_edit_screen' ) );
35 30 add_filter( 'woocommerce_order_item_get_formatted_meta_data', array( $this, 'remove_order_meta' ), 10, 1 );
36 31 add_filter( 'bulk_actions-edit-subscrpt_order', array( $this, 'remove_bulk_actions' ) );
37 32 add_action( 'restrict_manage_posts', array( $this, 'add_subscription_filter_select' ) );
38 33 add_action( 'admin_menu', array( $this, 'add_overview_submenu' ), 40 );
39 - add_action( 'edit_form_after_title', array( $this, 'display_subscription_details_section' ) );
34 + }
40 35
41 - add_action( 'admin_head-post.php', [ $this, 'add_back_to_list_button' ] );
36 + /**
37 + * Redirect the legacy CPT edit screen to the standalone details page.
38 + *
39 + * The subscription details UI now lives at
40 + * admin.php?page=wp-subscription-details. Anyone landing on the old
41 + * post.php edit screen for a subscrpt_order is sent there.
42 + *
43 + * @return void
44 + */
45 + public function redirect_legacy_edit_screen() {
46 + $post_id = isset( $_GET['post'] ) ? absint( wp_unslash( $_GET['post'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
47 + if ( $post_id && 'subscrpt_order' === get_post_type( $post_id ) ) {
48 + wp_safe_redirect( admin_url( 'admin.php?page=wp-subscription-details&id=' . $post_id ) );
49 + exit;
50 + }
42 51 }
43 52
44 53 /**
45 54 * Remove 'Edit` and 'Trash' from bulk actions.
@@ -154,9 +163,9 @@
154 163 } elseif ( 'subscrpt_status' === $column ) {
155 164 $status_obj = get_post_status_object( get_post_status( $post_id ) );
156 165 ?>
157 166 <span
158 - class="subscrpt-<?php echo esc_html( $status_obj->name ); ?>"><?php echo esc_html( $status_obj->label ); ?></span>
167 + class="subscrpt-legacy-status subscrpt-legacy-status--<?php echo esc_html( $status_obj->name ); ?>"><?php echo esc_html( $status_obj->label ); ?></span>
159 168 <?php
160 169 }
161 170 } else {
162 171 esc_html_e( 'Order not found !!', 'subscription' );
@@ -163,183 +172,31 @@
163 172 }
164 173 }
165 174
166 175 /**
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.
176 + * Build the subscription info rows.
212 177 *
213 - * @param \WP_Post $post Post Object.
178 + * Assembles the label/value rows describing a subscription (product, cost,
179 + * dates, status, payment method, addresses, trial, etc.) and applies the
180 + * `subscrpt_admin_info_rows` filter so extensions (e.g. the Pro plugin) can
181 + * add or reorder rows. Returns null when the related order is missing.
214 182 *
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
183 + * @param int $subscription_id Subscription (subscrpt_order) post ID.
238 184 *
239 - * @param \WP_Post $post Post Object.
240 - *
241 - * @return void
185 + * @return array<string,array{label:string,value:string}>|null
242 186 */
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 WP Subscription 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 );
187 + public static function get_info_rows( $subscription_id ) {
188 + $order_id = get_post_meta( $subscription_id, '_subscrpt_order_id', true );
189 + $order_item_id = get_post_meta( $subscription_id, '_subscrpt_order_item_id', true );
190 + $trial = get_post_meta( $subscription_id, '_subscrpt_trial', true );
191 + $start_date = get_post_meta( $subscription_id, '_subscrpt_start_date', true );
192 + $next_date = get_post_meta( $subscription_id, '_subscrpt_next_date', true );
193 + $trial_start_date = get_post_meta( $subscription_id, '_subscrpt_trial_started', true );
194 + $trial_end_date = get_post_meta( $subscription_id, '_subscrpt_trial_ended', true );
195 + $trial_mode = get_post_meta( $subscription_id, '_subscrpt_trial_mode', true );
339 196 $order = wc_get_order( $order_id );
340 197 if ( ! $order ) {
341 - return;
198 + return null;
342 199 }
343 200 $order_item = $order->get_item( $order_item_id );
344 201
345 202 $product_name = $order_item->get_name();
@@ -345,11 +202,11 @@
345 202 $product_name = $order_item->get_name();
346 203 $product_link = get_the_permalink( $order_item->get_product_id() );
347 204
348 205 // 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() );
206 + $product_id = $order_item->get_product_id();
207 + $max_payments = subscrpt_get_max_payments( $subscription_id ) ? subscrpt_get_max_payments( $subscription_id ) : 0;
208 + $payments_made = subscrpt_count_payments_made( $subscription_id );
352 209
353 210 $rows = array(
354 211 'product' => array(
355 212 'label' => __( 'Product', 'subscription' ),
@@ -356,9 +213,9 @@
356 213 'value' => '<a href="' . esc_html( $product_link ) . '" target="_blank">' . esc_html( $product_name ) . '</a>',
357 214 ),
358 215 'cost' => array(
359 216 'label' => __( 'Cost', 'subscription' ),
360 - 'value' => Helper::format_price_with_order_item( get_post_meta( get_the_ID(), '_subscrpt_price', true ), $order_item->get_id() ),
217 + 'value' => Helper::get_subscription_recurring_price_html( $subscription_id, $order_item ),
361 218 ),
362 219 'quantity' => array(
363 220 'label' => __( 'Qty', 'subscription' ),
364 221 'value' => "x{$order_item->get_quantity()}",
@@ -383,9 +240,9 @@
383 240 'value' => ! empty( $next_date ) ? wp_date( 'F d, Y', $trial && $trial_end_date && 'on' === $trial_mode ? $trial_end_date : ( $next_date ?? '-' ) ) : '-',
384 241 ),
385 242 'status' => array(
386 243 'label' => __( 'Status', 'subscription' ),
387 - 'value' => '<span class="subscrpt-' . get_post_status() . '">' . get_post_status_object( get_post_status() )->label . '</span>',
244 + 'value' => '<span class="subscrpt-legacy-status subscrpt-legacy-status--' . get_post_status( $subscription_id ) . '">' . get_post_status_object( get_post_status( $subscription_id ) )->label . '</span>',
388 245 ),
389 246 'payment_method' => array(
390 247 'label' => __( 'Payment Method', 'subscription' ),
391 248 'value' => empty( $order->get_payment_method_title() ) ? '-' : $order->get_payment_method_title(),
@@ -412,9 +269,9 @@
412 269 ) + array_slice( $rows, 3, count( $rows ) - 1, true );
413 270 }
414 271
415 272 if ( class_exists( 'WC_Stripe' ) && 'stripe' === $order->get_payment_method() ) {
416 - $is_auto_renew = get_post_meta( get_the_ID(), '_subscrpt_auto_renew', true );
273 + $is_auto_renew = get_post_meta( $subscription_id, '_subscrpt_auto_renew', true );
417 274 $new_rows = array();
418 275 foreach ( $rows as $key => $value ) {
419 276 $new_rows[ $key ] = $value;
420 277 if ( 'payment_method' === $key ) {
@@ -427,382 +284,33 @@
427 284
428 285 $rows = $new_rows;
429 286 }
430 287
431 - $rows = apply_filters( 'subscrpt_admin_info_rows', $rows, get_the_ID(), $order );
288 + $rows = apply_filters( 'subscrpt_admin_info_rows', $rows, $subscription_id, $order );
432 289
433 - include 'views/subscription-info.php';
290 + return $rows;
434 291 }
435 292
436 293 /**
437 - * Display a prominent subscription details section.
294 + * Apply a status change to a subscription.
438 295 *
439 - * @param \WP_Post $post The post object.
296 + * Updates the subscription post status, fires the admin status-change email
297 + * notification, runs the subscription status action, and completes the
298 + * related order when the subscription becomes active. Called from the
299 + * standalone subscription details page.
440 300 *
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 - $cost = $subscription_data['price'] ?? 0;
477 - $cost = empty( $cost ) ? $order_item->get_total() : $cost;
478 -
479 - $price_excl_tax = (float) $order_item->get_total();
480 - $tax_amount = (float) $order_item->get_total_tax();
481 - if ( $tax_amount > 0 ) {
482 - $cost = $price_excl_tax + $tax_amount;
483 - $cost = number_format( (float) $cost, 2, '.', '' );
484 - }
485 -
486 - $subscrpt_status = $subscription_data['status'] ?? '';
487 - $verbose_status = Helper::get_verbose_status( $subscrpt_status );
488 -
489 - $started_date = $subscription_data['start_date'] ?? '';
490 - $started_date = ! empty( $started_date ) ? wp_date( 'F j, Y - g:i A', strtotime( $started_date ) ) : '-';
491 -
492 - $next_payment_date = $subscription_data['next_date'] ?? '';
493 - $next_payment_date = ! empty( $next_payment_date ) ? wp_date( 'F j, Y - g:i A', strtotime( $next_payment_date ) ) : '-';
494 -
495 - $is_grace_period = isset( $subscription_data['grace_period'] );
496 - $grace_remaining = $subscription_data['grace_period']['remaining_days'] ?? 0;
497 - $grace_end_date = $subscription_data['grace_period']['end_date'] ?? '';
498 - $grace_end_date = ! empty( $grace_end_date ) ? wp_date( 'F j, Y - g:i A', strtotime( $grace_end_date ) ) : '';
499 -
500 - ?>
501 - <div class="wp-subscription-details-section">
502 - <h2 style="margin: 0 0 20px 0; padding: 0; border-bottom: 1px solid #ddd; padding-bottom: 12px;">
503 - <?php
504 - $text = sprintf(
505 - // translators: Subscription ID.
506 - __( 'Subscription #%d details', 'subscription' ),
507 - $post->ID
508 - );
509 - echo esc_html( $text );
510 - ?>
511 - </h2>
512 -
513 - <div class="subscription-details-grid">
514 - <!-- Primary Information -->
515 - <div class="details-group primary">
516 - <h3><?php esc_html_e( 'General', 'subscription' ); ?></h3>
517 - <table>
518 - <tr>
519 - <th><?php esc_html_e( 'Status', 'subscription' ); ?></th>
520 - <td>
521 - <?php if ( $is_grace_period && $grace_remaining > 0 ) : ?>
522 - <span class="subscrpt-active grace-active">
523 - Active
524 -
525 - <?php
526 - $grace_remaining_text = sprintf(
527 - // translators: Number of days remaining in grace period.
528 - __( '%d days remaining!', 'subscription' ),
529 - $grace_remaining
530 - );
531 - ?>
532 - <span class="grace-icon" data-tooltip="<?php echo esc_attr( $grace_remaining_text ); ?>">
533 - <span class="dashicons dashicons-warning"></span>
534 - </span>
535 - </span>
536 - <?php else : ?>
537 - <span class="subscrpt-<?php echo esc_attr( strtolower( $subscrpt_status ) ); ?>">
538 - <?php echo esc_html( $verbose_status ); ?>
539 - </span>
540 - <?php endif; ?>
541 - </td>
542 - </tr>
543 - <tr>
544 - <th><?php esc_html_e( 'Product', 'subscription' ); ?></th>
545 - <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>
546 - </tr>
547 - </table>
548 - </div>
549 -
550 - <!-- Subscription Terms -->
551 - <div class="details-group">
552 - <h3><?php esc_html_e( 'Subscription Terms', 'subscription' ); ?></h3>
553 - <table>
554 - <tr>
555 - <th><?php esc_html_e( 'Billing', 'subscription' ); ?></th>
556 - <td>
557 - <?php echo wp_kses_post( wc_price( $cost ) ); ?> /
558 - <?php
559 - echo esc_html( $subscrpt_time > 1 ? $subscrpt_time . '-' : '' );
560 - ?>
561 - <?php
562 - echo esc_html( $subscrpt_type );
563 - ?>
564 - </td>
565 - </tr>
566 -
567 - <?php if ( $signup_fee ) : ?>
568 - <tr>
569 - <th><?php esc_html_e( 'Signup Fee', 'subscription' ); ?></th>
570 - <td><?php echo wp_kses_post( wc_price( $signup_fee ) ); ?></td>
571 - </tr>
572 - <?php endif; ?>
573 -
574 - <?php if ( $trial_time ) : ?>
575 - <tr>
576 - <th><?php esc_html_e( 'Free Trial', 'subscription' ); ?></th>
577 - <td><?php echo esc_html( $trial_time . ' ' . $trial_type ); ?></td>
578 - </tr>
579 - <?php endif; ?>
580 -
581 - <?php if ( ! empty( $max_payments ) && $max_payments > 0 ) : ?>
582 - <tr>
583 - <th><?php esc_html_e( 'Total Payments', 'subscription' ); ?></th>
584 - <td><strong><?php echo esc_html( $payments_made . ' / ' . $max_payments ); ?></strong></td>
585 - </tr>
586 - <?php endif; ?>
587 - </table>
588 - </div>
589 -
590 - <!-- Schedule Dates -->
591 - <div class="details-group">
592 - <h3><?php esc_html_e( 'Schedule Dates', 'subscription' ); ?></h3>
593 - <table>
594 - <tr>
595 - <th><?php esc_html_e( 'Started', 'subscription' ); ?></th>
596 - <td><?php echo esc_html( $started_date ); ?></td>
597 - </tr>
598 - <tr>
599 - <th><?php esc_html_e( 'Next Payment', 'subscription' ); ?></th>
600 - <td><?php echo esc_html( $next_payment_date ); ?></td>
601 - </tr>
602 - </table>
603 - </div>
604 -
605 - <!-- Grace Period Info -->
606 - <?php if ( $is_grace_period ) : ?>
607 - <div class="details-group">
608 - <h3><?php esc_html_e( 'Grace Period', 'subscription' ); ?></h3>
609 - <table>
610 - <tr>
611 - <th><?php esc_html_e( 'Remaining', 'subscription' ); ?></th>
612 - <td><?php echo esc_html( $grace_remaining . ' days' ); ?></td>
613 - </tr>
614 - <tr>
615 - <th><?php esc_html_e( 'End Date', 'subscription' ); ?></th>
616 - <td><?php echo esc_html( $grace_end_date ); ?></td>
617 - </tr>
618 - </table>
619 - </div>
620 - <?php endif; ?>
621 - </div>
622 - </div>
623 - <?php
624 - }
625 -
626 - /**
627 - * Include some styles.
301 + * @param int $post_id Subscription (subscrpt_order) post ID.
302 + * @param string $action Target status slug.
628 303 *
629 304 * @return void
630 305 */
631 - public function some_styles() {
632 - global $post;
633 - if ( 'subscrpt_order' === $post->post_type ) :
634 - ?>
635 - <style>
636 - .submitbox {
637 - display: flex;
638 - justify-content: space-around;
639 - }
640 -
641 - .subscrpt_sub_box {
642 - display: grid;
643 - line-height: 2;
644 - }
645 -
646 - /* Hide WordPress title area margin */
647 - #poststuff #post-body.columns-2 {
648 - margin-right: 300px;
649 - }
650 -
651 - /* Clean, minimal details section */
652 - .wp-subscription-details-section {
653 - margin: 20px 0 30px 0;
654 - padding: 20px;
655 - border: 1px solid #ddd;
656 - background: #fff;
657 - }
658 -
659 - /* Grid layout for organized sections */
660 - .subscription-details-grid {
661 - display: grid;
662 - grid-template-columns: 1fr 1fr;
663 - gap: 30px;
664 - margin-top: 20px;
665 - }
666 -
667 - @media (max-width: 782px) {
668 - .subscription-details-grid {
669 - grid-template-columns: 1fr;
670 - }
671 - }
672 -
673 - /* Details group styling */
674 - .details-group h3 {
675 - margin: 0 0 12px 0;
676 - padding: 0 0 8px 0;
677 - border-bottom: 1px solid #eee;
678 - font-size: 14px;
679 - font-weight: 600;
680 - color: #555;
681 - text-transform: uppercase;
682 - letter-spacing: 0.5px;
683 - }
684 -
685 - .details-group.primary h3 {
686 - color: #333;
687 - }
688 -
689 - .details-group table {
690 - width: 100%;
691 - border-collapse: collapse;
692 - }
693 -
694 - .details-group table th {
695 - text-align: left;
696 - padding: 8px 12px 8px 0;
697 - font-weight: 500;
698 - color: #666;
699 - width: 40%;
700 - vertical-align: top;
701 - font-size: 13px;
702 - }
703 -
704 - .details-group table td {
705 - padding: 8px 0;
706 - color: #333;
707 - font-size: 13px;
708 - line-height: 1.4;
709 - }
710 -
711 - .details-group table tr {
712 - border-bottom: 1px solid #f5f5f5;
713 - }
714 -
715 - .details-group table tr:last-child {
716 - border-bottom: none;
717 - }
718 -
719 - /* Simple status badge */
720 - .status-badge {
721 - display: inline-block;
722 - padding: 2px 8px;
723 - border-radius: 3px;
724 - font-size: 12px;
725 - font-weight: 500;
726 - text-transform: capitalize;
727 - background: #f5f5f5;
728 - color: #666;
729 - border: 1px solid #ddd;
730 - }
731 -
732 - /* Clean links */
733 - .details-group a {
734 - color: #0073aa;
735 - text-decoration: none;
736 - }
737 -
738 - .details-group a:hover {
739 - text-decoration: underline;
740 - }
741 -
742 - /* Meta box styling improvements */
743 - .postbox {
744 - border: 1px solid #ddd;
745 - }
746 -
747 - .postbox .hndle {
748 - border-bottom: 1px solid #eee;
749 - background: #fafafa;
750 - }
751 -
752 - #subscrpt_order_history .inside table,
753 - #subscrpt_order_activities .inside table {
754 - border: none;
755 - }
756 - </style>
757 - <?php
758 - endif;
759 - }
760 -
761 - /**
762 - * Disable changes popup.
763 - *
764 - * @return void
765 - */
766 - public function some_scripts() {
767 - global $post;
768 - if ( 'subscrpt_order' === $post->post_type ) :
769 - ?>
770 - <script>
771 - jQuery(document).ready(function() {
772 - jQuery(window).off('beforeunload', null);
773 - });
774 - </script>
775 - <?php
776 - endif;
777 - }
778 -
779 - public function save_subscrpt_order( $post_id ) {
780 - if ( wp_is_post_revision( $post_id ) || ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || ! isset( $_POST['subscrpt_order_action'] ) ) {
781 - return;
782 - }
783 -
784 - // Verify nonce for security.
785 - 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' ) ) {
786 - return;
787 - }
788 -
789 - // Check permissions.
790 - if ( ! current_user_can( 'edit_post', $post_id ) ) {
791 - return;
792 - }
793 - remove_all_actions( 'save_post' );
794 -
795 - $action = sanitize_text_field( wp_unslash( $_POST['subscrpt_order_action'] ) );
306 + public static function process_status_change( $post_id, $action ) {
796 307 $old_status = get_post_status( $post_id );
797 308
798 - wp_update_post(
799 - array(
800 - 'ID' => $post_id,
801 - 'post_status' => $action,
802 - )
803 - );
804 -
309 + // Do not wp_update_post() the status here: Action::status() and the order
310 + // cascade below both skip their hooks (incl. next-date generation) when
311 + // the post_status already equals the target, so this must stay the only
312 + // place a real transition happens.
805 313 if ( $old_status !== $action ) {
806 314 $old_status_object = get_post_status_object( $old_status );
807 315 $new_status_object = get_post_status_object( $action );
808 316 WC()->mailer();
@@ -811,9 +319,11 @@
811 319
812 320 $order_id = get_post_meta( $post_id, '_subscrpt_order_id', true );
813 321 if ( 'active' === $action ) {
814 322 $order = wc_get_order( $order_id );
815 - $order->update_status( 'completed' );
323 + if ( $order ) {
324 + $order->update_status( 'completed' );
325 + }
816 326 Action::status( $action, $post_id );
817 327 } else {
818 328 Action::status( $action, $post_id );
819 329 }
@@ -862,19 +372,19 @@
862 372 <div class="wrap wpsubscription-overview" style="max-width:1100px;margin:40px auto 0 auto;">
863 373 <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;">
864 374 <div class="wpsubscription-overview-top" style="display:grid;grid-template-columns:1fr 1fr;gap:40px;align-items:start;margin-bottom:40px;">
865 375 <div class="wpsubscription-overview-info" style="display:flex;flex-direction:column;gap:18px;">
866 - <h1 style="margin-bottom:0.2em;"><?php esc_html_e( 'WP Subscription Overview', 'subscription' ); ?></h1>
376 + <h1 style="margin-bottom:0.2em;"><?php esc_html_e( 'WPSubscription Overview', 'subscription' ); ?></h1>
867 377 <p class="product-desc" style="font-size:1.15em;line-height:1.6;max-width:500px;">
868 - <?php esc_html_e( 'WP Subscription 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' ); ?>
378 + <?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' ); ?>
869 379 </p>
870 380 <div class="wpsubscription-links" style="display:flex;gap:12px;flex-wrap:wrap;">
871 - <a href="https://docs.converslabs.com/en" target="_blank" class="button button-secondary"><?php esc_html_e( 'Documentation', 'subscription' ); ?></a>
872 - <a href="https://wpsubscription.co/" target="_blank" class="button button-secondary"><?php esc_html_e( 'Website', 'subscription' ); ?></a>
381 + <a href="https://docs.wpsubscription.co/en?utm_source=plugin&utm_medium=admin&utm_campaign=docs" target="_blank" class="button button-secondary"><?php esc_html_e( 'Documentation', 'subscription' ); ?></a>
382 + <a href="https://wpsubscription.co/?utm_source=plugin&utm_medium=admin&utm_campaign=upgrade_pro" target="_blank" class="button button-secondary"><?php esc_html_e( 'Website', 'subscription' ); ?></a>
873 383 </div>
874 384 </div>
875 385 <div class="promo-video" style="text-align:center;">
876 - <iframe width="420" height="236" src="https://www.youtube.com/embed/2e6o5p0M7L4" title="WP Subscription Promo" frameborder="0" allowfullscreen style="max-width:100%;border-radius:8px;"></iframe>
386 + <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>
877 387 </div>
878 388 </div>
879 389
880 390 <div class="wpsubscription-what-section" style="margin-bottom:40px;">
@@ -879,9 +389,9 @@
879 389
880 390 <div class="wpsubscription-what-section" style="margin-bottom:40px;">
881 391 <h2><?php esc_html_e( 'What does Subscriptions for WooCommerce do?', 'subscription' ); ?></h2>
882 392 <p style="font-size:1.08em;max-width:900px;line-height:1.7;">
883 - <?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, WP Subscription gives you the tools to grow your recurring revenue.', 'subscription' ); ?>
393 + <?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' ); ?>
884 394 </p>
885 395 </div>
886 396
887 397 <h2 style="margin-top:2em;"><?php esc_html_e( 'Highlights', 'subscription' ); ?></h2>
@@ -940,9 +450,9 @@
940 450 }
941 451 ?>
942 452 <div class="wrap wpsubscription-go-pro" style="max-width:900px;margin:40px auto 0 auto;">
943 453 <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;">
944 - <h1 style="margin-bottom:0.5em;"><?php esc_html_e( 'Upgrade to WP Subscription Pro', 'subscription' ); ?></h1>
454 + <h1 style="margin-bottom:0.5em;"><?php esc_html_e( 'Upgrade to WPSubscription Pro', 'subscription' ); ?></h1>
945 455 <p style="font-size:1.12em;max-width:600px;line-height:1.6;">
946 456 <?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' ); ?>
947 457 </p>
948 458 <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;">
@@ -991,43 +501,13 @@
991 501 </tr>
992 502 </tbody>
993 503 </table>
994 504 <div style="text-align:center;margin-top:24px;">
995 - <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);">
505 + <a href="https://wpsubscription.co/?utm_source=plugin&utm_medium=admin&utm_campaign=upgrade_pro" 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);">
996 506 <?php esc_html_e( 'Upgrade to Pro', 'subscription' ); ?>
997 507 </a>
998 508 </div>
999 509 </div>
1000 510 </div>
1001 - <?php
1002 - }
1003 -
1004 - /**
1005 - * Add "Back to list" button next to the post title.
1006 - */
1007 - public function add_back_to_list_button() {
1008 - global $post;
1009 -
1010 - // Only apply on edit subscription screen
1011 - if ( ! isset( $post ) || $post->post_type !== 'subscrpt_order' ) {
1012 - return;
1013 - }
1014 -
1015 - $list_url = admin_url( 'admin.php?page=wp-subscription' );
1016 - ?>
1017 - <script type="text/javascript">
1018 - document.addEventListener('DOMContentLoaded', function() {
1019 - const heading = document.querySelector('.wrap .wp-heading-inline');
1020 - if (heading) {
1021 - const iconLink = document.createElement('a');
1022 - iconLink.href = '<?php echo esc_url( $list_url ); ?>';
1023 - iconLink.innerHTML = '<span class="dashicons dashicons-arrow-left-alt2" style="font-size:28px;height:28px;width:28px;"></span>';
1024 - iconLink.style.cssText = "text-decoration:none;color:#555;display:inline-flex;align-items:center;margin-right:2px;transform:translateY(20%);box-shadow:none;";
1025 - iconLink.title = '<?php echo esc_html_e( 'Back to subscriptions list.', 'subscription' ); ?>';
1026 -
1027 - heading.insertAdjacentElement('beforebegin', iconLink);
1028 - }
1029 - });
1030 - </script>
1031 511 <?php
1032 512 }
1033 513 }