Declanșare Javascript la Salvare în Gutenberg (Block Editor)
Am un metabox pentru care doresc să declanșez niște Javascript atunci când un post este salvat (pentru a reîmprospăta pagina în acest caz de utilizare).
În editorul clasic, acest lucru poate fi realizat printr-o simplă redirecționare legată de save_post
(cu o prioritate mare).
Dar deoarece Gutenberg transformă procesul de salvare pentru metabox-urile existente în apeluri AJAX individuale acum, este nevoie de Javascript, așa că cum pot să:
Ascult un eveniment în care toate procesele de salvare sunt finalizate și apoi să declanșez Javascript? Dacă da, cum se numește acest eveniment? Există undeva o referință pentru aceste evenimente? SAU
Declanșez Javascript în interiorul procesului AJAX de salvare al metabox-ului, care poate apoi să verifice starea procesului de salvare al paginii părinte înainte de a continua?

Nu sunt sigur dacă există o metodă mai bună, dar ascult evenimentul subscribe
în loc să adaug un event listener la buton:
wp.data.subscribe(function () {
var isSavingPost = wp.data.select('core/editor').isSavingPost();
var isAutosavingPost = wp.data.select('core/editor').isAutosavingPost();
if (isSavingPost && !isAutosavingPost) {
// Aici vine codul tău AJAX ......
}
})
Documentația oficială a datelor Editorului de Postări: https://wordpress.org/gutenberg/handbook/designers-developers/developers/data/data-core-editor/

pare mult mai curat, sunt doar curios de unde vine metoda subscribe
? face parte din funcția wp.data
? Nu o văd menționată în documentație.

Da, subscribe
este o metodă a modulului wp.data. Deschide consola când editezi un post cu Gutenberg și rulează wp.data
. Aceasta listează toate metodele disponibile ale modulului de date.

bravo că ai găsit asta! e păcat că documentația Gutenberg este atât de obscur organizată și nu are suficiente exemple. plus așteptarea ca dezvoltatorii să cunoască și/sau să vrea să învețe metode React este cu adevărat prea mult... sunt sigur că poate fi un mare economisitor de timp dacă le cunoști deja, dar este o pierdere de timp reală dacă nu - mi-a luat ore întregi doar să înțeleg cum să accesez ceva util în modelul wp.data
. pentru mine, revin la PHP (și editorul clasic).

Mulțumesc pentru share! Cum pot intercepta și opri actualizarea/publicarea postării pe baza unei condiții.

Se pare că această metodă declanșează și codul atunci când un utilizator apasă butonul "Mută în Coș" (starea postării se schimbă în "trash" și valoarea isSavingPost este "true" indiferent de acest lucru). De asemenea, un singur click pe "Actualizează" a declanșat codul de subscripție de 3 ori în cazul meu. Am ajuns să ascult pentru click pe .editor-post-publish-button, .editor-post-save-draft și .editor-post-preview.

Acest snippet este grozav dar va fi declanșat de mai multe ori, următorul thread explică cum să îl oprești: https://github.com/WordPress/gutenberg/issues/5975#issuecomment-483488988

Bine, deci o soluție mult mai improvisată decât aș fi vrut, dar am reușit să o fac să funcționeze...
Iată o metodă ușor simplificată și abstractizată din codul meu, în caz că cineva va avea nevoie să facă același lucru (sunt sigur că mai multe plugin-uri vor avea nevoie în viitorul apropiat.)
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('Salvare: '+postsaving+' - Autosalvare: '+autosaving+' - Succes: '+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('Este necesară reîncărcarea paginii. Reîmprospătați pagina acum?')) {
window.location.href = window.location.href+'&refreshed=1';
}
}
}, 1000);
});
}
}, 500);
});
...trebuie doar să schimbați metabox_input_id
și trigger_value
pentru a se potrivi cu ceea ce aveți nevoie. :-)

Aceasta a fost utilă, singurul exemplu de referință pe care l-am găsit pentru accesarea ierarhiei modulelor JavaScript din Gutenberg: https://github.com/front/gutenberg-js

Dacă cineva este încă interesat, am găsit o metodă simplă pentru a executa ceva imediat DUPA ce editorul de blocuri (Gutenberg) finalizează publicarea/actualizarea unui articol:
const editor = window.wp.data.dispatch('core/editor')
const savePost = editor.savePost
editor.savePost = function (options) {
options = options || {}
return savePost(options)
.then(() => {
// Faceți ceva după ce articolul a fost salvat efectiv în mod asincron.
console.log('Articolul a fost salvat.')
if (!options.isAutosave) {
// Acesta nu este un salvare automată.
}
})
}
Practic, fragmentul de cod de mai suprascrie funcția nativă savePost()
.
Deci o suprascrieți cu propria funcție, apelați din nou savePost()
în interiorul ei și profitați de promisiunea returnată folosind then
.

Pentru a declanșa acțiunea (în acest caz o cerere Ajax) DUPA ce salvarea postării este COMPLETĂ, poți folosi un interval pentru a aștepta până când isSavingPost returnează false din nou.
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);
}
}
});

Trebuie să colectezi funcția unsubscribe din abonare și să o apelezi pentru a evita apeluri multiple.
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-ul tău AICI();
}
});

Acest lucru pare să funcționeze bine, cu excepția faptului că se declanșează ÎNAINTE de salvarea completă a articolului. Codul meu plasat sub "unsubscribe() se declanșează înainte ca WP să lanseze salvarea articolului prin AJAX. Există o soluție pentru a rula codul după ce WP a terminat 100% cu salvarea/actualizarea articolului?

Pot confirma că se declanșează înainte ca articolul să fie salvat complet. Am adăugat un răspuns nou care cred că ar putea funcționa pentru a se declanșa doar după ce salvarea articolului s-a finalizat: https://wordpress.stackexchange.com/a/390543/171971

Am scris un articol pe blog despre acest subiect - https://thewpvoyage.com/how-to-detect-when-a-post-is-done-saving-in-wordpress-gutenberg/
Poți folosi următorul hook:
import { useBlockProps } from '@wordpress/block-editor';
import { useRef, useState, useEffect } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
/**
* Returnează `true` dacă postarea a fost salvată, `false` în caz contrar.
*
* @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 ) {
// Codul care rulează după ce postarea a fost salvată.
setIsPostSaved( true );
isPostSavingInProgress.current = false;
}
}, [ isSavingPost, isAutosavingPost ] );
return isPostSaved;
};
/**
* Funcția de editare a unui bloc exemplu.
*
* @return {WPElement} Elementul de randat.
*/
export default function Edit() {
const isAfterSave = useAfterSave();
useEffect( () => {
if ( isAfterSave ) {
// Adaugă aici codul care trebuie să ruleze după salvarea postării.
console.log( '...salvare finalizată...' )
}
}, [ isAfterSave ] );
return (
<p { ...useBlockProps() }>
{ __( 'Listă de Sarcini – salut de la editor!', 'todo-list' ) }
</p>
);
}
