Запуск JavaScript при сохранении в Gutenberg (Блочный редактор)

13 нояб. 2018 г., 03:01:39
Просмотры: 15.2K
Голосов: 16

У меня есть метабокс, и мне нужно запустить JavaScript при сохранении поста (в данном случае - для обновления страницы).

В классическом редакторе это можно сделать через простой редирект, подключенный к хуку save_post (с высоким приоритетом).

Но так как Gutenberg преобразует процесс сохранения для существующих метабоксов в отдельные AJAX-запросы, теперь это должно быть реализовано через JavaScript. Итак, как мне:

  • Отследить событие, когда все процессы сохранения завершены, и затем запустить JavaScript? Если да, то как называется это событие? Где можно найти документацию по этим событиям? ИЛИ

  • Запустить JavaScript внутри процесса сохранения метабокса через AJAX, который затем может проверить состояние процесса сохранения родительской страницы перед продолжением?

7
Комментарии

Перезагрузка только вашего метабокса в Гутенберге также является потенциальным решением, как и реализация UI метабокса на JS с использованием хранилищ данных wp.data

Tom J Nowell Tom J Nowell
13 нояб. 2018 г. 04:07:41

@TomJNowell Я нашел эту ссылку, которую могу использовать для проверки некоторых состояний, но не уверен, как к ним получить доступ: https://wordpress.org/gutenberg/handbook/data/data-core-editor/

majick majick
13 нояб. 2018 г. 04:37:45

Пока у меня есть: например wp.data.select('core/editor').isSavingPost() ... такой способ доступа не задокументирован нигде, что я вижу... и он также кажется ненадежным, так как возвращает false после первого сохранения поста (до этого он undefined), независимо от того, продолжает ли редактор сохранять или нет. facepalm

majick majick
13 нояб. 2018 г. 07:50:11

Вы также можете создать issue в репозитории Gutenberg для получения поддержки, это по теме, но там могут ответить более осведомленные люди. Также может подойти система хуков WP JS, но это всего лишь предположение

Tom J Nowell Tom J Nowell
13 нояб. 2018 г. 09:02:13

Удивительно, но такая простая вещь уже запрашивалась и не поддерживается: https://github.com/WordPress/gutenberg/issues/10044 ... поэтому я пытаюсь найти способ сделать это самостоятельно.

majick majick
13 нояб. 2018 г. 09:14:42

При дальнейшем тестировании оказалось, что isSavingPost в коде действительно работает (см. ответ), но при обращении из консоли браузера всегда возвращает false ошибочно. Ну что ж.

majick majick
13 нояб. 2018 г. 10:12:27

Довольно поздно, но я написал хук, который можно использовать для определения момента завершения процесса сохранения на стороне сервера. Хук можно найти здесь - https://thewpvoyage.com/how-to-detect-when-a-post-is-done-saving-in-wordpress-gutenberg/

Siddharth Thevaril Siddharth Thevaril
21 авг. 2024 г. 13:22:07
Показать остальные 2 комментариев
Все ответы на вопрос 6
6
16

Не уверен, есть ли лучший способ, но я использую subscribe вместо добавления обработчика событий к кнопке:

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

  if (isSavingPost && !isAutosavingPost) {
    // Здесь ваш AJAX код ......

  }
})

Официальная документация данных редактора записей: https://wordpress.org/gutenberg/handbook/designers-developers/developers/data/data-core-editor/

11 мар. 2019 г. 14:11:42
Комментарии

это выглядит намного чище, просто интересно, откуда вообще берётся метод subscribe? это часть функции wp.data? В документации я не нашёл упоминания об этом.

majick majick
12 мар. 2019 г. 15:50:33

Да, subscribe — это метод модуля wp.data. Откройте консоль при редактировании поста в Gutenberg и выполните wp.data. Это выведет список всех доступных методов модуля данных.

tomyam tomyam
13 мар. 2019 г. 10:37:07

отличная находка! жаль, что документация Gutenberg так запутанно организована и содержит мало примеров. плюс ожидание, что разработчики будут знать и/или захотят изучать методы React, — это действительно перебор... конечно, это может экономить время, если вы уже знакомы с ними, но если нет — это настоящая трата времени: у меня ушли часы, чтобы просто разобраться, как получить доступ к чему-то полезному в модели wp.data. я возвращаюсь к PHP (и классическому редактору).

majick majick
14 мар. 2019 г. 11:30:55

Спасибо за публикацию! Как я могу перехватить и остановить обновление/публикацию записи на основе условия.

Mohammed AlBanna Mohammed AlBanna
12 дек. 2019 г. 03:27:39

