De Ivory Search al motor nativo: cómo crear tu propio buscador de WordPress seguro, ligero y sin plugins externos

Valencia, 23/09/2026, G.B.
La búsqueda interna es una de las piezas clave en cualquier sitio web con una buena cantidad de contenidos, categorías y enlaces. Sin embargo, mantener un buscador funcional en WordPress sin cargar el sitio de dependencias o scripts superfluos puede llegar a ser complicado.

Durante mucho tiempo estuve utilizando en el sitio el conocido plugin Ivory Search. Cumplía su función, pero tras las últimas actualizaciones comenzó a fallar hasta que dejó de funcionar del todo. Como solución provisional, opté por sustituirlo por un buscador integrado directamente en la barra de navegación del menú (proceso que ya os comenté en un post anterior aquí en Indaga.net). Aunque funcionaba (y sigue funcionando) correctamente para búsquedas rápidas, faltaba la flexibilidad de disponer de una caja de búsqueda limpia, personalizable y reutilizable mediante shortcode en cualquier página, entrada o widget.

La solución por la que me he decidido ha sido desarrollar un  plugin propio en un único archivo .php: 100% nativo, ligero, sin librerías de terceros y  seguro.

¿Por qué prescindir de plugins comerciales de búsqueda?

La mayoría de los plugins de búsqueda del repositorio introducen tablas adicionales en la base de datos, hojas de estilo CSS pesadas, scripts JavaScript que ralentizan el renderizado («pintado») y paneles llenos de características comerciales inútiles.

El núcleo de WordPress ya cuenta con un motor de búsqueda integrado extremadamente eficiente que se invoca mediante el parámetro estándar ?s=. Lo único que necesitamos es una interfaz limpia para capturar la búsqueda.

