Indaga Native Icons 1.2.0: Control de tamaño nativo y más iconos para nuestra biblioteca SVG

Valencia, 29/10/2026, G.B.
En mi intento hacia un desarrollo web completamente independiente y optimizado, los iconos son una pieza fundamental. Tras el lanzamiento inicial de una biblioteca de iconos vectoriales, echaba en falta una característica muy concreta para el día a día en la maquetación: un control de tamaño más versátil y directo sin necesidad de sobrecargar las hojas de estilo con clases auxiliares para cada medida. Con esa idea nace la versión 1.2.0 de Indaga Native Icons. Manteniendo el compromiso de cero dependencias externas y cero peticiones HTTP adicionales, esta nueva actualización introduce mejoras estructurales importantes tanto en el backend como en el motor de renderizado de los SVG.

Qué hay de nuevo en la versión 1.2.0

  • Control de tamaño nativo por atributo: Ahora el shortcode y la función PHP incorporan el parámetro size. Podemos definir tamaños preestablecidos (sm para 16px, md para 24px, lg para 32px y xl para 48px) o pasar directamente valores numéricos en píxeles (por ejemplo, size="32") para un control absoluto del diseño.
  • Ampliación de la biblioteca de iconos: Se han incorporado nuevos iconos clave para interfaces modernas de administración y frontend, abarcando elementos de estado, acciones de edición, seguridad (candados, visibilidad), utilidades de nube y el logotipo oficial de WordPress en SVG puro.
  • Optimización del panel de administración: La cuadrícula visual de la biblioteca en wp-admin se ha actualizado para reflejar de forma más intuitiva las opciones de copia rápida de shortcodes y las nuevas directrices de uso técnico.

Ejemplos prácticos de uso

La flexibilidad que aporta el nuevo atributo size simplifica la inserción de iconos tanto en el editor de bloques como en las plantillas PHP personalizadas de nuestros temas (siempre entre corchetes):


Y si estamos picando código directamente en un template del theme:

<?php echo indaga_icon( 'close', 'indaga-icon-danger', 'Cerrar ventana', '32' ); ?>

Privacidad, rendimiento y control absoluto

Depender de librerías de iconos externas como Font Awesome implica abrir la puerta a peticiones de red hacia servidores de terceros, scripts pesados y posibles problemas de privacidad o rendimiento en la carga inicial. Con Indaga Native Icons, todo el código SVG vive de forma interna, inyectándose de manera limpia y segura.

Seguimos sumando herramientas propias a Indaga.net y para quien las necesite. Hasta pronto!

Ficha técnica del plugin

  • Nombre del Plugin: Indaga Native Icons
  • Versión: 1.2.0 (Con control de tamaño nativo)
  • Autor: Guillermo Beltrán Pilato (Indaga.net)
  • Descripción: Biblioteca ampliada de iconos SVG nativos con control de tamaño dinámico mediante atributos. Diseñada para reemplazar por completo a Font Awesome y soluciones de terceros en WordPress con rendimiento absoluto y control total.
  • Acceso Backend: Menú lateral Iconos Indaga (wp-admin/admin.php?page=indaga-icons).
  • Alias / Shortcodes: (entre corchetes) indaga_icon name="nombre-icono" size="md" (admite parámetros adicionales como size [sm, md, lg, xl o numérico], class y label).
  • Dependencias: 0 (Cero) – Sin CDNs, sin llamadas a servidores externos, sin librerías pesadas.
  • Seguridad: Sanitización completa mediante sanitize_key(), esc_attr() y esc_html(). Bloqueo estricto de accesos directos (ABSPATH) y validación de permisos de usuario (manage_options).

Descargar plugin

Cuaderno Técnico: Plugin «Agenda Indaga» (v1.3.0), parte 3

Entrega 3: Los Shortcodes de Frontend (Formulario y Calendario Interactivo)

Valencia, 25/10/2026, G.B.
En las entregas anteriores vimos cómo levantar los cimientos del plugin en la base de datos y cómo estructurar el panel de administración en el backend. En este tercer bloque me centro en la parte visible para el usuario: los shortcodes que dan vida a la agenda en el frontend de la web.

Para conseguirlo, divido la funcionalidad en dos shortcodes independientes pero complementarios: indaga_agenda (entre corchetes) para gestionar el alta, edición y listado de citas, y calendario_agenda (entre corchetes) para renderizar el calendario mensual interactivo.

1. El Shortcode de Gestión y Formulario (indaga_agenda) (entre corchetes)

Este shortcode permite desplegar un formulario de alta y edición de eventos, acompañado de una tabla con los registros actuales de la instancia. Todo ello protegido mediante comprobaciones de sesión de usuario, validación de nonces y funciones de saneamiento de datos.

public function renderizar_shortcode_agenda( $atts ) {
    global $wpdb;
    $tabla = $wpdb->prefix . 'indaga_agenda';
    $atts = shortcode_atts( array( 'id' => 'default' ), $atts, 'indaga_agenda' );
    $grupo_id = sanitize_text_field( $atts['id'] );
    $user_id = get_current_user_id();
    $mensaje = '';

    // Procesamiento del formulario de guardado / edición
    if ( isset( $_POST['indaga_agenda_frontend_nonce'] ) && wp_verify_nonce( $_POST['indaga_agenda_frontend_nonce'], 'guardar_evento_frontend' ) ) {
        if ( !is_user_logged_in() ) {
            return '<p style="color:red;">Debes iniciar sesión para gestionar la agenda.</p>';
        }

        $evento_id = isset( $_POST['evento_id'] ) ? absint( $_POST['evento_id'] ) : 0;
        $titulo = sanitize_text_field( $_POST['titulo'] );
        $descripcion = sanitize_textarea_field( $_POST['descripcion'] );
        $fecha_inicio = sanitize_text_field( $_POST['fecha_inicio'] );
        $fecha_fin = sanitize_text_field( $_POST['fecha_fin'] );
        $categoria = sanitize_text_field( $_POST['categoria'] );

        if ( !empty( $titulo ) && !empty( $fecha_inicio ) ) {
            $datos = array(
                'user_id' => $user_id,
                'grupo_id' => $grupo_id,
                'titulo' => $titulo,
                'descripcion' => $descripcion,
                'fecha_inicio' => $fecha_inicio,
                'fecha_fin' => !empty( $fecha_fin ) ? $fecha_fin : $fecha_inicio,
                'categoria' => $categoria
            );

            if ( $evento_id > 0 ) {
                $wpdb->update( $tabla, $datos, array( 'id' => $evento_id ), array( '%d', '%s', '%s', '%s', '%s', '%s', '%s' ), array( '%d' ) );
                $mensaje = '<div style="background:#d4edda; color:#155724; padding:10px; margin-bottom:15px; border-radius:4px;">¡Evento actualizado con éxito!</div>';
            } else {
                $wpdb->insert( $tabla, $datos, array( '%d', '%s', '%s', '%s', '%s', '%s', '%s' ) );
                $mensaje = '<div style="background:#d4edda; color:#155724; padding:10px; margin-bottom:15px; border-radius:4px;">¡Evento creado con éxito!</div>';
            }
        }
    }
    // ... (código de renderizado de la vista y formulario)
}

Puntos clave del formulario:

  • Soporte multinstancia por atributo: A través del parámetro id="nombre_instancia" (por defecto default), delimito los registros que pertenecen a esa agenda concreta.
  • Doble funcionalidad (Alta / Edición): Si el sistema detecta un parámetro editar_id en la URL, carga automáticamente los datos del evento en los inputs para modificarlos sin duplicar registros.

2. El calendario interactivo (calendario_agenda) (entre corchetes)

Para mostrar los eventos en una vista de calendario mensual limpia y visual, transformo los registros de la base de datos a un array de JavaScript y construyo una cuadrícula dinámica.

public function renderizar_shortcode_calendario( $atts ) {
    global $wpdb;
    $tabla = $wpdb->prefix . 'indaga_agenda';
    $atts = shortcode_atts( array( 'id' => 'default' ), $atts, 'calendario_agenda' );
    $grupo_id = sanitize_text_field( $atts['id'] );

    $eventos = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $tabla WHERE grupo_id = %s ORDER BY fecha_inicio ASC", $grupo_id ) );
    
    $eventos_js = array();
    foreach ( $eventos as $ev ) {
        $eventos_js[] = array(
            'id' => $ev->id,
            'titulo' => $ev->titulo,
            'descripcion' => $ev->descripcion,
            'categoria' => $ev->categoria,
            'fecha_inicio' => $ev->fecha_inicio,
            'fecha_fin' => $ev->fecha_fin
        );
    }
    // ... (retorno del HTML y script de renderizado)
}

Características del motor visual en JavaScript:

  • Navegación fluida por meses: Botones de avance y retroceso (cambiarMes()) que recalculan los días de la semana y sitúan correctamente el primer día del mes.
  • Fichas modales emergentes: Al hacer clic sobre cualquier evento listado dentro de una casilla del calendario, se despliega una ventana flotante con los detalles completos (horarios, categoría y descripción).
  • Conexión directa con el alta: El botón superior «+ Añadir Evento» o hacer clic directamente sobre cualquier día del calendario desplaza la vista automáticamente hacia el formulario y precarga la fecha seleccionada.

Con esta tercera entrega queda completamente documentada la arquitectura del plugin Agenda Indaga (v1.3.0): desde los cimientos en la base de datos, pasando por el panel de administración multinstancia, hasta la interacción visual en el frontend.

Cuaderno Técnico: Plugin «Agenda Indaga» (v1.3.0), parte 2

Entrega 2: El Panel de Administración y la Gestión Multinstancia

En la primera entrega vimos los cimientos del plugin: la estructura principal con la clase IndagaAgenda, la seguridad inicial para bloquear accesos directos y la creación nativa de la tabla en la base de datos.

En este segundo bloque me centro en cómo está construido el panel de administración en el backend de WordPress (ubicado en Ajustes > Agenda Indaga), explicando el menú nativo, la estructura modular por pestañas y el control de las distintas instancias o grupos de eventos.

1. Registro del menú en el panel de administración

Para integrar la interfaz dentro del escritorio de WordPress sin cargar librerías adicionales, utilizo la API nativa de menús a través del gancho admin_menu:

public function registrar_menu_admin() {
    add_menu_page(
        'Agenda Indaga',              // Título de la página
        'Agenda Indaga',              // Título del menú
        'manage_options',             // Capacidad / Permiso requerido
        'indaga-agenda',              // Slug único del menú
        array( $this, 'renderizar_panel_admin' ), // Función de callback
        'dashicons-calendar-alt',     // Icono nativo de Dashicons
        6                             // Posición en la barra lateral
    );
}

Puntos clave:

  • manage_options: Garantizo que solo las cuentas con perfil de administración puedan acceder a este panel de control.
  • dashicons-calendar-alt: Aprovecho la librería de iconos nativa de WordPress (Dashicons), manteniendo el plugin sin dependencias externas.

2. Estructura modular por pestañas

Para que la experiencia de uso sea limpia e intuitiva, organizo el panel de administración en tres pestañas bien diferenciadas usando la navegación nativa de WordPress (nav-tab-wrapper):

  1. Gestión e Instancias: Control global de los eventos y de las instancias creadas.
  2. Instrucciones y Shortcodes: Guía rápida para saber cómo insertar los shortcodes.
  3. Ficha Técnica: Resumen de especificaciones del desarrollo.

El cambio entre pestañas se gestiona capturando el parámetro tab mediante la URL (p. ej., ?page=indaga-agenda&tab=instrucciones), sanitizándolo adecuadamente:

$tab = isset( $_GET['tab'] ) ? sanitize_text_field( $_GET['tab'] ) : 'gestion';
?>
<h2 class="nav-tab-wrapper">
    <a href="?page=indaga-agenda&tab=gestion" class="nav-tab <?php echo $tab === 'gestion' ? 'nav-tab-active' : ''; ?>">Gestión e Instancias</a>
    <a href="?page=indaga-agenda&tab=instrucciones" class="nav-tab <?php echo $tab === 'instrucciones' ? 'nav-tab-active' : ''; ?>">Instrucciones y Shortcodes</a>
    <a href="?page=indaga-agenda&tab=tecnica" class="nav-tab <?php echo $tab === 'tecnica' ? 'nav-tab-active' : ''; ?>">Ficha Técnica</a>
</h2>

3. Procesamiento seguro de acciones (eliminación con nonces)

Antes de pintar la vista o consultar los datos, verifico si se ha enviado alguna petición desde los formularios de administración (por ejemplo, para eliminar un evento suelto o una instancia completa).

La seguridad aquí descansa en dos pilares: comprobación de permisos y validación de Nonce para evitar ataques CSRF:

