将个人数据导出器添加到您的插件

在 WordPress 4.9.6 中,添加了新工具以更轻松地遵守欧盟通用数据保护条例(简称 GDPR)等法律。添加的工具中有一个个人数据导出工具,它支持在 ZIP 文件中导出给定用户的所有个人数据。除了存储在 WordPress 评论等内容中的个人数据外,插件还可以连接到导出器功能以导出他们收集的个人数据,无论是在 postmeta 之类的东西中,还是在全新的自定义帖子类型 (CPT) 中。

所有导出的“关键”是用户的电子邮件地址——之所以选择它是因为它支持为成熟的注册用户和未注册用户(例如注销的评论者)导出个人数据。

然而,由于组装个人数据导出可能是一个密集的过程,并且可能包含敏感数据,我们不想在没有确认请求的情况下生成它并通过电子邮件将其发送给请求者,因此面向管理员的用户界面会启动所有请求让管理员输入发出请求的用户名或电子邮件地址,然后发送一个链接以单击以确认他们的请求。

确认请求后,管理员可以为用户生成并下载或直接通过电子邮件发送个人数据导出 ZIP 文件,或者在需要时进行导出。在用户收到的 ZIP 文件中,他们会发现一个带有索引 HTML 页面的“迷你网站”,其中包含按组组织的个人数据(例如评论组等)

无论管理员是下载个人数据导出 ZIP 文件还是直接将其发送给请求者,个人数据导出的组装方式都是相同的——并依靠挂钩“导出器”回调来完成收集所有数据以进行导出的肮脏工作. 当管理员单击下载或电子邮件链接时,一个 AJAX 循环开始迭代系统中注册的所有出口商,一次一个。除了核心中内置的导出器之外,插件还可以注册自己的导出器回调。

导出器回调接口设计得尽可能简单。出口商回调接收我们正在使用的电子邮件地址和页面参数。page 参数(从 1 开始)用于避免插件通过尝试一次导出他们收集的所有个人数据而可能导致超时。一个表现良好的插件将限制它试图在每页上删除的数据量(例如 100 个帖子、200 个评论等)

出口商回调回复它拥有的关于该电子邮件地址和页面的任何数据,以及它是否完成。如果导出器回调报告未完成,它将再次调用(在单独的请求中)并将页面参数递增 1。导出器回调应返回用于导出的项目数组。每个项目包含一个组标识符,该组标识符
是该项目所属的组(例如评论、帖子、订单等)、一个可选的组标签(已翻译)、一个项目标识符(例如 comment-133),然后是一个数组包含要为该项目导出的数据的名称、值对。

值得注意的是,该值可以是媒体路径,在这种情况下,指向媒体文件的链接将添加到导出中的索引 HTML 页面。

当所有导出器都被调用完成时,WordPress 首先组装一个“索引”HTML 文档,作为导出报告的核心。如果插件报告 WordPress 或其他插件已添加的项目的附加数据,则该项目的所有数据将一起显示。

导出在服务器上缓存 3 天,然后删除。

一个插件可以注册一个或多个导出器,但大多数插件只需要一个。让我们研究一个假设的插件,它将评论者的位置数据添加到评论中。

首先,我们假设插件已使用 add_comment_meta 来使用 `latitude` 和 `longitude` 的 `meta_key` 添加位置数据

插件需要做的第一件事是创建一个接受电子邮件地址和页面的导出器函数,例如:

/**
 * Export user meta for a user using the supplied email.
 *
 * @param string $email_address   email address to manipulate
 * @param int    $page            pagination
 *
 * @return array
 */
function wporg_export_user_data_by_email( $email_address, $page = 1 ) {
	$number = 500; // Limit us to avoid timing out
	$page   = (int) $page;

	$export_items = array();

	$comments = get_comments(
		array(
			'author_email' => $email_address,
			'number'       => $number,
			'paged'        => $page,
			'order_by'     => 'comment_ID',
			'order'        => 'ASC',
		)
	);

	foreach ( (array) $comments as $comment ) {
		$latitude  = get_comment_meta( $comment->comment_ID, 'latitude', true );
		$longitude = get_comment_meta( $comment->comment_ID, 'longitude', true );

		// Only add location data to the export if it is not empty.
		if ( ! empty( $latitude ) ) {
			// Most item IDs should look like postType-postID. If you don't have a post, comment or other ID to work with,
			// use a unique value to avoid having this item's export combined in the final report with other items
			// of the same id.
			$item_id = "comment-{$comment->comment_ID}";

			// Core group IDs include 'comments', 'posts', etc. But you can add your own group IDs as needed
			$group_id = 'comments';

			// Optional group label. Core provides these for core groups. If you define your own group, the first
			// exporter to include a label will be used as the group label in the final exported report.
			$group_label = __( 'Comments', 'text-domain' );

			// Plugins can add as many items in the item data array as they want.
			$data = array(
				array(
					'name'  => __( 'Commenter Latitude', 'text-domain' ),
					'value' => $latitude,
				),
				array(
					'name'  => __( 'Commenter Longitude', 'text-domain' ),
					'value' => $longitude,
				),
			);

			$export_items[] = array(
				'group_id'    => $group_id,
				'group_label' => $group_label,
				'item_id'     => $item_id,
				'data'        => $data,
			);
		}
	}

	// Tell core if we have more comments to work on still.
	$done = count( $comments ) > $number;
	return array(
		'data' => $export_items,
		'done' => $done,
	);
}

插件需要做的下一件事是通过使用 wp_privacy_personal_data_exporters 过滤器过滤导出器数组来注册回调。

注册时,您为导出提供一个友好的名称(以帮助调试——这个友好的名称此时不会向任何人显示)和回调,例如

/**
 * Registers all data exporters.
 *
 * @param array $exporters
 *
 * @return mixed
 */
function wporg_register_user_data_exporters( $exporters ) {
	$exporters['my-plugin-slug'] = array(
		'exporter_friendly_name' => __( 'Comment Location Plugin', 'text-domain' ),
		'callback'               => 'my_plugin_exporter',
	);
	return $exporters;
}

add_filter( 'wp_privacy_personal_data_exporters', 'wporg_register_user_data_exporters' );

这就是它的全部!您的插件现在将为导出提供数据!