Automattic\WooCommerce\Internal\TransientFiles

TransientFilesEngine::delete_expired_filespublicWC 1.0

Delete expired transient files from the filesystem.

Method of the class: TransientFilesEngine{}

No Hooks.

Returns

array. "deleted_count" with the number of files actually deleted, "files_remain" that will be true if there are still files left to delete.

Usage

$TransientFilesEngine = new TransientFilesEngine();
$TransientFilesEngine->delete_expired_files( $limit ): array;
$limit(int)
Maximum number of files to delete.
Default: 1000

TransientFilesEngine::delete_expired_files() code WC 11.1.2

public function delete_expired_files( int $limit = 1000 ): array {
	$expiration_date_gmt = $this->legacy_proxy->call_function( 'gmdate', 'Y-m-d' );
	$base_dir            = $this->get_transient_files_directory();

	/*
	 * scandir, not glob: glob doesn't support stream wrappers (it always goes to the local filesystem)
	 * and returns an empty array for paths like "s3://bucket/uploads", which would silently turn the
	 * cleanup into a no-op on those sites. scandir returns bare names rather than full paths.
	 */
	$entries = scandir( $base_dir );
	if ( false === $entries ) {
		// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Not rendered as output, and consistent with the other throws in this class.
		throw new Exception( "Error when getting the list of subdirectories of $base_dir" );
	}

	$subdirs = array_values(
		array_filter(
			$entries,
			fn( $name ) => 1 === preg_match( self::EXPIRATION_DATE_DIRECTORY_REGEX, $name ) && is_dir( $base_dir . '/' . $name )
		)
	);

	$expired_subdirs = array_filter( $subdirs, fn( $name ) => $name < $expiration_date_gmt );
	asort( $subdirs ); // We want to delete files starting with the oldest expiration month.

	$remaining_limit = $limit;
	$limit_reached   = false;
	foreach ( $expired_subdirs as $subdir ) {
		$full_dir_path = $base_dir . '/' . $subdir;

		$dir_entries = scandir( $full_dir_path );
		if ( false === $dir_entries ) {
			// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Not rendered as output, and consistent with the other throws in this class.
			throw new Exception( "Error when getting the list of files in $full_dir_path" );
		}

		$files_to_delete = array_values(
			array_map(
				fn( $name ) => $full_dir_path . '/' . $name,
				// Skip dot files, matching what the "*" glob pattern used to do. This also drops "." and "..".
				array_filter( $dir_entries, fn( $name ) => '.' !== $name[0] )
			)
		);

		if ( count( $files_to_delete ) > $remaining_limit ) {
			$limit_reached   = true;
			$files_to_delete = array_slice( $files_to_delete, 0, $remaining_limit );
		}
		array_map( 'wp_delete_file', $files_to_delete );
		$remaining_limit -= count( $files_to_delete );
		$this->delete_directory_if_not_empty( $full_dir_path );

		if ( $limit_reached ) {
			break;
		}
	}

	return array(
		'deleted_count' => $limit - $remaining_limit,
		'files_remain'  => $limit_reached,
	);
}