PluginProbe ʕ •ᴥ•ʔ
WP All Import – Drag & Drop Import for CSV, XML, Excel & Google Sheets / 2.13
WP All Import – Drag & Drop Import for CSV, XML, Excel & Google Sheets v2.13
3.9.5 3.9.6 4.0.0 4.0.1 4.1.0 trunk 2.12 2.13 2.14 3.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6 3.4.7 3.4.8 3.4.9 3.5.0 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.5.6 3.5.7 3.5.8 3.5.9 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.6.9 3.7.0 3.7.1 3.7.2 3.7.3 3.7.3-beta-1.0 3.7.4 3.7.4-beta-1.0 3.7.5 3.7.6 3.7.7 3.7.8 3.7.9 3.8.0 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4
wp-all-import / plugin.php
wp-all-import Last commit date
actions 13 years ago classes 13 years ago config 13 years ago controllers 13 years ago filters 13 years ago helpers 13 years ago history 13 years ago libraries 13 years ago models 13 years ago shortcodes 13 years ago static 13 years ago upload 13 years ago views 13 years ago plugin.php 13 years ago readme.txt 13 years ago schema.php 13 years ago
plugin.php
487 lines
1 <?php
2 /*
3 Plugin Name: WP All Import
4 Plugin URI: http://www.wpallimport.com/upgrade-to-pro
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. Perform scheduled updates and overwrite of existing import jobs. Free lite edition.
6 Version: 2.13
7 Author: Soflyy
8 */
9 /**
10 * Plugin root dir with forward slashes as directory separator regardless of actuall DIRECTORY_SEPARATOR value
11 * @var string
12 */
13 define('PMXI_ROOT_DIR', str_replace('\\', '/', dirname(__FILE__)));
14 /**
15 * Plugin root url for referencing static content
16 * @var string
17 */
18 define('PMXI_ROOT_URL', rtrim(plugin_dir_url(__FILE__), '/'));
19 /**
20 * Plugin prefix for making names unique (be aware that this variable is used in conjuction with naming convention,
21 * i.e. in order to change it one must not only modify this constant but also rename all constants, classes and functions which
22 * names composed using this prefix)
23 * @var string
24 */
25 define('PMXI_PREFIX', 'pmxi_');
26
27 /**
28 * Main plugin file, Introduces MVC pattern
29 *
30 * @singletone
31 * @author Pavel Kulbakin <p.kulbakin@gmail.com>
32 */
33 final class PMXI_Plugin {
34 /**
35 * Singletone instance
36 * @var PMXI_Plugin
37 */
38 protected static $instance;
39
40 /**
41 * Plugin options
42 * @var array
43 */
44 protected $options = array();
45
46 /**
47 * Plugin root dir
48 * @var string
49 */
50 const ROOT_DIR = PMXI_ROOT_DIR;
51 /**
52 * Plugin root URL
53 * @var string
54 */
55 const ROOT_URL = PMXI_ROOT_URL;
56 /**
57 * Prefix used for names of shortcodes, action handlers, filter functions etc.
58 * @var string
59 */
60 const PREFIX = PMXI_PREFIX;
61 /**
62 * Plugin file path
63 * @var string
64 */
65 const FILE = __FILE__;
66
67 public static $csv_mimes = array('text/comma-separated-values','text/csv','application/csv','application/excel','application/vnd.ms-excel','application/vnd.msexcel','text/anytext', 'text/plain');
68
69 /**
70 * Return singletone instance
71 * @return PMXI_Plugin
72 */
73 static public function getInstance() {
74 if (self::$instance == NULL) {
75 self::$instance = new self();
76 }
77 return self::$instance;
78 }
79
80 /**
81 * Common logic for requestin plugin info fields
82 */
83 public function __call($method, $args) {
84 if (preg_match('%^get(.+)%i', $method, $mtch)) {
85 $info = get_plugin_data(self::FILE);
86 if (isset($info[$mtch[1]])) {
87 return $info[$mtch[1]];
88 }
89 }
90 throw new Exception("Requested method " . get_class($this) . "::$method doesn't exist.");
91 }
92
93 /**
94 * Get path to plagin dir relative to wordpress root
95 * @param bool[optional] $noForwardSlash Whether path should be returned withot forwarding slash
96 * @return string
97 */
98 public function getRelativePath($noForwardSlash = false) {
99 $wp_root = str_replace('\\', '/', ABSPATH);
100 return ($noForwardSlash ? '' : '/') . str_replace($wp_root, '', self::ROOT_DIR);
101 }
102
103 /**
104 * Check whether plugin is activated as network one
105 * @return bool
106 */
107 public function isNetwork() {
108 if ( !is_multisite() )
109 return false;
110
111 $plugins = get_site_option('active_sitewide_plugins');
112 if (isset($plugins[plugin_basename(self::FILE)]))
113 return true;
114
115 return false;
116 }
117
118 /**
119 * Check whether permalinks is enabled
120 * @return bool
121 */
122 public function isPermalinks() {
123 global $wp_rewrite;
124
125 return $wp_rewrite->using_permalinks();
126 }
127
128 /**
129 * Return prefix for plugin database tables
130 * @return string
131 */
132 public function getTablePrefix() {
133 global $wpdb;
134 return ($this->isNetwork() ? $wpdb->base_prefix : $wpdb->prefix) . self::PREFIX;
135 }
136
137 /**
138 * Class constructor containing dispatching logic
139 * @param string $rootDir Plugin root dir
140 * @param string $pluginFilePath Plugin main file
141 */
142 protected function __construct() {
143 // regirster autoloading method
144 if (function_exists('__autoload') and ! in_array('__autoload', spl_autoload_functions())) { // make sure old way of autoloading classes is not broken
145 spl_autoload_register('__autoload');
146 }
147 spl_autoload_register(array($this, '__autoload'));
148
149 // register helpers
150 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) {
151 require_once $filePath;
152 }
153
154 // init plugin options
155 $option_name = get_class($this) . '_Options';
156 $options_default = PMXI_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray();
157 $this->options = array_intersect_key(get_option($option_name, array()), $options_default) + $options_default;
158 $this->options = array_intersect_key($options_default, array_flip(array('info_api_url'))) + $this->options; // make sure hidden options apply upon plugin reactivation
159 update_option($option_name, $this->options);
160 $this->options = get_option(get_class($this) . '_Options');
161
162 register_activation_hook(self::FILE, array($this, '__activation'));
163
164 // register action handlers
165 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) {
166 require_once $filePath;
167 $function = $actionName = basename($filePath, '.php');
168 if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
169 $actionName = $m[1];
170 $priority = intval($m[2]);
171 } else {
172 $priority = 10;
173 }
174 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)
175 }
176
177 // register filter handlers
178 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) {
179 require_once $filePath;
180 $function = $actionName = basename($filePath, '.php');
181 if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
182 $actionName = $m[1];
183 $priority = intval($m[2]);
184 } else {
185 $priority = 10;
186 }
187 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)
188 }
189
190 // register shortcodes handlers
191 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) {
192 $tag = strtolower(str_replace('/', '_', preg_replace('%^' . preg_quote(self::ROOT_DIR . '/shortcodes/', '%') . '|\.php$%', '', $filePath)));
193 add_shortcode($tag, array($this, 'shortcodeDispatcher'));
194 }
195
196 // register admin page pre-dispatcher
197 add_action('admin_init', array($this, '__adminInit'));
198
199 }
200
201 /**
202 * pre-dispatching logic for admin page controllers
203 */
204 public function __adminInit() {
205 $input = new PMXI_Input();
206 $page = strtolower($input->getpost('page', ''));
207 if (preg_match('%^' . preg_quote(str_replace('_', '-', self::PREFIX), '%') . '([\w-]+)$%', $page)) {
208 $this->adminDispatcher($page, strtolower($input->getpost('action', 'index')));
209 }
210 }
211
212 /**
213 * Dispatch shorttag: create corresponding controller instance and call its index method
214 * @param array $args Shortcode tag attributes
215 * @param string $content Shortcode tag content
216 * @param string $tag Shortcode tag name which is being dispatched
217 * @return string
218 */
219 public function shortcodeDispatcher($args, $content, $tag) {
220
221 $controllerName = self::PREFIX . preg_replace('%(^|_).%e', 'strtoupper("$0")', $tag); // capitalize first letters of class name parts and add prefix
222 $controller = new $controllerName();
223 if ( ! $controller instanceof PMXI_Controller) {
224 throw new Exception("Shortcode `$tag` matches to a wrong controller type.");
225 }
226 ob_start();
227 $controller->index($args, $content);
228 return ob_get_clean();
229 }
230
231 /**
232 * Dispatch admin page: call corresponding controller based on get parameter `page`
233 * The method is called twice: 1st time as handler `parse_header` action and then as admin menu item handler
234 * @param string[optional] $page When $page set to empty string ealier buffered content is outputted, otherwise controller is called based on $page value
235 */
236 public function adminDispatcher($page = '', $action = 'index') {
237 static $buffer = NULL;
238 static $buffer_callback = NULL;
239 if ('' === $page) {
240 if ( ! is_null($buffer)) {
241 echo '<div class="wrap">';
242 echo $buffer;
243 do_action('pmxi_action_after');
244 echo '</div>';
245 } elseif ( ! is_null($buffer_callback)) {
246 echo '<div class="wrap">';
247 call_user_func($buffer_callback);
248 do_action('pmxi_action_after');
249 echo '</div>';
250 } else {
251 throw new Exception('There is no previousely buffered content to display.');
252 }
253 } else {
254 $controllerName = preg_replace('%(^' . preg_quote(self::PREFIX, '%') . '|_).%e', 'strtoupper("$0")', str_replace('-', '_', $page)); // capitalize prefix and first letters of class name parts
255 $actionName = str_replace('-', '_', $action);
256 if (method_exists($controllerName, $actionName)) {
257 $this->_admin_current_screen = (object)array(
258 'id' => $controllerName,
259 'base' => $controllerName,
260 'action' => $actionName,
261 'is_ajax' => isset($_SERVER['HTTP_X_REQUESTED_WITH']) and strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest',
262 'is_network' => is_network_admin(),
263 'is_user' => is_user_admin(),
264 );
265 add_filter('current_screen', array($this, 'getAdminCurrentScreen'));
266 add_filter('admin_body_class', create_function('', 'return "' . PMXI_Plugin::PREFIX . 'plugin";'));
267
268 $controller = new $controllerName();
269 if ( ! $controller instanceof PMXI_Controller_Admin) {
270 throw new Exception("Administration page `$page` matches to a wrong controller type.");
271 }
272
273 if ($this->_admin_current_screen->is_ajax) { // ajax request
274 $controller->$action();
275 do_action('pmxi_action_after');
276 die(); // stop processing since we want to output only what controller is randered, nothing in addition
277 } elseif ( ! $controller->isInline) {
278 ob_start();
279 $controller->$action();
280 $buffer = ob_get_clean();
281 } else {
282 $buffer_callback = array($controller, $action);
283 }
284 } else { // redirect to dashboard if requested page and/or action don't exist
285 wp_redirect(admin_url()); die();
286 }
287 }
288 }
289
290 protected $_admin_current_screen = NULL;
291 public function getAdminCurrentScreen()
292 {
293 return $this->_admin_current_screen;
294 }
295
296 /**
297 * Autoloader
298 * It's assumed class name consists of prefix folloed by its name which in turn corresponds to location of source file
299 * if `_` symbols replaced by directory path separator. File name consists of prefix folloed by last part in class name (i.e.
300 * symbols after last `_` in class name)
301 * When class has prefix it's source is looked in `models`, `controllers`, `shortcodes` folders, otherwise it looked in `core` or `library` folder
302 *
303 * @param string $className
304 * @return bool
305 */
306 public function __autoload($className) {
307 $is_prefix = false;
308 $filePath = str_replace('_', '/', preg_replace('%^' . preg_quote(self::PREFIX, '%') . '%', '', strtolower($className), 1, $is_prefix)) . '.php';
309 if ( ! $is_prefix) { // also check file with original letter case
310 $filePathAlt = $className . '.php';
311 }
312 foreach ($is_prefix ? array('models', 'controllers', 'shortcodes', 'classes') : array('libraries') as $subdir) {
313 $path = self::ROOT_DIR . '/' . $subdir . '/' . $filePath;
314 if (is_file($path)) {
315 require $path;
316 return TRUE;
317 }
318 if ( ! $is_prefix) {
319 $pathAlt = self::ROOT_DIR . '/' . $subdir . '/' . $filePathAlt;
320 if (is_file($pathAlt)) {
321 require $pathAlt;
322 return TRUE;
323 }
324 }
325 }
326
327 return FALSE;
328 }
329
330 /**
331 * Get plugin option
332 * @param string[optional] $option Parameter to return, all array of options is returned if not set
333 * @return mixed
334 */
335 public function getOption($option = NULL) {
336 if (is_null($option)) {
337 return $this->options;
338 } else if (isset($this->options[$option])) {
339 return $this->options[$option];
340 } else {
341 throw new Exception("Specified option is not defined for the plugin");
342 }
343 }
344 /**
345 * Update plugin option value
346 * @param string $option Parameter name or array of name => value pairs
347 * @param mixed[optional] $value New value for the option, if not set than 1st parameter is supposed to be array of name => value pairs
348 * @return array
349 */
350 public function updateOption($option, $value = NULL) {
351 is_null($value) or $option = array($option => $value);
352 if (array_diff_key($option, $this->options)) {
353 throw new Exception("Specified option is not defined for the plugin");
354 }
355 $this->options = $option + $this->options;
356 update_option(get_class($this) . '_Options', $this->options);
357
358 return $this->options;
359 }
360
361 /**
362 * Plugin activation logic
363 */
364 public function __activation() {
365 // uncaught exception doesn't prevent plugin from being activated, therefore replace it with fatal error so it does
366 set_exception_handler(create_function('$e', 'trigger_error($e->getMessage(), E_USER_ERROR);'));
367
368 // create plugin options
369 $option_name = get_class($this) . '_Options';
370 $options_default = PMXI_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray();
371 update_option($option_name, $options_default);
372
373 // create/update required database tables
374 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
375 require self::ROOT_DIR . '/schema.php';
376 dbDelta($plugin_queries);
377
378 $this->__ver_1_04_transition_fix();
379
380 // sync data between plugin tables and wordpress (mostly for the case when plugin is reactivated)
381 global $wpdb;
382 $post = new PMXI_Post_Record();
383 $wpdb->query('DELETE FROM ' . $post->getTable() . ' WHERE post_id NOT IN (SELECT ID FROM ' . $wpdb->posts . ')');
384
385 }
386
387 /**
388 * Method perfoms transition from version when file history has been stored in dabase to the solution when it stored on disk
389 * NOTE: the function can be removed when plugin version progress and it's sure matter nobody has ver 1.03
390 */
391 public function __ver_1_04_transition_fix() {
392 if ( ! is_dir(self::ROOT_DIR . '/history') or ! is_writable(self::ROOT_DIR . '/history')) {
393 die(sprintf(__('History folder %s must be writable', 'pmxi_plugin'), self::ROOT_DIR . '/history'));
394 }
395
396 $table = $table = $this->getTablePrefix() . 'files';
397 global $wpdb;
398 $tablefields = $wpdb->get_results("DESCRIBE {$table};");
399 // For every field in the table
400 foreach ($tablefields as $tablefield) {
401 if ('contents' == $tablefield->Field) {
402 $list = new PMXI_File_List();
403 for ($i = 1; $list->getBy(NULL, 'id', $i, 1)->count(); $i++) {
404 foreach ($list->convertRecords() as $file) {
405 $file->save(); // resave file for file to be stored in history folder
406 }
407 }
408
409 $wpdb->query("ALTER TABLE {$table} DROP " . $tablefield->Field);
410 break;
411 }
412 }
413 }
414
415 /**
416 * Method returns default import options, main utility of the method is to avoid warnings when new
417 * option is introduced but already registered imports don't have it
418 */
419 public static function get_default_import_options() {
420 return array(
421 'type' => 'post',
422 'custom_type' => '',
423 'categories' => '',
424 'tags' => '',
425 'tags_delim' => ',',
426 'post_taxonomies' => array(),
427 'parent' => '',
428 'order' => '0',
429 'status' => 'publish',
430 'page_template' => 'default',
431 'page_taxonomies' => array(),
432 'date_type' => 'specific',
433 'date' => 'now',
434 'date_start' => 'now',
435 'date_end' => 'now',
436 'custom_name' => array(),
437 'custom_value' => array(),
438 'comment_status' => 'open',
439 'ping_status' => 'open',
440 'author' => wp_get_current_user()->ID,
441 'featured_image' => '',
442 'is_import_specified' => 0,
443 'import_specified' => '',
444 'is_delete_source' => 0,
445 'is_cloak' => 0,
446 'unique_key' => '',
447
448 'is_delete_missing' => 0,
449 'is_keep_former_posts' => 0,
450 'is_keep_status' => 0,
451 'is_keep_categories' => 0,
452 'is_keep_attachments' => 0,
453 'is_duplicates' => 0,
454
455 'duplicate_indicator' => 'title',
456 'duplicate_action' => 'keep',
457 'is_first_chank' => 0,
458 'is_update_previous' => 0,
459 'is_scheduled' => '',
460 'scheduled_period' => ''
461 );
462 }
463
464 /*
465 * Convert csv to xml using yahoo API
466 */
467 public static function csv_to_xml($csv_url){
468
469 include_once(self::ROOT_DIR.'/libraries/XmlImportCsvParse.php');
470
471 $csv = new PMXI_CsvParser($csv_url);
472
473 return $csv->toXML();
474
475 }
476 /*
477 *
478 * Detect CSV file
479 *
480 */
481 public static function detect_csv($type){
482 return in_array($type, self::$csv_mimes);
483 }
484 }
485
486 PMXI_Plugin::getInstance();
487