Похоже, этот метод также запускает код, когда пользователь нажимает кнопку "Переместить в корзину" (статус записи меняется на "trash", а значение isSavingPost равно "true" независимо от этого). Также в моем случае один клик по "Обновить" вызвал срабатывание кода подписки 3 раза. В итоге я стал отслеживать клики по .editor-post-publish-button, .editor-post-save-draft и .editor-post-preview.

Oksana Romaniv Oksana Romaniv
6 мар. 2020 г. 15:57:26

Этот сниппет отличный, но он будет срабатывать несколько раз, в следующей ветке объясняется, как это предотвратить: https://github.com/WordPress/gutenberg/issues/5975#issuecomment-483488988

csalmeida csalmeida
21 февр. 2021 г. 19:46:06
Показать остальные 1 комментариев
1

Хорошо, решение получилось гораздо более хакерским, чем я хотел, но оно работает...

Вот немного упрощенный и абстрагированный способ из моего кода, на случай, если кому-то понадобится сделать то же самое (я уверен, что в ближайшем будущем так поступят и другие плагины).

    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('Сохранение: '+postsaving+' - Автосохранение: '+autosaving+' - Успешно: '+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('Требуется перезагрузка страницы. Обновить страницу сейчас?')) {
                                window.location.href = window.location.href+'&refreshed=1';
                            }
                        }
                    }, 1000);
                });
            }
        }, 500);
    });

...просто нужно заменить metabox_input_id и trigger_value на нужные значения. :-)

13 нояб. 2018 г. 10:04:12
Комментарии

Это было полезно, единственный пример, который я смог найти по доступу к иерархии модулей Gutenberg в JavaScript: https://github.com/front/gutenberg-js

majick majick
13 нояб. 2018 г. 10:18:26
0

Если кому-то еще интересно, я придумал простой способ выполнить какой-то код сразу ПОСЛЕ того, как редактор блоков (Gutenberg) завершит публикацию/обновление записи:

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

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

    return savePost(options)
        .then(() => {
            // Выполнить что-то после фактического асинхронного сохранения записи.
            console.log('Запись была сохранена.')

            if (!options.isAutosave) {
               // Это не автосохранение.
            }
        })
}

По сути, приведенный выше сниппет переопределяет нативную функцию savePost().
Таким образом, вы переопределяете её своей собственной функцией, вызываете savePost() внутри неё и используете преимущество возвращаемого промиса через then.

27 янв. 2023 г. 22:48:36
1

Чтобы выполнить действие (в данном случае Ajax-запрос) ПОСЛЕ того, как сохранение записи будет ЗАВЕРШЕНО, можно использовать интервал для ожидания, пока isSavingPost снова вернет false.

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 июн. 2021 г. 03:32:52
Комментарии

Определенно правильный путь - работает отлично. Отличная работа!

Spencer Bigum Spencer Bigum
6 дек. 2021 г. 19:27:29
2

Вам необходимо собрать функцию отписки от подписки и вызвать её, чтобы избежать многократных вызовов.

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();


                // ваш AJAX ЗДЕСЬ();

            }
        });
13 апр. 2020 г. 14:14:19
Комментарии

Это работает нормально, за исключением того, что срабатывает ДО полного сохранения записи. Мой код, размещенный под "unsubscribe()", запускается до того, как WordPress инициирует сохранение записи через AJAX. Есть ли решение для выполнения кода после того, как WordPress на 100% завершит сохранение/обновление записи?

Neoweiter Neoweiter
1 июн. 2020 г. 22:21:19

Я подтверждаю, что это срабатывает до завершения сохранения записи. Я добавил новый ответ, который, как мне кажется, может сработать для запуска только после полного сохранения записи: https://wordpress.stackexchange.com/a/390543/171971

andergmartins andergmartins
15 июн. 2021 г. 03:34:13
0

Я написал статью в блоге на эту тему — https://thewpvoyage.com/how-to-detect-when-a-post-is-done-saving-in-wordpress-gutenberg/

Вы можете использовать следующий хук:

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

/**
 * Возвращает `true`, если запись завершила сохранение, иначе `false`.
 *
 * @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 ) {
            // Код, выполняемый после завершения сохранения записи.
            setIsPostSaved( true );
            isPostSavingInProgress.current = false;
        }
    }, [ isSavingPost, isAutosavingPost ] );

    return isPostSaved;
};

/**
 * Функция редактирования примера блока.
 *
 * @return {WPElement} Элемент для рендеринга.
 */
export default function Edit() {
    const isAfterSave = useAfterSave();

    useEffect( () => {
        if ( isAfterSave ) {
            // Добавьте здесь ваш код, который должен выполниться после сохранения записи.
            console.log( '...сохранение завершено...' )
        }
    }, [ isAfterSave ] );

    return (
        <p { ...useBlockProps() }>
            { __( 'Список дел — привет из редактора!', 'todo-list' ) }
        </p>
    );
}
21 авг. 2024 г. 13:23:34