Disparar JavaScript al guardar en Gutenberg (Editor de Bloques)

13 nov 2018, 03:01:39
Vistas: 15.2K
Votos: 16

Tengo un metabox y quiero activar algún código JavaScript cuando se guarda un post (para refrescar la página en este caso de uso).

En el Editor Clásico, esto se puede hacer mediante un simple redireccionamiento enganchado a save_post (con alta prioridad).

Pero como Gutenberg convierte el proceso de guardado para metaboxes existentes en llamadas AJAX individuales, ahora necesita ser JavaScript. Entonces, ¿cómo puedo:

  • Escuchar un evento donde todos los procesos de guardado estén completos y luego activar el JavaScript? Si es así, ¿cómo se llama este evento? ¿Existe alguna referencia a estos eventos? O

  • Activar JavaScript dentro del proceso AJAX de guardado del metabox, que luego pueda verificar el estado del proceso de guardado de la página principal antes de continuar?

7
Comentarios

Hacer que Gutenberg recargue solo tu metabox también es una solución potencial, al igual que implementar la interfaz de usuario del metabox en JS y depender de los almacenes de datos wp.data

Tom J Nowell Tom J Nowell
13 nov 2018 04:07:41

@TomJNowell He encontrado esta referencia que puedo usar para verificar algunos estados, pero no estoy seguro de cómo acceder a ellos: https://wordpress.org/gutenberg/handbook/data/data-core-editor/

majick majick
13 nov 2018 04:37:45

hasta ahora tengo: ej. wp.data.select('core/editor').isSavingPost() ... este tipo de acceso no está documentado en ningún lugar que pueda ver... y también parece poco confiable ya que devuelve false después de que el post se guarda por primera vez (antes de eso es undefined) independientemente de si el editor todavía está guardando o no. facepalm

majick majick
13 nov 2018 07:50:11

También puedes crear un issue en el repositorio de Gutenberg para obtener soporte, es un tema relevante aquí pero podrías obtener respuestas de personas más conocedoras allí. Además, el sistema de hooks WP en JS podría ser una posibilidad, pero eso es solo una suposición.

Tom J Nowell Tom J Nowell
13 nov 2018 09:02:13

Increíblemente, algo tan simple como esto ya ha sido solicitado y no está soportado: https://github.com/WordPress/gutenberg/issues/10044 ... por eso estoy intentando encontrar una forma de hacerlo yo mismo.

majick majick
13 nov 2018 09:14:42

Con más pruebas, el isSavingPost en realidad parece funcionar en el código (ver respuesta), pero cuando se accede desde la consola del navegador siempre parece devolver false falsamente. Bueno, qué se le va a hacer.

majick majick
13 nov 2018 10:12:27

Llego un poco tarde a esto, pero escribí un hook que se puede usar para detectar cuando se completa el proceso de guardado en el servidor. Puedes encontrar el hook aquí - https://thewpvoyage.com/how-to-detect-when-a-post-is-done-saving-in-wordpress-gutenberg/

Siddharth Thevaril Siddharth Thevaril
21 ago 2024 13:22:07
Mostrar los 2 comentarios restantes
Todas las respuestas a la pregunta 6
6
16

No estoy seguro si hay una mejor manera, pero estoy escuchando subscribe en lugar de agregar un event listener al botón:

wp.data.subscribe(function () {
  var isSavingPost = wp.data.select('core/editor').isSavingPost();
  var isAutosavingPost = wp.data.select('core/editor').isAutosavingPost();

  if (isSavingPost && !isAutosavingPost) {
    // Aquí va tu código AJAX ......

  }
})

Documentación oficial de los datos del Editor de Entradas: https://wordpress.org/gutenberg/handbook/designers-developers/developers/data/data-core-editor/

11 mar 2019 14:11:42
Comentarios

esto se ve mucho más limpio, solo por curiosidad ¿de dónde viene el método subscribe? ¿es parte de la función wp.data? No lo veo mencionado en la documentación.

majick majick
12 mar 2019 15:50:33

Sí, subscribe es un método del módulo wp.data. Abre la consola al editar una publicación con Gutenberg y ejecuta wp.data. Esto muestra todos los métodos disponibles del módulo de datos.

tomyam tomyam
13 mar 2019 10:37:07

