Blackstar, la obra maestra de David Bowie como carta de despedida

Ahora mismo volviendo a escuchar este álbum, antes de entregarme a los brazos de Morfeo…

Valencia, 08/10/2026, G.B.
Hablar de ★ (pronunciado Blackstar), el vigésimo quinto y último álbum de estudio de David Bowie, es adentrarse en una de las obras conceptuales y despedidas artísticas más deslumbrantes de la historia de la música contemporánea.

La obra maestra como carta de despedida

Lanzado el 8 de enero de 2016 —coincidiendo exactamente con el 69º cumpleaños de Bowie— y apenas dos días antes de su fallecimiento el 10 de enero, Blackstar no fue un disco más en su discografía: fue su obra final concebida minuciosamente como un regalo de despedida para sus seguidores y para la historia.

Durante meses, Bowie mantuvo en estricto secreto su diagnóstico de cáncer terminal. En lugar de retirarse en silencio, decidió transformar su propia mortalidad en una última performance artística.

Innovación e identidad sonora

En lugar de recurrir a la nostalgia o repasar sus grandes éxitos, Bowie volvió a hacer lo que mejor sabía: reinventarse y arriesgar.

Fusión y libertad estilística: Para la producción del disco (junto a su inseparable Tony Visconti), convocó a un quinteto de jazz neoyorquino liderado por el saxofonista Donny McCaslin y el batería Mark Guiliana. El resultado no es un disco de jazz tradicional, sino un híbrido fascinante de art rock, experimental jazz, drum and bass y texturas electrónicas de vanguardia (con influencias de artistas contemporáneos como Kendrick Lamar, Death Grips o Boards of Canada).

 

Minimalismo en el arte visual: Diseñado por Jonathan Barnbrook, fue el primer álbum de estudio de Bowie que no mostró su rostro en la portada, sustituyéndolo por una estrella negra troquelada sobre fondo blanco, repleta de simbolismos ocultos (como las subdivisiones inferiores que componen tipográficamente la palabra «BOWIE»).

 

Repertorio imprescindible

Con solo 7 canciones y poco más de 40 minutos de duración, cada tema tiene un peso específico en la narrativa del disco:
  • «Blackstar» (9:57): Una suite de casi diez minutos dividida en varias fases sonoras que combina cánticos litúrgicos, paisajes de ciencia ficción, ritmos sincopados y alusiones al ocultismo y a la trascendencia.
  • «Lazarus»: El centro emocional del álbum. Con su icónico e inquietante verso inicial («Look up here, I’m in heaven / I’ve got scars that can’t be seen»), anticipó vívidamente lo que ocurriría solo unas horas después de su publicación.
  • «’Tis a Pity She Was a Whore» y «Sue (Or in a Season of Crime)»: Dos cortes reestructurados desde sesiones previas, caracterizados por una batería frenética, secciones de vientos convulsas y un dinamismo abrasivo.
  • «Girl Loves Me»: Un experimento lírico en el que Bowie mezcla el Nadsat (la jerga inventada por Anthony Burgess en La naranja mecánica) con el Polari (el argot subcultural del Londres de mediados del siglo XX).
  • «Dollar Days» y «I Can’t Give Everything Away»: El cierre perfecto para la obra. Dos piezas impregnadas de melancolía, elegancia y aceptación, donde la voz y la armónica de Bowie se despiden dejando una huella imborrable.

Legado

Blackstar fue recibido con aclamación universal por la crítica y el público, obteniendo múltiples premios Grammy de forma póstuma. Más allá de sus méritos musicales, ha quedado grabado en la memoria colectiva como el testamento definitivo de un artista insustituible que convirtió su último aliento en arte puro.

Bonus Track

Escucha esta canción…

 

Plugin Solicitud de Congresos para organizaciones

Valencia, 08/10/2026, G.B.
He actualizado y consolidado el plugin Solicitud Congreso (versión 1.6.1), una solución nativa concebida para optimizar el procedimiento de solicitud, aprobación y registro de asistencia a congresos para cualquier tipo de organización, empresa o institución.

