'; woocommerce_wp_checkbox([ 'id' => '_abovault_is_subscription', 'label' => __('Subscription product', 'abovault'), 'description' => __('Bill this product on a recurring schedule (Abovault).', 'abovault'), ]); woocommerce_wp_text_input([ 'id' => '_abovault_interval_count', 'label' => __('Billing every', 'abovault'), 'type' => 'number', 'custom_attributes' => ['min' => '1', 'step' => '1'], 'value' => get_post_meta(get_the_ID(), '_abovault_interval_count', true) ?: '1', ]); woocommerce_wp_select([ 'id' => '_abovault_interval_unit', 'label' => __('Period', 'abovault'), 'options' => [ 'day' => __('Day(s)', 'abovault'), 'week' => __('Week(s)', 'abovault'), 'month' => __('Month(s)', 'abovault'), 'year' => __('Year(s)', 'abovault'), ], ]); woocommerce_wp_text_input([ 'id' => '_abovault_trial_days', 'label' => __('Free trial (days)', 'abovault'), 'type' => 'number', 'custom_attributes' => ['min' => '0', 'step' => '1'], 'value' => get_post_meta(get_the_ID(), '_abovault_trial_days', true) ?: '0', ]); echo ''; } public function save(int $postId): void { // WooCommerce verifies its product nonce before firing this hook; re-check // defensively so we never write meta from an unauthenticated request. $nonce = isset($_POST['woocommerce_meta_nonce']) ? sanitize_key(wp_unslash($_POST['woocommerce_meta_nonce'])) : ''; if (!wp_verify_nonce($nonce, 'woocommerce_save_data')) { return; } update_post_meta($postId, '_abovault_is_subscription', isset($_POST['_abovault_is_subscription']) ? 'yes' : 'no'); update_post_meta($postId, '_abovault_interval_count', max(1, absint(wp_unslash($_POST['_abovault_interval_count'] ?? 1)))); $unit = sanitize_text_field(wp_unslash($_POST['_abovault_interval_unit'] ?? 'month')); update_post_meta($postId, '_abovault_interval_unit', in_array($unit, ['day', 'week', 'month', 'year'], true) ? $unit : 'month'); update_post_meta($postId, '_abovault_trial_days', max(0, absint(wp_unslash($_POST['_abovault_trial_days'] ?? 0)))); } public static function isSubscription(int $productId): bool { return get_post_meta($productId, '_abovault_is_subscription', true) === 'yes'; } /** @return array{interval_count:int, interval_unit:string, trial_days:int} */ public static function terms(int $productId): array { return [ 'interval_count' => max(1, (int) get_post_meta($productId, '_abovault_interval_count', true)), 'interval_unit' => (string) (get_post_meta($productId, '_abovault_interval_unit', true) ?: 'month'), 'trial_days' => max(0, (int) get_post_meta($productId, '_abovault_trial_days', true)), ]; } }