├── .gitignore ├── README.md ├── composer.json ├── demo-files ├── .htaccess ├── content.xml ├── index.php ├── theme_options.txt └── widgets.json ├── example.php ├── importer ├── parsers.php ├── radium-importer.php └── wordpress-importer.php └── licence.txt /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /wp-content/ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Deprecated in favor of [OCDI plugin](https://github.com/proteusthemes/one-click-demo-import). 2 | ==================================== 3 | 4 | --- 5 | 6 | One Click Demo Install for WordPress Developers 7 | ---------------------------------------------- 8 | 9 | *Note: original script written by https://github.com/FrankM1/radium-one-click-demo-install.* 10 | 11 | This library works by importing wordpress content, widgets and theme options with just one click. 12 | 13 | ### Requirements: 14 | 15 | * WordPress Theme 16 | * `content.xml` - generated using the Worpress Content Exporter plugin. Upload it to your server. 17 | * `widgets.json` - generated using the Widget Importer Exporter plugin. Rename it from .wie to .json and upload it to your server. 18 | * `theme_options.txt` - generated using the theme options frameworks such as Redux Framework, NHP Options Framework or Radium Framework 19 | 20 | The new version v0.4.0 the script gets the demo data files (content.xml and widgets.json) from the server so you need to specify the URLs to these files: 21 | 22 | ``` 23 | public $content_demo_url = 'http://your_domain.com/path-to-file/content.xml'; 24 | public $widget_demo_url = 'http://your_domain.com/path-to-file/widgets.json'; 25 | ``` 26 | 27 | These files are then saved in the WordPress upload directory and used for demo import. 28 | 29 | 30 | ### How to use: 31 | 32 | Add `require_once( get_template_directory() . '/wordpress-one-click-demo-install/example.php' );` to your theme's `function.php`. 33 | 34 | Copy the files generated above into `demo-files/`. 35 | 36 | Modify what menus need to be loaded in the `Radium_Theme_Demo_Data_Importer` class located in `examle.php` as well as the theme options name to be used. 37 | 38 | A new menu should appear under ***Appearance » Import Demo Data***. 39 | 40 | Click the import button. 41 | 42 | That's it! 43 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "primozcigler/wordpress-one-click-demo-install", 3 | "description": "Once Click Demo Content Install for WordPress.", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Frank Gitonga" 8 | }, 9 | { 10 | "name": "Primoz Cigler", 11 | "email": "primoz@proteusnet.com" 12 | } 13 | ], 14 | "autoload": { 15 | "files": ["importer/radium-importer.php"] 16 | } 17 | } -------------------------------------------------------------------------------- /demo-files/.htaccess: -------------------------------------------------------------------------------- 1 | deny from all -------------------------------------------------------------------------------- /demo-files/content.xml: -------------------------------------------------------------------------------- 1 | This is a sample file. Export on one from Wordpress, give it the name "content.xml" replace. -------------------------------------------------------------------------------- /demo-files/index.php: -------------------------------------------------------------------------------- 1 | ","radium_widget_class":""},"radium_categories_widget-3":{"show_count":1,"title":"All Categories","selected_cats":null,"radium_widget_class":""}},"sidebar-5":{"radium_social_fans-2":{"title":"","animate":"","radium_widget_class":""},"radium_widgets_custom_banner-2":{"supertitle":"CUSTOM IMAGE BANNER","title":"Custom Banner","subtitle":"Nec malesuada faucibus lorem, ac consectetur neque varius sed.","imgurl":"http:\/\/cdn1.newscore.radiumthemes.com\/wp-content\/uploads\/2014\/04\/5101510772_9217f23388_o-1080x641-407x242.jpg","linkurl":"#","buttontext":"Custom Button","radium_widget_class":""},"radium_ad_widget-3":{"ad_code":"\"\"<\/a>\"\"<\/a>\"\"<\/a>\t","radium_widget_class":""},"radium_facebook_box_widget-3":{"title":"","appid":"","page":"envato","radium_widget_class":""},"radium_tweets-3":{"title":"Radium Tweets Plugin","tweetstoshow":"2","tweettext":"Follow Us","radium_widget_class":"blue"}},"sidebar-6":{"woocommerce_product_search-2":{"title":"Search Products","radium_widget_class":""},"woocommerce_price_filter-2":{"title":"Filter by price","radium_widget_class":""},"woocommerce_product_categories-2":{"title":"Product Categories","orderby":"name","dropdown":0,"count":"1","hierarchical":0,"show_children_only":0,"radium_widget_class":""},"woocommerce_recent_reviews-2":{"title":"Recent Reviews","number":"5","radium_widget_class":""}},"sidebar-7":{"video_central_search-2":{"title":"Search Videos","radium_widget_class":""},"video_central_recent_widget-2":{"title":"Recent Videos","number":"5","radium_widget_class":""},"video_central_popular_widget-4":{"title":"Popular Videos","number":"5","radium_widget_class":""}},"sidebar-8":{"text-3":{"title":"About","text":"We are a young and passionate news and development team from NY. We take pride in our work. Every feature was carefully chosen and designed to ease the way to that perfect news or magazine website.","filter":false,"radium_widget_class":""}},"sidebar-9":{"radium_widgets_custom_banner-3":{"supertitle":"CUSTOM IMAGE BANNER","title":"Custom Banner","subtitle":"Nec malesuada faucibus lorem, ac consectetur neque varius sed.","imgurl":"http:\/\/cdn1.newscore.radiumthemes.com\/wp-content\/uploads\/2014\/04\/5101510772_9217f23388_o-1080x641-407x242.jpg","linkurl":"#","buttontext":"Custom Button","radium_widget_class":""}},"sidebar-10":{"nav_menu-3":{"title":"","nav_menu":48,"radium_widget_class":""}},"sidebar-11":{"radium_newsletter-6":{"title":"Newsletter.","subscribecode":"#","placeholder":"Enter your email address...","desc":"This is a nice and simple email newsletter widget. Yuppers.","animate":"on","radium_widget_class":""}}} -------------------------------------------------------------------------------- /example.php: -------------------------------------------------------------------------------- 1 | demo_files_path = dirname(__FILE__) . '/demo-files/'; 50 | 51 | self::$instance = $this; 52 | parent::__construct(); 53 | 54 | } 55 | 56 | /** 57 | * Add menus 58 | * 59 | * @since 0.0.1 60 | */ 61 | public function set_demo_menus(){ 62 | 63 | // Menus to Import and assign - you can remove or add as many as you want 64 | $top_menu = get_term_by('name', 'Top Menu', 'nav_menu'); 65 | $main_menu = get_term_by('name', 'Main Menu', 'nav_menu'); 66 | $footer_menu = get_term_by('name', 'Main Menu', 'nav_menu'); 67 | 68 | set_theme_mod( 'nav_menu_locations', array( 69 | 'top-menu' => $top_menu->term_id, 70 | 'primary' => $main_menu->term_id, 71 | 'footer-menu' => $footer_menu->term_id 72 | ) 73 | ); 74 | } 75 | } 76 | 77 | new Radium_Theme_Demo_Data_Importer; -------------------------------------------------------------------------------- /importer/parsers.php: -------------------------------------------------------------------------------- 1 | parse( $file ); 18 | 19 | // If SimpleXML succeeds or this is an invalid WXR file then return the results 20 | if ( ! is_wp_error( $result ) || 'SimpleXML_parse_error' != $result->get_error_code() ) 21 | return $result; 22 | } else if ( extension_loaded( 'xml' ) ) { 23 | $parser = new WXR_Parser_XML; 24 | $result = $parser->parse( $file ); 25 | 26 | // If XMLParser succeeds or this is an invalid WXR file then return the results 27 | if ( ! is_wp_error( $result ) || 'XML_parse_error' != $result->get_error_code() ) 28 | return $result; 29 | } 30 | 31 | // We have a malformed XML file, so display the error and fallthrough to regex 32 | if ( isset($result) && defined('IMPORT_DEBUG') && IMPORT_DEBUG ) { 33 | echo '
';
 34 | 			if ( 'SimpleXML_parse_error' == $result->get_error_code() ) {
 35 | 				foreach  ( $result->get_error_data() as $error )
 36 | 					echo $error->line . ':' . $error->column . ' ' . esc_html( $error->message ) . "\n";
 37 | 			} else if ( 'XML_parse_error' == $result->get_error_code() ) {
 38 | 				$error = $result->get_error_data();
 39 | 				echo $error[0] . ':' . $error[1] . ' ' . esc_html( $error[2] );
 40 | 			}
 41 | 			echo '
'; 42 | echo '

' . esc_html__( 'There was an error when reading this WXR file', 'radium' ) . '
'; 43 | echo esc_html__( 'Details are shown above. The importer will now try again with a different parser...', 'radium' ) . '

'; 44 | } 45 | 46 | // use regular expressions if nothing else available or this is bad XML 47 | $parser = new WXR_Parser_Regex; 48 | return $parser->parse( $file ); 49 | } 50 | } 51 | 52 | class WP_FileSystem_Credentials { 53 | static function check_credentials() { 54 | // Get user credentials for WP filesystem API 55 | $demo_import_page_url = wp_nonce_url( 'themes.php?page=radium_demo_installer', 'radium_demo_installer' ); 56 | if ( false === ( $creds = request_filesystem_credentials( $demo_import_page_url, '', false, false, null ) ) ) { 57 | return new WP_Error( 'XML_parse_error', __( 'There was an error when reading this WXR file', 'wordpress-importer' ) ); 58 | } 59 | 60 | // Now we have credentials, try to get the wp_filesystem running 61 | if ( ! WP_Filesystem( $creds ) ) { 62 | // Our credentials were no good, ask the user for them again 63 | request_filesystem_credentials( $demo_import_page_url, '', true, false, null ); 64 | return true; 65 | } 66 | } 67 | } 68 | 69 | /** 70 | * WXR Parser that makes use of the SimpleXML PHP extension. 71 | */ 72 | class WXR_Parser_SimpleXML { 73 | function parse( $file ) { 74 | $authors = $posts = $categories = $tags = $terms = array(); 75 | 76 | $internal_errors = libxml_use_internal_errors(true); 77 | 78 | $dom = new DOMDocument; 79 | $old_value = null; 80 | if ( function_exists( 'libxml_disable_entity_loader' ) ) { 81 | $old_value = libxml_disable_entity_loader( true ); 82 | } 83 | 84 | WP_FileSystem_Credentials::check_credentials(); 85 | 86 | global $wp_filesystem; 87 | $success = $dom->loadXML( $wp_filesystem->get_contents( $file ) ); 88 | if ( ! is_null( $old_value ) ) { 89 | libxml_disable_entity_loader( $old_value ); 90 | } 91 | 92 | if ( ! $success || isset( $dom->doctype ) ) { 93 | return new WP_Error( 'SimpleXML_parse_error', __( 'There was an error when reading this WXR file', 'wordpress-importer' ), libxml_get_errors() ); 94 | } 95 | 96 | $xml = simplexml_import_dom( $dom ); 97 | unset( $dom ); 98 | 99 | // halt if loading produces an error 100 | if ( ! $xml ) 101 | return new WP_Error( 'SimpleXML_parse_error', esc_html__( 'There was an error when reading this WXR file', 'radium' ), libxml_get_errors() ); 102 | 103 | $wxr_version = $xml->xpath('/rss/channel/wp:wxr_version'); 104 | if ( ! $wxr_version ) 105 | return new WP_Error( 'WXR_parse_error', esc_html__( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'radium' ) ); 106 | 107 | $wxr_version = (string) trim( $wxr_version[0] ); 108 | // confirm that we are dealing with the correct file format 109 | if ( ! preg_match( '/^\d+\.\d+$/', $wxr_version ) ) 110 | return new WP_Error( 'WXR_parse_error', esc_html__( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'radium' ) ); 111 | 112 | $base_url = $xml->xpath('/rss/channel/wp:base_site_url'); 113 | $base_url = (string) trim( $base_url[0] ); 114 | 115 | $namespaces = $xml->getDocNamespaces(); 116 | if ( ! isset( $namespaces['wp'] ) ) 117 | $namespaces['wp'] = 'http://wordpress.org/export/1.1/'; 118 | if ( ! isset( $namespaces['excerpt'] ) ) 119 | $namespaces['excerpt'] = 'http://wordpress.org/export/1.1/excerpt/'; 120 | 121 | // grab authors 122 | foreach ( $xml->xpath('/rss/channel/wp:author') as $author_arr ) { 123 | $a = $author_arr->children( $namespaces['wp'] ); 124 | $login = (string) $a->author_login; 125 | $authors[$login] = array( 126 | 'author_id' => (int) $a->author_id, 127 | 'author_login' => $login, 128 | 'author_email' => (string) $a->author_email, 129 | 'author_display_name' => (string) $a->author_display_name, 130 | 'author_first_name' => (string) $a->author_first_name, 131 | 'author_last_name' => (string) $a->author_last_name 132 | ); 133 | } 134 | 135 | // grab cats, tags and terms 136 | foreach ( $xml->xpath('/rss/channel/wp:category') as $term_arr ) { 137 | $t = $term_arr->children( $namespaces['wp'] ); 138 | $categories[] = array( 139 | 'term_id' => (int) $t->term_id, 140 | 'category_nicename' => (string) $t->category_nicename, 141 | 'category_parent' => (string) $t->category_parent, 142 | 'cat_name' => (string) $t->cat_name, 143 | 'category_description' => (string) $t->category_description 144 | ); 145 | } 146 | 147 | foreach ( $xml->xpath('/rss/channel/wp:tag') as $term_arr ) { 148 | $t = $term_arr->children( $namespaces['wp'] ); 149 | $tags[] = array( 150 | 'term_id' => (int) $t->term_id, 151 | 'tag_slug' => (string) $t->tag_slug, 152 | 'tag_name' => (string) $t->tag_name, 153 | 'tag_description' => (string) $t->tag_description 154 | ); 155 | } 156 | 157 | foreach ( $xml->xpath('/rss/channel/wp:term') as $term_arr ) { 158 | $t = $term_arr->children( $namespaces['wp'] ); 159 | $terms[] = array( 160 | 'term_id' => (int) $t->term_id, 161 | 'term_taxonomy' => (string) $t->term_taxonomy, 162 | 'slug' => (string) $t->term_slug, 163 | 'term_parent' => (string) $t->term_parent, 164 | 'term_name' => (string) $t->term_name, 165 | 'term_description' => (string) $t->term_description 166 | ); 167 | } 168 | 169 | // grab posts 170 | foreach ( $xml->channel->item as $item ) { 171 | $post = array( 172 | 'post_title' => (string) $item->title, 173 | 'guid' => (string) $item->guid, 174 | ); 175 | 176 | $dc = $item->children( 'http://purl.org/dc/elements/1.1/' ); 177 | $post['post_author'] = (string) $dc->creator; 178 | 179 | $content = $item->children( 'http://purl.org/rss/1.0/modules/content/' ); 180 | $excerpt = $item->children( $namespaces['excerpt'] ); 181 | $post['post_content'] = (string) $content->encoded; 182 | $post['post_excerpt'] = (string) $excerpt->encoded; 183 | 184 | $wp = $item->children( $namespaces['wp'] ); 185 | $post['post_id'] = (int) $wp->post_id; 186 | $post['post_date'] = (string) $wp->post_date; 187 | $post['post_date_gmt'] = (string) $wp->post_date_gmt; 188 | $post['comment_status'] = (string) $wp->comment_status; 189 | $post['ping_status'] = (string) $wp->ping_status; 190 | $post['post_name'] = (string) $wp->post_name; 191 | $post['status'] = (string) $wp->status; 192 | $post['post_parent'] = (int) $wp->post_parent; 193 | $post['menu_order'] = (int) $wp->menu_order; 194 | $post['post_type'] = (string) $wp->post_type; 195 | $post['post_password'] = (string) $wp->post_password; 196 | $post['is_sticky'] = (int) $wp->is_sticky; 197 | 198 | if ( isset($wp->attachment_url) ) 199 | $post['attachment_url'] = (string) $wp->attachment_url; 200 | 201 | foreach ( $item->category as $c ) { 202 | $att = $c->attributes(); 203 | if ( isset( $att['nicename'] ) ) 204 | $post['terms'][] = array( 205 | 'name' => (string) $c, 206 | 'slug' => (string) $att['nicename'], 207 | 'domain' => (string) $att['domain'] 208 | ); 209 | } 210 | 211 | foreach ( $wp->postmeta as $meta ) { 212 | $post['postmeta'][] = array( 213 | 'key' => (string) $meta->meta_key, 214 | 'value' => (string) $meta->meta_value 215 | ); 216 | } 217 | 218 | foreach ( $wp->comment as $comment ) { 219 | $meta = array(); 220 | if ( isset( $comment->commentmeta ) ) { 221 | foreach ( $comment->commentmeta as $m ) { 222 | $meta[] = array( 223 | 'key' => (string) $m->meta_key, 224 | 'value' => (string) $m->meta_value 225 | ); 226 | } 227 | } 228 | 229 | $post['comments'][] = array( 230 | 'comment_id' => (int) $comment->comment_id, 231 | 'comment_author' => (string) $comment->comment_author, 232 | 'comment_author_email' => (string) $comment->comment_author_email, 233 | 'comment_author_IP' => (string) $comment->comment_author_IP, 234 | 'comment_author_url' => (string) $comment->comment_author_url, 235 | 'comment_date' => (string) $comment->comment_date, 236 | 'comment_date_gmt' => (string) $comment->comment_date_gmt, 237 | 'comment_content' => (string) $comment->comment_content, 238 | 'comment_approved' => (string) $comment->comment_approved, 239 | 'comment_type' => (string) $comment->comment_type, 240 | 'comment_parent' => (string) $comment->comment_parent, 241 | 'comment_user_id' => (int) $comment->comment_user_id, 242 | 'commentmeta' => $meta, 243 | ); 244 | } 245 | 246 | $posts[] = $post; 247 | } 248 | 249 | return array( 250 | 'authors' => $authors, 251 | 'posts' => $posts, 252 | 'categories' => $categories, 253 | 'tags' => $tags, 254 | 'terms' => $terms, 255 | 'base_url' => $base_url, 256 | 'version' => $wxr_version 257 | ); 258 | } 259 | } 260 | 261 | /** 262 | * WXR Parser that makes use of the XML Parser PHP extension. 263 | */ 264 | class WXR_Parser_XML { 265 | var $wp_tags = array( 266 | 'wp:post_id', 'wp:post_date', 'wp:post_date_gmt', 'wp:comment_status', 'wp:ping_status', 'wp:attachment_url', 267 | 'wp:status', 'wp:post_name', 'wp:post_parent', 'wp:menu_order', 'wp:post_type', 'wp:post_password', 268 | 'wp:is_sticky', 'wp:term_id', 'wp:category_nicename', 'wp:category_parent', 'wp:cat_name', 'wp:category_description', 269 | 'wp:tag_slug', 'wp:tag_name', 'wp:tag_description', 'wp:term_taxonomy', 'wp:term_parent', 270 | 'wp:term_name', 'wp:term_description', 'wp:author_id', 'wp:author_login', 'wp:author_email', 'wp:author_display_name', 271 | 'wp:author_first_name', 'wp:author_last_name', 272 | ); 273 | var $wp_sub_tags = array( 274 | 'wp:comment_id', 'wp:comment_author', 'wp:comment_author_email', 'wp:comment_author_url', 275 | 'wp:comment_author_IP', 'wp:comment_date', 'wp:comment_date_gmt', 'wp:comment_content', 276 | 'wp:comment_approved', 'wp:comment_type', 'wp:comment_parent', 'wp:comment_user_id', 277 | ); 278 | 279 | function parse( $file ) { 280 | $this->wxr_version = $this->in_post = $this->cdata = $this->data = $this->sub_data = $this->in_tag = $this->in_sub_tag = false; 281 | $this->authors = $this->posts = $this->term = $this->category = $this->tag = array(); 282 | 283 | $xml = xml_parser_create( 'UTF-8' ); 284 | xml_parser_set_option( $xml, XML_OPTION_SKIP_WHITE, 1 ); 285 | xml_parser_set_option( $xml, XML_OPTION_CASE_FOLDING, 0 ); 286 | xml_set_object( $xml, $this ); 287 | xml_set_character_data_handler( $xml, 'cdata' ); 288 | xml_set_element_handler( $xml, 'tag_open', 'tag_close' ); 289 | 290 | WP_FileSystem_Credentials::check_credentials(); 291 | 292 | global $wp_filesystem; 293 | if ( ! xml_parse( $xml, $wp_filesystem->get_contents( $file ), true ) ) { 294 | $current_line = xml_get_current_line_number( $xml ); 295 | $current_column = xml_get_current_column_number( $xml ); 296 | $error_code = xml_get_error_code( $xml ); 297 | $error_string = xml_error_string( $error_code ); 298 | return new WP_Error( 'XML_parse_error', 'There was an error when reading this WXR file', array( $current_line, $current_column, $error_string ) ); 299 | } 300 | xml_parser_free( $xml ); 301 | 302 | if ( ! preg_match( '/^\d+\.\d+$/', $this->wxr_version ) ) 303 | return new WP_Error( 'WXR_parse_error', esc_html__( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'radium' ) ); 304 | 305 | return array( 306 | 'authors' => $this->authors, 307 | 'posts' => $this->posts, 308 | 'categories' => $this->category, 309 | 'tags' => $this->tag, 310 | 'terms' => $this->term, 311 | 'base_url' => $this->base_url, 312 | 'version' => $this->wxr_version 313 | ); 314 | } 315 | 316 | function tag_open( $parse, $tag, $attr ) { 317 | if ( in_array( $tag, $this->wp_tags ) ) { 318 | $this->in_tag = substr( $tag, 3 ); 319 | return; 320 | } 321 | 322 | if ( in_array( $tag, $this->wp_sub_tags ) ) { 323 | $this->in_sub_tag = substr( $tag, 3 ); 324 | return; 325 | } 326 | 327 | switch ( $tag ) { 328 | case 'category': 329 | if ( isset($attr['domain'], $attr['nicename']) ) { 330 | $this->sub_data['domain'] = $attr['domain']; 331 | $this->sub_data['slug'] = $attr['nicename']; 332 | } 333 | break; 334 | case 'item': $this->in_post = true; 335 | case 'title': if ( $this->in_post ) $this->in_tag = 'post_title'; break; 336 | case 'guid': $this->in_tag = 'guid'; break; 337 | case 'dc:creator': $this->in_tag = 'post_author'; break; 338 | case 'content:encoded': $this->in_tag = 'post_content'; break; 339 | case 'excerpt:encoded': $this->in_tag = 'post_excerpt'; break; 340 | 341 | case 'wp:term_slug': $this->in_tag = 'slug'; break; 342 | case 'wp:meta_key': $this->in_sub_tag = 'key'; break; 343 | case 'wp:meta_value': $this->in_sub_tag = 'value'; break; 344 | } 345 | } 346 | 347 | function cdata( $parser, $cdata ) { 348 | if ( ! trim( $cdata ) ) 349 | return; 350 | 351 | $this->cdata .= trim( $cdata ); 352 | } 353 | 354 | function tag_close( $parser, $tag ) { 355 | switch ( $tag ) { 356 | case 'wp:comment': 357 | unset( $this->sub_data['key'], $this->sub_data['value'] ); // remove meta sub_data 358 | if ( ! empty( $this->sub_data ) ) 359 | $this->data['comments'][] = $this->sub_data; 360 | $this->sub_data = false; 361 | break; 362 | case 'wp:commentmeta': 363 | $this->sub_data['commentmeta'][] = array( 364 | 'key' => $this->sub_data['key'], 365 | 'value' => $this->sub_data['value'] 366 | ); 367 | break; 368 | case 'category': 369 | if ( ! empty( $this->sub_data ) ) { 370 | $this->sub_data['name'] = $this->cdata; 371 | $this->data['terms'][] = $this->sub_data; 372 | } 373 | $this->sub_data = false; 374 | break; 375 | case 'wp:postmeta': 376 | if ( ! empty( $this->sub_data ) ) 377 | $this->data['postmeta'][] = $this->sub_data; 378 | $this->sub_data = false; 379 | break; 380 | case 'item': 381 | $this->posts[] = $this->data; 382 | $this->data = false; 383 | break; 384 | case 'wp:category': 385 | case 'wp:tag': 386 | case 'wp:term': 387 | $n = substr( $tag, 3 ); 388 | array_push( $this->$n, $this->data ); 389 | $this->data = false; 390 | break; 391 | case 'wp:author': 392 | if ( ! empty($this->data['author_login']) ) 393 | $this->authors[$this->data['author_login']] = $this->data; 394 | $this->data = false; 395 | break; 396 | case 'wp:base_site_url': 397 | $this->base_url = $this->cdata; 398 | break; 399 | case 'wp:wxr_version': 400 | $this->wxr_version = $this->cdata; 401 | break; 402 | 403 | default: 404 | if ( $this->in_sub_tag ) { 405 | $this->sub_data[$this->in_sub_tag] = ! empty( $this->cdata ) ? $this->cdata : ''; 406 | $this->in_sub_tag = false; 407 | } else if ( $this->in_tag ) { 408 | $this->data[$this->in_tag] = ! empty( $this->cdata ) ? $this->cdata : ''; 409 | $this->in_tag = false; 410 | } 411 | } 412 | 413 | $this->cdata = false; 414 | } 415 | } 416 | 417 | /** 418 | * WXR Parser that uses regular expressions. Fallback for installs without an XML parser. 419 | */ 420 | class WXR_Parser_Regex { 421 | var $authors = array(); 422 | var $posts = array(); 423 | var $categories = array(); 424 | var $tags = array(); 425 | var $terms = array(); 426 | var $base_url = ''; 427 | 428 | function __construct() { 429 | $this->has_gzip = is_callable( 'gzopen' ); 430 | } 431 | 432 | function WXR_Parser_Regex() { 433 | $this->__construct(); 434 | } 435 | 436 | function parse( $file ) { 437 | $wxr_version = $in_post = false; 438 | 439 | $fp = $this->open_file( $file, 'r' ); 440 | if ( $fp ) { 441 | while ( ! $this->feof( $fp ) ) { 442 | $importline = rtrim( $this->fgets( $fp ) ); 443 | 444 | if ( ! $wxr_version && preg_match( '|(\d+\.\d+)|', $importline, $version ) ) 445 | $wxr_version = $version[1]; 446 | 447 | if ( false !== strpos( $importline, '' ) ) { 448 | preg_match( '|(.*?)|is', $importline, $url ); 449 | $this->base_url = $url[1]; 450 | continue; 451 | } 452 | if ( false !== strpos( $importline, '' ) ) { 453 | preg_match( '|(.*?)|is', $importline, $category ); 454 | $this->categories[] = $this->process_category( $category[1] ); 455 | continue; 456 | } 457 | if ( false !== strpos( $importline, '' ) ) { 458 | preg_match( '|(.*?)|is', $importline, $tag ); 459 | $this->tags[] = $this->process_tag( $tag[1] ); 460 | continue; 461 | } 462 | if ( false !== strpos( $importline, '' ) ) { 463 | preg_match( '|(.*?)|is', $importline, $term ); 464 | $this->terms[] = $this->process_term( $term[1] ); 465 | continue; 466 | } 467 | if ( false !== strpos( $importline, '' ) ) { 468 | preg_match( '|(.*?)|is', $importline, $author ); 469 | $a = $this->process_author( $author[1] ); 470 | $this->authors[$a['author_login']] = $a; 471 | continue; 472 | } 473 | if ( false !== strpos( $importline, '' ) ) { 474 | $post = ''; 475 | $in_post = true; 476 | continue; 477 | } 478 | if ( false !== strpos( $importline, '' ) ) { 479 | $in_post = false; 480 | $this->posts[] = $this->process_post( $post ); 481 | continue; 482 | } 483 | if ( $in_post ) { 484 | $post .= $importline . "\n"; 485 | } 486 | } 487 | 488 | $this->close_file($fp); 489 | } 490 | 491 | if ( ! $wxr_version ) 492 | return new WP_Error( 'WXR_parse_error', esc_html__( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'radium' ) ); 493 | 494 | return array( 495 | 'authors' => $this->authors, 496 | 'posts' => $this->posts, 497 | 'categories' => $this->categories, 498 | 'tags' => $this->tags, 499 | 'terms' => $this->terms, 500 | 'base_url' => $this->base_url, 501 | 'version' => $wxr_version 502 | ); 503 | } 504 | 505 | function get_tag( $string, $tag ) { 506 | preg_match( "|<$tag.*?>(.*?)|is", $string, $return ); 507 | if ( isset( $return[1] ) ) { 508 | if ( substr( $return[1], 0, 9 ) == '' ) !== false ) { 510 | preg_match_all( '||s', $return[1], $matches ); 511 | $return = ''; 512 | foreach( $matches[1] as $match ) 513 | $return .= $match; 514 | } else { 515 | $return = preg_replace( '|^$|s', '$1', $return[1] ); 516 | } 517 | } else { 518 | $return = $return[1]; 519 | } 520 | } else { 521 | $return = ''; 522 | } 523 | return $return; 524 | } 525 | 526 | function process_category( $c ) { 527 | return array( 528 | 'term_id' => $this->get_tag( $c, 'wp:term_id' ), 529 | 'cat_name' => $this->get_tag( $c, 'wp:cat_name' ), 530 | 'category_nicename' => $this->get_tag( $c, 'wp:category_nicename' ), 531 | 'category_parent' => $this->get_tag( $c, 'wp:category_parent' ), 532 | 'category_description' => $this->get_tag( $c, 'wp:category_description' ), 533 | ); 534 | } 535 | 536 | function process_tag( $t ) { 537 | return array( 538 | 'term_id' => $this->get_tag( $t, 'wp:term_id' ), 539 | 'tag_name' => $this->get_tag( $t, 'wp:tag_name' ), 540 | 'tag_slug' => $this->get_tag( $t, 'wp:tag_slug' ), 541 | 'tag_description' => $this->get_tag( $t, 'wp:tag_description' ), 542 | ); 543 | } 544 | 545 | function process_term( $t ) { 546 | return array( 547 | 'term_id' => $this->get_tag( $t, 'wp:term_id' ), 548 | 'term_taxonomy' => $this->get_tag( $t, 'wp:term_taxonomy' ), 549 | 'slug' => $this->get_tag( $t, 'wp:term_slug' ), 550 | 'term_parent' => $this->get_tag( $t, 'wp:term_parent' ), 551 | 'term_name' => $this->get_tag( $t, 'wp:term_name' ), 552 | 'term_description' => $this->get_tag( $t, 'wp:term_description' ), 553 | ); 554 | } 555 | 556 | function process_author( $a ) { 557 | return array( 558 | 'author_id' => $this->get_tag( $a, 'wp:author_id' ), 559 | 'author_login' => $this->get_tag( $a, 'wp:author_login' ), 560 | 'author_email' => $this->get_tag( $a, 'wp:author_email' ), 561 | 'author_display_name' => $this->get_tag( $a, 'wp:author_display_name' ), 562 | 'author_first_name' => $this->get_tag( $a, 'wp:author_first_name' ), 563 | 'author_last_name' => $this->get_tag( $a, 'wp:author_last_name' ), 564 | ); 565 | } 566 | 567 | function process_post( $post ) { 568 | $post_id = $this->get_tag( $post, 'wp:post_id' ); 569 | $post_title = $this->get_tag( $post, 'title' ); 570 | $post_date = $this->get_tag( $post, 'wp:post_date' ); 571 | $post_date_gmt = $this->get_tag( $post, 'wp:post_date_gmt' ); 572 | $comment_status = $this->get_tag( $post, 'wp:comment_status' ); 573 | $ping_status = $this->get_tag( $post, 'wp:ping_status' ); 574 | $status = $this->get_tag( $post, 'wp:status' ); 575 | $post_name = $this->get_tag( $post, 'wp:post_name' ); 576 | $post_parent = $this->get_tag( $post, 'wp:post_parent' ); 577 | $menu_order = $this->get_tag( $post, 'wp:menu_order' ); 578 | $post_type = $this->get_tag( $post, 'wp:post_type' ); 579 | $post_password = $this->get_tag( $post, 'wp:post_password' ); 580 | $is_sticky = $this->get_tag( $post, 'wp:is_sticky' ); 581 | $guid = $this->get_tag( $post, 'guid' ); 582 | $post_author = $this->get_tag( $post, 'dc:creator' ); 583 | 584 | $post_excerpt = $this->get_tag( $post, 'excerpt:encoded' ); 585 | $post_excerpt = preg_replace_callback( '|<(/?[A-Z]+)|', array( &$this, '_normalize_tag' ), $post_excerpt ); 586 | $post_excerpt = str_replace( '
', '
', $post_excerpt ); 587 | $post_excerpt = str_replace( '
', '
', $post_excerpt ); 588 | 589 | $post_content = $this->get_tag( $post, 'content:encoded' ); 590 | $post_content = preg_replace_callback( '|<(/?[A-Z]+)|', array( &$this, '_normalize_tag' ), $post_content ); 591 | $post_content = str_replace( '
', '
', $post_content ); 592 | $post_content = str_replace( '
', '
', $post_content ); 593 | 594 | $postdata = compact( 'post_id', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_excerpt', 595 | 'post_title', 'status', 'post_name', 'comment_status', 'ping_status', 'guid', 'post_parent', 596 | 'menu_order', 'post_type', 'post_password', 'is_sticky' 597 | ); 598 | 599 | $attachment_url = $this->get_tag( $post, 'wp:attachment_url' ); 600 | if ( $attachment_url ) 601 | $postdata['attachment_url'] = $attachment_url; 602 | 603 | preg_match_all( '|(.+?)|is', $post, $terms, PREG_SET_ORDER ); 604 | foreach ( $terms as $t ) { 605 | $post_terms[] = array( 606 | 'slug' => $t[2], 607 | 'domain' => $t[1], 608 | 'name' => str_replace( array( '' ), '', $t[3] ), 609 | ); 610 | } 611 | if ( ! empty( $post_terms ) ) $postdata['terms'] = $post_terms; 612 | 613 | preg_match_all( '|(.+?)|is', $post, $comments ); 614 | $comments = $comments[1]; 615 | if ( $comments ) { 616 | foreach ( $comments as $comment ) { 617 | preg_match_all( '|(.+?)|is', $comment, $commentmeta ); 618 | $commentmeta = $commentmeta[1]; 619 | $c_meta = array(); 620 | foreach ( $commentmeta as $m ) { 621 | $c_meta[] = array( 622 | 'key' => $this->get_tag( $m, 'wp:meta_key' ), 623 | 'value' => $this->get_tag( $m, 'wp:meta_value' ), 624 | ); 625 | } 626 | 627 | $post_comments[] = array( 628 | 'comment_id' => $this->get_tag( $comment, 'wp:comment_id' ), 629 | 'comment_author' => $this->get_tag( $comment, 'wp:comment_author' ), 630 | 'comment_author_email' => $this->get_tag( $comment, 'wp:comment_author_email' ), 631 | 'comment_author_IP' => $this->get_tag( $comment, 'wp:comment_author_IP' ), 632 | 'comment_author_url' => $this->get_tag( $comment, 'wp:comment_author_url' ), 633 | 'comment_date' => $this->get_tag( $comment, 'wp:comment_date' ), 634 | 'comment_date_gmt' => $this->get_tag( $comment, 'wp:comment_date_gmt' ), 635 | 'comment_content' => $this->get_tag( $comment, 'wp:comment_content' ), 636 | 'comment_approved' => $this->get_tag( $comment, 'wp:comment_approved' ), 637 | 'comment_type' => $this->get_tag( $comment, 'wp:comment_type' ), 638 | 'comment_parent' => $this->get_tag( $comment, 'wp:comment_parent' ), 639 | 'comment_user_id' => $this->get_tag( $comment, 'wp:comment_user_id' ), 640 | 'commentmeta' => $c_meta, 641 | ); 642 | } 643 | } 644 | if ( ! empty( $post_comments ) ) $postdata['comments'] = $post_comments; 645 | 646 | preg_match_all( '|(.+?)|is', $post, $postmeta ); 647 | $postmeta = $postmeta[1]; 648 | if ( $postmeta ) { 649 | foreach ( $postmeta as $p ) { 650 | $post_postmeta[] = array( 651 | 'key' => $this->get_tag( $p, 'wp:meta_key' ), 652 | 'value' => $this->get_tag( $p, 'wp:meta_value' ), 653 | ); 654 | } 655 | } 656 | if ( ! empty( $post_postmeta ) ) $postdata['postmeta'] = $post_postmeta; 657 | 658 | return $postdata; 659 | } 660 | 661 | function _normalize_tag( $matches ) { 662 | return '<' . strtolower( $matches[1] ); 663 | } 664 | 665 | function open_file( $filename, $mode = 'r' ) { 666 | if ( $this->has_gzip ) 667 | return gzopen( $filename, $mode ); 668 | 669 | WP_FileSystem_Credentials::check_credentials(); 670 | 671 | global $wp_filesystem; 672 | return $wp_filesystem->get_contents( $filename ); 673 | } 674 | 675 | function feof( $fp ) { 676 | if ( $this->has_gzip ) 677 | return gzeof( $fp ); 678 | return feof( $fp ); 679 | } 680 | 681 | function fgets( $fp, $len = 8192 ) { 682 | if ( $this->has_gzip ) 683 | return gzgets( $fp, $len ); 684 | return fgets( $fp, $len ); 685 | } 686 | 687 | function close_file( $fp ) { 688 | if ( $this->has_gzip ) 689 | return gzclose( $fp ); 690 | } 691 | } 692 | -------------------------------------------------------------------------------- /importer/radium-importer.php: -------------------------------------------------------------------------------- 1 | theme_options_file = $this->demo_files_path . $this->theme_options_file_name; 73 | $this->widgets = $this->demo_files_path . $this->widgets_file_name; 74 | $this->content_demo = $this->demo_files_path . $this->content_demo_file_name; 75 | 76 | add_action( 'admin_menu', array($this, 'add_admin') ); 77 | 78 | } 79 | 80 | /** 81 | * Add Panel Page 82 | * 83 | * @since 2.2.0 84 | */ 85 | public function add_admin() { 86 | 87 | add_theme_page("Import Demo Data", "Import Demo Data", 'switch_themes', 'radium_demo_installer', array($this, 'demo_installer')); 88 | 89 | } 90 | 91 | /** 92 | * [demo_installer description] 93 | * 94 | * @since 2.2.0 95 | * 96 | * @return [type] [description] 97 | */ 98 | public function demo_installer() { 99 | ?> 100 |
101 |

Import Demo Data

102 |
103 |

Importing demo data (post, pages, images, theme settings, ...) is the easiest way to setup your theme. It will allow you to quickly edit everything instead of creating content from scratch. When you import the data following things will happen:

104 | 105 |
    106 |
  • No existing posts, pages, categories, images, custom post types or any other data will be deleted or modified .
  • 107 |
  • No WordPress settings will be modified .
  • 108 |
  • Posts, pages, some images, some widgets and menus will get imported .
  • 109 |
  • Images will be downloaded from our server, these images are copyrighted and are for demo use only .
  • 110 |
  • Please click import only once and wait, it can take a couple of minutes
  • 111 |
112 |
113 | 114 |
115 |

Before you begin, make sure all the required plugins are activated.

116 |
117 |
118 | 119 | 120 | 121 |
122 | 123 | 132 | 133 |
134 |
135 |
136 | 137 | get_demo_content_data_files( $this->content_demo_url , $this->content_demo_file_name ); 145 | 146 | $this->set_demo_data( $this->content_demo ); 147 | 148 | $this->set_demo_theme_options( $this->theme_options_file ); //import before widgets incase we need more sidebars 149 | 150 | $this->set_demo_menus(); 151 | 152 | // Get widgets demo data file from the server 153 | $this->get_demo_content_data_files( $this->widget_demo_url, $this->widgets_file_name ); 154 | 155 | $this->process_widget_import_file( $this->widgets ); 156 | 157 | } 158 | 159 | } 160 | 161 | /** 162 | * get_demo_content_data_files Get demo data file defined in $file 163 | * from the server and save it in the uploads directory 164 | * @param string $file File name of the file to fetch from the server 165 | * 166 | * @return null 167 | */ 168 | public function get_demo_content_data_files( $url, $file ) { 169 | // Test if the URL to the file is defined 170 | if ( empty( $url ) ) { 171 | wp_die( printf( wp_kses_post( __( '

An error occurred! URL for %s is not defined!

Please try to manually import the demo data. Here are instructions on how to do that: Documentation: Import XML File

', 'radium' ) ), $file, apply_filters( 'wpoci_docs_url', 'https://www.proteusthemes.com/docs/cargopress-pt/#import-xml-file' ) ) ); 172 | } 173 | 174 | // Get file contents from the server 175 | $response = wp_remote_get( $url ); 176 | if ( ! is_wp_error( $response ) && 200 === $response['response']['code'] ) { 177 | $response_body = wp_remote_retrieve_body( $response ); 178 | } 179 | else { 180 | wp_die( printf( wp_kses_post( __( '

An error occurred while fetching %s from the server!

Reason: %s - %s

Please try to manually import the demo data. Here are instructions on how to do that: Documentation: Import XML File

', 'radium' ) ), $file, $response->get_error_code(), $response->get_error_message(), apply_filters( 'wpoci_docs_url', 'https://www.proteusthemes.com/docs/cargopress-pt/#import-xml-file' ) ) ); 181 | } 182 | 183 | // Get user credentials for WP filesystem API 184 | $demo_import_page_url = wp_nonce_url( 'themes.php?page=radium_demo_installer', 'radium_demo_installer' ); 185 | if ( false === ( $creds = request_filesystem_credentials( $demo_import_page_url, '', false, false, null ) ) ) { 186 | return true; 187 | } 188 | 189 | // Now we have credentials, try to get the wp_filesystem running 190 | if ( ! WP_Filesystem( $creds ) ) { 191 | // Our credentials were no good, ask the user for them again 192 | request_filesystem_credentials( $demo_import_page_url, '', true, false, null ); 193 | return true; 194 | } 195 | 196 | // Setup filename path to save the content from 197 | $filename = $this->demo_files_path . $file; 198 | 199 | // By this point, the $wp_filesystem global should be working, so let's use it to create a file 200 | global $wp_filesystem; 201 | if ( ! $wp_filesystem->put_contents( $filename, $response_body, FS_CHMOD_FILE ) ) { 202 | wp_die( printf( wp_kses_post( __( '

An error occurred while writing file %s to the upload directory!

Please try to manually import the demo data. Here are instructions on how to do that: Documentation: Import XML File

', 'radium' ) ), $file, apply_filters( 'wpoci_docs_url', 'https://www.proteusthemes.com/docs/cargopress-pt/#import-xml-file' ) ) ); 203 | } 204 | } 205 | 206 | /** 207 | * add_widget_to_sidebar Import sidebars 208 | * @param string $sidebar_slug Sidebar slug to add widget 209 | * @param string $widget_slug Widget slug 210 | * @param string $count_mod position in sidebar 211 | * @param array $widget_settings widget settings 212 | * 213 | * @since 2.2.0 214 | * 215 | * @return null 216 | */ 217 | public function add_widget_to_sidebar($sidebar_slug, $widget_slug, $count_mod, $widget_settings = array()){ 218 | 219 | $sidebars_widgets = get_option('sidebars_widgets'); 220 | 221 | if(!isset($sidebars_widgets[$sidebar_slug])) 222 | $sidebars_widgets[$sidebar_slug] = array('_multiwidget' => 1); 223 | 224 | $newWidget = get_option('widget_'.$widget_slug); 225 | 226 | if(!is_array($newWidget)) 227 | $newWidget = array(); 228 | 229 | $count = count($newWidget)+1+$count_mod; 230 | $sidebars_widgets[$sidebar_slug][] = $widget_slug.'-'.$count; 231 | 232 | $newWidget[$count] = $widget_settings; 233 | 234 | update_option('sidebars_widgets', $sidebars_widgets); 235 | update_option('widget_'.$widget_slug, $newWidget); 236 | 237 | } 238 | 239 | public function set_demo_data( $file ) { 240 | 241 | if ( !defined('WP_LOAD_IMPORTERS') ) define('WP_LOAD_IMPORTERS', true); 242 | 243 | require_once ABSPATH . 'wp-admin/includes/import.php'; 244 | 245 | $importer_error = false; 246 | 247 | if ( !class_exists( 'WP_Importer' ) ) { 248 | 249 | $class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php'; 250 | 251 | if ( file_exists( $class_wp_importer ) ){ 252 | 253 | require_once($class_wp_importer); 254 | 255 | } else { 256 | 257 | $importer_error = true; 258 | 259 | } 260 | 261 | } 262 | 263 | if ( !class_exists( 'WP_Import' ) ) { 264 | 265 | $class_wp_import = dirname( __FILE__ ) .'/wordpress-importer.php'; 266 | 267 | if ( file_exists( $class_wp_import ) ) 268 | require_once($class_wp_import); 269 | else 270 | $importer_error = true; 271 | 272 | } 273 | 274 | if($importer_error){ 275 | 276 | die("Error on import"); 277 | 278 | } else { 279 | 280 | if(!is_file( $file )){ 281 | 282 | echo "The XML file containing the dummy content is not available or could not be read .. You might want to try to set the file permission to chmod 755.
If this doesn't work please use the Wordpress importer and import the XML file (should be located in your download .zip: Sample Content folder) manually "; 283 | 284 | } else { 285 | 286 | $wp_import = new WP_Import(); 287 | $wp_import->fetch_attachments = true; 288 | $wp_import->import( $file ); 289 | 290 | } 291 | 292 | } 293 | 294 | } 295 | 296 | public function set_demo_menus() {} 297 | 298 | public function set_demo_theme_options( $file ) { 299 | 300 | // File exists? 301 | if ( ! file_exists( $file ) ) { 302 | wp_die( 303 | esc_html__( 'Theme options Import file could not be found. Please try again.', 'radium' ), 304 | '', 305 | array( 'back_link' => true ) 306 | ); 307 | } 308 | 309 | // Get file contents and decode 310 | global $wp_filesystem; 311 | $data = $wp_filesystem->get_contents( $file ); 312 | 313 | $data = unserialize( trim($data, '###') ); 314 | 315 | // Have valid data? 316 | // If no data or could not decode 317 | if ( empty( $data ) || ! is_array( $data ) ) { 318 | wp_die( 319 | esc_html__( 'Theme options import data could not be read. Please try a different file.', 'radium' ), 320 | '', 321 | array( 'back_link' => true ) 322 | ); 323 | } 324 | 325 | // Hook before import 326 | $data = apply_filters( 'radium_theme_import_theme_options', $data ); 327 | 328 | update_option($this->theme_option_name, $data); 329 | 330 | } 331 | 332 | /** 333 | * Available widgets 334 | * 335 | * Gather site's widgets into array with ID base, name, etc. 336 | * Used by export and import functions. 337 | * 338 | * @since 2.2.0 339 | * 340 | * @global array $wp_registered_widget_updates 341 | * @return array Widget information 342 | */ 343 | function available_widgets() { 344 | 345 | global $wp_registered_widget_controls; 346 | 347 | $widget_controls = $wp_registered_widget_controls; 348 | 349 | $available_widgets = array(); 350 | 351 | foreach ( $widget_controls as $widget ) { 352 | 353 | if ( ! empty( $widget['id_base'] ) && ! isset( $available_widgets[$widget['id_base']] ) ) { // no dupes 354 | 355 | $available_widgets[$widget['id_base']]['id_base'] = $widget['id_base']; 356 | $available_widgets[$widget['id_base']]['name'] = $widget['name']; 357 | 358 | } 359 | 360 | } 361 | 362 | return apply_filters( 'radium_theme_import_widget_available_widgets', $available_widgets ); 363 | 364 | } 365 | 366 | 367 | /** 368 | * Process import file 369 | * 370 | * This parses a file and triggers importation of its widgets. 371 | * 372 | * @since 2.2.0 373 | * 374 | * @param string $file Path to .wie file uploaded 375 | * @global string $widget_import_results 376 | */ 377 | function process_widget_import_file( $file ) { 378 | 379 | // File exists? 380 | if ( ! file_exists( $file ) ) { 381 | wp_die( 382 | esc_html__( 'Widget Import file could not be found. Please try again.', 'radium' ), 383 | '', 384 | array( 'back_link' => true ) 385 | ); 386 | } 387 | 388 | // Get file contents and decode 389 | global $wp_filesystem; 390 | $data = $wp_filesystem->get_contents( $file ); 391 | $data = json_decode( $data ); 392 | 393 | // Delete import file 394 | //unlink( $file ); 395 | 396 | // Import the widget data 397 | // Make results available for display on import/export page 398 | $this->widget_import_results = $this->import_widgets( $data ); 399 | 400 | } 401 | 402 | 403 | /** 404 | * Import widget JSON data 405 | * 406 | * @since 2.2.0 407 | * @global array $wp_registered_sidebars 408 | * @param object $data JSON widget data from .wie file 409 | * @return array Results array 410 | */ 411 | public function import_widgets( $data ) { 412 | 413 | global $wp_registered_sidebars; 414 | 415 | // Have valid data? 416 | // If no data or could not decode 417 | if ( empty( $data ) || ! is_object( $data ) ) { 418 | wp_die( 419 | esc_html__( 'Widget import data could not be read. Please try a different file.', 'radium' ), 420 | '', 421 | array( 'back_link' => true ) 422 | ); 423 | } 424 | 425 | // Hook before import 426 | $data = apply_filters( 'radium_theme_import_widget_data', $data ); 427 | 428 | // Get all available widgets site supports 429 | $available_widgets = $this->available_widgets(); 430 | 431 | // Get all existing widget instances 432 | $widget_instances = array(); 433 | foreach ( $available_widgets as $widget_data ) { 434 | $widget_instances[$widget_data['id_base']] = get_option( 'widget_' . $widget_data['id_base'] ); 435 | } 436 | 437 | // Begin results 438 | $results = array(); 439 | 440 | // Loop import data's sidebars 441 | foreach ( $data as $sidebar_id => $widgets ) { 442 | 443 | // Skip inactive widgets 444 | // (should not be in export file) 445 | if ( 'wp_inactive_widgets' == $sidebar_id ) { 446 | continue; 447 | } 448 | 449 | // Check if sidebar is available on this site 450 | // Otherwise add widgets to inactive, and say so 451 | if ( isset( $wp_registered_sidebars[$sidebar_id] ) ) { 452 | $sidebar_available = true; 453 | $use_sidebar_id = $sidebar_id; 454 | $sidebar_message_type = 'success'; 455 | $sidebar_message = ''; 456 | } else { 457 | $sidebar_available = false; 458 | $use_sidebar_id = 'wp_inactive_widgets'; // add to inactive if sidebar does not exist in theme 459 | $sidebar_message_type = 'error'; 460 | $sidebar_message = esc_html__( 'Sidebar does not exist in theme (using Inactive)', 'radium' ); 461 | } 462 | 463 | // Result for sidebar 464 | $results[$sidebar_id]['name'] = ! empty( $wp_registered_sidebars[$sidebar_id]['name'] ) ? $wp_registered_sidebars[$sidebar_id]['name'] : $sidebar_id; // sidebar name if theme supports it; otherwise ID 465 | $results[$sidebar_id]['message_type'] = $sidebar_message_type; 466 | $results[$sidebar_id]['message'] = $sidebar_message; 467 | $results[$sidebar_id]['widgets'] = array(); 468 | 469 | // Loop widgets 470 | foreach ( $widgets as $widget_instance_id => $widget ) { 471 | 472 | $fail = false; 473 | 474 | // Get id_base (remove -# from end) and instance ID number 475 | $id_base = preg_replace( '/-[0-9]+$/', '', $widget_instance_id ); 476 | $instance_id_number = str_replace( $id_base . '-', '', $widget_instance_id ); 477 | 478 | // Does site support this widget? 479 | if ( ! $fail && ! isset( $available_widgets[$id_base] ) ) { 480 | $fail = true; 481 | $widget_message_type = 'error'; 482 | $widget_message = esc_html__( 'Site does not support widget', 'radium' ); // explain why widget not imported 483 | } 484 | 485 | // Filter to modify settings before import 486 | // Do before identical check because changes may make it identical to end result (such as URL replacements) 487 | $widget = apply_filters( 'radium_theme_import_widget_settings', $widget ); 488 | 489 | // Does widget with identical settings already exist in same sidebar? 490 | if ( ! $fail && isset( $widget_instances[$id_base] ) ) { 491 | 492 | // Get existing widgets in this sidebar 493 | $sidebars_widgets = get_option( 'sidebars_widgets' ); 494 | $sidebar_widgets = isset( $sidebars_widgets[$use_sidebar_id] ) ? $sidebars_widgets[$use_sidebar_id] : array(); // check Inactive if that's where will go 495 | 496 | // Loop widgets with ID base 497 | $single_widget_instances = ! empty( $widget_instances[$id_base] ) ? $widget_instances[$id_base] : array(); 498 | foreach ( $single_widget_instances as $check_id => $check_widget ) { 499 | 500 | // Is widget in same sidebar and has identical settings? 501 | if ( in_array( "$id_base-$check_id", $sidebar_widgets ) && (array) $widget == $check_widget ) { 502 | 503 | $fail = true; 504 | $widget_message_type = 'warning'; 505 | $widget_message = esc_html__( 'Widget already exists', 'radium' ); // explain why widget not imported 506 | 507 | break; 508 | 509 | } 510 | 511 | } 512 | 513 | } 514 | 515 | // No failure 516 | if ( ! $fail ) { 517 | 518 | // Add widget instance 519 | $single_widget_instances = get_option( 'widget_' . $id_base ); // all instances for that widget ID base, get fresh every time 520 | $single_widget_instances = ! empty( $single_widget_instances ) ? $single_widget_instances : array( '_multiwidget' => 1 ); // start fresh if have to 521 | $single_widget_instances[] = (array) $widget; // add it 522 | 523 | // Get the key it was given 524 | end( $single_widget_instances ); 525 | $new_instance_id_number = key( $single_widget_instances ); 526 | 527 | // If key is 0, make it 1 528 | // When 0, an issue can occur where adding a widget causes data from other widget to load, and the widget doesn't stick (reload wipes it) 529 | if ( '0' === strval( $new_instance_id_number ) ) { 530 | $new_instance_id_number = 1; 531 | $single_widget_instances[$new_instance_id_number] = $single_widget_instances[0]; 532 | unset( $single_widget_instances[0] ); 533 | } 534 | 535 | // Move _multiwidget to end of array for uniformity 536 | if ( isset( $single_widget_instances['_multiwidget'] ) ) { 537 | $multiwidget = $single_widget_instances['_multiwidget']; 538 | unset( $single_widget_instances['_multiwidget'] ); 539 | $single_widget_instances['_multiwidget'] = $multiwidget; 540 | } 541 | 542 | // Update option with new widget 543 | update_option( 'widget_' . $id_base, $single_widget_instances ); 544 | 545 | // Assign widget instance to sidebar 546 | $sidebars_widgets = get_option( 'sidebars_widgets' ); // which sidebars have which widgets, get fresh every time 547 | $new_instance_id = $id_base . '-' . $new_instance_id_number; // use ID number from new widget instance 548 | $sidebars_widgets[$use_sidebar_id][] = $new_instance_id; // add new instance to sidebar 549 | update_option( 'sidebars_widgets', $sidebars_widgets ); // save the amended data 550 | 551 | // Success message 552 | if ( $sidebar_available ) { 553 | $widget_message_type = 'success'; 554 | $widget_message = esc_html__( 'Imported', 'radium' ); 555 | } else { 556 | $widget_message_type = 'warning'; 557 | $widget_message = esc_html__( 'Imported to Inactive', 'radium' ); 558 | } 559 | 560 | } 561 | 562 | // Result for widget instance 563 | $results[$sidebar_id]['widgets'][$widget_instance_id]['name'] = isset( $available_widgets[$id_base]['name'] ) ? $available_widgets[$id_base]['name'] : $id_base; // widget name or ID if name not available (not supported by site) 564 | $results[$sidebar_id]['widgets'][$widget_instance_id]['title'] = ! empty( $widget->title ) ? $widget->title : esc_html__( 'No Title', 'radium' ); // show "No Title" if widget instance is untitled 565 | $results[$sidebar_id]['widgets'][$widget_instance_id]['message_type'] = $widget_message_type; 566 | $results[$sidebar_id]['widgets'][$widget_instance_id]['message'] = $widget_message; 567 | 568 | } 569 | 570 | } 571 | 572 | // Hook after import 573 | do_action( 'radium_theme_import_widget_after_import' ); 574 | 575 | // Return results 576 | return apply_filters( 'radium_theme_import_widget_results', $results ); 577 | 578 | } 579 | 580 | } 581 | -------------------------------------------------------------------------------- /importer/wordpress-importer.php: -------------------------------------------------------------------------------- 1 | header(); 75 | 76 | $step = empty( $_GET['step'] ) ? 0 : (int) $_GET['step']; 77 | switch ( $step ) { 78 | case 0: 79 | $this->greet(); 80 | break; 81 | case 1: 82 | check_admin_referer( 'import-upload' ); 83 | if ( $this->handle_upload() ) 84 | $this->import_options(); 85 | break; 86 | case 2: 87 | check_admin_referer( 'import-wordpress' ); 88 | $this->fetch_attachments = ( ! empty( $_POST['fetch_attachments'] ) && $this->allow_fetch_attachments() ); 89 | $this->id = (int) $_POST['import_id']; 90 | $file = get_attached_file( $this->id ); 91 | set_time_limit(0); 92 | $this->import( $file ); 93 | break; 94 | } 95 | 96 | $this->footer(); 97 | } 98 | 99 | /** 100 | * The main controller for the actual import stage. 101 | * 102 | * @param string $file Path to the WXR file for importing 103 | */ 104 | function import( $file ) { 105 | add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) ); 106 | add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) ); 107 | 108 | $this->import_start( $file ); 109 | 110 | $this->get_author_mapping(); 111 | 112 | wp_suspend_cache_invalidation( true ); 113 | $this->process_categories(); 114 | $this->process_tags(); 115 | $this->process_terms(); 116 | $this->process_posts(); 117 | wp_suspend_cache_invalidation( false ); 118 | 119 | // update incorrect/missing information in the DB 120 | $this->backfill_parents(); 121 | $this->backfill_attachment_urls(); 122 | $this->remap_featured_images(); 123 | 124 | $this->import_end(); 125 | } 126 | 127 | /** 128 | * Parses the WXR file and prepares us for the task of processing parsed data 129 | * 130 | * @param string $file Path to the WXR file for importing 131 | */ 132 | function import_start( $file ) { 133 | if ( ! is_file($file) ) { 134 | echo '

' . esc_html__( 'Sorry, there has been an error.', 'radium' ) . '
'; 135 | echo esc_html__( 'The file does not exist, please try again.', 'radium' ) . '

'; 136 | $this->footer(); 137 | die(); 138 | } 139 | 140 | $import_data = $this->parse( $file ); 141 | 142 | if ( is_wp_error( $import_data ) ) { 143 | echo '

' . esc_html__( 'Sorry, there has been an error.', 'radium' ) . '
'; 144 | echo esc_html( $import_data->get_error_message() ) . '

'; 145 | $this->footer(); 146 | die(); 147 | } 148 | 149 | $this->version = $import_data['version']; 150 | $this->get_authors_from_import( $import_data ); 151 | $this->posts = $import_data['posts']; 152 | $this->terms = $import_data['terms']; 153 | $this->categories = $import_data['categories']; 154 | $this->tags = $import_data['tags']; 155 | $this->base_url = esc_url( $import_data['base_url'] ); 156 | 157 | wp_defer_term_counting( true ); 158 | wp_defer_comment_counting( true ); 159 | 160 | do_action( 'import_start' ); 161 | } 162 | 163 | /** 164 | * Performs post-import cleanup of files and the cache 165 | */ 166 | function import_end() { 167 | wp_import_cleanup( $this->id ); 168 | 169 | wp_cache_flush(); 170 | foreach ( get_taxonomies() as $tax ) { 171 | delete_option( "{$tax}_children" ); 172 | _get_term_hierarchy( $tax ); 173 | } 174 | 175 | wp_defer_term_counting( false ); 176 | wp_defer_comment_counting( false ); 177 | 178 | echo '

' . esc_html__( 'All done.', 'radium' ) . ' ' . esc_html__( 'Have fun!', 'radium' ) . '' . '

'; 179 | echo '

' . esc_html__( 'Remember to update the passwords and roles of imported users.', 'radium' ) . '

'; 180 | 181 | do_action( 'import_end' ); 182 | } 183 | 184 | /** 185 | * Handles the WXR upload and initial parsing of the file to prepare for 186 | * displaying author import options 187 | * 188 | * @return bool False if error uploading or invalid file, true otherwise 189 | */ 190 | function handle_upload() { 191 | $file = wp_import_handle_upload(); 192 | 193 | if ( isset( $file['error'] ) ) { 194 | echo '

' . esc_html__( 'Sorry, there has been an error.', 'radium' ) . '
'; 195 | echo esc_html( $file['error'] ) . '

'; 196 | return false; 197 | } else if ( ! file_exists( $file['file'] ) ) { 198 | echo '

' . esc_html__( 'Sorry, there has been an error.', 'radium' ) . '
'; 199 | printf( wp_kses( __( 'The export file could not be found at %s. It is likely that this was caused by a permissions problem.', 'radium' ), array( 'code' => array() ) ), esc_html( $file['file'] ) ); 200 | echo '

'; 201 | return false; 202 | } 203 | 204 | $this->id = (int) $file['id']; 205 | $import_data = $this->parse( $file['file'] ); 206 | if ( is_wp_error( $import_data ) ) { 207 | echo '

' . esc_html__( 'Sorry, there has been an error.', 'radium' ) . '
'; 208 | echo esc_html( $import_data->get_error_message() ) . '

'; 209 | return false; 210 | } 211 | 212 | $this->version = $import_data['version']; 213 | if ( $this->version > $this->max_wxr_version ) { 214 | echo '

'; 215 | printf( esc_html__( 'This WXR file (version %s) may not be supported by this version of the importer. Please consider updating.', 'radium' ), esc_html($import_data['version']) ); 216 | echo '

'; 217 | } 218 | 219 | $this->get_authors_from_import( $import_data ); 220 | 221 | return true; 222 | } 223 | 224 | /** 225 | * Retrieve authors from parsed WXR data 226 | * 227 | * Uses the provided author information from WXR 1.1 files 228 | * or extracts info from each post for WXR 1.0 files 229 | * 230 | * @param array $import_data Data returned by a WXR parser 231 | */ 232 | function get_authors_from_import( $import_data ) { 233 | if ( ! empty( $import_data['authors'] ) ) { 234 | $this->authors = $import_data['authors']; 235 | // no author information, grab it from the posts 236 | } else { 237 | foreach ( $import_data['posts'] as $post ) { 238 | $login = sanitize_user( $post['post_author'], true ); 239 | if ( empty( $login ) ) { 240 | printf( esc_html__( 'Failed to import author %s. Their posts will be attributed to the current user.', 'radium' ), esc_html( $post['post_author'] ) ); 241 | echo '
'; 242 | continue; 243 | } 244 | 245 | if ( ! isset($this->authors[$login]) ) 246 | $this->authors[$login] = array( 247 | 'author_login' => $login, 248 | 'author_display_name' => $post['post_author'] 249 | ); 250 | } 251 | } 252 | } 253 | 254 | /** 255 | * Display pre-import options, author importing/mapping and option to 256 | * fetch attachments 257 | */ 258 | function import_options() { 259 | $j = 0; 260 | ?> 261 |
262 | 263 | 264 | 265 | authors ) ) : ?> 266 |