Principales Novedades y Funcionalidades

  • Soporte Completo para Documentos Adjuntos: Permite adjuntar documentación acreditativa (programas, cartas de aceptación, justificaciones económicas) directamente en el formulario. Admite hasta 5 archivos por solicitud (PDF, Office, imágenes) con almacenamiento en una ubicación privada y descargas protegidas por permisos.

  • Doble Confirmación por Correo Electrónico: Cada acción (alta, modificación o cancelación) genera una notificación automática para los gestores y envía una copia exacta de confirmación al propio usuario solicitante con el resumen y sus adjuntos.

  • Integración Frontend por Shortcode: Con solo incluir el shortcode solicitud_congreso (entre corchetes, []) en cualquier página privada o de la intranet, los usuarios pueden enviar solicitudes, consultar su historial y gestionar o descargar sus documentos adjuntos sin necesidad de acceder al panel de administración de WordPress.

  • Panel de Control de Administración: Los administradores disponen de una pestaña de gestión global para revisar todas las solicitudes registradas, ajustar la dirección de correo notificadora y consultar la guía rápida de uso.

Garantía de Rendimiento y Seguridad

Siguiendo las directrices de desarrollo de Indaga.net, el plugin ha sido construido con tecnología 100% nativa de WordPress (API de WPDB, Options API y Shortcode API), sin depender de librerías de terceros ni servicios externos. Además, cuenta con validación estricta de seguridad anti-CSRF mediante nonces y aislamiento total de archivos adjuntos para garantizar el máximo cumplimiento en materia de protección de datos y privacidad.

Solicitud Congreso — Versión 1.6.1

  • Nombre del Plugin: Solicitud Congreso

  • Versión Actual: 1.6.1

  • Autor: Guillermo Beltrán Pilato / Indaga.net

  • Dominio del Texto: solicitud-congreso

  • Propósito: Gestión, solicitud y control centralizado de asistencia a congresos nacionales e internacionales para cualquier empresa, institución u organización. Incluye panel de control en administración, formulario frontend por shortcode, gestión privada de adjuntos y notificaciones automáticas por correo electrónico (con copia de confirmación al solicitante).

Arquitectura Técnica y Especificaciones

  1. Gestión de Base de Datos:

    • Tabla nativa independiente: {prefix}congresos.

    • Clave primaria con auto-incremento e índice secundario por id_solicitante para optimización de consultas.

    • Mantenimiento automático de estructura mediante dbDelta() y verificación dinámica de versión en el gancho plugins_loaded.

  2. Seguridad y Control de Acceso:

    • Sanitización y Escapado: Uso estricto de sanitize_text_field, sanitize_email, absint, esc_url_raw, esc_html y esc_attr.

    • Protección Anti-CSRF: Implementación de nonces dinámicos para operaciones de guardado, edición, borrado y descarga.

    • Aislamiento de Recursos: Validación de rol (manage_options) para vistas globales de administración y restricción estricta por get_current_user_id() para usuarios estándar.

  3. Sistema de Adjuntos Privado:

    • Carpeta Protegida: Guardado en wp-content/uploads/solicitud-congreso/ aislada de navegación mediante archivo .htaccess (Options -Indexes, Deny from all).

    • Ofuscación de Nombres: Guardado en disco con identificadores aleatorios de 24 caracteres (sc_nombre_aleatorio). El nombre original se mantiene en la base de datos dentro de una estructura JSON.

    • Descargas Seguras: Flujo de descarga derivado con verificación de permisos y cabeceras anti-caché (readfile con Content-Disposition).

    • Límites: Hasta 5 archivos por solicitud (máx. 5 MB por archivo) en formatos PDF, Word, ODT, Excel, JPG y PNG.

  4. Sistema Doble de Notificaciones por Email:

    • Notificaciones automáticas HTML en eventos de creación, modificación o cancelación/eliminación enviadas al correo del gestor.

    • Copia automática de confirmación enviada directamente al correo del solicitante (a través del email de contacto o del usuario registrado en WordPress).

    • Adjunto físico de archivos en el correo cuando el tamaño total acumulado no supere los 10 MB.

  5. Integración Frontend y Backend:

    • Shortcodes: solicitud_congreso y solicitud_congresos (entre corchetes []).

    • Patrón POST/Redirect/GET: Gestión de estados y mensajes temporales entre redirecciones mediante transients por usuario (sc_aviso_ y sc_form_old_).

    • Caché: Prevención explícita de almacenamiento en caché en páginas privadas activando la constante

    • Descargar el plugin desde mi pCloud 

