Last active
July 21, 2018 10:04
-
-
Save wpmudev-sls/206fae3dc5df8ee11a8e31267635314b to your computer and use it in GitHub Desktop.
[Pro Sites] - Additional Sites Per Level. Provides the ability to create additional sites without charge after singing up for a ProSite level
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Plugin Name: [Pro Sites] - Sites Per Level | |
* Plugin URI: https://premium.wpmudev.org/ | |
* Description: Allows a number of sites to be created per level | |
* Author: Panos Lyrakis @ WPMUDEV | |
* Author URI: https://premium.wpmudev.org/ | |
* License: GPLv2 or later | |
*/ | |
if ( ! defined( 'ABSPATH' ) ) { | |
exit; | |
} | |
if ( ! class_exists( 'WPMUDEV_PS_Sites_Per_Level' ) ) { | |
class WPMUDEV_PS_Sites_Per_Level { | |
private static $_instance = null; | |
private $sites_per_level = array(); | |
private $user_blog_levels = array(); | |
public static function get_instance() { | |
if( is_null( self::$_instance ) ){ | |
self::$_instance = new WPMUDEV_PS_Sites_Per_Level(); | |
} | |
return self::$_instance; | |
} | |
private function init() { | |
// Level => number of sites allowed | |
$this->sites_per_level = array( | |
'1' => 2, | |
'2' => 5, | |
'3' => 10 | |
); | |
} | |
private function __construct() { | |
$this->init(); | |
add_filter( 'prosites_render_checkout_page', array( &$this, 'checkout_page' ) ); | |
add_action( 'wp_ajax_wpmudev_ps_new_site_per_level', array( &$this, 'create_blog_ajax' ) ); | |
add_action( 'wp_ajax_nopriv_wpmudev_ps_new_site_per_level', array( &$this, 'create_blog_ajax' ) ); | |
} | |
public function get_user_sites( $user_id = null ) { | |
if ( ! empty( $this->user_blog_levels ) ) { | |
return $this->user_blog_levels; | |
} | |
global $psts; | |
if ( is_null( $user_id ) ){ | |
if ( ! is_user_logged_in() ){ | |
return array(); | |
} | |
$user_id = get_current_user_id(); | |
} | |
if( $user_id instanceof WP_User ) { | |
$user_id = $user_id->ID; | |
} | |
$user_id = (int) $user_id; | |
$user_blogs = get_blogs_of_user( $user_id ); | |
$user_blog_levels = array(); | |
foreach ( $user_blogs as $blog_id => $blog_info ) { | |
$level = $psts->get_level( $blog_id ); | |
if ( ! $level || 0 >= $level ) { | |
continue; | |
} | |
if( ! isset( $user_blog_levels[$level] ) ){ | |
$user_blog_levels[$level] = 0; | |
} | |
else{ | |
$user_blog_levels[$level] = (int) $user_blog_levels[$level] + 1; | |
} | |
} | |
$this->user_blog_levels = $user_blog_levels; | |
return $user_blog_levels; | |
} | |
private function remaining_levels_list( $remaining_sites_per_level ) { | |
global $psts; | |
$out = ""; | |
$levels = get_site_option( 'psts_levels' ); | |
if( empty( $levels ) ) { | |
return; | |
} | |
$out .= "<table class=\"ps-available-level-sites\">"; | |
$out .= "<thead>"; | |
$out .= "<tr>"; | |
$out .= "<td>Level</td>"; | |
$out .= "<td>Available</td>"; | |
$out .= "<td></td>"; | |
$out .= "</tr>"; | |
$out .= "</thead>"; | |
$out .= "<tbody>"; | |
foreach ( $remaining_sites_per_level as $level => $value ) { | |
if ( isset( $levels[$level] ) ){ | |
$out .= "<tr>"; | |
$out .= "<td><strong>{$levels[$level]['name']}</strong></td>"; | |
if ( $value > 0 ) : | |
$out .= "<td>{$value} sites</td>"; | |
$out .= "<td> | |
<a class=\"button-primary ps-create-form-btn\" data-level=\"{$level}\"> | |
Create a <strong>{$levels[$level]['name']}</strong> site | |
</a> | |
</td>"; | |
else: | |
$out .= "<td colspan='2'>No free sites available for <strong>{$levels[$level]['name']}</strong></td>"; | |
endif; | |
$out .= "</tr>"; | |
} | |
} | |
$out .= "</tbody>"; | |
$out .= "</table>"; | |
return $out; | |
} | |
private function get_parent_blog_data( $user_id, $level ) { | |
global $psts; | |
$user_blogs = get_blogs_of_user( $user_id ); | |
foreach ( $user_blogs as $blog_id => $blog_info ) { | |
$blog_level = $psts->get_level( $blog_id ); | |
if ( $blog_level == $level ) { | |
return array( | |
'expire' => $psts->get_expire( $blog_id ), | |
'is_recurring' => $psts->is_blog_recurring( $blog_id ) | |
); | |
} | |
} | |
} | |
private function create_nonce( $action ) { | |
$user = wp_get_current_user(); | |
$uid = (int) $user->ID; | |
if ( ! $uid ) { | |
/** | |
* Filters whether the user who generated the nonce is logged out. | |
* | |
* @since 3.5.0 | |
* | |
* @param int $uid ID of the nonce-owning user. | |
* @param string $action The nonce action. | |
*/ | |
$uid = apply_filters( 'ps_nonce_user_logged_out', $uid, $action ); | |
} | |
//$token = wp_get_session_token(); | |
$i = wp_nonce_tick(); | |
return $i . '|' . $action . '|' . $uid . '|' . session_id() ; | |
//return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10 ); | |
} | |
private function check_ajax_nonce( $nonce, $action = -1 ) { | |
$nonce = (string) $nonce; | |
$user = wp_get_current_user(); | |
$uid = (int) $user->ID; | |
if ( ! $uid ) { | |
/** | |
* Filters whether the user who generated the nonce is logged out. | |
* | |
* @param int $uid ID of the nonce-owning user. | |
* @param string $action The nonce action. | |
*/ | |
$uid = apply_filters( 'ps_nonce_user_logged_out', $uid, $action ); | |
} | |
if ( empty( $nonce ) ) { | |
return false; | |
} | |
//$token = wp_get_session_token(); | |
$i = wp_nonce_tick(); | |
// Nonce generated 0-12 hours ago | |
//$expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10 ); | |
$expected = $i . '|' . $action . '|' . $uid . '|' . session_id() ; | |
if ( hash_equals( $expected, $nonce ) ) { | |
return 1; | |
} | |
// Nonce generated 12-24 hours ago | |
$expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 ); | |
if ( hash_equals( $expected, $nonce ) ) { | |
return 2; | |
} | |
/** | |
* Fires when nonce verification fails. | |
* | |
* @param string $nonce The invalid nonce. | |
* @param string|int $action The nonce action. | |
* @param WP_User $user The current user object. | |
* @param string $token The user's session token. | |
*/ | |
do_action( 'ps_wp_verify_nonce_failed', $nonce, $action, $user, $token ); | |
// Invalid nonce | |
return false; | |
} | |
public function create_blog_ajax() { | |
$ajax_nonce_check = check_ajax_referer( 'wpmudev_ps_newsite_nonce', 'nonce', false ); | |
if ( ! $ajax_nonce_check ) { | |
if ( ! $this->check_ajax_nonce( $_POST['nonce'], 'wpmudev_ps_newsite_nonce' ) ) { | |
die( 'Nonce failed' ); | |
} | |
} | |
global $psts; | |
$level = filter_input( INPUT_POST, 'level', FILTER_VALIDATE_INT ); | |
$user_id = filter_input( INPUT_POST, 'user_id', FILTER_VALIDATE_INT ); | |
$path = "/" . stripslashes( filter_input( INPUT_POST, 'site_domain', FILTER_DEFAULT ) ) . "/"; | |
$site_name = filter_input( INPUT_POST, 'site_name', FILTER_DEFAULT ); | |
$gateway = false; | |
$amount = false; | |
$parent_blog_data = $this->get_parent_blog_data( $user_id, $level ); | |
$expire = $parent_blog_data['expire']; | |
$is_recurring = $parent_blog_data['is_recurring']; | |
$network = get_network(); | |
if ( ! $this->can_create_free_blog( $level ) ) { | |
$return = array( | |
'result' => '_FAIL_', | |
'message' => 'Not allowed to create a free blog for this level' | |
); | |
wp_send_json($return); | |
} | |
$blog_id = $this->create_blog( $network->domain, $path, $site_name , $user_id ); | |
if ( ! $blog_id instanceof WP_Error ){ | |
$psts->extend( $blog_id, $period, $gateway, $level, $amount, $expire, $is_recurring ); | |
$return = array( | |
'result' => '_SUCCESS_', | |
'blog_id' => $blog_id, | |
'redirect' => get_site_url( $blog_id ) | |
); | |
wp_send_json($return); | |
} | |
else { | |
$msg = $blog_id->get_error_message(); | |
$return = array( | |
'result' => '_FAIL_', | |
'message' => $msg | |
); | |
wp_send_json($return); | |
} | |
} | |
public function can_create_free_blog( $level ) { | |
$remaining_sites_per_level = $this->get_remaining_sites_per_level(); | |
if ( ! isset( $remaining_sites_per_level[$level] ) || $remaining_sites_per_level[$level] <= 0 ) { | |
return false; | |
} | |
return true; | |
} | |
public function create_blog( $domain, $path, $title, $user_id, $meta = array(), $network_id = 1 ) { | |
$defaults = array( | |
'public' => 0, | |
'WPLANG' => get_network_option( $network_id, 'WPLANG' ), | |
); | |
$meta = wp_parse_args( $meta, $defaults ); | |
$title = strip_tags( $title ); | |
$user_id = (int) $user_id; | |
$_domain = get_network()->domain; | |
if ( defined( 'SUBDOMAIN_INSTALL' ) && SUBDOMAIN_INSTALL ) { | |
$path = str_replace( '/', '', $path ); | |
$domain = $path . '.' . $_domain; | |
$path = '/'; | |
} | |
else{ | |
if ( strpos( $domain, $_domain ) === false) { | |
$domain = $_domain . '/' . $domain; | |
} | |
} | |
if ( empty($path) ) | |
$path = '/'; | |
if ( domain_exists($domain, $path, $network_id) ) | |
return new WP_Error( 'blog_taken', __( 'Sorry, that site already exists!' ) ); | |
if ( ! wp_installing() ) { | |
wp_installing( true ); | |
} | |
if ( ! $blog_id = insert_blog($domain, $path, $network_id) ) | |
return new WP_Error('insert_blog', __('Could not create site.')); | |
switch_to_blog($blog_id); | |
install_blog($blog_id, $title); | |
wp_install_defaults($user_id); | |
add_user_to_blog($blog_id, $user_id, 'administrator'); | |
foreach ( $meta as $key => $value ) { | |
if ( in_array( $key, array( 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id' ) ) ) | |
update_blog_status( $blog_id, $key, $value ); | |
else | |
update_option( $key, $value ); | |
} | |
update_option( 'blog_public', (int) $meta['public'] ); | |
if ( ! is_super_admin( $user_id ) && ! get_user_meta( $user_id, 'primary_blog', true ) ) | |
update_user_meta( $user_id, 'primary_blog', $blog_id ); | |
restore_current_blog(); | |
do_action( 'wpmu_new_blog', $blog_id, $user_id, $domain, $path, $network_id, $meta ); | |
wp_cache_set( 'last_changed', microtime(), 'sites' ); | |
return $blog_id; | |
} | |
private function checkout_scripts() { | |
$admin_url = get_admin_url(); | |
?> | |
<script type="text/javascript"> | |
(function(d,$){ | |
$(d).ready(function(){ | |
const level_list_wrap = $('.ps-available-level-sites'); | |
$('.ps-available-level-sites .ps-create-form-btn').on('click',function(){ | |
// Remove previous form is exists | |
$('.ps-create-site-form').hide(300,function(){$(this).remove()}); | |
let me = $(this), | |
level = me.data('level'), | |
form = $('<form />',{ | |
'class' : 'ps-create-site-form' | |
}), | |
site_domain_label = $('<label />',{ | |
text: 'New site path: ' | |
}), | |
site_domain_field = $('<input />',{ | |
'type': 'text', | |
id: 'site-domain' | |
}), | |
site_name_label = $('<label />',{ | |
text: 'New site name: ' | |
}), | |
site_name_field = $('<input />',{ | |
'type': 'text', | |
id: 'site-name' | |
}), | |
site_btn = $('<a />',{ | |
id: 'ps-create-site-btn', | |
text: 'Create new site' | |
}); | |
site_btn.attr('data-level', level); | |
level_list_wrap.append(form.append(site_domain_label).append(site_domain_field).append(site_name_label).append(site_name_field).append(site_btn)); | |
}); | |
$(d).on('click', '#ps-create-site-btn', function(){ | |
let me = $(this), | |
orig_btn_txt = me.html(), | |
ajaxurl = '<?php echo admin_url( 'admin-ajax.php' ); ?>', | |
level = $(this).data('level'), | |
site_name = $( '#site-name' ).val(), | |
site_domain = $('#site-domain').val(), | |
wpmudev_ps_newsite_nonce = '<?php echo $this->create_nonce( 'wpmudev_ps_newsite_nonce' ); //wp_create_nonce("wpmudev_ps_newsite_nonce"); ?>', | |
ajax_data ={ | |
action: 'wpmudev_ps_new_site_per_level', | |
nonce: wpmudev_ps_newsite_nonce, | |
level: level, | |
site_name: site_name, | |
site_domain: site_domain, | |
user_id: '<?php echo get_current_user_id(); ?>' | |
}; | |
me.html( 'Sending <img src="<?php echo $admin_url; ?>/images/spinner.gif" />' ).prop( "disabled", true ); | |
$.ajax({ | |
type: "POST", | |
url: ajaxurl, | |
data: ajax_data, | |
dataType: "json", | |
success: function(resp){ | |
if( resp.result == "_SUCCESS_" ) { | |
notice = $('<div />',{ | |
'class': 'updated notice is-dismissible', | |
text : 'ALL OK' | |
}); | |
window.location.replace( resp.redirect ); | |
} | |
else{ | |
notice = $('<div />',{ | |
'class': 'error notice is-dismissible', | |
'html' : '<p>' + resp.message + '</p>' | |
}); | |
} | |
level_list_wrap.append(notice); | |
setTimeout(function(){ | |
notice.hide(300, function(){$(this).remove()} ); | |
}, 5000); | |
me.html(orig_btn_txt).prop( "disabled", false ); | |
}, | |
failure: function(errMsg) { | |
console.log(errMsg); | |
} | |
}); | |
}); | |
}); | |
})(document,jQuery); | |
</script> | |
<?php | |
} | |
private function add_content( $content, $remaining_sites_per_level ) { | |
$levels_str = $this->remaining_levels_list( $remaining_sites_per_level ); | |
$top_options = "<div id='ps-levels-options'>"; | |
$top_options .= "<h2>You deserve a free site</h2>"; | |
$top_options .= "<div><strong>You can create</strong></div>"; | |
$top_options .= $levels_str; | |
$top_options .= "</div>"; | |
return "{$top_options}<div id='ps-default-prices-list' style=\"display:block;\">{$content}{$this->checkout_scripts()}</div>"; | |
} | |
public function checkout_page( $content ) { | |
if ( ! is_user_logged_in() || empty( $this->sites_per_level ) ){ | |
return $content; | |
} | |
$user_sites = $this->get_user_sites(); | |
if ( empty( $user_sites ) ) { | |
return $content; | |
} | |
$remaining_sites_per_level = $this->get_remaining_sites_per_level(); | |
//if ( empty( $remaining_sites_per_level ) || ! $this->has_site_to_offer( $remaining_sites_per_level ) ) { | |
// return $content; | |
//} | |
if ( empty( $remaining_sites_per_level ) ) { | |
return $content; | |
} | |
if ( ! $this->has_site_to_offer( $remaining_sites_per_level ) ) { | |
$out = "<div id='ps-no-levels-options'>"; | |
$out .= "<h3>Sorry no free sites available</h3>"; | |
$out .= "<strong>However you can create a new site by selecting one of the following plans!</strong>"; | |
$out .= "</div>"; | |
return $out . $content; | |
} | |
return $this->add_content( $content, $remaining_sites_per_level ); | |
} | |
public function get_remaining_sites_per_level() { | |
$user_sites = $this->get_user_sites(); | |
$remaining_sites_per_level = array(); | |
foreach ( $this->sites_per_level as $level => $value ) { | |
if ( array_key_exists( $level, $user_sites ) ){ | |
$remaining_sites_per_level[ $level ] = $value - $user_sites[ $level ]; | |
} | |
} | |
return $remaining_sites_per_level; | |
} | |
private function has_site_to_offer( $remaining_sites_per_level ) { | |
foreach ( $remaining_sites_per_level as $level => $value ) { | |
if ( $value > 0 ) { | |
return true; | |
} | |
} | |
return false; | |
} | |
} | |
add_action( 'plugins_loaded', function(){ | |
$GLOBALS['WPMUDEV_PS_Sites_Per_Level'] = WPMUDEV_PS_Sites_Per_Level::get_instance(); | |
}, 10 ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment