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 / views / onboarding-wizard.php

onboarding-wizard.php in Subscriptions for WooCommerce with Stripe Recurring Payments trunk, at includes/Admin/views/onboarding-wizard.php

586 lines 34.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Onboarding Wizard Template.
4 *
5 * SPA-style: every section is rendered at once and JS toggles visibility.
6 * Flow: Create Plan (type + name) -> Set Frequency (duration) ->
7 * Connect to a Product -> Finish. A persistent right-rail preview shows the
8 * plan → durations → products flow and fills in live as each step is filled.
9 * The plan (group), duration (term) and product relation are created through
10 * the Plans REST API; only product creation uses admin-ajax.
11 *
12 * @package SpringDevs\Subscription\Admin
13 */
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit;
17 }
18
19 $is_pro = subscrpt_pro_activated();
20 $currency_symbol = get_woocommerce_currency_symbol();
21
22 // Whether the store has any product at all — decides the connect step's shape.
23 $has_products = (bool) wc_get_products(
24 array(
25 'status' => array( 'publish', 'draft', 'pending', 'private' ),
26 'limit' => 1,
27 'return' => 'ids',
28 )
29 );
30
31 // Plan types. Only "recurring" is available on the free plugin; the others are
32 // shown Pro-locked so the choice is visible but not selectable without Pro.
33 $plan_types = array(
34 array(
35 'key' => 'recurring',
36 'label' => __( 'Recurring', 'subscription' ),
37 'desc' => __( 'Charge on a repeating schedule.', 'subscription' ),
38 'name' => __( 'Recurring Subscription', 'subscription' ),
39 'pro' => false,
40 'icon' => '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>',
41 ),
42 array(
43 'key' => 'subscribe_save',
44 'label' => __( 'Subscribe & Save', 'subscription' ),
45 'desc' => __( 'Recurring with a discount.', 'subscription' ),
46 'name' => __( 'Subscribe & Save', 'subscription' ),
47 'pro' => true,
48 'icon' => '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"/><line x1="7" y1="7" x2="7.01" y2="7"/></svg>',
49 ),
50 array(
51 'key' => 'installments',
52 'label' => __( 'Installments', 'subscription' ),
53 'desc' => __( 'Split a price into payments.', 'subscription' ),
54 'name' => __( 'Installment Plan', 'subscription' ),
55 'pro' => true,
56 'icon' => '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="1" y="4" width="22" height="16" rx="2" ry="2"/><line x1="1" y1="10" x2="23" y2="10"/></svg>',
57 ),
58 );
59
60 $interval_options = array(
61 array(
62 'value' => 'day',
63 'label' => __( 'Day(s)', 'subscription' ),
64 ),
65 array(
66 'value' => 'week',
67 'label' => __( 'Week(s)', 'subscription' ),
68 ),
69 array(
70 'value' => 'month',
71 'label' => __( 'Month(s)', 'subscription' ),
72 ),
73 array(
74 'value' => 'year',
75 'label' => __( 'Year(s)', 'subscription' ),
76 ),
77 );
78
79 $avatar_palette = array(
80 array(
81 'bg' => '#fde8d8',
82 'fg' => '#b85c20',
83 ),
84 array(
85 'bg' => '#dbeafe',
86 'fg' => '#1d4ed8',
87 ),
88 array(
89 'bg' => '#ede9fe',
90 'fg' => '#6d28d9',
91 ),
92 array(
93 'bg' => '#d1fae5',
94 'fg' => '#065f46',
95 ),
96 array(
97 'bg' => '#fce7f3',
98 'fg' => '#9d174d',
99 ),
100 );
101
102 // Small SVG icons reused inside the preview graph nodes.
103 $subscrpt_icon_cal = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>';
104 $subscrpt_icon_box = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"/><line x1="3" y1="6" x2="21" y2="6"/><path d="M16 10a4 4 0 0 1-8 0"/></svg>';
105 $subscrpt_icon_plan = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/></svg>';
106 ?>
107 <div class="wpsubs-layout" id="subscrpt-onboarding-wizard">
108
109 <!-- Step indicator -->
110 <div class="wpsubs-wizard-stepper" id="subscrpt-stepper">
111 <div class="wpsubs-wizard-stepper__step" data-step="1">
112 <div class="wpsubs-wizard-stepper__num">1</div>
113 <div class="wpsubs-wizard-stepper__label"><?php esc_html_e( 'Plan', 'subscription' ); ?></div>
114 </div>
115 <div class="wpsubs-wizard-stepper__line"></div>
116 <div class="wpsubs-wizard-stepper__step" data-step="2">
117 <div class="wpsubs-wizard-stepper__num">2</div>
118 <div class="wpsubs-wizard-stepper__label"><?php esc_html_e( 'Durations', 'subscription' ); ?></div>
119 </div>
120 <div class="wpsubs-wizard-stepper__line"></div>
121 <div class="wpsubs-wizard-stepper__step" data-step="3">
122 <div class="wpsubs-wizard-stepper__num">3</div>
123 <div class="wpsubs-wizard-stepper__label"><?php esc_html_e( 'Product', 'subscription' ); ?></div>
124 </div>
125 <div class="wpsubs-wizard-stepper__line"></div>
126 <div class="wpsubs-wizard-stepper__step" data-step="4">
127 <div class="wpsubs-wizard-stepper__num">4</div>
128 <div class="wpsubs-wizard-stepper__label"><?php esc_html_e( 'Finish', 'subscription' ); ?></div>
129 </div>
130 </div>
131
132 <!-- Hidden state -->
133 <input type="hidden" id="subscrpt-wizard-page" value="0">
134 <input type="hidden" id="subscrpt-has-products" value="<?php echo $has_products ? '1' : '0'; ?>">
135 <input type="hidden" id="subscrpt-plan-type" value="recurring">
136 <?php wp_nonce_field( 'subscrpt_onboarding_wizard', 'subscrpt_wizard_nonce' ); ?>
137
138 <div class="wpsubs-wizard-layout">
139
140 <!-- ======================= Steps (left) ======================= -->
141 <div class="wpsubs-wizard-steps">
142
143 <!-- PAGE 0: Welcome (no preview / no footer — button lives in the card) -->
144 <div class="wpsubs-wizard-section active" data-page="0" id="subscrpt-section-0">
145 <div class="wpsubs-welcome-bg" aria-hidden="true"></div>
146 <div class="wpsubs-wizard-card wpsubs-welcome">
147 <img class="wpsubs-welcome__logo" src="<?php echo esc_url( SUBSCRPT_ASSETS . '/images/logo.png' ); ?>" width="64" height="64" alt="<?php esc_attr_e( 'WPSubscription', 'subscription' ); ?>">
148 <h1 class="wpsubs-welcome__title"><?php esc_html_e( 'Thank you for installing WPSubscription!', 'subscription' ); ?></h1>
149 <p class="wpsubs-welcome__lead"><?php esc_html_e( "Let's set up your first subscription plan. A plan decides how customers are billed and connects to a product they can subscribe to.", 'subscription' ); ?></p>
150 <ul class="wpsubs-welcome__steps">
151 <li><span class="wpsubs-welcome__num">1</span><?php esc_html_e( 'Create a plan and choose how customers are billed', 'subscription' ); ?></li>
152 <li><span class="wpsubs-welcome__num">2</span><?php esc_html_e( 'Add one or more billing durations', 'subscription' ); ?></li>
153 <li><span class="wpsubs-welcome__num">3</span><?php esc_html_e( 'Connect it to a product', 'subscription' ); ?></li>
154 </ul>
155 <div class="wpsubs-welcome__actions">
156 <button type="button" id="subscrpt-btn-start" class="wpsubs-btn wpsubs-btn--primary wpsubs-btn--lg">
157 <?php esc_html_e( "Let's go", 'subscription' ); ?> &rsaquo;
158 </button>
159 <button type="button" id="subscrpt-btn-skip" class="wpsubs-welcome__skip">
160 <?php esc_html_e( 'Skip setup', 'subscription' ); ?>
161 </button>
162 </div>
163 </div>
164 </div>
165
166 <!-- PAGE 1: Create Plan (type + name) -->
167 <div class="wpsubs-wizard-section" data-page="1" id="subscrpt-section-1">
168 <div class="wpsubs-wizard-card">
169 <h1 class="wpsubs-p2-page-title"><?php esc_html_e( 'Create a plan', 'subscription' ); ?></h1>
170 <p class="wpsubs-p2-page-subtitle"><?php esc_html_e( 'Choose how customers are billed, then name your plan.', 'subscription' ); ?></p>
171
172 <div class="wpsubs-p2-section-block">
173 <p class="wpsubs-p2-section-label"><?php esc_html_e( '1. Plan type', 'subscription' ); ?></p>
174 <div class="wpsubs-p2-option-cards wpsubs-p2-option-cards--list">
175 <?php foreach ( $plan_types as $subscrpt_type ) : ?>
176 <?php $subscrpt_locked = $subscrpt_type['pro'] && ! $is_pro; ?>
177 <button type="button"
178 class="wpsubs-p2-option-card wpsubs-plan-type-card<?php echo 'recurring' === $subscrpt_type['key'] ? ' active' : ''; ?>"
179 data-type="<?php echo esc_attr( $subscrpt_type['key'] ); ?>"
180 data-name="<?php echo esc_attr( $subscrpt_type['name'] ); ?>"
181 data-label="<?php echo esc_attr( $subscrpt_type['label'] ); ?>"
182 <?php echo $subscrpt_locked ? 'disabled' : ''; ?>>
183 <div class="wpsubs-p2-option-card__icon"><?php echo $subscrpt_type['icon']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted static SVG defined above. ?></div>
184 <div class="wpsubs-p2-option-card__text">
185 <p class="wpsubs-p2-option-card__title">
186 <?php echo esc_html( $subscrpt_type['label'] ); ?>
187 <?php if ( $subscrpt_locked ) : ?>
188 <span class="wpsubs-p2-pro-badge" title="<?php esc_attr_e( 'WPSubscription Pro required', 'subscription' ); ?>"><?php esc_html_e( 'Pro', 'subscription' ); ?></span>
189 <?php endif; ?>
190 </p>
191 <p class="wpsubs-p2-option-card__desc"><?php echo esc_html( $subscrpt_type['desc'] ); ?></p>
192 </div>
193 </button>
194 <?php endforeach; ?>
195 </div>
196 </div>
197
198 <div class="wpsubs-p2-section-block" style="margin-bottom:0;">
199 <p class="wpsubs-p2-section-label"><?php esc_html_e( '2. Plan name', 'subscription' ); ?></p>
200 <div class="wpsubs-form-row" style="margin-bottom:0;max-width:420px;">
201 <input type="text" id="subscrpt_plan_title" class="wpsubs-input" autocomplete="off" value="<?php esc_attr_e( 'Recurring Subscription', 'subscription' ); ?>" placeholder="<?php esc_attr_e( 'e.g. Monthly Box', 'subscription' ); ?>">
202 </div>
203 </div>
204 </div>
205 </div>
206
207 <!-- PAGE 2: Set Frequency (duration) -->
208 <div class="wpsubs-wizard-section" data-page="2" id="subscrpt-section-2">
209 <div class="wpsubs-wizard-card">
210 <h1 class="wpsubs-p2-page-title"><?php esc_html_e( 'Add billing durations', 'subscription' ); ?></h1>
211 <p class="wpsubs-p2-page-subtitle"><?php esc_html_e( 'How often a customer is charged. Add one or more to offer a choice.', 'subscription' ); ?></p>
212
213 <div id="subscrpt-durations" data-durations></div>
214
215 <button type="button" id="subscrpt-btn-add-duration" class="wpsubs-btn wpsubs-btn--outline" style="width:100%;justify-content:center;margin-top:4px;">
216 <span class="dashicons dashicons-plus-alt2" style="font-size:15px;width:15px;height:15px;line-height:1;"></span>
217 <?php esc_html_e( 'Add another duration', 'subscription' ); ?>
218 </button>
219
220 <template id="subscrpt-duration-tpl">
221 <div class="wpsubs-dur is-open" data-dur>
222 <div class="wpsubs-dur__head" data-dur-toggle>
223 <span class="wpsubs-dur__icon"><?php echo $subscrpt_icon_cal; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted static SVG. ?></span>
224 <span class="wpsubs-dur__title" data-dur-title></span>
225 <button type="button" class="wpsubs-dur__remove" data-dur-remove title="<?php esc_attr_e( 'Remove duration', 'subscription' ); ?>" aria-label="<?php esc_attr_e( 'Remove duration', 'subscription' ); ?>">&times;</button>
226 <svg class="wpsubs-dur__chevron" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"></polyline></svg>
227 </div>
228 <div class="wpsubs-dur__body">
229 <div class="wpsubs-form-row">
230 <label><?php esc_html_e( 'Billing every', 'subscription' ); ?></label>
231 <div class="wpsubs-p2-billing-group">
232 <input type="number" class="wpsubs-input wpsubs-p2-billing-per-input" autocomplete="off" min="1" value="1" data-dur-freq
233 <?php echo $is_pro ? '' : 'readonly max="1" title="' . esc_attr__( 'Upgrade to Pro to bill every few periods.', 'subscription' ) . '"'; ?>>
234 <?php
235 wpsubs_render_adv_select(
236 array(
237 'name' => 'subscrpt_dur_interval',
238 'value' => 'month',
239 'options' => $interval_options,
240 'class' => 'wpsubs-dur__interval',
241 'attrs' => array( 'data-dur-interval' => '1' ),
242 )
243 );
244 ?>
245 </div>
246 </div>
247 <div class="wpsubs-form-row" style="margin-bottom:0;">
248 <label><?php esc_html_e( 'Name', 'subscription' ); ?></label>
249 <input type="text" class="wpsubs-input" autocomplete="off" data-dur-name placeholder="<?php esc_attr_e( 'e.g. Every Month', 'subscription' ); ?>">
250 </div>
251 </div>
252 </div>
253 </template>
254 </div>
255 </div>
256
257 <!-- PAGE 3: Connect to a Product -->
258 <div class="wpsubs-wizard-section" data-page="3" id="subscrpt-section-3">
259 <div class="wpsubs-wizard-card">
260 <h1 class="wpsubs-p2-page-title"><?php esc_html_e( 'Connect the plan to a product', 'subscription' ); ?></h1>
261 <p class="wpsubs-p2-page-subtitle"><?php esc_html_e( 'Connect this plan to a product to make it subscribable.', 'subscription' ); ?></p>
262
263 <div class="wpsubs-p2-section-block">
264 <?php if ( $has_products ) : ?>
265 <p class="wpsubs-p2-section-label"><?php esc_html_e( '1. Select a product', 'subscription' ); ?></p>
266 <div class="wpsubs-p2-option-cards wpsubs-p2-option-cards--compact">
267 <button type="button" class="wpsubs-p2-option-card wpsubs-connect-mode-card active" data-mode="existing">
268 <div class="wpsubs-p2-option-card__icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></svg></div>
269 <p class="wpsubs-p2-option-card__title"><?php esc_html_e( 'Use an existing product', 'subscription' ); ?></p>
270 </button>
271 <button type="button" class="wpsubs-p2-option-card wpsubs-connect-mode-card" data-mode="new">
272 <div class="wpsubs-p2-option-card__icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg></div>
273 <p class="wpsubs-p2-option-card__title"><?php esc_html_e( 'Create a new product', 'subscription' ); ?></p>
274 </button>
275 </div>
276
277 <div id="subscrpt-connect-existing">
278 <p class="wpsubs-p2-section-desc"><?php esc_html_e( 'Pick a product to attach this plan to.', 'subscription' ); ?></p>
279
280 <div id="subscrpt-product-select-wrap">
281 <div class="wpsubs-p2-product-search">
282 <div class="wpsubs-p2-product-search__input-wrap">
283 <svg class="wpsubs-p2-product-search__icon" width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-4.35-4.35M17 11A6 6 0 1 1 5 11a6 6 0 0 1 12 0z"/></svg>
284 <input type="text" class="wpsubs-p2-product-search__input wpsubs-input" id="subscrpt-product-search-input"
285 placeholder="<?php esc_attr_e( 'Search products by name or SKU...', 'subscription' ); ?>" autocomplete="off">
286 </div>
287 <div class="wpsubs-p2-product-search__dropdown" id="subscrpt-product-search-dropdown" style="display:none;">
288 <?php
289 $subscrpt_products = wc_get_products(
290 array(
291 'status' => 'publish',
292 'limit' => 100,
293 'orderby' => 'title',
294 'order' => 'ASC',
295 'type' => $is_pro ? array( 'simple', 'variable' ) : array( 'simple' ),
296 )
297 );
298 foreach ( $subscrpt_products as $subscrpt_i => $subscrpt_wc_p ) :
299 $subscrpt_price = $subscrpt_wc_p->get_price();
300 $subscrpt_sku = $subscrpt_wc_p->get_sku();
301 $subscrpt_type = ucfirst( $subscrpt_wc_p->get_type() ) . ' ' . __( 'product', 'subscription' );
302 $subscrpt_name = $subscrpt_wc_p->get_name();
303 $subscrpt_words = array_filter( explode( ' ', $subscrpt_name ) );
304 $subscrpt_initials = implode(
305 '',
306 array_slice(
307 array_map(
308 function ( $w ) {
309 return mb_strtoupper( mb_substr( $w, 0, 1 ) );
310 },
311 $subscrpt_words
312 ),
313 0,
314 2
315 )
316 );
317 $subscrpt_color = $avatar_palette[ $subscrpt_i % count( $avatar_palette ) ];
318 // A product already attached to a plan can't be connected again —
319 // same rule as the Plans page product tab.
320 $subscrpt_conns = \SpringDevs\Subscription\Illuminate\Plans\PlanRepository::get_product_connections( $subscrpt_wc_p->get_id() );
321 $subscrpt_connected = ! empty( $subscrpt_conns );
322 ?>
323 <div class="wpsubs-p2-product-search__item<?php echo $subscrpt_connected ? ' wpsubs-p2-product-search__item--disabled' : ''; ?>"
324 data-id="<?php echo esc_attr( $subscrpt_wc_p->get_id() ); ?>"
325 data-price="<?php echo esc_attr( $subscrpt_price ); ?>"
326 data-type="<?php echo esc_attr( $subscrpt_type ); ?>"
327 data-sku="<?php echo esc_attr( $subscrpt_sku ); ?>"
328 data-name="<?php echo esc_attr( $subscrpt_name ); ?>"
329 <?php echo $subscrpt_connected ? 'data-connected="1"' : ''; ?>>
330 <div class="wpsubs-p2-product-search__avatar" style="background:<?php echo esc_attr( $subscrpt_color['bg'] ); ?>;color:<?php echo esc_attr( $subscrpt_color['fg'] ); ?>">
331 <?php echo esc_html( $subscrpt_initials ? $subscrpt_initials : '?' ); ?>
332 </div>
333 <div class="wpsubs-p2-product-search__info">
334 <p class="wpsubs-p2-product-search__name">
335 <?php echo esc_html( $subscrpt_name ); ?>
336 <?php if ( $subscrpt_connected ) : ?>
337 <span class="wpsubs-p2-product-search__connected"><?php esc_html_e( 'Added to another plan', 'subscription' ); ?></span>
338 <?php endif; ?>
339 </p>
340 <p class="wpsubs-p2-product-search__meta"><?php echo esc_html( ( $subscrpt_sku ? 'SKU ' . $subscrpt_sku . ' · ' : '' ) . $subscrpt_type ); ?></p>
341 </div>
342 <?php if ( '' !== $subscrpt_price ) : ?>
343 <span class="wpsubs-p2-product-search__price"><?php echo esc_html( $currency_symbol . number_format( (float) $subscrpt_price, 2 ) ); ?></span>
344 <?php endif; ?>
345 </div>
346 <?php endforeach; ?>
347 <div class="wpsubs-p2-product-search__empty" style="display:none;"><?php esc_html_e( 'No products found.', 'subscription' ); ?></div>
348 </div>
349 </div>
350 <input type="hidden" id="subscrpt-existing-product-hidden" value="">
351 </div>
352
353 <div id="subscrpt-selected-product-chip" class="wpsubs-p2-selected-product" style="display:none;">
354 <div class="wpsubs-p2-selected-product__avatar" id="p3-chip-avatar"></div>
355 <div class="wpsubs-p2-selected-product__info">
356 <p class="wpsubs-p2-selected-product__name" id="p3-chip-name"></p>
357 <p class="wpsubs-p2-selected-product__meta" id="p3-chip-meta"></p>
358 </div>
359 <button type="button" class="wpsubs-p2-selected-product__clear" id="subscrpt-btn-clear-product" aria-label="<?php esc_attr_e( 'Clear selection', 'subscription' ); ?>">×</button>
360 </div>
361 </div><!-- /#subscrpt-connect-existing -->
362 <?php endif; ?>
363
364 <div id="subscrpt-connect-new" <?php echo $has_products ? 'style="display:none;"' : ''; ?>>
365 <?php if ( ! $has_products ) : ?>
366 <p class="wpsubs-p2-section-label"><?php esc_html_e( '1. Create a product', 'subscription' ); ?></p>
367 <p class="wpsubs-p2-section-desc"><?php esc_html_e( "You don't have any products yet. Create one to connect this plan.", 'subscription' ); ?></p>
368 <?php endif; ?>
369 <div class="wpsubs-form-row">
370 <label for="subscrpt_new_product_name"><?php esc_html_e( 'Product name', 'subscription' ); ?></label>
371 <input type="text" id="subscrpt_new_product_name" class="wpsubs-input" autocomplete="off" placeholder="<?php esc_attr_e( 'e.g. Monthly Subscription Box', 'subscription' ); ?>">
372 <p class="wpsubs-p2-field-hint"><?php esc_html_e( 'Shown on your store and in emails.', 'subscription' ); ?></p>
373 </div>
374 </div>
375
376 </div><!-- /product section-block -->
377
378 <!-- Per-duration pricing: each duration from step 2 gets a price and an
379 on/off toggle. Rows are built from JS (renderConnectDurations). -->
380 <div class="wpsubs-p2-section-block wpsubs-connect-pricing" style="margin-bottom:0;">
381 <p class="wpsubs-p2-section-label"><?php esc_html_e( '2. Set pricing', 'subscription' ); ?></p>
382 <p class="wpsubs-p2-section-desc"><?php esc_html_e( "Set a price for each duration. Turn off any you don't want.", 'subscription' ); ?></p>
383 <div id="subscrpt-connect-durations"></div>
384 </div>
385
386 <template id="subscrpt-connect-dur-tpl">
387 <div class="wpsubs-connect-dur" data-connect-row>
388 <span class="wpsubs-connect-dur__icon"><?php echo $subscrpt_icon_cal; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted static SVG. ?></span>
389 <div class="wpsubs-connect-dur__text">
390 <p class="wpsubs-connect-dur__name" data-connect-name></p>
391 <p class="wpsubs-connect-dur__billing" data-connect-billing></p>
392 </div>
393 <div class="wpsubs-p2-input-wrap wpsubs-connect-dur__price">
394 <span class="wpsubs-p2-input-prefix"><?php echo esc_html( $currency_symbol ); ?></span>
395 <input type="text" class="wpsubs-input" data-connect-price autocomplete="off" placeholder="0.00" style="padding-left:24px!important;">
396 </div>
397 <label class="wpsubs-connect-dur__switch">
398 <input type="checkbox" class="wpsubs-toggle" data-connect-enabled checked>
399 <span class="wpsubs-toggle-ui" aria-hidden="true"></span>
400 </label>
401 </div>
402 </template>
403 </div>
404 </div>
405
406 <!-- PAGE 4: Finish — everything is created here, sequentially. -->
407 <div class="wpsubs-wizard-section" data-page="4" id="subscrpt-section-4">
408 <div class="wpsubs-wizard-card wpsubs-p3-card">
409
410 <!-- Working state: shown while the plan, durations and product are created. -->
411 <div id="subscrpt-finalize-progress" class="wpsubs-finalize-progress">
412 <div class="wpsubs-finalize-spinner" aria-hidden="true"></div>
413 <h1 class="wpsubs-p3-heading"><?php esc_html_e( 'Setting things up…', 'subscription' ); ?></h1>
414 <p class="wpsubs-p3-subtext"><?php esc_html_e( 'Creating your plan, durations and product. This takes a moment.', 'subscription' ); ?></p>
415 <ul class="wpsubs-finalize-steps">
416 <li data-finalize-step="plan"><span class="wpsubs-finalize-steps__dot"></span><?php esc_html_e( 'Create the plan', 'subscription' ); ?></li>
417 <li data-finalize-step="durations"><span class="wpsubs-finalize-steps__dot"></span><?php esc_html_e( 'Add billing durations', 'subscription' ); ?></li>
418 <li data-finalize-step="product"><span class="wpsubs-finalize-steps__dot"></span><?php esc_html_e( 'Connect the product', 'subscription' ); ?></li>
419 </ul>
420 </div>
421
422 <!-- Error state: shown if any step fails; the user can retry. -->
423 <div id="subscrpt-finalize-error" class="wpsubs-finalize-error" hidden>
424 <div class="wpsubs-finalize-error__icon" aria-hidden="true">
425 <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>
426 </div>
427 <h1 class="wpsubs-p3-heading"><?php esc_html_e( "Something didn't go through.", 'subscription' ); ?></h1>
428 <p class="wpsubs-p3-subtext" id="subscrpt-finalize-error-msg"></p>
429 <button type="button" id="subscrpt-btn-retry-finalize" class="wpsubs-btn wpsubs-btn--primary"><?php esc_html_e( 'Try again', 'subscription' ); ?></button>
430 </div>
431
432 <!-- Success state: shown once everything is created. -->
433 <div id="subscrpt-finalize-success" hidden>
434 <div class="wpsubs-p3-success-icon">
435 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
436 <polyline points="20 6 9 17 4 12"></polyline>
437 </svg>
438 </div>
439
440 <h1 class="wpsubs-p3-heading"><?php esc_html_e( 'Your plan is live.', 'subscription' ); ?></h1>
441 <p class="wpsubs-p3-subtext"><?php esc_html_e( 'Your product is now subscribable. When a customer buys it, a subscription is created automatically.', 'subscription' ); ?></p>
442
443 <p class="wpsubs-p3-what-now-label"><?php esc_html_e( 'WHAT NOW?', 'subscription' ); ?></p>
444
445 <div class="wpsubs-p3-action-rows">
446 <button type="button" id="subscrpt-btn-add-another" class="wpsubs-p3-action-row">
447 <div class="wpsubs-p3-action-row__icon">
448 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
449 </div>
450 <div class="wpsubs-p3-action-row__content">
451 <p class="wpsubs-p3-action-row__title"><?php esc_html_e( 'Create another plan', 'subscription' ); ?></p>
452 <p class="wpsubs-p3-action-row__desc"><?php esc_html_e( 'Set up another subscription plan now.', 'subscription' ); ?></p>
453 </div>
454 <svg class="wpsubs-p3-action-row__chevron" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="9 18 15 12 9 6"></polyline></svg>
455 </button>
456 </div>
457
458 <p class="wpsubs-p3-help-text">
459 <?php esc_html_e( 'Need help? Check the', 'subscription' ); ?>
460 <a href="https://docs.wpsubscription.co/en?utm_source=plugin&utm_medium=admin&utm_campaign=docs" target="_blank" rel="noopener" class="wpsubs-p3-help-link"><?php esc_html_e( 'setup guide', 'subscription' ); ?></a>
461 <?php esc_html_e( 'or', 'subscription' ); ?>
462 <a href="https://wordpress.org/support/plugin/subscription/" target="_blank" rel="noopener" class="wpsubs-p3-help-link"><?php esc_html_e( 'contact support', 'subscription' ); ?></a>.
463 </p>
464 </div>
465 </div>
466 </div>
467
468 </div><!-- /.wpsubs-wizard-steps -->
469
470 <!-- ===================== Live preview (right) ===================== -->
471 <aside class="wpsubs-wizard-aside">
472 <div class="wpsubs-preview">
473 <p class="wpsubs-preview__label"><?php esc_html_e( 'Live preview', 'subscription' ); ?></p>
474 <div class="wpsubs-p1-graph" id="subscrpt-preview-graph" data-active="plan" aria-hidden="true">
475 <svg class="wpsubs-p1-graph__lines" viewBox="0 0 300 420" preserveAspectRatio="none">
476 <!-- Plan -> durations (left→right offsets +1.5, +3, +1: right highest,
477 left slightly lower, middle lowest). data-line-dur maps each line
478 to the duration it feeds, so it colours in when filled. -->
479 <path class="wpsubs-p1-flow" data-line-dur="1" d="M150,50 C150,80 51,80 51,130" />
480 <path class="wpsubs-p1-flow" data-line-dur="0" d="M150,50 L150,168" />
481 <path class="wpsubs-p1-flow" data-line-dur="2" d="M150,50 C150,74 249,74 249,118" />
482 <!-- Durations -> the single product (start at each card's bottom).
483 data-line-to="prod" keeps these muted until a product is added, and
484 each shows only while its duration's toggle is on. -->
485 <path class="wpsubs-p1-flow" data-line-dur="1" data-line-to="prod" d="M51,168 C51,235 75,235 75,300" />
486 <path class="wpsubs-p1-flow" data-line-dur="0" data-line-to="prod" d="M150,206 C150,255 75,255 75,300" />
487 <path class="wpsubs-p1-flow" data-line-dur="2" data-line-to="prod" d="M249,156 C249,250 75,250 75,300" />
488 <!-- Decorative lines to the second (muted) product. No data-line-*, so they never colour in -- they just keep the second card connected. -->
489 <path class="wpsubs-p1-flow" d="M51,168 C51,240 225,240 225,330" />
490 <path class="wpsubs-p1-flow" d="M150,206 C150,262 225,262 225,330" />
491 <path class="wpsubs-p1-flow" d="M249,156 C249,250 225,250 225,330" />
492 </svg>
493
494 <div class="wpsubs-p1-node wpsubs-p1-node--plan" data-group="plan" style="left:21%;top:2.9%;">
495 <span class="wpsubs-p1-node__icon"><?php echo $subscrpt_icon_plan; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted static SVG. ?></span>
496 <span class="wpsubs-p1-node__text">
497 <span class="wpsubs-p1-node__title" id="subscrpt-preview-plan"><?php esc_html_e( 'Recurring Subscription', 'subscription' ); ?></span>
498 <span class="wpsubs-p1-node__sub" id="subscrpt-preview-plan-type"><?php esc_html_e( 'Recurring', 'subscription' ); ?></span>
499 </span>
500 </div>
501
502 <div class="wpsubs-p1-node wpsubs-p1-node--dur wpsubs-p1-node--ghost" data-group="dur" data-preview-dur="1" style="left:2%;top:31%;">
503 <span class="wpsubs-p1-node__icon"><?php echo $subscrpt_icon_cal; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted static SVG. ?></span>
504 <span class="wpsubs-p1-node__text">
505 <span class="wpsubs-p1-node__title"><?php esc_html_e( 'Duration', 'subscription' ); ?></span>
506 <span class="wpsubs-p1-node__sub"><?php esc_html_e( 'Add more', 'subscription' ); ?></span>
507 </span>
508 </div>
509 <div class="wpsubs-p1-node wpsubs-p1-node--dur wpsubs-p1-node--ghost" data-group="dur" data-preview-dur="0" style="left:35%;top:40%;">
510 <span class="wpsubs-p1-node__icon"><?php echo $subscrpt_icon_cal; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted static SVG. ?></span>
511 <span class="wpsubs-p1-node__text">
512 <span class="wpsubs-p1-node__title"><?php esc_html_e( 'Duration', 'subscription' ); ?></span>
513 <span class="wpsubs-p1-node__sub"><?php esc_html_e( 'Add more', 'subscription' ); ?></span>
514 </span>
515 </div>
516 <div class="wpsubs-p1-node wpsubs-p1-node--dur wpsubs-p1-node--ghost" data-group="dur" data-preview-dur="2" style="left:68%;top:28%;">
517 <span class="wpsubs-p1-node__icon"><?php echo $subscrpt_icon_cal; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted static SVG. ?></span>
518 <span class="wpsubs-p1-node__text">
519 <span class="wpsubs-p1-node__title"><?php esc_html_e( 'Duration', 'subscription' ); ?></span>
520 <span class="wpsubs-p1-node__sub"><?php esc_html_e( 'Add more', 'subscription' ); ?></span>
521 </span>
522 </div>
523
524 <div class="wpsubs-p1-node wpsubs-p1-node--prod" data-group="prod" style="left:3%;top:71.4%;">
525 <span class="wpsubs-p1-node__icon"><?php echo $subscrpt_icon_box; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted static SVG. ?></span>
526 <span class="wpsubs-p1-node__text">
527 <span class="wpsubs-p1-node__title" id="subscrpt-preview-prod"><?php esc_html_e( 'Product', 'subscription' ); ?></span>
528 <span class="wpsubs-p1-node__sub" id="subscrpt-preview-prod-sub"><?php esc_html_e( 'Price', 'subscription' ); ?></span>
529 </span>
530 </div>
531 <div class="wpsubs-p1-node wpsubs-p1-node--prod wpsubs-p1-node--ghost" data-group="prod" style="left:53%;top:78.6%;">
532 <span class="wpsubs-p1-node__icon"><?php echo $subscrpt_icon_box; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted static SVG. ?></span>
533 <span class="wpsubs-p1-node__text">
534 <span class="wpsubs-p1-node__title"><?php esc_html_e( 'Product', 'subscription' ); ?></span>
535 <span class="wpsubs-p1-node__sub"><?php esc_html_e( 'Add more', 'subscription' ); ?></span>
536 </span>
537 </div>
538 </div>
539 <p class="wpsubs-preview__caption"><?php esc_html_e( 'A plan holds billing durations and connects to a product.', 'subscription' ); ?></p>
540 </div>
541 </aside>
542
543 <!-- ======================= Footer nav (under the left column) ======================= -->
544 <div class="wpsubs-wizard-footer">
545 <div class="wpsubs-wizard-nav" data-nav="1" hidden>
546 <button type="button" id="subscrpt-btn-back-0" class="wpsubs-p2-nav-back">
547 &#8249; <?php esc_html_e( 'Back', 'subscription' ); ?>
548 </button>
549 <button type="button" id="subscrpt-btn-next-1" class="wpsubs-btn wpsubs-btn--primary">
550 <?php esc_html_e( 'Continue', 'subscription' ); ?> &rsaquo;
551 </button>
552 </div>
553 <div class="wpsubs-wizard-nav" data-nav="2" hidden>
554 <button type="button" id="subscrpt-btn-back-1" class="wpsubs-p2-nav-back">
555 &#8249; <?php esc_html_e( 'Back', 'subscription' ); ?>
556 </button>
557 <button type="button" id="subscrpt-btn-next-2" class="wpsubs-btn wpsubs-btn--primary">
558 <?php esc_html_e( 'Continue', 'subscription' ); ?> &rsaquo;
559 </button>
560 </div>
561 <div class="wpsubs-wizard-nav" data-nav="3" hidden>
562 <button type="button" id="subscrpt-btn-back-2" class="wpsubs-p2-nav-back">
563 &#8249; <?php esc_html_e( 'Back', 'subscription' ); ?>
564 </button>
565 <button type="button" id="subscrpt-btn-next-3" class="wpsubs-btn wpsubs-btn--primary">
566 <?php esc_html_e( 'Continue', 'subscription' ); ?> &rsaquo;
567 </button>
568 </div>
569 <div class="wpsubs-wizard-nav" data-nav="4" hidden>
570 <div class="wpsubs-wizard-nav__group">
571 <a href="#" id="subscrpt-link-plans" class="wpsubs-btn wpsubs-btn--outline" hidden>
572 <?php esc_html_e( 'Go to Plans', 'subscription' ); ?>
573 </a>
574 <a href="#" id="subscrpt-link-products" class="wpsubs-btn wpsubs-btn--outline" hidden>
575 <?php esc_html_e( 'Go to products', 'subscription' ); ?>
576 </a>
577 </div>
578 <a href="<?php echo esc_url( admin_url( 'admin.php?page=wp-subscription' ) ); ?>" id="subscrpt-btn-finish" class="wpsubs-btn wpsubs-btn--primary" hidden>
579 <?php esc_html_e( 'Finish', 'subscription' ); ?>
580 </a>
581 </div>
582 </div>
583
584 </div><!-- /.wpsubs-wizard-layout -->
585 </div>
586