267 |

admins entries.', 'radium' ); ?>

268 | allow_create_users() ) : ?> 269 |

270 | 271 |
    272 | authors as $author ) : ?> 273 |
  1. author_select( $j++, $author ); ?>
  2. 274 | 275 |
276 | 277 | 278 | allow_fetch_attachments() ) : ?> 279 |

280 |

281 | 282 | 283 |

284 | 285 | 286 |

287 |
288 | ' . esc_html( $author['author_display_name'] ); 301 | if ( $this->version != '1.0' ) echo ' (' . esc_html( $author['author_login'] ) . ')'; 302 | echo '
'; 303 | 304 | if ( $this->version != '1.0' ) 305 | echo '
'; 306 | 307 | $create_users = $this->allow_create_users(); 308 | if ( $create_users ) { 309 | if ( $this->version != '1.0' ) { 310 | esc_html_e( 'or create new user with login name:', 'radium' ); 311 | $value = ''; 312 | } else { 313 | esc_html_e( 'as a new user:', 'radium' ); 314 | $value = esc_attr( sanitize_user( $author['author_login'], true ) ); 315 | } 316 | 317 | echo '
'; 318 | } 319 | 320 | if ( ! $create_users && $this->version == '1.0' ) 321 | esc_html_e( 'assign posts to an existing user:', 'radium' ); 322 | else 323 | esc_html_e( 'or assign posts to an existing user:', 'radium' ); 324 | wp_dropdown_users( array( 'name' => "user_map[$n]", 'multi' => true, 'show_option_all' => esc_html__( '- Select -', 'radium' ) ) ); 325 | echo ''; 326 | 327 | if ( $this->version != '1.0' ) 328 | echo '
'; 329 | } 330 | 331 | /** 332 | * Map old author logins to local user IDs based on decisions made 333 | * in import options form. Can map to an existing user, create a new user 334 | * or falls back to the current user in case of error with either of the previous 335 | */ 336 | function get_author_mapping() { 337 | if ( ! isset( $_POST['imported_authors'] ) ) 338 | return; 339 | 340 | $create_users = $this->allow_create_users(); 341 | 342 | foreach ( (array) $_POST['imported_authors'] as $i => $old_login ) { 343 | // Multisite adds strtolower to sanitize_user. Need to sanitize here to stop breakage in process_posts. 344 | $santized_old_login = sanitize_user( $old_login, true ); 345 | $old_id = isset( $this->authors[$old_login]['author_id'] ) ? intval($this->authors[$old_login]['author_id']) : false; 346 | 347 | if ( ! empty( $_POST['user_map'][$i] ) ) { 348 | $user = get_userdata( intval($_POST['user_map'][$i]) ); 349 | if ( isset( $user->ID ) ) { 350 | if ( $old_id ) 351 | $this->processed_authors[$old_id] = $user->ID; 352 | $this->author_mapping[$santized_old_login] = $user->ID; 353 | } 354 | } else if ( $create_users ) { 355 | if ( ! empty($_POST['user_new'][$i]) ) { 356 | $user_id = wp_create_user( $_POST['user_new'][$i], wp_generate_password() ); 357 | } else if ( $this->version != '1.0' ) { 358 | $user_data = array( 359 | 'user_login' => $old_login, 360 | 'user_pass' => wp_generate_password(), 361 | 'user_email' => isset( $this->authors[$old_login]['author_email'] ) ? $this->authors[$old_login]['author_email'] : '', 362 | 'display_name' => $this->authors[$old_login]['author_display_name'], 363 | 'first_name' => isset( $this->authors[$old_login]['author_first_name'] ) ? $this->authors[$old_login]['author_first_name'] : '', 364 | 'last_name' => isset( $this->authors[$old_login]['author_last_name'] ) ? $this->authors[$old_login]['author_last_name'] : '', 365 | ); 366 | $user_id = wp_insert_user( $user_data ); 367 | } 368 | 369 | if ( ! is_wp_error( $user_id ) ) { 370 | if ( $old_id ) 371 | $this->processed_authors[$old_id] = $user_id; 372 | $this->author_mapping[$santized_old_login] = $user_id; 373 | } else { 374 | printf( esc_html__( 'Failed to create new user for %s. Their posts will be attributed to the current user.', 'radium' ), esc_html($this->authors[$old_login]['author_display_name']) ); 375 | if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG ) 376 | echo ' ' . $user_id->get_error_message(); 377 | echo '
'; 378 | } 379 | } 380 | 381 | // failsafe: if the user_id was invalid, default to the current user 382 | if ( ! isset( $this->author_mapping[$santized_old_login] ) ) { 383 | if ( $old_id ) 384 | $this->processed_authors[$old_id] = (int) get_current_user_id(); 385 | $this->author_mapping[$santized_old_login] = (int) get_current_user_id(); 386 | } 387 | } 388 | } 389 | 390 | /** 391 | * Create new categories based on import information 392 | * 393 | * Doesn't create a new category if its slug already exists 394 | */ 395 | function process_categories() { 396 | $this->categories = apply_filters( 'wp_import_categories', $this->categories ); 397 | 398 | if ( empty( $this->categories ) ) 399 | return; 400 | 401 | foreach ( $this->categories as $cat ) { 402 | // if the category already exists leave it alone 403 | $term_id = term_exists( $cat['category_nicename'], 'category' ); 404 | if ( $term_id ) { 405 | if ( is_array($term_id) ) $term_id = $term_id['term_id']; 406 | if ( isset($cat['term_id']) ) 407 | $this->processed_terms[intval($cat['term_id'])] = (int) $term_id; 408 | continue; 409 | } 410 | 411 | $category_parent = empty( $cat['category_parent'] ) ? 0 : category_exists( $cat['category_parent'] ); 412 | $category_description = isset( $cat['category_description'] ) ? $cat['category_description'] : ''; 413 | $catarr = array( 414 | 'category_nicename' => $cat['category_nicename'], 415 | 'category_parent' => $category_parent, 416 | 'cat_name' => $cat['cat_name'], 417 | 'category_description' => $category_description 418 | ); 419 | 420 | $id = wp_insert_category( $catarr ); 421 | if ( ! is_wp_error( $id ) ) { 422 | if ( isset($cat['term_id']) ) 423 | $this->processed_terms[intval($cat['term_id'])] = $id; 424 | } else { 425 | printf( esc_html__( 'Failed to import category %s', 'radium' ), esc_html($cat['category_nicename']) ); 426 | if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG ) 427 | echo ': ' . $id->get_error_message(); 428 | echo '
'; 429 | continue; 430 | } 431 | } 432 | 433 | unset( $this->categories ); 434 | } 435 | 436 | /** 437 | * Create new post tags based on import information 438 | * 439 | * Doesn't create a tag if its slug already exists 440 | */ 441 | function process_tags() { 442 | $this->tags = apply_filters( 'wp_import_tags', $this->tags ); 443 | 444 | if ( empty( $this->tags ) ) 445 | return; 446 | 447 | foreach ( $this->tags as $tag ) { 448 | // if the tag already exists leave it alone 449 | $term_id = term_exists( $tag['tag_slug'], 'post_tag' ); 450 | if ( $term_id ) { 451 | if ( is_array($term_id) ) $term_id = $term_id['term_id']; 452 | if ( isset($tag['term_id']) ) 453 | $this->processed_terms[intval($tag['term_id'])] = (int) $term_id; 454 | continue; 455 | } 456 | 457 | $tag_desc = isset( $tag['tag_description'] ) ? $tag['tag_description'] : ''; 458 | $tagarr = array( 'slug' => $tag['tag_slug'], 'description' => $tag_desc ); 459 | 460 | $id = wp_insert_term( $tag['tag_name'], 'post_tag', $tagarr ); 461 | if ( ! is_wp_error( $id ) ) { 462 | if ( isset($tag['term_id']) ) 463 | $this->processed_terms[intval($tag['term_id'])] = $id['term_id']; 464 | } else { 465 | printf( esc_html__( 'Failed to import post tag %s', 'radium' ), esc_html($tag['tag_name']) ); 466 | if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG ) 467 | echo ': ' . $id->get_error_message(); 468 | echo '
'; 469 | continue; 470 | } 471 | } 472 | 473 | unset( $this->tags ); 474 | } 475 | 476 | /** 477 | * Create new terms based on import information 478 | * 479 | * Doesn't create a term its slug already exists 480 | */ 481 | function process_terms() { 482 | $this->terms = apply_filters( 'wp_import_terms', $this->terms ); 483 | 484 | if ( empty( $this->terms ) ) 485 | return; 486 | 487 | foreach ( $this->terms as $term ) { 488 | // if the term already exists in the correct taxonomy leave it alone 489 | $term_id = term_exists( $term['slug'], $term['term_taxonomy'] ); 490 | if ( $term_id ) { 491 | if ( is_array($term_id) ) $term_id = $term_id['term_id']; 492 | if ( isset($term['term_id']) ) 493 | $this->processed_terms[intval($term['term_id'])] = (int) $term_id; 494 | continue; 495 | } 496 | 497 | if ( empty( $term['term_parent'] ) ) { 498 | $parent = 0; 499 | } else { 500 | $parent = term_exists( $term['term_parent'], $term['term_taxonomy'] ); 501 | if ( is_array( $parent ) ) $parent = $parent['term_id']; 502 | } 503 | $description = isset( $term['term_description'] ) ? $term['term_description'] : ''; 504 | $termarr = array( 'slug' => $term['slug'], 'description' => $description, 'parent' => intval($parent) ); 505 | 506 | $id = wp_insert_term( $term['term_name'], $term['term_taxonomy'], $termarr ); 507 | if ( ! is_wp_error( $id ) ) { 508 | if ( isset($term['term_id']) ) 509 | $this->processed_terms[intval($term['term_id'])] = $id['term_id']; 510 | } else { 511 | printf( esc_html__( 'Failed to import %s %s', 'radium' ), esc_html($term['term_taxonomy']), esc_html($term['term_name']) ); 512 | if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG ) 513 | echo ': ' . $id->get_error_message(); 514 | echo '
'; 515 | continue; 516 | } 517 | } 518 | 519 | unset( $this->terms ); 520 | } 521 | 522 | /** 523 | * Create new posts based on import information 524 | * 525 | * Posts marked as having a parent which doesn't exist will become top level items. 526 | * Doesn't create a new post if: the post type doesn't exist, the given post ID 527 | * is already noted as imported or a post with the same title and date already exists. 528 | * Note that new/updated terms, comments and meta are imported for the last of the above. 529 | */ 530 | function process_posts() { 531 | $this->posts = apply_filters( 'wp_import_posts', $this->posts ); 532 | 533 | foreach ( $this->posts as $post ) { 534 | $post = apply_filters( 'wp_import_post_data_raw', $post ); 535 | 536 | if ( ! post_type_exists( $post['post_type'] ) ) { 537 | printf( esc_html__( 'Failed to import “%s”: Invalid post type %s', 'radium' ), 538 | esc_html($post['post_title']), esc_html($post['post_type']) ); 539 | echo '
'; 540 | do_action( 'wp_import_post_exists', $post ); 541 | continue; 542 | } 543 | 544 | if ( isset( $this->processed_posts[$post['post_id']] ) && ! empty( $post['post_id'] ) ) 545 | continue; 546 | 547 | if ( $post['status'] == 'auto-draft' ) 548 | continue; 549 | 550 | if ( 'nav_menu_item' == $post['post_type'] ) { 551 | $this->process_menu_item( $post ); 552 | continue; 553 | } 554 | 555 | $post_type_object = get_post_type_object( $post['post_type'] ); 556 | 557 | $post_exists = post_exists( $post['post_title'], '', $post['post_date'] ); 558 | if ( $post_exists && get_post_type( $post_exists ) == $post['post_type'] ) { 559 | printf( __('%s “%s” already exists.', 'radium'), $post_type_object->labels->singular_name, esc_html($post['post_title']) ); 560 | echo '
'; 561 | $comment_post_ID = $post_id = $post_exists; 562 | } else { 563 | $post_parent = (int) $post['post_parent']; 564 | if ( $post_parent ) { 565 | // if we already know the parent, map it to the new local ID 566 | if ( isset( $this->processed_posts[$post_parent] ) ) { 567 | $post_parent = $this->processed_posts[$post_parent]; 568 | // otherwise record the parent for later 569 | } else { 570 | $this->post_orphans[intval($post['post_id'])] = $post_parent; 571 | $post_parent = 0; 572 | } 573 | } 574 | 575 | // map the post author 576 | $author = sanitize_user( $post['post_author'], true ); 577 | if ( isset( $this->author_mapping[$author] ) ) 578 | $author = $this->author_mapping[$author]; 579 | else 580 | $author = (int) get_current_user_id(); 581 | 582 | $postdata = array( 583 | 'import_id' => $post['post_id'], 'post_author' => $author, 'post_date' => $post['post_date'], 584 | 'post_date_gmt' => $post['post_date_gmt'], 'post_content' => $post['post_content'], 585 | 'post_excerpt' => $post['post_excerpt'], 'post_title' => $post['post_title'], 586 | 'post_status' => $post['status'], 'post_name' => $post['post_name'], 587 | 'comment_status' => $post['comment_status'], 'ping_status' => $post['ping_status'], 588 | 'guid' => $post['guid'], 'post_parent' => $post_parent, 'menu_order' => $post['menu_order'], 589 | 'post_type' => $post['post_type'], 'post_password' => $post['post_password'] 590 | ); 591 | 592 | $original_post_ID = $post['post_id']; 593 | $postdata = apply_filters( 'wp_import_post_data_processed', $postdata, $post ); 594 | 595 | if ( 'attachment' == $postdata['post_type'] ) { 596 | $remote_url = ! empty($post['attachment_url']) ? $post['attachment_url'] : $post['guid']; 597 | 598 | // try to use _wp_attached file for upload folder placement to ensure the same location as the export site 599 | // e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload() 600 | $postdata['upload_date'] = $post['post_date']; 601 | if ( isset( $post['postmeta'] ) ) { 602 | foreach( $post['postmeta'] as $meta ) { 603 | if ( $meta['key'] == '_wp_attached_file' ) { 604 | if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta['value'], $matches ) ) 605 | $postdata['upload_date'] = $matches[0]; 606 | break; 607 | } 608 | } 609 | } 610 | 611 | $comment_post_ID = $post_id = $this->process_attachment( $postdata, $remote_url ); 612 | } else { 613 | $comment_post_ID = $post_id = wp_insert_post( $postdata, true ); 614 | do_action( 'wp_import_insert_post', $post_id, $original_post_ID, $postdata, $post ); 615 | } 616 | 617 | if ( is_wp_error( $post_id ) ) { 618 | printf( __( 'Failed to import %s “%s”', 'radium' ), 619 | $post_type_object->labels->singular_name, esc_html($post['post_title']) ); 620 | if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG ) 621 | echo ': ' . $post_id->get_error_message(); 622 | echo '
'; 623 | continue; 624 | } 625 | 626 | if ( $post['is_sticky'] == 1 ) 627 | stick_post( $post_id ); 628 | } 629 | 630 | // map pre-import ID to local ID 631 | $this->processed_posts[intval($post['post_id'])] = (int) $post_id; 632 | 633 | if ( ! isset( $post['terms'] ) ) 634 | $post['terms'] = array(); 635 | 636 | $post['terms'] = apply_filters( 'wp_import_post_terms', $post['terms'], $post_id, $post ); 637 | 638 | // add categories, tags and other terms 639 | if ( ! empty( $post['terms'] ) ) { 640 | $terms_to_set = array(); 641 | foreach ( $post['terms'] as $term ) { 642 | // back compat with WXR 1.0 map 'tag' to 'post_tag' 643 | $taxonomy = ( 'tag' == $term['domain'] ) ? 'post_tag' : $term['domain']; 644 | $term_exists = term_exists( $term['slug'], $taxonomy ); 645 | $term_id = is_array( $term_exists ) ? $term_exists['term_id'] : $term_exists; 646 | if ( ! $term_id ) { 647 | $t = wp_insert_term( $term['name'], $taxonomy, array( 'slug' => $term['slug'] ) ); 648 | if ( ! is_wp_error( $t ) ) { 649 | $term_id = $t['term_id']; 650 | do_action( 'wp_import_insert_term', $t, $term, $post_id, $post ); 651 | } else { 652 | printf( esc_html__( 'Failed to import %s %s', 'radium' ), esc_html($taxonomy), esc_html($term['name']) ); 653 | if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG ) 654 | echo ': ' . $t->get_error_message(); 655 | echo '
'; 656 | do_action( 'wp_import_insert_term_failed', $t, $term, $post_id, $post ); 657 | continue; 658 | } 659 | } 660 | $terms_to_set[$taxonomy][] = intval( $term_id ); 661 | } 662 | 663 | foreach ( $terms_to_set as $tax => $ids ) { 664 | $tt_ids = wp_set_post_terms( $post_id, $ids, $tax ); 665 | do_action( 'wp_import_set_post_terms', $tt_ids, $ids, $tax, $post_id, $post ); 666 | } 667 | unset( $post['terms'], $terms_to_set ); 668 | } 669 | 670 | if ( ! isset( $post['comments'] ) ) 671 | $post['comments'] = array(); 672 | 673 | $post['comments'] = apply_filters( 'wp_import_post_comments', $post['comments'], $post_id, $post ); 674 | 675 | // add/update comments 676 | if ( ! empty( $post['comments'] ) ) { 677 | $num_comments = 0; 678 | $inserted_comments = array(); 679 | foreach ( $post['comments'] as $comment ) { 680 | $comment_id = $comment['comment_id']; 681 | $newcomments[$comment_id]['comment_post_ID'] = $comment_post_ID; 682 | $newcomments[$comment_id]['comment_author'] = $comment['comment_author']; 683 | $newcomments[$comment_id]['comment_author_email'] = $comment['comment_author_email']; 684 | $newcomments[$comment_id]['comment_author_IP'] = $comment['comment_author_IP']; 685 | $newcomments[$comment_id]['comment_author_url'] = $comment['comment_author_url']; 686 | $newcomments[$comment_id]['comment_date'] = $comment['comment_date']; 687 | $newcomments[$comment_id]['comment_date_gmt'] = $comment['comment_date_gmt']; 688 | $newcomments[$comment_id]['comment_content'] = $comment['comment_content']; 689 | $newcomments[$comment_id]['comment_approved'] = $comment['comment_approved']; 690 | $newcomments[$comment_id]['comment_type'] = $comment['comment_type']; 691 | $newcomments[$comment_id]['comment_parent'] = $comment['comment_parent']; 692 | $newcomments[$comment_id]['commentmeta'] = isset( $comment['commentmeta'] ) ? $comment['commentmeta'] : array(); 693 | if ( isset( $this->processed_authors[$comment['comment_user_id']] ) ) 694 | $newcomments[$comment_id]['user_id'] = $this->processed_authors[$comment['comment_user_id']]; 695 | } 696 | ksort( $newcomments ); 697 | 698 | foreach ( $newcomments as $key => $comment ) { 699 | // if this is a new post we can skip the comment_exists() check 700 | if ( ! $post_exists || ! comment_exists( $comment['comment_author'], $comment['comment_date'] ) ) { 701 | if ( isset( $inserted_comments[$comment['comment_parent']] ) ) 702 | $comment['comment_parent'] = $inserted_comments[$comment['comment_parent']]; 703 | $comment = wp_filter_comment( $comment ); 704 | $inserted_comments[$key] = wp_insert_comment( $comment ); 705 | do_action( 'wp_import_insert_comment', $inserted_comments[$key], $comment, $comment_post_ID, $post ); 706 | 707 | foreach( $comment['commentmeta'] as $meta ) { 708 | $value = maybe_unserialize( $meta['value'] ); 709 | add_comment_meta( $inserted_comments[$key], $meta['key'], $value ); 710 | } 711 | 712 | $num_comments++; 713 | } 714 | } 715 | unset( $newcomments, $inserted_comments, $post['comments'] ); 716 | } 717 | 718 | if ( ! isset( $post['postmeta'] ) ) 719 | $post['postmeta'] = array(); 720 | 721 | $post['postmeta'] = apply_filters( 'wp_import_post_meta', $post['postmeta'], $post_id, $post ); 722 | 723 | // add/update post meta 724 | if ( ! empty( $post['postmeta'] ) ) { 725 | foreach ( $post['postmeta'] as $meta ) { 726 | $key = apply_filters( 'import_post_meta_key', $meta['key'], $post_id, $post ); 727 | $value = false; 728 | 729 | if ( '_edit_last' == $key ) { 730 | if ( isset( $this->processed_authors[intval($meta['value'])] ) ) 731 | $value = $this->processed_authors[intval($meta['value'])]; 732 | else 733 | $key = false; 734 | } 735 | 736 | if ( $key ) { 737 | // export gets meta straight from the DB so could have a serialized string 738 | if ( ! $value ) 739 | $value = maybe_unserialize( $meta['value'] ); 740 | 741 | add_post_meta( $post_id, $key, $value ); 742 | do_action( 'import_post_meta', $post_id, $key, $value ); 743 | 744 | // if the post has a featured image, take note of this in case of remap 745 | if ( '_thumbnail_id' == $key ) 746 | $this->featured_images[$post_id] = (int) $value; 747 | } 748 | } 749 | } 750 | } 751 | 752 | unset( $this->posts ); 753 | } 754 | 755 | /** 756 | * Attempt to create a new menu item from import data 757 | * 758 | * Fails for draft, orphaned menu items and those without an associated nav_menu 759 | * or an invalid nav_menu term. If the post type or term object which the menu item 760 | * represents doesn't exist then the menu item will not be imported (waits until the 761 | * end of the import to retry again before discarding). 762 | * 763 | * @param array $item Menu item details from WXR file 764 | */ 765 | function process_menu_item( $item ) { 766 | // skip draft, orphaned menu items 767 | if ( 'draft' == $item['status'] ) 768 | return; 769 | 770 | $menu_slug = false; 771 | if ( isset($item['terms']) ) { 772 | // loop through terms, assume first nav_menu term is correct menu 773 | foreach ( $item['terms'] as $term ) { 774 | if ( 'nav_menu' == $term['domain'] ) { 775 | $menu_slug = $term['slug']; 776 | break; 777 | } 778 | } 779 | } 780 | 781 | // no nav_menu term associated with this menu item 782 | if ( ! $menu_slug ) { 783 | esc_html_e( 'Menu item skipped due to missing menu slug', 'radium' ); 784 | echo '
'; 785 | return; 786 | } 787 | 788 | $menu_id = term_exists( $menu_slug, 'nav_menu' ); 789 | if ( ! $menu_id ) { 790 | printf( esc_html__( 'Menu item skipped due to invalid menu slug: %s', 'radium' ), esc_html( $menu_slug ) ); 791 | echo '
'; 792 | return; 793 | } else { 794 | $menu_id = is_array( $menu_id ) ? $menu_id['term_id'] : $menu_id; 795 | } 796 | 797 | foreach ( $item['postmeta'] as $meta ) 798 | $$meta['key'] = $meta['value']; 799 | 800 | if ( 'taxonomy' == $_menu_item_type && isset( $this->processed_terms[intval($_menu_item_object_id)] ) ) { 801 | $_menu_item_object_id = $this->processed_terms[intval($_menu_item_object_id)]; 802 | } else if ( 'post_type' == $_menu_item_type && isset( $this->processed_posts[intval($_menu_item_object_id)] ) ) { 803 | $_menu_item_object_id = $this->processed_posts[intval($_menu_item_object_id)]; 804 | } else if ( 'custom' != $_menu_item_type ) { 805 | // associated object is missing or not imported yet, we'll retry later 806 | $this->missing_menu_items[] = $item; 807 | return; 808 | } 809 | 810 | if ( isset( $this->processed_menu_items[intval($_menu_item_menu_item_parent)] ) ) { 811 | $_menu_item_menu_item_parent = $this->processed_menu_items[intval($_menu_item_menu_item_parent)]; 812 | } else if ( $_menu_item_menu_item_parent ) { 813 | $this->menu_item_orphans[intval($item['post_id'])] = (int) $_menu_item_menu_item_parent; 814 | $_menu_item_menu_item_parent = 0; 815 | } 816 | 817 | // wp_update_nav_menu_item expects CSS classes as a space separated string 818 | $_menu_item_classes = maybe_unserialize( $_menu_item_classes ); 819 | if ( is_array( $_menu_item_classes ) ) 820 | $_menu_item_classes = implode( ' ', $_menu_item_classes ); 821 | 822 | $args = array( 823 | 'menu-item-object-id' => $_menu_item_object_id, 824 | 'menu-item-object' => $_menu_item_object, 825 | 'menu-item-parent-id' => $_menu_item_menu_item_parent, 826 | 'menu-item-position' => intval( $item['menu_order'] ), 827 | 'menu-item-type' => $_menu_item_type, 828 | 'menu-item-title' => $item['post_title'], 829 | 'menu-item-url' => $_menu_item_url, 830 | 'menu-item-description' => $item['post_content'], 831 | 'menu-item-attr-title' => $item['post_excerpt'], 832 | 'menu-item-target' => $_menu_item_target, 833 | 'menu-item-classes' => $_menu_item_classes, 834 | 'menu-item-xfn' => $_menu_item_xfn, 835 | 'menu-item-status' => $item['status'] 836 | ); 837 | 838 | $id = wp_update_nav_menu_item( $menu_id, 0, $args ); 839 | if ( $id && ! is_wp_error( $id ) ) 840 | $this->processed_menu_items[intval($item['post_id'])] = (int) $id; 841 | } 842 | 843 | /** 844 | * If fetching attachments is enabled then attempt to create a new attachment 845 | * 846 | * @param array $post Attachment post details from WXR 847 | * @param string $url URL to fetch attachment from 848 | * @return int|WP_Error Post ID on success, WP_Error otherwise 849 | */ 850 | function process_attachment( $post, $url ) { 851 | if ( ! $this->fetch_attachments ) 852 | return new WP_Error( 'attachment_processing_error', 853 | esc_html__( 'Fetching attachments is not enabled', 'radium' ) ); 854 | 855 | // if the URL is absolute, but does not contain address, then upload it assuming base_site_url 856 | if ( preg_match( '|^/[\w\W]+$|', $url ) ) 857 | $url = rtrim( $this->base_url, '/' ) . $url; 858 | 859 | $upload = $this->fetch_remote_file( $url, $post ); 860 | if ( is_wp_error( $upload ) ) 861 | return $upload; 862 | 863 | if ( $info = wp_check_filetype( $upload['file'] ) ) 864 | $post['post_mime_type'] = $info['type']; 865 | else 866 | return new WP_Error( 'attachment_processing_error', esc_html__('Invalid file type', 'radium') ); 867 | 868 | $post['guid'] = $upload['url']; 869 | 870 | // as per wp-admin/includes/upload.php 871 | $post_id = wp_insert_attachment( $post, $upload['file'] ); 872 | wp_update_attachment_metadata( $post_id, wp_generate_attachment_metadata( $post_id, $upload['file'] ) ); 873 | 874 | // remap resized image URLs, works by stripping the extension and remapping the URL stub. 875 | if ( preg_match( '!^image/!', $info['type'] ) ) { 876 | $parts = pathinfo( $url ); 877 | $name = basename( $parts['basename'], ".{$parts['extension']}" ); // PATHINFO_FILENAME in PHP 5.2 878 | 879 | $parts_new = pathinfo( $upload['url'] ); 880 | $name_new = basename( $parts_new['basename'], ".{$parts_new['extension']}" ); 881 | 882 | $this->url_remap[$parts['dirname'] . '/' . $name] = $parts_new['dirname'] . '/' . $name_new; 883 | } 884 | 885 | return $post_id; 886 | } 887 | 888 | /** 889 | * Attempt to download a remote file attachment 890 | * 891 | * @param string $url URL of item to fetch 892 | * @param array $post Attachment details 893 | * @return array|WP_Error Local file location details on success, WP_Error otherwise 894 | */ 895 | function fetch_remote_file( $url, $post ) { 896 | // extract the file name and extension from the url 897 | $file_name = basename( $url ); 898 | 899 | // get placeholder file in the upload dir with a unique, sanitized filename 900 | $upload = wp_upload_bits( $file_name, 0, '', $post['upload_date'] ); 901 | if ( $upload['error'] ) 902 | return new WP_Error( 'upload_dir_error', $upload['error'] ); 903 | 904 | // fetch the remote url and write it to the placeholder file 905 | $response_data = wp_remote_get( $url ); 906 | 907 | // request failed 908 | if ( is_wp_error( $response_data ) ) { 909 | @unlink( $upload['file'] ); 910 | return new WP_Error( 'import_file_error', esc_html__('Remote server did not respond', 'radium') ); 911 | } 912 | 913 | // make sure the fetch was successful 914 | if ( $response_data['response']['code'] != 200 ) { 915 | @unlink( $upload['file'] ); 916 | return new WP_Error( 'import_file_error', sprintf( esc_html__('Remote server returned error response %1$d %2$s', 'radium'), esc_html($response_data['response']['code']), esc_html( $response_data['response']['message'] ) ) ); 917 | } 918 | 919 | // write the file to the placeholder file 920 | if ( ! is_wp_error( $response_data ) && 200 === $response_data['response']['code'] ) { 921 | $response_body = wp_remote_retrieve_body( $response_data ); 922 | 923 | // get user credentials for WP filesystem API 924 | $demo_import_page_url = wp_nonce_url( 'themes.php?page=radium_demo_installer', 'radium_demo_installer' ); 925 | if ( false === ( $creds = request_filesystem_credentials( $demo_import_page_url, '', false, false, null ) ) ) { 926 | return new WP_Error( 'import_file_error', esc_html__('Your credentials are not valid.', 'radium') ); 927 | } 928 | 929 | // now we have credentials, try to get the wp_filesystem running 930 | if ( ! WP_Filesystem( $creds ) ) { 931 | // our credentials were no good, ask the user for them again 932 | request_filesystem_credentials( $demo_import_page_url, '', true, false, null ); 933 | return new WP_Error( 'import_file_error', esc_html__('Your credentials are not valid.', 'radium') ); 934 | } 935 | 936 | // by this point, the $wp_filesystem global should be working, so let's use it to create a file 937 | global $wp_filesystem; 938 | if ( ! $wp_filesystem->put_contents( $upload['file'], $response_body, FS_CHMOD_FILE ) ) { 939 | return new WP_Error( 'import_file_error', sprintf( esc_html__( 'An error occurred while writing file %s to the upload directory!', 'radium' ), $upload['file'] ) ); 940 | } 941 | } 942 | 943 | $filesize = filesize( $upload['file'] ); 944 | 945 | if ( isset( $response_data['headers']['content-length'] ) && $filesize != $response_data['headers']['content-length'] ) { 946 | @unlink( $upload['file'] ); 947 | return new WP_Error( 'import_file_error', esc_html__('Remote file is incorrect size', 'radium') ); 948 | } 949 | 950 | if ( 0 == $filesize ) { 951 | @unlink( $upload['file'] ); 952 | return new WP_Error( 'import_file_error', esc_html__('Zero size file downloaded', 'radium') ); 953 | } 954 | 955 | $max_size = (int) $this->max_attachment_size(); 956 | if ( ! empty( $max_size ) && $filesize > $max_size ) { 957 | @unlink( $upload['file'] ); 958 | return new WP_Error( 'import_file_error', sprintf(esc_html__('Remote file is too large, limit is %s', 'radium'), size_format($max_size) ) ); 959 | } 960 | 961 | // keep track of the old and new urls so we can substitute them later 962 | $this->url_remap[$url] = $upload['url']; 963 | $this->url_remap[$post['guid']] = $upload['url']; // r13735, really needed? 964 | // keep track of the destination if the remote url is redirected somewhere else 965 | if ( isset($response_data['headers']['x-final-location']) && $response_data['headers']['x-final-location'] != $url ) 966 | $this->url_remap[$response_data['headers']['x-final-location']] = $upload['url']; 967 | 968 | return $upload; 969 | } 970 | 971 | /** 972 | * Attempt to associate posts and menu items with previously missing parents 973 | * 974 | * An imported post's parent may not have been imported when it was first created 975 | * so try again. Similarly for child menu items and menu items which were missing 976 | * the object (e.g. post) they represent in the menu 977 | */ 978 | function backfill_parents() { 979 | global $wpdb; 980 | 981 | // find parents for post orphans 982 | foreach ( $this->post_orphans as $child_id => $parent_id ) { 983 | $local_child_id = $local_parent_id = false; 984 | if ( isset( $this->processed_posts[$child_id] ) ) 985 | $local_child_id = $this->processed_posts[$child_id]; 986 | if ( isset( $this->processed_posts[$parent_id] ) ) 987 | $local_parent_id = $this->processed_posts[$parent_id]; 988 | 989 | if ( $local_child_id && $local_parent_id ) 990 | $wpdb->update( $wpdb->posts, array( 'post_parent' => $local_parent_id ), array( 'ID' => $local_child_id ), '%d', '%d' ); 991 | } 992 | 993 | // all other posts/terms are imported, retry menu items with missing associated object 994 | $missing_menu_items = $this->missing_menu_items; 995 | foreach ( $missing_menu_items as $item ) 996 | $this->process_menu_item( $item ); 997 | 998 | // find parents for menu item orphans 999 | foreach ( $this->menu_item_orphans as $child_id => $parent_id ) { 1000 | $local_child_id = $local_parent_id = 0; 1001 | if ( isset( $this->processed_menu_items[$child_id] ) ) 1002 | $local_child_id = $this->processed_menu_items[$child_id]; 1003 | if ( isset( $this->processed_menu_items[$parent_id] ) ) 1004 | $local_parent_id = $this->processed_menu_items[$parent_id]; 1005 | 1006 | if ( $local_child_id && $local_parent_id ) 1007 | update_post_meta( $local_child_id, '_menu_item_menu_item_parent', (int) $local_parent_id ); 1008 | } 1009 | } 1010 | 1011 | /** 1012 | * Use stored mapping information to update old attachment URLs 1013 | */ 1014 | function backfill_attachment_urls() { 1015 | global $wpdb; 1016 | // make sure we do the longest urls first, in case one is a substring of another 1017 | uksort( $this->url_remap, array(&$this, 'cmpr_strlen') ); 1018 | 1019 | foreach ( $this->url_remap as $from_url => $to_url ) { 1020 | // remap urls in post_content 1021 | $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url) ); 1022 | // remap enclosure urls 1023 | $result = $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url) ); 1024 | } 1025 | } 1026 | 1027 | /** 1028 | * Update _thumbnail_id meta to new, imported attachment IDs 1029 | */ 1030 | function remap_featured_images() { 1031 | // cycle through posts that have a featured image 1032 | foreach ( $this->featured_images as $post_id => $value ) { 1033 | if ( isset( $this->processed_posts[$value] ) ) { 1034 | $new_id = $this->processed_posts[$value]; 1035 | // only update if there's a difference 1036 | if ( $new_id != $value ) 1037 | update_post_meta( $post_id, '_thumbnail_id', $new_id ); 1038 | } 1039 | } 1040 | } 1041 | 1042 | /** 1043 | * Parse a WXR file 1044 | * 1045 | * @param string $file Path to WXR file for parsing 1046 | * @return array Information gathered from the WXR file 1047 | */ 1048 | function parse( $file ) { 1049 | $parser = new WXR_Parser(); 1050 | return $parser->parse( $file ); 1051 | } 1052 | 1053 | // Display import page title 1054 | function header() { 1055 | echo '
'; 1056 | echo '

' . esc_html__( 'Import WordPress', 'radium' ) . '

'; 1057 | 1058 | $updates = get_plugin_updates(); 1059 | $basename = plugin_basename(__FILE__); 1060 | if ( isset( $updates[$basename] ) ) { 1061 | $update = $updates[$basename]; 1062 | echo '

'; 1063 | printf( esc_html__( 'A new version of this importer is available. Please update to version %s to ensure compatibility with newer export files.', 'radium' ), $update->update->new_version ); 1064 | echo '

'; 1065 | } 1066 | } 1067 | 1068 | // Close div.wrap 1069 | function footer() { 1070 | echo '
'; 1071 | } 1072 | 1073 | /** 1074 | * Display introductory text and file upload form 1075 | */ 1076 | function greet() { 1077 | echo '
'; 1078 | echo '

'.esc_html__( 'Howdy! Upload your WordPress eXtended RSS (WXR) file and we’ll import the posts, pages, comments, custom fields, categories, and tags into this site.', 'radium' ).'

'; 1079 | echo '

'.esc_html__( 'Choose a WXR (.xml) file to upload, then click Upload file and import.', 'radium' ).'

'; 1080 | wp_import_upload_form( 'admin.php?import=wordpress&step=1' ); 1081 | echo '
'; 1082 | } 1083 | 1084 | /** 1085 | * Decide if the given meta key maps to information we will want to import 1086 | * 1087 | * @param string $key The meta key to check 1088 | * @return string|bool The key if we do want to import, false if not 1089 | */ 1090 | function is_valid_meta_key( $key ) { 1091 | // skip attachment metadata since we'll regenerate it from scratch 1092 | // skip _edit_lock as not relevant for import 1093 | if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) ) 1094 | return false; 1095 | return $key; 1096 | } 1097 | 1098 | /** 1099 | * Decide whether or not the importer is allowed to create users. 1100 | * Default is true, can be filtered via import_allow_create_users 1101 | * 1102 | * @return bool True if creating users is allowed 1103 | */ 1104 | function allow_create_users() { 1105 | return apply_filters( 'import_allow_create_users', true ); 1106 | } 1107 | 1108 | /** 1109 | * Decide whether or not the importer should attempt to download attachment files. 1110 | * Default is true, can be filtered via import_allow_fetch_attachments. The choice 1111 | * made at the import options screen must also be true, false here hides that checkbox. 1112 | * 1113 | * @return bool True if downloading attachments is allowed 1114 | */ 1115 | function allow_fetch_attachments() { 1116 | return apply_filters( 'import_allow_fetch_attachments', true ); 1117 | } 1118 | 1119 | /** 1120 | * Decide what the maximum file size for downloaded attachments is. 1121 | * Default is 0 (unlimited), can be filtered via import_attachment_size_limit 1122 | * 1123 | * @return int Maximum attachment file size to import 1124 | */ 1125 | function max_attachment_size() { 1126 | return apply_filters( 'import_attachment_size_limit', 0 ); 1127 | } 1128 | 1129 | /** 1130 | * Added to http_request_timeout filter to force timeout at 60 seconds during import 1131 | * @return int 60 1132 | */ 1133 | function bump_request_timeout( $val ) { 1134 | return 60; 1135 | } 1136 | 1137 | // return the difference in length between two strings 1138 | function cmpr_strlen( $a, $b ) { 1139 | return strlen($b) - strlen($a); 1140 | } 1141 | } 1142 | 1143 | } // class_exists( 'WP_Importer' ) 1144 | -------------------------------------------------------------------------------- /licence.txt: -------------------------------------------------------------------------------- 1 | Radium One Click Demo Install 2 | Copyright 2014 Franklin Gitonga 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 | 18 | Last Updated: 18/10/2014 19 | 20 | =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 21 | 22 | GNU GENERAL PUBLIC LICENSE 23 | Version 2, June 1991 24 | 25 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 26 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 27 | Everyone is permitted to copy and distribute verbatim copies 28 | of this license document, but changing it is not allowed. 29 | 30 | Preamble 31 | 32 | The licenses for most software are designed to take away your 33 | freedom to share and change it. By contrast, the GNU General Public 34 | License is intended to guarantee your freedom to share and change free 35 | software--to make sure the software is free for all its users. This 36 | General Public License applies to most of the Free Software 37 | Foundation's software and to any other program whose authors commit to 38 | using it. (Some other Free Software Foundation software is covered by 39 | the GNU Lesser General Public License instead.) You can apply it to 40 | your programs, too. 41 | 42 | When we speak of free software, we are referring to freedom, not 43 | price. Our General Public Licenses are designed to make sure that you 44 | have the freedom to distribute copies of free software (and charge for 45 | this service if you wish), that you receive source code or can get it 46 | if you want it, that you can change the software or use pieces of it 47 | in new free programs; and that you know you can do these things. 48 | 49 | To protect your rights, we need to make restrictions that forbid 50 | anyone to deny you these rights or to ask you to surrender the rights. 51 | These restrictions translate to certain responsibilities for you if you 52 | distribute copies of the software, or if you modify it. 53 | 54 | For example, if you distribute copies of such a program, whether 55 | gratis or for a fee, you must give the recipients all the rights that 56 | you have. You must make sure that they, too, receive or can get the 57 | source code. And you must show them these terms so they know their 58 | rights. 59 | 60 | We protect your rights with two steps: (1) copyright the software, and 61 | (2) offer you this license which gives you legal permission to copy, 62 | distribute and/or modify the software. 63 | 64 | Also, for each author's protection and ours, we want to make certain 65 | that everyone understands that there is no warranty for this free 66 | software. If the software is modified by someone else and passed on, we 67 | want its recipients to know that what they have is not the original, so 68 | that any problems introduced by others will not reflect on the original 69 | authors' reputations. 70 | 71 | Finally, any free program is threatened constantly by software 72 | patents. We wish to avoid the danger that redistributors of a free 73 | program will individually obtain patent licenses, in effect making the 74 | program proprietary. To prevent this, we have made it clear that any 75 | patent must be licensed for everyone's free use or not licensed at all. 76 | 77 | The precise terms and conditions for copying, distribution and 78 | modification follow. 79 | 80 | GNU GENERAL PUBLIC LICENSE 81 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 82 | 83 | 0. This License applies to any program or other work which contains 84 | a notice placed by the copyright holder saying it may be distributed 85 | under the terms of this General Public License. The "Program", below, 86 | refers to any such program or work, and a "work based on the Program" 87 | means either the Program or any derivative work under copyright law: 88 | that is to say, a work containing the Program or a portion of it, 89 | either verbatim or with modifications and/or translated into another 90 | language. (Hereinafter, translation is included without limitation in 91 | the term "modification".) Each licensee is addressed as "you". 92 | 93 | Activities other than copying, distribution and modification are not 94 | covered by this License; they are outside its scope. The act of 95 | running the Program is not restricted, and the output from the Program 96 | is covered only if its contents constitute a work based on the 97 | Program (independent of having been made by running the Program). 98 | Whether that is true depends on what the Program does. 99 | 100 | 1. You may copy and distribute verbatim copies of the Program's 101 | source code as you receive it, in any medium, provided that you 102 | conspicuously and appropriately publish on each copy an appropriate 103 | copyright notice and disclaimer of warranty; keep intact all the 104 | notices that refer to this License and to the absence of any warranty; 105 | and give any other recipients of the Program a copy of this License 106 | along with the Program. 107 | 108 | You may charge a fee for the physical act of transferring a copy, and 109 | you may at your option offer warranty protection in exchange for a fee. 110 | 111 | 2. You may modify your copy or copies of the Program or any portion 112 | of it, thus forming a work based on the Program, and copy and 113 | distribute such modifications or work under the terms of Section 1 114 | above, provided that you also meet all of these conditions: 115 | 116 | a) You must cause the modified files to carry prominent notices 117 | stating that you changed the files and the date of any change. 118 | 119 | b) You must cause any work that you distribute or publish, that in 120 | whole or in part contains or is derived from the Program or any 121 | part thereof, to be licensed as a whole at no charge to all third 122 | parties under the terms of this License. 123 | 124 | c) If the modified program normally reads commands interactively 125 | when run, you must cause it, when started running for such 126 | interactive use in the most ordinary way, to print or display an 127 | announcement including an appropriate copyright notice and a 128 | notice that there is no warranty (or else, saying that you provide 129 | a warranty) and that users may redistribute the program under 130 | these conditions, and telling the user how to view a copy of this 131 | License. (Exception: if the Program itself is interactive but 132 | does not normally print such an announcement, your work based on 133 | the Program is not required to print an announcement.) 134 | 135 | These requirements apply to the modified work as a whole. If 136 | identifiable sections of that work are not derived from the Program, 137 | and can be reasonably considered independent and separate works in 138 | themselves, then this License, and its terms, do not apply to those 139 | sections when you distribute them as separate works. But when you 140 | distribute the same sections as part of a whole which is a work based 141 | on the Program, the distribution of the whole must be on the terms of 142 | this License, whose permissions for other licensees extend to the 143 | entire whole, and thus to each and every part regardless of who wrote it. 144 | 145 | Thus, it is not the intent of this section to claim rights or contest 146 | your rights to work written entirely by you; rather, the intent is to 147 | exercise the right to control the distribution of derivative or 148 | collective works based on the Program. 149 | 150 | In addition, mere aggregation of another work not based on the Program 151 | with the Program (or with a work based on the Program) on a volume of 152 | a storage or distribution medium does not bring the other work under 153 | the scope of this License. 154 | 155 | 3. You may copy and distribute the Program (or a work based on it, 156 | under Section 2) in object code or executable form under the terms of 157 | Sections 1 and 2 above provided that you also do one of the following: 158 | 159 | a) Accompany it with the complete corresponding machine-readable 160 | source code, which must be distributed under the terms of Sections 161 | 1 and 2 above on a medium customarily used for software interchange; or, 162 | 163 | b) Accompany it with a written offer, valid for at least three 164 | years, to give any third party, for a charge no more than your 165 | cost of physically performing source distribution, a complete 166 | machine-readable copy of the corresponding source code, to be 167 | distributed under the terms of Sections 1 and 2 above on a medium 168 | customarily used for software interchange; or, 169 | 170 | c) Accompany it with the information you received as to the offer 171 | to distribute corresponding source code. (This alternative is 172 | allowed only for noncommercial distribution and only if you 173 | received the program in object code or executable form with such 174 | an offer, in accord with Subsection b above.) 175 | 176 | The source code for a work means the preferred form of the work for 177 | making modifications to it. For an executable work, complete source 178 | code means all the source code for all modules it contains, plus any 179 | associated interface definition files, plus the scripts used to 180 | control compilation and installation of the executable. However, as a 181 | special exception, the source code distributed need not include 182 | anything that is normally distributed (in either source or binary 183 | form) with the major components (compiler, kernel, and so on) of the 184 | operating system on which the executable runs, unless that component 185 | itself accompanies the executable. 186 | 187 | If distribution of executable or object code is made by offering 188 | access to copy from a designated place, then offering equivalent 189 | access to copy the source code from the same place counts as 190 | distribution of the source code, even though third parties are not 191 | compelled to copy the source along with the object code. 192 | 193 | 4. You may not copy, modify, sublicense, or distribute the Program 194 | except as expressly provided under this License. Any attempt 195 | otherwise to copy, modify, sublicense or distribute the Program is 196 | void, and will automatically terminate your rights under this License. 197 | However, parties who have received copies, or rights, from you under 198 | this License will not have their licenses terminated so long as such 199 | parties remain in full compliance. 200 | 201 | 5. You are not required to accept this License, since you have not 202 | signed it. However, nothing else grants you permission to modify or 203 | distribute the Program or its derivative works. These actions are 204 | prohibited by law if you do not accept this License. Therefore, by 205 | modifying or distributing the Program (or any work based on the 206 | Program), you indicate your acceptance of this License to do so, and 207 | all its terms and conditions for copying, distributing or modifying 208 | the Program or works based on it. 209 | 210 | 6. Each time you redistribute the Program (or any work based on the 211 | Program), the recipient automatically receives a license from the 212 | original licensor to copy, distribute or modify the Program subject to 213 | these terms and conditions. You may not impose any further 214 | restrictions on the recipients' exercise of the rights granted herein. 215 | You are not responsible for enforcing compliance by third parties to 216 | this License. 217 | 218 | 7. If, as a consequence of a court judgment or allegation of patent 219 | infringement or for any other reason (not limited to patent issues), 220 | conditions are imposed on you (whether by court order, agreement or 221 | otherwise) that contradict the conditions of this License, they do not 222 | excuse you from the conditions of this License. If you cannot 223 | distribute so as to satisfy simultaneously your obligations under this 224 | License and any other pertinent obligations, then as a consequence you 225 | may not distribute the Program at all. For example, if a patent 226 | license would not permit royalty-free redistribution of the Program by 227 | all those who receive copies directly or indirectly through you, then 228 | the only way you could satisfy both it and this License would be to 229 | refrain entirely from distribution of the Program. 230 | 231 | If any portion of this section is held invalid or unenforceable under 232 | any particular circumstance, the balance of the section is intended to 233 | apply and the section as a whole is intended to apply in other 234 | circumstances. 235 | 236 | It is not the purpose of this section to induce you to infringe any 237 | patents or other property right claims or to contest validity of any 238 | such claims; this section has the sole purpose of protecting the 239 | integrity of the free software distribution system, which is 240 | implemented by public license practices. Many people have made 241 | generous contributions to the wide range of software distributed 242 | through that system in reliance on consistent application of that 243 | system; it is up to the author/donor to decide if he or she is willing 244 | to distribute software through any other system and a licensee cannot 245 | impose that choice. 246 | 247 | This section is intended to make thoroughly clear what is believed to 248 | be a consequence of the rest of this License. 249 | 250 | 8. If the distribution and/or use of the Program is restricted in 251 | certain countries either by patents or by copyrighted interfaces, the 252 | original copyright holder who places the Program under this License 253 | may add an explicit geographical distribution limitation excluding 254 | those countries, so that distribution is permitted only in or among 255 | countries not thus excluded. In such case, this License incorporates 256 | the limitation as if written in the body of this License. 257 | 258 | 9. The Free Software Foundation may publish revised and/or new versions 259 | of the General Public License from time to time. Such new versions will 260 | be similar in spirit to the present version, but may differ in detail to 261 | address new problems or concerns. 262 | 263 | Each version is given a distinguishing version number. If the Program 264 | specifies a version number of this License which applies to it and "any 265 | later version", you have the option of following the terms and conditions 266 | either of that version or of any later version published by the Free 267 | Software Foundation. If the Program does not specify a version number of 268 | this License, you may choose any version ever published by the Free Software 269 | Foundation. 270 | 271 | 10. If you wish to incorporate parts of the Program into other free 272 | programs whose distribution conditions are different, write to the author 273 | to ask for permission. For software which is copyrighted by the Free 274 | Software Foundation, write to the Free Software Foundation; we sometimes 275 | make exceptions for this. Our decision will be guided by the two goals 276 | of preserving the free status of all derivatives of our free software and 277 | of promoting the sharing and reuse of software generally. 278 | 279 | NO WARRANTY 280 | 281 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 282 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 283 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 284 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 285 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 286 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 287 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 288 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 289 | REPAIR OR CORRECTION. 290 | 291 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 292 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 293 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 294 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 295 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 296 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 297 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 298 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 299 | POSSIBILITY OF SUCH DAMAGES. 300 | 301 | END OF TERMS AND CONDITIONS 302 | 303 | How to Apply These Terms to Your New Programs 304 | 305 | If you develop a new program, and you want it to be of the greatest 306 | possible use to the public, the best way to achieve this is to make it 307 | free software which everyone can redistribute and change under these terms. 308 | 309 | To do so, attach the following notices to the program. It is safest 310 | to attach them to the start of each source file to most effectively 311 | convey the exclusion of warranty; and each file should have at least 312 | the "copyright" line and a pointer to where the full notice is found. 313 | 314 | 315 | Copyright (C) 316 | 317 | This program is free software; you can redistribute it and/or modify 318 | it under the terms of the GNU General Public License as published by 319 | the Free Software Foundation; either version 2 of the License, or 320 | (at your option) any later version. 321 | 322 | This program is distributed in the hope that it will be useful, 323 | but WITHOUT ANY WARRANTY; without even the implied warranty of 324 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 325 | GNU General Public License for more details. 326 | 327 | You should have received a copy of the GNU General Public License along 328 | with this program; if not, write to the Free Software Foundation, Inc., 329 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 330 | 331 | Also add information on how to contact you by electronic and paper mail. 332 | 333 | If the program is interactive, make it output a short notice like this 334 | when it starts in an interactive mode: 335 | 336 | Gnomovision version 69, Copyright (C) year name of author 337 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 338 | This is free software, and you are welcome to redistribute it 339 | under certain conditions; type `show c' for details. 340 | 341 | The hypothetical commands `show w' and `show c' should show the appropriate 342 | parts of the General Public License. Of course, the commands you use may 343 | be called something other than `show w' and `show c'; they could even be 344 | mouse-clicks or menu items--whatever suits your program. 345 | 346 | You should also get your employer (if you work as a programmer) or your 347 | school, if any, to sign a "copyright disclaimer" for the program, if 348 | necessary. Here is a sample; alter the names: 349 | 350 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 351 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 352 | 353 | , 1 April 1989 354 | Ty Coon, President of Vice 355 | 356 | This General Public License does not permit incorporating your program into 357 | proprietary programs. If your program is a subroutine library, you may 358 | consider it more useful to permit linking proprietary applications with the 359 | library. If this is what you want to do, use the GNU Lesser General 360 | Public License instead of this License. 361 | 362 | WRITTEN OFFER 363 | 364 | The source code for any program binaries or compressed scripts that are 365 | included with Radium One Click Demo Install can be freely obtained at the following URL: 366 | 367 | https://github.com/FrankM1/radium-one-click-demo-install 368 | --------------------------------------------------------------------------------