# HG changeset patch # User ymh # Date 1433779911 0 # Node ID 346c88efed218498706c1081e8e72219ba887e99 # Parent 6d22aaa62d12fe67665535b5e33ac8c500317aa3 add blog-copier plugin diff -r 6d22aaa62d12 -r 346c88efed21 wp/wp-content/plugins/blog-copier/blog-copier.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wp/wp-content/plugins/blog-copier/blog-copier.php Mon Jun 08 16:11:51 2015 +0000 @@ -0,0 +1,431 @@ +setup_localization(); + add_submenu_page( 'sites.php', $this->_name, $this->_name, 'manage_sites', $this->_domain, array( $this, 'admin_page' ) ); + } + + /** + * Add "Copy Blog" link under each site in the sites list view. + * + * @param array $actions + * @param int $blog_id + * @return array $actions + */ + public function add_site_action( $actions, $blog_id ) { + if( !is_main_site( $blog_id ) ) { + $this->setup_localization(); + $url = add_query_arg( array( + 'page' => $this->_domain, + 'blog' => $blog_id + ), network_admin_url( 'sites.php' ) ); + $nonce_string = sprintf( '%s-%s', $this->_domain, $blog_id ); + $actions[$this->_domain] = '' . __( 'Copy', $this->_domain ) . ''; + } + + return $actions; + } + + /** + * Admin page + */ + public function admin_page() { + global $wpdb, $current_site; + + if( !current_user_can( 'manage_sites' ) ) + wp_die( __( "Sorry, you don't have permissions to use this page.", $this->_domain ) ); + + $from_blog = false; + $copy_id = 0; + $nonce_string = sprintf( '%s-%s', $this->_domain, $copy_id ); + if( isset($_GET['blog']) && wp_verify_nonce( $_GET['_wpnonce'], $nonce_string ) ) { + $copy_id = (int)$_GET['blog']; + $from_blog = get_blog_details( $copy_id ); + if( $from_blog->site_id != $current_site->id ) { + $from_blog = false; + } + } + $from_blog_id = ( isset( $_POST['source_blog'] ) ) ? (int) $_POST['source_blog'] : -1; + + if( isset($_POST[ 'action' ]) && $_POST[ 'action' ] == $this->_domain ) { + check_admin_referer( $this->_domain ); + $blog = $_POST['blog']; + $domain = sanitize_user( str_replace( '/', '', $blog[ 'domain' ] ) ); + $title = $blog[ 'title' ]; + $copy_files = (isset($_POST['copy_files']) && $_POST['copy_files'] == '1') ? true : false; + + if ( !$from_blog_id ) { + $msg = __( 'Please select a source blog.', $this->_domain ); + } elseif ( empty( $domain ) ) { + $msg = __( 'Please enter a "New Blog Address".', $this->_domain ); + } elseif ( empty( $title ) ) { + $msg = __( 'Please enter a "New Blog Title".', $this->_domain ); + } else { + $msg = $this->copy_blog( $domain, $title, $from_blog_id, $copy_files ); + } + } else { + $copy_files = true; // set the default for first page load + } ?> +

_name; ?>

+

+

blogs} b " . + "WHERE b.site_id = {$current_site->id} && b.blog_id > 1 ORDER BY domain_path ASC LIMIT 10000"; + + $blogs = $wpdb->get_results( $query ); + } + if( $from_blog || $blogs ) { ?> +
+

_domain ); ?>

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
_domain ); ?>%s', $from_blog->siteurl, $from_blog->blogname ); ?> + +
_domain ); ?> + +
_domain ); ?> + + .domain;?> + domain . $current_site->path ?> + +
_domain ); ?>
_domain ); ?>/>
+ _domain ); ?> +

_domain ); ?>' />

+
+ +
+

_domain ); ?>

+

create at least one subblog.', $this->_domain ), network_admin_url( 'site-new.php' ) ); + ?>

