Changes in wp-all-import/trunk [2737093:2749264]
- Location:
- wp-all-import/trunk
- Files:
-
- 3 edited
-
classes/upload.php (modified) (1 diff)
-
plugin.php (modified) (1 diff)
-
readme.txt (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
wp-all-import/trunk/classes/upload.php
r2737093 r2749264 1 1 <?php 2 2 if ( ! class_exists('PMXI_Upload')){ 3 3 4 4 class PMXI_Upload{ 5 5 6 6 protected $file; 7 7 protected $errors; 8 8 protected $root_element = ''; 9 9 protected $is_csv = false; 10 10 11 protected $uploadsPath; 11 protected $uploadsPath; 12 12 13 13 function __construct( $file, $errors, $targetDir = false ){ 14 14 15 15 $this->file = $file; 16 16 $this->errors = $errors; 17 17 18 18 $uploads = wp_upload_dir(); 19 19 20 20 $input = new PMXI_Input(); 21 21 $import_id = $input->get('id'); 22 22 // Get import ID from cron processing URL. 23 23 if (empty($import_id)) { 24 24 $import_id = $input->get('import_id'); 25 25 } 26 26 // Get import ID from CLI arguments. 27 27 if (empty($import_id) && PMXI_Plugin::getInstance()->isCli()) { 28 28 global $argv; 29 29 foreach ($argv as $key => $arg) { 30 30 if ($arg === 'run' && !empty($argv[$key + 1])) { 31 31 $import_id = $argv[$key + 1]; 32 32 } 33 33 } 34 34 } 35 35 if ( $uploads['error'] ) { 36 36 $this->uploadsPath = false; 37 37 } else { 38 38 $this->uploadsPath = wp_all_import_get_absolute_path( ( ! $targetDir ) ? wp_all_import_secure_file($uploads['basedir'] . DIRECTORY_SEPARATOR . PMXI_Plugin::UPLOADS_DIRECTORY, $import_id, true) : $targetDir ); 39 39 } 40 40 } 41 41 42 42 public function upload() { 43 43 44 44 $this->file = wp_all_import_get_absolute_path($this->file); 45 45 46 $templates = false; 47 48 $bundle = array(); 46 $templates = false; 47 48 $bundle = array(); 49 49 50 50 $bundleFiles = array(); 51 51 52 52 $csv_path = ''; 53 53 54 54 if (empty($this->file)) { 55 $this->errors->add('form-validation', __('Please specify a file to import.<br/><br/>If you are uploading the file from your computer, please wait for it to finish uploading (progress bar at 100%), before trying to continue.', 'wp_all_import_plugin')); 55 $this->errors->add('form-validation', __('Please specify a file to import.<br/><br/>If you are uploading the file from your computer, please wait for it to finish uploading (progress bar at 100%), before trying to continue.', 'wp_all_import_plugin')); 56 56 } elseif (!is_file($this->file)) { 57 57 $this->errors->add('form-validation', __('Uploaded file is empty', 'wp_all_import_plugin')); 58 58 } elseif ( ! preg_match('%\W(xml|gzip|zip|csv|tsv|gz|json|txt|dat|psv|sql|xls|xlsx)$%i', trim(basename($this->file)))) { 59 59 $this->errors->add('form-validation', __('Uploaded file must be XML, CSV, ZIP, GZIP, GZ, JSON, SQL, TXT, DAT or PSV', 'wp_all_import_plugin')); 60 60 } elseif (preg_match('%\W(zip)$%i', trim(basename($this->file)))) { 61 61 62 62 if (!class_exists('PclZip')) { 63 63 require_once ABSPATH . 'wp-admin/includes/class-pclzip.php'; 64 64 } 65 65 66 66 $archive = new PclZip($this->file); 67 67 if (($v_result_list = $archive->extract(PCLZIP_OPT_PATH, $this->uploadsPath, PCLZIP_OPT_REPLACE_NEWER)) == 0) { 68 68 $this->errors->add('form-validation', __('WP All Import couldn\'t find a file to import inside your ZIP.<br/><br/>Either the .ZIP file is broken, or doesn\'t contain a file with an extension of XML, CSV, PSV, DAT, or TXT. <br/>Please attempt to unzip your .ZIP file on your computer to ensure it is a valid .ZIP file which can actually be unzipped, and that it contains a file which WP All Import can import.', 'wp_all_import_plugin')); 69 69 } else { 70 70 $filePath = ''; 71 71 $decodedTemplates = array(); 72 72 if ( ! empty($v_result_list) ) { 73 73 foreach ($v_result_list as $unzipped_file) { 74 if ($unzipped_file['status'] == 'ok' and preg_match('%\W(php)$%i', trim($unzipped_file['stored_filename']))) { 75 unlink($unzipped_file['filename']); 76 continue; 77 } 74 78 if ($unzipped_file['status'] == 'ok' and preg_match('%\W(xml|csv|txt|dat|psv|json|xls|xlsx|gz)$%i', trim($unzipped_file['stored_filename'])) and strpos($unzipped_file['stored_filename'], 'readme.txt') === false ) { 75 79 if ( strpos(basename($unzipped_file['stored_filename']), 'WP All Import Template') === 0 || strpos(basename($unzipped_file['stored_filename']), 'templates_') === 0 ) { 76 80 $templates = file_get_contents($unzipped_file['filename']); 77 81 $decodedTemplates = json_decode($templates, true); 78 82 $templateOptions = empty($decodedTemplates[0]) ? current($decodedTemplates) : $decodedTemplates; 79 83 if ( ! empty($templateOptions) and isset($templateOptions[0]['_import_type']) and $templateOptions[0]['_import_type'] == 'url' ) { 80 84 $options = maybe_unserialize($templateOptions[0]['options']); 81 85 return array( 82 'filePath' => $templateOptions[0]['_import_url'], 86 'filePath' => $templateOptions[0]['_import_url'], 83 87 'bundle' => $bundle, 84 'template' => json_encode($templateOptions), 85 'templates' => $templates, 88 'template' => json_encode($templateOptions), 89 'templates' => $templates, 86 90 'post_type' => (!empty($options)) ? $options['custom_type'] : false, 87 91 'taxonomy_type' => (!empty($options['taxonomy_type'])) ? $options['taxonomy_type'] : false, 88 92 'is_empty_bundle_file' => true 89 93 ); 90 94 } 91 95 } else { 92 96 if ($filePath == '') { 93 $filePath = $unzipped_file['filename']; 97 $filePath = $unzipped_file['filename']; 94 98 } 95 99 if ( ! in_array($unzipped_file['filename'], $bundleFiles) ) { 96 100 $bundleFiles[basename($unzipped_file['filename'])] = $unzipped_file['filename']; 97 101 } 98 102 } 99 103 } 100 104 } 101 105 } 102 106 103 107 if (count($bundleFiles) > 1) { 104 108 if ( ! empty($decodedTemplates) ) { 105 109 foreach ($decodedTemplates as $cpt => $tpl) { 106 110 $fileFormats = $this->get_xml_file( $bundleFiles[basename($tpl[0]['source_file_name'])] ); 107 111 $bundle[$cpt] = $fileFormats['xml']; 108 112 } 109 113 } 110 114 if ( ! empty($bundle)) $filePath = current($bundle); 111 } 115 } 112 116 113 117 if ( $this->uploadsPath === false ){ 114 118 $this->errors->add('form-validation', __('WP All Import can\'t access your WordPress uploads folder.', 'wp_all_import_plugin')); 115 119 } 116 120 117 121 if (empty($filePath)) { 118 122 $zip = zip_open(trim($this->file)); 119 if (is_resource($zip)) { 123 if (is_resource($zip)) { 120 124 while ($zip_entry = zip_read($zip)) { 121 $filePath = zip_entry_name($zip_entry); 122 $fp = fopen($this->uploadsPath."/".$filePath, "w"); 123 if (zip_entry_open($zip, $zip_entry, "r")) { 124 $buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)); 125 fwrite($fp,"$buf"); 126 zip_entry_close($zip_entry); 127 fclose($fp); 128 } 129 break; 125 $filePath = zip_entry_name($zip_entry); 126 if (preg_match('%\W(xml|csv|txt|dat|psv|json|xls|xlsx|gz)$%i', trim($filePath))) { 127 $fp = fopen($this->uploadsPath."/".$filePath, "w"); 128 if (zip_entry_open($zip, $zip_entry, "r")) { 129 $buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)); 130 fwrite($fp,"$buf"); 131 zip_entry_close($zip_entry); 132 fclose($fp); 133 } 134 break; 135 } 130 136 } 131 137 zip_close($zip); 132 138 } else { 133 $this->errors->add('form-validation', __('WP All Import couldn\'t find a file to import inside your ZIP.<br/><br/>Either the .ZIP file is broken, or doesn\'t contain a file with an extension of XML, CSV, PSV, DAT, or TXT. <br/>Please attempt to unzip your .ZIP file on your computer to ensure it is a valid .ZIP file which can actually be unzipped, and that it contains a file which WP All Import can import.', 'wp_all_import_plugin')); 134 } 135 } 136 // Detect if file is very large 139 $this->errors->add('form-validation', __('WP All Import couldn\'t find a file to import inside your ZIP.<br/><br/>Either the .ZIP file is broken, or doesn\'t contain a file with an extension of XML, CSV, PSV, DAT, or TXT. <br/>Please attempt to unzip your .ZIP file on your computer to ensure it is a valid .ZIP file which can actually be unzipped, and that it contains a file which WP All Import can import.', 'wp_all_import_plugin')); 140 } 141 } 142 // Detect if file is very large 137 143 $source = array( 138 144 'name' => basename($this->file), 139 'type' => 'upload', 140 'path' => $this->file, 145 'type' => 'upload', 146 'path' => $this->file, 141 147 ); 142 148 $fileFormats = $this->get_xml_file( $filePath ); 143 149 $filePath = $fileFormats['xml']; 144 150 $csv_path = $fileFormats['csv']; 145 151 } 146 152 } elseif ( preg_match('%\W(csv|txt|dat|psv|tsv)$%i', trim($this->file))) { // If CSV file uploaded 147 153 148 154 if ( $this->uploadsPath === false ){ 149 155 $this->errors->add('form-validation', __('WP All Import can\'t access your WordPress uploads folder.', 'wp_all_import_plugin')); 150 } 156 } 151 157 $filePath = $this->file; 152 158 $source = array( 153 159 'name' => basename($this->file), 154 160 'type' => 'upload', 155 161 'path' => $filePath, 156 ); 157 158 include_once(PMXI_Plugin::ROOT_DIR.'/libraries/XmlImportCsvParse.php'); 159 160 $csv = new PMXI_CsvParser( array( 'filename' => $this->file, 'targetDir' => $this->uploadsPath ) ); 162 ); 163 164 include_once(PMXI_Plugin::ROOT_DIR.'/libraries/XmlImportCsvParse.php'); 165 166 $csv = new PMXI_CsvParser( array( 'filename' => $this->file, 'targetDir' => $this->uploadsPath ) ); 161 167 //@unlink($filePath); 162 168 $csv_path = $filePath; 163 $filePath = $csv->xml_path; 169 $filePath = $csv->xml_path; 164 170 $this->is_csv = $csv->is_csv; 165 $this->root_element = 'node'; 166 171 $this->root_element = 'node'; 172 167 173 } elseif(preg_match('%\W(gz)$%i', trim($this->file))){ // If gz file uploaded 168 174 $fileInfo = wp_all_import_get_gz($this->file, 0, $this->uploadsPath); 169 175 if ( ! is_wp_error($fileInfo) ){ 170 176 $filePath = $fileInfo['localPath']; 171 // Detect if file is very large 177 // Detect if file is very large 172 178 $source = array( 173 179 'name' => basename($this->file), 174 180 'type' => 'upload', 175 'path' => $this->file, 181 'path' => $this->file, 176 182 ); 177 // detect CSV or XML 178 if ( $fileInfo['type'] == 'csv') { // it is CSV file 179 180 include_once(PMXI_Plugin::ROOT_DIR.'/libraries/XmlImportCsvParse.php'); 183 // detect CSV or XML 184 if ( $fileInfo['type'] == 'csv') { // it is CSV file 185 186 include_once(PMXI_Plugin::ROOT_DIR.'/libraries/XmlImportCsvParse.php'); 181 187 $csv = new PMXI_CsvParser( array( 'filename' => $filePath, 'targeDir' => $this->uploadsPath ) ); // create chunks 182 188 //@unlink($filePath); 183 189 $csv_path = $filePath; 184 190 $filePath = $csv->xml_path; 185 191 $this->is_csv = $csv->is_csv; 186 192 $this->root_element = 'node'; 187 193 } 188 194 } 189 195 else $this->errors->add('form-validation', $fileInfo->get_error_message()); 190 196 } elseif (preg_match('%\W(json)$%i', trim($this->file))){ 191 197 192 // Detect if file is very large 198 // Detect if file is very large 193 199 $source = array( 194 200 'name' => basename($this->file), 195 201 'type' => 'upload', 196 'path' => $this->file, 202 'path' => $this->file, 197 203 ); 198 204 199 205 $json_str = trim(file_get_contents($this->file)); 200 206 $json_str = str_replace("\xEF\xBB\xBF",'', $json_str); 201 207 $is_json = wp_all_import_is_json($json_str); 202 208 203 209 if( is_wp_error($is_json)){ 204 210 $this->errors->add('form-validation', $is_json->get_error_message(), 'wp_all_import_plugin'); 205 211 } else { 206 212 $xml_data = wp_all_import_json_to_xml( json_decode($json_str, true) ); 207 213 if ( empty($xml_data) ){ 208 $this->errors->add('form-validation', __('Can not import this file. JSON to XML convertation failed.', 'wp_all_import_plugin')); 214 $this->errors->add('form-validation', __('Can not import this file. JSON to XML convertation failed.', 'wp_all_import_plugin')); 209 215 } else{ 210 216 $jsontmpname = $this->uploadsPath .'/'. wp_all_import_url_title(wp_unique_filename($this->uploadsPath, str_replace("json", "xml", basename($this->file)))); 211 217 //@unlink($this->file); 212 218 file_put_contents($jsontmpname, $xml_data); 213 $filePath = $jsontmpname; 214 219 $filePath = $jsontmpname; 220 215 221 } 216 222 } 217 223 } elseif (preg_match('%\W(sql)$%i', trim($this->file))) { 218 224 $source = array( 219 225 'name' => basename($this->file), 220 226 'type' => 'upload', 221 'path' => $this->file, 227 'path' => $this->file, 222 228 ); 223 229 include_once( PMXI_Plugin::ROOT_DIR . '/libraries/XmlImportSQLParse.php' ); 224 230 $sql = new PMXI_SQLParser( $this->file, $this->uploadsPath ); 225 231 $filePath = $sql->parse(); 226 232 } elseif (preg_match('%\W(xls|xlsx)$%i', trim($this->file))){ 227 233 $source = array( 228 234 'name' => basename($this->file), 229 235 'type' => 'upload', 230 'path' => $this->file, 236 'path' => $this->file, 231 237 ); 232 238 233 239 include_once( PMXI_Plugin::ROOT_DIR . '/libraries/XmlImportXLSParse.php' ); 234 240 $xls = new PMXI_XLSParser( $this->file, $this->uploadsPath ); 235 241 $filePath = $xls->parse(); 236 242 } else { // If XML file uploaded 237 243 $filePath = $this->file; 238 244 $source = array( 239 245 'name' => basename($this->file), 240 246 'type' => 'upload', 241 247 'path' => $filePath, 242 248 ); 243 } 249 } 244 250 245 251 if ( $this->errors->get_error_codes() ) return $this->errors; 246 252 247 $decodedTemplates = empty($templates) ? false : json_decode($templates, true); 248 249 $source['path'] = wp_all_import_get_relative_path($source['path']); 250 253 $decodedTemplates = empty($templates) ? false : json_decode($templates, true); 254 255 $source['path'] = wp_all_import_get_relative_path($source['path']); 256 251 257 $templateOptions = ""; 252 258 253 259 if ( is_array($decodedTemplates) ) { 254 260 $templateOptions = empty($decodedTemplates[0]) ? current($decodedTemplates) : $decodedTemplates; 255 } 256 257 $options = (empty($templateOptions[0]['options'])) ? false : maybe_unserialize($templateOptions[0]['options']); 261 } 262 263 $options = (empty($templateOptions[0]['options'])) ? false : maybe_unserialize($templateOptions[0]['options']); 258 264 259 265 if ( ! empty($options['root_element'])) $this->root_element = $options['root_element']; 260 266 261 267 return array( 262 268 'filePath' => $filePath, 263 269 'bundle' => $bundle, // sub imports [cpt => filepath] 264 270 'source' => $source, 265 271 'root_element' => $this->root_element, 266 272 'is_csv' => $this->is_csv, 267 273 'csv_path' => $csv_path, 268 274 'template' => empty($templateOptions) ? "" : json_encode($templateOptions), 269 275 'templates' => $templates, 270 276 'post_type' => (!empty($options)) ? $options['custom_type'] : false, 271 277 'taxonomy_type' => (!empty($options['taxonomy_type'])) ? $options['taxonomy_type'] : false, 272 278 ); 273 279 } 274 280 275 281 public function url( $feed_type = '', $feed_xpath = '', $importTemplate = ''){ 276 282 277 283 $uploads = wp_upload_dir(); 278 284 279 285 $templates = false; 280 286 281 $bundle = array(); 287 $bundle = array(); 282 288 283 289 $bundleFiles = array(); 284 290 285 291 if (empty($this->file)) { 286 $this->errors->add('form-validation', __('Please specify a file to import.', 'wp_all_import_plugin')); 292 $this->errors->add('form-validation', __('Please specify a file to import.', 'wp_all_import_plugin')); 287 293 } elseif ( ! preg_match('%^https?://%i', $this->file)) { 288 $this->errors->add('form-validation', __('The URL to your file is not valid.<br/><br/>Please make sure the URL starts with http:// or https://. To import from https://, your server must have OpenSSL installed.'), 'wp_all_import_plugin'); 294 $this->errors->add('form-validation', __('The URL to your file is not valid.<br/><br/>Please make sure the URL starts with http:// or https://. To import from https://, your server must have OpenSSL installed.'), 'wp_all_import_plugin'); 289 295 } elseif( ! is_writeable($this->uploadsPath)){ 290 296 $this->errors->add('form-validation', __('Uploads folder '.$this->uploadsPath.' is not writable.'), 'wp_all_import_plugin'); 291 297 } 292 298 293 299 $this->file = trim($this->file); 294 300 295 301 $csv_path = ''; 296 302 297 303 if ( empty($this->errors->errors) ){ 298 304 299 305 if( '' == $feed_type and ! preg_match('%\W(xml|csv|zip|gz|xls|xlsx)$%i', trim($this->file))) $feed_type = wp_all_import_get_remote_file_name(trim($this->file)); 300 306 301 if ('zip' == $feed_type or empty($feed_type) and preg_match('%\W(zip)$%i', trim($this->file))) { 302 307 if ('zip' == $feed_type or empty($feed_type) and preg_match('%\W(zip)$%i', trim($this->file))) { 308 303 309 $tmpname = $this->uploadsPath . '/' . wp_unique_filename($this->uploadsPath, md5(basename($this->file)) . '.zip'); 304 305 @copy($this->file, $tmpname); 306 307 if (!file_exists($tmpname)) { 310 311 @copy($this->file, $tmpname); 312 313 if (!file_exists($tmpname)) { 308 314 $request = get_file_curl($this->file, $tmpname); 309 if (is_wp_error($request)) $this->errors->add('form-validation', $request->get_error_message()); 310 if (!file_exists($tmpname)) $this->errors->add('form-validation', __('Failed upload ZIP archive', 'wp_all_import_plugin')); 315 if (is_wp_error($request)) $this->errors->add('form-validation', $request->get_error_message()); 316 if (!file_exists($tmpname)) $this->errors->add('form-validation', __('Failed upload ZIP archive', 'wp_all_import_plugin')); 311 317 } 312 318 313 319 if (!class_exists('PclZip')) { 314 320 require_once ABSPATH . 'wp-admin/includes/class-pclzip.php'; 315 321 } 316 322 317 323 $archive = new PclZip($tmpname); 318 324 if (($v_result_list = $archive->extract(PCLZIP_OPT_PATH, $this->uploadsPath, PCLZIP_OPT_REPLACE_NEWER)) == 0) { 319 325 $this->errors->add('form-validation', __('WP All Import couldn\'t find a file to import inside your ZIP.<br/><br/>Either the .ZIP file is broken, or doesn\'t contain a file with an extension of XML, CSV, PSV, DAT, or TXT. <br/>Please attempt to unzip your .ZIP file on your computer to ensure it is a valid .ZIP file which can actually be unzipped, and that it contains a file which WP All Import can import.', 'wp_all_import_plugin')); 320 326 } else { 321 327 $filePath = ''; 322 328 if (!empty($v_result_list)) { 323 329 foreach ($v_result_list as $unzipped_file) { 330 if ($unzipped_file['status'] == 'ok' and preg_match('%\W(php)$%i', trim($unzipped_file['stored_filename']))) { 331 unlink($unzipped_file['filename']); 332 continue; 333 } 324 334 if ($unzipped_file['status'] == 'ok' and preg_match('%\W(xml|csv|txt|dat|psv|json|xls|xlsx|gz)$%i', trim($unzipped_file['stored_filename'])) and strpos($unzipped_file['stored_filename'], 'readme.txt') === false ) { 325 335 if ( strpos(basename($unzipped_file['stored_filename']), 'WP All Import Template') === 0 || strpos(basename($unzipped_file['stored_filename']), 'templates_') === 0) { 326 336 $templates = file_get_contents($unzipped_file['filename']); 327 337 $decodedTemplates = json_decode($templates, true); 328 $templateOptions = empty($decodedTemplates[0]) ? current($decodedTemplates) : $decodedTemplates; 338 $templateOptions = empty($decodedTemplates[0]) ? current($decodedTemplates) : $decodedTemplates; 329 339 } 330 340 else { 331 341 if ($filePath == '') { 332 $filePath = $unzipped_file['filename']; 342 $filePath = $unzipped_file['filename']; 333 343 } 334 344 if ( ! in_array($unzipped_file['filename'], $bundleFiles) ) { 335 345 $bundleFiles[basename($unzipped_file['filename'])] = $unzipped_file['filename']; 336 } 346 } 337 347 } 338 348 } 339 349 } 340 350 } 341 351 342 352 if ( count($bundleFiles) > 1 ) { 343 353 if ( ! empty($decodedTemplates) ) { 344 354 foreach ($decodedTemplates as $cpt => $tpl) { 345 355 $fileFormats = $this->get_xml_file( $bundleFiles[basename($tpl[0]['source_file_name'])] ); 346 356 $bundle[$cpt] = $fileFormats['xml']; 347 357 } 348 358 } 349 359 if ( ! empty($bundle)) $filePath = current($bundle); 350 } 360 } 351 361 352 362 if($this->uploadsPath === false){ 353 363 $this->errors->add('form-validation', __('WP All Import can\'t access your WordPress uploads folder.', 'wp_all_import_plugin')); 354 } 355 356 if(empty($filePath)){ 364 } 365 366 if(empty($filePath)){ 357 367 $zip = zip_open(trim($tmpname)); 358 if (is_resource($zip)) { 368 if (is_resource($zip)) { 359 369 while ($zip_entry = zip_read($zip)) { 360 $filePath = zip_entry_name($zip_entry); 361 $fp = fopen($this->uploadsPath."/".$filePath, "w"); 362 if (zip_entry_open($zip, $zip_entry, "r")) { 363 $buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)); 364 fwrite($fp,"$buf"); 365 zip_entry_close($zip_entry); 366 fclose($fp); 367 } 368 break; 370 $filePath = zip_entry_name($zip_entry); 371 if (preg_match('%\W(xml|csv|txt|dat|psv|json|xls|xlsx|gz)$%i', trim($filePath))) { 372 $fp = fopen($this->uploadsPath . "/" . $filePath, "w"); 373 if (zip_entry_open($zip, $zip_entry, "r")) { 374 $buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)); 375 fwrite($fp, "$buf"); 376 zip_entry_close($zip_entry); 377 fclose($fp); 378 } 379 break; 380 } 369 381 } 370 382 zip_close($zip); 371 383 } else { 372 $this->errors->add('form-validation', __('WP All Import couldn\'t find a file to import inside your ZIP.<br/><br/>Either the .ZIP file is broken, or doesn\'t contain a file with an extension of XML, CSV, PSV, DAT, or TXT. <br/>Please attempt to unzip your .ZIP file on your computer to ensure it is a valid .ZIP file which can actually be unzipped, and that it contains a file which WP All Import can import.', 'wp_all_import_plugin')); 373 } 374 } 375 // Detect if file is very large 384 $this->errors->add('form-validation', __('WP All Import couldn\'t find a file to import inside your ZIP.<br/><br/>Either the .ZIP file is broken, or doesn\'t contain a file with an extension of XML, CSV, PSV, DAT, or TXT. <br/>Please attempt to unzip your .ZIP file on your computer to ensure it is a valid .ZIP file which can actually be unzipped, and that it contains a file which WP All Import can import.', 'wp_all_import_plugin')); 385 } 386 } 387 // Detect if file is very large 376 388 $source = array( 377 389 'name' => basename(parse_url($this->file, PHP_URL_PATH)), 378 390 'type' => 'url', 379 'path' => $feed_xpath, 391 'path' => $feed_xpath, 380 392 ); 381 393 $fileFormats = $this->get_xml_file( $filePath ); 382 394 $csv_path = $fileFormats['csv']; 383 395 $filePath = $fileFormats['xml']; 384 396 } 385 397 if (file_exists($tmpname)) wp_all_import_remove_source($tmpname, false); 386 398 } elseif ('csv' == $feed_type or '' == $feed_type and preg_match('%\W(csv|txt|dat|psv|tsv)$%i', trim($this->file))) { 387 399 388 400 $source = array( 389 401 'name' => basename(parse_url($this->file, PHP_URL_PATH)), 390 402 'type' => 'url', 391 'path' => $feed_xpath, 403 'path' => $feed_xpath, 392 404 ); 393 405 // copy remote file in binary mode 394 406 $filePath = wp_all_import_get_url($this->file, $this->uploadsPath, 'csv'); 395 407 if ( ! is_wp_error($filePath) ){ 396 408 if ( ! file_exists($filePath)) { 397 $this->errors->add('form-validation', __('WP All Import was not able to download your file.<br/><br/>Please make sure the URL to your file is valid.<br/>You can test this by pasting it into your browser.<br/>Other reasons for this error can include some server setting on your host restricting access to this particular URL or external URLs in general, or some setting on the server hosting the file you are trying to access preventing your server from accessing it.', 'wp_all_import_plugin')); 398 } 399 // Detect if file is very large 400 include_once(PMXI_Plugin::ROOT_DIR.'/libraries/XmlImportCsvParse.php'); 409 $this->errors->add('form-validation', __('WP All Import was not able to download your file.<br/><br/>Please make sure the URL to your file is valid.<br/>You can test this by pasting it into your browser.<br/>Other reasons for this error can include some server setting on your host restricting access to this particular URL or external URLs in general, or some setting on the server hosting the file you are trying to access preventing your server from accessing it.', 'wp_all_import_plugin')); 410 } 411 // Detect if file is very large 412 include_once(PMXI_Plugin::ROOT_DIR.'/libraries/XmlImportCsvParse.php'); 401 413 $csv = new PMXI_CsvParser( array( 'filename' => $filePath, 'targetDir' => $this->uploadsPath ) ); // create chunks 402 414 //wp_all_import_remove_source($filePath, false); 403 415 $csv_path = $filePath; 404 416 $filePath = $csv->xml_path; 405 417 $this->is_csv = $csv->is_csv; 406 418 $this->root_element = 'node'; 407 419 } 408 420 else $this->errors->add('form-validation', $filePath->get_error_message()); 409 421 410 422 } elseif ('json' == $feed_type or preg_match('%\W(json)$%i', trim($this->file))){ 411 423 412 424 $source = array( 413 425 'name' => basename(parse_url($this->file, PHP_URL_PATH)), 414 426 'type' => 'url', 415 'path' => $feed_xpath, 427 'path' => $feed_xpath, 416 428 ); 417 429 // copy remote file in binary mode 418 430 $filePath = wp_all_import_get_url($this->file, $this->uploadsPath, 'json'); 419 431 $json_str = file_get_contents($filePath); 420 432 $json_str = str_replace("\xEF\xBB\xBF",'', $json_str); 421 433 $is_json = wp_all_import_is_json($json_str); 422 434 if ( is_wp_error($is_json)){ 423 435 $this->errors->add('form-validation', $is_json->get_error_message(), 'wp_all_import_plugin'); 424 436 } else { 425 437 $xml_data = wp_all_import_json_to_xml( json_decode($json_str, true) ); 426 438 if ( empty($xml_data) ){ 427 $this->errors->add('form-validation', __('Can not import this file. JSON to XML convertation failed.', 'wp_all_import_plugin')); 439 $this->errors->add('form-validation', __('Can not import this file. JSON to XML convertation failed.', 'wp_all_import_plugin')); 428 440 } else { 429 $tmpname = $this->uploadsPath .'/'. wp_all_import_url_title(wp_unique_filename($this->uploadsPath, str_replace("json", "xml", basename($filePath)))); 441 $tmpname = $this->uploadsPath .'/'. wp_all_import_url_title(wp_unique_filename($this->uploadsPath, str_replace("json", "xml", basename($filePath)))); 430 442 file_put_contents($tmpname, $xml_data); 431 443 wp_all_import_remove_source($filePath, false); 432 $filePath = $tmpname; 444 $filePath = $tmpname; 433 445 } 434 446 } 435 447 } elseif ('sql' == $feed_type or preg_match('%\W(sql)$%i', trim($this->file))){ 436 448 $source = array( 437 449 'name' => basename($this->file), 438 450 'type' => 'url', 439 'path' => $feed_xpath, 451 'path' => $feed_xpath, 440 452 ); 441 453 // copy remote file in binary mode 442 454 $localSQLPath = wp_all_import_get_url($this->file, $this->uploadsPath, 'sql'); 443 455 include_once( PMXI_Plugin::ROOT_DIR . '/libraries/XmlImportSQLParse.php' ); 444 $sql = new PMXI_SQLParser( $localSQLPath, $this->uploadsPath ); 445 $filePath = $sql->parse(); 456 $sql = new PMXI_SQLParser( $localSQLPath, $this->uploadsPath ); 457 $filePath = $sql->parse(); 446 458 wp_all_import_remove_source($localSQLPath, false); 447 459 } elseif (preg_match('%\W(xls|xlsx)$%i', $feed_type) || preg_match('%\W(xls|xlsx)$%i', strtok(trim($this->file), "?")) || preg_match('%\W(xls|xlsx)$%i', trim($this->file))) { 448 460 449 461 $source = array( 450 462 'name' => basename($this->file), 451 463 'type' => 'url', 452 'path' => $feed_xpath, 464 'path' => $feed_xpath, 453 465 ); 454 466 // copy remote file in binary mode 455 467 $localXLSPath = wp_all_import_get_url($this->file, $this->uploadsPath, 'xls'); 456 468 include_once( PMXI_Plugin::ROOT_DIR . '/libraries/XmlImportXLSParse.php' ); 457 $xls = new PMXI_XLSParser( $localXLSPath, $this->uploadsPath ); 458 $filePath = $xls->parse(); 469 $xls = new PMXI_XLSParser( $localXLSPath, $this->uploadsPath ); 470 $filePath = $xls->parse(); 459 471 wp_all_import_remove_source($localXLSPath, false); 460 472 } else { 461 473 if ('gz' == $feed_type or '' == $feed_type and preg_match('%\W(gz|gzip)$%i', trim($this->file))){ 462 $fileInfo = wp_all_import_get_gz($this->file, 0, $this->uploadsPath); 474 $fileInfo = wp_all_import_get_gz($this->file, 0, $this->uploadsPath); 463 475 } else { 464 476 $headers = wp_all_import_get_feed_type($this->file); 465 if ($headers['Content-Type'] and in_array($headers['Content-Type'], array('gz', 'gzip')) or $headers['Content-Encoding'] and in_array($headers['Content-Encoding'], array('gz', 'gzip'))){ 477 if ($headers['Content-Type'] and in_array($headers['Content-Type'], array('gz', 'gzip')) or $headers['Content-Encoding'] and in_array($headers['Content-Encoding'], array('gz', 'gzip'))){ 466 478 $fileInfo = wp_all_import_get_gz($this->file, 0, $this->uploadsPath, $headers); 467 479 } else { 468 480 $fileInfo = wp_all_import_get_url($this->file, $this->uploadsPath, $headers['Content-Type'], $headers['Content-Encoding'], true); 469 } 470 } 471 481 } 482 } 483 472 484 if ( ! is_wp_error($fileInfo) ){ 473 485 $filePath = $fileInfo['localPath']; 474 486 if ( ! file_exists($filePath)) { 475 $this->errors->add('form-validation', __('WP All Import was not able to download your file.<br/><br/>Please make sure the URL to your file is valid.<br/>You can test this by pasting it into your browser.<br/>Other reasons for this error can include some server setting on your host restricting access to this particular URL or external URLs in general, or some setting on the server hosting the file you are trying to access preventing your server from accessing it.', 'wp_all_import_plugin')); 476 } 477 // Detect if file is very large 487 $this->errors->add('form-validation', __('WP All Import was not able to download your file.<br/><br/>Please make sure the URL to your file is valid.<br/>You can test this by pasting it into your browser.<br/>Other reasons for this error can include some server setting on your host restricting access to this particular URL or external URLs in general, or some setting on the server hosting the file you are trying to access preventing your server from accessing it.', 'wp_all_import_plugin')); 488 } 489 // Detect if file is very large 478 490 $source = array( 479 491 'name' => basename(parse_url($this->file, PHP_URL_PATH)), 480 492 'type' => 'url', 481 'path' => $feed_xpath, 493 'path' => $feed_xpath, 482 494 ); 483 495 $fileInfo['type'] = apply_filters('wp_all_import_feed_type', $fileInfo['type'], $this->file); 484 // detect CSV or XML 496 // detect CSV or XML 485 497 switch ($fileInfo['type']) { 486 498 case 'csv': 487 include_once(PMXI_Plugin::ROOT_DIR.'/libraries/XmlImportCsvParse.php'); 499 include_once(PMXI_Plugin::ROOT_DIR.'/libraries/XmlImportCsvParse.php'); 488 500 $csv = new PMXI_CsvParser( array( 'filename' => $filePath, 'targetDir' => $this->uploadsPath ) ); // create chunks 489 501 $csv_path = $filePath; 490 502 //wp_all_import_remove_source($filePath, false); 491 503 $filePath = $csv->xml_path; 492 504 $this->is_csv = $csv->is_csv; 493 $this->root_element = 'node'; 505 $this->root_element = 'node'; 494 506 break; 495 507 case 'json': 496 508 $json_str = file_get_contents($filePath); 497 509 $json_str = str_replace("\xEF\xBB\xBF",'', $json_str); 498 510 $is_json = wp_all_import_is_json($json_str); 499 511 500 512 if( is_wp_error($is_json)){ 501 513 $this->errors->add('form-validation', $is_json->get_error_message(), 'wp_all_import_plugin'); 502 514 } else { 503 515 $xml_data = wp_all_import_json_to_xml( json_decode($json_str, true) ); 504 516 if ( empty($xml_data) ) { 505 $this->errors->add('form-validation', __('Can not import this file. JSON to XML convertation failed.', 'wp_all_import_plugin')); 517 $this->errors->add('form-validation', __('Can not import this file. JSON to XML convertation failed.', 'wp_all_import_plugin')); 506 518 } else { 507 $tmpname = $this->uploadsPath .'/'. wp_all_import_url_title(wp_unique_filename($this->uploadsPath, str_replace("json", "xml", basename($filePath)))); 519 $tmpname = $this->uploadsPath .'/'. wp_all_import_url_title(wp_unique_filename($this->uploadsPath, str_replace("json", "xml", basename($filePath)))); 508 520 file_put_contents($tmpname, $xml_data); 509 521 wp_all_import_remove_source($filePath, false); 510 $filePath = $tmpname; 522 $filePath = $tmpname; 511 523 } 512 524 } 513 525 break; 514 526 case 'sql': 515 527 include_once( PMXI_Plugin::ROOT_DIR . '/libraries/XmlImportSQLParse.php' ); 516 $sql = new PMXI_SQLParser( $filePath, $this->uploadsPath ); 528 $sql = new PMXI_SQLParser( $filePath, $this->uploadsPath ); 517 529 $filePath = $sql->parse(); 518 break; 530 break; 519 531 default: 520 532 # code... 521 533 break; 522 534 } 523 535 } 524 536 else $this->errors->add('form-validation', $fileInfo->get_error_message()); 525 537 } 526 538 } 527 539 528 540 if ( $this->errors->get_error_codes() ) return $this->errors; 529 541 530 $decodedTemplates = empty($templates) ? json_decode($importTemplate, true) : json_decode($templates, true); 531 542 $decodedTemplates = empty($templates) ? json_decode($importTemplate, true) : json_decode($templates, true); 543 532 544 $templateOptions = ""; 533 545 534 546 if ( is_array($decodedTemplates) and ! empty($decodedTemplates)) { 535 547 $templateOptions = empty($decodedTemplates[0]) ? current($decodedTemplates) : $decodedTemplates; 536 548 } 537 549 538 $options = (empty($templateOptions[0]['options'])) ? false : maybe_unserialize($templateOptions[0]['options']); 550 $options = (empty($templateOptions[0]['options'])) ? false : maybe_unserialize($templateOptions[0]['options']); 539 551 540 552 if ( ! empty($options['root_element'])) $this->root_element = $options['root_element']; 541 553 542 554 return array( 543 555 'filePath' => $filePath, 544 556 'bundle' => $bundle, 545 557 'source' => $source, 546 558 'root_element' => $this->root_element, 547 559 'feed_type' => $feed_type, 548 560 'is_csv' => $this->is_csv, 549 561 'csv_path' => $csv_path, 550 562 'template' => empty($templateOptions) ? "" : json_encode($templateOptions), 551 563 'templates' => $templates, 552 564 'post_type' => (!empty($options)) ? $options['custom_type'] : false, 553 565 'taxonomy_type' => (!empty($options['taxonomy_type'])) ? $options['taxonomy_type'] : false, 554 566 ); 555 567 } 556 568 557 569 protected function get_xml_file( $filePath ) 558 570 { 559 571 $csv_path = ''; 560 572 561 573 if (preg_match('%\W(csv|txt|dat|psv|tsv)$%i', trim($filePath))){ // If CSV file found in archieve 562 574 563 575 if($this->uploadsPath === false){ 564 576 $this->errors->add('form-validation', __('WP All Import can\'t access your WordPress uploads folder.', 'wp_all_import_plugin')); 565 } 566 577 } 578 567 579 include_once(PMXI_Plugin::ROOT_DIR.'/libraries/XmlImportCsvParse.php'); 568 580 $csv = new PMXI_CsvParser( array( 'filename' => $filePath, 'targetDir' => $this->uploadsPath ) ); // create chunks 569 581 570 582 $csv_path = $filePath; 571 583 572 584 $filePath = $csv->xml_path; 573 585 $this->is_csv = $csv->is_csv; 574 $this->root_element = 'node'; 575 586 $this->root_element = 'node'; 587 576 588 } elseif (preg_match('%\W(json)$%i', trim($filePath))){ 577 589 578 590 $json_str = file_get_contents($filePath); 579 591 $json_str = str_replace("\xEF\xBB\xBF",'', $json_str); 580 592 $is_json = wp_all_import_is_json($json_str); 581 593 582 594 if( is_wp_error($is_json)){ 583 595 $this->errors->add('form-validation', $is_json->get_error_message(), 'wp_all_import_plugin'); 584 596 } 585 else{ 586 597 else{ 598 587 599 $xml_data = wp_all_import_json_to_xml( json_decode($json_str, true) ); 588 600 589 601 if ( empty($xml_data) ){ 590 $this->errors->add('form-validation', __('Can not import this file. JSON to XML convertation failed.', 'wp_all_import_plugin')); 602 $this->errors->add('form-validation', __('Can not import this file. JSON to XML convertation failed.', 'wp_all_import_plugin')); 591 603 } 592 604 else{ 593 $jsontmpname = $this->uploadsPath .'/'. wp_all_import_url_title(wp_unique_filename($this->uploadsPath, str_replace("json", "xml", basename($filePath)))); 605 $jsontmpname = $this->uploadsPath .'/'. wp_all_import_url_title(wp_unique_filename($this->uploadsPath, str_replace("json", "xml", basename($filePath)))); 594 606 file_put_contents($jsontmpname, $xml_data); 595 607 wp_all_import_remove_source($filePath, false); 596 608 $filePath = $jsontmpname; 597 609 } 598 610 } 599 611 600 612 } 601 613 elseif (preg_match('%\W(sql)$%i', trim($filePath))){ 602 614 603 include_once( PMXI_Plugin::ROOT_DIR . '/libraries/XmlImportSQLParse.php' ); 615 include_once( PMXI_Plugin::ROOT_DIR . '/libraries/XmlImportSQLParse.php' ); 604 616 605 617 $localSQLPath = $filePath; 606 618 $sql = new PMXI_SQLParser( $localSQLPath, $this->uploadsPath ); 607 619 $filePath = $sql->parse(); 608 620 wp_all_import_remove_source($localSQLPath, false); 609 } 621 } 610 622 elseif (preg_match('%\W(xls|xlsx)$%i', trim($filePath))){ 611 623 612 include_once( PMXI_Plugin::ROOT_DIR . '/libraries/XmlImportXLSParse.php' ); 613 614 $localXLSPath = $filePath; 615 $xls = new PMXI_XLSParser( $localXLSPath, $this->uploadsPath ); 616 $filePath = $xls->parse(); 624 include_once( PMXI_Plugin::ROOT_DIR . '/libraries/XmlImportXLSParse.php' ); 625 626 $localXLSPath = $filePath; 627 $xls = new PMXI_XLSParser( $localXLSPath, $this->uploadsPath ); 628 $filePath = $xls->parse(); 617 629 wp_all_import_remove_source($localXLSPath, false); 618 630 619 631 } 620 632 elseif(preg_match('%\W(gz)$%i', trim($filePath))) { // If gz file uploaded 621 633 622 634 $fileInfo = wp_all_import_get_gz($filePath, 0, $this->uploadsPath); 623 635 624 636 if (!is_wp_error($fileInfo)) { 625 637 626 638 $filePath = $fileInfo['localPath']; 627 639 628 640 // detect CSV or XML 629 641 if ($fileInfo['type'] == 'csv') { // it is CSV file 630 642 631 643 include_once(PMXI_Plugin::ROOT_DIR . '/libraries/XmlImportCsvParse.php'); 632 644 $csv_path = $filePath; 633 645 $csv = new PMXI_CsvParser(array( 634 646 'filename' => $filePath, 635 647 'targeDir' => $this->uploadsPath 636 648 )); // create chunks 637 649 //@unlink($filePath); 638 650 $filePath = $csv->xml_path; 639 651 $this->is_csv = $csv->is_csv; 640 652 $this->root_element = 'node'; 641 653 642 654 } 643 655 644 656 } 645 657 else $this->errors->add('form-validation', $fileInfo->get_error_message()); 646 658 } 647 659 648 660 return array( 649 661 'csv' => $csv_path, 650 662 'xml' => $filePath 651 663 ); 652 664 } 653 665 } 654 666 } -
wp-all-import/trunk/plugin.php
r2737093 r2749264 1 1 <?php 2 2 /* 3 3 Plugin Name: WP All Import 4 4 Plugin URI: http://www.wpallimport.com/wordpress-xml-csv-import/?utm_source=import-plugin-free&utm_medium=wp-plugins-page&utm_campaign=upgrade-to-pro 5 5 Description: The most powerful solution for importing XML and CSV files to WordPress. Create Posts and Pages with content from any XML or CSV file. A paid upgrade to WP All Import Pro is available for support and additional features. 6 Version: 3.6. 76 Version: 3.6.8 7 7 Author: Soflyy 8 8 */ 9 9 10 10 /** 11 11 * Plugin root dir with forward slashes as directory separator regardless of actuall DIRECTORY_SEPARATOR value 12 12 * @var string 13 13 */ 14 14 define('WP_ALL_IMPORT_ROOT_DIR', str_replace('\\', '/', dirname(__FILE__))); 15 15 /** 16 16 * Plugin root url for referencing static content 17 17 * @var string 18 18 */ 19 19 define('WP_ALL_IMPORT_ROOT_URL', rtrim(plugin_dir_url(__FILE__), '/')); 20 20 /** 21 21 * Plugin prefix for making names unique (be aware that this variable is used in conjuction with naming convention, 22 22 * i.e. in order to change it one must not only modify this constant but also rename all constants, classes and functions which 23 23 * names composed using this prefix) 24 24 * @var string 25 25 */ 26 26 define('WP_ALL_IMPORT_PREFIX', 'pmxi_'); 27 27 28 define('PMXI_VERSION', '3.6. 7');28 define('PMXI_VERSION', '3.6.8'); 29 29 30 30 define('PMXI_EDITION', 'free'); 31 31 32 32 /** 33 33 * Plugin root uploads folder name 34 34 * @var string 35 35 */ 36 36 define('WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY', 'wpallimport'); 37 37 /** 38 38 * Plugin logs folder name 39 39 * @var string 40 40 */ 41 41 define('WP_ALL_IMPORT_LOGS_DIRECTORY', WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'logs'); 42 42 /** 43 43 * Plugin files folder name 44 44 * @var string 45 45 */ 46 46 define('WP_ALL_IMPORT_FILES_DIRECTORY', WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'files'); 47 47 /** 48 48 * Plugin uploads folder name 49 49 * @var string 50 50 */ 51 51 define('WP_ALL_IMPORT_UPLOADS_DIRECTORY', WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'uploads'); 52 52 /** 53 53 * Plugin history folder name 54 54 * @var string 55 55 */ 56 56 define('WP_ALL_IMPORT_HISTORY_DIRECTORY', WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'history'); 57 57 /** 58 58 * Plugin temp folder name 59 59 * @var string 60 60 */ 61 61 define('WP_ALL_IMPORT_TEMP_DIRECTORY', WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'temp'); 62 62 63 63 /** 64 64 * Main plugin file, Introduces MVC pattern 65 65 * 66 66 * @singletone 67 67 * @author Maksym Tsypliakov <maksym.tsypliakov@gmail.com> 68 68 */ 69 69 final class PMXI_Plugin { 70 70 /** 71 71 * Singletone instance 72 72 * @var PMXI_Plugin 73 73 */ 74 74 protected static $instance; 75 75 76 76 /** 77 77 * Plugin options 78 78 * @var array 79 79 */ 80 80 protected $options = array(); 81 81 82 82 /** 83 83 * Plugin root dir 84 84 * @var string 85 85 */ 86 86 const ROOT_DIR = WP_ALL_IMPORT_ROOT_DIR; 87 87 /** 88 88 * Plugin root URL 89 89 * @var string 90 90 */ 91 91 const ROOT_URL = WP_ALL_IMPORT_ROOT_URL; 92 92 /** 93 93 * Prefix used for names of shortcodes, action handlers, filter functions etc. 94 94 * @var string 95 95 */ 96 96 const PREFIX = WP_ALL_IMPORT_PREFIX; 97 97 /** 98 98 * Plugin file path 99 99 * @var string 100 100 */ 101 101 const FILE = __FILE__; 102 102 /** 103 103 * Max allowed file size (bytes) to import in default mode 104 104 * @var int 105 105 */ 106 106 const LARGE_SIZE = 0; // all files will importing in large import mode 107 107 108 108 public static $session = null; 109 109 110 110 public static $is_csv = false; 111 111 112 112 public static $csv_path = false; 113 113 114 114 /** 115 115 * @var bool 116 116 */ 117 117 public static $is_php_allowed = true; 118 118 119 119 public static $capabilities = 'manage_options'; 120 120 121 121 /** 122 122 * WP All Import logs folder 123 123 * @var string 124 124 */ 125 125 const LOGS_DIRECTORY = WP_ALL_IMPORT_LOGS_DIRECTORY; 126 126 /** 127 127 * WP All Import files folder 128 128 * @var string 129 129 */ 130 130 const FILES_DIRECTORY = WP_ALL_IMPORT_FILES_DIRECTORY; 131 131 /** 132 132 * WP All Import temp folder 133 133 * @var string 134 134 */ 135 135 const TEMP_DIRECTORY = WP_ALL_IMPORT_TEMP_DIRECTORY; 136 136 /** 137 137 * WP All Import uploads folder 138 138 * @var string 139 139 */ 140 140 const UPLOADS_DIRECTORY = WP_ALL_IMPORT_UPLOADS_DIRECTORY; 141 141 142 142 /** 143 143 * WP All Import history folder 144 144 * @var string 145 145 */ 146 146 const HISTORY_DIRECTORY = WP_ALL_IMPORT_HISTORY_DIRECTORY; 147 147 148 148 /** 149 149 * Language domain key. 150 150 */ 151 151 const LANGUAGE_DOMAIN = 'wp_all_import_plugin'; 152 152 153 153 /** 154 154 * Return singletone instance 155 155 * @return PMXI_Plugin 156 156 */ 157 157 static public function getInstance() { 158 158 if (self::$instance == NULL) { 159 159 self::$instance = new self(); 160 160 } 161 161 return self::$instance; 162 162 } 163 163 164 164 static public function getEddName(){ 165 165 return 'WP All Import'; 166 166 } 167 167 168 168 /** 169 169 * Common logic for requestin plugin info fields 170 170 */ 171 171 public function __call($method, $args) { 172 172 if (preg_match('%^get(.+)%i', $method, $mtch)) { 173 173 $info = get_plugin_data(self::FILE); 174 174 if (isset($info[$mtch[1]])) { 175 175 return $info[$mtch[1]]; 176 176 } 177 177 } 178 178 throw new Exception("Requested method " . get_class($this) . "::$method doesn't exist."); 179 179 } 180 180 181 181 /** 182 182 * Get path to plagin dir relative to wordpress root 183 183 * @param bool[optional] $noForwardSlash Whether path should be returned withot forwarding slash 184 184 * @return string 185 185 */ 186 186 public function getRelativePath($noForwardSlash = false) { 187 187 $wp_root = str_replace('\\', '/', ABSPATH); 188 188 return ($noForwardSlash ? '' : '/') . str_replace($wp_root, '', self::ROOT_DIR); 189 189 } 190 190 191 191 /** 192 192 * Check whether plugin is activated as network one 193 193 * @return bool 194 194 */ 195 195 public function isNetwork() { 196 196 if ( !is_multisite() ) 197 197 return false; 198 198 199 199 $plugins = get_site_option('active_sitewide_plugins'); 200 200 if (isset($plugins[plugin_basename(self::FILE)])) 201 201 return true; 202 202 203 203 return false; 204 204 } 205 205 206 206 /** 207 207 * Check whether permalinks is enabled 208 208 * @return bool 209 209 */ 210 210 public function isPermalinks() { 211 211 global $wp_rewrite; 212 212 213 213 return $wp_rewrite->using_permalinks(); 214 214 } 215 215 216 216 /** 217 217 * Return prefix for plugin database tables 218 218 * @return string 219 219 */ 220 220 public function getTablePrefix() { 221 221 global $wpdb; 222 222 223 223 //return ($this->isNetwork() ? $wpdb->base_prefix : $wpdb->prefix) . self::PREFIX; 224 224 return $wpdb->prefix . self::PREFIX; 225 225 } 226 226 227 227 /** 228 228 * Return prefix for wordpress database tables 229 229 * @return string 230 230 */ 231 231 public function getWPPrefix() { 232 232 global $wpdb; 233 233 return ($this->isNetwork()) ? $wpdb->base_prefix : $wpdb->prefix; 234 234 } 235 235 236 236 /** 237 237 * Class constructor containing dispatching logic 238 238 * @param string $rootDir Plugin root dir 239 239 * @param string $pluginFilePath Plugin main file 240 240 */ 241 241 protected function __construct() { 242 242 243 243 // register autoloading method 244 244 spl_autoload_register(array($this, 'autoload')); 245 245 246 246 // register helpers 247 247 if (is_dir(self::ROOT_DIR . '/helpers')) foreach (PMXI_Helper::safe_glob(self::ROOT_DIR . '/helpers/*.php', PMXI_Helper::GLOB_RECURSE | PMXI_Helper::GLOB_PATH) as $filePath) { 248 248 require_once $filePath; 249 249 } 250 250 251 251 // init plugin options 252 252 $option_name = get_class($this) . '_Options'; 253 253 $options_default = PMXI_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray(); 254 254 $current_options = get_option($option_name, array()); 255 255 if (empty($current_options)) { 256 256 $current_options = array(); 257 257 } 258 258 259 259 $this->options = array_intersect_key($current_options, $options_default) + $options_default; 260 260 $this->options = array_intersect_key($options_default, array_flip(array('info_api_url'))) + $this->options; // make sure hidden options apply upon plugin reactivation 261 261 if ('' == $this->options['cron_job_key']) { 262 262 $this->options['cron_job_key'] = wp_all_import_url_title(wp_all_import_rand_char(12)); 263 263 } 264 264 265 265 if ($current_options !== $this->options) { 266 266 update_option($option_name, $this->options, false); 267 267 } 268 268 269 269 register_activation_hook(self::FILE, array($this, 'activation')); 270 270 271 271 // register action handlers 272 272 if (is_dir(self::ROOT_DIR . '/actions')) if (is_dir(self::ROOT_DIR . '/actions')) foreach (PMXI_Helper::safe_glob(self::ROOT_DIR . '/actions/*.php', PMXI_Helper::GLOB_RECURSE | PMXI_Helper::GLOB_PATH) as $filePath) { 273 273 require_once $filePath; 274 274 $function = $actionName = basename($filePath, '.php'); 275 275 if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) { 276 276 $actionName = $m[1]; 277 277 $priority = intval($m[2]); 278 278 } else { 279 279 $priority = 10; 280 280 } 281 281 add_action($actionName, self::PREFIX . str_replace('-', '_', $function), $priority, 99); // since we don't know at this point how many parameters each plugin expects, we make sure they will be provided with all of them (it's unlikely any developer will specify more than 99 parameters in a function) 282 282 } 283 283 284 284 // register filter handlers 285 285 if (is_dir(self::ROOT_DIR . '/filters')) foreach (PMXI_Helper::safe_glob(self::ROOT_DIR . '/filters/*.php', PMXI_Helper::GLOB_RECURSE | PMXI_Helper::GLOB_PATH) as $filePath) { 286 286 require_once $filePath; 287 287 $function = $actionName = basename($filePath, '.php'); 288 288 if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) { 289 289 $actionName = $m[1]; 290 290 $priority = intval($m[2]); 291 291 } else { 292 292 $priority = 10; 293 293 } 294 294 add_filter($actionName, self::PREFIX . str_replace('-', '_', $function), $priority, 99); // since we don't know at this point how many parameters each plugin expects, we make sure they will be provided with all of them (it's unlikely any developer will specify more than 99 parameters in a function) 295 295 } 296 296 297 297 // register admin page pre-dispatcher 298 298 add_action('admin_init', array($this, 'adminInit')); 299 299 add_action('admin_init', array($this, 'fix_options')); 300 300 add_action('init', array($this, 'init')); 301 301 302 302 add_action( 'plugins_loaded', array( $this, 'setup_allimport_dir' ) ); 303 303 304 304 } 305 305 306 306 /** 307 307 * Determines is process running from cli. 308 308 * 309 309 * @return bool 310 310 */ 311 311 public function isCli() { 312 312 return php_sapi_name() === 'cli'; 313 313 } 314 314 315 315 /** 316 316 * Setup required directory. 317 317 */ 318 318 public function setup_allimport_dir() { 319 319 // create history folder 320 320 $uploads = wp_upload_dir(); 321 321 322 322 $wpallimportDirs = array( WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY, self::LOGS_DIRECTORY, self::FILES_DIRECTORY, self::TEMP_DIRECTORY, self::UPLOADS_DIRECTORY, self::HISTORY_DIRECTORY); 323 323 324 324 foreach ($wpallimportDirs as $destination) { 325 325 326 326 $dir = $uploads['basedir'] . DIRECTORY_SEPARATOR . $destination; 327 327 328 328 if ( !is_dir($dir)) wp_mkdir_p($dir); 329 329 330 330 if ( ! @file_exists($dir . DIRECTORY_SEPARATOR . 'index.php') ) @touch( $dir . DIRECTORY_SEPARATOR . 'index.php' ); 331 331 332 332 } 333 333 } 334 334 335 335 public function init(){ 336 336 $this->load_plugin_textdomain(); 337 337 self::$is_php_allowed = apply_filters('wp_all_import_is_php_allowed', TRUE); 338 338 } 339 339 340 340 public function plugin_row_meta($links, $file) 341 341 { 342 342 if ( $file == plugin_basename( __FILE__ ) ) { 343 343 $row_meta = array( 344 344 'pro' => '<a href="http://www.wpallimport.com" target="_blank" title="' . esc_attr( __( 'WP All Import Pro Version', 'wp_all_import_plugin' ) ) . '">' . __( 'Pro Version', 'wp_all_import_plugin' ) . '</a>', 345 345 ); 346 346 347 347 return array_merge( $links, $row_meta ); 348 348 } 349 349 350 350 return (array) $links; 351 351 } 352 352 353 353 354 354 /** 355 355 * convert imports options 356 356 * compatibility with version 3.2.3 357 357 */ 358 358 public function fix_options(){ 359 359 360 360 global $wpdb; 361 361 362 362 $imports = new PMXI_Import_List(); 363 363 $post = new PMXI_Post_Record(); 364 364 365 365 $templates = new PMXI_Template_List(); 366 366 $template = new PMXI_Template_Record(); 367 367 368 368 $is_migrated = get_option('pmxi_is_migrated'); 369 369 370 370 $uploads = wp_upload_dir(); 371 371 372 372 if ( empty($is_migrated) or version_compare($is_migrated, PMXI_VERSION) < 0 ){ //PMXI_VERSION 373 373 374 374 $commit_migration = true; 375 375 376 376 if ( empty($is_migrated) ){ // plugin version less than 4.0.0 377 377 378 378 if ( is_dir($uploads['basedir'] . '/wpallimport_history') ) { 379 379 wp_all_import_rmdir($uploads['basedir'] . '/wpallimport_history'); 380 380 } 381 381 if ( is_dir($uploads['basedir'] . '/wpallimport_logs') ) { 382 382 wp_all_import_rmdir($uploads['basedir'] . '/wpallimport_logs'); 383 383 } 384 384 385 385 foreach ($imports->setColumns($imports->getTable() . '.*')->getBy(array('id !=' => ''))->convertRecords() as $imp){ 386 386 387 387 $imp->getById($imp->id); 388 388 389 389 if ( ! $imp->isEmpty() and ! empty($imp->template)){ 390 390 391 391 $options = array_merge($imp->options, $imp->template); 392 392 393 393 $this->ver_4_transition_fix($options); 394 394 395 395 $imp->set(array( 396 396 'options' => $options 397 397 ))->update(); 398 398 399 399 if ($imp->type == 'file'){ 400 400 $imp->set(array( 401 401 'path' => $uploads['basedir'] . DIRECTORY_SEPARATOR . self::FILES_DIRECTORY . DIRECTORY_SEPARATOR . basename($imp->path) 402 402 ))->update(); 403 403 } 404 404 } 405 405 } 406 406 407 407 foreach ($templates->setColumns($templates->getTable() . '.*')->getBy(array('id !=' => ''))->convertRecords() as $tpl){ 408 408 409 409 $tpl->getById($tpl->id); 410 410 411 411 if ( ! $tpl->isEmpty() and ! empty($tpl->title) ) { 412 412 413 413 $opt = ( empty($tpl->options) ) ? array() : $tpl->options; 414 414 415 415 $options = array_merge($opt, array( 416 416 'title' => $tpl->title, 417 417 'content' => $tpl->content, 418 418 'is_keep_linebreaks' => $tpl->is_keep_linebreaks, 419 419 'is_leave_html' => $tpl->is_leave_html, 420 420 'fix_characters' => $tpl->fix_characters 421 421 )); 422 422 423 423 $this->ver_4_transition_fix($options); 424 424 425 425 $tpl->set(array( 426 426 'options' => $options 427 427 ))->update(); 428 428 429 429 } 430 430 431 431 } 432 432 433 433 $commit_migration = $this->fix_db_schema(); // feature to version 4.0.0 434 434 435 435 } 436 436 else { 437 437 438 438 $commit_migration = $this->fix_db_schema(); 439 439 440 440 foreach ($imports->setColumns($imports->getTable() . '.*')->getBy(array('id !=' => ''))->convertRecords() as $imp){ 441 441 442 442 $imp->getById($imp->id); 443 443 444 444 if ( ! $imp->isEmpty() ){ 445 445 446 446 $options = $imp->options; 447 447 448 448 $this->ver_4x_transition_fix($options, $is_migrated); 449 449 450 450 $imp->set(array( 451 451 'options' => $options 452 452 ))->update(); 453 453 } 454 454 } 455 455 456 456 foreach ($templates->setColumns($templates->getTable() . '.*')->getBy(array('id !=' => ''))->convertRecords() as $tpl){ 457 457 458 458 $tpl->getById($tpl->id); 459 459 460 460 if ( ! $tpl->isEmpty() ) { 461 461 462 462 $options = ( empty($tpl->options) ) ? array() : $tpl->options; 463 463 464 464 $this->ver_4x_transition_fix($options, $is_migrated); 465 465 466 466 $tpl->set(array( 467 467 'options' => $options 468 468 ))->update(); 469 469 470 470 } 471 471 472 472 } 473 473 } 474 474 if ($commit_migration) update_option('pmxi_is_migrated', PMXI_VERSION); 475 475 } 476 476 } 477 477 478 478 public function ver_4_transition_fix( &$options ){ 479 479 480 480 $options['wizard_type'] = ($options['duplicate_matching'] == 'auto') ? 'new' : 'matching'; 481 481 482 482 if ($options['download_images']){ 483 483 $options['download_images'] = 'yes'; 484 484 $options['download_featured_image'] = $options['featured_image']; 485 485 $options['featured_image'] = ''; 486 486 $options['download_featured_delim'] = $options['featured_delim']; 487 487 $options['featured_delim'] = ''; 488 488 } 489 489 490 490 if ($options['set_image_meta_data']){ 491 491 $options['set_image_meta_title'] = 1; 492 492 $options['set_image_meta_caption'] = 1; 493 493 $options['set_image_meta_alt'] = 1; 494 494 $options['set_image_meta_description'] = 1; 495 495 } 496 496 497 497 if ("" == $options['custom_type']) $options['custom_type'] = $options['type']; 498 498 499 499 $exclude_taxonomies = (class_exists('PMWI_Plugin')) ? array('post_format', 'product_type') : array('post_format'); 500 500 $post_taxonomies = array_diff_key(get_taxonomies_by_object_type(array($options['custom_type']), 'object'), array_flip($exclude_taxonomies)); 501 501 502 502 $options['tax_logic'] = array(); 503 503 $options['tax_assing'] = array(); 504 504 $options['tax_multiple_xpath'] = array(); 505 505 $options['tax_multiple_delim'] = array(); 506 506 $options['tax_hierarchical_logic_entire'] = array(); 507 507 $options['tax_hierarchical_logic_manual'] = array(); 508 508 509 509 if ( ! empty($post_taxonomies)): 510 510 foreach ($post_taxonomies as $ctx): 511 511 512 512 $options['tax_logic'][$ctx->name] = ($ctx->hierarchical) ? 'hierarchical' : 'multiple'; 513 513 514 514 if ($ctx->name == 'category'){ 515 515 $options['post_taxonomies']['category'] = $options['categories']; 516 516 } 517 517 elseif ($ctx->name == 'post_tag' ){ 518 518 $options['tax_assing']['post_tag'] = 1; 519 519 $options['tax_multiple_xpath']['post_tag'] = $options['tags']; 520 520 $options['tax_multiple_delim']['post_tag'] = $options['tags_delim']; 521 521 } 522 522 523 523 if ( ! empty($options['post_taxonomies'][$ctx->name])){ 524 524 525 525 $taxonomies_hierarchy = json_decode($options['post_taxonomies'][$ctx->name], true); 526 526 $options['tax_assing'][$ctx->name] = (!empty($taxonomies_hierarchy[0]['assign'])) ? 1 : 0; 527 527 528 528 if ($options['tax_logic'][$ctx->name] == 'multiple') { 529 529 $options['tax_multiple_xpath'][$ctx->name] = (!empty($taxonomies_hierarchy[0]['xpath'])) ? $taxonomies_hierarchy[0]['xpath'] : ''; 530 530 $options['tax_multiple_delim'][$ctx->name] = (!empty($taxonomies_hierarchy[0]['delim'])) ? $taxonomies_hierarchy[0]['delim'] : ''; 531 531 } 532 532 else{ 533 533 $options['tax_hierarchical_logic_manual'][$ctx->name] = 1; 534 534 } 535 535 } 536 536 537 537 endforeach; 538 538 endif; 539 539 } 540 540 541 541 public function ver_4x_transition_fix(&$options, $version){ 542 542 if ( version_compare($version, '4.0.5') < 0 ){ 543 543 if ( ! empty($options['tax_hierarchical_logic']) and is_array($options['tax_hierarchical_logic']) ){ 544 544 foreach ($options['tax_hierarchical_logic'] as $tx => $type) { 545 545 switch ($type){ 546 546 case 'entire': 547 547 $options['tax_hierarchical_logic_entire'][$tx] = 1; 548 548 break; 549 549 case 'manual': 550 550 $options['tax_hierarchical_logic_manual'][$tx] = 1; 551 551 break; 552 552 default: 553 553 554 554 break; 555 555 } 556 556 } 557 557 unset($options['tax_hierarchical_logic']); 558 558 } 559 559 } 560 560 561 561 } 562 562 563 563 /** 564 564 * pre-dispatching logic for admin page controllers 565 565 */ 566 566 public function adminInit() { 567 567 568 568 self::$session = new PMXI_Handler(); 569 569 570 570 $input = new PMXI_Input(); 571 571 $page = strtolower($input->getpost('page', '')); 572 572 573 573 if (preg_match('%^' . preg_quote(str_replace('_', '-', self::PREFIX), '%') . '([\w-]+)$%', $page)) { 574 574 //$this->adminDispatcher($page, strtolower($input->getpost('action', 'index'))); 575 575 576 576 $action = strtolower($input->getpost('action', 'index')); 577 577 578 578 // capitalize prefix and first letters of class name parts 579 579 $controllerName = preg_replace_callback('%(^' . preg_quote(self::PREFIX, '%') . '|_).%', array($this, "replace_callback"),str_replace('-', '_', $page)); 580 580 $actionName = str_replace('-', '_', $action); 581 581 if (method_exists($controllerName, $actionName)) { 582 582 583 583 @ini_set("max_input_time", PMXI_Plugin::getInstance()->getOption('max_input_time')); 584 584 @ini_set("max_execution_time", PMXI_Plugin::getInstance()->getOption('max_execution_time')); 585 585 586 586 if ( ! get_current_user_id() or ! current_user_can( self::$capabilities )) { 587 587 // This nonce is not valid. 588 588 die( 'Security check' ); 589 589 590 590 } else { 591 591 592 592 $this->_admin_current_screen = (object)array( 593 593 'id' => $controllerName, 594 594 'base' => $controllerName, 595 595 'action' => $actionName, 596 596 'is_ajax' => (isset($_SERVER["HTTP_ACCEPT"]) && strpos($_SERVER["HTTP_ACCEPT"], 'json')) !== false, 597 597 'is_network' => is_network_admin(), 598 598 'is_user' => is_user_admin(), 599 599 ); 600 600 add_filter('current_screen', array($this, 'getAdminCurrentScreen')); 601 601 add_filter('admin_body_class', array($this, 'getAdminBodyClass'), 10, 1); 602 602 603 603 $controller = new $controllerName(); 604 604 if ( ! $controller instanceof PMXI_Controller_Admin) { 605 605 throw new Exception("Administration page `$page` matches to a wrong controller type."); 606 606 } 607 607 608 608 if ($this->_admin_current_screen->is_ajax) { // ajax request 609 609 $controller->$action(); 610 610 do_action('pmxi_action_after'); 611 611 wp_die(); // stop processing since we want to output only what controller is randered, nothing in addition 612 612 } elseif ( ! $controller->isInline) { 613 613 @ob_start(); 614 614 $controller->$action(); 615 615 self::$buffer = @ob_get_clean(); 616 616 } else { 617 617 self::$buffer_callback = array($controller, $action); 618 618 } 619 619 620 620 } 621 621 622 622 } else { // redirect to dashboard if requested page and/or action don't exist 623 623 wp_redirect(admin_url()); die(); 624 624 } 625 625 } 626 626 } 627 627 628 628 public function getAdminBodyClass($class){ 629 629 return $class . ' wpallimport-plugin'; 630 630 } 631 631 632 632 /** 633 633 * Dispatch shorttag: create corresponding controller instance and call its index method 634 634 * @param array $args Shortcode tag attributes 635 635 * @param string $content Shortcode tag content 636 636 * @param string $tag Shortcode tag name which is being dispatched 637 637 * @return string 638 638 */ 639 639 public function shortcodeDispatcher($args, $content, $tag) { 640 640 641 641 $controllerName = self::PREFIX . preg_replace_callback('%(^|_).%', array($this, "replace_callback"), $tag);// capitalize first letters of class name parts and add prefix 642 642 $controller = new $controllerName(); 643 643 if ( ! $controller instanceof PMXI_Controller) { 644 644 throw new Exception("Shortcode `$tag` matches to a wrong controller type."); 645 645 } 646 646 ob_start(); 647 647 $controller->index($args, $content); 648 648 return ob_get_clean(); 649 649 } 650 650 651 651 static $buffer = NULL; 652 652 static $buffer_callback = NULL; 653 653 654 654 /** 655 655 * Dispatch admin page: call corresponding controller based on get parameter `page` 656 656 * The method is called twice: 1st time as handler `parse_header` action and then as admin menu item handler 657 657 * @param string[optional] $page When $page set to empty string ealier buffered content is outputted, otherwise controller is called based on $page value 658 658 */ 659 659 public function adminDispatcher($page = '', $action = 'index') { 660 660 661 661 if ('' === $page) { 662 662 if ( ! is_null(self::$buffer)) { 663 663 echo '<div class="wrap">'; 664 664 665 665 echo self::$buffer; 666 666 667 667 do_action('pmxi_action_after'); 668 668 echo '</div>'; 669 669 } elseif ( ! is_null(self::$buffer_callback)) { 670 670 echo '<div class="wrap">'; 671 671 call_user_func(self::$buffer_callback); 672 672 do_action('pmxi_action_after'); 673 673 echo '</div>'; 674 674 } else { 675 675 throw new Exception('There is no previousely buffered content to display.'); 676 676 } 677 677 } 678 678 679 679 } 680 680 681 681 public function replace_callback($matches){ 682 682 return strtoupper($matches[0]); 683 683 } 684 684 685 685 protected $_admin_current_screen = NULL; 686 686 public function getAdminCurrentScreen() 687 687 { 688 688 return $this->_admin_current_screen; 689 689 } 690 690 691 691 /** 692 692 * Autoloader 693 693 * It's assumed class name consists of prefix folloed by its name which in turn corresponds to location of source file 694 694 * if `_` symbols replaced by directory path separator. File name consists of prefix folloed by last part in class name (i.e. 695 695 * symbols after last `_` in class name) 696 696 * When class has prefix it's source is looked in `models`, `controllers`, `shortcodes` folders, otherwise it looked in `core` or `library` folder 697 697 * 698 698 * @param string $className 699 699 * @return bool 700 700 */ 701 701 public function autoload($className) { 702 702 $is_prefix = false; 703 703 $filePath = str_replace('_', '/', preg_replace('%^' . preg_quote(self::PREFIX, '%') . '%', '', strtolower($className), 1, $is_prefix)) . '.php'; 704 704 if ( ! $is_prefix) { // also check file with original letter case 705 705 $filePathAlt = $className . '.php'; 706 706 } 707 707 foreach ($is_prefix ? array('models', 'controllers', 'shortcodes', 'classes') : array('libraries') as $subdir) { 708 708 $path = self::ROOT_DIR . '/' . $subdir . '/' . $filePath; 709 709 if (is_file($path)) { 710 710 require $path; 711 711 return TRUE; 712 712 } 713 713 if ( ! $is_prefix) { 714 714 $pathAlt = self::ROOT_DIR . '/' . $subdir . '/' . $filePathAlt; 715 715 if (is_file($pathAlt)) { 716 716 require $pathAlt; 717 717 return TRUE; 718 718 } 719 719 } 720 720 } 721 721 722 722 return FALSE; 723 723 } 724 724 725 725 /** 726 726 * Get plugin option 727 727 * @param string[optional] $option Parameter to return, all array of options is returned if not set 728 728 * @return mixed 729 729 */ 730 730 public function getOption($option = NULL) { 731 731 $options = apply_filters('wp_all_import_config_options', $this->options); 732 732 if (is_null($option)) { 733 733 return $options; 734 734 } else if (isset($options[$option])) { 735 735 return $options[$option]; 736 736 } else { 737 737 throw new Exception("Specified option is not defined for the plugin"); 738 738 } 739 739 } 740 740 /** 741 741 * Update plugin option value 742 742 * @param string $option Parameter name or array of name => value pairs 743 743 * @param mixed[optional] $value New value for the option, if not set than 1st parameter is supposed to be array of name => value pairs 744 744 * @return array 745 745 */ 746 746 public function updateOption($option, $value = NULL) { 747 747 is_null($value) or $option = array($option => $value); 748 748 if (array_diff_key($option, $this->options)) { 749 749 throw new Exception("Specified option is not defined for the plugin"); 750 750 } 751 751 $this->options = $option + $this->options; 752 752 update_option(get_class($this) . '_Options', $this->options); 753 753 754 754 return $this->options; 755 755 } 756 756 757 757 /** 758 758 * Plugin activation logic 759 759 */ 760 760 public function activation() { 761 761 // uncaught exception doesn't prevent plugin from being activated, therefore replace it with fatal error so it does 762 762 if (version_compare(phpversion(), '7.2' , "<")){ 763 763 $exception_handler = create_function('$e', 'trigger_error($e->getMessage(), E_USER_ERROR);'); 764 764 } 765 765 else{ 766 766 $exception_handler = function($e){ 767 767 trigger_error($e->getMessage(), E_USER_ERROR); 768 768 }; 769 769 } 770 770 set_exception_handler($exception_handler); 771 771 772 772 // create plugin options 773 773 $option_name = get_class($this) . '_Options'; 774 774 $options_default = PMXI_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray(); 775 775 $wpai_options = get_option($option_name, false); 776 776 if ( ! $wpai_options ) update_option($option_name, $options_default); 777 777 778 778 // create/update required database tables 779 779 require_once ABSPATH . 'wp-admin/includes/upgrade.php'; 780 780 require self::ROOT_DIR . '/schema.php'; 781 781 global $wpdb; 782 782 783 783 if (function_exists('is_multisite') && is_multisite()) { 784 784 // check if it is a network activation - if so, run the activation function for each blog id 785 785 if (isset($_GET['networkwide']) && (intval($_GET['networkwide']) == 1)) { 786 786 $old_blog = $wpdb->blogid; 787 787 // Get all blog ids 788 788 $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs"); 789 789 foreach ($blogids as $blog_id) { 790 790 switch_to_blog($blog_id); 791 791 require self::ROOT_DIR . '/schema.php'; 792 792 dbDelta($plugin_queries); 793 793 794 794 // sync data between plugin tables and wordpress (mostly for the case when plugin is reactivated) 795 795 796 796 //$post = new PMXI_Post_Record(); 797 797 //$wpdb->query('DELETE FROM ' . $post->getTable() . ' WHERE post_id NOT IN (SELECT ID FROM ' . $wpdb->posts . ')'); 798 798 $post = new PMXI_Post_Record(); 799 799 $import = new PMXI_Import_Record(); 800 800 $imports_list = $wpdb->get_results('SELECT id FROM ' . $import->getTable() . ''); 801 801 802 802 if ( ! empty($imports_list) ) { 803 803 804 804 $user_imports = array(); 805 805 $post_imports = array(); 806 806 807 807 foreach ($imports_list as $import_entry) { 808 808 $import_id = $import_entry->id; 809 809 $import = $import->getById($import_id); 810 810 $import_options = maybe_unserialize($import->options); 811 811 $import_type = $import_options['custom_type']; 812 812 if ( in_array($import_type, array('import_users', 'shop_customer')) ) { 813 813 $user_imports[] = $import_id; 814 814 } else { 815 815 $post_imports[] = $import_id; 816 816 } 817 817 } 818 818 819 819 if ( ! empty($user_imports) ) { 820 820 $user_table = $wpdb->base_prefix . 'users'; 821 821 $user_query = 'DELETE FROM ' . $post->getTable() . ' WHERE import_id IN (' . implode(',', $user_imports) . ') AND post_id NOT IN (SELECT ID FROM ' . $user_table . ')'; 822 822 $wpdb->query($user_query); 823 823 } 824 824 825 825 if ( ! empty($post_imports) ) { 826 826 $post_query = 'DELETE FROM ' . $post->getTable() . ' WHERE import_id IN (' . implode(',', $post_imports) . ') AND post_id NOT IN (SELECT ID FROM ' . $wpdb->posts . ')'; 827 827 $wpdb->query($post_query); 828 828 } 829 829 830 830 } 831 831 832 832 } 833 833 switch_to_blog($old_blog); 834 834 return; 835 835 } 836 836 } 837 837 838 838 dbDelta($plugin_queries); 839 839 840 840 // sync data between plugin tables and wordpress (mostly for the case when plugin is reactivated) 841 841 842 842 //$post = new PMXI_Post_Record(); 843 843 //$wpdb->query('DELETE FROM ' . $post->getTable() . ' WHERE post_id NOT IN (SELECT ID FROM ' . $wpdb->posts . ')'); 844 844 845 845 $post = new PMXI_Post_Record(); 846 846 $import = new PMXI_Import_Record(); 847 847 $imports_list = $wpdb->get_results('SELECT id FROM ' . $import->getTable() . ''); 848 848 849 849 if ( ! empty($imports_list) ) { 850 850 851 851 $user_imports = array(); 852 852 $post_imports = array(); 853 853 854 854 foreach ($imports_list as $import_entry) { 855 855 $import_id = $import_entry->id; 856 856 $import = $import->getById($import_id); 857 857 $import_options = maybe_unserialize($import->options); 858 858 $import_type = $import_options['custom_type']; 859 859 if ( in_array($import_type, array('import_users', 'shop_customer')) ) { 860 860 $user_imports[] = $import_id; 861 861 } else { 862 862 $post_imports[] = $import_id; 863 863 } 864 864 } 865 865 866 866 if ( ! empty($user_imports) ) { 867 867 $user_table = $wpdb->base_prefix . 'users'; 868 868 $user_query = 'DELETE FROM ' . $post->getTable() . ' WHERE import_id IN (' . implode(',', $user_imports) . ') AND post_id NOT IN (SELECT ID FROM ' . $user_table . ')'; 869 869 $wpdb->query($user_query); 870 870 } 871 871 872 872 if ( ! empty($post_imports) ) { 873 873 $post_query = 'DELETE FROM ' . $post->getTable() . ' WHERE import_id IN (' . implode(',', $post_imports) . ') AND post_id NOT IN (SELECT ID FROM ' . $wpdb->posts . ')'; 874 874 $wpdb->query($post_query); 875 875 } 876 876 877 877 } 878 878 879 879 } 880 880 881 881 /** 882 882 * Load Localisation files. 883 883 * 884 884 * Note: the first-loaded translation file overrides any following ones if the same translation is present 885 885 * 886 886 * @access public 887 887 * @return void 888 888 */ 889 889 public function load_plugin_textdomain() { 890 890 $locale = apply_filters( 'plugin_locale', get_locale(), 'wp_all_import_plugin' ); 891 891 892 892 load_plugin_textdomain( 'wp_all_import_plugin', false, dirname( plugin_basename( __FILE__ ) ) . "/i18n/languages" ); 893 893 } 894 894 895 895 public function fix_db_schema(){ 896 896 897 897 $uploads = wp_upload_dir(); 898 898 899 899 if ( ! is_dir($uploads['basedir'] . DIRECTORY_SEPARATOR . self::LOGS_DIRECTORY) or ! is_writable($uploads['basedir'] . DIRECTORY_SEPARATOR . self::LOGS_DIRECTORY)) { 900 900 die(sprintf(__('Uploads folder %s must be writable', 'wp_all_import_plugin'), esc_attr($uploads['basedir'] . DIRECTORY_SEPARATOR . self::LOGS_DIRECTORY))); 901 901 } 902 902 903 903 if ( ! is_dir($uploads['basedir'] . DIRECTORY_SEPARATOR . WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY) or ! is_writable($uploads['basedir'] . DIRECTORY_SEPARATOR . WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY)) { 904 904 die(sprintf(__('Uploads folder %s must be writable', 'wp_all_import_plugin'), esc_attr($uploads['basedir'] . DIRECTORY_SEPARATOR . WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY))); 905 905 } 906 906 907 907 // create/update required database tables 908 908 require_once ABSPATH . 'wp-admin/includes/upgrade.php'; 909 909 require self::ROOT_DIR . '/schema.php'; 910 910 global $wpdb; 911 911 912 912 if (function_exists('is_multisite') && is_multisite()) { 913 913 // check if it is a network activation - if so, run the activation function for each blog id 914 914 if (isset($_GET['networkwide']) && (intval($_GET['networkwide']) == 1)) { 915 915 $old_blog = $wpdb->blogid; 916 916 // Get all blog ids 917 917 $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs"); 918 918 foreach ($blogids as $blog_id) { 919 919 switch_to_blog($blog_id); 920 920 require self::ROOT_DIR . '/schema.php'; 921 921 dbDelta($plugin_queries); 922 922 923 923 // sync data between plugin tables and wordpress (mostly for the case when plugin is reactivated) 924 924 925 925 $post = new PMXI_Post_Record(); 926 926 $wpdb->query('DELETE FROM ' . $post->getTable() . ' WHERE post_id NOT IN (SELECT ID FROM ' . $wpdb->posts .') AND post_id NOT IN ( SELECT ID FROM ' . $wpdb->users . ') AND post_id NOT IN ( SELECT term_taxonomy_id FROM ' . $wpdb->term_taxonomy . ')'); 927 927 } 928 928 switch_to_blog($old_blog); 929 929 return; 930 930 } 931 931 } 932 932 933 933 dbDelta($plugin_queries); 934 934 935 935 // do not execute ALTER TABLE queries if sql user doesn't have ALTER privileges 936 936 $grands = $wpdb->get_results("SELECT * FROM information_schema.user_privileges WHERE grantee LIKE \"'" . DB_USER . "'%\" AND PRIVILEGE_TYPE = 'ALTER' AND IS_GRANTABLE = 'YES';"); 937 937 938 938 $table = $table = $this->getTablePrefix() . 'files'; 939 939 940 940 $tablefields = $wpdb->get_results("DESCRIBE {$table};"); 941 941 // For every field in the table 942 942 foreach ($tablefields as $tablefield) { 943 943 if ('contents' == $tablefield->Field) { 944 944 $list = new PMXI_File_List(); 945 945 for ($i = 1; $list->getBy(NULL, 'id', $i, 1)->count(); $i++) { 946 946 foreach ($list->convertRecords() as $file) { 947 947 $file->save(); // resave file for file to be stored in uploads folder 948 948 } 949 949 } 950 950 951 951 if (!empty($grands)) $wpdb->query("ALTER TABLE {$table} DROP " . $tablefield->Field); 952 952 953 953 break; 954 954 } 955 955 } 956 956 957 957 // alter images table 958 958 $table = $this->getTablePrefix() . 'images'; 959 959 $tablefields = $wpdb->get_results("DESCRIBE {$table};"); 960 960 $fields_to_alter = array( 961 961 'image_url', 962 962 'image_filename' 963 963 ); 964 964 965 965 // Check if field exists 966 966 foreach ($tablefields as $tablefield) { 967 967 if (in_array($tablefield->Field, $fields_to_alter)){ 968 968 $fields_to_alter = array_diff($fields_to_alter, array($tablefield->Field)); 969 969 } 970 970 } 971 971 972 972 if ( ! empty($fields_to_alter) ){ 973 973 974 974 if (empty($grands)) return false; 975 975 976 976 foreach ($fields_to_alter as $field) { 977 977 switch ($field) { 978 978 case 'image_url': 979 979 $wpdb->query("ALTER TABLE {$table} ADD `image_url` VARCHAR(600) NOT NULL DEFAULT '';"); 980 980 break; 981 981 case 'image_filename': 982 982 $wpdb->query("ALTER TABLE {$table} ADD `image_filename` VARCHAR(600) NOT NULL DEFAULT '';"); 983 983 break; 984 984 default: 985 985 # code... 986 986 break; 987 987 } 988 988 } 989 989 } 990 990 991 991 $table = $this->getTablePrefix() . 'imports'; 992 992 $tablefields = $wpdb->get_results("DESCRIBE {$table};"); 993 993 $fields_to_alter = array( 994 994 'parent_import_id', 995 995 'iteration', 996 996 'deleted', 997 997 'executing', 998 998 'canceled', 999 999 'canceled_on', 1000 1000 'failed', 1001 1001 'failed_on', 1002 1002 'settings_update_on', 1003 1003 'last_activity' 1004 1004 ); 1005 1005 1006 1006 // Check if field exists 1007 1007 foreach ($tablefields as $tablefield) { 1008 1008 if (in_array($tablefield->Field, $fields_to_alter)){ 1009 1009 $fields_to_alter = array_diff($fields_to_alter, array($tablefield->Field)); 1010 1010 } 1011 1011 } 1012 1012 1013 1013 if ( ! empty($fields_to_alter) ){ 1014 1014 1015 1015 if (empty($grands)) return false; 1016 1016 1017 1017 foreach ($fields_to_alter as $field) { 1018 1018 switch ($field) { 1019 1019 case 'parent_import_id': 1020 1020 $wpdb->query("ALTER TABLE {$table} ADD `parent_import_id` BIGINT(20) NOT NULL DEFAULT 0;"); 1021 1021 break; 1022 1022 case 'iteration': 1023 1023 $wpdb->query("ALTER TABLE {$table} ADD `iteration` BIGINT(20) NOT NULL DEFAULT 0;"); 1024 1024 break; 1025 1025 case 'deleted': 1026 1026 $wpdb->query("ALTER TABLE {$table} ADD `deleted` BIGINT(20) NOT NULL DEFAULT 0;"); 1027 1027 break; 1028 1028 case 'executing': 1029 1029 $wpdb->query("ALTER TABLE {$table} ADD `executing` BOOL NOT NULL DEFAULT 0;"); 1030 1030 break; 1031 1031 case 'canceled': 1032 1032 $wpdb->query("ALTER TABLE {$table} ADD `canceled` BOOL NOT NULL DEFAULT 0;"); 1033 1033 break; 1034 1034 case 'canceled_on': 1035 1035 $wpdb->query("ALTER TABLE {$table} ADD `canceled_on` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00';"); 1036 1036 break; 1037 1037 case 'failed': 1038 1038 $wpdb->query("ALTER TABLE {$table} ADD `failed` BOOL NOT NULL DEFAULT 0;"); 1039 1039 break; 1040 1040 case 'failed_on': 1041 1041 $wpdb->query("ALTER TABLE {$table} ADD `failed_on` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00';"); 1042 1042 break; 1043 1043 case 'settings_update_on': 1044 1044 $wpdb->query("ALTER TABLE {$table} ADD `settings_update_on` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00';"); 1045 1045 break; 1046 1046 case 'last_activity': 1047 1047 $wpdb->query("ALTER TABLE {$table} ADD `last_activity` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00';"); 1048 1048 break; 1049 1049 1050 1050 default: 1051 1051 # code... 1052 1052 break; 1053 1053 } 1054 1054 } 1055 1055 } 1056 1056 1057 1057 $table = $this->getTablePrefix() . 'posts'; 1058 1058 $tablefields = $wpdb->get_results("DESCRIBE {$table};"); 1059 1059 $iteration = false; 1060 1060 $specified = false; 1061 1061 1062 1062 // Check if field exists 1063 1063 foreach ($tablefields as $tablefield) { 1064 1064 if ('iteration' == $tablefield->Field) $iteration = true; 1065 1065 if ('specified' == $tablefield->Field) $specified = true; 1066 1066 } 1067 1067 1068 1068 if (!$iteration){ 1069 1069 1070 1070 if (empty($grands)) { 1071 1071 ?> 1072 1072 <div class="error"><p> 1073 1073 <?php printf( 1074 1074 __('<b>%s Plugin</b>: Current sql user %s doesn\'t have ALTER privileges', 'pmwi_plugin'), 1075 1075 esc_attr(self::getInstance()->getName()), esc_attr(DB_USER) 1076 1076 ) ?> 1077 1077 </p></div> 1078 1078 <?php 1079 1079 return false; 1080 1080 } 1081 1081 1082 1082 $wpdb->query("ALTER TABLE {$table} ADD `iteration` BIGINT(20) NOT NULL DEFAULT 0;"); 1083 1083 1084 1084 // Add indexing to pmxi_posts.post_id and pmxi_posts.import_id fields. 1085 1085 $wpdb->query("ALTER TABLE {$table} ADD INDEX `post_id`(`post_id`);"); 1086 1086 $wpdb->query("ALTER TABLE {$table} ADD INDEX `import_id`(`import_id`)"); 1087 1087 } 1088 1088 1089 1089 if (!$specified and !empty($grands)) 1090 1090 { 1091 1091 $wpdb->query("ALTER TABLE {$table} ADD `specified` BOOL NOT NULL DEFAULT 0;"); 1092 1092 } 1093 1093 1094 1094 if ( ! empty($wpdb->charset)) 1095 1095 $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset"; 1096 1096 if ( ! empty($wpdb->collate)) 1097 1097 $charset_collate .= " COLLATE $wpdb->collate"; 1098 1098 1099 1099 $table_prefix = $this->getTablePrefix(); 1100 1100 1101 1101 $wpdb->query("CREATE TABLE IF NOT EXISTS {$table_prefix}history ( 1102 1102 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, 1103 1103 import_id BIGINT(20) UNSIGNED NOT NULL, 1104 1104 type ENUM('manual','processing','trigger','continue','') NOT NULL DEFAULT '', 1105 1105 time_run TEXT, 1106 1106 date DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', 1107 1107 summary TEXT, 1108 1108 PRIMARY KEY (id) 1109 1109 ) $charset_collate;"); 1110 1110 1111 1111 return true; 1112 1112 } 1113 1113 1114 1114 /** 1115 1115 * Method returns default import options, main utility of the method is to avoid warnings when new 1116 1116 * option is introduced but already registered imports don't have it 1117 1117 */ 1118 1118 public static function get_default_import_options() { 1119 1119 return array( 1120 1120 'type' => 'post', 1121 1121 'is_override_post_type' => 0, 1122 1122 'post_type_xpath' => '', 1123 1123 'deligate' => '', 1124 1124 'wizard_type' => 'new', 1125 1125 'ftp_host' => '', 1126 1126 'ftp_path' => '', 1127 1127 'ftp_root' => '/', 1128 1128 'ftp_port' => 21, 1129 1129 'ftp_username' => '', 1130 1130 'ftp_password' => '', 1131 1131 'ftp_private_key' => '', 1132 1132 'custom_type' => '', 1133 1133 'featured_delim' => ',', 1134 1134 'atch_delim' => ',', 1135 1135 'is_search_existing_attach' => 0, 1136 1136 'post_taxonomies' => array(), 1137 1137 'parent' => 0, 1138 1138 'is_multiple_page_parent' => 'yes', 1139 1139 'single_page_parent' => '', 1140 1140 'order' => 0, 1141 1141 'status' => 'publish', 1142 1142 'page_template' => 'default', 1143 1143 'is_multiple_page_template' => 'yes', 1144 1144 'single_page_template' => '', 1145 1145 'page_taxonomies' => array(), 1146 1146 'date_type' => 'specific', 1147 1147 'date' => 'now', 1148 1148 'date_start' => 'now', 1149 1149 'date_end' => 'now', 1150 1150 'custom_name' => array(), 1151 1151 'custom_value' => array(), 1152 1152 'custom_format' => array(), 1153 1153 'custom_mapping' => array(), 1154 1154 'serialized_values' => array(), 1155 1155 'custom_mapping_rules' => array(), 1156 1156 'comment_status' => 'open', 1157 1157 'comment_status_xpath' => '', 1158 1158 'ping_status' => 'open', 1159 1159 'ping_status_xpath' => '', 1160 1160 'create_draft' => 'no', 1161 1161 'author' => '', 1162 1162 'post_excerpt' => '', 1163 1163 'post_slug' => '', 1164 1164 'attachments' => '', 1165 1165 'is_import_specified' => 0, 1166 1166 'import_specified' => '', 1167 1167 'is_delete_source' => 0, 1168 1168 'is_cloak' => 0, 1169 1169 'unique_key' => '', 1170 1170 'tmp_unique_key' => '', 1171 1171 'feed_type' => 'auto', 1172 1172 'search_existing_images' => 1, 1173 1173 1174 1174 'create_new_records' => 1, 1175 1175 'is_selective_hashing' => 0, 1176 1176 'is_delete_missing' => 0, 1177 1177 'set_missing_to_draft' => 0, 1178 1178 'is_update_missing_cf' => 0, 1179 1179 'update_missing_cf_name' => '', 1180 1180 'update_missing_cf_value' => '', 1181 1181 1182 1182 'is_keep_former_posts' => 'no', 1183 1183 'is_update_status' => 1, 1184 1184 'is_update_content' => 1, 1185 1185 'is_update_title' => 1, 1186 1186 'is_update_slug' => 1, 1187 1187 'is_update_excerpt' => 1, 1188 1188 'is_update_categories' => 1, 1189 1189 'is_update_author' => 1, 1190 1190 'is_update_comment_status' => 1, 1191 1191 'is_update_ping_status' => 1, 1192 1192 'is_update_post_type' => 1, 1193 1193 'is_update_post_format' => 1, 1194 1194 'update_categories_logic' => 'full_update', 1195 1195 'taxonomies_list' => array(), 1196 1196 'taxonomies_only_list' => array(), 1197 1197 'taxonomies_except_list' => array(), 1198 1198 'is_update_attachments' => 1, 1199 1199 'is_update_images' => 1, 1200 1200 'update_images_logic' => 'full_update', 1201 1201 'is_update_dates' => 1, 1202 1202 'is_update_menu_order' => 1, 1203 1203 'is_update_parent' => 1, 1204 1204 'is_keep_attachments' => 0, 1205 1205 'is_keep_imgs' => 0, 1206 1206 'do_not_remove_images' => 1, 1207 1207 1208 1208 'is_update_custom_fields' => 1, 1209 1209 'update_custom_fields_logic' => 'full_update', 1210 1210 'custom_fields_list' => array(), 1211 1211 'custom_fields_only_list' => array(), 1212 1212 'custom_fields_except_list' => array(), 1213 1213 1214 1214 'duplicate_matching' => 'auto', 1215 1215 'duplicate_indicator' => 'title', 1216 1216 'custom_duplicate_name' => '', 1217 1217 'custom_duplicate_value' => '', 1218 1218 'is_update_previous' => 0, 1219 1219 'is_scheduled' => '', 1220 1220 'scheduled_period' => '', 1221 1221 'friendly_name' => '', 1222 1222 'records_per_request' => 20, 1223 1223 'auto_rename_images' => 0, 1224 1224 'auto_rename_images_suffix' => '', 1225 1225 'images_name' => 'filename', 1226 1226 'post_format' => 'standard', 1227 1227 'post_format_xpath' => '', 1228 1228 'encoding' => 'UTF-8', 1229 1229 'delimiter' => '', 1230 1230 'image_meta_title' => '', 1231 1231 'image_meta_title_delim' => ',', 1232 1232 'image_meta_caption' => '', 1233 1233 'image_meta_caption_delim' => ',', 1234 1234 'image_meta_alt' => '', 1235 1235 'image_meta_alt_delim' => ',', 1236 1236 'image_meta_description' => '', 1237 1237 'image_meta_description_delim' => ',', 1238 1238 'image_meta_description_delim_logic' => 'separate', 1239 1239 'status_xpath' => '', 1240 1240 'download_images' => 'yes', 1241 1241 'converted_options' => 0, 1242 1242 'update_all_data' => 'yes', 1243 1243 'is_fast_mode' => 0, 1244 1244 'chuncking' => 1, 1245 1245 'import_processing' => 'ajax', 1246 1246 'processing_iteration_logic' => 'auto', 1247 1247 'save_template_as' => 0, 1248 1248 1249 1249 'title' => '', 1250 1250 'content' => '', 1251 1251 'name' => '', 1252 1252 'is_keep_linebreaks' => 1, 1253 1253 'is_leave_html' => 0, 1254 1254 'fix_characters' => 0, 1255 1255 'pid_xpath' => '', 1256 1256 'slug_xpath' => '', 1257 1257 'title_xpath' => '', 1258 1258 1259 1259 'featured_image' => '', 1260 1260 'download_featured_image' => '', 1261 1261 'download_featured_delim' => ',', 1262 1262 'gallery_featured_image' => '', 1263 1263 'gallery_featured_delim' => ',', 1264 1264 'is_featured' => 1, 1265 1265 'is_featured_xpath' => '', 1266 1266 'set_image_meta_title' => 0, 1267 1267 'set_image_meta_caption' => 0, 1268 1268 'set_image_meta_alt' => 0, 1269 1269 'set_image_meta_description' => 0, 1270 1270 'auto_set_extension' => 0, 1271 1271 'new_extension' => '', 1272 1272 'tax_logic' => array(), 1273 1273 'tax_assing' => array(), 1274 1274 'term_assing' => array(), 1275 1275 'multiple_term_assing' => array(), 1276 1276 'tax_hierarchical_assing' => array(), 1277 1277 'tax_hierarchical_last_level_assign' => array(), 1278 1278 'tax_single_xpath' => array(), 1279 1279 'tax_multiple_xpath' => array(), 1280 1280 'tax_hierarchical_xpath' => array(), 1281 1281 'tax_multiple_delim' => array(), 1282 1282 'tax_hierarchical_delim' => array(), 1283 1283 'tax_manualhierarchy_delim' => array(), 1284 1284 'tax_hierarchical_logic_entire' => array(), 1285 1285 'tax_hierarchical_logic_manual' => array(), 1286 1286 'tax_enable_mapping' => array(), 1287 1287 'tax_is_full_search_single' => array(), 1288 1288 'tax_is_full_search_multiple' => array(), 1289 1289 'tax_assign_to_one_term_single' => array(), 1290 1290 'tax_assign_to_one_term_multiple' => array(), 1291 1291 'tax_mapping' => array(), 1292 1292 'tax_logic_mapping' => array(), 1293 1293 'is_tax_hierarchical_group_delim' => array(), 1294 1294 'tax_hierarchical_group_delim' => array(), 1295 1295 'nested_files' => array(), 1296 1296 'xml_reader_engine' => 0, 1297 1297 'taxonomy_type' => '', 1298 1298 'taxonomy_parent' => '', 1299 1299 'taxonomy_slug' => 'auto', 1300 1300 'taxonomy_slug_xpath' => '', 1301 1301 'taxonomy_display_type' => '', 1302 1302 'taxonomy_display_type_xpath' => '', 1303 1303 'import_img_tags' => 0, 1304 1304 'search_existing_images_logic' => 'by_url', 1305 1305 'enable_import_scheduling' => 'false', 1306 1306 'scheduling_enable' => false, 1307 1307 'scheduling_weekly_days' => '', 1308 1308 'scheduling_run_on' => 'weekly', 1309 1309 'scheduling_monthly_day' => '', 1310 1310 'scheduling_times' => array(), 1311 1311 'scheduling_timezone' => 'UTC', 1312 1312 'is_update_comment_post_id' => 1, 1313 1313 'is_update_comment_author' => 1, 1314 1314 'is_update_comment_author_email' => 1, 1315 1315 'is_update_comment_author_url' => 1, 1316 1316 'is_update_comment_author_IP' => 1, 1317 1317 'is_update_comment_karma' => 1, 1318 1318 'is_update_comment_approved' => 1, 1319 1319 'is_update_comment_verified' => 1, 1320 1320 'is_update_comment_rating' => 1, 1321 1321 'is_update_comment_agent' => 1, 1322 1322 'is_update_comment_user_id' => 1, 1323 1323 'is_update_comment_type' => 1, 1324 1324 'is_update_comments' => 1, 1325 1325 'update_comments_logic' => 'full_update', 1326 1326 'comment_author' => '', 1327 1327 'comment_author_email' => '', 1328 1328 'comment_author_url' => '', 1329 1329 'comment_author_IP' => '', 1330 1330 'comment_karma' => '', 1331 1331 'comment_parent' => '', 1332 1332 'comment_approved' => '1', 1333 1333 'comment_approved_xpath' => '', 1334 1334 'comment_verified' => '1', 1335 1335 'comment_verified_xpath' => '', 1336 1336 'comment_agent' => '', 1337 1337 'comment_type' => '', 1338 1338 'comment_type_xpath' => '', 1339 1339 'comment_user_id' => 'email', 1340 1340 'comment_user_id_xpath' => '', 1341 1341 'comment_post' => '', 1342 1342 'comment_rating' => '', 1343 1343 'comments_repeater_mode' => 'csv', 1344 1344 'comments_repeater_mode_separator' => '|', 1345 1345 'comments_repeater_mode_foreach' => '', 1346 1346 'comments' => array( 1347 1347 'content' => '', 1348 1348 'author' => '', 1349 1349 'author_email' => '', 1350 1350 'author_url' => '', 1351 1351 'author_ip' => '', 1352 1352 'karma' => '', 1353 1353 'approved' => '', 1354 1354 'type' => '', 1355 1355 'date' => 'now' 1356 1356 ) 1357 1357 ); 1358 1358 } 1359 1359 1360 1360 /* 1361 1361 * Convert csv to xml 1362 1362 */ 1363 1363 public static function csv_to_xml($csv_url){ 1364 1364 1365 1365 include_once(self::ROOT_DIR.'/libraries/XmlImportCsvParse.php'); 1366 1366 1367 1367 $csv = new PMXI_CsvParser($csv_url); 1368 1368 1369 1369 $wp_uploads = wp_upload_dir(); 1370 1370 $tmpname = wp_unique_filename($wp_uploads['path'], str_replace("csv", "xml", basename($csv_url))); 1371 1371 $xml_file = $wp_uploads['path'] .'/'. $tmpname; 1372 1372 file_put_contents($xml_file, $csv->toXML()); 1373 1373 return $xml_file; 1374 1374 1375 1375 } 1376 1376 1377 1377 /** 1378 1378 * @return bool 1379 1379 */ 1380 1380 public static function is_ajax(){ 1381 1381 return (isset($_SERVER["HTTP_ACCEPT"]) && strpos($_SERVER["HTTP_ACCEPT"], 'json')) !== false; 1382 1382 } 1383 1383 1384 1384 /** 1385 1385 * Returns ID of current import. 1386 1386 * 1387 1387 * @return int|bool 1388 1388 */ 1389 1389 public static function getCurrentImportId() { 1390 1390 $input = new PMXI_Input(); 1391 1391 $import_id = $input->get('id'); 1392 1392 if (empty($import_id)) { 1393 1393 $import_id = $input->get('import_id'); 1394 1394 } 1395 1395 return $import_id; 1396 1396 } 1397 1397 1398 1398 } 1399 1399 1400 1400 PMXI_Plugin::getInstance(); -
wp-all-import/trunk/readme.txt
r2737093 r2749264 1 1 === Import any XML or CSV File to WordPress === 2 2 Contributors: soflyy, wpallimport 3 3 Requires at least: 4.1 4 4 Tested up to: 6.0 5 Stable tag: 3.6. 75 Stable tag: 3.6.8 6 6 Tags: wordpress csv import, wordpress xml import, xml, csv, datafeed, import, migrate, import csv to wordpress, import xml to wordpress, advanced xml import, advanced csv import, bulk csv import, bulk xml import, bulk data import, xml to custom post type, csv to custom post type, woocommerce csv import, woocommerce xml import, csv import, import csv, xml import, import xml, csv importer 7 7 8 8 WP All Import is an extremely powerful importer that makes it easy to import any XML or CSV file to WordPress. 9 9 10 10 == Description == 11 11 12 12 = WP All Import - Simple & Powerful XML / CSV Importer Plugin = 13 13 14 14 *“It's a wonderful plugin that does so much, so well that it's hard to list all of the features. But I'll tell you this, I was able to import the content of a pair of websites running the ModX CMS into a WordPress install in less than 30 minutes. No joke!”* 15 15 **Alex Vasquez** - DigiSavvy Co-Founder & WordCamp Los Angeles Organizer 16 16 17 17 WP All Import has a four step import process and an intuitive drag & drop interface that makes complicated import tasks simple and fast. 18 18 19 19 There are no special requirements that the elements in your file must be laid out in a certain way. WP All Import really can import any XML or CSV file. 20 20 21 21 WP All Import can be used for everything from migrating content from a legacy CMS to WordPress to building a store with an affiliate datafeed to displaying live stock quotes or sports scores to building a real estate portal. 22 22 23 23 Check out our [documentation and video tutorials](http://www.wpallimport.com/documentation/?utm_source=import-plugin-free&utm_medium=readme&utm_campaign=docs) to make the most of WP All Import. 24 24 25 25 WP All Import integrates with our companion plugin, [WP All Export](https://wordpress.org/plugins/wp-all-export/). You can export posts, WooCommerce products, orders, users, or anything else with WP All Export. Then you can edit in Excel and re-import to the same site or migrate the data to another site with WP All Import. 26 26 27 27 For technical support from the developers, please consider purchasing WP All Import Pro. 28 28 29 29 = WP All Import Professional Edition = 30 30 [youtube http://www.youtube.com/watch?v=pD6WQANJcJY /] 31 31 32 32 *WP All Import Pro* is a paid upgrade that includes premium support and adds the following features: 33 33 34 34 * Import data to Custom Fields - used by many themes, especially those using Custom Post Types - to store data associated with the posts. 35 35 36 36 * Import images to the post media gallery - WP All Import can download images from URLs in an XML or CSV file and put them in the media gallery. 37 37 38 38 * Cron Job/Recurring Imports - WP All Import pro can check periodically check a file for updates, and add, edit, and delete to the imported posts accordingly. 39 39 40 40 * Import files from a URL - Download and import files from external websites, even if they are password protected with HTTP authentication. URL imports are integrated with the recurring/cron imports feature, so WP All Import can periodically re-download the files and add, edit, and delete posts accordingly. 41 41 42 42 * Execution of Custom PHP Functions on data, i.e. use something like [my_function({xpath/to/a/field[1]})] in your template, to pass the value of {xpath/to/a/field[1]} to my_function and display whatever it returns. 43 43 44 44 * Guaranteed technical support via e-mail. 45 45 46 46 [Upgrade to the Pro edition of WP All Import.](http://www.wpallimport.com/wordpress-xml-csv-import/?utm_source=import-plugin-free&utm_medium=readme&utm_campaign=upgrade-to-pro) 47 47 48 48 Need to [import XML and CSV to WooCommerce?](http://www.wpallimport.com/woocommerce-product-import/?utm_source=import-plugin-free&utm_medium=readme&utm_campaign=upgrade-to-pro) Check out our WooCommerce add-on. 49 49 50 50 = WordPress CSV Imports = 51 51 52 52 Read on to learn more about the CSV importer functionality of WP All Import. Importing CSVs with WP All Import is exactly the same as importing XML files, because internally, WP All Import actually converts your CSV file to an XML file on the fly. You can use the same XPath filtering options and all the same features you have when importing XML files. 53 53 54 54 CSV imports don't require your CSV file to have a specific structure. Your CSV file can use any column names/headings. You can map the columns in your CSV file to the appropriate places in WordPress during the import process. 55 55 56 56 When importing CSV files, your CSV should have UTF-8 encoding if you are having trouble importing special characters. 57 57 58 58 In step 2 of a CSV import, you can specify an alternative delimiter if you aren't using a comma. WP All Import can import CSVs that are pipe-delimited, # delimited, or delimited/separated by any other character. 59 59 60 60 For CSV import tutorials and example files, visit our [documentation](http://www.wpallimport.com/documentation/?utm_source=import-plugin-free&utm_medium=readme&utm_campaign=docs). Please keep in mind CSV imports with WP All Import are just like XML imports - you have all the same functionality, and the process is exactly the same. Any of our tutorial videos that apply to XML files also apply to importing CSV files, so if you see a tutorial with us importing an XML file, know that you can follow the exact same steps for a CSV import. 61 61 62 62 = Add-Ons = 63 63 64 64 A number of premium add-ons are available to add functionality to the importer and make XML & CSV import tasks to complex plugins simple. 65 65 66 66 - Advanced Custom Fields Add-On - [ACF](http://www.advancedcustomfields.com/) XML & CSV importer 67 67 - WooCommerce Add-On - XML & CSV importer for all [WooCommerce](http://wordpress.org/plugins/woocommerce) product types 68 68 - User Import Add-On - XML & CSV importer for users, including user_meta 69 69 - Link Cloak Add-On - Auto-create redirects for links present during an XML or CSV import 70 70 71 71 Learn more about our add-ons at [http://www.wpallimport.com/add-ons](http://www.wpallimport.com/add-ons/?utm_source=import-plugin-free&utm_medium=readme&utm_campaign=add-ons) 72 72 73 73 A [developer API](http://www.wpallimport.com/documentation/developers/action-reference/?utm_source=import-plugin-free&utm_medium=readme&utm_campaign=docs) (action hooks) is also available. 74 74 75 75 == Premium Support == 76 76 Support for the free version of WP All Import is handled through the WordPress.org community forums. 77 77 78 78 Support is not guaranteed and is based on ability. For premium support over email, [purchase WP All Import.](https://www.wpallimport.com/checkout/?edd_action=add_to_cart&download_id=2707176&edd_options%5Bprice_id%5D=1&utm_source=import-plugin-free&utm_medium=readme&utm_campaign=premium-support) 79 79 80 80 == Import To WooCommerce == 81 81 82 82 Need to [import XML and CSV to WooCommerce?](http://wordpress.org/plugins/woocommerce-xml-csv-product-import/) Check out our WooCommerce add-on. 83 83 84 84 [WooCommerce XML & CSV Import Pro Version](http://www.wpallimport.com/woocommerce-product-import/?utm_source=import-plugin-free&utm_medium=readme&utm_campaign=import-wooco-products) 85 85 86 86 == Frequently Asked Questions == 87 87 88 88 **What Size Files Can WP All Import Handle?** 89 89 It depends on your hosting provider’s settings. We’ve imported files of 200Mb and up, even on shared hosts. WP All Import splits your file into manageable chunks. 90 90 91 91 [Various settings are available](http://www.wpallimport.com/documentation/advanced/import-processing/?utm_source=import-plugin-free&utm_medium=readme&utm_campaign=upgrade-to-pro) to make it possible to import larger files or speed up your import. 92 92 93 93 *The answer to all of the following questions is yes:* 94 94 95 95 Does this really work with ANY XML or CSV file? 96 96 Can WP All Import get ALL of the data out of the file? Even attributes? 97 97 Does it work with special character encoding like Hebrew, Arabic, Chinese, etc? 98 98 99 99 == Screenshots == 100 100 101 101 1. Choose file. 102 102 2. Filtering options. 103 103 3. Choose where to import your data. 104 104 4. Manage imports. 105 105 106 106 == Changelog == 107 108 = 3.6.8 = 109 * security improvement 107 110 108 111 = 3.6.7 = 109 112 * security improvement 110 113 * improvement: changed Manage Imports page button labels to be more precise 111 114 * improvement: assign 'Uncategorized' term to posts imported without a category assigned 112 115 * improvement: add support for taxonomies that return objects instead of IDs 113 116 * improvement: remove commented code that could cause false positives for security scans 114 117 * bug fix: jQuery error related to 'destroy' method 115 118 * bug fix: rare issue that prevented content image URLs from being updated during import 116 119 * bug fix: taxonomies section drag and drop doesn't save after rearranging fields 117 120 * bug fix: conflict with Advanced Ads plugin 118 121 * bug fix: 'Instead of deletion, set missing records to out of stock' still deleting products 119 122 120 123 = 3.6.6 = 121 124 * bug fix: jQuery nestedSortable compatibility with WordPress 5.9 122 125 123 126 = 3.6.5 = 124 127 * improvement: better sanitization and escaping of data in WP All Import interface 125 128 126 129 = 3.6.4 = 127 130 * improvement: better sanitization and escaping of data in WP All Import interface 128 131 * improvement: use libraries included in WordPress Core 129 132 130 133 = 3.6.3 = 131 134 * security fix 132 135 * bug fix: images not updated for existing products when using WooCommerce Import Add-On 133 136 134 137 = 3.6.2 = 135 138 * improvement: add ability to control taxonomy mapping case sensitivity via filter wpai_is_case_insensitive_taxonomy_mapping 136 139 * improvement: add ability to control uploads directory for single file/image via filters wp_all_import_single_image_uploads_dir and wp_all_import_single_attachment_uploads_dir 137 140 * improvement: add missing options on confirm import step 138 141 * bug fix 139 142 * improvement: initial PHP 8 support 140 143 * bugfix: manage_options capability check 141 144 142 145 = 3.6.1 = 143 146 * bug fix: categories were imported despite the taxonomy option being disabled 144 147 * improvement: add ability to filter csv escape symbol via wp_all_import_csv_parser_settings filter 145 148 146 149 = 3.6.0 = 147 150 * maintenance: compatibility with Elementor v3.3 JavaScript changes 148 151 149 152 = 3.5.9 = 150 153 * bug fix: call to the non existing function wp_all_import_sanitize_url 151 154 152 155 = 3.5.8 = 153 156 * bug fix: import of taxonomies hierarchy didn't work properly 154 157 155 158 = 3.5.7 = 156 159 * improvement: git rid if deprecated join query on manage imports screen 157 160 * improvement: add is_update_post_format option 158 161 * improvement: add wp_all_import_manual_matching filter 159 162 * improvement: add wp_all_import_logger filter 160 163 * bug fix: records were removed from pmxi_posts table when activating WPAI on multisite installation 161 164 * bug fix: get rid of unused deprecated function add_contextual_help() 162 165 163 166 = 3.5.6 = 164 167 * bug fix: PMXI_Hash_Record class doesn't exist error appears when deleting missing records 165 168 166 169 = 3.5.5 = 167 170 * improvement: get rid of deprecated setting 'High Speed Small File Processing' 168 171 * bug fix: chromium scroll anchoring caused screen jumping effect 169 172 * bug fix: pagenum query argument caused broken link on import complete screen 170 173 171 174 = 3.5.4 = 172 175 * improvement: compatibility with WordPress 5.5 173 176 * API: added helper function wp_all_import_get_import_id() 174 177 * API: added helper function wp_all_import_get_import_post_type($import_id) 175 178 176 179 = 3.5.3 = 177 180 * bug fix: switch to CodeMirror implementation shipped in WordPress core 178 181 * bug fix: unable to double click to insert XPath in some cases 179 182 * bug fix: unable to apply pmxi_is_images_to_update filter to featured images 180 183 * bug fix: unable to match existing images when suffix is added to file name during import 181 184 182 185 = 3.5.2 = 183 186 * improvement: match existing images by filename with underscores 184 187 * API: add new action wp_all_import_before_preserve_post_data 185 188 * API: add new filter wp_all_import_specified_delimiters 186 189 * bug fix: attachment author not imported for API image imports 187 190 188 191 = 3.5.1 = 189 192 * improvement: add support for importing WebP images 190 193 * bug fix: images in content not being imported when creating new simple WooCommerce products 191 194 192 195 = 3.5.0 = 193 196 * improvement: add support for .tsv format 194 197 * API: add current XML variable to pmxi_article_data filter 195 198 * bug fix: post terms incorrect after import complete, must be recounted 196 199 * bug fix: empty attachments created when attachment import fails 197 200 * bug fix: matching posts by ID matches and imports into attachments with the same ID 198 201 199 202 = 3.4.9 = 200 203 * bug fix: import using stream reader 201 204 * bug fix: generation temporary files in system temporary folder 202 205 203 206 = 3.4.8 = 204 207 * improvement: various import speed optimizations 205 208 * bug fix: remove deprecated function calls for PHP 7.2 compatibility 206 209 * bug fix: delete db tables when mu blog deleted 207 210 * bug fix: remove BOM from import templates 208 211 * bug fix: saving CSV delimiter when changing import file 209 212 210 213 = 3.4.7 = 211 214 * improvement: skip to the first specified record when importing only part of a file 212 215 * new filter: wp_all_import_is_render_whole_xml_tree 213 216 * new filter: wp_all_import_images_uploads_dir (add-on api) 214 217 * bug fix: patch XSS exploit 215 218 * bug fix: conflict with InfiniteWP 216 219 * bug fix: update notification for Link Cloaking Add-On 217 220 * bug fix: load functions before pmxi_before_xml_import 218 221 * bug fix: do not re-count category terms when post imported as draft 219 222 * bug fix: import base64 encoded images in add-ons 220 223 * security fix - XSS exploit (Special thanks to Yuji Tounai for reporting) 221 224 222 225 = 3.4.6 = 223 226 * improvement: added timestamp to import log lines 224 227 * improvement: added support for bmp images 225 228 * improvement: added new action pmxi_before_post_import_{$addon} 226 229 * security fix: patch XSS exploit 227 230 * bug fix: import pages hierarchy 228 231 * bug fix: error in pclzip.lib.php with php 7.1 229 232 * bug fix: import taxonomies hierarchy 230 233 * bug fix: json to xml convertation 231 234 * bug fix: removed SWFUpload 232 235 * security fix - XSS exploit (Special thanks to Mardan Muhidin for reporting) 233 236 234 237 = 3.4.5 = 235 238 * improvement: custom fields delection 236 239 * improvement: new action wp_all_import_post_skipped 237 240 * improvement: updated history page title 238 241 * improvement: optimize large imports deletion 239 242 * improvement: added import friendly name to confirm screen 240 243 * improvement: sql query optimization on manage imports screen 241 244 * bug fix: generation image filename 242 245 * bug fix: wp_all_import_specified_records filter 243 246 244 247 = 3.4.4 = 245 248 * bug fix: import template not worked when downloaded via Import Settings 246 249 * bug fix: updating user login 247 250 * bug fix: import images with encoded quotes 248 251 * improvement: added hungarian translation 249 252 250 253 = 3.4.3 = 251 254 * improvement: new filter 'wp_all_import_phpexcel_delimiter' 252 255 * improvement: new filter 'wp_all_import_is_trim_parsed_data' 253 256 * improvement: added new filter 'wp_all_import_skip_x_csv_rows' 254 257 * improvement: added csv delimiter setting to import options screen 255 258 * bug fix: import duplicate tags 256 259 257 260 = 3.4.2 = 258 261 * bug fix: conflict with the event calendar plugin 259 262 * bug fix: import images for newly created products 260 263 261 264 = 3.4.1 = 262 265 * improvement: Stop parsing data which is not going to be updated 263 266 * improvement: added new filter wp_all_import_phpexcel_object to modify excel data before import 264 267 * bug fix: search for images ending with underscores in media 265 268 * bug fix: import hierarchical posts/pages 266 269 * bug fix: import cpt page templates 267 270 268 271 = 3.4.0 = 269 272 * improvement: compatibility with PHP 7.x 270 273 271 274 = 3.3.9 = 272 275 * improvement: new re-import option 'is update post type' 273 276 * bug fix: hierarchy taxonomies preview 274 277 * bug fix: empty logs folder generation 275 278 * bug fix: 'Keep images currently in Media Library' option for add-ons 276 279 * bug fix: import bundles with gz files 277 280 * bug fix: custom functions for attachments 278 281 279 282 = 3.3.8 = 280 283 * improvement: 'Force Stream Reader' setting 281 284 * improvement: new filter 'wp_all_import_auto_create_csv_headers' 282 285 * improvement: new filter 'wp_all_import_is_base64_images_allowed' 283 286 * improvement: new filter 'wp_all_import_set_post_terms' to leave a specific category alone when a post is being updated 284 287 * bug fix: nodes navigation for xpath like /news/item 285 288 * bug fix: frozen import template screen for cyrillic XML feeds 286 289 * bug fix: conflict between taxonomies & user import 287 290 * bug fix: creating users with the same email 288 291 * bug fix: enable keep line breaks option by default 289 292 * bug fix: composer namespace conflict 290 293 * bug fix: images preview when wp is in subdirectory 291 294 * bug fix: 'Instead of deletion, set Custom Field' option for users import 292 295 293 296 = 3.3.7 = 294 297 * added new option 'Use StreamReader instead of XMLReader to parse import file' to fix issue with libxml 2.9.3 295 298 * execute 'pmxi_article_data' filter for all posts ( new & existing ) 296 299 297 300 = 3.3.6 = 298 301 * added de_CH translation 299 302 * added support for .svg images 300 303 * added possibility for import excerpts for pages 301 304 * added new filter 'wp_all_import_specified_records' 302 305 * added new filter 'wp_all_import_is_post_to_delete' 303 306 * disable XMLReader stream filter for HHVM 304 307 * improve search for existing images in media gallery 305 308 306 309 = 3.3.5 = 307 310 * fixed 'Use images currently in Media Library' option 308 311 309 312 = 3.3.4 = 310 313 * fixed error messages on step 1 in case when server throws fatal error e.q. time limit exception 311 314 * fixed option "Delete posts that are no longer present in your file", now it works with empty CSV files which has only one header row 312 315 * fixed custom php functions in images preview 313 316 * fixed detecting root nodes with colons in names 314 317 * added es_ES translation 315 318 * added de_DE translation 316 319 * added iterative ajax delete process ( deleting associated posts ) 317 320 * added feature to download template/bundle from import settings 318 321 * added new option for importing images "Use images currently in Media Library" 319 322 * added new action 'pmxi_missing_post' 320 323 321 324 = 3.3.3 = 322 325 * fixed duplicate matching by custom field 323 326 * fixed converting image filenames to lowercase 324 327 * fixed import html to image description 325 328 * fixed import _wp_old_slug 326 329 * added Post ID to manual record matching 327 330 * added 'Comment status' to 'Choose data to update' section 328 331 329 332 = 3.3.2 = 330 333 * fixed fatal error on saving settings 331 334 332 335 = 3.3.1 = 333 336 * fixed parsing CSV with empty lines 334 337 * fixed parsing multiple IF statements 335 338 * fixed preview in case when ‘Disable the visual editor when writing’ is enabled 336 339 * fixed conflict with WooCommerce - Store Exporter Deluxe 337 340 * added notifications for required addons 338 341 * added support for wp all export bundle 339 342 * added support for manual import bundle 340 343 * added feature 'click to download import file' 341 344 * added validation for excerpt and images sections 342 345 * added auto-detect a broken Unique ID notification 343 346 * added import template notifications 344 347 * removed support for importing WooCommerce Orders 345 348 * changed absolute paths to relative in db 346 349 347 350 = 3.3.0 = 348 351 * added new options to taxonomies import 'Try to match terms to existing child Product Categories' & 'Only assign Products to the imported Product Category, not the entire hierarchy' 349 352 * added support for Excel files ( .xls, .xlsx ) 350 353 351 354 = 3.2.9 = 352 355 * load ini_set only on plugin pages 353 356 * fixed saving import template 354 357 355 358 = 3.2.8 = 356 359 * fixed Apply mapping rules before splitting via separator symbol for manual hierarchy 357 360 * fixed path equal or less than 358 361 * fixed changing unique key when moving back from confirm screen 359 362 * fixed override page template 360 363 * updated wp_all_import_is_post_to_update filter with second argument XML node as array 361 364 * added a second argument to pmxi_saved_post action ( SimpleXML object ) of current record 362 365 363 366 = 3.2.7 = 364 367 * fixed enum fields mapping rules feature 365 368 366 369 = 3.2.6 = 367 370 * Compatibility with 3rd party development: http://www.wpallimport.com/documentation/addon-dev/overview/ 368 371 369 372 = 3.2.5 = 370 373 * Important security fixes - additional hardening, prevention of blind SQL injection and reflected XSS attacks 371 374 372 375 = 3.2.4 = 373 376 * critical security fix - stopping non-logged in users from accessing adminInit 374 377 375 378 = 3.2.3 = 376 379 * fixed re-count record when a file has been changed at an import setting screen 377 380 * fixed unlink attachment source when posts updated/deleted 378 381 * added a limit 10 to the existing meta values 379 382 380 383 = 3.2.2 = 381 384 * fixed database schema 382 385 * uploading large files 383 386 384 387 = 3.2.1 = 385 388 * fixed updating import settings 386 389 387 390 = 3.2.0 = 388 391 * IMPORTANT: WP All Import v4 (3.2.0) is a MAJOR update. Read this post before upgrading: http://www.wpallimport.com/2014/11/free-version-wordpress-org-update-information 389 392 * speed up the import of taxonomies/categories 390 393 * added taxonomies/categories mapping feature 391 394 * added custom fields auto-detection feature 392 395 * added custom fields mapping feature 393 396 * added images/taxonomies preview feature 394 397 * added unofficial support for more file formats - json & sql 395 398 * added new setting (secure mode) to protect your files 396 399 * better import logs 397 400 * updated design 398 401 399 402 = 3.1.5 = 400 403 * fixed pmxi_delete_post action 401 404 * fixed import menu order & post parent for pages 402 405 * fixed import log for continue import feature 403 406 * added is update author option 404 407 * fixed post formats 405 408 * fixed UTC dates on manage imports page 406 409 407 410 = 3.1.4 = 408 411 * changed support email 409 412 410 413 = 3.1.3 = 411 414 * fixed import pages 412 415 413 416 = 3.1.2 = 414 417 * added compatibility with WP 3.9 415 418 * added autodetect session mode 416 419 * updated convertation CSV to XML with XMLWriter 417 420 * fixed import *.zip files 418 421 * fixed xpath helper on step 2 419 422 * fixed showing zeros in XML tree 420 423 * fixed deleting history files 421 424 * fixed autodetect image extensions 422 425 * fixed increasing SQL query length 423 426 * allow post content to be empty on step 3 424 427 * delete deprecated settings "my csv contain html code" and "case sensitivity" 425 428 426 429 = 3.1.1 = 427 430 * Fixed compatibility with addons 428 431 * Fixed "download image" option for import products 429 432 * Fixed CSS for WP 3.8 430 433 * Fixed dismiss links 431 434 432 435 = 3.1.0 = 433 436 * Compatibility with WP 3.8 434 437 * Compatibility with WPAI WooCommerce add-on (paid) 1.2.4 435 438 * Performance Improvements 436 439 * Improved UI 437 440 * Lots of bug fixes 438 441 * New Record Matching section 439 442 * Added option to set Post Status with XPath (the value of presented XPath should be one of the following: publish, draft, trash) 440 443 * Preview navigation 441 444 442 445 = 3.0.4 = 443 446 * Fixed import categories; 444 447 * Updated UI/UX; 445 448 * Added import/export templates feature; 446 449 * Added enhanced session functionality; 447 450 * Added option to set post status with XPath; 448 451 * Added feeds encoding feature; 449 452 450 453 = 3.0.2 = 451 454 * Added support for the WooCommerce add-on 452 455 453 456 = 3.0 = 454 457 * Free edition of 3.0 pro release 455 458 456 459 = 2.14 = 457 460 * Category list delimiter bug fix 458 461 459 462 = 2.13 = 460 463 * Tons of bug fixes, updates, and additional features. 461 464 462 465 463 466 = 2.12 = 464 467 * Initial release on WordPress.org.
Note: See TracChangeset
for help on using the changeset viewer.