PluginProbe
Extendify / 3.2.2
Extendify v3.2.2
3.2.2 3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 All 128 releases
← All changes | src/Agent/workflows/block-selector/tools/find-blocks.js +33 -5 3.2.1 → 3.2.2 View file →
@@ -74,18 +74,40 @@
74 74 }
75 75 return [...found.values()];
76 76 };
77 77
78 +const bareAddress = (value) =>
79 + (value ?? '')
80 + .toLowerCase()
81 + .replace(/^https?:\/\//, '')
82 + .replace(/^www\./, '')
83 + .replace(/\/$/, '');
84 +
85 +// A link asked for by address carries only its label as text.
86 +const matchesAddress = ({ blockId, type }, text) => {
87 + if (type !== 'core/navigation-link') return false;
88 + const wanted = bareAddress(text);
89 + const href = resolveScopedId(blockId)
90 + ?.querySelector('a')
91 + ?.getAttribute('href');
92 + return Boolean(wanted && href) && bareAddress(href).includes(wanted);
93 +};
94 +
78 95 // A search for "footer" arrives as text and would otherwise match nothing.
79 -const matchesText = ({ text: blockText, part }, text) => {
96 +const matchesText = (entry, text) => {
80 97 if (!text) return true;
98 + const { text: blockText, part } = entry;
81 99 const needle = text.toLowerCase();
82 100 if ((blockText ?? '').toLowerCase().includes(needle)) return true;
101 + if (matchesAddress(entry, text)) return true;
83 102 return Boolean(part) && needle.includes(part.toLowerCase());
84 103 };
85 104
105 +// core/navigation never resolves to a type, so a menu search matches its links.
86 106 const matchesType = (type, blockTypes) =>
87 - !blockTypes?.length || blockTypes.includes(type);
107 + !blockTypes?.length ||
108 + blockTypes.includes(type) ||
109 + (type === 'core/navigation-link' && blockTypes.includes('core/navigation'));
88 110
89 111 const matchesPart = (entry, part) =>
90 112 !part || (entry.part ?? '').toLowerCase() === part.toLowerCase();
91 113
@@ -100,13 +122,19 @@
100 122 return true;
101 123 });
102 124 };
103 125
126 +// Page blocks carry no part, so an invented name like "post-content" empties the search.
127 +const knownPart = (entries, part) =>
128 + entries.some((entry) => matchesPart(entry, part) && entry.part) ? part : null;
129 +
104 130 export default ({ blockTypes, text, part } = {}) => {
105 131 const root = document.querySelector('.wp-site-blocks') ?? document.body;
106 - const all = scopeRoots(root)
107 - .flatMap(manifestFor)
108 - .filter((entry) => addressable(entry.type) && matchesPart(entry, part));
132 + const manifest = scopeRoots(root).flatMap(manifestFor);
133 + const scope = knownPart(manifest, part);
134 + const all = manifest.filter(
135 + (entry) => addressable(entry.type) && matchesPart(entry, scope),
136 + );
109 137 const byId = new Map(all.map((entry) => [entry.blockId, entry]));
110 138 const byType = all.filter(({ type }) => matchesType(type, blockTypes));
111 139 const matches = byType.filter((entry) => matchesText(entry, text));
112 140 // "hero" is a position, not text: AND-ing it would match nothing.