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
s2member / src / includes / menu-pages / gen-ops.inc.php

gen-ops.inc.php in s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions 260917, at src/includes/menu-pages/gen-ops.inc.php

2,025 lines 157.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // @codingStandardsIgnoreFile
3 /**
4 * Menu page for the s2Member plugin (General Options page).
5 *
6 * Copyright: © 2009-2011
7 * {@link http://websharks-inc.com/ WebSharks, Inc.}
8 * (coded in the USA)
9 *
10 * Released under the terms of the GNU General Public License.
11 * You should have received a copy of the GNU General Public License,
12 * along with this software. In the main directory, see: /licensing/
13 * If not, see: {@link http://www.gnu.org/licenses/}.
14 *
15 * @package s2Member\Menu_Pages
16 * @since 3.0
17 */
18 if(!defined('WPINC')) // MUST have WordPress.
19 exit("Do not access this file directly.");
20
21 if(!class_exists("c_ws_plugin__s2member_menu_page_gen_ops"))
22 {
23 /**
24 * Menu page for the s2Member plugin (General Options page).
25 *
26 * @package s2Member\Menu_Pages
27 * @since 110531
28 */
29 class c_ws_plugin__s2member_menu_page_gen_ops
30 {
31 public function __construct()
32 {
33 echo '<div class="wrap ws-menu-page">'."\n";
34
35 echo '<div class="wp-header-end"></div>'."\n";
36
37 echo '<div class="ws-menu-page-toolbox">'."\n";
38 c_ws_plugin__s2member_menu_pages_tb::display();
39 echo '</div>'."\n";
40
41 echo '<h2>General Options</h2>'."\n";
42
43 echo '<table class="ws-menu-page-table">'."\n";
44 echo '<tbody class="ws-menu-page-table-tbody">'."\n";
45 echo '<tr class="ws-menu-page-table-tr">'."\n";
46 echo '<td class="ws-menu-page-table-l">'."\n";
47
48 do_action("ws_plugin__s2member_during_gen_ops_page_before_left_sections_form", get_defined_vars());
49
50 echo '<form method="post" name="ws_plugin__s2member_options_form" id="ws-plugin--s2member-options-form" autocomplete="off">'."\n";
51 echo '<input type="hidden" name="ws_plugin__s2member_options_save" id="ws-plugin--s2member-options-save" value="'.esc_attr(wp_create_nonce("ws-plugin--s2member-options-save")).'" />'."\n";
52 echo '<input type="hidden" name="ws_plugin__s2member_configured" id="ws-plugin--s2member-configured" value="1" />'."\n";
53
54 do_action("ws_plugin__s2member_during_gen_ops_page_before_left_sections", get_defined_vars());
55
56 if(apply_filters("ws_plugin__s2member_during_gen_ops_page_during_left_sections_display_uninstall", (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site() || is_super_admin()), get_defined_vars()))
57 {
58 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_uninstall", get_defined_vars());
59
60 echo '<div class="ws-menu-page-group" title="Plugin Deletion Safeguards"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["run_uninstall_routines"]) ? ' default-state="open"' : '').'>'."\n";
61
62 echo '<div class="ws-menu-page-section ws-plugin--s2member-uninstall-section">'."\n";
63 echo '<h3>Plugin Deletion Safeguards (highly recommended)</h3>'."\n";
64 echo '<p>By default, s2Member will retain all of it\'s Roles, Capabilities, and your Configuration Options when/if you delete s2Member from the Plugins Menu in WordPress. However, if you would like for s2Member to erase itself completely, please choose: <code>No (upon deletion, erase all data/options)</code>. See also: <a href="http://s2member.com/kb-article/how-do-i-uninstall-s2member/" target="_blank" rel="external">s2Member Uninstall Instructions</a></p>';
65 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_uninstall", get_defined_vars());
66
67 echo '<table class="form-table">'."\n";
68 echo '<tbody>'."\n";
69 echo '<tr>'."\n";
70
71 echo '<th>'."\n";
72 echo '<label for="ws-plugin--s2member-run-uninstall-routines">'."\n";
73 echo 'Safeguard s2Member Data/Options?'."\n";
74 echo '</label>'."\n";
75 echo '</th>'."\n";
76
77 echo '</tr>'."\n";
78 echo '<tr>'."\n";
79
80 echo '<td>'."\n";
81 echo '<select name="ws_plugin__s2member_run_uninstall_routines" id="ws-plugin--s2member-run-uninstall-routines">'."\n";
82 echo '<option value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["run_uninstall_routines"]) ? ' selected="selected"' : '').'>Yes (safeguard all data/options)</option>'."\n";
83 echo '<option value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["run_uninstall_routines"]) ? ' selected="selected"' : '').'>No (upon deletion, erase all data/options)</option>'."\n";
84 echo '</select><br />'."\n";
85 echo 'Recommended setting: (<code>Yes, safeguard all data/options</code>)'."\n";
86 echo '</td>'."\n";
87
88 echo '</tr>'."\n";
89 echo '</tbody>'."\n";
90 echo '</table>'."\n";
91 echo '</div>'."\n";
92
93 echo '</div>'."\n";
94
95 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_after_uninstall", get_defined_vars());
96 }
97 if(apply_filters("ws_plugin__s2member_during_gen_ops_page_during_left_sections_display_security", TRUE, get_defined_vars()))
98 {
99 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_security", get_defined_vars());
100
101 echo '<div class="ws-menu-page-group" title="Security Encryption Key">'."\n";
102
103 echo '<div class="ws-menu-page-section ws-plugin--s2member-security-section">'."\n";
104 echo '<img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/src/images/large-icon.png" title="s2Member (a Membership management system for WordPress)" alt="" style="float:right; margin:0 0 0 25px; border:0;" />'."\n";
105 //260810 Clarify that s2Member always has an encryption secret and that this separate key is optional.
106 echo '<h3>Security Encryption Key (optional)</h3>'."\n";
107 echo '<p>s2Member uses an encryption secret to encrypt and validate certain sensitive values. If you leave this setting blank, s2Member automatically uses the WordPress salts via <code>wp_salt()</code>. You can instead configure a separate Security Encryption Key for s2Member, giving you independent control over this secret and making it easier to preserve across site moves or restores when you keep the same key.</p>'."\n";
108 echo '<p>Once a site is in use, avoid changing its effective encryption key unless you intend to invalidate or recover data encrypted with a previous key. Existing Specific Post/Page Access Links, Registration Access Links, registration/tracking cookies, pending transaction-return data, and values encrypted through s2Member\'s encryption API may depend on it. If you configure a key here, keep a secure backup of it.</p>'."\n";
109 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_security", get_defined_vars());
110
111 echo '<table class="form-table">'."\n";
112 echo '<tbody>'."\n";
113 echo '<tr>'."\n";
114
115 echo '<th>'."\n";
116 echo '<label for="ws-plugin--s2member-sec-encryption-key">'."\n";
117 echo 'Security Encryption Key (optional; 60+ chars recommended)'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key"]) ? ' <a href="#" onclick="ws_plugin__s2member_enableSecurityKey(); return false;" title="Changing the Key will invalidate existing data that was encrypted with the current effective key.">edit key</a>' : ' <a href="#" onclick="ws_plugin__s2member_generateSecurityKey(); return false;" title="Insert an auto-generated 64-character Key.">auto-generate</a>')."\n";
118 echo '</label>'."\n";
119 echo '</th>'."\n";
120
121 echo '</tr>'."\n";
122 echo '<tr>'."\n";
123
124 echo '<td>'."\n";
125 echo '<input type="text" maxlength="256" autocomplete="off" name="ws_plugin__s2member_sec_encryption_key" id="ws-plugin--s2member-sec-encryption-key" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key"]).'"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key"]) ? ' disabled="disabled"' : '').' />'."\n";
126 //260810 Make the configured-key guidance explicit without implying that a separate key is required.
127 echo (!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key"]) ? '<br />If you configure a separate key, use at least 60 characters. It may contain letters, numbers, spaces, and punctuation; up to 256 characters.<br /><em>Ex: <code>'.esc_html(strtoupper(c_ws_plugin__s2member_utils_strings::random_str_gen(64))).'</code></em>'."\n" : '';
128 echo (count($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key_history"]) > 1) ? '<br /><a href="#" onclick="ws_plugin__s2member_securityKeyHistory(); return false;">Click here</a> for a history of your last 10 configured Security Encryption Keys.<div id="ws-plugin--s2member-sec-encryption-key-history" style="display:none;"><code>'.implode('</code><br /><code>', $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key_history"]).'</code></div>'."\n" : '';
129 echo '</td>'."\n";
130
131 echo '</tr>'."\n";
132 echo '</tbody>'."\n";
133 echo '</table>'."\n";
134
135 echo '<div class="ws-menu-page-hr"></div>'."\n";
136
137 //260810 Explain how the configured key fits into s2Member's normal key resolution and what key changes affect.
138 echo '<h3>How this Key is Used:</h3>'."\n";
139 echo '<p>For normal encryption/decryption, a custom key supplied by code takes precedence. Otherwise s2Member uses the Security Encryption Key configured above; if this setting is blank, it falls back to the WordPress salts via <code>wp_salt()</code>.</p>'."\n";
140 echo '<p>Many encrypted values are short-lived, but some can remain valid much longer. Changing the effective key will invalidate existing data that was encrypted with the previous key, which can include Specific Post/Page Access Links, Registration Access Links, registration and tracking cookies, pending transaction-return data, and values created through s2Member\'s encryption API. If this setting is blank, changing the WordPress salts will likewise invalidate data encrypted with the previous salts.</p>'."\n";
141
142 echo '</div>'."\n";
143
144 echo '</div>'."\n";
145
146 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_after_security", get_defined_vars());
147 }
148 if(apply_filters("ws_plugin__s2member_during_gen_ops_page_during_left_sections_display_localhost_info", (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site() || is_super_admin()), get_defined_vars()))
149 {
150 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_localhost_info", get_defined_vars());
151
152 echo '<div class="ws-menu-page-group" title="Localhost WAMP/MAMP Developers">'."\n";
153
154 echo '<div class="ws-menu-page-section ws-plugin--s2member-localhost-info-section">'."\n";
155 echo '<h3>Localhost WAMP/MAMP Installs (are you a developer?)</h3>'."\n";
156 echo '<p>If you\'re developing your site in a <code>localhost</code> environment, running something like WAMP/MAMP, or <a href="https://s2member.com/r/easyphp/" target="_blank" rel="external">EasyPHP</a>, please add this line to your <code>/wp-config.php</code> file: <code><span style="color:#0000BB;">define</span><span style="color:#007700;">(</span><span style="color:#DD0000;">"LOCALHOST"</span>, <span style="color:#0000BB;">true</span><span style="color:#007700;">);</span></code>.</p>'."\n";
157 echo '<p>This lets s2Member know definitively that your site is in a <code>localhost</code> environment. s2Member will adjust itself accordingly, maximizing functionality during your developement. s2Member can usually auto-detect this, but in cases where your <code>localhost</code> installation runs on something other than <code>127.0.0.1/localhost</code>, you need to tell s2Member definitively, by adding that line to your <code>/wp-config.php</code> file. For instance, s2Member needs to know when your server IP is the same as all User IPs.</p>'."\n";
158 echo '<p><em>Once your site goes live, please remove the line. If you\'re already on a live server connected to the web, please ignore this section.</em></p>'."\n";
159 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_localhost_info", get_defined_vars());
160 echo '</div>'."\n";
161
162 echo '</div>'."\n";
163
164 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_after_localhost_info", get_defined_vars());
165 }
166 if(apply_filters("ws_plugin__s2member_during_gen_ops_page_during_left_sections_display_lazy_load", (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site() || is_super_admin()), get_defined_vars()))
167 {
168 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_lazy_load", get_defined_vars());
169
170 $open_performance_panel = !empty($_GET['s2member-open-panel']) && in_array((string)$_GET['s2member-open-panel'], array('frontend-static-assets', 'dynamic-asset-loader'), TRUE);
171 echo '<div class="ws-menu-page-group" title="Performance &amp; Caching"'.(($open_performance_panel) ? ' default-state="open"' : '').'>'."\n";
172
173 echo '<div class="ws-menu-page-section ws-plugin--s2member-lazy-load-section">'."\n";
174 echo '<h3>CSS/JS Lazy Loading (Client-Side Libraries)</h3>'."\n";
175 echo '<p>By default, s2Member will load it\'s CSS/JS libraries on every page of your site. However, you may wish to enable lazy-loading here (i.e., only load when absolutely necessary).</p>'."\n";
176 echo '<p><em><strong>Tip:</strong> Do you need s2Member\'s CSS/JS on every page? If not, you can turn lazy-loading on. If you need s2Member\'s CSS/JS on a given Post/Page, you can insert an HTML comment into the Post/Page content like this: <code>&lt;!--s2member--&gt;</code>. If a Post/Page contains the word <code>s2member</code> or an <code>[s2*</code> Shortcode, this will automatically trigger s2Member\'s lazy-load routine (no matter what you configure here). Thus, it\'s an easy way to force s2Member to load it\'s CSS/JS on specific Posts/Pages where you deem this necessary. There is also a WordPress filter available: <code>add_filter("ws_plugin__s2member_lazy_load_css_js", "__return_true");</code> for developers. This could be incorporated into more dynamic scenarios.</em></p>'."\n";
177 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_lazy_load", get_defined_vars());
178
179 echo '<table class="form-table">'."\n";
180 echo '<tbody>'."\n";
181 echo '<tr>'."\n";
182
183 echo '<th>'."\n";
184 echo '<label for="ws-plugin--s2member-lazy-load-css-js">'."\n";
185 echo 'Lazy-Load s2Member\'s CSS/JS Libraries?'."\n";
186 echo '</label>'."\n";
187 echo '</th>'."\n";
188
189 echo '</tr>'."\n";
190 echo '<tr>'."\n";
191
192 echo '<td>'."\n";
193 echo '<select name="ws_plugin__s2member_lazy_load_css_js" id="ws-plugin--s2member-lazy-load-css-js">'."\n";
194 echo '<option value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["lazy_load_css_js"]) ? ' selected="selected"' : '').'>No (always load the CSS/JS libraries; i.e., on every page of the site)</option>'."\n";
195 echo '<option value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["lazy_load_css_js"]) ? ' selected="selected"' : '').'>Yes (lazy-load CSS/JS libraries; i.e., load only when absolutely necessary)</option>'."\n";
196 echo '</select>'."\n";
197 echo '</td>'."\n";
198
199 echo '</tr>'."\n";
200 echo '</tbody>'."\n";
201 echo '</table>'."\n";
202 echo '</div>'."\n";
203
204 echo '<div style="margin:1em 0;">'."\n";
205 echo '<div class="ws-menu-page-hr"></div>'."\n";
206 echo '</div>'."\n";
207
208 //260904.2014 Dynamic delivery applies independently of static delivery, so give its loader choice a separate section.
209 echo '<div id="ws-plugin--s2member-dynamic-asset-loader-section" class="ws-menu-page-section ws-plugin--s2member-dynamic-asset-loader-section">'."\n";
210 echo '<h3>Dynamic CSS/JS Loader</h3>'."\n";
211 echo '<p>When s2Member needs to generate CSS or JavaScript dynamically, this controls the preferred dynamic route. If Static CSS/JS Delivery is enabled but current hooks or configuration specifically require the normal WordPress environment, s2Member uses the Full WordPress Dynamic Loader for compatibility instead.</p>'."\n";
212 echo '<table class="form-table">'."\n";
213 echo '<tbody>'."\n";
214
215 $dynamic_asset_loader = (!empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['dynamic_asset_loader']) && $GLOBALS['WS_PLUGIN__']['s2member']['o']['dynamic_asset_loader'] === 'wordpress') ? 'wordpress' : 's2o';
216 echo '<tr><th><label for="ws-plugin--s2member-dynamic-asset-loader">Dynamic CSS/JS Loader</label></th></tr>'."\n";
217 echo '<tr><td>'."\n";
218 echo '<select name="ws_plugin__s2member_dynamic_asset_loader" id="ws-plugin--s2member-dynamic-asset-loader">'."\n";
219 echo '<option value="s2o"'.(($dynamic_asset_loader === 's2o') ? ' selected="selected"' : '').'>s2Member-Only Dynamic Loader (recommended)</option>'."\n";
220 echo '<option value="wordpress"'.(($dynamic_asset_loader === 'wordpress') ? ' selected="selected"' : '').'>Full WordPress Dynamic Loader (compatibility)</option>'."\n";
221 echo '</select><br />'."\n";
222 //260910.0709 Keep the familiar s2member-o.php identity visible, explain the lighter WordPress load for new users, and link the two KB references needed when security rules block direct access to that plugin PHP file.
223 echo '<em>The s2Member-Only Dynamic Loader uses a lighter WordPress load for better performance through <code>s2member-o.php</code>. See <a href="https://s2member.com/kb-article/s2member-only-mode/" target="_blank" rel="noopener noreferrer external">s2Member-Only Mode</a>. Because this PHP file is inside the s2Member plugin directory, some server or security configurations need to explicitly allow web access to it. If it returns a 403, 503, or 500 error, see <a href="https://s2member.com/kb-article/mod-security-odd-403-503-500-errors/" target="_blank" rel="noopener noreferrer external">Mod Security (Odd 403, 503, 500 Errors)</a>. The Full WordPress Dynamic Loader uses the site\'s normal WordPress request as a compatibility alternative.</em>'."\n";
224 echo '</td></tr>'."\n";
225
226 echo '</tbody>'."\n";
227 echo '</table>'."\n";
228 echo '</div>'."\n";
229
230 echo '<div style="margin:1em 0;">'."\n";
231 echo '<div class="ws-menu-page-hr"></div>'."\n";
232 echo '</div>'."\n";
233
234 //260904.2014 Keep static CSS/JS delivery and its related optimizations together in a clearly named section.
235 echo '<div id="ws-plugin--s2member-static-assets" class="ws-menu-page-section ws-plugin--s2member-static-assets-section">'."\n";
236 echo '<h3>CSS/JS Delivery &amp; Optimization (Beta)</h3>'."\n";
237 echo '<p>These beta options build CSS and JavaScript files ahead of time under the WordPress uploads directory, so the web server can serve them directly without starting PHP and WordPress for each request. Framework and Pro files remain separate by default, with optional combining and minification for further optimization.</p>'."\n";
238 echo '<p><em>After enabling these options, test your membership, registration, profile, and payment pages. If static delivery cannot be used, s2Member switches to dynamic delivery automatically. Compatibility requirements that need normal WordPress hooks use the Full WordPress Dynamic Loader; Asset Health explains the active route and reason.</em></p>'."\n";
239
240 echo '<table class="form-table">'."\n";
241 echo '<tbody>'."\n";
242 echo '<tr><th><label for="ws-plugin--s2member-static-css">Static CSS Delivery?</label></th></tr>'."\n";
243 echo '<tr><td>'."\n";
244 echo '<select name="ws_plugin__s2member_static_css" id="ws-plugin--s2member-static-css" onchange="jQuery(\'#ws-plugin--s2member-static-css-minify\').prop(\'disabled\', this.value !== \'1\');">'."\n";
245 echo '<option value="0"'.((!$GLOBALS['WS_PLUGIN__']['s2member']['o']['static_css']) ? ' selected="selected"' : '').'>No (use dynamic CSS)</option>'."\n";
246 echo '<option value="1"'.(($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_css']) ? ' selected="selected"' : '').'>Yes (beta; generate and serve static CSS)</option>'."\n";
247 echo '</select><br />'."\n";
248 echo '<em>Generates timestamped Framework CSS and, when Pro is active, a separate Pro/gateway stylesheet by default. Generation failures or incompatible custom CSS hooks use legacy dynamic CSS.</em>'."\n";
249 echo '</td></tr>'."\n";
250
251 echo '<tr><th><label for="ws-plugin--s2member-static-css-minify">Minify Static CSS?</label></th></tr>'."\n";
252 echo '<tr><td>'."\n";
253 echo '<select name="ws_plugin__s2member_static_css_minify" id="ws-plugin--s2member-static-css-minify"'.((!$GLOBALS['WS_PLUGIN__']['s2member']['o']['static_css']) ? ' disabled="disabled"' : '').'>'."\n";
254 echo '<option value="0"'.((empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_css']) || empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_css_minify'])) ? ' selected="selected"' : '').'>No (keep generated CSS readable)</option>'."\n";
255 echo '<option value="1"'.((!empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_css']) && !empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_css_minify'])) ? ' selected="selected"' : '').'>Yes (beta; minify generated CSS)</option>'."\n";
256 echo '</select><br />'."\n";
257 echo '<em>Used only with Static CSS Delivery. Original source files remain readable and unchanged.</em>'."\n";
258 echo '</td></tr>'."\n";
259
260 echo '<tr><th><label for="ws-plugin--s2member-static-js">Static JS Delivery?</label></th></tr>'."\n";
261 echo '<tr><td>'."\n";
262 echo '<select name="ws_plugin__s2member_static_js" id="ws-plugin--s2member-static-js" onchange="jQuery(\'#ws-plugin--s2member-static-js-minify\').prop(\'disabled\', this.value !== \'1\');">'."\n";
263 echo '<option value="0"'.((!$GLOBALS['WS_PLUGIN__']['s2member']['o']['static_js']) ? ' selected="selected"' : '').'>No (use dynamic JavaScript)</option>'."\n";
264 echo '<option value="1"'.(($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_js']) ? ' selected="selected"' : '').'>Yes (beta; generate and serve static JavaScript)</option>'."\n";
265 echo '</select><br />'."\n";
266 echo '<em>Generates timestamped Framework JavaScript and, when Pro is active, a separate Pro/gateway script by default. Personal/member details always remain page-specific and are never stored in static files. WordPress 4.2–4.4 automatically keep dynamic JavaScript.</em>'."\n";
267 echo '</td></tr>'."\n";
268
269 $static_js_text = (isset($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_js_text']) && $GLOBALS['WS_PLUGIN__']['s2member']['o']['static_js_text'] === 'page') ? 'page' : 'static';
270 $static_js_page_text_supported = c_ws_plugin__s2member_utils_assets::static_js_page_text_supported();
271 //260913.2140 Link Asset Health guidance to the full setting row and leave room above it so the setting label remains visible below the WordPress admin bar.
272 echo '<tr id="ws-plugin--s2member-static-js-text-setting" style="scroll-margin-top:64px;"><th><label for="ws-plugin--s2member-static-js-text">JavaScript Text Delivery</label></th></tr>'."\n";
273 echo '<tr><td>'."\n";
274 echo '<p style="margin-top:0;"><em>Some s2Member messages and labels are shown or updated by JavaScript—for example, form validation and password feedback—so JavaScript needs access to that text too.</em></p>'."\n";
275 echo '<select name="ws_plugin__s2member_static_js_text" id="ws-plugin--s2member-static-js-text">'."\n";
276 echo '<option value="static"'.(($static_js_text === 'static') ? ' selected="selected"' : '').'>Load JavaScript text with the static files</option>'."\n";
277 echo '<option value="page"'.(($static_js_text === 'page') ? ' selected="selected"' : '').((!$static_js_page_text_supported) ? ' disabled="disabled"' : '').'>Load JavaScript text with each WordPress page</option>'."\n";
278 echo '</select><br />'."\n";
279 //260913.2111 Explain that page-loaded text can also preserve Static JS when request-specific values would otherwise require Dynamic delivery.
280 echo '<em><strong>Static files:</strong> best for sites that use one language throughout; the text is cached with the generated JavaScript and does not add the larger text block to every page. <strong>WordPress page:</strong> use this for multilingual sites or when page-specific JavaScript values vary by request; those values stay with the page so the same external JavaScript can remain static whenever no other compatibility requirement needs Dynamic delivery. Personal/member details are always loaded with the page and are never stored in static files.</em>'."\n";
281 if(!$static_js_page_text_supported)
282 echo '<p class="ws-menu-page-error" style="margin:.75em 0 0;"><em><strong>Load with each WordPress page is unavailable:</strong> update s2Member Pro to a version that supports page-loaded JavaScript text. If your site needs different JavaScript text between languages before updating Pro, set Static JS Delivery to No so WordPress generates the JavaScript dynamically.</em></p>'."\n";
283 echo '</td></tr>'."\n";
284
285 echo '<tr><th><label for="ws-plugin--s2member-static-js-minify">Minify Static JS?</label></th></tr>'."\n";
286 echo '<tr><td>'."\n";
287 echo '<select name="ws_plugin__s2member_static_js_minify" id="ws-plugin--s2member-static-js-minify"'.((!$GLOBALS['WS_PLUGIN__']['s2member']['o']['static_js']) ? ' disabled="disabled"' : '').'>'."\n";
288 echo '<option value="0"'.((empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_js']) || empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_js_minify'])) ? ' selected="selected"' : '').'>No (keep generated JavaScript readable)</option>'."\n";
289 echo '<option value="1"'.((!empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_js']) && !empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_js_minify'])) ? ' selected="selected"' : '').'>Yes (beta; minify generated JavaScript)</option>'."\n";
290 echo '</select><br />'."\n";
291 echo '<em>Used only with Static JS Delivery. s2Member generates from readable JavaScript sources; developers do not maintain parallel minified files.</em>'."\n";
292 echo '</td></tr>'."\n";
293
294 echo '<tr><th><label for="ws-plugin--s2member-static-assets-combine">Combine Framework + Pro Static Assets?</label></th></tr>'."\n";
295 echo '<tr><td>'."\n";
296 echo '<select name="ws_plugin__s2member_static_assets_combine" id="ws-plugin--s2member-static-assets-combine">'."\n";
297 echo '<option value="0"'.((empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_assets_combine'])) ? ' selected="selected"' : '').'>No (keep Framework and Pro files separate)</option>'."\n";
298 echo '<option value="1"'.((!empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_assets_combine'])) ? ' selected="selected"' : '').'>Yes (combine each enabled type to reduce requests)</option>'."\n";
299 echo '</select><br />'."\n";
300 echo '<em>Applies when s2Member Pro is active. Separate delivery is the default; combining is an optional optimization that serves one generated CSS file and/or one generated JavaScript file instead of separate Framework and Pro files.</em>'."\n";
301 echo '</td></tr>'."\n";
302
303 //260912.0522 Expose the frontend-asset wait as a 1–60-second diagnostic control; changing it must not alter when the CSS/JS itself is enqueued or executed.
304 $asset_health_wait_seconds = (!empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['asset_health_wait_seconds'])) ? max(1, min(60, (int)$GLOBALS['WS_PLUGIN__']['s2member']['o']['asset_health_wait_seconds'])) : 3;
305 echo '<tr><th><label for="ws-plugin--s2member-asset-health-wait-seconds">Wait Before Checking Frontend Assets (in seconds)</label></th></tr>'."\n";
306 echo '<tr><td>'."\n";
307 echo '<input type="number" min="1" max="60" step="1" name="ws_plugin__s2member_asset_health_wait_seconds" id="ws-plugin--s2member-asset-health-wait-seconds" value="'.esc_attr($asset_health_wait_seconds).'" /><br />'."\n";
308 echo '<em>After the page finishes loading, s2Member waits this many seconds before checking that its frontend CSS and JavaScript have loaded and become active. This helps avoid false warnings when caching or optimization tools delay CSS/JS execution. Default: 3 seconds. Allowed range: 1–60.</em>'."\n";
309 echo '</td></tr>'."\n";
310 echo '</tbody></table>'."\n";
311
312 $static_assets_enabled = !empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_css']) || !empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_js']);
313 echo '<table class="form-table">'."\n";
314 echo '<tbody>'."\n";
315 echo '<tr><th>Refresh Static Assets</th></tr>'."\n";
316 echo '<tr><td>'."\n";
317 echo '<span id="ws-plugin--s2member-refresh-static-assets-feedback" style="display:flex; align-items:center; gap:.5em; max-width:100%;"><button type="button" class="button" id="ws-plugin--s2member-refresh-static-assets" style="flex:0 0 auto;"'.((!$static_assets_enabled) ? ' disabled="disabled"' : '').'>Refresh Static Assets</button><span id="ws-plugin--s2member-refresh-static-assets-status" aria-live="polite" style="display:block; flex:1 1 auto; min-width:0;"></span></span><br />'."\n";
318 echo '<em>'.(($static_assets_enabled) ? 'Creates new timestamps immediately for every active generated file. Separate Framework/Pro files keep independent build timestamps, while combined mode uses one timestamp per enabled asset type. Save option changes before using this button.' : 'Enable Static CSS Delivery or Static JS Delivery and save the options before using this button.').'</em>'."\n";
319
320 //260907.2203 Point site owners to the CSS/JS operational history from the asset controls.
321 echo '<p style="margin:.75em 0 0;"><em>When s2Member logging is enabled, important static and dynamic CSS/JS events such as generation, refreshes, delivery problems, fallbacks, and recovery are recorded in <code>css-js.log</code>. Routine page loads are not logged.</em></p>'."\n";
322
323 echo '</td></tr>'."\n";
324 echo '</tbody>'."\n";
325 echo '</table>'."\n";
326 //260904.0649 Keep Refresh tied to saved settings: disable it when no static type is active and while related controls have unsaved changes.
327 //260911.1834 Refresh is an explicit admin recovery action; follow a completed server-side rebuild attempt with the existing trusted browser recheck so the displayed Health state updates without another click.
328 echo '<script type="text/javascript">jQuery(function($){var $b=$("#ws-plugin--s2member-refresh-static-assets"),$s=$("#ws-plugin--s2member-refresh-static-assets-status"),$controls=$("#ws-plugin--s2member-static-css,#ws-plugin--s2member-static-css-minify,#ws-plugin--s2member-static-js,#ws-plugin--s2member-static-js-text,#ws-plugin--s2member-static-js-minify,#ws-plugin--s2member-static-assets-combine"),savedEnabled='.($static_assets_enabled ? 'true' : 'false').',dirtyMessage="Save option changes before refreshing.";function values(){return $controls.map(function(){return this.value;}).get().join("|");}var initial=values();function sync(){var changed=values()!==initial;$b.prop("disabled",!savedEnabled||changed);if(changed)$s.text(dirtyMessage);else if($s.text()===dirtyMessage)$s.text("");}function recheck(message){var r=document.getElementById("ws-plugin--s2member-recheck-asset-health");$s.text(message+(r?" Rechecking delivery…":""));if(r)r.click();}$controls.on("change",sync);$b.on("click",function(){$b.prop("disabled",true);$s.text("Refreshing…");$.post(ajaxurl,{action:"ws_plugin__s2member_refresh_static_assets",_ajax_nonce:"'.esc_js(wp_create_nonce('ws-plugin--s2member-refresh-static-assets')).'"}).done(function(r){recheck(r&&r.data&&r.data.message?r.data.message:"Static assets refreshed.");}).fail(function(xhr){var r=xhr.responseJSON,m=r&&r.data&&r.data.message?r.data.message:"Static assets could not be refreshed.";if(r&&r.data)recheck(m);else $s.text(m);}).always(function(){sync();});});sync();});</script>'."\n";
329
330 $asset_health = c_ws_plugin__s2member_utils_assets::frontend_asset_health(TRUE);
331 $asset_health_http = get_option('ws_plugin__s2member_asset_http_health', array());
332 $asset_health_log = get_option('ws_plugin__s2member_assets_health_log', array());
333 $asset_health_last_generation = 0;
334 $asset_health_pending_rebuild = FALSE;
335 $asset_health_age = function($timestamp)
336 {
337 $seconds = max(0, time() - (int)$timestamp);
338 if($seconds < MINUTE_IN_SECONDS)
339 return '<1 min ago';
340 if($seconds < HOUR_IN_SECONDS)
341 return floor($seconds / MINUTE_IN_SECONDS).' min ago';
342 if($seconds < DAY_IN_SECONDS)
343 return floor($seconds / HOUR_IN_SECONDS).' hr ago';
344 return floor($seconds / DAY_IN_SECONDS).' d ago';
345 };
346 foreach(array('css', 'js') as $_asset_type)
347 if(!empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['static_'.$_asset_type]))
348 foreach(c_ws_plugin__s2member_utils_assets::static_asset_ids($_asset_type, 'all') as $_asset_id)
349 {
350 $_asset_build = abs((int)c_ws_plugin__s2member_utils_assets::static_asset_build($_asset_id));
351 if($_asset_build > $asset_health_last_generation)
352 $asset_health_last_generation = $_asset_build;
353 }
354 $asset_health_last_generation_label = (!$static_assets_enabled) ? 'Not in use' : (($asset_health_last_generation > 0) ? $asset_health_age($asset_health_last_generation) : 'Not generated yet');
355 //260912.1956 Loader rows depend on the complete trusted route check, so report that timestamp instead of a newer cheap partial probe when available.
356 $asset_health_last_check = (!empty($asset_health_http['full_checked'])) ? (int)$asset_health_http['full_checked'] : ((!empty($asset_health_http['checked'])) ? (int)$asset_health_http['checked'] : 0);
357 $asset_health_last_check_label = ($asset_health_last_check > 0) ? $asset_health_age($asset_health_last_check) : 'Not checked yet';
358 $asset_health_last_issue_time = 0;
359 $asset_health_last_issue_result = '';
360 $asset_health_last_issue_label = '';
361 $asset_health_last_issue_detail = '';
362 $asset_health_last_issue_page_id = 0;
363 $asset_health_last_issue_page_path = '';
364 if(!empty($asset_health_log['last_issue']) && is_array($asset_health_log['last_issue']))
365 {
366 //260911.1806 Prefer the dedicated historical snapshot so natural recovery and busy healthy traffic do not erase the useful cause from Last issue.
367 $asset_health_last_issue_time = (!empty($asset_health_log['last_issue']['time'])) ? (int)$asset_health_log['last_issue']['time'] : 0;
368 $asset_health_last_issue_result = (!empty($asset_health_log['last_issue']['result'])) ? (string)$asset_health_log['last_issue']['result'] : '';
369 $asset_health_last_issue_label = (!empty($asset_health_log['last_issue']['label'])) ? (string)$asset_health_log['last_issue']['label'] : '';
370 $asset_health_last_issue_detail = (!empty($asset_health_log['last_issue']['detail'])) ? (string)$asset_health_log['last_issue']['detail'] : '';
371 $asset_health_last_issue_page_id = (!empty($asset_health_log['last_issue']['page_id'])) ? (int)$asset_health_log['last_issue']['page_id'] : 0;
372 $asset_health_last_issue_page_path = (!empty($asset_health_log['last_issue']['page_path'])) ? (string)$asset_health_log['last_issue']['page_path'] : '';
373 }
374 else if(empty($asset_health_log['last_issue_cleared_at']) && !empty($asset_health_log['last_10_asset_loads']) && is_array($asset_health_log['last_10_asset_loads']))
375 foreach(array_reverse($asset_health_log['last_10_asset_loads']) as $_asset_health_load)
376 if(!empty($_asset_health_load['time']) && !empty($_asset_health_load['result']) && (string)$_asset_health_load['result'] !== 'okay')
377 {
378 $asset_health_last_issue_time = (int)$_asset_health_load['time'];
379 $asset_health_last_issue_result = (string)$_asset_health_load['result'];
380 break;
381 }
382 $asset_health_last_issue_label = str_replace(array('Full WordPress Dynamic ', 's2Member-Only Dynamic ', 'JavaScript'), array('WordPress ', 's2Member-Only ', 'JS'), $asset_health_last_issue_label);
383 $asset_health_last_issue = 'None';
384 if($asset_health_last_issue_time > 0 && $asset_health_last_issue_result !== '')
385 {
386 //260911.1834 Self-repaired missing files are historical issues, not degraded scored loads.
387 $_asset_health_result_labels = array('late' => 'late', 'fallback' => 'fallback', 'failed' => 'failed', 'fallback-unavailable' => 'fallback unavailable', 'repaired' => 'static asset missing');
388 $_asset_health_result_label = (isset($_asset_health_result_labels[$asset_health_last_issue_result])) ? $_asset_health_result_labels[$asset_health_last_issue_result] : $asset_health_last_issue_result;
389 $asset_health_last_issue = $asset_health_age($asset_health_last_issue_time).''.(($asset_health_last_issue_label !== '') ? $asset_health_last_issue_label.' ' : '').$_asset_health_result_label;
390 }
391 $asset_health_last_issue_page_label = '';
392 $asset_health_last_issue_page_url = '';
393 if($asset_health_last_issue_page_id > 0)
394 {
395 $_asset_health_page_title = (string)get_the_title($asset_health_last_issue_page_id);
396 $asset_health_last_issue_page_label = (($_asset_health_page_title !== '') ? $_asset_health_page_title.' ' : '').'(#'.$asset_health_last_issue_page_id.')';
397 $asset_health_last_issue_page_url = (string)get_permalink($asset_health_last_issue_page_id);
398 }
399 if($asset_health_last_issue_page_path !== '')
400 {
401 $asset_health_last_issue_page_label .= (($asset_health_last_issue_page_label !== '') ? '' : '').$asset_health_last_issue_page_path;
402 if($asset_health_last_issue_page_url === '')
403 {
404 //260913.0454 REQUEST_URI already includes any WordPress subdirectory, so append it to the site origin instead of duplicating the home path.
405 $_asset_health_home_parts = c_ws_plugin__s2member_utils_urls::parse_url(home_url('/'));
406 if(is_array($_asset_health_home_parts) && !empty($_asset_health_home_parts['scheme']) && !empty($_asset_health_home_parts['host']))
407 $asset_health_last_issue_page_url = $_asset_health_home_parts['scheme'].'://'.$_asset_health_home_parts['host'].((!empty($_asset_health_home_parts['port'])) ? ':'.(int)$_asset_health_home_parts['port'] : '').'/'.ltrim($asset_health_last_issue_page_path, '/');
408 }
409 }
410 unset($_asset_type, $_asset_id, $_asset_build, $_asset_health_load, $_asset_health_result_labels, $_asset_health_result_label, $_asset_health_page_title, $_asset_health_home_parts);
411 //260910.0638 New Health Status section for easier review.
412 echo '<div class="ws-menu-page-hr"></div>'."\n";
413 echo '<h3 id="ws-plugin--s2member-asset-health">CSS/JS Asset Health: <span class="ws-plugin--s2member-status-light ws-plugin--s2member-status-light-'.esc_attr($asset_health['status']).'" aria-hidden="true"></span>'.esc_html($asset_health['status_label']).'</h3>'."\n";
414 echo '<table class="ws-plugin--s2member-status-table"><tbody>'."\n";
415 //260911.0627 Keep healthy rows compact: the status light carries health while the value names the active delivery method; only exceptions add status text.
416 foreach($asset_health['rows'] as $_asset_health_row)
417 {
418 $_asset_health_pending = ((string)$_asset_health_row['status_label'] === 'Pending rebuild');
419 $_asset_health_url = (!empty($_asset_health_row['url'])) ? (string)$_asset_health_row['url'] : '';
420 $_asset_health_delivery = (!empty($_asset_health_row['delivery'])) ? (string)$_asset_health_row['delivery'] : '';
421 $_asset_health_exception = '';
422 if((string)$_asset_health_row['status_label'] !== 'Healthy' && (string)$_asset_health_row['status_label'] !== 'Using dynamic fallback')
423 {
424 $_asset_health_exception_labels = array('Rebuild issue' => 'Rebuild issue', 'Fallback check failed' => 'Check failed', 'Delivery check failed' => 'Check failed');
425 $_asset_health_exception = (isset($_asset_health_exception_labels[$_asset_health_row['status_label']])) ? $_asset_health_exception_labels[$_asset_health_row['status_label']] : (string)$_asset_health_row['status_label'];
426 }
427 $_asset_health_value = $_asset_health_delivery.(($_asset_health_exception !== '') ? ''.$_asset_health_exception : '');
428 $_asset_health_not_generated = ($_asset_health_delivery === 'Static' && $_asset_health_url === '' && $_asset_health_exception === '' && !$_asset_health_pending);
429 if($_asset_health_not_generated)
430 $_asset_health_value .= ' — Not generated yet';
431 $_asset_health_light = ($_asset_health_pending || $_asset_health_not_generated) ? 'disabled' : (string)$_asset_health_row['status'];
432 $_asset_health_light_label = ($_asset_health_not_generated) ? 'Not generated yet' : (string)$_asset_health_row['status_label'];
433 if($_asset_health_pending || $_asset_health_not_generated)
434 $asset_health_pending_rebuild = TRUE; //260911.1924 Both neutral waiting states benefit from the shared automatic-rebuild explanation.
435 //260911.1924 A Pending rebuild URL names the previous generation, so hiding [open] avoids implying that it is the asset waiting to be created.
436 echo '<tr><th scope="row">'.esc_html($_asset_health_row['label']).':</th><td><span class="ws-plugin--s2member-status-light ws-plugin--s2member-status-light-'.esc_attr($_asset_health_light).'" style="margin-left:0; margin-right:.3em;" role="img" aria-label="'.esc_attr($_asset_health_light_label).'"></span>'.esc_html($_asset_health_value).((!$_asset_health_pending && $_asset_health_url !== '') ? '<span style="margin-left:.3em;">[<a href="'.esc_url($_asset_health_url).'" target="_blank" rel="noopener noreferrer">open</a>]</span>' : '').((!$_asset_health_pending && ($_asset_health_row['status'] !== 'healthy' || $_asset_health_delivery === 'Dynamic required') && (string)$_asset_health_row['detail'] !== '') ? '<br /><em>'.wp_kses_post($_asset_health_row['detail']).'</em>' : '').'</td></tr>'."\n";
437 }
438 echo '<tr><th scope="row">Last generation:</th><td>'.esc_html($asset_health_last_generation_label).'</td></tr>'."\n";
439 echo '<tr><th scope="row">Last trusted check:</th><td>'.esc_html($asset_health_last_check_label).'</td></tr>'."\n";
440 $_asset_health_last_issue_clear = ($asset_health_last_issue_time > 0) ? ' <span>[<a href="#" class="ws-plugin--s2member-clear-asset-health" data-scope="last_issue">clear</a>]</span>' : '';
441 $_asset_health_last_issue_page = ($asset_health_last_issue_page_label !== '') ? '<br />Page: '.esc_html($asset_health_last_issue_page_label).(($asset_health_last_issue_page_url !== '') ? ' [<a href="'.esc_url($asset_health_last_issue_page_url).'" target="_blank" rel="noopener noreferrer">open</a>]' : '') : '';
442 echo '<tr><th scope="row">Last issue'.$_asset_health_last_issue_clear.':</th><td>'.esc_html($asset_health_last_issue).(($asset_health_last_issue_detail !== '') ? '<br />'.esc_html($asset_health_last_issue_detail) : '').$_asset_health_last_issue_page.'</td></tr>'."\n";
443 echo '</tbody></table>'."\n";
444 unset($_asset_health_row, $_asset_health_pending, $_asset_health_not_generated, $_asset_health_light, $_asset_health_light_label, $_asset_health_url, $_asset_health_delivery, $_asset_health_exception, $_asset_health_exception_labels, $_asset_health_value);
445 if($asset_health_pending_rebuild)
446 //260911.1924 Keep neutral waiting states easy to understand; normal admin use now also provides an automatic recovery opportunity before frontend traffic is needed.
447 echo '<p style="margin:.75em 0 0;"><em style="background:#e8f8fb; padding:2px 4px;">* Static assets marked Not generated yet or Pending rebuild will be created or rebuilt automatically on a later admin or frontend page-load, or immediately with Refresh Static Assets.</em></p>'."\n";
448 //260910.0818 Recheck gives immediate confirmation after an admin fixes routing/access; preserve this panel/anchor so the refreshed result returns here.
449 echo '<p><button type="button" class="button" id="ws-plugin--s2member-recheck-asset-health">Recheck Asset Health</button> <span id="ws-plugin--s2member-recheck-asset-health-status" aria-live="polite"></span></p>'."\n";
450 echo '<script type="text/javascript">(function(){var b=document.getElementById("ws-plugin--s2member-recheck-asset-health");if(!b||!window.URL||!window.history||!window.history.replaceState)return;b.addEventListener("click",function(){var u=new URL(window.location.href);u.searchParams.set("s2member-open-panel","frontend-static-assets");u.hash="ws-plugin--s2member-asset-health";window.history.replaceState(null,"",u.toString());},true);})();</script>'."\n";
451 $asset_health_latest_issues = (!empty($asset_health['latest_issues']) && is_array($asset_health['latest_issues'])) ? $asset_health['latest_issues'] : array();
452 $asset_health_latest_issues_blocks = array();
453 $_asset_health_result_labels = array('late' => 'Late', 'fallback' => 'Fallback', 'failed' => 'Failed', 'fallback-unavailable' => 'Fallback unavailable', 'repaired' => 'Static asset missing / repaired');
454 foreach($asset_health_latest_issues as $_asset_health_issue)
455 {
456 if(!is_array($_asset_health_issue))
457 continue;
458 $_issue_result = (!empty($_asset_health_issue['result'])) ? (string)$_asset_health_issue['result'] : 'issue';
459 $_issue_result_label = (isset($_asset_health_result_labels[$_issue_result])) ? $_asset_health_result_labels[$_issue_result] : ucfirst(str_replace('-', ' ', $_issue_result));
460 $_issue_label = (!empty($_asset_health_issue['label'])) ? (string)$_asset_health_issue['label'] : 'Asset';
461 $_issue_lines = array($_issue_label.''.$_issue_result_label);
462 if(!empty($_asset_health_issue['detail']))
463 $_issue_lines[] = (string)$_asset_health_issue['detail'];
464 //260913.0305 Keep Latest Issues compact and copyable: show the full queryless frontend URL, then one precise occurrence timestamp per line.
465 $_issue_page_path = (!empty($_asset_health_issue['page_path'])) ? (string)$_asset_health_issue['page_path'] : '';
466 $_issue_page_url = '';
467 if($_issue_page_path !== '')
468 {
469 $_issue_home_parts = c_ws_plugin__s2member_utils_urls::parse_url(home_url('/'));
470 if(is_array($_issue_home_parts) && !empty($_issue_home_parts['scheme']) && !empty($_issue_home_parts['host']))
471 $_issue_page_url = $_issue_home_parts['scheme'].'://'.$_issue_home_parts['host'].((!empty($_issue_home_parts['port'])) ? ':'.(int)$_issue_home_parts['port'] : '').'/'.ltrim($_issue_page_path, '/');
472 }
473 if($_issue_page_url !== '')
474 $_issue_lines[] = 'Page: '.$_issue_page_url;
475 $_issue_count = (!empty($_asset_health_issue['count'])) ? max(1, (int)$_asset_health_issue['count']) : 1;
476 $_issue_times = array();
477 if(!empty($_asset_health_issue['times']) && is_array($_asset_health_issue['times']))
478 foreach($_asset_health_issue['times'] as $_issue_time)
479 if((int)$_issue_time > 0)
480 $_issue_times[] = date_i18n('Y-m-d H:i:s', (int)$_issue_time);
481 if($_issue_times)
482 {
483 if($_issue_count > count($_issue_times))
484 $_issue_lines[] = 'Seen '.number_format_i18n($_issue_count).' times. Latest '.number_format_i18n(count($_issue_times)).' occurrences:';
485 else
486 $_issue_lines[] = 'Seen '.number_format_i18n($_issue_count).' '.(($_issue_count === 1) ? 'time' : 'times').':';
487 $_issue_lines = array_merge($_issue_lines, $_issue_times);
488 }
489 else
490 $_issue_lines[] = 'Seen '.number_format_i18n($_issue_count).' '.(($_issue_count === 1) ? 'time.' : 'times.');
491 $asset_health_latest_issues_blocks[] = implode("\n", $_issue_lines);
492 }
493 $asset_health_latest_issues_text = ($asset_health_latest_issues_blocks) ? implode("\n\n", $asset_health_latest_issues_blocks) : 'No Asset Health issues are currently recorded.';
494 echo '<h3 style="margin:.75em 0 0;">Latest Issues'.(($asset_health_latest_issues) ? ' <span>[<a href="#" class="ws-plugin--s2member-clear-asset-health" data-scope="latest_issues">clear</a>]</span>' : '').'</h3>'."\n";
495 echo '<textarea id="ws-plugin--s2member-asset-health-latest-issues" rows="5" wrap="on" spellcheck="false" readonly="readonly" style="width:100%; max-width:100%; box-sizing:border-box; resize:vertical; box-shadow:inset 0 0 5px rgba(0,0,0,0.5); background:#EEEEEE; color:#000000; overflow-y:scroll;">'.esc_textarea($asset_health_latest_issues_text).'</textarea>'."\n";
496 echo '<p style="margin:.5em 0 0;"><em>s2Member keeps the latest 10 distinct Asset Health issues here until cleared. Repeated occurrences of the same issue on the same page are grouped together and keep up to 10 recent occurrence times. Clearing Last issue or Latest Issues does not change Current Health or its recent scoring history. Recheck Asset Health safely resets recent scoring history after current delivery and its fallback verify healthy. Enable s2Member logging for more detailed CSS/JavaScript troubleshooting history.</em></p>'."\n";
497 //260913.0056 Keep explicit historical clearing separate from Recheck; neither clear action changes rolling Health or current delivery state.
498 echo '<script type="text/javascript">jQuery(function($){$(document).on("click","a.ws-plugin--s2member-clear-asset-health",function(e){e.preventDefault();var $a=$(this),scope=$a.data("scope");if(!scope)return;$a.css("pointer-events","none");$.post(ajaxurl,{action:"ws_plugin__s2member_clear_asset_health_details",_ajax_nonce:"'.esc_js(wp_create_nonce('ws-plugin--s2member-clear-asset-health-details')).'",scope:scope}).done(function(){window.location.reload();}).fail(function(xhr){var r=xhr.responseJSON,m=r&&r.data&&r.data.message?r.data.message:"Asset Health details could not be cleared.";window.alert(m);$a.css("pointer-events","");});});});</script>'."\n";
499 unset($asset_health_latest_issues, $asset_health_latest_issues_blocks, $asset_health_latest_issues_text, $_asset_health_issue, $_asset_health_result_labels, $_issue_result, $_issue_result_label, $_issue_label, $_issue_lines, $_issue_page_path, $_issue_page_url, $_issue_home_parts, $_issue_count, $_issue_times, $_issue_time);
500 //260911.2004 Explain Asset Health in site-owner language, with scores first so the relationship between each result/status and its score is easy to scan.
501 echo '<h3 style="margin:1.5em 0 0;">How is this health status calculated? (<a href="#" onclick="jQuery(\'div#ws-plugin--s2member-asset-health-calculation\').toggle(); return false;" class="ws-dotted-link">click here</a>)</h3>'."\n";
502 echo '<div id="ws-plugin--s2member-asset-health-calculation" style="margin-top:10px; display:none;">'."\n";
503 echo '<p><em><strong>Page-load results:</strong> Each relevant frontend page-load gets one result with a score from 1 to 4. If a page uses several s2Member CSS or JavaScript assets, the least healthy result is used for that page.</em></p>'."\n";
504 echo '<ul style="margin:.5em 0 1em 2em;">'."\n";
505 echo '<li><em><strong>4 - Okay:</strong> The expected CSS and JavaScript became active normally.</em></li>'."\n";
506 echo '<li><em><strong>3 - Late:</strong> s2Member could not confirm all expected assets within the configured wait time. They may still have loaded afterward, so this is a warning rather than a failure.</em></li>'."\n";
507 echo '<li><em><strong>2 - Fallback:</strong> The preferred delivery method was unavailable, but s2Member recovered using a working fallback.</em></li>'."\n";
508 echo '<li><em><strong>1 - Failed:</strong> Working delivery could not be confirmed.</em></li>'."\n";
509 echo '</ul>'."\n";
510 //260911.2004 Keep neutral static-asset maintenance states separate from delivery problems and identify the manual control explicitly.
511 echo '<p><em><strong>Not generated yet / Pending rebuild:</strong> These are not delivery failures. The static asset either has not been created yet or needs to be rebuilt after a configuration, plugin, upgrade, or other change. s2Member normally handles this automatically on an admin or frontend page-load. You can also rebuild them immediately with the <strong>Refresh Static Assets</strong> button in this section.</em></p>'."\n";
512 echo '<p><em><strong>Current Health:</strong> s2Member combines recent results from the last 10 page-loads with requests from the last 10 minutes. Newer activity carries more weight, so Health can improve again as successful requests replace older problems.</em></p>'."\n";
513 //260912.1956 The Full WordPress route is the safety net for static and s2Member-Only delivery, so a trusted failure there should lower Health without pretending that visitors actually used a fallback.
514 echo '<p><em><strong>Fallback health:</strong> When preferred delivery is working but its Full WordPress fallback is unavailable, that failed fallback check is averaged into Current Health because the safety net would not be available if needed.</em></p>'."\n";
515 echo '<p><em><strong>Health status:</strong> The combined result is shown as one of these health levels:</em></p>'."\n";
516 echo '<ul style="margin:.5em 0 1em 2em;">'."\n";
517 echo '<li><em><strong>4.00 &ndash; 3.51 - Healthy</strong></em></li>'."\n";
518 echo '<li><em><strong>3.50 &ndash; 2.51 - Recent issue</strong></em></li>'."\n";
519 echo '<li><em><strong>2.50 &ndash; 1.51 - Working, review suggested</strong></em></li>'."\n";
520 echo '<li><em><strong>1.50 &ndash; 1.00 - Needs attention</strong></em></li>'."\n";
521 echo '</ul>'."\n";
522 echo '<p><em><strong>Examples:</strong> One Late result followed by normal page-loads may briefly show Recent issue and then return to Healthy. Repeated Fallback results can move Health to Working, review suggested. Repeated Failed results can move it to Needs attention.</em></p>'."\n";
523 //260911.2004 Describe the six-hour review using the visible Healthy status instead of internal color/score terminology.
524 echo '<p><em><strong>Longer-term review:</strong> A Late result is only a diagnostic signal; it does not make s2Member load another copy of the CSS or JavaScript. A current Needs attention status can trigger an immediate admin notice. If Health does not return to Healthy within six hours, s2Member also reviews activity across that period and may suggest a review when the longer-term result remains substantially degraded.</em></p>'."\n";
525 echo '</div>'."\n";
526 echo '</div>'."\n";
527
528 echo '<div style="margin:1em 0;">'."\n";
529 echo '<div class="ws-menu-page-hr"></div>'."\n";
530 echo '</div>'."\n";
531
532 echo '<div class="ws-menu-page-section ws-plugin--s2member-no-cache-headers-section">'."\n";
533 echo '<h3>No-Cache Headers Behavior (beta)</h3>'."\n";
534 echo '<p>s2Member can render different output depending on logged-in state, access level, conditionals (e.g., <code>[s2If]</code>), and nonce-based forms. If a cache stores a page generated under one context and serves it to another, visitors may see incorrect content or stale nonces. These options control when s2Member sends HTTP no-cache headers (<code>Cache-Control: no-cache</code>) to reduce that risk while allowing caching where appropriate.</p>'."\n";
535 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_no_cache_headers", get_defined_vars());
536 echo '<table class="form-table">'."\n";
537 echo '<tbody>'."\n";
538 echo '<tr>'."\n";
539
540 echo '<th>'."\n";
541 echo '<label for="ws-plugin--s2member-no-cache-headers-mode">'."\n";
542 echo 'When should no-cache headers be sent?'."\n";
543 echo '</label>'."\n";
544 echo '</th>'."\n";
545
546 echo '</tr>'."\n";
547 echo '<tr>'."\n";
548
549 echo '<td>'."\n";
550 echo '<select name="ws_plugin__s2member_no_cache_headers_mode" id="ws-plugin--s2member-no-cache-headers-mode">'."\n";
551 echo '<option value="always"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["no_cache_headers_mode"] === 'always') ? ' selected="selected"' : '').'>Always (disables guest caching site-wide)</option>'."\n";
552 echo '<option value="selective"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["no_cache_headers_mode"] === 'selective') ? ' selected="selected"' : '').'>Selective (may improve caching for guests)</option>'."\n";
553 echo '<option value="evaluative"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["no_cache_headers_mode"] === 'evaluative') ? ' selected="selected"' : '').'>Evaluative (better informed guest caching)</option>'."\n";
554 echo '</select><br />'."\n";
555 echo '<em>Choose when s2Member should send HTTP no-cache headers.</em>'."\n";
556 echo '<ul style="margin: .3em 0 0 1.1em; line-height: 1.5em;">'."\n";
557 echo '<li><strong>Always:</strong> <em>Sends no-cache headers very early on every page request. This is the safest behavior when member-conditional output could appear anywhere (content, widgets, theme templates, menus) and caching is not configured to vary correctly. It can reduce performance because it prevents caching for guests site-wide.</em></li>'."\n";
558 echo '<li><strong>Selective:</strong> <em>Enables selective behavior via the long-standing <code>ws_plugin__s2member_no_cache_headers_selective</code> filter used by customizations/plugins to change the default. Headers are still decided very early, actually too early to reliably reflect decisions made while a page renders (for example, when <code>[s2If]</code> or other shortcodes execute). This may improve caching for guests, but it can miss some runtime no-cache triggers in edge cases. Use this for backward compatibility if you already rely on it and understand the tradeoffs.</em></li>'."\n";
559 echo '<li><strong>Evaluative (beta):</strong> <em>Evaluates the page later, after s2Member shortcodes and other runtime checks have affected the page, resulting in better informed guest caching. No-cache headers are then sent at WordPress\' standard header-sending stage. Because this mode sends no-cache headers later than Always or Selective modes, it may expose “headers already sent” issues caused by another plugin or theme outputting content too early. Output added in widgets, menus, or theme templates may still require using Always or Selective mode.</em></li>'."\n";
560 echo '</ul>'."\n";
561
562 //260308 Sub-setting UI for no-cache debug header; label-based heading without extra divider.
563 echo '<p style="margin-top:25px; font-size: 115%;"><strong>Enable no-cache debug header?</strong></p>'."\n";
564 echo '<p>'."\n";
565 echo '<input type="radio" name="ws_plugin__s2member_no_cache_headers_debug" id="ws-plugin--s2member-no-cache-headers-debug-no" value="0"'.((empty($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["no_cache_headers_debug"])) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-no-cache-headers-debug-no">No</label> &nbsp;&nbsp;&nbsp;'."\n";
566 echo '<input type="radio" name="ws_plugin__s2member_no_cache_headers_debug" id="ws-plugin--s2member-no-cache-headers-debug-yes" value="1"'.((!empty($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["no_cache_headers_debug"])) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-no-cache-headers-debug-yes">Yes, add a debug header.</label><br />'."\n";
567 echo '<em>This adds a <code>Server-Timing</code> header to help troubleshoot why no-cache headers are being applied or not. This header includes the following variables:</em>'."\n";
568 echo '</p>'."\n";
569 echo '<ul style="margin: .3em 0 0 1.1em; line-height: 1.5em; font-style: italic;">'."\n";
570 echo '<li><code>mode</code> = Behavior mode in effect: <code>always</code>, <code>selective</code>, <code>evaluative</code>.</li>'."\n";
571 echo '<li><code>no_cache</code> = <code>1</code> means forced no-cache via filter; <code>0</code> means not forced.</li>'."\n";
572 echo '<li><code>selective</code> = <code>1</code> means selective behavior enabled; <code>0</code> means not enabled.</li>'."\n";
573 echo '<li><code>headers</code> = <code>1</code> means s2Member decided this request shouldn\'t be cached; <code>0</code> means it didn\'t.</li>'."\n";
574 echo '</ul>'."\n";
575
576 echo '</td>'."\n";
577
578 echo '</tr>'."\n";
579 echo '</tbody>'."\n";
580 echo '</table>'."\n";
581 echo '</div>'."\n";
582
583 echo '</div>'."\n";
584
585 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_after_lazy_load", get_defined_vars());
586 }
587 if(apply_filters("ws_plugin__s2member_during_gen_ops_page_during_left_sections_display_s_badge_wp_footer_code", TRUE, get_defined_vars()))
588 {
589 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_s_badge_wp_footer_code", get_defined_vars());
590
591 echo '<div class="ws-menu-page-group" title="s2Member Security Badge">'."\n";
592
593 echo '<div class="ws-menu-page-section ws-plugin--s2member-s-badge-wp-footer-code-section">'."\n";
594 echo '<h3>Security Badge &amp; Footer Configuration (optional)</h3>'."\n";
595 echo '<div class="ws-menu-page-right">'.c_ws_plugin__s2member_utilities::s_badge_gen("1", TRUE, TRUE).'</div>'."\n";
596 echo '<p>An s2Member Security Badge can be used to express your site\'s concern for security. To qualify your site, you must enable the Badge Status API (see below), and you must <a href="http://www.s2member.com/kb/security-badges/" target="_blank" rel="external">properly configure all security features in WordPress &amp; s2Member</a>. If you enable the Badge Status API, s2Member will make a connection to your site <strong>once per day</strong>, to test your status. Once your status is <code>1</code> (secure), <strong>it can then take up to 12 hours</strong> for your s2Member Security Badge image to show a green status for the first time.</p>'."\n";
597 echo '<p><strong>How does s2Member know when my site is secure?</strong><br />If enabled below, an API call for "Security Badge Status" will allow web service connections to determine your status. For example, clicking <a href="'.esc_attr(home_url("/?s2member_s_badge_status=1")).'" target="_blank" rel="external">this link</a> will report <code>1</code> (secure), <code>0</code> (at risk), or <code>-</code> (API disabled). Once you have <a href="http://www.s2member.com/kb/security-badges/" target="_blank" rel="external">properly configured all security features in WordPress &amp; s2Member</a>, the s2Member Badge Status API will report <code>1</code> (secure) for your installation. <strong>Note:</strong> this simple API will not, and should not, report any other information. It will only report the current status of your Security Badge, as determined by your installation of s2Member.</p>'."\n";
598 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_s_badge_wp_footer_code", get_defined_vars());
599
600 echo '<table class="form-table">'."\n";
601 echo '<tbody>'."\n";
602 echo '<tr>'."\n";
603
604 echo '<th>'."\n";
605 echo '<label for="ws-plugin--s2member-s-badge-status-enabled">'."\n";
606 echo 'Enable Security Badge Status API?'."\n";
607 echo '</label>'."\n";
608 echo '</th>'."\n";
609
610 echo '</tr>'."\n";
611 echo '<tr>'."\n";
612
613 echo '<td>'."\n";
614 echo '<select name="ws_plugin__s2member_s_badge_status_enabled" id="ws-plugin--s2member-s-badge-status-enabled">'."\n";
615 echo '<option value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["s_badge_status_enabled"]) ? ' selected="selected"' : '').'>No (default, Badge Status API is disabled)</option>'."\n";
616 echo '<option value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["s_badge_status_enabled"]) ? ' selected="selected"' : '').'>Yes (enable Badge Status API for verification)</option>'."\n";
617 echo '</select><br />'."\n";
618 echo '<em>This must be enabled if you want s2Member to verify your Security Badge each day.</em>'."\n";
619 echo '</td>'."\n";
620
621 echo '</tr>'."\n";
622 echo '<tr>'."\n";
623
624 echo '<th>'."\n";
625 echo '<label for="ws-plugin--s2member-wp-footer-code">'."\n";
626 echo 'Customize WordPress Footer:<br />'."\n";
627 echo '<small>[ <a href="#" onclick="this.$code = jQuery(\'textarea#ws-plugin--s2member-wp-footer-code\'); this.$code.val(jQuery.trim(unescape(\''.rawurlencode('[s2Member-Security-Badge v="1" /]').'\')+\'\n\'+this.$code.val())); return false;">Click HERE to insert your Security Badge</a> ],<br />or use Shortcode <code>[s2Member-Security-Badge v="1" /]</code> in a Post/Page/Widget.<br />The <code>v="1"</code> attribute is a Security Badge style/variation. Try variations <code>1|2|3</code>.</small>'."\n";
628 echo '</label>'."\n";
629 echo '</th>'."\n";
630
631 echo '</tr>'."\n";
632 echo '<tr>'."\n";
633
634 echo '<td>'."\n";
635 echo '<textarea name="ws_plugin__s2member_wp_footer_code" id="ws-plugin--s2member-wp-footer-code" rows="8" wrap="off" spellcheck="false">'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["wp_footer_code"]).'</textarea><br />'."\n";
636 echo 'Any valid XHTML / JavaScript'.((is_multisite() && c_ws_plugin__s2member_utils_conds::is_multisite_farm() && !is_main_site()) ? '' : ' (or even PHP)').' code will work just fine here.'."\n";
637 echo '</td>'."\n";
638
639 echo '</tr>'."\n";
640 echo '</tbody>'."\n";
641 echo '</table>'."\n";
642 echo '</div>'."\n";
643
644 echo '</div>'."\n";
645
646 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_after_s_badge_wp_footer_code", get_defined_vars());
647 }
648 if(apply_filters("ws_plugin__s2member_during_gen_ops_page_during_left_sections_display_email_config", TRUE, get_defined_vars()))
649 {
650 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_email_config", get_defined_vars());
651
652 echo '<div class="ws-menu-page-group" title="Email Configuration">'."\n";
653
654 echo '<div class="ws-menu-page-section ws-plugin--s2member-email-section">'."\n";
655 echo '<h3 style="margin:0;">Email From: '.esc_html('"Name" <address>').'</h3>'."\n";
656 echo '<p style="margin:0;">This is the name/address that will appear in outgoing email notifications sent by the s2Member plugin.</p>'."\n";
657 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_email_from_name_config", get_defined_vars());
658
659 echo '<table class="form-table">'."\n";
660 echo '<tbody>'."\n";
661 echo '<tr>'."\n";
662
663 echo '<th>'."\n";
664 echo '<label for="ws-plugin--s2member-reg-email-from-name">'."\n";
665 echo 'Email From Name:'."\n";
666 echo '</label>'."\n";
667 echo '</th>'."\n";
668
669 echo '</tr>'."\n";
670 echo '<tr>'."\n";
671
672 echo '<td>'."\n";
673 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_reg_email_from_name" id="ws-plugin--s2member-reg-email-from-name" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_name"]).'" /><br />'."\n";
674 echo 'We recommend that you use the name of your site here.'."\n";
675 echo '</td>'."\n";
676
677 echo '</tr>'."\n";
678 echo '<tr>'."\n";
679
680 echo '<th>'."\n";
681 echo '<label for="ws-plugin--s2member-reg-email-from-email">'."\n";
682 echo 'Email From Address:'."\n";
683 echo '</label>'."\n";
684 echo '</th>'."\n";
685
686 echo '</tr>'."\n";
687 echo '<tr>'."\n";
688
689 echo '<td>'."\n";
690 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_reg_email_from_email" id="ws-plugin--s2member-reg-email-from-email" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"]).'" /><br />'."\n";
691 echo 'Example: support@your-domain.com. <em>Please read <a href="#" onclick="alert(\'Running WordPress with an SMTP mail plugin?\\n\\nPlease be advised. If you run an SMTP mail plugin with WordPress, be sure to configure s2Member with a valid `From:` address (i.e., one matching your SMTP configuration perhaps). Most free SMTP servers, such as Gmail and Yahoo, require that your `From:` header match the email address associated with your account. Please check with your SMTP service provider before attempting to configure plugins like s2Member to use a different `From:` address when sending email messages.\'); return false;">this important note</a></em>.'."\n";
692 echo '</td>'."\n";
693
694 echo '</tr>'."\n";
695 echo '<tr>'."\n";
696
697 echo '<th>'."\n";
698 echo '<label for="ws-plugin--s2member-reg-email-support-link">'."\n";
699 echo 'Email Support/Contact Link:'."\n";
700 echo '</label>'."\n";
701 echo '</th>'."\n";
702
703 echo '</tr>'."\n";
704 echo '<tr>'."\n";
705
706 echo '<td>'."\n";
707 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_reg_email_support_link" id="ws-plugin--s2member-reg-email-support-link" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_support_link"]).'" /><br />'."\n";
708 echo 'Ex: <code>mailto:support@your-domain.com</code> (<em>mailto link</em>)<br />'."\n";
709 echo 'Or: <code>'.esc_html(home_url("/contact-us/")).'</code>'."\n";
710 echo '</td>'."\n";
711
712 echo '</tr>'."\n";
713 echo '</tbody>'."\n";
714 echo '</table>'."\n";
715
716 // New table for HTML Emails option.
717 echo '<div class="ws-menu-page-hr"></div>'."\n";
718
719 echo '<table class="form-table">' . "\n";
720 echo '<tbody>' . "\n";
721
722 echo '<tr>' . "\n";
723 echo '<th>' . "\n";
724 echo '<label for="ws-plugin--s2member-html-emails-enabled">' . "\n";
725 echo 'Enable HTML Emails? (beta)' . "\n";
726 echo '</label>' . "\n";
727 echo '</th>' . "\n";
728 echo '</tr>' . "\n";
729
730 echo '<tr>' . "\n";
731 echo '<td>' . "\n";
732 echo '<input type="radio" name="ws_plugin__s2member_html_emails_enabled" id="ws-plugin--s2member-html-emails-enabled-0" value="0"' . (empty($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["html_emails_enabled"]) ? ' checked="checked"' : '') . ' /> <label for="ws-plugin--s2member-html-emails-enabled-0">No</label> &nbsp;&nbsp;&nbsp;' . "\n";
733 echo '<input type="radio" name="ws_plugin__s2member_html_emails_enabled" id="ws-plugin--s2member-html-emails-enabled-1" value="1"' . (!empty($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["html_emails_enabled"]) ? ' checked="checked"' : '') . ' /> <label for="ws-plugin--s2member-html-emails-enabled-1">Yes, enable HTML emails.</label><br />' . "\n";
734 echo '<em>This enables s2Member to send HTML emails instead of just plain text. It applies to all emails you can edit in the s2Member options.</em>' . "\n";
735 echo '</td>' . "\n";
736 echo '</tr>' . "\n";
737
738 echo '</tbody>' . "\n";
739 echo '</table>' . "\n";
740
741 echo '<div class="ws-menu-page-hr"></div>'."\n";
742
743 echo '<h3 style="margin:0;">New User Email Configuration</h3>'."\n";
744 echo '<input type="hidden" id="ws-plugin--s2member-pluggables-wp-new-user-notification" value="'.esc_attr((empty($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["pluggables"]["wp_new_user_notification"])) ? '0' : '1').'" />'."\n";
745 echo (empty($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["pluggables"]["wp_new_user_notification"])) ? '<p class="ws-menu-page-error" style="margin:0;"><em><strong>Conflict warning:</strong> You have another theme or plugin installed that is preventing s2Member from controlling this aspect of your installation. When the pluggable function <code><a href="http://codex.wordpress.org/Function_Reference/wp_new_user_notification" target="_blank" rel="external">wp_new_user_notification()</a></code> is handled by another plugin, it\'s not possible for s2Member to allow customization of New User Emails. This is NOT a major issue. In fact, in some cases, it might be desirable. That being said, if you DO want to use s2Member\'s customization of New User Emails, you will need to deactivate one plugin at a time until this conflict warning goes away.</em></p>'."\n" : '';
746 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_new_user_emails", get_defined_vars());
747
748 echo '<table class="form-table">'."\n";
749 echo '<tbody>'."\n";
750 echo '<tr>'."\n";
751
752 echo '<td>'."\n";
753 echo '<select name="ws_plugin__s2member_new_user_emails_enabled" id="ws-plugin--s2member-new-user-emails-enabled">'."\n";
754 echo '<option value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["new_user_emails_enabled"]) ? ' selected="selected"' : '').'>No (default, use WordPress defaults)</option>'."\n";
755 echo '<option value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["new_user_emails_enabled"]) ? ' selected="selected"' : '').'>Yes (customize New User Emails with s2Member)</option>'."\n";
756 echo '</select>'."\n";
757 echo '</td>'."\n";
758
759 echo '</tr>'."\n";
760 echo '</tbody>'."\n";
761 echo '</table>'."\n";
762
763 echo '<div id="ws-plugin--s2member-new-user-emails">'."\n";
764
765 echo '<div class="ws-menu-page-hr"></div>'."\n";
766
767 echo '<h3 style="margin:0;">New User Email Message (<a href="#" onclick="jQuery(\'div#ws-plugin--s2member-new-user-email-details\').toggle(); return false;" class="ws-dotted-link">click to customize</a>)</h3>'."\n";
768 echo '<p style="margin:0;">This email is sent to new Users/Members who did <em>not</em> set a Custom Password during registration.</p>'."\n";
769 if($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_password"])
770 echo '<p class="info" style="font-size:80%; margin:.5em 0 0 0;"><strong>↑ NOTE:</strong> You currently have Custom Passwords enabled in your s2Member Registration/Profile Field options. Therefore, this email is not going to be sent; i.e., it is only sent to users who need it for the purpose of obtaining their password.</p>'."\n";
771 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_new_user_email", get_defined_vars());
772
773 echo '<div id="ws-plugin--s2member-new-user-email-details" style="display:none;">'."\n";
774 echo c_ws_plugin__s2member_utils_conds::bp_is_installed() ? '<p><em><strong>BuddyPress:</strong> please note that BuddyPress does NOT send this email to Users that register through the BuddyPress registration system. This is because BuddyPress sends each User an activation link; eliminating the need for this email altogether. However, you CAN still customize s2Member\'s separate email to paying Members. See: <strong>s2Member → PayPal Options → Signup Confirmation Email</strong>.</em></p>'."\n" : '';
775 echo '<table class="form-table">'."\n";
776 echo '<tbody>'."\n";
777 echo '<tr>'."\n";
778
779 echo '<th>'."\n";
780 echo '<label for="ws-plugin--s2member-new-user-email-subject">'."\n";
781 echo 'New User Email Subject:'."\n";
782 echo '</label>'."\n";
783 echo '</th>'."\n";
784
785 echo '</tr>'."\n";
786 echo '<tr>'."\n";
787
788 echo '<td>'."\n";
789 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_new_user_email_subject" id="ws-plugin--s2member-new-user-email-subject" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["new_user_email_subject"]).'" /><br />'."\n";
790 echo 'Subject Line used in the email sent to new Users/Members.'."\n";
791 echo '</td>'."\n";
792
793 echo '</tr>'."\n";
794 echo '<tr>'."\n";
795
796 echo '<th>'."\n";
797 echo '<label for="ws-plugin--s2member-new-user-email-message">'."\n";
798 echo 'New User Email Message:'."\n";
799 echo '</label>'."\n";
800 echo '</th>'."\n";
801
802 echo '</tr>'."\n";
803 echo '<tr>'."\n";
804
805 echo '<td>'."\n";
806 echo '<p><em>(The purpose of this email is to send the user a password-setup link; i.e., <code>%%wp_set_pass_url%%</code>)</em></small><p>'."\n";
807 //250615 Visual editor for HTML emails.
808 if (empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['html_emails_enabled'])) {
809 echo '<textarea name="ws_plugin__s2member_new_user_email_message" id="ws-plugin--s2member-new-user-email-message" rows="10">'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["new_user_email_message"]).'</textarea><br />'."\n";
810 } else {
811 c_ws_plugin__s2member_utilities::editor('new_user_email_message');
812 }
813
814 echo 'Message Body used in the email sent to new Users/Members.<br /><br />'."\n";
815 echo '<strong>You can also use these special Replacement Codes if you need them:</strong>'."\n";
816 echo '<ul>'."\n";
817 echo '<li style="margin-bottom:1em;"><code>%%wp_set_pass_url%%</code> = The full URL where Users can set their password for the first time. Note that <code>%%wp_set_pass_url%%</code> should be used instead of the older/deprecated <code style="text-decoration:line-through;">%%user_pass%%</code> Replacement Code. Starting w/ WordPress v4.3+, a user can visit this link (i.e., <code>%%wp_set_pass_url%%</code>) to set a password of their own, and this is accomplished without sending a plain-text password via email; which improves security. It is suggested that you prefix this as follows: <em>To set your password, visit: <code>%%wp_set_pass_url%%</code></em></li>'."\n";
818 echo '<li><code>%%role%%</code> = The Role ID <code>(subscriber, s2member_level[0-9]+, administrator, editor, author, contributor)</code>.</li>'."\n";
819 echo '<li><code>%%label%%</code> = The Role ID Label <code>(Subscriber, s2Member Level 1, s2Member Level 2; or your own custom Labels—if configured)</code>.</li>'."\n";
820 echo '<li><code>%%level%%</code> = The Level number <code>(0, 1, 2, 3, 4)</code>. (<em>deprecated, no longer recommended; use <code>%%role%%</code></em>)</li>'."\n";
821 echo '<li><code>%%ccaps%%</code> = Custom Capabilities. Ex: <code>music,videos,free_gift</code> (<em>in comma-delimited format</em>).</li>'."\n";
822 echo '<li><code>%%user_first_name%%</code> = The First Name of the Member who registered their Username.</li>'."\n";
823 echo '<li><code>%%user_last_name%%</code> = The Last Name of the Member who registered their Username.</li>'."\n";
824 echo '<li><code>%%user_full_name%%</code> = The Full Name (First &amp; Last) of the Member who registered their Username.</li>'."\n";
825 echo '<li><code>%%user_email%%</code> = The Email Address of the Member who registered their Username.</li>'."\n";
826 echo '<li><code>%%user_login%%</code> = The Username the Member selected during registration.</li>'."\n";
827 echo '<li><code>%%user_ip%%</code> = The User\'s IP Address, detected via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>'."\n";
828 echo '<li><code>%%user_id%%</code> = A unique WordPress User ID generated during registration.</li>'."\n";
829 echo '<li><code>%%wp_login_url%%</code> = The full URL where Users can get logged into your site.</li>'."\n";
830 echo '<li style="margin-top:1em;"><code style="text-decoration:line-through;">%%user_pass%%</code> = <em>Deprecated, please stop using this. Starting w/ WordPress v4.3, this email is only sent to users who did NOT set a Custom Password during registration; i.e., the New User Notification email is only sent to the user whenever they need it to set their password. In that scenario, you should be sending the user the <code>%%wp_set_pass_url%%</code> instead of sending a plain-text password via email; which is a security no-no.</em></li>'."\n";
831 echo '</ul>'."\n";
832
833 echo '<strong>Custom Registration/Profile Fields are also supported in this email:</strong>'."\n";
834 echo '<ul>'."\n";
835 echo '<li><code>%%date_of_birth%%</code> would be valid; if you have a Custom Registration/Profile Field with the ID <code>date_of_birth</code>.</li>'."\n";
836 echo '<li><code>%%street_address%%</code> would be valid; if you have a Custom Registration/Profile Field with the ID <code>street_address</code>.</li>'."\n";
837 echo '<li><code>%%country%%</code> would be valid; if you have a Custom Registration/Profile Field with the ID <code>country</code>.</li>'."\n";
838 echo '<li><em><code>%%etc, etc...%%</code> <strong>see:</strong> s2Member → General Options → Registration/Profile Fields</em>.</li>'."\n";
839 echo '</ul>'."\n";
840
841 echo '<strong>Custom Replacement Codes can also be inserted using these instructions:</strong>'."\n";
842 echo '<ul>'."\n";
843 echo '<li><code>%%cv0%%</code> = The domain of your site, which is passed through the `custom` attribute in your Shortcode.</li>'."\n";
844 echo '<li><code>%%cv1%%</code> = If you need to track additional custom variables, you can pipe delimit them into the `custom` attribute; inside your Shortcode, like this: <code>custom="'.esc_html($_SERVER["HTTP_HOST"]).'|cv1|cv2|cv3"</code>. You can have an unlimited number of custom variables. Obviously, this is for advanced webmasters; but the functionality has been made available for those who need it.</li>'."\n";
845 echo '</ul>'."\n";
846 echo '<strong>This example uses cv1 to record a special marketing campaign:</strong><br />'."\n";
847 echo '<em>(The campaign (i.e., christmas-promo) could be referenced using <code>%%cv1%%</code>)</em><br />'."\n";
848 echo '<code>custom="'.esc_html($_SERVER["HTTP_HOST"]).'|christmas-promo"</code>'."\n";
849
850 echo (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) ?
851 '<div class="ws-menu-page-hr"></div>'."\n".
852 '<p style="margin:0;"><strong>Advanced Customization:</strong> Further customization is possible with the <code>ws_plugin__s2member_welcome_email_sbj</code> and <code>ws_plugin__s2member_welcome_email_msg</code> filters from a plugin or theme.</p>'."\n"
853 : '';
854 echo '</td>'."\n";
855
856 echo '</tr>'."\n";
857 echo '</tbody>'."\n";
858 echo '</table>'."\n";
859 echo '</div>'."\n";
860
861 echo '<div class="ws-menu-page-hr"></div>'."\n";
862
863 echo '<h3 style="margin:0;">Administrative: New User Notification (<a href="#" onclick="jQuery(\'div#ws-plugin--s2member-new-user-admin-email-details\').toggle(); return false;" class="ws-dotted-link">click to customize</a>)</h3>'."\n";
864 echo '<p style="margin:0;">This email notification is sent to you, each time a new User/Member registers.</p>'."\n";
865 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_new_user_admin_email", get_defined_vars());
866
867 echo '<div id="ws-plugin--s2member-new-user-admin-email-details" style="display:none;">'."\n";
868 echo '<table class="form-table">'."\n";
869 echo '<tbody>'."\n";
870 echo '<tr>'."\n";
871
872 echo '<th>'."\n";
873 echo '<label for="ws-plugin--s2member-new-user-admin-email-recipients">'."\n";
874 echo 'New User Notification Recipients:'."\n";
875 echo '</label>'."\n";
876 echo '</th>'."\n";
877
878 echo '</tr>'."\n";
879 echo '<tr>'."\n";
880
881 echo '<td>'."\n";
882 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_new_user_admin_email_recipients" id="ws-plugin--s2member-new-user-admin-email-recipients" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["new_user_admin_email_recipients"]).'" /><br />'."\n";
883 echo 'This is a semicolon ( ; ) delimited list of Recipients. Here is an example:<br />'."\n";
884 echo '<code>"Name" &lt;user@example.com&gt;; admin@example.com; "Webmaster" &lt;webmaster@example.com&gt;</code>'."\n";
885 echo '</td>'."\n";
886
887 echo '</tr>'."\n";
888 echo '<tr>'."\n";
889
890 echo '<th>'."\n";
891 echo '<label for="ws-plugin--s2member-new-user-admin-email-subject">'."\n";
892 echo 'New User Notification Subject:'."\n";
893 echo '</label>'."\n";
894 echo '</th>'."\n";
895
896 echo '</tr>'."\n";
897 echo '<tr>'."\n";
898
899 echo '<td>'."\n";
900 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_new_user_admin_email_subject" id="ws-plugin--s2member-new-user-admin-email-subject" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["new_user_admin_email_subject"]).'" /><br />'."\n";
901 echo 'Subject Line used in the email notification sent to Administrator.'."\n";
902 echo '</td>'."\n";
903
904 echo '</tr>'."\n";
905 echo '<tr>'."\n";
906
907 echo '<th>'."\n";
908 echo '<label for="ws-plugin--s2member-new-user-admin-email-message">'."\n";
909 echo 'New User Notification Message:'."\n";
910 echo '</label>'."\n";
911 echo '</th>'."\n";
912
913 echo '</tr>'."\n";
914 echo '<tr>'."\n";
915
916 echo '<td>'."\n";
917 //250615 Visual editor for HTML emails.
918 if (empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['html_emails_enabled'])) {
919 echo '<textarea name="ws_plugin__s2member_new_user_admin_email_message" id="ws-plugin--s2member-new-user-admin-email-message" rows="10">'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["new_user_admin_email_message"]).'</textarea><br />'."\n";
920 } else {
921 c_ws_plugin__s2member_utilities::editor('new_user_admin_email_message');
922 }
923
924 echo 'Message Body used in the email notification sent to Administrator.<br /><br />'."\n";
925 echo '<strong>You can also use these special Replacement Codes if you need them:</strong>'."\n";
926 echo '<ul>'."\n";
927 echo '<li><code>%%role%%</code> = The Role ID <code>(subscriber, s2member_level[0-9]+, administrator, editor, author, contributor)</code>.</li>'."\n";
928 echo '<li><code>%%label%%</code> = The Role ID Label <code>(Subscriber, s2Member Level 1, s2Member Level 2; or your own custom Labels—if configured)</code>.</li>'."\n";
929 echo '<li><code>%%level%%</code> = The Level number <code>(0, 1, 2, 3, 4)</code>. (<em>deprecated, no longer recommended; use <code>%%role%%</code></em>)</li>'."\n";
930 echo '<li><code>%%ccaps%%</code> = Custom Capabilities. Ex: <code>music,videos,free_gift</code> (<em>in comma-delimited format</em>).</li>'."\n";
931 echo '<li><code>%%user_first_name%%</code> = The First Name of the Member who registered their Username.</li>'."\n";
932 echo '<li><code>%%user_last_name%%</code> = The Last Name of the Member who registered their Username.</li>'."\n";
933 echo '<li><code>%%user_full_name%%</code> = The Full Name (First &amp; Last) of the Member who registered their Username.</li>'."\n";
934 echo '<li><code>%%user_email%%</code> = The Email Address of the Member who registered their Username.</li>'."\n";
935 echo '<li><code>%%user_login%%</code> = The Username the Member selected during registration.</li>'."\n";
936 echo '<li><code>%%user_ip%%</code> = The User\'s IP Address, detected via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>'."\n";
937 echo '<li><code>%%user_id%%</code> = A unique WordPress User ID generated during registration.</li>'."\n";
938 echo '<li><code>%%wp_login_url%%</code> = The full URL where Users can get logged into your site.</li>'."\n";
939 echo '<li style="margin-top:1em;"><code style="text-decoration:line-through;">%%user_pass%%</code> = <em>Deprecated. Starting w/ WordPress v4.3, this is no longer applicable (or advised).</em></li>'."\n";
940 echo '</ul>'."\n";
941
942 echo '<strong>Custom Registration/Profile Fields are also supported in this email:</strong>'."\n";
943 echo '<ul>'."\n";
944 echo '<li><code>%%date_of_birth%%</code> would be valid; if you have a Custom Registration/Profile Field with the ID <code>date_of_birth</code>.</li>'."\n";
945 echo '<li><code>%%street_address%%</code> would be valid; if you have a Custom Registration/Profile Field with the ID <code>street_address</code>.</li>'."\n";
946 echo '<li><code>%%country%%</code> would be valid; if you have a Custom Registration/Profile Field with the ID <code>country</code>.</li>'."\n";
947 echo '<li><em><code>%%etc, etc...%%</code> <strong>see:</strong> s2Member → General Options → Registration/Profile Fields</em>.</li>'."\n";
948 echo '</ul>'."\n";
949
950 echo '<strong>Custom Replacement Codes can also be inserted using these instructions:</strong>'."\n";
951 echo '<ul>'."\n";
952 echo '<li><code>%%cv0%%</code> = The domain of your site, which is passed through the `custom` attribute in your Shortcode.</li>'."\n";
953 echo '<li><code>%%cv1%%</code> = If you need to track additional custom variables, you can pipe delimit them into the `custom` attribute; inside your Shortcode, like this: <code>custom="'.esc_html($_SERVER["HTTP_HOST"]).'|cv1|cv2|cv3"</code>. You can have an unlimited number of custom variables. Obviously, this is for advanced webmasters; but the functionality has been made available for those who need it.</li>'."\n";
954 echo '</ul>'."\n";
955 echo '<strong>This example uses cv1 to record a special marketing campaign:</strong><br />'."\n";
956 echo '<em>(The campaign (i.e., christmas-promo) could be referenced using <code>%%cv1%%</code>)</em><br />'."\n";
957 echo '<code>custom="'.esc_html($_SERVER["HTTP_HOST"]).'|christmas-promo"</code>'."\n";
958
959 echo (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) ?
960 '<div class="ws-menu-page-hr"></div>'."\n".
961 '<p style="margin:0;"><strong>Advanced Customization:</strong> Further customization of the recipients, subject, and message is possible with the <code>ws_plugin__s2member_admin_new_user_email_recipients</code>, <code>ws_plugin__s2member_admin_new_user_email_sbj</code>, and <code>ws_plugin__s2member_admin_new_user_email_msg</code> filters from a plugin or theme.</p>'."\n"
962 : '';
963 echo '</td>'."\n";
964
965 echo '</tr>'."\n";
966 echo '</tbody>'."\n";
967 echo '</table>'."\n";
968 echo '</div>'."\n";
969 echo '</div>'."\n";
970
971 echo '</div>'."\n";
972
973 echo '</div>'."\n";
974
975 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_after_email_config", get_defined_vars());
976 }
977 if(apply_filters("ws_plugin__s2member_during_gen_ops_page_during_left_sections_display_open_registration", TRUE, get_defined_vars()))
978 {
979 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_open_registration", get_defined_vars());
980
981 if(is_multisite() && is_main_site()) // A Multisite Network, and we're on the Main Site?
982 {
983 echo '<div class="ws-menu-page-group" title="Open Registration">'."\n";
984
985 echo '<div class="ws-menu-page-section ws-plugin--s2member-open-registration-section">'."\n";
986 echo '<h3>Open Registration / Free Subscribers (optional)</h3>'."\n";
987 echo '<p>On the Main Site of a Multisite Network, the settings for Open Registration are consolidated into the <strong>s2Member → Multisite (Config)</strong> panel.</p>'."\n";
988 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_open_registration", get_defined_vars());
989 echo '</div>'."\n";
990
991 echo '</div>'."\n";
992 }
993 else // Else we display this section normally. No special considerations are required in this case.
994 {
995 echo '<div class="ws-menu-page-group" title="Open Registration">'."\n";
996
997 echo '<div class="ws-menu-page-section ws-plugin--s2member-open-registration-section">'."\n";
998 echo '<h3>Open Registration / Free Subscribers (optional)</h3>'."\n";
999 echo '<p>s2Member supports Free Subscribers (at Level #0), along with four Primary Levels [1-4] of paid Membership. If you want your visitors to be capable of registering absolutely free, you will want to "allow" Open Registration. Whenever a visitor registers without paying, they\'ll automatically become a Free Subscriber at Level #0.</p>'."\n";
1000 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_open_registration", get_defined_vars());
1001
1002 echo '<table class="form-table">'."\n";
1003 echo '<tbody>'."\n";
1004 echo '<tr>'."\n";
1005
1006 echo '<th>'."\n";
1007 echo '<label for="ws-plugin--s2member-allow-subscribers-in">'."\n";
1008 echo 'Allow Open Registration? (Free Subscribers)'."\n";
1009 echo '</label>'."\n";
1010 echo '</th>'."\n";
1011
1012 echo '</tr>'."\n";
1013 echo '<tr>'."\n";
1014
1015 echo '<td>'."\n";
1016 echo '<select name="ws_plugin__s2member_allow_subscribers_in" id="ws-plugin--s2member-allow-subscribers-in">'."\n";
1017 echo '<option value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["allow_subscribers_in"]) ? ' selected="selected"' : '').'>No (do NOT allow Open Registration)</option>'."\n";
1018 echo '<option value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["allow_subscribers_in"]) ? ' selected="selected"' : '').'>Yes (allow Open Registration; Free Subscribers at Level #0)</option>'."\n";
1019 echo '</select><br />'."\n";
1020 echo 'If you set this to <code>Yes</code>, you\'re unlocking <a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::wp_register_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your Standard Registration Form.\\n* s2Member makes this form available to logged-in Administrators, at all times (for testing purposes), regardless of configuration.'.((c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '\\n\\nBuddyPress: BuddyPress will use its own Registration Form. Please note, you will probably be redirected away from the BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re already logged-in. Please log out before testing BuddyPress registration.' : '').'\');">/wp-login.php?action=register</a>. When a visitor registers without paying, they\'ll automatically become a Free Subscriber at Level #0. The s2Member software reserves Level #0; to be used only for Free Subscribers. All other Membership Levels [1-4] require payment.'."\n";
1021 echo (c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '<br /><br /><em><strong>BuddyPress:</strong> BuddyPress will use its own Registration Form <a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::bp_register_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your BuddyPress Registration Form.\\n* However, you will probably be redirected away from this BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re already logged-in. Please log out before testing BuddyPress registration.\');">here</a>.<br />s2Member integrates with BuddyPress, and the above setting will control Open Regisration for BuddyPress too.</em>'."\n" : '';
1022 echo '</td>'."\n";
1023
1024 echo '</tr>'."\n";
1025 echo '</tbody>'."\n";
1026 echo '</table>'."\n";
1027 echo '</div>'."\n";
1028
1029 echo '</div>'."\n";
1030 }
1031 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_after_open_registration", get_defined_vars());
1032 }
1033 if(apply_filters("ws_plugin__s2member_during_gen_ops_page_during_left_sections_display_membership_levels", TRUE, get_defined_vars()))
1034 {
1035 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_membership_levels", get_defined_vars());
1036
1037 echo '<div class="ws-menu-page-group" title="Membership Levels/Labels">'."\n";
1038
1039 echo '<div class="ws-menu-page-section ws-plugin--s2member-membership-levels-section">'."\n";
1040 echo '<h3>Membership Levels (required, please customize these)</h3>'."\n";
1041 echo '<p>The default Membership Levels are labeled generically; feel free to modify them as needed. s2Member supports Free Subscribers <em>(at Level #0)</em>, along with several Primary Roles for paid Membership <em>(i.e., Levels 1-4)</em>, created by the s2Member plugin.'.((!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) ? ' s2Member also supports unlimited Custom Capability Packages <em>(see <strong>s2Member → API Scripting → Custom Capabilities</strong>)</em>' : '').'. That being said, you don\'t have to use all of the Membership Levels if you don\'t want to. To use only 1 or 2 of these Levels, just design your Membership Options Page, so it only includes Payment Buttons for the Levels being used.</p>'."\n";
1042 echo (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) ? '<p><em><strong>TIP:</strong> <strong>Unlimited Membership Levels</strong> are only possible with <a href="http://s2member.com/prices/" target="_blank" rel="external">s2Member Pro</a>. However, Custom Capabilities are possible in all versions of s2Member, including the free version. Custom Capabilities are a great way to extend s2Member in creative ways. If you\'re an advanced site owner, a theme designer, or a web developer integrating s2Member for a client, please check your Dashboard, under: <strong>s2Member → API Scripting → Custom Capabilities</strong>. We also recommend <a href="https://s2member.com/r/s2member-video-custom-capabilities-for-wordpress/" target="_blank" rel="external">this video tutorial</a>.</em></p>'."\n" : '';
1043 echo (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) ? '<p><strong>See also:</strong> These KB articles: <a href="http://www.s2member.com/kb/roles-caps/" target="_blank" rel="external">s2Member Roles/Capabilities</a> and <a href="http://www.s2member.com/kb/simple-shortcode-conditionals/" target="_blank" rel="external">Simple Shortcode Conditionals</a>.</p>'."\n" : '';
1044 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_membership_levels", get_defined_vars());
1045
1046 echo '<table class="form-table">'."\n";
1047 echo '<tbody>'."\n";
1048
1049 for($n = 0; $n <= $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]; $n++)
1050 {
1051 echo '<tr>'."\n";
1052
1053 echo '<th>'."\n";
1054 echo '<label for="ws-plugin--s2member-level'.$n.'-label">'."\n";
1055 echo ($n === 0) ? 'Level #'.$n.' <em>(Free Subscribers)</em>:'."\n" : 'Level #'.$n.' Members:'."\n";
1056 echo '</label>'."\n";
1057 echo '</th>'."\n";
1058
1059 echo '</tr>'."\n";
1060 echo '<tr>'."\n";
1061
1062 echo '<td>'."\n";
1063 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_level'.$n.'_label" id="ws-plugin--s2member-level'.$n.'-label" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level".$n."_label"]).'" /><br />'."\n";
1064 echo 'This is the Label for Level #'.$n.(($n === 0) ? ' (Free Subscribers)' : ' Members').'.<br />'."\n";
1065 echo '</td>'."\n";
1066
1067 echo '</tr>'."\n";
1068 }
1069 echo '</tbody>'."\n";
1070 echo '</table>'."\n";
1071
1072 echo '<div class="ws-menu-page-hr"></div>'."\n";
1073
1074 echo '<table class="form-table" style="margin-top:0;">'."\n";
1075 echo '<tbody>'."\n";
1076 echo '<tr>'."\n";
1077
1078 echo '<th style="padding-top:0;">'."\n";
1079 echo '<label for="ws-plugin--s2member-apply-label-translations">'."\n";
1080 echo 'Force WordPress to use your Labels?'."\n";
1081 echo '</label>'."\n";
1082 echo '</th>'."\n";
1083
1084 echo '</tr>'."\n";
1085 echo '<tr>'."\n";
1086
1087 echo '<td>'."\n";
1088 echo '<input type="radio" name="ws_plugin__s2member_apply_label_translations" id="ws-plugin--s2member-apply-label-translations-0" value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["apply_label_translations"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-apply-label-translations-0">No</label> &nbsp;&nbsp;&nbsp; <input type="radio" name="ws_plugin__s2member_apply_label_translations" id="ws-plugin--s2member-apply-label-translations-1" value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["apply_label_translations"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-apply-label-translations-1">Yes, force WordPress to use my Labels.</label><br />'."\n";
1089 echo 'This affects your administrative Dashboard only <em>(i.e., your list of Users)</em>.<br />s2Member can force WordPress to use your Labels instead of referencing Roles by `s2Member Level #`. If this is your first installation of s2Member, we suggest leaving this set to <code>no</code> until you\'ve had a chance to get acclimated with s2Member\'s functionality. In fact, many site owners choose to leave this off, because they find it less confusing when Roles are referred to by their s2Member Level #.'."\n";
1090 echo '</td>'."\n";
1091
1092 echo '</tr>'."\n";
1093 echo '</tbody>'."\n";
1094 echo '</table>'."\n";
1095
1096 echo '<div class="ws-menu-page-hr"></div>'."\n";
1097
1098 echo '<input type="button" value="Reset Roles/Capabilities" class="ws-menu-page-right ws-plugin--s2member-reset-roles-button" style="min-width:175px;" />'."\n";
1099 echo '<p>The button to the right, is a nifty tool, which allows you to reset s2Member\'s internal Roles and Capabilities that integrate with WordPress. If you, or a developer working with you, has made attempts to alter the default <em>internal</em> Role/Capability sets that come with s2Member, and you need to reset them back to the way s2Member expects them to be, please use this tool. <em>Attn Developers: it is also possible lock-in your modified Roles/Capabilities with an s2Member Filter. Please see <a href="http://s2member.com/kb-article/locking-s2member-rolescapabilities/" target="_blank" rel="external">this KB article for details</a>.</em></p>'."\n";
1100
1101 echo '</div>'."\n";
1102
1103 echo '</div>'."\n";
1104
1105 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_after_membership_levels", get_defined_vars());
1106 }
1107 if(apply_filters("ws_plugin__s2member_during_gen_ops_page_during_left_sections_display_login_registration", TRUE, get_defined_vars()))
1108 {
1109 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_login_registration", get_defined_vars());
1110
1111 echo '<div class="ws-menu-page-group" title="Login/Registration Design">'."\n";
1112
1113 echo '<div class="ws-menu-page-section ws-plugin--s2member-login-registration-section">'."\n";
1114 echo '<h3>Login/Registration Page Customization (optional)</h3>'."\n";
1115 echo '<p>These settings customize your Standard Login/Registration Pages:<br />(<a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::wp_register_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your Standard Registration Form.\\n* s2Member makes this form available to logged-in Administrators, at all times (for testing purposes), regardless of configuration.'.((c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '\\n\\nBuddyPress: * BuddyPress will use its own Registration Form. Please note, you will probably be redirected away from the BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re ALREADY logged-in. Please log out before testing BuddyPress registration.' : '').'\');">'.esc_html(c_ws_plugin__s2member_utils_urls::wp_register_url()).'</a>)</p>'."\n";
1116 echo (is_multisite() && c_ws_plugin__s2member_utils_conds::is_multisite_farm() && is_main_site()) ? '<p><em>The Main Site of a Multisite Blog Farm uses this Form instead, powered by your theme.<br />(<a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::wp_signup_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your Multisite Registration Form.\\n* s2Member makes this form available to logged-in Super Administrators, at all times (for testing purposes), regardless of configuration.'.((c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '\\n\\nBuddyPress: * BuddyPress will use its own Registration Form. Please note, you will probably be redirected away from the BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re ALREADY logged-in. Please log out before testing BuddyPress registration.' : '').'\');">'.esc_html(c_ws_plugin__s2member_utils_urls::wp_signup_url()).'</a>)</em></p>'."\n" : '';
1117 echo (c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '<p><em><strong>BuddyPress:</strong> BuddyPress will use its own Registration Form, powered by your theme.<br />(<a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::bp_register_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your BuddyPress Registration Form.\\n* However, you will probably be redirected away from this BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re ALREADY logged-in. Please log out before testing BuddyPress registration.\');">'.esc_html(c_ws_plugin__s2member_utils_urls::bp_register_url()).'</a>)</em></p>'."\n" : '';
1118 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_login_registration", get_defined_vars());
1119
1120 echo '<table class="form-table">'."\n";
1121 echo '<tbody>'."\n";
1122 echo '<tr>'."\n";
1123
1124 echo '<td>'."\n";
1125 echo '<h3 style="margin:0;">Enable This Functionality?</h3>'."\n";
1126 echo '<select name="ws_plugin__s2member_login_reg_design_enabled" id="ws-plugin--s2member-login-reg-design-enabled">'."\n";
1127 echo '<option value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_design_enabled"]) ? ' selected="selected"' : '').'>No (default, use WordPress defaults)</option>'."\n";
1128 echo '<option value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_design_enabled"]) ? ' selected="selected"' : '').'>Yes (customize Login/Registration with s2Member)</option>'."\n";
1129 echo '</select>'."\n";
1130 echo '</td>'."\n";
1131
1132 echo '</tr>'."\n";
1133 echo '</tbody>'."\n";
1134 echo '</table>'."\n";
1135
1136 echo '<div id="ws-plugin--s2member-login-reg-design"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_design_enabled"]) ? ' style="display:none;"' : '').'>'."\n";
1137
1138 echo '<div class="ws-menu-page-hr"></div>'."\n";
1139
1140 echo '<table class="form-table">'."\n";
1141 echo '<tbody>'."\n";
1142 echo '<tr>'."\n";
1143
1144 echo '<td>'."\n";
1145 echo '<h3 style="margin:0;">Overall Font/Size Configuration</h3>'."\n";
1146 echo '<p style="margin:0;">These settings are all focused on your Login/Registration Fonts.</p>'."\n";
1147 echo '</td>'."\n";
1148
1149 echo '</tr>'."\n";
1150 echo '<tr>'."\n";
1151
1152 echo '<th>'."\n";
1153 echo '<label for="ws-plugin--s2member-login-reg-font-size">'."\n";
1154 echo 'Overall Font Size:'."\n";
1155 echo '</label>'."\n";
1156 echo '</th>'."\n";
1157
1158 echo '</tr>'."\n";
1159 echo '<tr>'."\n";
1160
1161 echo '<td>'."\n";
1162 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_reg_font_size" id="ws-plugin--s2member-login-reg-font-size" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_font_size"]).'" /><br />'."\n";
1163 echo 'Set this to a numeric value, calculated in pixels.'."\n";
1164 echo '</td>'."\n";
1165
1166 echo '</tr>'."\n";
1167 echo '<tr>'."\n";
1168
1169 echo '<th>'."\n";
1170 echo '<label for="ws-plugin--s2member-login-reg-font-family">'."\n";
1171 echo 'Overall Font Family:'."\n";
1172 echo '</label>'."\n";
1173 echo '</th>'."\n";
1174
1175 echo '</tr>'."\n";
1176 echo '<tr>'."\n";
1177
1178 echo '<td>'."\n";
1179 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_reg_font_family" id="ws-plugin--s2member-login-reg-font-family" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_font_family"]).'" /><br />'."\n";
1180 echo 'Set this to a web-safe font family.'."\n";
1181 echo '</td>'."\n";
1182
1183 echo '</tr>'."\n";
1184 echo '<tr>'."\n";
1185
1186 echo '<th>'."\n";
1187 echo '<label for="ws-plugin--s2member-login-reg-font-field-size">'."\n";
1188 echo 'Form Field Font Size:'."\n";
1189 echo '</label>'."\n";
1190 echo '</th>'."\n";
1191
1192 echo '</tr>'."\n";
1193 echo '<tr>'."\n";
1194
1195 echo '<td>'."\n";
1196 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_reg_font_field_size" id="ws-plugin--s2member-login-reg-font-field-size" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_font_field_size"]).'" /><br />'."\n";
1197 echo 'Set this to a numeric value, calculated in pixels.'."\n";
1198 echo '</td>'."\n";
1199
1200 echo '</tr>'."\n";
1201 echo '</tbody>'."\n";
1202 echo '</table>'."\n";
1203
1204 echo '<div class="ws-menu-page-hr"></div>'."\n";
1205
1206 echo '<table class="form-table" style="margin-top:0;">'."\n";
1207 echo '<tbody>'."\n";
1208 echo '<tr>'."\n";
1209
1210 echo '<td>'."\n";
1211 echo '<h3 style="margin:0;">Background Configuration</h3>'."\n";
1212 echo '<p style="margin:0;">These settings are all focused on your Login/Registration Background.</p>'."\n";
1213 echo '</td>'."\n";
1214
1215 echo '</tr>'."\n";
1216 echo '<tr>'."\n";
1217
1218 echo '<th>'."\n";
1219 echo '<label for="ws-plugin--s2member-login-reg-background-color">'."\n";
1220 echo 'Background Color:'."\n";
1221 echo '</label>'."\n";
1222 echo '</th>'."\n";
1223
1224 echo '</tr>'."\n";
1225 echo '<tr>'."\n";
1226
1227 echo '<td>'."\n";
1228 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_reg_background_color" id="ws-plugin--s2member-login-reg-background-color" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_background_color"]).'" /><br />'."\n";
1229 echo 'Set this to a 6-digit hex color code.'."\n";
1230 echo '</td>'."\n";
1231
1232 echo '</tr>'."\n";
1233 echo '<tr>'."\n";
1234
1235 echo '<th>'."\n";
1236 echo '<label for="ws-plugin--s2member-login-reg-background-image">'."\n";
1237 echo 'Background Image:'."\n";
1238 echo '</label>'."\n";
1239 echo '</th>'."\n";
1240
1241 echo '</tr>'."\n";
1242 echo '<tr>'."\n";
1243
1244 echo '<td>'."\n";
1245 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_reg_background_image" id="ws-plugin--s2member-login-reg-background-image" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_background_image"]).'" /><br />'."\n";
1246 echo '<input type="button" id="ws-plugin--s2member-login-reg-background-image-media-btn" value="Open Media Library" class="ws-menu-page-media-btn" rel="ws-plugin--s2member-login-reg-background-image" />'."\n";
1247 echo 'Set this to the URL of your Background Image. (this is optional)<br />';
1248 echo 'If supplied, your Background Image will be tiled.'."\n";
1249 echo '</td>'."\n";
1250
1251 echo '</tr>'."\n";
1252 echo '<tr>'."\n";
1253
1254 echo '<th>'."\n";
1255 echo '<label for="ws-plugin--s2member-login-reg-background-image-repeat">'."\n";
1256 echo 'Background Image Tile:'."\n";
1257 echo '</label>'."\n";
1258 echo '</th>'."\n";
1259
1260 echo '</tr>'."\n";
1261 echo '<tr>'."\n";
1262
1263 echo '<td>'."\n";
1264 echo '<select name="ws_plugin__s2member_login_reg_background_image_repeat" id="ws-plugin--s2member-login-reg-background-image-repeat">'."\n";
1265 echo '<option value="repeat"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_background_image_repeat"] === "repeat") ? ' selected="selected"' : '').'>Seamless Tile ( background-repeat: repeat; )</option>'."\n";
1266 echo '<option value="repeat-x"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_background_image_repeat"] === "repeat-x") ? ' selected="selected"' : '').'>Tile Horizontally ( background-repeat: repeat-x; )</option>'."\n";
1267 echo '<option value="repeat-y"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_background_image_repeat"] === "repeat-y") ? ' selected="selected"' : '').'>Tile Vertically ( background-repeat: repeat-y; )</option>'."\n";
1268 echo '<option value="no-repeat"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_background_image_repeat"] === "no-repeat") ? ' selected="selected"' : '').'>No Tiles ( background-repeat: no-repeat; )</option>'."\n";
1269 echo '</select><br />'."\n";
1270 echo 'This controls the way your Background Image is styled with CSS. [ <a href="http://s2member.com/r/css-background-repeat/" target="_blank" rel="external">learn more</a> ]'."\n";
1271 echo '</td>'."\n";
1272
1273 echo '</tr>'."\n";
1274 echo '<tr>'."\n";
1275
1276 echo '<th>'."\n";
1277 echo '<label for="ws-plugin--s2member-login-reg-background-text-color">'."\n";
1278 echo 'Color of Text on top of your Background:'."\n";
1279 echo '</label>'."\n";
1280 echo '</th>'."\n";
1281
1282 echo '</tr>'."\n";
1283 echo '<tr>'."\n";
1284
1285 echo '<td>'."\n";
1286 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_reg_background_text_color" id="ws-plugin--s2member-login-reg-background-text-color" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_background_text_color"]).'" /><br />'."\n";
1287 echo 'Set this to a 6-digit hex color code.'."\n";
1288 echo '</td>'."\n";
1289
1290 echo '</tr>'."\n";
1291 echo '<tr>'."\n";
1292
1293 echo '<th>'."\n";
1294 echo '<label for="ws-plugin--s2member-login-reg-background-text-shadow-color">'."\n";
1295 echo 'Shadow Color for Text on top of your Background:'."\n";
1296 echo '</label>'."\n";
1297 echo '</th>'."\n";
1298
1299 echo '</tr>'."\n";
1300 echo '<tr>'."\n";
1301
1302 echo '<td>'."\n";
1303 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_reg_background_text_shadow_color" id="ws-plugin--s2member-login-reg-background-text-shadow-color" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_background_text_shadow_color"]).'" /><br />'."\n";
1304 echo 'Set this to a 6-digit hex color code.'."\n";
1305 echo '</td>'."\n";
1306
1307 echo '</tr>'."\n";
1308 echo '<tr>'."\n";
1309
1310 echo '<th>'."\n";
1311 echo '<label for="ws-plugin--s2member-login-reg-background-box-shadow-color">'."\n";
1312 echo 'Shadow Color for Boxes on top of your Background:'."\n";
1313 echo '</label>'."\n";
1314 echo '</th>'."\n";
1315
1316 echo '</tr>'."\n";
1317 echo '<tr>'."\n";
1318
1319 echo '<td>'."\n";
1320 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_reg_background_box_shadow_color" id="ws-plugin--s2member-login-reg-background-box-shadow-color" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_background_box_shadow_color"]).'" /><br />'."\n";
1321 echo 'Set this to a 6-digit hex color code.'."\n";
1322 echo '</td>'."\n";
1323
1324 echo '</tr>'."\n";
1325 echo '</tbody>'."\n";
1326 echo '</table>'."\n";
1327
1328 echo '<div class="ws-menu-page-hr"></div>'."\n";
1329
1330 echo '<table class="form-table" style="margin-top:0;">'."\n";
1331 echo '<tbody>'."\n";
1332 echo '<tr>'."\n";
1333
1334 echo '<td>'."\n";
1335 echo '<h3 style="margin:0;">Logo Image Configuration</h3>'."\n";
1336 echo '<p style="margin:0;">These settings are all focused on your Login/Registration Logo.</p>'."\n";
1337 echo '</td>'."\n";
1338
1339 echo '</tr>'."\n";
1340 echo '<tr>'."\n";
1341
1342 echo '<th>'."\n";
1343 echo '<label for="ws-plugin--s2member-login-reg-logo-src">'."\n";
1344 echo 'Logo Image Location:'."\n";
1345 echo '</label>'."\n";
1346 echo '</th>'."\n";
1347
1348 echo '</tr>'."\n";
1349 echo '<tr>'."\n";
1350
1351 echo '<td>'."\n";
1352 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_reg_logo_src" id="ws-plugin--s2member-login-reg-logo-src" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_logo_src"]).'" /><br />'."\n";
1353 echo '<input type="button" id="ws-plugin--s2member-login-reg-logo-src-media-btn" value="Open Media Library" class="ws-menu-page-media-btn" rel="ws-plugin--s2member-login-reg-logo-src" />'."\n";
1354 echo 'Set this to the URL of your Logo Image.<br />'."\n";
1355 echo 'Suggested size is around 500 x 100.'."\n";
1356 echo '</td>'."\n";
1357
1358 echo '</tr>'."\n";
1359 echo '<tr>'."\n";
1360
1361 echo '<th>'."\n";
1362 echo '<label for="ws-plugin--s2member-login-reg-logo-src-width">'."\n";
1363 echo 'Logo Image Width:'."\n";
1364 echo '</label>'."\n";
1365 echo '</th>'."\n";
1366
1367 echo '</tr>'."\n";
1368 echo '<tr>'."\n";
1369
1370 echo '<td>'."\n";
1371 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_reg_logo_src_width" id="ws-plugin--s2member-login-reg-logo-src-width" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_logo_src_width"]).'" /><br />'."\n";
1372 echo 'The pixel Width of your Logo Image. <em>* This ALSO affects the overall width of your Login/Registration forms. If you want wider form fields, use a wider Logo.</em>'."\n";
1373 echo '</td>'."\n";
1374
1375 echo '</tr>'."\n";
1376 echo '<tr>'."\n";
1377
1378 echo '<th>'."\n";
1379 echo '<label for="ws-plugin--s2member-login-reg-logo-src-height">'."\n";
1380 echo 'Logo Image Height:'."\n";
1381 echo '</label>'."\n";
1382 echo '</th>'."\n";
1383
1384 echo '</tr>'."\n";
1385 echo '<tr>'."\n";
1386
1387 echo '<td>'."\n";
1388 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_reg_logo_src_height" id="ws-plugin--s2member-login-reg-logo-src-height" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_logo_src_height"]).'" /><br />'."\n";
1389 echo 'The pixel Height of your Logo Image.'."\n";
1390 echo '</td>'."\n";
1391
1392 echo '</tr>'."\n";
1393 echo '<tr>'."\n";
1394
1395 echo '<th>'."\n";
1396 echo '<label for="ws-plugin--s2member-login-reg-logo-url">'."\n";
1397 echo 'Logo Image Click URL:'."\n";
1398 echo '</label>'."\n";
1399 echo '</th>'."\n";
1400
1401 echo '</tr>'."\n";
1402 echo '<tr>'."\n";
1403
1404 echo '<td>'."\n";
1405 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_reg_logo_url" id="ws-plugin--s2member-login-reg-logo-url" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_logo_url"]).'" /><br />'."\n";
1406 echo 'Set this to the Click URL for your Logo Image.'."\n";
1407 echo '</td>'."\n";
1408
1409 echo '</tr>'."\n";
1410 echo '<tr>'."\n";
1411
1412 echo '<th>'."\n";
1413 echo '<label for="ws-plugin--s2member-login-reg-logo-title">'."\n";
1414 echo 'Logo Image Title Attribute:'."\n";
1415 echo '</label>'."\n";
1416 echo '</th>'."\n";
1417
1418 echo '</tr>'."\n";
1419 echo '<tr>'."\n";
1420
1421 echo '<td>'."\n";
1422 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_reg_logo_title" id="ws-plugin--s2member-login-reg-logo-title" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_logo_title"]).'" /><br />'."\n";
1423 echo 'Used as the <code>title=""</code> attribute for your Logo Image.'."\n";
1424 echo '</td>'."\n";
1425
1426 echo '</tr>'."\n";
1427 echo '</tbody>'."\n";
1428 echo '</table>'."\n";
1429
1430 echo '<div class="ws-menu-page-hr"></div>'."\n";
1431
1432 echo '<table class="form-table" style="margin-top:0;">'."\n";
1433 echo '<tbody>'."\n";
1434 echo '<tr>'."\n";
1435
1436 echo '<th>'."\n";
1437 echo '<label for="ws-plugin--s2member-login-reg-footer-backtoblog">'."\n";
1438 echo 'Display [Back to Home Page] Link At Bottom?'."\n";
1439 echo '</label>'."\n";
1440 echo '</th>'."\n";
1441
1442 echo '</tr>'."\n";
1443 echo '<tr>'."\n";
1444
1445 echo '<td>'."\n";
1446 echo '<select name="ws_plugin__s2member_login_reg_footer_backtoblog" id="ws-plugin--s2member-login-reg-footer-backtoblog">'."\n";
1447 echo '<option value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_footer_backtoblog"]) ? ' selected="selected"' : '').'>Yes, display link at bottom pointing visitors back to the home page</option>'."\n";
1448 echo '<option value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_footer_backtoblog"]) ? ' selected="selected"' : '').'>No, hide this link (I\'ll create my own custom footer w/ the details I prefer)</option>'."\n";
1449 echo '</select>'."\n";
1450 echo '</td>'."\n";
1451
1452 echo '</tr>'."\n";
1453 echo '<tr>'."\n";
1454
1455 echo '<td>'."\n";
1456 echo '<h3 style="margin:0;">Footer Design (i.e., Bottom)</h3>'."\n";
1457 echo '<p style="margin:0;">This field accepts raw HTML'.((!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) ? ' (and/or PHP)' : '').' code.</p>'."\n";
1458 echo '</td>'."\n";
1459
1460 echo '</tr>'."\n";
1461 echo '<tr>'."\n";
1462
1463 echo '<th>'."\n";
1464 echo '<label for="ws-plugin--s2member-login-reg-footer-design">'."\n";
1465 echo 'Login/Registration Footer Design (optional):'."\n";
1466 echo '</label>'."\n";
1467 echo '</th>'."\n";
1468
1469 echo '</tr>'."\n";
1470 echo '<tr>'."\n";
1471
1472 echo '<td>'."\n";
1473 echo '<textarea name="ws_plugin__s2member_login_reg_footer_design" id="ws-plugin--s2member-login-reg-footer-design" rows="3" wrap="off" spellcheck="false">'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_footer_design"]).'</textarea><br />'."\n";
1474 echo 'This optional HTML'.((!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) ? ' (and/or PHP)' : '').' code will appear at the very bottom of your Login/Registration Forms.'."\n";
1475 echo '</td>'."\n";
1476
1477 echo '</tr>'."\n";
1478 echo '</tbody>'."\n";
1479 echo '</table>'."\n";
1480 echo '</div>'."\n";
1481
1482 echo '</div>'."\n";
1483
1484 echo '</div>'."\n";
1485
1486 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_after_login_registration", get_defined_vars());
1487 }
1488 if(apply_filters("ws_plugin__s2member_during_gen_ops_page_during_left_sections_display_custom_reg_fields", TRUE, get_defined_vars()))
1489 {
1490 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_custom_reg_fields", get_defined_vars());
1491
1492 echo '<div class="ws-menu-page-group" title="Registration/Profile Fields &amp; Options">'."\n";
1493
1494 echo '<div class="ws-menu-page-section ws-plugin--s2member-custom-reg-fields-section">'."\n";
1495 echo '<h3>Custom Registration/Profile Fields (optional, for further customization)</h3>'."\n";
1496 echo '<p>Some fields are already built-in by default. The defaults are: <code>*Username*, *Email*, *First Name*, *Last Name*</code>.</p>'."\n";
1497
1498 echo '<p>Custom Fields will appear in your Standard Registration Form, and in User/Member Profiles:<br />(<a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::wp_register_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your Standard Registration Form.\\n* s2Member makes this form available to logged-in Administrators, at all times (for testing purposes), regardless of configuration.'.((c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '\\n\\nBuddyPress: * BuddyPress will use its own Registration Form. Please note, you will probably be redirected away from the BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re ALREADY logged-in. Please log out before testing BuddyPress registration.' : '').'\');">'.esc_html(c_ws_plugin__s2member_utils_urls::wp_register_url()).'</a>)</p>'."\n";
1499 echo (is_multisite() && c_ws_plugin__s2member_utils_conds::is_multisite_farm() && is_main_site()) ? '<p><em>The Main Site of a Multisite Blog Farm uses this Form. s2Member supports Custom Fields here too.<br />(<a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::wp_signup_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your Multisite Registration Form.\\n* s2Member makes this form available to logged-in Super Administrators, at all times (for testing purposes), regardless of configuration.'.((c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '\\n\\nBuddyPress: * BuddyPress will use its own Registration Form. Please note, you will probably be redirected away from the BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re ALREADY logged-in. Please log out before testing BuddyPress registration.' : '').'\');">'.esc_html(c_ws_plugin__s2member_utils_urls::wp_signup_url()).'</a>)</em></p>'."\n" : '';
1500 echo (c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '<p><em><strong>BuddyPress:</strong> BuddyPress will use its own Registration Form <a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::bp_register_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your BuddyPress Registration Form.\\n* However, you will probably be redirected away from this BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re ALREADY logged-in. Please log out before testing BuddyPress registration.\');">here</a>.<br />s2Member can integrate your Custom Fields with BuddyPress too, please see options below.</em></p>'."\n" : '';
1501 echo '<p><strong>Regarding Registration:</strong> Custom Fields do not appear during repeat registration and/or checkout attempts (i.e., they do not appear for any user that is currently logged into the site). Please make sure that you test registration and/or checkout forms while not logged in (i.e., please test as a first-time customer). Existing users, members, customers may update Custom Fields by editing their Profile.</p>'."\n";
1502
1503 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_custom_reg_fields", get_defined_vars());
1504
1505 echo '<table class="form-table">'."\n";
1506 echo '<tbody>'."\n";
1507 echo '<tr>'."\n";
1508
1509 echo '<th>'."\n";
1510 echo '<label>'."\n";
1511 echo 'Custom Registration/Profile Fields:'."\n";
1512 echo '</label>'."\n";
1513 echo '</th>'."\n";
1514
1515 echo '</tr>'."\n";
1516 echo '<tr>'."\n";
1517
1518 echo '<td>'."\n";
1519 echo '<input type="hidden" name="ws_plugin__s2member_custom_reg_fields" id="ws-plugin--s2member-custom-reg-fields" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_fields"]).'" />'."\n";
1520 echo '<div id="ws-plugin--s2member-custom-reg-field-configuration"></div>'."\n"; // This is filled by JavaScript routines.
1521 echo '</td>'."\n";
1522
1523 echo '</tr>'."\n";
1524 echo '</tbody>'."\n";
1525 echo '</table>'."\n";
1526
1527 echo '<div class="ws-menu-page-hr"></div>'."\n";
1528
1529 echo '<table class="form-table">'."\n";
1530 echo '<tbody>'."\n";
1531 echo '<tr>'."\n";
1532
1533 echo '<th>'."\n";
1534 echo '<label for="ws-plugin--s2member-custom-reg-names">'."\n";
1535 echo 'Collect First/Last Names During Registration?'."\n";
1536 echo '</label>'."\n";
1537 echo '</th>'."\n";
1538
1539 echo '</tr>'."\n";
1540 echo '<tr>'."\n";
1541
1542 echo '<td>'."\n";
1543 echo '<select name="ws_plugin__s2member_custom_reg_names" id="ws-plugin--s2member-custom-reg-names">'."\n";
1544 echo '<option value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_names"]) ? ' selected="selected"' : '').'>Yes (always collect First/Last Names during registration)</option>'."\n";
1545 echo '<option value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_names"]) ? ' selected="selected"' : '').'>No (do NOT collect First/Last Names during registration)</option>'."\n";
1546 echo '</select><br />'."\n";
1547 echo 'Recommended setting (<code>Yes</code>). It\'s usually a good idea to leave this on.'."\n";
1548 echo (c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '<br /><em>* Has no affect on BuddyPress registration form (BuddyPress always collects a full <code>Name</code> field).</em>'."\n" : '';
1549 echo (c_ws_plugin__s2member_utils_conds::pro_is_installed()) ? '<br /><em>* s2Member Pro (Checkout) Forms always require a First/Last Name for billing.</em>'."\n" : '';
1550 echo '</td>'."\n";
1551
1552 echo '</tr>'."\n";
1553 echo '</tbody>'."\n";
1554 echo '</table>'."\n";
1555
1556 echo '<div class="ws-menu-page-hr"></div>'."\n";
1557
1558 echo '<table class="form-table">'."\n";
1559 echo '<tbody>'."\n";
1560 echo '<tr>'."\n";
1561
1562 echo '<th>'."\n";
1563 echo '<label for="ws-plugin--s2member-custom-reg-display-name">'."\n";
1564 echo 'Set "Display Name" During Registration?'."\n";
1565 echo '</label>'."\n";
1566 echo '</th>'."\n";
1567
1568 echo '</tr>'."\n";
1569 echo '<tr>'."\n";
1570
1571 echo '<td>'."\n";
1572 echo '<select name="ws_plugin__s2member_custom_reg_display_name" id="ws-plugin--s2member-custom-reg-display-name">'."\n";
1573 echo '<option value="full"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_display_name"] === "full") ? ' selected="selected"' : '').'>Yes (set Display Name to User\'s Full Name)</option>'."\n";
1574 echo '<option value="first"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_display_name"] === "first") ? ' selected="selected"' : '').'>Yes (set Display Name to User\'s First Name)</option>'."\n";
1575 echo '<option value="last"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_display_name"] === "last") ? ' selected="selected"' : '').'>Yes (set Display Name to User\'s Last Name)</option>'."\n";
1576 echo '<option value="login"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_display_name"] === "login") ? ' selected="selected"' : '').'>Yes (set Display Name to User\'s Username)</option>'."\n";
1577 echo '<option value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_display_name"]) ? ' selected="selected"' : '').'>No (leave Display Name at default WordPress value)</option>'."\n";
1578 echo '</select>'."\n";
1579 echo (c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '<br /><em>* Has no affect on BuddyPress registration form (BuddyPress always uses its full <code>Name</code> field).</em>'."\n" : '';
1580 echo '</td>'."\n";
1581
1582 echo '</tr>'."\n";
1583 echo '</tbody>'."\n";
1584 echo '</table>'."\n";
1585
1586 echo '<div class="ws-menu-page-hr"></div>'."\n";
1587
1588 echo '<table class="form-table">'."\n";
1589 echo '<tbody>'."\n";
1590 echo '<tr>'."\n";
1591
1592 echo '<th>'."\n";
1593 echo '<label for="ws-plugin--s2member-custom-reg-password">'."\n";
1594 echo 'Allow Custom Passwords During Registration?'."\n";
1595 echo '</label>'."\n";
1596 echo '</th>'."\n";
1597
1598 echo '</tr>'."\n";
1599 echo '<tr>'."\n";
1600
1601 echo '<td>'."\n";
1602 echo '<p style="margin-bottom:4px;"><em><strong>Note:</strong> Custom Passwords are easier for users. However, this has an impact on site security. Enabling Custom Passwords disables the New User Notification email that contains a password-setup link for each user. In other words, enabling Custom Passwords effectively disables any sort of email verification procedure, because the user is allowed to set their password during registration, instead of doing that via email confirmation—which is the default WordPress behavior.</em></p>'."\n";
1603 echo (is_multisite() && c_ws_plugin__s2member_utils_conds::is_multisite_farm() && is_main_site()) ? '<p style="margin-bottom:4px;"><em>* For security purposes, Custom Passwords are not possible on the Main Site of a Blog Farm. <a href="#" onclick="alert(\'For security purposes, Custom Passwords are not possible on the Main Site of a Blog Farm. A User must wait for the activation/confirmation email; where a randomly generated Password will be assigned. Please note, this limitation only affects your Main Site, via `/wp-signup.php`. In other words, your Customers (i.e., other Blog Owners) will still have the ability to allow Custom Passwords with s2Member. YOU are affected by this limitation, NOT them.\\n\\n* NOTE: s2Member (Pro) removes this limitation.\\nIf you install the s2Member Pro Add-on, you WILL be able to allow Custom Passwords through s2Member Pro-Forms; even on a Multisite Blog Farm.\'); return false;" tabindex="-1">[?]</a></em></p>'."\n" : '';
1604 echo (c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '<p style="margin-bottom:4px;"><em>* Does not affect BuddyPress registration form (always <code>yes</code> with BuddyPress registration).</em></p>'."\n" : '';
1605 echo '<select name="ws_plugin__s2member_custom_reg_password" id="ws-plugin--s2member-custom-reg-password"'.((is_multisite() && c_ws_plugin__s2member_utils_conds::is_multisite_farm() && is_main_site() && !c_ws_plugin__s2member_utils_conds::pro_is_installed()) ? ' disabled="disabled"' : '').'>'."\n";
1606 echo '<option value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_password"]) ? ' selected="selected"' : '').'>No (send each user a password-setup link after registration; recommended for best security)</option>'."\n";
1607 echo '<option value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_password"]) ? ' selected="selected"' : '').'>Yes (allow members to create their own password during registration)</option>'."\n";
1608 echo '</select>'."\n";
1609 echo '</td>'."\n";
1610
1611 echo '</tr>'."\n";
1612 echo '</tbody>'."\n";
1613 echo '</table>'."\n";
1614
1615 echo '<div class="ws-menu-page-hr"></div>'."\n";
1616
1617 echo '<table class="form-table">'."\n";
1618 echo '<tbody>'."\n";
1619 echo '<tr>'."\n";
1620
1621 echo '<th>'."\n";
1622 echo '<label for="ws-plugin--s2member-custom-reg-password-min-length">'."\n";
1623 echo 'Minimum Length/Strength for Custom Passwords:'."\n";
1624 echo '</label>'."\n";
1625 echo '</th>'."\n";
1626
1627 echo '</tr>'."\n";
1628 echo '<tr>'."\n";
1629
1630 echo '<td>'."\n";
1631 echo 'Minimum length: <input type="text" autocomplete="off" name="ws_plugin__s2member_custom_reg_password_min_length" id="ws-plugin--s2member-custom-reg-password-min-length" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_password_min_length"]).'" maxlength="2" size="2" style="width:auto;" /> characters.'."\n";
1632 echo '&nbsp;&nbsp;&nbsp; Minimum strength: <select name="ws_plugin__s2member_custom_reg_password_min_strength" id="ws-plugin--s2member-custom-reg-password-min-strength" style="width:auto;">'."\n";
1633 echo '<option value="n/a"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_password_min_strength"] === 'n/a') ? ' selected="selected"' : '').'>N/A (do not enforce a password strength requirement)</option>'."\n";
1634 echo '<option value="weak"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_password_min_strength"] === 'weak') ? ' selected="selected"' : '').'>Weak (only needs to meet minimum length requirement)</option>'."\n";
1635 echo '<option value="good"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_password_min_strength"] === 'good') ? ' selected="selected"' : '').'>Good (must have numbers, letters, and mixed caSe)</option>'."\n";
1636 echo '<option value="strong"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_password_min_strength"] === 'strong') ? ' selected="selected"' : '').'>Strong (must have numbers, letters, mixed caSe, and punctuation)</option>'."\n";
1637 echo '</select>'."\n";
1638 echo '<p><em><strong>Tip:</strong> Minimum length and password strength also impact profile updates, so it\'s a good idea to configure these even if you\'re not using Custom Passwords during registration.</em></p>'."\n";
1639 echo '</td>'."\n";
1640
1641 echo '</tr>'."\n";
1642 echo '</tbody>'."\n";
1643 echo '</table>'."\n";
1644
1645 echo '<div class="ws-menu-page-hr"></div>'."\n";
1646
1647 echo '<table class="form-table">'."\n";
1648 echo '<tbody>'."\n";
1649 echo '<tr>'."\n";
1650
1651 echo '<th>'."\n";
1652 echo '<label for="ws-plugin--s2member-custom-reg-force-personal-emails">'."\n";
1653 echo 'Force Personal Emails During Registration?'."\n";
1654 echo '</label>'."\n";
1655 echo '</th>'."\n";
1656
1657 echo '</tr>'."\n";
1658 echo '<tr>'."\n";
1659
1660 echo '<td>'."\n";
1661 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_custom_reg_force_personal_emails" id="ws-plugin--s2member-custom-reg-force-personal-emails" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_force_personal_emails"]).'" /><br />'."\n";
1662 echo 'To force personal email addresses, provide a comma-delimited list of email users to reject. <a href="#" onclick="alert(\'s2Member will reject [user]@ (based on your configuration here). A JavaScript alert message will be issued, asking the User to, `please use a personal email address`.\'); return false;" tabindex="-1">[?]</a><br />'."\n";
1663 echo 'Ex: <code>info,help,admin,webmaster,hostmaster,sales,support,spam</code><br />'."\n";
1664 echo 'See: <a href="http://s2member.com/r/mailchimp-role-based-emails/" target="_blank" rel="external">this article</a> for a more complete list.'."\n";
1665 echo (c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '<br /><em>* Affects BuddyPress registration form too.</em>'."\n" : '';
1666 echo '</td>'."\n";
1667
1668 echo '</tr>'."\n";
1669 echo '</tbody>'."\n";
1670 echo '</table>'."\n";
1671
1672 echo '<div class="ws-menu-page-hr"></div>'."\n";
1673
1674 echo '<table class="form-table">'."\n";
1675 echo '<tbody>'."\n";
1676 echo '<tr>'."\n";
1677
1678 echo '<th>'."\n";
1679 echo '<label for="ws-plugin--s2member-custom-reg-fields-4bp">'."\n";
1680 echo 'Integrate Custom Registration/Profile Fields with BuddyPress?'."\n";
1681 echo '</label>'."\n";
1682 echo '</th>'."\n";
1683
1684 echo '</tr>'."\n";
1685 echo '<tr>'."\n";
1686
1687 echo '<td>'."\n";
1688 echo '<div class="ws-menu-page-scrollbox" style="height:65px;">'."\n";
1689 echo '<input type="hidden" name="ws_plugin__s2member_custom_reg_fields_4bp[]" value="update-signal"'.((!c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? ' disabled="disabled"' : '').' />'."\n";
1690 foreach(array("profile-view" => "Yes, integrate with BuddyPress Public Profiles.", "registration" => "Yes, integrate with BuddyPress Registration Form.", "profile" => "Yes, integrate with BuddyPress Profile Editing Panel.") as $ws_plugin__s2member_temp_s_value => $ws_plugin__s2member_temp_s_label)
1691 echo '<input type="checkbox" name="ws_plugin__s2member_custom_reg_fields_4bp[]" id="ws-plugin--s2member-custom-reg-fields-4bp-'.esc_attr(preg_replace("/[^a-z0-9_\-]/", "-", $ws_plugin__s2member_temp_s_value)).'" value="'.esc_attr($ws_plugin__s2member_temp_s_value).'"'.((in_array($ws_plugin__s2member_temp_s_value, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_fields_4bp"])) ? ' checked="checked"' : '').((!c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? ' disabled="disabled"' : '').' /> <label for="ws-plugin--s2member-custom-reg-fields-4bp-'.esc_attr(preg_replace("/[^a-z0-9_\-]/", "-", $ws_plugin__s2member_temp_s_value)).'">'.$ws_plugin__s2member_temp_s_label.'</label><br />'."\n";
1692 echo '</div>'."\n";
1693 echo (!c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '<em>* BuddyPress is not installed; which is perfectly OK. BuddyPress is not a requirement.</em>'."\n" : '<em>* The options above, make it possible to integrate Custom Registration/Profile Fields (i.e., those configured with s2Member) into BuddyPress as well. However, if you configure Profile Fields with BuddyPress, those will NOT be integrated with s2Member. Therefore, if you need Custom Registration/Profile Fields to work with both s2Member and with BuddyPress, please configure them with s2Member.</em>';
1694 echo '</td>'."\n";
1695
1696 echo '</tr>'."\n";
1697 echo '</tbody>'."\n";
1698 echo '</table>'."\n";
1699
1700 echo '</div>'."\n";
1701
1702 echo '</div>'."\n";
1703
1704 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_after_custom_reg_fields", get_defined_vars());
1705 }
1706 if(apply_filters("ws_plugin__s2member_during_gen_ops_page_during_left_sections_display_sc_s2get_shortcode", TRUE, get_defined_vars()))
1707 {
1708 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_sc_s2get_shortcode", get_defined_vars());
1709
1710 //260812 This whitelist is shared by s2Get and s2Member-List; legacy hook and element names are retained for backward compatibility.
1711 echo '<div id="ws-plugin--s2member-shortcode-user-fields-whitelist"></div>'."\n";
1712 echo '<div class="ws-menu-page-group" title="Shortcode User Fields Whitelist"'.((!empty($_GET['s2member-open-panel']) && $_GET['s2member-open-panel'] === 'shortcode-user-fields-whitelist') ? ' default-state="open"' : '').'>'."\n";
1713
1714 echo '<div class="ws-menu-page-section ws-plugin--s2member-sc-get-shortcode-section">'."\n";
1715 echo '<h3>Shortcode User Fields Whitelist (optional)</h3>'."\n";
1716 echo '<p>Enter a comma-separated list of user fields that these shortcodes may display from a user account other than the person currently viewing the page. This applies to <code>[s2Get user_id="" /]</code> and <code>[s2Member-List show_fields="" /]</code>.</p>'."\n";
1717 echo '<p>Only allow fields that are appropriate to reveal about other user accounts wherever these shortcodes are used. If either shortcode tries to display an unlisted field from another user account, that cross-user field value will be blocked and s2Member will show administrators a security notice with the fields that need review.</p>'."\n";
1718 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_sc_s2get_shortcode", get_defined_vars());
1719
1720 echo '<table class="form-table">'."\n";
1721 echo '<tbody>'."\n";
1722 echo '<tr>'."\n";
1723
1724 echo '<th>'."\n";
1725 echo '<label for="ws-plugin--s2member-sc-s2get-userid-fields">'."\n";
1726 echo 'Allowed user fields:'."\n";
1727 echo '</label>'."\n";
1728 echo '</th>'."\n";
1729
1730 echo '</tr>'."\n";
1731 echo '<tr>'."\n";
1732
1733 echo '<td>'."\n";
1734 echo '<input type="text" name="ws_plugin__s2member_sc_user_fields_whitelist" id="ws-plugin--s2member-sc-s2get-userid-fields" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sc_user_fields_whitelist"]).'" placeholder="" style="width:100%;" /><br />'."\n";
1735 echo '<strong>Examples:</strong> <code>display_name, avatar, first_name, last_name, full_name</code>'."\n";
1736 echo '</td>'."\n";
1737
1738 echo '</tr>'."\n";
1739 echo '</tbody>'."\n";
1740 echo '</table>'."\n";
1741 echo '</div>'."\n";
1742
1743 echo '</div>'."\n";
1744
1745 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_after_sc_s2get_shortcode", get_defined_vars());
1746 }
1747 if(apply_filters("ws_plugin__s2member_during_gen_ops_page_during_left_sections_display_login_welcome_page", TRUE, get_defined_vars()))
1748 {
1749 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_login_welcome_page", get_defined_vars());
1750
1751
1752 echo '<div class="ws-menu-page-group" title="Login Welcome Page">'."\n";
1753
1754 echo '<div class="ws-menu-page-section ws-plugin--s2member-login-welcome-page-section">'."\n";
1755 echo '<h3>Login Welcome Page (required, please customize this)</h3>'."\n";
1756 echo '<p>Please create and/or choose an existing Page to use as the first page Members will see after logging in.</p>'."\n";
1757 echo (c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '<p><em><strong>BuddyPress:</strong> s2Member integrates with BuddyPress. Your Login Welcome Page affects BuddyPress too.</em></p>'."\n" : '';
1758 echo '<p><em><strong>Always Private:</strong> This Page will always require a logged-in User/Member. In fact, this Page will be protected from public access by s2Member automatically. <strong>Note:</strong> for technical reasons, your Login Welcome Page <strong>cannot</strong> be set to your Front Page (i.e., your Home Page); or your Posts Page (i.e., your main Blog page). Please create a separate dedicated Page in WordPress, and then designate it as your Login Welcome Page below.</em></p>'."\n";
1759 echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/customizing-your-lwp/" target="_blank" rel="external">Customizing Your Login Welcome Page</a>.</p>'."\n";
1760 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_login_welcome_page", get_defined_vars());
1761
1762 echo '<table class="form-table">'."\n";
1763 echo '<tbody>'."\n";
1764 echo '<tr>'."\n";
1765
1766 echo '<th>'."\n";
1767 echo '<label for="ws-plugin--s2member-login-welcome-page">'."\n";
1768 echo 'Login Welcome Page:'."\n";
1769 echo '</label>'."\n";
1770 echo '</th>'."\n";
1771
1772 echo '</tr>'."\n";
1773 echo '<tr>'."\n";
1774
1775 echo '<td>'."\n";
1776 echo '<select name="ws_plugin__s2member_login_welcome_page" id="ws-plugin--s2member-login-welcome-page">'."\n";
1777 echo '<option value="">&mdash; Select &mdash;</option>'."\n";
1778 foreach(($ws_plugin__s2member_temp_a = array_merge((array)get_pages())) as $ws_plugin__s2member_temp_o)
1779 echo '<option value="'.esc_attr($ws_plugin__s2member_temp_o->ID).'"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_override"] && $ws_plugin__s2member_temp_o->ID == $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"]) ? ' selected="selected"' : '').'>'.esc_html($ws_plugin__s2member_temp_o->post_title).'</option>'."\n";
1780 echo '</select><br />'."\n";
1781 echo 'Please choose a Page to be used as the first page Members will see after logging in. This Page can contain anything you like. We recommend the following title: <code>Welcome To Our Members Area</code>.'."\n";
1782 echo '</td>'."\n";
1783
1784 echo '</tr>'."\n";
1785 echo '<tr>'."\n";
1786
1787 echo '<th>'."\n";
1788 echo '<label for="ws-plugin--s2member-login-redirection-override">'."\n";
1789 echo 'Or, a Special Redirection URL?'."\n";
1790 echo '</label>'."\n";
1791 echo '</th>'."\n";
1792
1793 echo '</tr>'."\n";
1794 echo '<tr>'."\n";
1795
1796 echo '<td>'."\n";
1797 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_redirection_override" id="ws-plugin--s2member-login-redirection-override" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_override"]).'" /><br />'."\n";
1798 echo 'Or, you may configure a Special Redirection URL, if you prefer. You\'ll need to type in the full URL, starting with: <code>http://</code> or <code>https://</code>. <em>A few <a href="#" onclick="alert(\'Replacement Codes:\\n\\n%%current_user_login%% = The current User\\\'s Username, lowercase (deprecated, please use %%current_user_nicename%%).\\n\\n%%current_user_nicename%% = The current User\\\'s Nicename in lowercase format (i.e., a cleaner version of the username for URLs; recommended for best compatibility).\\n\\n%%current_user_id%% = The current User\\\'s ID.\\n\\n%%current_user_level%% = The current User\\\'s s2Member Level.\\n\\n%%current_user_role%% = The current User\\\'s WordPress Role.'.((!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) ? '\\n\\n%%current_user_ccaps%% = The current User\\\'s Custom Capabilities.' : '').'\\n\\n%%current_user_logins%% = Number of times the current User has logged in.\\n\\nFor example, if you\\\'re using BuddyPress, and you want to redirect Members to their BuddyPress Profile page after logging in, you would setup a Special Redirection URL, like this: '.home_url("/members/%%current_user_nicename%%/profile/").'\\n\\nOr ... using %%current_user_level%%, you could have a separate Login Welcome Page for each Membership Level that you plan to offer. BuddyPress not required.\'); return false;">Replacement Codes</a> are also supported here.</em>'."\n";
1799 echo '</td>'."\n";
1800
1801 echo '</tr>'."\n";
1802 echo '</tbody>'."\n";
1803 echo '</table>'."\n";
1804 echo '</div>'."\n";
1805
1806 echo '</div>'."\n";
1807
1808 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_after_login_welcome_page", get_defined_vars());
1809 }
1810 if(apply_filters("ws_plugin__s2member_during_gen_ops_page_during_left_sections_display_membership_options_page", TRUE, get_defined_vars()))
1811 {
1812 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_membership_options_page", get_defined_vars());
1813
1814 echo '<div class="ws-menu-page-group" title="Membership Options Page">'."\n";
1815
1816 echo '<div class="ws-menu-page-section ws-plugin--s2member-membership-options-page-section">'."\n";
1817 echo '<h3>Membership Options Page (required, please customize this)</h3>'."\n";
1818 echo '<p>Please create and/or choose an existing Page that showcases your Membership Options. This special Page is where you\'ll insert the Payment Button(s) generated for you by s2Member (or Pro-Forms; if you\'re running s2Member Pro). This Page serves as your lead-in signup page <em>(i.e., you\'ll give visitors one or more registration options here, and they\'ll pay for the option they choose)</em>.</p>'."\n";
1819 echo '<p>Your Membership Options Page should detail all of the features that come with Membership to your site, and provide a Payment Button (or Pro-Form; if you\'re running s2Member Pro) for each Level of access you plan to offer. This is also the Page that anyone could be redirected to <em>(by s2Member)</em>, should they attempt to access an area of your site that requires access to something they\'re currenty not allowed to view.</p>'."\n";
1820 echo '<p><em><strong>Tip:</strong> If you allow Open Registration (i.e., Free Subscribers), you might want to place a link on your Membership Options Page, which points directly to your free Registration Form, instead of routing a Customer through your Payment Gateway first. It\'s a matter of preference though. For further details, please check the section above: <strong>s2Member → General Options → Open Registration</strong>.</em></p>'."\n";
1821 echo c_ws_plugin__s2member_utils_conds::bp_is_installed() ? '<p><em><strong>BuddyPress:</strong> Even with BuddyPress, s2Member still needs a Membership Options Page. This is where your Payment Buttons (or Pro-Forms; if you\'re running s2Member Pro) will go, giving people the ability to pay you. And again, this is also the Page that anyone could be redirected to <em>(by s2Member)</em>, should they attempt to access an area of your site that requires access to something they\'re currenty not allowed to view.</em></p>'."\n" : '';
1822 echo '<p><em><strong>Always Public:</strong> This Page must be public at all times. In fact, s2Member will not allow this Page to be restricted in any way. <strong>Note:</strong> for technical reasons, your Membership Options Page <strong>cannot</strong> be set to your Front Page (i.e., your Home Page); or your Posts Page (i.e., your main Blog page). Please create a separate (dedicated) Page in WordPress, and then designate it as your Membership Options Page below.</em></p>'."\n";
1823 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_membership_options_page", get_defined_vars());
1824
1825 echo '<table class="form-table">'."\n";
1826 echo '<tbody>'."\n";
1827 echo '<tr>'."\n";
1828
1829 echo '<th>'."\n";
1830 echo '<label for="ws-plugin--s2member-membership-options-page">'."\n";
1831 echo 'Membership Options Page:'."\n";
1832 echo '</label>'."\n";
1833 echo '</th>'."\n";
1834
1835 echo '</tr>'."\n";
1836 echo '<tr>'."\n";
1837
1838 echo '<td>'."\n";
1839 echo '<select name="ws_plugin__s2member_membership_options_page" id="ws-plugin--s2member-membership-options-page">'."\n";
1840 echo '<option value="">&mdash; Select &mdash;</option>'."\n";
1841 foreach(($ws_plugin__s2member_temp_a = array_merge((array)get_pages())) as $ws_plugin__s2member_temp_o)
1842 echo '<option value="'.esc_attr($ws_plugin__s2member_temp_o->ID).'"'.(($ws_plugin__s2member_temp_o->ID == $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]) ? ' selected="selected"' : '').'>'.esc_html($ws_plugin__s2member_temp_o->post_title).'</option>'."\n";
1843 echo '</select><br />'."\n";
1844 echo 'Please choose a Page that provides Users with a way to sign up. We recommend the following title: <code>Membership Signup</code>'."\n";
1845 echo '</td>'."\n";
1846
1847 echo '</tr>'."\n";
1848 echo '</tbody>'."\n";
1849 echo '</table>'."\n";
1850
1851 echo '<div class="ws-menu-page-hr"></div>'."\n";
1852
1853 echo '<table class="form-table">'."\n";
1854 echo '<tbody>'."\n";
1855 echo '<tr>'."\n";
1856
1857 echo '<th>'."\n";
1858 echo '<label for="ws-plugin--s2member-membership-options-page-vars-enable">'."\n";
1859 echo 'Enable MOP Vars (i.e., Membership Options Page Variables)?'."\n";
1860 echo '</label>'."\n";
1861 echo '</th>'."\n";
1862
1863 echo '</tr>'."\n";
1864 echo '<tr>'."\n";
1865
1866 echo '<td>'."\n";
1867 echo '<select name="ws_plugin__s2member_membership_options_page_vars_enable" id="ws-plugin--s2member-membership-options-page-vars-enable">'."\n";
1868 echo '<option value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page_vars_enable"]) ? ' selected="selected"' : '').'>Yes (enable MOP Vars in all redirections; recommended behavior)</option>'."\n";
1869 echo '<option value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page_vars_enable"]) ? ' selected="selected"' : '').'>No (don\'t include the additional details provided by MOP Vars)</option>'."\n";
1870 echo '</select><br />'."\n";
1871 echo 'See also: <strong>Dashboard → s2Member → API / Scripting → Membership Options Page / Variables</strong><br />'."\n";
1872 echo 'Recommended setting: (<code>Yes, enable MOP Vars</code>)'."\n";
1873 echo '</td>'."\n";
1874
1875 echo '</tr>'."\n";
1876 echo '</tbody>'."\n";
1877 echo '</table>'."\n";
1878 echo '</div>'."\n";
1879
1880 echo '</div>'."\n";
1881
1882 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_after_membership_options_page", get_defined_vars());
1883 }
1884 if(apply_filters("ws_plugin__s2member_during_gen_ops_page_during_left_sections_display_profile_modifications", TRUE, get_defined_vars()))
1885 {
1886 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_profile_modifications", get_defined_vars());
1887
1888 echo '<div class="ws-menu-page-group" title="Member Profile Modifications">'."\n";
1889
1890 echo '<div class="ws-menu-page-section ws-plugin--s2member-profile-modifications-section">'."\n";
1891 echo '<h3>Giving Members The Ability To Modify Their Profile</h3>'."\n";
1892 echo '<p>s2Member can be configured to redirect Members away from the <a href="'.esc_attr(admin_url("/profile.php")).'" target="_blank" rel="external">default Profile Editing Panel</a> that is built into WordPress. When/if a Member attempts to access the default Profile Editing Panel, they\'ll instead be redirected to the Login Welcome Page that you\'ve configured with s2Member. <strong>Why would I redirect away from the default Profile Editing Panel?</strong> Unless you\'ve made some drastic modifications to your WordPress installation, the default Profile Editing Panel that comes with WordPress is <em>not</em> suited for any sort of public access.</p>'."\n";
1893 echo '<p>So instead of using this default Profile Editing Panel, s2Member provides you <em>(the site owner)</em> with a special Shortcode: <code>[s2Member-Profile /]</code>. You can insert this into your Login Welcome Page, or any Post/Page for that matter <em>(even into a Text Widget)</em>. This Shortcode produces an Inline Profile Editing Form that supports all aspects of s2Member, including Password changes; and any Custom Registration/Profile Fields that you\'ve configured with s2Member. Alternatively, you can send your Members to a <a href="'.esc_attr(home_url("/?s2member_profile=1")).'" target="_blank" rel="external">special Stand-Alone version</a>. The stand-alone version makes it possible for you to <a href="#" onclick="if(!window.open(\''.home_url("/?s2member_profile=1").'\', \'_popup\', \'width=600,height=400,left=100,screenX=100,top=100,screenY=100,location=0,menubar=0,toolbar=0,status=0,scrollbars=1,resizable=1\')) alert(\'Please disable popup blockers and try again!\'); return false;" rel="external">open it up in a popup window</a>, or embed it into your Login Welcome Page using an IFRAME. Code samples below.</p>'."\n";
1894 echo (c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '<p><em><strong>BuddyPress:</strong> BuddyPress already provides Users/Members with a Profile Editing Panel, powered by your theme. If you\'ve configured Custom Registration/Profile Fields with s2Member, you can also enable s2Member\'s Profile Field integration with BuddyPress (recommended). For further details, see: <strong>s2Member → General Options → Registration/Profile Fields</strong>.</em></p>'."\n" : '';
1895 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_profile_modifications", get_defined_vars());
1896
1897 echo '<table class="form-table">'."\n";
1898 echo '<tbody>'."\n";
1899 echo '<tr>'."\n";
1900
1901 echo '<th>'."\n";
1902 echo '<label for="ws-plugin--s2member-force-admin-lockouts">'."\n";
1903 echo 'Redirect Members away from the Default Profile Panel?'."\n";
1904 echo '</label>'."\n";
1905 echo '</th>'."\n";
1906
1907 echo '</tr>'."\n";
1908 echo '<tr>'."\n";
1909
1910 echo '<td>'."\n";
1911 echo '<select name="ws_plugin__s2member_force_admin_lockouts" id="ws-plugin--s2member-force-admin-lockouts">'."\n";
1912 echo '<option value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["force_admin_lockouts"]) ? ' selected="selected"' : '').'>No (I want to use the WordPress default methodologies)</option>'."\n";
1913 echo '<option value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["force_admin_lockouts"]) ? ' selected="selected"' : '').'>Yes (redirect to Login Welcome Page; locking all /wp-admin/ areas)</option>'."\n";
1914 echo '</select><br />'."\n";
1915 echo 'Recommended setting (<code>Yes</code>). <em><strong>Note:</strong> When this is set to (<code>Yes</code>), s2Member will take an initiative to further safeguard ALL <code>/wp-admin/</code> areas of your installation; not just the Default Profile Panel.</em>'."\n";
1916 echo '</td>'."\n";
1917
1918 echo '</tr>'."\n";
1919 echo '</tbody>'."\n";
1920 echo '</table>'."\n";
1921
1922 echo '<div class="ws-menu-page-hr"></div>'."\n";
1923
1924 echo '<p style="margin-bottom:0;"><strong>Shortcode (copy/paste)</strong>, for an Inline Profile Modification Form:<br />'."\n";
1925 echo '<p style="margin-top:0;"><input type="text" autocomplete="off" value="'.format_to_edit('[s2Member-Profile /]').'" onclick="this.select ();" /></p>'."\n";
1926
1927 echo '<p style="margin-top:25px; margin-bottom:0;"><strong>Stand-Alone (copy/paste)</strong>, for popup window:</p>'."\n";
1928 echo '<p style="margin-top:0;"><input type="text" autocomplete="off" value="'.format_to_edit(preg_replace("/\<\?php echo S2MEMBER_CURRENT_USER_PROFILE_MODIFICATION_PAGE_URL; \?\>/", c_ws_plugin__s2member_utils_strings::esc_refs(home_url("/?s2member_profile=1")), file_get_contents(dirname(__FILE__)."/code-samples/current-user-profile-modification-page-url-2-ops.x-php"))).'" onclick="this.select ();" /></p>'."\n";
1929 echo '</div>'."\n";
1930
1931 echo '</div>'."\n";
1932
1933 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_after_profile_modifications", get_defined_vars());
1934 }
1935 if(apply_filters("ws_plugin__s2member_during_gen_ops_page_during_left_sections_display_url_shortening", TRUE, get_defined_vars()))
1936 {
1937 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_url_shortening", get_defined_vars());
1938
1939 echo '<div class="ws-menu-page-group" title="URL Shortening Service Preference">'."\n";
1940
1941 echo '<div class="ws-menu-page-section ws-plugin--s2member-url-shortening-section">'."\n";
1942 echo '<h3>URL Shortening Service API (Preference)</h3>'."\n";
1943 echo '<p>In a few special cases, long URLs generated by s2Member (i.e., those containing encrypted authentication details) will be shortened. A shortened URL prevents issues with very long links becoming corrupted by a Customer\'s email application. For instance, the Signup Confirmation Email that s2Member sends out to a new paying Customer may contain a link which is shortened to prevent corruption by email applications. By default, s2Member uses its own built-in short links, stored temporarily on your site. You can also choose a third-party URL shortener, configure a custom shortener, or disable shortening.</p>'."\n";
1944 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_url_shortening", get_defined_vars());
1945
1946 echo '<table class="form-table">'."\n";
1947 echo '<tbody>'."\n";
1948 echo '<tr>'."\n";
1949
1950 echo '<th>'."\n";
1951 echo '<label for="ws-plugin--s2member-default-url-shortener">'."\n";
1952 echo 'URL Shortening Service API (Default):'."\n";
1953 echo '</label>'."\n";
1954 echo '</th>'."\n";
1955
1956 echo '</tr>'."\n";
1957 echo '<tr>'."\n";
1958
1959 echo '<td>'."\n";
1960 echo '<select name="ws_plugin__s2member_default_url_shortener" id="ws-plugin--s2member-default-url-shortener">'."\n";
1961 echo '<option value="s2member"'.((in_array($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["default_url_shortener"], array("s2member", "tiny_url"), TRUE)) ? ' selected="selected"' : '').'>s2Member Built-In (recommended)</option>'."\n";
1962 echo '<option value="none"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["default_url_shortener"] === "none") ? ' selected="selected"' : '').'>None (Don\'t shorten the URL)</option>'."\n";
1963 echo '<option value="bitly"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["default_url_shortener"] === "bitly") ? ' selected="selected"' : '').'>Bitly (free; API key required)</option>'."\n";
1964 echo '</select>'."\n";
1965 echo '</td>'."\n";
1966
1967 echo '</tr>'."\n";
1968 echo '<tr>'."\n";
1969
1970 echo '<td>'."\n";
1971 echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_default_url_shortener_key" id="ws-plugin--s2member-default-url-shortener-key" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["default_url_shortener_key"]).'" /><br />'."\n";
1972 echo '<em>If you choose Bitly, enter your <a href="http://s2member.com/r/bitly-oauth-access-token/" target="_blank" rel="external">Bitly oAuth Access Token</a>'."\n";
1973 echo '</td>'."\n";
1974
1975 echo '</tr>'."\n";
1976 if (c_ws_plugin__s2member_utils_conds::pro_is_installed()) {
1977 echo '<tr>'."\n";
1978
1979 echo '<th>'."\n";
1980 echo '<label for="ws-plugin--s2member-default-custom-str-url-shortener">'."\n";
1981 echo 'Custom URL Shortening Service API (Optional/Advanced):'."\n";
1982 echo '</label>'."\n";
1983 echo '</th>'."\n";
1984
1985 echo '</tr>'."\n";
1986 echo '<tr>'."\n";
1987
1988 echo '<td>'."\n";
1989 echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_default_custom_str_url_shortener" id="ws-plugin--s2member-default-custom-str-url-shortener" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["default_custom_str_url_shortener"]).'" /><br />'."\n";
1990 echo 'Your own custom URL <code>(i.e., GET request)</code>, with <code>%%s2_long_url%%</code> Replacement Code. [<a href="#" onclick="alert(\'Advanced site owners can use a custom URL shortening service they prefer.\\n\\nIn order for this to work, your URL shortening service must support simple GET requests through its API (sometimes referred to as a REST or NVP API).\\n\\nIn addition, your URL shortening service must return a plain-text URL in the response. See example below.\\n\\nYOURLS example GET request with format=simple:\\n\\nhttp://yoursite.com/yourls/yourls-api.php?signature=1234567890&action=shorturl&format=simple&url=%%s2_long_url%%\\n\\ns2Member expects a shortened URL in the response from YOURLS.\\n\\nIf you configure s2Member to use your own custom URL shortening service, s2Member will try your configuration first, and if anything fails, it will fall back on its own pre-integrated backups.\\n\\nWhen configuring your URL for the GET request, s2Member makes two Replacement Codes available:\\n\\n%%s2_long_url%% = The full URL that needs to be shortened (raw URL-encoded).\\n\\n%%s2_long_url_md5%% = An MD5 hash of the full URL (might be useful in some APIs).\'); return false;" tabindex="-1">details</a>]<br />'."\n";
1991 echo '</td>'."\n";
1992
1993 echo '</tr>'."\n";
1994 }
1995 echo '</tbody>'."\n";
1996 echo '</table>'."\n";
1997 echo '</div>'."\n";
1998
1999 echo '</div>'."\n";
2000
2001 do_action("ws_plugin__s2member_during_gen_ops_page_during_left_sections_after_url_shortening", get_defined_vars());
2002 }
2003 do_action("ws_plugin__s2member_during_gen_ops_page_after_left_sections", get_defined_vars());
2004
2005 echo '<p class="submit"><input type="submit" value="Save All Changes" /></p>'."\n";
2006
2007 echo '</form>'."\n";
2008
2009 echo '</td>'."\n";
2010
2011 echo '<td class="ws-menu-page-table-r">'."\n";
2012 c_ws_plugin__s2member_menu_pages_rs::display();
2013 echo '</td>'."\n";
2014
2015 echo '</tr>'."\n";
2016 echo '</tbody>'."\n";
2017 echo '</table>'."\n";
2018
2019 echo '</div>'."\n";
2020 }
2021 }
2022 }
2023
2024 new c_ws_plugin__s2member_menu_page_gen_ops ();
2025