if ( isset( $_POST['indaga_agenda_nonce'] ) && wp_verify_nonce( $_POST['indaga_agenda_nonce'], 'indaga_agenda_admin_action' ) ) {
    
    // Eliminación de un evento individual
    if ( isset( $_POST['accion'] ) && $_POST['accion'] === 'eliminar_evento' && !empty( $_POST['evento_id'] ) ) {
        $evento_id = absint( $_POST['evento_id'] );
        $wpdb->delete( $tabla, array( 'id' => $evento_id ), array( '%d' ) );
        $mensaje = '<div class="updated notice"><p>Evento eliminado correctamente.</p></div>';
    
    // Eliminación de una instancia completa (y todos sus eventos asociados)
    } elseif ( isset( $_POST['accion'] ) && $_POST['accion'] === 'eliminar_instancia' && !empty( $_POST['grupo_id'] ) ) {
        $grupo_id = sanitize_text_field( $_POST['grupo_id'] );
        $wpdb->delete( $tabla, array( 'grupo_id' => $grupo_id ), array( '%s' ) );
        $mensaje = '<div class="updated notice"><p>Instancia completa y todos sus eventos asociados eliminados correctamente.</p></div>';
    }
}
  • wp_verify_nonce(): Garantiza que la petición se ha originado legítimamente dentro del panel y por un usuario autorizado.
  • absint() y sanitize_text_field(): Aseguran que los datos recibidos sean enteros positivos o cadenas limpias sin código malicioso.

4. Consulta agrupada para la gestión multinstancia

El valor diferencial de la versión 1.3.0 es el soporte multinstancia. Mediante una consulta SQL optimizada con agrupamiento (GROUP BY), obtengo la lista de todas las agendas o grupos existentes en la base de datos sin necesidad de tablas auxiliares:

$instancias = $wpdb->get_results( 
    "SELECT grupo_id, COUNT(*) as total_eventos, MIN(fecha_inicio) as primer_evento 
     FROM $tabla 
     GROUP BY grupo_id 
     ORDER BY grupo_id ASC" 
);

Con esto puedo renderizar una tabla clara que indica el nombre del grupo, cuántos eventos almacena y qué shortcode exacto debe copiarse para mostrar esa agenda concreta en el frontend:

<?php foreach ( $instancias as $inst ): ?>
    <tr>
        <td><strong><?php echo esc_html( $inst->grupo_id ); ?></strong></td>
        <td><?php echo esc_html( $inst->total_eventos ); ?> evento(s)</td>
        <td><code>

Acceso restringido: necesitas permisos de administrador para gestionar esta agenda. Iniciar sesión

</code></td> <td><code>

</code></td> <td> <form method="POST" style="display:inline;" onsubmit="return confirm('¿Estás seguro de eliminar esta instancia completa y todos sus eventos?');"> <?php wp_nonce_field( 'indaga_agenda_admin_action', 'indaga_agenda_nonce' ); ?> <input type="hidden" name="accion" value="eliminar_instancia"> <input type="hidden" name="grupo_id" value="<?php echo esc_attr( $inst->grupo_id ); ?>"> <button type="submit" class="button button-small button-link-delete">Eliminar Instancia</button> </form> </td> </tr> <?php endforeach; ?>

Con esto queda cubierto todo el funcionamiento del panel de administración y el control multinstancia desde el backend.

En la siguiente entrega abordaremos la tercera parte del cuaderno técnico: los Shortcodes de Frontend (indaga_agenda y calendario_agenda) (entre corchetes), analizando el formulario de alta de eventos y el calendario mensual interactivo programado en JavaScript nativo.

Hasta pronto!

Plugin Resúmenes Indaga

Ya lo explicaré. aquí va el shortcode. Las  cinco últimas entradas publicadas en Indaga.net.

Últimas entradas

Cuaderno Técnico: Plugin «Agenda Indaga» (v1.3.0), parte I

Valencia, 21/10/2026, G.B.
Empiezo una serie de cuadernos técnicos para explicar paso a paso los plugins de Indaga.net. Es una forma práctica de documentar el proceso, compartir el aprendizaje y, de paso, ver de un vistazo qué se puede mejorar o dónde falló algo en su día. Aquí va la primera parte del plugin Agenda Indaga.

Bloque 1: Cabecera, Seguridad y Estructura de la Clase Principal

Todo buen plugin de WordPress empieza con una cabecera limpia y un pequeño control de seguridad para evitar que nadie acceda al archivo directamente desde el navegador.

1. Cabecera del Plugin e Identificación

En las primeras líneas definimos los metadatos que lee WordPress en el listado de plugins. Destaca el uso del dominio de texto (indaga-agenda) y la especificación de autoría de Indaga.net:

<?php
/**
* Plugin Name: Agenda Indaga
* Plugin URI: https://indaga.net
* Description: Plugin nativo de agenda y eventos con soporte multinstancia avanzada...
* Version: 1.3.0
* Author: Guillermo Beltrán Pilato (Indaga.net)
* Author URI: https://indaga.net
* License: GPLv2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: indaga-agenda
*/

2. Bloqueo de Acceso Directo

La seguridad en WordPress empieza por proteger los archivos individuales frente a peticiones HTTP directas que no pasen por el núcleo del CMS. Si la constante global ABSPATH no está definida, abortamos la ejecución de inmediato:

if ( ! defined( 'ABSPATH' ) ) {
exit; // Seguridad: Evitar acceso directo
}

3. Patrón Singleton (IndagaAgenda)

Para evitar duplicidad de instancias y mantener el código ordenado y eficiente en memoria, implementamos el patrón Singleton. Esto garantiza que la clase solo se cargue una vez:

class IndagaAgenda {
private static $instance = null;

public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}

private function __construct() {
// Aquí engancharemos nuestros hooks de activación, menús y shortcodes
register_activation_hook( __FILE__, array( $this, 'activar_plugin' ) );
add_action( 'admin_menu', array( $this, 'registrar_menu_admin' ) );
add_shortcode( 'indaga_agenda', array( $this, 'renderizar_shortcode_agenda' ) );
add_shortcode( 'calendario_agenda', array( $this, 'renderizar_shortcode_calendario' ) );
}
}

// Inicializamos el plugin
IndagaAgenda::get_instance();

Bloque 2: Creación Nativa de la Base de Datos (activar_plugin)

Una de las premisas clave de los plugins en Indaga.net es cero dependencias externas: toda la información reside en nuestras propias tablas optimizadas dentro de la base de datos de WordPress.

Cuando el usuario activa el plugin por primera vez, se dispara el gancho (register_activation_hook) que ejecuta el siguiente método:

public function activar_plugin() {
global $wpdb;
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );

$tabla = $wpdb->prefix . 'indaga_agenda';
$charset_collate = $wpdb->get_charset_collate();

