news 2026/10/9 1:43:33

wp-calypso 隐私工具集(@automattic/privacy-toolset):统一 Cookie 横幅与「不出售数据」弹窗的 React 组件库实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
wp-calypso 隐私工具集(@automattic/privacy-toolset):统一 Cookie 横幅与「不出售数据」弹窗的 React 组件库实战指南
  • 前端
  • CMS

【免费下载链接】wp-calypso

The JavaScript and API powered WordPress.com

项目地址:https://gitcode.com/gh_mirrors/wp/wp-calypso
点击查看免费下载

导读

本指南围绕 wp-calypso 仓库中的@automattic/privacy-toolset包展开,它是一组以 React 组件形态封装的隐私机制工具库,用于在 Automattic 各产品(如 WordPress.com、Jetpack 生态)中统一 Cookie 同意授权与「不出售/不共享我的数据」偏好设置的交互体验。读完本文,你将掌握该包的安装与样式接入方式、CookieBanner(简单同意 + 自定义分桶同意两级视图)与DoNotSellDialog(可选退出弹窗)的完整 Props 契约与数据建模、从源码到测试的底层实现细节,以及如何在 wp-calypso monorepo 中运行其单元测试与 Storybook 开发环境。

包概览:一套组件统一隐私机制

packages/privacy-toolset/是 wp-calypso monorepo 中发布到 npm 的独立包,当前版本 2.2.0(见 package.json)。包名与描述为 "Privacy tools and components for Automattic solutions.",定位非常明确:把隐私相关交互沉淀为可复用、可配置、可主题化的 React 组件,避免各产品各自为政地重复实现 Cookie 弹窗与数据出售偏好设置。

从入口文件 src/index.ts 可以看到,包对外只导出两类能力,恰好对应两种最核心的隐私交互场景:

  • CookieBanner(类型CookieBannerProps):Cookie 同意授权横幅;
  • DoNotSellDialog(类型DoNotSellDialogProps):面向「Do Not Sell / Do Not Share」合规要求的偏好设置弹窗。

包的工程形态:main指向dist/cjs/index.js,module指向dist/esm/index.js,同时通过exports字段为 Calypso 内部提供calypso:src(直接引用src/index.ts源码)入口,其余消费方则按标准import/require消费构建产物。sideEffects声明了*.css与*.scss,说明样式由组件自行引入。

安装与样式接入

1. 安装工具集

yarn add @automattic/privacy-toolset

2. 引入wp-components样式表

许多组件依赖样式才能正确渲染。接入方式取决于宿主环境:

  • WordPress 插件内:将wp-components样式表声明为插件样式表的依赖项,例如在wp_enqueue_style()调用时通过 dependencies 参数指定,这样 WordPress 会保证组件样式先于插件样式加载;
  • 非 WordPress 项目:直接链接node_modules/@wordpress/components/build-style/style.css文件。

这条要求的根源在于:包内部大量复用了@wordpress/components的 UI 原语(如FormToggle开关),这些原语的样式正是从wp-components样式表获得。从 package.json 的dependencies可以看到@wordpress/components: ^37.0.0,同时依赖clsx、react-modal与tslib。

3. 环境约束

包的peerDependencies声明了react: ^18.3.1 || ^19.0.0与react-dom: ^18.3.1 || ^19.0.0,即要求宿主项目提供 React 18.3+ 或 19 运行时,这是使用前需要核对的重要前提。

CookieBanner:两级视图的同意授权横幅

最小用法

import { CookieBanner } from '@automattic/privacy-toolset'; const Component = () => ( <> <CookieBanner content={ contentDefinition } onAccept={ fn } /> </> );

CookieBanner只有两个 Props:

Props类型说明
content{ simpleConsent: SimpleConsentContent; customizedConsent: CustomizedConsentContent }两级视图的文案与分类定义
onAccept( buckets: Buckets ) => void用户在任意一级视图做出决定后触发的回调,参数为最终同意的分桶结果

从源码看两级视图切换机制

组件内部通过useState维护一个ConsentViewType枚举(Simple/Customized),初始为简单视图。用户点击「Customize」时切换到自定义视图(见 index.tsx):

const handleAcceptAll = useCallback( () => { onAccept( allBucketsTrue ); }, [ onAccept ] ); const handleDeclineNonEssentials = useCallback( () => { onAccept( essentialOnly ); }, [ onAccept ] );
  • 点击Accept All→onAccept( allBucketsTrue );
  • 点击Decline Non-Essential(可选按钮)→onAccept( essentialOnly );
  • 点击Customize→ 切换视图,在自定义视图中点击「Accept Selection」→onAccept( 当前分桶状态 )。

数据模型:Buckets 分桶

