| @@ -85,8 +85,14 @@ | ||
| 85 | 85 | foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $$__v; |
| 86 | 86 | do_action('ws_plugin__s2member_during_update_all_options', get_defined_vars()); |
| 87 | 87 | unset($__refs, $__v); // Housekeeping. |
| 88 | 88 | |
| 89 | + //260812 Keep the old s2Get option synchronized for rollback compatibility, while accepting legacy updates during the transition. | |
| 90 | + if(isset($new_options['ws_plugin__s2member_sc_s2get_userid_whitelist']) && !isset($new_options['ws_plugin__s2member_sc_user_fields_whitelist'])) | |
| 91 | + $options['sc_user_fields_whitelist'] = $options['sc_s2get_userid_whitelist']; | |
| 92 | + if(isset($options['sc_user_fields_whitelist'])) | |
| 93 | + $options['sc_s2get_userid_whitelist'] = $options['sc_user_fields_whitelist']; | |
| 94 | + | |
| 89 | 95 | $options = ws_plugin__s2member_configure_options_and_their_defaults(($options = array_merge($options, array('options_version' => (string)($options['options_version'] + 0.001))))); |
| 90 | 96 | update_option('ws_plugin__s2member_options', $options).((is_multisite() && is_main_site()) ? update_site_option('ws_plugin__s2member_options', $options) : NULL).update_option('ws_plugin__s2member_cache', array()); |
| 91 | 97 | |
| 92 | 98 | if($update_other === TRUE || in_array('auto_eot_system', (array)$update_other)) // Handle the Auto-EOT System now (enable/disable). |
| @@ -127,8 +133,84 @@ | ||
| 127 | 133 | return apply_filters('ws_plugin__s2member_update_all_options', (($updated_all_options) ? TRUE : FALSE), get_defined_vars()); |
| 128 | 134 | } |
| 129 | 135 | |
| 130 | 136 | /** |
| 137 | + * Displays shared End-of-Term demotion-role settings on gateway option pages. | |
| 138 | + * | |
| 139 | + * @package s2Member\Menu_Pages | |
| 140 | + * @since 260916.2004 | |
| 141 | + * | |
| 142 | + * @return null | |
| 143 | + */ | |
| 144 | + public static function eot_demotion_options() | |
| 145 | + { | |
| 146 | + $demotion_to_role = (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['eot_demotion_to_role']; | |
| 147 | + $demotion_from = (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['eot_demotion_from']; | |
| 148 | + $demotion_disabled = ($GLOBALS['WS_PLUGIN__']['s2member']['o']['membership_eot_behavior'] === 'delete'); | |
| 149 | + | |
| 150 | + //260917.0003 Keep Demote From/To visible but disabled when EOT behavior is Delete; JavaScript mirrors this immediately when the behavior selector changes. | |
| 151 | + echo '<tr class="ws-plugin--s2member-eot-demotion-option-row"'.(($demotion_disabled) ? ' style="opacity:0.5;"' : '').'>'."\n"; | |
| 152 | + echo '<th><label for="ws-plugin--s2member-eot-demotion-from">Demote From:</label></th>'."\n"; | |
| 153 | + echo '</tr>'."\n"; | |
| 154 | + echo '<tr class="ws-plugin--s2member-eot-demotion-option-row"'.(($demotion_disabled) ? ' style="opacity:0.5;"' : '').'>'."\n"; | |
| 155 | + echo '<td>'."\n"; | |
| 156 | + echo '<select name="ws_plugin__s2member_eot_demotion_from" id="ws-plugin--s2member-eot-demotion-from"'.(($demotion_disabled) ? ' disabled="disabled"' : '').'>'."\n"; | |
| 157 | + echo '<option value="s2member_level"'.(($demotion_from === 's2member_level') ? ' selected="selected"' : '').'>s2Member Level role (preserve other WordPress roles)</option>'."\n"; | |
| 158 | + echo '<option value="all"'.(($demotion_from === 'all') ? ' selected="selected"' : '').'>All WordPress roles (legacy behavior)</option>'."\n"; | |
| 159 | + echo '</select><br />'."\n"; | |
| 160 | + echo '<em>These settings are used only when Membership End-of-Term Behavior is set to Demote.</em><br /><br />'."\n"; | |
| 161 | + //260916.2004 Explain the fresh-install behavior, legacy compatibility, and capability caveat without treating Subscriber/Level 0 as a role users are demoted from. | |
| 162 | + echo '<em>New installations remove only the user\'s <code>s2member_levelN</code> role at EOT and preserve other WordPress roles; upgraded installations retain the legacy all-role replacement until you change this setting. Preserved roles also preserve their existing capabilities, so roles such as Editor/Author/Contributor or custom roles may continue to grant s2Member access.</em>'."\n"; | |
| 163 | + echo '</td>'."\n"; | |
| 164 | + echo '</tr>'."\n"; | |
| 165 | + echo '<tr class="ws-plugin--s2member-eot-demotion-option-row"'.(($demotion_disabled) ? ' style="opacity:0.5;"' : '').'>'."\n"; | |
| 166 | + echo '<th><label for="ws-plugin--s2member-eot-demotion-to-role">Demote To Role:</label></th>'."\n"; | |
| 167 | + echo '</tr>'."\n"; | |
| 168 | + echo '<tr class="ws-plugin--s2member-eot-demotion-option-row"'.(($demotion_disabled) ? ' style="opacity:0.5;"' : '').'>'."\n"; | |
| 169 | + echo '<td>'."\n"; | |
| 170 | + //260916.2345 Group Subscriber and s2Member Levels first, then list other registered roles by slug so larger role lists stay predictable and easier to scan. | |
| 171 | + global $wp_roles; | |
| 172 | + if(!is_object($wp_roles)) | |
| 173 | + $wp_roles = new WP_Roles(); | |
| 174 | + $level_roles = $other_roles = array(); | |
| 175 | + foreach((array)$wp_roles->roles as $role_slug => $role_data) | |
| 176 | + { | |
| 177 | + if(in_array($role_slug, array('administrator', 'editor', 'author', 'contributor', 's2member_pending_deletion'), TRUE)) | |
| 178 | + continue; | |
| 179 | + $role_name = !empty($role_data['name']) ? translate_user_role($role_data['name']) : $role_slug; | |
| 180 | + if($role_slug === 'subscriber') | |
| 181 | + $level_roles[0] = array($role_slug, $role_name); | |
| 182 | + else if(preg_match('/^s2member_level([1-9][0-9]*)$/', $role_slug, $m)) | |
| 183 | + $level_roles[(int)$m[1]] = array($role_slug, $role_name); | |
| 184 | + else | |
| 185 | + $other_roles[$role_slug] = $role_name; | |
| 186 | + } | |
| 187 | + ksort($level_roles, SORT_NUMERIC); | |
| 188 | + ksort($other_roles, SORT_STRING); | |
| 189 | + echo '<select name="ws_plugin__s2member_eot_demotion_to_role" id="ws-plugin--s2member-eot-demotion-to-role"'.(($demotion_disabled) ? ' disabled="disabled"' : '').'>'."\n"; | |
| 190 | + if($level_roles) | |
| 191 | + { | |
| 192 | + echo '<optgroup label="s2Member Levels">'."\n"; | |
| 193 | + foreach($level_roles as $role) | |
| 194 | + echo '<option value="'.esc_attr($role[0]).'"'.(($demotion_to_role === $role[0]) ? ' selected="selected"' : '').'>'.esc_html($role[1]).' ('.esc_html($role[0]).')</option>'."\n"; | |
| 195 | + echo '</optgroup>'."\n"; | |
| 196 | + } | |
| 197 | + if($other_roles) | |
| 198 | + { | |
| 199 | + echo '<optgroup label="Other Roles">'."\n"; | |
| 200 | + foreach($other_roles as $role_slug => $role_name) | |
| 201 | + echo '<option value="'.esc_attr($role_slug).'"'.(($demotion_to_role === $role_slug) ? ' selected="selected"' : '').'>'.esc_html($role_name).' ('.esc_html($role_slug).')</option>'."\n"; | |
| 202 | + echo '</optgroup>'."\n"; | |
| 203 | + } | |
| 204 | + echo '</select><br />'."\n"; | |
| 205 | + echo '<em>Select the WordPress role to assign when s2Member demotes a member at EOT. Subscriber is the default.</em><br /><br />'."\n"; | |
| 206 | + echo '<em>WordPress\'s elevated default roles and s2Member\'s Pending Deletion role are intentionally not available here. Any role selected here keeps the capabilities assigned to it. If those capabilities grant s2Member access, the member may still be able to access protected content after EOT.</em><br /><br />'."\n"; | |
| 207 | + echo '<em>Developers who need a role not available here can use <code>ws_plugin__s2member_force_demotion_role</code>; see <a href="https://s2member.com/kb-article/how-do-i-specify-the-demotion-role-upon-eot/" target="_blank" rel="noopener noreferrer external">How do I specify the demotion role upon EOT?</a></em>'."\n"; | |
| 208 | + echo '</td>'."\n"; | |
| 209 | + echo '</tr>'."\n"; | |
| 210 | + } | |
| 211 | + | |
| 212 | + /** | |
| 131 | 213 | * Adds option menus / sub-menus. |
| 132 | 214 | * |
| 133 | 215 | * @package s2Member\Menu_Pages |
| 134 | 216 | * @since 3.5 |
| @@ -966,9 +1048,9 @@ | ||
| 966 | 1048 | // Sanitize display names |
| 967 | 1049 | $name_hdr = str_replace(array("\r\n", "\r", "\n"), ' ', (string) $name); |
| 968 | 1050 | $name_hdr = str_replace('"', "'", $name_hdr); |
| 969 | 1051 | |
| 970 | - $sitename = wp_parse_url(home_url(), PHP_URL_HOST); | |
| 1052 | + $sitename = c_ws_plugin__s2member_utils_urls::parse_url(home_url(), PHP_URL_HOST); | |
| 971 | 1053 | $sitename = is_string($sitename) ? strtolower($sitename) : ''; |
| 972 | 1054 | if (strpos($sitename, 'www.') === 0) $sitename = substr($sitename, 4); |
| 973 | 1055 | |
| 974 | 1056 | $default_from_email = 'wordpress@'.$sitename; |