'defer']
);
});
/**
* Map a shortcode element to the RoxyAPI request that feeds it. Returns
* [method, path, body] or null for an unknown element.
*/
function roxy_request_for($element, $atts) {
switch ($element) {
case 'horoscope-card':
return ['GET', sprintf('/astrology/horoscope/%s/%s', rawurlencode($atts['sign']), rawurlencode($atts['period'])), null];
case 'tarot-card':
return ['POST', '/tarot/daily', new stdClass()];
case 'numerology-card':
$parts = explode('-', $atts['date']);
return ['POST', '/numerology/life-path', ['year' => (int) $parts[0], 'month' => (int) $parts[1], 'day' => (int) $parts[2]]];
case 'vedic-kundli':
// Production tip: geocode the birth city with GET /location/search here
// instead of passing fixed coordinates in the shortcode.
return ['POST', '/vedic-astrology/birth-chart', [
'date' => $atts['date'],
'time' => $atts['time'],
'latitude' => (float) $atts['latitude'],
'longitude' => (float) $atts['longitude'],
'timezone' => (float) $atts['timezone'],
]];
default:
return null;
}
}
add_shortcode('roxy', function ($atts) {
$atts = shortcode_atts([
'element' => 'horoscope-card',
'sign' => 'aries',
'period' => 'daily',
'date' => '1990-01-15',
'time' => '14:30:00',
'latitude' => '',
'longitude' => '',
'timezone' => '5.5',
], $atts);
$element = sanitize_key($atts['element']);
$request = roxy_request_for($element, $atts);
if ($request === null) {
return '';
}
list($method, $path, $body) = $request;
$key = get_option('roxy_api_key', '');
if ($key === '') {
return '';
}
// Cache the response so repeat page views do not re-bill a call.
$cache_key = 'roxy_' . md5($element . wp_json_encode($atts));
$data = get_transient($cache_key);
if ($data === false) {
$url = 'https://roxyapi.com/api/v2' . $path;
$args = ['headers' => ['X-API-Key' => $key], 'timeout' => 10];
if ($method === 'POST') {
$args['headers']['Content-Type'] = 'application/json';
$args['body'] = wp_json_encode($body);
$response = wp_remote_post($url, $args);
} else {
$response = wp_remote_get($url, $args);
}
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
return '';
}
$data = wp_remote_retrieve_body($response);
set_transient($cache_key, $data, HOUR_IN_SECONDS);
}
// Escape the script-unsafe characters so no string field can break out of the
// inline ';
// Display attributes the component reads alongside data.
$display = [];
if ($element === 'horoscope-card') {
$display['period'] = $atts['period'];
} elseif ($element === 'numerology-card') {
$display['type'] = 'life-path';
} elseif ($element === 'vedic-kundli') {
$display['chart-style'] = 'south';
}
$attr = '';
foreach ($display as $name => $value) {
$attr .= sprintf(' %s="%s"', esc_attr($name), esc_attr($value));
}
$fallback = '';
return sprintf('%s%s', esc_attr($element), $attr, $json, esc_attr($element), $fallback);
});