PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / trunk
Subscriptions for WooCommerce with Stripe Recurring Payments vtrunk
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 / Plans.php

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

241 lines 8.2 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 'oneTimeOn' => __( 'One-time purchase turned on.', 'subscription' ),
129 'oneTimeOff' => __( 'One-time purchase turned off.', 'subscription' ),
130 /* translators: %d: number of products ticked in the picker. */
131 'picked' => __( '%d product(s) on this plan', 'subscription' ),
132 'pickedNone' => __( 'No products on this plan', 'subscription' ),
133 'productsUpdated' => __( 'Products updated.', 'subscription' ),
134 'productRemoved' => __( 'Product removed from this plan.', 'subscription' ),
135 'termDrafted' => __( 'Duration set to draft.', 'subscription' ),
136 /* translators: %1$s: first item number, %2$s: last item number, %3$s: total. */
137 'showingRange' => __( 'Showing %1-%2 of %3', 'subscription' ),
138 ),
139 )
140 );
141 }
142
143 /**
144 * Config for the shared plan-forms.js module (create group + selling-plan
145 * modals). Shared by the Plans screen and the product-editor Subscription
146 * tab so the term payload contract is localized identically on both.
147 *
148 * @return array
149 */
150 public static function plan_forms_config() {
151 return array(
152 'restUrl' => esc_url_raw( rest_url( 'wpsubscription/v1/plans' ) ),
153 'nonce' => wp_create_nonce( 'wp_rest' ),
154 'i18n' => array(
155 'genericError' => __( 'Something went wrong. Please try again.', 'subscription' ),
156 'nameRequired' => __( 'Please enter a name.', 'subscription' ),
157 'addTerm' => __( 'Add Duration', 'subscription' ),
158 'editTerm' => __( 'Edit Duration', 'subscription' ),
159 ),
160 );
161 }
162
163 /**
164 * Render the page: header + routed view (list or detail).
165 *
166 * @return void
167 */
168 public function render_page() {
169 // phpcs:disable WordPress.Security.NonceVerification.Recommended -- read-only view routing, no state change.
170 $view = isset( $_GET['view'] ) ? sanitize_key( wp_unslash( $_GET['view'] ) ) : 'list';
171 $plan_id = isset( $_GET['plan'] ) ? absint( wp_unslash( $_GET['plan'] ) ) : 0;
172 // phpcs:enable WordPress.Security.NonceVerification.Recommended
173
174 $plans = PlanPresenter::all();
175 $list_url = admin_url( 'admin.php?page=' . self::SLUG );
176
177 if ( 'detail' === $view && isset( $plans[ $plan_id ] ) ) {
178 $plan = $plans[ $plan_id ];
179
180 $this->render_header(
181 array(
182 array(
183 'label' => __( 'Plans', 'subscription' ),
184 'url' => $list_url,
185 ),
186 array( 'label' => $plan['name'] ),
187 )
188 );
189
190 include __DIR__ . '/views/plans/detail.php';
191 return;
192 }
193
194 $this->render_header( array( array( 'label' => __( 'Plans', 'subscription' ) ) ) );
195 include __DIR__ . '/views/plans/list.php';
196 }
197
198 /**
199 * Render the shared sticky admin header via the Menu class.
200 *
201 * @param array $breadcrumbs Ordered breadcrumb segments.
202 * @return void
203 */
204 private function render_header( $breadcrumbs ) {
205 $menu = new Menu();
206 if ( method_exists( $menu, 'render_admin_header' ) ) {
207 $menu->render_admin_header( __( 'Plans', 'subscription' ), '', $breadcrumbs );
208 }
209 }
210
211 /**
212 * Human label for a plan type.
213 *
214 * @param string $type Plan type key.
215 * @return string
216 */
217 public static function type_label( $type ) {
218 $labels = array(
219 'recurring' => __( 'Recurring Payment', 'subscription' ),
220 'subscribe_save' => __( 'Recurring Delivery', 'subscription' ),
221 'installments' => __( 'Split Payment', 'subscription' ),
222 );
223 return isset( $labels[ $type ] ) ? $labels[ $type ] : ucfirst( $type );
224 }
225
226 /**
227 * Dashicon class for a plan type.
228 *
229 * @param string $type Plan type key.
230 * @return string
231 */
232 public static function type_icon( $type ) {
233 $icons = array(
234 'recurring' => 'dashicons-update',
235 'subscribe_save' => 'dashicons-cart',
236 'installments' => 'dashicons-money-alt',
237 );
238 return isset( $icons[ $type ] ) ? $icons[ $type ] : 'dashicons-screenoptions';
239 }
240 }
241