WordPress Hosting

plugin incompatible colaboracion tiempo real wordpress

«Esta entrada usa plugins que no son compatibles con la colaboración en tiempo real»

Desde WordPress 7.0 está disponible una de las novedades más anunciadas de los últimos años, la colaboración en tiempo real en el editor de bloques. Con esta funcionalidad dos o más personas pueden editar la misma entrada a la vez, al estilo Google Docs, viendo los cambios del otro al momento. Hasta aquí bien, peeeero … es posible que que te hayas topado con un mensaje que corta de raíz la experiencia.

Al abrir una entrada que otro usuario ya está editando, en lugar de entrar en modo colaborativo, WordPress te muestra el aviso «Esta entrada ya está siendo editada» de siempre, pero con un cambio, este mensaje añadido:

«Debido a que esta entrada usa plugins que no son compatibles con la colaboración en tiempo real solo una persona puede editarla al mismo tiempo.»

Te da dos opciones, o «Tomar posesión» o «Salir del editor«, o sea, el bloqueo de siempre. Y lo más frustrante es que no te dice qué plugin es el incompatible, ni un nombre, ni una pista, te toca adivinarlo.

aviso plugin incompatible colaboracion en tiempo real wordpress

En este artículo te explico por qué sale este aviso, cómo encontrar el plugin que lo provoca, qué hacer si no eres desarrollador, y cómo corregir la incompatibilidad si mantienes plugins propios, con ejemplo real incluido.

Pero no adelantemos acontecimientos, que igual no sabes qué leches es esto de la colaboración en tiempo real. Te lo cuento.

Qué es la colaboración en tiempo real de WordPress

Hasta ahora, cuando alguien estaba editando una entrada en WordPress, el resto de usuarios quedaban bloqueados. Podías tomar posesión del post o irte, pero editar a la vez no era posible. Desde WordPress 7.0 esto cambia.

La colaboración en tiempo real (RTC) permite que dos o más personas editen el mismo contenido a la vez. Ves el cursor del otro usuario, sus cambios aparecen en tu pantalla al momento y el sistema se encarga de que no haya conflictos. Por debajo usa Yjs, una librería del tipo CRDT (Conflict-free Replicated Data Type) que resuelve los conflictos de edición sin perder datos.

Por defecto, WordPress usa HTTP polling como transporte, lo que significa que los clientes envían y reciben cambios a través de peticiones HTTP normales. No es lo más rápido del mundo, pero funciona en cualquier hosting sin necesidad de WebSockets ni configuración especial. Los proveedores de hosting que quieran ofrecer una experiencia mejor pueden sustituir el transporte por WebSockets usando el filtro sync.providers.

Desde las primeras betas de WordPress 7.0, la funcionalidad se ha podido activar manualmente desde Ajustes > Escritura, marcando la casilla ahí incluida, que por defecto se decidió que estuviese inactiva por defecto, ya que en realidad es muy poca gente quien va a usar esta herramienta y consume recursos.

También hay una constante, WP_ALLOW_COLLABORATION que puedes añadir en wp-config.php y permite activar o desactivar la funcionalidad si pasar por los ajustes, así:

define( 'WP_ALLOW_COLLABORATION', true );

Cómo funcionan las tripas de la sincronización en la RTC

La sincronización, como te acabo de comentar, se basa en Yjs, una librería de CRDT que permite que varios clientes editen el mismo documento sin coordinación central. Cada cambio se codifica como una operación CRDT que se puede aplicar en cualquier orden y siempre lleva al mismo resultado.

El proveedor de transporte mediante HTTP polling hace que los clientes envíen y reciban actualizaciones a través de la REST API de WordPress. Los datos CRDT se almacenan en post_meta en un tipo de contenido interno llamado wp_sync_storage (uno por documento). Las actualizaciones se agrupan en lotes y se compactan periódicamente.

