| @@ -279,8 +279,49 @@ | ||
| 279 | 279 | return (bool)apply_filters('ws_plugin__s2member_allow_eot_user_deletion', FALSE, get_defined_vars()); |
| 280 | 280 | } |
| 281 | 281 | |
| 282 | 282 | /** |
| 283 | + * Applies the configured EOT role demotion to a user. | |
| 284 | + * | |
| 285 | + * @package s2Member\Auto_EOT_System | |
| 286 | + * @since 260916.2004 | |
| 287 | + * | |
| 288 | + * @param \WP_User $user WordPress user being demoted. | |
| 289 | + * @param string $demotion_to_role Role assigned after EOT. | |
| 290 | + * | |
| 291 | + * @return string Role before demotion, for EOT history. | |
| 292 | + */ | |
| 293 | + public static function demote_user_roles($user = NULL, $demotion_to_role = 'subscriber') | |
| 294 | + { | |
| 295 | + if(!is_object($user) || empty($user->ID) || !is_string($demotion_to_role) || !$demotion_to_role) | |
| 296 | + return ''; | |
| 297 | + | |
| 298 | + $existing_role = c_ws_plugin__s2member_user_access::user_access_role($user); | |
| 299 | + //260916.2030 Preserve the historical all-role path exactly; upgraded installations are explicitly seeded to this policy. | |
| 300 | + if($GLOBALS['WS_PLUGIN__']['s2member']['o']['eot_demotion_from'] === 'all') | |
| 301 | + { | |
| 302 | + if($existing_role !== $demotion_to_role) | |
| 303 | + $user->set_role($demotion_to_role); | |
| 304 | + return $existing_role; | |
| 305 | + } | |
| 306 | + | |
| 307 | + $eot_original_role = ''; | |
| 308 | + //260916.2030 The new default removes only explicit paid s2Member Level roles; Subscriber/Level 0 is a possible destination, never a Demote From role. | |
| 309 | + foreach((array)$user->roles as $role) | |
| 310 | + if(preg_match('/^s2member_level[1-9][0-9]*$/', $role)) | |
| 311 | + { | |
| 312 | + if(!$eot_original_role) | |
| 313 | + $eot_original_role = $role; | |
| 314 | + if($role !== $demotion_to_role) | |
| 315 | + $user->remove_role($role); | |
| 316 | + } | |
| 317 | + if(!in_array($demotion_to_role, (array)$user->roles, TRUE)) | |
| 318 | + $user->add_role($demotion_to_role); | |
| 319 | + | |
| 320 | + return $eot_original_role ?: $existing_role; | |
| 321 | + } | |
| 322 | + | |
| 323 | + /** | |
| 283 | 324 | * Records when an End-of-Term action was processed and appends one compact history note. |
| 284 | 325 | * |
| 285 | 326 | * @package s2Member\Auto_EOT_System |
| 286 | 327 | * @since 260822.0653 |
| @@ -370,9 +411,9 @@ | ||
| 370 | 411 | $gateway_label = isset($gateway_labels[$gateway_key]) ? $gateway_labels[$gateway_key] : ucwords(str_replace(array('-', '_'), ' ', $gateway_key)); |
| 371 | 412 | $removed_ccaps = array_values(array_unique(array_filter(array_map('strval', (array)$removed_ccaps), 'strlen'))); |
| 372 | 413 | sort($removed_ccaps, SORT_STRING); |
| 373 | 414 | |
| 374 | - //260829.0618 Avoid recording a misleading role transition when EOT processing finds the user already in the configured demotion role. | |
| 415 | + //260829.0618 Avoid recording a misleading role transition when EOT processing finds the user already in the role selected under Demote To Role. | |
| 375 | 416 | if($original_role === $destination_role) |
| 376 | 417 | $note = $processed_display.' s2Member: EOT processed, already '.$role_labels[(string)$original_role]; |
| 377 | 418 | else |
| 378 | 419 | $note = $processed_display.' s2Member: Demoted from '.$role_labels[(string)$original_role].' to '.$role_labels[(string)$destination_role]; |
| @@ -1105,10 +1146,10 @@ | ||
| 1105 | 1146 | do_action('ws_plugin__s2member_during_collective_mods', $user_id, get_defined_vars(), $eot_del_type, 'modification', $demotion_role); |
| 1106 | 1147 | do_action('ws_plugin__s2member_during_collective_eots', $user_id, get_defined_vars(), $eot_del_type, 'modification'); |
| 1107 | 1148 | unset($__refs, $__v); // Housekeeping. |
| 1108 | 1149 | |
| 1109 | - if($existing_role !== $demotion_role /* Only if NOT the existing Role. */) | |
| 1110 | - $user->set_role($demotion_role /* Give User the demotion Role. */); | |
| 1150 | + //260916.2004 New installs replace only the s2Member Level role; upgraded sites retain legacy all-role replacement until the administrator changes it. | |
| 1151 | + $eot_membership_role = self::demote_user_roles($user, $demotion_role); | |
| 1111 | 1152 | |
| 1112 | 1153 | if(apply_filters('ws_plugin__s2member_remove_ccaps_during_eot_events', (bool)$GLOBALS['WS_PLUGIN__']['s2member']['o']['eots_remove_ccaps'], get_defined_vars())) |
| 1113 | 1154 | foreach($user->allcaps as $cap => $cap_enabled) |
| 1114 | 1155 | if(preg_match('/^access_s2member_ccap_/', $cap)) |
| @@ -1146,9 +1187,9 @@ | ||
| 1146 | 1187 | //260822.0653 Record the triggering EOT separately from when this worker actually completed the demotion, using the pre-cleanup role/payment snapshot above. |
| 1147 | 1188 | self::record_eot_history($user_id, array( |
| 1148 | 1189 | 'eot_time' => $auto_eot_time, |
| 1149 | 1190 | 'processed_at' => $processed_at, |
| 1150 | - 'original_role' => $existing_role, | |
| 1191 | + 'original_role' => $eot_membership_role, | |
| 1151 | 1192 | 'destination_role' => $demotion_role, |
| 1152 | 1193 | 'removed_ccaps' => $removed_ccaps, |
| 1153 | 1194 | 'subscr_gateway' => $subscr_gateway, |
| 1154 | 1195 | 'subscr_id' => $subscr_id, |