Expire a user’s secondary role after X days from it being allocated

As alternative to a cron job, you may use a “just in time” removal of the role.

i.e. when an user logs in, you can check if it has the role(s) you want to expire, check current date with download date and update the user accordingly.

This assumes that you are able to get the date or timestamp of (at least) the last download of an user.

I am not familiar with EDD, but this is a prof of concept code:

add_action( 'wp_login', function($username, $user) {

   $toExpire = [ 'buyer', 'other_role' ];

   $toRemove = array_intersect($user->roles, $toExpire);

   if (count($user->roles) < 2 || empty($toRemove)) {
     // nothing to do if the user has just 1 role or none of the roles you want to expire
     return;
   }

   // the function below does NOT exists
   // I think in EDD you should be able to get the date or timestamp of an user last download
   $downloadTimestamp = get_last_download_timestamp_for_user($user->ID);

   $dayLimit = 30 * DAY_IN_SECONDS; // expire after 30 days

   if ((time() - $dayLimit) < $paymentTimestamp) {
     // do nothing if not enough time passed
     return;
   }

   if (! array_diff($toExpire, $toRemove)) {
     // if an user has ONLY roles that might expire, keep the first role
     array_shift($toRemove);
   }

   // remove expired roles
   foreach($toRemove as $role) {
     $user->remove_role($role);
   }


}, 1, 2);

Doing like so you don’t need to set a cron job, and it is easier to implement.

However, using this method, in your system you may see users with “expired” roles just because they have not logged in since the role expired. If you have (or want) statistics in this regard, you need to keep this into account.