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);
// 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;
?>
'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;
?>
'🇪🇸', '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"' : '';
$items .= '
' . $flag . ' ' . $code . '';
}
?>
.wp-block-post-title { display:none !important; }';
}, 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 = ''
. esc_html($cats[0]->name) . '';
}
echo '';
});
add_action('wp_head', function() {
if (!is_single()) return;
?>
post_author;
$author_name = get_the_author_meta('display_name', $author_id);
$avatar_url = get_avatar_url($author_id, ['size' => 40, 'default' => 'identicon']);
$url = get_permalink($post->ID);
$title = fea_title($post->post_title);
return ''
. ''
. ''
. '';
}
/** IDs de las páginas de portada en todos los idiomas. */
function fea_front_page_ids(): array {
return [26542, 42756, 42757, 42758, 43889]; // ES, FR, IT, PT, EN
}
/** 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);
}
/** 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;
}
// ── 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']);
return '';
});
// ── Shortcode: [fea_articulos_semana] ─────────────────────────────────────
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();
// Selección editorial ACF (solo para ES; otros idiomas usan fallback)
$posts = [];
if ($lang === 'es' && function_exists('get_field')) {
$seleccion = get_field('portada_articulos', $page) ?: [];
foreach ($seleccion as $p) {
if ($p->post_status === 'publish') $posts[] = $p;
}
}
// 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 = ''
. '' . esc_html($atts['titulo']) . '
'
. '';
foreach ($posts as $post) $html .= fea_card($post);
return $html . '
';
});
// ── Shortcode: [fea_evangelio] ────────────────────────────────────────────
// Editorial (cat 1646) primero, luego comentarios (cat 1647). Máx 7 en total.
add_shortcode('fea_evangelio', function($atts) {
$lang = fea_current_lang();
$labels = fea_labels();
$atts = shortcode_atts(['titulo' => $labels['evangelio']], $atts);
$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 = ''
. '' . esc_html($atts['titulo']) . '
'
. '';
foreach ($posts as $post) $html .= fea_card($post);
return $html . '
';
});
// ── Shortcode: [fea_eucaristia] ───────────────────────────────────────────
add_shortcode('fea_eucaristia', function($atts) {
$lang = fea_current_lang();
$labels = fea_labels();
$atts = shortcode_atts(['titulo' => $labels['eucaristia']], $atts);
$posts = get_posts([
'posts_per_page' => 6,
'category__in' => [fea_cat(1648)],
'post_status' => 'publish',
'orderby' => 'date',
'order' => 'DESC',
]);
if (!$posts) return '';
$html = ''
. '' . esc_html($atts['titulo']) . '
'
. '';
foreach ($posts as $post) $html .= fea_card($post);
return $html . '
';
});
// ── Shortcode: [fea_multimedia] ───────────────────────────────────────────
add_shortcode('fea_multimedia', function($atts) {
$lang = fea_current_lang();
$labels = fea_labels();
$atts = shortcode_atts(['titulo' => $labels['multimedia']], $atts);
$page = fea_front_page_id();
$posts = [];
if ($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 = ''
. '' . esc_html($atts['titulo']) . '
'
. '';
foreach ($posts as $post) $html .= fea_card($post);
return $html . '
';
});
// ── Shortcode: [fea_prefooter] — 3 columnas sobre el footer ──────────────────
add_shortcode('fea_prefooter', function() {
$uploads = wp_upload_dir()['baseurl'];
// Columna centro: última noticia de alcance (cat term_id=41)
$latest_noticias = get_posts([
'posts_per_page' => 1,
'category__in' => [fea_cat(41)],
'post_status' => 'publish',
'orderby' => 'date',
'order' => 'DESC',
]);
$cat_noticias_url = get_category_link(fea_cat(41));
$noticia_title = !empty($latest_noticias) ? fea_title($latest_noticias[0]->post_title) : '';
$noticia_url = !empty($latest_noticias) ? get_permalink($latest_noticias[0]->ID) : $cat_noticias_url;
// Columna derecha: último vídeo (cat term_id=58)
$latest_video = get_posts([
'posts_per_page' => 1,
'category__in' => [fea_cat(58)],
'post_status' => 'publish',
'orderby' => 'date',
'order' => 'DESC',
]);
$video_url = !empty($latest_video) ? get_permalink($latest_video[0]->ID) : get_category_link(fea_cat(58));
$effa_url = get_permalink(42726);
$suma_url = get_permalink(18036);
$libros_url = get_category_link(1616);
$videos_escuela_url = get_permalink(21921);
ob_start(); ?>
.fea-prefooter{display:flex;gap:1.5rem;justify-content:center;align-items:flex-start;padding:2rem 1rem;border-top:2px solid #e5e5e5;margin-top:3rem;}
.fea-prefooter-col{flex:1;max-width:320px;text-align:center;}
.fea-prefooter-noticia{margin-top:0.6rem;font-size:0.85rem;font-weight:600;color:#0000cc;line-height:1.3;}
.fea-prefooter-noticia a{color:#0000cc;}
@media(max-width:640px){.fea-prefooter{flex-direction:column;align-items:center;}.fea-prefooter-col{max-width:100%;}}
';
return $css . ob_get_clean();
});
// ── 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;
return preg_replace_callback(
'/]*\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;
?>
]*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;
?>
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 = '';
return $out;
}
add_shortcode('fea_autores_habituales', function() {
$rows = fea_autores_query(30, [948, 1048]);
if (empty($rows)) return 'No hay datos disponibles.
';
$n = count($rows);
$out = 'Autores habituales (' . $n . ' autores)
';
$out .= fea_autores_html($rows, true);
$out .= ' ';
return $out;
});
add_shortcode('fea_autores_completo', function() {
$rows = fea_autores_query(0);
if (empty($rows)) return 'No hay datos disponibles.
';
$n = count($rows);
$out = 'Lista completa por orden alfabético (' . $n . ' autores)
';
$out .= fea_autores_html($rows, false, 'fea-autores-completo');
$out .= ' ';
return $out;
});
add_action('wp_head', function() {
if (!is_page('autores-lista')) return;
?>
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 'No hay contenido en esta sección todavía.
';
$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('~
]+src="([^"]+)"~', $p->post_content, $mi)) {
$thumb = $mi[1];
}
$cell = '';
$cell .= '';
if ($thumb) $cell .= ' ';
$cell .= '' . esc_html(fea_title($p->post_title)) . '';
$cell .= '';
$cell .= ' | ';
$items[] = $cell;
}
$html = '';
foreach (array_chunk($items, 4) as $row) {
while (count($row) < 4) $row[] = ' | ';
$html .= '' . implode('', $row) . '
';
}
$html .= '
';
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('~
]+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 = '';
$cell .= '';
if ($thumb) $cell .= ' ';
$cell .= '' . esc_html(fea_title($p->post_title)) . '';
$cell .= '';
$cell .= '' . esc_html($excerpt) . '';
$cell .= ' | ';
$items[] = $cell;
}
$html = '';
foreach (array_chunk($items, 4) as $row) {
while (count($row) < 4) $row[] = ' | ';
$html .= '' . implode('', $row) . '
';
}
$html .= '
';
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;
?>
'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 'No hay comentarios para este evangelio.
';
// 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 = '';
foreach ($groups as $cita => $posts) {
$n = count($posts);
$anchor = fea_cita_to_anchor($cita);
$html .= '
';
$html .= ''
. '' . esc_html($cita) . ''
. ' ' . $n . ' comentario' . ($n !== 1 ? 's' : '') . ''
. '
';
$html .= '';
foreach ($posts as $p) {
$av = $avatar_url($p->autor_email, $p->post_author);
$html .= '- '
. ''
. '
'
. ''
. ''
. '' . esc_html(fea_title($p->post_title)) . ''
. '' . esc_html($p->autor_name) . ''
. ''
. ' ';
}
$html .= '
';
}
$html .= '
';
return $html;
});
add_action('wp_head', function() {
global $post;
if (!$post || !has_shortcode($post->post_content, 'fea_citas_evangelio')) return;
?>
ID) || !in_array($post->ID, $index_ids)) return $content;
$bookmap = ['JUAN'=>'Jn','LUCAS'=>'Lc','MARCOS'=>'Mc','MATEO'=>'Mt'];
return preg_replace_callback(
'~]*)>\s*(]*>)\s*((JUAN|LUCAS|MARCOS|MATEO)\s+(\d+),\s*([\d\-–\s]+))\s*()\s*
~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 '' . $m[2] . $m[3] . $m[7] . '
';
},
$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 = ''; // .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;
?>