Los requisitos para este plugin han sido:

  • Cero dependencias externas: Sin librerías JS, sin llamadas a CDNs y con icono de lupa insertado en SVG nativo
  • Seguridad estricta: Validación y sanitización de todas las entradas del usuario y escape en el renderizado HTML (prevención de vulnerabilidades XSS
  • Aislamiento de estilos: Generación de selectores dinámicos para evitar conflictos con el tema activo de WordPress
  • Panel de administración e instrucciones: Un panel sencillo dentro de Ajustes > Buscador Indaga para cambiar colores, texto del placeholder y elegir varios diseños de maquetación
  • Atributos en Shortcode: Posibilidad de anular la configuración global directamente desde la etiqueta indaga_search (entre corchetes, []). Aquí podéis verlo insertado funcionamiento.

Estructura y código completo del plugin

Para instalarlo, basta con crear la carpeta /wp-content/plugins/indaga-search-plugin/ y guardar dentro el archivo indaga-search-plugin.php con el siguiente código PHP:

<?php
/**
 * Plugin Name: Indaga Search Form
 * Plugin URI:  https://indaga.net
 * Description: Buscador nativo de WordPress ligero, seguro y sin dependencias. Permite varios diseños y configuraciones personalizables desde el panel o mediante atributos de shortcode.
 * Version:     1.0.0
 * Author:      INDAGA.net
 * Text Domain: indaga-search
 */

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

/**
 * 1. REGISTRO DE OPCIONES Y PÁGINA DE CONFIGURACIÓN EN EL PANEL
 */
function isf_register_settings() {
	register_setting( 'isf_options_group', 'isf_placeholder', array(
		'type'              => 'string',
		'default'           => 'Buscar en el sitio...',
		'sanitize_callback' => 'sanitize_text_field',
	) );

	register_setting( 'isf_options_group', 'isf_button_text', array(
		'type'              => 'string',
		'default'           => 'Buscar',
		'sanitize_callback' => 'sanitize_text_field',
	) );

	register_setting( 'isf_options_group', 'isf_layout', array(
		'type'              => 'string',
		'default'           => 'inline',
		'sanitize_callback' => 'isf_sanitize_layout',
	) );

	register_setting( 'isf_options_group', 'isf_primary_color', array(
		'type'              => 'string',
		'default'           => '#2563eb',
		'sanitize_callback' => 'sanitize_hex_color',
	) );

	register_setting( 'isf_options_group', 'isf_bg_color', array(
		'type'              => 'string',
		'default'           => '#ffffff',
		'sanitize_callback' => 'sanitize_hex_color',
	) );

	register_setting( 'isf_options_group', 'isf_border_color', array(
		'type'              => 'string',
		'default'           => '#cbd5e1',
		'sanitize_callback' => 'sanitize_hex_color',
	) );
}
add_action( 'admin_init', 'isf_register_settings' );

function isf_sanitize_layout( $input ) {
	$valid_layouts = array( 'inline', 'stacked', 'minimal', 'icon_only' );
	return in_array( $input, $valid_layouts, true ) ? $input : 'inline';
}

function isf_add_admin_menu() {
	add_options_page(
		'Configuración de Buscador Indaga',
		'Buscador Indaga',
		'manage_options',
		'indaga-search',
		'isf_render_admin_page'
	);
}
add_action( 'admin_menu', 'isf_add_admin_menu' );

function isf_render_admin_page() {
	if ( ! current_user_can( 'manage_options' ) ) {
		return;
	}

	$placeholder   = get_option( 'isf_placeholder', 'Buscar en el sitio...' );
	$button_text   = get_option( 'isf_button_text', 'Buscar' );
	$layout        = get_option( 'isf_layout', 'inline' );
	$primary_color = get_option( 'isf_primary_color', '#2563eb' );
	$bg_color      = get_option( 'isf_bg_color', '#ffffff' );
	$border_color  = get_option( 'isf_border_color', '#cbd5e1' );
	?>
	<div class="wrap">
		<h1>Ajustes del Buscador Indaga.net</h1>
		<p>Personaliza el aspecto del buscador nativo o consulta las instrucciones para incrustarlo mediante shortcode.</p>

		<div style="display: flex; gap: 30px; flex-wrap: wrap; margin-top: 20px;">
			<div style="flex: 1; min-width: 320px; max-width: 600px;">
				<form method="post" action="options.php">
					<?php
					settings_fields( 'isf_options_group' );
					do_settings_sections( 'isf_options_group' );
					?>
					<table class="form-table" role="presentation">
						<tr>
							<th scope="row"><label for="isf_placeholder">Texto del placeholder</label></th>
							<td>
								<input type="text" id="isf_placeholder" name="isf_placeholder" value="<?php echo esc_attr( $placeholder ); ?>" class="regular-text" />
							</td>
						</tr>
						<tr>
							<th scope="row"><label for="isf_button_text">Texto del botón</label></th>
							<td>
								<input type="text" id="isf_button_text" name="isf_button_text" value="<?php echo esc_attr( $button_text ); ?>" class="regular-text" />
							</td>
						</tr>
						<tr>
							<th scope="row"><label for="isf_layout">Diseño de la estructura</label></th>
							<td>
								<select id="isf_layout" name="isf_layout">
									<option value="inline" <?php selected( $layout, 'inline' ); ?>>En línea (Clásico - Botón a la derecha)</option>
									<option value="stacked" <?php selected( $layout, 'stacked' ); ?>>Apilado (Campo de texto arriba, botón abajo)</option>
									<option value="minimal" <?php selected( $layout, 'minimal' ); ?>>Minimalista (Caja integrada con lupa)</option>
									<option value="icon_only" <?php selected( $layout, 'icon_only' ); ?>>Solo icono (Botón cuadrado compacto)</option>
								</select>
							</td>
						</tr>
						<tr>
							<th scope="row"><label for="isf_primary_color">Color principal</label></th>
							<td>
								<input type="color" id="isf_primary_color" name="isf_primary_color" value="<?php echo esc_attr( $primary_color ); ?>" />
							</td>
						</tr>
						<tr>
							<th scope="row"><label for="isf_bg_color">Color de fondo del campo</label></th>
							<td>
								<input type="color" id="isf_bg_color" name="isf_bg_color" value="<?php echo esc_attr( $bg_color ); ?>" />
							</td>
						</tr>
						<tr>
							<th scope="row"><label for="isf_border_color">Color del borde</label></th>
							<td>
								<input type="color" id="isf_border_color" name="isf_border_color" value="<?php echo esc_attr( $border_color ); ?>" />
							</td>
						</tr>
					</table>
					<?php submit_button( 'Guardar cambios' ); ?>
				</form>
			</div>

			<div style="flex: 1; min-width: 300px; max-width: 450px; background: #fff; padding: 20px; border: 1px solid #c3c4c7; border-radius: 4px; height: fit-content;">
				<h2>Instrucciones de Uso</h2>
				<p>Inserta el buscador en cualquier lugar utilizando:</p>
				<p><code>
</code></p> <hr style="margin: 15px 0; border: 0; border-top: 1px solid #eee;" /> <h3>Parámetros del Shortcode</h3> <ul> <li><code>layout="inline|stacked|minimal|icon_only"</code></li> <li><code>placeholder="Buscar..."</code></li> <li><code>color="#2563eb"</code></li> </ul> </div> </div> </div> <?php } /** * 2. LÓGICA DEL SHORTCODE
*/ function isf_search_shortcode( $atts ) { $db_placeholder = get_option( 'isf_placeholder', 'Buscar en el sitio...' ); $db_button_text = get_option( 'isf_button_text', 'Buscar' ); $db_layout = get_option( 'isf_layout', 'inline' ); $db_primary_color = get_option( 'isf_primary_color', '#2563eb' ); $db_bg_color = get_option( 'isf_bg_color', '#ffffff' ); $db_border_color = get_option( 'isf_border_color', '#cbd5e1' ); $atts = shortcode_atts( array( 'placeholder' => $db_placeholder, 'button_text' => $db_button_text, 'layout' => $db_layout, 'color' => $db_primary_color, 'bg' => $db_bg_color, 'border' => $db_border_color, ), $atts, 'indaga_search' ); $layout = isf_sanitize_layout( $atts['layout'] ); $placeholder = sanitize_text_field( $atts['placeholder'] ); $button_text = sanitize_text_field( $atts['button_text'] ); $primary_color = sanitize_hex_color( $atts['color'] ); $bg_color = sanitize_hex_color( $atts['bg'] ); $border_color = sanitize_hex_color( $atts['border'] ); $unique_id = 'indaga-search-' . wp_rand( 1000, 9999 ); $search_svg = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align: middle;"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>'; $output = '<style>'; $output .= '.' . $unique_id . ' { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; width: 100%; margin: 10px 0; }'; $output .= '.' . $unique_id . ' form { display: flex; gap: 8px; margin: 0; width: 100%; box-sizing: border-box; }'; $output .= '.' . $unique_id . ' input[type="search"] { flex: 1; background-color: ' . esc_attr( $bg_color ) . '; border: 1px solid ' . esc_attr( $border_color ) . '; border-radius: 4px; padding: 8px 12px; font-size: 14px; color: #1e293b; outline: none; transition: border-color 0.2s ease; box-sizing: border-box; }'; $output .= '.' . $unique_id . ' input[type="search"]:focus { border-color: ' . esc_attr( $primary_color ) . '; }'; $output .= '.' . $unique_id . ' button[type="submit"] { background-color: ' . esc_attr( $primary_color ) . '; color: #ffffff; border: none; border-radius: 4px; padding: 8px 16px; font-size: 14px; font-weight: 500; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 6px; }'; if ( 'stacked' === $layout ) { $output .= '.' . $unique_id . ' form { flex-direction: column; }'; $output .= '.' . $unique_id . ' button[type="submit"] { width: 100%; }'; } elseif ( 'minimal' === $layout ) { $output .= '.' . $unique_id . ' form { position: relative; }'; $output .= '.' . $unique_id . ' input[type="search"] { padding-right: 40px; }'; $output .= '.' . $unique_id . ' button[type="submit"] { position: absolute; right: 4px; top: 4px; bottom: 4px; background: transparent; color: ' . esc_attr( $primary_color ) . '; }'; } elseif ( 'icon_only' === $layout ) { $output .= '.' . $unique_id . ' button[type="submit"] { padding: 8px 12px; }'; } $output .= '</style>'; $home_url = esc_url( home_url( '/' ) ); $current_query = get_search_query(); $output .= '<div class="indaga-search-container ' . esc_attr( $unique_id ) . '">'; $output .= '<form role="search" method="get" action="' . $home_url . '">'; $output .= '<input type="search" value="' . esc_attr( $current_query ) . '" name="s" placeholder="' . esc_attr( $placeholder ) . '" aria-label="Buscar" required />'; $output .= '<button type="submit">'; if ( 'minimal' === $layout || 'icon_only' === $layout ) { $output .= $search_svg; } else { $output .= $search_svg . ' ' . esc_html( $button_text ); } $output .= '</button>'; $output .= '</form>'; $output .= '</div>'; return $output; } add_shortcode( 'indaga_search', 'isf_search_shortcode' );

Formas de invocación en tus páginas

Una vez activado el plugin en WordPress, puedes invocar el buscador en cualquier parte de varias formas distintas )lo encontrarás en Ajustes -> Buscador Indaga):

  • Buscador clásico en línea:

    indaga_search

    (recordad, siempre los shortcodes siempre entre corchetes):

  • Formato minimalista con la lupa integrada:
    indaga_search layout="minimal" placeholder="Explorar en Indaga.net..."

  • Formato apilado para barras laterales o pie de página:

    indaga_search layout="stacked" button_text="Buscar en el archivo"

Con este pequeño plugin vuelvo a tener más control sobre el rendimiento del sitio, asegurándome de que el buscador responda al instante, es seguro y no añade sobrecarga al servidor.

Descargar plugin de mi cuenta de pCloud

PD. Actualizaré la página Control de plugins. En breve…

Cómo filtrar direcciones IP y rangos en logs Web usando solo Bash

Valencia, 22/09/2026, G.B.
Cuando administramos servidores web como Apache, Nginx o LiteSpeed, los archivos de acceso (access.log) se convierten rápidamente en la fuente principal para identificar tráfico no deseado, bots malintencionados o intentos de fuerza bruta.

Aunque existen herramientas de análisis y cortafuegos dinámicos, en muchas ocasiones necesitamos realizar una limpieza rápida de un archivo de log directamente desde la consola, sin instalar dependencias adicionales ni recurrir a lenguajes externos como Python o Perl.

