Plugins bloques
This commit is contained in:
82
bloques-actuaciones-import/bloques-actuaciones-import.php
Normal file
82
bloques-actuaciones-import/bloques-actuaciones-import.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: Importar Actuaciones desde CSV
|
||||
* Description: Importador idempotente de Actuaciones (Bloques en Transición) desde CSV con mapeo interactivo de categorías.
|
||||
* Version: 1.1.0
|
||||
* Author: Freepress Coop
|
||||
* License: GPL-2.0+
|
||||
* Text Domain: bloques-actuaciones-import
|
||||
* Requires Plugins: bloques-transicion
|
||||
* Requires at least: 6.0
|
||||
* Requires PHP: 8.0
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
define('BLOQUES_IMPORT_VERSION', '1.1.0');
|
||||
define('BLOQUES_IMPORT_DIR', plugin_dir_path(__FILE__));
|
||||
define('BLOQUES_IMPORT_URL', plugin_dir_url(__FILE__));
|
||||
|
||||
require_once BLOQUES_IMPORT_DIR . 'includes/class-bloques-actuaciones-importer.php';
|
||||
|
||||
add_action('admin_menu', 'bloques_import_register_menu', 20);
|
||||
|
||||
function bloques_import_register_menu() {
|
||||
if (!defined('BLOQUES_PLUGIN_DIR')) {
|
||||
return;
|
||||
}
|
||||
add_submenu_page(
|
||||
'bloques-dashboard',
|
||||
__('Importar Actuaciones CSV', 'bloques-actuaciones-import'),
|
||||
__('📥 Importar CSV', 'bloques-actuaciones-import'),
|
||||
'manage_options',
|
||||
'bloques-import-actuaciones',
|
||||
'bloques_import_render_page'
|
||||
);
|
||||
}
|
||||
|
||||
function bloques_import_render_page() {
|
||||
$step = 'upload'; // upload | mapping | done
|
||||
$message = '';
|
||||
$message_type = '';
|
||||
$import_errors = [];
|
||||
$analysis = null;
|
||||
|
||||
// ── PASO 2: el usuario ha confirmado mapeos → importar ──
|
||||
if (
|
||||
isset($_POST['bloques_import_step']) &&
|
||||
$_POST['bloques_import_step'] === 'import' &&
|
||||
wp_verify_nonce($_POST['bloques_import_nonce'] ?? '', 'bloques_import_actuaciones')
|
||||
) {
|
||||
$csv_path = sanitize_text_field($_POST['csv_path'] ?? '');
|
||||
$geocode = !empty($_POST['reverse_geocode']);
|
||||
$ini_map = array_map('sanitize_text_field', (array) ($_POST['ini_map'] ?? []));
|
||||
$linea_map = array_map('sanitize_text_field', (array) ($_POST['linea_map'] ?? []));
|
||||
|
||||
$result = Bloques_Actuaciones_Importer::import($csv_path, $ini_map, $linea_map, $geocode);
|
||||
$message = $result['message'];
|
||||
$message_type = $result['success'] ? 'success' : 'error';
|
||||
$import_errors = $result['errors'] ?? [];
|
||||
$step = 'done';
|
||||
}
|
||||
|
||||
// ── PASO 1: subir CSV → analizar y mostrar mapeos ──
|
||||
elseif (
|
||||
isset($_POST['bloques_import_step']) &&
|
||||
$_POST['bloques_import_step'] === 'analyze' &&
|
||||
wp_verify_nonce($_POST['bloques_import_nonce'] ?? '', 'bloques_import_actuaciones')
|
||||
) {
|
||||
$analysis = Bloques_Actuaciones_Importer::analyze($_FILES['csv_file'] ?? null);
|
||||
if (!$analysis['success']) {
|
||||
$message = $analysis['message'];
|
||||
$message_type = 'error';
|
||||
$step = 'upload';
|
||||
} else {
|
||||
$step = 'mapping';
|
||||
}
|
||||
}
|
||||
|
||||
include BLOQUES_IMPORT_DIR . 'templates/admin/import-page.php';
|
||||
}
|
||||
@@ -0,0 +1,457 @@
|
||||
<?php
|
||||
/**
|
||||
* Importador de Actuaciones desde CSV — flujo en dos pasos.
|
||||
*
|
||||
* Paso 1 (analyze): lee el CSV, extrae valores únicos de Iniciativa y Línea de trabajo,
|
||||
* los compara con los términos existentes y devuelve los que necesitan mapeo.
|
||||
* Paso 2 (import): recibe el CSV guardado + los mapeos confirmados por el usuario
|
||||
* e importa/actualiza las actuaciones de forma idempotente.
|
||||
*
|
||||
* @package Bloques_Actuaciones_Import
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class Bloques_Actuaciones_Importer {
|
||||
|
||||
private const CSV_DELIMITER = ';';
|
||||
private const NOMINATIM_DELAY_US = 1100000; // 1.1 s
|
||||
private const NOMINATIM_USER_AGENT = 'BloquesTransicion/1.0 (WordPress; tangente.coop)';
|
||||
|
||||
/**
|
||||
* Mapeos por defecto del CSV a los slugs de WP.
|
||||
* clave = nombre tal como aparece en el CSV (mb_strtolower).
|
||||
*/
|
||||
private const DEFAULT_INICIATIVA_MAP = [
|
||||
'bloques' => 'oficina-transicion-justa',
|
||||
'colegios' => 'coles-transicion',
|
||||
];
|
||||
|
||||
/* ─────────────────────────────────────────────
|
||||
* PASO 1 — Analizar CSV
|
||||
* ───────────────────────────────────────────── */
|
||||
|
||||
/**
|
||||
* Analizar el CSV y devolver términos que necesitan mapeo.
|
||||
*
|
||||
* @param array $file $_FILES['csv_file']
|
||||
* @return array{ success:bool, message:string, csv_path:string,
|
||||
* unmatched_iniciativas:array, unmatched_lineas:array,
|
||||
* existing_iniciativas:array, existing_lineas:array,
|
||||
* stats:array }
|
||||
*/
|
||||
public static function analyze($file) {
|
||||
if (empty($file['tmp_name']) || !is_uploaded_file($file['tmp_name'])) {
|
||||
return ['success' => false, 'message' => __('No se ha subido ningún archivo válido.', 'bloques-actuaciones-import')];
|
||||
}
|
||||
|
||||
// Guardar el CSV temporalmente en uploads para el paso 2
|
||||
$upload_dir = wp_upload_dir();
|
||||
$tmp_path = trailingslashit($upload_dir['basedir']) . 'bloques-import-' . wp_generate_password(12, false) . '.csv';
|
||||
if (!move_uploaded_file($file['tmp_name'], $tmp_path)) {
|
||||
return ['success' => false, 'message' => __('No se pudo guardar el archivo temporal.', 'bloques-actuaciones-import')];
|
||||
}
|
||||
|
||||
$errors = [];
|
||||
$rows = self::parse_csv($tmp_path, $errors);
|
||||
if ($rows === null) {
|
||||
@unlink($tmp_path);
|
||||
return ['success' => false, 'message' => __('Error al leer el CSV.', 'bloques-actuaciones-import') . ' ' . implode(' ', $errors)];
|
||||
}
|
||||
|
||||
// Recoger valores únicos del CSV
|
||||
$csv_iniciativas = [];
|
||||
$csv_lineas = [];
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$ini = trim(self::val($row, ['Iniciativa']));
|
||||
if ($ini !== '') {
|
||||
$csv_iniciativas[$ini] = true;
|
||||
}
|
||||
|
||||
$lin = trim(self::val($row, ['Línea de trabajo', 'Líneas de trabajo', 'Linea de trabajo']));
|
||||
if ($lin !== '') {
|
||||
foreach (preg_split('/\s*;\s*/', $lin) as $l) {
|
||||
$l = trim($l);
|
||||
if ($l !== '') {
|
||||
$csv_lineas[$l] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$csv_iniciativas = array_keys($csv_iniciativas);
|
||||
$csv_lineas = array_keys($csv_lineas);
|
||||
|
||||
// Términos existentes en WP
|
||||
$existing_iniciativas = self::get_existing_terms('iniciativa');
|
||||
$existing_lineas = self::get_existing_terms('linea_trabajo');
|
||||
|
||||
// Determinar cuáles necesitan mapeo
|
||||
$unmatched_iniciativas = self::find_unmatched($csv_iniciativas, $existing_iniciativas, self::DEFAULT_INICIATIVA_MAP);
|
||||
$unmatched_lineas = self::find_unmatched($csv_lineas, $existing_lineas, []);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'csv_path' => $tmp_path,
|
||||
'total_rows' => count($rows),
|
||||
'unmatched_iniciativas' => $unmatched_iniciativas,
|
||||
'unmatched_lineas' => $unmatched_lineas,
|
||||
'existing_iniciativas' => $existing_iniciativas,
|
||||
'existing_lineas' => $existing_lineas,
|
||||
'default_map' => self::DEFAULT_INICIATIVA_MAP,
|
||||
];
|
||||
}
|
||||
|
||||
/* ─────────────────────────────────────────────
|
||||
* PASO 2 — Importar con mapeos confirmados
|
||||
* ───────────────────────────────────────────── */
|
||||
|
||||
/**
|
||||
* @param string $csv_path Ruta al CSV almacenado en paso 1
|
||||
* @param array $iniciativa_map csv_value => slug_existente | '__new__'
|
||||
* @param array $linea_map csv_value => slug_existente | '__new__'
|
||||
* @param bool $do_reverse_geocode
|
||||
* @return array{ success:bool, message:string, created:int, updated:int, errors:string[] }
|
||||
*/
|
||||
public static function import($csv_path, array $iniciativa_map, array $linea_map, $do_reverse_geocode = true) {
|
||||
$created = 0;
|
||||
$updated = 0;
|
||||
$errors = [];
|
||||
|
||||
if (!file_exists($csv_path) || !is_readable($csv_path)) {
|
||||
return self::result(false, __('No se encontró el archivo CSV temporal.', 'bloques-actuaciones-import'), 0, 0, []);
|
||||
}
|
||||
|
||||
$rows = self::parse_csv($csv_path, $errors);
|
||||
if ($rows === null) {
|
||||
return self::result(false, __('Error al leer el CSV.', 'bloques-actuaciones-import'), 0, 0, $errors);
|
||||
}
|
||||
|
||||
$total = count($rows);
|
||||
|
||||
foreach ($rows as $idx => $row) {
|
||||
$title = self::val($row, ['Título/Nombre', 'Título', 'Nombre']);
|
||||
if (trim((string) $title) === '') {
|
||||
$errors[] = sprintf(__('Fila %d: título vacío, omitida.', 'bloques-actuaciones-import'), $idx + 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = self::get_or_create($title);
|
||||
if (!$result) {
|
||||
$errors[] = sprintf(__('Fila %d: no se pudo crear/obtener "%s".', 'bloques-actuaciones-import'), $idx + 2, esc_html($title));
|
||||
continue;
|
||||
}
|
||||
|
||||
$post_id = $result['id'];
|
||||
$result['created'] ? $created++ : $updated++;
|
||||
|
||||
$desc = self::val($row, ['Descripción', 'Descripcion']);
|
||||
|
||||
wp_update_post([
|
||||
'ID' => $post_id,
|
||||
'post_title' => $title,
|
||||
'post_content' => $desc,
|
||||
'post_excerpt' => wp_trim_words(wp_strip_all_tags($desc), 30),
|
||||
'post_status' => 'publish',
|
||||
'post_type' => 'actuacion',
|
||||
]);
|
||||
|
||||
// Iniciativa
|
||||
$csv_ini = trim(self::val($row, ['Iniciativa']));
|
||||
if ($csv_ini !== '') {
|
||||
self::assign_term($post_id, 'iniciativa', $csv_ini, $iniciativa_map);
|
||||
}
|
||||
|
||||
// Líneas de trabajo
|
||||
$csv_lin = trim(self::val($row, ['Línea de trabajo', 'Líneas de trabajo', 'Linea de trabajo']));
|
||||
if ($csv_lin !== '') {
|
||||
$lineas_list = array_filter(array_map('trim', preg_split('/\s*;\s*/', $csv_lin)));
|
||||
$term_ids = [];
|
||||
foreach ($lineas_list as $l) {
|
||||
$tid = self::resolve_term('linea_trabajo', $l, $linea_map);
|
||||
if ($tid) {
|
||||
$term_ids[] = $tid;
|
||||
}
|
||||
}
|
||||
if (!empty($term_ids)) {
|
||||
wp_set_object_terms($post_id, $term_ids, 'linea_trabajo');
|
||||
}
|
||||
}
|
||||
|
||||
// Coordenadas
|
||||
$lat_long = self::val($row, ['Lat/Long', 'Lat', 'Long']);
|
||||
self::set_coords($post_id, $lat_long);
|
||||
|
||||
// Reverse geocode → dirección
|
||||
if ($do_reverse_geocode && $lat_long !== '') {
|
||||
$address = self::reverse_geocode($lat_long);
|
||||
if ($address !== '') {
|
||||
update_post_meta($post_id, 'direccion', $address);
|
||||
if (function_exists('update_field')) {
|
||||
update_field('direccion', $address, $post_id);
|
||||
}
|
||||
}
|
||||
if ($total > 1) {
|
||||
usleep(self::NOMINATIM_DELAY_US);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Limpiar archivo temporal
|
||||
@unlink($csv_path);
|
||||
|
||||
$msg = sprintf(
|
||||
__('Importación completada: %d creadas, %d actualizadas de %d filas.', 'bloques-actuaciones-import'),
|
||||
$created, $updated, $total
|
||||
);
|
||||
if (!empty($errors)) {
|
||||
$msg .= ' ' . sprintf(__('%d advertencias.', 'bloques-actuaciones-import'), count($errors));
|
||||
}
|
||||
|
||||
return self::result(true, $msg, $created, $updated, $errors);
|
||||
}
|
||||
|
||||
/* ─────────────────────────────────────────────
|
||||
* Helpers privados
|
||||
* ───────────────────────────────────────────── */
|
||||
|
||||
private static function result($ok, $msg, $c, $u, $e) {
|
||||
return ['success' => $ok, 'message' => $msg, 'created' => $c, 'updated' => $u, 'errors' => $e];
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener términos existentes de una taxonomía como [ slug => name ].
|
||||
*/
|
||||
private static function get_existing_terms($taxonomy) {
|
||||
$terms = get_terms(['taxonomy' => $taxonomy, 'hide_empty' => false]);
|
||||
$result = [];
|
||||
if (!is_wp_error($terms)) {
|
||||
foreach ($terms as $t) {
|
||||
$result[$t->slug] = $t->name;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determinar qué valores del CSV no coinciden con términos existentes.
|
||||
* Devuelve array de [ csv_value => suggested_slug|'' ].
|
||||
*/
|
||||
private static function find_unmatched(array $csv_values, array $existing, array $default_map) {
|
||||
$unmatched = [];
|
||||
$existing_lower = [];
|
||||
foreach ($existing as $slug => $name) {
|
||||
$existing_lower[mb_strtolower($name)] = $slug;
|
||||
}
|
||||
|
||||
foreach ($csv_values as $csv_val) {
|
||||
$key = mb_strtolower(trim($csv_val));
|
||||
|
||||
// Coincidencia exacta por nombre
|
||||
if (isset($existing_lower[$key])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Coincidencia exacta por slug
|
||||
$slug_candidate = sanitize_title($csv_val);
|
||||
if (isset($existing[$slug_candidate])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Mapeo por defecto
|
||||
if (isset($default_map[$key]) && isset($existing[$default_map[$key]])) {
|
||||
// Hay sugerencia pero se mostrará al usuario para que confirme
|
||||
$unmatched[$csv_val] = $default_map[$key];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sin coincidencia
|
||||
$unmatched[$csv_val] = '';
|
||||
}
|
||||
|
||||
return $unmatched;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asignar un término de taxonomía a un post, usando el mapa de mapeos.
|
||||
*/
|
||||
private static function assign_term($post_id, $taxonomy, $csv_value, array $map) {
|
||||
$tid = self::resolve_term($taxonomy, $csv_value, $map);
|
||||
if ($tid) {
|
||||
wp_set_object_terms($post_id, [$tid], $taxonomy);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolver un valor CSV a un term_id, creando si procede.
|
||||
*/
|
||||
private static function resolve_term($taxonomy, $csv_value, array $map) {
|
||||
$key = trim($csv_value);
|
||||
if ($key === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ¿Hay mapeo del usuario?
|
||||
if (isset($map[$key])) {
|
||||
$mapped = $map[$key];
|
||||
if ($mapped === '__new__') {
|
||||
// Crear nuevo término
|
||||
return self::ensure_term($taxonomy, $key);
|
||||
}
|
||||
// Usar slug existente
|
||||
$term = get_term_by('slug', $mapped, $taxonomy);
|
||||
return $term ? (int) $term->term_id : self::ensure_term($taxonomy, $key);
|
||||
}
|
||||
|
||||
// Intentar match directo por nombre (case-insensitive)
|
||||
$existing = self::get_existing_terms($taxonomy);
|
||||
foreach ($existing as $slug => $name) {
|
||||
if (mb_strtolower($name) === mb_strtolower($key)) {
|
||||
return (int) get_term_by('slug', $slug, $taxonomy)->term_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Intentar por slug
|
||||
$slug_try = sanitize_title($key);
|
||||
$term = get_term_by('slug', $slug_try, $taxonomy);
|
||||
if ($term) {
|
||||
return (int) $term->term_id;
|
||||
}
|
||||
|
||||
// Sin mapeo explícito → crear
|
||||
return self::ensure_term($taxonomy, $key);
|
||||
}
|
||||
|
||||
private static function ensure_term($taxonomy, $name) {
|
||||
$slug = sanitize_title($name);
|
||||
$term = get_term_by('slug', $slug, $taxonomy);
|
||||
if ($term) {
|
||||
return (int) $term->term_id;
|
||||
}
|
||||
$r = wp_insert_term($name, $taxonomy, ['slug' => $slug]);
|
||||
return is_wp_error($r) ? null : (int) $r['term_id'];
|
||||
}
|
||||
|
||||
/* ── Post idempotente ── */
|
||||
|
||||
private static function get_or_create($title) {
|
||||
global $wpdb;
|
||||
$id = $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT ID FROM {$wpdb->posts} WHERE post_type = 'actuacion' AND post_title = %s AND post_status IN ('publish','draft','pending','private') LIMIT 1",
|
||||
$title
|
||||
));
|
||||
if ($id) {
|
||||
return ['id' => (int) $id, 'created' => false];
|
||||
}
|
||||
$id = wp_insert_post(['post_title' => $title, 'post_type' => 'actuacion', 'post_status' => 'publish']);
|
||||
if (!$id || is_wp_error($id)) {
|
||||
return false;
|
||||
}
|
||||
return ['id' => (int) $id, 'created' => true];
|
||||
}
|
||||
|
||||
/* ── Coordenadas ── */
|
||||
|
||||
private static function set_coords($post_id, $lat_long) {
|
||||
if (!preg_match('/^(-?\d+\.?\d*)\s*,\s*(-?\d+\.?\d*)$/', trim($lat_long), $m)) {
|
||||
return;
|
||||
}
|
||||
$lat = (float) $m[1];
|
||||
$lng = (float) $m[2];
|
||||
update_post_meta($post_id, 'latitud', $lat);
|
||||
update_post_meta($post_id, 'longitud', $lng);
|
||||
if (function_exists('update_field')) {
|
||||
update_field('latitud', $lat, $post_id);
|
||||
update_field('longitud', $lng, $post_id);
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Reverse geocode (Nominatim) ── */
|
||||
|
||||
private static function reverse_geocode($lat_long) {
|
||||
if (!preg_match('/^(-?\d+\.?\d*)\s*,\s*(-?\d+\.?\d*)$/', trim($lat_long), $m)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$url = add_query_arg([
|
||||
'lat' => (float) $m[1],
|
||||
'lon' => (float) $m[2],
|
||||
'format' => 'json',
|
||||
'addressdetails' => 1,
|
||||
], 'https://nominatim.openstreetmap.org/reverse');
|
||||
|
||||
$resp = wp_remote_get($url, [
|
||||
'timeout' => 10,
|
||||
'user-agent' => self::NOMINATIM_USER_AGENT,
|
||||
'headers' => ['Accept-Language' => 'es'],
|
||||
]);
|
||||
|
||||
if (is_wp_error($resp) || wp_remote_retrieve_response_code($resp) !== 200) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$data = json_decode(wp_remote_retrieve_body($resp), true);
|
||||
if (empty($data['address'])) {
|
||||
return $data['display_name'] ?? '';
|
||||
}
|
||||
|
||||
$a = $data['address'];
|
||||
$parts = array_filter([
|
||||
$a['road'] ?? '',
|
||||
$a['house_number'] ?? '',
|
||||
$a['suburb'] ?? $a['neighbourhood'] ?? '',
|
||||
$a['city'] ?? $a['town'] ?? $a['village'] ?? $a['municipality'] ?? '',
|
||||
$a['state'] ?? '',
|
||||
]);
|
||||
return implode(', ', $parts);
|
||||
}
|
||||
|
||||
/* ── CSV parser ── */
|
||||
|
||||
private static function parse_csv($path, &$errors = []) {
|
||||
$handle = fopen($path, 'r');
|
||||
if (!$handle) {
|
||||
$errors[] = __('No se pudo abrir el archivo.', 'bloques-actuaciones-import');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Saltar BOM
|
||||
$bom = fread($handle, 3);
|
||||
if ($bom !== "\xEF\xBB\xBF") {
|
||||
rewind($handle);
|
||||
}
|
||||
|
||||
$header = fgetcsv($handle, 0, self::CSV_DELIMITER);
|
||||
if ($header === false || empty($header)) {
|
||||
fclose($handle);
|
||||
$errors[] = __('Cabecera CSV no válida.', 'bloques-actuaciones-import');
|
||||
return null;
|
||||
}
|
||||
|
||||
$header = array_map('trim', $header);
|
||||
$rows = [];
|
||||
|
||||
while (($raw = fgetcsv($handle, 0, self::CSV_DELIMITER)) !== false) {
|
||||
$padded = array_pad($raw, count($header), '');
|
||||
$row = array_combine($header, array_slice($padded, 0, count($header)));
|
||||
if (is_array($row)) {
|
||||
$rows[] = array_map(fn($v) => is_string($v) ? trim($v) : $v, $row);
|
||||
}
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
return $rows;
|
||||
}
|
||||
|
||||
private static function val(array $row, array $keys) {
|
||||
foreach ($keys as $k) {
|
||||
if (isset($row[$k]) && $row[$k] !== '') {
|
||||
return $row[$k];
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
172
bloques-actuaciones-import/templates/admin/import-page.php
Normal file
172
bloques-actuaciones-import/templates/admin/import-page.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$step = $step ?? 'upload';
|
||||
$message = $message ?? '';
|
||||
$message_type = $message_type ?? '';
|
||||
$import_errors = $import_errors ?? [];
|
||||
$analysis = $analysis ?? null;
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php esc_html_e('Importar Actuaciones desde CSV', 'bloques-actuaciones-import'); ?></h1>
|
||||
|
||||
<?php if ($message) : ?>
|
||||
<div class="notice notice-<?php echo esc_attr($message_type === 'success' ? 'success' : 'error'); ?> is-dismissible">
|
||||
<p><?php echo esc_html($message); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($import_errors)) : ?>
|
||||
<div class="notice notice-warning">
|
||||
<p><strong><?php esc_html_e('Detalle:', 'bloques-actuaciones-import'); ?></strong></p>
|
||||
<ul style="margin-left:1.5em;list-style:disc;">
|
||||
<?php foreach (array_slice($import_errors, 0, 30) as $err) : ?>
|
||||
<li><?php echo esc_html($err); ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php if (count($import_errors) > 30) : ?>
|
||||
<p><?php echo esc_html(sprintf(__('… y %d más.', 'bloques-actuaciones-import'), count($import_errors) - 30)); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php /* ═══════════════════════════════════════════
|
||||
* PASO 1 — Subir CSV
|
||||
* ═══════════════════════════════════════════ */ ?>
|
||||
<?php if ($step === 'upload' || $step === 'done') : ?>
|
||||
<div class="card" style="max-width:660px;padding:20px;">
|
||||
<h2 style="margin-top:0;"><?php esc_html_e('1. Subir archivo CSV', 'bloques-actuaciones-import'); ?></h2>
|
||||
<p><?php esc_html_e('CSV con delimitador punto y coma (;). Columnas: Título/Nombre, Descripción, Lat/Long, Iniciativa, Línea de trabajo.', 'bloques-actuaciones-import'); ?></p>
|
||||
<p><?php esc_html_e('La importación es idempotente: si la actuación ya existe (mismo título), se actualiza.', 'bloques-actuaciones-import'); ?></p>
|
||||
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<?php wp_nonce_field('bloques_import_actuaciones', 'bloques_import_nonce'); ?>
|
||||
<input type="hidden" name="bloques_import_step" value="analyze">
|
||||
|
||||
<p>
|
||||
<label for="csv_file"><strong><?php esc_html_e('Archivo CSV', 'bloques-actuaciones-import'); ?></strong></label><br>
|
||||
<input type="file" name="csv_file" id="csv_file" accept=".csv,.txt" required>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" name="reverse_geocode" value="1" checked>
|
||||
<?php esc_html_e('Obtener dirección desde coordenadas (Nominatim/OpenStreetMap, ~1 petición/s).', 'bloques-actuaciones-import'); ?>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<button type="submit" class="button button-primary"><?php esc_html_e('Analizar CSV', 'bloques-actuaciones-import'); ?></button>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php /* ═══════════════════════════════════════════
|
||||
* PASO 2 — Mapeo de categorías
|
||||
* ═══════════════════════════════════════════ */ ?>
|
||||
<?php if ($step === 'mapping' && $analysis) :
|
||||
$unmatched_ini = $analysis['unmatched_iniciativas'];
|
||||
$unmatched_lin = $analysis['unmatched_lineas'];
|
||||
$existing_ini = $analysis['existing_iniciativas'];
|
||||
$existing_lin = $analysis['existing_lineas'];
|
||||
$default_map = $analysis['default_map'];
|
||||
$has_unmatched = !empty($unmatched_ini) || !empty($unmatched_lin);
|
||||
?>
|
||||
<div class="card" style="max-width:780px;padding:20px;">
|
||||
<h2 style="margin-top:0;">
|
||||
<?php esc_html_e('2. Revisar mapeo de categorías', 'bloques-actuaciones-import'); ?>
|
||||
</h2>
|
||||
<p>
|
||||
<?php echo esc_html(sprintf(
|
||||
__('Se han encontrado %d filas en el CSV.', 'bloques-actuaciones-import'),
|
||||
$analysis['total_rows']
|
||||
)); ?>
|
||||
</p>
|
||||
|
||||
<form method="post">
|
||||
<?php wp_nonce_field('bloques_import_actuaciones', 'bloques_import_nonce'); ?>
|
||||
<input type="hidden" name="bloques_import_step" value="import">
|
||||
<input type="hidden" name="csv_path" value="<?php echo esc_attr($analysis['csv_path']); ?>">
|
||||
<input type="hidden" name="reverse_geocode" value="<?php echo !empty($_POST['reverse_geocode']) ? '1' : '0'; ?>">
|
||||
|
||||
<?php if (!$has_unmatched) : ?>
|
||||
<div class="notice notice-success inline" style="margin:12px 0;">
|
||||
<p><?php esc_html_e('Todas las categorías del CSV coinciden con términos existentes en WordPress. Puedes importar directamente.', 'bloques-actuaciones-import'); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php /* ── Iniciativas ── */ ?>
|
||||
<?php if (!empty($unmatched_ini)) : ?>
|
||||
<h3><?php esc_html_e('Iniciativas', 'bloques-actuaciones-import'); ?></h3>
|
||||
<p class="description"><?php esc_html_e('Estos valores de la columna "Iniciativa" no coinciden exactamente con ningún término existente. Elige a qué iniciativa asignarlos o crea uno nuevo.', 'bloques-actuaciones-import'); ?></p>
|
||||
<table class="widefat striped" style="max-width:720px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e('Valor en CSV', 'bloques-actuaciones-import'); ?></th>
|
||||
<th><?php esc_html_e('Asignar a…', 'bloques-actuaciones-import'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($unmatched_ini as $csv_val => $suggested_slug) : ?>
|
||||
<tr>
|
||||
<td><strong><?php echo esc_html($csv_val); ?></strong></td>
|
||||
<td>
|
||||
<select name="ini_map[<?php echo esc_attr($csv_val); ?>]" style="width:100%;">
|
||||
<option value="__new__"><?php echo esc_html(sprintf(__('Crear nueva: "%s"', 'bloques-actuaciones-import'), $csv_val)); ?></option>
|
||||
<?php foreach ($existing_ini as $slug => $name) : ?>
|
||||
<option value="<?php echo esc_attr($slug); ?>"<?php selected($suggested_slug, $slug); ?>>
|
||||
<?php echo esc_html($name); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php /* ── Líneas de trabajo ── */ ?>
|
||||
<?php if (!empty($unmatched_lin)) : ?>
|
||||
<h3 style="margin-top:24px;"><?php esc_html_e('Líneas de trabajo', 'bloques-actuaciones-import'); ?></h3>
|
||||
<p class="description"><?php esc_html_e('Estos valores de "Línea de trabajo" no coinciden con ningún término existente.', 'bloques-actuaciones-import'); ?></p>
|
||||
<table class="widefat striped" style="max-width:720px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e('Valor en CSV', 'bloques-actuaciones-import'); ?></th>
|
||||
<th><?php esc_html_e('Asignar a…', 'bloques-actuaciones-import'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($unmatched_lin as $csv_val => $suggested_slug) : ?>
|
||||
<tr>
|
||||
<td><strong><?php echo esc_html($csv_val); ?></strong></td>
|
||||
<td>
|
||||
<select name="linea_map[<?php echo esc_attr($csv_val); ?>]" style="width:100%;">
|
||||
<option value="__new__"><?php echo esc_html(sprintf(__('Crear nueva: "%s"', 'bloques-actuaciones-import'), $csv_val)); ?></option>
|
||||
<?php foreach ($existing_lin as $slug => $name) : ?>
|
||||
<option value="<?php echo esc_attr($slug); ?>"<?php selected($suggested_slug, $slug); ?>>
|
||||
<?php echo esc_html($name); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
|
||||
<p style="margin-top:20px;">
|
||||
<button type="submit" class="button button-primary button-hero">
|
||||
<?php esc_html_e('Confirmar e importar', 'bloques-actuaciones-import'); ?>
|
||||
</button>
|
||||
<a href="<?php echo esc_url(admin_url('admin.php?page=bloques-import-actuaciones')); ?>" class="button" style="margin-left:8px;">
|
||||
<?php esc_html_e('Cancelar', 'bloques-actuaciones-import'); ?>
|
||||
</a>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
107
bloques-transicion/README.md
Normal file
107
bloques-transicion/README.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# Bloques en Transición
|
||||
|
||||
Plugin de WordPress para gestionar el contenido del microsite "Bloques en Transición" de Tangente.coop.
|
||||
|
||||
## Descripción
|
||||
|
||||
Este plugin crea los tipos de contenido personalizados, taxonomías y campos ACF necesarios para el microsite de Bloques en Transición.
|
||||
|
||||
## Características
|
||||
|
||||
### Tipos de Contenido (CPTs)
|
||||
|
||||
- **Actuaciones** (`actuacion`): Proyectos y acciones del programa
|
||||
- **Recursos** (`recurso_bloques`): Documentos, guías e informes
|
||||
- **Eventos** (`evento_bloques`): Actividades y formaciones
|
||||
|
||||
### Taxonomías
|
||||
|
||||
- **Iniciativas**: Oficina de Transición Justa, Coles en transición, Comunidad energética, Creación de redes
|
||||
- **Líneas de Trabajo**: Energía, Cuidados, Alimentación, Movilidad, Renaturalización, Reutilización
|
||||
- **Tipos de Evento**: Online, Presencial
|
||||
|
||||
### Campos ACF
|
||||
|
||||
El plugin registra automáticamente los campos ACF necesarios para cada tipo de contenido:
|
||||
|
||||
- **Actuaciones**: Es piloto, Dirección, Localidad, Latitud, Longitud
|
||||
- **Recursos**: Archivo, Tipo de recurso, URL externa
|
||||
- **Eventos**: Fecha inicio/fin, Hora inicio/fin, Lugar, Dirección, URL online, URL inscripción
|
||||
|
||||
## Instalación
|
||||
|
||||
1. Sube la carpeta `bloques-transicion` a `/wp-content/plugins/`
|
||||
2. Activa el plugin desde el panel de WordPress
|
||||
3. Ve a **Bloques > Cargar datos** para crear las categorías iniciales
|
||||
|
||||
## Requisitos
|
||||
|
||||
- WordPress 6.0+
|
||||
- PHP 8.0+
|
||||
- Plugin ACF (Advanced Custom Fields) instalado y activo
|
||||
|
||||
## Uso
|
||||
|
||||
### Shortcodes disponibles
|
||||
|
||||
```
|
||||
[bloques-listado type="actuaciones" widget="grid" columns="3"]
|
||||
[bloques-listado type="recursos" filter="true"]
|
||||
[bloques-eventos limit="5" upcoming="true"]
|
||||
[bloques-iniciativas columns="4"]
|
||||
[bloques-lineas columns="6"]
|
||||
```
|
||||
|
||||
### Atributos del shortcode principal
|
||||
|
||||
| Atributo | Valores | Por defecto | Descripción |
|
||||
|----------|---------|-------------|-------------|
|
||||
| `type` | actuaciones, recursos, eventos | actuaciones | Tipo de contenido |
|
||||
| `widget` | grid, list | grid | Modo de visualización |
|
||||
| `columns` | 1, 2, 3, 4 | 3 | Número de columnas |
|
||||
| `pagination` | 0, 5, 10, 15, 20 | 0 | Items por página (0 = sin paginación) |
|
||||
| `filter` | true, false | false | Mostrar filtros |
|
||||
| `iniciativa` | slug | - | Filtrar por iniciativa |
|
||||
| `linea` | slug | - | Filtrar por línea de trabajo |
|
||||
| `limit` | número | -1 | Límite de items |
|
||||
| `orderby` | date, title, menu_order | date | Ordenar por |
|
||||
| `order` | ASC, DESC | DESC | Dirección del orden |
|
||||
|
||||
## Personalización de estilos
|
||||
|
||||
El plugin incluye estilos base que puedes personalizar desde tu theme usando las siguientes variables CSS:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--bloques-primary: #1E6B52;
|
||||
--bloques-secondary: #2A9D8F;
|
||||
--bloques-accent: #F4A261;
|
||||
--bloques-text: #333;
|
||||
--bloques-text-light: #666;
|
||||
--bloques-bg: #f8f9fa;
|
||||
--bloques-radius: 8px;
|
||||
}
|
||||
```
|
||||
|
||||
### Clases CSS principales
|
||||
|
||||
- `.bloques-listado` - Contenedor principal
|
||||
- `.bloques-items` - Grid de items
|
||||
- `.bloques-item` - Item individual
|
||||
- `.bloques-item-thumbnail` - Imagen del item
|
||||
- `.bloques-item-content` - Contenido del item
|
||||
- `.bloques-tag` - Etiquetas de taxonomía
|
||||
- `.bloques-btn` - Botones
|
||||
- `.bloques-filter-bar` - Barra de filtros
|
||||
|
||||
## Integración con Divi
|
||||
|
||||
El plugin es compatible con Divi Theme Builder. Puedes usar los shortcodes en cualquier módulo de código o texto.
|
||||
|
||||
## Soporte
|
||||
|
||||
Plugin desarrollado por [Freepress Coop](https://freepress.coop)
|
||||
|
||||
## Licencia
|
||||
|
||||
GPL-2.0+
|
||||
277
bloques-transicion/assets/css/admin.css
Normal file
277
bloques-transicion/assets/css/admin.css
Normal file
@@ -0,0 +1,277 @@
|
||||
/**
|
||||
* Estilos del panel de administración - Bloques en Transición
|
||||
*/
|
||||
|
||||
/* === DASHBOARD === */
|
||||
.bloques-dashboard {
|
||||
max-width: 1200px;
|
||||
}
|
||||
|
||||
.bloques-dashboard h1 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: #1E6B52;
|
||||
}
|
||||
|
||||
.bloques-dashboard h1 .dashicons {
|
||||
font-size: 32px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.bloques-dashboard-welcome {
|
||||
background: linear-gradient(135deg, #1E6B52 0%, #2A9D8F 100%);
|
||||
color: white;
|
||||
padding: 30px;
|
||||
border-radius: 8px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.bloques-dashboard-welcome h2 {
|
||||
color: white;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.bloques-dashboard-welcome p {
|
||||
font-size: 16px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* === STATS CARDS === */
|
||||
.bloques-dashboard-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 20px;
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
.bloques-stat-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.bloques-stat-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.12);
|
||||
}
|
||||
|
||||
.bloques-stat-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background: linear-gradient(135deg, #1E6B52 0%, #2A9D8F 100%);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.bloques-stat-icon .dashicons {
|
||||
font-size: 28px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.bloques-stat-content {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.bloques-stat-number {
|
||||
display: block;
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
color: #1E6B52;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.bloques-stat-label {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.bloques-stat-link {
|
||||
font-size: 13px;
|
||||
text-decoration: none;
|
||||
color: #2A9D8F;
|
||||
}
|
||||
|
||||
.bloques-stat-link:hover {
|
||||
color: #1E6B52;
|
||||
}
|
||||
|
||||
/* === TAXONOMIES === */
|
||||
.bloques-dashboard-taxonomies {
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
.bloques-dashboard-taxonomies h3 {
|
||||
color: #1E6B52;
|
||||
border-bottom: 2px solid #1E6B52;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.bloques-tax-cards {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.bloques-tax-card {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
min-width: 200px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.bloques-tax-count {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: #1E6B52;
|
||||
}
|
||||
|
||||
/* === SHORTCUTS === */
|
||||
.bloques-dashboard-shortcuts {
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
.bloques-dashboard-shortcuts h3 {
|
||||
color: #1E6B52;
|
||||
border-bottom: 2px solid #1E6B52;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.bloques-shortcuts {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.bloques-shortcuts .button-primary {
|
||||
background: #1E6B52;
|
||||
border-color: #1E6B52;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.bloques-shortcuts .button-primary:hover {
|
||||
background: #2A9D8F;
|
||||
border-color: #2A9D8F;
|
||||
}
|
||||
|
||||
/* === SHORTCODES TABLE === */
|
||||
.bloques-dashboard-shortcodes {
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
.bloques-dashboard-shortcodes h3 {
|
||||
color: #1E6B52;
|
||||
border-bottom: 2px solid #1E6B52;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.bloques-dashboard-shortcodes code {
|
||||
background: #f0f0f0;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* === SEEDER PAGE === */
|
||||
.bloques-seeder {
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.bloques-seeder h1 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: #1E6B52;
|
||||
}
|
||||
|
||||
.bloques-seeder-info {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.bloques-seeder-section {
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.bloques-seeder-section:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.bloques-seeder-section h3 {
|
||||
color: #1E6B52;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.bloques-seeder-section ul {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.bloques-seeder-section li {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.bloques-seeder-actions {
|
||||
background: #f8f9fa;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.bloques-seeder-actions .button-hero {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
background: #1E6B52;
|
||||
border-color: #1E6B52;
|
||||
}
|
||||
|
||||
.bloques-seeder-actions .button-hero:hover {
|
||||
background: #2A9D8F;
|
||||
border-color: #2A9D8F;
|
||||
}
|
||||
|
||||
.bloques-seeder-status {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.bloques-seeder-status h3 {
|
||||
color: #1E6B52;
|
||||
}
|
||||
|
||||
/* === ADMIN MENU STYLING === */
|
||||
#adminmenu .toplevel_page_bloques-dashboard .wp-menu-image:before {
|
||||
content: "\f512";
|
||||
}
|
||||
|
||||
#adminmenu .toplevel_page_bloques-dashboard.current,
|
||||
#adminmenu .toplevel_page_bloques-dashboard:hover {
|
||||
background: #1E6B52;
|
||||
}
|
||||
1070
bloques-transicion/assets/css/frontend.css
Normal file
1070
bloques-transicion/assets/css/frontend.css
Normal file
File diff suppressed because it is too large
Load Diff
34
bloques-transicion/assets/js/admin.js
Normal file
34
bloques-transicion/assets/js/admin.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Scripts del panel de administración - Bloques en Transición
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
$(document).ready(function() {
|
||||
// Confirmación antes de cargar datos
|
||||
$('.bloques-seeder form').on('submit', function(e) {
|
||||
if (!confirm('¿Estás seguro de que quieres cargar los datos iniciales?')) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
// Copiar shortcode al portapapeles
|
||||
$('.bloques-dashboard-shortcodes code').on('click', function() {
|
||||
const text = $(this).text();
|
||||
navigator.clipboard.writeText(text).then(function() {
|
||||
// Feedback visual
|
||||
const $code = $(this);
|
||||
const originalBg = $code.css('background');
|
||||
$code.css('background', '#d4edda');
|
||||
setTimeout(function() {
|
||||
$code.css('background', originalBg);
|
||||
}, 500);
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
// Añadir cursor pointer a los shortcodes
|
||||
$('.bloques-dashboard-shortcodes code').css('cursor', 'pointer').attr('title', 'Clic para copiar');
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
247
bloques-transicion/assets/js/frontend.js
Normal file
247
bloques-transicion/assets/js/frontend.js
Normal file
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* Scripts del frontend - Bloques en Transición
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
// Inicializar cuando el DOM esté listo
|
||||
$(document).ready(function() {
|
||||
initFilters();
|
||||
initLoadMore();
|
||||
initSearch();
|
||||
});
|
||||
|
||||
/**
|
||||
* Inicializar filtros tipo botonera
|
||||
*/
|
||||
function initFilters() {
|
||||
$('.bloques-filters').each(function() {
|
||||
const $filters = $(this);
|
||||
const containerId = $filters.data('container');
|
||||
const $container = $('#' + containerId);
|
||||
const $itemsContainer = $container.find('.bloques-items');
|
||||
|
||||
// Estado de filtros activos (incluye category para noticias)
|
||||
let activeFilters = {
|
||||
iniciativa: '',
|
||||
linea_trabajo: '',
|
||||
category: ''
|
||||
};
|
||||
|
||||
// Click en botones de filtro
|
||||
$filters.on('click', '.bloques-filter-btn', function() {
|
||||
const $btn = $(this);
|
||||
const taxonomy = $btn.data('taxonomy');
|
||||
const value = $btn.data('value');
|
||||
|
||||
// Actualizar estado activo en botones del mismo grupo
|
||||
$btn.closest('.bloques-filter-buttons')
|
||||
.find('.bloques-filter-btn')
|
||||
.removeClass('active');
|
||||
$btn.addClass('active');
|
||||
|
||||
// Actualizar filtros activos
|
||||
activeFilters[taxonomy] = value;
|
||||
|
||||
// Aplicar filtros
|
||||
applyFilters($container, $itemsContainer, activeFilters);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Aplicar filtros via AJAX
|
||||
*/
|
||||
function applyFilters($container, $itemsContainer, filters) {
|
||||
const type = $container.data('type');
|
||||
const widget = $container.data('widget');
|
||||
const upcoming = $container.data('upcoming');
|
||||
const search = $container.find('.bloques-search-input').val() || '';
|
||||
|
||||
// Mostrar loading
|
||||
$itemsContainer.addClass('bloques-loading');
|
||||
|
||||
$.ajax({
|
||||
url: bloquesData.ajaxUrl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'bloques_filter',
|
||||
nonce: bloquesData.nonce,
|
||||
type: type,
|
||||
iniciativa: filters.iniciativa || '',
|
||||
linea_trabajo: filters.linea_trabajo || '',
|
||||
category: filters.category || '',
|
||||
search: search,
|
||||
widget: widget,
|
||||
upcoming: upcoming
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
$itemsContainer.html(response.data.html);
|
||||
|
||||
// Actualizar contador
|
||||
const $resultsNumber = $container.find('.bloques-results-number');
|
||||
const $resultsLabel = $container.find('.bloques-results-label');
|
||||
|
||||
if ($resultsNumber.length) {
|
||||
$resultsNumber.text(response.data.count);
|
||||
}
|
||||
if ($resultsLabel.length) {
|
||||
$resultsLabel.text(response.data.label);
|
||||
}
|
||||
|
||||
// Ocultar botón "Ver más" cuando hay filtros activos
|
||||
const hasActiveFilters = filters.iniciativa || filters.linea_trabajo || filters.category || search;
|
||||
$container.find('.bloques-load-more-wrapper').toggle(!hasActiveFilters);
|
||||
|
||||
// Resetear offset
|
||||
$container.data('offset', $container.data('limit'));
|
||||
|
||||
// Animar entrada
|
||||
animateItems($itemsContainer);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
console.error('Error al filtrar contenido');
|
||||
},
|
||||
complete: function() {
|
||||
$itemsContainer.removeClass('bloques-loading');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inicializar búsqueda con debounce
|
||||
*/
|
||||
function initSearch() {
|
||||
let searchTimeout;
|
||||
|
||||
$('.bloques-search-input').on('input', function() {
|
||||
const $input = $(this);
|
||||
const $filters = $input.closest('.bloques-filters');
|
||||
const containerId = $filters.data('container');
|
||||
const $container = $('#' + containerId);
|
||||
const $itemsContainer = $container.find('.bloques-items');
|
||||
|
||||
// Obtener filtros activos
|
||||
const activeFilters = {
|
||||
iniciativa: $filters.find('.bloques-filter-btn[data-taxonomy="iniciativa"].active').data('value') || '',
|
||||
linea_trabajo: $filters.find('.bloques-filter-btn[data-taxonomy="linea_trabajo"].active').data('value') || '',
|
||||
category: $filters.find('.bloques-filter-btn[data-taxonomy="category"].active').data('value') || ''
|
||||
};
|
||||
|
||||
// Debounce
|
||||
clearTimeout(searchTimeout);
|
||||
searchTimeout = setTimeout(function() {
|
||||
applyFilters($container, $itemsContainer, activeFilters);
|
||||
}, 300);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inicializar botón "Ver más"
|
||||
*/
|
||||
function initLoadMore() {
|
||||
$(document).on('click', '.bloques-btn-load-more', function() {
|
||||
const $btn = $(this);
|
||||
const containerId = $btn.data('container');
|
||||
const $container = $('#' + containerId);
|
||||
const $itemsContainer = $container.find('.bloques-items');
|
||||
|
||||
const type = $container.data('type');
|
||||
const widget = $container.data('widget');
|
||||
const limit = parseInt($container.data('limit')) || 9;
|
||||
const offset = parseInt($container.data('offset')) || 0;
|
||||
const total = parseInt($container.data('total')) || 0;
|
||||
const upcoming = $container.data('upcoming');
|
||||
|
||||
// Obtener filtros activos si existen
|
||||
const $filters = $container.find('.bloques-filters');
|
||||
let iniciativa = '';
|
||||
let linea = '';
|
||||
let category = '';
|
||||
|
||||
if ($filters.length) {
|
||||
iniciativa = $filters.find('.bloques-filter-btn[data-taxonomy="iniciativa"].active').data('value') || '';
|
||||
linea = $filters.find('.bloques-filter-btn[data-taxonomy="linea_trabajo"].active').data('value') || '';
|
||||
category = $filters.find('.bloques-filter-btn[data-taxonomy="category"].active').data('value') || '';
|
||||
}
|
||||
|
||||
// Mostrar loading
|
||||
$btn.prop('disabled', true).text('Cargando...');
|
||||
|
||||
$.ajax({
|
||||
url: bloquesData.ajaxUrl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'bloques_load_more',
|
||||
nonce: bloquesData.nonce,
|
||||
type: type,
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
widget: widget,
|
||||
iniciativa: iniciativa,
|
||||
linea_trabajo: linea,
|
||||
category: category,
|
||||
upcoming: upcoming
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
// Añadir nuevos items
|
||||
$itemsContainer.append(response.data.html);
|
||||
|
||||
// Actualizar offset
|
||||
$container.data('offset', response.data.new_offset);
|
||||
|
||||
// Ocultar botón si no hay más
|
||||
if (!response.data.has_more) {
|
||||
$btn.closest('.bloques-load-more-wrapper').fadeOut();
|
||||
}
|
||||
|
||||
// Animar nuevos items
|
||||
animateItems($itemsContainer.find('.bloques-card:gt(' + (offset - 1) + '), .bloques-item:gt(' + (offset - 1) + ')'));
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
console.error('Error al cargar más contenido');
|
||||
},
|
||||
complete: function() {
|
||||
$btn.prop('disabled', false).html('Ver más <span class="bloques-arrow">→</span>');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Animación de entrada para items
|
||||
*/
|
||||
function animateItems($container) {
|
||||
const $items = $container.find('.bloques-card, .bloques-item, .bloques-novedad-item, .bloques-agenda-item');
|
||||
|
||||
$items.each(function(index) {
|
||||
const $item = $(this);
|
||||
$item.css({
|
||||
'opacity': 0,
|
||||
'transform': 'translateY(20px)'
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
$item.css({
|
||||
'opacity': 1,
|
||||
'transform': 'translateY(0)',
|
||||
'transition': 'opacity 0.3s ease, transform 0.3s ease'
|
||||
});
|
||||
}, index * 50);
|
||||
});
|
||||
}
|
||||
|
||||
// Exponer funciones públicas
|
||||
window.BloquesTransicion = {
|
||||
initFilters: initFilters,
|
||||
initLoadMore: initLoadMore,
|
||||
applyFilters: applyFilters,
|
||||
animateItems: animateItems
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
213
bloques-transicion/bloques-transicion.php
Normal file
213
bloques-transicion/bloques-transicion.php
Normal file
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: Bloques en Transición
|
||||
* Plugin URI: https://tangente.coop/bloques
|
||||
* Description: Gestión de contenidos para el microsite "Bloques en Transición" - Actuaciones, Entidades, Recursos y Eventos con taxonomías personalizadas.
|
||||
* Version: 1.0.0
|
||||
* Author: Freepress Coop
|
||||
* Author URI: https://freepress.coop
|
||||
* License: GPL-2.0+
|
||||
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
|
||||
* Text Domain: bloques-transicion
|
||||
* Domain Path: /languages
|
||||
* Requires at least: 6.0
|
||||
* Requires PHP: 8.0
|
||||
*/
|
||||
|
||||
// Si se accede directamente, salir
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Constantes del plugin
|
||||
define('BLOQUES_VERSION', '1.0.0');
|
||||
define('BLOQUES_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
||||
define('BLOQUES_PLUGIN_URL', plugin_dir_url(__FILE__));
|
||||
define('BLOQUES_PLUGIN_BASENAME', plugin_basename(__FILE__));
|
||||
|
||||
/**
|
||||
* Clase principal del plugin
|
||||
*/
|
||||
final class Bloques_Transicion {
|
||||
|
||||
/**
|
||||
* Instancia única del plugin
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Obtener instancia única (Singleton)
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if (null === self::$instance) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor privado
|
||||
*/
|
||||
private function __construct() {
|
||||
$this->load_dependencies();
|
||||
$this->init_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cargar dependencias
|
||||
*/
|
||||
private function load_dependencies() {
|
||||
// Core
|
||||
require_once BLOQUES_PLUGIN_DIR . 'includes/class-post-types.php';
|
||||
require_once BLOQUES_PLUGIN_DIR . 'includes/class-taxonomies.php';
|
||||
require_once BLOQUES_PLUGIN_DIR . 'includes/class-acf-fields.php';
|
||||
require_once BLOQUES_PLUGIN_DIR . 'includes/class-admin-menu.php';
|
||||
require_once BLOQUES_PLUGIN_DIR . 'includes/class-shortcodes.php';
|
||||
require_once BLOQUES_PLUGIN_DIR . 'includes/class-data-seeder.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Inicializar hooks
|
||||
*/
|
||||
private function init_hooks() {
|
||||
// Activación y desactivación
|
||||
register_activation_hook(__FILE__, [$this, 'activate']);
|
||||
register_deactivation_hook(__FILE__, [$this, 'deactivate']);
|
||||
|
||||
// Inicialización
|
||||
add_action('init', [$this, 'init'], 0);
|
||||
add_action('plugins_loaded', [$this, 'load_textdomain']);
|
||||
|
||||
// Admin
|
||||
if (is_admin()) {
|
||||
add_action('admin_enqueue_scripts', [$this, 'admin_assets']);
|
||||
}
|
||||
|
||||
// Frontend
|
||||
add_action('wp_enqueue_scripts', [$this, 'frontend_assets']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inicializar componentes
|
||||
*/
|
||||
public function init() {
|
||||
// Registrar CPTs y taxonomías
|
||||
Bloques_Post_Types::register();
|
||||
Bloques_Taxonomies::register();
|
||||
|
||||
// Registrar campos ACF
|
||||
if (class_exists('ACF')) {
|
||||
Bloques_ACF_Fields::register();
|
||||
}
|
||||
|
||||
// Registrar menú admin
|
||||
Bloques_Admin_Menu::register();
|
||||
|
||||
// Registrar shortcodes
|
||||
Bloques_Shortcodes::register();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cargar traducciones
|
||||
*/
|
||||
public function load_textdomain() {
|
||||
load_plugin_textdomain(
|
||||
'bloques-transicion',
|
||||
false,
|
||||
dirname(BLOQUES_PLUGIN_BASENAME) . '/languages/'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assets del admin
|
||||
*/
|
||||
public function admin_assets($hook) {
|
||||
$screen = get_current_screen();
|
||||
|
||||
// Solo cargar en páginas del plugin
|
||||
if ($screen && (
|
||||
strpos($screen->id, 'bloques') !== false ||
|
||||
in_array($screen->post_type, ['actuacion', 'recurso_bloques', 'evento_bloques'])
|
||||
)) {
|
||||
wp_enqueue_style(
|
||||
'bloques-admin',
|
||||
BLOQUES_PLUGIN_URL . 'assets/css/admin.css',
|
||||
[],
|
||||
BLOQUES_VERSION
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'bloques-admin',
|
||||
BLOQUES_PLUGIN_URL . 'assets/js/admin.js',
|
||||
['jquery'],
|
||||
BLOQUES_VERSION,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assets del frontend
|
||||
*/
|
||||
public function frontend_assets() {
|
||||
wp_enqueue_style(
|
||||
'bloques-frontend',
|
||||
BLOQUES_PLUGIN_URL . 'assets/css/frontend.css',
|
||||
[],
|
||||
BLOQUES_VERSION
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'bloques-frontend',
|
||||
BLOQUES_PLUGIN_URL . 'assets/js/frontend.js',
|
||||
['jquery'],
|
||||
BLOQUES_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
wp_localize_script('bloques-frontend', 'bloquesData', [
|
||||
'ajaxUrl' => admin_url('admin-ajax.php'),
|
||||
'nonce' => wp_create_nonce('bloques_nonce'),
|
||||
'pluginUrl' => BLOQUES_PLUGIN_URL,
|
||||
]);
|
||||
|
||||
// Añadir CSS personalizado
|
||||
$custom_css = get_option('bloques_custom_css', '');
|
||||
if (!empty($custom_css)) {
|
||||
wp_add_inline_style('bloques-frontend', $custom_css);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activación del plugin
|
||||
*/
|
||||
public function activate() {
|
||||
// Registrar CPTs y taxonomías
|
||||
Bloques_Post_Types::register();
|
||||
Bloques_Taxonomies::register();
|
||||
|
||||
// Flush rewrite rules
|
||||
flush_rewrite_rules();
|
||||
|
||||
// Marcar como activado
|
||||
update_option('bloques_transicion_activated', true);
|
||||
update_option('bloques_transicion_version', BLOQUES_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Desactivación del plugin
|
||||
*/
|
||||
public function deactivate() {
|
||||
flush_rewrite_rules();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iniciar el plugin
|
||||
*/
|
||||
function bloques_transicion() {
|
||||
return Bloques_Transicion::get_instance();
|
||||
}
|
||||
|
||||
// Arrancar
|
||||
bloques_transicion();
|
||||
453
bloques-transicion/includes/class-acf-fields.php
Normal file
453
bloques-transicion/includes/class-acf-fields.php
Normal file
@@ -0,0 +1,453 @@
|
||||
<?php
|
||||
/**
|
||||
* Registro de campos ACF
|
||||
*
|
||||
* @package Bloques_Transicion
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class Bloques_ACF_Fields {
|
||||
|
||||
/**
|
||||
* Registrar todos los grupos de campos
|
||||
*/
|
||||
public static function register() {
|
||||
add_action('acf/init', [__CLASS__, 'register_field_groups']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registrar grupos de campos ACF
|
||||
*/
|
||||
public static function register_field_groups() {
|
||||
if (!function_exists('acf_add_local_field_group')) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::register_actuacion_fields();
|
||||
self::register_recurso_fields();
|
||||
self::register_evento_fields();
|
||||
self::register_iniciativa_fields();
|
||||
self::register_linea_trabajo_fields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Campos para Actuaciones
|
||||
*/
|
||||
private static function register_actuacion_fields() {
|
||||
acf_add_local_field_group([
|
||||
'key' => 'group_bloques_actuacion',
|
||||
'title' => __('Datos de la Actuación', 'bloques-transicion'),
|
||||
'fields' => [
|
||||
// Es piloto
|
||||
[
|
||||
'key' => 'field_actuacion_es_piloto',
|
||||
'label' => __('Es actuación piloto', 'bloques-transicion'),
|
||||
'name' => 'es_piloto',
|
||||
'type' => 'true_false',
|
||||
'instructions' => __('Marcar si esta actuación es un proyecto piloto', 'bloques-transicion'),
|
||||
'ui' => 1,
|
||||
'ui_on_text' => __('Sí', 'bloques-transicion'),
|
||||
'ui_off_text' => __('No', 'bloques-transicion'),
|
||||
'default_value' => 0,
|
||||
],
|
||||
// Tab Ubicación
|
||||
[
|
||||
'key' => 'field_actuacion_tab_ubicacion',
|
||||
'label' => __('Ubicación', 'bloques-transicion'),
|
||||
'name' => '',
|
||||
'type' => 'tab',
|
||||
'placement' => 'top',
|
||||
],
|
||||
// Dirección
|
||||
[
|
||||
'key' => 'field_actuacion_direccion',
|
||||
'label' => __('Dirección', 'bloques-transicion'),
|
||||
'name' => 'direccion',
|
||||
'type' => 'text',
|
||||
'instructions' => __('Dirección completa', 'bloques-transicion'),
|
||||
],
|
||||
// Localidad
|
||||
[
|
||||
'key' => 'field_actuacion_localidad',
|
||||
'label' => __('Localidad', 'bloques-transicion'),
|
||||
'name' => 'localidad',
|
||||
'type' => 'text',
|
||||
'instructions' => __('Ciudad o barrio', 'bloques-transicion'),
|
||||
],
|
||||
// Latitud
|
||||
[
|
||||
'key' => 'field_actuacion_latitud',
|
||||
'label' => __('Latitud', 'bloques-transicion'),
|
||||
'name' => 'latitud',
|
||||
'type' => 'number',
|
||||
'instructions' => __('Coordenada de latitud (ej: 40.4168)', 'bloques-transicion'),
|
||||
'step' => 'any',
|
||||
'wrapper' => ['width' => '50'],
|
||||
],
|
||||
// Longitud
|
||||
[
|
||||
'key' => 'field_actuacion_longitud',
|
||||
'label' => __('Longitud', 'bloques-transicion'),
|
||||
'name' => 'longitud',
|
||||
'type' => 'number',
|
||||
'instructions' => __('Coordenada de longitud (ej: -3.7038)', 'bloques-transicion'),
|
||||
'step' => 'any',
|
||||
'wrapper' => ['width' => '50'],
|
||||
],
|
||||
// Mapa (Google Maps si está disponible, sino texto)
|
||||
[
|
||||
'key' => 'field_actuacion_mapa',
|
||||
'label' => __('Seleccionar en mapa', 'bloques-transicion'),
|
||||
'name' => 'mapa',
|
||||
'type' => 'google_map',
|
||||
'instructions' => __('Haz clic en el mapa para obtener las coordenadas automáticamente', 'bloques-transicion'),
|
||||
'center_lat' => '40.4168',
|
||||
'center_lng' => '-3.7038',
|
||||
'zoom' => 12,
|
||||
'conditional_logic' => [
|
||||
[
|
||||
[
|
||||
'field' => 'field_actuacion_latitud',
|
||||
'operator' => '==empty',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'location' => [
|
||||
[
|
||||
[
|
||||
'param' => 'post_type',
|
||||
'operator' => '==',
|
||||
'value' => 'actuacion',
|
||||
],
|
||||
],
|
||||
],
|
||||
'menu_order' => 0,
|
||||
'position' => 'normal',
|
||||
'style' => 'default',
|
||||
'label_placement' => 'top',
|
||||
'instruction_placement' => 'label',
|
||||
'active' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Campos para Recursos
|
||||
*/
|
||||
private static function register_recurso_fields() {
|
||||
acf_add_local_field_group([
|
||||
'key' => 'group_bloques_recurso',
|
||||
'title' => __('Datos del Recurso', 'bloques-transicion'),
|
||||
'fields' => [
|
||||
// Archivo
|
||||
[
|
||||
'key' => 'field_recurso_archivo',
|
||||
'label' => __('Archivo', 'bloques-transicion'),
|
||||
'name' => 'archivo',
|
||||
'type' => 'file',
|
||||
'instructions' => __('Sube el archivo del recurso (PDF, DOC, JPG, PNG, etc.)', 'bloques-transicion'),
|
||||
'required' => 0,
|
||||
'return_format' => 'array',
|
||||
'library' => 'all',
|
||||
'mime_types' => 'pdf,doc,docx,xls,xlsx,ppt,pptx,jpg,jpeg,png,gif,zip',
|
||||
],
|
||||
// Tipo de recurso (informativo)
|
||||
[
|
||||
'key' => 'field_recurso_tipo',
|
||||
'label' => __('Tipo de Recurso', 'bloques-transicion'),
|
||||
'name' => 'tipo_recurso',
|
||||
'type' => 'select',
|
||||
'instructions' => __('Categoría del tipo de recurso', 'bloques-transicion'),
|
||||
'choices' => [
|
||||
'documento' => __('Documento', 'bloques-transicion'),
|
||||
'guia' => __('Guía', 'bloques-transicion'),
|
||||
'informe' => __('Informe', 'bloques-transicion'),
|
||||
'presentacion' => __('Presentación', 'bloques-transicion'),
|
||||
'video' => __('Vídeo', 'bloques-transicion'),
|
||||
'imagen' => __('Imagen', 'bloques-transicion'),
|
||||
'otro' => __('Otro', 'bloques-transicion'),
|
||||
],
|
||||
'default_value' => 'documento',
|
||||
'allow_null' => 0,
|
||||
'return_format' => 'value',
|
||||
],
|
||||
// URL externa (alternativa al archivo)
|
||||
[
|
||||
'key' => 'field_recurso_url_externa',
|
||||
'label' => __('URL Externa', 'bloques-transicion'),
|
||||
'name' => 'url_externa',
|
||||
'type' => 'url',
|
||||
'instructions' => __('Si el recurso está alojado externamente (YouTube, Drive, etc.)', 'bloques-transicion'),
|
||||
],
|
||||
],
|
||||
'location' => [
|
||||
[
|
||||
[
|
||||
'param' => 'post_type',
|
||||
'operator' => '==',
|
||||
'value' => 'recurso_bloques',
|
||||
],
|
||||
],
|
||||
],
|
||||
'menu_order' => 0,
|
||||
'position' => 'normal',
|
||||
'style' => 'default',
|
||||
'label_placement' => 'top',
|
||||
'instruction_placement' => 'label',
|
||||
'active' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Campos para Eventos
|
||||
*/
|
||||
private static function register_evento_fields() {
|
||||
acf_add_local_field_group([
|
||||
'key' => 'group_bloques_evento',
|
||||
'title' => __('Datos del Evento', 'bloques-transicion'),
|
||||
'fields' => [
|
||||
// Tab Fecha y Hora
|
||||
[
|
||||
'key' => 'field_evento_tab_fecha',
|
||||
'label' => __('Fecha y Hora', 'bloques-transicion'),
|
||||
'name' => '',
|
||||
'type' => 'tab',
|
||||
'placement' => 'top',
|
||||
],
|
||||
// Fecha inicio
|
||||
[
|
||||
'key' => 'field_evento_fecha_inicio',
|
||||
'label' => __('Fecha de inicio', 'bloques-transicion'),
|
||||
'name' => 'fecha_inicio',
|
||||
'type' => 'date_picker',
|
||||
'instructions' => __('Fecha en que comienza el evento', 'bloques-transicion'),
|
||||
'required' => 1,
|
||||
'display_format' => 'd/m/Y',
|
||||
'return_format' => 'Y-m-d',
|
||||
'first_day' => 1,
|
||||
'wrapper' => ['width' => '50'],
|
||||
],
|
||||
// Hora inicio
|
||||
[
|
||||
'key' => 'field_evento_hora_inicio',
|
||||
'label' => __('Hora de inicio', 'bloques-transicion'),
|
||||
'name' => 'hora_inicio',
|
||||
'type' => 'time_picker',
|
||||
'instructions' => __('Hora de inicio del evento', 'bloques-transicion'),
|
||||
'display_format' => 'H:i',
|
||||
'return_format' => 'H:i',
|
||||
'wrapper' => ['width' => '50'],
|
||||
],
|
||||
// Fecha fin
|
||||
[
|
||||
'key' => 'field_evento_fecha_fin',
|
||||
'label' => __('Fecha de fin', 'bloques-transicion'),
|
||||
'name' => 'fecha_fin',
|
||||
'type' => 'date_picker',
|
||||
'instructions' => __('Fecha en que termina el evento (opcional)', 'bloques-transicion'),
|
||||
'display_format' => 'd/m/Y',
|
||||
'return_format' => 'Y-m-d',
|
||||
'first_day' => 1,
|
||||
'wrapper' => ['width' => '50'],
|
||||
],
|
||||
// Hora fin
|
||||
[
|
||||
'key' => 'field_evento_hora_fin',
|
||||
'label' => __('Hora de fin', 'bloques-transicion'),
|
||||
'name' => 'hora_fin',
|
||||
'type' => 'time_picker',
|
||||
'instructions' => __('Hora de finalización (opcional)', 'bloques-transicion'),
|
||||
'display_format' => 'H:i',
|
||||
'return_format' => 'H:i',
|
||||
'wrapper' => ['width' => '50'],
|
||||
],
|
||||
// Tab Ubicación
|
||||
[
|
||||
'key' => 'field_evento_tab_ubicacion',
|
||||
'label' => __('Ubicación', 'bloques-transicion'),
|
||||
'name' => '',
|
||||
'type' => 'tab',
|
||||
'placement' => 'top',
|
||||
],
|
||||
// Lugar
|
||||
[
|
||||
'key' => 'field_evento_lugar',
|
||||
'label' => __('Lugar', 'bloques-transicion'),
|
||||
'name' => 'lugar',
|
||||
'type' => 'text',
|
||||
'instructions' => __('Nombre del lugar donde se celebra', 'bloques-transicion'),
|
||||
],
|
||||
// Dirección
|
||||
[
|
||||
'key' => 'field_evento_direccion',
|
||||
'label' => __('Dirección', 'bloques-transicion'),
|
||||
'name' => 'direccion',
|
||||
'type' => 'text',
|
||||
],
|
||||
// URL Online
|
||||
[
|
||||
'key' => 'field_evento_url_online',
|
||||
'label' => __('Enlace para evento online', 'bloques-transicion'),
|
||||
'name' => 'url_online',
|
||||
'type' => 'url',
|
||||
'instructions' => __('URL de Zoom, Meet, YouTube, etc. para eventos online', 'bloques-transicion'),
|
||||
],
|
||||
// Tab Inscripción
|
||||
[
|
||||
'key' => 'field_evento_tab_inscripcion',
|
||||
'label' => __('Inscripción', 'bloques-transicion'),
|
||||
'name' => '',
|
||||
'type' => 'tab',
|
||||
'placement' => 'top',
|
||||
],
|
||||
// URL inscripción
|
||||
[
|
||||
'key' => 'field_evento_url_inscripcion',
|
||||
'label' => __('URL de inscripción', 'bloques-transicion'),
|
||||
'name' => 'url_inscripcion',
|
||||
'type' => 'url',
|
||||
'instructions' => __('Enlace al formulario de inscripción', 'bloques-transicion'),
|
||||
],
|
||||
// Plazas
|
||||
[
|
||||
'key' => 'field_evento_plazas',
|
||||
'label' => __('Número de plazas', 'bloques-transicion'),
|
||||
'name' => 'plazas',
|
||||
'type' => 'number',
|
||||
'instructions' => __('Aforo máximo (dejar vacío si no hay límite)', 'bloques-transicion'),
|
||||
'min' => 0,
|
||||
],
|
||||
],
|
||||
'location' => [
|
||||
[
|
||||
[
|
||||
'param' => 'post_type',
|
||||
'operator' => '==',
|
||||
'value' => 'evento_bloques',
|
||||
],
|
||||
],
|
||||
],
|
||||
'menu_order' => 0,
|
||||
'position' => 'normal',
|
||||
'style' => 'default',
|
||||
'label_placement' => 'top',
|
||||
'instruction_placement' => 'label',
|
||||
'active' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Campos para taxonomía Iniciativas
|
||||
*/
|
||||
private static function register_iniciativa_fields() {
|
||||
acf_add_local_field_group([
|
||||
'key' => 'group_bloques_iniciativa_tax',
|
||||
'title' => __('Datos de la Iniciativa', 'bloques-transicion'),
|
||||
'fields' => [
|
||||
// Icono
|
||||
[
|
||||
'key' => 'field_iniciativa_icono',
|
||||
'label' => __('Icono', 'bloques-transicion'),
|
||||
'name' => 'icono',
|
||||
'type' => 'image',
|
||||
'instructions' => __('Icono representativo de la iniciativa (SVG o PNG recomendado)', 'bloques-transicion'),
|
||||
'return_format' => 'url',
|
||||
'preview_size' => 'thumbnail',
|
||||
'library' => 'all',
|
||||
'mime_types' => 'svg,png,jpg,jpeg',
|
||||
],
|
||||
// Color
|
||||
[
|
||||
'key' => 'field_iniciativa_color',
|
||||
'label' => __('Color', 'bloques-transicion'),
|
||||
'name' => 'color',
|
||||
'type' => 'color_picker',
|
||||
'instructions' => __('Color identificativo de la iniciativa', 'bloques-transicion'),
|
||||
'default_value' => '#1E6B52',
|
||||
],
|
||||
// Ubicación
|
||||
[
|
||||
'key' => 'field_iniciativa_ubicacion',
|
||||
'label' => __('Ubicación', 'bloques-transicion'),
|
||||
'name' => 'ubicacion_texto',
|
||||
'type' => 'text',
|
||||
'instructions' => __('Texto descriptivo de la ubicación (ej: "Puente y Villa de Vallecas")', 'bloques-transicion'),
|
||||
],
|
||||
// Estado
|
||||
[
|
||||
'key' => 'field_iniciativa_estado',
|
||||
'label' => __('Estado', 'bloques-transicion'),
|
||||
'name' => 'estado',
|
||||
'type' => 'text',
|
||||
'instructions' => __('Estado actual de la iniciativa (ej: "En proceso", "Abierta")', 'bloques-transicion'),
|
||||
],
|
||||
],
|
||||
'location' => [
|
||||
[
|
||||
[
|
||||
'param' => 'taxonomy',
|
||||
'operator' => '==',
|
||||
'value' => 'iniciativa',
|
||||
],
|
||||
],
|
||||
],
|
||||
'menu_order' => 0,
|
||||
'position' => 'normal',
|
||||
'style' => 'default',
|
||||
'label_placement' => 'top',
|
||||
'instruction_placement' => 'label',
|
||||
'active' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Campos para taxonomía Líneas de Trabajo
|
||||
*/
|
||||
private static function register_linea_trabajo_fields() {
|
||||
acf_add_local_field_group([
|
||||
'key' => 'group_bloques_linea_trabajo_tax',
|
||||
'title' => __('Datos de la Línea de Trabajo', 'bloques-transicion'),
|
||||
'fields' => [
|
||||
// Icono
|
||||
[
|
||||
'key' => 'field_linea_trabajo_icono',
|
||||
'label' => __('Icono', 'bloques-transicion'),
|
||||
'name' => 'icono',
|
||||
'type' => 'image',
|
||||
'instructions' => __('Icono representativo de la línea de trabajo', 'bloques-transicion'),
|
||||
'return_format' => 'url',
|
||||
'preview_size' => 'thumbnail',
|
||||
'library' => 'all',
|
||||
'mime_types' => 'svg,png,jpg,jpeg',
|
||||
],
|
||||
// Color (opcional para líneas de trabajo)
|
||||
[
|
||||
'key' => 'field_linea_trabajo_color',
|
||||
'label' => __('Color', 'bloques-transicion'),
|
||||
'name' => 'color',
|
||||
'type' => 'color_picker',
|
||||
'instructions' => __('Color identificativo (opcional)', 'bloques-transicion'),
|
||||
],
|
||||
],
|
||||
'location' => [
|
||||
[
|
||||
[
|
||||
'param' => 'taxonomy',
|
||||
'operator' => '==',
|
||||
'value' => 'linea_trabajo',
|
||||
],
|
||||
],
|
||||
],
|
||||
'menu_order' => 0,
|
||||
'position' => 'normal',
|
||||
'style' => 'default',
|
||||
'label_placement' => 'top',
|
||||
'instruction_placement' => 'label',
|
||||
'active' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
265
bloques-transicion/includes/class-admin-menu.php
Normal file
265
bloques-transicion/includes/class-admin-menu.php
Normal file
@@ -0,0 +1,265 @@
|
||||
<?php
|
||||
/**
|
||||
* Menú de administración personalizado
|
||||
*
|
||||
* @package Bloques_Transicion
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class Bloques_Admin_Menu {
|
||||
|
||||
/**
|
||||
* Registrar menú
|
||||
*/
|
||||
public static function register() {
|
||||
add_action('admin_menu', [__CLASS__, 'add_admin_menu']);
|
||||
add_action('parent_file', [__CLASS__, 'fix_parent_menu']);
|
||||
add_action('submenu_file', [__CLASS__, 'fix_submenu']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Añadir menú principal y submenús
|
||||
*/
|
||||
public static function add_admin_menu() {
|
||||
// Menú principal: Bloques
|
||||
add_menu_page(
|
||||
__('Bloques en Transición', 'bloques-transicion'),
|
||||
__('Bloques', 'bloques-transicion'),
|
||||
'edit_posts',
|
||||
'bloques-dashboard',
|
||||
[__CLASS__, 'render_dashboard'],
|
||||
'dashicons-building',
|
||||
25
|
||||
);
|
||||
|
||||
// Dashboard
|
||||
add_submenu_page(
|
||||
'bloques-dashboard',
|
||||
__('Panel de Bloques', 'bloques-transicion'),
|
||||
__('Panel', 'bloques-transicion'),
|
||||
'edit_posts',
|
||||
'bloques-dashboard',
|
||||
[__CLASS__, 'render_dashboard']
|
||||
);
|
||||
|
||||
// === ACTUACIONES ===
|
||||
add_submenu_page(
|
||||
'bloques-dashboard',
|
||||
__('Actuaciones', 'bloques-transicion'),
|
||||
__('Actuaciones', 'bloques-transicion'),
|
||||
'edit_posts',
|
||||
'edit.php?post_type=actuacion'
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
'bloques-dashboard',
|
||||
__('Añadir Actuación', 'bloques-transicion'),
|
||||
__('↳ Añadir nueva', 'bloques-transicion'),
|
||||
'edit_posts',
|
||||
'post-new.php?post_type=actuacion'
|
||||
);
|
||||
|
||||
// === RECURSOS ===
|
||||
add_submenu_page(
|
||||
'bloques-dashboard',
|
||||
__('Recursos', 'bloques-transicion'),
|
||||
__('Recursos', 'bloques-transicion'),
|
||||
'edit_posts',
|
||||
'edit.php?post_type=recurso_bloques'
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
'bloques-dashboard',
|
||||
__('Añadir Recurso', 'bloques-transicion'),
|
||||
__('↳ Añadir nuevo', 'bloques-transicion'),
|
||||
'edit_posts',
|
||||
'post-new.php?post_type=recurso_bloques'
|
||||
);
|
||||
|
||||
// === EVENTOS ===
|
||||
add_submenu_page(
|
||||
'bloques-dashboard',
|
||||
__('Eventos', 'bloques-transicion'),
|
||||
__('Eventos', 'bloques-transicion'),
|
||||
'edit_posts',
|
||||
'edit.php?post_type=evento_bloques'
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
'bloques-dashboard',
|
||||
__('Añadir Evento', 'bloques-transicion'),
|
||||
__('↳ Añadir nuevo', 'bloques-transicion'),
|
||||
'edit_posts',
|
||||
'post-new.php?post_type=evento_bloques'
|
||||
);
|
||||
|
||||
// === SEPARADOR ===
|
||||
add_submenu_page(
|
||||
'bloques-dashboard',
|
||||
'',
|
||||
'<span style="display:block;border-top:1px solid #555;margin:10px 0;"></span>',
|
||||
'edit_posts',
|
||||
'#separator1'
|
||||
);
|
||||
|
||||
// === TAXONOMÍAS ===
|
||||
add_submenu_page(
|
||||
'bloques-dashboard',
|
||||
__('Iniciativas', 'bloques-transicion'),
|
||||
__('Iniciativas', 'bloques-transicion'),
|
||||
'manage_categories',
|
||||
'edit-tags.php?taxonomy=iniciativa'
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
'bloques-dashboard',
|
||||
__('Líneas de Trabajo', 'bloques-transicion'),
|
||||
__('Líneas de Trabajo', 'bloques-transicion'),
|
||||
'manage_categories',
|
||||
'edit-tags.php?taxonomy=linea_trabajo'
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
'bloques-dashboard',
|
||||
__('Tipos de Evento', 'bloques-transicion'),
|
||||
__('Tipos de Evento', 'bloques-transicion'),
|
||||
'manage_categories',
|
||||
'edit-tags.php?taxonomy=tipo_evento'
|
||||
);
|
||||
|
||||
// === SEPARADOR ===
|
||||
add_submenu_page(
|
||||
'bloques-dashboard',
|
||||
'',
|
||||
'<span style="display:block;border-top:1px solid #555;margin:10px 0;"></span>',
|
||||
'manage_options',
|
||||
'#separator2'
|
||||
);
|
||||
|
||||
// === HERRAMIENTAS ===
|
||||
add_submenu_page(
|
||||
'bloques-dashboard',
|
||||
__('Cargar datos iniciales', 'bloques-transicion'),
|
||||
__('⚙️ Cargar datos', 'bloques-transicion'),
|
||||
'manage_options',
|
||||
'bloques-seeder',
|
||||
[__CLASS__, 'render_seeder_page']
|
||||
);
|
||||
|
||||
// === AJUSTES ===
|
||||
add_submenu_page(
|
||||
'bloques-dashboard',
|
||||
__('Ajustes', 'bloques-transicion'),
|
||||
__('⚙️ Ajustes', 'bloques-transicion'),
|
||||
'manage_options',
|
||||
'bloques-settings',
|
||||
[__CLASS__, 'render_settings_page']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderizar página de ajustes
|
||||
*/
|
||||
public static function render_settings_page() {
|
||||
// Guardar opciones si se envió el formulario
|
||||
if (isset($_POST['bloques_settings_nonce']) && wp_verify_nonce($_POST['bloques_settings_nonce'], 'bloques_save_settings')) {
|
||||
$custom_css = isset($_POST['bloques_custom_css']) ? wp_strip_all_tags($_POST['bloques_custom_css']) : '';
|
||||
update_option('bloques_custom_css', $custom_css);
|
||||
$saved = true;
|
||||
}
|
||||
|
||||
$custom_css = get_option('bloques_custom_css', '');
|
||||
include BLOQUES_PLUGIN_DIR . 'templates/admin/settings.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Corregir menú padre activo
|
||||
*/
|
||||
public static function fix_parent_menu($parent_file) {
|
||||
global $current_screen;
|
||||
|
||||
if (!$current_screen) {
|
||||
return $parent_file;
|
||||
}
|
||||
|
||||
$post_types = Bloques_Post_Types::get_post_types();
|
||||
$taxonomies = Bloques_Taxonomies::get_taxonomies();
|
||||
|
||||
// Si estamos en un CPT de Bloques
|
||||
if (in_array($current_screen->post_type, $post_types)) {
|
||||
return 'bloques-dashboard';
|
||||
}
|
||||
|
||||
// Si estamos en una taxonomía de Bloques
|
||||
if (in_array($current_screen->taxonomy, $taxonomies)) {
|
||||
return 'bloques-dashboard';
|
||||
}
|
||||
|
||||
return $parent_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Corregir submenú activo
|
||||
*/
|
||||
public static function fix_submenu($submenu_file) {
|
||||
global $current_screen;
|
||||
|
||||
if (!$current_screen) {
|
||||
return $submenu_file;
|
||||
}
|
||||
|
||||
$post_types = Bloques_Post_Types::get_post_types();
|
||||
$taxonomies = Bloques_Taxonomies::get_taxonomies();
|
||||
|
||||
// CPTs
|
||||
if (in_array($current_screen->post_type, $post_types)) {
|
||||
if ($current_screen->base === 'post') {
|
||||
return 'post-new.php?post_type=' . $current_screen->post_type;
|
||||
}
|
||||
return 'edit.php?post_type=' . $current_screen->post_type;
|
||||
}
|
||||
|
||||
// Taxonomías
|
||||
if (in_array($current_screen->taxonomy, $taxonomies)) {
|
||||
return 'edit-tags.php?taxonomy=' . $current_screen->taxonomy;
|
||||
}
|
||||
|
||||
return $submenu_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderizar dashboard
|
||||
*/
|
||||
public static function render_dashboard() {
|
||||
// Obtener conteos
|
||||
$counts = [
|
||||
'actuacion' => wp_count_posts('actuacion')->publish ?? 0,
|
||||
'recurso_bloques' => wp_count_posts('recurso_bloques')->publish ?? 0,
|
||||
'evento_bloques' => wp_count_posts('evento_bloques')->publish ?? 0,
|
||||
];
|
||||
|
||||
$iniciativas = wp_count_terms(['taxonomy' => 'iniciativa', 'hide_empty' => false]);
|
||||
$lineas = wp_count_terms(['taxonomy' => 'linea_trabajo', 'hide_empty' => false]);
|
||||
|
||||
include BLOQUES_PLUGIN_DIR . 'templates/admin/dashboard.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderizar página de seeder
|
||||
*/
|
||||
public static function render_seeder_page() {
|
||||
// Procesar acción si se envió el formulario
|
||||
if (isset($_POST['bloques_seed_action']) && wp_verify_nonce($_POST['bloques_seed_nonce'], 'bloques_seed')) {
|
||||
$result = Bloques_Data_Seeder::seed_all();
|
||||
$message = $result ?
|
||||
__('Datos cargados correctamente.', 'bloques-transicion') :
|
||||
__('Error al cargar los datos.', 'bloques-transicion');
|
||||
$message_type = $result ? 'success' : 'error';
|
||||
}
|
||||
|
||||
include BLOQUES_PLUGIN_DIR . 'templates/admin/seeder.php';
|
||||
}
|
||||
}
|
||||
233
bloques-transicion/includes/class-data-seeder.php
Normal file
233
bloques-transicion/includes/class-data-seeder.php
Normal file
@@ -0,0 +1,233 @@
|
||||
<?php
|
||||
/**
|
||||
* Carga de datos iniciales (Iniciativas y Líneas de Trabajo)
|
||||
*
|
||||
* @package Bloques_Transicion
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class Bloques_Data_Seeder {
|
||||
|
||||
/**
|
||||
* Cargar todos los datos iniciales
|
||||
*/
|
||||
public static function seed_all() {
|
||||
$result_iniciativas = self::seed_iniciativas();
|
||||
$result_lineas = self::seed_lineas_trabajo();
|
||||
$result_tipos = self::seed_tipos_evento();
|
||||
|
||||
return $result_iniciativas && $result_lineas && $result_tipos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cargar Iniciativas
|
||||
*/
|
||||
public static function seed_iniciativas() {
|
||||
$iniciativas = [
|
||||
[
|
||||
'name' => 'Oficina de Transición Justa',
|
||||
'slug' => 'oficina-transicion-justa',
|
||||
'description' => 'Acompañamiento técnico, asesoramiento y formación para personas y comunidades interesadas en impulsar iniciativas de cambio.',
|
||||
'meta' => [
|
||||
'ubicacion_texto' => 'Puente y Villa de Vallecas',
|
||||
'estado' => 'Abierta - consultas permanentes',
|
||||
'color' => '#1E6B52',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Coles en transición',
|
||||
'slug' => 'coles-transicion',
|
||||
'description' => 'Acompañamiento en la elaboración e implementación de planes de adaptación climática en centros educativos y otras iniciativas de cambio con participación de la comunidad escolar.',
|
||||
'meta' => [
|
||||
'ubicacion_texto' => '7 centros en Puente y Villa de Vallecas',
|
||||
'estado' => 'En marcha',
|
||||
'color' => '#4A9B7F',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Comunidad energética',
|
||||
'slug' => 'comunidad-energetica',
|
||||
'description' => 'Acompañamiento en la creación de la Comunidad Energética Vallekana para producir, compartir y gestionar energía renovable.',
|
||||
'meta' => [
|
||||
'ubicacion_texto' => 'Puente de Vallecas',
|
||||
'estado' => 'En proceso de constitución',
|
||||
'color' => '#F4A261',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Creación de redes',
|
||||
'slug' => 'creacion-redes',
|
||||
'description' => 'Intercambio de conocimientos y participación. Acompañamiento e impulso del funcionamiento y la creación de redes locales y estatales multiactor para el aprendizaje y la puesta en marcha de acciones hacia la transición justa.',
|
||||
'meta' => [
|
||||
'ubicacion_texto' => 'Madrid, Cataluña y Valencia',
|
||||
'estado' => 'En proceso',
|
||||
'color' => '#E76F51',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
return self::insert_terms($iniciativas, 'iniciativa');
|
||||
}
|
||||
|
||||
/**
|
||||
* Cargar Líneas de Trabajo
|
||||
*/
|
||||
public static function seed_lineas_trabajo() {
|
||||
$lineas = [
|
||||
[
|
||||
'name' => 'Energía',
|
||||
'slug' => 'energia',
|
||||
'description' => 'Rehabilitación edificios, comunidades energéticas y autoconsumo renovable',
|
||||
'meta' => [
|
||||
'color' => '#F4A261',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Cuidados',
|
||||
'slug' => 'cuidados',
|
||||
'description' => 'Redes de apoyo mutuo y espacios vecinales',
|
||||
'meta' => [
|
||||
'color' => '#E9C46A',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Alimentación',
|
||||
'slug' => 'alimentacion',
|
||||
'description' => 'Alimentación sostenible y saludable y redes de consumo',
|
||||
'meta' => [
|
||||
'color' => '#2A9D8F',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Movilidad',
|
||||
'slug' => 'movilidad',
|
||||
'description' => 'Movilidad sostenible, uso de la bicicleta y espacio público',
|
||||
'meta' => [
|
||||
'color' => '#264653',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Renaturalización',
|
||||
'slug' => 'renaturalizacion',
|
||||
'description' => 'Renaturalización de comunidades y patios escolares',
|
||||
'meta' => [
|
||||
'color' => '#1E6B52',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Reutilización',
|
||||
'slug' => 'reutilizacion',
|
||||
'description' => 'Economía circular y consumo colaborativo',
|
||||
'meta' => [
|
||||
'color' => '#E76F51',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
return self::insert_terms($lineas, 'linea_trabajo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Cargar Tipos de Evento
|
||||
*/
|
||||
public static function seed_tipos_evento() {
|
||||
$tipos = [
|
||||
[
|
||||
'name' => 'Online',
|
||||
'slug' => 'online',
|
||||
'description' => 'Evento que se realiza de forma virtual',
|
||||
],
|
||||
[
|
||||
'name' => 'Presencial',
|
||||
'slug' => 'presencial',
|
||||
'description' => 'Evento que se realiza de forma presencial',
|
||||
],
|
||||
];
|
||||
|
||||
return self::insert_terms($tipos, 'tipo_evento');
|
||||
}
|
||||
|
||||
/**
|
||||
* Insertar términos en una taxonomía
|
||||
*/
|
||||
private static function insert_terms($terms, $taxonomy) {
|
||||
$success = true;
|
||||
|
||||
foreach ($terms as $term_data) {
|
||||
// Verificar si ya existe
|
||||
$existing = term_exists($term_data['slug'], $taxonomy);
|
||||
|
||||
if ($existing) {
|
||||
$term_id = is_array($existing) ? $existing['term_id'] : $existing;
|
||||
|
||||
// Actualizar descripción si existe
|
||||
wp_update_term($term_id, $taxonomy, [
|
||||
'description' => $term_data['description'] ?? '',
|
||||
]);
|
||||
} else {
|
||||
// Crear nuevo término
|
||||
$result = wp_insert_term(
|
||||
$term_data['name'],
|
||||
$taxonomy,
|
||||
[
|
||||
'slug' => $term_data['slug'],
|
||||
'description' => $term_data['description'] ?? '',
|
||||
]
|
||||
);
|
||||
|
||||
if (is_wp_error($result)) {
|
||||
$success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
$term_id = $result['term_id'];
|
||||
}
|
||||
|
||||
// Guardar meta datos con ACF si está disponible
|
||||
if (!empty($term_data['meta']) && function_exists('update_field')) {
|
||||
foreach ($term_data['meta'] as $key => $value) {
|
||||
update_field($key, $value, $taxonomy . '_' . $term_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eliminar todos los datos del plugin
|
||||
*/
|
||||
public static function clear_all() {
|
||||
// Eliminar términos de iniciativas
|
||||
$iniciativas = get_terms([
|
||||
'taxonomy' => 'iniciativa',
|
||||
'hide_empty' => false,
|
||||
]);
|
||||
foreach ($iniciativas as $term) {
|
||||
wp_delete_term($term->term_id, 'iniciativa');
|
||||
}
|
||||
|
||||
// Eliminar términos de líneas de trabajo
|
||||
$lineas = get_terms([
|
||||
'taxonomy' => 'linea_trabajo',
|
||||
'hide_empty' => false,
|
||||
]);
|
||||
foreach ($lineas as $term) {
|
||||
wp_delete_term($term->term_id, 'linea_trabajo');
|
||||
}
|
||||
|
||||
// Eliminar tipos de evento
|
||||
$tipos = get_terms([
|
||||
'taxonomy' => 'tipo_evento',
|
||||
'hide_empty' => false,
|
||||
]);
|
||||
foreach ($tipos as $term) {
|
||||
wp_delete_term($term->term_id, 'tipo_evento');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
192
bloques-transicion/includes/class-post-types.php
Normal file
192
bloques-transicion/includes/class-post-types.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Registro de Custom Post Types
|
||||
*
|
||||
* @package Bloques_Transicion
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class Bloques_Post_Types
|
||||
{
|
||||
|
||||
/**
|
||||
* Registrar todos los CPTs
|
||||
*/
|
||||
public static function register()
|
||||
{
|
||||
self::register_actuacion();
|
||||
self::register_recurso();
|
||||
self::register_evento();
|
||||
}
|
||||
|
||||
/**
|
||||
* CPT: Actuaciones
|
||||
*/
|
||||
private static function register_actuacion()
|
||||
{
|
||||
$labels = [
|
||||
'name' => _x('Actuaciones', 'Post type general name', 'bloques-transicion'),
|
||||
'singular_name' => _x('Actuación', 'Post type singular name', 'bloques-transicion'),
|
||||
'menu_name' => _x('Actuaciones', 'Admin Menu text', 'bloques-transicion'),
|
||||
'name_admin_bar' => _x('Actuación', 'Add New on Toolbar', 'bloques-transicion'),
|
||||
'add_new' => __('Añadir nueva', 'bloques-transicion'),
|
||||
'add_new_item' => __('Añadir nueva Actuación', 'bloques-transicion'),
|
||||
'new_item' => __('Nueva Actuación', 'bloques-transicion'),
|
||||
'edit_item' => __('Editar Actuación', 'bloques-transicion'),
|
||||
'view_item' => __('Ver Actuación', 'bloques-transicion'),
|
||||
'all_items' => __('Todas las Actuaciones', 'bloques-transicion'),
|
||||
'search_items' => __('Buscar Actuaciones', 'bloques-transicion'),
|
||||
'parent_item_colon' => __('Actuación padre:', 'bloques-transicion'),
|
||||
'not_found' => __('No se encontraron actuaciones.', 'bloques-transicion'),
|
||||
'not_found_in_trash' => __('No hay actuaciones en la papelera.', 'bloques-transicion'),
|
||||
'featured_image' => _x('Imagen destacada', 'Overrides the "Featured Image" phrase', 'bloques-transicion'),
|
||||
'set_featured_image' => _x('Establecer imagen destacada', 'Overrides the "Set featured image" phrase', 'bloques-transicion'),
|
||||
'remove_featured_image' => _x('Eliminar imagen destacada', 'Overrides the "Remove featured image" phrase', 'bloques-transicion'),
|
||||
'use_featured_image' => _x('Usar como imagen destacada', 'Overrides the "Use as featured image" phrase', 'bloques-transicion'),
|
||||
'archives' => _x('Archivo de Actuaciones', 'The post type archive label', 'bloques-transicion'),
|
||||
'insert_into_item' => _x('Insertar en actuación', 'Overrides the "Insert into post" phrase', 'bloques-transicion'),
|
||||
'uploaded_to_this_item' => _x('Subido a esta actuación', 'Overrides the "Uploaded to this post" phrase', 'bloques-transicion'),
|
||||
'filter_items_list' => _x('Filtrar lista de actuaciones', 'Screen reader text', 'bloques-transicion'),
|
||||
'items_list_navigation' => _x('Navegación de actuaciones', 'Screen reader text', 'bloques-transicion'),
|
||||
'items_list' => _x('Lista de actuaciones', 'Screen reader text', 'bloques-transicion'),
|
||||
];
|
||||
|
||||
$args = [
|
||||
'labels' => $labels,
|
||||
'public' => true,
|
||||
'publicly_queryable' => true,
|
||||
'show_ui' => true,
|
||||
'show_in_menu' => false, // Lo añadimos manualmente al menú de Bloques
|
||||
'query_var' => true,
|
||||
'rewrite' => ['slug' => 'bloques-en-transicion/actuaciones', 'with_front' => false],
|
||||
'capability_type' => 'post',
|
||||
'has_archive' => true,
|
||||
'hierarchical' => false,
|
||||
'menu_position' => null,
|
||||
'menu_icon' => 'dashicons-location-alt',
|
||||
'supports' => ['title', 'editor', 'thumbnail', 'excerpt', 'revisions'],
|
||||
'show_in_rest' => true,
|
||||
'taxonomies' => ['iniciativa', 'linea_trabajo'],
|
||||
];
|
||||
|
||||
register_post_type('actuacion', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* CPT: Recursos
|
||||
*/
|
||||
private static function register_recurso()
|
||||
{
|
||||
$labels = [
|
||||
'name' => _x('Recursos', 'Post type general name', 'bloques-transicion'),
|
||||
'singular_name' => _x('Recurso', 'Post type singular name', 'bloques-transicion'),
|
||||
'menu_name' => _x('Recursos', 'Admin Menu text', 'bloques-transicion'),
|
||||
'name_admin_bar' => _x('Recurso', 'Add New on Toolbar', 'bloques-transicion'),
|
||||
'add_new' => __('Añadir nuevo', 'bloques-transicion'),
|
||||
'add_new_item' => __('Añadir nuevo Recurso', 'bloques-transicion'),
|
||||
'new_item' => __('Nuevo Recurso', 'bloques-transicion'),
|
||||
'edit_item' => __('Editar Recurso', 'bloques-transicion'),
|
||||
'view_item' => __('Ver Recurso', 'bloques-transicion'),
|
||||
'all_items' => __('Todos los Recursos', 'bloques-transicion'),
|
||||
'search_items' => __('Buscar Recursos', 'bloques-transicion'),
|
||||
'parent_item_colon' => __('Recurso padre:', 'bloques-transicion'),
|
||||
'not_found' => __('No se encontraron recursos.', 'bloques-transicion'),
|
||||
'not_found_in_trash' => __('No hay recursos en la papelera.', 'bloques-transicion'),
|
||||
'featured_image' => _x('Imagen del recurso', 'Overrides the "Featured Image" phrase', 'bloques-transicion'),
|
||||
'set_featured_image' => _x('Establecer imagen', 'Overrides the "Set featured image" phrase', 'bloques-transicion'),
|
||||
'remove_featured_image' => _x('Eliminar imagen', 'Overrides the "Remove featured image" phrase', 'bloques-transicion'),
|
||||
'use_featured_image' => _x('Usar como imagen', 'Overrides the "Use as featured image" phrase', 'bloques-transicion'),
|
||||
'archives' => _x('Archivo de Recursos', 'The post type archive label', 'bloques-transicion'),
|
||||
'insert_into_item' => _x('Insertar en recurso', 'Overrides the "Insert into post" phrase', 'bloques-transicion'),
|
||||
'uploaded_to_this_item' => _x('Subido a este recurso', 'Overrides the "Uploaded to this post" phrase', 'bloques-transicion'),
|
||||
'filter_items_list' => _x('Filtrar lista de recursos', 'Screen reader text', 'bloques-transicion'),
|
||||
'items_list_navigation' => _x('Navegación de recursos', 'Screen reader text', 'bloques-transicion'),
|
||||
'items_list' => _x('Lista de recursos', 'Screen reader text', 'bloques-transicion'),
|
||||
];
|
||||
|
||||
$args = [
|
||||
'labels' => $labels,
|
||||
'public' => true,
|
||||
'publicly_queryable' => true,
|
||||
'show_ui' => true,
|
||||
'show_in_menu' => false,
|
||||
'query_var' => true,
|
||||
'rewrite' => ['slug' => 'bloques-en-transicion/recursos', 'with_front' => false],
|
||||
'capability_type' => 'post',
|
||||
'has_archive' => false, // Desactivado para usar la página de Divi
|
||||
'hierarchical' => false,
|
||||
'menu_position' => null,
|
||||
'menu_icon' => 'dashicons-media-document',
|
||||
'supports' => ['title', 'editor', 'thumbnail', 'excerpt', 'revisions'],
|
||||
'show_in_rest' => true,
|
||||
'taxonomies' => ['iniciativa', 'linea_trabajo'],
|
||||
];
|
||||
|
||||
register_post_type('recurso_bloques', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* CPT: Eventos
|
||||
*/
|
||||
private static function register_evento()
|
||||
{
|
||||
$labels = [
|
||||
'name' => _x('Eventos', 'Post type general name', 'bloques-transicion'),
|
||||
'singular_name' => _x('Evento', 'Post type singular name', 'bloques-transicion'),
|
||||
'menu_name' => _x('Eventos', 'Admin Menu text', 'bloques-transicion'),
|
||||
'name_admin_bar' => _x('Evento', 'Add New on Toolbar', 'bloques-transicion'),
|
||||
'add_new' => __('Añadir nuevo', 'bloques-transicion'),
|
||||
'add_new_item' => __('Añadir nuevo Evento', 'bloques-transicion'),
|
||||
'new_item' => __('Nuevo Evento', 'bloques-transicion'),
|
||||
'edit_item' => __('Editar Evento', 'bloques-transicion'),
|
||||
'view_item' => __('Ver Evento', 'bloques-transicion'),
|
||||
'all_items' => __('Todos los Eventos', 'bloques-transicion'),
|
||||
'search_items' => __('Buscar Eventos', 'bloques-transicion'),
|
||||
'parent_item_colon' => __('Evento padre:', 'bloques-transicion'),
|
||||
'not_found' => __('No se encontraron eventos.', 'bloques-transicion'),
|
||||
'not_found_in_trash' => __('No hay eventos en la papelera.', 'bloques-transicion'),
|
||||
'featured_image' => _x('Imagen del evento', 'Overrides the "Featured Image" phrase', 'bloques-transicion'),
|
||||
'set_featured_image' => _x('Establecer imagen', 'Overrides the "Set featured image" phrase', 'bloques-transicion'),
|
||||
'remove_featured_image' => _x('Eliminar imagen', 'Overrides the "Remove featured image" phrase', 'bloques-transicion'),
|
||||
'use_featured_image' => _x('Usar como imagen', 'Overrides the "Use as featured image" phrase', 'bloques-transicion'),
|
||||
'archives' => _x('Archivo de Eventos', 'The post type archive label', 'bloques-transicion'),
|
||||
'insert_into_item' => _x('Insertar en evento', 'Overrides the "Insert into post" phrase', 'bloques-transicion'),
|
||||
'uploaded_to_this_item' => _x('Subido a este evento', 'Overrides the "Uploaded to this post" phrase', 'bloques-transicion'),
|
||||
'filter_items_list' => _x('Filtrar lista de eventos', 'Screen reader text', 'bloques-transicion'),
|
||||
'items_list_navigation' => _x('Navegación de eventos', 'Screen reader text', 'bloques-transicion'),
|
||||
'items_list' => _x('Lista de eventos', 'Screen reader text', 'bloques-transicion'),
|
||||
];
|
||||
|
||||
$args = [
|
||||
'labels' => $labels,
|
||||
'public' => true,
|
||||
'publicly_queryable' => true,
|
||||
'show_ui' => true,
|
||||
'show_in_menu' => false,
|
||||
'query_var' => true,
|
||||
'rewrite' => ['slug' => 'bloques-en-transicion/eventos', 'with_front' => false],
|
||||
'capability_type' => 'post',
|
||||
'has_archive' => false, // Desactivado para usar la página de Divi
|
||||
'hierarchical' => false,
|
||||
'menu_position' => null,
|
||||
'menu_icon' => 'dashicons-calendar-alt',
|
||||
'supports' => ['title', 'editor', 'thumbnail', 'excerpt', 'revisions'],
|
||||
'show_in_rest' => true,
|
||||
'taxonomies' => ['iniciativa', 'linea_trabajo', 'tipo_evento'],
|
||||
];
|
||||
|
||||
register_post_type('evento_bloques', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener todos los CPTs del plugin
|
||||
*/
|
||||
public static function get_post_types()
|
||||
{
|
||||
return ['actuacion', 'recurso_bloques', 'evento_bloques'];
|
||||
}
|
||||
}
|
||||
1059
bloques-transicion/includes/class-shortcodes.php
Normal file
1059
bloques-transicion/includes/class-shortcodes.php
Normal file
File diff suppressed because it is too large
Load Diff
164
bloques-transicion/includes/class-taxonomies.php
Normal file
164
bloques-transicion/includes/class-taxonomies.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
/**
|
||||
* Registro de Taxonomías personalizadas
|
||||
*
|
||||
* @package Bloques_Transicion
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class Bloques_Taxonomies {
|
||||
|
||||
/**
|
||||
* Registrar todas las taxonomías
|
||||
*/
|
||||
public static function register() {
|
||||
self::register_iniciativa();
|
||||
self::register_linea_trabajo();
|
||||
self::register_tipo_evento();
|
||||
}
|
||||
|
||||
/**
|
||||
* Taxonomía: Iniciativas
|
||||
*/
|
||||
private static function register_iniciativa() {
|
||||
$labels = [
|
||||
'name' => _x('Iniciativas', 'taxonomy general name', 'bloques-transicion'),
|
||||
'singular_name' => _x('Iniciativa', 'taxonomy singular name', 'bloques-transicion'),
|
||||
'search_items' => __('Buscar Iniciativas', 'bloques-transicion'),
|
||||
'popular_items' => __('Iniciativas populares', 'bloques-transicion'),
|
||||
'all_items' => __('Todas las Iniciativas', 'bloques-transicion'),
|
||||
'parent_item' => __('Iniciativa padre', 'bloques-transicion'),
|
||||
'parent_item_colon' => __('Iniciativa padre:', 'bloques-transicion'),
|
||||
'edit_item' => __('Editar Iniciativa', 'bloques-transicion'),
|
||||
'view_item' => __('Ver Iniciativa', 'bloques-transicion'),
|
||||
'update_item' => __('Actualizar Iniciativa', 'bloques-transicion'),
|
||||
'add_new_item' => __('Añadir nueva Iniciativa', 'bloques-transicion'),
|
||||
'new_item_name' => __('Nombre de nueva Iniciativa', 'bloques-transicion'),
|
||||
'separate_items_with_commas' => __('Separar iniciativas con comas', 'bloques-transicion'),
|
||||
'add_or_remove_items' => __('Añadir o eliminar iniciativas', 'bloques-transicion'),
|
||||
'choose_from_most_used' => __('Elegir de las más usadas', 'bloques-transicion'),
|
||||
'not_found' => __('No se encontraron iniciativas.', 'bloques-transicion'),
|
||||
'no_terms' => __('No hay iniciativas', 'bloques-transicion'),
|
||||
'menu_name' => __('Iniciativas', 'bloques-transicion'),
|
||||
'items_list_navigation' => __('Navegación de iniciativas', 'bloques-transicion'),
|
||||
'items_list' => __('Lista de iniciativas', 'bloques-transicion'),
|
||||
'back_to_items' => __('← Volver a Iniciativas', 'bloques-transicion'),
|
||||
];
|
||||
|
||||
$args = [
|
||||
'labels' => $labels,
|
||||
'hierarchical' => true, // Como categorías
|
||||
'public' => true,
|
||||
'show_ui' => true,
|
||||
'show_admin_column' => true,
|
||||
'show_in_nav_menus' => true,
|
||||
'show_tagcloud' => false,
|
||||
'show_in_rest' => true,
|
||||
'rewrite' => ['slug' => 'bloques/iniciativa', 'with_front' => false],
|
||||
'query_var' => true,
|
||||
];
|
||||
|
||||
// Asociar a todos los CPTs de Bloques
|
||||
$post_types = ['actuacion', 'recurso_bloques', 'evento_bloques'];
|
||||
register_taxonomy('iniciativa', $post_types, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Taxonomía: Líneas de Trabajo
|
||||
*/
|
||||
private static function register_linea_trabajo() {
|
||||
$labels = [
|
||||
'name' => _x('Líneas de Trabajo', 'taxonomy general name', 'bloques-transicion'),
|
||||
'singular_name' => _x('Línea de Trabajo', 'taxonomy singular name', 'bloques-transicion'),
|
||||
'search_items' => __('Buscar Líneas de Trabajo', 'bloques-transicion'),
|
||||
'popular_items' => __('Líneas de Trabajo populares', 'bloques-transicion'),
|
||||
'all_items' => __('Todas las Líneas de Trabajo', 'bloques-transicion'),
|
||||
'parent_item' => __('Línea de Trabajo padre', 'bloques-transicion'),
|
||||
'parent_item_colon' => __('Línea de Trabajo padre:', 'bloques-transicion'),
|
||||
'edit_item' => __('Editar Línea de Trabajo', 'bloques-transicion'),
|
||||
'view_item' => __('Ver Línea de Trabajo', 'bloques-transicion'),
|
||||
'update_item' => __('Actualizar Línea de Trabajo', 'bloques-transicion'),
|
||||
'add_new_item' => __('Añadir nueva Línea de Trabajo', 'bloques-transicion'),
|
||||
'new_item_name' => __('Nombre de nueva Línea de Trabajo', 'bloques-transicion'),
|
||||
'separate_items_with_commas' => __('Separar líneas con comas', 'bloques-transicion'),
|
||||
'add_or_remove_items' => __('Añadir o eliminar líneas', 'bloques-transicion'),
|
||||
'choose_from_most_used' => __('Elegir de las más usadas', 'bloques-transicion'),
|
||||
'not_found' => __('No se encontraron líneas de trabajo.', 'bloques-transicion'),
|
||||
'no_terms' => __('No hay líneas de trabajo', 'bloques-transicion'),
|
||||
'menu_name' => __('Líneas de Trabajo', 'bloques-transicion'),
|
||||
'items_list_navigation' => __('Navegación de líneas', 'bloques-transicion'),
|
||||
'items_list' => __('Lista de líneas', 'bloques-transicion'),
|
||||
'back_to_items' => __('← Volver a Líneas de Trabajo', 'bloques-transicion'),
|
||||
];
|
||||
|
||||
$args = [
|
||||
'labels' => $labels,
|
||||
'hierarchical' => true,
|
||||
'public' => true,
|
||||
'show_ui' => true,
|
||||
'show_admin_column' => true,
|
||||
'show_in_nav_menus' => true,
|
||||
'show_tagcloud' => false,
|
||||
'show_in_rest' => true,
|
||||
'rewrite' => ['slug' => 'bloques/linea-trabajo', 'with_front' => false],
|
||||
'query_var' => true,
|
||||
];
|
||||
|
||||
$post_types = ['actuacion', 'recurso_bloques', 'evento_bloques'];
|
||||
register_taxonomy('linea_trabajo', $post_types, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Taxonomía: Tipo de Evento
|
||||
*/
|
||||
private static function register_tipo_evento() {
|
||||
$labels = [
|
||||
'name' => _x('Tipos de Evento', 'taxonomy general name', 'bloques-transicion'),
|
||||
'singular_name' => _x('Tipo de Evento', 'taxonomy singular name', 'bloques-transicion'),
|
||||
'search_items' => __('Buscar Tipos', 'bloques-transicion'),
|
||||
'popular_items' => __('Tipos populares', 'bloques-transicion'),
|
||||
'all_items' => __('Todos los Tipos', 'bloques-transicion'),
|
||||
'parent_item' => null,
|
||||
'parent_item_colon' => null,
|
||||
'edit_item' => __('Editar Tipo', 'bloques-transicion'),
|
||||
'view_item' => __('Ver Tipo', 'bloques-transicion'),
|
||||
'update_item' => __('Actualizar Tipo', 'bloques-transicion'),
|
||||
'add_new_item' => __('Añadir nuevo Tipo', 'bloques-transicion'),
|
||||
'new_item_name' => __('Nombre del nuevo Tipo', 'bloques-transicion'),
|
||||
'separate_items_with_commas' => __('Separar tipos con comas', 'bloques-transicion'),
|
||||
'add_or_remove_items' => __('Añadir o eliminar tipos', 'bloques-transicion'),
|
||||
'choose_from_most_used' => __('Elegir de los más usados', 'bloques-transicion'),
|
||||
'not_found' => __('No se encontraron tipos.', 'bloques-transicion'),
|
||||
'no_terms' => __('No hay tipos', 'bloques-transicion'),
|
||||
'menu_name' => __('Tipos de Evento', 'bloques-transicion'),
|
||||
'items_list_navigation' => __('Navegación de tipos', 'bloques-transicion'),
|
||||
'items_list' => __('Lista de tipos', 'bloques-transicion'),
|
||||
'back_to_items' => __('← Volver a Tipos', 'bloques-transicion'),
|
||||
];
|
||||
|
||||
$args = [
|
||||
'labels' => $labels,
|
||||
'hierarchical' => false, // Como etiquetas (permite múltiple selección)
|
||||
'public' => true,
|
||||
'show_ui' => true,
|
||||
'show_admin_column' => true,
|
||||
'show_in_nav_menus' => true,
|
||||
'show_tagcloud' => false,
|
||||
'show_in_rest' => true,
|
||||
'rewrite' => ['slug' => 'bloques/tipo-evento', 'with_front' => false],
|
||||
'query_var' => true,
|
||||
];
|
||||
|
||||
register_taxonomy('tipo_evento', ['evento_bloques'], $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener todas las taxonomías del plugin
|
||||
*/
|
||||
public static function get_taxonomies() {
|
||||
return ['iniciativa', 'linea_trabajo', 'tipo_evento'];
|
||||
}
|
||||
}
|
||||
493
bloques-transicion/templates/admin/dashboard.php
Normal file
493
bloques-transicion/templates/admin/dashboard.php
Normal file
@@ -0,0 +1,493 @@
|
||||
<?php
|
||||
/**
|
||||
* Template: Dashboard de Bloques en Transición
|
||||
*
|
||||
* @package Bloques_Transicion
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
<div class="wrap bloques-dashboard">
|
||||
<h1>
|
||||
<span class="dashicons dashicons-building"></span>
|
||||
<?php _e('Bloques en Transición', 'bloques-transicion'); ?>
|
||||
</h1>
|
||||
|
||||
<div class="bloques-dashboard-welcome">
|
||||
<h2><?php _e('Bienvenido al panel de gestión del microsite', 'bloques-transicion'); ?></h2>
|
||||
<p><?php _e('Desde aquí puedes gestionar todo el contenido del microsite "Bloques en Transición".', 'bloques-transicion'); ?></p>
|
||||
</div>
|
||||
|
||||
<div class="bloques-dashboard-stats">
|
||||
<div class="bloques-stat-card">
|
||||
<div class="bloques-stat-icon">
|
||||
<span class="dashicons dashicons-location-alt"></span>
|
||||
</div>
|
||||
<div class="bloques-stat-content">
|
||||
<span class="bloques-stat-number"><?php echo esc_html($counts['actuacion']); ?></span>
|
||||
<span class="bloques-stat-label"><?php _e('Actuaciones', 'bloques-transicion'); ?></span>
|
||||
</div>
|
||||
<a href="<?php echo admin_url('edit.php?post_type=actuacion'); ?>" class="bloques-stat-link">
|
||||
<?php _e('Ver todas', 'bloques-transicion'); ?> →
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="bloques-stat-card">
|
||||
<div class="bloques-stat-icon">
|
||||
<span class="dashicons dashicons-media-document"></span>
|
||||
</div>
|
||||
<div class="bloques-stat-content">
|
||||
<span class="bloques-stat-number"><?php echo esc_html($counts['recurso_bloques']); ?></span>
|
||||
<span class="bloques-stat-label"><?php _e('Recursos', 'bloques-transicion'); ?></span>
|
||||
</div>
|
||||
<a href="<?php echo admin_url('edit.php?post_type=recurso_bloques'); ?>" class="bloques-stat-link">
|
||||
<?php _e('Ver todos', 'bloques-transicion'); ?> →
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="bloques-stat-card">
|
||||
<div class="bloques-stat-icon">
|
||||
<span class="dashicons dashicons-calendar-alt"></span>
|
||||
</div>
|
||||
<div class="bloques-stat-content">
|
||||
<span class="bloques-stat-number"><?php echo esc_html($counts['evento_bloques']); ?></span>
|
||||
<span class="bloques-stat-label"><?php _e('Eventos', 'bloques-transicion'); ?></span>
|
||||
</div>
|
||||
<a href="<?php echo admin_url('edit.php?post_type=evento_bloques'); ?>" class="bloques-stat-link">
|
||||
<?php _e('Ver todos', 'bloques-transicion'); ?> →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bloques-dashboard-taxonomies">
|
||||
<h3><?php _e('Categorías', 'bloques-transicion'); ?></h3>
|
||||
<div class="bloques-tax-cards">
|
||||
<div class="bloques-tax-card">
|
||||
<strong><?php _e('Iniciativas', 'bloques-transicion'); ?></strong>
|
||||
<span class="bloques-tax-count"><?php echo esc_html($iniciativas); ?></span>
|
||||
<a href="<?php echo admin_url('edit-tags.php?taxonomy=iniciativa'); ?>">
|
||||
<?php _e('Gestionar', 'bloques-transicion'); ?>
|
||||
</a>
|
||||
</div>
|
||||
<div class="bloques-tax-card">
|
||||
<strong><?php _e('Líneas de Trabajo', 'bloques-transicion'); ?></strong>
|
||||
<span class="bloques-tax-count"><?php echo esc_html($lineas); ?></span>
|
||||
<a href="<?php echo admin_url('edit-tags.php?taxonomy=linea_trabajo'); ?>">
|
||||
<?php _e('Gestionar', 'bloques-transicion'); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bloques-dashboard-shortcuts">
|
||||
<h3><?php _e('Acciones rápidas', 'bloques-transicion'); ?></h3>
|
||||
<div class="bloques-shortcuts">
|
||||
<a href="<?php echo admin_url('post-new.php?post_type=actuacion'); ?>" class="button button-primary">
|
||||
<span class="dashicons dashicons-plus-alt"></span>
|
||||
<?php _e('Nueva Actuación', 'bloques-transicion'); ?>
|
||||
</a>
|
||||
<a href="<?php echo admin_url('post-new.php?post_type=recurso_bloques'); ?>" class="button button-primary">
|
||||
<span class="dashicons dashicons-plus-alt"></span>
|
||||
<?php _e('Nuevo Recurso', 'bloques-transicion'); ?>
|
||||
</a>
|
||||
<a href="<?php echo admin_url('post-new.php?post_type=evento_bloques'); ?>" class="button button-primary">
|
||||
<span class="dashicons dashicons-plus-alt"></span>
|
||||
<?php _e('Nuevo Evento', 'bloques-transicion'); ?>
|
||||
</a>
|
||||
<a href="<?php echo admin_url('admin.php?page=bloques-settings'); ?>" class="button">
|
||||
<span class="dashicons dashicons-admin-customizer"></span>
|
||||
<?php _e('CSS personalizado', 'bloques-transicion'); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bloques-dashboard-shortcodes">
|
||||
<h3><?php _e('Guía de Shortcodes', 'bloques-transicion'); ?></h3>
|
||||
|
||||
<div class="bloques-shortcode-section">
|
||||
<h4><?php _e('Shortcode principal', 'bloques-transicion'); ?></h4>
|
||||
<p class="description"><?php _e('Usa este shortcode para mostrar cualquier tipo de contenido con filtros y paginación.', 'bloques-transicion'); ?></p>
|
||||
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 45%;"><?php _e('Shortcode', 'bloques-transicion'); ?></th>
|
||||
<th><?php _e('Descripción', 'bloques-transicion'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>[bloques-listado type="recursos" filter="true"]</code></td>
|
||||
<td><?php _e('Recursos con filtros tipo botonera', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>[bloques-listado type="recursos" limit="9" pagination="true"]</code></td>
|
||||
<td><?php _e('Recursos con botón "Ver más"', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>[bloques-listado type="noticias" columns="3"]</code></td>
|
||||
<td><?php _e('Noticias en grid de 3 columnas', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>[bloques-listado type="eventos" widget="list"]</code></td>
|
||||
<td><?php _e('Eventos en formato lista', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>[bloques-listado type="actuaciones" filter="true" search="true"]</code></td>
|
||||
<td><?php _e('Actuaciones con filtros y buscador', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h5><?php _e('Atributos disponibles', 'bloques-transicion'); ?></h5>
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 20%;"><?php _e('Atributo', 'bloques-transicion'); ?></th>
|
||||
<th style="width: 25%;"><?php _e('Valores', 'bloques-transicion'); ?></th>
|
||||
<th style="width: 15%;"><?php _e('Default', 'bloques-transicion'); ?></th>
|
||||
<th><?php _e('Descripción', 'bloques-transicion'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>type</code></td>
|
||||
<td>recursos | noticias | eventos | actuaciones</td>
|
||||
<td>recursos</td>
|
||||
<td><?php _e('Tipo de contenido a mostrar', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>widget</code></td>
|
||||
<td>grid | list</td>
|
||||
<td>grid</td>
|
||||
<td><?php _e('Modo de visualización', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>columns</code></td>
|
||||
<td>1 | 2 | 3 | 4</td>
|
||||
<td>3</td>
|
||||
<td><?php _e('Número de columnas en grid', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>limit</code></td>
|
||||
<td>número</td>
|
||||
<td>-1 (todos)</td>
|
||||
<td><?php _e('Número máximo de items', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>pagination</code></td>
|
||||
<td>true | false</td>
|
||||
<td>false</td>
|
||||
<td><?php _e('Mostrar botón "Ver más"', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>filter</code></td>
|
||||
<td>true | false</td>
|
||||
<td>false</td>
|
||||
<td><?php _e('Mostrar filtros tipo botonera', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>search</code></td>
|
||||
<td>true | false</td>
|
||||
<td>false</td>
|
||||
<td><?php _e('Mostrar campo de búsqueda', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>iniciativa</code></td>
|
||||
<td>slug</td>
|
||||
<td>-</td>
|
||||
<td><?php _e('Filtrar por iniciativa (slug)', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>linea</code></td>
|
||||
<td>slug</td>
|
||||
<td>-</td>
|
||||
<td><?php _e('Filtrar por línea de trabajo (slug)', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>upcoming</code></td>
|
||||
<td>true | false</td>
|
||||
<td>true</td>
|
||||
<td><?php _e('Solo eventos futuros (solo para eventos)', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="bloques-shortcode-section">
|
||||
<h4><?php _e('Shortcodes con header (para Home)', 'bloques-transicion'); ?></h4>
|
||||
<p class="description"><?php _e('Bloques con cabecera y enlace "Ver más" para usar en la página de inicio.', 'bloques-transicion'); ?></p>
|
||||
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 45%;"><?php _e('Shortcode', 'bloques-transicion'); ?></th>
|
||||
<th><?php _e('Descripción', 'bloques-transicion'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>[bloques-novedades limit="3"]</code></td>
|
||||
<td><?php _e('Bloque de novedades con icono y enlace', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>[bloques-agenda limit="4"]</code></td>
|
||||
<td><?php _e('Bloque de agenda con próximos eventos', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h5><?php _e('Atributos para bloques con header', 'bloques-transicion'); ?></h5>
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 20%;"><?php _e('Atributo', 'bloques-transicion'); ?></th>
|
||||
<th style="width: 35%;"><?php _e('Default', 'bloques-transicion'); ?></th>
|
||||
<th><?php _e('Descripción', 'bloques-transicion'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>limit</code></td>
|
||||
<td>3 (novedades) / 4 (agenda)</td>
|
||||
<td><?php _e('Número de items', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>title</code></td>
|
||||
<td>"Novedades" / "Agenda"</td>
|
||||
<td><?php _e('Título del bloque', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>subtitle</code></td>
|
||||
<td>"Últimas noticias..." / "Próximas actividades"</td>
|
||||
<td><?php _e('Subtítulo', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>show_header</code></td>
|
||||
<td>true</td>
|
||||
<td><?php _e('Mostrar cabecera con icono', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>link_text</code></td>
|
||||
<td>"Ver todas las novedades" / "Ver calendario completo"</td>
|
||||
<td><?php _e('Texto del enlace', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>link_url</code></td>
|
||||
<td>/bloques-en-transicion/noticias/ | /bloques-en-transicion/eventos/</td>
|
||||
<td><?php _e('URL del enlace', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="bloques-shortcode-section">
|
||||
<h4><?php _e('Shortcodes de taxonomías', 'bloques-transicion'); ?></h4>
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 45%;"><?php _e('Shortcode', 'bloques-transicion'); ?></th>
|
||||
<th><?php _e('Descripción', 'bloques-transicion'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>[bloques-iniciativas columns="4"]</code></td>
|
||||
<td><?php _e('Cards de iniciativas', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>[bloques-lineas columns="6"]</code></td>
|
||||
<td><?php _e('Líneas de trabajo con iconos', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="bloques-shortcode-section">
|
||||
<h4><?php _e('Ejemplos de uso', 'bloques-transicion'); ?></h4>
|
||||
<div class="bloques-examples">
|
||||
<div class="bloques-example">
|
||||
<strong><?php _e('Página de Recursos:', 'bloques-transicion'); ?></strong>
|
||||
<code>[bloques-listado type="recursos" filter="true" search="true" limit="12" pagination="true"]</code>
|
||||
</div>
|
||||
<div class="bloques-example">
|
||||
<strong><?php _e('Home - Novedades y Agenda:', 'bloques-transicion'); ?></strong>
|
||||
<code>[bloques-novedades limit="3"]</code>
|
||||
<code>[bloques-agenda limit="4"]</code>
|
||||
</div>
|
||||
<div class="bloques-example">
|
||||
<strong><?php _e('Recursos de una iniciativa:', 'bloques-transicion'); ?></strong>
|
||||
<code>[bloques-listado type="recursos" iniciativa="coles-en-transicion"]</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.bloques-dashboard-welcome {
|
||||
background: linear-gradient(135deg, #1E6B52 0%, #2A9D8F 100%);
|
||||
color: white;
|
||||
padding: 30px;
|
||||
border-radius: 12px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
.bloques-dashboard-welcome h2 {
|
||||
color: white;
|
||||
margin-top: 0;
|
||||
}
|
||||
.bloques-dashboard-welcome p {
|
||||
opacity: 0.9;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.bloques-dashboard-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.bloques-stat-card {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
.bloques-stat-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 10px;
|
||||
background: #f0f9f7;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.bloques-stat-icon .dashicons {
|
||||
font-size: 24px;
|
||||
color: #1E6B52;
|
||||
}
|
||||
.bloques-stat-number {
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
color: #1f2937;
|
||||
}
|
||||
.bloques-stat-label {
|
||||
color: #6b7280;
|
||||
font-size: 14px;
|
||||
}
|
||||
.bloques-stat-link {
|
||||
color: #F97316;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
.bloques-dashboard-taxonomies,
|
||||
.bloques-dashboard-shortcuts,
|
||||
.bloques-dashboard-shortcodes {
|
||||
background: white;
|
||||
padding: 25px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.bloques-dashboard-taxonomies h3,
|
||||
.bloques-dashboard-shortcuts h3,
|
||||
.bloques-dashboard-shortcodes h3 {
|
||||
margin-top: 0;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.bloques-tax-cards {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.bloques-tax-card {
|
||||
background: #f8f9fa;
|
||||
padding: 15px 20px;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
.bloques-tax-count {
|
||||
background: #1E6B52;
|
||||
color: white;
|
||||
padding: 4px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.bloques-shortcuts {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.bloques-shortcuts .button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.bloques-shortcode-section {
|
||||
margin-top: 25px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
.bloques-shortcode-section:first-of-type {
|
||||
margin-top: 15px;
|
||||
padding-top: 0;
|
||||
border-top: none;
|
||||
}
|
||||
.bloques-shortcode-section h4 {
|
||||
margin: 0 0 10px;
|
||||
color: #1E6B52;
|
||||
}
|
||||
.bloques-shortcode-section h5 {
|
||||
margin: 20px 0 10px;
|
||||
color: #374151;
|
||||
}
|
||||
.bloques-shortcode-section .description {
|
||||
margin-bottom: 15px;
|
||||
color: #6b7280;
|
||||
}
|
||||
.bloques-examples {
|
||||
background: #f8f9fa;
|
||||
padding: 20px;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
.bloques-example {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
.bloques-example strong {
|
||||
color: #374151;
|
||||
}
|
||||
.bloques-example code {
|
||||
background: white;
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
}
|
||||
@media (max-width: 1024px) {
|
||||
.bloques-dashboard-stats {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.bloques-dashboard-stats {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.bloques-tax-cards {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
100
bloques-transicion/templates/admin/seeder.php
Normal file
100
bloques-transicion/templates/admin/seeder.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/**
|
||||
* Template: Página de carga de datos iniciales
|
||||
*
|
||||
* @package Bloques_Transicion
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
<div class="wrap bloques-seeder">
|
||||
<h1>
|
||||
<span class="dashicons dashicons-database-import"></span>
|
||||
<?php _e('Cargar datos iniciales', 'bloques-transicion'); ?>
|
||||
</h1>
|
||||
|
||||
<?php if (isset($message)): ?>
|
||||
<div class="notice notice-<?php echo esc_attr($message_type); ?> is-dismissible">
|
||||
<p><?php echo esc_html($message); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="bloques-seeder-info">
|
||||
<h2><?php _e('¿Qué datos se cargarán?', 'bloques-transicion'); ?></h2>
|
||||
|
||||
<div class="bloques-seeder-section">
|
||||
<h3><?php _e('Iniciativas (4)', 'bloques-transicion'); ?></h3>
|
||||
<ul>
|
||||
<li><strong>Oficina de Transición Justa</strong> - Puente y Villa de Vallecas</li>
|
||||
<li><strong>Coles en transición</strong> - 7 centros en Puente y Villa de Vallecas</li>
|
||||
<li><strong>Comunidad energética</strong> - Puente de Vallecas</li>
|
||||
<li><strong>Creación de redes</strong> - Madrid, Cataluña y Valencia</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="bloques-seeder-section">
|
||||
<h3><?php _e('Líneas de Trabajo (6)', 'bloques-transicion'); ?></h3>
|
||||
<ul>
|
||||
<li><strong>Energía</strong> - Rehabilitación edificios, comunidades energéticas y autoconsumo renovable</li>
|
||||
<li><strong>Cuidados</strong> - Redes de apoyo mutuo y espacios vecinales</li>
|
||||
<li><strong>Alimentación</strong> - Alimentación sostenible y saludable y redes de consumo</li>
|
||||
<li><strong>Movilidad</strong> - Movilidad sostenible, uso de la bicicleta y espacio público</li>
|
||||
<li><strong>Renaturalización</strong> - Renaturalización de comunidades y patios escolares</li>
|
||||
<li><strong>Reutilización</strong> - Economía circular y consumo colaborativo</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="bloques-seeder-section">
|
||||
<h3><?php _e('Tipos de Evento (2)', 'bloques-transicion'); ?></h3>
|
||||
<ul>
|
||||
<li><strong>Online</strong></li>
|
||||
<li><strong>Presencial</strong></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bloques-seeder-actions">
|
||||
<form method="post" action="">
|
||||
<?php wp_nonce_field('bloques_seed', 'bloques_seed_nonce'); ?>
|
||||
<input type="hidden" name="bloques_seed_action" value="1">
|
||||
|
||||
<p class="description">
|
||||
<?php _e('Esta acción creará o actualizará las categorías con los datos predefinidos. Los datos existentes no se eliminarán.', 'bloques-transicion'); ?>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<button type="submit" class="button button-primary button-hero">
|
||||
<span class="dashicons dashicons-database-import"></span>
|
||||
<?php _e('Cargar datos iniciales', 'bloques-transicion'); ?>
|
||||
</button>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="bloques-seeder-status">
|
||||
<h3><?php _e('Estado actual', 'bloques-transicion'); ?></h3>
|
||||
<?php
|
||||
$iniciativas_count = wp_count_terms(['taxonomy' => 'iniciativa', 'hide_empty' => false]);
|
||||
$lineas_count = wp_count_terms(['taxonomy' => 'linea_trabajo', 'hide_empty' => false]);
|
||||
$tipos_count = wp_count_terms(['taxonomy' => 'tipo_evento', 'hide_empty' => false]);
|
||||
?>
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><?php _e('Iniciativas', 'bloques-transicion'); ?></td>
|
||||
<td><strong><?php echo esc_html($iniciativas_count); ?></strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?php _e('Líneas de Trabajo', 'bloques-transicion'); ?></td>
|
||||
<td><strong><?php echo esc_html($lineas_count); ?></strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?php _e('Tipos de Evento', 'bloques-transicion'); ?></td>
|
||||
<td><strong><?php echo esc_html($tipos_count); ?></strong></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
149
bloques-transicion/templates/admin/settings.php
Normal file
149
bloques-transicion/templates/admin/settings.php
Normal file
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
/**
|
||||
* Template: Página de Ajustes
|
||||
*
|
||||
* @package Bloques_Transicion
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
<div class="wrap bloques-settings">
|
||||
<h1>
|
||||
<span class="dashicons dashicons-admin-settings"></span>
|
||||
<?php _e('Ajustes de Bloques en Transición', 'bloques-transicion'); ?>
|
||||
</h1>
|
||||
|
||||
<?php if (isset($saved) && $saved): ?>
|
||||
<div class="notice notice-success is-dismissible">
|
||||
<p><?php _e('Ajustes guardados correctamente.', 'bloques-transicion'); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="post" action="">
|
||||
<?php wp_nonce_field('bloques_save_settings', 'bloques_settings_nonce'); ?>
|
||||
|
||||
<div class="bloques-settings-section">
|
||||
<h2><?php _e('CSS Personalizado', 'bloques-transicion'); ?></h2>
|
||||
<p class="description">
|
||||
<?php _e('Añade CSS personalizado para los shortcodes de Bloques en Transición. Este CSS se cargará en el frontend.', 'bloques-transicion'); ?>
|
||||
</p>
|
||||
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="bloques_custom_css"><?php _e('CSS', 'bloques-transicion'); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<textarea
|
||||
name="bloques_custom_css"
|
||||
id="bloques_custom_css"
|
||||
rows="20"
|
||||
class="large-text code"
|
||||
style="font-family: monospace; font-size: 13px;"
|
||||
><?php echo esc_textarea($custom_css); ?></textarea>
|
||||
<p class="description">
|
||||
<?php _e('Puedes usar las variables CSS definidas:', 'bloques-transicion'); ?>
|
||||
</p>
|
||||
<pre style="background: #f6f7f7; padding: 15px; border-radius: 4px; font-size: 12px; overflow-x: auto;">
|
||||
--bloques-primary: #1E6B52; /* Color principal */
|
||||
--bloques-secondary: #2A9D8F; /* Color secundario */
|
||||
--bloques-accent: #F97316; /* Color de acento (naranja) */
|
||||
--bloques-text: #1f2937; /* Color del texto */
|
||||
--bloques-text-light: #6b7280; /* Color texto secundario */
|
||||
--bloques-bg: #f9fafb; /* Color de fondo */
|
||||
--bloques-border: #e5e7eb; /* Color de bordes */
|
||||
--bloques-radius: 12px; /* Radio de bordes */</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3><?php _e('Clases CSS disponibles', 'bloques-transicion'); ?></h3>
|
||||
<table class="wp-list-table widefat fixed striped" style="max-width: 800px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Clase', 'bloques-transicion'); ?></th>
|
||||
<th><?php _e('Descripción', 'bloques-transicion'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>.bloques-listado</code></td>
|
||||
<td><?php _e('Contenedor principal del shortcode', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.bloques-filters</code></td>
|
||||
<td><?php _e('Contenedor de filtros', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.bloques-filter-btn</code></td>
|
||||
<td><?php _e('Botones de filtro', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.bloques-filter-btn.active</code></td>
|
||||
<td><?php _e('Botón de filtro activo', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.bloques-items</code></td>
|
||||
<td><?php _e('Grid de items', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.bloques-card</code></td>
|
||||
<td><?php _e('Card de recurso o noticia', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.bloques-card-thumbnail</code></td>
|
||||
<td><?php _e('Imagen de la card', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.bloques-card-content</code></td>
|
||||
<td><?php _e('Contenido de la card', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.bloques-card-title</code></td>
|
||||
<td><?php _e('Título de la card', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.bloques-btn-outline</code></td>
|
||||
<td><?php _e('Botón con borde (descargar)', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.bloques-btn-load-more</code></td>
|
||||
<td><?php _e('Botón "Ver más"', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.bloques-agenda-item</code></td>
|
||||
<td><?php _e('Item de agenda', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.bloques-novedad-item</code></td>
|
||||
<td><?php _e('Item de novedad', 'bloques-transicion'); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p class="submit">
|
||||
<input type="submit" name="submit" class="button button-primary" value="<?php esc_attr_e('Guardar cambios', 'bloques-transicion'); ?>">
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.bloques-settings-section {
|
||||
background: white;
|
||||
padding: 20px 25px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
margin-top: 20px;
|
||||
}
|
||||
.bloques-settings-section h2 {
|
||||
margin-top: 0;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.bloques-settings-section h3 {
|
||||
margin-top: 30px;
|
||||
}
|
||||
</style>
|
||||
102
bloques-transicion/templates/frontend/item-actuaciones.php
Normal file
102
bloques-transicion/templates/frontend/item-actuaciones.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
/**
|
||||
* Template: Item de Actuación
|
||||
*
|
||||
* Variables disponibles:
|
||||
* - $id, $title, $excerpt, $content, $permalink, $thumbnail
|
||||
* - $iniciativas, $lineas, $widget, $type
|
||||
* - $es_piloto, $direccion, $localidad, $latitud, $longitud
|
||||
*
|
||||
* @package Bloques_Transicion
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$classes = ['bloques-item', 'bloques-item-actuacion'];
|
||||
if ($widget === 'list') {
|
||||
$classes[] = 'bloques-item-list';
|
||||
}
|
||||
if ($es_piloto) {
|
||||
$classes[] = 'bloques-item-piloto';
|
||||
}
|
||||
?>
|
||||
<article id="bloques-actuacion-<?php echo esc_attr($id); ?>" class="<?php echo esc_attr(implode(' ', $classes)); ?>">
|
||||
<?php if ($thumbnail): ?>
|
||||
<div class="bloques-item-thumbnail">
|
||||
<a href="<?php echo esc_url($permalink); ?>">
|
||||
<img src="<?php echo esc_url($thumbnail); ?>" alt="<?php echo esc_attr($thumbnail_alt ?: $title); ?>" loading="lazy">
|
||||
</a>
|
||||
<?php if ($es_piloto): ?>
|
||||
<span class="bloques-badge bloques-badge-piloto">
|
||||
<?php _e('Piloto', 'bloques-transicion'); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="bloques-item-content">
|
||||
<header class="bloques-item-header">
|
||||
<?php if (!empty($iniciativas)): ?>
|
||||
<div class="bloques-item-taxonomies">
|
||||
<?php foreach ($iniciativas as $term):
|
||||
$color = get_field('color', $term);
|
||||
$icono = get_field('icono', $term);
|
||||
?>
|
||||
<span class="bloques-tag bloques-tag-iniciativa" style="<?php echo $color ? '--tag-color: ' . esc_attr($color) . ';' : ''; ?>">
|
||||
<?php if ($icono): ?>
|
||||
<img src="<?php echo esc_url($icono); ?>" alt="" class="bloques-tag-icon">
|
||||
<?php endif; ?>
|
||||
<?php echo esc_html($term->name); ?>
|
||||
</span>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h3 class="bloques-item-title">
|
||||
<a href="<?php echo esc_url($permalink); ?>">
|
||||
<?php echo esc_html($title); ?>
|
||||
</a>
|
||||
</h3>
|
||||
</header>
|
||||
|
||||
<?php if ($excerpt): ?>
|
||||
<div class="bloques-item-excerpt">
|
||||
<?php echo wp_kses_post($excerpt); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($localidad || $direccion): ?>
|
||||
<div class="bloques-item-location">
|
||||
<span class="bloques-icon bloques-icon-location"></span>
|
||||
<?php
|
||||
$location_parts = array_filter([$direccion, $localidad]);
|
||||
echo esc_html(implode(', ', $location_parts));
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($lineas)): ?>
|
||||
<div class="bloques-item-lineas">
|
||||
<?php foreach ($lineas as $term):
|
||||
$icono = get_field('icono', $term);
|
||||
?>
|
||||
<span class="bloques-linea-badge" title="<?php echo esc_attr($term->name); ?>">
|
||||
<?php if ($icono): ?>
|
||||
<img src="<?php echo esc_url($icono); ?>" alt="<?php echo esc_attr($term->name); ?>">
|
||||
<?php else: ?>
|
||||
<?php echo esc_html(mb_substr($term->name, 0, 1)); ?>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<footer class="bloques-item-footer">
|
||||
<a href="<?php echo esc_url($permalink); ?>" class="bloques-item-link bloques-btn">
|
||||
<?php _e('Ver actuación', 'bloques-transicion'); ?>
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</article>
|
||||
72
bloques-transicion/templates/frontend/item-default.php
Normal file
72
bloques-transicion/templates/frontend/item-default.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
* Template: Item por defecto para listados
|
||||
*
|
||||
* Variables disponibles:
|
||||
* - $id, $title, $excerpt, $content, $permalink, $thumbnail
|
||||
* - $iniciativas, $lineas, $widget, $type
|
||||
*
|
||||
* @package Bloques_Transicion
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$classes = ['bloques-item', 'bloques-item-' . $type];
|
||||
if ($widget === 'list') {
|
||||
$classes[] = 'bloques-item-list';
|
||||
}
|
||||
?>
|
||||
<article id="bloques-item-<?php echo esc_attr($id); ?>" class="<?php echo esc_attr(implode(' ', $classes)); ?>">
|
||||
<?php if ($thumbnail): ?>
|
||||
<div class="bloques-item-thumbnail">
|
||||
<a href="<?php echo esc_url($permalink); ?>">
|
||||
<img src="<?php echo esc_url($thumbnail); ?>" alt="<?php echo esc_attr($thumbnail_alt ?: $title); ?>" loading="lazy">
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="bloques-item-content">
|
||||
<header class="bloques-item-header">
|
||||
<?php if (!empty($iniciativas) || !empty($lineas)): ?>
|
||||
<div class="bloques-item-taxonomies">
|
||||
<?php foreach ($iniciativas as $term):
|
||||
$color = get_field('color', $term);
|
||||
?>
|
||||
<span class="bloques-tag bloques-tag-iniciativa" style="<?php echo $color ? '--tag-color: ' . esc_attr($color) . ';' : ''; ?>">
|
||||
<?php echo esc_html($term->name); ?>
|
||||
</span>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?php foreach ($lineas as $term):
|
||||
$color = get_field('color', $term);
|
||||
?>
|
||||
<span class="bloques-tag bloques-tag-linea" style="<?php echo $color ? '--tag-color: ' . esc_attr($color) . ';' : ''; ?>">
|
||||
<?php echo esc_html($term->name); ?>
|
||||
</span>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h3 class="bloques-item-title">
|
||||
<a href="<?php echo esc_url($permalink); ?>">
|
||||
<?php echo esc_html($title); ?>
|
||||
</a>
|
||||
</h3>
|
||||
</header>
|
||||
|
||||
<?php if ($excerpt): ?>
|
||||
<div class="bloques-item-excerpt">
|
||||
<?php echo wp_kses_post($excerpt); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<footer class="bloques-item-footer">
|
||||
<a href="<?php echo esc_url($permalink); ?>" class="bloques-item-link">
|
||||
<?php _e('Ver más', 'bloques-transicion'); ?>
|
||||
<span class="bloques-arrow">→</span>
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</article>
|
||||
184
bloques-transicion/templates/frontend/item-eventos.php
Normal file
184
bloques-transicion/templates/frontend/item-eventos.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
/**
|
||||
* Template: Item de Evento
|
||||
*
|
||||
* Variables disponibles:
|
||||
* - $id, $title, $excerpt, $content, $permalink, $thumbnail
|
||||
* - $iniciativas, $lineas, $widget, $type, $date
|
||||
* - $fecha_inicio, $hora_inicio, $fecha_fin, $hora_fin
|
||||
* - $lugar, $direccion, $url_online, $url_inscripcion, $tipos_evento
|
||||
*
|
||||
* @package Bloques_Transicion
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Determinar si es online, presencial o híbrido
|
||||
$es_online = false;
|
||||
$es_presencial = false;
|
||||
if (!empty($tipos_evento)) {
|
||||
foreach ($tipos_evento as $tipo) {
|
||||
if ($tipo->slug === 'online') $es_online = true;
|
||||
if ($tipo->slug === 'presencial') $es_presencial = true;
|
||||
}
|
||||
}
|
||||
$modalidad = '';
|
||||
$modalidad_class = '';
|
||||
if ($es_online && $es_presencial) {
|
||||
$modalidad = __('Híbrido', 'bloques-transicion');
|
||||
$modalidad_class = 'bloques-modalidad-hibrido';
|
||||
} elseif ($es_online) {
|
||||
$modalidad = __('Online', 'bloques-transicion');
|
||||
$modalidad_class = 'bloques-modalidad-online';
|
||||
} elseif ($es_presencial) {
|
||||
$modalidad = __('Presencial', 'bloques-transicion');
|
||||
$modalidad_class = 'bloques-modalidad-presencial';
|
||||
}
|
||||
|
||||
// Meses en español abreviados
|
||||
$meses = [
|
||||
'01' => 'ENE', '02' => 'FEB', '03' => 'MAR', '04' => 'ABR',
|
||||
'05' => 'MAY', '06' => 'JUN', '07' => 'JUL', '08' => 'AGO',
|
||||
'09' => 'SEP', '10' => 'OCT', '11' => 'NOV', '12' => 'DIC',
|
||||
];
|
||||
|
||||
// Parsear fecha
|
||||
$dia = '';
|
||||
$mes = '';
|
||||
if ($fecha_inicio) {
|
||||
$fecha_clean = str_replace('-', '', $fecha_inicio);
|
||||
if (strlen($fecha_clean) >= 8) {
|
||||
$dia = ltrim(substr($fecha_clean, 6, 2), '0');
|
||||
$mes_num = substr($fecha_clean, 4, 2);
|
||||
$mes = $meses[$mes_num] ?? $mes_num;
|
||||
}
|
||||
}
|
||||
|
||||
// Determinar ubicación a mostrar
|
||||
$ubicacion_texto = $modalidad ?: $lugar;
|
||||
|
||||
// Widget "agenda" (para bloques-agenda)
|
||||
if ($widget === 'agenda'): ?>
|
||||
<article id="bloques-evento-<?php echo esc_attr($id); ?>" class="bloques-agenda-item">
|
||||
<div class="bloques-agenda-fecha">
|
||||
<span class="bloques-agenda-mes"><?php echo esc_html($mes); ?></span>
|
||||
<span class="bloques-agenda-dia"><?php echo esc_html($dia); ?></span>
|
||||
</div>
|
||||
<div class="bloques-agenda-content">
|
||||
<div class="bloques-agenda-meta">
|
||||
<?php if ($hora_inicio): ?>
|
||||
<span class="bloques-agenda-hora"><?php echo esc_html($hora_inicio); ?></span>
|
||||
<?php endif; ?>
|
||||
<?php if ($ubicacion_texto): ?>
|
||||
<span class="bloques-agenda-separator">•</span>
|
||||
<span class="bloques-agenda-ubicacion <?php echo esc_attr($modalidad_class); ?>">
|
||||
<?php echo esc_html($ubicacion_texto); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<h4 class="bloques-agenda-title"><?php echo esc_html($title); ?></h4>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<?php else:
|
||||
// Widget por defecto (list o grid)
|
||||
$classes = ['bloques-item', 'bloques-item-evento'];
|
||||
if ($widget === 'list') {
|
||||
$classes[] = 'bloques-item-list';
|
||||
}
|
||||
|
||||
// Formatear fecha completa
|
||||
$fecha_formateada = '';
|
||||
if ($fecha_inicio) {
|
||||
$fecha_obj = DateTime::createFromFormat('Ymd', str_replace('-', '', $fecha_inicio));
|
||||
if ($fecha_obj) {
|
||||
$meses_largo = ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'];
|
||||
$dia_num = $fecha_obj->format('j');
|
||||
$mes_nombre = $meses_largo[(int)$fecha_obj->format('n') - 1];
|
||||
$anio = $fecha_obj->format('Y');
|
||||
$fecha_formateada = "$dia_num de $mes_nombre, $anio";
|
||||
}
|
||||
}
|
||||
?>
|
||||
<article id="bloques-evento-<?php echo esc_attr($id); ?>" class="<?php echo esc_attr(implode(' ', $classes)); ?>">
|
||||
<div class="bloques-evento-fecha">
|
||||
<span class="bloques-evento-dia"><?php echo esc_html($dia); ?></span>
|
||||
<span class="bloques-evento-mes"><?php echo esc_html($mes); ?></span>
|
||||
</div>
|
||||
|
||||
<div class="bloques-item-content">
|
||||
<header class="bloques-item-header">
|
||||
<?php if ($modalidad): ?>
|
||||
<span class="bloques-evento-modalidad <?php echo esc_attr($modalidad_class); ?>">
|
||||
<?php echo esc_html($modalidad); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
|
||||
<h3 class="bloques-item-title">
|
||||
<a href="<?php echo esc_url($permalink); ?>">
|
||||
<?php echo esc_html($title); ?>
|
||||
</a>
|
||||
</h3>
|
||||
</header>
|
||||
|
||||
<div class="bloques-evento-meta">
|
||||
<?php if ($fecha_formateada): ?>
|
||||
<div class="bloques-evento-meta-item">
|
||||
<span class="bloques-icon bloques-icon-calendar"></span>
|
||||
<span><?php echo esc_html($fecha_formateada); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($hora_inicio): ?>
|
||||
<div class="bloques-evento-meta-item">
|
||||
<span class="bloques-icon bloques-icon-clock"></span>
|
||||
<span>
|
||||
<?php echo esc_html($hora_inicio); ?>
|
||||
<?php if ($hora_fin): ?>
|
||||
- <?php echo esc_html($hora_fin); ?>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($lugar || $direccion): ?>
|
||||
<div class="bloques-evento-meta-item">
|
||||
<span class="bloques-icon bloques-icon-location"></span>
|
||||
<span><?php echo esc_html($lugar ?: $direccion); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($excerpt): ?>
|
||||
<div class="bloques-item-excerpt">
|
||||
<?php echo wp_kses_post($excerpt); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($iniciativas)): ?>
|
||||
<div class="bloques-item-taxonomies">
|
||||
<?php foreach ($iniciativas as $term):
|
||||
$color = get_field('color', $term);
|
||||
?>
|
||||
<span class="bloques-tag bloques-tag-iniciativa" style="<?php echo $color ? '--tag-color: ' . esc_attr($color) . ';' : ''; ?>">
|
||||
<?php echo esc_html($term->name); ?>
|
||||
</span>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<footer class="bloques-item-footer">
|
||||
<a href="<?php echo esc_url($permalink); ?>" class="bloques-item-link bloques-btn">
|
||||
<?php _e('Ver evento', 'bloques-transicion'); ?>
|
||||
</a>
|
||||
<?php if ($url_inscripcion): ?>
|
||||
<a href="<?php echo esc_url($url_inscripcion); ?>" class="bloques-btn bloques-btn-secondary" target="_blank" rel="noopener">
|
||||
<?php _e('Inscribirse', 'bloques-transicion'); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</footer>
|
||||
</div>
|
||||
</article>
|
||||
<?php endif; ?>
|
||||
75
bloques-transicion/templates/frontend/item-noticias.php
Normal file
75
bloques-transicion/templates/frontend/item-noticias.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* Template: Item de Noticia
|
||||
*
|
||||
* Variables disponibles:
|
||||
* - $id, $title, $excerpt, $content, $permalink, $thumbnail
|
||||
* - $widget, $type, $date
|
||||
* - $category, $category_color
|
||||
*
|
||||
* @package Bloques_Transicion
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Widget compact (para bloques-novedades)
|
||||
if ($widget === 'compact'): ?>
|
||||
<article id="bloques-noticia-<?php echo esc_attr($id); ?>" class="bloques-novedad-item">
|
||||
<div class="bloques-novedad-content">
|
||||
<div class="bloques-novedad-meta">
|
||||
<?php if ($category): ?>
|
||||
<span class="bloques-novedad-category" style="background-color: <?php echo esc_attr($category_color); ?>;">
|
||||
<?php echo esc_html($category->name); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
<span class="bloques-novedad-date"><?php echo esc_html($date); ?></span>
|
||||
</div>
|
||||
<h4 class="bloques-novedad-title">
|
||||
<a href="<?php echo esc_url($permalink); ?>">
|
||||
<?php echo esc_html($title); ?>
|
||||
</a>
|
||||
</h4>
|
||||
<p class="bloques-novedad-excerpt">
|
||||
<?php echo wp_trim_words($excerpt, 15, '...'); ?>
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
<?php else:
|
||||
// Widget grid (card completa)
|
||||
$classes = ['bloques-card', 'bloques-card-noticia'];
|
||||
if ($widget === 'list') {
|
||||
$classes[] = 'bloques-card-horizontal';
|
||||
}
|
||||
?>
|
||||
<article id="bloques-noticia-<?php echo esc_attr($id); ?>" class="<?php echo esc_attr(implode(' ', $classes)); ?>">
|
||||
<a href="<?php echo esc_url($permalink); ?>" class="bloques-card-link">
|
||||
<div class="bloques-card-thumbnail">
|
||||
<?php if ($thumbnail): ?>
|
||||
<img src="<?php echo esc_url($thumbnail); ?>" alt="<?php echo esc_attr($thumbnail_alt ?: $title); ?>" loading="lazy">
|
||||
<?php else: ?>
|
||||
<div class="bloques-card-placeholder">
|
||||
<span class="bloques-card-placeholder-text">BLOQUES</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($category): ?>
|
||||
<span class="bloques-card-badge" style="background-color: <?php echo esc_attr($category_color); ?>;">
|
||||
<?php echo esc_html($category->name); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="bloques-card-content">
|
||||
<h3 class="bloques-card-title"><?php echo esc_html($title); ?></h3>
|
||||
|
||||
<?php if ($excerpt): ?>
|
||||
<p class="bloques-card-excerpt"><?php echo wp_trim_words($excerpt, 20, '...'); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<span class="bloques-card-date"><?php echo esc_html($date); ?></span>
|
||||
</div>
|
||||
</a>
|
||||
</article>
|
||||
<?php endif; ?>
|
||||
76
bloques-transicion/templates/frontend/item-recursos.php
Normal file
76
bloques-transicion/templates/frontend/item-recursos.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* Template: Item de Recurso (Grid Card)
|
||||
*
|
||||
* Variables disponibles:
|
||||
* - $id, $title, $excerpt, $content, $permalink, $thumbnail
|
||||
* - $iniciativas, $lineas, $widget, $type, $date
|
||||
* - $archivo, $tipo_recurso, $url_externa
|
||||
*
|
||||
* @package Bloques_Transicion
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Determinar URL de descarga
|
||||
$download_url = '';
|
||||
$file_info = '';
|
||||
$file_extension = '';
|
||||
$file_size = '';
|
||||
|
||||
if (!empty($archivo) && is_array($archivo)) {
|
||||
$download_url = $archivo['url'];
|
||||
$file_extension = strtoupper(pathinfo($archivo['filename'], PATHINFO_EXTENSION));
|
||||
$file_size = isset($archivo['filesize']) ? size_format($archivo['filesize']) : '';
|
||||
} elseif ($url_externa) {
|
||||
$download_url = $url_externa;
|
||||
$file_extension = 'WEB';
|
||||
}
|
||||
|
||||
// Clases según widget
|
||||
$classes = ['bloques-card', 'bloques-card-recurso'];
|
||||
if ($widget === 'list') {
|
||||
$classes[] = 'bloques-card-horizontal';
|
||||
}
|
||||
?>
|
||||
<article id="bloques-recurso-<?php echo esc_attr($id); ?>" class="<?php echo esc_attr(implode(' ', $classes)); ?>">
|
||||
<div class="bloques-card-thumbnail">
|
||||
<?php if ($thumbnail): ?>
|
||||
<img src="<?php echo esc_url($thumbnail); ?>" alt="<?php echo esc_attr($thumbnail_alt ?: $title); ?>" loading="lazy">
|
||||
<?php else: ?>
|
||||
<div class="bloques-card-placeholder">
|
||||
<span class="bloques-card-placeholder-text">COMMUNITY</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($file_extension): ?>
|
||||
<span class="bloques-card-badge"><?php echo esc_html($file_extension); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="bloques-card-content">
|
||||
<h3 class="bloques-card-title"><?php echo esc_html($title); ?></h3>
|
||||
|
||||
<?php if ($file_size): ?>
|
||||
<span class="bloques-card-meta">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M6 2c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6H6zm7 7V3.5L18.5 9H13z"/>
|
||||
</svg>
|
||||
<?php echo esc_html($file_size); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="bloques-card-footer">
|
||||
<?php if ($download_url): ?>
|
||||
<a href="<?php echo esc_url($download_url); ?>" class="bloques-btn-outline" target="_blank" rel="noopener">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
|
||||
</svg>
|
||||
<?php _e('Descargar', 'bloques-transicion'); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
48
bloques-transicion/uninstall.php
Normal file
48
bloques-transicion/uninstall.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* Desinstalación del plugin
|
||||
*
|
||||
* @package Bloques_Transicion
|
||||
*/
|
||||
|
||||
// Si no se llama desde WordPress, salir
|
||||
if (!defined('WP_UNINSTALL_PLUGIN')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Eliminar opciones del plugin
|
||||
delete_option('bloques_transicion_activated');
|
||||
delete_option('bloques_transicion_version');
|
||||
|
||||
// Nota: No eliminamos los CPTs ni taxonomías por defecto
|
||||
// para preservar el contenido del usuario.
|
||||
// Si se desea eliminar todo el contenido, descomentar las siguientes líneas:
|
||||
|
||||
/*
|
||||
// Eliminar todos los posts de los CPTs
|
||||
$post_types = ['actuacion', 'recurso_bloques', 'evento_bloques'];
|
||||
foreach ($post_types as $post_type) {
|
||||
$posts = get_posts([
|
||||
'post_type' => $post_type,
|
||||
'posts_per_page' => -1,
|
||||
'post_status' => 'any',
|
||||
]);
|
||||
|
||||
foreach ($posts as $post) {
|
||||
wp_delete_post($post->ID, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Eliminar taxonomías
|
||||
$taxonomies = ['iniciativa', 'linea_trabajo', 'tipo_evento'];
|
||||
foreach ($taxonomies as $taxonomy) {
|
||||
$terms = get_terms([
|
||||
'taxonomy' => $taxonomy,
|
||||
'hide_empty' => false,
|
||||
]);
|
||||
|
||||
foreach ($terms as $term) {
|
||||
wp_delete_term($term->term_id, $taxonomy);
|
||||
}
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user