$sql = "CREATE TABLE $tabla (
id mediumint(9) NOT NULL AUTO_INCREMENT,
user_id bigint(20) NOT NULL,
grupo_id varchar(50) DEFAULT 'default' NOT NULL,
titulo varchar(255) NOT NULL,
descripcion text NOT NULL,
fecha_inicio datetime NOT NULL,
fecha_fin datetime NOT NULL,
categoria varchar(50) DEFAULT 'general' NOT NULL,
observaciones text DEFAULT '',
PRIMARY KEY (id),
KEY user_id (user_id),
KEY grupo_id (grupo_id),
KEY fecha_inicio (fecha_inicio)
) $charset_collate;";

dbDelta( $sql );
update_option( 'indaga_agenda_version', '1.3.0' );
}

¿Qué ocurre paso a paso en este método?

  1. global $wpdb;: Cargamos la clase global de WordPress para interactuar de forma segura con la base de datos.

  2. $wpdb->prefix: Añadimos el prefijo personalizado de las tablas de tu instalación de WordPress (por defecto solía ser wp_, resultando en wp_indaga_agenda), garantizando compatibilidad con cualquier entorno.

  3. dbDelta( $sql );: Es la función nativa recomendada de WordPress. Compara si la tabla ya existe o si necesita actualizar su esquema sin destruir los datos ya almacenados.

  4. Campos clave (grupo_id): Este campo es el corazón del soporte multinstancia avanzada, ya que nos permite filtrar y agrupar múltiples agendas independientes dentro de una misma tabla.

Continuaré…

Plugin para tener tu propia agenda dentro de tu WordPress: Agenda Indaga

NOTA: Corrijo bugs de la versión y añado funcionalidades (comentar en Cuadernos Técnicos y en el foro). Versión actual: 1.3.1

Valencia, 19/10/2026, G.B.
Hoy quiero hablaros de un nuevo añadido que ya forma parte de casa en Indaga.net: el plugin de Agenda. Si habéis seguido otros desarrollos por aquí (como el de contabilidad casera o el control de reservas), ya sabéis cómo me gusta plantear las cosas: herramientas 100% nativas, sin dependencias externas pesadas y con los datos guardados de forma segura en nuestra propia base de datos.

Tras darle unas cuantas vueltas para que el calendario mensual en JavaScript fuera fluido, permitiera ver las fichas de los eventos al instante y ofreciera una gestión limpia de altas, modificaciones y borrados desde el propio panel, el resultado final ya está funcionando a la perfección. Os dejo su ficha técnica.

Ficha Técnica del Plugin: Agenda Indaga

  • Nombre del Plugin: Agenda Indaga
  • Versión Actual: 1.3.1
  • Autor: Guillermo Beltrán Pilato (Indaga.net)
  • Licencia: GPLv2 o posterior (Software libre)
  • Descripción: Gestión centralizada de agenda, eventos y citas personales o institucionales con soporte multinstancia por pestañas, vistas de calendario mensual interactivo nativo con fichas modales emergentes y panel de administración seguro.
  • Acceso: Ajustes > Agenda Indaga (wp-admin/options-general.php?page=indaga-agenda)
  • Shortcodes Disponibles:
    • indaga_agenda id="default" — Despliega el formulario seguro de alta, edición y listado de gestión de eventos.
    • calendario_agenda id="default" — Renderiza el calendario mensual interactivo nativo en JavaScript vanilla, con fichas modales emergentes al hacer clic en los eventos.
  • Arquitectura de Base de Datos: Tabla nativa independiente {prefix}indaga_agenda con soporte para multi-instancias (grupo_id), gestión de fechas/horas, categorías y control de usuarios.
  • Dependencias: 100% nativo (PHP Vanilla, WordPress WPDB API, Options API y JavaScript/CSS nativos sin librerías externas).
  • Seguridad y Permisos: Sanitización completa de entradas (sanitize_text_field, sanitize_textarea_field, absint), escapado estricto en salidas (esc_html, esc_attr), protección Anti-CSRF mediante nonces de WordPress, consultas preparadas ($wpdb->prepare) y restricción de administración a la capacidad manage_options.
  • Descarga: Agenda Indaga

Ejemplo:

Acceso restringido: necesitas permisos de administrador para gestionar esta agenda. Iniciar sesión

Control y Reserva de Recursos (CRR): un sistema para la gestión de salas, equipos y servicios en WordPress

Valencia, 14/10/2026, G.B.
Os presento la versión 1.12.0 de mi plugin Control y Reserva de Recursos (CRR) para WordPress
. Una solución 100% nativa y completa diseñada para la gestión integral de inventarios, control de disponibilidad en tiempo real y reserva de espacios, materiales y servicios de forma sencilla e intuitiva desde la web.

Aquí va un ejemplo del sistema principal:

Debes iniciar sesión para realizar, editar o gestionar tus reservas.

Para ver la ocupación mensual en la vista de calendario:

Lun
Mar
Mié
Jue
Vie
Sáb
Dom
1
2
00:00 Sala Conferencias
3
00:00 Sala Conferencias
4
5
6
09:00 Microscopia
09:00 Sala Conferencias
7
09:00 Microscopia
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
×

Ficha de Reserva

Recurso:
Solicitante:
Fechas:
Horario:
Cantidad:
Precio Estimado:
Observaciones:

Acerca de CRR

La gestión eficiente de espacios compartidos, equipamiento de alta gama o servicios especializados suele requerir herramientas complejas o plataformas de terceros que escapan al control directo del sitio web. Con el objetivo de mantener una solución 100% nativa, ligera y sin dependencias externas, nace Control y Reserva de Recursos (CRR), un plugin diseñado a medida para centralizar todo el ciclo de reservas de forma independiente y segura.

¿Qué ofrece Control y Reserva de Recursos (CRR)?

Este desarrollo unifica en un único paquete todo lo necesario para que tanto los usuarios como los administradores gestionen la disponibilidad de recursos de manera fluida:

1. Gestión de Inventario y tipologías flexibles

El administrador cuenta con un panel completo de inventario integrado directamente en la base de datos de WordPress. Los recursos se pueden clasificar en tres grandes categorías (ampliables):

  • Espacios / Salas

  • Material / Equipamiento

  • Servicios Cada recurso incluye control de stock o capacidad simultánea, precio por hora configurable y un correo electrónico asignado para el responsable directo del recurso.

2. Selector inteligente con buscador y filtros en tiempo real

A la hora de solicitar una reserva, los usuarios disfrutan de un selector visual moderno. Permite filtrar los recursos por tipo mediante botones interactivos y refinar la búsqueda al instante escribiendo en un cajón de texto inteligente que filtra por nombre o tipología sin necesidad de recargar la página.

3. Cálculo automático de presupuestos y notificaciones