En este artículo veremos cómo construir un script en Bash puro que nos permita eliminar líneas enteras de un log basándonos en direcciones IP individuales o rangos mediante expresiones regulares (regex).

La herramienta clave: grep en modo extendido

Para filtrar contenido en GNU/Linux descartando líneas completas, el comando por excelencia es grep. En lugar de buscar lo que queremos conservar, le indicamos lo que queremos excluir mediante el parámetro -v.

Para manejar rangos o múltiples patrones en una sola pasada, utilizaremos dos modificadores esenciales:

  • -v (--revert-match): Invierte el resultado de la búsqueda, conservando únicamente las líneas que no coinciden con el patrón.
  • -E (--extended-regexp): Activa las expresiones regulares extendidas, permitiéndonos usar operadores lógicos como la barra vertical (|) para el condicional «O» (OR) y corchetes [] para rangos numéricos.

Filtrado de rangos IP mediante Expresiones Regulares

A diferencia de las herramientas orientadas a red que interpretan notación CIDR (como /24), las utilidades del Shell procesan el archivo de log como texto plano. Por ello, traduciremos las subredes a expresiones regulares fijas.

A continuación, algunas equivalencias útiles para definir rangos dentro del patrón de filtrado:

Rango deseadoExpresión RegularExplicación
Subred /24 completa192\.168\.1\.Coincide con cualquier IP que comience por 192.168.1.
Subred /16 completa10\.0\.Coincide con cualquier IP que empiece por 10.0.
Rango .0 a .9172\.16\.0\.[0-9]\bFiltra del 172.16.0.0 al 172.16.0.9
Rango .10 a .19172\.16\.0\.1[0-9]\bFiltra del 172.16.0.10 al 172.16.0.19
IP única203\.0\.113\.45Filtra exclusivamente esa dirección

Nota: Es fundamental escapar los puntos (\.) con una barra invertida. De lo contrario, en expresiones regulares el punto actuaría como un comodín que representa cualquier carácter. Igualmente importante: los patrones que terminan en un dígito suelto (como [0-9] o 1[0-9]) deben cerrarse con \b (límite de palabra), o de lo contrario también harán match con números más largos que empiecen por esos mismos dígitos.

El Script Bash: filtrar_log.sh

A continuación se muestra la estructura completa del script. Este toma como entrada el archivo de log original y genera un nuevo archivo limpio sin las líneas asociadas a las IP definidas.

#!/bin/bash

# ==============================================================================
# Script de filtrado de IPs y rangos en logs de acceso
# Publicado en Indaga.net
# ==============================================================================

# Validar que se introduzcan los argumentos necesarios
if [ "$#" -ne 2 ]; then
    echo "Error: Argumentos insuficientes."
    echo "Uso: $0 <log_origen> <log_destino>"
    exit 1
fi

LOG_ORIGEN="$1"
LOG_DESTINO="$2"

# Verificar la existencia del archivo de origen
if [ ! -f "$LOG_ORIGEN" ]; then
    echo "Error: El archivo '$LOG_ORIGEN' no existe."
    exit 1
fi

# Definición de reglas y rangos a excluir (formato Regex)
PATRONES=(
    "192\.168\.1\."           # Subred 192.168.1.0/24
    "10\.0\."                  # Subred 10.0.0.0/16
    "172\.16\.0\.[0-9]\b"      # IPs del 172.16.0.0 al 172.16.0.9
    "172\.16\.0\.1[0-9]\b"     # IPs del 172.16.0.10 al 172.16.0.19
    "203\.0\.113\.45"          # Dirección IP única estática
)

# Unir el array de patrones utilizando la barra vertical (|) como separador OR
PATRON_REGEX=$(IFS='|'; echo "${PATRONES[*]}")

# Ejecución del filtrado con grep
grep -v -E "$PATRON_REGEX" "$LOG_ORIGEN" > "$LOG_DESTINO"
RESULTADO=$?

# Confirmación de salida
# grep devuelve: 0 = hubo líneas tras filtrar, 1 = ninguna línea coincidió
# (log resultante vacío, no es un error), 2 = error real (lectura, etc.)
if [ "$RESULTADO" -le 1 ]; then
    echo "Filtrado completado con éxito."
    echo "Archivo limpio guardado en: $LOG_DESTINO"
else
    echo "Ocurrió un error al procesar el archivo."
fi

Modo de empleo

  1. Guardar el archivo: Crea el script en tu servidor, por ejemplo con nano filtrar_log.sh.
  2. Asignar permisos de ejecución:
    chmod +x filtrar_log.sh
  3. Ejecutar el proceso: Pasa como primer argumento el log actual y como segundo el nombre del archivo resultante:
    ./filtrar_log.sh /var/log/nginx/access.log /var/log/nginx/access_limpio.log

Ejecución rápida en una sola línea (One-Liner)

Si no necesitas la estructura del script y buscas solucionar una tarea puntual en la terminal, puedes ejecutar el filtro directamente concatenando los patrones deseados:

grep -v -E "192\.168\.1\.|10\.0\.|172\.16\.0\.[0-9]\b" access.log > access_filtrado.log

Esta alternativa utiliza únicamente las utilidades nativas de cualquier sistema POSIX, garantizando un rendimiento óptimo al procesar grandes volúmenes de texto sin sobrecargar los recursos del sistema.

Hooks y actions de WordPress explicados con un plugin real: Mis Plugins

Valencia, 21/09/2026, G.B.
Ya he hablado varias veces por aquí de hooks, actions y filters en WordPress, pero siempre viene bien un ejemplo real y completo en vez de fragmentos sueltos. Así que voy a usar mi propio plugin Mis Plugins como caso práctico: es pequeño, no tiene dependencias externas, y toca casi todos los hooks que se usan en el día a día de un plugin.

Qué es un hook

Un hook es un punto del código de WordPress donde puedes «engancharte» para ejecutar tu propia función, sin tocar el núcleo. Hay dos tipos:

  • Actions: ejecutan tu función en un momento concreto (por ejemplo, cuando se activa un plugin, o cuando se carga el panel de administración). No devuelven nada, solo hacen algo.
  • Filters: reciben un valor, tu función lo modifica y lo devuelve. Se usan para transformar datos antes de que WordPress los use.

Mis Plugins usa sobre todo actions, así que empiezo por ahí.

register_activation_hook: al activar el plugin

Este hook se dispara una sola vez, justo cuando activas el plugin desde el panel. Lo uso para crear la tabla propia en la base de datos:

register_activation_hook( __FILE__, 'indaga_mp_activar' );

function indaga_mp_activar() {
    global $wpdb;
    $table_name = indaga_mp_table_name();
    $charset_collate = $wpdb->get_charset_collate();

    require_once ABSPATH . 'wp-admin/includes/upgrade.php';

    $sql = "CREATE TABLE {$table_name} (
        id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
        fecha DATE NOT NULL,
        nombre_plugin VARCHAR(191) NOT NULL,
        PRIMARY KEY (id)
    ) {$charset_collate};";

    dbDelta( $sql );
}

La función dbDelta es la forma segura de crear o actualizar tablas propias: compara la estructura que le pasas con la que ya existe y hace los cambios necesarios sin borrar datos.