Ejemplo:

Debes iniciar sesión para gestionar tus solicitudes de congreso. Iniciar sesión

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).

De músicas de ayer y hoy… y más allá

«It does not matter how slowly you go as long as you do not stop.»- Confucius

Es lo que me encontrado como frase aleatoria antes de publicar esta e-reflexión…

Valencia, 04/10/2026, G.B.
Bueno, ya queda poquito para mi 59 cumpleaños (madre mía!). Pero «no problemo»,:»Talk to the hand. mate!».

Mientras tanto, bastante cansado pero con ganas todavía de guerra, me permito el lujo de escuchar un poco de música, antes de apagarme, de ir a dormir; ese espejo o hermano de la muerte, que creo que mencionaba Borges.

Bien, de Ringo Starr -el cual sigue en activo , impresionante!- al album de Songs of the Century de George Michel, y ahora Peter Murphy, quemo los últimos cartuchos antes de abrazar el sueño de Morfeo, o como se llame.

Todavía quisiera hacer más coas (y tal vez las haga), pero es un buen momento para decir «Adiós, Papá, adiós Mamá,. Consíguenos un poco de dinero más». Bueno, no, que estoy cansado y soy un viejuno.

Aquí va un pequeño momento musical, tal vez demasiado movido para el momento del sueño, pero así de contradictorios somos los humanos…

Nighties!

Bonus track

Un descanso de unos pocos días…

Valencia, 30/09/2026, G.B.
Llevo bastante «tralla» últimamente, tanto en mi trabajo como con mis webs. Estudiar, aprender, experimentar y publicar está muy bien, pero descansar es fundamental. Despertarse a mitad de noche con la cabeza llena de ideas, aunque sean tontas, no mola nada de nada! Al día siguiente tienes que volver a la rutina, y sobre todo a madrugar: el precio es demasiado alto…

Así pues, me voy a dar el lujo de una pequeña pausa, aunque solo sea de dos o tres días (o lo que haga falta), en ese espacio. Os recomiendo que de vez en cuando, o todas las veces que sean necesarias, lo hagáis;  por vuestro bien, y el de los que comparten su vida con vosotros. Que al final todo se paga…

Hasta pronto!

PD. Os dejo un Bonus Track

 

 

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.

Cómo instalar Paper2Agent: convierte cualquier paper científico en un agente de IA consultable

Valencia, 25/09/2026, G.B.
Recientemente he leído un artículo sobre un proyecto que conecta modelos de lenguaje con herramientas externas vía MCP (Model Context Protocol). Se llama Paper2Agent: toma un paper científico con su repositorio de código y genera automáticamente un agente conversacional capaz de ejecutar los métodos del estudio. Nada de leerte el código y reconstruir el pipeline a mano, simplemente le preguntas directamente al agente.

El proyecto es de un equipo de Stanford (Jiacheng Miao, Joe R. Davis, Jonathan K. Pritchard y James Zou) y está publicado en GitHub bajo licencia MIT: github.com/jmiao24/Paper2Agent. Puedes probar Paper2Agent en modo live o instalarlo. Este es el proceso de instalación:

Lo que necesitas antes de empezar

  • Python 3.10 o superior
  • Node.js/npm, porque Claude Code (el agente de codificación de Anthropic sobre el que corre todo esto) se instala vía npm
  • Cuenta y acceso a Claude Code, la pieza que orquesta la generación del agente

Si no tienes Claude Code todavía, se instala en el mismo paso 3 de abajo, así que no hace falta que lo prepares antes por separado.

Instalación paso a paso

1. Clona el repositorio

git clone https://github.com/jmiao24/Paper2Agent.git
cd Paper2Agent

