Files
2025-11-18 23:16:28 +01:00

231 lines
6.8 KiB
PHP

<?php
/**
* Shortcode Handler
*
* Registers and processes shortcodes
*/
// Exit if accessed directly
if (!defined('ABSPATH')) {
exit;
}
class WHMCS_Pricing_Shortcodes {
/**
* Single instance
*/
private static $instance = null;
/**
* Translations cache
*/
private static $translations = null;
/**
* Get instance
*/
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor
*/
private function __construct() {
add_shortcode('whmcs_price', array($this, 'render_price_shortcode'));
}
/**
* Load translations from JSON file
*/
private static function load_translations() {
if (null !== self::$translations) {
return self::$translations;
}
$json_file = WHMCS_PRICING_PLUGIN_DIR . 'languages.json';
if (file_exists($json_file)) {
$json_content = file_get_contents($json_file);
self::$translations = json_decode($json_content, true);
}
if (!is_array(self::$translations)) {
self::$translations = array();
}
return self::$translations;
}
/**
* Render price shortcode
*
* @param array $atts Shortcode attributes
* @return string HTML output
*/
public function render_price_shortcode($atts) {
// Parse attributes
$atts = shortcode_atts(array(
'product_id' => '',
'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(
'<span class="%s" data-product-id="%d" data-cycle="%s">',
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(
'<span class="currency-symbol">%s</span>',
esc_html($price_data['symbol'])
);
}
$html .= sprintf(
'<span class="price-amount">%s</span>',
esc_html($price_data['formatted'])
);
if (!empty($cycle_text)) {
$html .= sprintf(
'<span class="billing-cycle">%s</span>',
esc_html($cycle_text)
);
}
$html .= '</span>';
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 '<span class="whmcs-price whmcs-price-error" style="display:none;"></span>';
}
return sprintf(
'<span class="whmcs-price whmcs-price-error" style="color: #dc3232; font-style: italic;">[WHMCS Pricing Error: %s]</span>',
esc_html($message)
);
}
}