# extendify/3.1.5/src/Agent/lib/replace-image.js

Extendify, version 3.1.5. 63 lines.

- Page: https://pluginprobe.com/plugins/extendify/3.1.5/code/src/Agent/lib/replace-image.js
- Raw: https://pluginprobe.com/plugins/extendify/3.1.5/raw/src/Agent/lib/replace-image.js
- Modified: 2026-08-12T16:23:58+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/extendify/3.1.5/code/src/Agent/lib/replace-image.js#L10-L20`.

```javascript
import { createBlock, parse, serialize } from '@wordpress/blocks';

// core/media-text keys its image off media* attributes; url/id do nothing there.
const IMAGE_ATTRIBUTES = {
	'core/image': { url: 'url', id: 'id', alt: 'alt' },
	'core/cover': { url: 'url', id: 'id', alt: 'alt' },
	'core/media-text': {
		url: 'mediaUrl',
		id: 'mediaId',
		alt: 'mediaAlt',
		// A video side would keep rendering as one.
		set: { mediaType: 'image' },
		// mediaSizeSlug names a size of the attachment being replaced.
		clear: ['mediaSizeSlug'],
	},
};

// Swapping an un-fetched url into the live img flashes broken while it loads.
export const preloadImage = (src) =>
	new Promise((resolve, reject) => {
		const img = new Image();
		img.onload = () => resolve(src);
		img.onerror = reject;
		img.src = src;
	});

// The block's own save() regenerates the markup (img src, wp-image-{id}) from
// the attributes, so nothing here touches the HTML.
export const swapBlockImage = (serializedBlock, image) => {
	const url = image?.source_url || image?.url;
	if (!url || !image?.id) return null;
	// The attachment's alt carries the AI-generated disclosure prefix.
	const alt = image.alt_text ?? '';
	const parsed = parse(serializedBlock);
	if (!parsed.some((block) => IMAGE_ATTRIBUTES[block.name])) return null;
	const blocks = parsed.map((block) => {
		const slots = IMAGE_ATTRIBUTES[block.name];
		if (!slots) return block;
		const attributes = {
			...block.attributes,
			[slots.url]: url,
			[slots.id]: image.id,
			...slots.set,
		};
		if (alt) attributes[slots.alt] = alt;
		else delete attributes[slots.alt];
		for (const name of slots.clear ?? []) delete attributes[name];
		// Remove the import class to stop the unsplash cron from seeing it
		const className = (attributes.className ?? '')
			.split(/\s+/)
			.filter((cls) => cls && cls !== 'extendify-image-import')
			.join(' ');
		if (className) attributes.className = className;
		else delete attributes.className;
		// serialize() echoes a drifted block's original source, dropping the swap —
		// rebuild it (the editor's own recovery) so the new image reaches the markup.
		return block.isValid === false
			? createBlock(block.name, attributes, block.innerBlocks)
			: { ...block, attributes };
	});
	return serialize(blocks);
};

```