WordPress 7.0 limita inicialmente la colaboración a dos usuarios simultáneos para proteger a los hosting. El equipo de desarrollo ha mencionado varias veces que será configurable desde el wp-config, pero a fecha de hoy todavía no se ha documentado el nombre concreto de esa constante. Los proveedores de hosting también pueden sustituir el transporte HTTP por WebSockets usando el filtro sync.providers para una latencia menor y mejor rendimiento con más usuarios.

Todo lo que pasa por los data stores de WordPress (core/editor, core/block-editor) se sincroniza automáticamente. Eso incluye los atributos de los bloques, el título, el extracto y el post meta registrado con show_in_rest. Lo que no pasa por esos data stores (meta boxes clásicas, handlers de save_post, scripts que modifican el DOM directamente) no se sincroniza.

Lo sé, es un poco técnico, pero es que este artículo es tanto para usuarios como para desarrolladores. No voy a hacer preguntas ni cuenta como nota para examen alguno. Seguimos…

Por qué sale el aviso de plugins no compatibles

entrada siendo editada colaboracion en tiempo real wordpress

La colaboración en tiempo real sincroniza el estado del editor a través de los almacenamientos de datos de WordPress y Yjs. Todo lo que pasa por ahí (atributos de bloques, post meta registrado con show_in_rest) se sincroniza automáticamente entre los usuarios conectados.

Pero las cajas meta clásicas no pasan por ahí. Una caja meta clásica (registrada con add_meta_box()) procesa HTML directamente y guarda sus datos a través de un gancho de save_post. Ese flujo no tiene nada que ver con el almacenamiento de datos de Gutenberg, así que los cambios que hagas en una caja meta clásica no se sincronizan con el otro usuario. Si los dos editáis a la vez, uno puede machacar los cambios del otro sin darse cuenta.

Para evitar eso, WordPress toma una decisión radical, y es que si detecta que hay cajas meta clásicas registradas en el editor desactiva la colaboración entera y te muestra el aviso. No intenta sincronizar unas cosas sí y otras no, simplemente la apaga.

Cómo encontrar el plugin culpable

Esta es la parte que a todo el mundo le interesa, seas usuario o desarrollador. WordPress no te dice qué plugin es, así que te toca investigar. Hay varias formas de hacerlo, de más fácil a más técnica.

Descarte por desactivación (el más fiable)

La forma más rápida y segura de identificar el plugin que bloquea la colaboración es esta:

  1. Asegúrate de que la colaboración en tiempo real está activada en Ajustes > Escritura.
  2. Desactiva todos los plugins.
  3. Abre una entrada con dos usuarios a la vez y comprueba que la colaboración funciona (deberías ver el cursor del otro usuario).
  4. Ve activando los plugins uno a uno.
  5. Después de activar cada plugin, vuelve a abrir la entrada con los dos usuarios.
  6. Cuando la colaboración deje de funcionar y te vuelva a salir el aviso, ese es el plugin problemático.

Es el método clásico de descarte. Lleva un rato, pero no falla, es gratis y tiene cero curva de aprendizaje, es para todos los públicos.

Mirar la parte inferior del editor

Fíjate en la captura del aviso, en la parte inferior de la pantalla del editor se ve el texto «Cajas meta» con un desplegable.

cajas meta editor bloques wordpress

Si algún plugin ha registrado cajas meta en ese contenido las verás listadas ahí. Eso ya te da una pista de cuáles son los candidatos, pero no es definitivo, porque a veces tampoco el editor las coloca ahí abajo.

Buscar en el código (para desarrolladores)

Si tienes acceso por SSH o FTP a tu servidor, un grep rápido te da la lista de todos los plugins que registran meta boxes:

grep -r "add_meta_box" wp-content/plugins/ --include="*.php" -l

Nota importante: No todos los plugins que registran cajas meta causan el problema. Solo los que las registran en tipos de contenido donde quieras usar la colaboración. Un plugin que solo registra cajas meta en una pantalla de ajustes o en un tipo de contenido personalizado que no uses para colaborar no va a interferir.

Query Monitor

Esa joya de plugin por el que nunca estaremos suficientemente agradecidos, Query Monitor, te muestra las cajas meta registradas y qué componente las ha registrado. Con eso puedes identificar rápidamente qué plugin está añadiendo cajas meta al editor.

