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 / classes / installation.inc.php

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

314 lines 19.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 * Installation routines for s2Member.
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\Installation
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_installation'))
22 {
23 /**
24 * Installation routines for s2Member.
25 *
26 * @package s2Member\Installation
27 * @since 3.5
28 */
29 class c_ws_plugin__s2member_installation
30 {
31 /**
32 * Activation routines for s2Member.
33 *
34 * @package s2Member\Installation
35 * @since 3.5
36 *
37 * @param string $reactivation_reason Optional.
38 */
39 public static function activate($reactivation_reason = '')
40 {
41 global $wpdb;
42 /** @var $wpdb wpdb */
43 global $current_site, $current_blog; // Multisite.
44
45 do_action('ws_plugin__s2member_before_activation', get_defined_vars());
46
47 c_ws_plugin__s2member_roles_caps::config_roles(); // Config Roles/Caps.
48 update_option('ws_plugin__s2member_activated_levels', $GLOBALS['WS_PLUGIN__']['s2member']['c']['levels']);
49
50 if(!is_dir($files_dir = $GLOBALS['WS_PLUGIN__']['s2member']['c']['files_dir']))
51 if(is_writable(dirname(c_ws_plugin__s2member_utils_dirs::strip_dir_app_data($files_dir))))
52 mkdir($files_dir, 0777, TRUE);
53
54 if(is_dir($files_dir) && is_writable($files_dir))
55 if(!is_file($htaccess = $files_dir.'/.htaccess') || !apply_filters('ws_plugin__s2member_preserve_files_dir_htaccess', !is_writable($files_dir.'/.htaccess'), get_defined_vars()))
56 file_put_contents($htaccess, trim(c_ws_plugin__s2member_utilities::evl(file_get_contents($GLOBALS['WS_PLUGIN__']['s2member']['c']['files_dir_htaccess']))));
57
58 c_ws_plugin__s2member_files::write_no_gzip_into_root_htaccess(); // Handle the root `.htaccess` file as well now, for GZIP exclusions.
59
60 if(!is_dir($logs_dir = $GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir']))
61 if(is_writable(dirname(c_ws_plugin__s2member_utils_dirs::strip_dir_app_data($logs_dir))))
62 mkdir($logs_dir, 0777, TRUE);
63
64 if(is_dir($logs_dir) && is_writable($logs_dir))
65 if(!is_file($htaccess = $logs_dir.'/.htaccess') || !apply_filters('ws_plugin__s2member_preserve_logs_dir_htaccess', !is_writable($logs_dir.'/.htaccess'), get_defined_vars()))
66 file_put_contents($htaccess, trim(c_ws_plugin__s2member_utilities::evl(file_get_contents($GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir_htaccess']))));
67
68 //260916.2137 Detect a genuinely fresh activation before creating the options row; missing options on any prior installation must retain legacy EOT demotion behavior.
69 $fresh_install = !get_option('ws_plugin__s2member_activated_version') && !is_array(get_option('ws_plugin__s2member_options'));
70
71 (!is_array(get_option('ws_plugin__s2member_cache'))) ? update_option('ws_plugin__s2member_cache', array()) : NULL;
72 (!is_array(get_option('ws_plugin__s2member_notices'))) ? update_option('ws_plugin__s2member_notices', array()) : NULL;
73 (!is_array(get_option('ws_plugin__s2member_options'))) ? update_option('ws_plugin__s2member_options', array()) : NULL;
74 (!is_numeric(get_option('ws_plugin__s2member_configured'))) ? update_option('ws_plugin__s2member_configured', '0') : NULL;
75
76 $options = (array)get_option('ws_plugin__s2member_options');
77 if(!array_key_exists('eot_demotion_from', $options))
78 {
79 $options['eot_demotion_from'] = $fresh_install ? 's2member_level' : 'all';
80 update_option('ws_plugin__s2member_options', $options);
81 if(is_multisite() && is_main_site())
82 update_site_option('ws_plugin__s2member_options', $options);
83 }
84 unset($fresh_install, $options);
85
86 //260902.0420 A Framework activation/update invalidates cached Pro update availability; the next admin request will refresh it in the background.
87 if($reactivation_reason === '' || $reactivation_reason === 'version')
88 {
89 $options = (array)get_option('ws_plugin__s2member_options');
90 if(isset($options['pro_latest_version']))
91 {
92 unset($options['pro_latest_version']);
93 $options = ws_plugin__s2member_configure_options_and_their_defaults($options);
94 update_option('ws_plugin__s2member_options', $options);
95 if(is_multisite() && is_main_site())
96 update_site_option('ws_plugin__s2member_options', $options);
97 }
98 unset($options);
99 }
100
101 //260809 Seed hashed Defuse key mappings on activation after installation or updates; migration is idempotent.
102 c_ws_plugin__s2member_utils_defuse::migrate_legacy_defuse_key_mappings();
103
104 if($GLOBALS['WS_PLUGIN__']['s2member']['c']['configured']) // If we are re-activating.
105 {
106 $v = get_option('ws_plugin__s2member_activated_version'); // Currently.
107
108 //260822.2048 Older EOT demotions recorded their processing time only in Administrative Notes; recover that history asynchronously where the legacy note is still available.
109 if(!$v || version_compare($v, '260822.2048', '<'))
110 c_ws_plugin__s2member_auto_eots::start_eot_processed_time_backfill();
111
112 //260824.1727 Refresh existing Checkout webhooks once more to add dispute-created notifications.
113 if(!$v || version_compare($v, '260824.1727', '<'))
114 {
115 $ppco_webhook_envs = array(
116 'live' => array(
117 'client_id' => (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_checkout_client_id'],
118 'secret' => (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_checkout_client_secret'],
119 'webhook_id' => (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_checkout_webhook_id'],
120 ),
121 'sandbox' => array(
122 'client_id' => (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_checkout_sandbox_client_id'],
123 'secret' => (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_checkout_sandbox_client_secret'],
124 'webhook_id' => (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_checkout_sandbox_webhook_id'],
125 ),
126 );
127 foreach($ppco_webhook_envs as $ppco_webhook_env => $ppco_webhook_config)
128 if($ppco_webhook_config['client_id'] && $ppco_webhook_config['secret'] && $ppco_webhook_config['webhook_id'])
129 if(!c_ws_plugin__s2member_paypal_utilities::paypal_checkout_webhook_upsert($ppco_webhook_env, TRUE))
130 {
131 $ppco_webhook_env_label = ($ppco_webhook_env === 'sandbox') ? 'Sandbox' : 'Live';
132 $ppco_webhook_settings_url = add_query_arg('s2member-open-panel', 'paypal-checkout', admin_url('/admin.php?page=ws-plugin--s2member-paypal-ops')).'#ws-plugin--s2member-paypal-checkout';
133
134 //260824.0507 Mark this persistent warning so a later successful reconciliation can remove it automatically.
135 $notice = '<span class="s2member-ppco-webhook-upgrade-notice-'.esc_attr($ppco_webhook_env).'"><strong>s2Member PayPal Checkout:</strong> Your '.esc_html($ppco_webhook_env_label).' webhook could not be updated automatically with the latest required events. Please go to <a href="'.esc_url($ppco_webhook_settings_url).'"><strong>s2Member → PayPal Options → PayPal Checkout</strong></a> and click <strong>Create/Update Webhook</strong> for '.esc_html($ppco_webhook_env_label).'.</span>';
136 c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, array(), TRUE, 0, TRUE);
137 }
138 }
139
140 if(!$v || !version_compare($v, '3.2', '>=')) // Needs to be upgraded?
141 // Version 3.2 is where `meta_key` names were changed. They're prefixed now.
142 {
143 $like = "`meta_key` LIKE 's2member\\_%' AND `meta_key` NOT LIKE '%s2member\\_originating\\_blog%'";
144 $wpdb->query("UPDATE `".$wpdb->usermeta."` SET `meta_key` = CONCAT('".$wpdb->prefix."', `meta_key`) WHERE ".$like);
145 }
146 if(!$v || !version_compare($v, '3.2.5', '>=')) // Needs to be upgraded?
147 // Version 3.2.5 is where transient names were changed. They're prefixed now.
148 {
149 $wpdb->query("DELETE FROM `".$wpdb->options."` WHERE `option_name` LIKE '\\_transient\\_%'");
150 }
151 if(!$v || !version_compare($v, '3.2.6', '>=')) // Needs to be upgraded?
152 // Version 3.2.6 fixed `s2member_ccaps_req` being stored empty and/or w/ one empty element in the array.
153 {
154 $wpdb->query("DELETE FROM `".$wpdb->postmeta."` WHERE `meta_key` = 's2member_ccaps_req' AND `meta_value` IN('','a:0:{}','a:1:{i:0;s:0:\"\";}')");
155 }
156 if((!$v || !version_compare($v, '110912', '>=')) && $GLOBALS['WS_PLUGIN__']['s2member']['o']['filter_wp_query'] === array('all'))
157 // s2Member v110912 changed the way the 'all' option for Alternative Views was handled.
158 {
159 $notice = '<strong>IMPORTANT:</strong> This version of s2Member changes the way your <code>Alternative View Protections</code> work. Please review your options under: <strong>s2Member → Restriction Options → Alternative View Protections</strong>.';
160 c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, array('blog|network:plugins.php', 'blog|network:ws-plugin--s2member-start', 'blog|network:ws-plugin--s2member-mms-ops', 'blog|network:ws-plugin--s2member-gen-ops', 'blog|network:ws-plugin--s2member-res-ops'));
161 }
162 if($v && version_compare($v, '130316', '<=')) // This version disables logging by default.
163 {
164 c_ws_plugin__s2member_menu_pages::update_all_options(array('ws_plugin__s2member_gateway_debug_logs' => '0', 'ws_plugin__s2member_gateway_debug_logs_extensive' => '0'), TRUE, FALSE, FALSE, FALSE, FALSE);
165
166 $notice = '<strong>IMPORTANT:</strong> This version of s2Member disables s2Member\'s debug logging by default (for added security). Please see: <a href="'.esc_attr(admin_url('/admin.php?page=ws-plugin--s2member-logs')).'">s2Member → Log Files (Debug) → Configuration</a> for further details.';
167 c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, array('blog|network:plugins.php', 'blog|network:ws-plugin--s2member-start', 'blog|network:ws-plugin--s2member-mms-ops', 'blog|network:ws-plugin--s2member-gen-ops', 'blog|network:ws-plugin--s2member-res-ops'));
168
169 $notice = '<strong>IMPORTANT / Regarding s2Member Security Badges:</strong> If debug logging is enabled, your site will no longer qualify for an s2Member Security Badge until you disable logging (and you must also download, and then delete any existing log files from the past). Please see KB Article: <a href="http://www.s2member.com/kb/security-badges/" target="_blank" rel="external">s2Member Security Badges</a> for further details. If you have existing s2Member log files, you will need to delete those files from the server before your s2Member Security Badge can be re-enabled. s2Member stores log files here: <code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir'])).'</code>. See also: <a href="'.esc_attr(admin_url('/admin.php?page=ws-plugin--s2member-logs')).'">s2Member → Log Files (Debug) → Configuration</a> for further details.';
170 c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, array('blog|network:plugins.php', 'blog|network:ws-plugin--s2member-start', 'blog|network:ws-plugin--s2member-mms-ops', 'blog|network:ws-plugin--s2member-gen-ops', 'blog|network:ws-plugin--s2member-res-ops'));
171 }
172 if($v && version_compare($v, '140128', '<=')) // This version introduces support for partial refunds.
173 {
174 if($GLOBALS['WS_PLUGIN__']['s2member']['o']['triggers_immediate_eot'] === 'refunds,reversals') // `refunds,reversals` => `refunds,partial_refunds,reversals`
175 c_ws_plugin__s2member_menu_pages::update_all_options(array('ws_plugin__s2member_triggers_immediate_eot' => 'refunds,partial_refunds,reversals'), TRUE, FALSE, FALSE, FALSE, FALSE);
176 }
177 $notice = '<strong>s2Member</strong> has been <strong>reactivated</strong>, with '.(($reactivation_reason === 'levels') ? '<code>'.esc_html($GLOBALS['WS_PLUGIN__']['s2member']['c']['levels']).'</code> Membership Levels' : 'the latest version').'.<br />';
178 $notice .= 'You now have version '.esc_html(WS_PLUGIN__S2MEMBER_VERSION).'. Your existing configuration remains.';
179
180 if(!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) // No Changelog on a Multisite Blog Farm.
181 $notice .= '<br />Have fun, <a href="'.esc_attr(c_ws_plugin__s2member_readmes::parse_readme_value('Changelog URI')).'" target="_blank">read the Changelog</a>, and make some money! :-)';
182
183 c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, array('blog|network:plugins.php', 'blog|network:ws-plugin--s2member-start', 'blog|network:ws-plugin--s2member-mms-ops', 'blog|network:ws-plugin--s2member-gen-ops', 'blog|network:ws-plugin--s2member-res-ops'));
184 }
185 else // Otherwise (initial activation); we'll help the Site Owner out by giving them a link to the Getting Started section.
186 {
187 $notice = '<strong>Note:</strong> s2Member adds some new data columns to your list of Users/Members. If your list gets overcrowded, please use the <strong>Screen Options</strong> tab <em>(upper right-hand corner)</em>. With WordPress Screen Options, you can add/remove specific data columns; thereby making the most important data easier to read. For example, if you create Custom Registration/Profile Fields with s2Member, those Custom Fields will result in new data columns; which can cause your list of Users/Members to become nearly unreadable. So just use the Screen Options tab to clean things up.';
188 c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, 'blog:users.php', FALSE, FALSE, TRUE);
189
190 $notice = '<strong>s2Member v'.esc_html(WS_PLUGIN__S2MEMBER_VERSION).' has been activated. Nice work!</strong><br />';
191 $notice .= 'We suggest a review of the "Getting Started" page to familiarize yourself with s2Member terminology and basic configuration.<br />&#8627;&nbsp; Would you like to review now? &nbsp;&nbsp;&nbsp; <a href="'.esc_attr(admin_url('/admin.php?page=ws-plugin--s2member-start')).'"><strong>Yes (explain)</strong></a>';
192
193 c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, array('blog|network:plugins.php', 'blog|network:ws-plugin--s2member-start', 'blog|network:ws-plugin--s2member-mms-ops', 'blog|network:ws-plugin--s2member-gen-ops', 'blog|network:ws-plugin--s2member-res-ops'));
194 }
195 if(is_multisite() && is_main_site()) // Network activation routines.
196 {
197 $wpdb->query("INSERT INTO `".$wpdb->usermeta."` (`user_id`, `meta_key`, `meta_value`) SELECT `ID`, 's2member_originating_blog', '".esc_sql($current_site->blog_id)."' FROM `".$wpdb->users."` WHERE `ID` NOT IN (SELECT `user_id` FROM `".$wpdb->usermeta."` WHERE `meta_key` = 's2member_originating_blog')");
198
199 $notice = '<strong>Multisite Network</strong> updated automatically by <strong>s2Member</strong> v'.esc_html(WS_PLUGIN__S2MEMBER_VERSION).'.<br />';
200 $notice .= 'You\'ll want to configure s2Member\'s Multisite options now.<br />';
201 $notice .= 'In the Dashboard for your Main Site, see:<br />';
202 $notice .= '<strong>s2Member → Multisite (Config)</strong>.';
203
204 c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, array('blog|network:plugins.php', 'blog|network:ws-plugin--s2member-start', 'blog|network:ws-plugin--s2member-mms-ops', 'blog|network:ws-plugin--s2member-gen-ops', 'blog|network:ws-plugin--s2member-res-ops'));
205
206 update_site_option('ws_plugin__s2member_options', (array)get_option('ws_plugin__s2member_options'));
207
208 update_option('ws_plugin__s2member_activated_mms_version', WS_PLUGIN__S2MEMBER_VERSION);
209 }
210 update_option('ws_plugin__s2member_activated_version', WS_PLUGIN__S2MEMBER_VERSION);
211
212 do_action('ws_plugin__s2member_after_activation', get_defined_vars());
213 }
214
215 /**
216 * Deactivation routines for s2Member.
217 *
218 * @package s2Member\Installation
219 * @since 3.5
220 */
221 public static function deactivate()
222 {
223 global $wpdb;
224 /** @var $wpdb wpdb */
225 global $current_site, $current_blog; // Multisite.
226
227 do_action('ws_plugin__s2member_before_deactivation', get_defined_vars());
228 do_action('ws_plugin__s2member_after_deactivation', get_defined_vars());
229 }
230
231 /**
232 * Uninstall routines for s2Member.
233 *
234 * @package s2Member\Installation
235 * @since 3.5
236 */
237 public static function uninstall()
238 {
239 global $wpdb;
240 /** @var $wpdb wpdb */
241 global $current_site, $current_blog; // Multisite.
242
243 do_action('ws_plugin__s2member_before_uninstall', get_defined_vars());
244
245 if($GLOBALS['WS_PLUGIN__']['s2member']['o']['run_uninstall_routines'])
246 {
247 c_ws_plugin__s2member_roles_caps::unlink_roles();
248
249 c_ws_plugin__s2member_files::remove_no_gzip_from_root_htaccess();
250
251 if(is_dir($files_dir = $GLOBALS['WS_PLUGIN__']['s2member']['c']['files_dir']))
252 {
253 if(file_exists($htaccess = $files_dir.'/.htaccess'))
254 if(is_writable($htaccess))
255 unlink($htaccess);
256
257 @rmdir($files_dir).@rmdir(c_ws_plugin__s2member_utils_dirs::strip_dir_app_data($files_dir));
258 }
259 if(is_dir($logs_dir = $GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir']))
260 {
261 foreach(scandir($logs_dir) as $log_file)
262 if(is_file($log_file = $logs_dir.'/'.$log_file))
263 if(is_writable($log_file))
264 unlink($log_file);
265
266 @rmdir($logs_dir).@rmdir(c_ws_plugin__s2member_utils_dirs::strip_dir_app_data($logs_dir));
267 }
268 delete_option('ws_plugin__s2member_cache');
269 delete_option('ws_plugin__s2member_notices');
270 delete_option('ws_plugin__s2member_options');
271 delete_option('ws_plugin__s2member_configured');
272 delete_option('ws_plugin__s2member_activated_levels');
273 delete_option('ws_plugin__s2member_activated_version');
274 delete_option('ws_plugin__s2member_activated_mms_version');
275
276 if(is_multisite() && is_main_site() /* Site options? */)
277 delete_site_option('ws_plugin__s2member_options');
278
279 $wpdb->query("DELETE FROM `".$wpdb->postmeta."` WHERE `meta_key` LIKE '".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('s2m_'))."%'");
280 $wpdb->query("DELETE FROM `".$wpdb->postmeta."` WHERE `meta_key` LIKE '%".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('_s2m_'))."%'");
281 $wpdb->query("DELETE FROM `".$wpdb->postmeta."` WHERE `meta_key` LIKE '%".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('s2member_'))."%'");
282
283 $wpdb->query("DELETE FROM `".$wpdb->usermeta."` WHERE `meta_key` LIKE '".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('s2m_'))."%'");
284 $wpdb->query("DELETE FROM `".$wpdb->usermeta."` WHERE `meta_key` LIKE '%".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('_s2m_'))."%'");
285 $wpdb->query("DELETE FROM `".$wpdb->usermeta."` WHERE `meta_key` LIKE '%".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('s2member_'))."%'");
286
287 $wpdb->query("DELETE FROM `".$wpdb->options."` WHERE `option_name` LIKE '".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('s2m_'))."%'");
288 $wpdb->query("DELETE FROM `".$wpdb->options."` WHERE `option_name` LIKE '%".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('_s2m_'))."%'");
289 $wpdb->query("DELETE FROM `".$wpdb->options."` WHERE `option_name` LIKE '%".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('s2member_'))."%'");
290
291 do_action('ws_plugin__s2member_during_uninstall', get_defined_vars());
292 }
293 do_action('ws_plugin__s2member_after_uninstall', get_defined_vars());
294 }
295
296 /**
297 * Disallow automatic updates of s2Member w/ Pro is installed.
298 *
299 * @package s2Member\Installation
300 * @since 150717
301 *
302 * @attaches-to `auto_update_plugin` filter.
303 */
304 public static function auto_update_filter($update = NULL, $item = NULL)
305 {
306 if(is_object($item) && !empty($item->slug) && $item->slug === 's2member')
307 if(c_ws_plugin__s2member_utils_conds::pro_is_installed())
308 $update = FALSE; // Disallow.
309
310 return $update; // Filter through.
311 }
312 }
313 }
314