633 lines
33 KiB
PHP
633 lines
33 KiB
PHP
<?php
|
||
/**
|
||
* Plugin Name: Fe Adulta — Buscador avanzado (#8)
|
||
* Description: Replica el «Buscador avanzado» K2 de Joomla con WordPress nativo.
|
||
* Filtros: palabra (FULLTEXT vía fea-search-fulltext.php), autor, tema
|
||
* (categoría), cita bíblica (_cita_evangelio), fecha.
|
||
* Formulario visible en la página de resultados (search template) y en
|
||
* la página dedicada /buscar. Multiidioma (Polylang).
|
||
* Version: 1.0
|
||
*/
|
||
if (!defined('ABSPATH')) exit;
|
||
|
||
// ─────────────────────────────────────────────────────────────────
|
||
// Constantes de configuración
|
||
// ─────────────────────────────────────────────────────────────────
|
||
|
||
/**
|
||
* IDs de usuarios a excluir del selector de autores.
|
||
* 1,890,1049,1540 = cuentas técnicas/admin.
|
||
* 408,409,1563..1570 = pseudo-autores "Nuevo/Antiguo Testamento" (y sus traducciones)
|
||
* que NO son personas. Además, abajo se excluye cualquier display_name que contenga
|
||
* "Testament" de forma robusta (por si aparecen nuevos IDs).
|
||
*/
|
||
defined('FEA_AUTORES_EXCLUIR') or define('FEA_AUTORES_EXCLUIR', [
|
||
1, 890, 1049, 1540,
|
||
408, 409, 1563, 1564, 1565, 1566, 1567, 1568, 1569, 1570,
|
||
]);
|
||
|
||
/**
|
||
* Categorías de ESTADO DE CARTA a excluir del selector de categorías:
|
||
* 6 (cartasemana), 21 (cartas-de-otras-semanas), 22 (carta-semana-pasada).
|
||
*/
|
||
defined('FEA_CATS_CARTA_EXCLUIR') or define('FEA_CATS_CARTA_EXCLUIR', [6, 21, 22]);
|
||
|
||
|
||
// ─────────────────────────────────────────────────────────────────
|
||
// i18n mínimo (es / en / fr / it / pt)
|
||
// ─────────────────────────────────────────────────────────────────
|
||
|
||
function fea_adv_t(string $key): string {
|
||
$lang = function_exists('pll_current_language') ? pll_current_language() : 'es';
|
||
$strings = [
|
||
'search_advanced' => ['es' => 'Búsqueda avanzada', 'en' => 'Advanced search',
|
||
'fr' => 'Recherche avancée', 'it' => 'Ricerca avanzata', 'pt' => 'Pesquisa avançada'],
|
||
'word' => ['es' => 'Palabra o frase', 'en' => 'Word or phrase',
|
||
'fr' => 'Mot ou phrase', 'it' => 'Parola o frase', 'pt' => 'Palavra ou frase'],
|
||
'author' => ['es' => 'Autor', 'en' => 'Author',
|
||
'fr' => 'Auteur', 'it' => 'Autore', 'pt' => 'Autor'],
|
||
'all_authors' => ['es' => '— Cualquier autor —', 'en' => '— Any author —',
|
||
'fr' => '— Tout auteur —', 'it' => '— Qualsiasi autore —', 'pt' => '— Qualquer autor —'],
|
||
'topic' => ['es' => 'Categoría', 'en' => 'Category',
|
||
'fr' => 'Catégorie', 'it' => 'Categoria', 'pt' => 'Categoria'],
|
||
'all_topics' => ['es' => '— Cualquier categoría —', 'en' => '— Any category —',
|
||
'fr' => '— Toute catégorie —', 'it' => '— Qualsiasi categoria —', 'pt' => '— Qualquer categoria —'],
|
||
'biblical_ref' => ['es' => 'Cita bíblica', 'en' => 'Biblical reference',
|
||
'fr' => 'Référence biblique', 'it' => 'Citazione biblica', 'pt' => 'Referência bíblica'],
|
||
'biblical_ph' => ['es' => 'Ej: Jn 3', 'en' => 'E.g. Jn 3',
|
||
'fr' => 'Ex: Jn 3', 'it' => 'Es: Gv 3', 'pt' => 'Ex: Jo 3'],
|
||
'date_from' => ['es' => 'Desde', 'en' => 'From',
|
||
'fr' => 'Du', 'it' => 'Dal', 'pt' => 'De'],
|
||
'date_to' => ['es' => 'Hasta', 'en' => 'To',
|
||
'fr' => "Jusqu'au", 'it' => 'Al', 'pt' => 'Até'],
|
||
'search_btn' => ['es' => 'Buscar', 'en' => 'Search',
|
||
'fr' => 'Rechercher', 'it' => 'Cerca', 'pt' => 'Pesquisar'],
|
||
'reset_btn' => ['es' => 'Limpiar', 'en' => 'Clear',
|
||
'fr' => 'Effacer', 'it' => 'Cancella', 'pt' => 'Limpar'],
|
||
'results' => ['es' => 'resultado(s)', 'en' => 'result(s)',
|
||
'fr' => 'résultat(s)', 'it' => 'risultato/i', 'pt' => 'resultado(s)'],
|
||
'no_results' => ['es' => 'Sin resultados. Prueba con otros términos.',
|
||
'en' => 'No results. Try other terms.',
|
||
'fr' => 'Aucun résultat. Essayez d\'autres termes.',
|
||
'it' => 'Nessun risultato. Prova con altri termini.',
|
||
'pt' => 'Sem resultados. Tente outros termos.'],
|
||
'active_filters' => ['es' => 'Filtros activos:', 'en' => 'Active filters:',
|
||
'fr' => 'Filtres actifs:', 'it' => 'Filtri attivi:', 'pt' => 'Filtros ativos:'],
|
||
'filter_author' => ['es' => 'Autor', 'en' => 'Author',
|
||
'fr' => 'Auteur', 'it' => 'Autore', 'pt' => 'Autor'],
|
||
'filter_topic' => ['es' => 'Categoría', 'en' => 'Category',
|
||
'fr' => 'Catégorie', 'it' => 'Categoria', 'pt' => 'Categoria'],
|
||
'filter_cita' => ['es' => 'Cita', 'en' => 'Ref.',
|
||
'fr' => 'Réf.', 'it' => 'Cit.', 'pt' => 'Ref.'],
|
||
'filter_date' => ['es' => 'Fecha', 'en' => 'Date',
|
||
'fr' => 'Date', 'it' => 'Data', 'pt' => 'Data'],
|
||
'by' => ['es' => 'por', 'en' => 'by',
|
||
'fr' => 'par', 'it' => 'di', 'pt' => 'por'],
|
||
];
|
||
$row = $strings[$key] ?? [];
|
||
return $row[$lang] ?? $row['es'] ?? $key;
|
||
}
|
||
|
||
// ─────────────────────────────────────────────────────────────────
|
||
// Query vars
|
||
// ─────────────────────────────────────────────────────────────────
|
||
|
||
add_filter('query_vars', function (array $vars): array {
|
||
$vars[] = 'fea_author';
|
||
$vars[] = 'fea_cat';
|
||
$vars[] = 'fea_cita';
|
||
$vars[] = 'fea_date_from';
|
||
$vars[] = 'fea_date_to';
|
||
return $vars;
|
||
});
|
||
|
||
// ─────────────────────────────────────────────────────────────────
|
||
// pre_get_posts — aplica los filtros avanzados
|
||
// ─────────────────────────────────────────────────────────────────
|
||
|
||
add_action('pre_get_posts', function (WP_Query $q): void {
|
||
if (is_admin() || !$q->is_main_query()) return;
|
||
|
||
// Leer los parámetros avanzados desde $_GET directamente (más fiable en pre_get_posts)
|
||
$fea_author = isset($_GET['fea_author']) ? (int)$_GET['fea_author'] : 0;
|
||
$fea_cat = isset($_GET['fea_cat']) ? (int)$_GET['fea_cat'] : 0;
|
||
$fea_cita = isset($_GET['fea_cita']) ? sanitize_text_field($_GET['fea_cita']) : '';
|
||
$fea_dfr = isset($_GET['fea_date_from']) ? sanitize_text_field($_GET['fea_date_from']) : '';
|
||
$fea_dto = isset($_GET['fea_date_to']) ? sanitize_text_field($_GET['fea_date_to']) : '';
|
||
|
||
$has_adv = ($fea_author > 0 || $fea_cat > 0 || $fea_cita !== '' || $fea_dfr !== '' || $fea_dto !== '');
|
||
$is_search = $q->is_search();
|
||
|
||
// Activar si: es búsqueda, o si hay vars avanzadas (con o sin ?s=)
|
||
if (!$is_search && !$has_adv) return;
|
||
|
||
// Si hay filtros avanzados pero no ?s=, convertimos el query en listado de posts
|
||
// (evitamos que WP muestre la home o una 404)
|
||
if ($has_adv && !$is_search) {
|
||
$q->set('post_type', 'post');
|
||
$q->set('post_status', 'publish');
|
||
// Forzamos is_search para que el template search se active
|
||
$q->is_home = false;
|
||
$q->is_front_page = false;
|
||
$q->is_archive = false;
|
||
$q->is_search = true;
|
||
}
|
||
|
||
// Autor
|
||
if ($fea_author > 0) $q->set('author', $fea_author);
|
||
|
||
// Categoría (tema)
|
||
if ($fea_cat > 0) $q->set('cat', $fea_cat);
|
||
|
||
// Cita bíblica: coincidencia por PREFIJO (el valor empieza por el término, ej. "Jn").
|
||
// Usamos REGEXP '^<term>' con el término escapado para evitar metacaracteres.
|
||
if ($fea_cita !== '') {
|
||
$regex = '^' . preg_quote($fea_cita, '/');
|
||
$q->set('meta_query', [
|
||
[
|
||
'key' => '_cita_evangelio',
|
||
'value' => $regex,
|
||
'compare' => 'REGEXP',
|
||
],
|
||
]);
|
||
}
|
||
|
||
// Fechas: la UI usa <input type="date"> → formato YYYY-MM-DD (fecha completa).
|
||
// Tratamos los límites como fechas exactas, inclusive.
|
||
if ($fea_dfr !== '' || $fea_dto !== '') {
|
||
$date_query = ['inclusive' => true];
|
||
if ($fea_dfr !== '' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $fea_dfr)) {
|
||
[$y, $m, $d] = array_map('intval', explode('-', $fea_dfr));
|
||
$date_query['after'] = ['year' => $y, 'month' => $m, 'day' => $d];
|
||
}
|
||
if ($fea_dto !== '' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $fea_dto)) {
|
||
[$y, $m, $d] = array_map('intval', explode('-', $fea_dto));
|
||
$date_query['before'] = ['year' => $y, 'month' => $m, 'day' => $d];
|
||
}
|
||
// Sólo aplicamos si quedó al menos un límite válido
|
||
if (isset($date_query['after']) || isset($date_query['before'])) {
|
||
$q->set('date_query', [$date_query]);
|
||
}
|
||
}
|
||
});
|
||
|
||
// ─────────────────────────────────────────────────────────────────
|
||
// Helpers: obtener datos del formulario
|
||
// ─────────────────────────────────────────────────────────────────
|
||
|
||
/** Devuelve los autores elegibles (≥30 posts, sin excluidos), cacheado por request. */
|
||
function fea_adv_get_authors(): array {
|
||
static $cache = null;
|
||
if ($cache !== null) return $cache;
|
||
global $wpdb;
|
||
$excl = implode(',', array_map('intval', FEA_AUTORES_EXCLUIR));
|
||
// Excluimos por ID y, de forma robusta, cualquier display_name que contenga "Testament"
|
||
// (Nuevo/Antiguo Testamento, New/Old Testament, Nouveau/Ancien Testament, etc.).
|
||
$cache = $wpdb->get_results("
|
||
SELECT u.ID, u.display_name, COUNT(p.ID) as cnt
|
||
FROM {$wpdb->users} u
|
||
JOIN {$wpdb->posts} p ON p.post_author = u.ID
|
||
WHERE p.post_status = 'publish'
|
||
AND p.post_type = 'post'
|
||
AND u.ID NOT IN ({$excl})
|
||
AND u.display_name NOT LIKE '%Testament%'
|
||
GROUP BY u.ID
|
||
HAVING cnt >= 30
|
||
ORDER BY u.display_name
|
||
");
|
||
return $cache;
|
||
}
|
||
|
||
/**
|
||
* Lista CURADA de categorías-sección reales (term_ids ES, idioma canónico), en orden
|
||
* editorial. Las 153 categorías reales de la BD incluyen categorías-autor y residuales
|
||
* de la migración K2 → desplegable inmanejable; por eso se cura a las secciones del sitio.
|
||
* En idiomas ≠ ES se traduce cada term con Polylang.
|
||
*/
|
||
defined('FEA_CATS_CURADA') or define('FEA_CATS_CURADA', [
|
||
1650, // Artículos
|
||
1647, // Comentarios al evangelio
|
||
1645, // Lecturas bíblicas
|
||
1648, // Eucaristía
|
||
1646, // Comentario editorial
|
||
1649, // Multimedia
|
||
63, // EFFA
|
||
14, // A la fuente cada día
|
||
23, // Cartas que nos llegan
|
||
41, // Noticias de alcance
|
||
24, // Tablón de anuncios
|
||
54, // Canciones religiosas
|
||
45, // Canciones-plegarias
|
||
]);
|
||
|
||
/**
|
||
* Etiqueta bonita en el desplegable (solo ES) para categorías cuyo nombre en BD quedó
|
||
* sin formatear en la migración K2 (no toca el dato del término).
|
||
*/
|
||
defined('FEA_CATS_LABEL') or define('FEA_CATS_LABEL', [
|
||
14 => 'A la fuente cada día', // en BD es "Alafuentecadadia"
|
||
]);
|
||
|
||
/**
|
||
* Devuelve las categorías del selector (lista curada FEA_CATS_CURADA), traducidas al
|
||
* idioma activo (Polylang) y conservando el orden editorial.
|
||
* Devuelve array de objetos {term_id, name} con el term_id DEL IDIOMA ACTUAL.
|
||
*/
|
||
function fea_adv_get_categories(): array {
|
||
static $cache = null;
|
||
if ($cache !== null) return $cache;
|
||
|
||
$lang = function_exists('pll_current_language') ? pll_current_language() : '';
|
||
$default = function_exists('pll_default_language') ? pll_default_language() : 'es';
|
||
|
||
$out = [];
|
||
foreach (FEA_CATS_CURADA as $es_id) {
|
||
$tid = (int) $es_id;
|
||
if ($lang && $lang !== $default && function_exists('pll_get_term')) {
|
||
$tr = pll_get_term($es_id, $lang);
|
||
if ($tr) $tid = (int) $tr;
|
||
}
|
||
$term = get_term($tid, 'category');
|
||
if (!$term || is_wp_error($term)) continue;
|
||
$name = $term->name;
|
||
if ((!$lang || $lang === $default) && isset(FEA_CATS_LABEL[$es_id])) {
|
||
$name = FEA_CATS_LABEL[$es_id];
|
||
}
|
||
$out[] = (object) ['term_id' => (int) $term->term_id, 'name' => $name];
|
||
}
|
||
$cache = $out;
|
||
return $cache;
|
||
}
|
||
|
||
/** URL base del idioma actual (para el action del form). */
|
||
function fea_adv_lang_base(): string {
|
||
$base = home_url('/');
|
||
if (function_exists('pll_current_language')) {
|
||
$lang = pll_current_language();
|
||
$default = function_exists('pll_default_language') ? pll_default_language() : 'es';
|
||
if ($lang && $lang !== $default) $base = home_url('/' . $lang . '/');
|
||
}
|
||
return $base;
|
||
}
|
||
|
||
/** Nombre traducido de una categoría (vía Polylang si está disponible). */
|
||
function fea_adv_cat_name(int $cat_id, string $fallback): string {
|
||
if (function_exists('pll_current_language')) {
|
||
$lang = pll_current_language();
|
||
$default = function_exists('pll_default_language') ? pll_default_language() : 'es';
|
||
if ($lang !== $default) {
|
||
$translated_id = function_exists('pll_get_term') ? pll_get_term($cat_id, $lang) : 0;
|
||
if ($translated_id) {
|
||
$term = get_term($translated_id);
|
||
if ($term && !is_wp_error($term)) return $term->name;
|
||
}
|
||
}
|
||
}
|
||
$term = get_term($cat_id, 'category');
|
||
return ($term && !is_wp_error($term)) ? $term->name : $fallback;
|
||
}
|
||
|
||
// ─────────────────────────────────────────────────────────────────
|
||
// Renderiza el formulario avanzado
|
||
// ─────────────────────────────────────────────────────────────────
|
||
|
||
function fea_adv_form_html(): string {
|
||
$action = esc_url(fea_adv_lang_base());
|
||
$s = esc_attr(get_search_query());
|
||
// Leer de $_GET para fiabilidad (get_query_var puede llegar vacío si la var no estaba registrada aún)
|
||
$sel_aut = isset($_GET['fea_author']) ? (int)$_GET['fea_author'] : 0;
|
||
$sel_cat = isset($_GET['fea_cat']) ? (int)$_GET['fea_cat'] : 0;
|
||
$sel_cit = isset($_GET['fea_cita']) ? esc_attr(sanitize_text_field($_GET['fea_cita'])) : '';
|
||
$sel_dfr = isset($_GET['fea_date_from'])? esc_attr(sanitize_text_field($_GET['fea_date_from'])) : '';
|
||
$sel_dto = isset($_GET['fea_date_to']) ? esc_attr(sanitize_text_field($_GET['fea_date_to'])) : '';
|
||
|
||
$authors = fea_adv_get_authors();
|
||
$cats = fea_adv_get_categories();
|
||
|
||
$t_title = esc_html(fea_adv_t('search_advanced'));
|
||
$t_word = esc_html(fea_adv_t('word'));
|
||
$t_author = esc_html(fea_adv_t('author'));
|
||
$t_allaut = esc_html(fea_adv_t('all_authors'));
|
||
$t_topic = esc_html(fea_adv_t('topic'));
|
||
$t_alltop = esc_html(fea_adv_t('all_topics'));
|
||
$t_cita = esc_html(fea_adv_t('biblical_ref'));
|
||
$t_citaph = esc_attr(fea_adv_t('biblical_ph'));
|
||
$t_dfr = esc_html(fea_adv_t('date_from'));
|
||
$t_dto = esc_html(fea_adv_t('date_to'));
|
||
$t_btn = esc_html(fea_adv_t('search_btn'));
|
||
$t_reset = esc_html(fea_adv_t('reset_btn'));
|
||
|
||
$html = '<div class="fea-adv-wrap" id="fea-adv-search">';
|
||
$html .= '<details class="fea-adv-details" open>';
|
||
$html .= '<summary class="fea-adv-summary">' . $t_title . '</summary>';
|
||
$html .= '<form class="fea-adv-form" method="get" action="' . $action . '">';
|
||
|
||
// Fila 1: Palabra
|
||
$html .= '<div class="fea-adv-row">';
|
||
$html .= '<label class="fea-adv-label" for="fea-s">' . $t_word . '</label>';
|
||
$html .= '<input class="fea-adv-input" id="fea-s" type="search" name="s" value="' . $s . '" autocomplete="off">';
|
||
$html .= '</div>';
|
||
|
||
// Fila 2: Autor
|
||
$html .= '<div class="fea-adv-row">';
|
||
$html .= '<label class="fea-adv-label" for="fea-author">' . $t_author . '</label>';
|
||
$html .= '<select class="fea-adv-select" id="fea-author" name="fea_author">';
|
||
$html .= '<option value="">' . $t_allaut . '</option>';
|
||
foreach ($authors as $a) {
|
||
$sel = selected($sel_aut, (int)$a->ID, false);
|
||
$name = esc_html($a->display_name);
|
||
$html .= "<option value=\"{$a->ID}\"{$sel}>{$name}</option>";
|
||
}
|
||
$html .= '</select></div>';
|
||
|
||
// Fila 3: Categoría (real, dinámica)
|
||
$html .= '<div class="fea-adv-row">';
|
||
$html .= '<label class="fea-adv-label" for="fea-cat">' . $t_topic . '</label>';
|
||
$html .= '<select class="fea-adv-select" id="fea-cat" name="fea_cat">';
|
||
$html .= '<option value="">' . $t_alltop . '</option>';
|
||
foreach ($cats as $c) {
|
||
$cat_name = esc_html($c->name);
|
||
$sel = selected($sel_cat, $c->term_id, false);
|
||
$html .= "<option value=\"{$c->term_id}\"{$sel}>{$cat_name}</option>";
|
||
}
|
||
$html .= '</select></div>';
|
||
|
||
// Fila 4: Cita bíblica
|
||
$html .= '<div class="fea-adv-row">';
|
||
$html .= '<label class="fea-adv-label" for="fea-cita">' . $t_cita . '</label>';
|
||
$html .= '<input class="fea-adv-input" id="fea-cita" type="text" name="fea_cita" value="' . $sel_cit . '" placeholder="' . $t_citaph . '">';
|
||
$html .= '</div>';
|
||
|
||
// Fila 5: Fechas
|
||
$html .= '<div class="fea-adv-row fea-adv-dates">';
|
||
$html .= '<span class="fea-adv-label">' . $t_dfr . '</span>';
|
||
$html .= '<input class="fea-adv-input fea-adv-date" type="date" name="fea_date_from" value="' . $sel_dfr . '">';
|
||
$html .= '<span class="fea-adv-label fea-adv-to">' . $t_dto . '</span>';
|
||
$html .= '<input class="fea-adv-input fea-adv-date" type="date" name="fea_date_to" value="' . $sel_dto . '">';
|
||
$html .= '</div>';
|
||
|
||
// Botones
|
||
$html .= '<div class="fea-adv-actions">';
|
||
$html .= '<button class="fea-adv-btn fea-adv-btn-primary" type="submit">' . $t_btn . '</button>';
|
||
$html .= '<a class="fea-adv-btn fea-adv-btn-secondary" href="' . $action . '">' . $t_reset . '</a>';
|
||
$html .= '</div>';
|
||
|
||
$html .= '</form></details></div>';
|
||
return $html;
|
||
}
|
||
|
||
// ─────────────────────────────────────────────────────────────────
|
||
// Chips de filtros activos + contador de resultados
|
||
// ─────────────────────────────────────────────────────────────────
|
||
|
||
function fea_adv_chips_html(): string {
|
||
$chips = [];
|
||
|
||
$aut_id = isset($_GET['fea_author']) ? (int)$_GET['fea_author'] : 0;
|
||
if ($aut_id > 0) {
|
||
$udata = get_userdata($aut_id);
|
||
$name = $udata ? esc_html($udata->display_name) : $aut_id;
|
||
$chips[] = fea_adv_chip(fea_adv_t('filter_author') . ': ' . $name, 'fea_author');
|
||
}
|
||
|
||
$cat_id = isset($_GET['fea_cat']) ? (int)$_GET['fea_cat'] : 0;
|
||
if ($cat_id > 0) {
|
||
$term = get_term($cat_id, 'category');
|
||
$name = ($term && !is_wp_error($term)) ? esc_html($term->name) : $cat_id;
|
||
$chips[] = fea_adv_chip(fea_adv_t('filter_topic') . ': ' . $name, 'fea_cat');
|
||
}
|
||
|
||
$cita = isset($_GET['fea_cita']) ? sanitize_text_field($_GET['fea_cita']) : '';
|
||
if ($cita !== '') {
|
||
$chips[] = fea_adv_chip(fea_adv_t('filter_cita') . ': ' . esc_html($cita), 'fea_cita');
|
||
}
|
||
|
||
$dfr = isset($_GET['fea_date_from']) ? sanitize_text_field($_GET['fea_date_from']) : '';
|
||
$dto = isset($_GET['fea_date_to']) ? sanitize_text_field($_GET['fea_date_to']) : '';
|
||
if ($dfr !== '' || $dto !== '') {
|
||
$label = fea_adv_t('filter_date') . ': ' . ($dfr ?: '?') . ' – ' . ($dto ?: '?');
|
||
$chips[] = fea_adv_chip(esc_html($label), 'fea_date_from', 'fea_date_to');
|
||
}
|
||
|
||
if (empty($chips)) return '';
|
||
return '<div class="fea-adv-chips"><span class="fea-adv-chips-label">' .
|
||
esc_html(fea_adv_t('active_filters')) . '</span>' . implode('', $chips) . '</div>';
|
||
}
|
||
|
||
/** Genera un chip con botón ✕ que elimina el filtro de la URL. */
|
||
function fea_adv_chip(string $label, string ...$remove_params): string {
|
||
$url = remove_query_arg($remove_params);
|
||
return '<span class="fea-adv-chip">' . $label .
|
||
' <a href="' . esc_url($url) . '" class="fea-adv-chip-x" aria-label="Eliminar filtro">×</a></span>';
|
||
}
|
||
|
||
// ─────────────────────────────────────────────────────────────────
|
||
// Inyección en la página de resultados (template search)
|
||
// ─────────────────────────────────────────────────────────────────
|
||
|
||
/**
|
||
* Inyecta el formulario avanzado + chips antes del primer bloque wp:query-title
|
||
* del template de búsqueda, modificando el HTML renderizado del bloque principal.
|
||
*/
|
||
add_filter('render_block', function (string $html, array $block): string {
|
||
if (is_admin()) return $html;
|
||
|
||
// Inyectar en búsquedas y cuando hay filtros avanzados activos
|
||
$has_adv_get = !empty($_GET['fea_author']) || !empty($_GET['fea_cat']) ||
|
||
!empty($_GET['fea_cita']) || !empty($_GET['fea_date_from']) || !empty($_GET['fea_date_to']);
|
||
|
||
if (!is_search() && !is_page('buscar') && !$has_adv_get) return $html;
|
||
|
||
if (($block['blockName'] ?? '') !== 'core/query-title') return $html;
|
||
|
||
$form = fea_adv_form_html();
|
||
$chips = fea_adv_chips_html();
|
||
|
||
// Contador de resultados (sólo cuando hay consulta activa)
|
||
$counter = '';
|
||
if (is_search() || $has_adv_get) {
|
||
global $wp_query;
|
||
if ($wp_query && $wp_query->found_posts !== null) {
|
||
$n = (int) $wp_query->found_posts;
|
||
$counter = '<div class="fea-adv-count">' . $n . ' ' . esc_html(fea_adv_t('results')) . '</div>';
|
||
}
|
||
}
|
||
|
||
return $form . $chips . $counter . $html;
|
||
}, 10, 2);
|
||
|
||
/**
|
||
* Añade byline (autor) en cada tarjeta fea-archive-card dentro del template search.
|
||
* Lo hacemos inyectando tras wp:post-date en el contexto correcto.
|
||
*/
|
||
add_filter('render_block', function (string $html, array $block): string {
|
||
if (is_admin()) return $html;
|
||
$has_adv_get2 = !empty($_GET['fea_author']) || !empty($_GET['fea_cat']) ||
|
||
!empty($_GET['fea_cita']) || !empty($_GET['fea_date_from']) || !empty($_GET['fea_date_to']);
|
||
if (!is_search() && !is_page('buscar') && !$has_adv_get2) return $html;
|
||
if (($block['blockName'] ?? '') !== 'core/post-date') return $html;
|
||
|
||
$post_id = $block['attrs']['postId'] ?? (in_the_loop() ? get_the_ID() : 0);
|
||
if (!$post_id) $post_id = get_the_ID();
|
||
if (!$post_id) return $html;
|
||
|
||
$author_id = (int) get_post_field('post_author', $post_id);
|
||
$author_name = get_the_author_meta('display_name', $author_id);
|
||
if (!$author_name) return $html;
|
||
|
||
$author_url = get_author_posts_url($author_id);
|
||
$byline = '<div class="fea-adv-byline">' . esc_html(fea_adv_t('by')) . ' ' .
|
||
'<a href="' . esc_url($author_url) . '">' . esc_html($author_name) . '</a></div>';
|
||
|
||
return $html . $byline;
|
||
}, 10, 2);
|
||
|
||
// ─────────────────────────────────────────────────────────────────
|
||
// Enlace «Búsqueda avanzada» desde la barra fea-search
|
||
// ─────────────────────────────────────────────────────────────────
|
||
|
||
add_filter('render_block', function (string $html, array $block): string {
|
||
if (is_admin()) return $html;
|
||
if (($block['blockName'] ?? '') !== 'core/template-part') return $html;
|
||
$slug = $block['attrs']['slug'] ?? '';
|
||
if (!in_array($slug, ['header', 'cabecera-portada'], true)) return $html;
|
||
|
||
// Sólo inyectamos el enlace si ya hay una barra de búsqueda (.fea-search-bar)
|
||
// Buscamos la barra y le añadimos el enlace de búsqueda avanzada.
|
||
if (strpos($html, 'fea-search-bar') === false) return $html;
|
||
|
||
$adv_url = home_url('/buscar/');
|
||
if (function_exists('pll_current_language')) {
|
||
$lang = pll_current_language();
|
||
$default = function_exists('pll_default_language') ? pll_default_language() : 'es';
|
||
if ($lang && $lang !== $default) {
|
||
// Intenta obtener la página /buscar traducida
|
||
$page = get_page_by_path('buscar');
|
||
if ($page) {
|
||
$tl = function_exists('pll_get_post') ? pll_get_post($page->ID, $lang) : 0;
|
||
if ($tl) $adv_url = get_permalink($tl);
|
||
}
|
||
}
|
||
}
|
||
|
||
$label = esc_html(fea_adv_t('search_advanced'));
|
||
$link = '<div class="fea-adv-link-wrap"><a class="fea-adv-link" href="' . esc_url($adv_url) . '">' . $label . '</a></div>';
|
||
|
||
// Insertamos el enlace justo al final del bloque .fea-search-bar (cerrando el div externo)
|
||
// fea-search.php genera: <div class="fea-search-bar"><form ...>...</form></div>
|
||
// Reemplazamos la ÚLTIMA ocurrencia del cierre del div de .fea-search-bar
|
||
$marker = '</div>';
|
||
$pos = strpos($html, 'fea-search-bar');
|
||
if ($pos !== false) {
|
||
// Buscamos el </div> que cierra .fea-search-bar (el wrapper externo)
|
||
// La estructura es: <div class="fea-search-bar"><form>...</form></div>
|
||
// Hay dos </div>: uno cierra el form y otro cierra .fea-search-bar
|
||
// Usamos una sustitución segura: buscamos el patrón exacto del cierre
|
||
$html = preg_replace('#(</form></div>)#', '$1' . $link, $html, 1);
|
||
}
|
||
return $html;
|
||
}, 25, 2);
|
||
|
||
// ─────────────────────────────────────────────────────────────────
|
||
// Página /buscar — inyectar formulario vía the_content
|
||
// ─────────────────────────────────────────────────────────────────
|
||
|
||
add_filter('the_content', function (string $content): string {
|
||
if (!is_page('buscar')) return $content;
|
||
// Envoltura: título + formulario + contenido original de la página
|
||
$form = fea_adv_form_html();
|
||
return $form . '<div class="fea-buscar-intro">' . $content . '</div>';
|
||
});
|
||
|
||
// Nota: la página /buscar se crea con scripts/create_buscar_page.php (ya ejecutado).
|
||
// El formulario se inyecta en the_content (hook arriba) y vía render_block en search.
|
||
|
||
// ─────────────────────────────────────────────────────────────────
|
||
// CSS
|
||
// ─────────────────────────────────────────────────────────────────
|
||
|
||
add_action('wp_head', function (): void {
|
||
if (!is_search() && !is_page('buscar') &&
|
||
empty($_GET['fea_author']) && empty($_GET['fea_cat']) &&
|
||
empty($_GET['fea_cita']) && empty($_GET['fea_date_from']) && empty($_GET['fea_date_to'])) return;
|
||
?>
|
||
<style>
|
||
/* ── Formulario buscador avanzado ─────────────────────────────── */
|
||
.fea-adv-wrap{max-width:860px;margin:0 auto 1.5rem;padding:0 1rem}
|
||
|
||
.fea-adv-details{background:#faf6f7;border:1px solid #e8d5da;border-radius:8px;overflow:hidden}
|
||
.fea-adv-summary{
|
||
padding:.75rem 1.2rem;font-weight:600;font-size:1rem;color:#8b1a2e;
|
||
cursor:pointer;list-style:none;display:flex;align-items:center;gap:.5rem;
|
||
background:#fff0f2;border-bottom:1px solid #e8d5da;
|
||
}
|
||
.fea-adv-summary::-webkit-details-marker{display:none}
|
||
.fea-adv-summary::before{content:"▸";transition:transform .2s}
|
||
details[open] .fea-adv-summary::before{transform:rotate(90deg)}
|
||
|
||
.fea-adv-form{display:grid;grid-template-columns:1fr 1fr;gap:.75rem 1.2rem;padding:1rem 1.2rem}
|
||
@media(max-width:600px){.fea-adv-form{grid-template-columns:1fr}}
|
||
|
||
/* min-width:0 evita que el contenido fuerce a la celda del grid a desbordar */
|
||
.fea-adv-row{display:flex;flex-direction:column;gap:.25rem;min-width:0}
|
||
.fea-adv-dates{grid-column:1/-1;flex-direction:row;align-items:center;flex-wrap:wrap;gap:.5rem}
|
||
.fea-adv-dates .fea-adv-label{white-space:nowrap}
|
||
|
||
.fea-adv-label{font-size:.8rem;font-weight:600;color:#5a3a40;text-transform:uppercase;letter-spacing:.04em}
|
||
.fea-adv-to{margin-left:.5rem}
|
||
|
||
.fea-adv-input,.fea-adv-select{
|
||
box-sizing:border-box;border:1px solid #d9c4c9;border-radius:6px;padding:.5rem .75rem;
|
||
font-size:.95rem;background:#fff;color:#222;width:100%;max-width:100%;
|
||
transition:border-color .15s;
|
||
}
|
||
.fea-adv-input:focus,.fea-adv-select:focus{border-color:#8b1a2e;outline:0;box-shadow:0 0 0 2px #8b1a2e33}
|
||
.fea-adv-date{box-sizing:border-box;width:auto;min-width:150px;flex:0 0 auto}
|
||
|
||
.fea-adv-actions{grid-column:1/-1;display:flex;gap:.75rem;align-items:center;margin-top:.25rem}
|
||
.fea-adv-btn{padding:.55rem 1.4rem;border-radius:999px;font-size:.95rem;font-weight:600;cursor:pointer;text-decoration:none;border:2px solid transparent}
|
||
.fea-adv-btn-primary{background:#8b1a2e;color:#fff;border-color:#8b1a2e}
|
||
.fea-adv-btn-primary:hover{background:#6f1525;border-color:#6f1525}
|
||
.fea-adv-btn-secondary{background:transparent;color:#8b1a2e;border-color:#8b1a2e}
|
||
.fea-adv-btn-secondary:hover{background:#8b1a2e;color:#fff}
|
||
|
||
/* ── Contador y chips ─────────────────────────────────────────── */
|
||
.fea-adv-count{max-width:860px;margin:.5rem auto .25rem;padding:0 1rem;
|
||
font-size:.9rem;color:#666}
|
||
|
||
.fea-adv-chips{max-width:860px;margin:.5rem auto;padding:0 1rem;
|
||
display:flex;flex-wrap:wrap;gap:.4rem;align-items:center}
|
||
.fea-adv-chips-label{font-size:.8rem;color:#5a3a40;font-weight:600;margin-right:.25rem}
|
||
.fea-adv-chip{display:inline-flex;align-items:center;gap:.35rem;background:#f0e2e5;
|
||
border:1px solid #d9c4c9;border-radius:999px;padding:.2rem .75rem;font-size:.82rem;color:#5a3a40}
|
||
.fea-adv-chip-x{color:#8b1a2e;text-decoration:none;font-weight:700;font-size:1rem;line-height:1}
|
||
.fea-adv-chip-x:hover{color:#6f1525}
|
||
|
||
/* ── Byline en tarjetas de resultado ──────────────────────────── */
|
||
.fea-archive-card .fea-adv-byline{font-size:.78rem;color:#7a5a62;margin-top:.1rem}
|
||
.fea-archive-card .fea-adv-byline a{color:#8b1a2e;text-decoration:none}
|
||
.fea-archive-card .fea-adv-byline a:hover{text-decoration:underline}
|
||
|
||
/* ── Enlace «Búsqueda avanzada» en barra header ───────────────── */
|
||
.fea-adv-link-wrap{display:none;justify-content:center;padding:.3rem 1rem .4rem;
|
||
background:#faf6f7;border-bottom:1px solid #efe2e5}
|
||
@media(max-width:600px){.fea-adv-link-wrap{display:flex}}
|
||
.fea-adv-link{font-size:.8rem;color:#8b1a2e;text-decoration:none;font-weight:500}
|
||
.fea-adv-link:hover{text-decoration:underline}
|
||
</style>
|
||
<?php
|
||
}, 10);
|
||
|
||
// CSS del enlace «Búsqueda avanzada» en header (se muestra en todas las páginas)
|
||
add_action('wp_head', function (): void {
|
||
?>
|
||
<style>
|
||
.fea-adv-link-wrap{display:none;justify-content:center;padding:.3rem 1rem .4rem;
|
||
background:#faf6f7;border-bottom:1px solid #efe2e5}
|
||
@media(max-width:600px){.fea-adv-link-wrap{display:flex}}
|
||
.fea-adv-link{font-size:.8rem;color:#8b1a2e;text-decoration:none;font-weight:500}
|
||
.fea-adv-link:hover{text-decoration:underline}
|
||
</style>
|
||
<?php
|
||
}, 15);
|