plugins_loaded: comprobar la versión en cada carga

register_activation_hook solo se dispara al activar, así que si subo una versión nueva del plugin con columnas añadidas, necesito otro punto de enganche que se ejecute siempre. Para eso uso plugins_loaded, comparando un número de versión guardado en las opciones:

add_action( 'plugins_loaded', 'indaga_mp_comprobar_version_bd' );

function indaga_mp_comprobar_version_bd() {
    if ( get_option( 'indaga_mp_db_version' ) !== INDAGA_MP_DB_VERSION ) {
        indaga_mp_activar();
    }
}

Así, cuando subí la versión 2.0.0 con los campos de autor y tags, la tabla se actualizó sola en cuanto WordPress cargó los plugins, sin que el usuario tuviera que desactivar y reactivar nada.

admin_menu: añadir la página al panel

Este hook se dispara mientras WordPress construye el menú de administración. Es el sitio correcto para registrar una nueva pantalla:

add_action( 'admin_menu', 'indaga_mp_menu_admin' );

function indaga_mp_menu_admin() {
    add_menu_page(
        'Mis Plugins',
        'Mis Plugins',
        'manage_options',
        INDAGA_MP_SLUG,
        'indaga_mp_render_pagina_admin',
        'dashicons-admin-plugins',
        80
    );
}

admin_init: procesar el formulario, nunca en el callback del menú

Este es el hook con el que más cuidado tengo, porque un error aquí ya me ha dado algún quebradero de cabeza en otros plugins: procesar un formulario POST dentro de la función que pinta la página de administración puede dejar la pantalla congelada. La solución es mover ese procesamiento a admin_init, comprobando primero en qué pantalla estamos:

add_action( 'admin_init', 'indaga_mp_procesar_admin_init' );

function indaga_mp_procesar_admin_init() {
    if ( ! isset( $_GET['page'] ) || INDAGA_MP_SLUG !== $_GET['page'] ) {
        return;
    }
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }
    // Aquí se valida el nonce y se guarda o borra el registro.
}

admin_enqueue_scripts: cargar estilos solo donde tocan

Para no meter CSS en todas las pantallas del panel, engancho los estilos a este hook y compruebo en qué página estoy antes de cargarlos:

add_action( 'admin_enqueue_scripts', 'indaga_mp_admin_estilos' );

function indaga_mp_admin_estilos( $hook ) {
    if ( strpos( (string) $hook, INDAGA_MP_SLUG ) === false ) {
        return;
    }
    wp_register_style( 'indaga-mp-admin', false );
    wp_enqueue_style( 'indaga-mp-admin' );
    wp_add_inline_style( 'indaga-mp-admin', '/* CSS aquí */' );
}

add_shortcode: mostrarlo en el front end

No es técnicamente un action ni un filter, pero funciona con la misma lógica de enganche: le dices a WordPress que, cuando encuentre el shortcode mis_plugins (entre brackets, que si no se ejecuta aquí)  en el contenido, ejecute tu función y sustituya el shortcode por lo que devuelva:

add_shortcode( 'mis_plugins', 'indaga_mp_shortcode' );

function indaga_mp_shortcode( $atts ) {
    $atts = shortcode_atts( array(
        'por_pagina' => 10,
    ), $atts, 'mis_plugins' );

    // Consulta a la base de datos y devuelve el HTML con ob_start()/ob_get_clean().
}

Un detalle interesante para quien quiera profundizar en filters: shortcode_atts, por dentro, aplica el filter shortcode_atts_mis_plugins, que permite a otro plugin modificar los atributos por defecto sin tocar mi código. Es un buen ejemplo de cómo WordPress deja puertas abiertas incluso en funciones tan pequeñas como esta.

Resumen

Con seis hooks (uno de activación, uno de carga, tres de administración y un shortcode) queda montado un plugin completo, con su propia tabla, su formulario y su vista en el front end. Si quieres verlo funcionando, tienes el listado en Control de plugins, con el catálogo de todos los que he ido publicando aquí.

Nextcloud: sincronización local vs. archivos virtuales, y cómo cambiar sin reinstalar

nextcloud

Valencia, 20/09/2026, G.B.
Si usas el cliente de escritorio de Nextcloud desde hace tiempo, es probable que en algún momento hayas notado que la carpeta sincronizada empieza a comportarse mal: tarda una eternidad en actualizarse, consume una cantidad de espacio en disco que ya no te cuadra, o directamente deja de sincronizar algunos archivos sin motivo aparente. La reacción típica  (desinstalar completamente el cliente, reinstalarlo y volver a configurar las conexiones desde cero) suele funcionar, pero es un martillazo para lo que a veces es un problema mucho más pequeño, es como cazar moscas a cañonazos. En otros casos, es necesario. Antes de llegar ahí merece la pena entender qué diferencia hay entre los dos modos de sincronización que ofrece Nextcloud, porque cambiar de uno a otro puede resolver el problema sin perder nada por el camino.

Sincronización local total: la de toda la vida

Es el modo por defecto y el que casi todo el mundo usa sin plantearse alternativas. Funciona de forma muy simple:

  • Todo el contenido de tu cuenta Nextcloud se descarga físicamente al disco duro.
  • Cada archivo ocupa espacio en disco de manera permanente, exactamente igual que si lo hubieras copiado tú a mano.
  • Puedes acceder a cualquier archivo en cualquier momento, incluso sin conexión a internet o con el cliente de Nextcloud completamente cerrado, porque son ficheros normales del sistema operativo.
  • El cliente solo entra en juego para detectar cambios y sincronizarlos; el acceso al archivo en sí no depende de que esté en ejecución.

El problema aparece cuando la cuenta crece: si gestionas varios gigas —o varios cientos— de documentos, fotos o archivos de proyecto, tener una copia local completa de todo empieza a pasar factura, tanto en espacio como en el tiempo que tarda el cliente en comprobar el estado de cada archivo.

Archivos virtuales (VFS): descarga solo lo que usas

Aquí es donde entra el modo de archivos virtuales, también conocido como VFS (Virtual File System). La idea es distinta:

  • El cliente crea una especie de «estructura fantasma»: ves todos los nombres de archivos y carpetas exactamente igual que antes, pero el contenido no se descarga hasta que lo abres.
  • En el momento en que abres un archivo, se descarga (con el pequeño retraso lógico según tamaño y velocidad de red) y queda cacheado en local.
  • Puedes marcar archivos o carpetas concretas como «siempre disponible sin conexión» para que se comporten exactamente como en el modo de sincronización total.
  • En Windows, esto se apoya en la API nativa CfAPI (Cloud Files API), la misma tecnología que usa OneDrive para su modo «bajo demanda». Requiere Windows 10 build 1809 o superior. En macOS también está soportado en las versiones recientes del cliente; en Linux el comportamiento es distinto, ya que se gestiona directamente desde el propio cliente sin depender de una API del sistema.

La pregunta que casi todo el mundo se hace: ¿y sin el cliente abierto?