El sistema calcula de manera automática el coste estimado de la reserva en función de los días, las horas exactas de inicio/fin y la cantidad seleccionada. Además, envía de forma automatizada correos de confirmación y actualización tanto al solicitante como al responsable del recurso, incluyendo opcionalmente el desglose detallado del presupuesto.

4. Vista de calendario mensual interactiva

Mediante el shortcode crr_calendario, cualquier página de la web puede transformarse en un calendario de ocupación mensual. Las reservas se listan ordenadas por horario y, al hacer clic sobre cualquiera de ellas, se despliega una ficha flotante de detalles con toda la información clave de la reserva.

5. Panel de control frontend para usuarios autorizados

No todo depende del panel de administración de WordPress. El plugin permite definir en los ajustes generales una lista de correos electrónicos autorizados. Estos usuarios, sin necesidad de ser administradores, podrán acceder desde el frontal a un Panel de Gestión Avanzado que incluye:

  • Filtros por rango de fechas (Desde / Hasta).

  • Filtro por categorías de recursos.

  • Búsqueda de texto libre compatible con comodines (por ejemplo, utilizando asteriscos como *proyector* o Servicio de*).

6. Exportación dual: Excel y CSV

Para la labor administrativa y de reporting, el panel incluye opciones de exportación instantánea (tanto de todo el histórico como de los datos filtrados en pantalla). El usuario puede elegir entre:

  • 📊 Excel (.csv optimizado): Formato configurado con delimitador de punto y coma (;) y codificación UTF-8 con BOM, garantizando que tildes, eñes y caracteres especiales se abran perfectamente al hacer doble clic en Microsoft Excel o LibreOffice Calc.

  • 📄 CSV estándar: Para integraciones universales.

Compromiso técnico de desarrollo

Siguiendo las directrices de desarrollo nativo de Indaga.net, CRR destaca por:

  • Cero dependencias externas: Sin librerías JavaScript pesadas ni llamadas a APIs de terceros.

  • Seguridad rigurosa: Uso estricto de consultas preparadas ($wpdb), sanitización de entradas, escapado de salidas y validación mediante Nonces de WordPress.

  • Experiencia de usuario optimizada: Incorporación de persistencia de scroll mediante sessionStorage, evitando los molestos saltos al principio de la página tras enviar formularios o aplicar filtros.

  • 📋 Ficha Técnica del Plugin

    • Nombre del Plugin: Control y Reserva de Recursos (CRR)

    • Versión: 1.12.0

    • Autor: Guillermo Beltrán Pilato

    • Sitio Web: Indaga.net

    • Compatibilidad WordPress: 6.0 o superior

    • Licencia: Software libre / Independiente

    • Descripción Breve: Sistema completo e independiente para la gestión y reserva de recursos, salas y servicios con presupuestos automáticos, vista de calendario interactiva, selector avanzado por categorías con buscador instantáneo, panel frontal de filtrado dinámico y exportación dual (Excel optimizado o CSV estándar).

    • Shortcodes Disponibles:

      • crr_reservas (entre corchetes []): Muestra el formulario de solicitud, inventario y panel de gestión frontal.

      • crr_calendario (entre corchetes []): Renderiza la vista de calendario mensual de ocupación.

  • Descargar plugin

Plugin para contabilidad casera y control de pasos diarios

NOTA: Actualizo a la versión 1.7.9

Valencia, 17/10/2026, G.B.
Este plugin para WordPress permite llevar una gestión clara del presupuesto familiar y el patrimonio, ofreciendo balances por períodos, gráficos visuales de ingresos y gastos, y un historial sencillo para el registro de pasos diarios.

Ficha Técnica del Plugin

Contabilidad Casera Indaga

  • Nombre del Plugin: Contabilidad Casera Indaga
  • Versión actual: 1.7.9
  • Autor: Guillermo Beltrán Pilato (Indaga.net)
  • Sitio Web del Autor: https://indaga.net
  • Licencia: GPL-2.0+
  • Texto de Dominio: contabilidad-casera-indaga
  • Enlace de Descarga: Descargar v.1.7.9

Descripción General

Sistema de contabilidad casera privado, ligero, seguro y 100% nativo en WordPress. Diseñado bajo los estándares de desarrollo de Indaga.net, opera sin dependencias externas ni servicios de terceros, garantizando la absoluta privacidad de los datos financieros, presupuestarios y de actividad física del usuario.

Actualización: Contabilidad Casera Indaga v1.7.9

Te presento la nueva versión 1.7.9 de Contabilidad Casera Indaga, mi plugin privado de gestión doméstica, presupuestos y control de actividad física. En esta iteración he incorporado importantes mejoras enfocadas en la flexibilidad de los registros y en la optimización de las herramientas de consulta y edición diaria.

Las principales novedades e implementaciones de esta versión son:

Edición y Gestión Avanzada del Registro de Pasos

  • Edición directa en la interfaz: He añadido un soporte completo para modificar registros de pasos anteriores de forma intuitiva, permitiendo que al pulsar el botón de edición en la tabla de actividad, los datos se carguen automáticamente en el formulario superior para su actualización.

  • Control de unicidad por fecha: He reforzado la lógica de guardado y actualización para evitar duplicidades de fechas en los registros diarios, incorporando avisos claros en caso de conflicto.

Buscador de Conceptos Dedicado

  • Búsqueda multicriterio: Se mantiene y consolida el bloque de búsqueda independiente en la pestaña de Gestión Financiera, permitiendo filtrar instantáneamente los movimientos contables por descripción, concepto o categoría mediante consultas seguras con comodines (LIKE).

Presupuestos Mensuales y Categorías Flexibles

  • Selector y edición libre: El sistema de presupuestos sigue permitiendo seleccionar categorías existentes desde un menú desplegable dinámico o introducir nombres personalizados (como Gastos fantasma, Ocio, etc.) para un control granular de los límites mensuales.

Exportación Completa a CSV

  • Compatibilidad optimizada con Excel: Continúa disponible la descarga directa y segura del histórico contable y de actividad física en formato CSV con codificación UTF-8 con BOM y separadores por punto y coma (;).

Arquitectura, Privacidad y Seguridad

  • Desarrollo 100% nativo: Siguiendo la filosofía de Indaga.net, el plugin opera de forma completamente autónoma, sin dependencias externas, librerías de terceros ni llamadas a servicios o APIs de pago en la nube.

  • Actualización transparente: Mediante el control de versión de base de datos (cci_comprobar_version_db() y dbDelta), las tablas se actualizan de forma segura al cargar el plugin sin comprometer ni alterar los datos previos.

  • Seguridad integral: He reforzado la validación de permisos administrativos (manage_options), la sanitización rigurosa de entradas y la protección estricta contra ataques CSRF mediante Nonces.

