From 6ca484f40e0f67e3873bfea557405bb413bd3833 Mon Sep 17 00:00:00 2001
From: Erick Hitter <git-contrib@ethitter.com>
Date: Sat, 9 Jul 2022 17:42:24 -0700
Subject: [PATCH] On activation and deactivation, clean up tokens in previous
 storage

Fixes #2
---
 inc/class-activation-deactivation-hooks.php | 93 +++++++++++++++++++++
 redis-user-session-storage.php              |  3 +
 2 files changed, 96 insertions(+)
 create mode 100644 inc/class-activation-deactivation-hooks.php

diff --git a/inc/class-activation-deactivation-hooks.php b/inc/class-activation-deactivation-hooks.php
new file mode 100644
index 0000000..d83f17c
--- /dev/null
+++ b/inc/class-activation-deactivation-hooks.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Plugin activation hooks to migrate and clean up data.
+ *
+ * @package Redis_User_Session_Storage
+ */
+
+namespace Redis_User_Session_Storage;
+
+/**
+ * Class Activation_Deactivation_Hooks.
+ */
+final class Activation_Deactivation_Hooks {
+	/**
+	 * Cron hook for usermeta session cleanup.
+	 *
+	 * @var string
+	 */
+	private $cron_hook = 'redis_user_session_storage_clean_usermeta_storage';
+
+	/**
+	 * Activation_Hooks constructor.
+	 *
+	 * @param string $plugin_file Path to plugin's main file.
+	 */
+	public function __construct( $plugin_file ) {
+		register_activation_hook(
+			$plugin_file,
+			array( $this, 'clean_usermeta_storage' )
+		);
+
+		register_deactivation_hook(
+			$plugin_file,
+			array( $this, 'clean_redis_storage' )
+		);
+
+		add_action(
+			$this->cron_hook,
+			array( $this, 'do_scheduled_cleanup' )
+		);
+	}
+
+	/**
+	 * Remove all sessions from usermeta on activation.
+	 *
+	 * @return void
+	 */
+	public function clean_usermeta_storage() {
+		wp_schedule_single_event(
+			time() + 600,
+			'redis_user_session_storage_clean_usermeta_storage'
+		);
+	}
+
+	/**
+	 * Remove session data from usermeta using cron to avoid excessive load.
+	 *
+	 * While this could use `WP_User_Meta_Session_Tokens::drop_sessions()`, this
+	 * approach is safer for large sites.
+	 *
+	 * @return void
+	 */
+	public function do_scheduled_cleanup() {
+		global $wpdb;
+
+		$this->clean_usermeta_storage();
+
+		$key = 'session_tokens';
+
+		$count = $wpdb->get_var(
+			"SELECT COUNT(*) FROM $wpdb->usermeta WHERE meta_key = '$key'"
+		);
+
+		if ( ! $count ) {
+			wp_clear_scheduled_hook( $this->cron_hook );
+		}
+
+		$wpdb->query(
+			"DELETE FROM $wpdb->usermeta WHERE meta_key = '$key' LIMIT 500"
+		);
+	}
+
+	/**
+	 * Remove all sessions from Redis on deactivation.
+	 *
+	 * @return void
+	 */
+	public function clean_redis_storage() {
+		wp_clear_scheduled_hook( $this->cron_hook );
+
+		Plugin::drop_sessions();
+	}
+}
diff --git a/redis-user-session-storage.php b/redis-user-session-storage.php
index 7aaccbe..d2a9ba5 100644
--- a/redis-user-session-storage.php
+++ b/redis-user-session-storage.php
@@ -47,6 +47,9 @@ function load() {
 	}
 
 	require_once __DIR__ . '/inc/class-plugin.php';
+	require_once __DIR__ . '/inc/class-activation-deactivation-hooks.php';
+
+	new Activation_Deactivation_Hooks( __FILE__ );
 
 	// Hooked at 9 in case old plugin is also active.
 	add_filter(
-- 
GitLab