2. Instala la dependencia de Python

Solo necesitas fastmcp, la librería que monta el servidor MCP:

pip install fastmcp

Si trabajas con varios proyectos Python en la misma máquina (como hago yo), te recomiendo meterlo en un entorno virtual para no ensuciar el sistema global.

3. Instala y arranca Claude Code

npm install -g @anthropic-ai/claude-code
claude

Con esto ya tienes todo el terreno preparado.

Generar tu primer agente

El comando base es este:

bash Paper2Agent.sh \
  --project_dir <NOMBRE_PROYECTO> \
  --github_url <URL_DEL_REPOSITORIO>

Por ejemplo, para convertir el repositorio de Scanpy (muy usado en análisis de datos de célula única) en un agente:

bash Paper2Agent.sh \
  --project_dir Scanpy_Agent \
  --github_url https://github.com/scverse/scanpy \
  --tutorials "Preprocessing and clustering"

El flag --tutorials te deja acotar el proceso a un tutorial concreto del repositorio en lugar de procesarlo entero, algo que agradecerás si el proyecto original es grande. También existen --api (para repos que piden clave de autenticación) y --benchmark (para que genere y evalúe preguntas de referencia sobre el agente resultante).

Un aviso sobre tiempos y coste

Esto no es instantáneo. Según la documentación oficial, el proceso completo puede tardar entre 30 minutos y más de 3 horas, dependiendo de lo complejo que sea el código fuente del paper. Y no es gratis: usando Claude Sonnet 4, el coste estimado para repositorios grandes como el de AlphaGenome ronda los 15 dólares, como pago único por la generación del agente (no por cada consulta posterior).

Vale la pena tenerlo en cuenta antes de lanzarlo sobre un repositorio enorme solo por curiosidad.

Verificar que el agente está activo

Al terminar, Claude Code se abre automáticamente con el servidor MCP recién generado ya cargado. Para comprobarlo en cualquier momento:

claude mcp list

o, ya dentro de la sesión de Claude Code, el comando \mcp.

Atajo: MCP ya generados

Si solo quieres probar el concepto sin montar nada tú mismo, el repositorio ya ofrece tres servidores MCP remotos listos para usar, alojados en Hugging Face: AlphaGenome, Scanpy y TISSUE. Se conectan con:

bash launch_remote_mcp.sh \
  --working_dir <directorio_de_trabajo> \
  --mcp_name <nombre_mcp> \
  --mcp_url <url_del_servidor>

Por ejemplo, para el de AlphaGenome:

bash launch_remote_mcp.sh \
  --working_dir analysis_dir \
  --mcp_name alphagenome \
  --mcp_url https://Paper2Agent-alphagenome-mcp.hf.space

Es la forma más rápida de hacerse una idea de qué se puede hacer con esto antes de meterte a generar un agente propio desde un paper que te interese.

«Steam» de Peter Gabriel, momentos musicales

Valencia, 24/09/2026, G.B.
Tanto código, tanta historia… Un poquito de por favor, de relajación. Aquí va un vídeo de la canción «Steam» de Peter Gabriel (creo que con su hija, qué bonito!). Además es en directo, como debe ser… Es de la gira Secret World Tour.

Disfrutadla.

Bonus track

Y aquí el concierto entero o casi, no lo sé. Eso sí, mala calidad de sonido:

Y solo la música (disco 1, buena calidad de sonido):

 

Nextcloud: porqué no puedes borrar tus carpetas sincronizadas después de desinstalarlo

Valencia, 24/09/2026, G.B.
Si alguna vez has desinstalado el cliente de escritorio de Nextcloud y luego te has encontrado con que las carpetas que sincronizabas no se dejan borrar (ni siquiera como administrador, ni cambiando permisos NTFS) no es un fallo aislado. Es un problema conocido que tiene que ver con cómo funcionan los archivos virtuales en Windows.

El origen: archivos que no son archivos

Desde hace varias versiones, el cliente de Nextcloud para Windows ofrece dos modos de sincronización:

  • Archivos locales: Todo el contenido se descarga físicamente a tu disco duro.
  • Archivos virtuales (bajo demanda): Solo ves un marcador (placeholder) de cada archivo. El contenido real no se descarga hasta que lo abres.