Qué hacer si no eres desarrollador

Si has identificado el plugin que causa el problema y no tienes ni idea de programación tienes dos opciones, ambas igual de válidas, pero mejor siempre la primera.

Contactar con el desarrollador del plugin

Esta es la mejor opción. Ve al repositorio del plugin en WordPress.org, busca el foro de soporte y abre un hilo explicando el problema. Algo así:

«He activado la colaboración en tiempo real de WordPress 7.0 y el editor me muestra el aviso ‘Debido a que esta entrada usa plugins que no son compatibles con la colaboración en tiempo real solo una persona puede editarla al mismo tiempo’. He comprobado por descarte que el plugin que lo provoca es el vuestro. ¿Tenéis previsto hacerlo compatible?»

Si el desarrollador del plugin lee español, puedes enlazarle este artículo directamente, que más abajo tiene la explicación técnica y el código necesario para hacer la corrección. Si solo lee inglés, la nota oficial de desarrollo y el documento de problemas comunes de VIP tienen toda la información que necesita.

Decidir qué prefieres: el plugin o la colaboración

Mientras el desarrollador actualiza el plugin (si lo hace) tienes que elegir. Si la funcionalidad que aporta el plugin no es imprescindible para ti, desactívalo y disfruta de la colaboración en tiempo real. Si el plugin te hace más falta que la colaboración déjalo activo y sigue editando como siempre, con el bloqueo de edición compartida de siempre.

No es la situación ideal, pero es la realidad de una versión mayor que cambia algo tan de base como el modelo de edición de WordPress. Con el tiempo, la mayoría de plugins se irán adaptando.

Los cuatro problemas de compatibilidad más comunes (para desarrolladores)

A partir de aquí el artículo se pone más técnico. Si desarrollas o mantienes plugins de WordPress, esto te interesa. La dev note oficial y la documentación de WordPress VIP identifican cuatro patrones que causan problemas con la colaboración en tiempo real.

Cajas meta clásicas (el caso más frecuente)

Si tu plugin registra una meta box con add_meta_box() y guarda datos con un gancho de save_post, WordPress desactiva la colaboración para ese tipo de post. Da igual que la meta box sea pequeña o que solo tenga un checkbox. Si está ahí, la colaboración se apaga.

La solución es migrar la funcionalidad a un panel en el sidebar del editor de bloques (usando PluginDocumentSettingPanel) y asegurarte de que el post meta esté registrado con show_in_rest => true. La meta box clásica puedes mantenerla como fallback para el editor clásico.

Inputs no controlados que no reflejan cambios externos

Esto afecta a plugins que ya tienen interfaz en el editor de bloques, pero la han construido usando defaultValue en lugar de value en los inputs. Un input con defaultValue solo responde a lo que escribe el usuario local, no a los cambios que llegan de otros clientes.

La solución: usa siempre inputs controlados con value, derivando ese valor del data store de WordPress con useSelect.

Estado local con useState que desconecta del data store

Otro error habitual: copiar el valor del data store a un useState local. En el momento que haces eso, tu componente se desconecta del estado compartido. Las actualizaciones de otros usuarios llegan al data store, pero tu componente sigue mostrando la copia local que hizo al montarse.

La regla: no copies datos compartidos a useState. Lee siempre directamente del data store.

Bloques con efectos secundarios al insertarse

Si tienes un bloque personalizado que abre un modal automáticamente cuando se inserta, ese modal se abrirá para todos los usuarios conectados, porque el contenido del bloque se sincroniza de inmediato.

La solución: en lugar de abrir el modal automáticamente, muestra un placeholder con un botón que abra el modal al hacer clic. Así el efecto es local y voluntario.

Ejemplo práctico: Adaptando el plugin AI Share & Summarize

