class-subscription-prices-admin.php (10879B)
1 <?php 2 /** 3 * Subscription Prices Admin 4 * 5 * Handles the subscription prices settings page. 6 */ 7 8 if (!defined('ABSPATH')) { 9 exit; 10 } 11 12 class Taler_Subscription_Prices_Admin { 13 14 public function __construct() { 15 add_action('admin_init', array($this, 'register_settings')); 16 add_action('admin_post_taler_save_subscription_prices', array($this, 'save_subscription_prices')); 17 } 18 19 public function register_settings() { 20 register_setting('taler_subscription_prices', 'taler_turnstile_subscription_prices', array( 21 'type' => 'array', 22 'default' => array(), 23 'sanitize_callback' => array($this, 'sanitize_subscription_prices') 24 )); 25 } 26 27 public function sanitize_subscription_prices($input) { 28 if (!is_array($input)) { 29 return array(); 30 } 31 32 $sanitized = array(); 33 34 foreach ($input as $subscription_id => $currencies) { 35 if (!is_array($currencies)) { 36 continue; 37 } 38 39 foreach ($currencies as $currency_code => $price) { 40 if ($price === '' || $price === null) { 41 continue; 42 } 43 44 if (is_numeric($price) && $price >= 0) { 45 $sanitized[$subscription_id][$currency_code] = floatval($price); 46 } 47 } 48 } 49 50 // Clear payment choices cache when subscription prices change 51 wp_cache_flush(); 52 53 return $sanitized; 54 } 55 56 public static function render_settings_page() { 57 if (!current_user_can('manage_options')) { 58 return; 59 } 60 61 $backend_url = get_option('taler_turnstile_payment_backend_url'); 62 $access_token = get_option('taler_turnstile_access_token'); 63 64 if (empty($backend_url) || empty($access_token) || 65 (0 == Taler_Merchant_API::check_access($backend_url, 66 $access_token))) { 67 ?> 68 <div class="wrap"> 69 <h1><?php echo esc_html(get_admin_page_title()); ?></h1> 70 <div class="notice notice-error"> 71 <p> 72 <?php 73 printf( 74 /* translators: placeholders are the HTML to generate the link (beginning and end) */ 75 esc_html__('Turnstile payment backend is not configured. Please %1$sconfigure the backend%1$s first.', 'taler-turnstile'), 76 '<a href="' . esc_url(admin_url('options-general.php?page=taler-turnstile-settings')) . '">', 77 '</a>' 78 ); 79 ?> 80 </p> 81 </div> 82 </div> 83 <?php 84 return; 85 } 86 87 $subscriptions = Taler_Merchant_API::get_subscriptions(); 88 $currencies = Taler_Merchant_API::get_currencies(); 89 90 if (empty($currencies)) { 91 ?> 92 <div class="wrap"> 93 <h1><?php echo esc_html(get_admin_page_title()); ?></h1> 94 <div class="notice notice-error"> 95 <p><?php esc_html_e('Unable to load currencies from the API. Please check your backend configuration.', 'taler-turnstile'); ?></p> 96 </div> 97 </div> 98 <?php 99 return; 100 } 101 102 if (empty($subscriptions) || (count($subscriptions) === 1 && isset($subscriptions['%none%']))) { 103 ?> 104 <div class="wrap"> 105 <h1><?php echo esc_html(get_admin_page_title()); ?></h1> 106 <div class="notice notice-warning"> 107 <p><?php esc_html_e('No subscriptions configured in Taler merchant backend.', 'taler-turnstile'); ?></p> 108 </div> 109 </div> 110 <?php 111 return; 112 } 113 114 $existing_prices = get_option('taler_turnstile_subscription_prices', array()); 115 116 ?> 117 <div class="wrap taler-subscription-prices"> 118 <h1><?php echo esc_html(get_admin_page_title()); ?></h1> 119 120 <p><?php esc_html_e('Set the price for buying each subscription type in different currencies. Leave a field empty to prevent users from buying that subscription with that currency.', 'taler-turnstile'); ?></p> 121 122 <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>"> 123 <input type="hidden" name="action" value="taler_save_subscription_prices"> 124 <?php wp_nonce_field('taler_save_subscription_prices'); ?> 125 126 <?php foreach ($subscriptions as $subscription_id => $subscription): ?> 127 <?php 128 // Skip the %none% case as you can't buy "no subscription" 129 if ($subscription_id === '%none%') { 130 continue; 131 } 132 133 $subscription_label = $subscription['label']; 134 $subscription_description = isset($subscription['description']) ? $subscription['description'] : ''; 135 ?> 136 137 <div class="postbox"> 138 <div class="postbox-header"> 139 <h2 class="hndle"><?php echo esc_html($subscription_label); ?></h2> 140 </div> 141 <div class="inside"> 142 <?php if (!empty($subscription_description)): ?> 143 <p class="description"><?php echo esc_html($subscription_description); ?></p> 144 <?php endif; ?> 145 146 <table class="form-table"> 147 <?php foreach ($currencies as $currency): ?> 148 <?php 149 $currency_code = $currency['code']; 150 $currency_label = $currency['label']; 151 $field_name = 'subscription_prices[' . esc_attr($subscription_id) . '][' . esc_attr($currency_code) . ']'; 152 $field_value = isset($existing_prices[$subscription_id][$currency_code]) ? $existing_prices[$subscription_id][$currency_code] : ''; 153 ?> 154 <tr> 155 <th scope="row"> 156 <label for="sub_price_<?php echo esc_attr($subscription_id . '_' . $currency_code); ?>"> 157 <?php echo esc_html($currency_label); ?> 158 </label> 159 </th> 160 <td> 161 <input type="number" 162 name="<?php echo esc_attr($field_name); ?>" 163 id="sub_price_<?php echo esc_attr($subscription_id . '_' . $currency_code); ?>" 164 value="<?php echo esc_attr($field_value); ?>" 165 min="0" 166 step="<?php echo esc_attr($currency['step']); ?>" 167 class="small-text"> 168 <p class="description"> 169 <?php 170 printf( 171 /* translators: placeholder is the currency code (like "USD" or "EUR") */ 172 esc_html__('Leave empty to prevent buying this subscription with %s.', 'taler-turnstile'), 173 esc_html($currency_code) 174 ); 175 ?> 176 </p> 177 </td> 178 </tr> 179 <?php endforeach; ?> 180 </table> 181 </div> 182 </div> 183 184 <?php endforeach; ?> 185 186 <p class="submit"> 187 <input type="submit" name="submit" id="submit" class="button button-primary" value="<?php esc_attr_e('Save', 'taler-turnstile'); ?>"> 188 </p> 189 </form> 190 </div> 191 <?php 192 } 193 194 public function save_subscription_prices() { 195 if (!current_user_can('manage_options')) { 196 wp_die(__('You do not have sufficient permissions to access this page.', 'taler-turnstile')); 197 } 198 199 check_admin_referer('taler_save_subscription_prices'); 200 201 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash 202 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized 203 $subscription_prices = isset($_POST['subscription_prices']) ? $_POST['subscription_prices'] : array(); 204 205 // Validate and sanitize 206 $sanitized_prices = $this->sanitize_subscription_prices($subscription_prices); 207 208 // Check for validation errors 209 $has_errors = false; 210 211 if (is_array($subscription_prices)) { 212 foreach ($subscription_prices as $subscription_id => $currencies) { 213 if (is_array($currencies)) { 214 foreach ($currencies as $currency_code => $price) { 215 if ($price !== '' && $price !== null) { 216 if (!is_numeric($price) || $price < 0) { 217 add_settings_error( 218 'taler_subscription_prices', 219 'invalid_price', 220 __('Subscription prices cannot be negative.', 'taler-turnstile'), 221 'error' 222 ); 223 $has_errors = true; 224 break 2; 225 } 226 } 227 } 228 } 229 } 230 } 231 232 if (!$has_errors) { 233 update_option('taler_turnstile_subscription_prices', $sanitized_prices); 234 235 add_settings_error( 236 'taler_subscription_prices', 237 'prices_saved', 238 __('Subscription prices saved successfully.', 'taler-turnstile'), 239 'success' 240 ); 241 } 242 243 set_transient('settings_errors', get_settings_errors(), 30); 244 245 wp_redirect(add_query_arg( 246 array('page' => 'taler-subscription-prices', 'settings-updated' => 'true'), 247 admin_url('admin.php') 248 )); 249 exit; 250 } 251 }