如何向编辑器预览下拉菜单添加自定义条目
自 WordPress 6.7 起,插件开发者可以使用自定义菜单项扩展编辑器中的预览下拉菜单。这可以通过 @wordpress/editor 包中的 <a href="https://developer.wordpress.org/block-editor/reference-guides/packages/packages-editor/#pluginpreviewmenuitem">PluginPreviewMenuItem</a> 组件实现。本文将指导构建一个添加“社交卡片预览”选项的小插件——展示文章在 X 上分享时的外观。
什么是 PluginPreviewMenuItem?
预览下拉菜单位于编辑器顶部工具栏,允许用户以不同方式预览其内容。在 WordPress 6.7 之前,只有核心功能可以添加项目。通过 PluginPreviewMenuItem 组件,插件可以在该下拉菜单中注册自己的条目。它使用与 PluginMoreMenuItem 或 PluginSidebar 等其他扩展点相同的 Slot/Fill 模式。
该组件接受用于按钮行为的 onClick 处理函数或用于链接行为的 href。您还可以传递可选的 icon 属性。放置在 <PluginPreviewMenuItem> 开始和结束标签之间的文本将成为菜单中显示的标签。
社交卡片预览示例
此插件向预览下拉菜单添加一个社交卡片预览项。点击时,它会打开一个模态框,显示当前文章作为 X 卡片时的模拟预览。该模态框直接从编辑器存储中读取文章标题、摘要和特色图片,因此始终反映最新的未保存编辑。您可以查看 GitHub 上的示例插件。
插件设置
首先从文件结构开始。插件需要一个主 PHP 文件供 WordPress 识别,一个用于构建工具的 package.json,以及位于 src/ 文件夹中的源文件。
custom-preview/
├── custom-preview.php
├── package.json
└── src/
├── index.js
├── social-card-preview.js
└── style.css
PHP 引导程序
主插件文件 custom-preview.php 在 enqueue_block_editor_assets 钩子上注册脚本和样式表。代码使用 @wordpress/scripts 在构建期间生成的资产文件——它包含依赖项列表和版本哈希,以便 WordPress 正确处理缓存。以下代码放在 PHP 插件头部之后。
function social_card_preview_enqueue_editor_assets() {
$asset_file = plugin_dir_path( __FILE__ ) . 'build/index.asset.php';
if ( ! file_exists( $asset_file ) ) {
return;
}
$asset = include $asset_file;
wp_enqueue_script(
'social-card-preview-editor',
plugin_dir_url( __FILE__ ) . 'build/index.js',
$asset['dependencies'],
$asset['version'],
true
);
wp_enqueue_style(
'social-card-preview-editor',
plugin_dir_url( __FILE__ ) . 'build/style-index.css',
array(),
$asset['version']
);
}
add_action( 'enqueue_block_editor_assets', 'social_card_preview_enqueue_editor_assets' );
这是 WordPress 块编辑器插件开发中的常见模式。enqueue_block_editor_assets 钩子确保脚本和样式仅在编辑器内部加载,而不是在前端。
构建工具
对于 JavaScript 构建,@wordpress/scripts 处理工具。package.json 非常简洁:
{
"name": "social-card-preview",
"version": "1.0.0",
"scripts": {
"build": "wp-scripts build",
"start": "wp-scripts start"
},
"devDependencies": {
"@wordpress/scripts": "^30.0.0"
}
}
运行 npm install 获取依赖项,然后运行 npm run build 进行编译。在开发过程中,npm run start 会监视更改并自动重新构建。
注册预览菜单项
入口点 src/index.js 是注册插件并将菜单项添加到预览下拉菜单的地方。其背后的思路是:渲染一个 PluginPreviewMenuItem,点击时打开一个模态框。
import { __ } from '@wordpress/i18n';
import { registerPlugin } from '@wordpress/plugins';
import { PluginPreviewMenuItem } from '@wordpress/editor';
import { useState } from '@wordpress/element';
import SocialCardPreview from './social-card-preview';
import './style.css';
const SocialCardPreviewMenuItem = () => {
const [ isOpen, setIsOpen ] = useState( false );
return (
<>
<PluginPreviewMenuItem
onClick={ () => setIsOpen( true ) }
>
{ __( 'Social Card Preview', 'social-card-preview' ) }
</PluginPreviewMenuItem>
{ isOpen && (
<SocialCardPreview
onClose={ () => setIsOpen( false ) }
/>
) }
</>
);
};
registerPlugin( 'social-card-preview', {
render: SocialCardPreviewMenuItem,
} );
这里需要注意几点:
- 代码使用
<a href="https://developer.wordpress.org/block-editor/reference-guides/packages/packages-plugins/">@wordpress/plugins</a>中的registerPlugin来注册组件。 PluginPreviewMenuItem的工作方式与其他菜单项类似——给它一个onClick和一些子元素作为标签。- 模态框的可见性通过基本的
useState切换来管理。
构建社交卡片模态框
SocialCardPreview 组件从编辑器存储中读取数据,并在 Modal 内渲染一个模拟的 X 卡片。
import { __ } from '@wordpress/i18n';
import { Modal } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { store as editorStore } from '@wordpress/editor';
import { store as coreStore } from '@wordpress/core-data';
const SocialCardPreview = ( { onClose } ) => {
const { title, excerpt, imageUrl, siteUrl } = useSelect( ( select ) => {
const { getEditedPostAttribute } = select( editorStore );
const featuredMediaId = getEditedPostAttribute( 'featured_media' );
let featuredImageUrl = '';
if ( featuredMediaId ) {
const media = select( coreStore ).getMedia( featuredMediaId );
featuredImageUrl =
media?.media_details?.sizes?.large?.source_url ||
media?.source_url ||
'';
}
return {
title: getEditedPostAttribute( 'title' ) || '',
excerpt: getEditedPostAttribute( 'excerpt' ) || '',
imageUrl: featuredImageUrl,
siteUrl: select( coreStore ).getSite()?.url || '',
};
}, [] );
const domain = siteUrl ? new URL( siteUrl ).hostname : '';
const truncatedExcerpt =
excerpt.length > 200
? excerpt.substring( 0, 200 ) + '…'
: excerpt;
return (
<Modal title={ __( 'X Preview', 'social-card-preview' ) }
onRequestClose={ onClose }
size="medium">
{ /* Card preview markup see below */ }
</Modal>
);
};
以下是详细说明。useSelect 钩子从两个存储中提取所需数据。从 editor 存储中,它检索文章标题、摘要和特色媒体 ID。从 core-data 存储中,它将媒体 ID 解析为实际的图片 URL,并获取站点 URL 以在卡片上显示域名。
对于特色图片,代码首先尝试 large 尺寸,回退到完整的 source_url。摘要被截断为 200 个字符,因为这大约是 X 显示的长度。
由于 useSelect 是响应式的,预览会在您编辑文章时实时更新。更改标题,卡片会立即更新——无需先保存。
卡片预览标记
卡片标记模仿了 X 渲染链接预览的方式。特色图片位于顶部,后面是包含域名、标题和截断摘要的内容区域。由于条件检查 imageUrl &&,仅当存在特色图片时才渲染图片。
每段文本都使用 <span> 而不是标题或段落,因为这是一个视觉模拟——不是语义文档内容。像 social-card-preview__title 这样的类名遵循 BEM(块元素修饰符)命名约定——social-card-preview 是块,__title、__domain、__description 是其中的元素。这可以保持样式的作用域,并避免与编辑器样式冲突。
以下文本放在上面代码示例中的 <Modal></Modal> 标签之间。完整的 <a href="https://github.com/bph/dev-blog-custom-preview/blob/main/src/social-card-preview.js">social-card-preview.js</a> 也可以在 GitHub 上找到:
<div className="social-card-preview">
<div className="social-card-preview__card social-card-preview__card--twitter">
{ imageUrl && (
<img className="social-card-preview__image"
src={ imageUrl }
alt=""
/>
) }
<div className="social-card-preview__content">
<span className="social-card-preview__domain">
{ domain }
</span>
<span className="social-card-preview__title">
{ title }
</span>
<span className="social-card-preview__description">
{ truncatedExcerpt }
</span>
</div>
</div>
</div>
卡片样式
CSS 近似模拟了 X 渲染链接卡片的方式,并遵循上述命名决策。
.social-card-preview__card {
border: 1px solid #dadce0;
border-radius: 16px;
overflow: hidden;
}
.social-card-preview__title {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
卡片使用 16px 的边框半径以匹配 X 的圆角样式。-webkit-line-clamp 规则处理标题和描述的文本截断。
使用 WordPress Playground 测试
您不需要完整的 WordPress 安装来测试此功能。Playground CLI 可以在几秒钟内为您提供一个一次性的 WordPress 实例。确保您有 Node.js 20.18 或更高版本,然后从插件目录运行:
npm install
npm run build
npx @wp-playground/cli@latest server --auto-mount --login
Playground 会检测到插件,自动挂载并登录管理员用户。在浏览器中打开 http://127.0.0.1:9400,创建或编辑一篇文章,您应该会在预览下拉菜单中看到“社交卡片预览”。
进一步探索
社交卡片示例只是使用 PluginPreviewMenuItem 的一种方式。该插槽开启了一系列以前仅 WordPress 核心可用的预览体验。以下是一些其他可以考虑的用例:
- 无障碍检查器——打开一个模态框,扫描文章内容中常见的无障碍问题,例如缺少替代文本或低对比度标题,然后再发布。
- 阅读水平预览——显示可读性分数和内容的简化版本,对于面向广泛或非专业受众的发布者很有用。
- 外部预览服务——使用
href属性而不是onClick,将作者直接发送到预填了文章 URL 的第三方暂存或 QA 环境。 - 电子邮件通讯预览——对于将文章同步到电子邮件列表的插件,显示内容在电子邮件客户端中的渲染预览,包括插件应用的任何模板包装。
每当您的插件需要为作者提供在发布前查看或检查其内容的方式时,PluginPreviewMenuItem 就是添加它的正确位置。