PluginProbe
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions / trunk
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions vtrunk
260909 260829 260814 260805 110710 110731 110812 110815 110912 110913 110915 110926 110927 111002 111003 111011 111017 111029 111105 111206 111216 111220 120213 120219 120301 All 187 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 trunk, at src/includes/classes/installation.inc.php

301 lines 18.9 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 (!is_array(get_option('ws_plugin__s2member_cache'))) ? update_option('ws_plugin__s2member_cache', array()) : NULL;
69 (!is_array(get_option('ws_plugin__s2member_notices'))) ? update_option('ws_plugin__s2member_notices', array()) : NULL;
70 (!is_array(get_option('ws_plugin__s2member_options'))) ? update_option('ws_plugin__s2member_options', array()) : NULL;
71 (!is_numeric(get_option('ws_plugin__s2member_configured'))) ? update_option('ws_plugin__s2member_configured', '0') : NULL;
72
73 //260902.0420 A Framework activation/update invalidates cached Pro update availability; the next admin request will refresh it in the background.
74 if($reactivation_reason === '' || $reactivation_reason === 'version')
75 {
76 $options = (array)get_option('ws_plugin__s2member_options');
77 if(isset($options['pro_latest_version']))
78 {
79 unset($options['pro_latest_version']);
80 $options = ws_plugin__s2member_configure_options_and_their_defaults($options);
81 update_option('ws_plugin__s2member_options', $options);
82 if(is_multisite() && is_main_site())
83 update_site_option('ws_plugin__s2member_options', $options);
84 }
85 unset($options);
86 }
87
88 //260809 Seed hashed Defuse key mappings on activation after installation or updates; migration is idempotent.
89 c_ws_plugin__s2member_utils_defuse::migrate_legacy_defuse_key_mappings();
90
91 if($GLOBALS['WS_PLUGIN__']['s2member']['c']['configured']) // If we are re-activating.
92 {
93 $v = get_option('ws_plugin__s2member_activated_version'); // Currently.
94
95 //260822.2048 Older EOT demotions recorded their processing time only in Administrative Notes; recover that history asynchronously where the legacy note is still available.
96 if(!$v || version_compare($v, '260822.2048', '<'))
97 c_ws_plugin__s2member_auto_eots::start_eot_processed_time_backfill();
98
99 //260824.1727 Refresh existing Checkout webhooks once more to add dispute-created notifications.
100 if(!$v || version_compare($v, '260824.1727', '<'))
101 {
102 $ppco_webhook_envs = array(
103 'live' => array(
104 'client_id' => (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_checkout_client_id'],
105 'secret' => (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_checkout_client_secret'],
106 'webhook_id' => (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_checkout_webhook_id'],
107 ),
108 'sandbox' => array(
109 'client_id' => (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_checkout_sandbox_client_id'],
110 'secret' => (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_checkout_sandbox_client_secret'],
111 'webhook_id' => (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_checkout_sandbox_webhook_id'],
112 ),
113 );
114 foreach($ppco_webhook_envs as $ppco_webhook_env => $ppco_webhook_config)
115 if($ppco_webhook_config['client_id'] && $ppco_webhook_config['secret'] && $ppco_webhook_config['webhook_id'])
116 if(!c_ws_plugin__s2member_paypal_utilities::paypal_checkout_webhook_upsert($ppco_webhook_env, TRUE))
117 {
118 $ppco_webhook_env_label = ($ppco_webhook_env === 'sandbox') ? 'Sandbox' : 'Live';
119 $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';
120
121 //260824.0507 Mark this persistent warning so a later successful reconciliation can remove it automatically.
122 $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>';
123 c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, array(), TRUE, 0, TRUE);
124 }
125 }
126
127 if(!$v || !version_compare($v, '3.2', '>=')) // Needs to be upgraded?
128 // Version 3.2 is where `meta_key` names were changed. They're prefixed now.
129 {
130 $like = "`meta_key` LIKE 's2member\\_%' AND `meta_key` NOT LIKE '%s2member\\_originating\\_blog%'";
131 $wpdb->query("UPDATE `".$wpdb->usermeta."` SET `meta_key` = CONCAT('".$wpdb->prefix."', `meta_key`) WHERE ".$like);
132 }
133 if(!$v || !version_compare($v, '3.2.5', '>=')) // Needs to be upgraded?
134 // Version 3.2.5 is where transient names were changed. They're prefixed now.
135 {
136 $wpdb->query("DELETE FROM `".$wpdb->options."` WHERE `option_name` LIKE '\\_transient\\_%'");
137 }
138 if(!$v || !version_compare($v, '3.2.6', '>=')) // Needs to be upgraded?
139 // Version 3.2.6 fixed `s2member_ccaps_req` being stored empty and/or w/ one empty element in the array.
140 {
141 $wpdb->query("DELETE FROM `".$wpdb->postmeta."` WHERE `meta_key` = 's2member_ccaps_req' AND `meta_value` IN('','a:0:{}','a:1:{i:0;s:0:\"\";}')");
142 }
143 if((!$v || !version_compare($v, '110912', '>=')) && $GLOBALS['WS_PLUGIN__']['s2member']['o']['filter_wp_query'] === array('all'))
144 // s2Member v110912 changed the way the 'all' option for Alternative Views was handled.
145 {
146 $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>.';
147 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'));
148 }
149 if($v && version_compare($v, '130316', '<=')) // This version disables logging by default.
150 {
151 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);
152
153 $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.';
154 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'));
155
156 $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.';
157 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'));
158 }
159 if($v && version_compare($v, '140128', '<=')) // This version introduces support for partial refunds.
160 {
161 if($GLOBALS['WS_PLUGIN__']['s2member']['o']['triggers_immediate_eot'] === 'refunds,reversals') // `refunds,reversals` => `refunds,partial_refunds,reversals`
162 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);
163 }
164 $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 />';
165 $notice .= 'You now have version '.esc_html(WS_PLUGIN__S2MEMBER_VERSION).'. Your existing configuration remains.';
166
167 if(!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) // No Changelog on a Multisite Blog Farm.
168 $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! :-)';
169
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 else // Otherwise (initial activation); we'll help the Site Owner out by giving them a link to the Getting Started section.
173 {
174 $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.';
175 c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, 'blog:users.php', FALSE, FALSE, TRUE);
176
177 $notice = '<strong>s2Member v'.esc_html(WS_PLUGIN__S2MEMBER_VERSION).' has been activated. Nice work!</strong><br />';
178 $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>';
179
180 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'));
181 }
182 if(is_multisite() && is_main_site()) // Network activation routines.
183 {
184 $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')");
185
186 $notice = '<strong>Multisite Network</strong> updated automatically by <strong>s2Member</strong> v'.esc_html(WS_PLUGIN__S2MEMBER_VERSION).'.<br />';
187 $notice .= 'You\'ll want to configure s2Member\'s Multisite options now.<br />';
188 $notice .= 'In the Dashboard for your Main Site, see:<br />';
189 $notice .= '<strong>s2Member → Multisite (Config)</strong>.';
190
191 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'));
192
193 update_site_option('ws_plugin__s2member_options', (array)get_option('ws_plugin__s2member_options'));
194
195 update_option('ws_plugin__s2member_activated_mms_version', WS_PLUGIN__S2MEMBER_VERSION);
196 }
197 update_option('ws_plugin__s2member_activated_version', WS_PLUGIN__S2MEMBER_VERSION);
198
199 do_action('ws_plugin__s2member_after_activation', get_defined_vars());
200 }
201
202 /**
203 * Deactivation routines for s2Member.
204 *
205 * @package s2Member\Installation
206 * @since 3.5
207 */
208 public static function deactivate()
209 {
210 global $wpdb;
211 /** @var $wpdb wpdb */
212 global $current_site, $current_blog; // Multisite.
213
214 do_action('ws_plugin__s2member_before_deactivation', get_defined_vars());
215 do_action('ws_plugin__s2member_after_deactivation', get_defined_vars());
216 }
217
218 /**
219 * Uninstall routines for s2Member.
220 *
221 * @package s2Member\Installation
222 * @since 3.5
223 */
224 public static function uninstall()
225 {
226 global $wpdb;
227 /** @var $wpdb wpdb */
228 global $current_site, $current_blog; // Multisite.
229
230 do_action('ws_plugin__s2member_before_uninstall', get_defined_vars());
231
232 if($GLOBALS['WS_PLUGIN__']['s2member']['o']['run_uninstall_routines'])
233 {
234 c_ws_plugin__s2member_roles_caps::unlink_roles();
235
236 c_ws_plugin__s2member_files::remove_no_gzip_from_root_htaccess();
237
238 if(is_dir($files_dir = $GLOBALS['WS_PLUGIN__']['s2member']['c']['files_dir']))
239 {
240 if(file_exists($htaccess = $files_dir.'/.htaccess'))
241 if(is_writable($htaccess))
242 unlink($htaccess);
243
244 @rmdir($files_dir).@rmdir(c_ws_plugin__s2member_utils_dirs::strip_dir_app_data($files_dir));
245 }
246 if(is_dir($logs_dir = $GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir']))
247 {
248 foreach(scandir($logs_dir) as $log_file)
249 if(is_file($log_file = $logs_dir.'/'.$log_file))
250 if(is_writable($log_file))
251 unlink($log_file);
252
253 @rmdir($logs_dir).@rmdir(c_ws_plugin__s2member_utils_dirs::strip_dir_app_data($logs_dir));
254 }
255 delete_option('ws_plugin__s2member_cache');
256 delete_option('ws_plugin__s2member_notices');
257 delete_option('ws_plugin__s2member_options');
258 delete_option('ws_plugin__s2member_configured');
259 delete_option('ws_plugin__s2member_activated_levels');
260 delete_option('ws_plugin__s2member_activated_version');
261 delete_option('ws_plugin__s2member_activated_mms_version');
262
263 if(is_multisite() && is_main_site() /* Site options? */)
264 delete_site_option('ws_plugin__s2member_options');
265
266 $wpdb->query("DELETE FROM `".$wpdb->postmeta."` WHERE `meta_key` LIKE '".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('s2m_'))."%'");
267 $wpdb->query("DELETE FROM `".$wpdb->postmeta."` WHERE `meta_key` LIKE '%".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('_s2m_'))."%'");
268 $wpdb->query("DELETE FROM `".$wpdb->postmeta."` WHERE `meta_key` LIKE '%".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('s2member_'))."%'");
269
270 $wpdb->query("DELETE FROM `".$wpdb->usermeta."` WHERE `meta_key` LIKE '".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('s2m_'))."%'");
271 $wpdb->query("DELETE FROM `".$wpdb->usermeta."` WHERE `meta_key` LIKE '%".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('_s2m_'))."%'");
272 $wpdb->query("DELETE FROM `".$wpdb->usermeta."` WHERE `meta_key` LIKE '%".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('s2member_'))."%'");
273
274 $wpdb->query("DELETE FROM `".$wpdb->options."` WHERE `option_name` LIKE '".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('s2m_'))."%'");
275 $wpdb->query("DELETE FROM `".$wpdb->options."` WHERE `option_name` LIKE '%".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('_s2m_'))."%'");
276 $wpdb->query("DELETE FROM `".$wpdb->options."` WHERE `option_name` LIKE '%".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('s2member_'))."%'");
277
278 do_action('ws_plugin__s2member_during_uninstall', get_defined_vars());
279 }
280 do_action('ws_plugin__s2member_after_uninstall', get_defined_vars());
281 }
282
283 /**
284 * Disallow automatic updates of s2Member w/ Pro is installed.
285 *
286 * @package s2Member\Installation
287 * @since 150717
288 *
289 * @attaches-to `auto_update_plugin` filter.
290 */
291 public static function auto_update_filter($update = NULL, $item = NULL)
292 {
293 if(is_object($item) && !empty($item->slug) && $item->slug === 's2member')
294 if(c_ws_plugin__s2member_utils_conds::pro_is_installed())
295 $update = FALSE; // Disallow.
296
297 return $update; // Filter through.
298 }
299 }
300 }
301