Es la duda más razonable, y la respuesta tiene matices: los archivos que ya se han abierto y descargado (o que has marcado como «siempre disponible») siguen ahí, en disco, accesibles sin conexión ni cliente activo. Pero los que aún no se han descargado son solo placeholders: el nombre y el icono existen, pero el contenido real no se puede recuperar hasta que el cliente de Nextcloud vuelva a estar en ejecución y haya conexión al servidor. Si trabajas mucho en un portátil que cierra procesos en segundo plano para ahorrar batería, o necesitas acceso offline a archivos que no has abierto antes, conviene tenerlo en cuenta y marcar de antemano como disponibles sin conexión las carpetas que sabes que vas a necesitar.

Cómo cambiar de local a virtual sin reinstalar nada

La buena noticia es que el cambio se hace desde la propia cuenta ya configurada, sin tocar la instalación del cliente:

  1. Abre la configuración de la cuenta desde el icono del cliente en la bandeja del sistema.
  2. Accede a las opciones de la carpeta sincronizada, normalmente a través de 3 puntos, una flecha o menú desplegable junto al nombre de la carpeta local.
  3. Selecciona «Activar soporte para archivos virtuales …» o un texto equivalente, según tu versión de Nextcloud Files
  4. Confirma la conversión cuando el cliente avise de que va a cambiar el modo de la carpeta.
  5. Espera a que se reindexe la carpeta —puede tardar varios minutos según el volumen de archivos—.
  6. Comprueba el resultado: en el explorador de Windows o en Finder verás iconos de nube (solo en línea) o de check verde (ya descargado) junto a cada archivo.

Antes de tocar nada: diagnostica primero

Si el motivo por el que te planteas este cambio es un problema de sincronización que no acaba de funcionar, no des el salto directamente. Revisa antes lo siguiente, porque a veces la causa es otra y cambiar el modo de sincronización solo la enmascara temporalmente:

  • Registro de actividad del cliente (Actividad reciente > filtrar por errores): suele señalar la causa real —conflictos, permisos, archivos bloqueados—.
  • Rutas y nombres problemáticos: en Windows, uno de los fallos más habituales es superar el límite de longitud de ruta (MAX_PATH) o usar caracteres no permitidos como : * ? " < > |.
  • Espacio en disco y estado de la carpeta local: a veces el problema es simplemente falta de espacio, no la sincronización en sí.

Si tras revisar todo esto el error persiste igual después de pasar a VFS, entonces sí, probablemente el problema no era el modo de sincronización y tiene sentido plantearse una reinstalación limpia.

Un truco útil si al final hay que reinstalar

Si después de todo el cambio a VFS no resuelve el problema y toca reinstalar, un método sencillo para no perder nada: tras desconectar la cuenta, cierra la sesión de Windows —así se liberan los procesos que puedan tener la carpeta bloqueada (Explorer, indexador de búsqueda, el propio cliente)— y renombra la carpeta local afectada en lugar de borrarla. De esta forma conservas una copia de seguridad intacta mientras configuras la conexión desde cero, y puedes rescatar cualquier archivo que se hubiera quedado a medio sincronizar.

En resumen: pasar de sincronización local a archivos virtuales es un cambio reversible, rápido y mucho menos drástico que una reinstalación completa. Merece la pena probarlo antes de tirar por el camino más largo.

Nota final: en Linux, de momento, no es una opción fiable

Todo lo anterior aplica sin problemas a Windows y macOS, pero conviene ser claro respecto a Linux: el cliente de escritorio de Nextcloud no ofrece soporte oficial de archivos virtuales en esta plataforma. Ni el paquete de nextcloud-desktop ni el AppImage muestran la opción en la configuración habitual de la cuenta.

Existe un workaround no oficial —añadir showExperimentalOptions=true en la sección [General] del archivo ~/.config/Nextcloud/nextcloud.cfg, lo que hace aparecer la opción como función experimental—, pero varios usuarios reportan que no funciona de forma fiable: en lugar de comportarse como archivos bajo demanda, el cliente intenta descargar o sincronizar toda la cuenta igualmente, anulando la ventaja que se busca.

De hecho, el propio anuncio de Nextcloud sobre su nueva «Virtual Drive» (la evolución de esta función) reconoce que la vista previa técnica funciona en Windows, que macOS llegará poco después, y que Linux «se abordará más adelante» — es decir, sigue sin ser una prioridad resuelta ni en la próxima generación de la función.

Conclusión para equipos Linux: si el problema de sincronización aparece en un equipo con este sistema, el cambio a archivos virtuales no es una alternativa segura a día de hoy. Lo más sensato es agotar primero el diagnóstico (registro de errores del cliente, rutas y nombres de archivo problemáticos, espacio en disco disponible) y, si el problema persiste, optar directamente por una reinstalación limpia — renombrando antes la carpeta local afectada tras cerrar sesión, para conservar una copia de seguridad por si acaso.

Soberanía digital en el escritorio: Euro-Office estrena aplicación

Valencia, 19/09/2026, G.B.
La ofimática europea ya no se limita al navegador. Nextcloud ha confirmado que Euro-Office tendrá su propia aplicación de escritorio, con soporte para Windows, y con ello la suite de código abierto que nació en abril como alternativa europea a Microsoft Office da un paso que yo, al menos, echaba en falta.

Qué es Euro-Office y por qué importa

Euro-Office es una suite ofimática de código abierto impulsada por empresas y organizaciones europeas, entre ellas Nextcloud, Ionos, Open-Xchange y Office.eu. Su objetivo declarado es reducir la dependencia tecnológica de Europa respecto a los gigantes estadounidenses, sobre todo Microsoft y Google. Dicho de otro modo, se trata de soberanía digital aplicada a algo tan cotidiano como redactar un documento o preparar una hoja de cálculo.

Hasta ahora solo se podía usar a través de su versión web. Para quien trabaja a diario con documentos y prefiere una aplicación instalada en el equipo, eso era una limitación seria.

Conviene saber que detrás de todo esto está Nextcloud, la empresa europea que lidera el desarrollo de Euro-Office. Su plataforma de código abierto para gestionar archivos y colaborar en equipo es la base sobre la que funcionan la edición compartida y el guardado en servidor, de modo que la aplicación de escritorio se integra directamente con ella.

La aplicación de escritorio

La nueva aplicación se llamará Nextcloud Office y se apoya en Euro-Office. Permite editar documentos en local sin necesidad de conexión a internet y guardarlos después en el propio dispositivo o en el servidor, según se prefiera. Entre sus funciones destacan dos:

  • Carga de tipografías propias por parte del usuario.
  • Funciones de seguridad avanzadas.

Gracias a los servicios de Nextcloud, también será posible la edición colaborativa entre varias personas. Cada participante podrá unirse tanto desde la aplicación como desde la versión web de la suite, algo que me parece clave para equipos que no trabajan todos igual.

Disponibilidad y plataformas

Conviene matizar el alcance del anuncio: según sus creadores, la aplicación se lanzará en las próximas semanas, es decir, todavía no se puede descargar. Cuando llegue, estará disponible para:

  • Windows, tanto en x64 como en ARM64.
  • macOS, en equipos con ARM64.
  • Linux.

El anuncio forma parte de la actualización Nextcloud Hub 26 Summer, que ya está publicada e incluye además mejoras como el filtrado de documentos y nuevos iconos para localizar y abrir archivos con más facilidad.

