feat(portada): modelo carta→portada + slider sync desde filesystem
- fea-carta-portada.php (nuevo, 1.0): parser de la carta semanal. Extrae secciones (Evangelio, Artículos, Eucaristía, Multimedia, EFFA) por encabezados y resuelve los href (WP slug o K2 legacy id) a wp_posts.ID. Cache en transient 15 min, invalidación en save_post. Cierra issue #38. - fea-homepage.php: 4 shortcodes reescritos para usar fea_carta_section_posts() como fuente primaria, manteniendo el fallback existente (ACF + últimos por categoría). Afecta: [fea_articulos_semana], [fea_evangelio], [fea_eucaristia], [fea_multimedia]. El hero y noticia_centro sin cambios. - fea-slider-sync.php (nuevo, 1.0): sincroniza Smart Slider 3 id 2 con uploads/home/. Editor sube/borra imágenes en esa carpeta y el slider se actualiza automáticamente al primer pageview (modelo paridad con Joomla mod_ariimageslider). Cierra issue #43. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: Fe Adulta — Carta → Portada
|
||||
* Description: Parser de la carta semanal. Extrae los links de cada sección de la
|
||||
* carta y los expone para que los shortcodes de portada los rendericen.
|
||||
* Version: 1.0
|
||||
*
|
||||
* Modelo: cada carta semanal es un post HTML con secciones encabezadas
|
||||
* (Evangelio, Artículos, Eucaristía, Multimedia, EFFA). Los links DENTRO de
|
||||
* cada sección son lo que la portada debe mostrar en su shortcode equivalente.
|
||||
*
|
||||
* Ver issue rafa/feadulta#38.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Devuelve el post-carta vigente para un idioma (más reciente en cat 6).
|
||||
* Si Polylang está activo y hay traducción del idioma, devuelve la traducida.
|
||||
*/
|
||||
function fea_get_current_carta_id($lang = null) {
|
||||
static $cache = [];
|
||||
$lang = $lang ?: (function_exists('pll_current_language') ? pll_current_language() : 'es');
|
||||
if ($lang === false || $lang === null) $lang = 'es';
|
||||
if (isset($cache[$lang])) return $cache[$lang];
|
||||
|
||||
$cat_es = 6;
|
||||
$cat = function_exists('fea_cat') ? fea_cat($cat_es) : $cat_es;
|
||||
|
||||
$cartas = get_posts([
|
||||
'posts_per_page' => 1,
|
||||
'category__in' => [$cat],
|
||||
'post_status' => 'publish',
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
'suppress_filters' => false,
|
||||
]);
|
||||
if (!$cartas) return $cache[$lang] = 0;
|
||||
|
||||
$carta_id = (int) $cartas[0]->ID;
|
||||
|
||||
if ($lang !== 'es' && function_exists('pll_get_post')) {
|
||||
$trans = pll_get_post($carta_id, $lang);
|
||||
if ($trans) $carta_id = (int) $trans;
|
||||
}
|
||||
|
||||
return $cache[$lang] = $carta_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsea el HTML de la carta y devuelve los post_ids agrupados por sección.
|
||||
*/
|
||||
function fea_parse_carta_sections($carta_id) {
|
||||
static $mem = [];
|
||||
$carta_id = (int) $carta_id;
|
||||
if (!$carta_id) return [];
|
||||
if (isset($mem[$carta_id])) return $mem[$carta_id];
|
||||
|
||||
$tk = 'fea_carta_sections_' . $carta_id;
|
||||
$cached = get_transient($tk);
|
||||
if (is_array($cached)) return $mem[$carta_id] = $cached;
|
||||
|
||||
$post = get_post($carta_id);
|
||||
if (!$post) return $mem[$carta_id] = [];
|
||||
|
||||
$sections = fea_extract_sections_from_html($post->post_content);
|
||||
|
||||
set_transient($tk, $sections, 15 * MINUTE_IN_SECONDS);
|
||||
return $mem[$carta_id] = $sections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extrae secciones del HTML. Pública para tests/CLI.
|
||||
*/
|
||||
function fea_extract_sections_from_html($html) {
|
||||
$section_patterns = [
|
||||
'evangelio' => '/Evangelio\s+y\s+comentarios\s+al\s+Evangelio/iu',
|
||||
'articulos' => '/Art[ií]culos\s+seleccionados\s+para\s+la\s+semana/iu',
|
||||
'eucaristia' => '/Para\s+unas\s+eucarist[ií]as\s+m[áa]s\s+participativas/iu',
|
||||
'multimedia' => '/Material\s+multimedia/iu',
|
||||
'effa' => '/Escuela\s+EFFA/iu',
|
||||
];
|
||||
|
||||
$positions = [];
|
||||
foreach ($section_patterns as $slug => $regex) {
|
||||
if (preg_match($regex, $html, $m, PREG_OFFSET_CAPTURE)) {
|
||||
$positions[$slug] = $m[0][1];
|
||||
}
|
||||
}
|
||||
if (empty($positions)) return [];
|
||||
asort($positions);
|
||||
|
||||
$slugs = array_keys($positions);
|
||||
$offsets = array_values($positions);
|
||||
$offsets[] = strlen($html);
|
||||
|
||||
$sections = [];
|
||||
for ($i = 0; $i < count($slugs); $i++) {
|
||||
$segment = substr($html, $offsets[$i], $offsets[$i+1] - $offsets[$i]);
|
||||
$ids = fea_resolve_links_in_html($segment);
|
||||
if ($ids) $sections[$slugs[$i]] = $ids;
|
||||
}
|
||||
return $sections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extrae los href de un fragmento HTML y los resuelve a wp_posts.ID.
|
||||
*/
|
||||
function fea_resolve_links_in_html($html) {
|
||||
if (!preg_match_all('/href=["\']([^"\']+)["\']/i', $html, $m)) return [];
|
||||
$ids = [];
|
||||
$seen = [];
|
||||
foreach ($m[1] as $url) {
|
||||
$pid = fea_url_to_post_id($url);
|
||||
if ($pid && !isset($seen[$pid])) {
|
||||
$seen[$pid] = true;
|
||||
$ids[] = $pid;
|
||||
}
|
||||
}
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resuelve una URL (WP o Joomla legacy) a wp_posts.ID o null.
|
||||
*/
|
||||
function fea_url_to_post_id($url) {
|
||||
global $wpdb;
|
||||
|
||||
if (preg_match('~(?:^|/)fea/([a-z0-9\-]+)/?(?:[?#]|$)~i', $url, $m)) {
|
||||
$slug = $m[1];
|
||||
if (in_array($slug, ['wp-admin','wp-content','category','tag','author','page','en','fr','it','pt'], true)) {
|
||||
return null;
|
||||
}
|
||||
$pid = $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT ID FROM {$wpdb->posts}
|
||||
WHERE post_name=%s AND post_status='publish' AND post_type='post'
|
||||
ORDER BY post_date DESC LIMIT 1",
|
||||
$slug
|
||||
));
|
||||
if ($pid) return (int) $pid;
|
||||
}
|
||||
|
||||
if (preg_match('~/item/(\d+)-[^/"]+\.html~i', $url, $m)) {
|
||||
$k2 = (int) $m[1];
|
||||
if ($k2 > 0) {
|
||||
$pid = $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key='_fgj2wp_old_k2_id' AND meta_value=%s LIMIT 1",
|
||||
(string) $k2
|
||||
));
|
||||
if ($pid) return (int) $pid;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Devuelve los WP_Post objects de una sección de la carta vigente,
|
||||
* o array vacío si no hay carta o no hay links resueltos en esa sección.
|
||||
*/
|
||||
function fea_carta_section_posts($section_slug, $lang = null) {
|
||||
$carta_id = fea_get_current_carta_id($lang);
|
||||
if (!$carta_id) return [];
|
||||
$sections = fea_parse_carta_sections($carta_id);
|
||||
$ids = $sections[$section_slug] ?? [];
|
||||
if (!$ids) return [];
|
||||
$posts = [];
|
||||
foreach ($ids as $pid) {
|
||||
$p = get_post($pid);
|
||||
if ($p && $p->post_status === 'publish') $posts[] = $p;
|
||||
}
|
||||
return $posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalida transients de secciones al guardar/editar un post.
|
||||
*/
|
||||
add_action('save_post_post', function($post_id, $post, $update) {
|
||||
$cats = wp_get_post_categories($post_id);
|
||||
$watch = [6, 21, 22];
|
||||
if (array_intersect($cats, $watch)) {
|
||||
global $wpdb;
|
||||
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_fea_carta_sections_%'");
|
||||
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout_fea_carta_sections_%'");
|
||||
}
|
||||
}, 10, 3);
|
||||
Regular → Executable
+132
-31
@@ -437,6 +437,56 @@ add_action('wp_head', function() {
|
||||
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);
|
||||
|
||||
// ── 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) ────
|
||||
@@ -518,6 +568,41 @@ function fea_is_front_page(): bool {
|
||||
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';
|
||||
@@ -625,22 +710,26 @@ add_shortcode('fea_carta_semana_hero', function() {
|
||||
});
|
||||
|
||||
// ── 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();
|
||||
|
||||
// Selección editorial ACF (solo para ES; otros idiomas usan fallback)
|
||||
$posts = [];
|
||||
if ($lang === 'es' && function_exists('get_field')) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: últimos artículos en el idioma actual
|
||||
// 3) Fallback: últimos artículos en el idioma actual
|
||||
if (empty($posts)) {
|
||||
$posts = get_posts([
|
||||
'posts_per_page' => 9,
|
||||
@@ -661,30 +750,33 @@ add_shortcode('fea_articulos_semana', function($atts) {
|
||||
});
|
||||
|
||||
// ── Shortcode: [fea_evangelio] ────────────────────────────────────────────
|
||||
// Editorial (cat 1646) primero, luego comentarios (cat 1647). Máx 7 en total.
|
||||
// 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);
|
||||
|
||||
$editorial = get_posts([
|
||||
'posts_per_page' => 1,
|
||||
'category__in' => [fea_cat(1646)],
|
||||
'post_status' => 'publish',
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
]);
|
||||
$posts = function_exists('fea_carta_section_posts') ? fea_carta_section_posts('evangelio', $lang) : [];
|
||||
|
||||
$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 (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">'
|
||||
@@ -695,18 +787,24 @@ add_shortcode('fea_evangelio', function($atts) {
|
||||
});
|
||||
|
||||
// ── 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 = get_posts([
|
||||
'posts_per_page' => 6,
|
||||
'category__in' => [fea_cat(1648)],
|
||||
'post_status' => 'publish',
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
]);
|
||||
$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">'
|
||||
@@ -717,14 +815,17 @@ add_shortcode('fea_eucaristia', function($atts) {
|
||||
});
|
||||
|
||||
// ── 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();
|
||||
$labels = fea_labels();
|
||||
$atts = shortcode_atts(['titulo' => $labels['multimedia']], $atts);
|
||||
$page = fea_front_page_id();
|
||||
|
||||
$posts = [];
|
||||
if ($lang === 'es' && function_exists('get_field')) {
|
||||
$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;
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: Fe Adulta — Slider home sync (filesystem → Smart Slider 3)
|
||||
* Description: Sincroniza los slides del Smart Slider 3 id 2 ("Slider_home")
|
||||
* con el contenido del directorio `wp-content/uploads/home/`.
|
||||
* Imita el modelo Joomla mod_ariimageslider que leía
|
||||
* `images/home/` automáticamente.
|
||||
* Version: 1.0
|
||||
*
|
||||
* Operativa para el editor: subir/borrar ficheros en `uploads/home/`.
|
||||
* El slider de la portada se actualiza solo al primer pageview.
|
||||
*
|
||||
* Ver issue rafa/feadulta#43.
|
||||
*/
|
||||
|
||||
const FEA_SLIDER_ID = 2;
|
||||
const FEA_SLIDER_DIRNAME = 'home';
|
||||
const FEA_SLIDER_EXTS = ['jpg', 'jpeg', 'png', 'webp'];
|
||||
const FEA_SLIDER_OPT_KEY = 'fea_slider_home_mtime';
|
||||
|
||||
/**
|
||||
* Lista las imágenes del directorio uploads/home/, ordenadas por nombre.
|
||||
*/
|
||||
function fea_slider_home_files() {
|
||||
$uploads = wp_upload_dir();
|
||||
$dir = trailingslashit($uploads['basedir']) . FEA_SLIDER_DIRNAME;
|
||||
if (!is_dir($dir)) return [];
|
||||
$files = [];
|
||||
foreach (scandir($dir) as $name) {
|
||||
if ($name === '.' || $name === '..') continue;
|
||||
$ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
|
||||
if (!in_array($ext, FEA_SLIDER_EXTS, true)) continue;
|
||||
$files[] = $name;
|
||||
}
|
||||
sort($files, SORT_NATURAL);
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* mtime del directorio (cambia al añadir/borrar ficheros).
|
||||
*/
|
||||
function fea_slider_home_dir_mtime() {
|
||||
$uploads = wp_upload_dir();
|
||||
$dir = trailingslashit($uploads['basedir']) . FEA_SLIDER_DIRNAME;
|
||||
if (!is_dir($dir)) return 0;
|
||||
$m = (int) @filemtime($dir);
|
||||
// Sumar mtime de cada fichero para detectar reemplazos del mismo nombre
|
||||
foreach (fea_slider_home_files() as $f) {
|
||||
$m = max($m, (int) @filemtime($dir . '/' . $f));
|
||||
}
|
||||
return $m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sincroniza la tabla wp_nextend2_smartslider3_slides para el slider 2
|
||||
* con los ficheros del directorio. Idempotente.
|
||||
*
|
||||
* - Reusa slides existentes (manteniendo IDs) cuando coincide la imagen
|
||||
* - Crea slides nuevos para imágenes nuevas
|
||||
* - Borra slides cuya imagen ya no está
|
||||
*/
|
||||
function fea_slider_home_sync_now($force = false) {
|
||||
global $wpdb;
|
||||
$mtime = fea_slider_home_dir_mtime();
|
||||
if (!$force) {
|
||||
$last = (int) get_option(FEA_SLIDER_OPT_KEY, 0);
|
||||
if ($last === $mtime && $mtime > 0) return false;
|
||||
}
|
||||
|
||||
$files = fea_slider_home_files();
|
||||
|
||||
$uploads = wp_upload_dir();
|
||||
$reldir = '$upload$/' . FEA_SLIDER_DIRNAME; // SS3 variable placeholder
|
||||
|
||||
// Leer slides actuales del slider 2 → mapeo imagen → row
|
||||
$existing = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT id, title, params, ordering FROM {$wpdb->prefix}nextend2_smartslider3_slides WHERE slider=%d ORDER BY ordering",
|
||||
FEA_SLIDER_ID
|
||||
), ARRAY_A);
|
||||
|
||||
$by_image = [];
|
||||
foreach ($existing as $row) {
|
||||
$p = json_decode($row['params'], true) ?: [];
|
||||
$img = isset($p['backgroundImage']) ? basename($p['backgroundImage']) : null;
|
||||
if ($img) $by_image[$img] = $row;
|
||||
}
|
||||
|
||||
$keep_ids = [];
|
||||
$ordering = 0;
|
||||
foreach ($files as $file) {
|
||||
$ordering++;
|
||||
if (isset($by_image[$file])) {
|
||||
// Reutilizar slide existente — actualizar params si fuera necesario
|
||||
$row = $by_image[$file];
|
||||
$p = json_decode($row['params'], true) ?: [];
|
||||
$expected = $reldir . '/' . $file;
|
||||
$needs_update = false;
|
||||
if (($p['backgroundImage'] ?? '') !== $expected) { $p['backgroundImage'] = $expected; $needs_update = true; }
|
||||
if (($p['background-type'] ?? '') !== 'image') { $p['background-type'] = 'image'; $needs_update = true; }
|
||||
if ($needs_update) {
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'nextend2_smartslider3_slides',
|
||||
['params' => wp_json_encode($p), 'ordering' => $ordering],
|
||||
['id' => $row['id']],
|
||||
['%s','%d'], ['%d']
|
||||
);
|
||||
} else {
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'nextend2_smartslider3_slides',
|
||||
['ordering' => $ordering],
|
||||
['id' => $row['id']],
|
||||
['%d'], ['%d']
|
||||
);
|
||||
}
|
||||
$keep_ids[] = (int) $row['id'];
|
||||
} else {
|
||||
// Crear slide nuevo
|
||||
$title = pathinfo($file, PATHINFO_FILENAME);
|
||||
$params = wp_json_encode([
|
||||
'background-type' => 'image',
|
||||
'backgroundImage' => $reldir . '/' . $file,
|
||||
'version' => '3.5.1.32',
|
||||
]);
|
||||
$img_url = $reldir . '/' . $file;
|
||||
$wpdb->insert(
|
||||
$wpdb->prefix . 'nextend2_smartslider3_slides',
|
||||
[
|
||||
'slider' => FEA_SLIDER_ID,
|
||||
'title' => $title,
|
||||
'description' => '',
|
||||
'params' => $params,
|
||||
'slide' => '[]',
|
||||
'thumbnail' => $img_url,
|
||||
'publish_up' => '1970-01-01 00:00:00',
|
||||
'publish_down' => '1970-01-01 00:00:00',
|
||||
'published' => 1,
|
||||
'first' => 0,
|
||||
'generator_id' => 0,
|
||||
'ordering' => $ordering,
|
||||
],
|
||||
['%d','%s','%s','%s','%s','%s','%s','%s','%d','%d','%d','%d']
|
||||
);
|
||||
$keep_ids[] = (int) $wpdb->insert_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Borrar slides cuya imagen ya no está en el directorio
|
||||
if ($keep_ids) {
|
||||
$in = implode(',', array_map('intval', $keep_ids));
|
||||
$wpdb->query($wpdb->prepare(
|
||||
"DELETE FROM {$wpdb->prefix}nextend2_smartslider3_slides WHERE slider=%d AND id NOT IN ($in)",
|
||||
FEA_SLIDER_ID
|
||||
));
|
||||
} else {
|
||||
$wpdb->query($wpdb->prepare(
|
||||
"DELETE FROM {$wpdb->prefix}nextend2_smartslider3_slides WHERE slider=%d",
|
||||
FEA_SLIDER_ID
|
||||
));
|
||||
}
|
||||
|
||||
update_option(FEA_SLIDER_OPT_KEY, $mtime);
|
||||
|
||||
// Marcar slider como cambiado para que SS3 regenere su manifest
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'nextend2_section_storage',
|
||||
['value' => (string) $mtime],
|
||||
['application' => 'smartslider', 'section' => 'sliderChanged', 'referenceKey' => (string) FEA_SLIDER_ID],
|
||||
['%s'], ['%s','%s','%s']
|
||||
);
|
||||
|
||||
return count($files);
|
||||
}
|
||||
|
||||
// Ejecutar sync en cada carga de portada (la comprobación de mtime evita trabajo si nada cambió).
|
||||
add_action('template_redirect', function() {
|
||||
if (!is_front_page()) return;
|
||||
fea_slider_home_sync_now();
|
||||
}, 5);
|
||||
|
||||
// Sync también al entrar al admin (por si el editor sube ficheros desde wp-admin).
|
||||
add_action('admin_init', function() {
|
||||
fea_slider_home_sync_now();
|
||||
});
|
||||
|
||||
// WP-CLI helper: `wp eval "fea_slider_home_sync_now(true);"` fuerza resync ignorando mtime.
|
||||
Reference in New Issue
Block a user