# password-reset-enforcement/trunk/src/class-processing.php

Teydea Password Reset – Force Password Reset &amp; Expiration, version trunk. 288 lines.

- Page: https://pluginprobe.com/plugins/password-reset-enforcement/trunk/code/src/class-processing.php
- Raw: https://pluginprobe.com/plugins/password-reset-enforcement/trunk/raw/src/class-processing.php
- Modified: 2026-08-27T22:13:58+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/password-reset-enforcement/trunk/code/src/class-processing.php#L10-L20`.

```php
<?php
/**
 * Processes password reset enforcement for users
 *
 * @package Teydea_Studio\Password_Reset
 */

namespace Teydea_Studio\Password_Reset;

use Teydea_Studio\Password_Reset\Dependencies\Utils;
use WP_User;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // @codeCoverageIgnore
}

/**
 * The "Processing" class
 */
class Processing {
	/**
	 * Applicability: log the user out immediately
	 *
	 * @var string
	 */
	const APPLICABILITY_IMMEDIATELY = 'immediately';

	/**
	 * Applicability: enforce the reset once the current session expires
	 *
	 * @var string
	 */
	const APPLICABILITY_AFTER_SESSION_EXPIRY = 'after_session_expiry';

	/**
	 * Allowed applicability values
	 *
	 * @var string[]
	 */
	const APPLICABILITIES = [
		self::APPLICABILITY_IMMEDIATELY,
		self::APPLICABILITY_AFTER_SESSION_EXPIRY,
	];

	/**
	 * Container instance
	 *
	 * @var Utils\Container
	 */
	protected object $container;

	/**
	 * Constructor
	 *
	 * @param Utils\Container $container Container instance.
	 */
	public function __construct( object $container ) {
		$this->container = $container;
	}

	/**
	 * Build the default user factory
	 *
	 * @return callable(WP_User): User Factory turning a WP_User into the plugin's User instance.
	 */
	protected function get_default_user_factory(): callable {
		return function ( WP_User $wp_user ): User {
			return new User( $this->container, $wp_user ); // @codeCoverageIgnore
		};
	}

	/**
	 * Collect user IDs based on given criteria
	 *
	 * @param bool           $to_all   Whether to apply to all users.
	 * @param string[]       $to_roles Array of roles to apply to.
	 * @param int[]|string[] $to_users Array of user IDs to apply to.
	 * @param ?int           $limit    Number of users to process per batch, or null.
	 * @param ?int           $paged    Page number for pagination, or null.
	 * @param ?Utils\Users   $users    Users utility instance for dependency injection (optional, creates new if not provided).
	 *
	 * @return int[] Array of user IDs collected.
	 */
	public function collect_user_ids( bool $to_all, array $to_roles, array $to_users, ?int $limit = null, ?int $paged = null, ?object $users = null ): array {
		if ( null === $users ) {
			$users = new Utils\Users( $this->container ); // @codeCoverageIgnore
		}

		if ( true === $to_all ) {
			$to_roles = [];
			$to_users = [];
		}

		// Map user logins to user IDs, as the user query requires user IDs.
		if ( ! empty( $to_users ) ) {
			$to_users = $users->maybe_map_user_logins_to_user_ids( $to_users );
		}

		return $users->get_users_batch( $to_all, $to_roles, $to_users, $limit, $paged, true );
	}

	/**
	 * Clear password reset enforcement for users
	 *
	 * @param int[]                          $user_ids    Array of user IDs to process.
	 * @param (callable(WP_User): User)|null $user_factory Optional user factory callable for dependency injection. If null, uses default User instantiation.
	 *
	 * @return void
	 */
	public function clear_password_reset_enforcement( array $user_ids, ?callable $user_factory = null ): void {
		$user_factory ??= $this->get_default_user_factory();

		foreach ( $user_ids as $user_id ) {
			$wp_user = get_user_by( 'ID', $user_id );

			if ( ! $wp_user instanceof WP_User ) {
				continue;
			}

			$user = $user_factory( $wp_user );
			$user->remove_password_reset_enforcement();
		}
	}

	/**
	 * Force password reset for users
	 *
	 * @param int[]                          $user_ids                      Array of user IDs to process.
	 * @param string                         $applicability                 One of the self::APPLICABILITY_* values.
	 * @param bool                           $with_email                    Whether to send email notification.
	 * @param bool                           $with_current_password_allowed Whether to allow current password.
	 * @param int|string                     $requestor                     Current user ID or identifier performing the action.
	 * @param (callable(WP_User): User)|null $user_factory                  Optional user factory callable for dependency injection. If null, uses default User instantiation.
	 *
	 * @return void
	 */
	public function force_password_reset( array $user_ids, string $applicability, bool $with_email, bool $with_current_password_allowed, $requestor = '', ?callable $user_factory = null ): void {
		$user_factory ??= $this->get_default_user_factory();

		foreach ( $user_ids as $user_id ) {
			$wp_user = get_user_by( 'ID', $user_id );

			if ( ! $wp_user instanceof WP_User ) {
				continue;
			}

			$user = $user_factory( $wp_user );

			if ( self::APPLICABILITY_IMMEDIATELY === $applicability ) {
				$user->logout_everywhere();
			}

			if ( true === $with_email ) {
				$user->send_email_with_link();
			}

			$user->force_password_reset( $requestor, $with_current_password_allowed );
		}
	}

	/**
	 * Get the password reset enforcement status for users
	 *
	 * @param int[]                          $user_ids    Array of user IDs to process.
	 * @param (callable(WP_User): User)|null $user_factory Optional user factory callable for dependency injection. If null, uses default User instantiation.
	 *
	 * @return array<int,array{user_id:int,needs_password_reset:string,requested_at:string,requested_by:string,with_current_password_allowed:string}> Array containing status information about the password reset enforcement for users.
	 */
	public function get_password_reset_enforcement_status( array $user_ids, ?callable $user_factory = null ): array {
		$user_factory ??= $this->get_default_user_factory();
		$results        = [];

		foreach ( $user_ids as $user_id ) {
			$wp_user = get_user_by( 'ID', $user_id );

			if ( ! $wp_user instanceof WP_User ) {
				continue;
			}

			$user = $user_factory( $wp_user );
			$data = $user->get_password_reset_request_data();

			$result = [
				'user_id'                       => $user_id,
				'user_name'                     => $user->get_user_login(),
				'needs_password_reset'          => 'no',
				'requested_at'                  => '-',
				'requested_by'                  => '-',
				'with_current_password_allowed' => '-',
			];

			if ( null !== $data ) {
				$result['needs_password_reset'] = 'yes';

				$result['requested_at'] = sprintf(
					'%1$s (%2$s ago)',
					Utils\Date_Time::get_i18n_datetime_string( $data['requested_at'] ),
					human_time_diff( $data['requested_at'] ),
				);

				$result['requested_by']                  = $user->get_requestor_display_name( $data['requested_by'] );
				$result['with_current_password_allowed'] = Utils\Type::ensure_bool( $data['with_current_password_allowed'] ) ? 'yes' : 'no';
			}

			$results[] = $result;
		}

		return $results;
	}

	/**
	 * List users who have a pending password reset request
	 *
	 * Resolves affected users by querying for the existence of the enforcement
	 * request user meta — the feature's data store.
	 *
	 * @param ?int                           $limit        Number of users to process per batch, or null for no limit.
	 * @param ?int                           $paged        Page number for pagination (1-based), or null for no pagination.
	 * @param (callable(WP_User): User)|null $user_factory Optional user factory callable for dependency injection. If null, uses default User instantiation.
	 *
	 * @return array<int,array{user_id:int,user_name:string,requested_at:string,requested_by:string,with_current_password_allowed:string}> Array containing information about users with pending password reset requests.
	 */
	public function list_users_with_enforced_password_reset( ?int $limit = null, ?int $paged = null, ?callable $user_factory = null ): array {
		$user_factory ??= $this->get_default_user_factory();
		$results        = [];

		// "blog_id => 0" keeps the network-wide scope of the enforcement request meta.
		$args = [
			'meta_key'     => ( new User( $this->container ) )->get_prefixed_meta_key( User::USER_META_KEY__REQUEST ), // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- the enforcement request meta is the feature's data store; there's no other way to resolve affected users.
			'meta_compare' => 'EXISTS',
			'fields'       => 'ID',
			'orderby'      => 'ID',
			'order'        => 'ASC',
			'count_total'  => false,
			'blog_id'      => 0,
		];

		if ( null !== $limit ) {
			$args['number'] = $limit;

			if ( null !== $paged ) {
				$args['paged'] = $paged;
			}
		}

		$user_ids = Utils\Type::ensure_array_of_ints( get_users( $args ) );

		foreach ( $user_ids as $user_id ) {
			$wp_user = get_user_by( 'ID', $user_id );

			if ( ! $wp_user instanceof WP_User ) {
				continue;
			}

			$user = $user_factory( $wp_user );

			if ( null === $user->get_user_login() ) {
				continue;
			}

			$data = $user->get_password_reset_request_data();

			$result = [
				'user_id'                       => $user_id,
				'user_name'                     => $user->get_user_login(),
				'requested_at'                  => '-',
				'requested_by'                  => '-',
				'with_current_password_allowed' => '-',
			];

			if ( null !== $data ) {
				$result['requested_at'] = sprintf(
					'%1$s (%2$s ago)',
					Utils\Date_Time::get_i18n_datetime_string( $data['requested_at'] ),
					human_time_diff( $data['requested_at'] ),
				);

				$result['requested_by']                  = $user->get_requestor_display_name( $data['requested_by'] );
				$result['with_current_password_allowed'] = Utils\Type::ensure_bool( $data['with_current_password_allowed'] ) ? 'yes' : 'no';
			}

			$results[] = $result;
		}

		return $results;
	}
}

```