Vamos a verlo con un caso real, mi plugin AI Share & Summarize, que tiene una caja meta en la barra lateral del editor que permite ocultar los botones de compartir en entradas o páginas individuales. Es una casilla sencilla, pero esa caja meta clásica es suficiente para que WordPress desactive la colaboración en tiempo real en todos los tipos de contenido donde esté registrada. Pequeñita pero potente ¿no?

Vamos a ver el código actual, entender por qué falla y hacer las modificaciones necesarias paso a paso.

El código actual y por qué causa el problema

El archivo includes/class-meta-box.php del plugin hace tres cosas: registra el post meta con register_post_meta() y show_in_rest => true (esto está bien hecho), registra una caja meta clásica con add_meta_box() (esto causa el problema) y guarda los datos desde un gancho de save_post (necesario para el editor clásico, pero innecesario en el de bloques).

La buena noticia es que la parte más complicada ya está resuelta, porque el meta está correctamente registrado para la REST API. Solo necesitamos cuatro cambios.

Paso 1: Añadir revisions_enabled al registro del meta

La nota para desarrolladores de WordPress 7.0 recomienda que el post meta registrado para la colaboración tenga revisions_enabled => true. Esto hace que los cambios en el meta se registren en el historial de revisiones, algo que viene muy bien cuando hay varios editores trabajando a la vez.

En el método ayudawp_register_meta(), añade el parámetro:

public function ayudawp_register_meta() {
    $post_types = get_post_types( array( 'public' => true ), 'names' );

    foreach ( $post_types as $post_type ) {
        register_post_meta( $post_type, self::META_KEY, array(
            'show_in_rest'      => true,
            'single'            => true,
            'type'              => 'boolean',
            'default'           => false,
            'revisions_enabled' => true, // Track changes in revision history.
            'auth_callback'     => function() {
                return current_user_can( 'edit_posts' );
            },
        ) );
    }
}

Paso 2: Registrar la meta box solo en el editor clásico

Este es el cambio clave. Necesitamos que add_meta_box() solo se ejecute cuando estemos en el editor clásico. Cuando el editor de bloques esté activo, no registramos la meta box, y eso permite que la colaboración funcione.

Modifica el método ayudawp_add_meta_box():

public function ayudawp_add_meta_box() {
    $post_types = get_post_types( array( 'public' => true ), 'names' );

    foreach ( $post_types as $post_type ) {
        // Skip if the block editor is active for this post type.
        if ( function_exists( 'use_block_editor_for_post_type' )
            && use_block_editor_for_post_type( $post_type )
        ) {
            continue;
        }

        add_meta_box(
            'ayudawp_aiss_exclude_metabox',
            __( 'AI Share & Summarize', 'ai-share-summarize' ),
            array( $this, 'ayudawp_render_meta_box' ),
            $post_type,
            'side',
            'default'
        );
    }
}

Con este cambio, los usuarios del editor clásico siguen teniendo la meta box de siempre. Los que usen el editor de bloques no la verán, y la colaboración no se desactivará.

Paso 3: Crear un panel en la barra lateral del editor de bloques

Ahora necesitamos que los usuarios del editor de bloques puedan seguir ocultando los botones en entradas individuales. Para eso toca crear un panel en la barra lateral del editor usando PluginDocumentSettingPanel.

Creamos (bueno, yo en este ejemplo, que el plugin es mío) un nuevo archivo assets/js/editor-sidebar.js:

/**
 * AI Share & Summarize - Block Editor Sidebar Panel
 *
 * Replaces the classic meta box in the block editor with a sidebar panel
 * compatible with WordPress 7.0 real-time collaboration.
 */
