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/block-patching.js +42 -2 3.2.0 → 3.2.2 View file →
@@ -1,7 +1,10 @@
1 1 import { fetchBlockCodeById } from '@agent/lib/block-code';
2 +import { findBlockEl, scopeOf } from '@agent/lib/block-el';
2 3 import { applyBlockPatch } from '@agent/lib/block-patch';
4 +import { duplicateMarkup } from '@agent/lib/duplicate-block';
3 5 import { buildNewBlock } from '@agent/lib/insertable-blocks';
6 +import { fetchLinkablePages } from '@agent/lib/linkable-pages';
4 7 import { ensureCoreBlocksRegistered } from '@agent/lib/register-blocks';
5 8 import { swapBlockImage } from '@agent/lib/replace-image';
6 9 import { SETTING_TEXT_BLOCKS } from '@agent/lib/setting-text-blocks';
7 10 import { useQuickEditStore } from '@quick-edit/state/store';
@@ -21,15 +24,51 @@
21 24 if (blockCode === previousContent) return null;
22 25 return { op: 'edit', blockId, block: blockCode };
23 26 };
24 27
25 -const buildAdd = ({ anchorId, position, blockType, patch, clear }) => {
28 +const ANCHOR_ROW_CLASS = { 'core/social-link': 'wp-block-social-link' };
29 +
30 +const joinsAnchorRow = (anchorId, blockType, source) => {
31 + const className = ANCHOR_ROW_CLASS[blockType];
32 + if (!className || anchorId == null) return false;
33 + const anchor = findBlockEl(String(anchorId), document, scopeOf({ source }));
34 + return Boolean(anchor?.classList?.contains(className));
35 +};
36 +
37 +// Unbound, the editor shows a bare custom URL and WP keeps linking a deleted page.
38 +const bindPage = async (patch) => {
39 + const pages = await fetchLinkablePages();
40 + const page = pages.find(({ url, link }) => [url, link].includes(patch?.url));
41 + return page
42 + ? { ...patch, id: page.id, type: 'page', kind: 'post-type' }
43 + : patch;
44 +};
45 +
46 +const buildAdd = async (
47 + { anchorId, position, blockType, patch, clear },
48 + source,
49 +) => {
26 50 const presetSlugs = window.extAgentData?.context?.presetSlugs ?? {};
27 - const block = buildNewBlock(blockType, patch, clear ?? [], presetSlugs);
51 + const linked =
52 + blockType === 'core/navigation-link' ? await bindPage(patch) : patch;
53 + const block = buildNewBlock(blockType, linked, clear ?? [], presetSlugs, {
54 + joinsRow: joinsAnchorRow(anchorId, blockType, source),
55 + });
28 56 if (!block) return null;
29 57 return { op: 'add', anchorId, position, block };
30 58 };
31 59
60 +const buildDuplicate = async (operation, source, postId) => {
61 + const { blockId, targetId, position } = operation;
62 + const block = await duplicateMarkup(operation, source, postId);
63 + return {
64 + op: 'duplicate',
65 + blockId,
66 + ...(targetId && { targetId, position: position ?? 'after' }),
67 + ...(block && { block }),
68 + };
69 +};
70 +
32 71 // The backend op has no image — the confirm UI attaches it before the tool runs.
33 72 const buildReplaceImage = async ({ blockId, image }, source, postId) => {
34 73 if (!image) return null;
35 74 const previousContent = await fetchBlockCodeById(blockId, source, postId);
@@ -49,8 +88,9 @@
49 88 targetId,
50 89 position,
51 90 }),
52 91 wrap: ({ blockId, container }) => ({ op: 'wrap', blockId, container }),
92 + duplicate: buildDuplicate,
53 93 add: buildAdd,
54 94 };
55 95
56 96 const writeSetting = (data) =>