¡bien hecho por encontrar esto! es una lástima que la documentación de Gutenberg esté tan oscuramente organizada y no tenga suficientes ejemplos. además, la expectativa de que los desarrolladores sepan y/o quieran aprender métodos de React es realmente demasiado... Estoy seguro de que puede ahorrar mucho tiempo si ya lo conoces, pero es una verdadera pérdida de tiempo si no lo sabes; me tomó horas solo para averiguar cómo acceder a algo útil en el modelo wp.data. vuelvo a PHP (y al editor clásico) para mí.

majick majick
14 mar 2019 11:30:55

¡Gracias por compartir esto! ¿Cómo puedo interceptar y detener la actualización/publicación del post basado en una condición?

Mohammed AlBanna Mohammed AlBanna
12 dic 2019 03:27:39

Parece que este método también activa el código cuando un usuario hace clic en el botón "Mover a la papelera" (el estado del post cambia a "trash" y el valor de isSavingPost es "true" independientemente de esto). Además, un solo clic en "Actualizar" activó el código de suscripción 3 veces en mi caso. Terminé escuchando los clics en .editor-post-publish-button, .editor-post-save-draft y .editor-post-preview.

Oksana Romaniv Oksana Romaniv
6 mar 2020 15:57:26

Este fragmento de código es genial pero se activará múltiples veces, el siguiente hilo explica cómo evitar que esto suceda: https://github.com/WordPress/gutenberg/issues/5975#issuecomment-483488988

csalmeida csalmeida
21 feb 2021 19:46:06
Mostrar los 1 comentarios restantes
1

Bien, esta es una solución mucho más improvisada de lo que quería, pero funciona...

Aquí hay una forma ligeramente simplificada y abstracta de hacerlo según mi código, por si alguien necesita hacer lo mismo (estoy seguro de que más plugins lo necesitarán en un futuro cercano).

    var reload_check = false; var publish_button_click = false;
    jQuery(document).ready(function($) {
        add_publish_button_click = setInterval(function() {
            $publish_button = jQuery('.edit-post-header__settings .editor-post-publish-button');
            if ($publish_button && !publish_button_click) {
                publish_button_click = true;
                $publish_button.on('click', function() {
                    var reloader = setInterval(function() {
                        if (reload_check) {return;} else {reload_check = true;}
                        postsaving = wp.data.select('core/editor').isSavingPost();
                        autosaving = wp.data.select('core/editor').isAutosavingPost();
                        success = wp.data.select('core/editor').didPostSaveRequestSucceed();
                        console.log('Guardando: '+postsaving+' - Autoguardado: '+autosaving+' - Éxito: '+success);
                        if (postsaving || autosaving || !success) {classic_reload_check = false; return;}
                        clearInterval(reloader);

                        value = document.getElementById('metabox_input_id').value;
                        if (value == 'trigger_value') {
                            if (confirm('Se requiere recargar la página. ¿Recargar ahora?')) {
                                window.location.href = window.location.href+'&refreshed=1';
                            }
                        }
                    }, 1000);
                });
            }
        }, 500);
    });

...solo hay que cambiar metabox_input_id y trigger_value según sea necesario. :-)

13 nov 2018 10:04:12
Comentarios

Esto fue útil, el único ejemplo de referencia que pude encontrar para acceder a la jerarquía de módulos JavaScript de Gutenberg: https://github.com/front/gutenberg-js

majick majick
13 nov 2018 10:18:26
0

Si alguien todavía está interesado, encontré una forma simple de ejecutar algo justo DESPUÉS de que el editor de bloques (Gutenberg) termine de publicar/actualizar una entrada:

const editor = window.wp.data.dispatch('core/editor')
const savePost = editor.savePost

editor.savePost = function (options) {
    options = options || {}

    return savePost(options)
        .then(() => {
            // Hacer algo después de que la entrada se guarde de forma asíncrona.
            console.log('La entrada fue guardada.')

            if (!options.isAutosave) {
               // Esto no es un guardado automático.
            }
        })
}

Básicamente, el fragmento de código anterior sobrescribe la función nativa savePost().
Así que la sobrescribes con tu propia función, llamas a savePost() nuevamente dentro de ella y aprovechas la promesa devuelta simplemente usando then.

27 ene 2023 22:48:36
1

Para activar la acción (en este caso una solicitud Ajax) DESPUÉS de que el guardado del post esté COMPLETO, puedes usar un intervalo para esperar hasta que isSavingPost devuelva false nuevamente.

let intervalCheckPostIsSaved;
let ajaxRequest;