Mi valoración

Me alegra ver que Linux figura desde el principio en la lista de sistemas compatibles, porque no siempre ocurre y llevo años moviéndome entre Windows y Linux. Aun así, prefiero esperar a probarla antes de sacar conclusiones: un anuncio no es una instalación, y una suite ofimática se juzga por lo bien que abre y guarda los documentos de siempre. Cuando esté disponible la instalaré y contaré qué tal se comporta con archivos reales.

Fuentes

PD. Ya me he registrado (en Office.eu)…

Cómo conectar Nextcloud en local: la guía sencilla para Windows y Linux

Valencia, 19/09/2026, G.B.
Si usas Nextcloud como tu nube personal —ya sea en un servidor propio o contratado a un proveedor, tarde o temprano te planteas lo mismo: ¿merece la pena tener una copia sincronizada en el ordenador, o es mejor trabajar directamente «en la nube»? La respuesta corta es que depende de cómo trabajes, pero para entenderlo bien primero hay que aclarar un concepto que mucha gente pasa por alto: la diferencia entre archivos locales y archivos virtuales.

Archivos locales vs. archivos virtuales

Cuando instalas el cliente de escritorio de Nextcloud, tienes dos formas de sincronizar tus carpetas:

  • Archivos locales (sincronización tradicional): cada archivo se descarga por completo y se guarda en tu disco duro o SSD. Ocupan espacio real en tu equipo, pero están disponibles al instante, sin conexión a internet, y los programas pueden abrirlos y editarlos sin ningún retraso.
  • Archivos virtuales (Virtual Files / «archivos bajo demanda»): ves toda la estructura de carpetas y archivos como si estuvieran en tu disco, pero en realidad solo son «marcadores». El contenido real se queda en el servidor y solo se descarga en el momento en que abres ese archivo concreto. Una vez lo cierras, puedes liberar el espacio de nuevo marcándolo como «solo en línea».

¿Cuándo usar cada uno?

Usa archivos locales cuando:

  • Trabajas habitualmente sin conexión (viajes, zonas sin buena cobertura).
  • Necesitas acceso instantáneo a carpetas grandes de trabajo (proyectos, bases de datos, código).
  • Tienes espacio de sobra en el disco y prefieres no depender de la red para nada.

Usa archivos virtuales cuando:

  • Tu Nextcloud tiene más datos de los que caben cómodamente en tu disco (fotos, backups, archivos históricos).
  • Solo necesitas consultar ocasionalmente ciertas carpetas.
  • Trabajas con un portátil de almacenamiento reducido (SSD pequeño) y quieres ahorrar espacio sin perder visibilidad de todo lo que tienes en la nube.

Lo habitual, y lo que yo recomiendo, es un enfoque mixto: carpetas de trabajo activo en local, y el resto —archivo histórico, fotos, documentación antigua— en modo virtual.

Preparativos antes de empezar