Compromiso de desarrollo: Porqué las actualizaciones de mis plugins nunca más perderán funcionalidades

Valencia, 05/10/2026, G.B.
Me he dado cuenta de que, tras lanzar algunas actualizaciones en mis plugins, he llegado a perder por el camino funcionalidades que eran importantes para mí y para quienes los usan. A partir de ahora mi intención y compromiso es: ninguna actualización volverá a dar un paso atrás.

Cuando desarrollamos y evolucionamos software, es fácil centrarse en la emoción de lanzar una nueva característica o refactorizar el código. Sin embargo, la verdadera calidad de un plugin no solo se mide por lo nuevo que aporta, sino por respetar y conservar la estabilidad de todo lo que ya funcionaba.

Las 3 reglas de oro para las próximas versiones

Para garantizar que cada nueva versión sea una mejora 100% acumulativa, he establecido un protocolo de desarrollo estricto basado en tres pilares:

Compatibilidad acumulativa y no regresión:
Antes de liberar cualquier versión (como las recientes iteraciones de Contabilidad Casera Indaga), se verifica minuciosamente que cada función previa (desde la exportación de datos a CSV con UTF-8 BOM hasta los gráficos de análisis, el seguimiento de actividad o los sistemas de presupuestos) se mantenga intacta y plenamente operativa.

Evolución segura de la base de datos:
Las migraciones de datos y las modificaciones de tablas se seguirán ejecutando de forma incremental mediante procesos seguros (dbDelta y control de versiones interno). El historial de datos y las configuraciones estarán siempre a salvo, sin riesgo de sobrescritura o pérdida de registros.

Auditoría de código previa al despliegue:
Cada actualización pasará por un proceso de revisión completa para asegurar que ningún hook, acción o vista de la interfaz quede fuera por descuido al integrar nuevas herramientas.

Creciendo con solidez

El software debe evolucionar para simplificar la vida, no para complicarla reaprendiendo lo que ya estaba resuelto. Con este compromiso, cada actualización en Indaga.net sumará valor real, manteniendo intactas la confianza, la usabilidad y la potencia de herramientas desarrolladas. Al menos esa es mi intención…

Resumen de las directrices de desarrollo de plugins (Indaga.net)

  1. Retrocompatibilidad Garantizada: Las nuevas funciones deben añadirse como capas opcionales. No se eliminarán ni romperán funcionalidades existentes en instalaciones previas.

  2. Cero Dependencias Externas: Desarrollo 100% nativo en WordPress. Sin librerías JS/PHP de terceros ni llamadas a APIs externas innecesarias, garantizando máxima velocidad, independencia y ligereza.

  3. Seguridad Nativa y Rigurosa:

    • Sanitización de entradas (sanitize_text_field, sanitize_email, etc.).

    • Escapado de salidas (esc_html, esc_attr, esc_textarea, etc.).

    • Validación anti-CSRF mediante Nonces (wp_nonce_field, check_admin_referer).

    • Control estricto de permisos mediante capacidades de usuario (manage_options, user_id).

Cuaderno de Ideas: un plugin ligero para tus anotaciones privadas en WordPress

Valencia, 28/09/2026, G.B.
A la hora de gestionar publicaciones y proyectos de contenidos, la dispersión de notas es un dolor de cabeza. Solemos acumular anotaciones en aplicaciones externas, documentos sueltos o notas rápidas que terminan perdiéndose. Para resolver esto, decidí crear un cuaderno de ideas privado integrado dentro del propio panel de administración de WordPress, permitiéndome preparar borradores, visualizarlos de forma privada y exportarlos a distintos formatos (HTML, Markdown o TPL/BBCode para foros como phpBB) de manera 100% nativa.

¿Por qué desarrollar este plugin?

Aunque en el repositorio de WordPress existen bastantes extensiones para tomar notas, la gran mayoría sufren de dos grandes inconvenientes: o cargan librerías pesadas en JavaScript que ralentizan el panel, o guardan la información en servidores de terceros con modelos de suscripción.

Con este plugin conseguimos un entorno de trabajo rápido, privado e integrado en la base de datos de WordPress. Nos permite trabajar sin dependencias externas y transformar cualquier borrador en el código necesario para publicar en blogs, repositorios como GitHub o comunidades en phpBB.

Requisitos y arquitectura técnica

Para mantener el desarrollo ligero y libre de conflictos de compatibilidad, la arquitectura del plugin se apoya en tres pilares básicos:

  • Cero dependencias externas: Funciona única y exclusivamente con la API nativa de WordPress (Custom Post Types, Custom Taxonomies y Meta Boxes). No requiere frameworks ni scripts externos.
  • Seguridad por diseño: Implementa tokens de seguridad (nonces) para validar formularios, comprobación estricta de permisos de usuario (edit_posts), restricción de vista previa pública y sanitización de campos de texto antes de guardarlos en la base de datos.
  • Exportación y vista previa en el servidor: Genera vistas dinámicas para copiar el código transformado al portapapeles y permite la previsualización del post en el frontend de forma estrictamente privada (devolviendo un error 403 de acceso denegado si intenta acceder un usuario no autenticado).

El código completo del plugin

Crea la carpeta /wp-content/plugins/cuaderno-ideas/ y guarda dentro el archivo cuaderno-ideas.php con el siguiente código:

<?php
/**
 * Plugin Name: Cuaderno de Ideas Privado
 * Description: Diario de ideas privado para gestión de publicaciones con vista previa privada y exportación a HTML, Markdown y TPL (BBCode).
 * Version:     1.2.0
 * Author:      INDAGA.net
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Evitar acceso directo
}

/**
 * 1. REGISTRO DEL CUSTOM POST TYPE Y TAXONOMÍAS NATIVAS
 */
