| 1 |
<?php |
| 2 |
/** |
| 3 |
* Add / Edit Duration modal. |
| 4 |
* |
| 5 |
* Common rows: name, billing every, free trial, signup fee (Pro). |
| 6 |
* Recurring Delivery adds: delivery schedule + synchronize toggle (all Pro). |
| 7 |
* Split Payment adds: number of payments + access-ends timing (all Pro). |
| 8 |
* |
| 9 |
* @var array $plan Plan (provides id + type). |
| 10 |
* |
| 11 |
* @package SpringDevs\Subscription\Admin |
| 12 |
*/ |
| 13 |
|
| 14 |
if ( ! defined( 'ABSPATH' ) ) { |
| 15 |
exit; |
| 16 |
} |
| 17 |
|
| 18 |
$interval_options = array( |
| 19 |
array( |
| 20 |
'value' => 'day', |
| 21 |
'label' => __( 'Day(s)', 'subscription' ), |
| 22 |
), |
| 23 |
array( |
| 24 |
'value' => 'week', |
| 25 |
'label' => __( 'Week(s)', 'subscription' ), |
| 26 |
), |
| 27 |
array( |
| 28 |
'value' => 'month', |
| 29 |
'label' => __( 'Month(s)', 'subscription' ), |
| 30 |
), |
| 31 |
array( |
| 32 |
'value' => 'year', |
| 33 |
'label' => __( 'Year(s)', 'subscription' ), |
| 34 |
), |
| 35 |
); |
| 36 |
|
| 37 |
$access_options = array( |
| 38 |
array( |
| 39 |
'value' => 'lifetime', |
| 40 |
'label' => __( 'Never', 'subscription' ), |
| 41 |
), |
| 42 |
array( |
| 43 |
'value' => 'full_duration', |
| 44 |
'label' => __( 'After full duration', 'subscription' ), |
| 45 |
), |
| 46 |
array( |
| 47 |
'value' => 'custom', |
| 48 |
'label' => __( 'Custom', 'subscription' ), |
| 49 |
), |
| 50 |
); |
| 51 |
|
| 52 |
global $wp_locale; |
| 53 |
$weekday_options = array(); |
| 54 |
for ( $subscrpt_wd = 0; $subscrpt_wd < 7; $subscrpt_wd++ ) { |
| 55 |
$weekday_options[] = array( |
| 56 |
'value' => (string) $subscrpt_wd, |
| 57 |
'label' => $wp_locale ? $wp_locale->get_weekday( $subscrpt_wd ) : (string) $subscrpt_wd, |
| 58 |
); |
| 59 |
} |
| 60 |
|
| 61 |
// Match the onboarding "Subscription details" form-row styling. |
| 62 |
$label_style = 'display:block;font-size:13px;font-weight:500;color:var(--wpsubs-text);margin:0 0 7px;'; |
| 63 |
$row_style = 'margin-bottom:22px;'; |
| 64 |
$pair_style = 'display:flex;gap:8px;align-items:center;'; |
| 65 |
|
| 66 |
/** |
| 67 |
* Render a field description as a hover tooltip beside the label, so the |
| 68 |
* descriptions no longer clutter the form as paragraphs. Uses the shared |
| 69 |
* wpsubs-tooltip component (via wpsubs_render_hint()). |
| 70 |
* |
| 71 |
* @param string $text Description text. |
| 72 |
* @return string Hint markup (already escaped). |
| 73 |
*/ |
| 74 |
$hint = function ( $text ) { |
| 75 |
return wpsubs_render_hint( $text ); |
| 76 |
}; |
| 77 |
|
| 78 |
$pro_active = function_exists( 'subscrpt_pro_activated' ) && subscrpt_pro_activated(); |
| 79 |
$currency = function_exists( 'get_woocommerce_currency_symbol' ) |
| 80 |
? html_entity_decode( get_woocommerce_currency_symbol(), ENT_QUOTES, 'UTF-8' ) |
| 81 |
: '$'; |
| 82 |
|
| 83 |
$group_type = isset( $plan['type'] ) ? $plan['type'] : 'recurring'; |
| 84 |
$is_delivery = 'subscribe_save' === $group_type; |
| 85 |
$is_installments = 'installments' === $group_type; |
| 86 |
|
| 87 |
// The delivery + split-payment fields are Pro. When Pro is inactive (e.g. a |
| 88 |
// Pro-typed group opened after Pro was deactivated), lock them: a Pro badge on |
| 89 |
// the label, disabled native inputs, and a non-interactive look on adv-selects. |
| 90 |
$pro_locked = ! $pro_active; |
| 91 |
$pro_badge = $pro_locked |
| 92 |
? ' <span class="wpsubs-badge wpsubs-badge--pro" style="margin-left:6px;" title="' . esc_attr__( 'WPSubscription Pro required', 'subscription' ) . '">' . esc_html__( 'Pro', 'subscription' ) . '</span>' |
| 93 |
: ''; |
| 94 |
$adv_lock = $pro_locked ? 'opacity:0.55;pointer-events:none;' : ''; |
| 95 |
?> |
| 96 |
<div class="wpsubs-modal" id="subscrpt-term-modal" hidden data-subscrpt-term-modal data-group-id="<?php echo esc_attr( $plan['id'] ); ?>" data-group-type="<?php echo esc_attr( $group_type ); ?>"> |
| 97 |
<div class="wpsubs-modal__backdrop" data-wpsubs-modal-close></div> |
| 98 |
<div class="wpsubs-modal__dialog" style="width:min(460px, calc(100vw - 40px));"> |
| 99 |
<div class="wpsubs-modal__head"> |
| 100 |
<h2 class="wpsubs-modal__title" data-subscrpt-term-title><?php esc_html_e( 'Add Duration', 'subscription' ); ?></h2> |
| 101 |
<button type="button" class="wpsubs-modal__close" data-wpsubs-modal-close aria-label="<?php esc_attr_e( 'Close', 'subscription' ); ?>">×</button> |
| 102 |
</div> |
| 103 |
<div class="wpsubs-modal__body" style="overflow:visible;"> |
| 104 |
|
| 105 |
<!-- Duration name --> |
| 106 |
<div style="<?php echo esc_attr( $row_style ); ?>"> |
| 107 |
<label style="<?php echo esc_attr( $label_style ); ?>" for="subscrpt-term-name"><?php esc_html_e( 'Duration Name', 'subscription' ); ?><?php echo wp_kses_post( $hint( __( 'Shown to customers when they pick this plan.', 'subscription' ) ) ); ?></label> |
| 108 |
<input type="text" id="subscrpt-term-name" class="wpsubs-input" value="" placeholder="<?php esc_attr_e( 'e.g. Monthly', 'subscription' ); ?>" data-subscrpt-field="title" /> |
| 109 |
</div> |
| 110 |
|
| 111 |
<?php |
| 112 |
// Billing every + interval; for Split Payment it shares a row with the |
| 113 |
// number of payments. |
| 114 |
ob_start(); |
| 115 |
?> |
| 116 |
<label style="<?php echo esc_attr( $label_style ); ?>"><?php esc_html_e( 'Billing every', 'subscription' ); ?><?php echo wp_kses_post( $hint( __( 'How often the customer is charged, for example every 1 month.', 'subscription' ) ) ); ?></label> |
| 117 |
<div style="<?php echo esc_attr( $pair_style ); ?>"> |
| 118 |
<input type="number" class="wpsubs-input" value="1" min="1" max="<?php echo $pro_active ? '' : '1'; ?>" style="flex:1 1 auto;min-width:0;" data-subscrpt-field="billing_frequency" aria-label="<?php esc_attr_e( 'Frequency', 'subscription' ); ?>"<?php echo $pro_active ? '' : ' title="' . esc_attr__( 'Upgrade to Pro to bill every few periods.', 'subscription' ) . '"'; ?> <?php disabled( ! $pro_active ); ?> /> |
| 119 |
<?php |
| 120 |
wpsubs_render_adv_select( |
| 121 |
array( |
| 122 |
'name' => 'subscrpt_billing_interval', |
| 123 |
'value' => 'month', |
| 124 |
'options' => $interval_options, |
| 125 |
'attrs' => array( |
| 126 |
'data-subscrpt-field' => 'billing_interval', |
| 127 |
'style' => 'flex:0 0 auto;', |
| 128 |
), |
| 129 |
) |
| 130 |
); |
| 131 |
?> |
| 132 |
</div> |
| 133 |
<?php |
| 134 |
$billing_every_html = ob_get_clean(); |
| 135 |
?> |
| 136 |
|
| 137 |
<?php if ( $is_installments ) : ?> |
| 138 |
<!-- Billing every (billing group) | Number of payments --> |
| 139 |
<div style="display:grid;grid-template-columns:2fr 1fr;gap:8px;align-items:start;<?php echo esc_attr( $row_style ); ?>"> |
| 140 |
<div><?php echo $billing_every_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Pre-escaped markup (esc_* + wpsubs_render_adv_select()). ?></div> |
| 141 |
<?php // Label text is too long for this column; keep only the hint and an "×" prefix so it reads as a count: "1 Month(s) × 5". ?> |
| 142 |
<div> |
| 143 |
<label style="<?php echo esc_attr( $label_style ); ?>text-align:right;" for="subscrpt-term-installments"><?php echo wp_kses_post( $hint( __( 'Total payments to collect (minimum 2).', 'subscription' ) ) ); ?></label> |
| 144 |
<div style="display:flex;align-items:center;gap:8px;"> |
| 145 |
<span style="font-size:15px;color:var(--wpsubs-text-muted);line-height:1;" aria-hidden="true">×</span> |
| 146 |
<input type="number" id="subscrpt-term-installments" class="wpsubs-input" value="2" min="2" placeholder="<?php esc_attr_e( 'times', 'subscription' ); ?>" style="flex:1 1 auto;min-width:0;" data-subscrpt-field="installment_count" aria-label="<?php esc_attr_e( 'Number of payments', 'subscription' ); ?>" <?php disabled( $pro_locked ); ?> /> |
| 147 |
</div> |
| 148 |
</div> |
| 149 |
</div> |
| 150 |
<?php else : ?> |
| 151 |
<!-- Billing every --> |
| 152 |
<div style="<?php echo esc_attr( $row_style ); ?>"><?php echo $billing_every_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Pre-escaped markup (esc_* + wpsubs_render_adv_select()). ?></div> |
| 153 |
<?php endif; ?> |
| 154 |
|
| 155 |
<!-- Free trial | Signup fee --> |
| 156 |
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;<?php echo ( $is_delivery || $is_installments ) ? esc_attr( $row_style ) : 'margin-bottom:0;'; ?>"> |
| 157 |
<div> |
| 158 |
<label style="<?php echo esc_attr( $label_style ); ?>"><?php esc_html_e( 'Free trial', 'subscription' ); ?> <span style="color:var(--wpsubs-text-subtle);font-weight:400;">(<?php esc_html_e( 'optional', 'subscription' ); ?>)</span><?php echo wp_kses_post( $hint( __( 'Charge nothing until the trial ends.', 'subscription' ) ) ); ?></label> |
| 159 |
<div style="<?php echo esc_attr( $pair_style ); ?>"> |
| 160 |
<input type="number" class="wpsubs-input" value="" min="0" placeholder="0" style="flex:1 1 auto;min-width:0;" data-subscrpt-field="free_trial" aria-label="<?php esc_attr_e( 'Trial length', 'subscription' ); ?>" /> |
| 161 |
<?php |
| 162 |
wpsubs_render_adv_select( |
| 163 |
array( |
| 164 |
'name' => 'subscrpt_free_trial_interval', |
| 165 |
'value' => 'day', |
| 166 |
'options' => $interval_options, |
| 167 |
'attrs' => array( |
| 168 |
'data-subscrpt-field' => 'free_trial_interval', |
| 169 |
'style' => 'flex:0 0 auto;', |
| 170 |
), |
| 171 |
) |
| 172 |
); |
| 173 |
?> |
| 174 |
</div> |
| 175 |
</div> |
| 176 |
|
| 177 |
<div> |
| 178 |
<label style="<?php echo esc_attr( $label_style ); ?>" for="subscrpt-term-signup-fee"> |
| 179 |
<?php esc_html_e( 'Signup fee', 'subscription' ); ?> <span style="color:var(--wpsubs-text-subtle);font-weight:400;">(<?php esc_html_e( 'optional', 'subscription' ); ?>)</span> |
| 180 |
<?php if ( ! $pro_active ) : ?> |
| 181 |
<span class="wpsubs-badge wpsubs-badge--pro" style="margin-left:6px;" title="<?php esc_attr_e( 'WPSubscription Pro required', 'subscription' ); ?>"><?php esc_html_e( 'Pro', 'subscription' ); ?></span> |
| 182 |
<?php endif; ?> |
| 183 |
<?php echo wp_kses_post( $hint( __( 'One-time fee on the first payment.', 'subscription' ) ) ); ?> |
| 184 |
</label> |
| 185 |
<div style="position:relative;"> |
| 186 |
<span style="position:absolute;left:11px;top:50%;transform:translateY(-50%);font-size:13px;color:var(--wpsubs-text-muted);pointer-events:none;z-index:1;"><?php echo esc_html( $currency ); ?></span> |
| 187 |
<input type="number" id="subscrpt-term-signup-fee" class="wpsubs-input" value="" min="0" step="0.01" placeholder="0.00" style="padding-left:26px!important;" data-subscrpt-field="signup_fee_amount" <?php disabled( ! $pro_active ); ?> /> |
| 188 |
</div> |
| 189 |
</div> |
| 190 |
</div> |
| 191 |
|
| 192 |
<?php if ( $is_delivery ) : ?> |
| 193 |
<!-- Recurring Delivery extras --> |
| 194 |
<div style="<?php echo esc_attr( $row_style ); ?>"> |
| 195 |
<label style="<?php echo esc_attr( $label_style ); ?>"><?php esc_html_e( 'Delivery schedule', 'subscription' ); ?><?php echo wp_kses_post( $pro_badge ); ?><?php echo wp_kses_post( $hint( __( 'How often the product ships. Leave empty to match the billing schedule.', 'subscription' ) ) ); ?></label> |
| 196 |
<div style="<?php echo esc_attr( $pair_style ); ?>"> |
| 197 |
<input type="number" class="wpsubs-input" value="" min="1" placeholder="<?php esc_attr_e( 'Same as billing', 'subscription' ); ?>" style="flex:1 1 auto;min-width:0;" data-subscrpt-field="delivery_frequency" aria-label="<?php esc_attr_e( 'Delivery frequency', 'subscription' ); ?>" <?php disabled( $pro_locked ); ?> /> |
| 198 |
<?php |
| 199 |
wpsubs_render_adv_select( |
| 200 |
array( |
| 201 |
'name' => 'subscrpt_delivery_interval', |
| 202 |
'value' => 'month', |
| 203 |
'options' => $interval_options, |
| 204 |
'attrs' => array( |
| 205 |
'data-subscrpt-field' => 'delivery_interval', |
| 206 |
'style' => 'flex:0 0 auto;' . $adv_lock, |
| 207 |
), |
| 208 |
) |
| 209 |
); |
| 210 |
?> |
| 211 |
</div> |
| 212 |
</div> |
| 213 |
|
| 214 |
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;align-items:start;margin-bottom:0;"> |
| 215 |
<div> |
| 216 |
<label style="<?php echo esc_attr( $label_style ); ?>"><?php esc_html_e( 'Synchronize schedule', 'subscription' ); ?><?php echo wp_kses_post( $pro_badge ); ?><?php echo wp_kses_post( $hint( __( 'Deliver everyone on the same weekday.', 'subscription' ) ) ); ?></label> |
| 217 |
<label class="wpsubs-settings-toggle-label" style="display:inline-flex;align-items:center;gap:8px;height:36px;<?php echo esc_attr( $adv_lock ); ?>"> |
| 218 |
<input type="checkbox" class="wpsubs-toggle" data-subscrpt-field="delivery_sync" <?php disabled( $pro_locked ); ?> /> |
| 219 |
<span class="wpsubs-toggle-ui" aria-hidden="true"></span> |
| 220 |
</label> |
| 221 |
</div> |
| 222 |
<div data-subscrpt-delivery-day style="opacity:0.55;pointer-events:none;"> |
| 223 |
<label style="<?php echo esc_attr( $label_style ); ?>"><?php esc_html_e( 'Delivery day', 'subscription' ); ?><?php echo wp_kses_post( $pro_badge ); ?></label> |
| 224 |
<?php |
| 225 |
wpsubs_render_adv_select( |
| 226 |
array( |
| 227 |
'name' => 'subscrpt_delivery_day', |
| 228 |
'value' => '1', |
| 229 |
'options' => $weekday_options, |
| 230 |
'attrs' => array( |
| 231 |
'data-subscrpt-field' => 'delivery_day', |
| 232 |
'style' => 'width:100%;', |
| 233 |
), |
| 234 |
) |
| 235 |
); |
| 236 |
?> |
| 237 |
</div> |
| 238 |
</div> |
| 239 |
<?php endif; ?> |
| 240 |
|
| 241 |
<?php if ( $is_installments ) : ?> |
| 242 |
<!-- Split Payment: Access ends (full width) → Access ends | Custom duration when "Custom" is picked (JS toggles the grid). --> |
| 243 |
<div data-subscrpt-access-grid style="display:grid;grid-template-columns:1fr;gap:16px;align-items:start;margin-bottom:0;"> |
| 244 |
<div> |
| 245 |
<label style="<?php echo esc_attr( $label_style ); ?>"><?php esc_html_e( 'Access ends', 'subscription' ); ?><?php echo wp_kses_post( $pro_badge ); ?><?php echo wp_kses_post( $hint( __( 'When the customer loses access after the payments finish.', 'subscription' ) ) ); ?></label> |
| 246 |
<?php |
| 247 |
wpsubs_render_adv_select( |
| 248 |
array( |
| 249 |
'name' => 'subscrpt_access_ends', |
| 250 |
'value' => 'lifetime', |
| 251 |
'options' => $access_options, |
| 252 |
'attrs' => array( |
| 253 |
'data-subscrpt-field' => 'access_ends', |
| 254 |
'style' => 'width:100%;' . $adv_lock, |
| 255 |
), |
| 256 |
) |
| 257 |
); |
| 258 |
?> |
| 259 |
</div> |
| 260 |
|
| 261 |
<div data-subscrpt-access-custom style="display:none;"> |
| 262 |
<label style="<?php echo esc_attr( $label_style ); ?>"><?php esc_html_e( 'Custom access duration', 'subscription' ); ?><?php echo wp_kses_post( $pro_badge ); ?><?php echo wp_kses_post( $hint( __( 'How long access should continue after the last payment is completed.', 'subscription' ) ) ); ?></label> |
| 263 |
<div style="<?php echo esc_attr( $pair_style ); ?>"> |
| 264 |
<input type="number" class="wpsubs-input" value="1" min="1" style="flex:1 1 auto;min-width:0;" data-subscrpt-field="access_custom_value" aria-label="<?php esc_attr_e( 'Access length', 'subscription' ); ?>" <?php disabled( $pro_locked ); ?> /> |
| 265 |
<?php |
| 266 |
wpsubs_render_adv_select( |
| 267 |
array( |
| 268 |
'name' => 'subscrpt_access_custom_interval', |
| 269 |
'value' => 'month', |
| 270 |
'options' => $interval_options, |
| 271 |
'attrs' => array( |
| 272 |
'data-subscrpt-field' => 'access_custom_interval', |
| 273 |
'style' => 'flex:0 0 auto;' . $adv_lock, |
| 274 |
), |
| 275 |
) |
| 276 |
); |
| 277 |
?> |
| 278 |
</div> |
| 279 |
</div> |
| 280 |
</div> |
| 281 |
<?php endif; ?> |
| 282 |
|
| 283 |
</div> |
| 284 |
<div class="wpsubs-modal__footer"> |
| 285 |
<button type="button" class="wpsubs-btn wpsubs-btn--outline" data-wpsubs-modal-close><?php esc_html_e( 'Cancel', 'subscription' ); ?></button> |
| 286 |
<button type="button" class="wpsubs-btn wpsubs-btn--primary" data-subscrpt-term-submit><?php esc_html_e( 'Save Duration', 'subscription' ); ?></button> |
| 287 |
</div> |
| 288 |
</div> |
| 289 |
</div> |
| 290 |
|