first commit
This commit is contained in:
1034
packages/gutenberg-to-portable-text/src/transformers/core.ts
Normal file
1034
packages/gutenberg-to-portable-text/src/transformers/core.ts
Normal file
File diff suppressed because it is too large
Load Diff
142
packages/gutenberg-to-portable-text/src/transformers/embed.ts
Normal file
142
packages/gutenberg-to-portable-text/src/transformers/embed.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* Transformers for WordPress embed blocks
|
||||
*/
|
||||
|
||||
import type { BlockTransformer } from "../types.js";
|
||||
import { attrString } from "../types.js";
|
||||
|
||||
// Regex patterns for embed parsing
|
||||
const IFRAME_SRC_PATTERN = /<iframe[^>]+src=["']([^"']+)["']/i;
|
||||
const VIDEO_SRC_PATTERN = /<video[^>]+src=["']([^"']+)["']/i;
|
||||
const VIDEO_SOURCE_PATTERN = /<source[^>]+src=["']([^"']+)["']/i;
|
||||
const AUDIO_SRC_PATTERN = /<audio[^>]+src=["']([^"']+)["']/i;
|
||||
const AUDIO_SOURCE_PATTERN = /<source[^>]+src=["']([^"']+)["']/i;
|
||||
|
||||
/**
|
||||
* core/embed and variants → embed block
|
||||
*/
|
||||
export const embed: BlockTransformer = (block, _options, context) => {
|
||||
const url = attrString(block.attrs, "url");
|
||||
const providerSlug = attrString(block.attrs, "providerNameSlug");
|
||||
|
||||
// Extract iframe src if present
|
||||
const iframeMatch = block.innerHTML.match(IFRAME_SRC_PATTERN);
|
||||
const iframeSrc = iframeMatch?.[1];
|
||||
|
||||
return [
|
||||
{
|
||||
_type: "embed",
|
||||
_key: context.generateKey(),
|
||||
url: url || iframeSrc || "",
|
||||
provider: providerSlug || detectProvider(url || iframeSrc || ""),
|
||||
html: block.innerHTML.trim() || undefined,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* core-embed/youtube → embed block
|
||||
*/
|
||||
export const youtube: BlockTransformer = (block, options, context) => {
|
||||
return embed(block, options, context);
|
||||
};
|
||||
|
||||
/**
|
||||
* core-embed/twitter → embed block
|
||||
*/
|
||||
export const twitter: BlockTransformer = (block, options, context) => {
|
||||
return embed(block, options, context);
|
||||
};
|
||||
|
||||
/**
|
||||
* core-embed/vimeo → embed block
|
||||
*/
|
||||
export const vimeo: BlockTransformer = (block, options, context) => {
|
||||
return embed(block, options, context);
|
||||
};
|
||||
|
||||
/**
|
||||
* core/video → embed block (self-hosted video)
|
||||
*/
|
||||
export const video: BlockTransformer = (block, _options, context) => {
|
||||
const src = attrString(block.attrs, "src");
|
||||
|
||||
// Extract from video tag if not in attrs
|
||||
const videoMatch = block.innerHTML.match(VIDEO_SRC_PATTERN);
|
||||
const sourceMatch = block.innerHTML.match(VIDEO_SOURCE_PATTERN);
|
||||
const videoSrc = src || videoMatch?.[1] || sourceMatch?.[1];
|
||||
|
||||
return [
|
||||
{
|
||||
_type: "embed",
|
||||
_key: context.generateKey(),
|
||||
url: videoSrc || "",
|
||||
provider: "video",
|
||||
html: block.innerHTML.trim() || undefined,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* core/audio → embed block (self-hosted audio)
|
||||
*/
|
||||
export const audio: BlockTransformer = (block, _options, context) => {
|
||||
const src = attrString(block.attrs, "src");
|
||||
|
||||
// Extract from audio tag if not in attrs
|
||||
const audioMatch = block.innerHTML.match(AUDIO_SRC_PATTERN);
|
||||
const sourceMatch = block.innerHTML.match(AUDIO_SOURCE_PATTERN);
|
||||
const audioSrc = src || audioMatch?.[1] || sourceMatch?.[1];
|
||||
|
||||
return [
|
||||
{
|
||||
_type: "embed",
|
||||
_key: context.generateKey(),
|
||||
url: audioSrc || "",
|
||||
provider: "audio",
|
||||
html: block.innerHTML.trim() || undefined,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* Detect embed provider from URL
|
||||
*/
|
||||
function detectProvider(url: string): string | undefined {
|
||||
if (!url) return undefined;
|
||||
|
||||
const urlLower = url.toLowerCase();
|
||||
|
||||
if (urlLower.includes("youtube.com") || urlLower.includes("youtu.be")) {
|
||||
return "youtube";
|
||||
}
|
||||
if (urlLower.includes("vimeo.com")) {
|
||||
return "vimeo";
|
||||
}
|
||||
if (urlLower.includes("twitter.com") || urlLower.includes("x.com")) {
|
||||
return "twitter";
|
||||
}
|
||||
if (urlLower.includes("instagram.com")) {
|
||||
return "instagram";
|
||||
}
|
||||
if (urlLower.includes("facebook.com")) {
|
||||
return "facebook";
|
||||
}
|
||||
if (urlLower.includes("tiktok.com")) {
|
||||
return "tiktok";
|
||||
}
|
||||
if (urlLower.includes("spotify.com")) {
|
||||
return "spotify";
|
||||
}
|
||||
if (urlLower.includes("soundcloud.com")) {
|
||||
return "soundcloud";
|
||||
}
|
||||
if (urlLower.includes("codepen.io")) {
|
||||
return "codepen";
|
||||
}
|
||||
if (urlLower.includes("gist.github.com")) {
|
||||
return "gist";
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
115
packages/gutenberg-to-portable-text/src/transformers/index.ts
Normal file
115
packages/gutenberg-to-portable-text/src/transformers/index.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Block transformers registry
|
||||
*/
|
||||
|
||||
import type { BlockTransformer, PortableTextBlock } from "../types.js";
|
||||
import * as core from "./core.js";
|
||||
import * as embed from "./embed.js";
|
||||
|
||||
/**
|
||||
* Default block transformers for core WordPress blocks
|
||||
*/
|
||||
export const defaultTransformers: Record<string, BlockTransformer> = {
|
||||
// Text blocks
|
||||
"core/paragraph": core.paragraph,
|
||||
"core/heading": core.heading,
|
||||
"core/list": core.list,
|
||||
"core/quote": core.quote,
|
||||
"core/code": core.code,
|
||||
"core/preformatted": core.preformatted,
|
||||
"core/pullquote": core.pullquote,
|
||||
"core/verse": core.verse,
|
||||
|
||||
// Media blocks
|
||||
"core/image": core.image,
|
||||
"core/gallery": core.gallery,
|
||||
"core/file": core.file,
|
||||
"core/media-text": core.mediaText,
|
||||
"core/cover": core.cover,
|
||||
|
||||
// Layout blocks
|
||||
"core/columns": core.columns,
|
||||
"core/group": core.group,
|
||||
"core/separator": core.separator,
|
||||
"core/spacer": core.separator,
|
||||
"core/table": core.table,
|
||||
"core/buttons": core.buttons,
|
||||
"core/button": core.button,
|
||||
|
||||
// Structural blocks
|
||||
"core/more": core.more,
|
||||
"core/nextpage": core.nextpage,
|
||||
|
||||
// Pass-through blocks (preserve as HTML)
|
||||
"core/html": core.html,
|
||||
"core/shortcode": core.shortcode,
|
||||
|
||||
// Embed blocks
|
||||
"core/embed": embed.embed,
|
||||
"core/video": embed.video,
|
||||
"core/audio": embed.audio,
|
||||
|
||||
// Legacy embed block names (WP < 5.6)
|
||||
"core-embed/youtube": embed.youtube,
|
||||
"core-embed/twitter": embed.twitter,
|
||||
"core-embed/vimeo": embed.vimeo,
|
||||
"core-embed/facebook": embed.embed,
|
||||
"core-embed/instagram": embed.embed,
|
||||
"core-embed/soundcloud": embed.embed,
|
||||
"core-embed/spotify": embed.embed,
|
||||
};
|
||||
|
||||
/**
|
||||
* Fallback transformer for unknown blocks
|
||||
* Stores the original HTML for manual review
|
||||
*/
|
||||
export const fallbackTransformer: BlockTransformer = (
|
||||
block,
|
||||
_options,
|
||||
context,
|
||||
): PortableTextBlock[] => {
|
||||
// Skip completely empty blocks
|
||||
if (!block.innerHTML.trim() && block.innerBlocks.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// If it has inner blocks, try to transform those
|
||||
if (block.innerBlocks.length > 0) {
|
||||
return context.transformBlocks(block.innerBlocks);
|
||||
}
|
||||
|
||||
// Store as HTML fallback
|
||||
return [
|
||||
{
|
||||
_type: "htmlBlock",
|
||||
_key: context.generateKey(),
|
||||
html: block.innerHTML,
|
||||
originalBlockName: block.blockName,
|
||||
originalAttrs: Object.keys(block.attrs).length > 0 ? block.attrs : undefined,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get transformer for a block
|
||||
*/
|
||||
export function getTransformer(
|
||||
blockName: string | null,
|
||||
customTransformers?: Record<string, BlockTransformer>,
|
||||
): BlockTransformer {
|
||||
if (!blockName) {
|
||||
return fallbackTransformer;
|
||||
}
|
||||
|
||||
// Check custom transformers first
|
||||
if (customTransformers?.[blockName]) {
|
||||
return customTransformers[blockName];
|
||||
}
|
||||
|
||||
// Check default transformers
|
||||
if (defaultTransformers[blockName]) {
|
||||
return defaultTransformers[blockName];
|
||||
}
|
||||
|
||||
return fallbackTransformer;
|
||||
}
|
||||
Reference in New Issue
Block a user