function cip_registrar_post_type() {
    $labels = array(
        'name'               => 'Ideas',
        'singular_name'      => 'Idea',
        'menu_name'          => 'Cuaderno Ideas',
        'add_new'            => 'Añadir Idea',
        'add_new_item'       => 'Añadir Nueva Idea',
        'edit_item'          => 'Editar Idea',
        'new_item'           => 'Nueva Idea',
        'view_item'          => 'Ver Idea Privada',
        'search_items'       => 'Buscar Ideas',
        'not_found'          => 'No se encontraron ideas',
    );

    $args = array(
        'labels'             => $labels,
        'public'             => false, // No se indexa en listados públicos
        'publicly_queryable' => true,  // Permite renderizar la vista individual
        'show_ui'            => true,  // Visible en el panel de administración
        'show_in_menu'       => true,
        'query_var'          => true,
        'rewrite'            => array( 'slug' => 'idea-privada' ),
        'capability_type'    => 'post',
        'has_archive'        => false,
        'hierarchical'       => false,
        'menu_position'      => 20,
        'menu_icon'          => 'dashicons-lightbulb',
        'supports'           => array( 'title', 'editor' ),
    );

    register_post_type( 'cip_idea', $args );

    // Categorías de Ideas
    register_taxonomy( 'cip_categoria', 'cip_idea', array(
        'label'        => 'Categorías de Ideas',
        'rewrite'      => false,
        'hierarchical' => true,
        'show_ui'      => true,
    ) );

    // Etiquetas de Ideas
    register_taxonomy( 'cip_etiqueta', 'cip_idea', array(
        'label'        => 'Etiquetas de Ideas',
        'rewrite'      => false,
        'hierarchical' => false,
        'show_ui'      => true,
    ) );
}
add_action( 'init', 'cip_registrar_post_type' );

/**
 * 2. SEGURIDAD: BLOQUEAR VISTA PÚBLICA A USUARIOS NO AUTENTICADOS
 */
function cip_proteger_vista_privada() {
    if ( is_singular( 'cip_idea' ) ) {
        if ( ! is_user_logged_in() || ! current_user_can( 'edit_posts' ) ) {
            wp_die(
                'Acceso restringido: Esta idea pertenece a un cuaderno de notas privado.',
                'Acceso Denegado',
                array( 'response' => 403 )
            );
        }
    }
}
add_action( 'template_redirect', 'cip_proteger_vista_privada' );

/**
 * 3. SUBMENÚ Y PÁGINA DE INSTRUCCIONES / CONFIGURACIÓN EN EL PANEL
 */
function cip_agregar_menu_instrucciones() {
    add_submenu_page(
        'edit.php?post_type=cip_idea',
        'Instrucciones y Uso',
        'Instrucciones',
        'manage_options',
        'cip-instrucciones',
        'cip_render_pagina_instrucciones'
    );
}
add_action( 'admin_menu', 'cip_agregar_menu_instrucciones' );

function cip_render_pagina_instrucciones() {
    $active_tab = isset( $_GET['tab'] ) ? sanitize_text_field( $_GET['tab'] ) : 'instrucciones';
    ?>
    <div class="wrap">
        <h1>Cuaderno de Ideas Privado</h1>

        <h2 class="nav-tab-wrapper">
            <a href="?post_type=cip_idea&page=cip-instrucciones&tab=instrucciones" class="nav-tab <?php echo $active_tab === 'instrucciones' ? 'nav-tab-active' : ''; ?>">
                Instrucciones
            </a>
            <a href="?post_type=cip_idea&page=cip-instrucciones&tab=ficha" class="nav-tab <?php echo $active_tab === 'ficha' ? 'nav-tab-active' : ''; ?>">
                Ficha Técnica
            </a>
        </h2>

        <div class="tab-content" style="margin-top:20px; background:#fff; padding:20px; border:1px solid #ccc; max-width:900px;">
            <?php if ( $active_tab === 'instrucciones' ) : ?>
                <h2>Guía de Uso del Cuaderno de Ideas</h2>
                <hr>
                <ol>
                    <li><strong>Crear una Idea:</strong> Dirígete a <code>Cuaderno Ideas &gt; Añadir Idea</code>. Escribe el título y el cuerpo del borrador utilizando el editor nativo.</li>
                    <li><strong>Ver Idea como Post Privado:</strong> Haz clic en el botón «Ver Idea Privada» en el panel lateral para abrir la vista individual de la entrada en el frontend (solo accesible si has iniciado sesión).</li>
                    <li><strong>Categorización:</strong> Asigna categorías y etiquetas en la barra lateral para organizar tus temas.</li>
                    <li><strong>Gestión de Estado:</strong> En el panel lateral «Detalles y Estado de la Idea», define la prioridad (Baja, Media, Alta), marca la casilla si ya ha sido publicada, e indica el lugar y fecha de publicación.</li>
                    <li><strong>Exportar Contenido:</strong> En el panel inferior del editor («Exportar Contenido»), selecciona entre las versiones <strong>HTML</strong>, <strong>Markdown</strong> o <strong>TPL (BBCode para phpBB)</strong> y utiliza los botones para copiar directamente el código al portapapeles.</li>
                </ol>
            <?php else : ?>
                <h2>Ficha del Plugin</h2>
                <hr>
                <p>Diario de ideas privado para gestión interna de publicaciones, vista previa privada e exportación a múltiples formatos de marcado.</p>
                
                <p><strong>Acceso:</strong> Cuaderno Ideas &gt; Instrucciones (<code>wp-admin/edit.php?post_type=cip_idea&amp;page=cip-instrucciones</code>)</p>
                
                <p><strong>Alias / Shortcodes:</strong> No aplica (es un plugin exclusivamente de administración interna privada).</p>
                
                <p><strong>Dependencias:</strong> Ninguna (100% nativo mediante Custom Post Types y API de WordPress).</p>
                
                <p><strong>Seguridad:</strong> Validación mediante nonces (<code>wp_verify_nonce</code>), restricción de vista previa en frontend (<code>template_redirect</code> con respuesta 403 para usuarios no autorizados), verificación de capacidades (<code>edit_posts</code>), sanitización al guardar (<code>sanitize_text_field</code>) y escapado estricto en la salida (<code>esc_textarea</code>, <code>esc_attr</code>, <code>esc_url</code>).</p>
            <?php endif; ?>
        </div>
    </div>
    <?php
}

/**
 * 4. CREACIÓN DE CAMPOS PERSONALIZADOS (META BOXES)
 */
function cip_agregar_meta_boxes() {
    add_meta_box(
        'cip_detalles_idea',
        'Detalles y Estado de la Idea',
        'cip_render_meta_box',
        'cip_idea',
        'side',
        'high'
    );

    add_meta_box(
        'cip_exportar_idea',
        'Exportar Contenido',
        'cip_render_export_box',
        'cip_idea',
        'normal',
        'high'
    );
}
add_action( 'add_meta_boxes', 'cip_agregar_meta_boxes' );

