woocommerce-subscriptions/includes/core/privacy/class-wcs-privacy.php

376 lines
16 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Privacy/GDPR related functionality which ties into WordPress functionality.
*
* @author Prospress
* @category Class
* @package WooCommerce Subscriptions\Privacy
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class WCS_Privacy extends WC_Abstract_Privacy {
/**
* Background updater to process personal data removal from subscriptions and related orders.
*
* @var WCS_Privacy_Background_Updater
*/
protected static $background_process;
/**
* A flag which is set when WC is doing a user inactivity cleanup.
* Used to exclude subscription customers from the inactive user query.
*
* @var bool
*/
protected static $doing_user_inactivity_query = false;
/**
* WCS_Privacy constructor.
*/
public function __construct() {
if ( ! self::$background_process ) {
self::$background_process = new WCS_Privacy_Background_Updater();
}
parent::__construct();
add_action( 'init', array( $this, 'register_erasers_exporters' ) );
}
/**
* Register erasers and exporters.
*/
public function register_erasers_exporters() {
$this->name = __( 'WooCommerce Subscriptions', 'woocommerce-subscriptions' );
// Add our exporters and erasers.
$this->add_exporter( 'woocommerce-subscriptions-data', __( 'Subscriptions Data', 'woocommerce-subscriptions' ), array( 'WCS_Privacy_Exporters', 'subscription_data_exporter' ) );
$this->add_eraser( 'woocommerce-subscriptions-data', __( 'Subscriptions Data', 'woocommerce-subscriptions' ), array( 'WCS_Privacy_Erasers', 'subscription_data_eraser' ) );
}
/**
* Attach callbacks.
*/
public function init() {
parent::init();
self::$background_process->init();
add_filter( 'woocommerce_subscription_bulk_actions', array( __CLASS__, 'add_privacy_bulk_action' ) );
add_action( 'load-edit.php', array( __CLASS__, 'process_bulk_action' ) );
add_action( 'woocommerce_remove_subscription_personal_data', array( 'WCS_Privacy_Erasers', 'remove_subscription_personal_data' ) );
add_action( 'admin_notices', array( __CLASS__, 'bulk_admin_notices' ) );
add_filter( 'woocommerce_account_settings', array( __CLASS__, 'add_caveat_to_order_data_retention_settings' ) );
add_filter( 'woocommerce_account_settings', array( __CLASS__, 'add_subscription_data_retention_settings' ) );
// Attach callbacks to prevent subscription related orders being trashed or anonymized
add_filter( 'woocommerce_trash_pending_orders_query_args', array( __CLASS__, 'remove_subscription_orders_from_anonymization_query' ) );
add_filter( 'woocommerce_trash_failed_orders_query_args', array( __CLASS__, 'remove_subscription_orders_from_anonymization_query' ) );
add_filter( 'woocommerce_trash_cancelled_orders_query_args', array( __CLASS__, 'remove_subscription_orders_from_anonymization_query' ) );
add_filter( 'woocommerce_anonymize_completed_orders_query_args', array( __CLASS__, 'remove_subscription_orders_from_anonymization_query' ) );
add_action( 'woocommerce_cleanup_personal_data', array( $this, 'queue_cleanup_personal_data' ) );
// Hook in late so there is less opportunity for our flag to affect other user queries called on this hook.
add_filter( 'woocommerce_delete_inactive_account_roles', array( __CLASS__, 'flag_subscription_user_exclusion_from_query' ), 1000 );
add_action( 'pre_get_users', array( __CLASS__, 'maybe_exclude_subscription_customers' ) );
add_filter( 'woocommerce_account_settings', array( __CLASS__, 'add_inactive_user_retention_note' ) );
add_action( 'handle_bulk_actions-woocommerce_page_wc-orders--shop_subscription', [ __CLASS__, 'handle_privacy_bulk_actions' ], 10, 3 );
}
/**
* Spawn events for subscription cleanup.
*
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
*/
public function queue_cleanup_personal_data() {
self::$background_process->schedule_ended_subscription_anonymization();
}
/**
* Add privacy policy content for the privacy policy page.
*
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
*/
public function get_privacy_message() {
return '' .
'<p>' . __( 'By using WooCommerce Subscriptions, you may be storing personal data and depending on which third-party payment processors youre using to take subscription payments, you may be sharing personal data with external sources.', 'woocommerce-subscriptions' ) . '</p>' .
// translators: placeholders are opening and closing link tags, linking to additional privacy policy documentation.
'<h3>' . __( 'What we collect and store', 'woocommerce-subscriptions' ) . '</h3>' .
'<p>' . __( 'For the purposes of processing recurring subscription payments, we store the customer\'s name, billing address, shipping address, email address, phone number and credit card/payment details.', 'woocommerce-subscriptions' ) . '</p>' .
'<h3>' . __( 'What we share with others', 'woocommerce-subscriptions' ) . '</h3>' .
'<p>' . __( 'What personal information your store shares with external sources depends on which third-party payment processor plugins you are using to collect subscription payments. We recommend that you consult with their privacy policies to inform this section of your privacy policy.', 'woocommerce-subscriptions' ) . '</p>' .
// translators: placeholders are opening and closing link tags, linking to additional privacy policy documentation.
'<p>' . sprintf( __( 'If you are using PayPal Standard or PayPal Reference transactions please see the %1$sPayPal Privacy Policy%2$s for more details.', 'woocommerce-subscriptions' ), '<a href="https://www.paypal.com/us/webapps/mpp/ua/privacy-full">', '</a>' ) . '</p>';
}
/**
* Adds the option to remove personal data from subscription via a bulk action.
*
* @since 5.2.0
*
* @param array $bulk_actions Subscription bulk actions.
*
* @return array
*/
public static function add_privacy_bulk_action( $bulk_actions ) {
$bulk_actions['wcs_remove_personal_data'] = __( 'Cancel and remove personal data', 'woocommerce-subscriptions' );
return $bulk_actions;
}
/**
* Handles the Remove Personal Data bulk action requests for Subscriptions.
*
* @param string $redirect_url The default URL to redirect to after handling the bulk action request.
* @param string $action The action to take against the list of subscriptions.
* @param array $subscription_ids The list of subscription to run the action against.
*/
public static function handle_privacy_bulk_actions( $redirect_url, $action, $subscription_ids ) {
if ( 'wcs_remove_personal_data' !== $action ) {
return $redirect_url;
}
$changed = 0;
$sendback_args = [
'bulk_action' => 'wcs_remove_personal_data',
'ids' => join( ',', $subscription_ids ),
'error_count' => 0,
];
foreach ( $subscription_ids as $subscription_id ) {
$subscription = wcs_get_subscription( $subscription_id );
if ( is_a( $subscription, 'WC_Subscription' ) ) {
do_action( 'woocommerce_remove_subscription_personal_data', $subscription );
$changed++;
}
}
$sendback_args['changed'] = $changed;
$sendback = add_query_arg( $sendback_args, $redirect_url );
return esc_url_raw( $sendback );
}
/**
* Process the request to delete personal data from subscriptions via admin bulk action.
*
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
*/
public static function process_bulk_action() {
/**
* We only want to deal with shop_subscription bulk actions.
*
* Note: The nonce checks are ignored below as we are validating the request before returning.
*/
if ( ! isset( $_REQUEST['post_type'] ) || 'shop_subscription' !== $_REQUEST['post_type'] || ! isset( $_REQUEST['post'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return;
}
check_admin_referer( 'bulk-posts' );
$action = '';
if ( isset( $_REQUEST['action'] ) && -1 !== $_REQUEST['action'] ) {
$action = wc_clean( wp_unslash( $_REQUEST['action'] ) );
} elseif ( isset( $_REQUEST['action2'] ) && -1 !== $_REQUEST['action2'] ) {
$action = wc_clean( wp_unslash( $_REQUEST['action2'] ) );
}
$subscription_ids = array_map( 'absint', (array) $_REQUEST['post'] );
$base_redirect_url = wp_get_referer() ? wp_get_referer() : '';
$redirect_url = self::handle_privacy_bulk_actions( $base_redirect_url, $action, $subscription_ids );
wp_safe_redirect( $redirect_url );
exit();
}
/**
* Add admin notice after processing personal data removal bulk action.
*
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
*/
public static function bulk_admin_notices() {
// Nonce verification is not required here because we're just displaying an admin notice after a verified request was made.
if ( ! isset( $_REQUEST['bulk_action'] ) || ! 'wcs_remove_personal_data' === wc_clean( wp_unslash( $_REQUEST['bulk_action'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return;
}
if ( wcs_is_custom_order_tables_usage_enabled() ) {
$current_screen = get_current_screen();
$is_subscription_list_table = $current_screen && wcs_get_page_screen_id( 'shop_subscription' ) === $current_screen->id;
} else {
global $post_type, $pagenow;
$is_subscription_list_table = 'edit.php' === $pagenow && 'shop_subscription' === $post_type;
}
// Bail out if not on shop subscription list page.
if ( ! $is_subscription_list_table ) {
return;
}
$changed = isset( $_REQUEST['changed'] ) ? absint( $_REQUEST['changed'] ) : 0;
// translators: %d: number of subscriptions affected.
$message = sprintf( _n( 'Removed personal data from %d subscription.', 'Removed personal data from %d subscriptions.', $changed, 'woocommerce-subscriptions' ), number_format_i18n( $changed ) );
echo '<div class="updated"><p>' . esc_html( $message ) . '</p></div>';
}
/**
* Add a note to WC Personal Data Retention settings explaining that subscription orders aren't affected.
*
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
* @param array $settings WooCommerce Account and Privacy settings.
* @return array Account and Privacy settings.
*/
public static function add_caveat_to_order_data_retention_settings( $settings ) {
if ( ! is_array( $settings ) ) {
return $settings;
}
foreach ( $settings as &$setting ) {
if ( isset( $setting['id'], $setting['type'] ) && 'personal_data_retention' === $setting['id'] && 'title' === $setting['type'] ) {
// translators: placeholders are opening and closing tags.
$note = sprintf( __( '%1$sNote:%2$s Orders which are related to subscriptions will not be included in the orders affected by these settings.', 'woocommerce-subscriptions' ), '<b>', '</b>' );
$setting['desc'] = isset( $setting['desc'] ) ? $setting['desc'] . '<br>' . $note : $note;
}
}
return $settings;
}
/**
* Add admin setting to turn subscription data removal when processing erasure requests on or off.
*
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
* @param array $settings WooCommerce Account and Privacy settings.
* @return array Account and Privacy settings.
*/
public static function add_subscription_data_retention_settings( $settings ) {
if ( ! is_array( $settings ) ) {
return $settings;
}
$erasure_text = esc_html__( 'account erasure request', 'woocommerce-subscriptions' );
if ( current_user_can( 'manage_privacy_options' ) ) {
$erasure_text = sprintf( '<a href="%s">%s</a>', esc_url( admin_url( 'tools.php?page=remove_personal_data' ) ), $erasure_text );
}
WC_Subscriptions_Admin::insert_setting_after( $settings, 'woocommerce_erasure_request_removes_order_data', array(
'desc' => __( 'Remove personal data from subscriptions', 'woocommerce-subscriptions' ),
/* Translators: %s URL to erasure request screen. */
'desc_tip' => sprintf( __( 'When handling an %s, should personal data within subscriptions be retained or removed?', 'woocommerce-subscriptions' ), $erasure_text ),
'id' => 'woocommerce_erasure_request_removes_subscription_data',
'type' => 'checkbox',
'default' => 'no',
'checkboxgroup' => '',
'autoload' => false,
) );
WC_Subscriptions_Admin::insert_setting_after( $settings, 'woocommerce_anonymize_completed_orders', array(
'title' => __( 'Retain ended subscriptions', 'woocommerce-subscriptions' ),
'desc_tip' => __( 'Retain ended subscriptions and their related orders for a specified duration before anonymizing the personal data within them.', 'woocommerce-subscriptions' ),
'id' => 'woocommerce_anonymize_ended_subscriptions',
'type' => 'relative_date_selector',
'placeholder' => __( 'N/A', 'woocommerce-subscriptions' ),
'default' => array(
'number' => '',
'unit' => 'months',
),
'autoload' => false,
) );
return $settings;
}
/**
* Remove subscription related order types from the order anonymization query.
*
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
* @param array $query_args @see wc_get_orders() args.
* @return array The args used to get orders to anonymize.
*/
public static function remove_subscription_orders_from_anonymization_query( $query_args ) {
if ( ! is_array( $query_args ) ) {
return $query_args;
}
$query_args['subscription_parent'] = false;
$query_args['subscription_renewal'] = false;
$query_args['subscription_switch'] = false;
$query_args['subscription_resubscribe'] = false;
return $query_args;
}
/**
* Add a note to the inactive user data retention setting noting that users with a subscription are excluded.
*
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.4
* @param array $settings WooCommerce Account and Privacy settings.
* @return array Account and Privacy settings.
*/
public static function add_inactive_user_retention_note( $settings ) {
foreach ( $settings as &$setting ) {
if ( isset( $setting['id'], $setting['desc_tip'] ) && 'woocommerce_delete_inactive_accounts' === $setting['id'] ) {
$setting['desc_tip'] .= ' ' . __( 'Customers with a subscription are excluded from this setting.', 'woocommerce-subscriptions' );
break;
}
}
return $settings;
}
/**
* Set a flag to record inactive user account deletion.
*
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.4
* @param array $user_roles The user roles included in the inactive user query.
* @return array
*/
public static function flag_subscription_user_exclusion_from_query( $user_roles ) {
self::$doing_user_inactivity_query = true;
return $user_roles;
}
/**
* Exclude customers who have subscriptions from the inactive user cleanup query.
*
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.4
* @param WP_User_Query $user_query
*/
public static function maybe_exclude_subscription_customers( $user_query ) {
if ( ! self::$doing_user_inactivity_query ) {
return;
}
$user_query->set( 'exclude', array_merge(
(array) $user_query->get( 'exclude' ),
WC_Data_Store::load( 'subscription' )->get_subscription_customer_ids()
) );
self::$doing_user_inactivity_query = false;
}
/* Deprecated Functions */
/**
* Add the option to remove personal data from subscription via a bulk action.
*
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
* @param array $bulk_actions Subscription bulk actions.
*/
public static function add_remove_personal_data_bulk_action( $bulk_actions ) {
wcs_deprecated_function( __METHOD__, 'subscriptions-core 5.2.0', 'WCS_Privacy_Exporters::add_privacy_bulk_action' );
$bulk_actions['remove_personal_data'] = __( 'Cancel and remove personal data', 'woocommerce-subscriptions' );
return $bulk_actions;
}
}