From eef16f5a0f5af0aea313e411534643678ba4bea1 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sun, 06 Sep 2026 20:58:21 +0000
Subject: [PATCH] =Polishing up the gutenberg sidebar for custom meta. Seems to be working more or less. Added integration with OpenStreetMaps for location fields. Still to add: row ordering for repeaters, Maybe a better view for the selector field (terms, posts, etc), ensure fields save correctly and repopulate.
---
src/editor-fields/fields/selector-field.js | 64 +++++++++++++++++++++++++++-----
1 files changed, 54 insertions(+), 10 deletions(-)
diff --git a/src/editor-fields/fields/selector-field.js b/src/editor-fields/fields/selector-field.js
index 88d32ec..3e4cad2 100644
--- a/src/editor-fields/fields/selector-field.js
+++ b/src/editor-fields/fields/selector-field.js
@@ -17,16 +17,26 @@
return (search) => addQueryArgs('/wp/v2/search', { search, type: 'post', subtype: field.post_type, per_page: 20 });
};
+const createPayload = (field, subtype, name) =>
+ subtype === 'post' ? { title: name, status: 'publish', postType: field.post_type } : { name };
+
const labelOf = (item, subtype) => (subtype === 'user' ? item.name : item.title?.rendered ?? item.title ?? item.name);
const SelectorField = ({ field, value, onChange }) => {
const subtype = resolveSubtype(field);
+ const canCreate = subtype === 'taxonomy';
+ console.log(field);
const buildPath = searchPath(field);
- const ids = Array.isArray(value) ? value : value ? [value] : [];
+ const ids = Array.isArray(value) ? value : value ? value.split(',') : [];
const [tokens, setTokens] = useState([]); // display strings
const [idByLabel, setIdByLabel] = useState({});
const [options, setOptions] = useState({}); // label -> id, from last search
+ const [search, setSearch] = useState('');
+ const [creating, setCreating] = useState(false);
+
+ const createLabel = search ? `Not found. Create "${search}"?` : null;
+
// Resolve current IDs to labels on mount / value change
useEffect(() => {
@@ -54,7 +64,9 @@
}, [JSON.stringify(ids)]);
const onInputChange = useCallback((search) => {
- if (!search) return;
+ setSearch(search);
+ if (!search) { setOptions({}); return;}
+
apiFetch({ path: buildPath(search) })
.then((results) => {
const map = {};
@@ -64,13 +76,7 @@
.catch(() => {});
}, [buildPath, subtype]);
- const onChangeTokens = (newTokens) => {
- setTokens(newTokens);
- const newIds = newTokens
- .map((label) => idByLabel[label] ?? options[label])
- .filter((id) => id !== undefined);
- setIdByLabel((prev) => ({ ...prev, ...options }));
-
+ const commitIds = (newIds) => {
const isSingle = field.max === 1;
if (isSingle) {
onChange(newIds[newIds.length - 1] ?? 0);
@@ -79,15 +85,53 @@
}
};
+ const onChangeTokens = (newTokens) => {
+ const pendingCreate = newTokens.find((t) => t === createLabel);
+
+ if (pendingCreate && canCreate && !creating) {
+ setCreating(true);
+ apiFetch({ path: `/wp/v2/${field.taxonomy}`, method: 'POST', data: createPayload(field, subtype, search) })
+ .then((item) => {
+ const label = labelOf(item, subtype);
+ setIdByLabel((prev) => ({ ...prev, [label]: item.id }));
+ setTokens((prev) => {
+ const finalTokens = prev.filter((t) => t !== createLabel).concat(label);
+ const newIds = finalTokens.map((l) => idByLabel[l] ?? options[l] ?? (l === label ? item.id : undefined))
+ .filter((id) => id !== undefined);
+ commitIds(newIds);
+ return finalTokens;
+ });
+ })
+ .catch(() => {})
+ .finally(() => setCreating(false));
+ return;
+ }
+
+ const resolved = newTokens.filter(
+ (label) => idByLabel[label] !== undefined || options[label] !== undefined
+ );
+ const newIds = resolved.map((label) => idByLabel[label] ?? options[label]);
+ setTokens(resolved);
+ setIdByLabel((prev) => ({ ...prev, ...options }));
+ commitIds(newIds);
+ };
+
+ const noMatch = search && !Object.keys(options).some((l) => l.toLowerCase() === search.toLowerCase());
+ const suggestions = field.max === 1 && tokens.length
+ ? []
+ : [...Object.keys(options), ...(canCreate && noMatch ? [createLabel] : [])];
+
+
return (
<FormTokenField
label={field.label}
help={field.description}
value={tokens}
- suggestions={field.max === 1 && tokens.length ? [] : Object.keys(options)}
+ suggestions={suggestions}
onChange={onChangeTokens}
onInputChange={onInputChange}
maxLength={field.max || undefined}
+ id={field.name}
__experimentalExpandOnFocus
/>
);
--
Gitblit v1.10.0