function cip_render_meta_box( $post ) {
    wp_nonce_field( 'cip_guardar_metas', 'cip_nonce' );

    $prioridad   = get_post_meta( $post->ID, '_cip_prioridad', true ) ?: 'media';
    $publicado   = get_post_meta( $post->ID, '_cip_publicado', true );
    $donde       = get_post_meta( $post->ID, '_cip_donde_publicado', true );
    $fecha_pub   = get_post_meta( $post->ID, '_cip_fecha_publicado', true );
    $permalink   = get_permalink( $post->ID );

    ?>
    <?php if ( 'publish' === $post->post_status ) : ?>
        <p>
            <a href="<?php echo esc_url( $permalink ); ?>" target="_blank" class="button button-secondary" style="width:100%; text-align:center;">
                <span class="dashicons dashicons-visibility" style="vertical-align:middle; margin-top:-2px;"></span> Ver Idea Privada
            </a>
        </p>
        <hr>
    <?php endif; ?>

    <p>
        <label for="cip_prioridad"><strong>Prioridad:</strong></label><br>
        <select name="cip_prioridad" id="cip_prioridad" style="width:100%;">
            <option value="baja" <?php selected( $prioridad, 'baja' ); ?>>Baja</option>
            <option value="media" <?php selected( $prioridad, 'media' ); ?>>Media</option>
            <option value="alta" <?php selected( $prioridad, 'alta' ); ?>>Alta</option>
        </select>
    </p>
    <hr>
    <p>
        <label for="cip_publicado">
            <input type="checkbox" name="cip_publicado" id="cip_publicado" value="1" <?php checked( $publicado, '1' ); ?>>
            <strong>¿Publicado fuera?</strong>
        </label>
    </p>
    <p>
        <label for="cip_donde_publicado"><strong>¿Dónde se ha publicado?</strong></label><br>
        <input type="text" name="cip_donde_publicado" id="cip_donde_publicado" value="<?php echo esc_attr( $donde ); ?>" style="width:100%;" placeholder="Ej: Blog principal, Medium...">
    </p>
    <p>
        <label for="cip_fecha_publicado"><strong>Fecha de publicación:</strong></label><br>
        <input type="date" name="cip_fecha_publicado" id="cip_fecha_publicado" value="<?php echo esc_attr( $fecha_pub ); ?>" style="width:100%;">
    </p>
    <?php
}

/**
 * 5. GUARDADO SEGURO DE DATOS (SANITIZACIÓN)
 */
function cip_guardar_metas( $post_id ) {
    if ( ! isset( $_POST['cip_nonce'] ) || ! wp_verify_nonce( $_POST['cip_nonce'], 'cip_guardar_metas' ) ) {
        return;
    }
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return;
    }
    if ( ! current_user_can( 'edit_post', $post_id ) ) {
        return;
    }

    if ( isset( $_POST['cip_prioridad'] ) ) {
        update_post_meta( $post_id, '_cip_prioridad', sanitize_text_field( $_POST['cip_prioridad'] ) );
    }

    $publicado = isset( $_POST['cip_publicado'] ) ? '1' : '0';
    update_post_meta( $post_id, '_cip_publicado', $publicado );

    if ( isset( $_POST['cip_donde_publicado'] ) ) {
        update_post_meta( $post_id, '_cip_donde_publicado', sanitize_text_field( $_POST['cip_donde_publicado'] ) );
    }

    if ( isset( $_POST['cip_fecha_publicado'] ) ) {
        update_post_meta( $post_id, '_cip_fecha_publicado', sanitize_text_field( $_POST['cip_fecha_publicado'] ) );
    }
}
add_action( 'save_post', 'cip_guardar_metas' );

/**
 * 6. MOTOR DE EXPORTACIÓN (HTML, MARKDOWN, TPL/BBCODE)
 */
function cip_render_export_box( $post ) {
    $content = $post->post_content;
    $title   = $post->post_title;

    $markdown = "# " . $title . "\n\n" . strip_tags( $content );

    $bbcode = "[b]" . $title . "[/b]\n\n";
    $bbcode .= wp_strip_all_tags( $content );

    ?>
    <p>Copia directamente la idea convertida al formato de destino:</p>
    <div style="margin-bottom:15px;">
        <button type="button" class="button" onclick="document.getElementById('cip_exp_html').select(); document.execCommand('copy');">Copiar HTML</button>
        <button type="button" class="button" onclick="document.getElementById('cip_exp_md').select(); document.execCommand('copy');">Copiar Markdown</button>
        <button type="button" class="button" onclick="document.getElementById('cip_exp_tpl').select(); document.execCommand('copy');">Copiar TPL / BBCode</button>
    </div>

    <h4>HTML Limpio:</h4>
    <textarea id="cip_exp_html" style="width:100%; height:80px;" readonly><?php echo esc_textarea( wpautop( $content ) ); ?></textarea>

    <h4>Markdown (.md):</h4>
    <textarea id="cip_exp_md" style="width:100%; height:80px;" readonly><?php echo esc_textarea( $markdown ); ?></textarea>

    <h4>TPL / phpBB (BBCode):</h4>
    <textarea id="cip_exp_tpl" style="width:100%; height:80px;" readonly><?php echo esc_textarea( $bbcode ); ?></textarea>
    <?php
}

Explicación del código de forma sencilla

Para entender la lógica tras el plugin, podemos resumir su funcionamiento en cinco partes clave:

Custom Post Type privado pero consultable

Utilizamos register_post_type configurando 'public' => false pero activando 'publicly_queryable' => true. Esto nos permite generar un enlace individual para visualizar la entrada como si fuera un post publicado estándar dentro de nuestro tema gráfico, pero sin aparecer en buscadores ni en los listados generales del sitio.

Protección de la vista privada en el servidor

Para asegurar que nadie ajeno lea nuestras anotaciones, la función cip_proteger_vista_privada() se ejecuta en el hook template_redirect. Si un visitante no autenticado (o sin permisos de edición) intenta abrir la URL directa de una idea, el servidor interrumpe la carga y devuelve una pantalla de error 403 (Acceso Denegado).

Panel de Instrucciones integrado

Siguiendo la estructura limpia que usamos en nuestros desarrollos, se añade una página dentro del menú del plugin (Cuaderno Ideas > Instrucciones) con pestañas dinámicas que recogen la guía de uso y la ficha técnica con los detalles de seguridad y accesos.

Metadatos y control de estado

Mediante add_meta_box creamos un panel lateral en el editor para fijar la prioridad de la idea, indicar si ya ha sido publicada fuera, la fecha y el medio de destino. Al guardar, el proceso valida un código nonce anti-CSRF y limpia los datos recibidos mediante sanitize_text_field.

Motor de exportación al vuelo

El panel inferior convierte el título y el cuerpo del borrador a tres formatos limpios. Para el HTML aplica la función wpautop() para estructurar los párrafos; para Markdown añade la sintaxis básica de encabezados; y para TPL/phpBB traduce el formato a etiquetas BBCode tipo [b]. Incluye además botones en JavaScript nativo para copiar el resultado con un solo clic.

Si quieres probarlo, puedes descargarlo desde Control de plugins.