UNPKG

@wordpress/blocks

Version:
198 lines (197 loc) 6.61 kB
// 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