wp.data.subscribe(function () {
    let editor = wp.data.select('core/editor');

    if (editor.isSavingPost()
         && !editor.isAutosavingPost()
         && editor.didPostSaveRequestSucceed()) {

        if (!intervalCheckPostIsSaved) {
            intervalCheckPostIsSaved = setInterval(function () {
                if (!wp.data.select('core/editor').isSavingPost()) {
                    if (ajaxRequest) {
                        ajaxRequest.abort();
                    }

                    ajaxRequest = $.ajax({
                        url: ajaxurl,
                        type: 'POST',
                        data: {},
                        success: function (data) {
                            ajaxRequest = null;
                        }
                    });

                    clearInterval(intervalCheckPostIsSaved);
                    intervalCheckPostIsSaved = null;
                }
            }, 800);
        }
    }
});
15 jun 2021 03:32:52
Comentarios

Definitivamente el camino a seguir: funciona tan bien. ¡Excelente trabajo!

Spencer Bigum Spencer Bigum
6 dic 2021 19:27:29
2

Necesitas recoger la función unsubscribe de la suscripción y llamarla para evitar llamadas múltiples.

const unsubscribe = wp.data.subscribe(function () {
            let select = wp.data.select('core/editor');
            var isSavingPost = select.isSavingPost();
            var isAutosavingPost = select.isAutosavingPost();
            var didPostSaveRequestSucceed = select.didPostSaveRequestSucceed();
            if (isSavingPost && !isAutosavingPost && didPostSaveRequestSucceed) {
                console.log("isSavingPost && !isAutosavingPost && didPostSaveRequestSucceed");
                unsubscribe();


                // tu AJAX AQUÍ();

            }
        });
13 abr 2020 14:14:19
Comentarios

Esto parece funcionar bien, excepto que aún se activa ANTES de que se complete el guardado del post. Mi código colocado debajo de "unsubscribe()" se ejecuta antes de que WP inicie el guardado del post mediante AJAX. ¿Existe alguna solución para ejecutar código después de que WP haya terminado al 100% con el guardado/actualización del post?

Neoweiter Neoweiter
1 jun 2020 22:21:19

Puedo confirmar que se activa antes de que termine de guardarse el post. He añadido una nueva respuesta que creo que podría funcionar para activarse solo después de que el post haya terminado de guardarse: https://wordpress.stackexchange.com/a/390543/171971

andergmartins andergmartins
15 jun 2021 03:34:13
0

Escribí una publicación en mi blog sobre esto - https://thewpvoyage.com/how-to-detect-when-a-post-is-done-saving-in-wordpress-gutenberg/

Puedes usar el siguiente hook:

import { useBlockProps } from '@wordpress/block-editor';
import { useRef, useState, useEffect } from '@wordpress/element';
import { useSelect } from '@wordpress/data';

/**
 * Retorna `true` si el post ha terminado de guardarse, `false` en caso contrario.
 *
 * @returns {Boolean}
 */
const useAfterSave = () => {
    const [ isPostSaved, setIsPostSaved ] = useState( false );
    const isPostSavingInProgress = useRef( false );
    const { isSavingPost, isAutosavingPost } = useSelect( ( __select ) => {
        return {
            isSavingPost: __select( 'core/editor' ).isSavingPost(),
            isAutosavingPost: __select( 'core/editor' ).isAutosavingPost(),
        }
    } );

    useEffect( () => {
        if ( ( isSavingPost || isAutosavingPost ) && ! isPostSavingInProgress.current ) {
            setIsPostSaved( false );
            isPostSavingInProgress.current = true;
        }
        if ( ! ( isSavingPost || isAutosavingPost ) && isPostSavingInProgress.current ) {
            // Código a ejecutar después de que el post se haya guardado.
            setIsPostSaved( true );
            isPostSavingInProgress.current = false;
        }
    }, [ isSavingPost, isAutosavingPost ] );

    return isPostSaved;
};

/**
 * Función de edición de un bloque de ejemplo.
 *
 * @return {WPElement} Elemento a renderizar.
 */
export default function Edit() {
    const isAfterSave = useAfterSave();

    useEffect( () => {
        if ( isAfterSave ) {
            // Agrega aquí tu código que debe ejecutarse después de guardar el post.
            console.log( '...guardado completado...' )
        }
    }, [ isAfterSave ] );

    return (
        <p { ...useBlockProps() }>
            { __( 'Lista de Tareas – ¡hola desde el editor!', 'todo-list' ) }
        </p>
    );
}
21 ago 2024 13:23:34