wp-all-import
Last commit date
actions
11 years ago
classes
11 years ago
config
11 years ago
controllers
11 years ago
filters
11 years ago
helpers
11 years ago
i18n
11 years ago
libraries
11 years ago
models
11 years ago
shortcodes
11 years ago
static
11 years ago
views
11 years ago
banner-772x250.png
11 years ago
plugin.php
11 years ago
readme.txt
11 years ago
schema.php
11 years ago
screenshot-1.png
11 years ago
screenshot-2.png
11 years ago
screenshot-3.png
11 years ago
screenshot-4.png
11 years ago
plugin.php
907 lines
| 1 | <?php |
| 2 | /* |
| 3 | Plugin Name: WP All Import |
| 4 | Plugin URI: http://www.wpallimport.com/upgrade-to-pro?utm_source=wordpress.org&utm_medium=plugins-page&utm_campaign=free+plugin |
| 5 | Description: The most powerful solution for importing XML and CSV files to WordPress. Create Posts and Pages with content from any XML or CSV file. A paid upgrade to WP All Import Pro is available for support and additional features. |
| 6 | Version: 3.2.2 |
| 7 | Author: Soflyy |
| 8 | */ |
| 9 | |
| 10 | /** |
| 11 | * Plugin root dir with forward slashes as directory separator regardless of actuall DIRECTORY_SEPARATOR value |
| 12 | * @var string |
| 13 | */ |
| 14 | define('PMXI_ROOT_DIR', str_replace('\\', '/', dirname(__FILE__))); |
| 15 | /** |
| 16 | * Plugin root url for referencing static content |
| 17 | * @var string |
| 18 | */ |
| 19 | define('PMXI_ROOT_URL', rtrim(plugin_dir_url(__FILE__), '/')); |
| 20 | /** |
| 21 | * Plugin prefix for making names unique (be aware that this variable is used in conjuction with naming convention, |
| 22 | * i.e. in order to change it one must not only modify this constant but also rename all constants, classes and functions which |
| 23 | * names composed using this prefix) |
| 24 | * @var string |
| 25 | */ |
| 26 | define('PMXI_PREFIX', 'pmxi_'); |
| 27 | |
| 28 | define('PMXI_VERSION', '3.2.2'); |
| 29 | |
| 30 | define('PMXI_EDITION', 'free'); |
| 31 | |
| 32 | /** |
| 33 | * Main plugin file, Introduces MVC pattern |
| 34 | * |
| 35 | * @singletone |
| 36 | * @author Pavel Kulbakin <p.kulbakin@gmail.com> |
| 37 | */ |
| 38 | final class PMXI_Plugin { |
| 39 | /** |
| 40 | * Singletone instance |
| 41 | * @var PMXI_Plugin |
| 42 | */ |
| 43 | protected static $instance; |
| 44 | |
| 45 | /** |
| 46 | * Plugin options |
| 47 | * @var array |
| 48 | */ |
| 49 | protected $options = array(); |
| 50 | |
| 51 | /** |
| 52 | * Plugin root dir |
| 53 | * @var string |
| 54 | */ |
| 55 | const ROOT_DIR = PMXI_ROOT_DIR; |
| 56 | /** |
| 57 | * Plugin root URL |
| 58 | * @var string |
| 59 | */ |
| 60 | const ROOT_URL = PMXI_ROOT_URL; |
| 61 | /** |
| 62 | * Prefix used for names of shortcodes, action handlers, filter functions etc. |
| 63 | * @var string |
| 64 | */ |
| 65 | const PREFIX = PMXI_PREFIX; |
| 66 | /** |
| 67 | * Plugin file path |
| 68 | * @var string |
| 69 | */ |
| 70 | const FILE = __FILE__; |
| 71 | /** |
| 72 | * Max allowed file size (bytes) to import in default mode |
| 73 | * @var int |
| 74 | */ |
| 75 | const LARGE_SIZE = 0; // all files will importing in large import mode |
| 76 | |
| 77 | public static $session = null; |
| 78 | |
| 79 | public static $encodings = array('UTF-8', 'UTF-16', 'Windows-1250', 'Windows-1251', 'Windows-1252', 'Windows-1253', 'Windows-1254', 'Windows-1255', 'Windows-1256', 'Windows-1257', 'Windows-1258', 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9', 'ISO-8859-10', 'KOI8-R', 'KOI8-U'); |
| 80 | |
| 81 | public static $is_csv = false; |
| 82 | |
| 83 | public static $csv_path = false; |
| 84 | |
| 85 | /** |
| 86 | * Return singletone instance |
| 87 | * @return PMXI_Plugin |
| 88 | */ |
| 89 | static public function getInstance() { |
| 90 | if (self::$instance == NULL) { |
| 91 | self::$instance = new self(); |
| 92 | } |
| 93 | return self::$instance; |
| 94 | } |
| 95 | |
| 96 | /** |
| 97 | * Common logic for requestin plugin info fields |
| 98 | */ |
| 99 | public function __call($method, $args) { |
| 100 | if (preg_match('%^get(.+)%i', $method, $mtch)) { |
| 101 | $info = get_plugin_data(self::FILE); |
| 102 | if (isset($info[$mtch[1]])) { |
| 103 | return $info[$mtch[1]]; |
| 104 | } |
| 105 | } |
| 106 | throw new Exception("Requested method " . get_class($this) . "::$method doesn't exist."); |
| 107 | } |
| 108 | |
| 109 | /** |
| 110 | * Get path to plagin dir relative to wordpress root |
| 111 | * @param bool[optional] $noForwardSlash Whether path should be returned withot forwarding slash |
| 112 | * @return string |
| 113 | */ |
| 114 | public function getRelativePath($noForwardSlash = false) { |
| 115 | $wp_root = str_replace('\\', '/', ABSPATH); |
| 116 | return ($noForwardSlash ? '' : '/') . str_replace($wp_root, '', self::ROOT_DIR); |
| 117 | } |
| 118 | |
| 119 | /** |
| 120 | * Check whether plugin is activated as network one |
| 121 | * @return bool |
| 122 | */ |
| 123 | public function isNetwork() { |
| 124 | if ( !is_multisite() ) |
| 125 | return false; |
| 126 | |
| 127 | $plugins = get_site_option('active_sitewide_plugins'); |
| 128 | if (isset($plugins[plugin_basename(self::FILE)])) |
| 129 | return true; |
| 130 | |
| 131 | return false; |
| 132 | } |
| 133 | |
| 134 | /** |
| 135 | * Check whether permalinks is enabled |
| 136 | * @return bool |
| 137 | */ |
| 138 | public function isPermalinks() { |
| 139 | global $wp_rewrite; |
| 140 | |
| 141 | return $wp_rewrite->using_permalinks(); |
| 142 | } |
| 143 | |
| 144 | /** |
| 145 | * Return prefix for plugin database tables |
| 146 | * @return string |
| 147 | */ |
| 148 | public function getTablePrefix() { |
| 149 | global $wpdb; |
| 150 | |
| 151 | //return ($this->isNetwork() ? $wpdb->base_prefix : $wpdb->prefix) . self::PREFIX; |
| 152 | return $wpdb->prefix . self::PREFIX; |
| 153 | } |
| 154 | |
| 155 | /** |
| 156 | * Return prefix for wordpress database tables |
| 157 | * @return string |
| 158 | */ |
| 159 | public function getWPPrefix() { |
| 160 | global $wpdb; |
| 161 | return ($this->isNetwork()) ? $wpdb->base_prefix : $wpdb->prefix; |
| 162 | } |
| 163 | |
| 164 | /** |
| 165 | * Class constructor containing dispatching logic |
| 166 | * @param string $rootDir Plugin root dir |
| 167 | * @param string $pluginFilePath Plugin main file |
| 168 | */ |
| 169 | protected function __construct() { |
| 170 | |
| 171 | $this->load_plugin_textdomain(); |
| 172 | |
| 173 | // regirster autoloading method |
| 174 | if (function_exists('__autoload') and ! in_array('__autoload', spl_autoload_functions())) { // make sure old way of autoloading classes is not broken |
| 175 | spl_autoload_register('__autoload'); |
| 176 | } |
| 177 | spl_autoload_register(array($this, '__autoload')); |
| 178 | |
| 179 | // register helpers |
| 180 | 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) { |
| 181 | require_once $filePath; |
| 182 | } |
| 183 | |
| 184 | // create history folder |
| 185 | $uploads = wp_upload_dir(); |
| 186 | |
| 187 | $wpallimportDirs = array('wpallimport', 'wpallimport/logs', 'wpallimport/files', 'wpallimport/temp', 'wpallimport/uploads'); |
| 188 | |
| 189 | foreach ($wpallimportDirs as $dir) { |
| 190 | |
| 191 | if ( !is_dir($uploads['basedir'] . '/' . $dir)) wp_mkdir_p($uploads['basedir'] . '/' . $dir); |
| 192 | |
| 193 | if ( ! @file_exists($uploads['basedir'] . '/' . $dir . '/index.php') ) |
| 194 | @touch( $uploads['basedir'] . '/' . $dir . '/index.php' ); |
| 195 | |
| 196 | } |
| 197 | |
| 198 | // init plugin options |
| 199 | $option_name = get_class($this) . '_Options'; |
| 200 | $options_default = PMXI_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray(); |
| 201 | $this->options = array_intersect_key(get_option($option_name, array()), $options_default) + $options_default; |
| 202 | $this->options = array_intersect_key($options_default, array_flip(array('info_api_url'))) + $this->options; // make sure hidden options apply upon plugin reactivation |
| 203 | if ('' == $this->options['cron_job_key']) $this->options['cron_job_key'] = url_title(rand_char(12)); |
| 204 | |
| 205 | update_option($option_name, $this->options); |
| 206 | $this->options = get_option(get_class($this) . '_Options'); |
| 207 | |
| 208 | register_activation_hook(self::FILE, array($this, '__activation')); |
| 209 | |
| 210 | // register action handlers |
| 211 | 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) { |
| 212 | require_once $filePath; |
| 213 | $function = $actionName = basename($filePath, '.php'); |
| 214 | if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) { |
| 215 | $actionName = $m[1]; |
| 216 | $priority = intval($m[2]); |
| 217 | } else { |
| 218 | $priority = 10; |
| 219 | } |
| 220 | 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) |
| 221 | } |
| 222 | |
| 223 | // register filter handlers |
| 224 | 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) { |
| 225 | require_once $filePath; |
| 226 | $function = $actionName = basename($filePath, '.php'); |
| 227 | if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) { |
| 228 | $actionName = $m[1]; |
| 229 | $priority = intval($m[2]); |
| 230 | } else { |
| 231 | $priority = 10; |
| 232 | } |
| 233 | 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) |
| 234 | } |
| 235 | |
| 236 | // register shortcodes handlers |
| 237 | if (is_dir(self::ROOT_DIR . '/shortcodes')) foreach (PMXI_Helper::safe_glob(self::ROOT_DIR . '/shortcodes/*.php', PMXI_Helper::GLOB_RECURSE | PMXI_Helper::GLOB_PATH) as $filePath) { |
| 238 | $tag = strtolower(str_replace('/', '_', preg_replace('%^' . preg_quote(self::ROOT_DIR . '/shortcodes/', '%') . '|\.php$%', '', $filePath))); |
| 239 | add_shortcode($tag, array($this, 'shortcodeDispatcher')); |
| 240 | } |
| 241 | |
| 242 | // register admin page pre-dispatcher |
| 243 | add_action('admin_init', array($this, '__adminInit')); |
| 244 | add_action('admin_init', array($this, '_fix_options')); |
| 245 | |
| 246 | } |
| 247 | |
| 248 | /** |
| 249 | * convert imports options |
| 250 | * compatibility with version 4.0 |
| 251 | */ |
| 252 | public function _fix_options(){ |
| 253 | |
| 254 | $imports = new PMXI_Import_List(); |
| 255 | $post = new PMXI_Post_Record(); |
| 256 | |
| 257 | $templates = new PMXI_Template_List(); |
| 258 | $template = new PMXI_Template_Record(); |
| 259 | |
| 260 | $is_migrated = get_option('pmxi_is_migrated'); |
| 261 | |
| 262 | $uploads = wp_upload_dir(); |
| 263 | |
| 264 | if ( empty($is_migrated) or version_compare($is_migrated, PMXI_VERSION) < 0 ){ |
| 265 | |
| 266 | if ( empty($is_migrated) ){ // plugin version less than 3.2.0 |
| 267 | |
| 268 | pmxi_rmdir($uploads['basedir'] . '/wpallimport_history'); |
| 269 | pmxi_rmdir($uploads['basedir'] . '/wpallimport_logs'); |
| 270 | |
| 271 | foreach ($imports->setColumns($imports->getTable() . '.*')->getBy(array('id !=' => ''))->convertRecords() as $imp){ |
| 272 | |
| 273 | $imp->getById($imp->id); |
| 274 | |
| 275 | if ( ! $imp->isEmpty() and ! empty($imp->template)){ |
| 276 | |
| 277 | $options = array_merge($imp->options, $imp->template); |
| 278 | |
| 279 | $this->__ver_4_transition_fix($options); |
| 280 | |
| 281 | $imp->set(array( |
| 282 | 'options' => $options |
| 283 | ))->update(); |
| 284 | |
| 285 | if ($imp->type == 'file'){ |
| 286 | $imp->set(array( |
| 287 | 'path' => $uploads['basedir'] . '/wpallimport/files/' . basename($imp->path) |
| 288 | ))->update(); |
| 289 | } |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | foreach ($templates->setColumns($templates->getTable() . '.*')->getBy(array('id !=' => ''))->convertRecords() as $tpl){ |
| 294 | |
| 295 | $tpl->getById($tpl->id); |
| 296 | |
| 297 | if ( ! $tpl->isEmpty() and ! empty($tpl->title) ) { |
| 298 | |
| 299 | $opt = ( empty($tpl->options) ) ? array() : $tpl->options; |
| 300 | |
| 301 | $options = array_merge($opt, array( |
| 302 | 'title' => $tpl->title, |
| 303 | 'content' => $tpl->content, |
| 304 | 'is_keep_linebreaks' => $tpl->is_keep_linebreaks, |
| 305 | 'is_leave_html' => $tpl->is_leave_html, |
| 306 | 'fix_characters' => $tpl->fix_characters |
| 307 | )); |
| 308 | |
| 309 | $this->__ver_4_transition_fix($options); |
| 310 | |
| 311 | $tpl->set(array( |
| 312 | 'options' => $options |
| 313 | ))->update(); |
| 314 | |
| 315 | } |
| 316 | |
| 317 | } |
| 318 | |
| 319 | $this->__fix_db_schema(); // feature to version 3.2.0 |
| 320 | |
| 321 | } |
| 322 | else { |
| 323 | |
| 324 | // migration fixes for vesions |
| 325 | switch ($is_migrated) { |
| 326 | |
| 327 | case '3.2.0': |
| 328 | case '3.2.1': |
| 329 | $this->__fix_db_schema(); // feature to version 3.2.0 |
| 330 | break; |
| 331 | |
| 332 | default: |
| 333 | # code... |
| 334 | break; |
| 335 | } |
| 336 | |
| 337 | } |
| 338 | update_option('pmxi_is_migrated', PMXI_VERSION); |
| 339 | } |
| 340 | } |
| 341 | |
| 342 | public function __ver_4_transition_fix( &$options ){ |
| 343 | |
| 344 | $options['wizard_type'] = ($options['duplicate_matching'] == 'auto') ? 'new' : 'matching'; |
| 345 | |
| 346 | if ($options['download_images']){ |
| 347 | $options['download_images'] = 'yes'; |
| 348 | $options['download_featured_image'] = $options['featured_image']; |
| 349 | $options['featured_image'] = ''; |
| 350 | $options['download_featured_delim'] = $options['featured_delim']; |
| 351 | $options['featured_delim'] = ''; |
| 352 | } |
| 353 | |
| 354 | if ($options['set_image_meta_data']){ |
| 355 | $options['set_image_meta_title'] = 1; |
| 356 | $options['set_image_meta_caption'] = 1; |
| 357 | $options['set_image_meta_alt'] = 1; |
| 358 | $options['set_image_meta_description'] = 1; |
| 359 | } |
| 360 | |
| 361 | if ("" == $options['custom_type']) $options['custom_type'] = $options['type']; |
| 362 | |
| 363 | $exclude_taxonomies = (class_exists('PMWI_Plugin')) ? array('post_format', 'product_type') : array('post_format'); |
| 364 | $post_taxonomies = array_diff_key(get_taxonomies_by_object_type(array($options['custom_type']), 'object'), array_flip($exclude_taxonomies)); |
| 365 | |
| 366 | $options['tax_logic'] = array(); |
| 367 | $options['tax_assing'] = array(); |
| 368 | $options['tax_multiple_xpath'] = array(); |
| 369 | $options['tax_multiple_delim'] = array(); |
| 370 | $options['tax_hierarchical_logic'] = array(); |
| 371 | |
| 372 | if ( ! empty($post_taxonomies)): |
| 373 | foreach ($post_taxonomies as $ctx): |
| 374 | |
| 375 | $options['tax_logic'][$ctx->name] = ($ctx->hierarchical) ? 'hierarchical' : 'multiple'; |
| 376 | |
| 377 | if ($ctx->name == 'category'){ |
| 378 | $options['post_taxonomies']['category'] = $options['categories']; |
| 379 | } |
| 380 | elseif ($ctx->name == 'post_tag' ){ |
| 381 | $options['tax_assing']['post_tag'] = 1; |
| 382 | $options['tax_multiple_xpath']['post_tag'] = $options['tags']; |
| 383 | $options['tax_multiple_delim']['post_tag'] = $options['tags_delim']; |
| 384 | } |
| 385 | |
| 386 | if ( ! empty($options['post_taxonomies'][$ctx->name])){ |
| 387 | |
| 388 | $taxonomies_hierarchy = json_decode($options['post_taxonomies'][$ctx->name], true); |
| 389 | $options['tax_assing'][$ctx->name] = (!empty($taxonomies_hierarchy[0]['assign'])) ? 1 : 0; |
| 390 | |
| 391 | if ($options['tax_logic'][$ctx->name] == 'multiple') { |
| 392 | $options['tax_multiple_xpath'][$ctx->name] = (!empty($taxonomies_hierarchy[0]['xpath'])) ? $taxonomies_hierarchy[0]['xpath'] : ''; |
| 393 | $options['tax_multiple_delim'][$ctx->name] = (!empty($taxonomies_hierarchy[0]['delim'])) ? $taxonomies_hierarchy[0]['delim'] : ''; |
| 394 | } |
| 395 | else{ |
| 396 | |
| 397 | $options['tax_hierarchical_logic'][$ctx->name] = 'manual'; |
| 398 | |
| 399 | } |
| 400 | } |
| 401 | |
| 402 | endforeach; |
| 403 | endif; |
| 404 | } |
| 405 | |
| 406 | /** |
| 407 | * pre-dispatching logic for admin page controllers |
| 408 | */ |
| 409 | public function __adminInit() { |
| 410 | |
| 411 | self::$session = new PMXI_Handler(); |
| 412 | |
| 413 | $input = new PMXI_Input(); |
| 414 | $page = strtolower($input->getpost('page', '')); |
| 415 | |
| 416 | if (preg_match('%^' . preg_quote(str_replace('_', '-', self::PREFIX), '%') . '([\w-]+)$%', $page)) { |
| 417 | //$this->adminDispatcher($page, strtolower($input->getpost('action', 'index'))); |
| 418 | |
| 419 | $action = strtolower($input->getpost('action', 'index')); |
| 420 | |
| 421 | // capitalize prefix and first letters of class name parts |
| 422 | if (function_exists('preg_replace_callback')){ |
| 423 | $controllerName = preg_replace_callback('%(^' . preg_quote(self::PREFIX, '%') . '|_).%', array($this, "replace_callback"),str_replace('-', '_', $page)); |
| 424 | } |
| 425 | else{ |
| 426 | $controllerName = preg_replace('%(^' . preg_quote(self::PREFIX, '%') . '|_).%e', 'strtoupper("$0")', str_replace('-', '_', $page)); |
| 427 | } |
| 428 | $actionName = str_replace('-', '_', $action); |
| 429 | if (method_exists($controllerName, $actionName)) { |
| 430 | $this->_admin_current_screen = (object)array( |
| 431 | 'id' => $controllerName, |
| 432 | 'base' => $controllerName, |
| 433 | 'action' => $actionName, |
| 434 | 'is_ajax' => strpos($_SERVER["HTTP_ACCEPT"], 'json') !== false, |
| 435 | 'is_network' => is_network_admin(), |
| 436 | 'is_user' => is_user_admin(), |
| 437 | ); |
| 438 | add_filter('current_screen', array($this, 'getAdminCurrentScreen')); |
| 439 | add_filter('admin_body_class', create_function('', 'return "' . 'wpallimport-plugin";')); |
| 440 | |
| 441 | $controller = new $controllerName(); |
| 442 | if ( ! $controller instanceof PMXI_Controller_Admin) { |
| 443 | throw new Exception("Administration page `$page` matches to a wrong controller type."); |
| 444 | } |
| 445 | |
| 446 | if ($this->_admin_current_screen->is_ajax) { // ajax request |
| 447 | $controller->$action(); |
| 448 | do_action('pmxi_action_after'); |
| 449 | die(); // stop processing since we want to output only what controller is randered, nothing in addition |
| 450 | } elseif ( ! $controller->isInline) { |
| 451 | @ob_start(); |
| 452 | $controller->$action(); |
| 453 | self::$buffer = @ob_get_clean(); |
| 454 | } else { |
| 455 | self::$buffer_callback = array($controller, $action); |
| 456 | } |
| 457 | } else { // redirect to dashboard if requested page and/or action don't exist |
| 458 | wp_redirect(admin_url()); die(); |
| 459 | } |
| 460 | |
| 461 | } |
| 462 | |
| 463 | } |
| 464 | |
| 465 | /** |
| 466 | * Dispatch shorttag: create corresponding controller instance and call its index method |
| 467 | * @param array $args Shortcode tag attributes |
| 468 | * @param string $content Shortcode tag content |
| 469 | * @param string $tag Shortcode tag name which is being dispatched |
| 470 | * @return string |
| 471 | */ |
| 472 | public function shortcodeDispatcher($args, $content, $tag) { |
| 473 | |
| 474 | $controllerName = self::PREFIX . preg_replace('%(^|_).%e', 'strtoupper("$0")', $tag); // capitalize first letters of class name parts and add prefix |
| 475 | $controller = new $controllerName(); |
| 476 | if ( ! $controller instanceof PMXI_Controller) { |
| 477 | throw new Exception("Shortcode `$tag` matches to a wrong controller type."); |
| 478 | } |
| 479 | ob_start(); |
| 480 | $controller->index($args, $content); |
| 481 | return ob_get_clean(); |
| 482 | } |
| 483 | |
| 484 | static $buffer = NULL; |
| 485 | static $buffer_callback = NULL; |
| 486 | |
| 487 | /** |
| 488 | * Dispatch admin page: call corresponding controller based on get parameter `page` |
| 489 | * The method is called twice: 1st time as handler `parse_header` action and then as admin menu item handler |
| 490 | * @param string[optional] $page When $page set to empty string ealier buffered content is outputted, otherwise controller is called based on $page value |
| 491 | */ |
| 492 | public function adminDispatcher($page = '', $action = 'index') { |
| 493 | if ('' === $page) { |
| 494 | if ( ! is_null(self::$buffer)) { |
| 495 | echo '<div class="wrap">'; |
| 496 | echo self::$buffer; |
| 497 | do_action('pmxi_action_after'); |
| 498 | echo '</div>'; |
| 499 | } elseif ( ! is_null(self::$buffer_callback)) { |
| 500 | echo '<div class="wrap">'; |
| 501 | call_user_func(self::$buffer_callback); |
| 502 | do_action('pmxi_action_after'); |
| 503 | echo '</div>'; |
| 504 | } else { |
| 505 | throw new Exception('There is no previousely buffered content to display.'); |
| 506 | } |
| 507 | } |
| 508 | } |
| 509 | |
| 510 | public function replace_callback($matches){ |
| 511 | return strtoupper($matches[0]); |
| 512 | } |
| 513 | |
| 514 | protected $_admin_current_screen = NULL; |
| 515 | public function getAdminCurrentScreen() |
| 516 | { |
| 517 | return $this->_admin_current_screen; |
| 518 | } |
| 519 | |
| 520 | /** |
| 521 | * Autoloader |
| 522 | * It's assumed class name consists of prefix folloed by its name which in turn corresponds to location of source file |
| 523 | * if `_` symbols replaced by directory path separator. File name consists of prefix folloed by last part in class name (i.e. |
| 524 | * symbols after last `_` in class name) |
| 525 | * When class has prefix it's source is looked in `models`, `controllers`, `shortcodes` folders, otherwise it looked in `core` or `library` folder |
| 526 | * |
| 527 | * @param string $className |
| 528 | * @return bool |
| 529 | */ |
| 530 | public function __autoload($className) { |
| 531 | $is_prefix = false; |
| 532 | $filePath = str_replace('_', '/', preg_replace('%^' . preg_quote(self::PREFIX, '%') . '%', '', strtolower($className), 1, $is_prefix)) . '.php'; |
| 533 | if ( ! $is_prefix) { // also check file with original letter case |
| 534 | $filePathAlt = $className . '.php'; |
| 535 | } |
| 536 | foreach ($is_prefix ? array('models', 'controllers', 'shortcodes', 'classes') : array('libraries') as $subdir) { |
| 537 | $path = self::ROOT_DIR . '/' . $subdir . '/' . $filePath; |
| 538 | if (is_file($path)) { |
| 539 | require $path; |
| 540 | return TRUE; |
| 541 | } |
| 542 | if ( ! $is_prefix) { |
| 543 | $pathAlt = self::ROOT_DIR . '/' . $subdir . '/' . $filePathAlt; |
| 544 | if (is_file($pathAlt)) { |
| 545 | require $pathAlt; |
| 546 | return TRUE; |
| 547 | } |
| 548 | } |
| 549 | } |
| 550 | |
| 551 | return FALSE; |
| 552 | } |
| 553 | |
| 554 | /** |
| 555 | * Get plugin option |
| 556 | * @param string[optional] $option Parameter to return, all array of options is returned if not set |
| 557 | * @return mixed |
| 558 | */ |
| 559 | public function getOption($option = NULL) { |
| 560 | if (is_null($option)) { |
| 561 | return $this->options; |
| 562 | } else if (isset($this->options[$option])) { |
| 563 | return $this->options[$option]; |
| 564 | } else { |
| 565 | throw new Exception("Specified option is not defined for the plugin"); |
| 566 | } |
| 567 | } |
| 568 | /** |
| 569 | * Update plugin option value |
| 570 | * @param string $option Parameter name or array of name => value pairs |
| 571 | * @param mixed[optional] $value New value for the option, if not set than 1st parameter is supposed to be array of name => value pairs |
| 572 | * @return array |
| 573 | */ |
| 574 | public function updateOption($option, $value = NULL) { |
| 575 | is_null($value) or $option = array($option => $value); |
| 576 | if (array_diff_key($option, $this->options)) { |
| 577 | throw new Exception("Specified option is not defined for the plugin"); |
| 578 | } |
| 579 | $this->options = $option + $this->options; |
| 580 | update_option(get_class($this) . '_Options', $this->options); |
| 581 | |
| 582 | return $this->options; |
| 583 | } |
| 584 | |
| 585 | /** |
| 586 | * Plugin activation logic |
| 587 | */ |
| 588 | public function __activation() { |
| 589 | // uncaught exception doesn't prevent plugin from being activated, therefore replace it with fatal error so it does |
| 590 | set_exception_handler(create_function('$e', 'trigger_error($e->getMessage(), E_USER_ERROR);')); |
| 591 | |
| 592 | // create plugin options |
| 593 | $option_name = get_class($this) . '_Options'; |
| 594 | $options_default = PMXI_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray(); |
| 595 | $wpai_options = get_option($option_name, false); |
| 596 | if ( ! $wpai_options ) update_option($option_name, $options_default); |
| 597 | |
| 598 | // create/update required database tables |
| 599 | require_once ABSPATH . 'wp-admin/includes/upgrade.php'; |
| 600 | require self::ROOT_DIR . '/schema.php'; |
| 601 | global $wpdb; |
| 602 | |
| 603 | if (function_exists('is_multisite') && is_multisite()) { |
| 604 | // check if it is a network activation - if so, run the activation function for each blog id |
| 605 | if (isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) { |
| 606 | $old_blog = $wpdb->blogid; |
| 607 | // Get all blog ids |
| 608 | $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs"); |
| 609 | foreach ($blogids as $blog_id) { |
| 610 | switch_to_blog($blog_id); |
| 611 | require self::ROOT_DIR . '/schema.php'; |
| 612 | dbDelta($plugin_queries); |
| 613 | |
| 614 | // sync data between plugin tables and wordpress (mostly for the case when plugin is reactivated) |
| 615 | |
| 616 | $post = new PMXI_Post_Record(); |
| 617 | $wpdb->query('DELETE FROM ' . $post->getTable() . ' WHERE post_id NOT IN (SELECT ID FROM ' . $wpdb->posts . ')'); |
| 618 | } |
| 619 | switch_to_blog($old_blog); |
| 620 | return; |
| 621 | } |
| 622 | } |
| 623 | |
| 624 | dbDelta($plugin_queries); |
| 625 | |
| 626 | // sync data between plugin tables and wordpress (mostly for the case when plugin is reactivated) |
| 627 | |
| 628 | $post = new PMXI_Post_Record(); |
| 629 | $wpdb->query('DELETE FROM ' . $post->getTable() . ' WHERE post_id NOT IN (SELECT ID FROM ' . $wpdb->posts . ')'); |
| 630 | |
| 631 | } |
| 632 | |
| 633 | /** |
| 634 | * Load Localisation files. |
| 635 | * |
| 636 | * Note: the first-loaded translation file overrides any following ones if the same translation is present |
| 637 | * |
| 638 | * @access public |
| 639 | * @return void |
| 640 | */ |
| 641 | public function load_plugin_textdomain() { |
| 642 | $locale = apply_filters( 'plugin_locale', get_locale(), 'pmxi_plugin' ); |
| 643 | |
| 644 | load_plugin_textdomain( 'pmxi_plugin', false, dirname( plugin_basename( __FILE__ ) ) . "/i18n/languages" ); |
| 645 | } |
| 646 | |
| 647 | public function __fix_db_schema(){ |
| 648 | |
| 649 | $uploads = wp_upload_dir(); |
| 650 | |
| 651 | if ( ! is_dir($uploads['basedir'] . '/wpallimport/logs') or ! is_writable($uploads['basedir'] . '/wpallimport/logs')) { |
| 652 | die(sprintf(__('Uploads folder %s must be writable', 'pmxi_plugin'), $uploads['basedir'] . '/wpallimport/logs')); |
| 653 | } |
| 654 | |
| 655 | if ( ! is_dir($uploads['basedir'] . '/wpallimport') or ! is_writable($uploads['basedir'] . '/wpallimport')) { |
| 656 | die(sprintf(__('Uploads folder %s must be writable', 'pmxi_plugin'), $uploads['basedir'] . '/wpallimport')); |
| 657 | } |
| 658 | |
| 659 | $table = $table = $this->getTablePrefix() . 'files'; |
| 660 | global $wpdb; |
| 661 | $tablefields = $wpdb->get_results("DESCRIBE {$table};"); |
| 662 | // For every field in the table |
| 663 | foreach ($tablefields as $tablefield) { |
| 664 | if ('contents' == $tablefield->Field) { |
| 665 | $list = new PMXI_File_List(); |
| 666 | for ($i = 1; $list->getBy(NULL, 'id', $i, 1)->count(); $i++) { |
| 667 | foreach ($list->convertRecords() as $file) { |
| 668 | $file->save(); // resave file for file to be stored in uploads folder |
| 669 | } |
| 670 | } |
| 671 | |
| 672 | $wpdb->query("ALTER TABLE {$table} DROP " . $tablefield->Field); |
| 673 | break; |
| 674 | } |
| 675 | } |
| 676 | |
| 677 | $table = $this->getTablePrefix() . 'imports'; |
| 678 | |
| 679 | $tablefields = $wpdb->get_results("DESCRIBE {$table};"); |
| 680 | $parent_import_id = false; |
| 681 | $iteration = false; |
| 682 | $deleted = false; |
| 683 | $executing = false; |
| 684 | $canceled = false; |
| 685 | $canceled_on = false; |
| 686 | $failed = false; |
| 687 | $failed_on = false; |
| 688 | $settings_update_on = false; |
| 689 | $last_activity = false; |
| 690 | |
| 691 | // Check if field exists |
| 692 | foreach ($tablefields as $tablefield) { |
| 693 | if ('parent_import_id' == $tablefield->Field) $parent_import_id = true; |
| 694 | if ('iteration' == $tablefield->Field) $iteration = true; |
| 695 | if ('deleted' == $tablefield->Field) $deleted = true; |
| 696 | if ('executing' == $tablefield->Field) $executing = true; |
| 697 | if ('canceled' == $tablefield->Field) $canceled = true; |
| 698 | if ('canceled_on' == $tablefield->Field) $canceled_on = true; |
| 699 | if ('failed' == $tablefield->Field) $failed = true; |
| 700 | if ('failed_on' == $tablefield->Field) $failed_on = true; |
| 701 | if ('settings_update_on' == $tablefield->Field) $settings_update_on = true; |
| 702 | if ('last_activity' == $tablefield->Field) $last_activity = true; |
| 703 | } |
| 704 | |
| 705 | if (!$parent_import_id) $wpdb->query("ALTER TABLE {$table} ADD `parent_import_id` BIGINT(20) NOT NULL DEFAULT 0;"); |
| 706 | if (!$iteration) $wpdb->query("ALTER TABLE {$table} ADD `iteration` BIGINT(20) NOT NULL DEFAULT 0;"); |
| 707 | if (!$deleted) $wpdb->query("ALTER TABLE {$table} ADD `deleted` BIGINT(20) NOT NULL DEFAULT 0;"); |
| 708 | if (!$executing) $wpdb->query("ALTER TABLE {$table} ADD `executing` BOOL NOT NULL DEFAULT 0;"); |
| 709 | if (!$canceled) $wpdb->query("ALTER TABLE {$table} ADD `canceled` BOOL NOT NULL DEFAULT 0;"); |
| 710 | if (!$canceled_on) $wpdb->query("ALTER TABLE {$table} ADD `canceled_on` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00';"); |
| 711 | if (!$failed) $wpdb->query("ALTER TABLE {$table} ADD `failed` BOOL NOT NULL DEFAULT 0;"); |
| 712 | if (!$failed_on) $wpdb->query("ALTER TABLE {$table} ADD `failed_on` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00';"); |
| 713 | if (!$settings_update_on) $wpdb->query("ALTER TABLE {$table} ADD `settings_update_on` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00';"); |
| 714 | if (!$last_activity) $wpdb->query("ALTER TABLE {$table} ADD `last_activity` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00';"); |
| 715 | |
| 716 | $table = $this->getTablePrefix() . 'posts'; |
| 717 | $tablefields = $wpdb->get_results("DESCRIBE {$table};"); |
| 718 | $iteration = false; |
| 719 | |
| 720 | // Check if field exists |
| 721 | foreach ($tablefields as $tablefield) { |
| 722 | if ('iteration' == $tablefield->Field) $iteration = true; |
| 723 | } |
| 724 | |
| 725 | if (!$iteration) $wpdb->query("ALTER TABLE {$table} ADD `iteration` BIGINT(20) NOT NULL DEFAULT 0;"); |
| 726 | |
| 727 | if ( ! empty($wpdb->charset)) |
| 728 | $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset"; |
| 729 | if ( ! empty($wpdb->collate)) |
| 730 | $charset_collate .= " COLLATE $wpdb->collate"; |
| 731 | |
| 732 | $table_prefix = $this->getTablePrefix(); |
| 733 | |
| 734 | $wpdb->query("CREATE TABLE IF NOT EXISTS {$table_prefix}history ( |
| 735 | id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, |
| 736 | import_id BIGINT(20) UNSIGNED NOT NULL, |
| 737 | type ENUM('manual','processing','trigger','continue','') NOT NULL DEFAULT '', |
| 738 | time_run TEXT, |
| 739 | date DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', |
| 740 | summary TEXT, |
| 741 | PRIMARY KEY (id) |
| 742 | ) $charset_collate;"); |
| 743 | } |
| 744 | |
| 745 | /** |
| 746 | * Method returns default import options, main utility of the method is to avoid warnings when new |
| 747 | * option is introduced but already registered imports don't have it |
| 748 | */ |
| 749 | public static function get_default_import_options() { |
| 750 | return array( |
| 751 | 'type' => 'post', |
| 752 | 'wizard_type' => 'new', |
| 753 | 'custom_type' => '', |
| 754 | 'featured_delim' => ',', |
| 755 | 'atch_delim' => ',', |
| 756 | 'post_taxonomies' => array(), |
| 757 | 'parent' => 0, |
| 758 | 'order' => 0, |
| 759 | 'status' => 'publish', |
| 760 | 'page_template' => 'default', |
| 761 | 'page_taxonomies' => array(), |
| 762 | 'date_type' => 'specific', |
| 763 | 'date' => 'now', |
| 764 | 'date_start' => 'now', |
| 765 | 'date_end' => 'now', |
| 766 | 'custom_name' => array(), |
| 767 | 'custom_value' => array(), |
| 768 | 'custom_format' => array(), |
| 769 | 'custom_mapping' => array(), |
| 770 | 'serialized_values' => array(), |
| 771 | 'custom_mapping_rules' => array(), |
| 772 | 'comment_status' => 'open', |
| 773 | 'ping_status' => 'open', |
| 774 | 'create_draft' => 'no', |
| 775 | 'author' => '', |
| 776 | 'post_excerpt' => '', |
| 777 | 'post_slug' => '', |
| 778 | 'attachments' => '', |
| 779 | 'is_import_specified' => 0, |
| 780 | 'import_specified' => '', |
| 781 | 'is_delete_source' => 0, |
| 782 | 'is_cloak' => 0, |
| 783 | 'unique_key' => '', |
| 784 | 'tmp_unique_key' => '', |
| 785 | 'feed_type' => 'auto', |
| 786 | |
| 787 | 'create_new_records' => 1, |
| 788 | 'is_delete_missing' => 0, |
| 789 | 'set_missing_to_draft' => 0, |
| 790 | 'is_update_missing_cf' => 0, |
| 791 | 'update_missing_cf_name' => '', |
| 792 | 'update_missing_cf_value' => '', |
| 793 | |
| 794 | 'is_keep_former_posts' => 'no', |
| 795 | 'is_update_status' => 1, |
| 796 | 'is_update_content' => 1, |
| 797 | 'is_update_title' => 1, |
| 798 | 'is_update_slug' => 1, |
| 799 | 'is_update_excerpt' => 1, |
| 800 | 'is_update_categories' => 1, |
| 801 | 'is_update_author' => 1, |
| 802 | 'update_categories_logic' => 'full_update', |
| 803 | 'taxonomies_list' => array(), |
| 804 | 'taxonomies_only_list' => array(), |
| 805 | 'taxonomies_except_list' => array(), |
| 806 | 'is_update_attachments' => 1, |
| 807 | 'is_update_images' => 1, |
| 808 | 'update_images_logic' => 'full_update', |
| 809 | 'is_update_dates' => 1, |
| 810 | 'is_update_menu_order' => 1, |
| 811 | 'is_update_parent' => 1, |
| 812 | 'is_keep_attachments' => 0, |
| 813 | 'is_keep_imgs' => 0, |
| 814 | |
| 815 | 'is_update_custom_fields' => 1, |
| 816 | 'update_custom_fields_logic' => 'full_update', |
| 817 | 'custom_fields_list' => array(), |
| 818 | 'custom_fields_only_list' => array(), |
| 819 | 'custom_fields_except_list' => array(), |
| 820 | |
| 821 | 'duplicate_matching' => 'auto', |
| 822 | 'duplicate_indicator' => 'title', |
| 823 | 'custom_duplicate_name' => '', |
| 824 | 'custom_duplicate_value' => '', |
| 825 | 'is_update_previous' => 0, |
| 826 | 'is_scheduled' => '', |
| 827 | 'scheduled_period' => '', |
| 828 | 'friendly_name' => '', |
| 829 | 'records_per_request' => 20, |
| 830 | 'auto_rename_images' => 0, |
| 831 | 'auto_rename_images_suffix' => '', |
| 832 | 'images_name' => 'filename', |
| 833 | 'post_format' => 'standard', |
| 834 | 'encoding' => 'UTF-8', |
| 835 | 'delimiter' => '', |
| 836 | 'image_meta_title' => '', |
| 837 | 'image_meta_title_delim' => ',', |
| 838 | 'image_meta_caption' => '', |
| 839 | 'image_meta_caption_delim' => ',', |
| 840 | 'image_meta_alt' => '', |
| 841 | 'image_meta_alt_delim' => ',', |
| 842 | 'image_meta_description' => '', |
| 843 | 'image_meta_description_delim' => ',', |
| 844 | 'status_xpath' => '', |
| 845 | 'download_images' => 'yes', |
| 846 | 'converted_options' => 0, |
| 847 | 'update_all_data' => 'yes', |
| 848 | 'is_fast_mode' => 0, |
| 849 | 'chuncking' => 1, |
| 850 | 'import_processing' => 'ajax', |
| 851 | |
| 852 | 'title' => '', |
| 853 | 'content' => '', |
| 854 | 'name' => '', |
| 855 | 'is_keep_linebreaks' => 0, |
| 856 | 'is_leave_html' => 0, |
| 857 | 'fix_characters' => 0, |
| 858 | |
| 859 | 'featured_image' => '', |
| 860 | 'download_featured_image' => '', |
| 861 | 'download_featured_delim' => ',', |
| 862 | 'is_featured' => 1, |
| 863 | 'set_image_meta_title' => 0, |
| 864 | 'set_image_meta_caption' => 0, |
| 865 | 'set_image_meta_alt' => 0, |
| 866 | 'set_image_meta_description' => 0, |
| 867 | 'auto_set_extension' => 0, |
| 868 | 'new_extension' => '', |
| 869 | 'tax_logic' => array(), |
| 870 | 'tax_assing' => array(), |
| 871 | 'tax_single_xpath' => array(), |
| 872 | 'tax_multiple_xpath' => array(), |
| 873 | 'tax_hierarchical_xpath' => array(), |
| 874 | 'tax_multiple_delim' => array(), |
| 875 | 'tax_hierarchical_delim' => array(), |
| 876 | 'tax_hierarchical_logic' => array(), |
| 877 | 'tax_enable_mapping' => array(), |
| 878 | 'tax_mapping' => array(), |
| 879 | 'nested_files' => array() |
| 880 | ); |
| 881 | } |
| 882 | |
| 883 | /* |
| 884 | * Convert csv to xml |
| 885 | */ |
| 886 | public static function csv_to_xml($csv_url){ |
| 887 | |
| 888 | include_once(self::ROOT_DIR.'/libraries/XmlImportCsvParse.php'); |
| 889 | |
| 890 | $csv = new PMXI_CsvParser($csv_url); |
| 891 | |
| 892 | $wp_uploads = wp_upload_dir(); |
| 893 | $tmpname = wp_unique_filename($wp_uploads['path'], str_replace("csv", "xml", basename($csv_url))); |
| 894 | $xml_file = $wp_uploads['path'] .'/'. $tmpname; |
| 895 | file_put_contents($xml_file, $csv->toXML()); |
| 896 | return $xml_file; |
| 897 | |
| 898 | } |
| 899 | |
| 900 | public static function is_ajax(){ |
| 901 | return strpos($_SERVER["HTTP_ACCEPT"], 'json') !== false; |
| 902 | } |
| 903 | |
| 904 | } |
| 905 | |
| 906 | PMXI_Plugin::getInstance(); |
| 907 |