+
+ domain; + $path = $base; + } else { + $newdomain = $current_site->domain; + $path = trailingslashit( $base ) . trailingslashit( $domain ); + } + + // The new domain that will be created for the destination blog. + $newdomain = apply_filters('copy_blog_domain', $newdomain, $domain); + + // The new path that will be created for the destination blog. + $path = apply_filters('copy_blog_path', $path, $domain); + + $wpdb->hide_errors(); + $to_blog_id = wpmu_create_blog( $newdomain, $path, $title, $user_id , array( "public" => 1 ), $current_site->id ); + $wpdb->show_errors(); + + if( !is_wp_error( $to_blog_id ) ) { + $dashboard_blog = get_dashboard_blog(); + if( !is_super_admin() && get_user_option( 'primary_blog', $user_id ) == $dashboard_blog->blog_id ) + update_user_option( $user_id, 'primary_blog', $to_blog_id, true ); + + // now copy + if( $from_blog_id ) { + + $this->copy_blog_data( $from_blog_id, $to_blog_id ); + + if ($copy_files) { + + $this->copy_blog_files( $from_blog_id, $to_blog_id ); + $this->replace_content_urls( $from_blog_id, $to_blog_id ); + + } + $msg = sprintf(__( 'Copied: %s in %s seconds', $this->_domain ),''.$title.'', number_format_i18n(timer_stop())); + do_action( 'log', __( 'Copy Complete!', $this->_domain ), $this->_domain, $msg ); + } + } else { + $msg = $to_blog_id->get_error_message(); + } + return $msg; + } + + /** + * Copy blog data from one blog to another + * + * @param int $from_blog_id ID of the blog being copied from. + * @param int $to_blog_id ID of the blog being copied to. + */ + private function copy_blog_data( $from_blog_id, $to_blog_id ) { + global $wpdb, $wp_version; + if( $from_blog_id ) { + $from_blog_prefix = $this->get_blog_prefix( $from_blog_id ); + $to_blog_prefix = $this->get_blog_prefix( $to_blog_id ); + $from_blog_prefix_length = strlen($from_blog_prefix); + $to_blog_prefix_length = strlen($to_blog_prefix); + $from_blog_escaped_prefix = str_replace( '_', '\_', $from_blog_prefix ); + + // Grab key options from new blog. + $saved_options = array( + 'siteurl'=>'', + 'home'=>'', + 'upload_path'=>'', + 'fileupload_url'=>'', + 'upload_url_path'=>'', + 'admin_email'=>'', + 'blogname'=>'' + ); + // Options that should be preserved in the new blog. + $saved_options = apply_filters('copy_blog_data_saved_options', $saved_options); + foreach($saved_options as $option_name => $option_value) { + $saved_options[$option_name] = get_blog_option( $to_blog_id, $option_name ); + } + + // Copy over ALL the tables. + $query = $wpdb->prepare('SHOW TABLES LIKE %s',$from_blog_escaped_prefix.'%'); + do_action( 'log', $query, $this->_domain); + $old_tables = $wpdb->get_col($query); + + foreach ($old_tables as $k => $table) { + $raw_table_name = substr( $table, $from_blog_prefix_length ); + $newtable = $to_blog_prefix . $raw_table_name; + + $query = "DROP TABLE IF EXISTS {$newtable}"; + do_action( 'log', $query, $this->_domain); + $wpdb->get_results($query); + + $query = "CREATE TABLE IF NOT EXISTS {$newtable} LIKE {$table}"; + do_action( 'log', $query, $this->_domain); + $wpdb->get_results($query); + + $query = "INSERT {$newtable} SELECT * FROM {$table}"; + do_action( 'log', $query, $this->_domain); + $wpdb->get_results($query); + } + + // apply key opptions from new blog. + switch_to_blog( $to_blog_id ); + foreach( $saved_options as $option_name => $option_value ) { + update_option( $option_name, $option_value ); + } + + /// fix all options with the wrong prefix... + $query = $wpdb->prepare("SELECT * FROM {$wpdb->options} WHERE option_name LIKE %s",$from_blog_escaped_prefix.'%'); + $options = $wpdb->get_results( $query ); + do_action( 'log', $query, $this->_domain, count($options).' results found.'); + if( $options ) { + foreach( $options as $option ) { + $raw_option_name = substr($option->option_name,$from_blog_prefix_length); + $wpdb->update( $wpdb->options, array( 'option_name' => $to_blog_prefix . $raw_option_name ), array( 'option_id' => $option->option_id ) ); + } + wp_cache_flush(); + } + + // Fix GUIDs on copied posts + $this->replace_guid_urls( $from_blog_id, $to_blog_id ); + + restore_current_blog(); + } + } + + /** + * Copy files from one blog to another. + * + * @param int $from_blog_id ID of the blog being copied from. + * @param int $to_blog_id ID of the blog being copied to. + */ + private function copy_blog_files( $from_blog_id, $to_blog_id ) { + set_time_limit( 2400 ); // 60 seconds x 10 minutes + @ini_set('memory_limit','2048M'); + + // Path to source blog files. + switch_to_blog($from_blog_id); + $dir_info = wp_upload_dir(); + $from = str_replace(' ', "\\ ", trailingslashit($dir_info['basedir']).'*'); // * necessary with GNU cp, doesn't hurt anything with BSD cp + restore_current_blog(); + $from = apply_filters('copy_blog_files_from', $from, $from_blog_id); + + // Path to destination blog files. + switch_to_blog($to_blog_id); + $dir_info = wp_upload_dir(); + $to = str_replace(' ', "\\ ", trailingslashit($dir_info['basedir'])); + restore_current_blog(); + $to = apply_filters('copy_blog_files_to', $to, $to_blog_id); + + // Shell command used to copy files. + $command = apply_filters('copy_blog_files_command', sprintf("cp -Rfp %s %s", $from, $to), $from, $to ); + exec($command); + } + + /** + * Replace URLs in post content + * + * @param int $from_blog_id ID of the blog being copied from. + * @param int $to_blog_id ID of the blog being copied to. + */ + private function replace_content_urls( $from_blog_id, $to_blog_id ) { + global $wpdb; + $to_blog_prefix = $this->get_blog_prefix( $to_blog_id ); + $from_blog_url = get_blog_option( $from_blog_id, 'siteurl' ); + $to_blog_url = get_blog_option( $to_blog_id, 'siteurl' ); + $query = $wpdb->prepare( "UPDATE {$to_blog_prefix}posts SET post_content = REPLACE(post_content, '%s', '%s')", $from_blog_url, $to_blog_url ); + do_action( 'log', $query, $this->_domain); + $wpdb->query( $query ); + } + + /** + * Replace URLs in post GUIDs + * + * @param int $from_blog_id ID of the blog being copied from. + * @param int $to_blog_id ID of the blog being copied to. + */ + private function replace_guid_urls( $from_blog_id, $to_blog_id ) { + global $wpdb; + $to_blog_prefix = $this->get_blog_prefix( $to_blog_id ); + $from_blog_url = get_blog_option( $from_blog_id, 'siteurl' ); + $to_blog_url = get_blog_option( $to_blog_id, 'siteurl' ); + $query = $wpdb->prepare( "UPDATE {$to_blog_prefix}posts SET guid = REPLACE(guid, '%s', '%s')", $from_blog_url, $to_blog_url ); + do_action( 'log', $query, $this->_domain); + $wpdb->query( $query ); + } + + /** + * Get the database prefix for a blog + * + * @param int $blog_id ID of the blog. + * @return string prefix + */ + private function get_blog_prefix( $blog_id ) { + global $wpdb; + if( is_callable( array( &$wpdb, 'get_blog_prefix' ) ) ) { + $prefix = $wpdb->get_blog_prefix( $blog_id ); + } else { + $prefix = $wpdb->base_prefix . $blog_id . '_'; + } + return $prefix; + } + + /** + * Load the localization file + */ + private function setup_localization() { + if ( !isset( $this->_name ) ) { + load_plugin_textdomain( $this->_domain, false, trailingslashit(dirname(__FILE__)) . 'lang/'); + $this->_name = __( 'Blog Copier', $this->_domain ); + } + } + + } + + global $BlogCopier; + $BlogCopier = new BlogCopier(); +} +?> diff -r 6d22aaa62d12 -r 346c88efed21 wp/wp-content/plugins/blog-copier/lang/blog-copier.pot --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wp/wp-content/plugins/blog-copier/lang/blog-copier.pot Mon Jun 08 16:11:51 2015 +0000 @@ -0,0 +1,113 @@ +# Copyright (C) 2012 Blog Copier +# This file is distributed under the same license as the Blog Copier package. +msgid "" +msgstr "" +"Project-Id-Version: Blog Copier 1.0.2\n" +"Report-Msgid-Bugs-To: http://wordpress.org/tag/blog-copier\n" +"POT-Creation-Date: 2012-03-16 20:47:37+00:00\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"PO-Revision-Date: 2012-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" + +#: blog-copier.php:72 +msgid "Copy" +msgstr "" + +#: blog-copier.php:85 +msgid "Sorry, you don't have permissions to use this page." +msgstr "" + +#: blog-copier.php:108 +msgid "Please select a source blog." +msgstr "" + +#: blog-copier.php:110 +msgid "Please enter a \"New Blog Address\"." +msgstr "" + +#: blog-copier.php:112 +msgid "Please enter a \"New Blog Title\"." +msgstr "" + +#: blog-copier.php:133 +msgid "Blog Copy Settings" +msgstr "" + +#: blog-copier.php:140 +msgid "Source Blog to Copy" +msgstr "" + +#: blog-copier.php:147 +msgid "Choose Source Blog to Copy" +msgstr "" + +#: blog-copier.php:159 +msgid "New Blog Address" +msgstr "" + +#: blog-copier.php:162 +msgid "Subdomain" +msgstr "" + +#: blog-copier.php:164 +msgid "Domain" +msgstr "" + +#: blog-copier.php:170 +msgid "New Blog Title" +msgstr "" + +#: blog-copier.php:171 +msgid "Title" +msgstr "" + +#: blog-copier.php:175 +msgid "Copy Files?" +msgstr "" + +#: blog-copier.php:181 +msgid "Copy Now" +msgstr "" + +#: blog-copier.php:185 +msgid "Oops!" +msgstr "" + +#: blog-copier.php:187 +msgid "" +"This plugin only works on subblogs. To use this you'll need to create at least one subblog." +msgstr "" + +#: blog-copier.php:248 +msgid "Copied: %s in %s seconds" +msgstr "" + +#: blog-copier.php:249 +msgid "Copy Complete!" +msgstr "" + +#. #-#-#-#-# plugin.pot (Blog Copier 1.0.2) #-#-#-#-# +#. Plugin Name of the plugin/theme +#: blog-copier.php:409 +msgid "Blog Copier" +msgstr "" + +#. Plugin URI of the plugin/theme +msgid "http://wordpress.org/extend/plugins/blog-copier/" +msgstr "" + +#. Description of the plugin/theme +msgid "Enables superusers to copy existing sub blogs to new sub blogs." +msgstr "" + +#. Author of the plugin/theme +msgid "Modern Tribe, Inc." +msgstr "" + +#. Author URI of the plugin/theme +msgid "http://tri.be" +msgstr "" diff -r 6d22aaa62d12 -r 346c88efed21 wp/wp-content/plugins/blog-copier/readme.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wp/wp-content/plugins/blog-copier/readme.txt Mon Jun 08 16:11:51 2015 +0000 @@ -0,0 +1,96 @@ +=== Blog Copier === +Contributors: ModernTribe, peterchester +Donate Link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=TWM2GF6BQZGSN +Tags: copy, duplicate, replicate, blog, site, duplicator, replicator, moderntribe, tribe, wpmu, multisite, network, superadmin +Requires at least: 3.0 +Tested up to: 3.9.2 +Stable tag: 1.0.5 + +Enables superusers to copy existing sub blogs to new sub blogs. + +== Description == + +A simple and effective approach to copying blogs within a multisite network. + +* Copy a blog including all its widgets, template settings and more. +* Option to copy or not copy files. +* GUIDs and urls in post contents are migrated automatically. + +This plugin was derived from Ron Renneck's awesome WP Replicator (http://wpebooks.com/replicator/) plugin, although it's been 90% rewritten. Changes from the original include the following: + +* Improved performance on large scale blogs. +* Improved file copy performance and an option in the admin to bypass copying altogether. +* Removed limit of number of blogs that can be used as a copy source. +* Encapsulated the code in a Class and renamed variables to be more readable. +* Revised UI to keep it simple and easy to use. + +Sadly the WordPress file management code is not idea for handling the copying of a large folder with subdirectories so we opted to stick with exec('cp'). On the flip side, we set up a filter (copy_blog_files_command) so that you can override it with your own custom copy code. + +This plugin is actively supported and we will do our best to help you. In return we simply as 3 things: + +1. Help Out. If you see a question on the forum you can help with or have a great idea and want to code it up and submit a patch, that would be just plain awesome and we will shower your with praise. Might even be a good way to get to know us and lead to some paid work if you freelance. Also, we are happy to post translations if you provide them. +1. Donate - if this is generating enough revenue to support our time it makes all the difference in the world +https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=TWM2GF6BQZGSN +1. Support us by buying our Premium plugins. In particular, check out our Events Calendar Pro http://tri.be/wordpress-events-calendar-pro/ + +== Installation == + += Install = + +1. In your WordPress Network administration, go to the Plugins page +1. Activate this plugin and a subpage for the plugin will appear + in your Sites menu. + +Please visit the forum for questions or comments: http://wordpress.org/tags/blog-copier/ + += Requirements = + +* PHP 5.1 or above +* WordPress 3.0 or above +* Multisite activated with at least one sub-blog + +== Documentation == + +It's pretty straight forward. Select the blog you want to copy. Set a new domain or subdomain and a title. Decide if you want to copy the files or just the data. Click "Copy Now". Done. + +This DOES NOT copy blogs across networks, back up blogs off the network, or copy the master blog. This also does NOT copy users from one blog to another. + +== Changelog == + += 1.0.5 = + +* Fix error with directory based blog structure. + += 1.0.4 = + +* Handle the new uploads directory structure of networks created with WP 3.5+ + += 1.0.3 = + +* Fixed a wildcard table selection bug that was causing some real problems. +* Fixed a minor bug that caused required empty options to not get copied from the source blog. +* Remove superfluous db prepare() functions. +Thanks @jbrinley! + += 1.0.2 = + +Added .pot file. Anyone interested in submitting a translation??? http://wordpress.org/tags/blog-copier/ + += 1.0.1 = + +Minor documentation updates. + += 1.0 = + +Initial plugin release. Woohoo! + +== Screenshots == + +1. Blog Copier Screen +1. Sites "Copy" Option + +== Frequently Asked Questions == + += Where do I go to file a bug or ask a question? = + +Please visit the forum for questions or comments: http://wordpress.org/tags/blog-copier/ diff -r 6d22aaa62d12 -r 346c88efed21 wp/wp-content/plugins/blog-copier/screenshot-1.png Binary file wp/wp-content/plugins/blog-copier/screenshot-1.png has changed diff -r 6d22aaa62d12 -r 346c88efed21 wp/wp-content/plugins/blog-copier/screenshot-2.png Binary file wp/wp-content/plugins/blog-copier/screenshot-2.png has changed