@wordpress/blocks
Version:
Block API for WordPress.
198 lines (197 loc) • 6.61 kB
JavaScript
// packages/blocks/src/api/serializer.js
import {
Component,
cloneElement,
renderToString,
RawHTML
} from "@wordpress/element";
import { hasFilter, applyFilters } from "@wordpress/hooks";
import isShallowEqual from "@wordpress/is-shallow-equal";
import { removep } from "@wordpress/autop";
import deprecated from "@wordpress/deprecated";
import {
getBlockType,
getFreeformContentHandlerName,
getUnregisteredTypeHandlerName
} from "./registration";
import { serializeRawBlock } from "./parser/serialize-raw-block";
import { isUnmodifiedDefaultBlock, normalizeBlockType } from "./utils";
import { jsx } from "react/jsx-runtime";
function getBlockDefaultClassName(blockName) {
const className = "wp-block-" + blockName.replace(/\//, "-").replace(/^core-/, "");
return applyFilters(
"blocks.getBlockDefaultClassName",
className,
blockName
);
}
function getBlockMenuDefaultClassName(blockName) {
const className = "editor-block-list-item-" + blockName.replace(/\//, "-").replace(/^core-/, "");
return applyFilters(
"blocks.getBlockMenuDefaultClassName",
className,
blockName
);
}
var blockPropsProvider = {};
var innerBlocksPropsProvider = {};
function getBlockProps(props = {}) {
const { blockType, attributes } = blockPropsProvider;
return getBlockProps.skipFilters ? props : applyFilters(
"blocks.getSaveContent.extraProps",
{ ...props },
blockType,
attributes
);
}
function getInnerBlocksProps(props = {}) {
const { innerBlocks } = innerBlocksPropsProvider;
if (!Array.isArray(innerBlocks)) {
return { ...props, children: innerBlocks };
}
const html = serialize(innerBlocks, { isInnerBlocks: true });
const children = /* @__PURE__ */ jsx(RawHTML, { children: html });
return { ...props, children };
}
function getSaveElement(blockTypeOrName, attributes, innerBlocks = []) {
const blockType = normalizeBlockType(blockTypeOrName);
if (!blockType?.save) {
return null;
}
let { save } = blockType;
if (save.prototype instanceof Component) {
const instance = new save({ attributes });
save = instance.render.bind(instance);
}
blockPropsProvider.blockType = blockType;
blockPropsProvider.attributes = attributes;
innerBlocksPropsProvider.innerBlocks = innerBlocks;
let element = save({ attributes, innerBlocks });
if (element !== null && typeof element === "object" && hasFilter("blocks.getSaveContent.extraProps") && !(blockType.apiVersion > 1)) {
const props = applyFilters(
"blocks.getSaveContent.extraProps",
{ ...element.props },
blockType,
attributes
);
if (!isShallowEqual(props, element.props)) {
element = cloneElement(element, props);
}
}
return applyFilters(
"blocks.getSaveElement",
element,
blockType,
attributes
);
}
function getSaveContent(blockTypeOrName, attributes, innerBlocks) {
const blockType = normalizeBlockType(blockTypeOrName);
return renderToString(
getSaveElement(blockType, attributes, innerBlocks)
);
}
function getCommentAttributes(blockType, attributes) {
return Object.entries(blockType.attributes ?? {}).reduce(
(accumulator, [key, attributeSchema]) => {
const value = attributes[key];
if (void 0 === value) {
return accumulator;
}
if (attributeSchema.source !== void 0) {
return accumulator;
}
if (attributeSchema.role === "local") {
return accumulator;
}
if (attributeSchema.__experimentalRole === "local") {
deprecated("__experimentalRole attribute", {
since: "6.7",
version: "6.8",
alternative: "role attribute",
hint: `Check the block.json of the ${blockType?.name} block.`
});
return accumulator;
}
if ("default" in attributeSchema && JSON.stringify(attributeSchema.default) === JSON.stringify(value)) {
return accumulator;
}
accumulator[key] = value;
return accumulator;
},
{}
);
}
function serializeAttributes(attributes) {
return JSON.stringify(attributes).replaceAll("\\\\", "\\u005c").replaceAll("--", "\\u002d\\u002d").replaceAll("<", "\\u003c").replaceAll(">", "\\u003e").replaceAll("&", "\\u0026").replaceAll('\\"', "\\u0022");
}
function getBlockInnerHTML(block) {
let saveContent = block.originalContent;
if (block.isValid || block.innerBlocks.length) {
try {
saveContent = getSaveContent(
block.name,
block.attributes,
block.innerBlocks
);
} catch (error) {
}
}
return saveContent;
}
function getCommentDelimitedContent(rawBlockName, attributes, content) {
const serializedAttributes = attributes && Object.entries(attributes).length ? serializeAttributes(attributes) + " " : "";
const blockName = rawBlockName?.startsWith("core/") ? rawBlockName.slice(5) : rawBlockName;
if (!content) {
return `<!-- wp:${blockName} ${serializedAttributes}/-->`;
}
return `<!-- wp:${blockName} ${serializedAttributes}-->
` + content + `
<!-- /wp:${blockName} -->`;
}
function serializeBlock(block, { isInnerBlocks = false } = {}) {
if (!block.isValid && block.__unstableBlockSource) {
return serializeRawBlock(block.__unstableBlockSource);
}
const blockName = block.name;
const saveContent = getBlockInnerHTML(block);
if (blockName === getUnregisteredTypeHandlerName() || !isInnerBlocks && blockName === getFreeformContentHandlerName()) {
return saveContent;
}
const blockType = getBlockType(blockName);
if (!blockType) {
return saveContent;
}
const saveAttributes = getCommentAttributes(blockType, block.attributes);
return getCommentDelimitedContent(blockName, saveAttributes, saveContent);
}
function __unstableSerializeAndClean(blocks) {
if (blocks.length === 1 && isUnmodifiedDefaultBlock(blocks[0])) {
blocks = [];
}
let content = serialize(blocks);
if (blocks.length === 1 && blocks[0].name === getFreeformContentHandlerName() && blocks[0].name === "core/freeform") {
content = removep(content);
}
return content;
}
function serialize(blocks, options) {
const blocksArray = Array.isArray(blocks) ? blocks : [blocks];
return blocksArray.map((block) => serializeBlock(block, options)).join("\n\n");
}
export {
__unstableSerializeAndClean,
serialize as default,
getBlockDefaultClassName,
getBlockInnerHTML,
getBlockMenuDefaultClassName,
getBlockProps,
getCommentAttributes,
getCommentDelimitedContent,
getInnerBlocksProps,
getSaveContent,
getSaveElement,
serializeAttributes,
serializeBlock
};
//# sourceMappingURL=serializer.js.map