- 前端
- CMS
【免费下载链接】wp-calypso
The JavaScript and API powered WordPress.com
SiteIndicator 是 wp-calypso(WordPress.com 的 JavaScript 与 API 驱动前端)中用于在站点条目旁显示圆形状态徽章的 React 组件,集中呈现"有待更新"、"Jetpack 连接异常"等运维关键信息。本文基于 client/my-sites/site-indicator/README.md,结合组件源码、样式与测试用例,完整讲解其 Props 契约、显示判定逻辑、Redux 数据链与视觉交互,帮助你直接复用或二次开发该组件。
组件概述:一个徽章承载的站点健康情报
SiteIndicator 的作用是在站点列表 / 站点管理界面中,于站点名称旁渲染一个圆形徽章(badge),用来直观提示用户以下几类信息:
- 该站点有可用的更新(WordPress 核心、插件或主题);
- 该站点与 Jetpack 存在连接问题(Jetpack 无法与站点通信);
- 该站点是否为Jetpack 站点(决定徽章是否显示);
- 升级即将到期等状态(源码注释表明这是为 WP.com 站点预留的扩展方向)。
从 index.jsx 的showIndicator()逻辑可以确认一个关键事实:当前版本只对 Jetpack 站点显示徽章,且需要当前用户拥有站点管理权限。代码中的注释直白地说明了这一设计取舍:
Until WP.com sites have indicators (upgrades expiring, etc) we only show them for Jetpack sites
即"在 WP.com 站点具备指示器(升级到期等)之前,我们只对 Jetpack 站点显示它们"。
快速上手:安装与基础用法
该组件位于client/my-sites/site-indicator目录下,无需单独安装,通过 calypso 的模块别名直接引入即可:
import SiteIndicator from 'calypso/my-sites/site-indicator'; function render() { return <SiteIndicator site={ siteObject } />; }site是必传的站点对象,通常来自getSelectedSite()、getSite( state, siteId )等站点 selector。传入site后,组件会自行从 Redux 派生所需的全部状态(连接状态、更新数据、用户权限),并渲染对应的徽章,调用方无需关心内部数据获取逻辑。
在正式接入前,组件还依赖样式文件与国际化,这些都已内置在组件模块中:
- 样式:style.scss
- 国际化:组件通过
localize高阶组件注入translate函数,文案均已接入 i18n 流程。
Props 契约:完整参数说明
组件对外暴露两个公开 Props,均在 README 中以表格形式定义,完整继承如下:
site
| 项目 | 值 |
|---|---|
| 类型 | Object |
| 必填 | 是 |
站点对象(Site object),组件据此识别站点 ID、更新数据、权限与 Jetpack 属性。从 index.jsx 的 propTypes 可看到,site是唯一的公开入参,其余状态全部由 Reduxconnect注入。
onSelect
| 项目 | 值 |
|---|---|
| 类型 | Function |
| 必填 | 否 |
可选的回调函数。需要说明的是:从当前 index.jsx 的实现看,该属性在组件渲染逻辑中尚未被消费,属于预留接口——README 将其定义为可选参数,表明它面向未来交互扩展(如点击徽章后触发站点选中行为)。接入时请按可选 Props 对待,不传不影响基础功能。
此外,组件源码中还定义了由 Redux 注入的内部 Props(调用方无需也不能直接传入):
| 内部 Prop | 来源 | 含义 |
|---|---|---|
siteIsJetpack | isJetpackSite | 站点是否为 Jetpack 站点 |
siteIsConnected | isJetpackConnectionUnhealthy取反 | Jetpack 连接是否健康 |
siteIsAutomatedTransfer | isSiteAutomatedTransfer | 站点是否为 Atomic(自动迁移)站点 |
siteUpdates | getUpdatesBySiteId | 站点的更新统计对象 |
userCanManage | canCurrentUser( ..., 'manage_options' ) | 当前用户是否可管理该站点 |
显示判定逻辑:什么情况下渲染徽章
徽章是否出现,由 showIndicator() 严格把关,其判定条件可概括为一条复合表达式:
userCanManage && siteIsJetpack && ( ( ! siteIsAutomatedTransfer && hasUpdate() ) || hasError() )逐一拆解:
userCanManage:当前用户必须拥有该站点的manage_options能力,权限通过 canCurrentUser 从state.currentUser.capabilities[ siteId ]中读取;siteIsJetpack:站点必须是 Jetpack 站点,由isJetpackSite判定;- 更新分支:
! siteIsAutomatedTransfer && hasUpdate()——Atomic(自动迁移)站点不显示更新徽章,因为其更新由平台托管,无需用户手动处理;普通 Jetpack 站点则只要存在更新即显示; - 错误分支:
hasError()即siteIsConnected === false,代表 Jetpack 连接已确认异常,此时无论是否 Atomic 都会显示错误徽章。
两个状态判定函数位于 index.jsx:
hasUpdate() { const { siteUpdates } = this.props; return siteUpdates && ! this.hasError() && siteUpdates.total > 0; } hasError() { return this.props.siteIsConnected === false; }注意hasUpdate()内部先排除了hasError()的情况——当连接异常与更新同时存在时,优先展示错误状态,避免信息混淆。该优先级在 getText() / getIcon() 中同样体现:更新优先,错误其次,否则返回null。
徽章内容:更新提示与错误提示的完整消息矩阵
点击展开徽章后,getText()会根据状态渲染两种消息体。
更新可用(updatesAvailable())
updatesAvailable() 依据siteUpdates各分项与总数total的比对关系,输出逐级细分的提示文案,并附带对应的跳转链接:
| 条件 | 文案 | 链接目标 |
|---|---|---|
wordpress === total且canUpdateFiles | "A newer version of WordPress is available. Update to %(version)s" | 站点的/activity-log/{slug}活动日志页 |
plugins === total且canUpdateFiles | "There is a plugin update available."(复数形式按count自动切换) | 同上 |
themes === total且canUpdateFiles | "There is a theme update available."(复数形式同理) | 同上 |
themes + plugins + wordpress === total且canUpdateFiles | "There are updates available." | 同上 |
| 其余情况(含翻译等无法自动更新的部分) | "There is an update available." / "There are updates available." | 站点 wp-admin 的update-core.php |
最后一层分支很有工程价值:当更新项包含翻译(translations,Jetpack 无法代管)时,组件会把用户引导到 WordPress 后台的update-core.php,让用户自己完成剩余更新。目标 URL 通过site.options.admin_url + 'update-core.php'拼装,使用ExternalLink组件新窗口打开,该细节定义在 index.jsx。
同时,点击更新链接前会调用resetWindowState()(index.jsx),将页面滚动回顶部并收起徽章,保证跳转后页面状态干净。
连接异常(errorAccessing())
errorAccessing() 处理 Jetpack 无法与站点通信的场景:
- 若
site存在,展示文案"Jetpack can't communicate with your site."并附带一个"Learn how to fix"按钮,新窗口打开 Jetpack 官方重连指南(https://jetpack.com/support/reconnecting-reinstalling-jetpack/); - 若
site不存在(未定义),退化为通用文案"This site cannot be accessed."。
错误场景还埋入了两条埋点(Tracks):
- 视图事件
calypso_jetpack_connection_health_issue_sidebar_view(通过TrackComponentView在渲染时上报); - 点击事件
calypso_jetpack_connection_health_issue_sidebar_click(点击"Learn how to fix"时上报,带is_atomic属性)。
这些事件定义在 handleJetpackConnectionHealthSidebarLinkClick 中,用于观测连接健康问题的暴露与转化情况。
交互与视觉:圆形徽章、展开消息与状态配色
图标与按钮
徽章默认是一个 26×26 的圆形按钮,由 renderIndicator() 渲染:
- 状态图标通过
Gridicon输出:有更新时显示sync(同步/刷新)图标,有错误时显示notice(警告)图标,尺寸 16px; - 未展开时按钮包裹在
Animate type="appear"中,以淡入动画出现; - 点击按钮通过
toggleExpand切换expand状态,展开后按钮切换为cross(关闭)图标并叠加在消息右上角。
状态样式
style.scss 通过父容器的修饰类控制视觉语义:
| 修饰类 | 触发条件 | 背景色 | 场景 |
|---|---|---|---|
is-action | 恒存在 | — | 使按钮可点击(cursor: pointer) |
is-update | hasUpdate() | --color-warning(警示黄) | 有待更新 |
is-error | hasError() | --color-error(错误红) | 连接异常 |
展开后的消息层.site-indicator__message会覆盖整个站点条目区域(position: absolute铺满父容器),背景色跟随is-update/is-error,内部文案与链接使用反色(--color-text-inverted)保证对比度。组件还考虑了可访问性:.accessible-focus下聚焦按钮会显示 1px 虚线描边(style.scss)。
数据层:Redux 连接与 Selector 调用链
组件的数据完全来自 Redux,connect映射定义在 index.jsx 底部。其数据流如下:
1. 更新数据
siteUpdates来自 getUpdatesBySiteId,该 selector 本质上是读取原始站点对象上的updates字段:
export default function getUpdatesBySiteId( state, siteId ) { const site = getRawSite( state, siteId ); return site?.updates ?? null; }updates对象形如{ total, wordpress, plugins, themes },total即更新总数,也是hasUpdate()的判断依据。
2. 连接健康
siteIsConnected并非直接读取某个布尔标志,而是通过isJetpackConnectionUnhealthy的取反得出:is-jetpack-connection-unhealthy.js 要求同时满足"报告了连接问题"(jetpack_connection_problem === true)且"存在错误信息"(error为真值)才判定为不健康;其底层数据由 get-jetpack-connection-health.js 从state.jetpackConnectionHealth[ siteId ].connectionHealth读取。
连接状态的获取则由数据查询组件 QuerySiteConnectionStatus 触发——它在挂载时 dispatchrequestConnectionStatus( siteId )拉取最新连接状态,且内部通过isRequestingSiteConnectionStatus防止重复请求(index.jsx 中仅在siteIsJetpack时才渲染该查询组件)。
3. 站点属性与权限
isJetpackSite:判定站点是否连接 Jetpack;isSiteAutomatedTransfer:判定是否 Atomic 站点(用于抑制更新徽章);canCurrentUser( state, siteId, 'manage_options' ):从state.currentUser.capabilities查表得出当前用户权限(can-current-user.js),无权限数据时返回null(视为无权)。
测试验证:行为规格即文档
组件行为由 test/index.js 中的 Jest + Testing Library 用例锁定,测试通过redux-mock-store与直接传入内部 Props 的方式隔离了 Redux 依赖,共覆盖四个关键场景:
- 非 Atomic 站点有更新 → 显示
is-update徽章:传入userCanManage: true, siteIsJetpack: true, siteIsConnected: true, siteIsAutomatedTransfer: false, siteUpdates: { total: 1 },断言is-update类存在、is-error类不存在; - Atomic 站点有更新 → 不显示更新徽章:同样条件但
siteIsAutomatedTransfer: true,断言两类徽章均不渲染,直接验证了showIndicator()中的 Atomic 抑制分支; - Jetpack 连接异常 → 显示
is-error徽章:siteIsConnected: false时断言is-error存在、is-update不存在; - 点击展开交互:默认不渲染消息层(
site-indicator-message不存在),fireEvent.click点击site-indicator-button后消息层出现。
这些用例同时充当了组件的行为规格说明——任何改动若破坏上述判定逻辑,都会在测试中被捕获。测试对QuerySiteConnectionStatus做了 mock,因此用例聚焦于组件自身的渲染与交互逻辑,而非网络数据层。
小结
SiteIndicator 虽是一个不足 300 行的组件,却完整演示了 wp-calypso 中"状态类 UI 组件"的标准工程范式:
- 公共 API 极简:仅暴露
site与onSelect两个 Props,所有派生状态由 Reduxconnect内部注入; - 判定逻辑集中:
showIndicator()一条表达式收敛了权限、站点类型、Atomic 与更新/错误状态的全部组合; - 状态可观测:通过
is-update/is-error修饰类驱动视觉,配合sync/notice图标完成语义化表达; - 数据可追踪:更新与连接健康均来自明确的 selector 链,并借助
QuerySiteConnectionStatus按需拉取; - 行为有保障:测试用例覆盖 Atomic 抑制、错误优先与展开交互等关键分支。
如需在自有功能中复用,只需传入正确的site对象并确保站点已通过 Jetpack 连接即可;若要扩展"升级到期"等新指示类型,可参照showIndicator()的判定结构与getIcon()/getText()的分支模式继续叠加。
- 前端
- CMS
【免费下载链接】wp-calypso
The JavaScript and API powered WordPress.com
相关推荐
wp-calypso NoSitesMessage 组件全解:无站点用户的引导式空状态实现
wp calypso NoSitesMessage 组件全解:无站点用户的引导式空状态实现 NoSitesMessage 是 wp calypso(WordPr
前端CMSwp-calypso 数据查询组件实战:QuerySiteConnectionStatus 获取 Jetpack 站点连接状态
wp calypso 数据查询组件实战:QuerySiteConnectionStatus 获取 Jetpack 站点连接状态 <QuerySiteConnec
前端CMSUpsellSwitch 组件全解析:用 wp-calypso 实现站点状态驱动的付费升级兜底
UpsellSwitch 组件全解析:用 wp calypso 实现站点状态驱动的付费升级兜底 导读 <UpsellSwitch / 是 wp calypso
前端CMS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考