2131 lines
93 KiB
PHP
Executable File
2131 lines
93 KiB
PHP
Executable File
<?php
|
||
/**
|
||
* Plugin Name: Fe Adulta — Homepage
|
||
* Description: Portada con selección editorial via ACF.
|
||
* Version: 1.4
|
||
*/
|
||
|
||
// ── Flush rewrite rules una sola vez tras cambios de configuración ────────
|
||
add_action('init', function() {
|
||
if (get_option('fea_flush_needed')) {
|
||
flush_rewrite_rules(true);
|
||
delete_option('fea_flush_needed');
|
||
}
|
||
});
|
||
|
||
// ── Portada multilingüe: sirve la página traducida en el home de cada idioma ──
|
||
// Polylang free no traduce page_on_front automáticamente.
|
||
// Este hook intercepta el query del home de idioma y carga la página correcta.
|
||
add_action('pre_get_posts', function(WP_Query $query) {
|
||
if (!$query->is_main_query()) return;
|
||
if (!function_exists('pll_current_language') || !function_exists('pll_get_post')) return;
|
||
|
||
// Solo actuar cuando WP cree que está en el home/front page
|
||
if (!$query->is_home() && !$query->is_front_page()) return;
|
||
|
||
$lang = pll_current_language();
|
||
if (!$lang || $lang === 'es') return;
|
||
|
||
$translated_id = pll_get_post(26542, $lang);
|
||
if (!$translated_id) return;
|
||
|
||
// Forzar carga de la página traducida como si fuera la portada estática
|
||
$query->set('page_id', $translated_id);
|
||
$query->set('post_type', 'page');
|
||
$query->is_home = false;
|
||
$query->is_front_page = true;
|
||
$query->is_singular = true;
|
||
$query->is_page = true;
|
||
}, 1);
|
||
|
||
// ── Multimedia: 30 entradas por página en su archivo (#63) ──
|
||
add_action('pre_get_posts', function(WP_Query $query) {
|
||
if (is_admin() || !$query->is_main_query()) return;
|
||
if ($query->is_category('multimedia')) {
|
||
$query->set('posts_per_page', 30);
|
||
}
|
||
});
|
||
|
||
// ── Tablón de anuncios (#97): ocultar del listado los anuncios de más de 12 meses ──
|
||
// Ventana móvil, no destructiva: los posts siguen publicados/accesibles por URL; solo
|
||
// se excluyen del archivo de la categoría para que el Tablón no parezca desactualizado.
|
||
// Cubre las 5 categorías Polylang (ES + en/fr/it/pt).
|
||
add_action('pre_get_posts', function(WP_Query $query) {
|
||
if (is_admin() || !$query->is_main_query()) return;
|
||
if ($query->is_category(['tablon-de-anuncios', 'tablon-de-anuncios-en',
|
||
'tablon-de-anuncios-fr', 'tablon-de-anuncios-it', 'tablon-de-anuncios-pt'])) {
|
||
$query->set('date_query', [[
|
||
'after' => date('Y-m-d', strtotime('-12 months')),
|
||
'inclusive' => true,
|
||
]]);
|
||
}
|
||
});
|
||
|
||
// ── Normalizar títulos (TODO CAPS legacy → frase) en todo el front #63 #73 ──
|
||
// Mismo criterio que la portada (fea_title). Cubre listados/búsqueda/home, el artículo
|
||
// (single), el <title>/SEO y los feeds. El wp-admin se deja SIN tocar para que el editor
|
||
// vea el dato real (en mayúsculas) al editar.
|
||
add_filter('the_title', function($title, $post_id = 0) {
|
||
if (is_admin() || !function_exists('fea_title')) return $title;
|
||
// Artículo individual: solo el título del propio post mostrado (no widgets/relacionados).
|
||
if (is_singular()) {
|
||
if (in_the_loop() || (int) $post_id === (int) get_queried_object_id()) {
|
||
return fea_title($title);
|
||
}
|
||
return $title;
|
||
}
|
||
// Listados (incluida portada) dentro del loop.
|
||
if ((is_archive() || is_search() || is_home() || is_front_page()) && in_the_loop()) {
|
||
return fea_title($title);
|
||
}
|
||
return $title;
|
||
}, 20, 2);
|
||
|
||
// <title> del documento — núcleo WP (cuando Yoast no lo sobrescribe).
|
||
add_filter('document_title_parts', function($parts) {
|
||
if (is_admin() || !function_exists('fea_title')) return $parts;
|
||
if (!empty($parts['title'])) $parts['title'] = fea_title($parts['title']);
|
||
return $parts;
|
||
}, 20);
|
||
|
||
// <title>/OG/Twitter vía Yoast: normaliza solo la porción del título del post.
|
||
$fea_seo_title = function($title) {
|
||
if (is_admin() || !is_singular() || !function_exists('fea_title')) return $title;
|
||
$raw = get_post_field('post_title', get_queried_object_id());
|
||
if ($raw && mb_strpos($title, $raw) !== false) {
|
||
$title = str_replace($raw, fea_title($raw), $title);
|
||
}
|
||
return $title;
|
||
};
|
||
add_filter('wpseo_title', $fea_seo_title, 20);
|
||
add_filter('wpseo_opengraph_title', $fea_seo_title, 20);
|
||
add_filter('wpseo_twitter_title', $fea_seo_title, 20);
|
||
|
||
// Título del item en feeds RSS.
|
||
add_filter('the_title_rss', function($title) {
|
||
return function_exists('fea_title') ? fea_title($title) : $title;
|
||
}, 20);
|
||
|
||
// Asegura que option_page_on_front devuelve la página traducida al idioma actual
|
||
// (necesario para is_front_page() y para que el template FSE lo reconozca)
|
||
add_filter('option_page_on_front', function($value) {
|
||
if (!function_exists('pll_current_language') || !function_exists('pll_get_post')) return $value;
|
||
static $running = false;
|
||
if ($running) return $value; // evitar recursión
|
||
$running = true;
|
||
$lang = pll_current_language();
|
||
$running = false;
|
||
if (!$lang || $lang === 'es') return $value;
|
||
$translated = pll_get_post((int) $value, $lang);
|
||
return $translated ?: $value;
|
||
});
|
||
|
||
// ── Traducir links de categoría "Esta semana" / "Semana pasada" al idioma actual ─
|
||
// Las categorías traducidas EN/FR/IT/PT dan 404 (bug WP_Tax_Query AND 0=1 con Polylang).
|
||
// Solución: redirigir ES cat URL → post traducido directamente (no a la categoría).
|
||
// Para "Otras semanas" (cartas-de-otras-semanas, count=729): se deja como está.
|
||
add_action('wp_footer', function() {
|
||
if (!function_exists('pll_current_language') || !function_exists('pll_get_post')) return;
|
||
$lang = pll_current_language();
|
||
if (!$lang || $lang === 'es') return;
|
||
|
||
global $wpdb;
|
||
$map = [];
|
||
|
||
// Categorías de carta única (count=1) → redirigir al post traducido
|
||
$single_carta_cats = [
|
||
'cartasemana' => 6,
|
||
'carta-semana-pasada' => 22,
|
||
];
|
||
foreach ($single_carta_cats as $slug => $es_cat_id) {
|
||
// term_taxonomy_id de la categoría ES (bypassa Polylang)
|
||
$tt_id = (int) $wpdb->get_var($wpdb->prepare(
|
||
"SELECT term_taxonomy_id FROM {$wpdb->term_taxonomy}
|
||
WHERE term_id=%d AND taxonomy='category'", $es_cat_id
|
||
));
|
||
if (!$tt_id) continue;
|
||
// Post ES más reciente en esa categoría
|
||
$es_post_id = (int) $wpdb->get_var($wpdb->prepare(
|
||
"SELECT p.ID FROM {$wpdb->posts} p
|
||
JOIN {$wpdb->term_relationships} tr ON p.ID=tr.object_id
|
||
WHERE tr.term_taxonomy_id=%d AND p.post_status='publish'
|
||
ORDER BY p.post_date DESC LIMIT 1", $tt_id
|
||
));
|
||
if (!$es_post_id) continue;
|
||
// Post traducido
|
||
$trans_id = pll_get_post($es_post_id, $lang);
|
||
if (!$trans_id) continue;
|
||
$trans_url = get_permalink($trans_id);
|
||
if ($trans_url) {
|
||
$map[home_url('/category/' . $slug . '/')] = $trans_url;
|
||
}
|
||
}
|
||
if (empty($map)) return;
|
||
?>
|
||
<script>
|
||
(function(){
|
||
var map = <?php echo json_encode($map); ?>;
|
||
document.querySelectorAll('a[href]').forEach(function(a){
|
||
var clean = a.href.split('?')[0];
|
||
if (map[clean]) a.href = map[clean];
|
||
});
|
||
})();
|
||
</script>
|
||
<?php
|
||
}, 25);
|
||
|
||
// ── Foto de perfil de autor via ACF (campo en perfil de usuario) ──────────
|
||
add_action('acf/init', function() {
|
||
if (!function_exists('acf_add_local_field_group')) return;
|
||
acf_add_local_field_group([
|
||
'key' => 'group_user_foto_perfil',
|
||
'title' => 'Foto de perfil',
|
||
'fields' => [[
|
||
'key' => 'field_user_foto_perfil',
|
||
'label' => 'Foto',
|
||
'name' => 'foto_perfil',
|
||
'type' => 'image',
|
||
'instructions' => 'Sube una foto cuadrada del autor (mínimo 100×100px).',
|
||
'return_format' => 'url',
|
||
'preview_size' => 'thumbnail',
|
||
'upload_folder' => 'autores',
|
||
]],
|
||
'location' => [[
|
||
['param' => 'user_form', 'operator' => '==', 'value' => 'all'],
|
||
]],
|
||
]);
|
||
});
|
||
|
||
// Usar la foto del autor en lugar del Gravatar cuando existe
|
||
// Lee el attachment ID guardado en el meta 'foto_perfil' (campo ACF)
|
||
add_filter('get_avatar_url', function($url, $id_or_email, $args) {
|
||
$user_id = null;
|
||
if (is_numeric($id_or_email)) $user_id = (int) $id_or_email;
|
||
elseif ($id_or_email instanceof WP_User) $user_id = $id_or_email->ID;
|
||
elseif (is_string($id_or_email)) {
|
||
$user = get_user_by('email', $id_or_email);
|
||
if ($user) $user_id = $user->ID;
|
||
}
|
||
if (!$user_id) return $url;
|
||
$attach_id = get_user_meta($user_id, 'foto_perfil', true);
|
||
if ($attach_id) {
|
||
$foto = wp_get_attachment_image_url((int) $attach_id, 'full');
|
||
if ($foto) return $foto;
|
||
}
|
||
return $url;
|
||
}, 10, 3);
|
||
|
||
// ── Ordenar por fecha los resultados del buscador ACF en campos de portada ─
|
||
add_filter('acf/fields/relationship/query/key=field_portada_articulos', function($args) {
|
||
$args['orderby'] = 'date';
|
||
$args['order'] = 'DESC';
|
||
return $args;
|
||
});
|
||
add_filter('acf/fields/relationship/query/key=field_portada_multimedia', function($args) {
|
||
$args['orderby'] = 'date';
|
||
$args['order'] = 'DESC';
|
||
return $args;
|
||
});
|
||
|
||
// ── Campos ACF para la portada ────────────────────────────────────────────
|
||
add_action('acf/init', function() {
|
||
if (!function_exists('acf_add_local_field_group')) return;
|
||
|
||
$front_page_id = (int) get_option('page_on_front');
|
||
|
||
acf_add_local_field_group([
|
||
'key' => 'group_portada_fea',
|
||
'title' => 'Contenido de la portada',
|
||
'fields' => [
|
||
[
|
||
'key' => 'field_portada_articulos',
|
||
'label' => 'Artículos seleccionados',
|
||
'name' => 'portada_articulos',
|
||
'type' => 'relationship',
|
||
'instructions' => 'Elige los artículos que aparecerán en la portada esta semana (máx. 9). Puedes buscar por título.',
|
||
'post_type' => ['post'],
|
||
'post_status' => ['publish', 'draft'],
|
||
'filters' => ['search', 'taxonomy'],
|
||
'elements' => ['featured_image'],
|
||
'min' => 0,
|
||
'max' => 9,
|
||
'return_format' => 'object',
|
||
'query_args' => ['orderby' => 'date', 'order' => 'DESC'],
|
||
],
|
||
[
|
||
'key' => 'field_portada_multimedia',
|
||
'label' => 'Multimedia seleccionado',
|
||
'name' => 'portada_multimedia',
|
||
'type' => 'relationship',
|
||
'instructions' => 'Elige los vídeos o audios para la portada (máx. 4).',
|
||
'post_type' => ['post'],
|
||
'post_status' => ['publish', 'draft'],
|
||
'filters' => ['search'],
|
||
'elements' => ['featured_image'],
|
||
'min' => 0,
|
||
'max' => 4,
|
||
'return_format' => 'object',
|
||
'query_args' => ['orderby' => 'date', 'order' => 'DESC'],
|
||
],
|
||
],
|
||
'location' => [[
|
||
['param' => 'page', 'operator' => '==', 'value' => (string) $front_page_id],
|
||
]],
|
||
'position' => 'normal',
|
||
'style' => 'default',
|
||
'label_placement' => 'top',
|
||
]);
|
||
});
|
||
|
||
// ── Selector de idioma (dropdown con bandera + 2 letras) ─────────────────
|
||
add_action('wp_head', function() {
|
||
if (!function_exists('pll_the_languages')) return;
|
||
?>
|
||
<style>
|
||
#fea-lang-switcher {
|
||
position: relative;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
font-family: inherit;
|
||
z-index: 9999;
|
||
}
|
||
#fea-lang-btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 5px;
|
||
background: none;
|
||
border: 1px solid rgba(0,0,0,0.25);
|
||
border-radius: 5px;
|
||
padding: 4px 9px;
|
||
cursor: pointer;
|
||
font-size: 0.82rem;
|
||
font-weight: 700;
|
||
color: inherit;
|
||
line-height: 1.4;
|
||
white-space: nowrap;
|
||
}
|
||
#fea-lang-btn:hover { background: rgba(0,0,0,0.06); }
|
||
#fea-lang-btn .arrow { font-size: 0.6rem; opacity: 0.6; }
|
||
#fea-lang-dropdown {
|
||
display: none;
|
||
position: absolute;
|
||
top: calc(100% + 4px);
|
||
right: 0;
|
||
background: #fff;
|
||
border: 1px solid #ddd;
|
||
border-radius: 7px;
|
||
box-shadow: 0 6px 16px rgba(0,0,0,0.13);
|
||
min-width: 90px;
|
||
padding: 4px 0;
|
||
list-style: none;
|
||
margin: 0;
|
||
}
|
||
#fea-lang-switcher.open #fea-lang-dropdown { display: block; }
|
||
#fea-lang-dropdown li { margin: 0; padding: 0; }
|
||
#fea-lang-dropdown a {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 7px;
|
||
padding: 7px 14px;
|
||
font-size: 0.82rem;
|
||
font-weight: 600;
|
||
text-decoration: none;
|
||
color: #222;
|
||
white-space: nowrap;
|
||
}
|
||
#fea-lang-dropdown a:hover { background: #f5f5f5; }
|
||
#fea-lang-dropdown a[aria-current] { font-weight: 700; color: #000; background: #efefef; }
|
||
#fea-lang-dropdown a.fea-lang-untrans { opacity: 0.45; }
|
||
#fea-lang-dropdown a.fea-lang-untrans::after { content: "·"; margin-left: 4px; opacity: 0.7; }
|
||
</style>
|
||
<?php
|
||
});
|
||
|
||
add_action('wp_footer', function() {
|
||
if (!function_exists('pll_the_languages')) return;
|
||
|
||
$flags = ['es' => '🇪🇸', 'en' => '🇬🇧', 'fr' => '🇫🇷', 'it' => '🇮🇹', 'pt' => '🇵🇹'];
|
||
|
||
$langs = pll_the_languages(['raw' => 1, 'hide_if_no_translation' => 0]);
|
||
if (!$langs) return;
|
||
|
||
$current = array_filter($langs, fn($l) => $l['current_lang']);
|
||
$current = $current ? array_values($current)[0] : null;
|
||
$cur_slug = $current ? $current['slug'] : 'es';
|
||
$cur_flag = $flags[$cur_slug] ?? '🌐';
|
||
$cur_code = strtoupper($cur_slug);
|
||
|
||
$items = '';
|
||
foreach ($langs as $l) {
|
||
$flag = $flags[$l['slug']] ?? '🌐';
|
||
$code = strtoupper($l['slug']);
|
||
$cur = $l['current_lang'] ? ' aria-current="true"' : '';
|
||
// Marcar los idiomas SIN traducción de esta página (Polylang enlaza al inicio del
|
||
// idioma): se atenúan y avisan, para no hacer creer que traducen el contenido actual.
|
||
$notr = !empty($l['no_translation']) && empty($l['current_lang']);
|
||
$cls = $notr ? ' class="fea-lang-untrans"' : '';
|
||
$ttl = $notr ? ' title="Esta página no está traducida — irás al inicio en ' . esc_attr($code) . '"' : '';
|
||
$items .= '<li><a href="' . esc_url($l['url']) . '"' . $cur . $cls . $ttl . '>' . $flag . ' ' . $code . '</a></li>';
|
||
}
|
||
?>
|
||
<div id="fea-lang-switcher" role="navigation" aria-label="Idioma / Language">
|
||
<button id="fea-lang-btn" aria-haspopup="listbox" aria-expanded="false"
|
||
onclick="var s=this.closest('#fea-lang-switcher'),o=s.classList.toggle('open');this.setAttribute('aria-expanded',o)">
|
||
<?= $cur_flag ?> <?= $cur_code ?> <span class="arrow">▼</span>
|
||
</button>
|
||
<ul id="fea-lang-dropdown" role="listbox"><?= $items ?></ul>
|
||
</div>
|
||
<script>
|
||
(function() {
|
||
var sw = document.getElementById('fea-lang-switcher');
|
||
if (!sw) return;
|
||
// Cerrar al clicar fuera
|
||
document.addEventListener('click', function(e) {
|
||
if (!sw.contains(e.target)) {
|
||
sw.classList.remove('open');
|
||
document.getElementById('fea-lang-btn').setAttribute('aria-expanded', 'false');
|
||
}
|
||
});
|
||
// Inyectar en el nav principal del header
|
||
function inject() {
|
||
// Buscar la barra de navegación principal (primer nivel dentro del header)
|
||
var header = document.querySelector('header.wp-block-template-part');
|
||
if (!header) header = document.querySelector('header');
|
||
if (!header) return;
|
||
// Buscar el div/group que contiene el menú de navegación
|
||
var navGroup = header.querySelector('.wp-block-navigation__container');
|
||
if (!navGroup) navGroup = header.querySelector('nav');
|
||
if (!navGroup) {
|
||
// Fallback: poner en el header con posición absoluta
|
||
header.style.position = 'relative';
|
||
sw.style.cssText = 'position:absolute;top:50%;right:1.5rem;transform:translateY(-50%);';
|
||
header.appendChild(sw);
|
||
return;
|
||
}
|
||
// Crear li wrapper para el nav
|
||
var li = document.createElement('li');
|
||
li.className = 'wp-block-navigation-item';
|
||
li.style.cssText = 'display:flex;align-items:center;margin-left:0.5rem;';
|
||
li.appendChild(sw);
|
||
// Insertar DESPUÉS del buscador (si existe)
|
||
var searchItem = navGroup.querySelector('.wp-block-search');
|
||
if (searchItem) {
|
||
// Subir hasta el li/div hermano directo del navGroup
|
||
var anchor = searchItem;
|
||
while (anchor.parentNode && anchor.parentNode !== navGroup) {
|
||
anchor = anchor.parentNode;
|
||
}
|
||
anchor.parentNode.insertBefore(li, anchor.nextSibling);
|
||
} else {
|
||
navGroup.appendChild(li);
|
||
}
|
||
}
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('DOMContentLoaded', inject);
|
||
} else {
|
||
inject();
|
||
}
|
||
})();
|
||
</script>
|
||
<?php
|
||
}, 20);
|
||
|
||
// ── Centrar bloque slider+librería (header template, todas las páginas) ───
|
||
add_action('wp_head', function() {
|
||
?>
|
||
<style>
|
||
/* El bloque de columnas con el slider usa márgenes negativos del FSE
|
||
que lo desplazan. Lo forzamos a centrar con max-width explícito. */
|
||
.wp-block-columns:has(.wp-block-nextend-smartslider3) {
|
||
max-width: min(var(--wp--style--global--wide-size, 1340px), 100%);
|
||
margin-left: auto !important;
|
||
margin-right: auto !important;
|
||
box-sizing: border-box;
|
||
padding-left: var(--wp--preset--spacing--30);
|
||
padding-right: var(--wp--preset--spacing--30);
|
||
}
|
||
|
||
/* Ocultar columna librería en tablet */
|
||
@media (max-width: 900px) {
|
||
.fea-slider-block .wp-block-column:last-child {
|
||
display: none !important;
|
||
}
|
||
}
|
||
|
||
/* Ocultar slider en móvil (banner superior sigue visible) */
|
||
@media (max-width: 600px) {
|
||
.fea-slider-block {
|
||
display: none !important;
|
||
}
|
||
}
|
||
|
||
/* Buscador del header: reducir altura */
|
||
.wp-block-search__input {
|
||
padding-top: 0.25rem !important;
|
||
padding-bottom: 0.25rem !important;
|
||
line-height: 1.3 !important;
|
||
}
|
||
.wp-block-search__button {
|
||
padding-top: 0.25rem !important;
|
||
padding-bottom: 0.25rem !important;
|
||
}
|
||
</style>
|
||
<?php
|
||
});
|
||
|
||
// ── Estilos ───────────────────────────────────────────────────────────────
|
||
add_action('wp_head', function() {
|
||
if (!fea_is_front_page()) return;
|
||
?>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,600;9..144,700&display=swap" rel="stylesheet">
|
||
<style>
|
||
/* ── Hero: Carta (izq) + Carrusel (der) en banda beige full-width ── */
|
||
.fea-hero-band { max-width: none !important; width: 100vw; margin-left: calc(50% - 50vw) !important; margin-right: calc(50% - 50vw) !important; background: linear-gradient(180deg, #efe9e1, #f4f0ea); border-bottom: 1px solid #e4ddd1; margin-bottom: 3rem; }
|
||
.fea-hero-inner { max-width: 1180px; margin: 0 auto; padding: 2.75rem 28px; display: grid; grid-template-columns: minmax(260px, 400px) minmax(0, 1fr); gap: 2.5rem; align-items: center; }
|
||
.fea-hero-text { min-width: 0; }
|
||
.fea-hero-link { display: block; text-decoration: none; color: inherit; }
|
||
.fea-hero-link:hover .fea-hero-title { text-decoration: underline; text-underline-offset: 4px; }
|
||
.fea-section-label { display: inline-block; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: #8b1a2e; margin-bottom: 0.7rem; }
|
||
.fea-hero-title { font-family: 'Fraunces', Georgia, serif; font-size: clamp(2rem, 3.4vw, 3rem); font-weight: 600; line-height: 1.08; letter-spacing: -0.01em; margin: 0 0 1rem; color: #2a2320; }
|
||
.fea-hero-meta { display: flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; color: #6f655c; }
|
||
.fea-hero-cta { display: inline-block; margin-top: 1.25rem; background: #8b1a2e; color: #fff; font-weight: 600; font-size: 0.92rem; padding: 0.7rem 1.4rem; border-radius: 8px; }
|
||
.fea-hero-slider { min-width: 0; overflow: hidden; }
|
||
.fea-hero-slider .n2-ss-align { max-width: 100% !important; width: 100% !important; }
|
||
@media (max-width: 860px) { .fea-hero-inner { grid-template-columns: 1fr; gap: 1.75rem; } }
|
||
|
||
/* Ancho de las secciones de portada: contenedor centrado (aire a los lados) */
|
||
body.home .fea-section, .fea-front .fea-section { max-width: 1180px !important; margin-left: auto !important; margin-right: auto !important; }
|
||
|
||
/* ── Secciones — dirección "Cálido editorial" (Mockup A, #57) ── */
|
||
.fea-section { margin-bottom: 3.75rem; padding-top: 0.5rem; }
|
||
.fea-section-title { display: flex; align-items: center; gap: 1rem; font-family: 'Fraunces', Georgia, serif; font-size: 1.65rem; font-weight: 600; letter-spacing: -0.01em; text-transform: none; color: #2a2320; margin: 0 0 1.6rem; padding: 0; border: 0; }
|
||
.fea-section-title::after { content: ''; display: inline-block; flex: 0 0 46px; height: 3px; background: #8b1a2e; border-radius: 2px; }
|
||
.fea-section-head { display: flex; align-items: center; gap: 1rem; margin-bottom: 1.6rem; }
|
||
.fea-section-head .fea-section-title { flex: 1 1 auto; min-width: 0; margin-bottom: 0; }
|
||
.fea-section-more { flex: 0 0 auto; color: #8b1a2e; font-size: 0.86rem; font-weight: 700; text-decoration: none; white-space: nowrap; }
|
||
.fea-section-more:hover { text-decoration: underline; text-underline-offset: 3px; }
|
||
@media (max-width: 480px) {
|
||
.fea-section-head { gap: 0.65rem; }
|
||
.fea-section-head .fea-section-title { font-size: 1.45rem; gap: 0.65rem; }
|
||
.fea-section-head .fea-section-title::after { flex-basis: 28px; }
|
||
.fea-section-more { font-size: 0.8rem; }
|
||
}
|
||
|
||
.fea-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.6rem; }
|
||
@media (max-width: 980px) { .fea-grid { grid-template-columns: repeat(3, 1fr); } }
|
||
@media (max-width: 680px) { .fea-grid { grid-template-columns: 1fr 1fr; } }
|
||
@media (max-width: 420px) { .fea-grid { grid-template-columns: 1fr; } }
|
||
|
||
.fea-card { background: #fff; border: 1px solid #efe7d8; border-radius: 14px; padding: 1.5rem 1rem; text-align: center; transition: transform .18s ease, box-shadow .18s ease; }
|
||
.fea-card:hover { transform: translateY(-5px); box-shadow: 0 18px 36px -20px rgba(42,35,32,.45); }
|
||
/* Ocultar visualmente el texto de accesibilidad del Smart Slider (nombres de fichero con guiones bajos) */
|
||
.n2-ss-slide--focus { position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important; overflow: hidden !important; clip: rect(0,0,0,0) !important; white-space: nowrap !important; border: 0 !important; }
|
||
.fea-card-avatar-link { display: block; }
|
||
.fea-card-avatar { box-shadow: 0 0 0 3px #f7ecd9, 0 0 0 4px #e7d7bb; transition: transform .2s ease; }
|
||
.fea-card:hover .fea-card-avatar { transform: scale(1.05); }
|
||
.fea-card-author { color: #8b1a2e; font-weight: 600; font-size: 0.9rem; margin: 0.95rem 0 0.5rem; line-height: 1.25; }
|
||
.fea-card-title { font-size: 0.98rem; font-weight: 600; line-height: 1.32; margin: 0; }
|
||
.fea-card-title a { text-decoration: none; color: #2a2320; }
|
||
.fea-card-title a:hover { text-decoration: underline; text-underline-offset: 3px; }
|
||
|
||
/* ── Footer portada: contener anchos, aire a los lados (no entre medias) ── */
|
||
/* Reduce el espaciado preset 80 (enorme) solo dentro del footer, sin tocar listas */
|
||
.fea-footer-portada { max-width: 1180px; margin-left: auto; margin-right: auto; --wp--preset--spacing--80: 3rem; }
|
||
/* Las 3 imágenes (Librería / Noticias / Portal-EFFA): columnas iguales, aires iguales */
|
||
.fea-footer-portada .wp-block-columns { max-width: 900px; margin-left: auto; margin-right: auto; gap: 2.5rem !important; align-items: start; justify-content: center; }
|
||
.fea-footer-portada .wp-block-columns .wp-block-column { flex: 1 1 0 !important; width: auto !important; min-width: 0; display: flex; flex-direction: column; align-items: center; text-align: center; }
|
||
.fea-footer-portada .wp-block-columns .wp-block-column img { max-width: 100%; width: auto; height: auto; margin-left: auto; margin-right: auto; }
|
||
/* Las columnas de enlaces: centrarlas (aire a los lados, no entre medias) */
|
||
.fea-footer-portada .wp-block-group.is-content-justification-space-between { justify-content: center !important; gap: 3.5rem !important; }
|
||
</style>
|
||
<?php
|
||
});
|
||
|
||
// ── Slider del hero a prueba de fuego: llena la columna y, si es más estrecha
|
||
// que el ancho base del slider (Smart Slider no baja de él), lo escala con transform ──
|
||
add_action('wp_footer', function() {
|
||
if (!fea_is_front_page()) return;
|
||
?>
|
||
<script>
|
||
(function () {
|
||
var els = function () {
|
||
return {
|
||
c: document.querySelector('.fea-hero-slider'),
|
||
s: document.querySelector('.fea-hero-slider .n2-ss-slider')
|
||
};
|
||
};
|
||
var lastW = -1, busy = false, raf = 0;
|
||
function apply() {
|
||
var e = els();
|
||
if (!e.c || !e.s) return;
|
||
// reset para medir el tamaño natural que decide Smart Slider
|
||
e.s.style.transform = '';
|
||
e.s.style.transformOrigin = '';
|
||
e.c.style.height = '';
|
||
// que Smart Slider recalcule (crece hasta llenar la columna si cabe)
|
||
busy = true; window.dispatchEvent(new Event('resize')); busy = false;
|
||
requestAnimationFrame(function () {
|
||
var avail = e.c.clientWidth;
|
||
var rect = e.s.getBoundingClientRect();
|
||
if (rect.width > avail + 1) { // columna más estrecha que el slider → escalar
|
||
var k = avail / rect.width;
|
||
e.s.style.transformOrigin = 'top left';
|
||
e.s.style.transform = 'scale(' + k + ')';
|
||
e.c.style.height = Math.round(rect.height * k) + 'px';
|
||
}
|
||
});
|
||
}
|
||
function schedule() { cancelAnimationFrame(raf); raf = requestAnimationFrame(apply); }
|
||
function onChange(force) {
|
||
if (busy) return;
|
||
var c = els().c; if (!c) return;
|
||
var w = c.clientWidth;
|
||
if (!force && w === lastW) return; // solo reaccionar a cambios de ANCHO (evita bucle por la altura)
|
||
lastW = w; schedule();
|
||
}
|
||
window.addEventListener('load', function () { onChange(true); setTimeout(function(){onChange(true);}, 300); setTimeout(function(){onChange(true);}, 800); });
|
||
window.addEventListener('resize', function () { onChange(false); });
|
||
if ('ResizeObserver' in window) {
|
||
var c = els().c;
|
||
if (c) new ResizeObserver(function () { onChange(false); }).observe(c);
|
||
}
|
||
})();
|
||
</script>
|
||
<?php
|
||
}, 99);
|
||
|
||
// ── Estilos para listados/archivos (categoría, autor, fecha, búsqueda) #63 ──
|
||
add_action('wp_head', function() {
|
||
if (is_admin() || fea_is_front_page()) return;
|
||
if (!(is_archive() || is_search() || is_home())) return;
|
||
?>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,600;9..144,700&display=swap" rel="stylesheet">
|
||
<style>
|
||
/* Título del archivo: serif con barra granate (coherente con la portada) */
|
||
.wp-block-query-title { font-family: 'Fraunces', Georgia, serif !important; font-weight: 600 !important; color: #2a2320 !important; letter-spacing: -0.01em; display: flex; align-items: center; gap: 1rem; }
|
||
.wp-block-query-title::after { content: ''; flex: 0 0 46px; height: 3px; background: #8b1a2e; border-radius: 2px; }
|
||
/* Anchura coherente con la portada */
|
||
.wp-block-query.alignwide { max-width: 1180px !important; margin-left: auto !important; margin-right: auto !important; }
|
||
/* Grid de tarjetas */
|
||
.fea-archive-grid { display: grid !important; grid-template-columns: repeat(3, 1fr) !important; gap: 1.5rem !important; }
|
||
@media (max-width: 900px) { .fea-archive-grid { grid-template-columns: repeat(2, 1fr) !important; } }
|
||
@media (max-width: 560px) { .fea-archive-grid { grid-template-columns: 1fr !important; } }
|
||
.fea-archive-card { background: #fff; border: 1px solid #efe7d8; border-radius: 14px; padding: 1.4rem 1.3rem; height: 100%; display: flex; flex-direction: column; transition: transform .18s ease, box-shadow .18s ease; }
|
||
.fea-archive-card:hover { transform: translateY(-4px); box-shadow: 0 18px 36px -20px rgba(42,35,32,.45); }
|
||
.fea-archive-title { margin: 0 !important; }
|
||
.fea-archive-title a { font-family: 'Fraunces', Georgia, serif; font-weight: 600; color: #2a2320; text-decoration: none; line-height: 1.25; }
|
||
.fea-archive-card:hover .fea-archive-title a { color: #8b1a2e; }
|
||
.fea-archive-date { margin: 0.45rem 0 0 !important; }
|
||
.fea-archive-date a, .fea-archive-date { color: #8b1a2e !important; font-weight: 600; text-decoration: none; }
|
||
.fea-archive-excerpt { margin: 0.6rem 0 0 !important; color: #6f655c; font-size: 0.92rem; line-height: 1.45; }
|
||
.fea-archive-excerpt a { display: none; }
|
||
</style>
|
||
<?php
|
||
});
|
||
|
||
|
||
// ── Ocultar título de página en todas las portadas ────────────────────────
|
||
add_action('wp_head', function() {
|
||
if (!fea_is_front_page()) return;
|
||
echo '<style>.wp-block-post-title { display:none !important; }</style>';
|
||
}, 20);
|
||
|
||
// ── H1 semántico oculto para páginas sin título visible ───────────────────
|
||
add_action('wp_head', function() {
|
||
?>
|
||
<style>
|
||
.fea-sr-only {
|
||
position: absolute !important;
|
||
width: 1px !important;
|
||
height: 1px !important;
|
||
padding: 0 !important;
|
||
margin: -1px !important;
|
||
overflow: hidden !important;
|
||
clip: rect(0, 0, 0, 0) !important;
|
||
clip-path: inset(50%) !important;
|
||
white-space: nowrap !important;
|
||
border: 0 !important;
|
||
}
|
||
</style>
|
||
<?php
|
||
}, 20);
|
||
|
||
add_filter('the_content', function($content) {
|
||
if (is_admin() || !is_main_query() || !in_the_loop()) return $content;
|
||
if (preg_match('/<h1\b/i', $content)) return $content;
|
||
|
||
$title = '';
|
||
if (fea_is_front_page()) {
|
||
$title = get_bloginfo('name') ?: 'Fe Adulta';
|
||
} elseif (fea_is_escuela_page()) {
|
||
$title = 'Escuela de Formación en Fe Adulta';
|
||
}
|
||
|
||
if (!$title) return $content;
|
||
|
||
return '<h1 class="fea-sr-only fea-page-h1">' . esc_html($title) . '</h1>' . $content;
|
||
}, 5);
|
||
|
||
// ── Título <title> para páginas sin post_title propio (Escuela) ───────────
|
||
add_filter('document_title_parts', function($parts) {
|
||
if (fea_is_escuela_page()) {
|
||
$parts['title'] = 'Escuela de Formación en Fe Adulta';
|
||
}
|
||
return $parts;
|
||
});
|
||
|
||
// ── Ocultar metadatos de post en páginas estáticas ────────────────────────
|
||
add_action('wp_head', function() {
|
||
if (!fea_hide_static_meta()) return;
|
||
?>
|
||
<style>
|
||
.wp-block-group:has(> .wp-block-avatar):has(.wp-block-post-author-name),
|
||
.wp-block-post-author-name,
|
||
.wp-block-post-terms.taxonomy-category {
|
||
display: none !important;
|
||
}
|
||
</style>
|
||
<?php
|
||
}, 20);
|
||
|
||
// ── Byline personalizado en artículos individuales ────────────────────────
|
||
|
||
// ── Byline personalizado: se gestiona desde el template FSE (ID 42359) ────
|
||
// El template wp_template 'single' ya contiene wp:avatar + wp:post-author-name
|
||
// + wp:post-terms. Este hook solo añade los estilos necesarios.
|
||
add_action('astra_single_header_bottom', function() {
|
||
if (!is_single()) return;
|
||
|
||
$author_id = (int) get_the_author_meta('ID');
|
||
$author_name = get_the_author_meta('display_name');
|
||
$avatar_url = get_avatar_url($author_id, ['size' => 48]);
|
||
$author_url = get_author_posts_url($author_id);
|
||
|
||
$cat_str = '';
|
||
$cats = get_the_category();
|
||
if ($cats) {
|
||
$cat_url = get_category_link($cats[0]->term_id);
|
||
$cat_str = '<a href="' . esc_url($cat_url) . '" class="fea-byline-cat">'
|
||
. esc_html($cats[0]->name) . '</a>';
|
||
}
|
||
|
||
echo '<div class="fea-byline">'
|
||
. '<a href="' . esc_url($author_url) . '" class="fea-byline-avatar-link">'
|
||
. '<img src="' . esc_url($avatar_url) . '" alt="' . esc_attr($author_name) . '" width="48" height="48" class="fea-byline-avatar">'
|
||
. '</a>'
|
||
. '<div class="fea-byline-info">'
|
||
. '<a href="' . esc_url($author_url) . '" class="fea-byline-name">' . esc_html($author_name) . '</a>'
|
||
. $cat_str
|
||
. '</div>'
|
||
. '</div>';
|
||
});
|
||
|
||
add_action('wp_head', function() {
|
||
if (!is_single()) return;
|
||
?>
|
||
<style>
|
||
.fea-byline { display: flex; align-items: center; gap: 0.75rem; margin-top: 0.75rem; }
|
||
.fea-byline-avatar-link { flex-shrink: 0; }
|
||
.fea-byline-avatar { border-radius: 50%; display: block; }
|
||
.fea-byline-info { display: flex; flex-direction: column; gap: 0.2rem; }
|
||
.fea-byline-name { font-size: 0.9rem; font-weight: 600; color: #222; text-decoration: none; }
|
||
.fea-byline-name:hover { text-decoration: underline; }
|
||
.fea-byline-cat { font-size: 0.78rem; color: #888; text-decoration: none; }
|
||
.fea-byline-cat:hover { text-decoration: underline; color: #555; }
|
||
.wp-block-group:has(> .wp-block-avatar):has(.wp-block-post-author-name) {
|
||
align-items: center;
|
||
gap: 0.7rem;
|
||
}
|
||
.wp-block-group:has(> .wp-block-avatar):has(.wp-block-post-author-name) > .wp-block-avatar {
|
||
flex: 0 0 54px;
|
||
}
|
||
.wp-block-group:has(> .wp-block-avatar):has(.wp-block-post-author-name) > .wp-block-avatar img {
|
||
width: 54px !important;
|
||
height: 54px !important;
|
||
}
|
||
.fea-post-date-inline {
|
||
font-size: 0.74rem;
|
||
line-height: 1.2;
|
||
color: #888;
|
||
margin-top: 0.08rem;
|
||
}
|
||
.fea-post-date-inline time { white-space: nowrap; }
|
||
@media (max-width: 720px) {
|
||
.wp-block-group:has(> .wp-block-avatar):has(.wp-block-post-author-name) > .wp-block-avatar {
|
||
flex-basis: 50px;
|
||
}
|
||
.wp-block-group:has(> .wp-block-avatar):has(.wp-block-post-author-name) > .wp-block-avatar img {
|
||
width: 50px !important;
|
||
height: 50px !important;
|
||
}
|
||
}
|
||
</style>
|
||
<?php
|
||
});
|
||
|
||
add_filter('render_block_core/post-terms', function($block_content, $block) {
|
||
if (!is_single() || get_post_type() !== 'post') return $block_content;
|
||
|
||
$taxonomy = $block['attrs']['term'] ?? '';
|
||
if ($taxonomy !== 'category') return $block_content;
|
||
if (strpos($block_content, 'fea-post-date-inline') !== false) return $block_content;
|
||
|
||
$date_attr = esc_attr(get_the_date('c'));
|
||
$date_text = esc_html(ucfirst(wp_date(get_option('date_format'), get_post_timestamp())));
|
||
if ($date_text === '') return $block_content;
|
||
|
||
return $block_content
|
||
. '<div class="fea-post-date-inline"><time datetime="' . $date_attr . '">' . $date_text . '</time></div>';
|
||
}, 10, 2);
|
||
|
||
// ── Helpers ───────────────────────────────────────────────────────────────
|
||
function fea_title(string $title): string {
|
||
$lower = mb_strtolower($title, 'UTF-8');
|
||
$out = mb_strtoupper(mb_substr($lower, 0, 1, 'UTF-8'), 'UTF-8') . mb_substr($lower, 1, null, 'UTF-8');
|
||
// Capitalizar también la primera letra tras separadores de cláusula (citas bíblicas
|
||
// dobles "Isaías 5,1 / Filipenses 4,6", subtítulos "Título: Subtítulo", ¿…?, ¡…!).
|
||
$out = preg_replace_callback('/([\/:¿¡] *)(\p{Ll})/u', function ($m) {
|
||
return $m[1] . mb_strtoupper($m[2], 'UTF-8');
|
||
}, $out);
|
||
return $out;
|
||
}
|
||
|
||
/** Lista de libros bíblicos (para avatar genérico de lecturas/eucaristías). #61 */
|
||
function fea_libros_biblicos(): array {
|
||
return [
|
||
'Nuevo Testamento','Antiguo Testamento',
|
||
'Génesis','Éxodo','Levítico','Números','Deuteronomio','Josué','Jueces','Rut',
|
||
'Samuel','Reyes','Crónicas','Esdras','Nehemías','Tobías','Judit','Ester','Macabeos',
|
||
'Job','Salmos','Salmo','Proverbios','Eclesiastés','Cantar','Sabiduría','Eclesiástico','Sirácide',
|
||
'Isaías','Jeremías','Lamentaciones','Baruc','Ezequiel','Daniel',
|
||
'Oseas','Joel','Amós','Abdías','Jonás','Miqueas','Nahúm','Habacuc','Sofonías','Ageo','Zacarías','Malaquías',
|
||
'Hechos','Romanos','Corintios','Gálatas','Efesios','Filipenses','Colosenses','Tesalonicenses',
|
||
'Timoteo','Tito','Filemón','Hebreos','Santiago','Pedro','Judas','Apocalipsis',
|
||
];
|
||
}
|
||
|
||
/** Devuelve la abreviatura del evangelista si el texto es una cita de evangelio, o ''. #61 */
|
||
function fea_evangelista_de_texto(string $txt): string {
|
||
if (preg_match('/^\s*(Mateo|Mt|Marcos|Mc|Lucas|Lc|Juan|Jn)\b\.?\s*\d/iu', $txt, $m)) {
|
||
$k = mb_strtolower($m[1], 'UTF-8');
|
||
$map = ['mateo'=>'mateo-angel','mt'=>'mateo-angel','marcos'=>'marcos-leon','mc'=>'marcos-leon',
|
||
'lucas'=>'lucas-toro','lc'=>'lucas-toro','juan'=>'juan-aguila','jn'=>'juan-aguila'];
|
||
return $map[$k] ?? '';
|
||
}
|
||
return '';
|
||
}
|
||
|
||
/** Devuelve 'antiguo-testamento' / 'nuevo-testamento' si el texto es esa firma, o ''. #66 */
|
||
function fea_testamento_de_texto(string $txt): string {
|
||
$t = mb_strtolower(trim($txt), 'UTF-8');
|
||
if ($t === 'antiguo testamento') return 'antiguo-testamento';
|
||
if ($t === 'nuevo testamento') return 'nuevo-testamento';
|
||
return '';
|
||
}
|
||
|
||
/** True si el texto empieza por un libro bíblico (cita) o es el nombre de un libro. #61 */
|
||
function fea_es_libro_biblico(string $txt): bool {
|
||
$txt = trim($txt);
|
||
foreach (fea_libros_biblicos() as $libro) {
|
||
if (mb_strtolower($txt, 'UTF-8') === mb_strtolower($libro, 'UTF-8')) return true;
|
||
if (preg_match('/^' . preg_quote($libro, '/') . '\b/iu', $txt)) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* URL del avatar para un post de portada/listado. #61
|
||
* - Citas de evangelio (Mt/Mc/Lc/Jn + número) → símbolo del evangelista.
|
||
* - Lecturas/eucaristías firmadas por un libro bíblico → Biblia.
|
||
* - Resto → avatar real del autor.
|
||
*/
|
||
function fea_avatar_url(object $post, int $size, int $author_id, string $author_name): string {
|
||
$base = content_url('uploads/avatares/evangelistas/');
|
||
// Solo la LECTURA en sí (cuyo título es la cita, p.ej. "Mateo 9, 36") lleva símbolo de
|
||
// evangelista; los comentaristas humanos conservan su avatar aunque comenten ese evangelio.
|
||
$title = (string) $post->post_title;
|
||
// Las traducciones tienen el título en su idioma (Matteo, Geremia, Romani…) que no
|
||
// reconocemos. Usamos el título del ORIGINAL ES, donde sí detectamos el libro → la
|
||
// traducción hereda el mismo símbolo que el ES (#135).
|
||
if (function_exists('pll_get_post_language') && pll_get_post_language($post->ID) !== 'es') {
|
||
$es = function_exists('pll_get_post') ? pll_get_post($post->ID, 'es') : 0;
|
||
if ($es) {
|
||
$esp = get_post($es);
|
||
if ($esp) $title = (string) $esp->post_title;
|
||
}
|
||
}
|
||
if ($ev = fea_evangelista_de_texto($title)) return $base . $ev . '.svg';
|
||
// "Antiguo Testamento" / "Nuevo Testamento" llevan símbolo propio (no el genérico). #66
|
||
if ($t = fea_testamento_de_texto($title) ?: fea_testamento_de_texto($author_name)) return $base . $t . '.svg';
|
||
if (fea_es_libro_biblico($title) || fea_es_libro_biblico($author_name)) return $base . 'biblia.svg';
|
||
return get_avatar_url($author_id, ['size' => $size, 'default' => 'identicon']);
|
||
}
|
||
|
||
function fea_card(object $post): string {
|
||
$author_id = $post->post_author;
|
||
$author_name = get_the_author_meta('display_name', $author_id);
|
||
$avatar_url = fea_avatar_url($post, 96, (int) $author_id, (string) $author_name);
|
||
$url = get_permalink($post->ID);
|
||
$title = fea_title($post->post_title);
|
||
return '<article class="fea-card">'
|
||
. '<a href="' . esc_url($url) . '" class="fea-card-avatar-link" aria-label="' . esc_attr($author_name) . '">'
|
||
. '<span class="fea-card-avatar" style="display:block;width:84px;height:84px;border-radius:50%;overflow:hidden;margin:0 auto;">'
|
||
. '<img src="' . esc_url($avatar_url) . '" alt="' . esc_attr($author_name) . '" width="84" height="84" class="fea-avatar" style="width:100%;height:100%;object-fit:cover;display:block;" loading="lazy">'
|
||
. '</span>'
|
||
. '</a>'
|
||
. '<div class="fea-card-author">' . esc_html($author_name) . '</div>'
|
||
. '<h3 class="fea-card-title"><a href="' . esc_url($url) . '">' . esc_html($title) . '</a></h3>'
|
||
. '</article>';
|
||
}
|
||
|
||
/** IDs de las páginas de portada en todos los idiomas. */
|
||
function fea_front_page_ids(): array {
|
||
return [26542, 42756, 42757, 42758, 43889]; // ES=26542, PT=42756, IT=42757, FR=42758, EN=43889 (FR/PT corregidos #75)
|
||
}
|
||
|
||
/** True si la página actual es alguna de las portadas (multilingüe). */
|
||
function fea_is_front_page(): bool {
|
||
if (is_front_page()) return true;
|
||
$id = get_queried_object_id();
|
||
return $id && in_array($id, fea_front_page_ids(), true);
|
||
}
|
||
|
||
/** True para la landing de Escuela, que no muestra título visible. */
|
||
function fea_is_escuela_page(): bool {
|
||
if (!is_page()) return false;
|
||
$page = get_queried_object();
|
||
return $page instanceof WP_Post && $page->post_name === 'escuela';
|
||
}
|
||
|
||
/** True para contenidos importados que funcionan como páginas institucionales. */
|
||
function fea_hide_static_meta(): bool {
|
||
if (is_admin() || fea_is_front_page()) return false;
|
||
|
||
$post = get_queried_object();
|
||
if (!$post instanceof WP_Post) return false;
|
||
|
||
if ($post->post_type === 'page') return true;
|
||
|
||
$slugs = [
|
||
'colaboradores',
|
||
'contactar',
|
||
'multimedia',
|
||
'ayuda',
|
||
'video-tutorial',
|
||
'como-usar-el-buscador-avanzado',
|
||
'portal',
|
||
'paraponeraldialafe',
|
||
'alta',
|
||
'alta-en-effa',
|
||
'regala',
|
||
'catalogo-de-publicaciones-2018',
|
||
'nueva-politica-de-privacidad',
|
||
];
|
||
|
||
return in_array($post->post_name, $slugs, true);
|
||
}
|
||
|
||
/** Devuelve el idioma actual de Polylang, o 'es' si no está activo. */
|
||
function fea_current_lang(): string {
|
||
return (function_exists('pll_current_language') ? pll_current_language() : null) ?: 'es';
|
||
}
|
||
|
||
/** Etiquetas de sección traducidas por idioma. */
|
||
function fea_labels(): array {
|
||
$all = [
|
||
'es' => [
|
||
'carta' => 'Carta de la semana',
|
||
'evangelio' => 'Comentarios al evangelio',
|
||
'articulos' => 'Artículos de esta semana',
|
||
'eucaristia' => 'Para una eucaristía más participativa',
|
||
'multimedia' => 'Multimedia',
|
||
],
|
||
'en' => [
|
||
'carta' => 'Letter of the week',
|
||
'evangelio' => 'Gospel commentary',
|
||
'articulos' => 'Articles of the week',
|
||
'eucaristia' => 'For a more participatory Eucharist',
|
||
'multimedia' => 'Multimedia',
|
||
],
|
||
'fr' => [
|
||
'carta' => 'Lettre de la semaine',
|
||
'evangelio' => 'Commentaires de l\'évangile',
|
||
'articulos' => 'Articles de la semaine',
|
||
'eucaristia' => 'Pour une eucharistie plus participative',
|
||
'multimedia' => 'Multimédia',
|
||
],
|
||
'it' => [
|
||
'carta' => 'Lettera della settimana',
|
||
'evangelio' => 'Commenti al vangelo',
|
||
'articulos' => 'Articoli della settimana',
|
||
'eucaristia' => 'Per una eucaristia più partecipativa',
|
||
'multimedia' => 'Multimedia',
|
||
],
|
||
'pt' => [
|
||
'carta' => 'Carta da semana',
|
||
'evangelio' => 'Comentários ao evangelho',
|
||
'articulos' => 'Artigos da semana',
|
||
'eucaristia' => 'Para uma eucaristia mais participativa',
|
||
'multimedia' => 'Multimédia',
|
||
],
|
||
];
|
||
return $all[fea_current_lang()] ?? $all['es'];
|
||
}
|
||
|
||
/**
|
||
* ID de la página de portada para el idioma actual.
|
||
*/
|
||
function fea_front_page_id(): int {
|
||
$es_front = 26542;
|
||
$lang = fea_current_lang();
|
||
if ($lang === 'es') return $es_front;
|
||
if (function_exists('pll_get_post')) {
|
||
$translated = pll_get_post($es_front, $lang);
|
||
if ($translated) return (int) $translated;
|
||
}
|
||
return $es_front;
|
||
}
|
||
|
||
/**
|
||
* Traduce un term_id de categoría ES al idioma actual.
|
||
* Si no hay traducción disponible, devuelve el ID original.
|
||
*/
|
||
function fea_cat(int $es_cat_id): int {
|
||
$lang = fea_current_lang();
|
||
if ($lang === 'es') return $es_cat_id;
|
||
if (function_exists('pll_get_term')) {
|
||
$translated = pll_get_term($es_cat_id, $lang);
|
||
if ($translated) return (int) $translated;
|
||
}
|
||
return $es_cat_id;
|
||
}
|
||
|
||
// ── Enlace "Evangelio del día · fecha" ────────────────────────────────────
|
||
// Píldora discreta, estilo "fecha con contenido", a la página del Evangelio de
|
||
// cada día. Se inserta dentro del hero de la carta (portada). Multiidioma.
|
||
function fea_eed_link_html() {
|
||
$tz = new DateTimeZone('Europe/Madrid');
|
||
$now = new DateTimeImmutable('now', $tz);
|
||
$d = (int) $now->format('j');
|
||
$m = (int) $now->format('n');
|
||
$lang = function_exists('fea_current_lang') ? fea_current_lang() : 'es';
|
||
|
||
$LBL = ['es'=>'Evangelio del día','en'=>'Gospel of the day','fr'=>'Évangile du jour','it'=>'Vangelo del giorno','pt'=>'Evangelho do dia'];
|
||
$MES = [
|
||
'es'=>[1=>'enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre'],
|
||
'en'=>[1=>'January','February','March','April','May','June','July','August','September','October','November','December'],
|
||
'fr'=>[1=>'janvier','février','mars','avril','mai','juin','juillet','août','septembre','octobre','novembre','décembre'],
|
||
'it'=>[1=>'gennaio','febbraio','marzo','aprile','maggio','giugno','luglio','agosto','settembre','ottobre','novembre','dicembre'],
|
||
'pt'=>[1=>'janeiro','fevereiro','março','abril','maio','junho','julho','agosto','setembro','outubro','novembro','dezembro'],
|
||
];
|
||
$L = isset($MES[$lang]) ? $lang : 'es';
|
||
$mes = $MES[$L][$m];
|
||
if ($L === 'es' || $L === 'pt') $fecha = $d . ' de ' . $mes;
|
||
elseif ($L === 'en') $fecha = $mes . ' ' . $d;
|
||
else $fecha = $d . ' ' . $mes; // fr, it
|
||
|
||
// get_posts usa suppress_filters=true → Polylang no filtra y siempre
|
||
// devuelve la página ES. Resolvemos la traducción del idioma actual.
|
||
$pg = get_posts(['name'=>'evangelio-de-cada-dia','post_type'=>'post','post_status'=>'publish','numberposts'=>1]);
|
||
$pid = $pg ? (int) $pg[0]->ID : 0;
|
||
if ($pid && $lang !== 'es' && function_exists('pll_get_post')) {
|
||
$tr = pll_get_post($pid, $lang);
|
||
if ($tr) $pid = (int) $tr;
|
||
}
|
||
$url = $pid ? get_permalink($pid) : home_url('/evangelio-de-cada-dia/');
|
||
|
||
$css = '<style>'
|
||
. '.fea-eed-link{margin:1.6rem 0 0}'
|
||
. '.fea-eed-link a{display:inline-flex;align-items:center;gap:.5rem;color:#8b1a2e;text-decoration:none;font-size:.92rem;line-height:1}'
|
||
. '.fea-eed-link a:hover{text-decoration:underline;text-underline-offset:3px}'
|
||
. '.fea-eed-link .lbl{font-weight:700}'
|
||
. '.fea-eed-link .sep{color:#caa9b0}'
|
||
. '.fea-eed-link .fecha{color:#6f655c}'
|
||
. '.fea-eed-link .arrow{color:#8b1a2e;font-weight:700}'
|
||
. '</style>';
|
||
|
||
return $css . '<div class="fea-eed-link"><a href="' . esc_url($url) . '">'
|
||
. '<span class="lbl">' . esc_html($LBL[$L]) . '</span>'
|
||
. '<span class="sep">·</span>'
|
||
. '<span class="fecha">' . esc_html($fecha) . '</span>'
|
||
. '<span class="arrow">›</span></a></div>';
|
||
}
|
||
|
||
// ── Shortcode: [fea_carta_semana_hero] ────────────────────────────────────
|
||
add_shortcode('fea_carta_semana_hero', function() {
|
||
$lang = fea_current_lang();
|
||
$labels = fea_labels();
|
||
|
||
$cartas = get_posts([
|
||
'posts_per_page' => 1,
|
||
'category__in' => [fea_cat(6)],
|
||
'post_status' => 'publish',
|
||
'orderby' => 'date',
|
||
'order' => 'DESC',
|
||
]);
|
||
if (!$cartas) return '';
|
||
|
||
$c = $cartas[0];
|
||
$url = get_permalink($c->ID);
|
||
$fecha = date_i18n('j F Y', strtotime($c->post_date));
|
||
$author_name = get_the_author_meta('display_name', $c->post_author);
|
||
$avatar_url = get_avatar_url($c->post_author, ['size' => 32, 'default' => 'identicon']);
|
||
$slider = do_shortcode('[smartslider3 slider="2"]');
|
||
|
||
return '<section class="fea-hero-band"><div class="fea-hero-inner">'
|
||
. '<div class="fea-hero-text">'
|
||
. '<a href="' . esc_url($url) . '" class="fea-hero-link">'
|
||
. '<span class="fea-section-label">' . esc_html($labels['carta']) . '</span>'
|
||
. '<h2 class="fea-hero-title">' . esc_html(fea_title($c->post_title)) . '</h2>'
|
||
. '<div class="fea-hero-meta">'
|
||
. '<img src="' . esc_url($avatar_url) . '" alt="' . esc_attr($author_name) . '" width="32" height="32" class="fea-avatar" style="width:32px;height:32px;border-radius:50%;object-fit:cover;">'
|
||
. '<span>' . esc_html($author_name) . ' · ' . $fecha . '</span>'
|
||
. '</div>'
|
||
. '<span class="fea-hero-cta">' . esc_html($labels['carta'] ? 'Leer la carta' : 'Leer la carta') . ' →</span>'
|
||
. '</a>'
|
||
. fea_eed_link_html()
|
||
. '</div>'
|
||
. '<div class="fea-hero-slider">' . $slider . '</div>'
|
||
. '</div></section>';
|
||
});
|
||
|
||
// ── Shortcode: [fea_articulos_semana] ─────────────────────────────────────
|
||
// Fuente principal: links de la sección "Artículos seleccionados" de la carta vigente.
|
||
// Fallbacks: ACF portada_articulos → últimos por categoría.
|
||
add_shortcode('fea_articulos_semana', function($atts) {
|
||
$lang = fea_current_lang();
|
||
$labels = fea_labels();
|
||
$atts = shortcode_atts(['titulo' => $labels['articulos']], $atts);
|
||
$page = fea_front_page_id();
|
||
|
||
// 1) Fuente principal: sección "Artículos seleccionados" de la carta vigente
|
||
$posts = function_exists('fea_carta_section_posts') ? fea_carta_section_posts('articulos', $lang) : [];
|
||
|
||
// 2) Fallback ACF (solo ES)
|
||
if (empty($posts) && $lang === 'es' && function_exists('get_field')) {
|
||
$seleccion = get_field('portada_articulos', $page) ?: [];
|
||
foreach ($seleccion as $p) {
|
||
if ($p->post_status === 'publish') $posts[] = $p;
|
||
}
|
||
}
|
||
|
||
// 3) Fallback: últimos artículos en el idioma actual
|
||
if (empty($posts)) {
|
||
$posts = get_posts([
|
||
'posts_per_page' => 9,
|
||
'category__in' => [fea_cat(1650)],
|
||
'category__not_in' => array_map('fea_cat', [6, 21, 22, 23, 26, 58, 40, 1645, 1646, 1647, 1648, 1649, 1651, 1652]),
|
||
'post_status' => 'publish',
|
||
'orderby' => 'date',
|
||
'order' => 'DESC',
|
||
]);
|
||
}
|
||
if (!$posts) return '';
|
||
|
||
$html = '<section class="fea-section">'
|
||
. '<h2 class="fea-section-title">' . esc_html($atts['titulo']) . '</h2>'
|
||
. '<div class="fea-grid">';
|
||
foreach ($posts as $post) $html .= fea_card($post);
|
||
return $html . '</div></section>';
|
||
});
|
||
|
||
// ── Shortcode: [fea_evangelio] ────────────────────────────────────────────
|
||
// Fuente principal: sección "Evangelio y comentarios" de la carta vigente.
|
||
// Fallback: editorial cat 1646 + comentarios cat 1647 por fecha.
|
||
add_shortcode('fea_evangelio', function($atts) {
|
||
$lang = fea_current_lang();
|
||
$labels = fea_labels();
|
||
$atts = shortcode_atts(['titulo' => $labels['evangelio']], $atts);
|
||
|
||
$posts = function_exists('fea_carta_section_posts') ? fea_carta_section_posts('evangelio', $lang) : [];
|
||
|
||
if (empty($posts)) {
|
||
$editorial = get_posts([
|
||
'posts_per_page' => 1,
|
||
'category__in' => [fea_cat(1646)],
|
||
'post_status' => 'publish',
|
||
'orderby' => 'date',
|
||
'order' => 'DESC',
|
||
]);
|
||
$comentarios = get_posts([
|
||
'posts_per_page' => 6,
|
||
'category__in' => [fea_cat(1647)],
|
||
'category__not_in' => [fea_cat(1646)],
|
||
'post_status' => 'publish',
|
||
'orderby' => 'date',
|
||
'order' => 'DESC',
|
||
]);
|
||
$posts = array_merge($editorial, $comentarios);
|
||
}
|
||
if (!$posts) return '';
|
||
|
||
$html = '<section class="fea-section">'
|
||
. '<h2 class="fea-section-title">' . esc_html($atts['titulo']) . '</h2>'
|
||
. '<div class="fea-grid">';
|
||
foreach ($posts as $post) $html .= fea_card($post);
|
||
return $html . '</div></section>';
|
||
});
|
||
|
||
// ── Shortcode: [fea_evangelio_diario] ─────────────────────────────────────
|
||
// "El Evangelio de cada día": dos devocionales diarios indexados por día del año.
|
||
// · A la fuente cada día (texto, Fray Marcos) → categoría term_id 14
|
||
// · Otro evangelio es posible (vídeo YouTube) → categoría term_id 15
|
||
// Los posts están titulados "D mes" (ej. "21 junio"). Se muestra el de HOY
|
||
// (zona horaria del sitio) o el día indicado por ?fed=M-D, con pestañas para
|
||
// que el usuario elija formato y navegación día anterior / siguiente.
|
||
// Contenido solo en ES (devocional sin traducción) → categorías 14/15 fijas.
|
||
add_shortcode('fea_evangelio_diario', function($atts) {
|
||
$MESES = [1=>'enero',2=>'febrero',3=>'marzo',4=>'abril',5=>'mayo',6=>'junio',
|
||
7=>'julio',8=>'agosto',9=>'septiembre',10=>'octubre',11=>'noviembre',12=>'diciembre'];
|
||
// Día litúrgico de referencia: España (la web es ES); el servidor va en UTC.
|
||
$tz = new DateTimeZone('Europe/Madrid');
|
||
$now = new DateTimeImmutable('now', $tz);
|
||
$m = (int) $now->format('n');
|
||
$d = (int) $now->format('j');
|
||
if (!empty($_GET['fed']) && preg_match('/^(\d{1,2})-(\d{1,2})$/', $_GET['fed'], $mm)) {
|
||
$gm = (int) $mm[1]; $gd = (int) $mm[2];
|
||
if ($gm >= 1 && $gm <= 12 && $gd >= 1 && $gd <= 31) { $m = $gm; $d = $gd; }
|
||
}
|
||
$titulo_dia = $d . ' ' . $MESES[$m]; // "21 junio"
|
||
|
||
$find = function($cat) use ($titulo_dia) {
|
||
global $wpdb;
|
||
$id = $wpdb->get_var($wpdb->prepare(
|
||
"SELECT p.ID FROM {$wpdb->posts} p
|
||
JOIN {$wpdb->term_relationships} tr ON tr.object_id = p.ID
|
||
JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
|
||
WHERE tt.taxonomy = 'category' AND tt.term_id = %d
|
||
AND p.post_type = 'post' AND p.post_status = 'publish'
|
||
AND LOWER(TRIM(p.post_title)) = %s
|
||
ORDER BY p.ID ASC LIMIT 1",
|
||
$cat, $titulo_dia));
|
||
return $id ? get_post((int) $id) : null;
|
||
};
|
||
$texto = $find(14);
|
||
$video = $find(15);
|
||
|
||
// navegación por día del calendario (año irrelevante; usamos un año bisiesto fijo)
|
||
$base = get_permalink();
|
||
$cur = DateTimeImmutable::createFromFormat('!Y-n-j', '2024-' . $m . '-' . $d, $tz);
|
||
$prev = $cur->modify('-1 day');
|
||
$next = $cur->modify('+1 day');
|
||
$lbl = function($dt) use ($MESES) { return ((int)$dt->format('j')) . ' ' . substr($MESES[(int)$dt->format('n')], 0, 3); };
|
||
$href = function($dt) use ($base) { return esc_url(add_query_arg('fed', $dt->format('n') . '-' . $dt->format('j'), $base)); };
|
||
|
||
$render = function($post, $tipo) {
|
||
if (!$post) {
|
||
return '<p class="fea-eed-empty">No hay ' . ($tipo === 'video' ? 'vídeo' : 'texto') . ' disponible para este día.</p>';
|
||
}
|
||
$c = apply_filters('the_content', $post->post_content);
|
||
return '<div class="fea-eed-art">' . $c . '</div>';
|
||
};
|
||
|
||
$css = '<style>'
|
||
. '.fea-eed{max-width:760px;margin:0 auto}'
|
||
. '.fea-eed-head{display:flex;align-items:center;justify-content:space-between;gap:.5rem;margin:.2rem 0 1.1rem}'
|
||
. '.fea-eed-date{font-size:1.15rem;color:#8b1a2e;margin:0;text-align:center;flex:1}'
|
||
. '.fea-eed-nav{white-space:nowrap;color:#8b1a2e;text-decoration:none;font-weight:600;font-size:.9rem;padding:.3rem .6rem;border:1px solid #e2cdd2;border-radius:8px}'
|
||
. '.fea-eed-nav:hover{background:#faf3f4}'
|
||
. '.fea-eed-tabs input{position:absolute;opacity:0;pointer-events:none}'
|
||
. '.fea-eed-labels{display:flex;gap:.5rem;border-bottom:2px solid #e2cdd2;margin-bottom:1.2rem}'
|
||
. '.fea-eed-labels label{flex:1;text-align:center;cursor:pointer;padding:.6rem 1rem;font-weight:700;color:#888;border:2px solid transparent;border-bottom:none;border-radius:8px 8px 0 0;margin-bottom:-2px}'
|
||
. '#fed-texto:checked~.fea-eed-labels label[for=fed-texto],'
|
||
. '#fed-video:checked~.fea-eed-labels label[for=fed-video]{color:#8b1a2e;border-color:#e2cdd2;background:#faf3f4}'
|
||
. '.fea-eed-panel{display:none}'
|
||
. '#fed-texto:checked~.fea-eed-panel-texto{display:block}'
|
||
. '#fed-video:checked~.fea-eed-panel-video{display:block}'
|
||
. '.fea-eed-art iframe{max-width:100%}'
|
||
. '.fea-eed-panel-video .fea-eed-art iframe{width:100%;max-width:600px;height:auto;aspect-ratio:16/9;display:block;margin:0 auto}'
|
||
. '.fea-eed-art h1{font-size:1.4rem;line-height:1.3;text-align:center}'
|
||
. '.fea-eed-empty{color:#888;font-style:italic;text-align:center;padding:1.5rem}'
|
||
. '.wp-block-post-title{text-align:center}'
|
||
. '</style>';
|
||
|
||
$h = $css . '<div class="fea-eed">';
|
||
$h .= '<div class="fea-eed-head">'
|
||
. '<a class="fea-eed-nav" href="' . $href($prev) . '">‹ ' . esc_html($lbl($prev)) . '</a>'
|
||
. '<h2 class="fea-eed-date">' . esc_html($d . ' de ' . $MESES[$m]) . '</h2>'
|
||
. '<a class="fea-eed-nav" href="' . $href($next) . '">' . esc_html($lbl($next)) . ' ›</a>'
|
||
. '</div>';
|
||
$h .= '<div class="fea-eed-tabs">'
|
||
. '<input type="radio" name="fed-tab" id="fed-texto" checked>'
|
||
. '<input type="radio" name="fed-tab" id="fed-video">'
|
||
. '<div class="fea-eed-labels">'
|
||
. '<label for="fed-texto">A la fuente cada día</label>'
|
||
. '<label for="fed-video">Otro evangelio es posible (vídeo)</label>'
|
||
. '</div>'
|
||
. '<div class="fea-eed-panel fea-eed-panel-texto">' . $render($texto, 'texto') . '</div>'
|
||
. '<div class="fea-eed-panel fea-eed-panel-video">' . $render($video, 'video') . '</div>'
|
||
. '</div></div>';
|
||
return $h;
|
||
});
|
||
|
||
// ── Shortcode: [fea_eucaristia] ───────────────────────────────────────────
|
||
// Fuente principal: sección "Para unas eucaristías más participativas" de la carta.
|
||
// Fallback: cat 1648 por fecha.
|
||
add_shortcode('fea_eucaristia', function($atts) {
|
||
$lang = fea_current_lang();
|
||
$labels = fea_labels();
|
||
$atts = shortcode_atts(['titulo' => $labels['eucaristia']], $atts);
|
||
|
||
$posts = function_exists('fea_carta_section_posts') ? fea_carta_section_posts('eucaristia', $lang) : [];
|
||
|
||
if (empty($posts)) {
|
||
$posts = get_posts([
|
||
'posts_per_page' => 6,
|
||
'category__in' => [fea_cat(1648)],
|
||
'post_status' => 'publish',
|
||
'orderby' => 'date',
|
||
'order' => 'DESC',
|
||
]);
|
||
}
|
||
if (!$posts) return '';
|
||
|
||
$html = '<section class="fea-section">'
|
||
. '<h2 class="fea-section-title">' . esc_html($atts['titulo']) . '</h2>'
|
||
. '<div class="fea-grid">';
|
||
foreach ($posts as $post) $html .= fea_card($post);
|
||
return $html . '</div></section>';
|
||
});
|
||
|
||
// ── Shortcode: [fea_multimedia] ───────────────────────────────────────────
|
||
// Fuente principal: sección "Material multimedia" de la carta vigente.
|
||
// Fallbacks: ACF portada_multimedia → últimos por categoría.
|
||
add_shortcode('fea_multimedia', function($atts) {
|
||
$lang = fea_current_lang();
|
||
// Multimedia es contenido ES y externo (sin traducir) → solo se muestra en
|
||
// español de momento; en otros idiomas la sección se oculta (#135).
|
||
if ($lang !== 'es') return '';
|
||
$labels = fea_labels();
|
||
$atts = shortcode_atts(['titulo' => $labels['multimedia']], $atts);
|
||
$page = fea_front_page_id();
|
||
$more_labels = [
|
||
'es' => 'Ver más',
|
||
'en' => 'View all',
|
||
'fr' => 'Voir plus',
|
||
'it' => 'Vedi tutto',
|
||
'pt' => 'Ver mais',
|
||
];
|
||
$more_label = $more_labels[$lang] ?? $more_labels['es'];
|
||
$index_id = 18977;
|
||
if ($lang !== 'es' && function_exists('pll_get_post')) {
|
||
$translated_index = (int) pll_get_post($index_id, $lang);
|
||
if ($translated_index) $index_id = $translated_index;
|
||
}
|
||
$index_url = get_permalink($index_id);
|
||
|
||
$posts = function_exists('fea_carta_section_posts') ? fea_carta_section_posts('multimedia', $lang) : [];
|
||
|
||
if (empty($posts) && $lang === 'es' && function_exists('get_field')) {
|
||
$seleccion = get_field('portada_multimedia', $page) ?: [];
|
||
foreach ($seleccion as $p) {
|
||
if ($p->post_status === 'publish') $posts[] = $p;
|
||
}
|
||
}
|
||
|
||
if (empty($posts)) {
|
||
$posts = get_posts([
|
||
'posts_per_page' => 4,
|
||
'category__in' => array_map('fea_cat', [1649, 26, 58]),
|
||
'post_status' => 'publish',
|
||
'orderby' => 'date',
|
||
'order' => 'DESC',
|
||
]);
|
||
}
|
||
if (!$posts) return '';
|
||
|
||
$html = '<section class="fea-section">'
|
||
. '<div class="fea-section-head">'
|
||
. '<h2 class="fea-section-title">' . esc_html($atts['titulo']) . '</h2>'
|
||
. ($index_url ? '<a class="fea-section-more" href="' . esc_url($index_url) . '">'
|
||
. esc_html($more_label) . ' <span aria-hidden="true">→</span></a>' : '')
|
||
. '</div>'
|
||
. '<div class="fea-grid">';
|
||
foreach ($posts as $post) $html .= fea_card($post);
|
||
return $html . '</div></section>';
|
||
});
|
||
|
||
// ── Shortcode: [fea_noticia_centro] — bloque central del footer (Noticias) ───
|
||
add_shortcode('fea_noticia_centro', function() {
|
||
$uploads = wp_upload_dir()['baseurl'];
|
||
$cat_url = get_category_link(fea_cat(41));
|
||
$latest = get_posts([
|
||
'posts_per_page' => 1,
|
||
'category__in' => [fea_cat(41)],
|
||
'post_status' => 'publish',
|
||
'orderby' => 'date',
|
||
'order' => 'DESC',
|
||
]);
|
||
$title = !empty($latest) ? fea_title($latest[0]->post_title) : '';
|
||
$url = !empty($latest) ? get_permalink($latest[0]->ID) : $cat_url;
|
||
|
||
$html = '<a href="' . esc_url($cat_url) . '">';
|
||
$html .= '<img src="' . esc_url($uploads . '/recursos/noticias_2025.jpg') . '" '
|
||
. 'alt="Noticias de alcance" width="300" height="340" '
|
||
. 'style="display:block;margin:0 auto;" />';
|
||
$html .= '</a>';
|
||
if ($title) {
|
||
$html .= '<p style="text-align:center;margin-top:0.5rem;font-size:0.85rem;font-weight:600;line-height:1.3;">'
|
||
. '<a href="' . esc_url($url) . '" style="color:#0000cc;">'
|
||
. esc_html($title) . '</a></p>';
|
||
}
|
||
return $html;
|
||
});
|
||
|
||
// ── Reescribir links internos al idioma activo (Polylang) ─────────────────
|
||
add_filter('the_content', function($content) {
|
||
if (!function_exists('pll_current_language') || !function_exists('pll_get_post')) return $content;
|
||
$lang = pll_current_language();
|
||
if (!$lang || $lang === 'es') return $content;
|
||
// Los archivos de cartas pueden contener cientos de enlaces. Resolver cada uno
|
||
// con url_to_postid() en un listado agota memoria; la reescritura solo aporta
|
||
// valor al mostrar el contenido completo de una entrada o página.
|
||
if (!is_singular()) return $content;
|
||
|
||
return preg_replace_callback(
|
||
'/<a\s([^>]*\s)?href=["\']([^"\']+)["\']([^>]*)>/i',
|
||
function($m) use ($lang) {
|
||
$href = $m[2];
|
||
$home = home_url();
|
||
if (strpos($href, $home) === false) return $m[0];
|
||
|
||
$post_id = url_to_postid($href);
|
||
if (!$post_id) return $m[0];
|
||
|
||
$translated_id = pll_get_post($post_id, $lang);
|
||
if (!$translated_id || $translated_id === $post_id) return $m[0];
|
||
|
||
$new_url = get_permalink($translated_id);
|
||
if (!$new_url) return $m[0];
|
||
|
||
return str_replace($href, $new_url, $m[0]);
|
||
},
|
||
$content
|
||
);
|
||
}, 20);
|
||
|
||
// ── Ordenar categoría Evangelios y Comentarios por título ASC ─────────────
|
||
add_action('pre_get_posts', function($query) {
|
||
if ($query->is_main_query() && $query->is_category('evangelios-y-comentarios')) {
|
||
$query->set('orderby', 'title');
|
||
$query->set('order', 'ASC');
|
||
}
|
||
});
|
||
|
||
|
||
// ── Acordeón de versículos en posts de Evangelios y Comentarios ───────────
|
||
add_action('wp_footer', function() {
|
||
if (!is_single()) return;
|
||
global $post;
|
||
if (!has_category('evangelios-y-comentarios', $post)) return;
|
||
?>
|
||
<style>
|
||
.versiculo-group { margin: 0.5em 0; }
|
||
.versiculo-toggle {
|
||
display: flex; align-items: center; gap: 10px;
|
||
cursor: default; margin: 0.8em 0 0;
|
||
}
|
||
.versiculo-toggle .v-icon {
|
||
display: inline-flex; align-items: center; justify-content: center;
|
||
width: 22px; height: 22px; min-width: 22px; border-radius: 50%;
|
||
background: #c8860a; color: white; font-size: 18px; line-height: 1;
|
||
cursor: pointer; user-select: none; font-weight: bold;
|
||
transition: background 0.15s;
|
||
}
|
||
.versiculo-group.open .v-icon { background: #6b3080; }
|
||
.v-icon::after { content: '+'; }
|
||
.versiculo-group.open .v-icon::after { content: '\2212'; }
|
||
.versiculo-body { display: none; padding-left: 4px; }
|
||
.versiculo-group.open .versiculo-body { display: block; }
|
||
</style>
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
var content = document.querySelector('.wp-block-post-content, .entry-content');
|
||
if (!content) return;
|
||
|
||
var verseRe = /^(JUAN|LUCAS|MARCOS|MATEO)\s+\d/i;
|
||
|
||
function isVerse(el) {
|
||
if (el.tagName !== 'P') return false;
|
||
var links = el.querySelectorAll('a');
|
||
if (links.length !== 1) return false;
|
||
return verseRe.test(el.textContent.trim());
|
||
}
|
||
|
||
var children = Array.from(content.children);
|
||
var i = 0;
|
||
while (i < children.length) {
|
||
var child = children[i];
|
||
if (isVerse(child)) {
|
||
var group = document.createElement('div');
|
||
group.className = 'versiculo-group';
|
||
|
||
var header = document.createElement('div');
|
||
header.className = 'versiculo-toggle';
|
||
|
||
var icon = document.createElement('span');
|
||
icon.className = 'v-icon';
|
||
|
||
var link = child.querySelector('a').cloneNode(true);
|
||
header.appendChild(icon);
|
||
header.appendChild(link);
|
||
group.appendChild(header);
|
||
|
||
var body = document.createElement('div');
|
||
body.className = 'versiculo-body';
|
||
|
||
child.parentNode.insertBefore(group, child);
|
||
child.remove();
|
||
i++;
|
||
|
||
while (i < children.length && !isVerse(children[i])) {
|
||
body.appendChild(children[i]);
|
||
i++;
|
||
}
|
||
|
||
group.appendChild(body);
|
||
|
||
icon.addEventListener('click', function() {
|
||
this.closest('.versiculo-group').classList.toggle('open');
|
||
});
|
||
} else {
|
||
i++;
|
||
}
|
||
}
|
||
});
|
||
</script>
|
||
<?php
|
||
}, 30);
|
||
|
||
// ── Avatares en artículos de versículos (Evangelios y Comentarios) ─────────
|
||
add_action('wp_footer', function() {
|
||
if (!is_single()) return;
|
||
global $post, $wpdb;
|
||
if (!has_category('evangelios-y-comentarios', $post)) return;
|
||
|
||
// Extraer todos los slugs de links internos del contenido
|
||
preg_match_all('/<a\s[^>]*href=["\']([^"\']+)["\']/', $post->post_content, $m);
|
||
$slugs = [];
|
||
foreach ($m[1] as $url) {
|
||
$slug = basename(rtrim(parse_url($url, PHP_URL_PATH), '/'));
|
||
if ($slug) {
|
||
$slugs[] = $slug;
|
||
}
|
||
}
|
||
$slugs = array_values(array_unique(array_filter($slugs)));
|
||
if (empty($slugs)) return;
|
||
|
||
// Una sola query: slug → author_id
|
||
$ph = implode(',', array_fill(0, count($slugs), '%s'));
|
||
$rows = $wpdb->get_results(
|
||
$wpdb->prepare(
|
||
"SELECT post_name, post_author FROM {$wpdb->posts}
|
||
WHERE post_name IN ($ph) AND post_status IN ('publish','draft') AND post_type='post'",
|
||
$slugs
|
||
)
|
||
);
|
||
|
||
// Construir mapa slug → avatar_url (reutilizando cache de autor)
|
||
$author_cache = [];
|
||
$avatar_map = [];
|
||
foreach ($rows as $row) {
|
||
$aid = (int) $row->post_author;
|
||
if (!isset($author_cache[$aid])) {
|
||
$user = get_userdata($aid);
|
||
$author_cache[$aid] = ['src' => get_avatar_url($aid, ['size' => 40, 'default' => 'identicon']), 'name' => $user ? $user->display_name : ''];
|
||
}
|
||
if ($author_cache[$aid]) {
|
||
$avatar_map[$row->post_name] = $author_cache[$aid];
|
||
}
|
||
}
|
||
if (empty($avatar_map)) return;
|
||
?>
|
||
<style>
|
||
.versiculo-body ul { padding-left: 0; list-style: none; }
|
||
.versiculo-body li { display: flex; align-items: center; gap: 7px; margin-bottom: 4px; }
|
||
.fea-li-avatar { width: 24px; height: 24px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
|
||
.transl-toggle { font-size: 11px; color: #888; cursor: pointer; margin-left: 6px; user-select: none; white-space: nowrap; flex-shrink: 0; }
|
||
.transl-toggle:hover { color: #777; }
|
||
.transl-block { display: none; margin: 2px 0 6px 32px; font-size: 11px; line-height: 1.8; }
|
||
.transl-block.open { display: block; }
|
||
.transl-block a { color: #aaa; display: block; }
|
||
.transl-block a:hover { color: #555; }
|
||
</style>
|
||
<script>
|
||
(function() {
|
||
var map = <?php echo json_encode($avatar_map); ?>;
|
||
function slug(url) {
|
||
return url.replace(/\/$/, '').split('/').pop().split('?')[0].split('#')[0];
|
||
}
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
document.querySelectorAll('.versiculo-body li').forEach(function(li) {
|
||
var a = li.querySelector('a');
|
||
if (!a) return;
|
||
var entry = map[slug(a.href)];
|
||
if (!entry) return;
|
||
var img = document.createElement('img');
|
||
img.src = entry.src;
|
||
img.title = entry.name;
|
||
img.alt = '';
|
||
img.className = 'fea-li-avatar';
|
||
li.insertBefore(img, li.firstChild);
|
||
});
|
||
|
||
// Colapsar traducciones (p margin-left:90px) bajo "(…)"
|
||
document.querySelectorAll('.versiculo-body').forEach(function(body) {
|
||
Array.from(body.children).forEach(function(el) {
|
||
if (el.tagName !== 'P') return;
|
||
var ml = parseInt(el.style.marginLeft || '0');
|
||
if (ml < 60) return;
|
||
var prev = el.previousElementSibling;
|
||
while (prev && prev.tagName !== 'UL') prev = prev.previousElementSibling;
|
||
if (!prev) return;
|
||
var lis = prev.querySelectorAll('li');
|
||
if (!lis.length) return;
|
||
var lastLi = lis[lis.length - 1];
|
||
el.classList.add('transl-block');
|
||
var btn = document.createElement('span');
|
||
btn.className = 'transl-toggle';
|
||
btn.textContent = 'Otros idiomas (\u2026)';
|
||
lastLi.appendChild(btn);
|
||
btn.addEventListener('click', function(e) {
|
||
e.stopPropagation();
|
||
el.classList.toggle('open');
|
||
});
|
||
});
|
||
});
|
||
});
|
||
})();
|
||
</script>
|
||
<?php
|
||
}, 31);
|
||
|
||
|
||
// ── Shortcodes lista de autores ────────────────────────────────────────────
|
||
|
||
// IDs excluidos: Fe Adulta (1,890), Ediciones Feadulta (1540), José Chicharro (1049)
|
||
if (!defined('FEA_AUTORES_EXCLUIR')) define('FEA_AUTORES_EXCLUIR', [1, 890, 1049, 1540]);
|
||
if (!defined('FEA_LANG_ES_TTID')) define('FEA_LANG_ES_TTID', 1404);
|
||
|
||
function fea_autores_query($min_count = 0, $extra_exclude = []) {
|
||
global $wpdb;
|
||
$excl = implode(',', array_merge(FEA_AUTORES_EXCLUIR, $extra_exclude));
|
||
$ttid = FEA_LANG_ES_TTID;
|
||
$having = $min_count > 0 ? "HAVING cnt >= $min_count" : '';
|
||
$order = $min_count > 0 ? 'cnt DESC' : 'u.display_name ASC';
|
||
return $wpdb->get_results("
|
||
SELECT u.ID, u.display_name, COUNT(*) as cnt
|
||
FROM {$wpdb->posts} p
|
||
JOIN {$wpdb->term_relationships} tr ON tr.object_id = p.ID
|
||
JOIN {$wpdb->users} u ON u.ID = p.post_author
|
||
WHERE p.post_type = 'post'
|
||
AND p.post_status = 'publish'
|
||
AND tr.term_taxonomy_id = $ttid
|
||
AND u.ID NOT IN ($excl)
|
||
GROUP BY p.post_author
|
||
$having
|
||
ORDER BY $order
|
||
");
|
||
}
|
||
|
||
function fea_autores_html($rows, $show_count = false, $extra_class = "") {
|
||
$extra = $extra_class ? ' ' . $extra_class : '';
|
||
$out = '<ul class="fea-autores-lista' . $extra . '" style="list-style:none;padding-left:0;">';
|
||
foreach ($rows as $r) {
|
||
$url = esc_url(get_author_posts_url($r->ID));
|
||
$name = esc_html($r->display_name);
|
||
$avatar = esc_url(get_avatar_url($r->ID, ['size' => 40, 'default' => 'identicon']));
|
||
$cnt = $show_count ? ' <span class="fea-autor-cnt">(' . $r->cnt . ')</span>' : '';
|
||
$out .= '<li><span style="display:inline-block;width:40px;height:40px;min-width:40px;border-radius:50%;overflow:hidden;flex-shrink:0;"><img src="' . $avatar . '" width="40" height="40" alt="" loading="lazy" style="width:40px;height:40px;object-fit:cover;display:block;"></span> <a href="' . $url . '">' . $name . '</a>' . $cnt . '</li>';
|
||
}
|
||
$out .= '</ul>';
|
||
return $out;
|
||
}
|
||
|
||
add_shortcode('fea_autores_habituales', function() {
|
||
$rows = fea_autores_query(30, [948, 1048]);
|
||
if (empty($rows)) return '<p>No hay datos disponibles.</p>';
|
||
$n = count($rows);
|
||
$out = '<details class="fea-autores-section"><summary class="fea-autores-summary">Autores habituales <span class="fea-autor-cnt">(' . $n . ' autores)</span></summary>';
|
||
$out .= fea_autores_html($rows, true);
|
||
$out .= '</details>';
|
||
return $out;
|
||
});
|
||
|
||
add_shortcode('fea_autores_completo', function() {
|
||
$rows = fea_autores_query(0);
|
||
if (empty($rows)) return '<p>No hay datos disponibles.</p>';
|
||
$n = count($rows);
|
||
$out = '<details class="fea-autores-section"><summary class="fea-autores-summary">Lista completa por orden alfabético <span class="fea-autor-cnt">(' . $n . ' autores)</span></summary>';
|
||
$out .= fea_autores_html($rows, false, 'fea-autores-completo');
|
||
$out .= '</details>';
|
||
return $out;
|
||
});
|
||
|
||
add_action('wp_head', function() {
|
||
if (!is_page('autores-lista')) return;
|
||
?>
|
||
<style>
|
||
.fea-autores-section { margin-bottom: 1.5em; }
|
||
.fea-autores-summary {
|
||
font-size: 1.3rem; font-weight: 600; cursor: pointer;
|
||
padding: 0.5em 0; list-style: none;
|
||
display: flex; align-items: center; gap: 0.5em;
|
||
border-bottom: 2px solid #046bd2; margin-bottom: 0.8em;
|
||
user-select: none;
|
||
}
|
||
.fea-autores-summary::-webkit-details-marker { display: none; }
|
||
.fea-autores-summary::before {
|
||
content: "\25B6"; font-size: 0.75em; color: #046bd2;
|
||
transition: transform 0.2s; display: inline-block;
|
||
}
|
||
details[open] > .fea-autores-summary::before { transform: rotate(90deg); }
|
||
.fea-autores-lista { list-style: none; padding: 0; margin: 0.5em 0 1em; }
|
||
.fea-autores-lista li {
|
||
display: flex; align-items: center; gap: 12px;
|
||
padding: 3px 0; border-bottom: 1px solid #f5f5f5;
|
||
}
|
||
.fea-autores-lista li img.fea-autor-avatar {
|
||
width: 40px; height: 40px; min-width: 40px;
|
||
border-radius: 50%; clip-path: circle(50%);
|
||
object-fit: cover; display: block; flex-shrink: 0;
|
||
}
|
||
.fea-autor-cnt { color: #888; font-size: 0.85em; }
|
||
.fea-autores-completo { column-count: 3; column-gap: 2em; }
|
||
.fea-autores-completo li { break-inside: avoid; }
|
||
@media (max-width: 700px) { .fea-autores-completo { column-count: 2; } }
|
||
@media (max-width: 480px) { .fea-autores-completo { column-count: 1; } }
|
||
</style>
|
||
<?php
|
||
}, 20);
|
||
|
||
// ── Aumentar posts por página en archivos de autor ─────────────────────────
|
||
add_action('pre_get_posts', function($query) {
|
||
if ($query->is_main_query() && $query->is_author()) {
|
||
$query->set('posts_per_page', 30);
|
||
}
|
||
});
|
||
|
||
// ── Shortcodes EFFA (Escuela de Formación en Fe Adulta) ────────────────────
|
||
|
||
// Sección de vídeos (subpáginas): thumbnail YT o primera imagen del contenido
|
||
add_shortcode('effa_seccion', function($atts) {
|
||
$atts = shortcode_atts(['cat' => '', 'num' => -1], $atts);
|
||
if (!$atts['cat']) return '';
|
||
|
||
$posts = get_posts([
|
||
'numberposts' => (int) $atts['num'],
|
||
'category_name' => $atts['cat'],
|
||
'post_status' => 'publish',
|
||
'orderby' => 'meta_value',
|
||
'meta_key' => '_effa_joomla_alias',
|
||
'order' => 'ASC',
|
||
]);
|
||
|
||
if (!$posts) return '<p>No hay contenido en esta sección todavía.</p>';
|
||
|
||
$items = [];
|
||
foreach ($posts as $p) {
|
||
$url = get_permalink($p->ID);
|
||
$thumb = get_the_post_thumbnail_url($p->ID, 'medium');
|
||
if (!$thumb && preg_match('~youtube\.com/watch\?v=([a-zA-Z0-9_-]+)~', $p->post_content, $m)) {
|
||
$thumb = 'https://img.youtube.com/vi/' . $m[1] . '/mqdefault.jpg';
|
||
}
|
||
if (!$thumb && preg_match('~<img[^>]+src="([^"]+)"~', $p->post_content, $mi)) {
|
||
$thumb = $mi[1];
|
||
}
|
||
$cell = '<td style="width:25%;padding:6px;vertical-align:top;">';
|
||
$cell .= '<a href="' . esc_url($url) . '" style="text-decoration:none;color:inherit;display:block;">';
|
||
if ($thumb) $cell .= '<img src="' . esc_url($thumb) . '" style="width:100%;height:auto;display:block;border-radius:4px;">';
|
||
$cell .= '<strong style="display:block;font-size:0.85rem;margin-top:5px;color:#222;">' . esc_html(fea_title($p->post_title)) . '</strong>';
|
||
$cell .= '</a>';
|
||
$cell .= '</td>';
|
||
$items[] = $cell;
|
||
}
|
||
|
||
$html = '<table class="effa-proyecto-table" style="width:100%;border-collapse:collapse;table-layout:fixed;">';
|
||
foreach (array_chunk($items, 4) as $row) {
|
||
while (count($row) < 4) $row[] = '<td></td>';
|
||
$html .= '<tr>' . implode('', $row) . '</tr>';
|
||
}
|
||
$html .= '</table>';
|
||
return $html;
|
||
});
|
||
|
||
// Hub del proyecto (8 artículos de presentación): primera imagen + extracto
|
||
add_shortcode('effa_proyecto', function() {
|
||
$posts = get_posts([
|
||
'numberposts' => -1,
|
||
'category_name' => 'proyecat',
|
||
'post_status' => 'publish',
|
||
'orderby' => 'name',
|
||
'order' => 'ASC',
|
||
]);
|
||
if (!$posts) return '';
|
||
|
||
$items = [];
|
||
foreach ($posts as $p) {
|
||
$url = get_permalink($p->ID);
|
||
preg_match('~<img[^>]+src="([^"]+)"~', $p->post_content, $mi);
|
||
$thumb = $mi[1] ?? '';
|
||
$text = trim(preg_replace('/\s+/', ' ', wp_strip_all_tags($p->post_content)));
|
||
$excerpt = wp_trim_words($text, 12, '…');
|
||
|
||
$cell = '<td style="width:25%;padding:6px;vertical-align:top;">';
|
||
$cell .= '<a href="' . esc_url($url) . '" style="text-decoration:none;color:inherit;display:block;">';
|
||
if ($thumb) $cell .= '<img src="' . esc_url($thumb) . '" style="width:100%;height:auto;display:block;border-radius:4px;">';
|
||
$cell .= '<strong style="display:block;font-size:0.85rem;margin-top:5px;color:#222;">' . esc_html(fea_title($p->post_title)) . '</strong>';
|
||
$cell .= '</a>';
|
||
$cell .= '<span style="display:block;font-size:0.75rem;color:#666;margin-top:3px;line-height:1.3;">' . esc_html($excerpt) . '</span>';
|
||
$cell .= '</td>';
|
||
$items[] = $cell;
|
||
}
|
||
|
||
$html = '<table class="effa-proyecto-table" style="width:100%;border-collapse:collapse;table-layout:fixed;">';
|
||
foreach (array_chunk($items, 4) as $row) {
|
||
while (count($row) < 4) $row[] = '<td></td>';
|
||
$html .= '<tr>' . implode('', $row) . '</tr>';
|
||
}
|
||
$html .= '</table>';
|
||
return $html;
|
||
});
|
||
|
||
// CSS EFFA (tabs nav, logo, CTA, cards)
|
||
add_action('wp_head', function() {
|
||
global $post;
|
||
if (!$post || (strpos($post->post_content, 'effa_') === false && strpos($post->post_name ?? '', 'effa') === false)) return;
|
||
?>
|
||
<style>
|
||
.effa-logo { display: block; margin: 0 auto 1rem; max-width: 200px; }
|
||
.effa-intro { text-align: center; margin-bottom: 1.5rem; }
|
||
.effa-nav { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 1.5rem 0 2rem; padding: 0 0 1rem; list-style: none; border-bottom: 2px solid #e5e5e5; }
|
||
.effa-nav li { list-style: none; }
|
||
.effa-nav a { display: inline-block; padding: 0.35em 1em; border: 1px solid #ccc; border-radius: 999px; font-size: 0.85rem; text-decoration: none; color: #444; transition: background 0.15s, color 0.15s, border-color 0.15s; }
|
||
.effa-nav a:hover, .effa-nav a.active { background: #E89A1A; color: #fff; border-color: #E89A1A; }
|
||
.effa-cta-wrap { text-align: center; margin: 2rem 0 1rem; }
|
||
.effa-cta { display: inline-block; padding: 0.6em 1.8em; background: #E89A1A; color: #fff; border-radius: 999px; text-decoration: none; font-weight: 700; font-size: 1rem; }
|
||
.effa-cta:hover { background: #c97d10; color: #fff; }
|
||
/* Tarjetas EFFA: reflota de 4 columnas a 2 en movil */
|
||
@media (max-width: 600px) {
|
||
.effa-proyecto-table tr { display: flex; flex-wrap: wrap; }
|
||
.effa-proyecto-table td { width: 50% !important; box-sizing: border-box; }
|
||
.effa-proyecto-table td:empty { display: none; }
|
||
}
|
||
</style>
|
||
<?php
|
||
}, 20);
|
||
|
||
// ── Índice dinámico de evangelio por libro ─────────────────────────────────
|
||
|
||
// "Jn 4, 5-42" → "jn-4-5-42" (anchor ID format)
|
||
function fea_cita_to_anchor(string $cita): string {
|
||
return strtolower(preg_replace('/[,\.\s]+/', '-', trim($cita)));
|
||
}
|
||
|
||
// Parse "Jn 4, 5-42" → [4, 5] for numeric sorting
|
||
function fea_cita_sort_key(string $cita): array {
|
||
preg_match('/(\d+),\s*(\d+)/', $cita, $m);
|
||
return [(int)($m[1] ?? 0), (int)($m[2] ?? 0)];
|
||
}
|
||
|
||
add_shortcode('fea_citas_evangelio', function($atts) {
|
||
$atts = shortcode_atts(['libro' => 'Jn'], $atts);
|
||
$libro = preg_replace('/[^A-Za-z]/', '', $atts['libro']); // sanitize
|
||
global $wpdb;
|
||
$cat_com = 1647;
|
||
|
||
// One query: all posts + author + avatar email in this book
|
||
$rows = $wpdb->get_results($wpdb->prepare(
|
||
"SELECT p.ID, p.post_title, p.post_author,
|
||
pm.meta_value AS cita,
|
||
u.display_name AS autor_name,
|
||
u.user_email AS autor_email
|
||
FROM {$wpdb->posts} p
|
||
JOIN {$wpdb->postmeta} pm ON pm.post_id = p.ID AND pm.meta_key = '_cita_evangelio'
|
||
JOIN {$wpdb->term_relationships} tr ON tr.object_id = p.ID
|
||
JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = tr.term_taxonomy_id AND tt.term_id = %d
|
||
JOIN {$wpdb->users} u ON u.ID = p.post_author
|
||
WHERE p.post_status = 'publish'
|
||
AND pm.meta_value LIKE %s
|
||
ORDER BY pm.meta_value, p.post_date ASC",
|
||
$cat_com, $libro . ' %'
|
||
));
|
||
|
||
if (empty($rows)) return '<p>No hay comentarios para este evangelio.</p>';
|
||
|
||
// Group by cita
|
||
$groups = [];
|
||
foreach ($rows as $r) $groups[$r->cita][] = $r;
|
||
|
||
// Sort groups numerically by chapter, then verse
|
||
uksort($groups, function($a, $b) {
|
||
[$ca, $va] = fea_cita_sort_key($a);
|
||
[$cb, $vb] = fea_cita_sort_key($b);
|
||
return $ca !== $cb ? $ca - $cb : $va - $vb;
|
||
});
|
||
|
||
// Avatar URL by email (Gravatar, with fallback)
|
||
$avatar_cache = [];
|
||
$avatar_url = function(string $email, int $id) use (&$avatar_cache): string {
|
||
if (!isset($avatar_cache[$id])) {
|
||
$url = get_avatar_url($id, ['size' => 40, 'default' => 'mystery']);
|
||
$avatar_cache[$id] = $url ?: 'https://www.gravatar.com/avatar/' . md5(strtolower(trim($email))) . '?s=40&d=mystery';
|
||
}
|
||
return $avatar_cache[$id];
|
||
};
|
||
|
||
$html = '<div class="fea-indice-evangelio">';
|
||
|
||
foreach ($groups as $cita => $posts) {
|
||
$n = count($posts);
|
||
$anchor = fea_cita_to_anchor($cita);
|
||
$html .= '<details class="fea-cita-group" id="' . esc_attr($anchor) . '">';
|
||
$html .= '<summary class="fea-cita-summary">'
|
||
. '<span class="fea-cita-ref">' . esc_html($cita) . '</span>'
|
||
. ' <span class="fea-cita-count">' . $n . ' comentario' . ($n !== 1 ? 's' : '') . '</span>'
|
||
. '</summary>';
|
||
$html .= '<ul class="fea-cita-lista">';
|
||
foreach ($posts as $p) {
|
||
$av = $avatar_url($p->autor_email, $p->post_author);
|
||
$html .= '<li class="fea-cita-item">'
|
||
. '<span class="fea-cita-avatar">'
|
||
. '<img src="' . esc_url($av) . '" width="40" height="40" alt="" loading="lazy">'
|
||
. '</span>'
|
||
. '<span class="fea-cita-meta">'
|
||
. '<a href="' . esc_url(get_permalink($p->ID)) . '">' . esc_html(fea_title($p->post_title)) . '</a>'
|
||
. '<span class="fea-cita-autor">' . esc_html($p->autor_name) . '</span>'
|
||
. '</span>'
|
||
. '</li>';
|
||
}
|
||
$html .= '</ul></details>';
|
||
}
|
||
|
||
$html .= '</div>';
|
||
return $html;
|
||
});
|
||
|
||
add_action('wp_head', function() {
|
||
global $post;
|
||
if (!$post || !has_shortcode($post->post_content, 'fea_citas_evangelio')) return;
|
||
?>
|
||
<style>
|
||
.fea-indice-evangelio { margin: 1.5rem 0; }
|
||
|
||
.fea-cita-group {
|
||
border-bottom: 1px solid #e5e5e5;
|
||
padding: 0;
|
||
}
|
||
.fea-cita-summary {
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 0.6rem;
|
||
padding: 0.75rem 0.5rem;
|
||
cursor: pointer;
|
||
list-style: none;
|
||
user-select: none;
|
||
}
|
||
.fea-cita-summary::-webkit-details-marker { display: none; }
|
||
.fea-cita-summary::before {
|
||
content: '›';
|
||
font-size: 1.1rem;
|
||
color: #046bd2;
|
||
transition: transform 0.15s;
|
||
display: inline-block;
|
||
flex-shrink: 0;
|
||
}
|
||
.fea-cita-group[open] > .fea-cita-summary::before { transform: rotate(90deg); }
|
||
.fea-cita-ref {
|
||
font-weight: 700;
|
||
font-size: 0.95rem;
|
||
}
|
||
.fea-cita-count {
|
||
font-size: 0.8rem;
|
||
color: #888;
|
||
}
|
||
|
||
.fea-cita-lista {
|
||
list-style: none;
|
||
padding: 0 0 0.75rem 1.5rem;
|
||
margin: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.5rem;
|
||
}
|
||
.fea-cita-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
}
|
||
.fea-cita-avatar {
|
||
display: inline-block;
|
||
width: 40px; height: 40px; min-width: 40px;
|
||
border-radius: 50%;
|
||
overflow: hidden;
|
||
flex-shrink: 0;
|
||
}
|
||
.fea-cita-avatar img {
|
||
width: 40px; height: 40px;
|
||
object-fit: cover; display: block;
|
||
}
|
||
.fea-cita-meta {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.1rem;
|
||
line-height: 1.3;
|
||
}
|
||
.fea-cita-meta a { font-size: 0.9rem; }
|
||
.fea-cita-autor {
|
||
font-size: 0.78rem;
|
||
color: #888;
|
||
}
|
||
</style>
|
||
<?php
|
||
}, 20);
|
||
|
||
// ── Pie de comentario: carta, cita evangelio, otros comentarios ────────────
|
||
|
||
// Add id anchors to verse headings in the 4 gospel index pages
|
||
add_filter('the_content', function($content) {
|
||
global $post;
|
||
$index_ids = [17874, 17881, 17882, 17883];
|
||
if (!isset($post->ID) || !in_array($post->ID, $index_ids)) return $content;
|
||
|
||
$bookmap = ['JUAN'=>'Jn','LUCAS'=>'Lc','MARCOS'=>'Mc','MATEO'=>'Mt'];
|
||
|
||
return preg_replace_callback(
|
||
'~<p([^>]*)>\s*(<a[^>]*>)\s*((JUAN|LUCAS|MARCOS|MATEO)\s+(\d+),\s*([\d\-–\s]+))\s*(</a>)\s*</p>~i',
|
||
function($m) use ($bookmap) {
|
||
$abbr = $bookmap[strtoupper($m[4])] ?? '';
|
||
if (!$abbr) return $m[0];
|
||
$anchor = strtolower($abbr . '-' . $m[5] . '-' . preg_replace('/[\s–\-]+/', '-', trim($m[6])));
|
||
$anchor = rtrim($anchor, '-');
|
||
return '<p' . $m[1] . ' id="' . $anchor . '">' . $m[2] . $m[3] . $m[7] . '</p>';
|
||
},
|
||
$content
|
||
);
|
||
}, 9); // priority 9 so it runs before the_content shortcode processing
|
||
|
||
add_filter('the_content', function($content) {
|
||
if (!is_single()) return $content;
|
||
global $post;
|
||
if (!in_category('comentarios-al-evangelio', $post)) return $content;
|
||
|
||
$carta_id = get_post_meta($post->ID, '_carta_id', true);
|
||
$cita = get_post_meta($post->ID, '_cita_evangelio', true);
|
||
|
||
if (!$carta_id && !$cita) return $content;
|
||
|
||
$html = '<div class="fea-com-footer">';
|
||
|
||
// --- Carta de la semana ---
|
||
if ($carta_id) {
|
||
$carta = get_post($carta_id);
|
||
if ($carta && $carta->post_status === 'publish') {
|
||
$fecha = date_i18n('j F Y', strtotime($carta->post_date));
|
||
$html .= '<div class="fea-com-row fea-com-carta">'
|
||
. '<span class="fea-com-label">Carta de la semana</span>'
|
||
. '<a href="' . esc_url(get_permalink($carta_id)) . '">'
|
||
. esc_html(fea_title($carta->post_title))
|
||
. ' <span class="fea-com-fecha">(' . $fecha . ')</span>'
|
||
. '</a>'
|
||
. '</div>';
|
||
}
|
||
}
|
||
|
||
// --- Cita del evangelio — link directo al anchor en el índice ---
|
||
if ($cita) {
|
||
$book_post_id = ['Mt' => 43908, 'Mc' => 43909, 'Lc' => 43907, 'Jn' => 43906];
|
||
$abbr = substr($cita, 0, 2);
|
||
$anchor = fea_cita_to_anchor($cita);
|
||
$index_url = isset($book_post_id[$abbr])
|
||
? esc_url(get_permalink($book_post_id[$abbr]) . '#' . $anchor)
|
||
: '';
|
||
|
||
$html .= '<div class="fea-com-row fea-com-cita">'
|
||
. '<span class="fea-com-label">Evangelio</span>'
|
||
. ($index_url
|
||
? '<a href="' . $index_url . '">' . esc_html($cita) . '</a>'
|
||
: '<span>' . esc_html($cita) . '</span>')
|
||
. '</div>';
|
||
}
|
||
|
||
// --- Otros comentarios de esta misma cita ---
|
||
if ($cita) {
|
||
$others = get_posts([
|
||
'post_type' => 'post',
|
||
'post_status' => 'publish',
|
||
'posts_per_page' => 30,
|
||
'post__not_in' => [$post->ID],
|
||
'category_name' => 'comentarios-al-evangelio',
|
||
'meta_key' => '_cita_evangelio',
|
||
'meta_value' => $cita,
|
||
'orderby' => 'date',
|
||
'order' => 'ASC',
|
||
]);
|
||
|
||
if (!empty($others)) {
|
||
$html .= '<div class="fea-com-row fea-com-otros">'
|
||
. '<span class="fea-com-label">Otros comentarios sobre ' . esc_html($cita) . '</span>'
|
||
. '<ul class="fea-com-lista">';
|
||
foreach ($others as $o) {
|
||
$html .= '<li><a href="' . esc_url(get_permalink($o->ID)) . '">'
|
||
. esc_html(fea_title($o->post_title)) . '</a></li>';
|
||
}
|
||
$html .= '</ul></div>';
|
||
}
|
||
}
|
||
|
||
$html .= '</div>'; // .fea-com-footer
|
||
return $content . $html;
|
||
});
|
||
|
||
add_action('wp_head', function() {
|
||
if (!is_single()) return;
|
||
global $post;
|
||
if (!$post || !in_category('comentarios-al-evangelio', $post)) return;
|
||
?>
|
||
<style>
|
||
.fea-com-footer {
|
||
margin-top: 2.5rem;
|
||
padding-top: 1.5rem;
|
||
border-top: 2px solid #e5e5e5;
|
||
font-size: 0.9rem;
|
||
}
|
||
.fea-com-row {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.4rem 0.8rem;
|
||
align-items: baseline;
|
||
margin-bottom: 1rem;
|
||
}
|
||
.fea-com-label {
|
||
font-weight: 700;
|
||
color: #555;
|
||
white-space: nowrap;
|
||
flex-shrink: 0;
|
||
}
|
||
.fea-com-label::after { content: ':'; margin-right: 0.2em; }
|
||
.fea-com-fecha { color: #888; font-size: 0.85em; }
|
||
.fea-com-lista {
|
||
list-style: none;
|
||
padding: 0;
|
||
margin: 0.3rem 0 0;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.3rem 0;
|
||
flex-direction: column;
|
||
}
|
||
.fea-com-lista li::before {
|
||
content: '›';
|
||
margin-right: 0.4em;
|
||
color: #046bd2;
|
||
}
|
||
.fea-com-otros .fea-com-label { display: block; margin-bottom: 0.4rem; }
|
||
.fea-com-otros { flex-direction: column; align-items: flex-start; }
|
||
</style>
|
||
<?php
|
||
}, 20);
|