Files
feadulta/mu-plugins/fea-pensamientos.php
T

454 lines
15 KiB
PHP

<?php
/**
* fea-pensamientos — Galerías Joomla y pausa aleatoria en artículos.
*
* Reutiliza /images de Joomla sin duplicar ficheros en WordPress.
*/
if (!defined('FEA_JOOMLA_IMAGES_DIR')) {
define('FEA_JOOMLA_IMAGES_DIR', file_exists('/web/images') ? '/web/images' : '/var/www/joomla-images');
}
if (!defined('FEA_JOOMLA_IMAGES_URL')) {
$fea_is_prod = (defined('ABSPATH') && strpos((string) ABSPATH, '/web/wp-nuevo/') === 0)
|| (isset($_SERVER['HTTP_HOST']) && preg_match('/(^|\.)feadulta\.com$/', (string) $_SERVER['HTTP_HOST']))
|| file_exists('/web/images');
define(
'FEA_JOOMLA_IMAGES_URL',
$fea_is_prod ? 'https://www.feadulta.com/images' : 'https://farmer.taild3aaf6.ts.net/joomla/images'
);
}
if (!defined('FEA_PENS_DIR')) {
define('FEA_PENS_DIR', rtrim(FEA_JOOMLA_IMAGES_DIR, '/') . '/Pensamientos');
}
if (!defined('FEA_PENS_URL')) {
define('FEA_PENS_URL', rtrim(FEA_JOOMLA_IMAGES_URL, '/') . '/Pensamientos');
}
if (!defined('FEA_GALLERY_PER_PAGE')) {
define('FEA_GALLERY_PER_PAGE', 72);
}
if (!defined('FEA_RANDOM_THOUGHT_EXCLUDED_CATS')) {
// Categorías que NO muestran pensamiento aleatorio:
// 1645 Lecturas bíblicas · 28 Evangelios y comentarios (textos del evangelio)
// 20 Presentación colaboradores (fichas de colaboradores)
// 1647 Comentarios al evangelio SÍ muestra pensamiento (decisión Rafa 2026-06-19).
define('FEA_RANDOM_THOUGHT_EXCLUDED_CATS', '1645,28,20');
}
if (!defined('FEA_RANDOM_THOUGHT_EXCLUDED_IDS')) {
// Posts estructurales (páginas disfrazadas de post) que no deben llevar pensamiento.
// 17563 = índice /colaboradores/ (está en «Sin categoría», no lo cubre la cat 20).
define('FEA_RANDOM_THOUGHT_EXCLUDED_IDS', '17563');
}
if (!defined('FEA_GALLERY_MANIFEST')) {
define('FEA_GALLERY_MANIFEST', WP_CONTENT_DIR . '/uploads/fea-gallery-manifest.json');
}
function fea_gallery_safe_dir(string $dir): string {
$dir = trim($dir);
$dir = trim($dir, "/\\ \t\n\r\0\x0B");
return preg_replace('/[^A-Za-z0-9._-]/', '', $dir);
}
function fea_gallery_base_dir(): string {
return rtrim(FEA_JOOMLA_IMAGES_DIR, '/');
}
function fea_gallery_base_url(): string {
return rtrim(FEA_JOOMLA_IMAGES_URL, '/');
}
function fea_gallery_manifest_files(string $dir, string $order = 'desc'): array {
static $manifest = null;
if ($manifest === null) {
$manifest = [];
$path = (string) FEA_GALLERY_MANIFEST;
if (is_readable($path)) {
$decoded = json_decode((string) file_get_contents($path), true);
if (is_array($decoded)) {
$manifest = $decoded;
}
}
}
if (empty($manifest[$dir]) || !is_array($manifest[$dir])) return [];
$files = array_values(array_filter(array_map('strval', $manifest[$dir]), function ($file) {
return preg_match('/\.(jpe?g|png|gif|webp)$/i', $file);
}));
natsort($files);
$files = array_values($files);
if ($order === 'desc') {
$files = array_reverse($files);
}
return $files;
}
function fea_gallery_files(string $dir, string $order = 'desc'): array {
$dir = fea_gallery_safe_dir($dir);
if ($dir === '') return [];
$path = fea_gallery_base_dir() . '/' . $dir;
if (!is_dir($path) || !is_readable($path)) {
return fea_gallery_manifest_files($dir, $order);
}
$mtime = (int) @filemtime($path);
$cache_key = 'fea_gallery_' . md5($path . '|' . $mtime . '|' . $order);
$cached = get_transient($cache_key);
if (is_array($cached)) return $cached;
$files = [];
$entries = @scandir($path);
if (!is_array($entries)) return [];
foreach ($entries as $entry) {
if ($entry === '.' || $entry === '..') continue;
if (!preg_match('/\.(jpe?g|png|gif|webp)$/i', $entry)) continue;
if (!is_file($path . '/' . $entry)) continue;
$files[] = $entry;
}
natsort($files);
$files = array_values($files);
if ($order === 'desc') {
$files = array_reverse($files);
}
set_transient($cache_key, $files, 10 * MINUTE_IN_SECONDS);
return $files;
}
function fea_gallery_url(string $dir, string $file): string {
return fea_gallery_base_url() . '/' . rawurlencode(fea_gallery_safe_dir($dir)) . '/' . rawurlencode($file);
}
function fea_gallery_page_param(string $dir): string {
return 'fea_gallery_' . substr(md5($dir), 0, 8);
}
function fea_gallery_render(array $atts = []): string {
$atts = shortcode_atts([
'dir' => 'Pensamientos',
'per_page' => (string) FEA_GALLERY_PER_PAGE,
'order' => 'desc',
], $atts, 'fea_galeria');
$dir = fea_gallery_safe_dir((string) $atts['dir']);
if ($dir === '') return '';
$order = strtolower((string) $atts['order']) === 'asc' ? 'asc' : 'desc';
$files = fea_gallery_files($dir, $order);
if (!$files) {
return '<p class="fea-gallery-empty">Galería no disponible.</p>';
}
$per_page = max(12, min(144, (int) $atts['per_page']));
$total = count($files);
$pages = max(1, (int) ceil($total / $per_page));
$param = fea_gallery_page_param($dir);
$page = isset($_GET[$param]) ? max(1, (int) $_GET[$param]) : 1;
$page = min($page, $pages);
$offset = ($page - 1) * $per_page;
$visible = array_slice($files, $offset, $per_page);
$html = '<div class="fea-gallery" data-fea-gallery="' . esc_attr($dir) . '">';
$html .= '<div class="fea-gallery-grid">';
foreach ($visible as $file) {
$url = fea_gallery_url($dir, $file);
$alt = preg_replace('/\.[^.]+$/', '', $file);
$html .= '<a class="fea-gallery-item" href="' . esc_url($url) . '" data-fea-lightbox="1">';
$html .= '<img src="' . esc_url($url) . '" alt="' . esc_attr($alt) . '" loading="lazy" decoding="async">';
$html .= '</a>';
}
$html .= '</div>';
if ($pages > 1) {
$html .= '<nav class="fea-gallery-pages" aria-label="Paginación de galería">';
if ($page > 1) {
$html .= '<a href="' . esc_url(add_query_arg($param, $page - 1)) . '">Anterior</a>';
}
$html .= '<span>Página ' . esc_html((string) $page) . ' de ' . esc_html((string) $pages) . '</span>';
if ($page < $pages) {
$html .= '<a href="' . esc_url(add_query_arg($param, $page + 1)) . '">Siguiente</a>';
}
$html .= '</nav>';
}
$html .= '</div>';
return $html;
}
add_shortcode('fea_galeria', 'fea_gallery_render');
add_filter('the_content', function ($content) {
if (is_admin() || stripos($content, '{gallery}') === false) return $content;
return preg_replace_callback(
'/\{gallery\}\s*([^{}]+?)\s*\{\/gallery\}/i',
function ($m) {
return fea_gallery_render(['dir' => trim($m[1])]);
},
$content
);
}, 8);
function fea_random_thought_html(): string {
$files = fea_gallery_files('Pensamientos', 'desc');
if (!$files) return '';
$file = $files[array_rand($files)];
$url = fea_gallery_url('Pensamientos', $file);
return '<aside class="fea-random-thought" aria-label="Una pausa">'
. '<div class="fea-random-thought-title"><span></span><strong>Una pausa para el alma</strong><span></span></div>'
. '<a href="' . esc_url($url) . '" data-fea-lightbox="1">'
. '<img src="' . esc_url($url) . '" alt="Pensamiento aleatorio" loading="lazy" decoding="async">'
. '</a></aside>';
}
function fea_random_thought_excluded(): bool {
if (!is_singular('post')) return true;
$post_id = get_the_ID();
$excluded_ids = array_filter(array_map('intval', explode(',', (string) FEA_RANDOM_THOUGHT_EXCLUDED_IDS)));
if ($post_id && in_array((int) $post_id, $excluded_ids, true)) return true;
if ($post_id) {
$raw = (string) get_post_field('post_content', $post_id);
if (stripos($raw, '{gallery}') !== false || stripos($raw, '[fea_galeria') !== false) {
return true;
}
}
$ids = array_filter(array_map('intval', explode(',', (string) FEA_RANDOM_THOUGHT_EXCLUDED_CATS)));
foreach ($ids as $id) {
if ($id > 0 && has_category($id)) return true;
}
return false;
}
add_shortcode('fea_reflexion_aleatoria', function () {
return fea_random_thought_html();
});
add_filter('the_content', function ($content) {
if (is_admin() || !is_main_query() || !in_the_loop() || fea_random_thought_excluded()) {
return $content;
}
if (strpos($content, 'fea-random-thought') !== false) return $content;
$thought = fea_random_thought_html();
return $thought ? $content . $thought : $content;
}, 18);
function fea_pensamientos_assets_needed(): bool {
if (!is_singular()) return false;
$post_id = get_queried_object_id();
$raw = $post_id ? (string) get_post_field('post_content', $post_id) : '';
if (stripos($raw, '{gallery}') !== false || stripos($raw, '[fea_galeria') !== false || stripos($raw, '[fea_reflexion_aleatoria') !== false) {
return true;
}
return !fea_random_thought_excluded();
}
add_action('wp_head', function () {
if (!fea_pensamientos_assets_needed()) return;
?>
<style>
.fea-gallery {
width: min(1180px, 100%);
max-width: none;
margin: 1.5rem auto 2rem;
}
.fea-gallery .fea-gallery-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
gap: 0.65rem !important;
}
.fea-gallery-item {
display: flex;
align-items: center;
justify-content: center;
aspect-ratio: 275 / 160;
overflow: hidden;
border: 1px solid rgba(0,0,0,0.08);
border-radius: 3px;
background: #fff;
box-shadow: 0 1px 3px rgba(0,0,0,0.07);
}
.fea-gallery-item img {
width: 98.5%;
height: 96.5%;
object-fit: contain;
display: block;
transition: transform 0.16s ease;
}
.fea-gallery-item:hover img { transform: scale(1.02); }
.fea-gallery-pages {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
margin-top: 1.25rem;
font-size: 0.95rem;
}
.fea-gallery-pages a {
padding: 0.45rem 0.75rem;
border: 1px solid currentColor;
border-radius: 6px;
text-decoration: none;
}
.fea-random-thought {
margin: 2.4rem auto 1.4rem;
max-width: 720px;
text-align: center;
}
.fea-random-thought-title {
display: grid;
grid-template-columns: 1fr auto 1fr;
align-items: center;
gap: 0.75rem;
margin-bottom: 1rem;
color: #7f1d1d;
font-size: 0.95rem;
}
.fea-random-thought-title span {
height: 1px;
background: currentColor;
opacity: 0.28;
}
.fea-random-thought a { display: inline-block; max-width: min(100%, 560px); }
.fea-random-thought img {
display: block;
width: 100%;
height: auto;
border-radius: 6px;
box-shadow: 0 8px 24px rgba(0,0,0,0.14);
}
.fea-lightbox {
position: fixed;
inset: 0;
z-index: 99999;
display: none;
align-items: center;
justify-content: center;
padding: 4rem 5rem;
background: rgba(0,0,0,0.86);
}
.fea-lightbox.is-open { display: flex; }
.fea-lightbox-frame {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.fea-lightbox-frame img {
max-width: min(100%, 1100px);
max-height: calc(100vh - 8rem);
width: auto;
height: auto;
border-radius: 4px;
background: #fff;
box-shadow: 0 18px 60px rgba(0,0,0,0.45);
}
.fea-lightbox button {
position: absolute;
border: 0;
border-radius: 999px;
background: rgba(255,255,255,0.92);
color: #111;
line-height: 1;
cursor: pointer;
}
.fea-lightbox-close {
top: 0.75rem;
right: 0.75rem;
width: 2.5rem;
height: 2.5rem;
font-size: 1.6rem;
}
.fea-lightbox-prev,
.fea-lightbox-next {
top: 50%;
width: 3rem;
height: 3rem;
font-size: 2rem;
transform: translateY(-50%);
}
.fea-lightbox-prev { left: 1rem; }
.fea-lightbox-next { right: 1rem; }
@media (max-width: 700px) {
.fea-gallery { width: min(100%, calc(100vw - 1rem)); }
.fea-gallery .fea-gallery-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
.fea-lightbox { padding: 3.5rem 1rem; }
.fea-lightbox-prev,
.fea-lightbox-next {
top: auto;
bottom: 0.75rem;
transform: none;
}
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function () {
var links = Array.prototype.slice.call(document.querySelectorAll('[data-fea-lightbox="1"]'));
if (!links.length) return;
var box = document.createElement('div');
box.className = 'fea-lightbox';
box.innerHTML = '<button type="button" class="fea-lightbox-close" aria-label="Cerrar">&times;</button><button type="button" class="fea-lightbox-prev" aria-label="Anterior">&#8249;</button><div class="fea-lightbox-frame"><img alt=""></div><button type="button" class="fea-lightbox-next" aria-label="Siguiente">&#8250;</button>';
document.body.appendChild(box);
var img = box.querySelector('img');
var closeButton = box.querySelector('.fea-lightbox-close');
var prevButton = box.querySelector('.fea-lightbox-prev');
var nextButton = box.querySelector('.fea-lightbox-next');
var index = 0;
var show = function (nextIndex) {
index = (nextIndex + links.length) % links.length;
img.src = links[index].href;
img.alt = links[index].querySelector('img') ? links[index].querySelector('img').alt : '';
box.classList.add('is-open');
};
var close = function () {
box.classList.remove('is-open');
img.removeAttribute('src');
};
box.addEventListener('click', function (event) {
if (event.target === box) close();
});
closeButton.addEventListener('click', close);
prevButton.addEventListener('click', function () { show(index - 1); });
nextButton.addEventListener('click', function () { show(index + 1); });
document.addEventListener('keydown', function (event) {
if (!box.classList.contains('is-open')) return;
if (event.key === 'Escape') close();
if (event.key === 'ArrowLeft') show(index - 1);
if (event.key === 'ArrowRight') show(index + 1);
});
links.forEach(function (link, linkIndex) {
link.addEventListener('click', function (event) {
event.preventDefault();
show(linkIndex);
});
});
});
</script>
<?php
}, 30);