/** * Get all duplicable sites * @since 0.2.0 * @return array of blog data */ public static function get_site_list() { $site_list = array(); $network_blogs = wp_get_sites(array('limit' => MUCD_MAX_NUMBER_OF_SITE)); foreach ($network_blogs as $blog) { if (MUCD_Functions::is_duplicable($blog['blog_id']) && MUCD_SITE_DUPLICATION_EXCLUDE != $blog['blog_id']) { $site_list[] = $blog; } } return $site_list; }
/** * Duplication form validation * @since 0.2.0 * @param array $init_data default data * @return array $data validated data, or errors */ public static function check_form($init_data) { $data = $init_data; $data['copy_files'] = 'no'; $data['keep_users'] = 'no'; $data['log'] = 'no'; // Check referer and nonce if (check_admin_referer(MUCD_DOMAIN)) { global $current_site; $error = array(); // Merge $data / $_POST['site'] to get Posted data and fill form $data = array_merge($data, $_POST['site']); // format and check source $data['from_site_id'] = intval($data['source']); if ($data['from_site_id'] < 1 || !get_blog_details($data['from_site_id'], false)) { $error[] = new WP_Error('mucd_error', MUCD_NETWORK_PAGE_DUPLICATE_MISSING_FIELDS); } $domain = ''; if (preg_match('|^([a-zA-Z0-9-])+$|', $data['domain'])) { $domain = strtolower($data['domain']); } // If not a subdomain install, make sure the domain isn't a reserved word if (!is_subdomain_install()) { /** This filter is documented in wp-includes/ms-functions.php */ $subdirectory_reserved_names = apply_filters('subdirectory_reserved_names', array('page', 'comments', 'blog', 'files', 'feed')); if (in_array($domain, $subdirectory_reserved_names)) { $error[] = new WP_Error('mucd_error', sprintf(MUCD_NETWORK_PAGE_DUPLICATE_DOMAIN_ERROR_RESERVED_WORDS, implode('</code>, <code>', $subdirectory_reserved_names))); } } if (empty($domain)) { $error[] = new WP_Error('mucd_error', MUCD_NETWORK_PAGE_DUPLICATE_DOMAIN_ERROR_REQUIRE); } if (is_subdomain_install()) { $newdomain = $domain . '.' . preg_replace('|^www\\.|', '', $current_site->domain); $path = $current_site->path; } else { $newdomain = $current_site->domain; $path = $current_site->path . $domain . '/'; } // format and check title if (empty($data['title'])) { $error[] = new WP_Error('mucd_error', MUCD_NETWORK_PAGE_DUPLICATE_TITLE_ERROR_REQUIRE); } // format and check email admin if (empty($data['email'])) { $error[] = new WP_Error('mucd_error', MUCD_NETWORK_PAGE_DUPLICATE_EMAIL_MISSING); } $valid_mail = sanitize_email($data['email']); if (is_email($valid_mail)) { $data['email'] = $valid_mail; } else { $error[] = new WP_Error('mucd_error', MUCD_NETWORK_PAGE_DUPLICATE_EMAIL_ERROR_FORMAT); } $data['domain'] = $domain; $data['newdomain'] = $newdomain; $data['path'] = $path; $data['public'] = !isset($data['private']); // Network $data['network_id'] = $current_site->id; if (isset($data['log']) && $data['log'] == 'yes' && (!isset($data['log-path']) || $data['log-path'] == "" || !MUCD_Functions::valid_path($data['log-path']))) { $error[] = new WP_Error('mucd_error', MUCD_NETWORK_PAGE_DUPLICATE_VIEW_LOG_PATH_EMPTY); } if (isset($error[0])) { $data['error'] = $error[0]; } } else { $data['error'] = MUCD_GAL_ERROR_CAPABILITIES; } return $data; }
/** * Stop process on SQL Error, print and log error, removes the new blog * @since 0.2.0 * @param string $sql_query the query * @param string $sql_error the error */ public static function sql_error($sql_query, $sql_error) { $error_1 = 'ERROR SQL ON : ' . $sql_query; MUCD_Duplicate::write_log($error_1); $error_2 = 'WPDB ERROR : ' . $sql_error; MUCD_Duplicate::write_log($error_2); MUCD_Duplicate::write_log('Duplication interrupted on SQL ERROR'); echo '<br />Duplication failed :<br /><br />' . $error_1 . '<br /><br />' . $error_2 . '<br /><br />'; if ($log_url = MUCD_Duplicate::log_url()) { echo '<a href="' . $log_url . '">' . MUCD_NETWORK_PAGE_DUPLICATE_VIEW_LOG . '</a>'; } MUCD_Functions::remove_blog(self::$to_site_id); wp_die(); }
require_once realpath(dirname(__FILE__)) . '/include/config.php'; // Plugin options require_once MUCD_COMPLETE_PATH . '/include/option.php'; // Load textdomain load_plugin_textdomain(MUCD_DOMAIN, NULL, MUCD_PATH . '/language/'); // Load language require_once MUCD_COMPLETE_PATH . '/include/lang.php'; // Load Functions require_once MUCD_COMPLETE_PATH . '/lib/functions.php'; if (is_admin()) { require_once MUCD_COMPLETE_PATH . '/include/admin.php'; MUCD_Admin::hooks(); } if (defined('WP_CLI') && WP_CLI) { require_once MUCD_COMPLETE_PATH . '/lib/duplicate.php'; MUCD_Functions::set_locale_to_en_US(); require_once MUCD_COMPLETE_PATH . '/wp-cli/wp-cli-site-duplicate-subcommand.php'; } /** * Main class of the plugin */ class MUCD { /** * Register hooks used by the plugin */ public static function hooks() { // Register (de)activation hook register_activation_hook(__FILE__, array(__CLASS__, 'activate')); register_deactivation_hook(__FILE__, array(__CLASS__, 'deactivate'));
/** * Duplicate a site in a multisite install. * * ## OPTIONS * * --slug=<slug> * : Path for the new site. Subdomain on subdomain installs, directory on subdirectory installs. * * --source=<site_id> * : ID of the site to duplicate. * * [--title=<title>] * : Title of the new site. Default: prettified slug. * * [--email=<email>] * : Email for Admin user. User will be created if none exists. Assignement to Super Admin if not included. * * [--network_id=<network-id>] * : Network to associate new site with. Defaults to current network (typically 1). * * [--private] * : If set, the new site will be non-public (not indexed) * * [--porcelain] * : If set, only the site id will be output on success. * * [--v] * : If set, print more details about the new site (Verbose mode). Do not work if --procelain is set. * * [--do_not_copy_files] * : If set, files of the duplicated site will not be copied. * * [--keep_users] * : If set, the new site will have the same users as the duplicated site. * * [--log=<dir_path>] * : If set, a log will be written in this directory (please check this directory is writable). * * @alias clone * * @synopsis --slug=<slug> --source=<site_id> [--title=<title>] [--email=<email>] [--network_id=<network-id>] [--private] [--porcelain] [--v] [--do_not_copy_files] [--keep_users] [--log=<dir_path>] */ public function __invoke($_, $assoc_args) { if (!is_multisite()) { WP_CLI::error('This is not a multisite install.'); } global $wpdb, $current_site; $base = $assoc_args['slug']; $title = isset($assoc_args['title']) ? $assoc_args['title'] : ucfirst($base); $email = empty($assoc_args['email']) ? '' : $assoc_args['email']; // Network if (!empty($assoc_args['network_id'])) { $network = MUCD_Functions::get_network($assoc_args['network_id']); if ($network === false) { WP_CLI::error(sprintf('Network with id %d does not exist.', $assoc_args['network_id'])); } } else { $network = $current_site; } $network_id = $network->id; $public = !isset($assoc_args['private']); // Sanitize if (preg_match('|^([a-zA-Z0-9-])+$|', $base)) { $base = strtolower($base); } // If not a subdomain install, make sure the domain isn't a reserved word if (!is_subdomain_install()) { $subdirectory_reserved_names = apply_filters('subdirectory_reserved_names', array('page', 'comments', 'blog', 'files', 'feed')); if (in_array($base, $subdirectory_reserved_names)) { WP_CLI::error('The following words are reserved and cannot be used as blog names: ' . implode(', ', $subdirectory_reserved_names)); } } // Check for valid email, if not, use the first Super Admin found // Probably a more efficient way to do this so we dont query for the // User twice if super admin $email = sanitize_email($email); if (empty($email) || !is_email($email)) { $super_admins = get_super_admins(); $email = ''; if (!empty($super_admins) && is_array($super_admins)) { // Just get the first one $super_login = $super_admins[0]; $super_user = get_user_by('login', $super_login); if ($super_user) { $email = $super_user->user_email; } } } if (is_subdomain_install()) { $newdomain = $base . '.' . preg_replace('|^www\\.|', '', $network->domain); $path = $network->path; } else { $newdomain = $network->domain; $path = $network->path . $base . '/'; } // Source ? $source = $assoc_args['source']; if (!intval($source) != 0) { WP_CLI::error($source . ' is not a valid site ID.'); } if (!MUCD_Functions::site_exists($source)) { WP_CLI::error('There is no site with ID=' . $source . '. The site to duplicate must be an existing site of the network.'); } // Copy files ? $copy_files = isset($assoc_args['do_not_copy_files']) ? 'no' : 'yes'; // Keep users ? $keep_users = isset($assoc_args['keep_users']) ? 'yes' : 'no'; // Write log if (isset($assoc_args['log'])) { $log = 'yes'; $log_path = $assoc_args['log']; } else { $log = 'no'; $log_path = ''; } $data = array('source' => $source, 'domain' => $base, 'title' => $title, 'email' => $email, 'copy_files' => $copy_files, 'keep_users' => $keep_users, 'log' => $log, 'log-path' => $log_path, 'from_site_id' => $source, 'newdomain' => $newdomain, 'path' => $path, 'public' => $public, 'network_id' => $network_id); $wpdb->hide_errors(); $form_message = MUCD_Duplicate::duplicate_site($data); $wpdb->show_errors(); if (isset($form_message['error'])) { WP_CLI::error($form_message['error']); } else { if (isset($assoc_args['porcelain'])) { WP_CLI::line($form_message['site_id']); } else { switch_to_blog($form_message['site_id']); if (!isset($assoc_args['v'])) { WP_CLI::success('Site ' . $form_message['site_id'] . ' created: ' . get_site_url()); } else { // Verbose mode WP_CLI::success($form_message['msg']); $user = get_current_user_id(); WP_CLI::line("ID : " . $form_message['site_id']); WP_CLI::line("Title : " . get_bloginfo('name')); WP_CLI::line("Front : " . get_site_url()); WP_CLI::line("Dashboard : " . admin_url()); WP_CLI::line("Customize : " . admin_url('customize.php')); } restore_current_blog(); } } }
/** * Stop process on Creating dir Error, print and log error, removes the new blog * @since 0.2.0 * @param string $dir_path the path */ public static function mkdir_error($dir_path) { $error_1 = 'ERROR DURING FILE COPY : CANNOT CREATE ' . $dir_path; MUCD_Duplicate::write_log($error_1); $error_2 = sprintf(MUCD_NETWORK_PAGE_DUPLICATE_COPY_FILE_ERROR, MUCD_Functions::get_primary_upload_dir()); MUCD_Duplicate::write_log($error_2); MUCD_Duplicate::write_log('Duplication interrupted on FILE COPY ERROR'); echo '<br />Duplication failed :<br /><br />' . $error_1 . '<br /><br />' . $error_2 . '<br /><br />'; if ($log_url = MUCD_Duplicate::log_url()) { echo '<a href="' . $log_url . '">' . MUCD_NETWORK_PAGE_DUPLICATE_VIEW_LOG . '</a>'; } MUCD_Functions::remove_blog(self::$to_site_id); wp_die(); }