diff --git a/build/validation-api.asset.php b/build/validation-api.asset.php
index 7ad85b7..438ceb3 100644
--- a/build/validation-api.asset.php
+++ b/build/validation-api.asset.php
@@ -1 +1 @@
- array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-plugins'), 'version' => '52847e18bf95c1b9a5a4');
+ array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-plugins'), 'version' => 'ebffb00f91b03991c44b');
diff --git a/build/validation-api.js b/build/validation-api.js
index 9fbb094..ada7d3d 100644
--- a/build/validation-api.js
+++ b/build/validation-api.js
@@ -1,11 +1,45 @@
(() => {
'use strict';
- const e = window.wp.plugins,
- t = window.wp.data,
- r = window.wp.element;
- function n(e) {
+ var e = {
+ d: (t, r) => {
+ for (var n in r)
+ e.o(r, n) &&
+ !e.o(t, n) &&
+ Object.defineProperty(t, n, { enumerable: !0, get: r[n] });
+ },
+ o: (e, t) => Object.prototype.hasOwnProperty.call(e, t),
+ r: e => {
+ ('undefined' != typeof Symbol &&
+ Symbol.toStringTag &&
+ Object.defineProperty(e, Symbol.toStringTag, { value: 'Module' }),
+ Object.defineProperty(e, '__esModule', { value: !0 }));
+ },
+ },
+ t = {};
+ (e.r(t),
+ e.d(t, {
+ getBlockValidation: () => re,
+ getInvalidBlocks: () => Y,
+ getInvalidEditorChecks: () => te,
+ getInvalidMeta: () => ee,
+ hasErrors: () => ne,
+ hasWarnings: () => oe,
+ }));
+ var r = {};
+ (e.r(r),
+ e.d(r, {
+ clearBlockValidation: () => ue,
+ setBlockValidation: () => ce,
+ setInvalidBlocks: () => ie,
+ setInvalidEditorChecks: () => le,
+ setInvalidMeta: () => ae,
+ }));
+ const n = window.wp.plugins,
+ o = window.wp.data,
+ i = window.wp.element;
+ function a(e) {
return (
- (n =
+ (a =
'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator
? function (e) {
return typeof e;
@@ -18,10 +52,10 @@
? 'symbol'
: typeof e;
}),
- n(e)
+ a(e)
);
}
- function o(e, t) {
+ function l(e, t) {
var r = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var n = Object.getOwnPropertySymbols(e);
@@ -33,35 +67,35 @@
}
return r;
}
- function a(e) {
+ function c(e) {
for (var t = 1; t < arguments.length; t++) {
var r = null != arguments[t] ? arguments[t] : {};
t % 2
- ? o(Object(r), !0).forEach(function (t) {
- i(e, t, r[t]);
+ ? l(Object(r), !0).forEach(function (t) {
+ u(e, t, r[t]);
})
: Object.getOwnPropertyDescriptors
? Object.defineProperties(e, Object.getOwnPropertyDescriptors(r))
- : o(Object(r)).forEach(function (t) {
+ : l(Object(r)).forEach(function (t) {
Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(r, t));
});
}
return e;
}
- function i(e, t, r) {
+ function u(e, t, r) {
return (
(t = (function (e) {
var t = (function (e) {
- if ('object' != n(e) || !e) return e;
+ if ('object' != a(e) || !e) return e;
var t = e[Symbol.toPrimitive];
if (void 0 !== t) {
var r = t.call(e, 'string');
- if ('object' != n(r)) return r;
+ if ('object' != a(r)) return r;
throw new TypeError('@@toPrimitive must return a primitive value.');
}
return String(e);
})(e);
- return 'symbol' == n(t) ? t : t + '';
+ return 'symbol' == a(t) ? t : t + '';
})(t)) in e
? Object.defineProperty(e, t, {
value: r,
@@ -73,42 +107,42 @@
e
);
}
- var l = function (e, t) {
+ var s = function (e, t) {
return e.filter(function (e) {
return e.type === t;
});
},
- c = function (e) {
- return l(e, 'error');
+ f = function (e) {
+ return s(e, 'error');
},
- u = function (e) {
- return l(e, 'warning');
+ d = function (e) {
+ return s(e, 'warning');
},
- s = function (e) {
+ m = function (e) {
return e.some(function (e) {
return 'error' === e.type;
});
},
- f = function (e) {
+ p = function (e) {
return e.some(function (e) {
return 'warning' === e.type;
});
},
- m = function (e) {
+ v = function (e) {
return null != e && !1 !== e.enabled;
},
- d = function (e, t) {
+ y = function (e, t) {
var r = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {},
n = e.message || '',
o = e.error_msg || n,
i = e.warning_msg || e.error_msg || n,
- l = e.level || 'error';
- return a(
+ a = e.level || 'error';
+ return c(
{
check: t,
checkName: t,
- type: l,
- priority: 'error' === l ? 1 : 'warning' === l ? 2 : 3,
+ type: a,
+ priority: 'error' === a ? 1 : 'warning' === a ? 2 : 3,
message: n,
errorMsg: o,
warningMsg: i,
@@ -118,39 +152,39 @@
r
);
},
- p = function (e) {
+ b = function (e) {
var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
- return a({ isValid: 0 === e.length, issues: e, hasErrors: s(e), hasWarnings: f(e) }, t);
+ return c({ isValid: 0 === e.length, issues: e, hasErrors: m(e), hasWarnings: p(e) }, t);
};
- const v = window.wp.hooks;
- function y(e, t) {
+ const g = window.wp.hooks;
+ function h(e, t) {
(null == t || t > e.length) && (t = e.length);
for (var r = 0, n = Array(t); r < t; r++) n[r] = e[r];
return n;
}
- var b,
- g = function (e) {
+ var w,
+ O = function (e) {
var t,
r = e.name,
n = e.attributes,
o = [],
- a =
+ i =
(null === (t = window.ValidationAPI) ||
void 0 === t ||
null === (t = t.validationRules) ||
void 0 === t
? void 0
: t[r]) || {};
- if (0 === Object.keys(a).length)
+ if (0 === Object.keys(i).length)
return { isValid: !0, issues: [], mode: 'none', clientId: e.clientId, name: r };
- Object.entries(a).forEach(function (t) {
- var a,
- i,
+ Object.entries(i).forEach(function (t) {
+ var i,
+ a,
l =
- ((i = 2),
+ ((a = 2),
(function (e) {
if (Array.isArray(e)) return e;
- })((a = t)) ||
+ })((i = t)) ||
(function (e, t) {
var r =
null == e
@@ -160,19 +194,19 @@
if (null != r) {
var n,
o,
- a,
i,
+ a,
l = [],
c = !0,
u = !1;
try {
- if (((a = (r = r.call(e)).next), 0 === t)) {
+ if (((i = (r = r.call(e)).next), 0 === t)) {
if (Object(r) !== r) return;
c = !1;
} else
for (
;
- !(c = (n = a.call(r)).done) &&
+ !(c = (n = i.call(r)).done) &&
(l.push(n.value), l.length !== t);
c = !0
);
@@ -183,7 +217,7 @@
if (
!c &&
null != r.return &&
- ((i = r.return()), Object(i) !== i)
+ ((a = r.return()), Object(a) !== a)
)
return;
} finally {
@@ -192,10 +226,10 @@
}
return l;
}
- })(a, i) ||
+ })(i, a) ||
(function (e, t) {
if (e) {
- if ('string' == typeof e) return y(e, t);
+ if ('string' == typeof e) return h(e, t);
var r = {}.toString.call(e).slice(8, -1);
return (
'Object' === r && e.constructor && (r = e.constructor.name),
@@ -203,11 +237,11 @@
? Array.from(e)
: 'Arguments' === r ||
/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)
- ? y(e, t)
+ ? h(e, t)
: void 0
);
}
- })(a, i) ||
+ })(i, a) ||
(function () {
throw new TypeError(
'Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.'
@@ -215,42 +249,42 @@
})()),
c = l[0],
u = l[1];
- if (m(u)) {
+ if (v(u)) {
var s = !0;
('function' == typeof u.validator && (s = u.validator(n, e)),
- (s = (0, v.applyFilters)('validation_api_validate_block', s, r, n, c, e)) ||
- o.push(d(u, c)));
+ (s = (0, g.applyFilters)('validation_api_validate_block', s, r, n, c, e)) ||
+ o.push(y(u, c)));
}
});
- var i = 'none';
+ var a = 'none';
return (
- s(o) ? (i = 'error') : f(o) && (i = 'warning'),
- p(o, { mode: i, clientId: e.clientId, name: r })
+ m(o) ? (a = 'error') : p(o) && (a = 'warning'),
+ b(o, { mode: a, clientId: e.clientId, name: r })
);
};
- function w(e, t) {
+ function E(e, t) {
if (e) {
- if ('string' == typeof e) return h(e, t);
+ if ('string' == typeof e) return j(e, t);
var r = {}.toString.call(e).slice(8, -1);
return (
'Object' === r && e.constructor && (r = e.constructor.name),
'Map' === r || 'Set' === r
? Array.from(e)
: 'Arguments' === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)
- ? h(e, t)
+ ? j(e, t)
: void 0
);
}
}
- function h(e, t) {
+ function j(e, t) {
(null == t || t > e.length) && (t = e.length);
for (var r = 0, n = Array(t); r < t; r++) n[r] = e[r];
return n;
}
- function O(e) {
+ function S(e) {
return e.flatMap(function (e) {
var t,
- r = g(e),
+ r = O(e),
n = [];
return (
r.isValid || n.push(r),
@@ -258,8 +292,8 @@
? [].concat(
n,
(function (e) {
- if (Array.isArray(e)) return h(e);
- })((t = O(e.innerBlocks))) ||
+ if (Array.isArray(e)) return j(e);
+ })((t = S(e.innerBlocks))) ||
(function (e) {
if (
('undefined' != typeof Symbol &&
@@ -268,7 +302,7 @@
)
return Array.from(e);
})(t) ||
- w(t) ||
+ E(t) ||
(function () {
throw new TypeError(
'Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.'
@@ -279,12 +313,12 @@
);
});
}
- function E(e) {
+ function k(e) {
var t,
r = (function (e) {
var t = ('undefined' != typeof Symbol && e[Symbol.iterator]) || e['@@iterator'];
if (!t) {
- if (Array.isArray(e) || (t = w(e))) {
+ if (Array.isArray(e) || (t = E(e))) {
t && (e = t);
var _n = 0,
r = function () {};
@@ -305,7 +339,7 @@
}
var n,
o = !0,
- a = !1;
+ i = !1;
return {
s: function () {
t = t.call(e);
@@ -315,13 +349,13 @@
return ((o = e.done), e);
},
e: function (e) {
- ((a = !0), (n = e));
+ ((i = !0), (n = e));
},
f: function () {
try {
o || null == t.return || t.return();
} finally {
- if (a) throw n;
+ if (i) throw n;
}
},
};
@@ -331,7 +365,7 @@
var n = t.value;
if ('core/post-content' === n.name) return n;
if (n.innerBlocks && n.innerBlocks.length > 0) {
- var o = E(n.innerBlocks);
+ var o = k(n.innerBlocks);
if (o) return o;
}
}
@@ -342,39 +376,39 @@
}
return null;
}
- function j() {
+ function P() {
var e,
- r =
+ t =
(null === (e = window.ValidationAPI) || void 0 === e ? void 0 : e.editorContext) ||
'none',
- n = 'post-editor' === r || 'post-editor-template' === r;
- return O(
- (0, t.useSelect)(
+ r = 'post-editor' === t || 'post-editor-template' === t;
+ return S(
+ (0, o.useSelect)(
function (e) {
var t = e('core/block-editor'),
- r = t.getBlocks();
- if (n) {
- var o = E(r);
+ n = t.getBlocks();
+ if (r) {
+ var o = k(n);
if (o) {
- var a = t.getBlock(o.clientId),
- i = t
+ var i = t.getBlock(o.clientId),
+ a = t
.getBlockOrder(o.clientId)
.map(function (e) {
var r = t.getBlock(e);
return (t.getBlockOrder(e), r);
})
.filter(Boolean);
- return i.length > 0 ? i : (null == a ? void 0 : a.innerBlocks) || [];
+ return a.length > 0 ? a : (null == i ? void 0 : i.innerBlocks) || [];
}
- return r;
+ return n;
}
- return r;
+ return n;
},
- [n]
+ [r]
)
);
}
- function S(e, t) {
+ function R(e, t) {
return (
(function (e) {
if (Array.isArray(e)) return e;
@@ -387,26 +421,26 @@
if (null != r) {
var n,
o,
- a,
i,
+ a,
l = [],
c = !0,
u = !1;
try {
- if (((a = (r = r.call(e)).next), 0 === t)) {
+ if (((i = (r = r.call(e)).next), 0 === t)) {
if (Object(r) !== r) return;
c = !1;
} else
for (
;
- !(c = (n = a.call(r)).done) && (l.push(n.value), l.length !== t);
+ !(c = (n = i.call(r)).done) && (l.push(n.value), l.length !== t);
c = !0
);
} catch (e) {
((u = !0), (o = e));
} finally {
try {
- if (!c && null != r.return && ((i = r.return()), Object(i) !== i))
+ if (!c && null != r.return && ((a = r.return()), Object(a) !== a))
return;
} finally {
if (u) throw o;
@@ -417,7 +451,7 @@
})(e, t) ||
(function (e, t) {
if (e) {
- if ('string' == typeof e) return P(e, t);
+ if ('string' == typeof e) return I(e, t);
var r = {}.toString.call(e).slice(8, -1);
return (
'Object' === r && e.constructor && (r = e.constructor.name),
@@ -425,7 +459,7 @@
? Array.from(e)
: 'Arguments' === r ||
/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)
- ? P(e, t)
+ ? I(e, t)
: void 0
);
}
@@ -437,48 +471,48 @@
})()
);
}
- function P(e, t) {
+ function I(e, t) {
(null == t || t > e.length) && (t = e.length);
for (var r = 0, n = Array(t); r < t; r++) n[r] = e[r];
return n;
}
- var R,
- k =
- (null === (b = window.ValidationAPI) || void 0 === b
+ var _,
+ A =
+ (null === (w = window.ValidationAPI) || void 0 === w
? void 0
- : b.metaValidationRules) || {};
- function A(e, t, r, n) {
+ : w.metaValidationRules) || {};
+ function N(e, t, r, n) {
var o,
- a =
- null === (o = k[e]) || void 0 === o || null === (o = o[t]) || void 0 === o
+ i =
+ null === (o = A[e]) || void 0 === o || null === (o = o[t]) || void 0 === o
? void 0
: o[n];
- if (!m(a)) return !0;
- var i = !0;
+ if (!v(i)) return !0;
+ var a = !0;
return (
- 'required' === n && (i = '' !== r && null != r),
- (0, v.applyFilters)('validation_api_validate_meta', i, r, e, t, n)
+ 'required' === n && (a = '' !== r && null != r),
+ (0, g.applyFilters)('validation_api_validate_meta', a, r, e, t, n)
);
}
- function I(e, t, r) {
+ function C(e, t, r) {
for (
- var n = (k[e] || {})[t] || {}, o = [], a = 0, i = Object.entries(n);
- a < i.length;
- a++
+ var n = (A[e] || {})[t] || {}, o = [], i = 0, a = Object.entries(n);
+ i < a.length;
+ i++
) {
- var l = S(i[a], 2),
+ var l = R(a[i], 2),
c = l[0],
u = l[1];
- if (m(u) && !A(e, t, r, c)) {
- var s = d(u, c, { metaKey: t });
+ if (v(u) && !N(e, t, r, c)) {
+ var s = y(u, c, { metaKey: t });
o.push(s);
}
}
- return p(o);
+ return b(o);
}
- function _(e) {
+ function B(e) {
return (
- (_ =
+ (B =
'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator
? function (e) {
return typeof e;
@@ -491,10 +525,10 @@
? 'symbol'
: typeof e;
}),
- _(e)
+ B(e)
);
}
- function N(e, t) {
+ function V(e, t) {
var r = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var n = Object.getOwnPropertySymbols(e);
@@ -506,35 +540,35 @@
}
return r;
}
- function C(e) {
+ function L(e) {
for (var t = 1; t < arguments.length; t++) {
var r = null != arguments[t] ? arguments[t] : {};
t % 2
- ? N(Object(r), !0).forEach(function (t) {
- L(e, t, r[t]);
+ ? V(Object(r), !0).forEach(function (t) {
+ T(e, t, r[t]);
})
: Object.getOwnPropertyDescriptors
? Object.defineProperties(e, Object.getOwnPropertyDescriptors(r))
- : N(Object(r)).forEach(function (t) {
+ : V(Object(r)).forEach(function (t) {
Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(r, t));
});
}
return e;
}
- function L(e, t, r) {
+ function T(e, t, r) {
return (
(t = (function (e) {
var t = (function (e) {
- if ('object' != _(e) || !e) return e;
+ if ('object' != B(e) || !e) return e;
var t = e[Symbol.toPrimitive];
if (void 0 !== t) {
var r = t.call(e, 'string');
- if ('object' != _(r)) return r;
+ if ('object' != B(r)) return r;
throw new TypeError('@@toPrimitive must return a primitive value.');
}
return String(e);
})(e);
- return 'symbol' == _(t) ? t : t + '';
+ return 'symbol' == B(t) ? t : t + '';
})(t)) in e
? Object.defineProperty(e, t, {
value: r,
@@ -546,35 +580,7 @@
e
);
}
- function T() {
- for (
- var e,
- r = (0, t.useSelect)(function (e) {
- var t = e('core/editor');
- return {
- postType: t.getCurrentPostType(),
- meta: t.getEditedPostAttribute('meta'),
- };
- }, []),
- n = r.postType,
- o = r.meta,
- a =
- ((null === (e = window.ValidationAPI) || void 0 === e
- ? void 0
- : e.metaValidationRules) || {})[n] || {},
- i = [],
- l = 0,
- c = Object.keys(a);
- l < c.length;
- l++
- ) {
- var u = c[l],
- s = I(n, u, null == o ? void 0 : o[u]);
- s.isValid || i.push(C(C({}, s), {}, { metaKey: u }));
- }
- return i;
- }
- function B(e, t) {
+ function D(e, t) {
return (
(function (e) {
if (Array.isArray(e)) return e;
@@ -587,26 +593,26 @@
if (null != r) {
var n,
o,
- a,
i,
+ a,
l = [],
c = !0,
u = !1;
try {
- if (((a = (r = r.call(e)).next), 0 === t)) {
+ if (((i = (r = r.call(e)).next), 0 === t)) {
if (Object(r) !== r) return;
c = !1;
} else
for (
;
- !(c = (n = a.call(r)).done) && (l.push(n.value), l.length !== t);
+ !(c = (n = i.call(r)).done) && (l.push(n.value), l.length !== t);
c = !0
);
} catch (e) {
((u = !0), (o = e));
} finally {
try {
- if (!c && null != r.return && ((i = r.return()), Object(i) !== i))
+ if (!c && null != r.return && ((a = r.return()), Object(a) !== a))
return;
} finally {
if (u) throw o;
@@ -617,7 +623,7 @@
})(e, t) ||
(function (e, t) {
if (e) {
- if ('string' == typeof e) return V(e, t);
+ if ('string' == typeof e) return M(e, t);
var r = {}.toString.call(e).slice(8, -1);
return (
'Object' === r && e.constructor && (r = e.constructor.name),
@@ -625,7 +631,7 @@
? Array.from(e)
: 'Arguments' === r ||
/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)
- ? V(e, t)
+ ? M(e, t)
: void 0
);
}
@@ -637,110 +643,377 @@
})()
);
}
- function V(e, t) {
+ function M(e, t) {
(null == t || t > e.length) && (t = e.length);
for (var r = 0, n = Array(t); r < t; r++) n[r] = e[r];
return n;
}
- var D =
- (null === (R = window.ValidationAPI) || void 0 === R ? void 0 : R.editorValidationRules) ||
+ var x =
+ (null === (_ = window.ValidationAPI) || void 0 === _ ? void 0 : _.editorValidationRules) ||
{};
- function M() {
- var e = (0, t.useSelect)(function (e) {
- var t = e('core/editor'),
- r = e('core/block-editor');
- return {
- postType: t.getCurrentPostType(),
- blocks: r.getBlocks(),
- title: t.getEditedPostAttribute('title'),
- };
- }, []),
- r = e.blocks,
- n = e.postType;
- if (!n || !r) return [];
- var o = (function (e, t) {
- for (var r = D[e] || {}, n = [], o = 0, a = Object.entries(r); o < a.length; o++) {
- var i = B(a[o], 2),
- l = i[0],
- c = i[1];
- if (
- m(c) &&
- !(0, v.applyFilters)('validation_api_validate_editor', !0, t, e, l, c)
+ var F = 'validation-api',
+ K = 'SET_INVALID_BLOCKS',
+ W = 'SET_INVALID_META',
+ U = 'SET_INVALID_EDITOR_CHECKS',
+ $ = 'SET_BLOCK_VALIDATION',
+ q = 'CLEAR_BLOCK_VALIDATION',
+ H = { blocks: [], meta: [], editor: [], blockValidation: {} },
+ Z = Object.freeze({ mode: 'none', issues: [] });
+ function z(e) {
+ return (
+ (z =
+ 'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator
+ ? function (e) {
+ return typeof e;
+ }
+ : function (e) {
+ return e &&
+ 'function' == typeof Symbol &&
+ e.constructor === Symbol &&
+ e !== Symbol.prototype
+ ? 'symbol'
+ : typeof e;
+ }),
+ z(e)
+ );
+ }
+ function G(e, t) {
+ var r = Object.keys(e);
+ if (Object.getOwnPropertySymbols) {
+ var n = Object.getOwnPropertySymbols(e);
+ (t &&
+ (n = n.filter(function (t) {
+ return Object.getOwnPropertyDescriptor(e, t).enumerable;
+ })),
+ r.push.apply(r, n));
+ }
+ return r;
+ }
+ function J(e) {
+ for (var t = 1; t < arguments.length; t++) {
+ var r = null != arguments[t] ? arguments[t] : {};
+ t % 2
+ ? G(Object(r), !0).forEach(function (t) {
+ Q(e, t, r[t]);
+ })
+ : Object.getOwnPropertyDescriptors
+ ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(r))
+ : G(Object(r)).forEach(function (t) {
+ Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(r, t));
+ });
+ }
+ return e;
+ }
+ function Q(e, t, r) {
+ return (
+ (t = X(t)) in e
+ ? Object.defineProperty(e, t, {
+ value: r,
+ enumerable: !0,
+ configurable: !0,
+ writable: !0,
+ })
+ : (e[t] = r),
+ e
+ );
+ }
+ function X(e) {
+ var t = (function (e) {
+ if ('object' != z(e) || !e) return e;
+ var t = e[Symbol.toPrimitive];
+ if (void 0 !== t) {
+ var r = t.call(e, 'string');
+ if ('object' != z(r)) return r;
+ throw new TypeError('@@toPrimitive must return a primitive value.');
+ }
+ return String(e);
+ })(e);
+ return 'symbol' == z(t) ? t : t + '';
+ }
+ function Y(e) {
+ return e.blocks;
+ }
+ function ee(e) {
+ return e.meta;
+ }
+ function te(e) {
+ return e.editor;
+ }
+ function re(e, t) {
+ return e.blockValidation[t] || Z;
+ }
+ function ne(e) {
+ var t = e.blocks.some(function (e) {
+ return 'error' === e.mode;
+ }),
+ r = e.meta.some(function (e) {
+ return e.hasErrors;
+ }),
+ n = e.editor.some(function (e) {
+ return 'error' === e.type;
+ });
+ return t || r || n;
+ }
+ function oe(e) {
+ if (ne(e)) return !1;
+ var t = e.blocks.some(function (e) {
+ return 'warning' === e.mode;
+ }),
+ r = e.meta.some(function (e) {
+ return e.hasWarnings && !e.hasErrors;
+ }),
+ n = e.editor.some(function (e) {
+ return 'warning' === e.type;
+ });
+ return t || r || n;
+ }
+ function ie(e) {
+ return { type: K, results: e };
+ }
+ function ae(e) {
+ return { type: W, results: e };
+ }
+ function le(e) {
+ return { type: U, issues: e };
+ }
+ function ce(e, t) {
+ return { type: $, clientId: e, result: t };
+ }
+ function ue(e) {
+ return { type: q, clientId: e };
+ }
+ var se = (0, o.createReduxStore)(F, {
+ reducer: function () {
+ var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : H,
+ t = arguments.length > 1 ? arguments[1] : void 0;
+ switch (t.type) {
+ case K:
+ return J(J({}, e), {}, { blocks: t.results });
+ case W:
+ return J(J({}, e), {}, { meta: t.results });
+ case U:
+ return J(J({}, e), {}, { editor: t.issues });
+ case $:
+ return J(
+ J({}, e),
+ {},
+ {
+ blockValidation: J(
+ J({}, e.blockValidation),
+ {},
+ Q({}, t.clientId, t.result)
+ ),
+ }
+ );
+ case q:
+ var r = e.blockValidation,
+ n = t.clientId,
+ o =
+ (r[n],
+ (function (e, t) {
+ if (null == e) return {};
+ var r,
+ n,
+ o = (function (e, t) {
+ if (null == e) return {};
+ var r = {};
+ for (var n in e)
+ if ({}.hasOwnProperty.call(e, n)) {
+ if (-1 !== t.indexOf(n)) continue;
+ r[n] = e[n];
+ }
+ return r;
+ })(e, t);
+ if (Object.getOwnPropertySymbols) {
+ var i = Object.getOwnPropertySymbols(e);
+ for (n = 0; n < i.length; n++)
+ ((r = i[n]),
+ -1 === t.indexOf(r) &&
+ {}.propertyIsEnumerable.call(e, r) &&
+ (o[r] = e[r]));
+ }
+ return o;
+ })(r, [n].map(X)));
+ return J(J({}, e), {}, { blockValidation: o });
+ default:
+ return e;
+ }
+ },
+ selectors: t,
+ actions: r,
+ });
+ function fe() {
+ var e,
+ t,
+ r,
+ n = P(),
+ a = (function () {
+ for (
+ var e,
+ t = (0, o.useSelect)(function (e) {
+ var t = e('core/editor');
+ return {
+ postType: t.getCurrentPostType(),
+ meta: t.getEditedPostAttribute('meta'),
+ };
+ }, []),
+ r = t.postType,
+ n = t.meta,
+ i =
+ ((null === (e = window.ValidationAPI) || void 0 === e
+ ? void 0
+ : e.metaValidationRules) || {})[r] || {},
+ a = [],
+ l = 0,
+ c = Object.keys(i);
+ l < c.length;
+ l++
) {
- var u = d(c, l);
- n.push(u);
+ var u = c[l],
+ s = C(r, u, null == n ? void 0 : n[u]);
+ s.isValid || a.push(L(L({}, s), {}, { metaKey: u }));
}
- }
- return (
- n.sort(function (e, t) {
- return e.priority - t.priority;
- }),
- p(n)
- );
- })(n, r);
- return o.issues;
+ return a;
+ })(),
+ l =
+ ((e = (0, o.useSelect)(function (e) {
+ var t = e('core/editor'),
+ r = e('core/block-editor');
+ return {
+ postType: t.getCurrentPostType(),
+ blocks: r.getBlocks(),
+ title: t.getEditedPostAttribute('title'),
+ };
+ }, [])),
+ (t = e.blocks),
+ (r = e.postType) && t
+ ? (function (e, t) {
+ for (
+ var r = x[e] || {}, n = [], o = 0, i = Object.entries(r);
+ o < i.length;
+ o++
+ ) {
+ var a = D(i[o], 2),
+ l = a[0],
+ c = a[1];
+ if (
+ v(c) &&
+ !(0, g.applyFilters)(
+ 'validation_api_validate_editor',
+ !0,
+ t,
+ e,
+ l,
+ c
+ )
+ ) {
+ var u = y(c, l);
+ n.push(u);
+ }
+ }
+ return (
+ n.sort(function (e, t) {
+ return e.priority - t.priority;
+ }),
+ b(n)
+ );
+ })(r, t).issues
+ : []),
+ c = (0, o.useDispatch)(F),
+ u = c.setInvalidBlocks,
+ s = c.setInvalidMeta,
+ f = c.setInvalidEditorChecks;
+ return (
+ (0, i.useEffect)(
+ function () {
+ u(n);
+ },
+ [n, u]
+ ),
+ (0, i.useEffect)(
+ function () {
+ s(a);
+ },
+ [a, s]
+ ),
+ (0, i.useEffect)(
+ function () {
+ f(l);
+ },
+ [l, f]
+ ),
+ null
+ );
}
- function x() {
+ function de() {
var e,
- n =
+ t =
(null === (e = window.ValidationAPI) || void 0 === e ? void 0 : e.editorContext) ||
'none',
- o = 'post-editor' === n || 'post-editor-template' === n,
- a = 'core/editor',
- i = (0, t.useDispatch)(a),
- l = wp.data && wp.data.select && wp.data.select(a),
- c = j(),
- u = T(),
- m = M(),
- d = i || {},
- p = d.lockPostSaving,
- v = d.unlockPostSaving,
- y = d.lockPostAutosaving,
- b = d.unlockPostAutosaving,
- g = d.disablePublishSidebar,
+ r = 'post-editor' === t || 'post-editor-template' === t,
+ n = 'core/editor',
+ a = (0, o.useDispatch)(n),
+ l = wp.data && wp.data.select && wp.data.select(n),
+ c = (0, o.useSelect)(function (e) {
+ var t = e(F);
+ return {
+ invalidBlocks: t.getInvalidBlocks(),
+ invalidMeta: t.getInvalidMeta(),
+ invalidEditorChecks: t.getInvalidEditorChecks(),
+ };
+ }, []),
+ u = c.invalidBlocks,
+ s = c.invalidMeta,
+ f = c.invalidEditorChecks,
+ d = a || {},
+ v = d.lockPostSaving,
+ y = d.unlockPostSaving,
+ b = d.lockPostAutosaving,
+ g = d.unlockPostAutosaving,
+ h = d.disablePublishSidebar,
w = d.enablePublishSidebar;
return (
- (0, r.useEffect)(
+ (0, i.useEffect)(
function () {
- if (o && 'none' !== n && l && p && v) {
- var e = c.some(function (e) {
+ if (r && 'none' !== t && l && v && y) {
+ var e = u.some(function (e) {
return 'error' === e.mode;
}),
- t = u.some(function (e) {
+ n = s.some(function (e) {
return e.hasErrors;
}),
- r = s(m);
- e || t || r
- ? (p('validation-api'), y && y('validation-api'), g && g())
- : (v('validation-api'), b && b('validation-api'), w && w());
+ o = m(f);
+ e || n || o
+ ? (v('validation-api'), b && b('validation-api'), h && h())
+ : (y('validation-api'), g && g('validation-api'), w && w());
}
},
- [c, u, m, p, v, y, b, g, w, o, n, l]
+ [u, s, f, v, y, b, g, h, w, r, t, l]
),
- (0, r.useEffect)(
+ (0, i.useEffect)(
function () {
- if (o && 'none' !== n && document.body) {
- var e = c.some(function (e) {
+ if (r && 'none' !== t && document.body) {
+ var e = u.some(function (e) {
return 'error' === e.mode;
}),
- t = c.some(function (e) {
+ n = u.some(function (e) {
return 'warning' === e.mode;
}),
- r = u.some(function (e) {
+ o = s.some(function (e) {
return e.hasErrors;
}),
- a = u.some(function (e) {
+ i = s.some(function (e) {
return e.hasWarnings && !e.hasErrors;
}),
- i = s(m),
- l = f(m),
- d = e || r || i,
- p = !d && (t || a || l);
+ a = m(f),
+ l = p(f),
+ c = e || o || a,
+ d = !c && (n || i || l);
return (
- d
+ c
? (document.body.classList.add('has-validation-errors'),
document.body.classList.remove('has-validation-warnings'))
- : p
+ : d
? (document.body.classList.add('has-validation-warnings'),
document.body.classList.remove('has-validation-errors'))
: document.body.classList.remove(
@@ -757,16 +1030,17 @@
);
}
},
- [c, u, m, o, n]
+ [u, s, f, r, t]
),
null
);
}
- const F = window.wp.editor,
- U = window.wp.components,
- W = window.wp.i18n,
- $ = window.wp.blocks;
- function q(e) {
+ (0, o.register)(se);
+ const me = window.wp.editor,
+ pe = window.wp.components,
+ ve = window.wp.i18n,
+ ye = window.wp.blocks;
+ function be(e) {
var t = e.fill,
r = void 0 === t ? 'currentColor' : t;
return React.createElement(
@@ -786,22 +1060,22 @@
})
);
}
- function K(e, t) {
+ function ge(e, t) {
var r = new Map();
return (
e.forEach(function (e) {
- ('error' === t ? c(e.issues || []) : u(e.issues || [])).forEach(function (n) {
+ ('error' === t ? f(e.issues || []) : d(e.issues || [])).forEach(function (n) {
var o,
- a,
- i = 'error' === t ? n.error_msg : n.warning_msg || n.error_msg,
- l = ''.concat(e.name, '|').concat(i);
+ i,
+ a = 'error' === t ? n.error_msg : n.warning_msg || n.error_msg,
+ l = ''.concat(e.name, '|').concat(a);
(r.has(l) ||
r.set(l, {
blockName:
((o = e.name),
- (a = (0, $.getBlockType)(o)),
- a && a.title
- ? a.title
+ (i = (0, ye.getBlockType)(o)),
+ i && i.title
+ ? i.title
: (o.split('/')[1] || o)
.split(/[-_]/)
.map(function (e) {
@@ -809,7 +1083,7 @@
})
.join(' ')),
blockType: e.name,
- message: i,
+ message: a,
clientIds: [],
}),
e.clientId &&
@@ -820,20 +1094,20 @@
Array.from(r.values())
);
}
- function H(e, t) {
+ function he(e, t) {
var r = new Map();
return (
e.forEach(function (e) {
- ('error' === t ? c(e.issues || []) : u(e.issues || [])).forEach(function (n) {
+ ('error' === t ? f(e.issues || []) : d(e.issues || [])).forEach(function (n) {
var o = 'error' === t ? n.error_msg : n.warning_msg || n.error_msg,
- a = ''.concat(e.metaKey, '|').concat(o);
- r.has(a) || r.set(a, { metaKey: e.metaKey, message: o });
+ i = ''.concat(e.metaKey, '|').concat(o);
+ r.has(i) || r.set(i, { metaKey: e.metaKey, message: o });
});
}),
Array.from(r.values())
);
}
- function Z(e, t) {
+ function we(e, t) {
var r = new Map();
return (
e.forEach(function (e) {
@@ -847,30 +1121,38 @@
Array.from(r.values())
);
}
- function z() {
- var e = j() || [],
- n = T() || [],
- o = M() || [],
- a = (0, t.useDispatch)('core/block-editor').selectBlock,
- i = (0, r.useRef)(null),
- c = l(o, 'error'),
- u = l(o, 'warning'),
- s = K(e, 'error'),
- f = K(e, 'warning'),
- m = H(n, 'error'),
- d = H(n, 'warning'),
- p = Z(c, 'error'),
- v = Z(u, 'warning'),
- y = s.length + m.length + p.length,
- b = f.length + d.length + v.length,
- g = 'currentColor';
- y > 0 ? (g = '#d82000') : b > 0 && (g = '#dbc900');
- var w = React.createElement(q, { fill: g }),
- h = function (e) {
+ function Oe() {
+ var e = (0, o.useSelect)(function (e) {
+ var t = e(F);
+ return {
+ invalidBlocks: t.getInvalidBlocks(),
+ invalidMeta: t.getInvalidMeta(),
+ invalidEditorChecks: t.getInvalidEditorChecks(),
+ };
+ }, []),
+ t = e.invalidBlocks,
+ r = e.invalidMeta,
+ n = e.invalidEditorChecks,
+ a = (0, o.useDispatch)('core/block-editor').selectBlock,
+ l = (0, i.useRef)(null),
+ c = s(n, 'error'),
+ u = s(n, 'warning'),
+ f = ge(t, 'error'),
+ d = ge(t, 'warning'),
+ m = he(r, 'error'),
+ p = he(r, 'warning'),
+ v = we(c, 'error'),
+ y = we(u, 'warning'),
+ b = f.length + m.length + v.length,
+ g = d.length + p.length + y.length,
+ h = 'currentColor';
+ b > 0 ? (h = '#d82000') : g > 0 && (h = '#dbc900');
+ var w = React.createElement(be, { fill: h }),
+ O = function (e) {
e &&
(a(e),
- i.current && clearTimeout(i.current),
- (i.current = setTimeout(function () {
+ l.current && clearTimeout(l.current),
+ (l.current = setTimeout(function () {
var t = document.querySelector('[data-block="'.concat(e, '"]'));
(t ||
(t = document.querySelector(
@@ -884,36 +1166,36 @@
}, 100)));
};
return (
- (0, r.useEffect)(function () {
+ (0, i.useEffect)(function () {
return function () {
- i.current && clearTimeout(i.current);
+ l.current && clearTimeout(l.current);
};
}, []),
- 0 === y && 0 === b
+ 0 === b && 0 === g
? null
: React.createElement(
- F.PluginSidebar,
+ me.PluginSidebar,
{
name: 'validation-sidebar',
- title: (0, W.__)('Validation', 'validation-api'),
+ title: (0, ve.__)('Validation', 'validation-api'),
icon: w,
className: 'validation-api-validation-sidebar',
},
- y > 0 &&
+ b > 0 &&
React.createElement(
- U.PanelBody,
+ pe.PanelBody,
{
- title: (0, W.sprintf)(
+ title: (0, ve.sprintf)(
/* translators: %d: number of errors */ /* translators: %d: number of errors */
- (0, W.__)('Errors (%d)', 'validation-api'),
- y
+ (0, ve.__)('Errors (%d)', 'validation-api'),
+ b
),
initialOpen: !0,
className: 'validation-api-errors-panel',
},
- s.length > 0 &&
+ f.length > 0 &&
React.createElement(
- U.PanelRow,
+ pe.PanelRow,
null,
React.createElement(
'div',
@@ -921,12 +1203,12 @@
React.createElement(
'p',
{ className: 'validation-api-error-subheading' },
- (0, W.__)('Block Issues', 'validation-api')
+ (0, ve.__)('Block Issues', 'validation-api')
),
React.createElement(
'ul',
{ className: 'validation-api-error-list' },
- s.map(function (e, t) {
+ f.map(function (e, t) {
var r = e.clientIds.length,
n = r > 1 ? ' (x'.concat(r, ')') : '';
return React.createElement(
@@ -939,7 +1221,7 @@
className:
'validation-api-issue-link',
onClick: function () {
- return h(e.clientIds[0]);
+ return O(e.clientIds[0]);
},
},
e.blockName
@@ -954,7 +1236,7 @@
),
m.length > 0 &&
React.createElement(
- U.PanelRow,
+ pe.PanelRow,
null,
React.createElement(
'div',
@@ -962,7 +1244,7 @@
React.createElement(
'p',
{ className: 'validation-api-error-subheading' },
- (0, W.__)('Field Issues', 'validation-api')
+ (0, ve.__)('Field Issues', 'validation-api')
),
React.createElement(
'ul',
@@ -977,9 +1259,9 @@
)
)
),
- p.length > 0 &&
+ v.length > 0 &&
React.createElement(
- U.PanelRow,
+ pe.PanelRow,
null,
React.createElement(
'div',
@@ -987,12 +1269,12 @@
React.createElement(
'p',
{ className: 'validation-api-error-subheading' },
- (0, W.__)('Editor Issues', 'validation-api')
+ (0, ve.__)('Editor Issues', 'validation-api')
),
React.createElement(
'ul',
{ className: 'validation-api-error-list' },
- p.map(function (e, t) {
+ v.map(function (e, t) {
return React.createElement(
'li',
{ key: 'editor-error-'.concat(t) },
@@ -1003,21 +1285,21 @@
)
)
),
- b > 0 &&
+ g > 0 &&
React.createElement(
- U.PanelBody,
+ pe.PanelBody,
{
- title: (0, W.sprintf)(
+ title: (0, ve.sprintf)(
/* translators: %d: number of warnings */ /* translators: %d: number of warnings */
- (0, W.__)('Warnings (%d)', 'validation-api'),
- b
+ (0, ve.__)('Warnings (%d)', 'validation-api'),
+ g
),
initialOpen: !0,
className: 'validation-api-warnings-panel',
},
- f.length > 0 &&
+ d.length > 0 &&
React.createElement(
- U.PanelRow,
+ pe.PanelRow,
null,
React.createElement(
'div',
@@ -1025,12 +1307,12 @@
React.createElement(
'p',
{ className: 'validation-api-warning-subheading' },
- (0, W.__)('Block Issues', 'validation-api')
+ (0, ve.__)('Block Issues', 'validation-api')
),
React.createElement(
'ul',
{ className: 'validation-api-warning-list' },
- f.map(function (e, t) {
+ d.map(function (e, t) {
var r = e.clientIds.length,
n = r > 1 ? ' (x'.concat(r, ')') : '';
return React.createElement(
@@ -1043,7 +1325,7 @@
className:
'validation-api-issue-link',
onClick: function () {
- return h(e.clientIds[0]);
+ return O(e.clientIds[0]);
},
},
e.blockName
@@ -1056,9 +1338,9 @@
)
)
),
- d.length > 0 &&
+ p.length > 0 &&
React.createElement(
- U.PanelRow,
+ pe.PanelRow,
null,
React.createElement(
'div',
@@ -1066,12 +1348,12 @@
React.createElement(
'p',
{ className: 'validation-api-warning-subheading' },
- (0, W.__)('Field Issues', 'validation-api')
+ (0, ve.__)('Field Issues', 'validation-api')
),
React.createElement(
'ul',
{ className: 'validation-api-warning-list' },
- d.map(function (e, t) {
+ p.map(function (e, t) {
return React.createElement(
'li',
{ key: 'meta-warning-'.concat(t) },
@@ -1081,9 +1363,9 @@
)
)
),
- v.length > 0 &&
+ y.length > 0 &&
React.createElement(
- U.PanelRow,
+ pe.PanelRow,
null,
React.createElement(
'div',
@@ -1091,12 +1373,12 @@
React.createElement(
'p',
{ className: 'validation-api-warning-subheading' },
- (0, W.__)('Editor Issues', 'validation-api')
+ (0, ve.__)('Editor Issues', 'validation-api')
),
React.createElement(
'ul',
{ className: 'validation-api-warning-list' },
- v.map(function (e, t) {
+ y.map(function (e, t) {
return React.createElement(
'li',
{ key: 'editor-warning-'.concat(t) },
@@ -1110,30 +1392,31 @@
)
);
}
- (0, e.registerPlugin)('validation-api', {
+ (0, n.registerPlugin)('validation-api', {
render: function () {
return React.createElement(
React.Fragment,
null,
- React.createElement(x, null),
- React.createElement(z, null)
+ React.createElement(fe, null),
+ React.createElement(de, null),
+ React.createElement(Oe, null)
);
},
});
- const G = window.wp.compose,
- J = window.wp.blockEditor;
- function Q(e, t) {
+ const Ee = window.wp.compose,
+ je = window.wp.blockEditor;
+ function Se(e, t) {
(null == t || t > e.length) && (t = e.length);
for (var r = 0, n = Array(t); r < t; r++) n[r] = e[r];
return n;
}
- function X(e) {
+ function ke(e) {
var t,
- n,
- o = e.issues,
- a =
- ((t = (0, r.useState)(!1)),
- (n = 2),
+ r,
+ n = e.issues,
+ o =
+ ((t = (0, i.useState)(!1)),
+ (r = 2),
(function (e) {
if (Array.isArray(e)) return e;
})(t) ||
@@ -1146,19 +1429,19 @@
if (null != r) {
var n,
o,
- a,
i,
+ a,
l = [],
c = !0,
u = !1;
try {
- if (((a = (r = r.call(e)).next), 0 === t)) {
+ if (((i = (r = r.call(e)).next), 0 === t)) {
if (Object(r) !== r) return;
c = !1;
} else
for (
;
- !(c = (n = a.call(r)).done) &&
+ !(c = (n = i.call(r)).done) &&
(l.push(n.value), l.length !== t);
c = !0
);
@@ -1169,7 +1452,7 @@
if (
!c &&
null != r.return &&
- ((i = r.return()), Object(i) !== i)
+ ((a = r.return()), Object(a) !== a)
)
return;
} finally {
@@ -1178,10 +1461,10 @@
}
return l;
}
- })(t, n) ||
+ })(t, r) ||
(function (e, t) {
if (e) {
- if ('string' == typeof e) return Q(e, t);
+ if ('string' == typeof e) return Se(e, t);
var r = {}.toString.call(e).slice(8, -1);
return (
'Object' === r && e.constructor && (r = e.constructor.name),
@@ -1189,42 +1472,42 @@
? Array.from(e)
: 'Arguments' === r ||
/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)
- ? Q(e, t)
+ ? Se(e, t)
: void 0
);
}
- })(t, n) ||
+ })(t, r) ||
(function () {
throw new TypeError(
'Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.'
);
})()),
- i = a[0],
- l = a[1];
- if (!o || 0 === o.length) return null;
- var f = s(o),
- m = c(o),
- d = u(o),
- p = f
- ? React.createElement(q, { fill: '#d82000' })
- : React.createElement(q, { fill: '#dbc900' });
+ a = o[0],
+ l = o[1];
+ if (!n || 0 === n.length) return null;
+ var c = m(n),
+ u = f(n),
+ s = d(n),
+ p = c
+ ? React.createElement(be, { fill: '#d82000' })
+ : React.createElement(be, { fill: '#dbc900' });
return React.createElement(
React.Fragment,
null,
- React.createElement(U.ToolbarButton, {
+ React.createElement(pe.ToolbarButton, {
icon: p,
onClick: function () {
return l(!0);
},
- label: (0, W.__)('View block issues or concerns', 'validation-api'),
+ label: (0, ve.__)('View block issues or concerns', 'validation-api'),
className: 'validation-api-toolbar-button',
isCompact: !0,
}),
- i &&
+ a &&
React.createElement(
- U.Modal,
+ pe.Modal,
{
- title: (0, W.__)('Issues or Concerns', 'validation-api'),
+ title: (0, ve.__)('Issues or Concerns', 'validation-api'),
onRequestClose: function () {
return l(!1);
},
@@ -1233,7 +1516,7 @@
React.createElement(
'div',
{ className: 'validation-api-indicator-modal-content' },
- m.length > 0 &&
+ u.length > 0 &&
React.createElement(
'div',
{
@@ -1246,12 +1529,12 @@
React.createElement('span', {
className: 'validation-api-indicator-section-title-circle',
}),
- (0, W.__)('Errors', 'validation-api')
+ (0, ve.__)('Errors', 'validation-api')
),
React.createElement(
'ul',
null,
- m.map(function (e, t) {
+ u.map(function (e, t) {
return React.createElement(
'li',
{ key: 'error-'.concat(t) },
@@ -1260,7 +1543,7 @@
})
)
),
- d.length > 0 &&
+ s.length > 0 &&
React.createElement(
'div',
{
@@ -1273,12 +1556,12 @@
React.createElement('span', {
className: 'validation-api-indicator-section-title-circle',
}),
- (0, W.__)('Warnings', 'validation-api')
+ (0, ve.__)('Warnings', 'validation-api')
),
React.createElement(
'ul',
null,
- d.map(function (e, t) {
+ s.map(function (e, t) {
return React.createElement(
'li',
{ key: 'warning-'.concat(t) },
@@ -1291,16 +1574,14 @@
)
);
}
- function Y(e, t) {
+ function Pe(e, t) {
(null == t || t > e.length) && (t = e.length);
for (var r = 0, n = Array(t); r < t; r++) n[r] = e[r];
return n;
}
- var ee = new Map(),
- te = Object.freeze({ mode: 'none', issues: [] });
- function re(e) {
+ function Re(e) {
return (
- (re =
+ (Re =
'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator
? function (e) {
return typeof e;
@@ -1313,10 +1594,10 @@
? 'symbol'
: typeof e;
}),
- re(e)
+ Re(e)
);
}
- function ne(e, t) {
+ function Ie(e, t) {
var r = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var n = Object.getOwnPropertySymbols(e);
@@ -1328,35 +1609,35 @@
}
return r;
}
- function oe(e) {
+ function _e(e) {
for (var t = 1; t < arguments.length; t++) {
var r = null != arguments[t] ? arguments[t] : {};
t % 2
- ? ne(Object(r), !0).forEach(function (t) {
- ae(e, t, r[t]);
+ ? Ie(Object(r), !0).forEach(function (t) {
+ Ae(e, t, r[t]);
})
: Object.getOwnPropertyDescriptors
? Object.defineProperties(e, Object.getOwnPropertyDescriptors(r))
- : ne(Object(r)).forEach(function (t) {
+ : Ie(Object(r)).forEach(function (t) {
Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(r, t));
});
}
return e;
}
- function ae(e, t, r) {
+ function Ae(e, t, r) {
return (
(t = (function (e) {
var t = (function (e) {
- if ('object' != re(e) || !e) return e;
+ if ('object' != Re(e) || !e) return e;
var t = e[Symbol.toPrimitive];
if (void 0 !== t) {
var r = t.call(e, 'string');
- if ('object' != re(r)) return r;
+ if ('object' != Re(r)) return r;
throw new TypeError('@@toPrimitive must return a primitive value.');
}
return String(e);
})(e);
- return 'symbol' == re(t) ? t : t + '';
+ return 'symbol' == Re(t) ? t : t + '';
})(t)) in e
? Object.defineProperty(e, t, {
value: r,
@@ -1368,30 +1649,33 @@
e
);
}
- var ie = (0, G.createHigherOrderComponent)(function (e) {
- return function (n) {
- var o = n.clientId,
- a = n.attributes,
- i = (0, t.useSelect)(
+ var Ne = (0, Ee.createHigherOrderComponent)(function (e) {
+ return function (t) {
+ var r = t.clientId,
+ n = t.attributes,
+ a = (0, o.useSelect)(
function (e) {
- return e('core/block-editor').getBlock(o);
+ return e('core/block-editor').getBlock(r);
},
- [o]
+ [r]
),
- l = (function (e, t) {
- var n,
- o,
- a = (arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {})
+ l = (0, o.useDispatch)(F),
+ c = l.setBlockValidation,
+ u = l.clearBlockValidation,
+ s = (function (e, t) {
+ var r,
+ n,
+ o = (arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {})
.delay,
- i = void 0 === a ? 300 : a,
+ a = void 0 === o ? 300 : o,
l =
- ((n = (0, r.useState)(function () {
+ ((r = (0, i.useState)(function () {
return e();
})),
- (o = 2),
+ (n = 2),
(function (e) {
if (Array.isArray(e)) return e;
- })(n) ||
+ })(r) ||
(function (e, t) {
var r =
null == e
@@ -1402,19 +1686,19 @@
if (null != r) {
var n,
o,
- a,
i,
+ a,
l = [],
c = !0,
u = !1;
try {
- if (((a = (r = r.call(e)).next), 0 === t)) {
+ if (((i = (r = r.call(e)).next), 0 === t)) {
if (Object(r) !== r) return;
c = !1;
} else
for (
;
- !(c = (n = a.call(r)).done) &&
+ !(c = (n = i.call(r)).done) &&
(l.push(n.value), l.length !== t);
c = !0
);
@@ -1425,7 +1709,7 @@
if (
!c &&
null != r.return &&
- ((i = r.return()), Object(i) !== i)
+ ((a = r.return()), Object(a) !== a)
)
return;
} finally {
@@ -1434,10 +1718,10 @@
}
return l;
}
- })(n, o) ||
+ })(r, n) ||
(function (e, t) {
if (e) {
- if ('string' == typeof e) return Y(e, t);
+ if ('string' == typeof e) return Pe(e, t);
var r = {}.toString.call(e).slice(8, -1);
return (
'Object' === r &&
@@ -1449,11 +1733,11 @@
/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(
r
)
- ? Y(e, t)
+ ? Pe(e, t)
: void 0
);
}
- })(n, o) ||
+ })(r, n) ||
(function () {
throw new TypeError(
'Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.'
@@ -1461,16 +1745,16 @@
})()),
c = l[0],
u = l[1],
- s = (0, r.useRef)(null),
- f = (0, r.useRef)(!0);
+ s = (0, i.useRef)(null),
+ f = (0, i.useRef)(!0);
return (
- (0, r.useEffect)(function () {
+ (0, i.useEffect)(function () {
return f.current
? ((f.current = !1), void u(e()))
: (s.current && clearTimeout(s.current),
(s.current = setTimeout(function () {
u(e());
- }, i)),
+ }, a)),
function () {
s.current && clearTimeout(s.current);
});
@@ -1479,46 +1763,42 @@
);
})(
function () {
- if (!i) return { isValid: !0, issues: [], mode: 'none' };
- var e = oe(oe({}, i), {}, { attributes: a || i.attributes });
- return g(e);
+ if (!a) return { isValid: !0, issues: [], mode: 'none' };
+ var e = _e(_e({}, a), {}, { attributes: n || a.attributes });
+ return O(e);
},
- [i, a],
+ [a, n],
{ delay: 300 }
);
return (
- (0, r.useEffect)(
+ (0, i.useEffect)(
function () {
return (
- (function (e, t) {
- ee.set(e, t);
- })(o, l),
+ c(r, s),
function () {
- return (function (e) {
- ee.delete(e);
- })(o);
+ return u(r);
}
);
},
- [o, l]
+ [r, s, c, u]
),
React.createElement(
React.Fragment,
null,
- React.createElement(e, n),
- !l.isValid &&
+ React.createElement(e, t),
+ !s.isValid &&
React.createElement(
- J.BlockControls,
+ je.BlockControls,
{ group: 'block' },
- React.createElement(X, { issues: l.issues })
+ React.createElement(ke, { issues: s.issues })
)
)
);
};
}, 'withErrorHandling');
- function le(e) {
+ function Ce(e) {
return (
- (le =
+ (Ce =
'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator
? function (e) {
return typeof e;
@@ -1531,12 +1811,12 @@
? 'symbol'
: typeof e;
}),
- le(e)
+ Ce(e)
);
}
- function ce() {
+ function Be() {
return (
- (ce = Object.assign
+ (Be = Object.assign
? Object.assign.bind()
: function (e) {
for (var t = 1; t < arguments.length; t++) {
@@ -1545,10 +1825,10 @@
}
return e;
}),
- ce.apply(null, arguments)
+ Be.apply(null, arguments)
);
}
- function ue(e, t) {
+ function Ve(e, t) {
var r = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var n = Object.getOwnPropertySymbols(e);
@@ -1560,35 +1840,35 @@
}
return r;
}
- function se(e) {
+ function Le(e) {
for (var t = 1; t < arguments.length; t++) {
var r = null != arguments[t] ? arguments[t] : {};
t % 2
- ? ue(Object(r), !0).forEach(function (t) {
- fe(e, t, r[t]);
+ ? Ve(Object(r), !0).forEach(function (t) {
+ Te(e, t, r[t]);
})
: Object.getOwnPropertyDescriptors
? Object.defineProperties(e, Object.getOwnPropertyDescriptors(r))
- : ue(Object(r)).forEach(function (t) {
+ : Ve(Object(r)).forEach(function (t) {
Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(r, t));
});
}
return e;
}
- function fe(e, t, r) {
+ function Te(e, t, r) {
return (
(t = (function (e) {
var t = (function (e) {
- if ('object' != le(e) || !e) return e;
+ if ('object' != Ce(e) || !e) return e;
var t = e[Symbol.toPrimitive];
if (void 0 !== t) {
var r = t.call(e, 'string');
- if ('object' != le(r)) return r;
+ if ('object' != Ce(r)) return r;
throw new TypeError('@@toPrimitive must return a primitive value.');
}
return String(e);
})(e);
- return 'symbol' == le(t) ? t : t + '';
+ return 'symbol' == Ce(t) ? t : t + '';
})(t)) in e
? Object.defineProperty(e, t, {
value: r,
@@ -1600,9 +1880,9 @@
e
);
}
- function me(e) {
+ function De(e) {
return (
- (me =
+ (De =
'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator
? function (e) {
return typeof e;
@@ -1615,10 +1895,10 @@
? 'symbol'
: typeof e;
}),
- me(e)
+ De(e)
);
}
- function de(e, t) {
+ function Me(e, t) {
var r = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var n = Object.getOwnPropertySymbols(e);
@@ -1630,35 +1910,35 @@
}
return r;
}
- function pe(e) {
+ function xe(e) {
for (var t = 1; t < arguments.length; t++) {
var r = null != arguments[t] ? arguments[t] : {};
t % 2
- ? de(Object(r), !0).forEach(function (t) {
- ve(e, t, r[t]);
+ ? Me(Object(r), !0).forEach(function (t) {
+ Fe(e, t, r[t]);
})
: Object.getOwnPropertyDescriptors
? Object.defineProperties(e, Object.getOwnPropertyDescriptors(r))
- : de(Object(r)).forEach(function (t) {
+ : Me(Object(r)).forEach(function (t) {
Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(r, t));
});
}
return e;
}
- function ve(e, t, r) {
+ function Fe(e, t, r) {
return (
(t = (function (e) {
var t = (function (e) {
- if ('object' != me(e) || !e) return e;
+ if ('object' != De(e) || !e) return e;
var t = e[Symbol.toPrimitive];
if (void 0 !== t) {
var r = t.call(e, 'string');
- if ('object' != me(r)) return r;
+ if ('object' != De(r)) return r;
throw new TypeError('@@toPrimitive must return a primitive value.');
}
return String(e);
})(e);
- return 'symbol' == me(t) ? t : t + '';
+ return 'symbol' == De(t) ? t : t + '';
})(t)) in e
? Object.defineProperty(e, t, {
value: r,
@@ -1670,9 +1950,9 @@
e
);
}
- function ye(e) {
+ function Ke(e) {
return (
- (ye =
+ (Ke =
'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator
? function (e) {
return typeof e;
@@ -1685,43 +1965,47 @@
? 'symbol'
: typeof e;
}),
- ye(e)
+ Ke(e)
);
}
- (wp.hooks.addFilter('editor.BlockEdit', 'validation-api/with-error-handling', ie),
- (0, v.addFilter)(
+ (wp.hooks.addFilter('editor.BlockEdit', 'validation-api/with-error-handling', Ne),
+ (0, g.addFilter)(
'editor.BlockListBlock',
'validation-api/with-block-validation-classes',
function (e) {
return function (t) {
- var r,
- n = ((r = t.clientId), ee.get(r) || te);
- if ('none' === n.mode) return React.createElement(e, t);
- var o =
- 'error' === n.mode
+ var r = (0, o.useSelect)(
+ function (e) {
+ return e(F).getBlockValidation(t.clientId);
+ },
+ [t.clientId]
+ );
+ if ('none' === r.mode) return React.createElement(e, t);
+ var n =
+ 'error' === r.mode
? 'validation-api-block-error'
: 'validation-api-block-warning',
- a = t.wrapperProps || {},
- i = se(
- se({}, a),
+ i = t.wrapperProps || {},
+ a = Le(
+ Le({}, i),
{},
- { className: [a.className, o].filter(Boolean).join(' ') }
+ { className: [i.className, n].filter(Boolean).join(' ') }
);
- return React.createElement(e, ce({}, t, { wrapperProps: i }));
+ return React.createElement(e, Be({}, t, { wrapperProps: a }));
};
}
),
void 0 === window.ValidationAPI && (window.ValidationAPI = {}),
(window.ValidationAPI.useMetaField = function (e) {
- var r = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : '',
- n = (function (e) {
- return (0, t.useSelect)(
+ var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : '',
+ r = (function (e) {
+ return (0, o.useSelect)(
function (t) {
var r = t('core/editor'),
n = r.getEditedPostAttribute,
o = (0, r.getCurrentPostType)(),
- a = n('meta'),
- i = a ? a[e] : '';
+ i = n('meta'),
+ a = i ? i[e] : '';
if (!o || !e)
return {
isValid: !0,
@@ -1730,19 +2014,19 @@
issues: [],
wrapperClassName: '',
};
- var l = I(o, e, i),
+ var l = C(o, e, a),
c = '';
return (
l.hasErrors
? (c = 'validation-api-meta-error')
: l.hasWarnings && (c = 'validation-api-meta-warning'),
- pe(pe({}, l), {}, { wrapperClassName: c })
+ xe(xe({}, l), {}, { wrapperClassName: c })
);
},
[e]
);
})(e),
- o = (0, t.useSelect)(
+ n = (0, o.useSelect)(
function (t) {
var r = t('core/editor');
if (!r) return { value: '' };
@@ -1751,48 +2035,48 @@
},
[e]
).value,
- a = (0, t.useDispatch)('core/editor').editPost,
- i = r;
- if (n && (n.hasErrors || n.hasWarnings)) {
- var l = n.issues
+ i = (0, o.useDispatch)('core/editor').editPost,
+ a = t;
+ if (r && (r.hasErrors || r.hasWarnings)) {
+ var l = r.issues
.map(function (e) {
return e.message || e.error_msg || e.warning_msg;
})
.join('. '),
- c = n.hasErrors ? 'validation-api-error-text' : 'validation-api-warning-text';
- i = i
+ c = r.hasErrors ? 'validation-api-error-text' : 'validation-api-warning-text';
+ a = a
? React.createElement(
React.Fragment,
null,
- i,
+ a,
React.createElement('span', { className: c }, '* ', l)
)
: React.createElement('span', { className: c }, '* ', l);
}
return {
- value: o || '',
+ value: n || '',
onChange: function (t) {
var r, n, o;
- a &&
- a({
+ i &&
+ i({
meta:
((r = {}),
(n = e),
(o = t),
(n = (function (e) {
var t = (function (e) {
- if ('object' != ye(e) || !e) return e;
+ if ('object' != Ke(e) || !e) return e;
var t = e[Symbol.toPrimitive];
if (void 0 !== t) {
var r = t.call(e, 'string');
- if ('object' != ye(r)) return r;
+ if ('object' != Ke(r)) return r;
throw new TypeError(
'@@toPrimitive must return a primitive value.'
);
}
return String(e);
})(e);
- return 'symbol' == ye(t) ? t : t + '';
+ return 'symbol' == Ke(t) ? t : t + '';
})(n)) in r
? Object.defineProperty(r, n, {
value: o,
@@ -1804,10 +2088,10 @@
r),
});
},
- help: i,
+ help: a,
className:
- null != n && n.wrapperClassName
- ? 'validation-api-field '.concat(n.wrapperClassName)
+ null != r && r.wrapperClassName
+ ? 'validation-api-field '.concat(r.wrapperClassName)
: '',
};
}));
diff --git a/docs/DATASTORE.md b/docs/DATASTORE.md
deleted file mode 100644
index f2e5818..0000000
--- a/docs/DATASTORE.md
+++ /dev/null
@@ -1,135 +0,0 @@
-# Data Store Plan
-
-## Current State
-
-Validation state is computed independently by each consumer. The three core hooks — `GetInvalidBlocks`, `GetInvalidMeta`, and `GetInvalidEditorChecks` — each run their own `useSelect` calls against `core/editor` and `core/block-editor`. Two components call all three hooks:
-
-- **ValidationAPI.js** — locks/unlocks post saving based on errors, manages body classes
-- **ValidationSidebar.js** — renders the sidebar UI with deduplicated issues
-
-This means every block edit triggers both components to independently re-derive the full validation state.
-
-Additionally, a lightweight in-memory `Map` exists at `src/editor/store/blockValidationStore.js` that shares per-block validation results between the `editor.BlockEdit` filter (writes) and `editor.BlockListBlock` filter (reads). This is not a `@wordpress/data` store — it's a plain module-scoped Map with no reactivity or selectors.
-
-### Current Consumers and Their Data Sources
-
-| Consumer | Hooks Used | WordPress Selectors |
-|----------|-----------|-------------------|
-| ValidationAPI.js | GetInvalidBlocks, GetInvalidMeta, GetInvalidEditorChecks | core/editor (dispatch: lock/unlock saving) |
-| ValidationSidebar.js | GetInvalidBlocks, GetInvalidMeta, GetInvalidEditorChecks | core/block-editor (dispatch: selectBlock) |
-| withErrorHandling.js (HOC) | useDebouncedValidation + validateBlock | core/block-editor (getBlock) |
-| useMetaField.js | useMetaValidation | core/editor (getEditedPostAttribute, editPost) |
-| useMetaValidation.js | validateAllMetaChecks | core/editor (getCurrentPostType, getEditedPostAttribute) |
-
-### Validation Rules Source
-
-All rules originate from PHP and are exposed via `window.ValidationAPI`:
-- `validationRules` — block validation rules by block type
-- `metaValidationRules` — meta validation rules by post type
-- `editorValidationRules` — editor validation rules by post type
-- `editorContext` — current editor context
-
----
-
-## Problem
-
-1. **Duplicated computation** — `ValidationAPI` and `ValidationSidebar` each independently call the same three hooks, running identical validation logic twice per change.
-2. **No shared reactivity** — the `blockValidationStore` Map has no subscription mechanism, so consumers can't react to changes without their own `useSelect` wiring.
-3. **Scaling concern** — adding a new consumer (e.g., toolbar badge, status bar) requires importing and re-running the same hooks again.
-
----
-
-## Proposed Solution: Custom `@wordpress/data` Store
-
-Create a `validation-api` store using `createReduxStore` that centralizes validation state and exposes it through selectors.
-
-### Store Namespace
-
-```
-validation-api
-```
-
-### State Shape
-
-```js
-{
- blocks: [], // Array of invalid block results
- meta: [], // Array of invalid meta results
- editor: [], // Array of editor check issues
-}
-```
-
-### Selectors
-
-| Selector | Returns | Description |
-|----------|---------|-------------|
-| `getInvalidBlocks(state)` | `Array` | All invalid block validation results |
-| `getInvalidMeta(state)` | `Array` | All invalid meta validation results |
-| `getInvalidEditorChecks(state)` | `Array` | All editor-level validation issues |
-| `hasErrors(state)` | `boolean` | True if any error exists across all types |
-| `hasWarnings(state)` | `boolean` | True if any warning exists (and no errors) |
-| `getBlockValidation(state, clientId)` | `Object` | Per-block validation result (replaces Map store) |
-
-### Actions
-
-| Action | Payload | Description |
-|--------|---------|-------------|
-| `setInvalidBlocks(results)` | `Array` | Update block validation results |
-| `setInvalidMeta(results)` | `Array` | Update meta validation results |
-| `setInvalidEditorChecks(issues)` | `Array` | Update editor check results |
-| `setBlockValidation(clientId, result)` | `string, Object` | Set per-block validation (replaces Map) |
-| `clearBlockValidation(clientId)` | `string` | Remove per-block validation |
-
-### File Structure
-
-```
-src/editor/store/
- index.js // createReduxStore + register, barrel exports
- selectors.js // All selector functions
- actions.js // All action creators
- reducer.js // State reducer
- blockValidationStore.js // (removed — absorbed into store)
-```
-
----
-
-## Migration Path
-
-### Phase 1: Create the Store
-
-- Create `reducer.js`, `actions.js`, `selectors.js`
-- Register the store via `createReduxStore` in `index.js`
-- Keep existing hooks working alongside the store
-
-### Phase 2: Write to the Store
-
-- Update `GetInvalidBlocks`, `GetInvalidMeta`, and `GetInvalidEditorChecks` to dispatch results into the store after computing them
-- Update `withErrorHandling.js` to use store actions instead of the Map
-
-### Phase 3: Read from the Store
-
-- Refactor `ValidationAPI.js` to read from `select('validation-api')` instead of calling hooks directly
-- Refactor `ValidationSidebar.js` to read from `select('validation-api')`
-- Only one component (or a top-level provider) needs to drive the validation hooks
-
-### Phase 4: Clean Up
-
-- Remove `blockValidationStore.js` (Map-based store)
-- Simplify the three `Get*` hooks into internal update functions rather than public hooks
-- Remove duplicate validation calls
-
----
-
-## Benefits
-
-- **Single computation** — validation runs once, multiple components subscribe
-- **Memoized selectors** — `useSelect` bails out when results haven't changed, reducing re-renders
-- **Decoupled consumers** — any component can `select('validation-api').hasErrors()` without importing hooks
-- **Testable** — selectors and reducers are plain functions
-- **Replaces Map store** — per-block validation moves into the same reactive system
-
-## Trade-offs
-
-- Adds boilerplate (reducer, actions, selectors)
-- Slightly more complex mental model for a small plugin
-- Store registration must happen early enough for all consumers
diff --git a/src/editor/components/ValidationProvider.js b/src/editor/components/ValidationProvider.js
new file mode 100644
index 0000000..c560b7d
--- /dev/null
+++ b/src/editor/components/ValidationProvider.js
@@ -0,0 +1,45 @@
+/**
+ * WordPress dependencies
+ */
+import { useDispatch } from '@wordpress/data';
+import { useEffect } from '@wordpress/element';
+
+/**
+ * Internal dependencies
+ */
+import {
+ GetInvalidBlocks,
+ GetInvalidMeta,
+ GetInvalidEditorChecks,
+} from '../../shared/utils/validation';
+import { STORE_NAME } from '../store';
+
+/**
+ * Validation Provider Component
+ *
+ * Renderless component that computes validation state from the three core hooks
+ * and dispatches the results into the validation-api data store. This is the
+ * single place where validation is computed — all other consumers read from
+ * the store via selectors.
+ */
+export function ValidationProvider() {
+ const invalidBlocks = GetInvalidBlocks();
+ const invalidMeta = GetInvalidMeta();
+ const invalidEditorChecks = GetInvalidEditorChecks();
+
+ const { setInvalidBlocks, setInvalidMeta, setInvalidEditorChecks } = useDispatch(STORE_NAME);
+
+ useEffect(() => {
+ setInvalidBlocks(invalidBlocks);
+ }, [invalidBlocks, setInvalidBlocks]);
+
+ useEffect(() => {
+ setInvalidMeta(invalidMeta);
+ }, [invalidMeta, setInvalidMeta]);
+
+ useEffect(() => {
+ setInvalidEditorChecks(invalidEditorChecks);
+ }, [invalidEditorChecks, setInvalidEditorChecks]);
+
+ return null;
+}
diff --git a/src/editor/components/ValidationSidebar.js b/src/editor/components/ValidationSidebar.js
index 28f57f9..4375227 100644
--- a/src/editor/components/ValidationSidebar.js
+++ b/src/editor/components/ValidationSidebar.js
@@ -4,7 +4,7 @@
import { PluginSidebar } from '@wordpress/editor';
import { PanelBody, PanelRow } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
-import { useDispatch } from '@wordpress/data';
+import { useSelect, useDispatch } from '@wordpress/data';
import { useEffect, useRef } from '@wordpress/element';
import { getBlockType } from '@wordpress/blocks';
@@ -12,14 +12,8 @@ import { getBlockType } from '@wordpress/blocks';
* Internal dependencies
*/
import { ValidationIcon } from './ValidationIcon';
-import {
- GetInvalidBlocks,
- GetInvalidMeta,
- GetInvalidEditorChecks,
- filterIssuesByType,
- getErrors,
- getWarnings,
-} from '../../shared/utils/validation';
+import { STORE_NAME } from '../store';
+import { filterIssuesByType, getErrors, getWarnings } from '../../shared/utils/validation';
/**
* Get display name for a block type
@@ -164,10 +158,15 @@ function deduplicateEditorIssues(issues, severity) {
* The icon color reflects the highest severity issue present (red for errors, yellow for warnings).
*/
export function ValidationSidebar() {
- // Retrieve validation results from all sources
- const invalidBlocks = GetInvalidBlocks() || [];
- const invalidMeta = GetInvalidMeta() || [];
- const invalidEditorChecks = GetInvalidEditorChecks() || [];
+ // Read validation results from the centralized store
+ const { invalidBlocks, invalidMeta, invalidEditorChecks } = useSelect(select => {
+ const store = select(STORE_NAME);
+ return {
+ invalidBlocks: store.getInvalidBlocks(),
+ invalidMeta: store.getInvalidMeta(),
+ invalidEditorChecks: store.getInvalidEditorChecks(),
+ };
+ }, []);
// Get dispatch function to select blocks when user clicks on issues
const { selectBlock } = useDispatch('core/block-editor');
diff --git a/src/editor/hoc/withBlockValidationClasses.js b/src/editor/hoc/withBlockValidationClasses.js
index fe48560..7366492 100644
--- a/src/editor/hoc/withBlockValidationClasses.js
+++ b/src/editor/hoc/withBlockValidationClasses.js
@@ -2,11 +2,12 @@
* WordPress dependencies
*/
import { addFilter } from '@wordpress/hooks';
+import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
-import { getBlockValidation } from '../store';
+import { STORE_NAME } from '../store';
/**
* Adds validation CSS classes to the block's own wrapper element.
@@ -15,12 +16,18 @@ import { getBlockValidation } from '../store';
* classes directly onto the block's native DOM element, avoiding
* the need for an extra wrapper div.
*
+ * Reads per-block validation state from the data store, giving it
+ * proper reactive subscriptions so classes update when validation changes.
+ *
* @param {Function} BlockListBlock The original BlockListBlock component.
* @return {Function} Wrapped component with validation classes.
*/
function withBlockValidationClasses(BlockListBlock) {
return props => {
- const validation = getBlockValidation(props.clientId);
+ const validation = useSelect(
+ select => select(STORE_NAME).getBlockValidation(props.clientId),
+ [props.clientId]
+ );
if (validation.mode === 'none') {
return ;
diff --git a/src/editor/hoc/withErrorHandling.js b/src/editor/hoc/withErrorHandling.js
index a05a06a..209dc19 100644
--- a/src/editor/hoc/withErrorHandling.js
+++ b/src/editor/hoc/withErrorHandling.js
@@ -2,7 +2,7 @@
* WordPress dependencies
*/
import { createHigherOrderComponent } from '@wordpress/compose';
-import { useSelect } from '@wordpress/data';
+import { useSelect, useDispatch } from '@wordpress/data';
import { useEffect } from '@wordpress/element';
import { BlockControls } from '@wordpress/block-editor';
@@ -12,7 +12,7 @@ import { BlockControls } from '@wordpress/block-editor';
import { validateBlock } from '../validation/blocks';
import { ValidationToolbarButton } from '../components/ValidationToolbarButton';
import { useDebouncedValidation } from '../../shared/hooks';
-import { setBlockValidation, clearBlockValidation } from '../store';
+import { STORE_NAME } from '../store';
/**
* Higher-order component that adds validation indicators to blocks.
@@ -34,6 +34,8 @@ const withErrorHandling = createHigherOrderComponent(BlockEdit => {
[clientId]
);
+ const { setBlockValidation, clearBlockValidation } = useDispatch(STORE_NAME);
+
const validationResult = useDebouncedValidation(
() => {
if (!block) {
@@ -49,12 +51,12 @@ const withErrorHandling = createHigherOrderComponent(BlockEdit => {
{ delay: 300 }
);
- // Sync validation state to the shared store so the
+ // Sync validation state to the data store so the
// editor.BlockListBlock filter can read it for CSS classes.
useEffect(() => {
setBlockValidation(clientId, validationResult);
return () => clearBlockValidation(clientId);
- }, [clientId, validationResult]);
+ }, [clientId, validationResult, setBlockValidation, clearBlockValidation]);
return (
<>
diff --git a/src/editor/register.js b/src/editor/register.js
index f2cc0b5..f72aa6f 100644
--- a/src/editor/register.js
+++ b/src/editor/register.js
@@ -6,6 +6,7 @@ import { registerPlugin } from '@wordpress/plugins';
/**
* Internal dependencies
*/
+import { ValidationProvider } from './components/ValidationProvider';
import { ValidationAPI } from './validation/ValidationAPI';
import { ValidationSidebar } from './components/ValidationSidebar';
@@ -20,6 +21,7 @@ import { ValidationSidebar } from './components/ValidationSidebar';
registerPlugin('validation-api', {
render: () => (
<>
+
>
diff --git a/src/editor/store/actions.js b/src/editor/store/actions.js
new file mode 100644
index 0000000..9496cb1
--- /dev/null
+++ b/src/editor/store/actions.js
@@ -0,0 +1,61 @@
+/**
+ * Internal dependencies
+ */
+import {
+ SET_INVALID_BLOCKS,
+ SET_INVALID_META,
+ SET_INVALID_EDITOR_CHECKS,
+ SET_BLOCK_VALIDATION,
+ CLEAR_BLOCK_VALIDATION,
+} from './constants';
+
+/**
+ * Set the array of invalid block validation results.
+ *
+ * @param {Array} results Invalid block results from GetInvalidBlocks.
+ * @return {Object} Action object.
+ */
+export function setInvalidBlocks(results) {
+ return { type: SET_INVALID_BLOCKS, results };
+}
+
+/**
+ * Set the array of invalid meta validation results.
+ *
+ * @param {Array} results Invalid meta results from GetInvalidMeta.
+ * @return {Object} Action object.
+ */
+export function setInvalidMeta(results) {
+ return { type: SET_INVALID_META, results };
+}
+
+/**
+ * Set the array of editor-level validation issues.
+ *
+ * @param {Array} issues Editor check issues from GetInvalidEditorChecks.
+ * @return {Object} Action object.
+ */
+export function setInvalidEditorChecks(issues) {
+ return { type: SET_INVALID_EDITOR_CHECKS, issues };
+}
+
+/**
+ * Store a single block's validation result.
+ *
+ * @param {string} clientId Block client ID.
+ * @param {Object} result Validation result ({ mode, issues }).
+ * @return {Object} Action object.
+ */
+export function setBlockValidation(clientId, result) {
+ return { type: SET_BLOCK_VALIDATION, clientId, result };
+}
+
+/**
+ * Remove a single block's validation result.
+ *
+ * @param {string} clientId Block client ID.
+ * @return {Object} Action object.
+ */
+export function clearBlockValidation(clientId) {
+ return { type: CLEAR_BLOCK_VALIDATION, clientId };
+}
diff --git a/src/editor/store/blockValidationStore.js b/src/editor/store/blockValidationStore.js
deleted file mode 100644
index 337696e..0000000
--- a/src/editor/store/blockValidationStore.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Block Validation Store
- *
- * Module-level Map that shares validation state between the
- * editor.BlockEdit filter (writes) and editor.BlockListBlock filter (reads).
- * This avoids the overhead of a full WordPress data store while keeping
- * both filters in sync.
- */
-
-const validationMap = new Map();
-
-const defaultResult = Object.freeze({ mode: 'none', issues: [] });
-
-/**
- * Store a block's validation result.
- *
- * @param {string} clientId Block client ID.
- * @param {Object} result Validation result.
- * @param {string} result.mode 'none' | 'error' | 'warning'
- * @param {Array} result.issues Array of issue objects.
- */
-export function setBlockValidation(clientId, result) {
- validationMap.set(clientId, result);
-}
-
-/**
- * Read a block's validation result.
- *
- * @param {string} clientId Block client ID.
- * @return {Object} Validation result or default (mode: 'none', issues: []).
- */
-export function getBlockValidation(clientId) {
- return validationMap.get(clientId) || defaultResult;
-}
-
-/**
- * Remove a block's validation result (call on unmount).
- *
- * @param {string} clientId Block client ID.
- */
-export function clearBlockValidation(clientId) {
- validationMap.delete(clientId);
-}
diff --git a/src/editor/store/constants.js b/src/editor/store/constants.js
new file mode 100644
index 0000000..ff3384e
--- /dev/null
+++ b/src/editor/store/constants.js
@@ -0,0 +1,20 @@
+/**
+ * Store constants for the validation-api data store.
+ */
+
+export const STORE_NAME = 'validation-api';
+
+export const SET_INVALID_BLOCKS = 'SET_INVALID_BLOCKS';
+export const SET_INVALID_META = 'SET_INVALID_META';
+export const SET_INVALID_EDITOR_CHECKS = 'SET_INVALID_EDITOR_CHECKS';
+export const SET_BLOCK_VALIDATION = 'SET_BLOCK_VALIDATION';
+export const CLEAR_BLOCK_VALIDATION = 'CLEAR_BLOCK_VALIDATION';
+
+export const DEFAULT_STATE = {
+ blocks: [],
+ meta: [],
+ editor: [],
+ blockValidation: {},
+};
+
+export const DEFAULT_BLOCK_RESULT = Object.freeze({ mode: 'none', issues: [] });
diff --git a/src/editor/store/index.js b/src/editor/store/index.js
index a963a86..5e119a7 100644
--- a/src/editor/store/index.js
+++ b/src/editor/store/index.js
@@ -1,11 +1,43 @@
/**
- * Store
+ * WordPress dependencies
+ */
+import { createReduxStore, register } from '@wordpress/data';
+
+/**
+ * Internal dependencies
+ */
+import { STORE_NAME } from './constants';
+import { reducer } from './reducer';
+import * as selectors from './selectors';
+import * as actions from './actions';
+
+/**
+ * Validation API data store.
*
- * Barrel export for editor store utilities.
+ * Centralizes all validation state (blocks, meta, editor checks, per-block results)
+ * so that multiple consumers can subscribe via useSelect without duplicating computation.
*/
+const store = createReduxStore(STORE_NAME, {
+ reducer,
+ selectors,
+ actions,
+});
+
+register(store);
+export { STORE_NAME } from './constants';
export {
+ setInvalidBlocks,
+ setInvalidMeta,
+ setInvalidEditorChecks,
setBlockValidation,
- getBlockValidation,
clearBlockValidation,
-} from './blockValidationStore';
+} from './actions';
+export {
+ getInvalidBlocks,
+ getInvalidMeta,
+ getInvalidEditorChecks,
+ getBlockValidation,
+ hasErrors,
+ hasWarnings,
+} from './selectors';
diff --git a/src/editor/store/reducer.js b/src/editor/store/reducer.js
new file mode 100644
index 0000000..6e1a13d
--- /dev/null
+++ b/src/editor/store/reducer.js
@@ -0,0 +1,48 @@
+/**
+ * Internal dependencies
+ */
+import {
+ DEFAULT_STATE,
+ SET_INVALID_BLOCKS,
+ SET_INVALID_META,
+ SET_INVALID_EDITOR_CHECKS,
+ SET_BLOCK_VALIDATION,
+ CLEAR_BLOCK_VALIDATION,
+} from './constants';
+
+/**
+ * Reducer for the validation-api store.
+ *
+ * @param {Object} state Current state.
+ * @param {Object} action Dispatched action.
+ * @return {Object} Updated state.
+ */
+export function reducer(state = DEFAULT_STATE, action) {
+ switch (action.type) {
+ case SET_INVALID_BLOCKS:
+ return { ...state, blocks: action.results };
+
+ case SET_INVALID_META:
+ return { ...state, meta: action.results };
+
+ case SET_INVALID_EDITOR_CHECKS:
+ return { ...state, editor: action.issues };
+
+ case SET_BLOCK_VALIDATION:
+ return {
+ ...state,
+ blockValidation: {
+ ...state.blockValidation,
+ [action.clientId]: action.result,
+ },
+ };
+
+ case CLEAR_BLOCK_VALIDATION: {
+ const { [action.clientId]: _, ...remaining } = state.blockValidation;
+ return { ...state, blockValidation: remaining };
+ }
+
+ default:
+ return state;
+ }
+}
diff --git a/src/editor/store/selectors.js b/src/editor/store/selectors.js
new file mode 100644
index 0000000..2587e8c
--- /dev/null
+++ b/src/editor/store/selectors.js
@@ -0,0 +1,74 @@
+/**
+ * Internal dependencies
+ */
+import { DEFAULT_BLOCK_RESULT } from './constants';
+
+/**
+ * Get all invalid block validation results.
+ *
+ * @param {Object} state Store state.
+ * @return {Array} Array of invalid block results.
+ */
+export function getInvalidBlocks(state) {
+ return state.blocks;
+}
+
+/**
+ * Get all invalid meta validation results.
+ *
+ * @param {Object} state Store state.
+ * @return {Array} Array of invalid meta results.
+ */
+export function getInvalidMeta(state) {
+ return state.meta;
+}
+
+/**
+ * Get all editor-level validation issues.
+ *
+ * @param {Object} state Store state.
+ * @return {Array} Array of editor check issues.
+ */
+export function getInvalidEditorChecks(state) {
+ return state.editor;
+}
+
+/**
+ * Get a single block's validation result.
+ *
+ * @param {Object} state Store state.
+ * @param {string} clientId Block client ID.
+ * @return {Object} Validation result ({ mode, issues }).
+ */
+export function getBlockValidation(state, clientId) {
+ return state.blockValidation[clientId] || DEFAULT_BLOCK_RESULT;
+}
+
+/**
+ * Check if any validation errors exist across blocks, meta, and editor checks.
+ *
+ * @param {Object} state Store state.
+ * @return {boolean} True if any errors exist.
+ */
+export function hasErrors(state) {
+ const hasBlockErrors = state.blocks.some(block => block.mode === 'error');
+ const hasMetaErrors = state.meta.some(meta => meta.hasErrors);
+ const hasEditorErrors = state.editor.some(issue => issue.type === 'error');
+ return hasBlockErrors || hasMetaErrors || hasEditorErrors;
+}
+
+/**
+ * Check if any validation warnings exist (only when no errors are present).
+ *
+ * @param {Object} state Store state.
+ * @return {boolean} True if warnings exist and no errors exist.
+ */
+export function hasWarnings(state) {
+ if (hasErrors(state)) {
+ return false;
+ }
+ const hasBlockWarnings = state.blocks.some(block => block.mode === 'warning');
+ const hasMetaWarnings = state.meta.some(meta => meta.hasWarnings && !meta.hasErrors);
+ const hasEditorWarnings = state.editor.some(issue => issue.type === 'warning');
+ return hasBlockWarnings || hasMetaWarnings || hasEditorWarnings;
+}
diff --git a/src/editor/validation/ValidationAPI.js b/src/editor/validation/ValidationAPI.js
index de8284a..2262508 100644
--- a/src/editor/validation/ValidationAPI.js
+++ b/src/editor/validation/ValidationAPI.js
@@ -1,18 +1,16 @@
/**
* WordPress dependencies
*/
-import { useDispatch } from '@wordpress/data';
+import { useSelect, useDispatch } from '@wordpress/data';
import { useEffect } from '@wordpress/element';
/**
* Internal dependencies
*/
+import { STORE_NAME } from '../store';
import {
- GetInvalidBlocks,
- GetInvalidMeta,
- GetInvalidEditorChecks,
- hasErrors,
- hasWarnings,
+ hasErrors as issueHasErrors,
+ hasWarnings as issueHasWarnings,
} from '../../shared/utils/validation';
/**
@@ -46,11 +44,15 @@ export function ValidationAPI() {
// Verify the store exists before using it
const storeExists = wp.data && wp.data.select && wp.data.select(editorStore);
- // Retrieve validation results from all validation sources
- // Called unconditionally to avoid unused variable lint errors
- const invalidBlocks = GetInvalidBlocks();
- const invalidMeta = GetInvalidMeta();
- const invalidEditorChecks = GetInvalidEditorChecks();
+ // Read validation results from the centralized store
+ const { invalidBlocks, invalidMeta, invalidEditorChecks } = useSelect(select => {
+ const store = select(STORE_NAME);
+ return {
+ invalidBlocks: store.getInvalidBlocks(),
+ invalidMeta: store.getInvalidMeta(),
+ invalidEditorChecks: store.getInvalidEditorChecks(),
+ };
+ }, []);
// Destructure functions - these exist in core/editor for both contexts
const {
@@ -86,7 +88,7 @@ export function ValidationAPI() {
// Check for errors across all validation types
const hasBlockErrors = invalidBlocks.some(block => block.mode === 'error');
const hasMetaErrors = invalidMeta.some(meta => meta.hasErrors);
- const hasEditorErrors = hasErrors(invalidEditorChecks);
+ const hasEditorErrors = issueHasErrors(invalidEditorChecks);
// Lock saving if any validation errors exist
if (hasBlockErrors || hasMetaErrors || hasEditorErrors) {
@@ -148,8 +150,8 @@ export function ValidationAPI() {
const hasBlockWarnings = invalidBlocks.some(block => block.mode === 'warning');
const hasMetaErrors = invalidMeta.some(meta => meta.hasErrors);
const hasMetaWarnings = invalidMeta.some(meta => meta.hasWarnings && !meta.hasErrors);
- const hasEditorErrors = hasErrors(invalidEditorChecks);
- const hasEditorWarnings = hasWarnings(invalidEditorChecks);
+ const hasEditorErrors = issueHasErrors(invalidEditorChecks);
+ const hasEditorWarnings = issueHasWarnings(invalidEditorChecks);
// Check for overall errors first (blocks, meta, or editor)
const hasAnyErrors = hasBlockErrors || hasMetaErrors || hasEditorErrors;