The editor keeps its state in a Redux-like store, and everything on screen is derived from it — which means a plugin can read the current post, the selected block or the save status without touching the DOM.
const { select, subscribe, dispatch } = wp.data;
select('core/editor').getEditedPostAttribute('title');
select('core/block-editor').getSelectedBlock();
select('core/editor').isSavingPost();
// and a subscription that fires on every state change
const unsubscribe = subscribe(() => {
if (select('core/editor').isCurrentPostPublished()) {
// ...
}
});
The subscription fires on every change including keystrokes, so the callback has to be cheap and has to compare against a previous value it keeps itself — otherwise a publish handler runs a hundred times. Store names moved during 5.x, with block-related selectors migrating from core/editor to core/block-editor, so examples from 2018 silently return undefined. Checking which store a selector lives in is the first debugging step.