Files
yogibook_aury_new/wp plugin/yogasoul-eventi/yogasoul-eventi.php
T
2026-09-18 15:36:44 +02:00

276 lines
14 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Plugin Name: YogaSoul Eventi
* Description: Mostra gli eventi di YogiBook con card di prenotazione (lista d'attesa inclusa). Shortcode: [yogasoul_eventi], [yogasoul_eventi ids="12,15"], [yogasoul_eventi id="12"], [yogasoul_eventi limit="3"].
* Version: 1.0.0
* Author: YogaSoul
*/
if (!defined('ABSPATH')) {
exit;
}
/**
* Base dell'API YogiBook. Sovrascrivibile in wp-config.php con:
* define('YSE_API_BASE', 'https://yogibook.yogasoul.it/apiwp');
*/
if (!defined('YSE_API_BASE')) {
define('YSE_API_BASE', 'https://yogibook.yogasoul.it/apiwp');
}
/* Registra gli asset (accodati solo quando lo shortcode è in pagina).
Nessun Google Font: il widget eredita il carattere del tema. */
add_action('wp_enqueue_scripts', function () {
wp_register_style('yse-eventi', plugins_url('assets/yogasoul-eventi.css', __FILE__), [], '1.0.1');
wp_register_script('yse-eventi', plugins_url('assets/yogasoul-eventi.js', __FILE__), [], '1.0.0', true);
});
add_shortcode('yogasoul_eventi', 'yse_render_shortcode');
function yse_render_shortcode($atts)
{
$atts = shortcode_atts([
'ids' => '',
'id' => '',
'limit' => '',
], $atts, 'yogasoul_eventi');
wp_enqueue_style('yse-eventi');
wp_enqueue_script('yse-eventi');
// Costruisce l'URL dell'endpoint lista
$query = [];
if ($atts['id'] !== '') {
$query['id'] = (int) $atts['id'];
}
if ($atts['ids'] !== '') {
$clean = preg_replace('/[^0-9,]/', '', $atts['ids']);
if ($clean !== '') {
$query['ids'] = $clean;
}
}
if ($atts['limit'] !== '') {
$query['limit'] = (int) $atts['limit'];
}
$url = YSE_API_BASE . '/events.php' . (!empty($query) ? '?' . http_build_query($query) : '');
// Lettura server-side (niente CORS) + anti-cache
$resp = wp_remote_get($url . (strpos($url, '?') !== false ? '&' : '?') . '_=' . time(), [
'timeout' => 8,
'headers' => ['Cache-Control' => 'no-cache'],
]);
if (is_wp_error($resp) || (int) wp_remote_retrieve_response_code($resp) !== 200) {
return '<div class="yse-widget"><p class="yse-empty">Eventi non disponibili al momento.</p></div>';
}
$data = json_decode(wp_remote_retrieve_body($resp), true);
if (!is_array($data) || empty($data['ok'])) {
return '<div class="yse-widget"><p class="yse-empty">Eventi non disponibili al momento.</p></div>';
}
if (empty($data['events'])) {
return '<div class="yse-widget"><p class="yse-empty">Nessun evento in programma al momento.</p></div>';
}
$out = '<div class="yse-widget" data-api="' . esc_attr(YSE_API_BASE) . '">';
foreach ($data['events'] as $ev) {
$out .= yse_render_card($ev);
}
$out .= '</div>';
return $out;
}
/* Icona SVG inline (stroke = currentColor) */
function yse_icon($name)
{
$p = [
'user' => '<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>',
'pin' => '<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/>',
'clock' => '<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>',
'heart' => '<path d="M20.8 5.6a5 5 0 0 0-7-.1L12 7l-1.8-1.5a5 5 0 1 0-6.6 7.5L12 21l8.4-8a5 5 0 0 0 .4-7.4z"/>',
'bag' => '<path d="M6 7h12l1 13H5L6 7z"/><path d="M9 7a3 3 0 0 1 6 0"/>',
'info' => '<circle cx="12" cy="12" r="9"/><path d="M12 11v5"/><path d="M12 8h.01"/>',
'img' => '<rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-5-5L5 21"/>',
'chev' => '<path d="m6 9 6 6 6-6"/>',
];
$inner = $p[$name] ?? '';
return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7">' . $inner . '</svg>';
}
/* Rende una singola card evento */
function yse_render_card($ev)
{
$mesiAbbr = [1 => 'GEN', 2 => 'FEB', 3 => 'MAR', 4 => 'APR', 5 => 'MAG', 6 => 'GIU', 7 => 'LUG', 8 => 'AGO', 9 => 'SET', 10 => 'OTT', 11 => 'NOV', 12 => 'DIC'];
$mesi = [1 => 'gennaio', 2 => 'febbraio', 3 => 'marzo', 4 => 'aprile', 5 => 'maggio', 6 => 'giugno', 7 => 'luglio', 8 => 'agosto', 9 => 'settembre', 10 => 'ottobre', 11 => 'novembre', 12 => 'dicembre'];
$id = (int) $ev['id'];
$cost = (float) $ev['cost'];
$sym = (string) $ev['currency_symbol'];
$price = $cost > 0 ? $sym . number_format($cost, 2, ',', '.') : 'Gratuito';
$color = (isset($ev['color']) && preg_match('/^#[0-9a-fA-F]{6}$/', $ev['color'])) ? $ev['color'] : '#4CAF50';
$soldOut = !empty($ev['sold_out']);
$waitOn = !empty($ev['waitlist_enabled']);
$waitMode = $soldOut && $waitOn;
$hardFull = $soldOut && !$waitOn;
$maxPer = max(1, (int) $ev['max_per_booking']);
$remaining = (int) $ev['remaining'];
$maxQty = $soldOut ? ($waitMode ? $maxPer : 0) : max(1, min($maxPer, $remaining));
$startTs = strtotime($ev['starts_at']);
$dayNum = (int) date('j', $startTs);
$monAbbr = $mesiAbbr[(int) date('n', $startTs)];
$dateLong = $dayNum . ' ' . $mesi[(int) date('n', $startTs)] . ' ' . date('Y', $startTs);
$timeLabel = date('H:i', $startTs) . (!empty($ev['ends_at']) ? '–' . date('H:i', strtotime($ev['ends_at'])) : '');
$address = trim((string) ($ev['address'] ?? ''));
$organizer = trim((string) ($ev['organizer'] ?? ''));
$mapQuery = $address !== '' ? $address : ((isset($ev['lat'], $ev['lng']) && $ev['lat'] && $ev['lng']) ? ($ev['lat'] . ',' . $ev['lng']) : '');
$gallery = is_array($ev['gallery'] ?? null) ? $ev['gallery'] : [];
$hasDetails = trim((string) ($ev['description'] ?? '')) !== ''
|| trim((string) ($ev['suitable_for'] ?? '')) !== ''
|| trim((string) ($ev['what_to_bring'] ?? '')) !== ''
|| trim((string) ($ev['instructions'] ?? '')) !== ''
|| !empty($ev['cover_image']) || !empty($gallery) || $mapQuery !== '';
ob_start();
?>
<div class="yse-card" style="--yse-accent: <?php echo esc_attr($color); ?>;"
data-eid="<?php echo $id; ?>"
data-cost="<?php echo esc_attr($cost); ?>"
data-sym="<?php echo esc_attr($sym); ?>"
data-maxqty="<?php echo (int) $maxQty; ?>"
data-waitmode="<?php echo $waitMode ? 1 : 0; ?>">
<!-- HEADER COMPATTO -->
<div class="yse-chead">
<div class="yse-datechip">
<div class="yse-m"><?php echo esc_html($monAbbr); ?></div>
<div class="yse-d"><?php echo $dayNum; ?></div>
</div>
<?php if (!empty($ev['cover_image'])) : ?>
<img class="yse-thumb" src="<?php echo esc_url($ev['cover_image']); ?>" alt="<?php echo esc_attr($ev['title']); ?>">
<?php endif; ?>
<div class="yse-main">
<div class="yse-title-row">
<h3><?php echo esc_html($ev['title']); ?></h3>
<?php if ($hasDetails) : ?>
<button type="button" class="yse-toggle" aria-expanded="false">
<span class="yse-tlabel">Dettagli</span><?php echo yse_icon('chev'); ?>
</button>
<?php endif; ?>
</div>
<div class="yse-meta">
<span class="yse-item"><?php echo yse_icon('user'); ?> Capacità <strong><?php echo (int) $ev['occupied']; ?>/<?php echo (int) $ev['max_seats']; ?></strong></span>
<?php if ($address !== '') : ?>
<span class="yse-item"><?php echo yse_icon('pin'); ?> <?php echo esc_html($address); ?></span>
<?php endif; ?>
<span class="yse-item"><?php echo yse_icon('clock'); ?> <?php echo esc_html($dateLong); ?> · <?php echo esc_html($timeLabel); ?></span>
</div>
</div>
<div class="yse-price"><?php echo esc_html($price); ?></div>
</div>
<!-- DETTAGLI ESPANDIBILI -->
<?php if ($hasDetails) : ?>
<div class="yse-details">
<div class="yse-hero <?php echo empty($ev['cover_image']) ? 'yse-nocover' : ''; ?>">
<?php if (!empty($ev['cover_image'])) : ?>
<img src="<?php echo esc_url($ev['cover_image']); ?>" alt="<?php echo esc_attr($ev['title']); ?>">
<?php else : ?>
<div class="yse-emblem"><?php echo yse_icon('img'); ?></div>
<?php endif; ?>
</div>
<div class="yse-body">
<?php if (trim((string) ($ev['description'] ?? '')) !== '') : ?>
<div class="yse-desc"><?php echo wp_kses_post($ev['description']); ?></div>
<?php endif; ?>
<?php if (trim((string) ($ev['suitable_for'] ?? '')) !== '' || trim((string) ($ev['what_to_bring'] ?? '')) !== '' || trim((string) ($ev['instructions'] ?? '')) !== '') : ?>
<div class="yse-detail-grid">
<?php if (trim((string) ($ev['suitable_for'] ?? '')) !== '') : ?>
<div class="yse-detail"><div class="yse-dh"><?php echo yse_icon('heart'); ?> Per chi è adatto</div><div class="yse-dt"><?php echo nl2br(esc_html($ev['suitable_for'])); ?></div></div>
<?php endif; ?>
<?php if (trim((string) ($ev['what_to_bring'] ?? '')) !== '') : ?>
<div class="yse-detail"><div class="yse-dh"><?php echo yse_icon('bag'); ?> Cosa portare</div><div class="yse-dt"><?php echo nl2br(esc_html($ev['what_to_bring'])); ?></div></div>
<?php endif; ?>
<?php if (trim((string) ($ev['instructions'] ?? '')) !== '') : ?>
<div class="yse-detail"><div class="yse-dh"><?php echo yse_icon('info'); ?> Istruzioni</div><div class="yse-dt"><?php echo nl2br(esc_html($ev['instructions'])); ?></div></div>
<?php endif; ?>
</div>
<?php endif; ?>
<?php if (!empty($gallery)) : ?>
<div class="yse-section">
<h4><?php echo yse_icon('img'); ?> Galleria</h4>
<div class="yse-gallery">
<?php foreach ($gallery as $g) : ?>
<img src="<?php echo esc_url($g); ?>" alt="" data-full="<?php echo esc_url($g); ?>">
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
<?php if ($mapQuery !== '') : ?>
<div class="yse-section">
<h4><?php echo yse_icon('pin'); ?> Dove</h4>
<iframe class="yse-map" loading="lazy" src="https://www.google.com/maps?q=<?php echo rawurlencode($mapQuery); ?>&output=embed"></iframe>
</div>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
<!-- BOOKING -->
<div class="yse-booking">
<?php if (!empty($ev['scheduled'])) :
$pt = !empty($ev['publish_at']) ? strtotime($ev['publish_at']) : 0;
$ptLabel = $pt ? ((int) date('j', $pt) . ' ' . $mesi[(int) date('n', $pt)] . ' ' . date('Y', $pt) . ' alle ' . date('H:i', $pt)) : '';
?>
<div class="yse-scheduled">Prenotazioni aperte dal <strong><?php echo esc_html($ptLabel); ?></strong></div>
<?php elseif ($hardFull) : ?>
<div class="yse-soldout">Evento esaurito — non ci sono più posti disponibili.</div>
<?php else : ?>
<?php if ($waitMode) :
$waitingCount = (int) ($ev['waiting'] ?? 0);
$waitingTxt = $waitingCount > 0
? ' Al momento ' . ($waitingCount === 1 ? "c'è 1 persona" : "ci sono {$waitingCount} persone") . ' in coda.'
: '';
?>
<div class="yse-wl-banner">Posti esauriti — puoi iscriverti alla <strong>lista d'attesa</strong>: ti avviseremo se si libera un posto.<?php echo esc_html($waitingTxt); ?></div>
<?php endif; ?>
<div class="yse-bcompact">
<div class="yse-btitle"><?php echo $waitMode ? "Lista d'attesa" : 'Prenota questo evento'; ?></div>
<div class="yse-bblock">
<div class="yse-lbl">Persone</div>
<div class="yse-stepper">
<button type="button" class="yse-minus">−</button>
<span class="yse-num">1</span>
<button type="button" class="yse-plus">+</button>
</div>
</div>
<div class="yse-bblock yse-total">
<div class="yse-lbl">Totale</div>
<div class="yse-val"><?php echo esc_html($price); ?></div>
</div>
<button type="button" class="yse-cta yse-open"><?php echo $waitMode ? "Lista d'attesa" : 'Prenota'; ?></button>
</div>
<div class="yse-bform">
<div class="yse-frow">
<div class="yse-field"><label>Nome *</label><input type="text" class="yse-name" placeholder="Il tuo nome"></div>
<div class="yse-field"><label>Cognome *</label><input type="text" class="yse-surname" placeholder="Il tuo cognome"></div>
</div>
<div class="yse-field"><label>Email *</label><input type="email" class="yse-email" placeholder="latua@email.it"></div>
<label class="yse-consent"><input type="checkbox" class="yse-c-privacy"> <span>Ho letto e accetto l'informativa privacy. *</span></label>
<label class="yse-consent"><input type="checkbox" class="yse-c-mkt"> <span>Desidero ricevere aggiornamenti e novità via email.</span></label>
<!-- honeypot anti-bot -->
<input type="text" class="yse-hp" name="website" tabindex="-1" autocomplete="off">
<button type="button" class="yse-cta yse-full yse-submit"><?php echo $waitMode ? "Iscriviti alla lista d'attesa" : 'Conferma prenotazione'; ?></button>
<div class="yse-error"></div>
</div>
<?php endif; ?>
</div>
</div>
<?php
return ob_get_clean();
}