278 lines
12 KiB
PHP
278 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* fea-recopilatorios — Listados dinámicos auto-actualizables (issues #96-#118).
|
|
*
|
|
* Sustituye las páginas-recopilatorio MANUALES de Joomla (tablas/listas de
|
|
* enlaces mantenidas a mano) por un listado generado desde una categoría.
|
|
* Así, cada carta/post nuevo que entre en la categoría aparece solo, sin
|
|
* copiar y pegar.
|
|
*
|
|
* Uso:
|
|
* [fea_recopilatorio cat="1648"] (por term_id)
|
|
* [fea_recopilatorio cat="eucaristia"] (por slug)
|
|
* [fea_recopilatorio cat="1648" per_page="150" group="year" order="desc"]
|
|
*
|
|
* - group="year" (def.): separadores por año. group="none": lista plana.
|
|
* - Paginación propia (?recop=N) para no chocar con la paginación del tema.
|
|
* - Títulos normalizados con fea_title() si existe (legacy en MAYÚSCULAS).
|
|
*/
|
|
|
|
if (!defined('FEA_RECOP_DEFAULT_PER_PAGE')) {
|
|
define('FEA_RECOP_DEFAULT_PER_PAGE', 200);
|
|
}
|
|
|
|
function fea_recop_resolve_term($cat): int {
|
|
$cat = trim((string) $cat);
|
|
if ($cat === '') return 0;
|
|
if (ctype_digit($cat)) return (int) $cat;
|
|
$t = get_term_by('slug', $cat, 'category');
|
|
return $t ? (int) $t->term_id : 0;
|
|
}
|
|
|
|
function fea_recop_title(string $raw): string {
|
|
return function_exists('fea_title') ? fea_title($raw) : $raw;
|
|
}
|
|
|
|
function fea_recop_render(array $atts = []): string {
|
|
$atts = shortcode_atts([
|
|
'cat' => '',
|
|
'per_page' => (string) FEA_RECOP_DEFAULT_PER_PAGE,
|
|
'group' => 'year',
|
|
'order' => 'desc',
|
|
], $atts, 'fea_recopilatorio');
|
|
|
|
$term_id = fea_recop_resolve_term($atts['cat']);
|
|
if (!$term_id) return '<p class="fea-recop-empty">Recopilatorio no disponible.</p>';
|
|
|
|
$per_page = max(20, min(500, (int) $atts['per_page']));
|
|
$order = strtolower($atts['order']) === 'asc' ? 'ASC' : 'DESC';
|
|
$paged = isset($_GET['recop']) ? max(1, (int) $_GET['recop']) : 1;
|
|
|
|
$q = new WP_Query([
|
|
'post_type' => 'post',
|
|
'post_status' => 'publish',
|
|
'cat' => $term_id,
|
|
'posts_per_page' => $per_page,
|
|
'paged' => $paged,
|
|
'orderby' => 'date',
|
|
'order' => $order,
|
|
'ignore_sticky_posts' => true,
|
|
'no_found_rows' => false,
|
|
]);
|
|
|
|
if (!$q->have_posts()) {
|
|
wp_reset_postdata();
|
|
return '<p class="fea-recop-empty">Todavía no hay entradas en esta sección.</p>';
|
|
}
|
|
|
|
$by_year = ($atts['group'] === 'year');
|
|
$html = '<div class="fea-recop">';
|
|
$cur_year = null;
|
|
$open = false;
|
|
|
|
while ($q->have_posts()) {
|
|
$q->the_post();
|
|
if ($by_year) {
|
|
$y = get_the_date('Y');
|
|
if ($y !== $cur_year) {
|
|
if ($open) $html .= '</ul>';
|
|
$html .= '<h3 class="fea-recop-year">' . esc_html($y) . '</h3><ul class="fea-recop-list">';
|
|
$cur_year = $y; $open = true;
|
|
}
|
|
} elseif (!$open) {
|
|
$html .= '<ul class="fea-recop-list">'; $open = true;
|
|
}
|
|
$title = fea_recop_title(get_the_title());
|
|
$html .= '<li><a href="' . esc_url(get_permalink()) . '">' . esc_html($title) . '</a>'
|
|
. ' <span class="fea-recop-date">' . esc_html(get_the_date('j M Y')) . '</span></li>';
|
|
}
|
|
if ($open) $html .= '</ul>';
|
|
wp_reset_postdata();
|
|
|
|
// Paginación propia
|
|
$total_pages = (int) $q->max_num_pages;
|
|
if ($total_pages > 1) {
|
|
$html .= '<nav class="fea-recop-pages" aria-label="Paginación del recopilatorio">';
|
|
if ($paged > 1) {
|
|
$html .= '<a href="' . esc_url(add_query_arg('recop', $paged - 1)) . '">Anterior</a>';
|
|
}
|
|
$html .= '<span>Página ' . $paged . ' de ' . $total_pages . '</span>';
|
|
if ($paged < $total_pages) {
|
|
$html .= '<a href="' . esc_url(add_query_arg('recop', $paged + 1)) . '">Siguiente</a>';
|
|
}
|
|
$html .= '</nav>';
|
|
}
|
|
$html .= '</div>';
|
|
return $html;
|
|
}
|
|
add_shortcode('fea_recopilatorio', 'fea_recop_render');
|
|
|
|
// ── [fea_multimedia_indice] — galería visual de multimedia (issue #110) ──────
|
|
// Sustituye la página intermedia /multimedia/ (4 enlaces) por la lista directa
|
|
// de los artículos de las categorías multimedia, con preview visual (miniatura
|
|
// de YouTube o primera imagen del contenido) + extracto, para invitar al clic.
|
|
|
|
/** Extrae una preview del contenido: ['type'=>'video'|'image'|'none','src'=>url]. */
|
|
function fea_mm_preview(string $content): array {
|
|
// 1) Vídeo de YouTube embebido → miniatura hqdefault
|
|
if (preg_match('~(?:youtube(?:-nocookie)?\.com/(?:embed/|watch\?v=)|youtu\.be/)([A-Za-z0-9_-]{6,})~', $content, $m)) {
|
|
return ['type' => 'video', 'src' => 'https://img.youtube.com/vi/' . $m[1] . '/hqdefault.jpg'];
|
|
}
|
|
// 2) Vimeo → sin thumbnail server-side fiable; marcar como vídeo sin src
|
|
if (preg_match('~vimeo\.com/(?:video/)?(\d+)~', $content)) {
|
|
return ['type' => 'video', 'src' => ''];
|
|
}
|
|
// 3) Primera imagen del contenido
|
|
if (preg_match('~<img[^>]+src=["\']([^"\']+)["\']~i', $content, $m)) {
|
|
return ['type' => 'image', 'src' => $m[1]];
|
|
}
|
|
return ['type' => 'none', 'src' => ''];
|
|
}
|
|
|
|
function fea_mm_indice_render(array $atts = []): string {
|
|
$atts = shortcode_atts([
|
|
'cats' => '1649,26', // Multimedia + Índice multimedia
|
|
'per_page' => '24',
|
|
], $atts, 'fea_multimedia_indice');
|
|
|
|
$cats = array_filter(array_map('intval', explode(',', $atts['cats'])));
|
|
if (!$cats) return '';
|
|
$per_page = max(6, min(60, (int) $atts['per_page']));
|
|
$paged = isset($_GET['mmpag']) ? max(1, (int) $_GET['mmpag']) : 1;
|
|
|
|
$q = new WP_Query([
|
|
'post_type' => 'post',
|
|
'post_status' => 'publish',
|
|
'category__in' => $cats,
|
|
'posts_per_page' => $per_page,
|
|
'paged' => $paged,
|
|
'orderby' => 'date',
|
|
'order' => 'DESC',
|
|
'ignore_sticky_posts' => true,
|
|
]);
|
|
|
|
if (!$q->have_posts()) {
|
|
wp_reset_postdata();
|
|
return '<p class="fea-recop-empty">Todavía no hay multimedia disponible.</p>';
|
|
}
|
|
|
|
$html = '<div class="fea-mm-wrap"><div class="fea-mm-grid">';
|
|
while ($q->have_posts()) {
|
|
$q->the_post();
|
|
$content = get_the_content();
|
|
$prev = fea_mm_preview($content);
|
|
$title = fea_recop_title(get_the_title());
|
|
$url = get_permalink();
|
|
$excerpt = wp_trim_words(trim(preg_replace('/\s+/', ' ', wp_strip_all_tags($content))), 22, '…');
|
|
|
|
$thumb = '';
|
|
if ($prev['src'] !== '') {
|
|
$thumb = '<img class="fea-mm-img" src="' . esc_url($prev['src']) . '" alt="" loading="lazy" '
|
|
. 'onerror="this.style.display=\'none\';this.parentNode.classList.add(\'fea-mm-noimg\');">';
|
|
}
|
|
$cls = 'fea-mm-thumb' . ($prev['src'] === '' ? ' fea-mm-noimg' : '');
|
|
$play = $prev['type'] === 'video'
|
|
? '<span class="fea-mm-play" aria-hidden="true"></span>' : '';
|
|
|
|
$html .= '<a class="fea-mm-card" href="' . esc_url($url) . '">'
|
|
. '<span class="' . $cls . '">' . $thumb . $play . '</span>'
|
|
. '<span class="fea-mm-body">'
|
|
. '<span class="fea-mm-title">' . esc_html($title) . '</span>'
|
|
. '<span class="fea-mm-date">' . esc_html(get_the_date('j M Y')) . '</span>'
|
|
. '<span class="fea-mm-excerpt">' . esc_html($excerpt) . '</span>'
|
|
. '</span></a>';
|
|
}
|
|
$html .= '</div>';
|
|
|
|
$total_pages = (int) $q->max_num_pages;
|
|
wp_reset_postdata();
|
|
if ($total_pages > 1) {
|
|
$html .= '<nav class="fea-recop-pages" aria-label="Paginación de multimedia">';
|
|
if ($paged > 1) $html .= '<a href="' . esc_url(add_query_arg('mmpag', $paged - 1)) . '">Anterior</a>';
|
|
$html .= '<span>Página ' . $paged . ' de ' . $total_pages . '</span>';
|
|
if ($paged < $total_pages) $html .= '<a href="' . esc_url(add_query_arg('mmpag', $paged + 1)) . '">Siguiente</a>';
|
|
$html .= '</nav>';
|
|
}
|
|
$html .= '</div>'; // .fea-mm-wrap
|
|
return $html;
|
|
}
|
|
add_shortcode('fea_multimedia_indice', 'fea_mm_indice_render');
|
|
|
|
add_action('wp_head', function () {
|
|
if (is_admin()) return;
|
|
?>
|
|
<style id="fea-recop-css">
|
|
.fea-recop { margin: 1.5rem 0; }
|
|
.fea-recop-year {
|
|
font-family: 'Fraunces', Georgia, serif; font-weight: 600;
|
|
color: #8b1a2e; margin: 1.6rem 0 0.6rem; font-size: 1.3rem;
|
|
border-bottom: 1px solid #efe7d8; padding-bottom: 0.25rem;
|
|
}
|
|
.fea-recop-list { list-style: none; margin: 0; padding: 0; }
|
|
.fea-recop-list li {
|
|
padding: 0.35rem 0; border-bottom: 1px solid #f4eee2;
|
|
display: flex; justify-content: space-between; gap: 1rem; align-items: baseline;
|
|
}
|
|
.fea-recop-list a { text-decoration: none; color: #2a2320; }
|
|
.fea-recop-list a:hover { color: #8b1a2e; text-decoration: underline; }
|
|
.fea-recop-date { color: #998; font-size: 0.82rem; white-space: nowrap; }
|
|
.fea-recop-pages {
|
|
display: flex; gap: 1rem; align-items: center; justify-content: center;
|
|
margin-top: 1.4rem; font-size: 0.95rem;
|
|
}
|
|
.fea-recop-pages a {
|
|
padding: 0.4rem 0.8rem; border: 1px solid #8b1a2e; border-radius: 6px;
|
|
text-decoration: none; color: #8b1a2e;
|
|
}
|
|
/* Galería multimedia (#110) */
|
|
/* wrapper: el padre es entry-content alignfull (ancho completo), así que basta
|
|
centrar con margin:auto; max-width:none vence el cap de is-layout-constrained */
|
|
.fea-mm-wrap {
|
|
width: min(1180px, 100%);
|
|
max-width: none;
|
|
margin: 1.5rem auto 2rem;
|
|
}
|
|
.fea-mm-grid {
|
|
display: grid; gap: 1.3rem;
|
|
grid-template-columns: 1fr;
|
|
}
|
|
@media (min-width: 520px) { .fea-mm-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
|
|
@media (min-width: 760px) { .fea-mm-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
|
|
@media (max-width: 700px) { .fea-mm-wrap { width: min(100%, calc(100vw - 1rem)); } }
|
|
.fea-mm-card {
|
|
display: flex; flex-direction: column; text-decoration: none;
|
|
background: #fff; border: 1px solid #efe7d8; border-radius: 10px;
|
|
overflow: hidden; transition: box-shadow .15s, transform .15s;
|
|
}
|
|
.fea-mm-card:hover { box-shadow: 0 6px 18px rgba(139,26,46,.13); transform: translateY(-2px); }
|
|
.fea-mm-thumb {
|
|
position: relative; display: block; aspect-ratio: 16/9; background: #f4eee2;
|
|
overflow: hidden;
|
|
}
|
|
.fea-mm-img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
|
.fea-mm-noimg {
|
|
background: linear-gradient(135deg, #8b1a2e 0%, #b34255 100%);
|
|
}
|
|
.fea-mm-play {
|
|
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
|
|
width: 54px; height: 54px; border-radius: 50%;
|
|
background: rgba(0,0,0,.55); pointer-events: none;
|
|
}
|
|
.fea-mm-play::after {
|
|
content: ''; position: absolute; top: 50%; left: 54%; transform: translate(-50%, -50%);
|
|
border-style: solid; border-width: 11px 0 11px 18px;
|
|
border-color: transparent transparent transparent #fff;
|
|
}
|
|
.fea-mm-card:hover .fea-mm-play { background: rgba(139,26,46,.85); }
|
|
.fea-mm-body { padding: 0.8rem 0.9rem 1rem; display: flex; flex-direction: column; gap: 0.3rem; }
|
|
.fea-mm-title {
|
|
font-family: 'Fraunces', Georgia, serif; font-weight: 600; color: #2a2320;
|
|
font-size: 1.02rem; line-height: 1.25;
|
|
}
|
|
.fea-mm-card:hover .fea-mm-title { color: #8b1a2e; }
|
|
.fea-mm-date { color: #998; font-size: 0.78rem; }
|
|
.fea-mm-excerpt { color: #5a534e; font-size: 0.85rem; line-height: 1.4; margin-top: 0.15rem; }
|
|
</style>
|
|
<?php
|
|
}, 26);
|