三个预设分桶常量定义在 consts.ts:

export const allBucketsTrue: Buckets = { essential: true, analytics: true, advertising: true, }; export const essentialOnly: Buckets = { essential: true, analytics: false, advertising: false, }; export const defaultBuckets: Buckets = { essential: true, analytics: true, advertising: false, };

Buckets由三个布尔字段组成:essential(必要)、analytics(分析)、advertising(广告)。值得注意的设计细节:默认分桶状态(defaultBuckets)是「必要 + 分析开启、广告关闭」——即既比"全接受"克制,又比"仅必要"激进,这是自定义视图的初始态。

简单视图(SimpleConsent)的文案契约

export type SimpleConsentContent = { description: LongText; // 长文案,支持 ReactNode customizeButton: ShortText; // 「Customize」按钮文案 acceptAllButton: ShortText; // 「Accept All」按钮文案 declineNonEssentialButton?: ShortText; // 可选:是否渲染「Decline Non-Essential」按钮 };

从 simple-consent.tsx 源码可确认:declineNonEssentialButton是否传入会直接影响 DOM 结构——按钮区会追加cookie-banner__simple-options-non-essential类,并额外渲染一个拒绝非必要 Cookie 的按钮。因此,若合规文案中不需要"仅拒绝非必要"的快捷入口,省略该字段即可自动隐藏按钮。

自定义视图(CustomizedConsent)的文案契约

export type CustomizedConsentContent = { description: LongText; // 引导文案 categories: Record< keyof Buckets, GranularConsentContent >; // 三个分桶各自的名称与描述 acceptSelectionButton: ShortText; // 「Accept Selection」按钮文案 }; type GranularConsentContent = { name: ShortText; // 分类名,如 "Required" / "Analytics" / "Advertising" description: LongText; };

自定义视图的初始开关状态取自defaultBuckets,用户切换某个分桶后通过handleChangeBucket更新状态(见 customized-consent.tsx)。其中essential分桶的开关以disabled状态渲染——必要型 Cookie 不可关闭,这是隐私合规的常见要求,也保证了Buckets.essential恒为 true 的不变量。

每个分桶的开关复用@wordpress/components的FormToggle,并带有aria-labelledby与data-testid(格式为`${name}-bucket-toggle`),后者方便测试按analytics-bucket-toggle等定位(见 granular-consent.tsx)。

content 参数的完整示例

README 明确指出:content参数的详细结构以 cookie-banner.stories.tsx 为准。其Defaultstory 给出了完整可运行的结构(含 "Accept all"、"Customize" 两级文案与三个分类),Declinestory 则演示了追加declineNonEssentialButton: 'Decline Non-Essential Cookies'的三按钮形态。实际接入时只需将 story 中的占位文案替换为真实的多语言文案即可。

DoNotSellDialog:「不出售/不共享我的数据」偏好弹窗

第二个组件面向 CCPA 等法规中的 "Do Not Sell or Share My Data" 场景,底层使用react-modal实现,对外暴露可控状态(index.tsx):

export type DoNotSellDialogProps = { content: { title: string; // 弹窗标题 longDescription: React.ReactNode; // 长说明文案 toggleLabel: string; // 开关标签 closeButton: string; // 关闭按钮文案 }; isOpen: boolean; // 受控:是否打开 onClose: () => void; // 关闭回调 isActive?: boolean; // 当前偏好是否生效 onToggleActive: ( isActive: boolean ) => void; // 切换偏好 modalProps?: Omit< ModalProps, 'className' | 'overlayClassName' | 'aria' | 'onRequestClose' | 'isOpen' | 'children' >; // 透传 react-modal 其余选项 };

源码细节说明:

  • 组件是完全受控的:isOpen/isActive由父组件传入,交互结果通过onClose/onToggleActive回传,方便业务侧与持久化层(如用户偏好存储)对接;
  • 无障碍方面,react-modal的aria配置了modal: true、labelledby: 'do-not-sell-title'、describedby: 'do-not-sell-description',标题与正文分别挂上对应 id;
  • modalProps采用 Omit 类型,锁定内部必须控制的 Modal 属性,只允许透传如appElement、shouldCloseOnOverlayClick等其余配置;
  • 偏好开关同样是@wordpress/components的FormToggle,配合do-not-sell__preference标签渲染。

其 Storybook 示例(do-not-sell-dialog.stories.tsx)演示了标准的受控用法:父组件用useState持有isActive,将setActive作为onToggleActive传入,并以isOpen固定为 true 展示弹窗内容。

在 wp-calypso monorepo 中开发与测试

该包在 Calypso monorepo 内开发,仓库根目录执行yarn即可拉取全部devDependencies(含@automattic/calypso-build、@automattic/calypso-storybook、@testing-library/react、storybook、typescript等)。

单元测试

yarn run test-packages -- packages/privacy-toolset yarn run test-packages:watch -- packages/privacy-toolset

测试源码位于组件同级的test/目录:cookie-banner与do-not-sell-dialog各有一套基于@testing-library的用例及快照(__snapshots__/*.tsx.snap)。快照文件记录了渲染出的 DOM 结构,可作为组件输出稳定性的回归依据;测试文件(如 cookie-banner.tsx)可用来验证"点击 Accept All 触发allBucketsTrue回调""essential 开关 disabled"等行为契约。

Storybook 开发环境

yarn workspace @automattic/privacy-toolset run storybook:start

该命令对应 package.json 中的storybook dev -p 26840,会以26840 端口启动本地 Storybook。两个组件均有 story 文件:Cookie Banner包含Default/Decline两个 story,Do Not Sell Dialog包含Defaultstory,是调试文案、验证布局与演示组件行为的最直接入口。

构建与发布

  • yarn run build:通过tsc --build ./tsconfig.json ./tsconfig-cjs.json生成 ESM/CJS/类型声明,并执行copy-assets复制样式资源;
  • yarn run prepack:发布前先clean(清理 dist)再build;
  • yarn run watch:TS 增量编译,便于边改边看。

总结:在自身产品中落地的要点

  1. 两条集成前提缺一不可:yarn add @automattic/privacy-toolset后,务必按宿主环境接入wp-components样式表(WordPress 插件走wp_enqueue_style依赖声明,其他项目直接 linkbuild-style/style.css),并确保 React 版本满足^18.3.1 || ^19.0.0;
  2. CookieBanner 的接入成本集中在 content 上:按simpleConsent/customizedConsent两级结构补齐文案与三分类描述,onAccept中收到的Buckets(essential/analytics/advertising)即可映射到你的 Cookie 存储与埋点开关;
  3. DoNotSellDialog 走完全受控模式:由业务侧管理isOpen/isActive,通过onToggleActive持久化用户偏好,modalProps可透传react-modal的补充配置;
  4. 迭代与验证闭环:单测(test-packages -- packages/privacy-toolset)与 Storybook(端口 26840)覆盖了从行为契约到视觉呈现的完整开发回路,是所有接入场景的可靠参照。
  • 前端
  • CMS

【免费下载链接】wp-calypso

The JavaScript and API powered WordPress.com

项目地址:https://gitcode.com/gh_mirrors/wp/wp-calypso
点击查看免费下载
上一篇:告别print调试:IceCream如何提升机器学习项目效率
下一篇:docker-selenium Edge 150 版本发布:镜像 Tag 命名约定与浏览器版本锁定实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/9 1:41:55

AI编程第四天:Claude Code本地部署与Landing page实战指南

1. 从零上手&#xff1a;AI编程第四天到底在折腾什么很多人学AI编程&#xff0c;前三天都在跟聊天窗口较劲——问它写个函数、改个bug、解释一段报错。到了第四天&#xff0c;你会发现光在网页里复制粘贴已经不够用了&#xff0c;真正想让它帮你干活&#xff0c;得把它请进你的…

作者头像 李华
网站建设 2026/10/9 1:41:32

养成记录好习惯(1)——nfs离线包,适用于Ubuntu22.4(amd64架构)

今天要在公司内网机器上连接nfs&#xff0c;在网上找了很多的离线包都会出现依赖相关问题&#xff0c;今天更新一下nfs的离线包https://gitee.com/yzw139831/nfs_server。 操作步骤&#xff1a; 1.将nfs_server.zip下载之后拷贝至离线机器&#xff0c;并解压。 2.上传至Ubun…

作者头像 李华
网站建设 2026/10/9 1:40:06

dinero.js 中 halfAwayFromZero:远离零的四舍五入模式全解析

金融科技 【免费下载链接】dinero.js Create, calculate, and format money in JavaScript and TypeScript 项目地址&#xff1a; https://gitcode.com/gh_mirrors/di/dinero.js 点击查看 免费下载 导读 本文聚焦 dinero.js 中提供的一种关键舍入模式 —— halfAwayFromZero&…

作者头像 李华
网站建设 2026/10/9 1:39:37

EverSpark Forge:面向多AI协作的模块化工作流编排系统

1. EverSpark Forge 不是又一个 WebUI&#xff0c;而是一套可插拔的 AI 工作流操作系统你有没有试过把 Stable Diffusion、Ollama、RVC 和 Whisper 全部塞进同一个 WebUI 里&#xff0c;结果发现&#xff1a;模型加载冲突、显存爆表、保存工作流时 JSON 崩溃、换台机器就跑不起…

作者头像 李华