Este segundo modo se apoya en una tecnología de Windows llamada Cloud Filter API, la misma que usa OneDrive para sus «archivos bajo demanda». Cada placeholder no es un archivo normal: es un reparse point, una entrada especial del sistema de archivos NTFS que le dice a Windows: «Esto no está aquí de verdad, pregúntale al driver de Nextcloud».

El problema aparece cuando desinstalas el cliente sin haber convertido antes esas carpetas a archivos locales. El controlador (driver) que sabía interpretar esos reparse points desaparece, pero las entradas se quedan en el disco, huérfanas. Windows ve algo que dice que es un reparse point gestionado por un proceso externo inexistente y bloquea la operación al no tener forma de resolverlo con normalidad.

Por qué cambiar permisos no sirve

Aquí está la trampa: como usuario, lo primero que se prueba es tomar posesión de la carpeta y ajustar las listas de control de acceso (ACL) de NTFS. Pero no es un problema de permisos.

El sistema operativo no te está diciendo que no tienes acceso, te está diciendo que no sabe qué es ese objeto. Los permisos estándar de Windows no tocan ni eliminan el atributo de reparse point.

Cómo solucionarlo

Opción rápida: desbloqueo de procesos

Cierra cualquier proceso de Nextcloud que pueda seguir corriendo en segundo plano y reinicia explorer.exe (o reinicia el equipo directamente). Muchas veces el bloqueo es simplemente un identificador (handle) que quedó abierto tras un cierre de sesión incompleto.

Opción limpia: reinstalación previa

Si tienes margen, vuelve a instalar el cliente, conecta de nuevo esa carpeta y cambia su configuración de «archivos virtuales» a «archivos locales». Esto fuerza la descarga completa y limpia los reparse points. Después ya puedes desconectar la cuenta y desinstalar la aplicación sin dejar rastro.

Opción quirúrgica: desde PowerShell con fsutil

Desde una ventana de PowerShell como administrador, puedes comprobar si un archivo o carpeta conserva dicho atributo ejecutando:

Get-Item 'C:\ruta\a\la\carpeta' | Select-Object Attributes

Si en los atributos devueltos aparece ReparsePoint, puedes eliminar el enlace directamente con la herramienta nativa fsutil:

fsutil reparsepoint delete "C:\ruta\a\la\carpeta"

Esto convierte el marcador en un archivo o directorio normal (vacío, ya que su contenido residía en la nube) que sí se puede borrar sin errores desde el explorador.

Último recurso

Arrancar Windows en Modo Seguro (donde no se cargan los controladores de integración con la nube) o emplear la herramienta robocopy con la opción /MIR contra una carpeta vacía para forzar el vaciado del directorio bloqueado.

La lección para la próxima vez

Si vas a desinstalar el cliente de Nextcloud, conviene poner primero las carpetas sincronizadas en modo «solo archivos locales» desde los ajustes de la aplicación antes de desconectar la cuenta. Es un paso de treinta segundos que te ahorra este dolor de cabeza por completo.

Buenos presagios, Good Omens…

Valencia, 23/09/2026, G.B.
Acabo de terminar el libro «Buenos presagios» («Good Omens«) de Terry Pratchett y Neil Gaiman. Debo decir que me ha encantado. Tanto es así que me he comprado la versión original, en inglés y voy a leerlo ya!.

«Buenos presagios (Good Omens) es un libro que os recomiendo encarecidamente, si os gusta la fantasía, claro… Os dejo un fragmento del mismo (en .pdf) en castellano.

Y no, no dejéis que se os caiga a la bañera, que Terry ya no os lo podrá firmar, por desgracia. Neil Gaiman podría hacerlo (aunque ya sin sombreo…) , pero tal vez con una sonrisa apagada por haber perdido a su «compadre»…

Una última cosa más: Adam Young, ¿se nos acaba ya realmente el mundo, o sigue la tregua?…

Más información del libro (Wikipedia)