Antes de instalar nada, ten a mano:

  1. La URL de tu servidor Nextcloud (por ejemplo, https://tudominio.com , la IP si es una instalación local o un servior externo).
  2. Tu usuario y contraseña, o mejor aún, un token de aplicación generado desde Ajustes → Seguridad → Crear nueva contraseña de aplicación. Es más seguro que usar tu contraseña principal, y puedes revocarlo sin afectar al resto de sesiones.
  3. Decidir qué carpetas quieres sincronizar de entrada (siempre puedes ajustarlo después).

Instalación en Windows

  1. Descarga el cliente oficial desde la página de descargas de Nextcloud e instálalo con el asistente habitual.
  2. Al abrirlo por primera vez, introduce la URL de tu servidor y autentícate (usa el token de aplicación si lo has creado).
  3. El asistente te preguntará qué tipo de sincronización quieres:
    • «Sincronizar todo desde el servidor» con opción de archivos virtuales activada por defecto en versiones recientes del cliente.
    • Puedes elegir manualmente qué carpetas quieres en local y cuáles en modo virtual.
  4. Para gestionar esto más adelante, haz clic derecho sobre cualquier carpeta dentro del explorador de archivos: verás opciones como «Liberar espacio local» (la convierte en virtual) o «Hacer disponible sin conexión» (la descarga por completo).
  5. Un detalle útil en Windows: los archivos virtuales se integran con el Explorador de Windows mostrando un icono de nube junto a cada archivo, y uno de check verde cuando ya está descargado en local.

Instalación en Linux

En Ubuntu, Debian y derivadas, el cliente está disponible tanto desde el repositorio oficial de Nextcloud como en algunos casos desde los repos de la propia distribución (aunque suelen ir más desactualizados).

  1. Añade el repositorio oficial (recomendable para tener siempre la última versión):
sudo add-apt-repository universe
sudo apt update
sudo apt install nextcloud-desktop
  1. Si prefieres evitar PPAs de terceros, también puedes usar el paquete Flatpak, que Nextcloud mantiene oficialmente:
flatpak install flathub com.nextcloud.desktopclient.nextcloud
  1. Al abrir el cliente, el proceso de configuración es idéntico al de Windows: URL del servidor, autenticación y selección de carpetas.
  2. Un matiz importante en Linux: el soporte de archivos virtuales depende del sistema de archivos. Funciona de forma nativa en particiones ext4 (gracias a la tecnología de Windows-style «placeholders» que Nextcloud ha portado a Linux desde hace un par de versiones), pero si usas otros sistemas de archivos puede no estar disponible, y en ese caso el cliente recurre a la sincronización tradicional en local.
  3. Puedes comprobar y cambiar el modo de sincronización de cada carpeta sincronizada desde el propio cliente: icono de la bandeja del sistema → engranaje → pestaña de la cuenta → clic derecho sobre la carpeta.

Algunos consejos prácticos

  • No actives archivos virtuales en carpetas que uses con herramientas de línea de comandos o scripts (por ejemplo, si sincronizas backups que luego procesas con rsync o similares). Al no estar el contenido descargado, algunos procesos por lotes pueden fallar o volverse muy lentos al tener que ir descargando archivo a archivo.
  • Si notas que el cliente consume muchos recursos en un equipo modesto, revisa el intervalo de sondeo (polling) en los ajustes avanzados: por defecto Nextcloud comprueba cambios cada pocos minutos, y puedes ajustarlo si te sobra rendimiento o si necesitas ahorrar batería en un portátil.
  • Excluye siempre las carpetas de caché o temporales de tu sincronización (node_modules, carpetas de compilación, etc.) desde Ajustes → Política de sincronización de archivos y carpetas, para evitar sincronizar basura innecesaria y saturar el servidor.
  • Si gestionas varios equipos, ten en cuenta que cada cliente puede tener una configuración de local/virtual distinta para las mismas carpetas: es perfectamente normal (y recomendable) tener una carpeta en local en tu equipo de escritorio y en modo virtual en el portátil.

En resumen

La elección entre archivos locales y virtuales no es una decisión única ni definitiva: puedes combinarlas según la carpeta, el equipo y el momento. Lo importante es entender que un archivo virtual no es una copia «peor», sino una forma de tener visibilidad total sobre tu nube sin gastar espacio de disco que no necesitas ahora mismo. Empieza con lo esencial en local, deja el resto en modo virtual, y ajusta sobre la marcha según cómo lo vayas usando.

Cómo eliminar el aviso de zona horaria de Modern Events Calendar Lite

Valencia, 17/09/2026, G.B.
Aunque lo he publicado en los foros de Puntocomunica, quiero dejar también aquí constancia, para que no se me olvide si volviera a necesitar solucionarlo. Creo en la redundancia en la Red…

Sitio: (no lo indico por privacidad)
Plugin implicado: Modern Events Calendar Lite (Webnus), v7.36.4
Fecha de resolución: septiembre de 2026

El problema

Tras importar eventos en el calendario, aparece este aviso en el escritorio
de WordPress, en cualquier pantalla del área de administración y no solo en
los ajustes del calendario:

It is advisable to utilize a geographic timezone, such as
«America/Los_Angeles» instead of a UTC timezone offset, like «UTC+0,»
while using The Modern Events Calendar. The latter may cause issues when
importing events or with Daylight Saving Time.

Causa raíz

El propio plugin comprueba, en
wp-content/plugins/modern-events-calendar-lite/app/features/events.php
—líneas 208-218—, si la opción interna de WordPress
timezone_string está vacía:

// Timezone Notice
$timezone_string = get_option('timezone_string');

if (trim($timezone_string) === '')
{
    add_action('admin_notices', function ()
    {
        echo '<div class="notice notice-warning is-dismissible">
            <p>' . esc_html__('It is advisable to utilize a geographic timezone...', 'modern-events-calendar-lite') . '</p>
        </div>';
    });
}

timezone_string queda vacía cuando, en
Ajustes → Generales, se utiliza un desplazamiento numérico
—por ejemplo, UTC+2— en lugar de una zona horaria geográfica,
como Europe/Madrid.

Aunque el aviso incluye la clase is-dismissible, no hay ningún
código que recuerde el descarte. Por eso reaparece en cada carga de página
hasta corregir la causa.

Complicación encontrada en este sitio

En Ajustes → Generales, el desplegable de zona horaria solo
ofrece desplazamientos UTC —UTC+0, UTC+1, etc.—,
sin la lista habitual de ciudades y continentes.

Esto indica que la base de datos de zonas horarias de PHP,
timezone_identifiers_list(), no está completa en el servidor.
Se trata de un problema de configuración de PHP o del hosting, no de
WordPress en sí. Por eso no se pudo resolver simplemente seleccionando una
ciudad en el desplegable.

Solución aplicada: editar directamente wp_options mediante phpMyAdmin

Como el desplegable no permitía elegir una zona geográfica, se editaron
directamente las dos opciones implicadas en la tabla
wp_options:

  • timezone_string: antes estaba vacía; se estableció como
    Europe/Madrid.
  • gmt_offset: antes tenía el valor 2, reflejo de
    UTC+2 en horario de verano; se dejó vacío.

Pasos

  1. Entrar en phpMyAdmin, seleccionar la base de datos del sitio y abrir la
    tabla wp_options.
  2. Buscar la fila cuyo option_name sea
    timezone_string, editar option_value y
    establecerlo como Europe/Madrid.
  3. Buscar la fila cuyo option_name sea
    gmt_offset y vaciar su valor.
  4. Guardar los cambios y recargar el escritorio de WordPress.

El aviso desaparece de inmediato porque
trim($timezone_string) === '' deja de cumplirse.

Nota sobre falsas pistas descartadas

Antes de llegar a la causa real, se investigaron dos vías que no aplicaban
a este caso. Se mantienen como referencia por si el aviso reapareciera con
un texto ligeramente distinto:

  • El texto del aviso es casi idéntico al que muestra
    The Events Calendar (Modern Tribe/StellarWP), un plugin de
    calendario distinto con un nombre parecido. Ese plugin no está instalado
    en la web, pero en wp_options quedan opciones residuales
    con el prefijo tec_, como
    tec_ct1_migration_state y
    tec_timed_events_timezone_update_needed. Esto indica que
    estuvo instalado en algún momento y se desinstaló sin limpiar por
    completo la base de datos. Estas opciones no afectan al problema del
    MEC, pero podrían eliminarse en una limpieza futura.
  • Un mirror desactualizado del código de MEC Lite en GitHub, versión
    5.21.2 de 2021, no contenía el texto del aviso. Fue necesario conseguir
    el ZIP real de la versión 7.36.4 instalada para localizar el código
    exacto.

Cuadernos de Gemini vs. Proyectos de Claude: ¿Cuál es el mejor espacio de trabajo con IA para tu día a día?

Valencia, 16/09/2026, G.B.
Si utilizas modelos de lenguaje no solo para preguntas rápidas, sino como un espacio de trabajo donde ir guardando información, documentos y contexto sobre un tema concreto, seguro que conoces los Cuadernos de Gemini (NotebookLM) de Google y los Proyectos de Claude (Claude Projects) de Anthropic. Son dos formas distintas de tener a la IA «al día» sobre lo que estás haciendo, sin tener que repetirle todo cada vez que le preguntas algo.

Llevo un tiempo usando ambos y quiero contaros, sin tecnicismos, qué hace bien cada uno y cuándo os puede interesar más uno u otro.

¿Qué tipo de información aguanta mejor cada uno?

La primera diferencia que noté es qué tipo de material admite bien cada herramienta:

Cuadernos de Gemini

  • Admite de todo: vídeos, audios, PDFs, documentos de Google Drive, enlaces… Lo pegas o lo subes y ya está, sin tener que convertir nada antes.
  • Aguanta muchísima cantidad de información: puedes meterle documentos larguísimos o varias horas de audio transcrito y sigue funcionando con soltura.
  • Te dice de dónde saca cada dato: cuando responde, suele señalar en qué parte del documento se ha basado, lo cual ayuda a comprobar que no se está inventando nada.

Proyectos de Claude

  • Se le dan muy bien el texto y el código: documentación técnica, archivos de código, esquemas… todo lo que sea texto estructurado lo entiende de maravilla.
  • Razona muy bien sobre lógica compleja: si le explicas cómo funciona un sistema o unas reglas de negocio algo enrevesadas, tiene una capacidad de «atar cabos» que me ha sorprendido más de una vez.
  • Puedes darle instrucciones fijas: le dices cómo quieres que se comporte dentro de ese proyecto y lo respeta de forma bastante estricta durante toda la conversación.

¿Y a la hora de trabajar con lo que te devuelve?

Aquí es donde más se nota la diferencia en el día a día:

[Lo que le das] ──> [Proyecto de Claude] ──> Panel aparte con el resultado (código, esquemas, texto)
[Lo que le das] ──> [Cuaderno de Gemini] ──> Resumen o audio explicativo, integrado con Google

Claude y sus «Artefactos»

Si trabajas con código o documentos técnicos, esto os va a gustar: Claude abre lo que genera en un panel aparte, al lado de la conversación. Puedes pedirle que cambie solo un trozo concreto sin que tengas que releer toda la charla ni que se pierda el hilo. Para quien programa o escribe documentación, es muy cómodo.

Gemini y su lado «todo en uno»

Gemini, en cambio, apuesta por juntarlo todo: te puede generar un resumen en audio de tus documentos (como si fuera un podcast explicándote el tema), esquemas de estudio, y además se conecta directamente con Google Workspace, así que no hace falta ir exportando cosas a mano de un lado a otro.

Tabla resumen

AspectoCuadernos de GeminiProyectos de Claude
Qué formatos admiteCasi todo: texto, audio, vídeo, DriveSobre todo texto, PDFs y código
Trabajando con códigoBienMuy bien, es su punto fuerte
Cómo lo controlasInstrucciones sencillasInstrucciones más estrictas y detalladas
Cómo te muestra el resultadoRespuestas normales o formatos interactivosPanel aparte, editable al momento
Para qué lo usaríaInvestigar, mezclar formatos, trabajar en equipoProgramar, escribir textos técnicos, desarrollo web

Entonces, ¿cuál elijo?

Sinceramente, no creo que una sustituya del todo a la otra, porque cubren momentos distintos del trabajo:

  • Para investigar y reunir información (Gemini): si tienes materiales de muchos tipos —audios, vídeos, documentos sueltos— y quieres un resumen rápido de todo, tira de Gemini.
  • Para ponerte a construir algo (Claude): cuando ya toca escribir código, documentación o cualquier cosa técnica bien hecha, Claude me da mejores resultados.

Yo, según el día, acabo usando los dos por motivos distintos, y creo que esa es la conclusión más honesta que os puedo dar.

De Claude Projects a NotebookLM: cómo mover tus notas, reglas y contexto sin volverte loco

Valencia, 14/09/2026, G.B.
Si llevas un tiempo cacharreando con la Inteligencia Artificial para organizar tus notas, tus proyectos web o tu flujo de trabajo diario, seguro que te has cruzado con los Proyectos de Claude. Tienen una ventaja clara: les tiras un montón de archivos, les pones unas Custom Instructions (instrucciones del sistema) bastante finas y a trabajar.

Pero claro, la curiosidad o las necesidades técnicas cambian. Ahora resulta que quieres mover todo ese ecosistema a NotebookLM de Google, que para bregar con documentos locales, fuentes en PDF y notas estructuradas va como un tiro.

La mala noticia: no existe un botón mágico de «Exportar todo mi proyecto de Claude a NotebookLM con un clic».

La buena noticia: con un poco de orden y un par de comandos de ratón se soluciona en cinco minutos. Aquí va el paso a paso de cómo hacerlo y dónde están los «trucos» para que no pierdas la configuración por el camino.

Paso 1. Rescatar la «chicha» del proyecto en Claude

Lo primero es vaciar la mochila de Claude:

  1. Los archivos de contexto (Project Knowledge): Descarga a tu equipo los PDF, notas de texto (.txt), esquemas en Markdown (.md) o CSVs que subiste en su día.
  2. Las instrucciones del sistema: Esto es crucial. En el panel de tu proyecto en Claude, entra en Project details o edita las instrucciones personalizadas. Copia todo ese texto donde le decías a la IA cómo debía comportarse, qué tono usar o qué criterios seguir.

Ojo al dato: Si vas a los ajustes generales de Claude y le das a Exportar datos, lo que te descargará será el historial completo de tus conversaciones, no el paquete estructurado del proyecto. Toca hacer la recolección a mano.

Paso 2. Mover las fuentes a NotebookLM

Te vas a NotebookLM, creas un Nuevo cuaderno y le pones un título apañado.

En la columna izquierda (Fuentes / Sources):

  • Sube los archivos que acabas de descargar de Claude.
  • Acepta PDFs, documentos de Google Docs, texto plano, URLs directas, etc.

Hasta aquí la parte fácil. Pero ¿qué hacemos con las reglas de comportamiento que tenías configuradas en Claude?

Paso 3. Cómo pasar las reglas y el rol (el truco del documento 00_)

En Claude, las instrucciones del proyecto actúan como un System Prompt invisible que se ejecuta siempre por debajo. En NotebookLM la filosofía cambia: todo se basa en las fuentes.

Para no perder tu rol ni tus instrucciones personalizadas:

  1. Crea un archivo de reglas: Abre un editor de texto o un Google Doc y pega las instrucciones que usabas en Claude.
  2. Nómbralo con estrategia: Titúlalo algo como 00_Reglas_y_Configuracion.txt. Al ponerle el 00_ delante, te quedará arriba en la lista de fuentes y será facilísimo identificarlo.
  3. Súbelo como fuente: Al subirlo, NotebookLM lo indexará como conocimiento base.
  4. Configura la Notebook Guide (Guía del cuaderno): En el panel derecho de NotebookLM, abre la Guía del cuaderno y pega un resumen de las reglas principales (formato de respuesta, tono técnico, etc.). También puedes dejar notas fijadas (Add note) con los prompts que más repitas.

Paso 4. Ponlo a prueba

Cuando vayas a chatear en tu nuevo cuaderno, solo tienes que recordarle a la herramienta que aplique el criterio guardado. Basta con arrancar con algo similar a:

«Basándote en el documento 00_Reglas_y_Configuracion y en el resto de las fuentes, analiza lo siguiente…»

Y listo. Con esto dejas tu proyecto operativo en la plataforma de Google sin perder el contexto ni el trabajo de prompt engineering que te costó configurar en Claude.

Pocas complicaciones y todo tu conocimiento centralizado en un solo cuaderno.

SYSADMIT, un veterano blog de administración de sistemas

sysadmit

Valencia, 13/09/2026, G.B.
Sigo ampliando el directorio de webs recomendadas con sitios que uso o consulto a menudo si me surgen dudas relativas a administración de sistemas; o por pura curiosidad. Hoy le toca el turno a SYSADMIT, un blog de referencia en castellano sobre sysadmin, mantenido por Xavier Genestós.

Qué es SYSADMIT

SYSADMIT es un blog de administración de sistemas con años de recorrido, alojado en Blogger, centrado en Windows Server, Windows Client, virtualización con VMware, backups con Veeam, y también con presencia de contenidos sobre Linux, Docker, PowerShell, Active Directory y redes. El propio autor ha publicado varios libros técnicos en castellano bajo el sello de la casa (como los de la serie «LABS»), lo que da una idea del nivel de detalle que maneja en sus artículos.

Qué se puede encontrar

El contenido está organizado por etiquetas, y ahí se ve claramente hacia dónde apunta el blog: VMware, Windows Client y Windows Server concentran el grueso de las entradas, seguidos de Veeam Backup, Networking y PowerShell. Linux también tiene su hueco, con posts sobre Docker (persistencia de datos, laboratorios rápidos, actualización de contenedores) que están bastante bien explicados para quien se inicia en contenedores.

El formato de los artículos es el típico de guía práctica: se plantea un problema o una tarea concreta (por ejemplo, ver el tamaño de un directorio con PowerShell, o desinstalar un parche desde línea de comandos) y se resuelve paso a paso, sin rodeos.

Por qué lo recomiendo

Me parece un blog útil sobre todo si te mueves en entornos mixtos Windows/Linux, algo muy habitual en el día a día de un sysadmin. Yo ya no llevo servidores Windows como antes,  pero sigo consultándolo cuando me surge alguna duda de la vieja escuela.