PluginProbe
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions / 260805
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions v260805
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 / classes / menu-pages.inc.php

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

1,018 lines 58.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // @codingStandardsIgnoreFile
3 /**
4 * Administrative menu pages.
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.5
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_pages'))
22 {
23 /**
24 * Administrative menu pages.
25 *
26 * @package s2Member\Menu_Pages
27 * @since 3.5
28 */
29 class c_ws_plugin__s2member_menu_pages
30 {
31 /**
32 * Pre-display errors.
33 *
34 * @package s2Member\Menu_Pages
35 * @since 111209
36 *
37 * @var array
38 */
39 public static $pre_display_errors = array();
40
41 /**
42 * Saves all options from any menu page.
43 *
44 * Can also be self-verified; and configured extensively with function parameters.
45 *
46 * @package s2Member\Menu_Pages
47 * @since 3.5
48 *
49 * @param null|array $new_options Optional. Force feed an array of new options. Defaults to ``$_POST`` vars.
50 * If ``$new_options`` are passed in, be SURE that you've already applied ``stripslashes_deep()``.
51 * @param bool $verified Optional. Defaults to false. If true, ``wp_verify_nonce()`` is skipped in this routine.
52 * @param bool $update_other Optional. Defaults to true. If false, other option-dependent routines will not be processed.
53 * @param bool|array $display_notices Optional. Defaults to true. Can be false, or an array of certain notices that can be displayed.
54 * @param bool|array $enqueue_notices Optional. Defaults to false. Can be true, or an array of certain notices that should be enqueued.
55 * @param bool $request_refresh Optional. Defaults to false. If true, resulting `success` notice will include a link to refresh the menu page.
56 *
57 * @return bool True if all s2Member options were updated successfully, else false.
58 */
59 public static function update_all_options($new_options = NULL, $verified = FALSE, $update_other = TRUE, $display_notices = TRUE, $enqueue_notices = FALSE, $request_refresh = FALSE)
60 {
61 $updated_all_options = FALSE; // Initializing this variable here makes it an available reference-variable to Hooks/Filters.
62
63 foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $$__v;
64 do_action('ws_plugin__s2member_before_update_all_options', get_defined_vars()); // If you use this Hook, be sure to use ``wp_verify_nonce()``.
65 unset($__refs, $__v); // Housekeeping.
66
67 if($verified || (!empty($_POST['ws_plugin__s2member_options_save']) && ($nonce = $_POST['ws_plugin__s2member_options_save']) && wp_verify_nonce($nonce, 'ws-plugin--s2member-options-save')))
68 {
69 $options = $GLOBALS['WS_PLUGIN__']['s2member']['o']; // Acquire the full existing configuration options array here.
70
71 $new_options = (is_array($new_options)) ? $new_options : ((!empty($_POST) && is_array($_POST)) ? stripslashes_deep($_POST) : array());
72 $new_options = c_ws_plugin__s2member_utils_strings::trim_deep($new_options);
73
74 foreach($new_options as $key => $value) // Find all keys contained within ``$new_options`` matching `^ws_plugin__s2member_`.
75 if(strpos($key, 'ws_plugin__s2member_') === 0) // A relevant ``$new_options`` key matching `^ws_plugin__s2member_`?
76
77 if($key === 'ws_plugin__s2member_configured') // s2Member is now configured (according to these options)?
78 ($GLOBALS['WS_PLUGIN__']['s2member']['c']['configured'] = $value).update_option('ws_plugin__s2member_configured', $value);
79
80 else if(!is_array($value) || (is_array($value) && array_shift($value) === 'update-signal')) // Updating an array?
81 $options[preg_replace('/^'.preg_quote('ws_plugin__s2member_', '/').'/', '', $key)] = $value;
82
83 unset($key, $value); // Unset these utility variables now. This prevents bleeding vars into Hooks/Filters that are of no use.
84
85 foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $$__v;
86 do_action('ws_plugin__s2member_during_update_all_options', get_defined_vars());
87 unset($__refs, $__v); // Housekeeping.
88
89 $options = ws_plugin__s2member_configure_options_and_their_defaults(($options = array_merge($options, array('options_version' => (string)($options['options_version'] + 0.001)))));
90 update_option('ws_plugin__s2member_options', $options).((is_multisite() && is_main_site()) ? update_site_option('ws_plugin__s2member_options', $options) : NULL).update_option('ws_plugin__s2member_cache', array());
91
92 if($update_other === TRUE || in_array('auto_eot_system', (array)$update_other)) // Handle the Auto-EOT System now (enable/disable).
93 ($options['auto_eot_system_enabled'] == 1) ? c_ws_plugin__s2member_auto_eots::add_auto_eot_system() : c_ws_plugin__s2member_auto_eots::delete_auto_eot_system();
94
95 if(($display_notices === TRUE || in_array('success', (array)$display_notices)) && ($notice = '<strong>Options saved.'.(($request_refresh) ? ' Please <a href="'.esc_attr($_SERVER['REQUEST_URI']).'">refresh</a>.' : '').'</strong>'))
96 ($enqueue_notices === TRUE || in_array('success', (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, '*:*') : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice);
97
98 if(empty($_GET['page']) || $_GET['page'] !== 'ws-plugin--s2member-mms-ops') // Do NOT display page-conflict-warnings on the Main Multisite Configuration panel.
99 {
100 if(!$options['membership_options_page'] && ($display_notices === TRUE || in_array('page-conflict-warnings', (array)$display_notices)) && ($notice = '<strong>NOTE:</strong> s2Member security restrictions will NOT be enforced until you\'ve configured a Membership Options Page. See: <strong>s2Member → General Options → Membership Options Page</strong>.'))
101 ($enqueue_notices === TRUE || in_array('page-conflict-warnings', (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, '*:*', TRUE) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, TRUE);
102
103 if($options['login_welcome_page'] && $options['login_welcome_page'] === $options['membership_options_page'] && ($display_notices === TRUE || in_array('page-conflict-warnings', (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Login Welcome Page is the same as your Membership Options Page. Please correct this. See: <strong>s2Member → General Options → Login Welcome Page</strong>.'))
104 ($enqueue_notices === TRUE || in_array('page-conflict-warnings', (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, '*:*', TRUE) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, TRUE);
105
106 if($options['membership_options_page'] && (string)get_option('page_on_front') === $options['membership_options_page'] && ($display_notices === TRUE || in_array('page-conflict-warnings', (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Membership Options Page is currently configured as your Home Page (i.e., static page) for WordPress. This causes internal conflicts with s2Member. Your Membership Options Page MUST stand alone. Please correct this. See: <strong>WordPress → Reading Options</strong>. Or change: <strong>s2Member → General Options → Membership Options Page</strong>.'))
107 ($enqueue_notices === TRUE || in_array('page-conflict-warnings', (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, '*:*', TRUE) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, TRUE);
108
109 if($options['login_welcome_page'] && (string)get_option('page_on_front') === $options['login_welcome_page'] && ($display_notices === TRUE || in_array('page-conflict-warnings', (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Login Welcome Page is currently configured as your Home Page (i.e., static page) for WordPress. This causes internal conflicts with s2Member. Your Login Welcome Page MUST stand alone. Please correct this. See: <strong>WordPress → Reading Options</strong>. Or change: <strong>s2Member → General Options → Login Welcome Page</strong>.'))
110 ($enqueue_notices === TRUE || in_array('page-conflict-warnings', (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, '*:*', TRUE) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, TRUE);
111
112 if($options['membership_options_page'] && (string)get_option('page_for_posts') === $options['membership_options_page'] && ($display_notices === TRUE || in_array('page-conflict-warnings', (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Membership Options Page is currently configured as your Posts Page (i.e., static page) for WordPress. This causes internal conflicts with s2Member. Your Membership Options Page MUST stand alone. Please correct this. See: <strong>WordPress → Reading Options</strong>. Or change: <strong>s2Member → General Options → Membership Options Page</strong>.'))
113 ($enqueue_notices === TRUE || in_array('page-conflict-warnings', (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, '*:*', TRUE) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, TRUE);
114
115 if($options['login_welcome_page'] && (string)get_option('page_for_posts') === $options['login_welcome_page'] && ($display_notices === TRUE || in_array('page-conflict-warnings', (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Login Welcome Page is currently configured as your Posts Page (i.e., static page) for WordPress. This causes internal conflicts with s2Member. Your Login Welcome Page MUST stand alone. Please correct this. See: <strong>WordPress → Reading Options</strong>. Or change: <strong>s2Member → General Options → Login Welcome Page</strong>.'))
116 ($enqueue_notices === TRUE || in_array('page-conflict-warnings', (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, '*:*', TRUE) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, TRUE);
117
118 if($options['file_download_limit_exceeded_page'] && $options['file_download_limit_exceeded_page'] === $options['membership_options_page'] && ($display_notices === TRUE || in_array('page-conflict-warnings', (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Download Limit Exceeded Page is the same as your Membership Options Page. Please correct this. See: <strong>s2Member → Download Options</strong>.'))
119 ($enqueue_notices === TRUE || in_array('page-conflict-warnings', (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, '*:*', TRUE) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, TRUE);
120 }
121 $updated_all_options = TRUE; // Flag indicating this routine was processed successfully; and that all s2Member options have been updated successfully.
122 }
123 foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $$__v;
124 do_action('ws_plugin__s2member_after_update_all_options', get_defined_vars());
125 unset($__refs, $__v); // Housekeeping.
126
127 return apply_filters('ws_plugin__s2member_update_all_options', (($updated_all_options) ? TRUE : FALSE), get_defined_vars());
128 }
129
130 /**
131 * Adds option menus / sub-menus.
132 *
133 * @package s2Member\Menu_Pages
134 * @since 3.5
135 *
136 * @attaches-to ``add_action('admin_menu');``
137 */
138 public static function add_admin_options()
139 {
140 do_action('ws_plugin__s2member_before_add_admin_options', get_defined_vars());
141
142 add_filter('plugin_action_links', 'c_ws_plugin__s2member_menu_pages::_add_settings_link', 10, 2);
143
144 if(apply_filters('ws_plugin__s2member_during_add_admin_options_create_menu_items', TRUE, get_defined_vars()))
145 {
146 if((is_multisite() && c_ws_plugin__s2member_utils_conds::is_multisite_farm() && !is_main_site()) || apply_filters('ws_plugin__s2member_during_add_admin_options_clear_right_side', FALSE, get_defined_vars()))
147 $GLOBALS['WS_PLUGIN__']['s2member']['c']['menu_pages'] = array(); // Clear right side.
148
149 $menu = apply_filters('ws_plugin__s2member_during_add_admin_options_menu_slug', 'ws-plugin--s2member-start', get_defined_vars());
150
151 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_menu_page', TRUE, get_defined_vars()))
152 add_menu_page(((c_ws_plugin__s2member_utils_conds::pro_is_installed()) ? 's2Member (Pro)' : 's2Member'), ((c_ws_plugin__s2member_utils_conds::pro_is_installed()) ? 's2Member (Pro)' : 's2Member'),
153 'create_users', $menu, 'c_ws_plugin__s2member_menu_pages::start_page', $GLOBALS['WS_PLUGIN__']['s2member']['c']['dir_url'].'/src/images/brand-favicon.png');
154
155 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_start_page', TRUE, get_defined_vars()))
156 add_submenu_page($menu, 'Getting Started w/ s2Member', 'Getting Started', 'create_users', 'ws-plugin--s2member-start', 'c_ws_plugin__s2member_menu_pages::start_page');
157
158 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_help_page', !is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site (), get_defined_vars()))
159 add_submenu_page($menu, 'Getting Help w/ s2Member', 'Getting Help', 'create_users', 'ws-plugin--s2member-help', 'c_ws_plugin__s2member_menu_pages::help_page');
160
161 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_divider_1', TRUE, get_defined_vars()))
162 add_submenu_page($menu, '', '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', 'create_users', '#');
163
164 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_mms_ops_page', (!is_multisite() || is_main_site()), get_defined_vars()))
165 add_submenu_page($menu, 's2Member Multisite Configuration', 'Multisite (Config)', 'create_users', 'ws-plugin--s2member-mms-ops', 'c_ws_plugin__s2member_menu_pages::mms_ops_page');
166
167 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_gen_ops_page', TRUE, get_defined_vars()))
168 add_submenu_page($menu, 's2Member General Options', 'General Options', 'create_users', 'ws-plugin--s2member-gen-ops', 'c_ws_plugin__s2member_menu_pages::gen_ops_page');
169
170 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_res_ops_page', TRUE, get_defined_vars()))
171 add_submenu_page($menu, 's2Member Restriction Options', 'Restriction Options', 'create_users', 'ws-plugin--s2member-res-ops', 'c_ws_plugin__s2member_menu_pages::res_ops_page');
172
173 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_down_ops_page', (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()), get_defined_vars()))
174 add_submenu_page($menu, 's2Member Download Options', 'Download Options', 'create_users', 'ws-plugin--s2member-down-ops', 'c_ws_plugin__s2member_menu_pages::down_ops_page');
175
176 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_divider_2', TRUE, get_defined_vars()))
177 add_submenu_page($menu, '', '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', 'create_users', '#');
178
179 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_paypal_ops_page', TRUE, get_defined_vars()))
180 add_submenu_page($menu, 's2Member PayPal Options', 'PayPal Options', 'create_users', 'ws-plugin--s2member-paypal-ops', 'c_ws_plugin__s2member_menu_pages::paypal_ops_page');
181
182 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_paypal_buttons_page', TRUE, get_defined_vars()))
183 add_submenu_page($menu, 's2Member PayPal Buttons', 'PayPal Buttons', 'create_users', 'ws-plugin--s2member-paypal-buttons', 'c_ws_plugin__s2member_menu_pages::paypal_buttons_page');
184
185 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_divider_3', TRUE, get_defined_vars()))
186 add_submenu_page($menu, '', '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', 'create_users', '#');
187
188 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_trk_ops_page', TRUE, get_defined_vars()))
189 add_submenu_page($menu, 's2Member API / Tracking', 'API / Tracking', 'create_users', 'ws-plugin--s2member-trk-ops', 'c_ws_plugin__s2member_menu_pages::trk_ops_page');
190
191 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_els_ops_page', TRUE, get_defined_vars()))
192 add_submenu_page($menu, 's2Member API / List Servers', 'API / List Servers', 'create_users', 'ws-plugin--s2member-els-ops', 'c_ws_plugin__s2member_menu_pages::els_ops_page');
193
194 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_api_ops_page', TRUE, get_defined_vars()))
195 add_submenu_page($menu, 's2Member API / Notifications', 'API / Notifications', 'create_users', 'ws-plugin--s2member-api-ops', 'c_ws_plugin__s2member_menu_pages::api_ops_page');
196
197 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_scripting_page', TRUE, get_defined_vars()))
198 add_submenu_page($menu, 's2Member API / Scripting', 'API / Scripting', 'create_users', 'ws-plugin--s2member-scripting', 'c_ws_plugin__s2member_menu_pages::scripting_page');
199
200 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_divider_4', TRUE, get_defined_vars()))
201 add_submenu_page($menu, '', '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', 'create_users', '#');
202
203 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_integrations_page', (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()), get_defined_vars()))
204 add_submenu_page($menu, 's2Member / Other Integrations', 'Other Integrations', 'create_users', 'ws-plugin--s2member-integrations', 'c_ws_plugin__s2member_menu_pages::integrations_page');
205
206 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_divider_5', TRUE, get_defined_vars()))
207 add_submenu_page($menu, '', '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', 'create_users', '#');
208
209 if(apply_filters('ws_plugin__s2member_during_add_admin_options_add_logs_page', (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()), get_defined_vars()))
210 add_submenu_page($menu, 's2Member Logs', 'Log Files (Debug)', 'create_users', 'ws-plugin--s2member-logs', 'c_ws_plugin__s2member_menu_pages::logs_page');
211
212 do_action('ws_plugin__s2member_during_add_admin_options_additional_pages', get_defined_vars());
213 }
214 do_action('ws_plugin__s2member_after_add_admin_options', get_defined_vars());
215 }
216
217 /**
218 * Adds network option menus / sub-menus.
219 *
220 * @package s2Member\Menu_Pages
221 * @since 3.5
222 *
223 * @attaches-to ``add_action('network_admin_menu');``
224 */
225 public static function add_network_admin_options()
226 {
227 do_action('ws_plugin__s2member_before_add_network_admin_options', get_defined_vars());
228
229 if(apply_filters('ws_plugin__s2member_during_add_network_admin_options_create_menu_items', TRUE, get_defined_vars()))
230 {
231 if((is_multisite() && c_ws_plugin__s2member_utils_conds::is_multisite_farm() && !is_main_site()) || apply_filters('ws_plugin__s2member_during_add_network_admin_options_clear_right_side', FALSE, get_defined_vars()))
232 $GLOBALS['WS_PLUGIN__']['s2member']['c']['menu_pages'] = array(); // Clear right side.
233
234 $menu = 'ws-plugin--s2member-mms-ops'; // Used below for nesting additional sub-menu pages.
235
236 add_menu_page('s2Member', 's2Member', 'create_users', $menu, 'c_ws_plugin__s2member_menu_pages::mms_ops_page', $GLOBALS['WS_PLUGIN__']['s2member']['c']['dir_url'].'/src/images/brand-favicon.png');
237
238 add_submenu_page($menu, 's2Member Multisite (Configuration)', 'Multisite (Config)', 'create_users', 'ws-plugin--s2member-mms-ops', 'c_ws_plugin__s2member_menu_pages::mms_ops_page');
239
240 do_action('ws_plugin__s2member_during_add_network_admin_options_additional_pages', get_defined_vars());
241 }
242 do_action('ws_plugin__s2member_after_add_network_admin_options', get_defined_vars());
243 }
244
245 /**
246 * A sort of callback function to add the settings link.
247 *
248 * @package s2Member\Menu_Pages
249 * @since 3.5
250 *
251 * @attaches-to ``add_filter('plugin_action_links');``
252 *
253 * @param array $actions Expects an existing array of actions links, passed in by the Filter.
254 * @param string $plugin_file Expects path to a plugin file. We need to test against this for s2Member.
255 *
256 * @return array An array of links, Filtered by this routine.
257 */
258 public static function _add_settings_link($actions = array(), $plugin_file = '')
259 {
260 foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $$__v;
261 do_action('_ws_plugin__s2member_before_add_settings_link', get_defined_vars());
262 unset($__refs, $__v); // Housekeeping.
263
264 if($plugin_file === $GLOBALS['WS_PLUGIN__']['s2member']['c']['plugin_basename'] && is_array($actions))
265 {
266 $settings = '<a href="'.esc_attr(admin_url('/admin.php?page=ws-plugin--s2member-gen-ops')).'">Settings</a>';
267 array_unshift($actions, apply_filters('ws_plugin__s2member_add_settings_link', $settings, get_defined_vars()));
268
269 foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $$__v;
270 do_action('_ws_plugin__s2member_during_add_settings_link', get_defined_vars());
271 unset($__refs, $__v); // Housekeeping.
272 }
273 return apply_filters('_ws_plugin__s2member_add_settings_link', $actions, get_defined_vars());
274 }
275
276 /**
277 * Enqueue scripts for administrative menu pages.
278 *
279 * @package s2Member\Menu_Pages
280 * @since 3.5
281 *
282 * @attaches-to ``add_action('admin_print_scripts');``
283 */
284 public static function add_admin_scripts()
285 {
286 do_action('ws_plugin__s2member_before_add_admin_scripts', get_defined_vars());
287
288 if(!empty($_GET['page']) && preg_match('/ws-plugin--s2member-/', $_GET['page']))
289 {
290 wp_enqueue_script('jquery');
291 wp_enqueue_script('thickbox');
292 wp_enqueue_script('media-upload');
293 wp_enqueue_script('jquery-ui-core');
294 wp_enqueue_script('jquery-sprintf', $GLOBALS['WS_PLUGIN__']['s2member']['c']['dir_url'].'/src/includes/jquery/jquery.sprintf/jquery.sprintf.min.js', array('jquery'), c_ws_plugin__s2member_utilities::ver_checksum());
295 wp_enqueue_script('jquery-json-ps', $GLOBALS['WS_PLUGIN__']['s2member']['c']['dir_url'].'/src/includes/jquery/jquery.json-ps/jquery.json-ps.min.js', array('jquery'), c_ws_plugin__s2member_utilities::ver_checksum());
296 wp_enqueue_script('jquery-ui-effects', $GLOBALS['WS_PLUGIN__']['s2member']['c']['dir_url'].'/src/includes/jquery/jquery.ui-effects/jquery.ui-effects.min.js', array('jquery', 'jquery-ui-core'), c_ws_plugin__s2member_utilities::ver_checksum());
297 wp_enqueue_script('ws-plugin--s2member-menu-pages', admin_url('admin.php?ws_plugin__s2member_menu_pages_js='.urlencode(mt_rand()), is_ssl() ? 'https' : 'http'), array('jquery', 'thickbox', 'media-upload', 'jquery-sprintf', 'jquery-json-ps', 'jquery-ui-core', 'jquery-ui-effects', 'password-strength-meter'), c_ws_plugin__s2member_utilities::ver_checksum());
298
299 do_action('ws_plugin__s2member_during_add_admin_scripts', get_defined_vars());
300 }
301 do_action('ws_plugin__s2member_after_add_admin_scripts', get_defined_vars());
302 }
303
304 /**
305 * Enqueue styles for administrative menu pages.
306 *
307 * @package s2Member\Menu_Pages
308 * @since 3.5
309 *
310 * @attaches-to ``add_action('admin_print_styles');``
311 */
312 public static function add_admin_styles()
313 {
314 do_action('ws_plugin__s2member_before_add_admin_styles', get_defined_vars());
315
316 if(!empty($_GET['page']) && preg_match('/ws-plugin--s2member-/', $_GET['page']))
317 {
318 wp_enqueue_style('thickbox');
319 wp_enqueue_style('ws-plugin--s2member-menu-pages', admin_url('admin.php?ws_plugin__s2member_menu_pages_css='.urlencode(mt_rand()), is_ssl() ? 'https' : 'http'), array('thickbox'), c_ws_plugin__s2member_utilities::ver_checksum(), 'all');
320
321 do_action('ws_plugin__s2member_during_add_admin_styles', get_defined_vars());
322 }
323 do_action('ws_plugin__s2member_after_add_admin_styles', get_defined_vars());
324 }
325
326 /**
327 * Handles log file downloads.
328 *
329 * @package s2Member\Menu_Pages
330 * @since 120310
331 */
332 public static function log_file_downloader()
333 {
334 if(!current_user_can('create_users')) return;
335 if(is_multisite() && c_ws_plugin__s2member_utils_conds::is_multisite_farm() && !is_main_site())
336 return; // We do NOT provide this functionality on Child Blogs of a Blog Farm Network.
337
338 if(!empty($_GET['ws_plugin__s2member_download_log_file']) && is_string($log_file = $_GET['ws_plugin__s2member_download_log_file']) && strpos($log_file, '..') === FALSE && strpos(basename($log_file), '.') !== 0)
339 if(!empty($_GET['ws_plugin__s2member_download_log_file_v']) && is_string($nonce = $_GET['ws_plugin__s2member_download_log_file_v']) && wp_verify_nonce($nonce, 'ws-plugin--s2member-download-log-file-v'))
340 {
341 $logs_dir = $GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir'];
342
343 if(file_exists($logs_dir.'/'.$log_file))
344 $log_file_contents = file_get_contents($logs_dir.'/'.$log_file);
345 else $log_file_contents = '';
346
347 @set_time_limit(0);
348 @ini_set('memory_limit', apply_filters('admin_memory_limit', WP_MAX_MEMORY_LIMIT));
349
350 @ini_set('zlib.output_compression', 0);
351 if(function_exists('apache_setenv'))
352 @apache_setenv('no-gzip', '1');
353
354 while(@ob_end_clean()) ;
355
356 status_header(200); // 200 OK status header.
357
358 header('Content-Encoding: none');
359 header('Accept-Ranges: none');
360 header('Content-Type: text/plain; charset=UTF-8');
361 header('Content-Length: '.strlen($log_file_contents));
362 header('Expires: '.gmdate('D, d M Y H:i:s', strtotime('-1 week')).' GMT');
363 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
364 header('Cache-Control: no-cache, must-revalidate, max-age=0');
365 header('Cache-Control: post-check=0, pre-check=0', FALSE);
366 header('Pragma: no-cache');
367
368 header('Content-Disposition: attachment; filename="'.$log_file.'"');
369
370 exit($log_file_contents); // Log file.
371 }
372 }
373
374 /**
375 * Handles log file downloads (in ZIP format).
376 *
377 * @package s2Member\Menu_Pages
378 * @since 120310
379 */
380 public static function logs_zip_downloader()
381 {
382 if(!current_user_can('create_users')) return;
383 if(is_multisite() && c_ws_plugin__s2member_utils_conds::is_multisite_farm() && !is_main_site())
384 return; // We do NOT provide this functionality on Child Blogs of a Blog Farm Network.
385
386 if(!empty($_POST['ws_plugin__s2member_logs_download_zip']) && is_string($nonce = $_POST['ws_plugin__s2member_logs_download_zip']) && wp_verify_nonce($nonce, 'ws-plugin--s2member-logs-download-zip'))
387 {
388 $logs_dir = $GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir'];
389 $s2member_logs_zip = $logs_dir.'/'.$_SERVER['HTTP_HOST'].'--s2member-logs.zip';
390
391 if(is_dir($logs_dir)) // Do we have a logs directory?
392 {
393 include_once ABSPATH.'wp-admin/includes/class-pclzip.php';
394
395 if(file_exists($s2member_logs_zip) && is_writable($s2member_logs_zip))
396 unlink($s2member_logs_zip);
397
398 $archive = new PclZip($s2member_logs_zip);
399 $archive->create($logs_dir, PCLZIP_OPT_REMOVE_ALL_PATH);
400 }
401 if(file_exists($s2member_logs_zip))
402 $s2member_logs_zip_size = filesize($s2member_logs_zip);
403 else $s2member_logs_zip_size = 0;
404
405 @set_time_limit(0);
406 @ini_set('memory_limit', apply_filters('admin_memory_limit', WP_MAX_MEMORY_LIMIT));
407
408 @ini_set('zlib.output_compression', 0);
409 if(function_exists('apache_setenv'))
410 @apache_setenv('no-gzip', '1');
411
412 while(@ob_end_clean()) ;
413
414 status_header(200); // 200 OK status header.
415
416 header('Content-Encoding: none');
417 header('Accept-Ranges: none');
418 header('Content-Type: application/zip');
419 header('Content-Length: '.$s2member_logs_zip_size);
420 header('Expires: '.gmdate('D, d M Y H:i:s', strtotime('-1 week')).' GMT');
421 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
422 header('Cache-Control: no-cache, must-revalidate, max-age=0');
423 header('Cache-Control: post-check=0, pre-check=0', FALSE);
424 header('Pragma: no-cache');
425
426 header('Content-Disposition: attachment; filename="'.basename($s2member_logs_zip).'"');
427
428 if($s2member_logs_zip_size && is_resource($resource = fopen($s2member_logs_zip, 'rb')))
429 {
430 $_bytes_to_read = $s2member_logs_zip_size; // Total bytes we need to read for this file.
431
432 $chunk_size = apply_filters('ws_plugin__s2member_file_downloads_chunk_size', 2097152, get_defined_vars());
433
434 while($_bytes_to_read) // We have bytes to read here.
435 {
436 $_bytes_to_read -= ($_reading = ($_bytes_to_read > $chunk_size) ? $chunk_size : $_bytes_to_read);
437 echo fread($resource, $_reading); // Serve file in chunks (default chunk size is 2MB).
438 flush(); // Flush each chunk to the browser as it is served (avoids high memory consumption).
439 }
440 fclose($resource); // Close file resource handle.
441 unset($_bytes_to_read, $_reading); // Housekeeping.
442 }
443 exit; // Clean exit after serving file.
444 }
445 }
446
447 /**
448 * Archives existing log files and starts fresh with new logs.
449 *
450 * @package s2Member\Menu_Pages
451 * @since 120310
452 */
453 public static function archive_logs_start_fresh()
454 {
455 if(!current_user_can('create_users')) return;
456 if(is_multisite() && c_ws_plugin__s2member_utils_conds::is_multisite_farm() && !is_main_site())
457 return; // We do NOT provide this functionality on Child Blogs of a Blog Farm Network.
458
459 if(!empty($_POST['ws_plugin__s2member_logs_archive_start_fresh']) && is_string($nonce = $_POST['ws_plugin__s2member_logs_archive_start_fresh']) && wp_verify_nonce($nonce, 'ws-plugin--s2member-logs-archive-start-fresh'))
460 {
461 if(is_dir($logs_dir = $GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir']))
462 foreach(scandir($logs_dir) as $log_file) // Archive existing log files here.
463 {
464 if(preg_match('/\.log$/', $log_file) && stripos($log_file, '-ARCHIVED-') === FALSE)
465 if(is_file($log_dir_file = $logs_dir.'/'.$log_file) && is_writable($log_dir_file))
466 if(!rename($log_dir_file, preg_replace('/\.log$/i', '', $log_dir_file).'-ARCHIVED-'.date('m-d-Y').'-'.time().'.log'))
467 $error = TRUE;
468 }
469 if(!empty($error))
470 c_ws_plugin__s2member_admin_notices::display_admin_notice('Unknown error when attempting to archive log files. Please check directory permissions.', TRUE);
471 else c_ws_plugin__s2member_admin_notices::display_admin_notice('All log files have been archived succesfully.');
472 }
473 }
474
475 /**
476 * Deletes existing log files and starts fresh with new logs.
477 *
478 * @package s2Member\Menu_Pages
479 * @since 120312
480 */
481 public static function delete_logs_start_fresh()
482 {
483 if(!current_user_can('create_users')) return;
484 if(is_multisite() && c_ws_plugin__s2member_utils_conds::is_multisite_farm() && !is_main_site())
485 return; // We do NOT provide this functionality on Child Blogs of a Blog Farm Network.
486
487 if(!empty($_POST['ws_plugin__s2member_logs_delete_start_fresh']) && is_string($nonce = $_POST['ws_plugin__s2member_logs_delete_start_fresh']) && wp_verify_nonce($nonce, 'ws-plugin--s2member-logs-delete-start-fresh'))
488 {
489 if(is_dir($logs_dir = $GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir']))
490 foreach(scandir($logs_dir) as $log_file) // Delete existing log files here.
491 {
492 if(preg_match('/\.log$/', $log_file))
493 if(is_file($log_dir_file = $logs_dir.'/'.$log_file) && is_writable($log_dir_file))
494 if(!unlink($log_dir_file)) $error = TRUE;
495 }
496 if(!empty($error))
497 c_ws_plugin__s2member_admin_notices::display_admin_notice('Unknown error when attempting to delete log files. Please check directory permissions.', TRUE);
498 else c_ws_plugin__s2member_admin_notices::display_admin_notice('All log files have been deleted succesfully.');
499 }
500 }
501
502 /**
503 * Builds and handles the Getting Started page.
504 *
505 * @package s2Member\Menu_Pages
506 * @since 3.5
507 */
508 public static function start_page()
509 {
510 do_action('ws_plugin__s2member_before_start_page', get_defined_vars());
511
512 include_once dirname(dirname(__FILE__)).'/menu-pages/start.inc.php';
513
514 do_action('ws_plugin__s2member_after_start_page', get_defined_vars());
515 }
516
517 /**
518 * Builds and handles the Getting Help page.
519 *
520 * @package s2Member\Menu_Pages
521 * @since 151218
522 */
523 public static function help_page()
524 {
525 do_action('ws_plugin__s2member_before_help_page', get_defined_vars());
526
527 include_once dirname(dirname(__FILE__)).'/menu-pages/help.inc.php';
528
529 do_action('ws_plugin__s2member_after_help_page', get_defined_vars());
530 }
531
532 /**
533 * Builds and handles the Main Multisite Options page.
534 *
535 * @package s2Member\Menu_Pages
536 * @since 3.5
537 */
538 public static function mms_ops_page()
539 {
540 do_action('ws_plugin__s2member_before_mms_ops_page', get_defined_vars());
541
542 include_once dirname(dirname(__FILE__)).'/menu-pages/mms-ops.inc.php';
543
544 do_action('ws_plugin__s2member_after_mms_ops_page', get_defined_vars());
545 }
546
547 /**
548 * Builds and handles the General Options page.
549 *
550 * @package s2Member\Menu_Pages
551 * @since 3.5
552 */
553 public static function gen_ops_page()
554 {
555 do_action('ws_plugin__s2member_before_gen_ops_page', get_defined_vars());
556
557 c_ws_plugin__s2member_menu_pages::update_all_options();
558
559 include_once dirname(dirname(__FILE__)).'/menu-pages/gen-ops.inc.php';
560
561 do_action('ws_plugin__s2member_after_gen_ops_page', get_defined_vars());
562 }
563
564 /**
565 * Builds and handles the Restriction Options page.
566 *
567 * @package s2Member\Menu_Pages
568 * @since 3.5
569 */
570 public static function res_ops_page()
571 {
572 do_action('ws_plugin__s2member_before_res_ops_page', get_defined_vars());
573
574 c_ws_plugin__s2member_menu_pages::update_all_options();
575
576 include_once dirname(dirname(__FILE__)).'/menu-pages/res-ops.inc.php';
577
578 do_action('ws_plugin__s2member_after_res_ops_page', get_defined_vars());
579 }
580
581 /**
582 * Builds and handles the Paypal Options page.
583 *
584 * @package s2Member\Menu_Pages
585 * @since 3.5
586 */
587 public static function paypal_ops_page()
588 {
589 do_action('ws_plugin__s2member_before_paypal_ops_page', get_defined_vars());
590
591 c_ws_plugin__s2member_menu_pages::update_all_options();
592
593 $logs_dir = $GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir'];
594
595 if(!is_dir($logs_dir) && is_writable(dirname(c_ws_plugin__s2member_utils_dirs::strip_dir_app_data($logs_dir))))
596 mkdir($logs_dir, 0777, TRUE).clearstatcache();
597
598 $htaccess = $GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir'].'/.htaccess';
599 $htaccess_contents = trim(c_ws_plugin__s2member_utilities::evl(file_get_contents($GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir_htaccess'])));
600
601 if(is_dir($logs_dir) && is_writable($logs_dir) && !file_exists($htaccess))
602 file_put_contents($htaccess, $htaccess_contents).clearstatcache();
603
604 if($GLOBALS['WS_PLUGIN__']['s2member']['o']['gateway_debug_logs']) // Logging enabled?
605 {
606 if(!is_dir($logs_dir)) // If the security-enabled logs directory does not exist yet.
607 c_ws_plugin__s2member_admin_notices::display_admin_notice('The security-enabled logs directory (<code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($logs_dir)).'</code>) does not exist. Please create this directory manually &amp; make it writable (chmod 777).', TRUE);
608
609 else if(!is_writable($logs_dir)) // If the logs directory is not writable yet.
610 c_ws_plugin__s2member_admin_notices::display_admin_notice('Permissions error. The security-enabled logs directory (<code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($logs_dir)).'</code>) is not writable. Please make this directory writable (chmod 777).', TRUE);
611
612 if(!file_exists($htaccess)) // If the .htaccess file has not been created yet.
613 c_ws_plugin__s2member_admin_notices::display_admin_notice('The .htaccess protection file (<code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($htaccess)).'</code>) does not exist. Please create this file manually. Inside your .htaccess file, add this:<br /><pre>'.esc_html($htaccess_contents).'</pre>', TRUE);
614
615 else if(!preg_match('/deny from all/i', file_get_contents($htaccess))) // Else if the .htaccess file does not offer the required protection.
616 c_ws_plugin__s2member_admin_notices::display_admin_notice('Unprotected. The .htaccess protection file (<code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($htaccess)).'</code>) does not contain <code>deny from all</code>. Inside your .htaccess file, add this:<br /><pre>'.esc_html($htaccess_contents).'</pre>', TRUE);
617 }
618 include_once dirname(dirname(__FILE__)).'/menu-pages/paypal-ops.inc.php';
619
620 do_action('ws_plugin__s2member_after_paypal_ops_page', get_defined_vars());
621 }
622
623 /**
624 * Builds and handles the Download Options page.
625 *
626 * @package s2Member\Menu_Pages
627 * @since 3.5
628 */
629 public static function down_ops_page()
630 {
631 do_action('ws_plugin__s2member_before_down_ops_page', get_defined_vars());
632
633 c_ws_plugin__s2member_menu_pages::update_all_options();
634
635 if(!empty($_REQUEST['ws_plugin__s2member_cf_options_reset'])
636 && wp_verify_nonce($_REQUEST['ws_plugin__s2member_cf_options_reset'], 'ws-plugin--s2member-cf-options-reset')
637 )
638 {
639 c_ws_plugin__s2member_files_in::reset_aws_cf_config_values(); // A full CloudFront reset.
640 c_ws_plugin__s2member_admin_notices::display_admin_notice('Amazon CloudFront configuration reset successfully.');
641 }
642 $files_dir = $GLOBALS['WS_PLUGIN__']['s2member']['c']['files_dir'];
643
644 $htaccess = $GLOBALS['WS_PLUGIN__']['s2member']['c']['files_dir'].'/.htaccess';
645 $htaccess_contents = trim(c_ws_plugin__s2member_utilities::evl(file_get_contents($GLOBALS['WS_PLUGIN__']['s2member']['c']['files_dir_htaccess'])));
646
647 $no_gzip_htaccess = ABSPATH.'.htaccess'; // Always located in the absolute root path for WordPress.
648 $no_gzip_htaccess_contents = trim(c_ws_plugin__s2member_utilities::evl(file_get_contents($GLOBALS['WS_PLUGIN__']['s2member']['c']['files_no_gzip_htaccess'])));
649
650 if(!c_ws_plugin__s2member_files::no_gzip_rules_in_root_htaccess()) // If s2Member's GZIP exclusions do NOT yet exist in the root `.htaccess` file.
651 c_ws_plugin__s2member_files::write_no_gzip_into_root_htaccess().clearstatcache(); // Handle the root `.htaccess` file now.
652
653 if(!is_dir($files_dir) && is_writable(dirname(c_ws_plugin__s2member_utils_dirs::strip_dir_app_data($files_dir))))
654 mkdir($files_dir, 0777, TRUE).clearstatcache(); // Create this directory structure now.
655
656 if(is_dir($files_dir) && is_writable($files_dir) && !file_exists($htaccess)) // This file does NOT exist yet?
657 file_put_contents($htaccess, $htaccess_contents).clearstatcache(); // Create the `.htaccess` file now.
658
659 if(!c_ws_plugin__s2member_files::no_gzip_rules_in_root_htaccess()) // If s2Member's GZIP exclusions do NOT yet exist in the root `.htaccess` file.
660 c_ws_plugin__s2member_admin_notices::display_admin_notice('Possible GZIP conflict on server. Unable to write GZIP exclusions into root .htaccess file (<code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($no_gzip_htaccess)).'</code>). Please read the panel below: <strong>Preventing GZIP Conflicts</strong>, and add this section yourself:<br /><pre>'.esc_html($no_gzip_htaccess_contents).'</pre>', TRUE);
661
662 if(!is_dir($files_dir)) // If the security-enabled files directory does not exist yet.
663 c_ws_plugin__s2member_admin_notices::display_admin_notice('The security-enabled files directory (<code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($files_dir)).'</code>) does not exist. Please create this directory manually.', TRUE);
664
665 if(!file_exists($htaccess)) // If the `.htaccess` file has not been created yet.
666 c_ws_plugin__s2member_admin_notices::display_admin_notice('The .htaccess protection file (<code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($htaccess)).'</code>) does not exist. Please create this file manually. Inside your .htaccess file, add this:<br /><pre>'.esc_html($htaccess_contents).'</pre>', TRUE);
667
668 else if(!preg_match('/deny from all/i', file_get_contents($htaccess))) // Else if the `.htaccess` file does not offer the required protection.
669 c_ws_plugin__s2member_admin_notices::display_admin_notice('Unprotected. The .htaccess protection file (<code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($htaccess)).'</code>) does not contain <code>deny from all</code>. Inside your .htaccess file, add this:<br /><pre>'.esc_html($htaccess_contents).'</pre>', TRUE);
670
671 if(!empty($_POST['ws_plugin__s2member_amazon_cf_files_auto_configure_distros']) && ($nonce = $_POST['ws_plugin__s2member_amazon_cf_files_auto_configure_distros']) && wp_verify_nonce($nonce, 'ws-plugin--s2member-amazon-cf-files-auto-configure-distros'))
672 if(($amazon_cf_auto_configure_distros = c_ws_plugin__s2member_files_in::amazon_cf_auto_configure_distros()) && $amazon_cf_auto_configure_distros['success'])
673 c_ws_plugin__s2member_admin_notices::display_admin_notice('Amazon CloudFront Distributions auto-configured successfully. Please allow 30 minutes for initial propagation. <strong>Tip:</strong> If you try to stream over the RTMP protocol using something like the <code>[s2Stream /]</code> shortcode, and you keep getting an "ID Not Found" error while using JW Player; please note that it can <em>sometimes</em> take a full 24 hours for RTMP (i.e., streaming distributions) to begin working properly. This is because there are a few initialization routines that must complete on the AWS side when you first integrate with CloudFront. Please be patient.'.(($GLOBALS['WS_PLUGIN__']['s2member']['o']['amazon_cf_files_distro_downloads_cname']) ? '<br /><em>Downloads Distribution CNAME: <code>'.esc_html($GLOBALS['WS_PLUGIN__']['s2member']['o']['amazon_cf_files_distro_downloads_cname']).' &mdash;&raquo; '.esc_html($GLOBALS['WS_PLUGIN__']['s2member']['o']['amazon_cf_files_distro_downloads_dname']).'</code></em>' : '').(($GLOBALS['WS_PLUGIN__']['s2member']['o']['amazon_cf_files_distro_streaming_cname']) ? '<br /><em>Streaming Distribution CNAME: <code>'.esc_html($GLOBALS['WS_PLUGIN__']['s2member']['o']['amazon_cf_files_distro_streaming_cname']).' &mdash;&raquo; '.esc_html($GLOBALS['WS_PLUGIN__']['s2member']['o']['amazon_cf_files_distro_streaming_dname']).'</code></em>' : ''));
674 else // Else there was an error. We need to report this back to the site owner so they can understand what's going on.
675 (c_ws_plugin__s2member_menu_pages::$pre_display_errors['cf_files_auto_configure_distros'] = TRUE).c_ws_plugin__s2member_admin_notices::display_admin_notice('Unable to auto-configure Amazon CloudFront Distributions.<br />Error code: <code>'.esc_html($amazon_cf_auto_configure_distros['code']).'</code>. Error Message: <code>'.esc_html($amazon_cf_auto_configure_distros['message']).'</code>', TRUE);
676
677 if(!empty($_POST['ws_plugin__s2member_amazon_s3_files_auto_configure_acls']) && ($nonce = $_POST['ws_plugin__s2member_amazon_s3_files_auto_configure_acls']) && wp_verify_nonce($nonce, 'ws-plugin--s2member-amazon-s3-files-auto-configure-acls'))
678 if(($amazon_s3_auto_configure_acls = c_ws_plugin__s2member_files_in::amazon_s3_auto_configure_acls()) && $amazon_s3_auto_configure_acls['success'])
679 c_ws_plugin__s2member_admin_notices::display_admin_notice('Amazon S3 ACLs auto-configured successfully.');
680 else // Else there was an error. We need to report this back to the site owner so they can understand what's going on.
681 (c_ws_plugin__s2member_menu_pages::$pre_display_errors['s3_files_auto_configure_acls'] = TRUE).c_ws_plugin__s2member_admin_notices::display_admin_notice('Unable to auto-configure Amazon S3 ACLs.<br />Error code: <code>'.esc_html($amazon_s3_auto_configure_acls['code']).'</code>. Error Message: <code>'.esc_html($amazon_s3_auto_configure_acls['message']).'</code>', TRUE);
682
683 include_once dirname(dirname(__FILE__)).'/menu-pages/down-ops.inc.php';
684
685 do_action('ws_plugin__s2member_after_down_ops_page', get_defined_vars());
686 }
687
688 /**
689 * Builds and handles the API Tracking options page.
690 *
691 * @package s2Member\Menu_Pages
692 * @since 3.5
693 */
694 public static function trk_ops_page()
695 {
696 do_action('ws_plugin__s2member_before_trk_ops_page', get_defined_vars());
697
698 c_ws_plugin__s2member_menu_pages::update_all_options();
699
700 include_once dirname(dirname(__FILE__)).'/menu-pages/trk-ops.inc.php';
701
702 do_action('ws_plugin__s2member_after_trk_ops_page', get_defined_vars());
703 }
704
705 /**
706 * Builds and handles the API List Server options page.
707 *
708 * @package s2Member\Menu_Pages
709 * @since 3.5
710 */
711 public static function els_ops_page()
712 {
713 do_action('ws_plugin__s2member_before_els_ops_page', get_defined_vars());
714
715 c_ws_plugin__s2member_menu_pages::update_all_options();
716
717 include_once dirname(dirname(__FILE__)).'/menu-pages/els-ops.inc.php';
718
719 do_action('ws_plugin__s2member_after_els_ops_page', get_defined_vars());
720 }
721
722 /**
723 * Builds and handles the API Notifications page.
724 *
725 * @package s2Member\Menu_Pages
726 * @since 3.5
727 */
728 public static function api_ops_page()
729 {
730 do_action('ws_plugin__s2member_before_api_ops_page', get_defined_vars());
731
732 c_ws_plugin__s2member_menu_pages::update_all_options();
733
734 include_once dirname(dirname(__FILE__)).'/menu-pages/api-ops.inc.php';
735
736 do_action('ws_plugin__s2member_after_api_ops_page', get_defined_vars());
737 }
738
739 /**
740 * Builds and handles the PayPal Button Generator page.
741 *
742 * @package s2Member\Menu_Pages
743 * @since 3.5
744 */
745 public static function paypal_buttons_page()
746 {
747 do_action('ws_plugin__s2member_before_paypal_buttons_page', get_defined_vars());
748
749 if(!$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_business'] || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_merchant_id'] || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_api_username'] || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_api_password'] || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_api_signature'])
750 c_ws_plugin__s2member_admin_notices::display_admin_notice('Please configure <strong>s2Member → PayPal Options</strong> first. Once all of your PayPal Options are configured; including your Email Address, Merchant ID, API Username, Password, and Signature; return to this page &amp; generate your PayPal Button(s).', TRUE);
751
752 include_once dirname(dirname(__FILE__)).'/menu-pages/paypal-buttons.inc.php';
753
754 do_action('ws_plugin__s2member_after_paypal_buttons_page', get_defined_vars());
755 }
756
757 /**
758 * Builds and handles the API Scripting page.
759 *
760 * @package s2Member\Menu_Pages
761 * @since 3.5
762 */
763 public static function scripting_page()
764 {
765 do_action('ws_plugin__s2member_before_scripting_page', get_defined_vars());
766
767 c_ws_plugin__s2member_menu_pages::update_all_options();
768
769 include_once dirname(dirname(__FILE__)).'/menu-pages/scripting.inc.php';
770
771 do_action('ws_plugin__s2member_after_scripting_page', get_defined_vars());
772 }
773
774 /**
775 * Builds and handles the Integrations page.
776 *
777 * @package s2Member\Menu_Pages
778 * @since 3.5
779 */
780 public static function integrations_page()
781 {
782 do_action('ws_plugin__s2member_before_integrations_page', get_defined_vars());
783
784 include_once dirname(dirname(__FILE__)).'/menu-pages/integrations.inc.php';
785
786 do_action('ws_plugin__s2member_after_integrations_page', get_defined_vars());
787 }
788
789 /**
790 * Builds and handles the Logs page.
791 *
792 * @package s2Member\Menu_Pages
793 * @since 120310
794 */
795 public static function logs_page()
796 {
797 do_action('ws_plugin__s2member_before_logs_page', get_defined_vars());
798
799 c_ws_plugin__s2member_menu_pages::update_all_options();
800 c_ws_plugin__s2member_menu_pages::archive_logs_start_fresh();
801 c_ws_plugin__s2member_menu_pages::delete_logs_start_fresh();
802
803 $logs_dir = $GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir'];
804
805 if(!is_dir($logs_dir) && is_writable(dirname(c_ws_plugin__s2member_utils_dirs::strip_dir_app_data($logs_dir))))
806 mkdir($logs_dir, 0777, TRUE).clearstatcache();
807
808 $htaccess = $GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir'].'/.htaccess';
809 $htaccess_contents = trim(c_ws_plugin__s2member_utilities::evl(file_get_contents($GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir_htaccess'])));
810
811 if(is_dir($logs_dir) && is_writable($logs_dir) && !file_exists($htaccess))
812 file_put_contents($htaccess, $htaccess_contents).clearstatcache();
813
814 if(!is_dir($logs_dir)) // If the security-enabled logs directory does not exist yet.
815 c_ws_plugin__s2member_admin_notices::display_admin_notice('The security-enabled logs directory (<code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($logs_dir)).'</code>) does not exist. Please create this directory manually &amp; make it writable (chmod 777).', TRUE);
816
817 else if(!is_writable($logs_dir)) // If the logs directory is not writable yet.
818 c_ws_plugin__s2member_admin_notices::display_admin_notice('Permissions error. The security-enabled logs directory (<code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($logs_dir)).'</code>) is not writable. Please make this directory writable (chmod 777).', TRUE);
819
820 if(!file_exists($htaccess)) // If the .htaccess file has not been created yet.
821 c_ws_plugin__s2member_admin_notices::display_admin_notice('The .htaccess protection file (<code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($htaccess)).'</code>) does not exist. Please create this file manually. Inside your .htaccess file, add this:<br /><pre>'.esc_html($htaccess_contents).'</pre>', TRUE);
822
823 else if(!preg_match('/deny from all/i', file_get_contents($htaccess))) // Else if the .htaccess file does not offer the required protection.
824 c_ws_plugin__s2member_admin_notices::display_admin_notice('Unprotected. The .htaccess protection file (<code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($htaccess)).'</code>) does not contain <code>deny from all</code>. Inside your .htaccess file, add this:<br /><pre>'.esc_html($htaccess_contents).'</pre>', TRUE);
825
826 if(!$GLOBALS['WS_PLUGIN__']['s2member']['o']['gateway_debug_logs']) // Logging disabled?
827 c_ws_plugin__s2member_admin_notices::display_admin_notice('Logging is currently disabled by your configuration.');
828
829 include_once dirname(dirname(__FILE__)).'/menu-pages/logs.inc.php';
830
831 do_action('ws_plugin__s2member_after_logs_page', get_defined_vars());
832 }
833
834 /**
835 * Registers the Get Help panel across admin pages.
836 *
837 * @package s2Member\Menu_Pages
838 * @since 250824
839 *
840 * @attaches-to ``add_action('admin_menu');``
841 */
842 public static function get_help_panel() {
843 $hooks = array(
844 // Framework
845 'ws_plugin__s2member_during_api_ops_page_before_left_sections_form',
846 'ws_plugin__s2member_during_down_ops_page_before_left_sections_form',
847 'ws_plugin__s2member_during_els_ops_page_before_left_sections_form',
848 'ws_plugin__s2member_during_gen_ops_page_before_left_sections_form',
849 'ws_plugin__s2member_during_help_page_before_left_sections',
850 'ws_plugin__s2member_during_integrations_page_before_left_sections',
851 'ws_plugin__s2member_during_logs_page_before_left_sections',
852 'ws_plugin__s2member_during_paypal_buttons_page_before_left_sections',
853 'ws_plugin__s2member_during_paypal_ops_page_before_left_sections_form',
854 'ws_plugin__s2member_during_res_ops_page_before_left_sections_form',
855 'ws_plugin__s2member_during_scripting_page_before_left_sections',
856 'ws_plugin__s2member_during_start_page_before_left_sections',
857 'ws_plugin__s2member_during_trk_ops_page_before_left_sections_form',
858 // Pro
859 'ws_plugin__s2member_during_authnet_forms_page_before_left_sections',
860 'ws_plugin__s2member_during_authnet_ops_page_before_left_sections_form',
861 'ws_plugin__s2member_during_clickbank_buttons_page_before_left_sections',
862 'ws_plugin__s2member_during_clickbank_ops_page_before_left_sections_form',
863 'ws_plugin__s2member_during_coupon_codes_page_before_left_sections_form',
864 'ws_plugin__s2member_during_import_export_page_before_left_sections',
865 'ws_plugin__s2member_during_mms_ops_page_before_left_sections_form',
866 'ws_plugin__s2member_during_other_gateways_page_before_left_sections_form',
867 'ws_plugin__s2member_during_paypal_forms_page_before_left_sections',
868 'ws_plugin__s2member_during_stripe_forms_page_before_left_sections',
869 'ws_plugin__s2member_during_stripe_ops_page_before_left_sections_form',
870 );
871
872 foreach ($hooks as $hook) {
873 add_action($hook, 'c_ws_plugin__s2member_menu_pages::get_help_panel_load', 1, 1);
874 }
875 }
876
877 /**
878 * Renders the Get Help panel (computes $notice/$draft and includes template).
879 *
880 * @package s2Member\Menu_Pages
881 * @since 250824
882 *
883 * @param array $vars Optional vars passed by the hook (unused).
884 */
885 public static function get_help_panel_load($vars = array()) {
886 if (!current_user_can('manage_options')) return;
887
888 // Build notice (if POST).
889 $notice = array('type' => '', 'text' => '');
890 if (!empty($_POST['s2m_help_nonce']) && isset($_POST['s2m_help_submit']) && wp_verify_nonce($_POST['s2m_help_nonce'], 's2member_get_help')) {
891 $result = c_ws_plugin__s2member_menu_pages::get_help_mail();
892 if (!empty($result['ok'])) {
893 $notice = array('type' => 'success', 'text' => __('Thanks — your message was sent. You’ll receive a copy by email.', 's2member'));
894 $_POST = array(); // clear fields after success so defaults repopulate
895 } else {
896 $msg = isset($result['msg']) ? $result['msg'] : __('Sorry, your message could not be sent. Please try again.', 's2member');
897 $notice = array('type' => 'error', 'text' => $msg);
898 }
899 }
900
901 // Build draft (preserve POST on error; else defaults from current user).
902 $current = wp_get_current_user();
903 $draft = array(
904 'name' => is_object($current) ? trim($current->display_name) : '',
905 'email' => is_object($current) ? trim($current->user_email) : '',
906 'subject' => '',
907 'details' => '',
908 'meta' => home_url()."\n"
909 .'PHP v'.PHP_VERSION
910 .', WordPress v'.(isset($GLOBALS['wp_version']) ? $GLOBALS['wp_version'] : '')
911 .', s2Member v'.(defined('WS_PLUGIN__S2MEMBER_VERSION') ? WS_PLUGIN__S2MEMBER_VERSION : '')
912 .(defined('WS_PLUGIN__S2MEMBER_PRO_VERSION') ? ', Pro v'.WS_PLUGIN__S2MEMBER_PRO_VERSION : ''),
913 );
914
915 if (isset($_POST['name'])) $draft['name'] = wp_strip_all_tags(trim(wp_unslash($_POST['name'])));
916 if (isset($_POST['email'])) $draft['email'] = sanitize_email(trim(wp_unslash($_POST['email'])));
917 if (isset($_POST['subject'])) $draft['subject'] = sanitize_text_field(trim(wp_unslash($_POST['subject'])));
918 if (isset($_POST['details'])) $draft['details'] = trim(wp_unslash($_POST['details']));
919 if (isset($_POST['meta'])) $draft['meta'] = trim(wp_unslash($_POST['meta']));
920
921 // Include template (variables $draft and $notice are in scope for the include).
922 include_once dirname(dirname(__FILE__)).'/menu-pages/get-help-panel.inc.php';
923 }
924
925 /**
926 * Sends the Get Help email (simple contact form, Bcc user).
927 *
928 * @package s2Member\Menu_Pages
929 * @since 250824
930 *
931 * @return array Array like ['ok' => bool, 'msg' => string].
932 */
933 public static function get_help_mail() {
934 if (!current_user_can('manage_options')) {
935 return array('ok' => false, 'msg' => __('You do not have permission to send support requests from this page.', 's2member'));
936 }
937
938 $name = isset($_POST['name']) ? wp_strip_all_tags(trim(wp_unslash($_POST['name']))) : '';
939 $email = isset($_POST['email']) ? sanitize_email(trim(wp_unslash($_POST['email']))) : '';
940 $subject_in = isset($_POST['subject']) ? sanitize_text_field(trim(wp_unslash($_POST['subject']))) : '';
941 $details = isset($_POST['details']) ? trim(wp_unslash($_POST['details'])) : '';
942 $meta = isset($_POST['meta']) ? trim(wp_unslash($_POST['meta'])) : '';
943
944 $email = str_replace(array("\r", "\n"), '', $email); // header-injection safety
945 if (empty($email) || !is_email($email)) {
946 return array('ok' => false, 'msg' => __('Please provide a valid email address.', 's2member'));
947 }
948 if ($details === '') {
949 return array('ok' => false, 'msg' => __('Please describe how I can help.', 's2member'));
950 }
951
952 // Cap length and normalize body fields
953 $max_len = 100000;
954 if (strlen($details) > $max_len) $details = substr($details, 0, $max_len);
955 if (strlen($meta) > $max_len) $meta = substr($meta, 0, $max_len);
956
957 $details = str_replace(array("\r\n", "\r"), "\n", $details);
958 $meta = str_replace(array("\r\n", "\r"), "\n", $meta);
959 $message = $details."\n\n".$meta;
960
961 // Subject with fallback/prefix
962 $subject = (string) apply_filters('ws_plugin__s2member_get_help_subject', $subject_in);
963 $subject = str_replace(array("\r\n", "\r", "\n"), ' ', trim($subject));
964 $subject = ($subject === '') ? __('s2Member help request', 's2member') : 's2Member help: '.$subject;
965
966 // Sanitize display names
967 $name_hdr = str_replace(array("\r\n", "\r", "\n"), ' ', (string) $name);
968 $name_hdr = str_replace('"', "'", $name_hdr);
969
970 $sitename = wp_parse_url(home_url(), PHP_URL_HOST);
971 $sitename = is_string($sitename) ? strtolower($sitename) : '';
972 if (strpos($sitename, 'www.') === 0) $sitename = substr($sitename, 4);
973
974 $default_from_email = 'wordpress@'.$sitename;
975 $default_from_name = ($name_hdr !== '' ? $name_hdr : get_bloginfo('name'));
976
977 // Honor WP and s2 filters, then cleanup
978 $from_email = (string) apply_filters('wp_mail_from', $default_from_email);
979 $from_name = (string) apply_filters('wp_mail_from_name', $default_from_name);
980
981 $from_email = (string) apply_filters('ws_plugin__s2member_get_help_from_email', $from_email);
982 $from_name = (string) apply_filters('ws_plugin__s2member_get_help_from_name', $from_name);
983
984 $from_email = str_replace(array("\r", "\n"), '', $from_email);
985 $from_name = str_replace(array("\r\n", "\r", "\n"), ' ', $from_name);
986 $from_name = str_replace('"', "'", $from_name);
987
988 // Build headers
989 $from_line = '"'.$from_name.'" <'.$from_email.'>';
990 $user_line = ($name_hdr !== '' ? '"'.$name_hdr.'" ' : '').'<'.$email.'>';
991
992 $headers = array('Content-Type: text/plain; charset=UTF-8');
993 $headers[] = 'From: '.$from_line;
994 $headers[] = 'Reply-To: '.$user_line;
995 $headers[] = 'Bcc: '.$user_line;
996 $headers[] = 'X-s2Member-Help: 1';
997
998 $headers = apply_filters('ws_plugin__s2member_get_help_headers', $headers, compact('name','email','subject','details','meta'));
999
1000 // Recipient
1001 $to = (string) apply_filters('ws_plugin__s2member_get_help_mailbox', 'support@wpsharks.com');
1002 if (empty($to) || !is_email($to)) {
1003 return array('ok' => false, 'msg' => __('Support mailbox is not configured correctly.', 's2member'));
1004 }
1005
1006 $sent = wp_mail($to, $subject, $message, $headers);
1007
1008 if (!$sent) {
1009 if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
1010 error_log('s2Member Get Help: wp_mail() returned false. To='.$to.' | Subject='.$subject);
1011 }
1012 return array('ok' => false, 'msg' => __('Email could not be sent (mail server issue). Please try again or contact us directly.', 's2member'));
1013 }
1014 return array('ok' => true, 'msg' => __('Thanks — your message was sent. You’ll receive a copy by email.', 's2member'));
1015 }
1016 }
1017 }
1018