diff --git a/readme.txt b/readme.txt
index cf543356..bd6b0c74 100644
--- a/readme.txt
+++ b/readme.txt
@@ -44,11 +44,7 @@ Changelog URI: http://s2member.com/changelog/
Video Tutorials: http://s2member.com/videos/
Knowledge Base: http://s2member.com/kb/
Newsletter: http://s2member.com/r/subscribe/
-Pro Add-on / Home Page: http://s2member.com/
-Pro Add-on / Prices: http://s2member.com/prices/
-Pro Add-on / Auto-Update URL: https://www.s2member.com/
PayPal Pro Integration: http://s2member.com/r/pp-account-types/
-Professional Installation URI: http://s2member.com/r/professional-installation/
Description: s2Member® Pro adds PayPal® Payments Pro integration, advanced import/export tools, and many other enhancements.
Tags: membership, subscribers, subscriber, members only, roles, capabilities, capability, register, signup, paypal, ecommerce, restriction
@@ -57,19 +53,19 @@ s2Member® Pro adds Stripe™, PayPal® Payments Pro and Authorize.Net integrati
== Description ==
-You can learn more about s2Member® Pro at [s2Member.com](http://www.s2member.com/).
+You can learn more about s2Member® Pro at [s2Member.com](http://s2member.com/).
== Installation ==
= s2Member® Pro is Very Easy to Install =
-1. First, you need to have the latest version of the [s2Member® Framework](http://www.s2member.com/framework/) already installed.
+1. First, you need to have the latest version of the [s2Member® Framework](http://s2member.com/release-archive/) already installed.
2. Then, upload the `/s2member-pro` folder to your `/wp-content/plugins/` directory.
3. That's it! s2Member® Pro will be loaded into the free version of s2Member automatically.
= See Also (s2Member.com) =
-[Detailed installation/upgrade instructions](http://www.s2member.com/pro/#!s2_tab_jump=s2-pro-install-update).
+[Detailed installation/upgrade instructions](http://s2member.com/installation/).
= Is s2Member compatible with Multisite Networking? =
@@ -255,7 +251,7 @@ Released under the terms of the [GNU General Public License](http://www.gnu.org/
- (s2Member) **Multisite Support:** This release of s2Member (the free version only) removes full support for Multisite Networks, which is now a Pro feature; i.e., only available in the Pro version.
##### Is s2Member still compatible with WordPress Multisite Networking?
- Multisite support is no longer included in the s2Member Framework. However, it is available with s2Member Pro. s2Member Pro is compatible with Multisite Networking. After you enable Multisite Networking, install the s2Member Pro Add-On. Then, navigate to `s2Member → Multisite (Config)` in the Dashboard of your Main Site. You can learn more about s2Member Pro at [s2Member.com](http://www.s2member.com/).
+ Multisite support is no longer included in the s2Member Framework. However, it is available with s2Member Pro. s2Member Pro is compatible with Multisite Networking. After you enable Multisite Networking, install the s2Member Pro Add-On. Then, navigate to `s2Member → Multisite (Config)` in the Dashboard of your Main Site. You can learn more about s2Member Pro at [s2Member.com](http://s2member.com/).
##### I was using the free version in a Multisite Network before. What happened?
s2Member (when running on a Multisite Network) requires minor alterations in WordPress core that are not compatible with plugins available at WordPress.org (i.e., not allowed) at this time. For this reason, full support for Multisite Networks is now available only in the pro version.
@@ -528,7 +524,7 @@ Released under the terms of the [GNU General Public License](http://www.gnu.org/
= v150102 =
- (s2Member/s2Member Pro) **Custom Field Mapping:** This release of s2Member adds an internal mapping from s2Member's Custom Field values for each user, to the `get_user_option()` function in the WordPress core. This makes it possible to retrieve user custom field values like always via `get_user_field()` or now through the native `get_user_option()` function also. The benefit of this is that s2Member's custom fields are now more compatible with other themes/plugins for WordPress.
-- (s2Member Pro) **[s2Member-List /] Shortcode:** It is now possible to search through custom fields created with s2Member using the `search_columns=""` attribute; e.g., `search_columns="user_login,user_email,s2member_custom_field_MYFIELDID"`; where `MYFIELDID` can be replaced with a field ID that you generate with s2Member via `Dashboard → s2Member → General Options → Registration/Profile Fields`. See also: [this KB article](http://www.s2member.com/kb/s2member-list-shortcode/) for further details. See also: [this GitHub issue](https://github.com/websharks/s2member/issues/155) for details regarding this improvement.
+- (s2Member Pro) **[s2Member-List /] Shortcode:** It is now possible to search through custom fields created with s2Member using the `search_columns=""` attribute; e.g., `search_columns="user_login,user_email,s2member_custom_field_MYFIELDID"`; where `MYFIELDID` can be replaced with a field ID that you generate with s2Member via `Dashboard → s2Member → General Options → Registration/Profile Fields`. See also: [this KB article](http://s2member.com/kb-article/s2member-list-shortcode-documentation/) for further details. See also: [this GitHub issue](https://github.com/websharks/s2member/issues/155) for details regarding this improvement.
- (s2Member/s2Member Pro) **MailChimp Bug Fix** This release fixes a bug first introduced in the previous release, which was causing Interest Groups configured w/ s2Member to not be added properly. Resolved in this release. Props to @ethanpil Thanks!
- (s2Member Pro) **ccBill Buttons** This release updates all ccBill button graphics. The MasterCard logo has been removed, and a new set of buttons was created to improve upon the set provided in previous versions of s2Member Pro. See: [this GitHub issue](https://github.com/websharks/s2member/issues/392) if you'd like further details.
- (s2Member Pro) **Authorize.Net** The `AUD` currency code is now supported by Authorize.Net, and thus, s2Member Pro has been updated to support the `AUD` currency code for Pro-Forms integrated with Authorize.Net. See [this GitHub issue](https://github.com/websharks/s2member/issues/383) if you'd like further details.
@@ -570,7 +566,7 @@ Released under the terms of the [GNU General Public License](http://www.gnu.org/
= v141007 =
- (s2Member Pro) **ClickBank IPN v6:** This release enables a new integration option for site owners integrated with ClickBank. You may now choose to integrate with v6 of ClickBank's IPN service, since all previous versions are slowly being phased out by ClickBank. Please see: `Dashboard → s2Member → ClickBank Options → IPN Integration` for v6 config. options. See also [this GitHub issue](https://github.com/websharks/s2member/issues/256) if you'd like further details regarding this topic. See also: [this article @ ClickBank](https://support.clickbank.com/entries/22803622-instant-notification-service).
-- (s2Member/s2Member Pro) **AWeber API Integration:** This release of s2Member adds a new option for site owners using AWeber. It is now possible to integrate with the new [s2Member App](http://www.s2member.com/r/aweber-api-key) for AWeber; i.e., via the AWeber API instead of via email-based communication. For further details, please see: `Dashboard → s2Member → API / List Servers → AWeber Integration`. See also: [this GitHub issue](https://github.com/websharks/s2member/issues/303) if you'd like additional details.
+- (s2Member/s2Member Pro) **AWeber API Integration:** This release of s2Member adds a new option for site owners using AWeber. It is now possible to integrate with the new [s2Member App](http://s2member.com/r/aweber-api-key) for AWeber; i.e., via the AWeber API instead of via email-based communication. For further details, please see: `Dashboard → s2Member → API / List Servers → AWeber Integration`. See also: [this GitHub issue](https://github.com/websharks/s2member/issues/303) if you'd like additional details.
- (s2Member/s2Member Pro) **Bug Fix:** The EOT Behavior option for `refunds,partial_refunds,reversals` was not being accepted by s2Member. Fixed in this release. Please see [this GitHub issue](https://github.com/websharks/s2member/issues/345) if you'd like further details.
- (s2Member/s2Member Pro) **MailChimp API Wrapper:** This release of s2Member comes with an updated API wrapper class for MailChimp integration. No change in functionality, just a smoother, slightly faster, and more bug-free interaction with the MailChimp API. Please see [this GitHub issue](https://github.com/websharks/s2member/issues/303) if you'd like further details regarding this improvement. See also: [the official MailChimp API class](https://bitbucket.org/mailchimp/mailchimp-api-php); i.e., what s2Member has been updated to in this release.
- (s2Member/s2Member Pro) **URI Restrictions caSe-insensitive (Security Fix)** This release of s2Member changes the way URI Restrictions work. All URI Restrictions are now caSe-insensitive (i.e., `/some-path/` is now the same as `/some-Path/`), allowing s2Member to automatically pick up different variations used in attempts to exploit the behavior of certain slugs within the WordPress core. You can also change this new default behavior, if you prefer. Please see: `Dashboard → s2Member → Restriction Options → URI Restrictions`. See also: [this GitHub issue](https://github.com/websharks/s2member/issues/354) for the details about why this was changed in the most recent copy of s2Member.
diff --git a/src/includes/classes/readmes.inc.php b/src/includes/classes/readmes.inc.php
index 6c7162d7..ae2f18f2 100644
--- a/src/includes/classes/readmes.inc.php
+++ b/src/includes/classes/readmes.inc.php
@@ -62,8 +62,8 @@ public static function parse_readme ($specific_path = FALSE, $specific_section =
{
if (!($path = $specific_path)) // Was a specific path passed in?
{
- $path = dirname (dirname (dirname (__FILE__))) . "/readme.txt";
- $dev_path = dirname (dirname (dirname (__FILE__))) . "/readme-dev.txt";
+ $path = dirname( dirname (dirname (dirname (__FILE__)))) . "/readme.txt";
+ $dev_path = dirname( dirname (dirname (dirname (__FILE__)))) . "/readme-dev.txt";
$path = (file_exists ($dev_path)) ? $dev_path : $path;
}
@@ -84,8 +84,8 @@ public static function parse_readme_value ($key = FALSE, $specific_path = FALSE)
{
if (!($path = $specific_path)) // Was a specific path passed in?
{
- $path = dirname (dirname (dirname (__FILE__))) . "/readme.txt";
- $dev_path = dirname (dirname (dirname (__FILE__))) . "/readme-dev.txt";
+ $path = dirname( dirname (dirname (dirname (__FILE__)))) . "/readme.txt";
+ $dev_path = dirname( dirname (dirname (dirname (__FILE__)))) . "/readme-dev.txt";
$path = (file_exists ($dev_path)) ? $dev_path : $path;
}
diff --git a/src/includes/classes/upgrader.inc.php b/src/includes/classes/upgrader.inc.php
index d3244786..94d0e9ff 100644
--- a/src/includes/classes/upgrader.inc.php
+++ b/src/includes/classes/upgrader.inc.php
@@ -1,311 +1,323 @@
'."\n";
- $wizard .= '
Your s2Member Pro Add-on must be updated to v'.WS_PLUGIN__S2MEMBER_MIN_PRO_VERSION.'+.
Please log in at s2Member.com for access to the latest version.
'."\n";
- $wizard .= '';
-
- $wizard .= /* Form to collect credentials. */ $credentials_form."\n";
- }
- else // Otherwise, we just need to collect their s2Member.com Username/Password combination.
- {
- $wizard = ''."\n";
- $wizard .= '
Your s2Member Pro Add-on must be updated to v'.WS_PLUGIN__S2MEMBER_MIN_PRO_VERSION.'+.
Please log in at s2Member.com for access to the latest version.
'."\n";
- $wizard .= '
'."\n";
- $wizard .= '
';
- }
- return /* Return HTML markup. */ $wizard;
- }
- /**
- * Upgrade processor.
- *
- * @package s2Member\Upgrader
- * @since 1.5
- *
- * @attaches-to ``add_action("admin_init");``
- *
- * @return null Upgrader does NOT return anything.
- */
- public static function upgrade /* Pro Upgrader. */()
- {
- if(!current_user_can('update_plugins'))
- return; // Not applicable.
-
- global /* Need this global object reference. */ $wp_filesystem;
-
- if(!empty($_POST["ws_plugin__s2member_pro_upgrade"]) && ($nonce = (string)$_POST["ws_plugin__s2member_pro_upgrade"]) && wp_verify_nonce($nonce, "ws-plugin--s2member-pro-upgrade") && ($_p = c_ws_plugin__s2member_utils_strings::trim_deep(stripslashes_deep($_POST))))
- {
- if(@set_time_limit(0) !== "nill" && @ini_set("memory_limit", apply_filters("admin_memory_limit", WP_MAX_MEMORY_LIMIT)) !== "nill" && c_ws_plugin__s2member_pro_upgrader::abbr_bytes(@ini_get("memory_limit")) >= c_ws_plugin__s2member_pro_upgrader::abbr_bytes(apply_filters("admin_memory_limit", WP_MAX_MEMORY_LIMIT)))
- {
- if(!empty($_p["ws_plugin__s2member_pro_upgrade_username"]) && !empty($_p["ws_plugin__s2member_pro_upgrade_password"]) && is_array($s2_pro_upgrade = maybe_unserialize(c_ws_plugin__s2member_utils_urls::remote(add_query_arg(urlencode_deep(array("s2_pro_upgrade" => array("username" => (string)$_p["ws_plugin__s2member_pro_upgrade_username"], "password" => (string)$_p["ws_plugin__s2member_pro_upgrade_password"], "version" => WS_PLUGIN__S2MEMBER_PRO_VERSION))), c_ws_plugin__s2member_readmes::parse_readme_value("Pro Add-on / Auto-Update URL", dirname(dirname(dirname(dirname(__FILE__))))."/readme.txt"))))) && !empty($s2_pro_upgrade["zip"]) && !empty($s2_pro_upgrade["ver"]))
- {
- set_transient(md5("ws_plugin__s2member_pro_upgrade_credentials"), array("username" => (string)$_p["ws_plugin__s2member_pro_upgrade_username"], "password" => (string)$_p["ws_plugin__s2member_pro_upgrade_password"]), 5184000);
-
- ob_start /* We collect credentials here too, in case data is posted. Buffer output from the ``request_filesystem_credentials()`` function, which generates a form to collect filesystem credentials. */();
- if(is_array($credentials = /* Does this function return us an array? */ request_filesystem_credentials($_SERVER["REQUEST_URI"], false, false, dirname(dirname(dirname(dirname(dirname(__FILE__))))))))
- c_ws_plugin__s2member_pro_upgrader::$credentials = /* Set static ``$credentials`` var. We have credentials now, possibly via data posted by site owner. */ $credentials;
- $credentials_form = /* Get form to collect credentials, although NOT needed by this routine. */ ob_get_clean();
-
- c_ws_plugin__s2member_pro_upgrader::maintenance /* Create the `.maintenance` file now. We don't want anything loading up on the site during this process. */(true);
-
- if(WP_Filesystem(c_ws_plugin__s2member_pro_upgrader::$credentials, ($plugins_dir = $_plugins_dir = dirname(dirname(dirname(dirname(dirname(__FILE__))))))) && ($plugins_dir = rtrim($wp_filesystem->find_folder($plugins_dir), "/")) && ($plugin_dir = rtrim($wp_filesystem->find_folder($_plugin_dir = dirname(dirname(dirname(dirname(__FILE__))))), "/")))
- {
- if(($tmp_zip = wp_unique_filename($_plugins_dir, basename($plugin_dir).".zip")) && ($_tmp_zip = $_plugins_dir."/".$tmp_zip) && ($tmp_zip = $plugins_dir."/".$tmp_zip) && $wp_filesystem->put_contents($tmp_zip, c_ws_plugin__s2member_utils_urls::remote($s2_pro_upgrade["zip"], false, array("timeout" => 120)), FS_CHMOD_FILE))
- {
- if((!$wp_filesystem->is_dir($plugin_dir."-new") || $wp_filesystem->delete($plugin_dir."-new", true)) && $wp_filesystem->mkdir($plugin_dir."-new", FS_CHMOD_DIR))
- {
- if(!is_wp_error($unzip = unzip_file /* Unzip into the `/s2member-pro-new` directory. */($_tmp_zip, $plugin_dir."-new")))
- {
- if(!$wp_filesystem->is_dir($plugin_dir) || $wp_filesystem->delete($plugin_dir, true) /* Point of no return. */)
- {
- if($wp_filesystem->move /* Live in this directory. */($plugin_dir."-new/s2member-pro", $plugin_dir))
- {
- $wp_filesystem->delete($plugin_dir."-new", true).$wp_filesystem->delete($tmp_zip);
-
- $notice = 's2Member Pro successfully updated to v'.esc_html($s2_pro_upgrade["ver"]).'.';
-
- do_action("ws_plugin__s2member_pro_during_successfull_upgrade", get_defined_vars());
-
- c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, "blog|network:*");
-
- c_ws_plugin__s2member_pro_upgrader::maintenance(false);
-
- wp_redirect(self_admin_url("/plugins.php")).exit();
- }
- else // Bummer. OK, now we'll deal with cleanup & error reporting.
- {
- $wp_filesystem->delete($plugin_dir."-new", true).$wp_filesystem->delete($tmp_zip);
-
- c_ws_plugin__s2member_pro_upgrader::$error = "Upgrade failed. Error #0009. Please upgrade via FTP.";
- }
- }
- else // Bummer. OK, now we'll deal with cleanup & error reporting.
- {
- $wp_filesystem->delete($plugin_dir."-new", true).$wp_filesystem->delete($tmp_zip);
-
- c_ws_plugin__s2member_pro_upgrader::$error = "Upgrade failed. Error #0008. Please upgrade via FTP.";
- }
- }
- else // Bummer. OK, now we'll deal with cleanup & error reporting.
- {
- $wp_filesystem->delete($plugin_dir."-new", true).$wp_filesystem->delete($tmp_zip);
-
- c_ws_plugin__s2member_pro_upgrader::$error = "Upgrade failed. Error #0007. ".$unzip->get_error_message()." ~ Please upgrade via FTP. ";
- }
- }
- else // Bummer. OK, now we'll deal with cleanup & error reporting.
- {
- $wp_filesystem->delete($plugin_dir."-new", true).$wp_filesystem->delete($tmp_zip);
-
- c_ws_plugin__s2member_pro_upgrader::$error = "Upgrade failed. Error #0006. Please upgrade via FTP.";
- }
- }
- else // Bummer. OK, now we'll deal with cleanup & error reporting.
- {
- $wp_filesystem->delete($plugin_dir."-new", true).$wp_filesystem->delete($tmp_zip);
-
- c_ws_plugin__s2member_pro_upgrader::$error = "Upgrade failed. Error #0005. Please upgrade via FTP.";
- }
- }
- else // Bummer. OK, error reporting (no cleanup). Wizard handles `#0004`. Use `#0004` in ``::$error``.
- {
- c_ws_plugin__s2member_pro_upgrader::$error = // Wizard handles. Use `#0004` in ``::$error``.
- "Upgrade failed. Error #0004. Please upgrade via FTP, or supply valid Filesystem Credentials.";
- }
- c_ws_plugin__s2member_pro_upgrader::maintenance /* Remove the `.maintenance` file now. */(false);
- }
- else if(!empty($s2_pro_upgrade) && $s2_pro_upgrade === /* Forbidden? */ "403 Forbidden")
- {
- c_ws_plugin__s2member_pro_upgrader::$error = "Upgrade failed. Invalid Username/Password (or License Key); please try again.";
- }
- else if(!empty($s2_pro_upgrade) && $s2_pro_upgrade === "503 Service Unavailable")
- {
- c_ws_plugin__s2member_pro_upgrader::$error = "Upgrade failed. Service currently unavailable (please try again).";
- }
- else // Else, display a default error message (server unavailable). Possible connectivity issues.
- {
- c_ws_plugin__s2member_pro_upgrader::$error = "Upgrade failed. Connection failed (please try again).";
- }
- }
- else // Insufficient memory. This requires some special attention. Unzipping large files requires memory.
- {
- c_ws_plugin__s2member_pro_upgrader::$error = "Not enough memory.".
- " Unzipping s2Member Pro via WordPress requires ".WP_MAX_MEMORY_LIMIT." of RAM.".
- " Please upgrade via FTP instead..";
- }
- }
- return /* Return for uniformity. */;
- }
- /**
- * Maintenance mode.
- *
- * @package s2Member\Upgrader
- * @since 1.5
- *
- * @param bool $enable If true, enable maintenance mode. If false, disable maintenance mode.
- * @return bool This function always returns true.
- */
- public static function maintenance($enable = NULL)
- {
- global /* Need this global object reference. */ $wp_filesystem;
-
- if(is_bool($enable) && apply_filters("ws_plugin__s2member_pro_upgrade_maintenance", ($_SERVER["HTTP_HOST"] !== "www.s2member.com"), get_defined_vars()))
- {
- if($enable === true && WP_Filesystem(c_ws_plugin__s2member_pro_upgrader::$credentials, ABSPATH) && ($maintenance = $wp_filesystem->abspath().".maintenance"))
- $wp_filesystem->delete($maintenance).$wp_filesystem->put_contents($maintenance, '', FS_CHMOD_FILE);
-
- else if($enable === false && WP_Filesystem(c_ws_plugin__s2member_pro_upgrader::$credentials, ABSPATH) && ($maintenance = $wp_filesystem->abspath().".maintenance"))
- $wp_filesystem->delete($maintenance);
- }
- return /* Always return true. */ true;
- }
-
- /**
- * Converts an abbreviated byte notation into bytes.
- *
- * @package s2Member\Upgrader
- * @since 130819
- *
- * @param string $string A string value in byte notation.
- *
- * @return float A float indicating the number of bytes.
- */
- public static function abbr_bytes($string)
- {
- $string = (string)$string;
-
- $notation = '/^(?P[0-9\.]+)\s*(?Pbytes|byte|kbs|kb|k|mb|m|gb|g|tb|t)$/i';
-
- if(!preg_match($notation, $string, $_op))
- return (float)0;
-
- $value = (float)$_op['value'];
- $modifier = strtolower($_op['modifier']);
- unset($_op); // Housekeeping.
-
- switch($modifier) // Fall through based on modifier.
- {
- case 't': // Multiplied four times.
- case 'tb':
- $value *= 1024;
- case 'g': // Multiplied three times.
- case 'gb':
- $value *= 1024;
- case 'm': // Multiple two times.
- case 'mb':
- $value *= 1024;
- case 'k': // One time only.
- case 'kb':
- case 'kbs':
- $value *= 1024;
- }
- return (float)$value;
- }
- }
- }
+ * s2Member Pro upgrader.
+ *
+ * Copyright: © 2009-2011
+ * {@link http://websharks-inc.com/ WebSharks, Inc.}
+ * (coded in the USA)
+ *
+ * This WordPress plugin (s2Member Pro) is comprised of two parts:
+ *
+ * o (1) Its PHP code is licensed under the GPL license, as is WordPress.
+ * You should have received a copy of the GNU General Public License,
+ * along with this software. In the main directory, see: /licensing/
+ * If not, see: {@link http://www.gnu.org/licenses/}.
+ *
+ * o (2) All other parts of (s2Member Pro); including, but not limited to:
+ * the CSS code, some JavaScript code, images, and design;
+ * are licensed according to the license purchased.
+ * See: {@link http://s2member.com/prices/}
+ *
+ * Unless you have our prior written consent, you must NOT directly or indirectly license,
+ * sub-license, sell, resell, or provide for free; part (2) of the s2Member Pro Add-on;
+ * or make an offer to do any of these things. All of these things are strictly
+ * prohibited with part (2) of the s2Member Pro Add-on.
+ *
+ * Your purchase of s2Member Pro includes free lifetime upgrades via s2Member.com
+ * (i.e., new features, bug fixes, updates, improvements); along with full access
+ * to our video tutorial library: {@link http://s2member.com/videos/}
+ *
+ * @since 1.5
+ */
+if (!defined('WPINC')) { // MUST have.
+ exit('Do not access this file directly.');
+}
+if (!class_exists('c_ws_plugin__s2member_pro_upgrader')) {
+ /**
+ * s2Member Pro upgrader.
+ *
+ * @since 1.5
+ */
+ class c_ws_plugin__s2member_pro_upgrader
+ {
+ /**
+ * Upgrade error.
+ *
+ * @since 111027
+ *
+ * @type string
+ */
+ public static $error = '';
+
+ /**
+ * Filesystem credentials.
+ *
+ * @since 111027
+ *
+ * @type array
+ */
+ public static $credentials = array();
+
+ /**
+ * Upgrade wizard markup.
+ *
+ * @since 1.5 Adding pro upgrader.
+ * @since 170105 Enhancing pro upgrader.
+ *
+ * @return string Wizard HTML markup.
+ */
+ public static function wizard()
+ {
+ if (!current_user_can('update_plugins')) {
+ return ''; // Not applicable.
+ }
+ $error = !empty(self::$error) ? (string) self::$error : '';
+ $wp_error = $error ? new WP_Error('s2member_pro_upgrade_error', $error) : false;
+
+ $stored = (array) get_transient(md5('ws_plugin__s2member_pro_upgrade_credentials'));
+ $_p = !empty($_POST) ? c_ws_plugin__s2member_utils_strings::trim_deep(stripslashes_deep((array) $_POST)) : array();
+
+ $username = !empty($_p['ws_plugin__s2member_pro_upgrade_username']) ? (string) $_p['ws_plugin__s2member_pro_upgrade_username'] : '';
+ $username = !$username && !empty($stored['username']) ? (string) $stored['username'] : $username;
+
+ $password = !empty($_p['ws_plugin__s2member_pro_upgrade_password']) ? (string) $_p['ws_plugin__s2member_pro_upgrade_password'] : '';
+ $password = !$password && !empty($stored['password']) ? (string) $stored['password'] : $password;
+
+ $plugin_dir = dirname(dirname(dirname(dirname(__FILE__)))); // Pro.
+ $plugins_dir = dirname(dirname(dirname(dirname(dirname(__FILE__)))));
+
+ $credentials = self::$credentials = array(); // Reset & collect below.
+ $credential_extra_fields = array('ws_plugin__s2member_pro_upgrade', 'ws_plugin__s2member_pro_upgrade_username', 'ws_plugin__s2member_pro_upgrade_password');
+
+ ob_start(); // Buffer output, this generates a form for credentials, when necessary.
+ if (is_array($credentials = request_filesystem_credentials($_SERVER['REQUEST_URI'], false, $wp_error, $plugins_dir, $credential_extra_fields))) {
+ self::$credentials = $credentials; // Pass to `WP_Filesystem()`.
+ } // Collect the form in case it is needed below.
+ $credentials_form = ob_get_clean();
+
+ if (!empty($_p['ws_plugin__s2member_pro_upgrade']) && $error && strpos($error, '#0004') !== false && $credentials_form) {
+ $wizard = ''."\n";
+ $wizard .= '
Your s2Member Pro Add-on must be updated to v'.esc_html(WS_PLUGIN__S2MEMBER_MIN_PRO_VERSION).'+.
Please log in at s2Member.com for access to the latest version.
'."\n";
+ $wizard .= '
'."\n";
+ $wizard .= $credentials_form."\n";
+ //
+ } else { // Otherwise, default handling.
+ $wizard = ''."\n";
+ $wizard .= '
Your s2Member Pro Add-on must be updated to v'.esc_html(WS_PLUGIN__S2MEMBER_MIN_PRO_VERSION).'+.
Please log in at s2Member.com for access to the latest version.
'."\n";
+
+ $wizard .= '
'."\n";
+
+ $wizard .= '
';
+ }
+ return $wizard;
+ }
+
+ /**
+ * Upgrade processor.
+ *
+ * @since 1.5 Adding pro upgrader.
+ * @since 170105 Enhancing pro upgrader.
+ *
+ * @attaches-to `add_action('admin_init');`
+ */
+ public static function upgrade()
+ {
+ global $wp_filesystem;
+
+ if (!current_user_can('update_plugins')) {
+ return; // Not applicable.
+ } elseif (empty($_POST['ws_plugin__s2member_pro_upgrade'])) {
+ return; // Not applicable.
+ } elseif (!($nonce = (string) $_POST['ws_plugin__s2member_pro_upgrade'])) {
+ return; // Not applicable.
+ } elseif (!wp_verify_nonce($nonce, 'ws-plugin--s2member-pro-upgrade')) {
+ return; // Not applicable.
+ }
+ @set_time_limit(0); // No time limit during upgrade.
+ $admin_memory_limit = apply_filters('admin_memory_limit', WP_MAX_MEMORY_LIMIT);
+ @ini_set('memory_limit', $admin_memory_limit); // Attempt to maximize.
+
+ $memory_limit = @ini_get('memory_limit');
+ $memory_limit_bytes = self::abbr_bytes($memory_limit);
+ $admin_memory_limit_bytes = self::abbr_bytes($admin_memory_limit);
+
+ if ($memory_limit_bytes && $admin_memory_limit_bytes && $memory_limit_bytes < $admin_memory_limit_bytes) {
+ self::$error = 'Upgrade failed. Error #0001. Not enough memory. Unzipping s2Member Pro via WordPress requires plenty of RAM. Please upgrade via FTP instead.';
+ return; // Nothing more we can do here.
+ }
+ $stored = (array) get_transient(md5('ws_plugin__s2member_pro_upgrade_credentials'));
+ $_p = !empty($_POST) ? c_ws_plugin__s2member_utils_strings::trim_deep(stripslashes_deep((array) $_POST)) : array();
+
+ $username = !empty($_p['ws_plugin__s2member_pro_upgrade_username']) ? (string) $_p['ws_plugin__s2member_pro_upgrade_username'] : '';
+ $username = !$username && !empty($stored['username']) ? (string) $stored['username'] : $username;
+
+ $password = !empty($_p['ws_plugin__s2member_pro_upgrade_password']) ? (string) $_p['ws_plugin__s2member_pro_upgrade_password'] : '';
+ $password = !$password && !empty($stored['password']) ? (string) $stored['password'] : $password;
+
+ if (!$username || !$password) { // Both of these are absolutely required to complete the upgrade.
+ self::$error = 'Upgrade failed. Error #0002. Empty username or license key. Please try again.';
+ return; // Nothing more we can do here.
+ }
+ $latest_query_vars = array('product_api' => array(
+ 'action' => 'latest_pro_update',
+ 'username' => $username, 'password' => $password,
+ ));
+ $latest_request_url = 'https://s2member.com/'; // Always over `https://` at main site.
+ $latest_request_url = add_query_arg(urlencode_deep($latest_query_vars), $latest_request_url);
+ $latest = json_decode(c_ws_plugin__s2member_utils_urls::remote($latest_request_url), true);
+
+ if (empty($latest['pro_zip']) || empty($latest['pro_version'])) {
+ self::$error = 'Upgrade failed. Error #0003. Invalid username or license key. Please try again.';
+ return; // Nothing more we can do here.
+ }
+ set_transient(md5('ws_plugin__s2member_pro_upgrade_credentials'), compact('username', 'password'), 5184000);
+
+ $plugin_dir = dirname(dirname(dirname(dirname(__FILE__)))); // Pro.
+ $plugins_dir = dirname(dirname(dirname(dirname(dirname(__FILE__)))));
+
+ ob_start(); // Buffer output, this generates a form that is not necessary here.
+ if (is_array($credentials = request_filesystem_credentials($_SERVER['REQUEST_URI'], false, false, $plugins_dir))) {
+ self::$credentials = $credentials; // Pass to `WP_Filesystem()`.
+ } // The output from this call is not needed here.
+ ob_end_clean(); // End & clean only.
+
+ self::maintenance(true); // Enter maintenance mode.
+
+ if (!WP_Filesystem(self::$credentials, $plugins_dir)
+ || !($fs_plugins_dir = rtrim($wp_filesystem->find_folder($plugins_dir), '/'))
+ || !($fs_plugin_dir = rtrim($wp_filesystem->find_folder($plugin_dir), '/'))) {
+ self::$error = 'Upgrade failed. Error #0004. Please upgrade via FTP or supply valid filesystem credentials.';
+ self::maintenance(false); // Exit maintenance mode.
+ return; // Nothing more we can do here.
+ }
+ $tmp_zip = wp_unique_filename($plugins_dir, basename($plugin_dir).'.zip');
+ $fs_tmp_zip = $fs_plugins_dir.'/'.$tmp_zip;
+ $tmp_zip = $plugins_dir.'/'.$tmp_zip;
+
+ $zip_file_contents = c_ws_plugin__s2member_utils_urls::remote($latest['pro_zip'], false, array('timeout' => 120));
+
+ if (!$zip_file_contents || !$wp_filesystem->put_contents($fs_tmp_zip, $zip_file_contents, FS_CHMOD_FILE)) {
+ self::$error = 'Upgrade failed. Error #0005. Please upgrade via FTP.';
+ $wp_filesystem->delete($fs_tmp_zip);
+ $wp_filesystem->delete($fs_plugin_dir.'-new', true);
+ self::maintenance(false);
+ return;
+ }
+ if ($wp_filesystem->is_dir($fs_plugin_dir.'-new') && !$wp_filesystem->delete($fs_plugin_dir.'-new', true)) {
+ self::$error = 'Upgrade failed. Error #0006. Please upgrade via FTP. ';
+ $wp_filesystem->delete($fs_tmp_zip);
+ $wp_filesystem->delete($fs_plugin_dir.'-new', true);
+ self::maintenance(false);
+ return;
+ }
+ if (!$wp_filesystem->mkdir($fs_plugin_dir.'-new', FS_CHMOD_DIR)) {
+ self::$error = 'Upgrade failed. Error #0007. Please upgrade via FTP. ';
+ $wp_filesystem->delete($fs_tmp_zip);
+ $wp_filesystem->delete($fs_plugin_dir.'-new', true);
+ self::maintenance(false);
+ return;
+ }
+ if (is_wp_error($unzip = unzip_file($tmp_zip, $plugin_dir.'-new'))) {
+ $wp_filesystem->delete($fs_tmp_zip);
+ $wp_filesystem->delete($fs_plugin_dir.'-new', true);
+ self::$error = 'Upgrade failed. Error #0008. '.esc_html($unzip->get_error_message());
+ self::maintenance(false);
+ return;
+ }
+ if ($wp_filesystem->is_dir($fs_plugin_dir) && !$wp_filesystem->delete($fs_plugin_dir, true)) {
+ $wp_filesystem->delete($fs_tmp_zip);
+ $wp_filesystem->delete($fs_plugin_dir.'-new', true);
+ self::$error = 'Upgrade failed. Error #0009. Please upgrade via FTP.';
+ // self::maintenance(false); // Stay in maintenance mode.
+ return;
+ }
+ if (!$wp_filesystem->move($fs_plugin_dir.'-new/s2member-pro', $fs_plugin_dir)) {
+ $wp_filesystem->delete($fs_tmp_zip);
+ $wp_filesystem->delete($plugin_dir.'-new', true);
+ self::$error = 'Upgrade failed. Error #0010. Please upgrade via FTP.';
+ // self::maintenance(false); // Stay in maintenance mode.
+ return;
+ }
+ $wp_filesystem->delete($fs_tmp_zip);
+ $wp_filesystem->delete($fs_plugin_dir.'-new', true);
+
+ $notice = 's2Member Pro successfully updated to v'.esc_html($latest['pro_version']).'.';
+ c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, 'blog|network:*');
+ self::maintenance(false); // Exit maintenance mode now.
+
+ do_action('ws_plugin__s2member_pro_during_successfull_upgrade', get_defined_vars());
+
+ wp_redirect(self_admin_url('/plugins.php')).exit();
+ }
+
+ /**
+ * Maintenance mode.
+ *
+ * @since 170105 Enhancing pro upgrader.
+ *
+ * @param bool $enable Enable or disable; i.e., true|false.
+ */
+ public static function maintenance_mode($enable = true)
+ {
+ global $wp_filesystem; // Need this below.
+
+ if (apply_filters('ws_plugin__s2member_pro_upgrade_maintenance', true) && WP_Filesystem(self::$credentials, ABSPATH)) {
+ $dot_maintenance = $wp_filesystem->abspath().'.maintenance'; // Remote filesystem path.
+
+ $wp_filesystem->delete($dot_maintenance); // In case it exists.
+ if ($enable) { // If enabling maintenance mode, update file with a fresh timestamp.
+ $wp_filesystem->put_contents($dot_maintenance, '', FS_CHMOD_FILE);
+ }
+ }
+ }
+
+ /**
+ * Converts an abbreviated byte notation into bytes.
+ *
+ * @since 130819 Enhancing pro upgrader.
+ *
+ * @param string $string A string value in byte notation.
+ *
+ * @return float A float indicating the number of bytes.
+ */
+ public static function abbr_bytes($string)
+ {
+ $string = (string) $string;
+
+ $notation = '/^(?P[0-9\.]+)\s*(?Pbytes|byte|kbs|kb|k|mb|m|gb|g|tb|t)$/i';
+
+ if (!preg_match($notation, $string, $_op)) {
+ return (float) 0;
+ }
+
+ $value = (float) $_op['value'];
+ $modifier = strtolower($_op['modifier']);
+ unset($_op); // Housekeeping.
+
+ switch ($modifier) { // Fall throughs.
+ case 't': // Multiplied four times.
+ case 'tb':
+ $value *= 1024;
+ case 'g': // Multiplied three times.
+ case 'gb':
+ $value *= 1024;
+ case 'm': // Multiple two times.
+ case 'mb':
+ $value *= 1024;
+ case 'k': // One time only.
+ case 'kb':
+ case 'kbs':
+ $value *= 1024;
+ }
+ return (float) $value;
+ }
+ }
+}
diff --git a/src/includes/menu-pages/mms-ops.inc.php b/src/includes/menu-pages/mms-ops.inc.php
index 824f6a5f..62c52994 100644
--- a/src/includes/menu-pages/mms-ops.inc.php
+++ b/src/includes/menu-pages/mms-ops.inc.php
@@ -158,8 +158,8 @@ public function __construct()
echo ''."\n";
echo '
'."\n";
echo '
'."\n";
- echo '
The most important thing to do when setting up a Blog Farm with s2Member, is to add this line to your /wp-config.php
file: define("MULTISITE_FARM", true);
. This will add a default layer of security, to all Blogs within your Network, with respect to s2Member. But, before you go live, please contact s2Member.com for full documentation. There is some additional functionality that can be enabled for security on a Blog Farm installation; and also some menus/documentation/functionality that can be disabled. You will be asked to purchase our Network Support Package when you need assistance in this regard.
'."\n";
- echo '
Multisite Blog Farms require a site owner that fully understands the potential security risks associated with Blog Farming. s2Member\'s Network Support Package provides you with the information you need, and priority support for anything about s2Member that you don\'t understand. In addition, our Network Support Package includes a lengthy PDF file that details a list of things affected by define("MULTISITE_FARM", true);
, best practices, and other supplemental documentation focused on Blog Farms.
'."\n";
+ echo '
The most important thing to do when setting up a Blog Farm with s2Member, is to add this line to your /wp-config.php
file: define("MULTISITE_FARM", true);
. This will add a default layer of security, to all Blogs within your Network, with respect to s2Member. But, before you go live, please contact s2Member.com for full documentation. There is some additional functionality that can be enabled for security on a Blog Farm installation; and also some menus/documentation/functionality that can be disabled. You will be asked to purchase our Network Support Package when you need assistance in this regard.
'."\n";
+ echo '
Multisite Blog Farms require a site owner that fully understands the potential security risks associated with Blog Farming. s2Member\'s Network Support Package provides you with the information you need, and priority support for anything about s2Member that you don\'t understand. In addition, our Network Support Package includes a lengthy PDF file that details a list of things affected by define("MULTISITE_FARM", true);
, best practices, and other supplemental documentation focused on Blog Farms.
'."\n";
echo '
Definition of a Multisite Blog Farm: If your Network is making it possible for "Members" of your Main Site, to create and/or manage Blogs (in any way), s2Member will consider your installation to be a Multisite Blog Farm. That being said, some site owners run a Multisite Network for the purpose of maintaining their own sites. The term Multisite Blog Farm does NOT apply to a Network that hosts multiple Child Blogs, all of which are operated by a single site owner and/or a single company. Again, a Multisite Blog Farm (in the eyes of s2Member), is any Network that is making it possible for "Members" of its Main Site, to create and/or manage Blogs; where one or more of these Child Blogs is being administered by a Customer (i.e., if you offer both Membership and Blog creation, as configured below).
'."\n";
echo '
When NOT to run a Multisite Blog Farm: If you run a Multisite Network for the purpose of maintaining your own sites. You should NOT run a Multisite Blog Farm. You can still activate s2Member Network-wide, if you like (optional), but the advanced security considerations offered through s2Member\'s Multisite Blog Farm functionality are NOT needed in this case; because all of the Child Blogs in your Network belong to trusted Administrators (i.e., your Customers are NOT going to run Child Blogs on your Network in this case).
'."\n";
echo '
'."\n";