Shortcode WordPressDEV
Mostra il menu MenuFacile su una pagina WordPress con shortcode + cache.
Obiettivo: una pagina WordPress che mostra il menu del ristorante leggendolo dall'API MenuFacile, con cache server-side per ridurre il numero di chiamate e tenere i tempi di risposta sotto i 100ms.
Caso d'uso
Il cliente ha già un sito WordPress (template Astra, Divi, Avada, qualsiasi). Vuole una pagina "Il nostro menu" che mostri il menu live, senza duplicare i piatti su WordPress (così quando cambia un piatto sul pannello MenuFacile, il sito si aggiorna in 5 minuti senza copia-incolla).
Codice
Aggiungi al functions.php del tema (o meglio in un plugin custom):
<?php
/**
* MenuFacile shortcode for WordPress.
* Usage: [menufacile tenant="ducatarocco" locale="it"]
*/
function menufacile_render_menu($atts) {
$atts = shortcode_atts([
'tenant' => '',
'locale' => 'it',
'cache_minutes' => 5,
], $atts, 'menufacile');
if (empty($atts['tenant'])) {
return '<!-- MenuFacile: tenant attribute mancante -->';
}
$tenant = sanitize_key($atts['tenant']);
$locale = sanitize_key($atts['locale']);
$cache_key = "mf_menu_{$tenant}_{$locale}";
$data = get_transient($cache_key);
if (false === $data) {
$url = sprintf(
'https://%s.menufacile.it/api/v1/menu/%s',
$tenant,
$locale
);
$resp = wp_remote_get($url, [
'timeout' => 5,
'headers' => ['Accept' => 'application/json'],
]);
if (is_wp_error($resp) || 200 !== wp_remote_retrieve_response_code($resp)) {
return '<p class="mf-error">Menu temporaneamente non disponibile.</p>';
}
$body = json_decode(wp_remote_retrieve_body($resp), true);
$data = $body['data'] ?? null;
if ($data) {
set_transient(
$cache_key,
$data,
absint($atts['cache_minutes']) * MINUTE_IN_SECONDS
);
}
}
if (!$data) {
return '<p class="mf-error">Menu non disponibile.</p>';
}
return menufacile_format_html($data);
}
function menufacile_format_html($data) {
$html = '<div class="mf-menu">';
if (!empty($data['settings']['name'])) {
$html .= '<h1 class="mf-restaurant-name">' . esc_html($data['settings']['name']) . '</h1>';
}
foreach ($data['sections'] as $section) {
if (empty($section['is_active'])) {
continue;
}
$html .= '<section class="mf-section mf-section--' . esc_attr($section['menu_type']) . '">';
$html .= '<h2>' . esc_html($section['name']) . '</h2>';
if (!empty($section['notes'])) {
$html .= '<p class="mf-section-notes">' . wp_kses_post($section['notes']) . '</p>';
}
$html .= '<ul class="mf-items">';
foreach ($section['items'] as $item) {
$html .= '<li class="mf-item">';
$html .= '<div class="mf-item-header">';
$html .= '<strong class="mf-item-name">' . esc_html($item['name']) . '</strong>';
$html .= '<span class="mf-item-price">€ ' . number_format((float) $item['price'], 2, ',', '') . '</span>';
$html .= '</div>';
if (!empty($item['description'])) {
$html .= '<p class="mf-item-description">' . esc_html($item['description']) . '</p>';
}
if (!empty($item['allergens'])) {
$html .= '<p class="mf-item-allergens">Allergeni: ' . esc_html(implode(', ', $item['allergens'])) . '</p>';
}
$html .= '</li>';
}
$html .= '</ul></section>';
}
return $html . '</div>';
}
add_shortcode('menufacile', 'menufacile_render_menu');
/**
* Stile minimale: aggiungilo nel CSS del tema o estendilo a piacere.
*/
function menufacile_inline_styles() {
echo '<style>
.mf-menu { max-width: 800px; margin: 0 auto; }
.mf-section { margin-bottom: 2rem; }
.mf-items { list-style: none; padding: 0; }
.mf-item { padding: 0.75rem 0; border-bottom: 1px solid #eee; }
.mf-item-header { display: flex; justify-content: space-between; gap: 1rem; }
.mf-item-price { font-weight: 600; white-space: nowrap; }
.mf-item-allergens { font-size: 0.85em; color: #999; margin: 0.25rem 0 0; }
</style>';
}
add_action('wp_head', 'menufacile_inline_styles');
Uso nella pagina
Crea una pagina "Il nostro menu", modalità classica (non Gutenberg, oppure usa il blocco "Shortcode"):
[menufacile tenant="ducatarocco" locale="it"]
Versione inglese:
[menufacile tenant="ducatarocco" locale="en"]
Cache più aggressiva (10 minuti):
[menufacile tenant="ducatarocco" locale="it" cache_minutes="10"]
Considerazioni
Cache
Il transient API di WordPress salva su DB (o Redis se hai object-cache). Con cache_minutes=5 il sito chiama MenuFacile una volta ogni 5 minuti indipendentemente dal traffico. Anche con 10.000 visite/giorno fai ~288 richieste/giorno: carico minimo lato server, esperienza utente immediata.
Invalidazione manuale
Se il ristoratore vuole vedere subito una modifica senza aspettare i 5 minuti, può cancellare il transient. Comodo da WP-CLI:
wp transient delete mf_menu_ducatarocco_it
Multilingua (Polylang/WPML)
Se il sito WP è multilingua, in ogni versione di pagina passa il locale corretto:
[menufacile tenant="ducatarocco" locale="it"]
[menufacile tenant="ducatarocco" locale="en"]
Performance lato server
wp_remote_get con timeout=5: se MenuFacile dovesse essere lento, la pagina WordPress non si blocca oltre 5 secondi. Per siti high-traffic considera object cache (Redis) invece dei transient su DB.
SEO
Il menu è renderizzato server-side (HTML statico nella response): Googlebot lo vede senza problemi. Per arricchirlo ulteriormente con dati strutturati, vedi Schema.org JSON-LD.
Hai bisogno di aiuto?
Scrivi a info@menufacile.it.