'', 'billing_cycle' => 'monthly', 'currency' => '', 'format' => 'default', 'show_cycle' => 'true', 'class' => '', 'lang' => 'english', 'language' => '' // Support both lang and language ), $atts, 'whmcs_price'); // Validate product ID if (empty($atts['product_id'])) { return $this->render_error(__('Product ID is required', 'whmcs-pricing')); } // Sanitize attributes $product_id = absint($atts['product_id']); $billing_cycle = sanitize_text_field($atts['billing_cycle']); $currency = !empty($atts['currency']) ? sanitize_text_field($atts['currency']) : ''; $format = sanitize_text_field($atts['format']); $show_cycle = filter_var($atts['show_cycle'], FILTER_VALIDATE_BOOLEAN); $custom_class = sanitize_html_class($atts['class']); // Support both 'lang' and 'language' parameters $lang = !empty($atts['language']) ? sanitize_text_field($atts['language']) : sanitize_text_field($atts['lang']); // Get price from API $price_data = WHMCS_Pricing_API::get_price($product_id, array( 'billing_cycle' => $billing_cycle, 'currency' => $currency, 'format' => $format )); // Check for errors if (is_wp_error($price_data)) { return $this->render_error($price_data->get_error_message()); } // Render the price return $this->render_price_html($price_data, $billing_cycle, $product_id, $show_cycle, $custom_class, $lang); } /** * Render price HTML * * @param array $price_data Price data from API * @param string $billing_cycle Billing cycle * @param int $product_id Product ID * @param bool $show_cycle Whether to show billing cycle * @param string $custom_class Custom CSS class * @param string $lang Language code * @return string HTML output */ private function render_price_html($price_data, $billing_cycle, $product_id, $show_cycle, $custom_class, $lang = 'english') { $classes = array('whmcs-price'); if (!empty($custom_class)) { $classes[] = $custom_class; } // Get global settings $settings = get_option('whmcs_pricing_settings', array()); $hide_currency_symbol = isset($settings['hide_currency_symbol']) && $settings['hide_currency_symbol']; $hide_billing_cycle = isset($settings['hide_billing_cycle']) && $settings['hide_billing_cycle']; // Override billing cycle display based on global setting if ($hide_billing_cycle) { $show_cycle = false; } $cycle_text = $show_cycle ? $this->get_cycle_text($billing_cycle, $lang) : ''; $html = sprintf( '', esc_attr(implode(' ', $classes)), esc_attr($product_id), esc_attr($billing_cycle) ); // Only show currency symbol if not hidden if (!$hide_currency_symbol) { $html .= sprintf( '%s', esc_html($price_data['symbol']) ); } $html .= sprintf( '%s', esc_html($price_data['formatted']) ); if (!empty($cycle_text)) { $html .= sprintf( '%s', esc_html($cycle_text) ); } $html .= ''; return $html; } /** * Get billing cycle text * * @param string $cycle Billing cycle * @param string $lang Language code * @return string Human-readable cycle text */ private function get_cycle_text($cycle, $lang = 'english') { $cycle = strtolower($cycle); // Load translations $translations = self::load_translations(); // Check if language exists, fallback to English if (!isset($translations[$lang])) { $lang = 'english'; } // Get translated text if (isset($translations[$lang][$cycle])) { return ' ' . $translations[$lang][$cycle]; } // Final fallback to English defaults $defaults = array( 'monthly' => 'per month', 'quarterly' => 'per quarter', 'semiannually' => 'per 6 months', 'annually' => 'per year', 'biennially' => 'per 2 years', 'triennially' => 'per 3 years' ); return isset($defaults[$cycle]) ? ' ' . $defaults[$cycle] : ''; } /** * Render error message * * @param string $message Error message * @return string HTML output */ private function render_error($message) { // Only show errors to administrators if (!current_user_can('manage_options')) { return ''; } return sprintf( '[WHMCS Pricing Error: %s]', esc_html($message) ); } }