PluginProbe
WP All Export – Drag & Drop Export to Any Custom CSV, XML & Excel / 1.0.1
WP All Export – Drag & Drop Export to Any Custom CSV, XML & Excel v1.0.1
trunk 0.9.0 0.9.1 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2.0 1.2.1 1.2.10 1.2.2 1.2.3 1.2.4 All 57 releases
wp-all-export / wp-all-export.php
wp-all-export.php
607 lines 20.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: WP All Export
4 Plugin URI: http://www.wpallimport.com/export/
5 Description: Export any post type to a CSV or XML file. Edit the exported data, and then re-import it later using WP All Import.
6 Version: 1.0.1
7 Author: Soflyy
8 */
9
10 if( ! defined( 'PMXE_SESSION_COOKIE' ) )
11 define( 'PMXE_SESSION_COOKIE', '_pmxe_session' );
12
13 /**
14 * Plugin root dir with forward slashes as directory separator regardless of actuall DIRECTORY_SEPARATOR value
15 * @var string
16 */
17 define('PMXE_ROOT_DIR', str_replace('\\', '/', dirname(__FILE__)));
18 /**
19 * Plugin root url for referencing static content
20 * @var string
21 */
22 define('PMXE_ROOT_URL', rtrim(plugin_dir_url(__FILE__), '/'));
23
24 if ( class_exists('PMXE_Plugin') and PMXE_EDITION == "paid"){
25
26 function pmxe_notice(){
27
28 ?>
29 <div class="error">
30 <p>
31 <?php printf(__('Please de-activate and remove the free version of the WP All Export before activating the paid version.', 'wp_all_export_plugin')); ?>
32 </p>
33 </div>
34 <?php
35
36 deactivate_plugins( str_replace('\\', '/', dirname(__FILE__)) . '/wp-all-export.php');
37
38 }
39
40 add_action('admin_notices', 'pmxe_notice');
41
42 }
43 else {
44
45 /**
46 * Plugin prefix for making names unique (be aware that this variable is used in conjuction with naming convention,
47 * i.e. in order to change it one must not only modify this constant but also rename all constants, classes and functions which
48 * names composed using this prefix)
49 * @var string
50 */
51 define('PMXE_PREFIX', 'pmxe_');
52
53 define('PMXE_VERSION', '1.0.1');
54
55 define('PMXE_EDITION', 'free');
56
57 /**
58 * Plugin root uploads folder name
59 * @var string
60 */
61 define('WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY', 'wpallexport');
62 /**
63 * Plugin uploads folder name
64 * @var string
65 */
66 define('WP_ALL_EXPORT_UPLOADS_DIRECTORY', WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'exports');
67
68 /**
69 * Plugin temp folder name
70 * @var string
71 */
72 define('WP_ALL_EXPORT_TEMP_DIRECTORY', WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'temp');
73
74 /**
75 * Plugin temp folder name
76 * @var string
77 */
78 define('WP_ALL_EXPORT_CRON_DIRECTORY', WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'exports');
79
80 /**
81 * Main plugin file, Introduces MVC pattern
82 *
83 * @singletone
84 * @author Pavel Kulbakin <p.kulbakin@gmail.com>
85 */
86 final class PMXE_Plugin {
87 /**
88 * Singletone instance
89 * @var PMXE_Plugin
90 */
91 protected static $instance;
92
93 /**
94 * Plugin options
95 * @var array
96 */
97 protected $options = array();
98
99 /**
100 * Plugin root dir
101 * @var string
102 */
103 const ROOT_DIR = PMXE_ROOT_DIR;
104 /**
105 * Plugin root URL
106 * @var string
107 */
108 const ROOT_URL = PMXE_ROOT_URL;
109 /**
110 * Prefix used for names of shortcodes, action handlers, filter functions etc.
111 * @var string
112 */
113 const PREFIX = PMXE_PREFIX;
114 /**
115 * Plugin file path
116 * @var string
117 */
118 const FILE = __FILE__;
119 /**
120 * Max allowed file size (bytes) to import in default mode
121 * @var int
122 */
123 const LARGE_SIZE = 0; // all files will importing in large import mode
124
125 /**
126 * WP All Import temp folder
127 * @var string
128 */
129 const TEMP_DIRECTORY = WP_ALL_EXPORT_TEMP_DIRECTORY;
130 /**
131 * WP All Import uploads folder
132 * @var string
133 */
134 const UPLOADS_DIRECTORY = WP_ALL_EXPORT_UPLOADS_DIRECTORY;
135 /**
136 * WP All Import uploads folder
137 * @var string
138 */
139 const CRON_DIRECTORY = WP_ALL_EXPORT_CRON_DIRECTORY;
140
141 public static $session = null;
142
143 /**
144 * Return singletone instance
145 * @return PMXE_Plugin
146 */
147 static public function getInstance() {
148 if (self::$instance == NULL) {
149 self::$instance = new self();
150 }
151 return self::$instance;
152 }
153
154 static public function getEddName(){
155 return 'WP All Export';
156 }
157
158 /**
159 * Common logic for requestin plugin info fields
160 */
161 public function __call($method, $args) {
162 if (preg_match('%^get(.+)%i', $method, $mtch)) {
163 $info = get_plugin_data(self::FILE);
164 if (isset($info[$mtch[1]])) {
165 return $info[$mtch[1]];
166 }
167 }
168 throw new Exception("Requested method " . get_class($this) . "::$method doesn't exist.");
169 }
170
171 /**
172 * Get path to plagin dir relative to wordpress root
173 * @param bool[optional] $noForwardSlash Whether path should be returned withot forwarding slash
174 * @return string
175 */
176 public function getRelativePath($noForwardSlash = false) {
177 $wp_root = str_replace('\\', '/', ABSPATH);
178 return ($noForwardSlash ? '' : '/') . str_replace($wp_root, '', self::ROOT_DIR);
179 }
180
181 /**
182 * Check whether plugin is activated as network one
183 * @return bool
184 */
185 public function isNetwork() {
186 if ( !is_multisite() )
187 return false;
188
189 $plugins = get_site_option('active_sitewide_plugins');
190 if (isset($plugins[plugin_basename(self::FILE)]))
191 return true;
192
193 return false;
194 }
195
196 /**
197 * Check whether permalinks is enabled
198 * @return bool
199 */
200 public function isPermalinks() {
201 global $wp_rewrite;
202
203 return $wp_rewrite->using_permalinks();
204 }
205
206 /**
207 * Return prefix for plugin database tables
208 * @return string
209 */
210 public function getTablePrefix() {
211 global $wpdb;
212
213 //return ($this->isNetwork() ? $wpdb->base_prefix : $wpdb->prefix) . self::PREFIX;
214 return $wpdb->prefix . self::PREFIX;
215 }
216
217 /**
218 * Return prefix for wordpress database tables
219 * @return string
220 */
221 public function getWPPrefix() {
222 global $wpdb;
223 return ($this->isNetwork()) ? $wpdb->base_prefix : $wpdb->prefix;
224 }
225
226 /**
227 * Class constructor containing dispatching logic
228 * @param string $rootDir Plugin root dir
229 * @param string $pluginFilePath Plugin main file
230 */
231 protected function __construct() {
232
233 $this->load_plugin_textdomain();
234
235 // regirster autoloading method
236 if (function_exists('__autoload') and ! in_array('__autoload', spl_autoload_functions())) { // make sure old way of autoloading classes is not broken
237 spl_autoload_register('__autoload');
238 }
239 spl_autoload_register(array($this, '__autoload'));
240
241 // register helpers
242 if (is_dir(self::ROOT_DIR . '/helpers')) foreach (PMXE_Helper::safe_glob(self::ROOT_DIR . '/helpers/*.php', PMXE_Helper::GLOB_RECURSE | PMXE_Helper::GLOB_PATH) as $filePath) {
243 require_once $filePath;
244 }
245
246 // init plugin options
247 $option_name = get_class($this) . '_Options';
248 $options_default = PMXE_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray();
249 $this->options = array_intersect_key(get_option($option_name, array()), $options_default) + $options_default;
250 $this->options = array_intersect_key($options_default, array_flip(array('info_api_url'))) + $this->options; // make sure hidden options apply upon plugin reactivation
251 if ('' == $this->options['cron_job_key']) $this->options['cron_job_key'] = wp_all_export_url_title(wp_all_export_rand_char(12));
252
253 update_option($option_name, $this->options);
254 $this->options = get_option(get_class($this) . '_Options');
255 register_activation_hook(self::FILE, array($this, '__activation'));
256
257 // register action handlers
258 if (is_dir(self::ROOT_DIR . '/actions')) if (is_dir(self::ROOT_DIR . '/actions')) foreach (PMXE_Helper::safe_glob(self::ROOT_DIR . '/actions/*.php', PMXE_Helper::GLOB_RECURSE | PMXE_Helper::GLOB_PATH) as $filePath) {
259 require_once $filePath;
260 $function = $actionName = basename($filePath, '.php');
261 if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
262 $actionName = $m[1];
263 $priority = intval($m[2]);
264 } else {
265 $priority = 10;
266 }
267 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)
268 }
269
270 // register filter handlers
271 if (is_dir(self::ROOT_DIR . '/filters')) foreach (PMXE_Helper::safe_glob(self::ROOT_DIR . '/filters/*.php', PMXE_Helper::GLOB_RECURSE | PMXE_Helper::GLOB_PATH) as $filePath) {
272 require_once $filePath;
273 $function = $actionName = basename($filePath, '.php');
274 if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
275 $actionName = $m[1];
276 $priority = intval($m[2]);
277 } else {
278 $priority = 10;
279 }
280 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)
281 }
282
283 // register shortcodes handlers
284 if (is_dir(self::ROOT_DIR . '/shortcodes')) foreach (PMXE_Helper::safe_glob(self::ROOT_DIR . '/shortcodes/*.php', PMXE_Helper::GLOB_RECURSE | PMXE_Helper::GLOB_PATH) as $filePath) {
285 $tag = strtolower(str_replace('/', '_', preg_replace('%^' . preg_quote(self::ROOT_DIR . '/shortcodes/', '%') . '|\.php$%', '', $filePath)));
286 add_shortcode($tag, array($this, 'shortcodeDispatcher'));
287 }
288
289 // register admin page pre-dispatcher
290 add_action('admin_init', array($this, '__adminInit'));
291 }
292
293 /**
294 * pre-dispatching logic for admin page controllers
295 */
296 public function __adminInit() {
297
298 // create history folder
299 $uploads = wp_upload_dir();
300
301 $wpallimportDirs = array( WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY, self::TEMP_DIRECTORY, self::UPLOADS_DIRECTORY, self::CRON_DIRECTORY);
302
303 foreach ($wpallimportDirs as $destination) {
304
305 $dir = $uploads['basedir'] . DIRECTORY_SEPARATOR . $destination;
306
307 if ( !is_dir($dir)) wp_mkdir_p($dir);
308
309 if ( ! @file_exists($dir . DIRECTORY_SEPARATOR . 'index.php') ) @touch( $dir . DIRECTORY_SEPARATOR . 'index.php' );
310
311 }
312
313 if ( ! is_dir($uploads['basedir'] . DIRECTORY_SEPARATOR . WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY) or ! is_writable($uploads['basedir'] . DIRECTORY_SEPARATOR . WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY)) {
314 die(sprintf(__('Uploads folder %s must be writable', 'wp_all_export_plugin'), $uploads['basedir'] . DIRECTORY_SEPARATOR . WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY));
315 }
316
317 if ( ! is_dir($uploads['basedir'] . DIRECTORY_SEPARATOR . self::UPLOADS_DIRECTORY) or ! is_writable($uploads['basedir'] . DIRECTORY_SEPARATOR . self::UPLOADS_DIRECTORY)) {
318 die(sprintf(__('Uploads folder %s must be writable', 'wp_all_export_plugin'), $uploads['basedir'] . DIRECTORY_SEPARATOR . self::UPLOADS_DIRECTORY));
319 }
320
321 self::$session = new PMXE_Handler();
322
323 $input = new PMXE_Input();
324 $page = strtolower($input->getpost('page', ''));
325
326 if (preg_match('%^' . preg_quote(str_replace('_', '-', self::PREFIX), '%') . '([\w-]+)$%', $page)) {
327 //$this->adminDispatcher($page, strtolower($input->getpost('action', 'index')));
328
329 $action = strtolower($input->getpost('action', 'index'));
330
331 // capitalize prefix and first letters of class name parts
332 if (function_exists('preg_replace_callback')){
333 $controllerName = preg_replace_callback('%(^' . preg_quote(self::PREFIX, '%') . '|_).%', array($this, "replace_callback"),str_replace('-', '_', $page));
334 }
335 else{
336 $controllerName = preg_replace('%(^' . preg_quote(self::PREFIX, '%') . '|_).%e', 'strtoupper("$0")', str_replace('-', '_', $page));
337 }
338 $actionName = str_replace('-', '_', $action);
339 if (method_exists($controllerName, $actionName)) {
340
341 if ( ! get_current_user_id() or ! current_user_can('manage_options')) {
342 // This nonce is not valid.
343 die( 'Security check' );
344
345 } else {
346
347 $this->_admin_current_screen = (object)array(
348 'id' => $controllerName,
349 'base' => $controllerName,
350 'action' => $actionName,
351 'is_ajax' => strpos($_SERVER["HTTP_ACCEPT"], 'json') !== false,
352 'is_network' => is_network_admin(),
353 'is_user' => is_user_admin(),
354 );
355 add_filter('current_screen', array($this, 'getAdminCurrentScreen'));
356 add_filter('admin_body_class', create_function('', 'return "' . 'wpallexport-plugin";'));
357
358 $controller = new $controllerName();
359 if ( ! $controller instanceof PMXE_Controller_Admin) {
360 throw new Exception("Administration page `$page` matches to a wrong controller type.");
361 }
362
363 if ($this->_admin_current_screen->is_ajax) { // ajax request
364 $controller->$action();
365 do_action('wpallexport_action_after');
366 die(); // stop processing since we want to output only what controller is randered, nothing in addition
367 } elseif ( ! $controller->isInline) {
368 @ob_start();
369 $controller->$action();
370 self::$buffer = @ob_get_clean();
371 } else {
372 self::$buffer_callback = array($controller, $action);
373 }
374 }
375
376 } else { // redirect to dashboard if requested page and/or action don't exist
377 wp_redirect(admin_url()); die();
378 }
379
380 }
381 }
382
383 /**
384 * Dispatch shorttag: create corresponding controller instance and call its index method
385 * @param array $args Shortcode tag attributes
386 * @param string $content Shortcode tag content
387 * @param string $tag Shortcode tag name which is being dispatched
388 * @return string
389 */
390 public function shortcodeDispatcher($args, $content, $tag) {
391
392 $controllerName = self::PREFIX . preg_replace('%(^|_).%e', 'strtoupper("$0")', $tag); // capitalize first letters of class name parts and add prefix
393 $controller = new $controllerName();
394 if ( ! $controller instanceof PMXE_Controller) {
395 throw new Exception("Shortcode `$tag` matches to a wrong controller type.");
396 }
397 ob_start();
398 $controller->index($args, $content);
399 return ob_get_clean();
400 }
401
402 static $buffer = NULL;
403 static $buffer_callback = NULL;
404
405 /**
406 * Dispatch admin page: call corresponding controller based on get parameter `page`
407 * The method is called twice: 1st time as handler `parse_header` action and then as admin menu item handler
408 * @param string[optional] $page When $page set to empty string ealier buffered content is outputted, otherwise controller is called based on $page value
409 */
410 public function adminDispatcher($page = '', $action = 'index') {
411 if ('' === $page) {
412 if ( ! is_null(self::$buffer)) {
413 echo '<div class="wrap">';
414 echo self::$buffer;
415 do_action('wpallexport_action_after');
416 echo '</div>';
417 } elseif ( ! is_null(self::$buffer_callback)) {
418 echo '<div class="wrap">';
419 call_user_func(self::$buffer_callback);
420 do_action('wpallexport_action_after');
421 echo '</div>';
422 } else {
423 throw new Exception('There is no previousely buffered content to display.');
424 }
425 }
426 }
427
428 public function replace_callback($matches){
429 return strtoupper($matches[0]);
430 }
431
432 protected $_admin_current_screen = NULL;
433 public function getAdminCurrentScreen()
434 {
435 return $this->_admin_current_screen;
436 }
437
438 /**
439 * Autoloader
440 * It's assumed class name consists of prefix folloed by its name which in turn corresponds to location of source file
441 * if `_` symbols replaced by directory path separator. File name consists of prefix folloed by last part in class name (i.e.
442 * symbols after last `_` in class name)
443 * When class has prefix it's source is looked in `models`, `controllers`, `shortcodes` folders, otherwise it looked in `core` or `library` folder
444 *
445 * @param string $className
446 * @return bool
447 */
448 public function __autoload($className) {
449 $is_prefix = false;
450 $filePath = str_replace('_', '/', preg_replace('%^' . preg_quote(self::PREFIX, '%') . '%', '', strtolower($className), 1, $is_prefix)) . '.php';
451 if ( ! $is_prefix) { // also check file with original letter case
452 $filePathAlt = $className . '.php';
453 }
454 foreach ($is_prefix ? array('models', 'controllers', 'shortcodes', 'classes') : array('libraries') as $subdir) {
455 $path = self::ROOT_DIR . '/' . $subdir . '/' . $filePath;
456 if (is_file($path)) {
457 require $path;
458 return TRUE;
459 }
460 if ( ! $is_prefix) {
461 $pathAlt = self::ROOT_DIR . '/' . $subdir . '/' . $filePathAlt;
462 if (is_file($pathAlt)) {
463 require $pathAlt;
464 return TRUE;
465 }
466 }
467 }
468
469 return FALSE;
470 }
471
472 /**
473 * Get plugin option
474 * @param string[optional] $option Parameter to return, all array of options is returned if not set
475 * @return mixed
476 */
477 public function getOption($option = NULL) {
478 if (is_null($option)) {
479 return $this->options;
480 } else if (isset($this->options[$option])) {
481 return $this->options[$option];
482 } else {
483 throw new Exception("Specified option is not defined for the plugin");
484 }
485 }
486 /**
487 * Update plugin option value
488 * @param string $option Parameter name or array of name => value pairs
489 * @param mixed[optional] $value New value for the option, if not set than 1st parameter is supposed to be array of name => value pairs
490 * @return array
491 */
492 public function updateOption($option, $value = NULL) {
493 is_null($value) or $option = array($option => $value);
494 if (array_diff_key($option, $this->options)) {
495 throw new Exception("Specified option is not defined for the plugin");
496 }
497 $this->options = $option + $this->options;
498 update_option(get_class($this) . '_Options', $this->options);
499
500 return $this->options;
501 }
502
503 /**
504 * Plugin activation logic
505 */
506 public function __activation() {
507 // uncaught exception doesn't prevent plugin from being activated, therefore replace it with fatal error so it does
508 set_exception_handler(create_function('$e', 'trigger_error($e->getMessage(), E_USER_ERROR);'));
509
510 // create plugin options
511 $option_name = get_class($this) . '_Options';
512 $options_default = PMXE_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray();
513 $wpai_options = get_option($option_name, false);
514 if ( ! $wpai_options ) update_option($option_name, $options_default);
515
516 // create/update required database tables
517 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
518 require self::ROOT_DIR . '/schema.php';
519 global $wpdb;
520
521 if (function_exists('is_multisite') && is_multisite()) {
522 // check if it is a network activation - if so, run the activation function for each blog id
523 if (isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
524 $old_blog = $wpdb->blogid;
525 // Get all blog ids
526 $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
527 foreach ($blogids as $blog_id) {
528 switch_to_blog($blog_id);
529 require self::ROOT_DIR . '/schema.php';
530 dbDelta($plugin_queries);
531 }
532 switch_to_blog($old_blog);
533 return;
534 }
535 }
536
537 dbDelta($plugin_queries);
538
539 }
540
541 /**
542 * Load Localisation files.
543 *
544 * Note: the first-loaded translation file overrides any following ones if the same translation is present
545 *
546 * @access public
547 * @return void
548 */
549 public function load_plugin_textdomain() {
550 $locale = apply_filters( 'plugin_locale', get_locale(), 'wp_all_export_plugin' );
551
552 load_plugin_textdomain( 'wp_all_export_plugin', false, dirname( plugin_basename( __FILE__ ) ) . "/i18n/languages" );
553 }
554
555 /**
556 * Method returns default import options, main utility of the method is to avoid warnings when new
557 * option is introduced but already registered imports don't have it
558 */
559 public static function get_default_import_options() {
560 return array(
561 'cpt' => array(),
562 'whereclause' => '',
563 'joinclause' => '',
564 'filter_rules_hierarhy' => '',
565 'product_matching_mode' => 'strict',
566 'order_item_per_row' => 1,
567 'filepath' => '',
568 'export_type' => 'specific',
569 'wp_query' => '',
570 'wp_query_selector' => 'wp_query',
571 'is_user_export' => false,
572 'export_to' => 'csv',
573 'delimiter' => ',',
574 'encoding' => 'UTF-8',
575 'is_generate_templates' => 1,
576 'is_generate_import' => 1,
577 'import_id' => 0,
578 'template_name' => '',
579 'is_scheduled' => 0,
580 'scheduled_period' => '',
581 'scheduled_email' => '',
582 'cc_label' => array(),
583 'cc_type' => array(),
584 'cc_value' => array(),
585 'cc_name' => array(),
586 'cc_php' => array(),
587 'cc_code' => array(),
588 'cc_sql' => array(),
589 'cc_options' => array(),
590 'friendly_name' => '',
591 'fields' => array('default', 'other', 'cf', 'cats'),
592 'ids' => array(),
593 'rules' => array(),
594 'records_per_iteration' => 50
595 );
596 }
597
598 public static function is_ajax(){
599 return (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') ? true : false ;
600 }
601
602 }
603
604 PMXE_Plugin::getInstance();
605
606 }
607