PluginProbe ʕ •ᴥ•ʔ
WP All Import – Drag & Drop Import for CSV, XML, Excel & Google Sheets / 2.12
WP All Import – Drag & Drop Import for CSV, XML, Excel & Google Sheets v2.12
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 screenshot-1.png 13 years ago screenshot-2.png 13 years ago screenshot-3.png 13 years ago screenshot-4.png 13 years ago
plugin.php
480 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.12
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 /**
68 * Return singletone instance
69 * @return PMXI_Plugin
70 */
71 static public function getInstance() {
72 if (self::$instance == NULL) {
73 self::$instance = new self();
74 }
75 return self::$instance;
76 }
77
78 /**
79 * Common logic for requestin plugin info fields
80 */
81 public function __call($method, $args) {
82 if (preg_match('%^get(.+)%i', $method, $mtch)) {
83 $info = get_plugin_data(self::FILE);
84 if (isset($info[$mtch[1]])) {
85 return $info[$mtch[1]];
86 }
87 }
88 throw new Exception("Requested method " . get_class($this) . "::$method doesn't exist.");
89 }
90
91 /**
92 * Get path to plagin dir relative to wordpress root
93 * @param bool[optional] $noForwardSlash Whether path should be returned withot forwarding slash
94 * @return string
95 */
96 public function getRelativePath($noForwardSlash = false) {
97 $wp_root = str_replace('\\', '/', ABSPATH);
98 return ($noForwardSlash ? '' : '/') . str_replace($wp_root, '', self::ROOT_DIR);
99 }
100
101 /**
102 * Check whether plugin is activated as network one
103 * @return bool
104 */
105 public function isNetwork() {
106 if ( !is_multisite() )
107 return false;
108
109 $plugins = get_site_option('active_sitewide_plugins');
110 if (isset($plugins[plugin_basename(self::FILE)]))
111 return true;
112
113 return false;
114 }
115
116 /**
117 * Check whether permalinks is enabled
118 * @return bool
119 */
120 public function isPermalinks() {
121 global $wp_rewrite;
122
123 return $wp_rewrite->using_permalinks();
124 }
125
126 /**
127 * Return prefix for plugin database tables
128 * @return string
129 */
130 public function getTablePrefix() {
131 global $wpdb;
132 return ($this->isNetwork() ? $wpdb->base_prefix : $wpdb->prefix) . self::PREFIX;
133 }
134
135 /**
136 * Class constructor containing dispatching logic
137 * @param string $rootDir Plugin root dir
138 * @param string $pluginFilePath Plugin main file
139 */
140 protected function __construct() {
141 // regirster autoloading method
142 if (function_exists('__autoload') and ! in_array('__autoload', spl_autoload_functions())) { // make sure old way of autoloading classes is not broken
143 spl_autoload_register('__autoload');
144 }
145 spl_autoload_register(array($this, '__autoload'));
146
147 // register helpers
148 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) {
149 require_once $filePath;
150 }
151
152 // init plugin options
153 $option_name = get_class($this) . '_Options';
154 $options_default = PMXI_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray();
155 $this->options = array_intersect_key(get_option($option_name, array()), $options_default) + $options_default;
156 $this->options = array_intersect_key($options_default, array_flip(array('info_api_url'))) + $this->options; // make sure hidden options apply upon plugin reactivation
157 update_option($option_name, $this->options);
158 $this->options = get_option(get_class($this) . '_Options');
159
160 register_activation_hook(self::FILE, array($this, '__activation'));
161
162 // register action handlers
163 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) {
164 require_once $filePath;
165 $function = $actionName = basename($filePath, '.php');
166 if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
167 $actionName = $m[1];
168 $priority = intval($m[2]);
169 } else {
170 $priority = 10;
171 }
172 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)
173 }
174
175 // register filter handlers
176 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) {
177 require_once $filePath;
178 $function = $actionName = basename($filePath, '.php');
179 if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
180 $actionName = $m[1];
181 $priority = intval($m[2]);
182 } else {
183 $priority = 10;
184 }
185 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)
186 }
187
188 // register shortcodes handlers
189 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) {
190 $tag = strtolower(str_replace('/', '_', preg_replace('%^' . preg_quote(self::ROOT_DIR . '/shortcodes/', '%') . '|\.php$%', '', $filePath)));
191 add_shortcode($tag, array($this, 'shortcodeDispatcher'));
192 }
193
194 // register admin page pre-dispatcher
195 add_action('admin_init', array($this, '__adminInit'));
196
197 }
198
199 /**
200 * pre-dispatching logic for admin page controllers
201 */
202 public function __adminInit() {
203 $input = new PMXI_Input();
204 $page = strtolower($input->getpost('page', ''));
205 if (preg_match('%^' . preg_quote(str_replace('_', '-', self::PREFIX), '%') . '([\w-]+)$%', $page)) {
206 $this->adminDispatcher($page, strtolower($input->getpost('action', 'index')));
207 }
208 }
209
210 /**
211 * Dispatch shorttag: create corresponding controller instance and call its index method
212 * @param array $args Shortcode tag attributes
213 * @param string $content Shortcode tag content
214 * @param string $tag Shortcode tag name which is being dispatched
215 * @return string
216 */
217 public function shortcodeDispatcher($args, $content, $tag) {
218
219 $controllerName = self::PREFIX . preg_replace('%(^|_).%e', 'strtoupper("$0")', $tag); // capitalize first letters of class name parts and add prefix
220 $controller = new $controllerName();
221 if ( ! $controller instanceof PMXI_Controller) {
222 throw new Exception("Shortcode `$tag` matches to a wrong controller type.");
223 }
224 ob_start();
225 $controller->index($args, $content);
226 return ob_get_clean();
227 }
228
229 /**
230 * Dispatch admin page: call corresponding controller based on get parameter `page`
231 * The method is called twice: 1st time as handler `parse_header` action and then as admin menu item handler
232 * @param string[optional] $page When $page set to empty string ealier buffered content is outputted, otherwise controller is called based on $page value
233 */
234 public function adminDispatcher($page = '', $action = 'index') {
235 static $buffer = NULL;
236 static $buffer_callback = NULL;
237 if ('' === $page) {
238 if ( ! is_null($buffer)) {
239 echo '<div class="wrap">';
240 echo $buffer;
241 do_action('pmxi_action_after');
242 echo '</div>';
243 } elseif ( ! is_null($buffer_callback)) {
244 echo '<div class="wrap">';
245 call_user_func($buffer_callback);
246 do_action('pmxi_action_after');
247 echo '</div>';
248 } else {
249 throw new Exception('There is no previousely buffered content to display.');
250 }
251 } else {
252 $controllerName = preg_replace('%(^' . preg_quote(self::PREFIX, '%') . '|_).%e', 'strtoupper("$0")', str_replace('-', '_', $page)); // capitalize prefix and first letters of class name parts
253 $actionName = str_replace('-', '_', $action);
254 if (method_exists($controllerName, $actionName)) {
255 $this->_admin_current_screen = (object)array(
256 'id' => $controllerName,
257 'base' => $controllerName,
258 'action' => $actionName,
259 'is_ajax' => isset($_SERVER['HTTP_X_REQUESTED_WITH']) and strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest',
260 'is_network' => is_network_admin(),
261 'is_user' => is_user_admin(),
262 );
263 add_filter('current_screen', array($this, 'getAdminCurrentScreen'));
264 add_filter('admin_body_class', create_function('', 'return "' . PMXI_Plugin::PREFIX . 'plugin";'));
265
266 $controller = new $controllerName();
267 if ( ! $controller instanceof PMXI_Controller_Admin) {
268 throw new Exception("Administration page `$page` matches to a wrong controller type.");
269 }
270
271 if ($this->_admin_current_screen->is_ajax) { // ajax request
272 $controller->$action();
273 do_action('pmxi_action_after');
274 die(); // stop processing since we want to output only what controller is randered, nothing in addition
275 } elseif ( ! $controller->isInline) {
276 ob_start();
277 $controller->$action();
278 $buffer = ob_get_clean();
279 } else {
280 $buffer_callback = array($controller, $action);
281 }
282 } else { // redirect to dashboard if requested page and/or action don't exist
283 wp_redirect(admin_url()); die();
284 }
285 }
286 }
287
288 protected $_admin_current_screen = NULL;
289 public function getAdminCurrentScreen()
290 {
291 return $this->_admin_current_screen;
292 }
293
294 /**
295 * Autoloader
296 * It's assumed class name consists of prefix folloed by its name which in turn corresponds to location of source file
297 * if `_` symbols replaced by directory path separator. File name consists of prefix folloed by last part in class name (i.e.
298 * symbols after last `_` in class name)
299 * When class has prefix it's source is looked in `models`, `controllers`, `shortcodes` folders, otherwise it looked in `core` or `library` folder
300 *
301 * @param string $className
302 * @return bool
303 */
304 public function __autoload($className) {
305 $is_prefix = false;
306 $filePath = str_replace('_', '/', preg_replace('%^' . preg_quote(self::PREFIX, '%') . '%', '', strtolower($className), 1, $is_prefix)) . '.php';
307 if ( ! $is_prefix) { // also check file with original letter case
308 $filePathAlt = $className . '.php';
309 }
310 foreach ($is_prefix ? array('models', 'controllers', 'shortcodes', 'classes') : array('libraries') as $subdir) {
311 $path = self::ROOT_DIR . '/' . $subdir . '/' . $filePath;
312 if (is_file($path)) {
313 require $path;
314 return TRUE;
315 }
316 if ( ! $is_prefix) {
317 $pathAlt = self::ROOT_DIR . '/' . $subdir . '/' . $filePathAlt;
318 if (is_file($pathAlt)) {
319 require $pathAlt;
320 return TRUE;
321 }
322 }
323 }
324
325 $this->__ver_2_06_load_options_add();
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 *
417 *
418 *
419 */
420 public function __ver_2_06_load_options_add() {
421 $table = $table = $this->getTablePrefix() . 'templates';
422 global $wpdb;
423 $wpdb->query("ALTER TABLE {$table} ADD options TEXT NOT NULL");
424 $wpdb->query("ALTER TABLE {$table} ADD scheduled VARCHAR(64) NOT NULL");
425 }
426
427 /**
428 * Method returns default import options, main utility of the method is to avoid warnings when new
429 * option is introduced but already registered imports don't have it
430 */
431 public static function get_default_import_options() {
432 return array(
433 'type' => 'post',
434 'custom_type' => '',
435 'categories' => '',
436 'categories_delim' => ',',
437 'tags' => '',
438 'tags_delim' => ',',
439 'post_taxonomies' => array(),
440 'post_taxonomies_delim' => array(),
441 'parent' => '',
442 'order' => '0',
443 'status' => 'publish',
444 'page_taxonomies' => array(),
445 'page_taxonomies_delim' => array(),
446 'date_type' => 'specific',
447 'date' => 'now',
448 'date_start' => 'now',
449 'date_end' => 'now',
450 'custom_name' => array(),
451 'custom_value' => array(),
452 'comment_status' => 'open',
453 'ping_status' => 'open',
454 'author' => wp_get_current_user()->ID,
455 'featured_image' => '',
456 'is_import_specified' => 0,
457 'import_specified' => '',
458 'is_delete_source' => 0,
459 'is_cloak' => 0,
460 'unique_key' => '',
461
462 'is_delete_missing' => 0,
463 'is_keep_former_posts' => 0,
464 'is_keep_status' => 0,
465 'is_keep_categories' => 0,
466 'is_keep_attachments' => 0,
467 'is_duplicates' => 0,
468
469 'duplicate_indicator' => 'title',
470 'duplicate_action' => 'keep',
471 'is_first_chank' => 0,
472 'is_update_previous' => 0,
473 'is_scheduled' => '',
474 'scheduled_period' => ''
475 );
476 }
477 }
478
479 PMXI_Plugin::getInstance();
480