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

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

654 lines 31.5 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 function Avifinfo\read;
6
7 /**
8 * Menu class
9 *
10 * @package SpringDevs\Subscription\Admin
11 */
12 class Menu {
13
14 /**
15 * Initialize the class
16 */
17 public function __construct() {
18 add_action( 'admin_menu', array( $this, 'create_admin_menu' ) );
19 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) );
20 add_action( 'wp_ajax_wp_subscription_bulk_action', array( $this, 'handle_bulk_action_ajax' ) );
21 }
22
23 /**
24 * Enqueue admin assets
25 */
26 public function enqueue_admin_assets() {
27 wp_enqueue_style(
28 'wp-subscription-admin',
29 WP_SUBSCRIPTION_ASSETS . '/css/admin.css',
30 array(),
31 WP_SUBSCRIPTION_VERSION
32 );
33
34 // Enqueue admin JavaScript for subscription list functionality
35 wp_enqueue_script(
36 'sdevs_subscription_admin',
37 WP_SUBSCRIPTION_ASSETS . '/js/admin.js',
38 array( 'jquery' ),
39 WP_SUBSCRIPTION_VERSION,
40 true
41 );
42
43 // Localize script for AJAX
44 wp_localize_script(
45 'sdevs_subscription_admin',
46 'wp_subscription_ajax',
47 array(
48 'nonce' => wp_create_nonce( 'wp_subscription_bulk_action_nonce' ),
49 'ajaxurl' => admin_url( 'admin-ajax.php' )
50 )
51 );
52 }
53
54 /**
55 * Create Subscriptions Menu.
56 */
57 public function create_admin_menu() {
58 $parent_slug = 'wp-subscription';
59 // Determine if the menu is active
60 $is_active = isset($_GET['page']) && strpos($_GET['page'], 'wp-subscription') === 0;
61 $icon_url = $is_active
62 ? WP_SUBSCRIPTION_ASSETS . '/images/icons/subscription-20.png'
63 : WP_SUBSCRIPTION_ASSETS . '/images/icons/subscription-20-gray.png';
64 // Main menu
65 add_menu_page(
66 __( 'WP Subscription', 'wp_subscription' ),
67 __( 'WP Subscription', 'wp_subscription' ),
68 'manage_woocommerce',
69 $parent_slug,
70 array( $this, 'render_subscriptions_page' ),
71 $icon_url,
72 40
73 );
74
75 // Subscriptions List
76 add_submenu_page(
77 $parent_slug,
78 __( 'Subscriptions', 'wp_subscription' ),
79 __( 'Subscriptions', 'wp_subscription' ),
80 'manage_woocommerce',
81 $parent_slug,
82 array( $this, 'render_subscriptions_page' )
83 );
84
85 // Stats Overview
86 add_submenu_page(
87 $parent_slug,
88 __( 'Reports', 'wp_subscription' ),
89 __( 'Reports', 'wp_subscription' ),
90 'manage_woocommerce',
91 'wp-subscription-stats',
92 array( $this, 'render_stats_page' )
93 );
94
95 // Settings
96 add_submenu_page(
97 $parent_slug,
98 __( 'Settings', 'wp_subscription' ),
99 __( 'Settings', 'wp_subscription' ),
100 'manage_woocommerce',
101 'wp-subscription-settings',
102 array( $this, 'render_settings_page' )
103 );
104
105 // Support
106 add_submenu_page(
107 $parent_slug,
108 __( 'Support', 'wp_subscription' ),
109 __( 'Support', 'wp_subscription' ),
110 'manage_woocommerce',
111 'wp-subscription-support',
112 array( $this, 'render_support_page' )
113 );
114
115 // Add WP Subscription link under WooCommerce menu
116 add_submenu_page(
117 'woocommerce',
118 __( 'WP Subscription', 'wp_subscription' ),
119 __( 'WP Subscription', 'wp_subscription' ),
120 'manage_woocommerce',
121 'wp-subscription',
122 array( $this, 'render_subscriptions_page' )
123 );
124 }
125 /**
126 * Render the admin header
127 */
128 public function render_admin_footer() {
129 ?>
130 <div style="text-align:center;margin:38px 0 0 0;font-size:14px;color:#888;">
131 Made with <span style="color:#e25555;font-size:1.1em;"></span> by the WP Subscription Team
132 <div style="margin-top:6px;">
133 <a href="https://wpsubscription.co/contact" target="_blank" style="color:#2563eb;text-decoration:none;">Support</a>
134 &nbsp;/&nbsp;
135 <a href="https://docs.converslabs.com/en" target="_blank" style="color:#2563eb;text-decoration:none;">Docs</a>
136 </div>
137 </div>
138 <?php
139 }
140 /**
141 * Render the admin header
142 */
143 public function render_admin_header() {
144 // Get current page slug
145 $current = isset($_GET['page']) ? sanitize_text_field($_GET['page']) : 'wp-subscription';
146 $menu_items = [
147 [
148 'slug' => 'wp-subscription',
149 'label' => __('Subscriptions', 'wp_subscription'),
150 'url' => admin_url('admin.php?page=wp-subscription'),
151 ],
152 [
153 'slug' => 'wp-subscription-stats',
154 'label' => __('Reports', 'wp_subscription'),
155 'url' => admin_url('admin.php?page=wp-subscription-stats'),
156 ],
157 [
158 'slug' => 'wp-subscription-settings',
159 'label' => __('Settings', 'wp_subscription'),
160 'url' => admin_url('admin.php?page=wp-subscription-settings'),
161 ]
162 ];
163 // Allow pro plugin to inject menu items
164 $menu_items = apply_filters('wp_subscription_admin_header_menu_items', $menu_items, $current);
165 $menu_items = array_merge($menu_items, [
166 [
167 'slug' => 'wp-subscription-support',
168 'label' => __('Support', 'wp_subscription'),
169 'url' => admin_url('admin.php?page=wp-subscription-support'),
170 ],
171 ]);
172 ?>
173 <div class="wp-subscription-admin-header">
174 <div style="width:1240px;margin:0 auto;display:flex;align-items:center;justify-content:space-between;">
175 <div class="wp-subscription-admin-header-left" style="display:flex;align-items:center;gap:14px;">
176 <img style="height:30px;" src="<?php echo esc_url( WP_SUBSCRIPTION_ASSETS . '/images/logo-title.svg' ); ?>" alt="WP Subscription" class="wp-subscription-logo">
177 <nav class="wp-subscription-admin-header-menu">
178 <?php foreach ($menu_items as $item): ?>
179 <a href="<?php echo esc_url($item['url']); ?>" class="<?php echo ($current === $item['slug']) ? 'current' : ''; ?>">
180 <?php echo esc_html($item['label']); ?>
181 </a>
182 <?php endforeach; ?>
183 </nav>
184 </div>
185 <div class="wp-subscription-admin-header-right">
186 <?php if ( ! class_exists('Sdevs_Wc_Subscription_Pro') ) : ?>
187 <a target="_blank" href="https://wpsubscription.co/?utm_source=plugin&utm_medium=admin&utm_campaign=upgrade_pro" class="wp-subscription-upgrade-btn"><?php _e( 'Upgrade to Pro', 'wp_subscription' ); ?></a>
188 <?php endif; ?>
189 </div>
190 </div>
191 </div>
192 <?php
193 }
194
195 /**
196 * Render Subscriptions page
197 */
198 public function render_subscriptions_page() {
199 $this->render_admin_header();
200
201 // Handle filters
202 $status = isset($_GET['subscrpt_status']) ? sanitize_text_field($_GET['subscrpt_status']) : '';
203 $search = isset($_GET['s']) ? sanitize_text_field($_GET['s']) : '';
204 $date_filter = isset($_GET['date_filter']) ? sanitize_text_field($_GET['date_filter']) : '';
205 $per_page = isset($_GET['per_page']) ? max(1, intval($_GET['per_page'])) : 20;
206 $paged = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1;
207
208 // Handle form submissions (both filters and bulk actions)
209 if ($_SERVER['REQUEST_METHOD'] === 'POST') {
210 // Handle bulk actions
211 if (isset($_POST['bulk_action']) || isset($_POST['bulk_action2'])) {
212 $bulk_action = isset($_POST['bulk_action']) ? sanitize_text_field($_POST['bulk_action']) : sanitize_text_field($_POST['bulk_action2']);
213 $action = isset($_POST['action']) ? sanitize_text_field($_POST['action']) : sanitize_text_field($_POST['action2']);
214
215 if ($bulk_action && $action && $action !== '-1' && isset($_POST['subscription_ids']) && is_array($_POST['subscription_ids'])) {
216 $subscription_ids = array_map('intval', $_POST['subscription_ids']);
217
218 if ($action === 'trash') {
219 foreach ($subscription_ids as $sub_id) {
220 wp_trash_post($sub_id);
221 }
222 } elseif ($action === 'restore') {
223 foreach ($subscription_ids as $sub_id) {
224 wp_untrash_post($sub_id);
225 }
226 } elseif ($action === 'delete') {
227 foreach ($subscription_ids as $sub_id) {
228 wp_delete_post($sub_id, true);
229 }
230 }
231
232 wp_safe_redirect(admin_url('admin.php?page=wp-subscription'));
233 exit;
234 }
235 }
236
237 // Handle filter form submission
238 if (isset($_POST['filter_action'])) {
239 $filter_params = array();
240
241 if (!empty($_POST['subscrpt_status'])) {
242 $filter_params['subscrpt_status'] = sanitize_text_field($_POST['subscrpt_status']);
243 }
244 if (!empty($_POST['date_filter'])) {
245 $filter_params['date_filter'] = sanitize_text_field($_POST['date_filter']);
246 }
247 if (!empty($_POST['s'])) {
248 $filter_params['s'] = sanitize_text_field($_POST['s']);
249 }
250 if (!empty($_POST['per_page'])) {
251 $filter_params['per_page'] = intval($_POST['per_page']);
252 }
253
254 $redirect_url = add_query_arg($filter_params, admin_url('admin.php?page=wp-subscription'));
255 wp_safe_redirect($redirect_url);
256 exit;
257 }
258 }
259
260 // Handle individual actions
261 if (isset($_GET['action']) && !empty($_GET['sub_id'])) {
262 $sub_id = intval($_GET['sub_id']);
263 $action = sanitize_text_field($_GET['action']);
264
265 if ($action === 'duplicate') {
266 $post = get_post($sub_id);
267 if ($post && $post->post_type === 'subscrpt_order') {
268 $new_post = [
269 'post_title' => $post->post_title . ' (Copy)',
270 'post_content' => $post->post_content,
271 'post_status' => 'draft',
272 'post_type' => 'subscrpt_order',
273 ];
274 $new_id = wp_insert_post($new_post);
275 if ($new_id) {
276 $meta = get_post_meta($sub_id);
277 foreach ($meta as $key => $values) {
278 foreach ($values as $value) {
279 add_post_meta($new_id, $key, maybe_unserialize($value));
280 }
281 }
282 }
283 }
284 wp_safe_redirect(admin_url('admin.php?page=wp-subscription'));
285 exit;
286 } elseif ($action === 'trash') {
287 // Move to trash
288 wp_trash_post($sub_id);
289 wp_safe_redirect(admin_url('admin.php?page=wp-subscription'));
290 exit;
291 } elseif ($action === 'restore') {
292 // Restore from trash
293 wp_untrash_post($sub_id);
294 wp_safe_redirect(admin_url('admin.php?page=wp-subscription'));
295 exit;
296 } elseif ($action === 'delete') {
297 // Permanent delete
298 wp_delete_post($sub_id, true);
299 wp_safe_redirect(admin_url('admin.php?page=wp-subscription'));
300 exit;
301 } elseif ($action === 'clean_trash') {
302 // Clean all trash items
303 $trash_posts = get_posts([
304 'post_type' => 'subscrpt_order',
305 'post_status' => 'trash',
306 'numberposts' => -1,
307 'fields' => 'ids'
308 ]);
309
310 foreach ($trash_posts as $trash_id) {
311 wp_delete_post($trash_id, true);
312 }
313
314 wp_safe_redirect(admin_url('admin.php?page=wp-subscription&subscrpt_status=trash'));
315 exit;
316 }
317 }
318
319 $args = [
320 'post_type' => 'subscrpt_order',
321 'post_status' => 'any',
322 'posts_per_page' => $per_page,
323 'paged' => $paged,
324 'orderby' => 'date',
325 'order' => 'DESC',
326 ];
327
328 if ($status) {
329 $args['post_status'] = $status;
330 }
331 // Search only by subscription ID
332 if ($search !== '') {
333 if (is_numeric($search)) {
334 $args['p'] = intval($search);
335 } else {
336 // If not numeric, return no results
337 $args['post__in'] = array(0);
338 }
339 }
340 // Dynamic date filter (YYYY-MM)
341 if ($date_filter && preg_match('/^\d{4}-\d{2}$/', $date_filter)) {
342 $year = substr($date_filter, 0, 4);
343 $month = substr($date_filter, 5, 2);
344 $args['date_query'][] = [
345 'year' => intval($year),
346 'month' => intval($month),
347 ];
348 }
349
350 $query = new \WP_Query($args);
351 $subscriptions = $query->posts;
352 $total = $query->found_posts;
353 $max_num_pages = $query->max_num_pages;
354
355 // Get all possible statuses for filter dropdown
356 $all_statuses = get_post_stati(['show_in_admin_all_list' => true], 'objects');
357
358 include dirname(__FILE__) . '/views/subscription-list.php';
359 ?>
360 <div style="text-align:center;margin:38px 0 0 0;font-size:14px;color:#888;">
361 Made with <span style="color:#e25555;font-size:1.1em;"></span> by the WP Subscription Team
362 <div style="margin-top:6px;">
363 <a href="https://wpsubscription.co/contact" target="_blank" style="color:#2563eb;text-decoration:none;">Support</a>
364 &nbsp;/&nbsp;
365 <a href="https://docs.converslabs.com/en" target="_blank" style="color:#2563eb;text-decoration:none;">Docs</a>
366 </div>
367 </div>
368 <?php
369 }
370
371 /**
372 * Render Stats page
373 */
374 public function render_stats_page() {
375 $this->render_admin_header();
376
377 if ( ! class_exists('Sdevs_Wc_Subscription_Pro') ) { ?>
378 <div class="wp-subscription-admin-content" style="max-width:1240px;margin:32px auto 0 auto">
379 <div class="wp-subscription-hero-upgrade" style="margin-bottom:18px;">
380 <div class="wp-subscription-hero-content">
381 <span class="wp-subscription-hero-icon"></span>
382 <span class="wp-subscription-hero-title">
383 Unlock advanced features, priority support,<br>
384 and more subscription control and reporting.
385 </span>
386 </div>
387 <a href="https://wpsubscription.co/?utm_source=plugin&utm_medium=admin&utm_campaign=upgrade_pro"
388 target="_blank"
389 class="wp-subscription-hero-btn">
390 UPGRADE TO PRO
391 </a>
392 </div>
393 </div>
394 <?php
395 } else {
396 // Allow pro plugin to override the entire stats page content
397 do_action('wp_subscription_render_stats_page');
398 }
399
400 $this->render_admin_footer();
401
402 return;
403 }
404
405 /**
406 * Render Settings page
407 */
408 public function render_settings_page() {
409 $this->render_admin_header();
410 ?>
411 <div class="wp-subscription-admin-content" style="max-width:1240px;margin:32px auto 0 auto">
412 <div class="wp-subscription-admin-box">
413 <?php include_once dirname(__FILE__) . '/views/settings.php'; ?>
414 </div>
415 </div>
416 <div style="text-align:center;margin:38px 0 0 0;font-size:14px;color:#888;">
417 Made with <span style="color:#e25555;font-size:1.1em;"></span> by the WP Subscription Team
418 <div style="margin-top:6px;">
419 <a href="https://wpsubscription.co/contact" target="_blank" style="color:#2563eb;text-decoration:none;">Support</a>
420 &nbsp;/&nbsp;
421 <a href="https://docs.converslabs.com/en" target="_blank" style="color:#2563eb;text-decoration:none;">Docs</a>
422 </div>
423 </div>
424 <?php
425 }
426
427 /**
428 * Render Support page
429 */
430 public function render_support_page() {
431 $this->render_admin_header();
432 ?>
433 <div class="wp-subscription-admin-content" style="max-width:1240px;margin:32px auto 0 auto">
434 <?php if ( ! class_exists('Sdevs_Wc_Subscription_Pro') ) : ?>
435 <!-- HERO VARIANT 1: Emoji -->
436 <div class="wp-subscription-hero-upgrade" style="margin-bottom:18px;">
437 <div class="wp-subscription-hero-content">
438 <span class="wp-subscription-hero-icon"></span>
439 <span class="wp-subscription-hero-title">
440 Unlock advanced features, priority support,<br>
441 and more subscription control and reporting.
442 </span>
443 </div>
444 <a href="https://wpsubscription.co/?utm_source=plugin&utm_medium=admin&utm_campaign=upgrade_pro"
445 target="_blank"
446 class="wp-subscription-hero-btn">
447 UPGRADE TO PRO
448 </a>
449 </div>
450 <?php endif; ?>
451
452 <!-- Product Overview & Video -->
453 <div class="wp-subscription-admin-box" style="margin-bottom:24px;display:flex;gap:32px;align-items:flex-start;flex-wrap:wrap;">
454 <div style="flex:1;">
455 <h3>Product Overview</h3>
456 <p style="font-size:14px;line-height:1.7;margin:0 0 10px 0;">
457 WPSubscription helps you to sell products and services on a recurring basis using your existing WooCommerce store. Whether you're offering digital licenses, physical product boxes, or ongoing service plans, this plugin provides the tools to build and manage subscription models.
458 </p>
459 <ul style="font-size:14px;line-height:1.6;margin:0 0 0 18px;padding:0;list-style:disc;">
460 <li>Create simple or variable subscription products</li>
461 <li>Set billing intervals (daily, weekly, monthly, yearly)</li>
462 <li>Offer free trials and sign-up fees</li>
463 <li>Allow customers to cancel or renew subscriptions manually</li>
464 <li>View and manage subscriptions from the admin dashboard</li>
465 <li>Customize subscription behavior and role assignment</li>
466 <li>Integrate with payment gateways that support recurring billing (Stripe, PayPal)</li>
467 </ul>
468 </div>
469 <div style="flex:1;">
470 <div style="background:#f4f7fa;border-radius:8px;padding:10px 10px 6px 10px;box-shadow:0 2px 8px #e0e7ef;">
471 <div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:6px;text-align: center;">
472 <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/o8usgcZp1nY?si=iPb5z7bvcy0rIyOQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
473 ß </div>
474 <!-- <div style="text-align:center;font-size:13px;color:#888;margin-top:4px;">Watch: Quick Product Tour</div> -->
475 </div>
476 </div>
477 </div>
478
479 <!-- PRO Features List -->
480 <div class="wp-subscription-admin-box wp-subscription-pro-features" style="margin-bottom:32px;">
481 <div style="font-size:1.3em;font-weight:600;margin-bottom:12px;display:flex;align-items:center;gap:10px;">
482 <svg width="28" height="28" fill="none" viewBox="0 0 28 28"><circle cx="14" cy="14" r="14" fill="#2196f3"/><path d="M9 14.5l3 3 7-7" stroke="#fff" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
483 <span>WP Subscription PRO Features</span>
484 </div>
485 <ul class="wp-subscription-pro-feature-list" style="list-style:none;padding:0;margin:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:18px;">
486 <li style="background:#f4f7fa;border-radius:8px;padding:18px 20px;display:flex;align-items:center;gap:14px;box-shadow:0 2px 8px #e0e7ef;">
487 <span style="font-size:1.5em;color:#2196f3;">🔀</span>
488 <span><b>Variable Product</b><br><span style="color:#555;font-size:0.98em;">Offer flexible subscription options for variable products.</span></span>
489 </li>
490 <li style="background:#f4f7fa;border-radius:8px;padding:18px 20px;display:flex;align-items:center;gap:14px;box-shadow:0 2px 8px #e0e7ef;">
491 <span style="font-size:1.5em;color:#2196f3;">🚚</span>
492 <span><b>Delivery Schedule</b><br><span style="color:#555;font-size:0.98em;">Set custom delivery intervals for each subscription.</span></span>
493 </li>
494 <li style="background:#f4f7fa;border-radius:8px;padding:18px 20px;display:flex;align-items:center;gap:14px;box-shadow:0 2px 8px #e0e7ef;">
495 <span style="font-size:1.5em;color:#2196f3;">📜</span>
496 <span><b>Subscription History</b><br><span style="color:#555;font-size:0.98em;">Track all changes and events for every subscription.</span></span>
497 </li>
498 <li style="background:#f4f7fa;border-radius:8px;padding:18px 20px;display:flex;align-items:center;gap:14px;box-shadow:0 2px 8px #e0e7ef;">
499 <span style="font-size:1.5em;color:#2196f3;">⏳</span>
500 <span><b>More Subscription Durations</b><br><span style="color:#555;font-size:0.98em;">Offer more flexible and custom subscription periods.</span></span>
501 </li>
502 <li style="background:#f4f7fa;border-radius:8px;padding:18px 20px;display:flex;align-items:center;gap:14px;box-shadow:0 2px 8px #e0e7ef;">
503 <span style="font-size:1.5em;color:#2196f3;">💶</span>
504 <span><b>Sign Up Fee</b><br><span style="color:#555;font-size:0.98em;">Charge a one-time sign up fee for new subscribers.</span></span>
505 </li>
506 <li style="background:#f4f7fa;border-radius:8px;padding:18px 20px;display:flex;align-items:center;gap:14px;box-shadow:0 2px 8px #e0e7ef;">
507 <span style="font-size:1.5em;color:#2196f3;">⏩</span>
508 <span><b>Early Renewal</b><br><span style="color:#555;font-size:0.98em;">Allow customers to renew their subscription before expiry.</span></span>
509 </li>
510 <li style="background:#f4f7fa;border-radius:8px;padding:18px 20px;display:flex;align-items:center;gap:14px;box-shadow:0 2px 8px #e0e7ef;">
511 <span style="font-size:1.5em;color:#2196f3;">💳</span>
512 <span><b>Renewal Price</b><br><span style="color:#555;font-size:0.98em;">Set a different price for subscription renewals.</span></span>
513 </li>
514 </ul>
515 </div>
516
517 <!-- Support Resources: 2 rows, 2 columns, each in its own box -->
518 <div class="wp-subscription-support-resources" style="display:grid;grid-template-columns:repeat(2,1fr);gap:24px;margin-bottom:24px;">
519 <div class="wp-subscription-admin-box">
520 <h3>Documentation</h3>
521 <p style="font-size:14px;margin:0 0 8px 0;">Read our <a href="https://docs.converslabs.com/en\" target=\"_blank\" style=\"color:#2271b1;\">comprehensive docs</a> for setup, migration, and advanced usage.</p>
522 <a href="https://docs.converslabs.com/en" target="_blank" class="button button-small" style="font-size:13px;padding:5px 14px;">View Docs</a>
523 </div>
524 <div class="wp-subscription-admin-box">
525 <h3>Facing An Issue?</h3>
526 <p style="font-size:14px;margin:0 0 8px 0;">If you have a problem, <a href="https://wpsubscription.co/contact\" target=\"_blank\" style=\"color:#d93025;\">open a support ticket</a> or check our FAQ.</p>
527 <a href="https://wpsubscription.co/contact" target="_blank" class="button button-small" style="font-size:13px;padding:5px 14px;">Get Support</a>
528 </div>
529 <div class="wp-subscription-admin-box">
530 <h3>Request a Feature</h3>
531 <p style="font-size:14px;margin:0 0 8px 0;">Have an idea? <a href="https://wpsubscription.co/contact\" target=\"_blank\" style=\"color:#2271b1;\">Request a feature</a> or vote on others.</p>
532 <a href="https://wpsubscription.co/contact" target="_blank" class="button button-small" style="font-size:13px;padding:5px 14px;">Request Feature</a>
533 </div>
534 <div class="wp-subscription-admin-box">
535 <h3>Show Your Love</h3>
536 <p style="font-size:14px;margin:0 0 8px 0;">Enjoying WP Subscription? <a href="https://wordpress.org/support/plugin/subscription/reviews/\" target=\"_blank\" style=\"color:#f59e42;\">Leave us a review</a> or share your experience!</p>
537 <a href="https://wordpress.org/support/plugin/subscription/reviews/" target="_blank" class="button button-small" style="font-size:13px;padding:5px 14px;">Leave a Review</a>
538 </div>
539 </div>
540 </div>
541 <div style="text-align:center;margin:38px 0 0 0;font-size:14px;color:#888;">
542 Made with <span style="color:#e25555;font-size:1.1em;">♥</span> by the WP Subscription Team
543 <div style="margin-top:6px;">
544 <a href="https://wpsubscription.co/contact" target="_blank" style="color:#2563eb;text-decoration:none;">Support</a>
545 &nbsp;/&nbsp;
546 <a href="https://docs.converslabs.com/en" target="_blank" style="color:#2563eb;text-decoration:none;">Docs</a>
547 </div>
548 </div>
549 <?php
550 }
551
552 /**
553 * Render the legacy subscriptions list page (WP_List_Table based)
554 */
555 public function render_legacy_subscriptions_page() {
556 // No longer needed, as the menu now links directly to the post type list.
557 }
558
559 /**
560 * Handle bulk action AJAX
561 */
562 public function handle_bulk_action_ajax() {
563 // Verify nonce
564 if ( ! wp_verify_nonce( $_POST['nonce'], 'wp_subscription_bulk_action_nonce' ) ) {
565 wp_send_json_error( array( 'message' => __( 'Security check failed.', 'wp_subscription' ) ) );
566 }
567
568 // Check permissions
569 if ( ! current_user_can( 'manage_woocommerce' ) ) {
570 wp_send_json_error( array( 'message' => __( 'You do not have permission to perform this action.', 'wp_subscription' ) ) );
571 }
572
573 // Get action and subscription IDs
574 $bulk_action = sanitize_text_field( $_POST['bulk_action'] );
575 $subscription_ids = isset( $_POST['subscription_ids'] ) ? array_map( 'intval', $_POST['subscription_ids'] ) : array();
576
577 if ( empty( $subscription_ids ) ) {
578 wp_send_json_error( array( 'message' => __( 'No subscriptions selected.', 'wp_subscription' ) ) );
579 }
580
581 $processed_count = 0;
582 $errors = array();
583
584 foreach ( $subscription_ids as $subscription_id ) {
585 $post = get_post( $subscription_id );
586
587 if ( ! $post || $post->post_type !== 'subscrpt_order' ) {
588 $errors[] = sprintf( __( 'Subscription #%d not found.', 'wp_subscription' ), $subscription_id );
589 continue;
590 }
591
592 try {
593 switch ( $bulk_action ) {
594 case 'trash':
595 if ( wp_trash_post( $subscription_id ) ) {
596 $processed_count++;
597 } else {
598 $errors[] = sprintf( __( 'Failed to move subscription #%d to trash.', 'wp_subscription' ), $subscription_id );
599 }
600 break;
601
602 case 'restore':
603 if ( wp_untrash_post( $subscription_id ) ) {
604 $processed_count++;
605 } else {
606 $errors[] = sprintf( __( 'Failed to restore subscription #%d.', 'wp_subscription' ), $subscription_id );
607 }
608 break;
609
610 case 'delete':
611 if ( wp_delete_post( $subscription_id, true ) ) {
612 $processed_count++;
613 } else {
614 $errors[] = sprintf( __( 'Failed to delete subscription #%d.', 'wp_subscription' ), $subscription_id );
615 }
616 break;
617
618 default:
619 $errors[] = sprintf( __( 'Unknown action: %s', 'wp_subscription' ), $bulk_action );
620 break;
621 }
622 } catch ( Exception $e ) {
623 $errors[] = sprintf( __( 'Error processing subscription #%d: %s', 'wp_subscription' ), $subscription_id, $e->getMessage() );
624 }
625 }
626
627 // Prepare response message
628 $message = '';
629 if ( $processed_count > 0 ) {
630 switch ( $bulk_action ) {
631 case 'trash':
632 $message = sprintf( _n( '%d subscription moved to trash.', '%d subscriptions moved to trash.', $processed_count, 'wp_subscription' ), $processed_count );
633 break;
634 case 'restore':
635 $message = sprintf( _n( '%d subscription restored.', '%d subscriptions restored.', $processed_count, 'wp_subscription' ), $processed_count );
636 break;
637 case 'delete':
638 $message = sprintf( _n( '%d subscription permanently deleted.', '%d subscriptions permanently deleted.', $processed_count, 'wp_subscription' ), $processed_count );
639 break;
640 }
641 }
642
643 if ( ! empty( $errors ) ) {
644 $message .= ' ' . __( 'Some errors occurred:', 'wp_subscription' ) . ' ' . implode( ', ', $errors );
645 }
646
647 if ( $processed_count > 0 ) {
648 wp_send_json_success( array( 'message' => $message ) );
649 } else {
650 wp_send_json_error( array( 'message' => $message ?: __( 'No subscriptions were processed.', 'wp_subscription' ) ) );
651 }
652 }
653 }
654