PluginProbe
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions / 260917
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions v260917
260917 260913 260909 260829 260814 260805 110710 110731 110812 110815 110912 110913 110915 110926 110927 111002 111003 111011 111017 111029 111105 111206 111216 111220 120213 All 189 releases
← All changes | src/includes/classes/auto-eots.inc.php +62 -8 260829260917 View file →
@@ -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
@@ -347,9 +388,16 @@
347 388 foreach(array($original_role, $destination_role) as $_role)
348 389 {
349 390 $_role = (string)$_role;
350 391 if(preg_match('/^s2member_level([0-9]+)$/', $_role, $_matches))
351 - $role_labels[$_role] = 'Level '.(int)$_matches[1];
392 + {
393 + //260829.0618 Keep EOT audit notes consistent with the administrator's forced s2Member labels, while retaining concise Level N names when label translation is disabled.
394 + $_level = (int)$_matches[1];
395 + $_label_key = 'level'.$_level.'_label';
396 + $role_labels[$_role] = !empty($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["apply_label_translations"]) && !empty($GLOBALS["WS_PLUGIN__"]["s2member"]["o"][$_label_key])
397 + ? $GLOBALS["WS_PLUGIN__"]["s2member"]["o"][$_label_key]
398 + : 'Level '.$_level;
399 + }
352 400 else if($_role === 's2member_pending_deletion')
353 401 $role_labels[$_role] = 'Pending Deletion';
354 402 else if($_role && isset($wp_roles->roles[$_role]['name']))
355 403 $role_labels[$_role] = translate_user_role($wp_roles->roles[$_role]['name']);
@@ -355,9 +403,9 @@
355 403 $role_labels[$_role] = translate_user_role($wp_roles->roles[$_role]['name']);
356 404 else
357 405 $role_labels[$_role] = $_role ? ucwords(str_replace(array('-', '_'), ' ', $_role)) : 'Unknown Role';
358 406 }
359 - unset($_role, $_matches);
407 + unset($_role, $_matches, $_level, $_label_key);
360 408
361 409 $gateway_labels = array('paypal' => 'PayPal', 'authnet' => 'Authorize.Net', 'clickbank' => 'ClickBank', 'ccbill' => 'ccBill', 'alipay' => 'AliPay', 'google' => 'Google Wallet', 'stripe' => 'Stripe');
362 410 $gateway_key = strtolower((string)$subscr_gateway);
363 411 $gateway_label = isset($gateway_labels[$gateway_key]) ? $gateway_labels[$gateway_key] : ucwords(str_replace(array('-', '_'), ' ', $gateway_key));
@@ -363,9 +411,13 @@
363 411 $gateway_label = isset($gateway_labels[$gateway_key]) ? $gateway_labels[$gateway_key] : ucwords(str_replace(array('-', '_'), ' ', $gateway_key));
364 412 $removed_ccaps = array_values(array_unique(array_filter(array_map('strval', (array)$removed_ccaps), 'strlen')));
365 413 sort($removed_ccaps, SORT_STRING);
366 414
367 - $note = $processed_display.' s2Member: Demoted from '.$role_labels[(string)$original_role].' to '.$role_labels[(string)$destination_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.
416 + if($original_role === $destination_role)
417 + $note = $processed_display.' s2Member: EOT processed, already '.$role_labels[(string)$original_role];
418 + else
419 + $note = $processed_display.' s2Member: Demoted from '.$role_labels[(string)$original_role].' to '.$role_labels[(string)$destination_role];
368 420 if($removed_ccaps)
369 421 $note .= ' (removed ccaps: '.implode(', ', $removed_ccaps).')';
370 422 $note .= '.';
371 423 if($subscr_gateway && $subscr_id)
@@ -720,9 +772,10 @@
720 772 {
721 773 if(!function_exists('wp_cron') || !$recurring_at)
722 774 $issues['cron_missing'] = $critical = TRUE;
723 775 else if((int)$recurring_at < $now - HOUR_IN_SECONDS)
724 - $issues['cron_overdue'] = $critical = TRUE;
776 + //260908.2031 An overdue WP-Cron event can be normal on a quiet site; keep it visible as Attention, while missing cron or an actual overdue EOT backlog remain critical.
777 + $issues['cron_overdue'] = TRUE;
725 778 }
726 779 else if($mode === '2' && !empty($state['last_external_completed_at']) && $now - (int)$state['last_external_completed_at'] >= 2 * HOUR_IN_SECONDS)
727 780 $issues['external_cron_stale'] = $critical = TRUE;
728 781
@@ -802,9 +855,10 @@
802 855 $reasons[] = number_format_i18n($health['pending_count']).' End-of-Term action'.($health['pending_count'] === 1 ? ' is' : 's are').' pending; the oldest has been overdue for '.human_time_diff($health['oldest_due_at'], time()).'.';
803 856 if(in_array('repeated_abandoned', $health['issues'], TRUE))
804 857 $reasons[] = number_format_i18n($health['consecutive_abandoned_runs']).' consecutive Automatic End-of-Term workers ended without reaching normal completion.';
805 858
806 - $settings_url = admin_url('/admin.php?page=ws-plugin--s2member-paypal-ops').'#ws-plugin--s2member-auto-eot-system-enabled';
859 + //260908.2031 Open the collapsed EOT panel before scrolling to its setting; a hash alone targets a hidden control.
860 + $settings_url = admin_url('/admin.php?page=ws-plugin--s2member-paypal-ops&s2member-open-panel=auto-eot').'#ws-plugin--s2member-auto-eot-system-enabled';
807 861 $notice = '<strong>s2Member Automatic End-of-Term needs attention.</strong> '.esc_html(implode(' ', $reasons)).' <a href="'.esc_url($settings_url).'">Review Automatic End-of-Term settings</a>.';
808 862 c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, TRUE);
809 863 }
810 864
@@ -1092,10 +1146,10 @@
1092 1146 do_action('ws_plugin__s2member_during_collective_mods', $user_id, get_defined_vars(), $eot_del_type, 'modification', $demotion_role);
1093 1147 do_action('ws_plugin__s2member_during_collective_eots', $user_id, get_defined_vars(), $eot_del_type, 'modification');
1094 1148 unset($__refs, $__v); // Housekeeping.
1095 1149
1096 - if($existing_role !== $demotion_role /* Only if NOT the existing Role. */)
1097 - $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);
1098 1152
1099 1153 if(apply_filters('ws_plugin__s2member_remove_ccaps_during_eot_events', (bool)$GLOBALS['WS_PLUGIN__']['s2member']['o']['eots_remove_ccaps'], get_defined_vars()))
1100 1154 foreach($user->allcaps as $cap => $cap_enabled)
1101 1155 if(preg_match('/^access_s2member_ccap_/', $cap))
@@ -1133,9 +1187,9 @@
1133 1187 //260822.0653 Record the triggering EOT separately from when this worker actually completed the demotion, using the pre-cleanup role/payment snapshot above.
1134 1188 self::record_eot_history($user_id, array(
1135 1189 'eot_time' => $auto_eot_time,
1136 1190 'processed_at' => $processed_at,
1137 - 'original_role' => $existing_role,
1191 + 'original_role' => $eot_membership_role,
1138 1192 'destination_role' => $demotion_role,
1139 1193 'removed_ccaps' => $removed_ccaps,
1140 1194 'subscr_gateway' => $subscr_gateway,
1141 1195 'subscr_id' => $subscr_id,