Skip to content

Instantly share code, notes, and snippets.

@wpmudev-sls
Last active July 21, 2018 10:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wpmudev-sls/206fae3dc5df8ee11a8e31267635314b to your computer and use it in GitHub Desktop.
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
<?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