( function () {
    var el              = wp.element.createElement;
    var registerPlugin  = wp.plugins.registerPlugin;
    var PluginDocPanel  = wp.editor.PluginDocumentSettingPanel
                          || wp.editPost.PluginDocumentSettingPanel;
    var CheckboxControl = wp.components.CheckboxControl;
    var useSelect       = wp.data.useSelect;
    var useDispatch     = wp.data.useDispatch;
    var __              = wp.i18n.__;

    /**
     * Sidebar panel component
     *
     * Reads the exclusion meta value directly from the data store
     * using a controlled input. This keeps the panel in sync across
     * all connected editors during real-time collaboration.
     */
    function AissExcludePanel() {
        // Always read from the data store, never from local state.
        var isExcluded = useSelect( function ( select ) {
            var meta = select( 'core/editor' ).getEditedPostAttribute( 'meta' );
            return meta && meta._ayudawp_aiss_exclude ? true : false;
        }, [] );

        var editPost = useDispatch( 'core/editor' ).editPost;

        return el(
            PluginDocPanel,
            {
                name: 'aiss-exclude-panel',
                title: 'AI Share & Summarize',
                icon: 'share',
            },
            el( CheckboxControl, {
                label: __( 'Hide share buttons on this content', 'ai-share-summarize' ),
                checked: isExcluded,
                onChange: function ( value ) {
                    editPost( { meta: { _ayudawp_aiss_exclude: value } } );
                },
                help: __(
                    'Check this box to prevent the share and AI buttons from appearing on this specific content.',
                    'ai-share-summarize'
                ),
            } )
        );
    }

    registerPlugin( 'aiss-exclude-panel', {
        render: AissExcludePanel,
        icon: 'share',
    } );
} )();

Hay varios detalles importantes en este código. El valor del checkbox se lee siempre del data store con useSelect, nunca se copia a un useState local. El input usa checked (controlado), no defaultChecked. Y los cambios se escriben directamente al data store con editPost. Esos tres puntos son los que garantizan que el panel funcione correctamente cuando varios usuarios editan a la vez.

El archivo no necesita JSX ni siquiera proceso de build. Usa wp.element.createElement directamente, así que funciona tal cual.

Paso 4: Encolar el script en el editor de bloques

Ahora hay que decirle a WordPress que cargue ese script cuando se abra el editor de bloques. Añade el gancho en el constructor de la clase y el nuevo método:

En el constructor:

public function __construct() {
    add_action( 'add_meta_boxes', array( $this, 'ayudawp_add_meta_box' ) );
    add_action( 'save_post', array( $this, 'ayudawp_save_meta_box' ), 10, 2 );
    add_action( 'init', array( $this, 'ayudawp_register_meta' ) );
    add_action( 'enqueue_block_editor_assets', array( $this, 'ayudawp_enqueue_editor_sidebar' ) );
}

Y el nuevo método:

public function ayudawp_enqueue_editor_sidebar() {
    wp_enqueue_script(
        'ayudawp-aiss-editor-sidebar',
        AYUDAWP_AISS_PLUGIN_URL . 'assets/js/editor-sidebar.js',
        array( 'wp-plugins', 'wp-editor', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n' ),
        AYUDAWP_AISS_VERSION,
        true
    );
}

El gancho enqueue_block_editor_assets se dispara solo cuando se carga el editor de bloques, así que el script no se carga en ningún otro sitio.

El archivo completo modificado

Para que no tengas que ir juntando piezas, abajo tienes el archivo includes/class-meta-box.php completo con todos los cambios aplicados, para que veas el resultado final por si te sirve para tu plugin. Puedes descargarlo directamente desde el enlace que he puesto al final del artículo.

Qué pasa con los datos existentes

Las entradas que ya tenían la casilla marcado con la caja meta clásica siguen funcionando con el panel nuevo sin tocar nada. Ambos sistemas leen y escriben en la misma clave de meta (_ayudawp_aiss_exclude). El editor clásico guarda el valor como string '1' y el editor de bloques lo guarda como booleano true, pero la función ayudawp_is_post_excluded() hace un cast a booleano con (bool), así que las dos representaciones funcionan bien. No hay que migrar datos.

Probar la colaboración

Con los cambios hechos, los pasos para comprobar que todo funciona:

  1. Asegúrate de tener WordPress 7.0 instalado y la colaboración activada en los ajustes de escritura
  2. Abre una entrada en el editor de bloques con dos usuarios distintos. Si todo va bien verás el cursor del otro usuario en el editor y podréis editar a la vez sin que salte el aviso
  3. Revisa que el panel «AI Share & Summarize» (o el tuyo, claro) aparece en la barra lateral de la pestaña «Entrada» (no confundir con la pestaña «Bloque»)
  4. Marca y desmarca la casilla desde ambas sesiones y comprueba que el cambio se refleja en la otra

Resumen de los cambios para desarrolladores

Para que quede claro qué archivos se tocan y qué cambia en cada uno:

En includes/class-meta-box.php se hacen cuatro modificaciones: se añade revisions_enabled => true al register_post_meta(), se condiciona add_meta_box() para que solo se registre en el editor clásico, se añade el gancho enqueue_block_editor_assets en el constructor, y se añade el método ayudawp_enqueue_editor_sidebar() para encolar el script.

Se crea un archivo nuevo, assets/js/editor-sidebar.js, con el panel del sidebar para el editor de bloques.

No se toca nada más. El handler de save_post se mantiene porque sigue siendo necesario para el editor clásico. La función ayudawp_is_post_excluded() también se mantiene porque lee de la misma clave de meta sea cual sea el editor que la haya guardado.

Resumen de comprobación de compatibilidad de RTC para plugins

Si mantienes plugins de WordPress y quieres que sean compatibles con la colaboración en tiempo real de WordPress 7.0, repasa estos puntos.

Cajas meta

Comprueba si tu plugin registra meta boxes con add_meta_box(). Si lo hace, tienes dos opciones: eliminar la meta box y sustituirla por un panel en el sidebar del editor de bloques, o mantener la meta box solo para el editor clásico y crear el panel en paralelo (como en el ejemplo de arriba). Para cualquiera de las dos opciones, el post meta tiene que estar registrado con register_post_meta() y show_in_rest => true.

Componentes JavaScript

Revisa que todos tus componentes que leen datos compartidos (meta, atributos de bloques) los lean directamente del data store con useSelect. No copies esos valores a useState. Usa inputs controlados (value y checked), no inputs no controlados (defaultValue y defaultChecked).

Efectos secundarios

Si alguno de tus bloques ejecuta código automáticamente al insertarse (abrir un modal, hacer una petición HTTP, disparar un evento), ten en cuenta que ese efecto se ejecutará en todas las sesiones conectadas. Convierte esos disparadores automáticos en acciones manuales para que solo afecten al usuario que los inicia.

Revisiones

Añade revisions_enabled => true a los post meta que modifiques desde el editor. Así el historial de revisiones recoge los cambios en el meta y no solo en el contenido de la entrada.

Cómo desactivar la colaboración desde un plugin

Puede que tengas un plugin donde la colaboración cause problemas que no puedes resolver de momento, o que quieras desactivarla durante un despliegue gradual. Hay una forma limpia de hacerlo sin tocar nada de WordPress.

El filtro sync.providers controla qué proveedores de sincronización están activos. Si devuelves un array vacío la colaboración se desactiva:

import { addFilter } from '@wordpress/hooks';

addFilter( 'sync.providers', 'my-plugin/disable-collab', () => [] );

Esto es temporal y limpio. No afecta a ninguna otra funcionalidad del editor.

Documentación y recursos

Los enlaces a la documentación oficial para profundizar en todo lo que hemos visto:

Si te ha saltado el aviso de plugins no compatibles y has conseguido identificar cuál era el culpable (o si eres desarrollador y has adaptado tu plugin), cuéntamelo en los comentarios.

Saber qué plugins dan problemas con la colaboración en tiempo real nos viene bien a todos, y si tienes dudas con la migración de cajas meta también te puedo echar una mano por ahí.

Compartir en redes
Resumir con IA

¿De cuánta utilidad te ha parecido este contenido?

¡Haz clic en las estrellas para valorarlo!

Promedio de puntuación 5 / 5. Total de votos: 4

¡Todavía no hay votos! Sé el primero en valorar este contenido.

Ya que has encontrado útil este contenido...

¡Sígueme en las redes sociales!

¿Te gustó este artículo? ¡Ni te imaginas lo que te estás perdiendo en YouTube!



Sobre el autor

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio