__( 'PrintBlob designs', 'printblob' ), 'callback' => array( __CLASS__, 'export' ), ); return $exporters; } public static function add_eraser( array $erasers ): array { $erasers[ self::ID ] = array( 'eraser_friendly_name' => __( 'PrintBlob designs', 'printblob' ), 'callback' => array( __CLASS__, 'erase' ), ); return $erasers; } /** The designs of the person with this email: theirs as a signed-in shopper, and those on their orders. */ private static function designs_of( string $email, int $page ): array { $user = get_user_by( 'email', $email ); $orders = wc_get_orders( array( 'billing_email' => $email, 'limit' => -1, 'return' => 'ids', ) ); if ( $user ) { $orders = array_merge( $orders, wc_get_orders( array( 'customer_id' => $user->ID, 'limit' => -1, 'return' => 'ids', ) ) ); } $meta = array( 'relation' => 'OR' ); if ( $user ) { $meta[] = array( 'key' => Design_Store::META_OWNER, 'value' => (string) $user->ID, ); } if ( $orders ) { $meta[] = array( 'key' => Design_Store::META_ORDER, 'value' => array_map( 'intval', array_unique( $orders ) ), 'compare' => 'IN', ); } if ( count( $meta ) < 2 ) { return array(); } return get_posts( array( 'post_type' => Design_Store::POST_TYPE, 'post_status' => 'private', 'numberposts' => self::PER_PAGE, 'paged' => $page, 'meta_query' => $meta, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query ) ); } public static function export( string $email, int $page = 1 ): array { $data = array(); foreach ( self::designs_of( $email, $page ) as $design ) { $product = Design_Store::product_of( $design->ID ); $order = Design_Store::order_id( $design->ID ); $items = array( array( 'name' => __( 'Product', 'printblob' ), 'value' => $product ? $product->get_name() : '', ), array( 'name' => __( 'Created', 'printblob' ), 'value' => $design->post_date_gmt . ' UTC', ), array( 'name' => __( 'Order', 'printblob' ), 'value' => $order ? (string) $order : __( 'Not ordered', 'printblob' ), ), ); foreach ( Design_Store::sides( $design->ID ) as $side => $files ) { $url = ! empty( $files['preview_id'] ) ? wp_get_attachment_url( (int) $files['preview_id'] ) : ''; if ( $url ) { $items[] = array( /* translators: %s: printed side, e.g. Front. */ 'name' => sprintf( __( 'Preview, %s', 'printblob' ), Product_Settings::side_label( $side ) ), 'value' => $url, ); } foreach ( (array) ( $files['uploads'] ?? array() ) as $upload ) { $items[] = array( /* translators: %s: printed side, e.g. Front. */ 'name' => sprintf( __( 'Uploaded image, %s', 'printblob' ), Product_Settings::side_label( $side ) ), 'value' => wp_basename( (string) $upload ), ); } } $data[] = array( 'group_id' => self::ID, 'group_label' => __( 'Designs', 'printblob' ), 'item_id' => 'printblob-design-' . $design->ID, 'data' => $items, ); } return array( 'data' => $data, 'done' => count( $data ) < self::PER_PAGE, ); } public static function erase( string $email ): array { $orders_too = 'yes' === get_option( 'woocommerce_erasure_request_removes_order_data', 'no' ); $removed = false; $retained = false; // Always page 1: what is deleted no longer shows up, and what is kept is counted only once below. foreach ( self::designs_of( $email, 1 ) as $design ) { $ordered = Design_Store::order_id( $design->ID ) > 0; if ( $ordered && ! $orders_too ) { $retained = true; continue; } Design_Store::delete_design( $design->ID ); $removed = true; } return array( 'items_removed' => $removed, 'items_retained' => $retained, 'messages' => $retained ? array( __( 'Designs that are part of an order were kept with the order (WooCommerce › Settings › Accounts & Privacy decides whether order data is removed on request).', 'printblob' ) ) : array(), 'done' => true, ); } public static function policy_text(): void { if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) { return; } wp_add_privacy_policy_content( 'PrintBlob', '
' . esc_html__( 'When you design a product, the images you upload and the text you add are stored on this site with your design: a preview of each printed side, and a print file that only the shop’s staff can download. Designs that are not ordered are deleted after a few days; designs that are ordered are kept with the order. Nothing is sent to PrintBlob or any other service.', 'printblob' ) . '
' ); } /** An order deleted for good takes its designs, previews and print files with it. */ public static function delete_order_designs( $order_id ): void { foreach ( get_posts( array( 'post_type' => Design_Store::POST_TYPE, 'post_status' => 'private', 'numberposts' => -1, 'fields' => 'ids', 'meta_key' => Design_Store::META_ORDER, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- One order's designs, by the order they are saved with. 'meta_value' => (int) $order_id, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- As above. ) ) as $design_id ) { Design_Store::delete_design( (int) $design_id ); } } /** The same for orders stored as posts (WooCommerce without High-Performance Order Storage). */ public static function delete_order_designs_legacy( $post_id ): void { if ( 'shop_order' === get_post_type( $post_id ) ) { self::delete_order_designs( (int) $post_id ); } } }