PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 2.3.0
Subscriptions for WooCommerce with Stripe Recurring Payments v2.3.0
2.4.0 2.3.0 2.2.0 2.1.0 2.0.0 1.11.2 1.11.1 1.11.0 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.6 1.9.5 trunk 1.3.0 1.3.1 1.3.2 1.4.0 All 65 releases
subscription / includes / Admin / Plans.php

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

250 lines 8.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plans - admin class.
4 *
5 * Registers the Subscription Plans admin screens (list + detail) and enqueues
6 * their assets. Data is read live from PlanRepository via PlanPresenter; all
7 * writes go through the wpsubscription/v1 REST API (admin-only). The UI is
8 * built entirely on the shared `wpsubs-*` component system (admin-components).
9 *
10 * @package SpringDevs\Subscription\Admin
11 */
12
13 namespace SpringDevs\Subscription\Admin;
14
15 /**
16 * Plans - admin class.
17 */
18 class Plans {
19
20 /**
21 * Admin page slug.
22 */
23 const SLUG = 'wp-subscription-plans';
24
25 /**
26 * The page hook returned by add_submenu_page (for the enqueue gate).
27 *
28 * @var string
29 */
30 private $hook = '';
31
32 /**
33 * Initialize the class.
34 */
35 public function __construct() {
36 add_action( 'admin_menu', array( $this, 'register_page' ), 11 );
37 add_filter( 'subscrpt_submenu_order', array( $this, 'position_submenu' ) );
38 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
39 }
40
41 /**
42 * Register the Plans submenu under the WPSubscription top menu.
43 *
44 * @return void
45 */
46 public function register_page() {
47 $this->hook = (string) add_submenu_page(
48 'wp-subscription',
49 __( 'Plans', 'subscription' ),
50 __( 'Plans', 'subscription' ),
51 'manage_options',
52 self::SLUG,
53 array( $this, 'render_page' )
54 );
55 }
56
57 /**
58 * Position the Plans item within the WPSubscription submenu order.
59 *
60 * @param array $order Ordered slug => position map.
61 * @return array
62 */
63 public function position_submenu( $order ) {
64 if ( is_array( $order ) ) {
65 $order[ self::SLUG ] = 10;
66 }
67 return $order;
68 }
69
70 /**
71 * Enqueue Plans assets only on the Plans page.
72 *
73 * Reuses the shared `subscrpt_admin_components` bundle (registered by
74 * Assets) for all styling; adds only the Plans interaction script on top.
75 *
76 * @param string $hook Current admin page hook.
77 * @return void
78 */
79 public function enqueue_assets( $hook ) {
80 if ( ! $this->hook || $hook !== $this->hook ) {
81 return;
82 }
83
84 wp_enqueue_style( 'subscrpt_admin_components' );
85 wp_enqueue_script( 'subscrpt_admin_components' );
86
87 // Shared plan-group + selling-plan modal logic.
88 wp_enqueue_script( 'subscrpt_plan_forms_js' );
89 wp_localize_script( 'subscrpt_plan_forms_js', 'subscrptPlanForms', self::plan_forms_config() );
90
91 wp_enqueue_script(
92 'subscrpt_admin_plans_js',
93 SUBSCRPT_ASSETS . '/js/admin/plans.js',
94 array( 'subscrpt_admin_components', 'subscrpt_plan_forms_js' ),
95 SUBSCRPT_VERSION,
96 true
97 );
98
99 wp_localize_script(
100 'subscrpt_admin_plans_js',
101 'subscrptPlans',
102 array(
103 'restUrl' => esc_url_raw( rest_url( 'wpsubscription/v1/plans' ) ),
104 'nonce' => wp_create_nonce( 'wp_rest' ),
105 'listUrl' => admin_url( 'admin.php?page=' . self::SLUG ),
106 'currency' => function_exists( 'get_woocommerce_currency_symbol' )
107 ? html_entity_decode( get_woocommerce_currency_symbol(), ENT_QUOTES, 'UTF-8' )
108 : '$',
109 'i18n' => array(
110 'saved' => __( 'Saved.', 'subscription' ),
111 'deleted' => __( 'Deleted.', 'subscription' ),
112 'confirmPlan' => __( 'Delete this plan and all its durations? This cannot be undone.', 'subscription' ),
113 /* translators: %d: number of selected plans. */
114 'confirmBulkDelete' => __( 'Delete %d selected plan(s) and all their durations? This cannot be undone.', 'subscription' ),
115 'selectPlans' => __( 'Please select at least one plan.', 'subscription' ),
116 'confirmTerm' => __( 'Delete this duration?', 'subscription' ),
117 'confirmRemoveProduct' => __( 'Remove this product from the plan? It will be detached from every duration.', 'subscription' ),
118 'confirmRemoveVariation' => __( 'Remove this variation from the plan? It will be detached from every duration.', 'subscription' ),
119 'genericError' => __( 'Something went wrong. Please try again.', 'subscription' ),
120 'nameRequired' => __( 'Please enter a name.', 'subscription' ),
121 'addTerm' => __( 'Add Duration', 'subscription' ),
122 'editTerm' => __( 'Edit Duration', 'subscription' ),
123 'draft' => __( 'Draft', 'subscription' ),
124 'setDraft' => __( 'Set as Draft', 'subscription' ),
125 'setActive' => __( 'Set as Active', 'subscription' ),
126 'termActivated' => __( 'Duration activated.', 'subscription' ),
127 'pricesSaved' => __( 'Prices saved.', 'subscription' ),
128 'bulkApplied' => __( 'Prices updated.', 'subscription' ),
129 'bulkNoPrice' => __( 'Enter a regular price.', 'subscription' ),
130 'bulkNoProducts' => __( 'Select at least one product.', 'subscription' ),
131 'bulkNoTerms' => __( 'Select at least one duration.', 'subscription' ),
132 /* translators: %d: number of selected items. */
133 'bulkSelected' => __( '%d selected', 'subscription' ),
134 'oneTimeOn' => __( 'One-time purchase turned on.', 'subscription' ),
135 'oneTimeOff' => __( 'One-time purchase turned off.', 'subscription' ),
136 'userCancelOn' => __( 'User cancellation turned on.', 'subscription' ),
137 'userCancelOff' => __( 'User cancellation turned off.', 'subscription' ),
138 /* translators: %d: number of products ticked in the picker. */
139 'picked' => __( '%d product(s) on this plan', 'subscription' ),
140 'pickedNone' => __( 'No products on this plan', 'subscription' ),
141 'productsUpdated' => __( 'Products updated.', 'subscription' ),
142 'productRemoved' => __( 'Product removed from this plan.', 'subscription' ),
143 'termDrafted' => __( 'Duration set to draft.', 'subscription' ),
144 'orderSaved' => __( 'Order saved.', 'subscription' ),
145 /* translators: %1$s: first item number, %2$s: last item number, %3$s: total. */
146 'showingRange' => __( 'Showing %1-%2 of %3', 'subscription' ),
147 ),
148 )
149 );
150 }
151
152 /**
153 * Config for the shared plan-forms.js module (create group + selling-plan
154 * modals). Shared by the Plans screen and the product-editor Subscription
155 * tab so the term payload contract is localized identically on both.
156 *
157 * @return array
158 */
159 public static function plan_forms_config() {
160 return array(
161 'restUrl' => esc_url_raw( rest_url( 'wpsubscription/v1/plans' ) ),
162 'nonce' => wp_create_nonce( 'wp_rest' ),
163 'i18n' => array(
164 'genericError' => __( 'Something went wrong. Please try again.', 'subscription' ),
165 'nameRequired' => __( 'Please enter a name.', 'subscription' ),
166 'addTerm' => __( 'Add Duration', 'subscription' ),
167 'editTerm' => __( 'Edit Duration', 'subscription' ),
168 ),
169 );
170 }
171
172 /**
173 * Render the page: header + routed view (list or detail).
174 *
175 * @return void
176 */
177 public function render_page() {
178 // phpcs:disable WordPress.Security.NonceVerification.Recommended -- read-only view routing, no state change.
179 $view = isset( $_GET['view'] ) ? sanitize_key( wp_unslash( $_GET['view'] ) ) : 'list';
180 $plan_id = isset( $_GET['plan'] ) ? absint( wp_unslash( $_GET['plan'] ) ) : 0;
181 // phpcs:enable WordPress.Security.NonceVerification.Recommended
182
183 $plans = PlanPresenter::all();
184 $list_url = admin_url( 'admin.php?page=' . self::SLUG );
185
186 if ( 'detail' === $view && isset( $plans[ $plan_id ] ) ) {
187 $plan = $plans[ $plan_id ];
188
189 $this->render_header(
190 array(
191 array(
192 'label' => __( 'Plans', 'subscription' ),
193 'url' => $list_url,
194 ),
195 array( 'label' => $plan['name'] ),
196 )
197 );
198
199 include __DIR__ . '/views/plans/detail.php';
200 return;
201 }
202
203 $this->render_header( array( array( 'label' => __( 'Plans', 'subscription' ) ) ) );
204 include __DIR__ . '/views/plans/list.php';
205 }
206
207 /**
208 * Render the shared sticky admin header via the Menu class.
209 *
210 * @param array $breadcrumbs Ordered breadcrumb segments.
211 * @return void
212 */
213 private function render_header( $breadcrumbs ) {
214 $menu = new Menu();
215 if ( method_exists( $menu, 'render_admin_header' ) ) {
216 $menu->render_admin_header( __( 'Plans', 'subscription' ), '', $breadcrumbs );
217 }
218 }
219
220 /**
221 * Human label for a plan type.
222 *
223 * @param string $type Plan type key.
224 * @return string
225 */
226 public static function type_label( $type ) {
227 $labels = array(
228 'recurring' => __( 'Recurring Payment', 'subscription' ),
229 'subscribe_save' => __( 'Recurring Delivery', 'subscription' ),
230 'installments' => __( 'Split Payment', 'subscription' ),
231 );
232 return isset( $labels[ $type ] ) ? $labels[ $type ] : ucfirst( $type );
233 }
234
235 /**
236 * Dashicon class for a plan type.
237 *
238 * @param string $type Plan type key.
239 * @return string
240 */
241 public static function type_icon( $type ) {
242 $icons = array(
243 'recurring' => 'dashicons-update',
244 'subscribe_save' => 'dashicons-cart',
245 'installments' => 'dashicons-money-alt',
246 );
247 return isset( $icons[ $type ] ) ? $icons[ $type ] : 'dashicons-screenoptions';
248 }
249 }
250