Plugin Directory


Ignore:
Location:
wp-all-import/trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • wp-all-import/trunk/classes/upload.php

    r2737093 r2749264  
    11<?php
    22if ( ! class_exists('PMXI_Upload')){
    33
    44    class PMXI_Upload{
    55
    66        protected $file;
    77        protected $errors;
    88        protected $root_element = '';
    99        protected $is_csv = false;
    1010
    11         protected $uploadsPath;             
     11        protected $uploadsPath;
    1212
    1313        function __construct( $file,  $errors, $targetDir = false ){
    1414
    1515            $this->file = $file;
    1616            $this->errors = $errors;
    1717
    1818            $uploads = wp_upload_dir();
    1919
    2020            $input = new PMXI_Input();
    2121            $import_id = $input->get('id');
    2222            // Get import ID from cron processing URL.
    2323            if (empty($import_id)) {
    2424                $import_id = $input->get('import_id');
    2525            }
    2626            // Get import ID from CLI arguments.
    2727            if (empty($import_id) && PMXI_Plugin::getInstance()->isCli()) {
    2828                global $argv;
    2929                foreach ($argv as $key => $arg) {
    3030                    if ($arg === 'run' && !empty($argv[$key + 1])) {
    3131                        $import_id = $argv[$key + 1];
    3232                    }
    3333                }
    3434            }
    3535            if ( $uploads['error'] ) {
    3636                $this->uploadsPath = false;
    3737            } else {
    3838                $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 );
    3939            }
    4040        }
    4141
    4242        public function upload() {
    4343
    4444            $this->file = wp_all_import_get_absolute_path($this->file);
    4545
    46             $templates = false;     
    47 
    48             $bundle = array(); 
     46            $templates = false;
     47
     48            $bundle = array();
    4949
    5050            $bundleFiles = array();
    5151
    5252            $csv_path = '';
    5353
    5454            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'));
    5656            } elseif (!is_file($this->file)) {
    5757                $this->errors->add('form-validation', __('Uploaded file is empty', 'wp_all_import_plugin'));
    5858            } elseif ( ! preg_match('%\W(xml|gzip|zip|csv|tsv|gz|json|txt|dat|psv|sql|xls|xlsx)$%i', trim(basename($this->file)))) {
    5959                $this->errors->add('form-validation', __('Uploaded file must be XML, CSV, ZIP, GZIP, GZ, JSON, SQL, TXT, DAT or PSV', 'wp_all_import_plugin'));
    6060            } elseif (preg_match('%\W(zip)$%i', trim(basename($this->file)))) {
    61                                        
     61
    6262                if (!class_exists('PclZip')) {
    6363                    require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
    6464                }
    6565
    6666                $archive = new PclZip($this->file);
    6767                if (($v_result_list = $archive->extract(PCLZIP_OPT_PATH, $this->uploadsPath, PCLZIP_OPT_REPLACE_NEWER)) == 0) {
    6868                    $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'));
    6969                } else {
    7070                    $filePath = '';
    7171                    $decodedTemplates = array();
    7272                    if ( ! empty($v_result_list) ) {
    7373                        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                            }
    7478                            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 ) {
    7579                                if ( strpos(basename($unzipped_file['stored_filename']), 'WP All Import Template') === 0 || strpos(basename($unzipped_file['stored_filename']), 'templates_') === 0 ) {
    7680                                    $templates = file_get_contents($unzipped_file['filename']);
    7781                                    $decodedTemplates = json_decode($templates, true);
    7882                                    $templateOptions = empty($decodedTemplates[0]) ? current($decodedTemplates) : $decodedTemplates;
    7983                                    if ( ! empty($templateOptions) and isset($templateOptions[0]['_import_type']) and $templateOptions[0]['_import_type'] == 'url' ) {
    8084                                        $options = maybe_unserialize($templateOptions[0]['options']);
    8185                                        return array(
    82                                             'filePath' => $templateOptions[0]['_import_url'],                                                                                                                                   
     86                                            'filePath' => $templateOptions[0]['_import_url'],
    8387                                            'bundle' => $bundle,
    84                                             'template' => json_encode($templateOptions),           
    85                                             'templates' => $templates,                             
     88                                            'template' => json_encode($templateOptions),
     89                                            'templates' => $templates,
    8690                                            'post_type' => (!empty($options)) ? $options['custom_type'] : false,
    8791                                            'taxonomy_type' => (!empty($options['taxonomy_type'])) ? $options['taxonomy_type'] : false,
    8892                                            'is_empty_bundle_file' => true
    8993                                        );
    9094                                    }
    9195                                } else {
    9296                                    if ($filePath == '') {
    93                                         $filePath = $unzipped_file['filename'];                                 
     97                                        $filePath = $unzipped_file['filename'];
    9498                                    }
    9599                                    if ( ! in_array($unzipped_file['filename'], $bundleFiles) ) {
    96100                                        $bundleFiles[basename($unzipped_file['filename'])] = $unzipped_file['filename'];
    97101                                    }
    98102                                }
    99103                            }
    100104                        }
    101105                    }
    102106
    103107                    if (count($bundleFiles) > 1)  {
    104108                        if ( ! empty($decodedTemplates) ) {
    105109                            foreach ($decodedTemplates as $cpt => $tpl) {
    106110                                $fileFormats  = $this->get_xml_file( $bundleFiles[basename($tpl[0]['source_file_name'])] );
    107111                                $bundle[$cpt] = $fileFormats['xml'];
    108112                            }
    109113                        }
    110114                        if ( ! empty($bundle)) $filePath = current($bundle);
    111                     }                                       
     115                    }
    112116
    113117                    if ( $this->uploadsPath === false ){
    114118                        $this->errors->add('form-validation', __('WP All Import can\'t access your WordPress uploads folder.', 'wp_all_import_plugin'));
    115119                    }
    116120
    117121                    if (empty($filePath)) {
    118122                        $zip = zip_open(trim($this->file));
    119                         if (is_resource($zip)) {                                                       
     123                        if (is_resource($zip)) {
    120124                            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                                }
    130136                            }
    131137                            zip_close($zip);
    132138                        } 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
    137143                    $source = array(
    138144                        'name' => basename($this->file),
    139                         'type' => 'upload',                         
    140                         'path' => $this->file,                 
     145                        'type' => 'upload',
     146                        'path' => $this->file,
    141147                    );
    142148                    $fileFormats = $this->get_xml_file( $filePath );
    143149                    $filePath = $fileFormats['xml'];
    144150                    $csv_path = $fileFormats['csv'];
    145151                }
    146152            } elseif ( preg_match('%\W(csv|txt|dat|psv|tsv)$%i', trim($this->file))) { // If CSV file uploaded
    147                    
     153
    148154                if ( $this->uploadsPath === false ){
    149155                     $this->errors->add('form-validation', __('WP All Import can\'t access your WordPress uploads folder.', 'wp_all_import_plugin'));
    150                 }                                   
     156                }
    151157                $filePath = $this->file;
    152158                $source = array(
    153159                    'name' => basename($this->file),
    154160                    'type' => 'upload',
    155161                    '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 ) );
    161167                //@unlink($filePath);
    162168                $csv_path = $filePath;
    163                 $filePath = $csv->xml_path;                             
     169                $filePath = $csv->xml_path;
    164170                $this->is_csv = $csv->is_csv;
    165                 $this->root_element = 'node';               
    166                        
     171                $this->root_element = 'node';
     172
    167173            } elseif(preg_match('%\W(gz)$%i', trim($this->file))){ // If gz file uploaded
    168174                $fileInfo = wp_all_import_get_gz($this->file, 0, $this->uploadsPath);
    169175                if ( ! is_wp_error($fileInfo) ){
    170176                    $filePath = $fileInfo['localPath'];
    171                     // Detect if file is very large             
     177                    // Detect if file is very large
    172178                    $source = array(
    173179                        'name' => basename($this->file),
    174180                        'type' => 'upload',
    175                         'path' => $this->file,                 
     181                        'path' => $this->file,
    176182                    );
    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');
    181187                        $csv = new PMXI_CsvParser( array( 'filename' => $filePath, 'targeDir' => $this->uploadsPath ) ); // create chunks
    182188                        //@unlink($filePath);
    183189                        $csv_path = $filePath;
    184190                        $filePath = $csv->xml_path;
    185191                        $this->is_csv = $csv->is_csv;
    186192                        $this->root_element = 'node';
    187193                    }
    188194                }
    189195                else $this->errors->add('form-validation', $fileInfo->get_error_message());
    190196            } elseif (preg_match('%\W(json)$%i', trim($this->file))){
    191197
    192                 // Detect if file is very large             
     198                // Detect if file is very large
    193199                $source = array(
    194200                    'name' => basename($this->file),
    195201                    'type' => 'upload',
    196                     'path' => $this->file,                 
     202                    'path' => $this->file,
    197203                );
    198204
    199205                $json_str = trim(file_get_contents($this->file));
    200206                $json_str = str_replace("\xEF\xBB\xBF",'', $json_str);
    201207                $is_json = wp_all_import_is_json($json_str);
    202                
     208
    203209                if( is_wp_error($is_json)){
    204210                    $this->errors->add('form-validation', $is_json->get_error_message(), 'wp_all_import_plugin');
    205211                } else {
    206212                    $xml_data = wp_all_import_json_to_xml( json_decode($json_str, true) );
    207213                    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'));
    209215                    } else{
    210216                        $jsontmpname = $this->uploadsPath  .'/'. wp_all_import_url_title(wp_unique_filename($this->uploadsPath, str_replace("json", "xml", basename($this->file))));
    211217                        //@unlink($this->file);
    212218                        file_put_contents($jsontmpname, $xml_data);
    213                         $filePath = $jsontmpname;       
    214                        
     219                        $filePath = $jsontmpname;
     220
    215221                    }
    216222                }
    217223            } elseif (preg_match('%\W(sql)$%i', trim($this->file))) {
    218224                $source = array(
    219225                    'name' => basename($this->file),
    220226                    'type' => 'upload',
    221                     'path' => $this->file,                 
     227                    'path' => $this->file,
    222228                );
    223229                include_once( PMXI_Plugin::ROOT_DIR . '/libraries/XmlImportSQLParse.php' );
    224230                $sql = new PMXI_SQLParser( $this->file, $this->uploadsPath );
    225231                $filePath = $sql->parse();
    226232            } elseif (preg_match('%\W(xls|xlsx)$%i', trim($this->file))){
    227233                $source = array(
    228234                    'name' => basename($this->file),
    229235                    'type' => 'upload',
    230                     'path' => $this->file,                 
     236                    'path' => $this->file,
    231237                );
    232238
    233239                include_once( PMXI_Plugin::ROOT_DIR . '/libraries/XmlImportXLSParse.php' );
    234240                $xls = new PMXI_XLSParser( $this->file, $this->uploadsPath );
    235241                $filePath = $xls->parse();
    236242            } else { // If XML file uploaded
    237243                $filePath = $this->file;
    238244                $source = array(
    239245                    'name' => basename($this->file),
    240246                    'type' => 'upload',
    241247                    'path' => $filePath,
    242248                );
    243             }           
     249            }
    244250
    245251            if ( $this->errors->get_error_codes() ) return $this->errors;
    246252
    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
    251257            $templateOptions = "";
    252258
    253259            if ( is_array($decodedTemplates) ) {
    254260                $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']);
    258264
    259265            if ( ! empty($options['root_element'])) $this->root_element = $options['root_element'];
    260266
    261267            return array(
    262268                'filePath'      => $filePath,
    263269                'bundle'        => $bundle, // sub imports [cpt => filepath]
    264270                'source'        => $source,
    265271                'root_element'  => $this->root_element,
    266272                'is_csv'        => $this->is_csv,
    267273                'csv_path'      => $csv_path,
    268274                'template'      => empty($templateOptions) ? "" : json_encode($templateOptions),
    269275                'templates'     => $templates,
    270276                'post_type'     => (!empty($options)) ? $options['custom_type'] : false,
    271277                'taxonomy_type' => (!empty($options['taxonomy_type'])) ? $options['taxonomy_type'] : false,
    272278            );
    273279        }
    274280
    275281        public function url( $feed_type = '', $feed_xpath = '', $importTemplate = ''){
    276282
    277283            $uploads = wp_upload_dir();
    278284
    279285            $templates = false;
    280286
    281             $bundle = array(); 
     287            $bundle = array();
    282288
    283289            $bundleFiles = array();
    284290
    285291            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'));
    287293            } 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');
    289295            } elseif( ! is_writeable($this->uploadsPath)){
    290296                $this->errors->add('form-validation', __('Uploads folder '.$this->uploadsPath.' is not writable.'), 'wp_all_import_plugin');
    291297            }
    292298
    293299            $this->file = trim($this->file);
    294300
    295301            $csv_path = '';
    296302
    297303            if ( empty($this->errors->errors) ){
    298304
    299305                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));
    300306
    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
    303309                    $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)) {
    308314                        $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'));
    311317                    }
    312318
    313319                    if (!class_exists('PclZip'))  {
    314320                        require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
    315321                    }
    316322
    317323                    $archive = new PclZip($tmpname);
    318324                    if (($v_result_list = $archive->extract(PCLZIP_OPT_PATH, $this->uploadsPath, PCLZIP_OPT_REPLACE_NEWER)) == 0) {
    319325                        $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'));
    320326                    } else {
    321327                        $filePath = '';
    322328                        if (!empty($v_result_list)) {
    323329                            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                                }
    324334                                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 ) {
    325335                                    if ( strpos(basename($unzipped_file['stored_filename']), 'WP All Import Template') === 0 || strpos(basename($unzipped_file['stored_filename']), 'templates_') === 0) {
    326336                                        $templates = file_get_contents($unzipped_file['filename']);
    327337                                        $decodedTemplates = json_decode($templates, true);
    328                                         $templateOptions = empty($decodedTemplates[0]) ? current($decodedTemplates) : $decodedTemplates;           
     338                                        $templateOptions = empty($decodedTemplates[0]) ? current($decodedTemplates) : $decodedTemplates;
    329339                                    }
    330340                                    else {
    331341                                        if ($filePath == '') {
    332                                             $filePath = $unzipped_file['filename'];                                 
     342                                            $filePath = $unzipped_file['filename'];
    333343                                        }
    334344                                        if ( ! in_array($unzipped_file['filename'], $bundleFiles) ) {
    335345                                            $bundleFiles[basename($unzipped_file['filename'])] = $unzipped_file['filename'];
    336                                         }                                       
     346                                        }
    337347                                    }
    338348                                }
    339349                            }
    340350                        }
    341351
    342352                        if ( count($bundleFiles) > 1 ) {
    343353                            if ( ! empty($decodedTemplates) ) {
    344354                                foreach ($decodedTemplates as $cpt => $tpl) {
    345355                                    $fileFormats  = $this->get_xml_file( $bundleFiles[basename($tpl[0]['source_file_name'])] );
    346356                                    $bundle[$cpt] = $fileFormats['xml'];
    347357                                }
    348358                            }
    349359                            if ( ! empty($bundle)) $filePath = current($bundle);
    350                         }                       
     360                        }
    351361
    352362                        if($this->uploadsPath === false){
    353363                             $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)){
    357367                            $zip = zip_open(trim($tmpname));
    358                             if (is_resource($zip)) {                                                       
     368                            if (is_resource($zip)) {
    359369                                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                                    }
    369381                                }
    370382                                zip_close($zip);
    371383                            } 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
    376388                        $source = array(
    377389                            'name' => basename(parse_url($this->file, PHP_URL_PATH)),
    378390                            'type' => 'url',
    379                             'path' => $feed_xpath,                         
     391                            'path' => $feed_xpath,
    380392                        );
    381393                        $fileFormats = $this->get_xml_file( $filePath );
    382394                        $csv_path = $fileFormats['csv'];
    383395                        $filePath = $fileFormats['xml'];
    384396                    }
    385397                    if (file_exists($tmpname)) wp_all_import_remove_source($tmpname, false);
    386398                } elseif ('csv' == $feed_type or '' == $feed_type and preg_match('%\W(csv|txt|dat|psv|tsv)$%i', trim($this->file))) {
    387                                    
     399
    388400                    $source = array(
    389401                        'name' => basename(parse_url($this->file, PHP_URL_PATH)),
    390402                        'type' => 'url',
    391                         'path' => $feed_xpath,                 
     403                        'path' => $feed_xpath,
    392404                    );
    393405                    // copy remote file in binary mode
    394406                    $filePath = wp_all_import_get_url($this->file, $this->uploadsPath, 'csv');
    395407                    if ( ! is_wp_error($filePath) ){
    396408                        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');
    401413                        $csv = new PMXI_CsvParser( array( 'filename' => $filePath, 'targetDir' => $this->uploadsPath ) ); // create chunks
    402414                        //wp_all_import_remove_source($filePath, false);
    403415                        $csv_path = $filePath;
    404416                        $filePath = $csv->xml_path;
    405417                        $this->is_csv = $csv->is_csv;
    406418                        $this->root_element = 'node';
    407419                    }
    408420                    else $this->errors->add('form-validation', $filePath->get_error_message());
    409421
    410422                } elseif ('json' == $feed_type or preg_match('%\W(json)$%i', trim($this->file))){
    411423
    412424                    $source = array(
    413425                        'name' => basename(parse_url($this->file, PHP_URL_PATH)),
    414426                        'type' => 'url',
    415                         'path' => $feed_xpath,                 
     427                        'path' => $feed_xpath,
    416428                    );
    417429                    // copy remote file in binary mode
    418430                    $filePath = wp_all_import_get_url($this->file, $this->uploadsPath, 'json');
    419431                    $json_str = file_get_contents($filePath);
    420432                    $json_str = str_replace("\xEF\xBB\xBF",'', $json_str);
    421433                    $is_json = wp_all_import_is_json($json_str);
    422434                    if ( is_wp_error($is_json)){
    423435                        $this->errors->add('form-validation', $is_json->get_error_message(), 'wp_all_import_plugin');
    424436                    } else {
    425437                        $xml_data = wp_all_import_json_to_xml( json_decode($json_str, true) );
    426438                        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'));
    428440                        } 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))));
    430442                            file_put_contents($tmpname, $xml_data);
    431443                            wp_all_import_remove_source($filePath, false);
    432                             $filePath = $tmpname;                           
     444                            $filePath = $tmpname;
    433445                        }
    434446                    }
    435447                } elseif ('sql' == $feed_type or preg_match('%\W(sql)$%i', trim($this->file))){
    436448                    $source = array(
    437449                        'name' => basename($this->file),
    438450                        'type' => 'url',
    439                         'path' => $feed_xpath,                 
     451                        'path' => $feed_xpath,
    440452                    );
    441453                    // copy remote file in binary mode
    442454                    $localSQLPath = wp_all_import_get_url($this->file, $this->uploadsPath, 'sql');
    443455                    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();
    446458                    wp_all_import_remove_source($localSQLPath, false);
    447459                } 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))) {
    448460
    449461                    $source = array(
    450462                        'name' => basename($this->file),
    451463                        'type' => 'url',
    452                         'path' => $feed_xpath,                 
     464                        'path' => $feed_xpath,
    453465                    );
    454466                    // copy remote file in binary mode
    455467                    $localXLSPath = wp_all_import_get_url($this->file, $this->uploadsPath, 'xls');
    456468                    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();
    459471                    wp_all_import_remove_source($localXLSPath, false);
    460472                } else {
    461473                    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);
    463475                    } else {
    464476                        $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'))){
    466478                            $fileInfo = wp_all_import_get_gz($this->file, 0, $this->uploadsPath, $headers);
    467479                        } else {
    468480                            $fileInfo = wp_all_import_get_url($this->file, $this->uploadsPath, $headers['Content-Type'], $headers['Content-Encoding'], true);
    469                         }                                           
    470                     }                                       
    471                    
     481                        }
     482                    }
     483
    472484                    if ( ! is_wp_error($fileInfo) ){
    473485                        $filePath = $fileInfo['localPath'];
    474486                        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
    478490                        $source = array(
    479491                            'name' => basename(parse_url($this->file, PHP_URL_PATH)),
    480492                            'type' => 'url',
    481                             'path' => $feed_xpath,                 
     493                            'path' => $feed_xpath,
    482494                        );
    483495                        $fileInfo['type'] = apply_filters('wp_all_import_feed_type', $fileInfo['type'], $this->file);
    484                         // detect CSV or XML 
     496                        // detect CSV or XML
    485497                        switch ($fileInfo['type']) {
    486498                            case 'csv':
    487                                 include_once(PMXI_Plugin::ROOT_DIR.'/libraries/XmlImportCsvParse.php');                 
     499                                include_once(PMXI_Plugin::ROOT_DIR.'/libraries/XmlImportCsvParse.php');
    488500                                $csv = new PMXI_CsvParser( array( 'filename' => $filePath, 'targetDir' => $this->uploadsPath ) ); // create chunks
    489501                                $csv_path = $filePath;
    490502                                //wp_all_import_remove_source($filePath, false);
    491503                                $filePath = $csv->xml_path;
    492504                                $this->is_csv = $csv->is_csv;
    493                                 $this->root_element = 'node';                                                   
     505                                $this->root_element = 'node';
    494506                                break;
    495507                            case 'json':
    496508                                $json_str = file_get_contents($filePath);
    497509                                $json_str = str_replace("\xEF\xBB\xBF",'', $json_str);
    498510                                $is_json = wp_all_import_is_json($json_str);
    499                                
     511
    500512                                if( is_wp_error($is_json)){
    501513                                    $this->errors->add('form-validation', $is_json->get_error_message(), 'wp_all_import_plugin');
    502514                                } else {
    503515                                    $xml_data = wp_all_import_json_to_xml( json_decode($json_str, true) );
    504516                                    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'));
    506518                                    } 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))));
    508520                                        file_put_contents($tmpname, $xml_data);
    509521                                        wp_all_import_remove_source($filePath, false);
    510                                         $filePath = $tmpname;                           
     522                                        $filePath = $tmpname;
    511523                                    }
    512524                                }
    513525                                break;
    514526                            case 'sql':
    515527                                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 );
    517529                                $filePath = $sql->parse();
    518                                 break; 
     530                                break;
    519531                            default:
    520532                                # code...
    521533                                break;
    522534                        }
    523535                    }
    524536                    else $this->errors->add('form-validation', $fileInfo->get_error_message());
    525537                }
    526538            }
    527539
    528540            if ( $this->errors->get_error_codes() ) return $this->errors;
    529541
    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
    532544            $templateOptions = "";
    533545
    534546            if ( is_array($decodedTemplates) and ! empty($decodedTemplates)) {
    535547                $templateOptions = empty($decodedTemplates[0]) ? current($decodedTemplates) : $decodedTemplates;
    536548            }
    537549
    538             $options = (empty($templateOptions[0]['options'])) ? false : maybe_unserialize($templateOptions[0]['options']);     
     550            $options = (empty($templateOptions[0]['options'])) ? false : maybe_unserialize($templateOptions[0]['options']);
    539551
    540552            if ( ! empty($options['root_element'])) $this->root_element = $options['root_element'];
    541553
    542554            return array(
    543555                'filePath'      => $filePath,
    544556                'bundle'        => $bundle,
    545557                'source'        => $source,
    546558                'root_element'  => $this->root_element,
    547559                'feed_type'     => $feed_type,
    548560                'is_csv'        => $this->is_csv,
    549561                'csv_path'      => $csv_path,
    550562                'template'      => empty($templateOptions) ? "" : json_encode($templateOptions),
    551563                'templates'     => $templates,
    552564                'post_type'     => (!empty($options)) ? $options['custom_type'] : false,
    553565                'taxonomy_type' => (!empty($options['taxonomy_type'])) ? $options['taxonomy_type'] : false,
    554566            );
    555567        }
    556                
     568
    557569        protected function get_xml_file( $filePath )
    558570        {
    559571            $csv_path = '';
    560572
    561573            if (preg_match('%\W(csv|txt|dat|psv|tsv)$%i', trim($filePath))){ // If CSV file found in archieve
    562574
    563575                if($this->uploadsPath === false){
    564576                     $this->errors->add('form-validation', __('WP All Import can\'t access your WordPress uploads folder.', 'wp_all_import_plugin'));
    565                 }                                                                                               
    566                
     577                }
     578
    567579                include_once(PMXI_Plugin::ROOT_DIR.'/libraries/XmlImportCsvParse.php');
    568580                $csv = new PMXI_CsvParser( array( 'filename' => $filePath, 'targetDir' => $this->uploadsPath ) ); // create chunks
    569                
     581
    570582                $csv_path = $filePath;
    571583
    572584                $filePath = $csv->xml_path;
    573585                $this->is_csv = $csv->is_csv;
    574                 $this->root_element = 'node';       
    575                
     586                $this->root_element = 'node';
     587
    576588            } elseif (preg_match('%\W(json)$%i', trim($filePath))){
    577589
    578590                $json_str = file_get_contents($filePath);
    579591                $json_str = str_replace("\xEF\xBB\xBF",'', $json_str);
    580592                $is_json = wp_all_import_is_json($json_str);
    581                
     593
    582594                if( is_wp_error($is_json)){
    583595                    $this->errors->add('form-validation', $is_json->get_error_message(), 'wp_all_import_plugin');
    584596                }
    585                 else{                   
    586                    
     597                else{
     598
    587599                    $xml_data = wp_all_import_json_to_xml( json_decode($json_str, true) );
    588600
    589601                    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'));
    591603                    }
    592604                    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))));
    594606                        file_put_contents($jsontmpname, $xml_data);
    595607                        wp_all_import_remove_source($filePath, false);
    596608                        $filePath = $jsontmpname;
    597609                    }
    598610                }
    599611
    600612            }
    601613            elseif (preg_match('%\W(sql)$%i', trim($filePath))){
    602614
    603                 include_once( PMXI_Plugin::ROOT_DIR . '/libraries/XmlImportSQLParse.php' ); 
     615                include_once( PMXI_Plugin::ROOT_DIR . '/libraries/XmlImportSQLParse.php' );
    604616
    605617                $localSQLPath = $filePath;
    606618                $sql = new PMXI_SQLParser( $localSQLPath, $this->uploadsPath );
    607619                $filePath = $sql->parse();
    608620                wp_all_import_remove_source($localSQLPath, false);
    609             }       
     621            }
    610622            elseif (preg_match('%\W(xls|xlsx)$%i', trim($filePath))){
    611623
    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();
    617629                wp_all_import_remove_source($localXLSPath, false);
    618630
    619631            }
    620632            elseif(preg_match('%\W(gz)$%i', trim($filePath))) { // If gz file uploaded
    621633
    622634                $fileInfo = wp_all_import_get_gz($filePath, 0, $this->uploadsPath);
    623635
    624636                if (!is_wp_error($fileInfo)) {
    625637
    626638                    $filePath = $fileInfo['localPath'];
    627639
    628640                    // detect CSV or XML
    629641                    if ($fileInfo['type'] == 'csv') { // it is CSV file
    630642
    631643                        include_once(PMXI_Plugin::ROOT_DIR . '/libraries/XmlImportCsvParse.php');
    632644                        $csv_path = $filePath;
    633645                        $csv = new PMXI_CsvParser(array(
    634646                            'filename' => $filePath,
    635647                            'targeDir' => $this->uploadsPath
    636648                        )); // create chunks
    637649                        //@unlink($filePath);
    638650                        $filePath = $csv->xml_path;
    639651                        $this->is_csv = $csv->is_csv;
    640652                        $this->root_element = 'node';
    641653
    642654                    }
    643655
    644656                }
    645657                else $this->errors->add('form-validation', $fileInfo->get_error_message());
    646658            }
    647659
    648660            return array(
    649661                'csv' => $csv_path,
    650662                'xml' => $filePath
    651663            );
    652664        }
    653665    }
    654666}
  • wp-all-import/trunk/plugin.php

    r2737093 r2749264  
    11<?php
    22/*
    33Plugin Name: WP All Import
    44Plugin URI: http://www.wpallimport.com/wordpress-xml-csv-import/?utm_source=import-plugin-free&utm_medium=wp-plugins-page&utm_campaign=upgrade-to-pro
    55Description: 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.7
     6Version: 3.6.8
    77Author: Soflyy
    88*/
    99
    1010/**
    1111 * Plugin root dir with forward slashes as directory separator regardless of actuall DIRECTORY_SEPARATOR value
    1212 * @var string
    1313 */
    1414define('WP_ALL_IMPORT_ROOT_DIR', str_replace('\\', '/', dirname(__FILE__)));
    1515/**
    1616 * Plugin root url for referencing static content
    1717 * @var string
    1818 */
    1919define('WP_ALL_IMPORT_ROOT_URL', rtrim(plugin_dir_url(__FILE__), '/'));
    2020/**
    2121 * Plugin prefix for making names unique (be aware that this variable is used in conjuction with naming convention,
    2222 * i.e. in order to change it one must not only modify this constant but also rename all constants, classes and functions which
    2323 * names composed using this prefix)
    2424 * @var string
    2525 */
    2626define('WP_ALL_IMPORT_PREFIX', 'pmxi_');
    2727
    28 define('PMXI_VERSION', '3.6.7');
     28define('PMXI_VERSION', '3.6.8');
    2929
    3030define('PMXI_EDITION', 'free');
    3131
    3232/**
    3333 * Plugin root uploads folder name
    3434 * @var string
    3535 */
    3636define('WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY', 'wpallimport');
    3737/**
    3838 * Plugin logs folder name
    3939 * @var string
    4040 */
    4141define('WP_ALL_IMPORT_LOGS_DIRECTORY', WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'logs');
    4242/**
    4343 * Plugin files folder name
    4444 * @var string
    4545 */
    4646define('WP_ALL_IMPORT_FILES_DIRECTORY', WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'files');
    4747/**
    4848 * Plugin uploads folder name
    4949 * @var string
    5050 */
    5151define('WP_ALL_IMPORT_UPLOADS_DIRECTORY', WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'uploads');
    5252/**
    5353 * Plugin history folder name
    5454 * @var string
    5555 */
    5656define('WP_ALL_IMPORT_HISTORY_DIRECTORY', WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'history');
    5757/**
    5858 * Plugin temp folder name
    5959 * @var string
    6060 */
    6161define('WP_ALL_IMPORT_TEMP_DIRECTORY', WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'temp');
    6262
    6363/**
    6464 * Main plugin file, Introduces MVC pattern
    6565 *
    6666 * @singletone
    6767 * @author Maksym Tsypliakov <maksym.tsypliakov@gmail.com>
    6868 */
    6969final class PMXI_Plugin {
    7070    /**
    7171     * Singletone instance
    7272     * @var PMXI_Plugin
    7373     */
    7474    protected static $instance;
    7575
    7676    /**
    7777     * Plugin options
    7878     * @var array
    7979     */
    8080    protected $options = array();
    8181
    8282    /**
    8383     * Plugin root dir
    8484     * @var string
    8585     */
    8686    const ROOT_DIR = WP_ALL_IMPORT_ROOT_DIR;
    8787    /**
    8888     * Plugin root URL
    8989     * @var string
    9090     */
    9191    const ROOT_URL = WP_ALL_IMPORT_ROOT_URL;
    9292    /**
    9393     * Prefix used for names of shortcodes, action handlers, filter functions etc.
    9494     * @var string
    9595     */
    9696    const PREFIX = WP_ALL_IMPORT_PREFIX;
    9797    /**
    9898     * Plugin file path
    9999     * @var string
    100100     */
    101101    const FILE = __FILE__;
    102102    /**
    103103     * Max allowed file size (bytes) to import in default mode
    104104     * @var int
    105105     */
    106106    const LARGE_SIZE = 0; // all files will importing in large import mode
    107107
    108108    public static $session = null;
    109109
    110110    public static $is_csv = false;
    111111
    112112    public static $csv_path = false;
    113113
    114114    /**
    115115     * @var bool
    116116     */
    117117    public static $is_php_allowed = true;
    118118
    119119    public static $capabilities = 'manage_options';
    120120
    121121    /**
    122122     * WP All Import logs folder
    123123     * @var string
    124124     */
    125125    const LOGS_DIRECTORY =  WP_ALL_IMPORT_LOGS_DIRECTORY;
    126126    /**
    127127     * WP All Import files folder
    128128     * @var string
    129129     */
    130130    const FILES_DIRECTORY =  WP_ALL_IMPORT_FILES_DIRECTORY;
    131131    /**
    132132     * WP All Import temp folder
    133133     * @var string
    134134     */
    135135    const TEMP_DIRECTORY =  WP_ALL_IMPORT_TEMP_DIRECTORY;
    136136    /**
    137137     * WP All Import uploads folder
    138138     * @var string
    139139     */
    140140    const UPLOADS_DIRECTORY =  WP_ALL_IMPORT_UPLOADS_DIRECTORY;
    141141
    142142    /**
    143143     * WP All Import history folder
    144144     * @var string
    145145     */
    146146    const HISTORY_DIRECTORY =  WP_ALL_IMPORT_HISTORY_DIRECTORY;
    147147
    148148        /**
    149149         *  Language domain key.
    150150         */
    151151        const LANGUAGE_DOMAIN = 'wp_all_import_plugin';
    152152
    153153    /**
    154154     * Return singletone instance
    155155     * @return PMXI_Plugin
    156156     */
    157157    static public function getInstance() {
    158158        if (self::$instance == NULL) {
    159159            self::$instance = new self();
    160160        }
    161161        return self::$instance;
    162162    }
    163163
    164164    static public function getEddName(){
    165165        return 'WP All Import';
    166166    }
    167167
    168168    /**
    169169     * Common logic for requestin plugin info fields
    170170     */
    171171    public function __call($method, $args) {
    172172        if (preg_match('%^get(.+)%i', $method, $mtch)) {
    173173            $info = get_plugin_data(self::FILE);
    174174            if (isset($info[$mtch[1]])) {
    175175                return $info[$mtch[1]];
    176176            }
    177177        }
    178178        throw new Exception("Requested method " . get_class($this) . "::$method doesn't exist.");
    179179    }
    180180
    181181    /**
    182182     * Get path to plagin dir relative to wordpress root
    183183     * @param bool[optional] $noForwardSlash Whether path should be returned withot forwarding slash
    184184     * @return string
    185185     */
    186186    public function getRelativePath($noForwardSlash = false) {
    187187        $wp_root = str_replace('\\', '/', ABSPATH);
    188188        return ($noForwardSlash ? '' : '/') . str_replace($wp_root, '', self::ROOT_DIR);
    189189    }
    190190
    191191    /**
    192192     * Check whether plugin is activated as network one
    193193     * @return bool
    194194     */
    195195    public function isNetwork() {
    196196        if ( !is_multisite() )
    197197        return false;
    198198
    199199        $plugins = get_site_option('active_sitewide_plugins');
    200200        if (isset($plugins[plugin_basename(self::FILE)]))
    201201            return true;
    202202
    203203        return false;
    204204    }
    205205
    206206    /**
    207207     * Check whether permalinks is enabled
    208208     * @return bool
    209209     */
    210210    public function isPermalinks() {
    211211        global $wp_rewrite;
    212212
    213213        return $wp_rewrite->using_permalinks();
    214214    }
    215215
    216216    /**
    217217     * Return prefix for plugin database tables
    218218     * @return string
    219219     */
    220220    public function getTablePrefix() {
    221221        global $wpdb;
    222222
    223223        //return ($this->isNetwork() ? $wpdb->base_prefix : $wpdb->prefix) . self::PREFIX;
    224224        return $wpdb->prefix . self::PREFIX;
    225225    }
    226226
    227227    /**
    228228     * Return prefix for wordpress database tables
    229229     * @return string
    230230     */
    231231    public function getWPPrefix() {
    232232        global $wpdb;
    233233        return ($this->isNetwork()) ? $wpdb->base_prefix : $wpdb->prefix;
    234234    }
    235235
    236236    /**
    237237     * Class constructor containing dispatching logic
    238238     * @param string $rootDir Plugin root dir
    239239     * @param string $pluginFilePath Plugin main file
    240240     */
    241241    protected function __construct() {
    242242
    243243        // register autoloading method
    244244        spl_autoload_register(array($this, 'autoload'));
    245245
    246246        // register helpers
    247247        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) {
    248248            require_once $filePath;
    249249        }
    250250
    251251        // init plugin options
    252252        $option_name = get_class($this) . '_Options';
    253253        $options_default = PMXI_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray();
    254254        $current_options = get_option($option_name, array());
    255255        if (empty($current_options)) {
    256256            $current_options = array();
    257257        }
    258258
    259259        $this->options = array_intersect_key($current_options, $options_default) + $options_default;
    260260        $this->options = array_intersect_key($options_default, array_flip(array('info_api_url'))) + $this->options; // make sure hidden options apply upon plugin reactivation
    261261        if ('' == $this->options['cron_job_key']) {
    262262            $this->options['cron_job_key'] = wp_all_import_url_title(wp_all_import_rand_char(12));
    263263        }
    264264
    265265            if ($current_options !== $this->options) {
    266266                update_option($option_name, $this->options, false);
    267267            }
    268268
    269269        register_activation_hook(self::FILE, array($this, 'activation'));
    270270
    271271        // register action handlers
    272272        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) {
    273273            require_once $filePath;
    274274            $function = $actionName = basename($filePath, '.php');
    275275            if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
    276276                $actionName = $m[1];
    277277                $priority = intval($m[2]);
    278278            } else {
    279279                $priority = 10;
    280280            }
    281281            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)
    282282        }
    283283
    284284        // register filter handlers
    285285        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) {
    286286            require_once $filePath;
    287287            $function = $actionName = basename($filePath, '.php');
    288288            if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
    289289                $actionName = $m[1];
    290290                $priority = intval($m[2]);
    291291            } else {
    292292                $priority = 10;
    293293            }
    294294            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)
    295295        }
    296296
    297297        // register admin page pre-dispatcher
    298298        add_action('admin_init', array($this, 'adminInit'));
    299299        add_action('admin_init', array($this, 'fix_options'));
    300300        add_action('init', array($this, 'init'));
    301301
    302302        add_action( 'plugins_loaded', array( $this, 'setup_allimport_dir' ) );
    303303
    304304    }
    305305
    306306    /**
    307307     * Determines is process running from cli.
    308308     *
    309309     * @return bool
    310310     */
    311311    public function isCli() {
    312312        return php_sapi_name() === 'cli';
    313313    }
    314314
    315315    /**
    316316     * Setup required directory.
    317317     */
    318318    public function setup_allimport_dir() {
    319319        // create history folder
    320320        $uploads = wp_upload_dir();
    321321
    322322        $wpallimportDirs = array( WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY, self::LOGS_DIRECTORY, self::FILES_DIRECTORY, self::TEMP_DIRECTORY, self::UPLOADS_DIRECTORY, self::HISTORY_DIRECTORY);
    323323
    324324        foreach ($wpallimportDirs as $destination) {
    325325
    326326            $dir = $uploads['basedir'] . DIRECTORY_SEPARATOR . $destination;
    327327
    328328            if ( !is_dir($dir)) wp_mkdir_p($dir);
    329329
    330330            if ( ! @file_exists($dir . DIRECTORY_SEPARATOR . 'index.php') ) @touch( $dir . DIRECTORY_SEPARATOR . 'index.php' );
    331331
    332332        }
    333333    }
    334334
    335335    public function init(){
    336336        $this->load_plugin_textdomain();
    337337        self::$is_php_allowed = apply_filters('wp_all_import_is_php_allowed', TRUE);
    338338    }
    339339
    340340    public function plugin_row_meta($links, $file)
    341341    {
    342342        if ( $file == plugin_basename( __FILE__ ) ) {
    343343            $row_meta = array(
    344344                '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>',
    345345            );
    346346
    347347            return array_merge( $links, $row_meta );
    348348        }
    349349
    350350        return (array) $links;
    351351    }
    352352
    353353
    354354    /**
    355355     * convert imports options
    356356     * compatibility with version 3.2.3
    357357     */
    358358    public function fix_options(){
    359359
    360360        global $wpdb;
    361361
    362362        $imports = new PMXI_Import_List();
    363363        $post    = new PMXI_Post_Record();
    364364
    365365        $templates = new PMXI_Template_List();
    366366        $template  = new PMXI_Template_Record();
    367367
    368368        $is_migrated = get_option('pmxi_is_migrated');
    369369
    370370        $uploads = wp_upload_dir();
    371371
    372372        if ( empty($is_migrated) or version_compare($is_migrated, PMXI_VERSION) < 0 ){ //PMXI_VERSION
    373373
    374374            $commit_migration = true;
    375375
    376376            if ( empty($is_migrated) ){ // plugin version less than 4.0.0
    377377
    378378                    if ( is_dir($uploads['basedir'] . '/wpallimport_history') ) {
    379379                        wp_all_import_rmdir($uploads['basedir'] . '/wpallimport_history');
    380380                    }
    381381                    if ( is_dir($uploads['basedir'] . '/wpallimport_logs') ) {
    382382                        wp_all_import_rmdir($uploads['basedir'] . '/wpallimport_logs');
    383383                    }
    384384
    385385                foreach ($imports->setColumns($imports->getTable() . '.*')->getBy(array('id !=' => ''))->convertRecords() as $imp){
    386386
    387387                    $imp->getById($imp->id);
    388388
    389389                    if ( ! $imp->isEmpty() and ! empty($imp->template)){
    390390
    391391                        $options = array_merge($imp->options, $imp->template);
    392392
    393393                        $this->ver_4_transition_fix($options);
    394394
    395395                        $imp->set(array(
    396396                            'options' => $options
    397397                        ))->update();
    398398
    399399                        if ($imp->type == 'file'){
    400400                            $imp->set(array(
    401401                                'path' => $uploads['basedir'] . DIRECTORY_SEPARATOR . self::FILES_DIRECTORY . DIRECTORY_SEPARATOR . basename($imp->path)
    402402                            ))->update();
    403403                        }
    404404                    }
    405405                }
    406406
    407407                foreach ($templates->setColumns($templates->getTable() . '.*')->getBy(array('id !=' => ''))->convertRecords() as $tpl){
    408408
    409409                    $tpl->getById($tpl->id);
    410410
    411411                    if ( ! $tpl->isEmpty() and ! empty($tpl->title) ) {
    412412
    413413                        $opt = ( empty($tpl->options) ) ? array() : $tpl->options;
    414414
    415415                        $options = array_merge($opt, array(
    416416                            'title' => $tpl->title,
    417417                            'content' => $tpl->content,
    418418                            'is_keep_linebreaks' => $tpl->is_keep_linebreaks,
    419419                            'is_leave_html' => $tpl->is_leave_html,
    420420                            'fix_characters' => $tpl->fix_characters
    421421                        ));
    422422
    423423                        $this->ver_4_transition_fix($options);
    424424
    425425                        $tpl->set(array(
    426426                            'options' => $options
    427427                        ))->update();
    428428
    429429                    }
    430430
    431431                }
    432432
    433433                $commit_migration = $this->fix_db_schema(); // feature to version 4.0.0
    434434
    435435            }
    436436            else {
    437437
    438438                $commit_migration = $this->fix_db_schema();
    439439
    440440                foreach ($imports->setColumns($imports->getTable() . '.*')->getBy(array('id !=' => ''))->convertRecords() as $imp){
    441441
    442442                    $imp->getById($imp->id);
    443443
    444444                    if ( ! $imp->isEmpty() ){
    445445
    446446                        $options = $imp->options;
    447447
    448448                        $this->ver_4x_transition_fix($options, $is_migrated);
    449449
    450450                        $imp->set(array(
    451451                            'options' => $options
    452452                        ))->update();
    453453                    }
    454454                }
    455455
    456456                foreach ($templates->setColumns($templates->getTable() . '.*')->getBy(array('id !=' => ''))->convertRecords() as $tpl){
    457457
    458458                    $tpl->getById($tpl->id);
    459459
    460460                    if ( ! $tpl->isEmpty() ) {
    461461
    462462                        $options = ( empty($tpl->options) ) ? array() : $tpl->options;
    463463
    464464                        $this->ver_4x_transition_fix($options, $is_migrated);
    465465
    466466                        $tpl->set(array(
    467467                            'options' => $options
    468468                        ))->update();
    469469
    470470                    }
    471471
    472472                }
    473473            }
    474474            if ($commit_migration) update_option('pmxi_is_migrated', PMXI_VERSION);
    475475        }
    476476    }
    477477
    478478    public function ver_4_transition_fix( &$options ){
    479479
    480480        $options['wizard_type'] = ($options['duplicate_matching'] == 'auto') ? 'new' : 'matching';
    481481
    482482        if ($options['download_images']){
    483483            $options['download_images'] = 'yes';
    484484            $options['download_featured_image'] = $options['featured_image'];
    485485            $options['featured_image'] = '';
    486486            $options['download_featured_delim'] = $options['featured_delim'];
    487487            $options['featured_delim'] = '';
    488488        }
    489489
    490490        if ($options['set_image_meta_data']){
    491491            $options['set_image_meta_title'] = 1;
    492492            $options['set_image_meta_caption'] = 1;
    493493            $options['set_image_meta_alt'] = 1;
    494494            $options['set_image_meta_description'] = 1;
    495495        }
    496496
    497497        if ("" == $options['custom_type']) $options['custom_type'] = $options['type'];
    498498
    499499        $exclude_taxonomies = (class_exists('PMWI_Plugin')) ? array('post_format', 'product_type') : array('post_format');
    500500        $post_taxonomies = array_diff_key(get_taxonomies_by_object_type(array($options['custom_type']), 'object'), array_flip($exclude_taxonomies));
    501501
    502502        $options['tax_logic'] = array();
    503503        $options['tax_assing'] = array();
    504504        $options['tax_multiple_xpath'] = array();
    505505        $options['tax_multiple_delim'] = array();
    506506        $options['tax_hierarchical_logic_entire'] = array();
    507507        $options['tax_hierarchical_logic_manual'] = array();
    508508
    509509        if ( ! empty($post_taxonomies)):
    510510            foreach ($post_taxonomies as $ctx):
    511511
    512512                $options['tax_logic'][$ctx->name] = ($ctx->hierarchical) ? 'hierarchical' : 'multiple';
    513513
    514514                if ($ctx->name == 'category'){
    515515                    $options['post_taxonomies']['category'] = $options['categories'];
    516516                }
    517517                elseif ($ctx->name == 'post_tag' ){
    518518                    $options['tax_assing']['post_tag'] = 1;
    519519                    $options['tax_multiple_xpath']['post_tag'] = $options['tags'];
    520520                    $options['tax_multiple_delim']['post_tag'] = $options['tags_delim'];
    521521                    }
    522522
    523523                if ( ! empty($options['post_taxonomies'][$ctx->name])){
    524524
    525525                    $taxonomies_hierarchy = json_decode($options['post_taxonomies'][$ctx->name], true);
    526526                    $options['tax_assing'][$ctx->name] = (!empty($taxonomies_hierarchy[0]['assign'])) ? 1 : 0;
    527527
    528528                    if ($options['tax_logic'][$ctx->name] == 'multiple') {
    529529                        $options['tax_multiple_xpath'][$ctx->name] = (!empty($taxonomies_hierarchy[0]['xpath'])) ? $taxonomies_hierarchy[0]['xpath'] : '';
    530530                        $options['tax_multiple_delim'][$ctx->name] = (!empty($taxonomies_hierarchy[0]['delim'])) ? $taxonomies_hierarchy[0]['delim'] : '';
    531531                    }
    532532                    else{
    533533                        $options['tax_hierarchical_logic_manual'][$ctx->name] = 1;
    534534                    }
    535535                }
    536536
    537537            endforeach;
    538538        endif;
    539539    }
    540540
    541541    public function ver_4x_transition_fix(&$options, $version){
    542542        if ( version_compare($version, '4.0.5') < 0  ){
    543543            if ( ! empty($options['tax_hierarchical_logic']) and is_array($options['tax_hierarchical_logic']) ){
    544544                foreach ($options['tax_hierarchical_logic'] as $tx => $type) {
    545545                    switch ($type){
    546546                        case 'entire':
    547547                            $options['tax_hierarchical_logic_entire'][$tx] = 1;
    548548                            break;
    549549                        case 'manual':
    550550                            $options['tax_hierarchical_logic_manual'][$tx] = 1;
    551551                            break;
    552552                        default:
    553553
    554554                            break;
    555555                    }
    556556                }
    557557                unset($options['tax_hierarchical_logic']);
    558558            }
    559559        }
    560560
    561561    }
    562562
    563563    /**
    564564     * pre-dispatching logic for admin page controllers
    565565     */
    566566    public function adminInit() {
    567567
    568568        self::$session = new PMXI_Handler();
    569569
    570570        $input = new PMXI_Input();
    571571        $page = strtolower($input->getpost('page', ''));
    572572
    573573        if (preg_match('%^' . preg_quote(str_replace('_', '-', self::PREFIX), '%') . '([\w-]+)$%', $page)) {
    574574            //$this->adminDispatcher($page, strtolower($input->getpost('action', 'index')));
    575575
    576576            $action = strtolower($input->getpost('action', 'index'));
    577577
    578578            // capitalize prefix and first letters of class name parts
    579579            $controllerName = preg_replace_callback('%(^' . preg_quote(self::PREFIX, '%') . '|_).%', array($this, "replace_callback"),str_replace('-', '_', $page));
    580580            $actionName = str_replace('-', '_', $action);
    581581            if (method_exists($controllerName, $actionName)) {
    582582
    583583                @ini_set("max_input_time", PMXI_Plugin::getInstance()->getOption('max_input_time'));
    584584                @ini_set("max_execution_time", PMXI_Plugin::getInstance()->getOption('max_execution_time'));
    585585
    586586                if ( ! get_current_user_id() or ! current_user_can( self::$capabilities )) {
    587587                    // This nonce is not valid.
    588588                    die( 'Security check' );
    589589
    590590                } else {
    591591
    592592                        $this->_admin_current_screen = (object)array(
    593593                            'id' => $controllerName,
    594594                            'base' => $controllerName,
    595595                            'action' => $actionName,
    596596                            'is_ajax' => (isset($_SERVER["HTTP_ACCEPT"]) && strpos($_SERVER["HTTP_ACCEPT"], 'json')) !== false,
    597597                            'is_network' => is_network_admin(),
    598598                            'is_user' => is_user_admin(),
    599599                        );
    600600                        add_filter('current_screen', array($this, 'getAdminCurrentScreen'));
    601601                        add_filter('admin_body_class', array($this, 'getAdminBodyClass'), 10, 1);
    602602
    603603                        $controller = new $controllerName();
    604604                        if ( ! $controller instanceof PMXI_Controller_Admin) {
    605605                            throw new Exception("Administration page `$page` matches to a wrong controller type.");
    606606                        }
    607607
    608608                        if ($this->_admin_current_screen->is_ajax) { // ajax request
    609609                            $controller->$action();
    610610                            do_action('pmxi_action_after');
    611611                            wp_die(); // stop processing since we want to output only what controller is randered, nothing in addition
    612612                        } elseif ( ! $controller->isInline) {
    613613                            @ob_start();
    614614                            $controller->$action();
    615615                            self::$buffer = @ob_get_clean();
    616616                        } else {
    617617                            self::$buffer_callback = array($controller, $action);
    618618                        }
    619619
    620620                }
    621621
    622622            } else { // redirect to dashboard if requested page and/or action don't exist
    623623                wp_redirect(admin_url()); die();
    624624            }
    625625        }
    626626    }
    627627
    628628    public function getAdminBodyClass($class){
    629629        return $class . ' wpallimport-plugin';
    630630    }
    631631
    632632    /**
    633633     * Dispatch shorttag: create corresponding controller instance and call its index method
    634634     * @param array $args Shortcode tag attributes
    635635     * @param string $content Shortcode tag content
    636636     * @param string $tag Shortcode tag name which is being dispatched
    637637     * @return string
    638638     */
    639639    public function shortcodeDispatcher($args, $content, $tag) {
    640640
    641641        $controllerName = self::PREFIX . preg_replace_callback('%(^|_).%', array($this, "replace_callback"), $tag);// capitalize first letters of class name parts and add prefix
    642642        $controller = new $controllerName();
    643643        if ( ! $controller instanceof PMXI_Controller) {
    644644            throw new Exception("Shortcode `$tag` matches to a wrong controller type.");
    645645        }
    646646        ob_start();
    647647        $controller->index($args, $content);
    648648        return ob_get_clean();
    649649    }
    650650
    651651    static $buffer = NULL;
    652652    static $buffer_callback = NULL;
    653653
    654654    /**
    655655     * Dispatch admin page: call corresponding controller based on get parameter `page`
    656656     * The method is called twice: 1st time as handler `parse_header` action and then as admin menu item handler
    657657     * @param string[optional] $page When $page set to empty string ealier buffered content is outputted, otherwise controller is called based on $page value
    658658     */
    659659    public function adminDispatcher($page = '', $action = 'index') {
    660660
    661661        if ('' === $page) {
    662662            if ( ! is_null(self::$buffer)) {
    663663                echo '<div class="wrap">';
    664664
    665665                echo self::$buffer;
    666666
    667667                do_action('pmxi_action_after');
    668668                echo '</div>';
    669669            } elseif ( ! is_null(self::$buffer_callback)) {
    670670                echo '<div class="wrap">';
    671671                call_user_func(self::$buffer_callback);
    672672                do_action('pmxi_action_after');
    673673                echo '</div>';
    674674            } else {
    675675                throw new Exception('There is no previousely buffered content to display.');
    676676            }
    677677        }
    678678
    679679    }
    680680
    681681    public function replace_callback($matches){
    682682        return strtoupper($matches[0]);
    683683    }
    684684
    685685    protected $_admin_current_screen = NULL;
    686686    public function getAdminCurrentScreen()
    687687    {
    688688        return $this->_admin_current_screen;
    689689    }
    690690
    691691    /**
    692692     * Autoloader
    693693     * It's assumed class name consists of prefix folloed by its name which in turn corresponds to location of source file
    694694     * if `_` symbols replaced by directory path separator. File name consists of prefix folloed by last part in class name (i.e.
    695695     * symbols after last `_` in class name)
    696696     * When class has prefix it's source is looked in `models`, `controllers`, `shortcodes` folders, otherwise it looked in `core` or `library` folder
    697697     *
    698698     * @param string $className
    699699     * @return bool
    700700     */
    701701    public function autoload($className) {
    702702        $is_prefix = false;
    703703        $filePath = str_replace('_', '/', preg_replace('%^' . preg_quote(self::PREFIX, '%') . '%', '', strtolower($className), 1, $is_prefix)) . '.php';
    704704        if ( ! $is_prefix) { // also check file with original letter case
    705705            $filePathAlt = $className . '.php';
    706706        }
    707707        foreach ($is_prefix ? array('models', 'controllers', 'shortcodes', 'classes') : array('libraries') as $subdir) {
    708708            $path = self::ROOT_DIR . '/' . $subdir . '/' . $filePath;
    709709            if (is_file($path)) {
    710710                require $path;
    711711                return TRUE;
    712712            }
    713713            if ( ! $is_prefix) {
    714714                $pathAlt = self::ROOT_DIR . '/' . $subdir . '/' . $filePathAlt;
    715715                if (is_file($pathAlt)) {
    716716                    require $pathAlt;
    717717                    return TRUE;
    718718                }
    719719            }
    720720        }
    721721
    722722        return FALSE;
    723723    }
    724724
    725725    /**
    726726     * Get plugin option
    727727     * @param string[optional] $option Parameter to return, all array of options is returned if not set
    728728     * @return mixed
    729729     */
    730730    public function getOption($option = NULL) {
    731731        $options = apply_filters('wp_all_import_config_options', $this->options);
    732732        if (is_null($option)) {
    733733            return $options;
    734734        } else if (isset($options[$option])) {
    735735            return $options[$option];
    736736        } else {
    737737            throw new Exception("Specified option is not defined for the plugin");
    738738        }
    739739    }
    740740    /**
    741741     * Update plugin option value
    742742     * @param string $option Parameter name or array of name => value pairs
    743743     * @param mixed[optional] $value New value for the option, if not set than 1st parameter is supposed to be array of name => value pairs
    744744     * @return array
    745745     */
    746746    public function updateOption($option, $value = NULL) {
    747747        is_null($value) or $option = array($option => $value);
    748748        if (array_diff_key($option, $this->options)) {
    749749            throw new Exception("Specified option is not defined for the plugin");
    750750        }
    751751        $this->options = $option + $this->options;
    752752        update_option(get_class($this) . '_Options', $this->options);
    753753
    754754        return $this->options;
    755755    }
    756756
    757757    /**
    758758     * Plugin activation logic
    759759     */
    760760    public function activation() {
    761761        // uncaught exception doesn't prevent plugin from being activated, therefore replace it with fatal error so it does
    762762        if (version_compare(phpversion(), '7.2'  , "<")){
    763763            $exception_handler = create_function('$e', 'trigger_error($e->getMessage(), E_USER_ERROR);');
    764764        }
    765765        else{
    766766            $exception_handler = function($e){
    767767                trigger_error($e->getMessage(), E_USER_ERROR);
    768768            };
    769769        }
    770770        set_exception_handler($exception_handler);
    771771
    772772        // create plugin options
    773773        $option_name = get_class($this) . '_Options';
    774774        $options_default = PMXI_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray();
    775775        $wpai_options = get_option($option_name, false);
    776776        if ( ! $wpai_options ) update_option($option_name, $options_default);
    777777
    778778        // create/update required database tables
    779779        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    780780        require self::ROOT_DIR . '/schema.php';
    781781        global $wpdb;
    782782
    783783        if (function_exists('is_multisite') && is_multisite()) {
    784784            // check if it is a network activation - if so, run the activation function for each blog id
    785785            if (isset($_GET['networkwide']) && (intval($_GET['networkwide']) == 1)) {
    786786                $old_blog = $wpdb->blogid;
    787787                // Get all blog ids
    788788                $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
    789789                foreach ($blogids as $blog_id) {
    790790                    switch_to_blog($blog_id);
    791791                    require self::ROOT_DIR . '/schema.php';
    792792                    dbDelta($plugin_queries);
    793793
    794794                    // sync data between plugin tables and wordpress (mostly for the case when plugin is reactivated)
    795795
    796796                        //$post = new PMXI_Post_Record();
    797797                    //$wpdb->query('DELETE FROM ' . $post->getTable() . ' WHERE post_id NOT IN (SELECT ID FROM ' . $wpdb->posts . ')');
    798798                    $post = new PMXI_Post_Record();
    799799                    $import = new PMXI_Import_Record();
    800800                    $imports_list = $wpdb->get_results('SELECT id FROM ' . $import->getTable() . '');
    801801
    802802                    if ( ! empty($imports_list) ) {
    803803
    804804                        $user_imports = array();
    805805                        $post_imports = array();
    806806
    807807                        foreach ($imports_list as $import_entry) {
    808808                            $import_id = $import_entry->id;
    809809                            $import = $import->getById($import_id);
    810810                            $import_options = maybe_unserialize($import->options);
    811811                            $import_type = $import_options['custom_type'];
    812812                            if ( in_array($import_type, array('import_users', 'shop_customer')) ) {
    813813                                $user_imports[] = $import_id;
    814814                            } else {
    815815                                $post_imports[] = $import_id;
    816816                            }
    817817                        }
    818818
    819819                        if ( ! empty($user_imports) ) {
    820820                            $user_table = $wpdb->base_prefix . 'users';
    821821                            $user_query = 'DELETE FROM ' . $post->getTable() . ' WHERE import_id IN (' . implode(',', $user_imports) . ') AND post_id NOT IN (SELECT ID FROM ' . $user_table . ')';
    822822                            $wpdb->query($user_query);
    823823                        }
    824824
    825825                        if ( ! empty($post_imports) ) {
    826826                            $post_query = 'DELETE FROM ' . $post->getTable() . ' WHERE import_id IN (' . implode(',', $post_imports) . ') AND post_id NOT IN (SELECT ID FROM ' . $wpdb->posts . ')';
    827827                            $wpdb->query($post_query);
    828828                        }
    829829
    830830                    }
    831831
    832832                }
    833833                switch_to_blog($old_blog);
    834834                return;
    835835            }
    836836        }
    837837
    838838        dbDelta($plugin_queries);
    839839
    840840        // sync data between plugin tables and wordpress (mostly for the case when plugin is reactivated)
    841841
    842842        //$post = new PMXI_Post_Record();
    843843        //$wpdb->query('DELETE FROM ' . $post->getTable() . ' WHERE post_id NOT IN (SELECT ID FROM ' . $wpdb->posts . ')');
    844844
    845845        $post = new PMXI_Post_Record();
    846846        $import = new PMXI_Import_Record();
    847847        $imports_list = $wpdb->get_results('SELECT id FROM ' . $import->getTable() . '');
    848848
    849849        if ( ! empty($imports_list) ) {
    850850
    851851            $user_imports = array();
    852852            $post_imports = array();
    853853
    854854                foreach ($imports_list as $import_entry) {
    855855                    $import_id = $import_entry->id;
    856856                    $import = $import->getById($import_id);
    857857                    $import_options = maybe_unserialize($import->options);
    858858                    $import_type = $import_options['custom_type'];
    859859                    if ( in_array($import_type, array('import_users', 'shop_customer')) ) {
    860860                        $user_imports[] = $import_id;
    861861                    } else {
    862862                        $post_imports[] = $import_id;
    863863                    }
    864864                }
    865865
    866866                if ( ! empty($user_imports) ) {
    867867                    $user_table = $wpdb->base_prefix . 'users';
    868868                    $user_query = 'DELETE FROM ' . $post->getTable() . ' WHERE import_id IN (' . implode(',', $user_imports) . ') AND post_id NOT IN (SELECT ID FROM ' . $user_table . ')';
    869869                    $wpdb->query($user_query);
    870870                }
    871871
    872872                if ( ! empty($post_imports) ) {
    873873                    $post_query = 'DELETE FROM ' . $post->getTable() . ' WHERE import_id IN (' . implode(',', $post_imports) . ') AND post_id NOT IN (SELECT ID FROM ' . $wpdb->posts . ')';
    874874                    $wpdb->query($post_query);
    875875                }
    876876
    877877            }
    878878
    879879    }
    880880
    881881    /**
    882882     * Load Localisation files.
    883883     *
    884884     * Note: the first-loaded translation file overrides any following ones if the same translation is present
    885885     *
    886886     * @access public
    887887     * @return void
    888888     */
    889889    public function load_plugin_textdomain() {
    890890        $locale = apply_filters( 'plugin_locale', get_locale(), 'wp_all_import_plugin' );
    891891
    892892        load_plugin_textdomain( 'wp_all_import_plugin', false, dirname( plugin_basename( __FILE__ ) ) . "/i18n/languages" );
    893893    }
    894894
    895895    public function fix_db_schema(){
    896896
    897897        $uploads = wp_upload_dir();
    898898
    899899        if ( ! is_dir($uploads['basedir'] . DIRECTORY_SEPARATOR . self::LOGS_DIRECTORY) or ! is_writable($uploads['basedir'] . DIRECTORY_SEPARATOR . self::LOGS_DIRECTORY)) {
    900900            die(sprintf(__('Uploads folder %s must be writable', 'wp_all_import_plugin'), esc_attr($uploads['basedir'] . DIRECTORY_SEPARATOR . self::LOGS_DIRECTORY)));
    901901        }
    902902
    903903        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)) {
    904904            die(sprintf(__('Uploads folder %s must be writable', 'wp_all_import_plugin'), esc_attr($uploads['basedir'] . DIRECTORY_SEPARATOR . WP_ALL_IMPORT_UPLOADS_BASE_DIRECTORY)));
    905905        }
    906906
    907907        // create/update required database tables
    908908        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    909909        require self::ROOT_DIR . '/schema.php';
    910910        global $wpdb;
    911911
    912912        if (function_exists('is_multisite') && is_multisite()) {
    913913            // check if it is a network activation - if so, run the activation function for each blog id
    914914            if (isset($_GET['networkwide']) && (intval($_GET['networkwide']) == 1)) {
    915915                $old_blog = $wpdb->blogid;
    916916                // Get all blog ids
    917917                $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
    918918                foreach ($blogids as $blog_id) {
    919919                    switch_to_blog($blog_id);
    920920                    require self::ROOT_DIR . '/schema.php';
    921921                    dbDelta($plugin_queries);
    922922
    923923                    // sync data between plugin tables and wordpress (mostly for the case when plugin is reactivated)
    924924
    925925                    $post = new PMXI_Post_Record();
    926926                        $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 . ')');
    927927                }
    928928                switch_to_blog($old_blog);
    929929                return;
    930930            }
    931931        }
    932932
    933933        dbDelta($plugin_queries);
    934934
    935935        // do not execute ALTER TABLE queries if sql user doesn't have ALTER privileges
    936936        $grands = $wpdb->get_results("SELECT * FROM information_schema.user_privileges WHERE grantee LIKE \"'" . DB_USER . "'%\" AND PRIVILEGE_TYPE = 'ALTER' AND IS_GRANTABLE = 'YES';");
    937937
    938938        $table = $table = $this->getTablePrefix() . 'files';
    939939
    940940        $tablefields = $wpdb->get_results("DESCRIBE {$table};");
    941941        // For every field in the table
    942942        foreach ($tablefields as $tablefield) {
    943943            if ('contents' == $tablefield->Field) {
    944944                $list = new PMXI_File_List();
    945945                for ($i = 1; $list->getBy(NULL, 'id', $i, 1)->count(); $i++) {
    946946                    foreach ($list->convertRecords() as $file) {
    947947                        $file->save(); // resave file for file to be stored in uploads folder
    948948                    }
    949949                }
    950950
    951951                if (!empty($grands)) $wpdb->query("ALTER TABLE {$table} DROP " . $tablefield->Field);
    952952
    953953                break;
    954954            }
    955955        }
    956956
    957957        // alter images table
    958958        $table = $this->getTablePrefix() . 'images';
    959959        $tablefields = $wpdb->get_results("DESCRIBE {$table};");
    960960        $fields_to_alter = array(
    961961            'image_url',
    962962            'image_filename'
    963963        );
    964964
    965965        // Check if field exists
    966966        foreach ($tablefields as $tablefield) {
    967967            if (in_array($tablefield->Field, $fields_to_alter)){
    968968                $fields_to_alter = array_diff($fields_to_alter, array($tablefield->Field));
    969969            }
    970970        }
    971971
    972972        if ( ! empty($fields_to_alter) ){
    973973
    974974            if (empty($grands)) return false;
    975975
    976976            foreach ($fields_to_alter as $field) {
    977977                switch ($field) {
    978978                    case 'image_url':
    979979                        $wpdb->query("ALTER TABLE {$table} ADD `image_url` VARCHAR(600) NOT NULL DEFAULT '';");
    980980                        break;
    981981                    case 'image_filename':
    982982                        $wpdb->query("ALTER TABLE {$table} ADD `image_filename` VARCHAR(600) NOT NULL DEFAULT '';");
    983983                        break;
    984984                    default:
    985985                        # code...
    986986                        break;
    987987                }
    988988            }
    989989        }
    990990
    991991        $table = $this->getTablePrefix() . 'imports';
    992992        $tablefields = $wpdb->get_results("DESCRIBE {$table};");
    993993        $fields_to_alter = array(
    994994            'parent_import_id',
    995995            'iteration',
    996996            'deleted',
    997997            'executing',
    998998            'canceled',
    999999            'canceled_on',
    10001000            'failed',
    10011001            'failed_on',
    10021002            'settings_update_on',
    10031003            'last_activity'
    10041004        );
    10051005
    10061006        // Check if field exists
    10071007        foreach ($tablefields as $tablefield) {
    10081008            if (in_array($tablefield->Field, $fields_to_alter)){
    10091009                $fields_to_alter = array_diff($fields_to_alter, array($tablefield->Field));
    10101010            }
    10111011        }
    10121012
    10131013        if ( ! empty($fields_to_alter) ){
    10141014
    10151015            if (empty($grands)) return false;
    10161016
    10171017            foreach ($fields_to_alter as $field) {
    10181018                switch ($field) {
    10191019                    case 'parent_import_id':
    10201020                        $wpdb->query("ALTER TABLE {$table} ADD `parent_import_id` BIGINT(20) NOT NULL DEFAULT 0;");
    10211021                        break;
    10221022                    case 'iteration':
    10231023                        $wpdb->query("ALTER TABLE {$table} ADD `iteration` BIGINT(20) NOT NULL DEFAULT 0;");
    10241024                        break;
    10251025                    case 'deleted':
    10261026                        $wpdb->query("ALTER TABLE {$table} ADD `deleted` BIGINT(20) NOT NULL DEFAULT 0;");
    10271027                        break;
    10281028                    case 'executing':
    10291029                        $wpdb->query("ALTER TABLE {$table} ADD `executing` BOOL NOT NULL DEFAULT 0;");
    10301030                        break;
    10311031                    case 'canceled':
    10321032                        $wpdb->query("ALTER TABLE {$table} ADD `canceled` BOOL NOT NULL DEFAULT 0;");
    10331033                        break;
    10341034                    case 'canceled_on':
    10351035                        $wpdb->query("ALTER TABLE {$table} ADD `canceled_on` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00';");
    10361036                        break;
    10371037                    case 'failed':
    10381038                        $wpdb->query("ALTER TABLE {$table} ADD `failed` BOOL NOT NULL DEFAULT 0;");
    10391039                        break;
    10401040                    case 'failed_on':
    10411041                        $wpdb->query("ALTER TABLE {$table} ADD `failed_on` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00';");
    10421042                        break;
    10431043                    case 'settings_update_on':
    10441044                        $wpdb->query("ALTER TABLE {$table} ADD `settings_update_on` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00';");
    10451045                        break;
    10461046                    case 'last_activity':
    10471047                        $wpdb->query("ALTER TABLE {$table} ADD `last_activity` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00';");
    10481048                        break;
    10491049
    10501050                    default:
    10511051                        # code...
    10521052                        break;
    10531053                }
    10541054            }
    10551055        }
    10561056
    10571057        $table = $this->getTablePrefix() . 'posts';
    10581058        $tablefields = $wpdb->get_results("DESCRIBE {$table};");
    10591059        $iteration = false;
    10601060        $specified = false;
    10611061
    10621062        // Check if field exists
    10631063        foreach ($tablefields as $tablefield) {
    10641064            if ('iteration' == $tablefield->Field) $iteration = true;
    10651065            if ('specified' == $tablefield->Field) $specified = true;
    10661066        }
    10671067
    10681068        if (!$iteration){
    10691069
    10701070            if (empty($grands)) {
    10711071                ?>
    10721072                <div class="error"><p>
    10731073                    <?php printf(
    10741074                            __('<b>%s Plugin</b>: Current sql user %s doesn\'t have ALTER privileges', 'pmwi_plugin'),
    10751075                            esc_attr(self::getInstance()->getName()), esc_attr(DB_USER)
    10761076                    ) ?>
    10771077                </p></div>
    10781078                <?php
    10791079                return false;
    10801080            }
    10811081
    10821082            $wpdb->query("ALTER TABLE {$table} ADD `iteration` BIGINT(20) NOT NULL DEFAULT 0;");
    10831083
    10841084            // Add indexing to pmxi_posts.post_id and pmxi_posts.import_id fields.
    10851085            $wpdb->query("ALTER TABLE {$table} ADD INDEX `post_id`(`post_id`);");
    10861086            $wpdb->query("ALTER TABLE {$table} ADD INDEX `import_id`(`import_id`)");
    10871087        }
    10881088
    10891089        if (!$specified and !empty($grands))
    10901090        {
    10911091            $wpdb->query("ALTER TABLE {$table} ADD `specified` BOOL NOT NULL DEFAULT 0;");
    10921092        }
    10931093
    10941094        if ( ! empty($wpdb->charset))
    10951095            $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
    10961096        if ( ! empty($wpdb->collate))
    10971097            $charset_collate .= " COLLATE $wpdb->collate";
    10981098
    10991099        $table_prefix = $this->getTablePrefix();
    11001100
    11011101        $wpdb->query("CREATE TABLE IF NOT EXISTS {$table_prefix}history (
    11021102            id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
    11031103            import_id BIGINT(20) UNSIGNED NOT NULL,
    11041104            type ENUM('manual','processing','trigger','continue','') NOT NULL DEFAULT '',   
    11051105            time_run TEXT, 
    11061106            date DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',       
    11071107            summary TEXT,
    11081108            PRIMARY KEY  (id)
    11091109        ) $charset_collate;");
    11101110
    11111111        return true;
    11121112    }
    11131113
    11141114        /**
    11151115         * Method returns default import options, main utility of the method is to avoid warnings when new
    11161116         * option is introduced but already registered imports don't have it
    11171117         */
    11181118        public static function get_default_import_options() {
    11191119            return array(
    11201120                'type' => 'post',
    11211121                'is_override_post_type' => 0,
    11221122                'post_type_xpath' => '',
    11231123                'deligate' => '',
    11241124                'wizard_type' => 'new',
    11251125                'ftp_host' => '',
    11261126                'ftp_path' => '',
    11271127                'ftp_root' => '/',
    11281128                'ftp_port' => 21,
    11291129                'ftp_username' => '',
    11301130                'ftp_password' => '',
    11311131                'ftp_private_key' => '',
    11321132                'custom_type' => '',
    11331133                'featured_delim' => ',',
    11341134                'atch_delim' => ',',
    11351135                'is_search_existing_attach' => 0,
    11361136                'post_taxonomies' => array(),
    11371137                'parent' => 0,
    11381138                'is_multiple_page_parent' => 'yes',
    11391139                'single_page_parent' => '',
    11401140                'order' => 0,
    11411141                'status' => 'publish',
    11421142                'page_template' => 'default',
    11431143                'is_multiple_page_template' => 'yes',
    11441144                'single_page_template' => '',
    11451145                'page_taxonomies' => array(),
    11461146                'date_type' => 'specific',
    11471147                'date' => 'now',
    11481148                'date_start' => 'now',
    11491149                'date_end' => 'now',
    11501150                'custom_name' => array(),
    11511151                'custom_value' => array(),
    11521152                'custom_format' => array(),
    11531153                'custom_mapping' => array(),
    11541154                'serialized_values' => array(),
    11551155                'custom_mapping_rules' => array(),
    11561156                'comment_status' => 'open',
    11571157                'comment_status_xpath' => '',
    11581158                'ping_status' => 'open',
    11591159                'ping_status_xpath' => '',
    11601160                'create_draft' => 'no',
    11611161                'author' => '',
    11621162                'post_excerpt' => '',
    11631163                'post_slug' => '',
    11641164                'attachments' => '',
    11651165                'is_import_specified' => 0,
    11661166                'import_specified' => '',
    11671167                'is_delete_source' => 0,
    11681168                'is_cloak' => 0,
    11691169                'unique_key' => '',
    11701170                'tmp_unique_key' => '',
    11711171                'feed_type' => 'auto',
    11721172                'search_existing_images' => 1,
    11731173
    11741174                'create_new_records' => 1,
    11751175                'is_selective_hashing' => 0,
    11761176                'is_delete_missing' => 0,
    11771177                'set_missing_to_draft' => 0,
    11781178                'is_update_missing_cf' => 0,
    11791179                'update_missing_cf_name' => '',
    11801180                'update_missing_cf_value' => '',
    11811181
    11821182                'is_keep_former_posts' => 'no',
    11831183                'is_update_status' => 1,
    11841184                'is_update_content' => 1,
    11851185                'is_update_title' => 1,
    11861186                'is_update_slug' => 1,
    11871187                'is_update_excerpt' => 1,
    11881188                'is_update_categories' => 1,
    11891189                'is_update_author' => 1,
    11901190                'is_update_comment_status' => 1,
    11911191                'is_update_ping_status' => 1,
    11921192                'is_update_post_type' => 1,
    11931193                'is_update_post_format' => 1,
    11941194                'update_categories_logic' => 'full_update',
    11951195                'taxonomies_list' => array(),
    11961196                'taxonomies_only_list' => array(),
    11971197                'taxonomies_except_list' => array(),
    11981198                'is_update_attachments' => 1,
    11991199                'is_update_images' => 1,
    12001200                'update_images_logic' => 'full_update',
    12011201                'is_update_dates' => 1,
    12021202                'is_update_menu_order' => 1,
    12031203                'is_update_parent' => 1,
    12041204                'is_keep_attachments' => 0,
    12051205                'is_keep_imgs' => 0,
    12061206                'do_not_remove_images' => 1,
    12071207
    12081208                'is_update_custom_fields' => 1,
    12091209                'update_custom_fields_logic' => 'full_update',
    12101210                'custom_fields_list' => array(),
    12111211                'custom_fields_only_list' => array(),
    12121212                'custom_fields_except_list' => array(),
    12131213
    12141214                'duplicate_matching' => 'auto',
    12151215                'duplicate_indicator' => 'title',
    12161216                'custom_duplicate_name' => '',
    12171217                'custom_duplicate_value' => '',
    12181218                'is_update_previous' => 0,
    12191219                'is_scheduled' => '',
    12201220                'scheduled_period' => '',
    12211221                'friendly_name' => '',
    12221222                'records_per_request' => 20,
    12231223                'auto_rename_images' => 0,
    12241224                'auto_rename_images_suffix' => '',
    12251225                'images_name' => 'filename',
    12261226                'post_format' => 'standard',
    12271227                'post_format_xpath' => '',
    12281228                'encoding' => 'UTF-8',
    12291229                'delimiter' => '',
    12301230                'image_meta_title' => '',
    12311231                'image_meta_title_delim' => ',',
    12321232                'image_meta_caption' => '',
    12331233                'image_meta_caption_delim' => ',',
    12341234                'image_meta_alt' => '',
    12351235                'image_meta_alt_delim' => ',',
    12361236                'image_meta_description' => '',
    12371237                'image_meta_description_delim' => ',',
    12381238                'image_meta_description_delim_logic' => 'separate',
    12391239                'status_xpath' => '',
    12401240                'download_images' => 'yes',
    12411241                'converted_options' => 0,
    12421242                'update_all_data' => 'yes',
    12431243                'is_fast_mode' => 0,
    12441244                'chuncking' => 1,
    12451245                'import_processing' => 'ajax',
    12461246                'processing_iteration_logic' => 'auto',
    12471247                'save_template_as' => 0,
    12481248
    12491249                'title' => '',
    12501250                'content' => '',
    12511251                'name' => '',
    12521252                'is_keep_linebreaks' => 1,
    12531253                'is_leave_html' => 0,
    12541254                'fix_characters' => 0,
    12551255                'pid_xpath' => '',
    12561256                'slug_xpath' => '',
    12571257                'title_xpath' => '',
    12581258
    12591259                'featured_image' => '',
    12601260                'download_featured_image' => '',
    12611261                'download_featured_delim' => ',',
    12621262                'gallery_featured_image' => '',
    12631263                'gallery_featured_delim' => ',',
    12641264                'is_featured' => 1,
    12651265                'is_featured_xpath' => '',
    12661266                'set_image_meta_title' => 0,
    12671267                'set_image_meta_caption' => 0,
    12681268                'set_image_meta_alt' => 0,
    12691269                'set_image_meta_description' => 0,
    12701270                'auto_set_extension' => 0,
    12711271                'new_extension' => '',
    12721272                'tax_logic' => array(),
    12731273                'tax_assing' => array(),
    12741274                'term_assing' => array(),
    12751275                'multiple_term_assing' => array(),
    12761276                'tax_hierarchical_assing' => array(),
    12771277                'tax_hierarchical_last_level_assign' => array(),
    12781278                'tax_single_xpath' => array(),
    12791279                'tax_multiple_xpath' => array(),
    12801280                'tax_hierarchical_xpath' => array(),
    12811281                'tax_multiple_delim' => array(),
    12821282                'tax_hierarchical_delim' => array(),
    12831283                'tax_manualhierarchy_delim' => array(),
    12841284                'tax_hierarchical_logic_entire' => array(),
    12851285                'tax_hierarchical_logic_manual' => array(),
    12861286                'tax_enable_mapping' => array(),
    12871287                'tax_is_full_search_single' => array(),
    12881288                'tax_is_full_search_multiple' => array(),
    12891289                'tax_assign_to_one_term_single' => array(),
    12901290                'tax_assign_to_one_term_multiple' => array(),
    12911291                'tax_mapping' => array(),
    12921292                'tax_logic_mapping' => array(),
    12931293                'is_tax_hierarchical_group_delim' => array(),
    12941294                'tax_hierarchical_group_delim' => array(),
    12951295                'nested_files' => array(),
    12961296                'xml_reader_engine' => 0,
    12971297                'taxonomy_type' => '',
    12981298                'taxonomy_parent' => '',
    12991299                'taxonomy_slug' => 'auto',
    13001300                'taxonomy_slug_xpath' => '',
    13011301                'taxonomy_display_type' => '',
    13021302                'taxonomy_display_type_xpath' => '',
    13031303                'import_img_tags' => 0,
    13041304                'search_existing_images_logic' => 'by_url',
    13051305                'enable_import_scheduling' => 'false',
    13061306                'scheduling_enable' => false,
    13071307                'scheduling_weekly_days' => '',
    13081308                'scheduling_run_on' => 'weekly',
    13091309                'scheduling_monthly_day' => '',
    13101310                'scheduling_times' => array(),
    13111311                'scheduling_timezone' => 'UTC',
    13121312                'is_update_comment_post_id' => 1,
    13131313                'is_update_comment_author' => 1,
    13141314                'is_update_comment_author_email' => 1,
    13151315                'is_update_comment_author_url' => 1,
    13161316                'is_update_comment_author_IP' => 1,
    13171317                'is_update_comment_karma' => 1,
    13181318                'is_update_comment_approved' => 1,
    13191319                'is_update_comment_verified' => 1,
    13201320                'is_update_comment_rating' => 1,
    13211321                'is_update_comment_agent' => 1,
    13221322                'is_update_comment_user_id' => 1,
    13231323                'is_update_comment_type' => 1,
    13241324                'is_update_comments' => 1,
    13251325                'update_comments_logic' => 'full_update',
    13261326                'comment_author' => '',
    13271327                'comment_author_email' => '',
    13281328                'comment_author_url' => '',
    13291329                'comment_author_IP' => '',
    13301330                'comment_karma' => '',
    13311331                'comment_parent' => '',
    13321332                'comment_approved' => '1',
    13331333                'comment_approved_xpath' => '',
    13341334                'comment_verified' => '1',
    13351335                'comment_verified_xpath' => '',
    13361336                'comment_agent' => '',
    13371337                'comment_type' => '',
    13381338                'comment_type_xpath' => '',
    13391339                'comment_user_id' => 'email',
    13401340                'comment_user_id_xpath' => '',
    13411341                'comment_post' => '',
    13421342                'comment_rating' => '',
    13431343                'comments_repeater_mode' => 'csv',
    13441344                'comments_repeater_mode_separator' => '|',
    13451345                'comments_repeater_mode_foreach' => '',
    13461346                'comments' => array(
    13471347                    'content' => '',
    13481348                    'author' => '',
    13491349                    'author_email' => '',
    13501350                    'author_url' => '',
    13511351                    'author_ip' => '',
    13521352                    'karma' => '',
    13531353                    'approved' => '',
    13541354                    'type' => '',
    13551355                    'date' => 'now'
    13561356                )
    13571357            );
    13581358        }
    13591359
    13601360    /*
    13611361     * Convert csv to xml
    13621362     */
    13631363    public static function csv_to_xml($csv_url){
    13641364
    13651365        include_once(self::ROOT_DIR.'/libraries/XmlImportCsvParse.php');
    13661366
    13671367        $csv = new PMXI_CsvParser($csv_url);
    13681368
    13691369        $wp_uploads = wp_upload_dir();
    13701370        $tmpname = wp_unique_filename($wp_uploads['path'], str_replace("csv", "xml", basename($csv_url)));
    13711371        $xml_file = $wp_uploads['path']  .'/'. $tmpname;
    13721372        file_put_contents($xml_file, $csv->toXML());
    13731373        return $xml_file;
    13741374
    13751375    }
    13761376
    13771377        /**
    13781378         * @return bool
    13791379         */
    13801380        public static function is_ajax(){
    13811381            return (isset($_SERVER["HTTP_ACCEPT"]) && strpos($_SERVER["HTTP_ACCEPT"], 'json')) !== false;
    13821382        }
    13831383
    13841384    /**
    13851385     * Returns ID of current import.
    13861386     *
    13871387     * @return int|bool
    13881388     */
    13891389    public static function getCurrentImportId() {
    13901390        $input = new PMXI_Input();
    13911391        $import_id = $input->get('id');
    13921392        if (empty($import_id)) {
    13931393            $import_id = $input->get('import_id');
    13941394        }
    13951395        return $import_id;
    13961396    }
    13971397
    13981398}
    13991399
    14001400PMXI_Plugin::getInstance();
  • wp-all-import/trunk/readme.txt

    r2737093 r2749264  
    11=== Import any XML or CSV File to WordPress ===
    22Contributors: soflyy, wpallimport
    33Requires at least: 4.1
    44Tested up to: 6.0
    5 Stable tag: 3.6.7
     5Stable tag: 3.6.8
    66Tags: 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
    77
    88WP All Import is an extremely powerful importer that makes it easy to import any XML or CSV file to WordPress.
    99
    1010== Description ==
    1111
    1212= WP All Import - Simple & Powerful XML / CSV Importer Plugin =
    1313
    1414*“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!”*
    1515**Alex Vasquez** - DigiSavvy Co-Founder & WordCamp Los Angeles Organizer
    1616
    1717WP All Import has a four step import process and an intuitive drag & drop interface that makes complicated import tasks simple and fast.
    1818
    1919There 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.
    2020
    2121WP 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.
    2222
    2323Check 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.
    2424
    2525WP 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.
    2626
    2727For technical support from the developers, please consider purchasing WP All Import Pro.
    2828
    2929= WP All Import Professional Edition =
    3030[youtube http://www.youtube.com/watch?v=pD6WQANJcJY /]
    3131
    3232*WP All Import Pro* is a paid upgrade that includes premium support and adds the following features:
    3333
    3434* Import data to Custom Fields - used by many themes, especially those using Custom Post Types - to store data associated with the posts.
    3535
    3636* 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.
    3737
    3838* 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.
    3939
    4040* 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.
    4141
    4242* 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.
    4343
    4444* Guaranteed technical support via e-mail.
    4545
    4646[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)
    4747
    4848Need 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.
    4949
    5050= WordPress CSV Imports =
    5151
    5252Read 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.
    5353
    5454CSV 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.
    5555
    5656When importing CSV files, your CSV should have UTF-8 encoding if you are having trouble importing special characters.
    5757
    5858In 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.
    5959
    6060For 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.
    6161
    6262= Add-Ons =
    6363
    6464A number of premium add-ons are available to add functionality to the importer and make XML & CSV import tasks to complex plugins simple.
    6565
    6666 - Advanced Custom Fields Add-On - [ACF](http://www.advancedcustomfields.com/) XML & CSV importer
    6767 - WooCommerce Add-On - XML & CSV importer for all [WooCommerce](http://wordpress.org/plugins/woocommerce) product types
    6868 - User Import Add-On - XML & CSV importer for users, including user_meta
    6969 - Link Cloak Add-On - Auto-create redirects for links present during an XML or CSV import
    7070
    7171Learn 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)
    7272
    7373A [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.
    7474
    7575== Premium Support ==
    7676Support for the free version of WP All Import is handled through the WordPress.org community forums.
    7777
    7878Support 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)
    7979
    8080== Import To WooCommerce ==
    8181
    8282Need to [import XML and CSV to WooCommerce?](http://wordpress.org/plugins/woocommerce-xml-csv-product-import/) Check out our WooCommerce add-on.
    8383
    8484[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)
    8585
    8686== Frequently Asked Questions ==
    8787
    8888**What Size Files Can WP All Import Handle?**
    8989It 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.
    9090
    9191[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.
    9292
    9393*The answer to all of the following questions is yes:*
    9494
    9595Does this really work with ANY XML or CSV file?
    9696Can WP All Import get ALL of the data out of the file? Even attributes?
    9797Does it work with special character encoding like Hebrew, Arabic, Chinese, etc?
    9898
    9999== Screenshots ==
    100100
    1011011. Choose file.
    1021022. Filtering options.
    1031033. Choose where to import your data.
    1041044. Manage imports.
    105105
    106106== Changelog ==
     107
     108= 3.6.8 =
     109* security improvement
    107110
    108111= 3.6.7 =
    109112* security improvement
    110113* improvement: changed Manage Imports page button labels to be more precise
    111114* improvement: assign 'Uncategorized' term to posts imported without a category assigned
    112115* improvement: add support for taxonomies that return objects instead of IDs
    113116* improvement: remove commented code that could cause false positives for security scans
    114117* bug fix: jQuery error related to 'destroy' method
    115118* bug fix: rare issue that prevented content image URLs from being updated during import
    116119* bug fix: taxonomies section drag and drop doesn't save after rearranging fields
    117120* bug fix: conflict with Advanced Ads plugin
    118121* bug fix: 'Instead of deletion, set missing records to out of stock' still deleting products
    119122
    120123= 3.6.6 =
    121124* bug fix: jQuery nestedSortable compatibility with WordPress 5.9
    122125
    123126= 3.6.5 =
    124127* improvement: better sanitization and escaping of data in WP All Import interface
    125128
    126129= 3.6.4 =
    127130* improvement: better sanitization and escaping of data in WP All Import interface
    128131* improvement: use libraries included in WordPress Core
    129132
    130133= 3.6.3 =
    131134* security fix
    132135* bug fix: images not updated for existing products when using WooCommerce Import Add-On
    133136
    134137= 3.6.2 =
    135138* improvement: add ability to control taxonomy mapping case sensitivity via filter wpai_is_case_insensitive_taxonomy_mapping
    136139* 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
    137140* improvement: add missing options on confirm import step
    138141* bug fix
    139142* improvement: initial PHP 8 support
    140143* bugfix: manage_options capability check
    141144
    142145= 3.6.1 =
    143146* bug fix: categories were imported despite the taxonomy option being disabled
    144147* improvement: add ability to filter csv escape symbol via wp_all_import_csv_parser_settings filter
    145148
    146149= 3.6.0 =
    147150* maintenance: compatibility with Elementor v3.3 JavaScript changes
    148151
    149152= 3.5.9 =
    150153* bug fix: call to the non existing function wp_all_import_sanitize_url
    151154
    152155= 3.5.8 =
    153156* bug fix: import of taxonomies hierarchy didn't work properly
    154157
    155158= 3.5.7 =
    156159* improvement: git rid if deprecated join query on manage imports screen
    157160* improvement: add is_update_post_format option
    158161* improvement: add wp_all_import_manual_matching filter
    159162* improvement: add wp_all_import_logger filter
    160163* bug fix: records were removed from pmxi_posts table when activating WPAI on multisite installation
    161164* bug fix: get rid of unused deprecated function add_contextual_help()
    162165
    163166= 3.5.6 =
    164167* bug fix: PMXI_Hash_Record class doesn't exist error appears when deleting missing records
    165168
    166169= 3.5.5 =
    167170* improvement: get rid of deprecated setting 'High Speed Small File Processing'
    168171* bug fix: chromium scroll anchoring caused screen jumping effect
    169172* bug fix: pagenum query argument caused broken link on import complete screen
    170173
    171174= 3.5.4 =
    172175* improvement: compatibility with WordPress 5.5
    173176* API: added helper function wp_all_import_get_import_id()
    174177* API: added helper function wp_all_import_get_import_post_type($import_id)
    175178
    176179= 3.5.3 =
    177180* bug fix: switch to CodeMirror implementation shipped in WordPress core
    178181* bug fix: unable to double click to insert XPath in some cases
    179182* bug fix: unable to apply pmxi_is_images_to_update filter to featured images
    180183* bug fix: unable to match existing images when suffix is added to file name during import
    181184
    182185= 3.5.2 =
    183186* improvement: match existing images by filename with underscores
    184187* API: add new action wp_all_import_before_preserve_post_data
    185188* API: add new filter wp_all_import_specified_delimiters
    186189* bug fix: attachment author not imported for API image imports
    187190
    188191= 3.5.1 =
    189192* improvement: add support for importing WebP images
    190193* bug fix: images in content not being imported when creating new simple WooCommerce products
    191194
    192195= 3.5.0 =
    193196* improvement: add support for .tsv format
    194197* API: add current XML variable to pmxi_article_data filter
    195198* bug fix: post terms incorrect after import complete, must be recounted
    196199* bug fix: empty attachments created when attachment import fails
    197200* bug fix: matching posts by ID matches and imports into attachments with the same ID
    198201
    199202= 3.4.9 =
    200203* bug fix: import using stream reader
    201204* bug fix: generation temporary files in system temporary folder
    202205
    203206= 3.4.8 =
    204207* improvement: various import speed optimizations
    205208* bug fix: remove deprecated function calls for PHP 7.2 compatibility
    206209* bug fix: delete db tables when mu blog deleted
    207210* bug fix: remove BOM from import templates
    208211* bug fix: saving CSV delimiter when changing import file
    209212
    210213= 3.4.7 =
    211214* improvement: skip to the first specified record when importing only part of a file
    212215* new filter: wp_all_import_is_render_whole_xml_tree
    213216* new filter: wp_all_import_images_uploads_dir (add-on api)
    214217* bug fix: patch XSS exploit
    215218* bug fix: conflict with InfiniteWP
    216219* bug fix: update notification for Link Cloaking Add-On
    217220* bug fix: load functions before pmxi_before_xml_import
    218221* bug fix: do not re-count category terms when post imported as draft
    219222* bug fix: import base64 encoded images in add-ons
    220223* security fix - XSS exploit (Special thanks to Yuji Tounai for reporting)
    221224
    222225= 3.4.6 =
    223226* improvement: added timestamp to import log lines
    224227* improvement: added support for bmp images
    225228* improvement: added new action pmxi_before_post_import_{$addon}
    226229* security fix: patch XSS exploit
    227230* bug fix: import pages hierarchy
    228231* bug fix: error in pclzip.lib.php with php 7.1
    229232* bug fix: import taxonomies hierarchy
    230233* bug fix: json to xml convertation
    231234* bug fix: removed SWFUpload
    232235* security fix - XSS exploit (Special thanks to Mardan Muhidin for reporting)
    233236
    234237= 3.4.5 =
    235238* improvement: custom fields delection
    236239* improvement: new action wp_all_import_post_skipped
    237240* improvement: updated history page title
    238241* improvement: optimize large imports deletion
    239242* improvement: added import friendly name to confirm screen
    240243* improvement: sql query optimization on manage imports screen
    241244* bug fix: generation image filename
    242245* bug fix: wp_all_import_specified_records filter
    243246
    244247= 3.4.4 =
    245248* bug fix: import template not worked when downloaded via Import Settings
    246249* bug fix: updating user login
    247250* bug fix: import images with encoded quotes
    248251* improvement: added hungarian translation
    249252
    250253= 3.4.3 =
    251254* improvement: new filter 'wp_all_import_phpexcel_delimiter'
    252255* improvement: new filter 'wp_all_import_is_trim_parsed_data'
    253256* improvement: added new filter 'wp_all_import_skip_x_csv_rows'
    254257* improvement: added csv delimiter setting to import options screen
    255258* bug fix: import duplicate tags
    256259
    257260= 3.4.2 =
    258261* bug fix: conflict with the event calendar plugin
    259262* bug fix: import images for newly created products
    260263
    261264= 3.4.1 =
    262265* improvement: Stop parsing data which is not going to be updated
    263266* improvement: added new filter wp_all_import_phpexcel_object to modify excel data before import
    264267* bug fix: search for images ending with underscores in media
    265268* bug fix: import hierarchical posts/pages
    266269* bug fix: import cpt page templates
    267270
    268271= 3.4.0 =
    269272* improvement: compatibility with PHP 7.x
    270273
    271274= 3.3.9 =
    272275* improvement: new re-import option 'is update post type'
    273276* bug fix: hierarchy taxonomies preview
    274277* bug fix: empty logs folder generation
    275278* bug fix: 'Keep images currently in Media Library' option for add-ons
    276279* bug fix: import bundles with gz files
    277280* bug fix: custom functions for attachments
    278281
    279282= 3.3.8 =
    280283* improvement: 'Force Stream Reader' setting
    281284* improvement: new filter 'wp_all_import_auto_create_csv_headers'
    282285* improvement: new filter 'wp_all_import_is_base64_images_allowed'
    283286* improvement: new filter 'wp_all_import_set_post_terms' to leave a specific category alone when a post is being updated
    284287* bug fix: nodes navigation for xpath like /news/item
    285288* bug fix: frozen import template screen for cyrillic XML feeds
    286289* bug fix: conflict between taxonomies & user import
    287290* bug fix: creating users with the same email
    288291* bug fix: enable keep line breaks option by default
    289292* bug fix: composer namespace conflict
    290293* bug fix: images preview when wp is in subdirectory
    291294* bug fix: 'Instead of deletion, set Custom Field' option for users import
    292295
    293296= 3.3.7 =
    294297* added new option 'Use StreamReader instead of XMLReader to parse import file' to fix issue with libxml 2.9.3
    295298* execute 'pmxi_article_data' filter for all posts ( new & existing )
    296299
    297300= 3.3.6 =
    298301* added de_CH translation
    299302* added support for .svg images
    300303* added possibility for import excerpts for pages
    301304* added new filter 'wp_all_import_specified_records'
    302305* added new filter 'wp_all_import_is_post_to_delete'
    303306* disable XMLReader stream filter for HHVM
    304307* improve search for existing images in media gallery
    305308
    306309= 3.3.5 =
    307310* fixed 'Use images currently in Media Library' option
    308311
    309312= 3.3.4 =
    310313* fixed error messages on step 1 in case when server throws fatal error e.q. time limit exception
    311314* 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
    312315* fixed custom php functions in images preview
    313316* fixed detecting root nodes with colons in names
    314317* added es_ES translation
    315318* added de_DE translation
    316319* added iterative ajax delete process ( deleting associated posts )
    317320* added feature to download template/bundle from import settings
    318321* added new option for importing images "Use images currently in Media Library"
    319322* added new action 'pmxi_missing_post'
    320323
    321324= 3.3.3 =
    322325* fixed duplicate matching by custom field
    323326* fixed converting image filenames to lowercase
    324327* fixed import html to image description
    325328* fixed import _wp_old_slug
    326329* added Post ID to manual record matching
    327330* added 'Comment status' to 'Choose data to update' section
    328331
    329332= 3.3.2 =
    330333* fixed fatal error on saving settings
    331334
    332335= 3.3.1 =
    333336* fixed parsing CSV with empty lines
    334337* fixed parsing multiple IF statements
    335338* fixed preview in case when ‘Disable the visual editor when writing’ is enabled
    336339* fixed conflict with WooCommerce - Store Exporter Deluxe
    337340* added notifications for required addons
    338341* added support for wp all export bundle
    339342* added support for manual import bundle
    340343* added feature 'click to download import file'
    341344* added validation for excerpt and images sections
    342345* added auto-detect a broken Unique ID notification
    343346* added import template notifications
    344347* removed support for importing WooCommerce Orders
    345348* changed absolute paths to relative in db
    346349
    347350= 3.3.0 =
    348351* 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'
    349352* added support for Excel files ( .xls, .xlsx )
    350353
    351354= 3.2.9 =
    352355* load ini_set only on plugin pages
    353356* fixed saving import template
    354357
    355358= 3.2.8 =
    356359* fixed Apply mapping rules before splitting via separator symbol for manual hierarchy
    357360* fixed path equal or less than
    358361* fixed changing unique key when moving back from confirm screen
    359362* fixed override page template
    360363* updated wp_all_import_is_post_to_update filter with second argument XML node as array
    361364* added a second argument to pmxi_saved_post action ( SimpleXML object ) of current record
    362365
    363366= 3.2.7 =
    364367* fixed enum fields mapping rules feature
    365368
    366369= 3.2.6 =
    367370* Compatibility with 3rd party development: http://www.wpallimport.com/documentation/addon-dev/overview/
    368371
    369372= 3.2.5 =
    370373* Important security fixes - additional hardening, prevention of blind SQL injection and reflected XSS attacks
    371374
    372375= 3.2.4 =
    373376* critical security fix - stopping non-logged in users from accessing adminInit
    374377
    375378= 3.2.3 =
    376379* fixed re-count record when a file has been changed at an import setting screen
    377380* fixed unlink attachment source when posts updated/deleted
    378381* added a limit 10 to the existing meta values
    379382
    380383= 3.2.2 =
    381384* fixed database schema
    382385* uploading large files
    383386
    384387= 3.2.1 =
    385388* fixed updating import settings
    386389
    387390= 3.2.0 =
    388391* 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
    389392* speed up the import of taxonomies/categories
    390393* added taxonomies/categories mapping feature
    391394* added custom fields auto-detection feature
    392395* added custom fields mapping feature
    393396* added images/taxonomies preview feature
    394397* added unofficial support for more file formats - json & sql
    395398* added new setting (secure mode) to protect your files
    396399* better import logs
    397400* updated design
    398401
    399402= 3.1.5 =
    400403* fixed pmxi_delete_post action
    401404* fixed import menu order & post parent for pages
    402405* fixed import log for continue import feature
    403406* added is update author option
    404407* fixed post formats
    405408* fixed UTC dates on manage imports page
    406409
    407410= 3.1.4 =
    408411* changed support email
    409412
    410413= 3.1.3 =
    411414* fixed import pages
    412415
    413416= 3.1.2 =
    414417* added compatibility with WP 3.9
    415418* added autodetect session mode
    416419* updated convertation CSV to XML with XMLWriter
    417420* fixed import *.zip files
    418421* fixed xpath helper on step 2
    419422* fixed showing zeros in XML tree
    420423* fixed deleting history files
    421424* fixed autodetect image extensions
    422425* fixed increasing SQL query length
    423426* allow post content to be empty on step 3
    424427* delete deprecated settings "my csv contain html code" and "case sensitivity"
    425428
    426429= 3.1.1 =
    427430* Fixed compatibility with addons
    428431* Fixed "download image" option for import products
    429432* Fixed CSS for WP 3.8
    430433* Fixed dismiss links
    431434
    432435= 3.1.0 =
    433436* Compatibility with WP 3.8
    434437* Compatibility with WPAI WooCommerce add-on (paid) 1.2.4
    435438* Performance Improvements
    436439* Improved UI
    437440* Lots of bug fixes
    438441* New Record Matching section
    439442* Added option to set Post Status with XPath (the value of presented XPath should be one of the following: publish, draft, trash)
    440443* Preview navigation
    441444
    442445= 3.0.4 =
    443446* Fixed import categories;
    444447* Updated UI/UX;
    445448* Added import/export templates feature;
    446449* Added enhanced session functionality;
    447450* Added option to set post status with XPath;
    448451* Added feeds encoding feature;
    449452
    450453= 3.0.2 =
    451454* Added support for the WooCommerce add-on
    452455
    453456= 3.0 =
    454457* Free edition of 3.0 pro release
    455458
    456459= 2.14 =
    457460* Category list delimiter bug fix
    458461
    459462= 2.13 =
    460463* Tons of bug fixes, updates, and additional features.
    461464
    462465
    463466= 2.12 =
    464467* Initial release on WordPress.org.
Note: See TracChangeset for help on using the changeset viewer.