PluginProbe ʕ •ᴥ•ʔ
WP All Export – Drag & Drop Export to Any Custom CSV, XML & Excel / 1.2.2
WP All Export – Drag & Drop Export to Any Custom CSV, XML & Excel v1.2.2
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 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 1.4.13 1.4.14 1.4.15 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0
wp-all-export / wp-all-export.php
wp-all-export Last commit date
actions 7 years ago classes 7 years ago config 7 years ago controllers 7 years ago dist 7 years ago filters 7 years ago frontend 7 years ago helpers 7 years ago history 7 years ago i18n 7 years ago libraries 7 years ago models 7 years ago sessions 7 years ago shortcodes 7 years ago src 7 years ago static 7 years ago views 7 years ago banner-772x250.png 7 years ago readme.txt 7 years ago schema.php 7 years ago screenshot-1.png 7 years ago screenshot-2.png 7 years ago wp-all-export.php 7 years ago wpae_api.php 7 years ago
wp-all-export.php
896 lines
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.2.2
7 Author: Soflyy
8 */
9
10 require_once(__DIR__.'/classes/CdataStrategyFactory.php');
11
12 if( ! defined( 'PMXE_SESSION_COOKIE' ) )
13 define( 'PMXE_SESSION_COOKIE', '_pmxe_session' );
14
15 // Enable error reporting in development
16 if(getenv('WPAE_DEV')) {
17 error_reporting(E_ALL ^ E_DEPRECATED );
18 ini_set('display_errors', 1);
19 // xdebug_disable();
20 }
21
22 /**
23 * Plugin root dir with forward slashes as directory separator regardless of actuall DIRECTORY_SEPARATOR value
24 * @var string
25 */
26 define('PMXE_ROOT_DIR', str_replace('\\', '/', dirname(__FILE__)));
27 /**
28 * Plugin root url for referencing static content
29 * @var string
30 */
31 define('PMXE_ROOT_URL', rtrim(plugin_dir_url(__FILE__), '/'));
32
33 if ( class_exists('PMXE_Plugin') and PMXE_EDITION == "paid"){
34
35 function pmxe_notice(){
36
37 ?>
38 <div class="error">
39 <p>
40 <?php printf(__('Please de-activate and remove the free version of the WP All Export before activating the paid version.', 'wp_all_export_plugin')); ?>
41 </p>
42 </div>
43 <?php
44
45 deactivate_plugins( str_replace('\\', '/', dirname(__FILE__)) . '/wp-all-export.php');
46
47 }
48
49 add_action('admin_notices', 'pmxe_notice');
50
51 }
52 else {
53
54 /**
55 * Plugin prefix for making names unique (be aware that this variable is used in conjuction with naming convention,
56 * i.e. in order to change it one must not only modify this constant but also rename all constants, classes and functions which
57 * names composed using this prefix)
58 * @var string
59 */
60 define('PMXE_PREFIX', 'pmxe_');
61
62 define('PMXE_VERSION', '1.2.2');
63
64 define('PMXE_EDITION', 'free');
65
66 /**
67 * Plugin root uploads folder name
68 * @var string
69 */
70 define('WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY', 'wpallexport');
71 /**
72 * Plugin uploads folder name
73 * @var string
74 */
75 define('WP_ALL_EXPORT_UPLOADS_DIRECTORY', WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'exports');
76
77 /**
78 * Plugin temp folder name
79 * @var string
80 */
81 define('WP_ALL_EXPORT_TEMP_DIRECTORY', WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'temp');
82
83 /**
84 * Plugin temp folder name
85 * @var string
86 */
87 define('WP_ALL_EXPORT_CRON_DIRECTORY', WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'exports');
88
89 /**
90 * Main plugin file, Introduces MVC pattern
91 *
92 * @singletone
93 * @author Pavel Kulbakin <p.kulbakin@gmail.com>
94 */
95 final class PMXE_Plugin {
96 /**
97 * Singletone instance
98 * @var PMXE_Plugin
99 */
100 protected static $instance;
101
102 /**
103 * Plugin options
104 * @var array
105 */
106 protected $options = array();
107
108 /**
109 * Plugin root dir
110 * @var string
111 */
112 const ROOT_DIR = PMXE_ROOT_DIR;
113 /**
114 * Plugin root URL
115 * @var string
116 */
117 const ROOT_URL = PMXE_ROOT_URL;
118 /**
119 * Prefix used for names of shortcodes, action handlers, filter functions etc.
120 * @var string
121 */
122 const PREFIX = PMXE_PREFIX;
123 /**
124 * Plugin file path
125 * @var string
126 */
127 const FILE = __FILE__;
128 /**
129 * Max allowed file size (bytes) to import in default mode
130 * @var int
131 */
132 const LARGE_SIZE = 0; // all files will importing in large import mode
133
134 /**
135 * WP All Import temp folder
136 * @var string
137 */
138 const TEMP_DIRECTORY = WP_ALL_EXPORT_TEMP_DIRECTORY;
139 /**
140 * WP All Import uploads folder
141 * @var string
142 */
143 const UPLOADS_DIRECTORY = WP_ALL_EXPORT_UPLOADS_DIRECTORY;
144 /**
145 * WP All Import uploads folder
146 * @var string
147 */
148 const CRON_DIRECTORY = WP_ALL_EXPORT_CRON_DIRECTORY;
149
150 const LANGUAGE_DOMAIN = 'wp_all_export_plugin';
151
152 public static $session = null;
153
154 public static $capabilities = 'manage_options';
155
156 private static $hasActiveSchedulingLicense = null;
157
158 public static $cache_key = '';
159
160 /**
161 * Class constructor containing dispatching logic
162 * @param string $rootDir Plugin root dir
163 * @param string $pluginFilePath Plugin main file
164 */
165 protected function __construct() {
166
167 require_once (self::ROOT_DIR . '/classes/installer.php');
168
169 $installer = new PMXE_Installer();
170 $installer->checkActivationConditions();
171
172 $plugin_basename = plugin_basename( __FILE__ );
173
174 self::$cache_key = md5( 'edd_plugin_' . sanitize_key( $plugin_basename ) . '_version_info' );
175
176 // uncaught exception doesn't prevent plugin from being activated, therefore replace it with fatal error so it does
177 //set_exception_handler(create_function('$e', 'trigger_error($e->getMessage(), E_USER_ERROR);'));
178
179 // register autoloading method
180 spl_autoload_register(array($this, 'autoload'));
181
182 // register helpers
183 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) {
184 require_once $filePath;
185 }
186
187 // init plugin options
188 $option_name = get_class($this) . '_Options';
189 $options_default = PMXE_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray();
190 $this->options = array_intersect_key(get_option($option_name, array()), $options_default) + $options_default;
191 $this->options = array_intersect_key($options_default, array_flip(array('info_api_url'))) + $this->options; // make sure hidden options apply upon plugin reactivation
192 if ('' == $this->options['cron_job_key']) $this->options['cron_job_key'] = wp_all_export_url_title(wp_all_export_rand_char(12));
193
194 update_option($option_name, $this->options);
195 $this->options = get_option(get_class($this) . '_Options');
196 register_activation_hook(self::FILE, array($this, 'activation'));
197
198 // register action handlers
199 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) {
200 require_once $filePath;
201 $function = $actionName = basename($filePath, '.php');
202 if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
203 $actionName = $m[1];
204 $priority = intval($m[2]);
205 } else {
206 $priority = 10;
207 }
208 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)
209 }
210
211 // register filter handlers
212 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) {
213 require_once $filePath;
214 $function = $actionName = basename($filePath, '.php');
215 if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
216 $actionName = $m[1];
217 $priority = intval($m[2]);
218 } else {
219 $priority = 10;
220 }
221 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)
222 }
223
224 // register shortcodes handlers
225 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) {
226 $tag = strtolower(str_replace('/', '_', preg_replace('%^' . preg_quote(self::ROOT_DIR . '/shortcodes/', '%') . '|\.php$%', '', $filePath)));
227 add_shortcode($tag, array($this, 'shortcodeDispatcher'));
228 }
229
230 // register admin page pre-dispatcher
231 add_action('admin_init', array($this, 'adminInit'));
232 add_action('admin_init', array($this, 'fix_db_schema'));
233 add_action('init', array($this, 'init'));
234 add_action( 'in_plugin_update_message-wp-all-export/wp-all-export.php', array($this, 'wpae_plugin_update_message'), 10, 2 );
235
236 }
237
238 /**
239 * Return singletone instance
240 * @return PMXE_Plugin
241 */
242 static public function getInstance() {
243 if (self::$instance == NULL) {
244 self::$instance = new self();
245 }
246 return self::$instance;
247 }
248
249 static public function getSchedulingName(){
250 return 'Automatic Scheduling';
251 }
252
253 static public function hasActiveSchedulingLicense() {
254
255 if(is_null(self::$hasActiveSchedulingLicense)) {
256 $scheduling = \Wpae\Scheduling\Scheduling::create();
257 $hasActiveSchedulingLicense = $scheduling->checkLicense();
258 self::$hasActiveSchedulingLicense = $hasActiveSchedulingLicense;
259 }
260
261 return self::$hasActiveSchedulingLicense;
262 }
263
264 /**
265 * Common logic for requestin plugin info fields
266 */
267 public function __call($method, $args) {
268 if (preg_match('%^get(.+)%i', $method, $mtch)) {
269 $info = get_plugin_data(self::FILE);
270 if (isset($info[$mtch[1]])) {
271 return $info[$mtch[1]];
272 }
273 }
274 throw new Exception("Requested method " . get_class($this) . "::$method doesn't exist.");
275 }
276
277 /**
278 * Get path to plagin dir relative to wordpress root
279 * @param bool[optional] $noForwardSlash Whether path should be returned withot forwarding slash
280 * @return string
281 */
282 public function getRelativePath($noForwardSlash = false) {
283 $wp_root = str_replace('\\', '/', ABSPATH);
284 return ($noForwardSlash ? '' : '/') . str_replace($wp_root, '', self::ROOT_DIR);
285 }
286
287 /**
288 * Check whether plugin is activated as network one
289 * @return bool
290 */
291 public function isNetwork() {
292 if ( !is_multisite() )
293 return false;
294
295 $plugins = get_site_option('active_sitewide_plugins');
296 if (isset($plugins[plugin_basename(self::FILE)]))
297 return true;
298
299 return false;
300 }
301
302 /**
303 * Check whether permalinks is enabled
304 * @return bool
305 */
306 public function isPermalinks() {
307 global $wp_rewrite;
308
309 return $wp_rewrite->using_permalinks();
310 }
311
312 /**
313 * Return prefix for plugin database tables
314 * @return string
315 */
316 public function getTablePrefix() {
317 global $wpdb;
318
319 //return ($this->isNetwork() ? $wpdb->base_prefix : $wpdb->prefix) . self::PREFIX;
320 return $wpdb->prefix . self::PREFIX;
321 }
322
323 /**
324 * Return prefix for wordpress database tables
325 * @return string
326 */
327 public function getWPPrefix() {
328 global $wpdb;
329 return ($this->isNetwork()) ? $wpdb->base_prefix : $wpdb->prefix;
330 }
331
332 public function init(){
333 $this->load_plugin_textdomain();
334 }
335
336 /**
337 * pre-dispatching logic for admin page controllers
338 */
339 public function adminInit() {
340
341 // create history folder
342 $uploads = wp_upload_dir();
343
344 $wpallimportDirs = array( WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY, self::TEMP_DIRECTORY, self::UPLOADS_DIRECTORY, self::CRON_DIRECTORY);
345
346 foreach ($wpallimportDirs as $destination) {
347
348 $dir = $uploads['basedir'] . DIRECTORY_SEPARATOR . $destination;
349
350 if ( !is_dir($dir)) wp_mkdir_p($dir);
351
352 if ( ! @file_exists($dir . DIRECTORY_SEPARATOR . 'index.php') ) @touch( $dir . DIRECTORY_SEPARATOR . 'index.php' );
353
354 }
355
356 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)) {
357 die(sprintf(__('Uploads folder %s must be writable', 'wp_all_export_plugin'), $uploads['basedir'] . DIRECTORY_SEPARATOR . WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY));
358 }
359
360 if ( ! is_dir($uploads['basedir'] . DIRECTORY_SEPARATOR . self::UPLOADS_DIRECTORY) or ! is_writable($uploads['basedir'] . DIRECTORY_SEPARATOR . self::UPLOADS_DIRECTORY)) {
361 die(sprintf(__('Uploads folder %s must be writable', 'wp_all_export_plugin'), $uploads['basedir'] . DIRECTORY_SEPARATOR . self::UPLOADS_DIRECTORY));
362 }
363
364 self::$session = new PMXE_Handler();
365
366 $input = new PMXE_Input();
367 $page = strtolower($input->getpost('page', ''));
368
369 if (preg_match('%^' . preg_quote(str_replace('_', '-', self::PREFIX), '%') . '([\w-]+)$%', $page)) {
370 //$this->adminDispatcher($page, strtolower($input->getpost('action', 'index')));
371
372 $action = strtolower($input->getpost('action', 'index'));
373
374 // capitalize prefix and first letters of class name parts
375 $controllerName = preg_replace_callback('%(^' . preg_quote(self::PREFIX, '%') . '|_).%', array($this, "replace_callback"),str_replace('-', '_', $page));
376 $actionName = str_replace('-', '_', $action);
377 if (method_exists($controllerName, $actionName)) {
378
379 if ( ! get_current_user_id() or ! current_user_can(self::$capabilities)) {
380 // This nonce is not valid.
381 die( 'Security check' );
382
383 } else {
384
385 $this->_admin_current_screen = (object)array(
386 'id' => $controllerName,
387 'base' => $controllerName,
388 'action' => $actionName,
389 'is_ajax' => strpos($_SERVER["HTTP_ACCEPT"], 'json') !== false,
390 'is_network' => is_network_admin(),
391 'is_user' => is_user_admin(),
392 );
393 add_filter('current_screen', array($this, 'getAdminCurrentScreen'));
394 add_filter('admin_body_class',
395 function() {
396 return 'wpallexport-plugin';
397 }
398 );
399
400 $controller = new $controllerName();
401 if ( ! $controller instanceof PMXE_Controller_Admin) {
402 throw new Exception("Administration page `$page` matches to a wrong controller type.");
403 }
404
405 if ($this->_admin_current_screen->is_ajax) { // ajax request
406 $controller->$action();
407 do_action('wpallexport_action_after');
408 die(); // stop processing since we want to output only what controller is randered, nothing in addition
409 } elseif ( ! $controller->isInline) {
410 @ob_start();
411 $controller->$action();
412 self::$buffer = @ob_get_clean();
413 } else {
414 self::$buffer_callback = array($controller, $action);
415 }
416 }
417
418 } else { // redirect to dashboard if requested page and/or action don't exist
419 wp_redirect(admin_url()); die();
420 }
421
422 }
423 }
424
425 function wpae_plugin_update_message( $data, $response ) {
426
427 if(version_compare($data['new_version'], '1.2.3') >= 0)
428 \_e("<br/><br/><strong>Important</strong> - Read This Before Installing
429 <br/><br/>
430 Some functionality in WP All Export has been moved to add-ons: WooCommerce Add-On and ACF Add-On. You'll need to install those add-ons to export that data. There's a little more to the story, and you can read all about it here: <a href=\"http://www.wpallimport.com/2018/11/export-add-ons/\" target=\"_blank\">Export Add-Ons</a>
431 <br/><br/>
432 This version of WP All Export will still export that data with or without the add-ons. However, a future version will completely remove support for exporting WooCommerce and ACF data unless you also have the appropriate add-ons installed.
433 <br/><br/>
434 Please submit a support request if you run in to any problems: <a href=\"http://www.wpallimport.com/support/\" target=\"_blank\">http://www.wpallimport.com/support/</a>", \PMXE_Plugin::LANGUAGE_DOMAIN);
435 }
436
437
438 /**
439 * Dispatch shorttag: create corresponding controller instance and call its index method
440 * @param array $args Shortcode tag attributes
441 * @param string $content Shortcode tag content
442 * @param string $tag Shortcode tag name which is being dispatched
443 * @return string
444 * @throws Exception
445 */
446 public function shortcodeDispatcher($args, $content, $tag) {
447
448 $controllerName = self::PREFIX . preg_replace_callback('%(^|_).%', array($this, "replace_callback"), $tag);// capitalize first letters of class name parts and add prefix
449 $controller = new $controllerName();
450 if ( ! $controller instanceof PMXE_Controller) {
451 throw new Exception("Shortcode `$tag` matches to a wrong controller type.");
452 }
453 ob_start();
454 $controller->index($args, $content);
455 return ob_get_clean();
456 }
457
458 static $buffer = NULL;
459 static $buffer_callback = NULL;
460
461 /**
462 * Dispatch admin page: call corresponding controller based on get parameter `page`
463 * The method is called twice: 1st time as handler `parse_header` action and then as admin menu item handler
464 * @param string $page
465 * @param string $action
466 * @throws Exception
467 * @internal param $string [optional] $page When $page set to empty string ealier buffered content is outputted, otherwise controller is called based on $page value
468 */
469 public function adminDispatcher($page = '', $action = 'index') {
470 if ('' === $page) {
471 if ( ! is_null(self::$buffer)) {
472 echo '<div class="wrap">';
473 echo self::$buffer;
474 do_action('wpallexport_action_after');
475 echo '</div>';
476 } elseif ( ! is_null(self::$buffer_callback)) {
477 echo '<div class="wrap">';
478 call_user_func(self::$buffer_callback);
479 do_action('wpallexport_action_after');
480 echo '</div>';
481 } else {
482 throw new Exception('There is no previousely buffered content to display.');
483 }
484 }
485 }
486
487 public function replace_callback($matches){
488 return strtoupper($matches[0]);
489 }
490
491 protected $_admin_current_screen = NULL;
492 public function getAdminCurrentScreen()
493 {
494 return $this->_admin_current_screen;
495 }
496
497 /**
498 * Autoloader
499 * It's assumed class name consists of prefix folloed by its name which in turn corresponds to location of source file
500 * if `_` symbols replaced by directory path separator. File name consists of prefix folloed by last part in class name (i.e.
501 * symbols after last `_` in class name)
502 * When class has prefix it's source is looked in `models`, `controllers`, `shortcodes` folders, otherwise it looked in `core` or `library` folder
503 *
504 * @param string $className
505 * @return bool
506 */
507 public function autoload($className) {
508
509 $is_prefix = false;
510 $filePath = str_replace('_', '/', preg_replace('%^' . preg_quote(self::PREFIX, '%') . '%', '', strtolower($className), 1, $is_prefix)) . '.php';
511 if ( ! $is_prefix) { // also check file with original letter case
512 $filePathAlt = $className . '.php';
513 }
514 foreach ($is_prefix ? array('models', 'controllers', 'shortcodes', 'classes') : array('libraries') as $subdir) {
515 $path = self::ROOT_DIR . '/' . $subdir . '/' . $filePath;
516 if (is_file($path)) {
517 require_once $path;
518 return TRUE;
519 }
520 if ( ! $is_prefix) {
521 $pathAlt = self::ROOT_DIR . '/' . $subdir . '/' . $filePathAlt;
522 if(strpos($className, '_') !== false) {
523 $pathAlt = $this->lreplace('_',DIRECTORY_SEPARATOR, $pathAlt);
524 }
525 if (is_file($pathAlt)) {
526 require_once $pathAlt;
527 return TRUE;
528 }
529 }
530 }
531 if($className === 'CdataStrategyFactory') {
532 //TODO: Move this to a namespace
533 require_once (self::ROOT_DIR . '/classes/CdataStrategyFactory.php');
534 }
535
536
537 if(strpos($className, '\\') !== false){
538
539 // project-specific namespace prefix
540 $prefix = 'Wpae\\';
541
542 // base directory for the namespace prefix
543 $base_dir = self::ROOT_DIR . '/src/';
544
545 // does the class use the namespace prefix?
546 $len = strlen($prefix);
547 if (strncmp($prefix, $className, $len) !== 0) {
548 // no, move to the next registered autoloader
549 return;
550 }
551
552 // get the relative class name
553 $relative_class = substr($className, $len);
554
555 // replace the namespace prefix with the base directory, replace namespace
556 // separators with directory separators in the relative class name, append
557 // with .php
558 $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
559
560 // if the file exists, require it
561 if (file_exists($file)) {
562 require_once $file;
563 }
564 }
565
566 return FALSE;
567 }
568
569 /**
570 * Get plugin option
571 * @param string [optional] $option Parameter to return, all array of options is returned if not set
572 * @return mixed
573 * @throws Exception
574 */
575 public function getOption($option = NULL) {
576 $options = apply_filters('wp_all_export_config_options', $this->options);
577 if (is_null($option)) {
578 return $options;
579 } else if (isset($options[$option])) {
580 return $options[$option];
581 } else {
582 throw new Exception("Specified option is not defined for the plugin");
583 }
584 }
585
586 /**
587 * Update plugin option value
588 * @param string $option Parameter name or array of name => value pairs
589 * @param null $value
590 * @return array
591 * @throws Exception
592 * @internal param $mixed [optional] $value New value for the option, if not set than 1st parameter is supposed to be array of name => value pairs
593 */
594 public function updateOption($option, $value = NULL) {
595 is_null($value) or $option = array($option => $value);
596 if (array_diff_key($option, $this->options)) {
597 throw new Exception("Specified option is not defined for the plugin");
598 }
599 $this->options = $option + $this->options;
600 update_option(get_class($this) . '_Options', $this->options);
601
602 return $this->options;
603 }
604
605 /**
606 * Plugin activation logic
607 */
608 public function activation() {
609 // uncaught exception doesn't prevent plugin from being activated, therefore replace it with fatal error so it does
610 set_exception_handler(function($e) {trigger_error($e->getMessage(), E_USER_ERROR); });
611
612 // create plugin options
613 $option_name = get_class($this) . '_Options';
614 $options_default = PMXE_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray();
615 $wpai_options = get_option($option_name, false);
616 if ( ! $wpai_options ) update_option($option_name, $options_default);
617
618 // create/update required database tables
619 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
620 require self::ROOT_DIR . '/schema.php';
621 global $wpdb;
622
623 if (function_exists('is_multisite') && is_multisite()) {
624 // check if it is a network activation - if so, run the activation function for each blog id
625 if (isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
626 $old_blog = $wpdb->blogid;
627 // Get all blog ids
628 $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
629 foreach ($blogids as $blog_id) {
630 switch_to_blog($blog_id);
631 require self::ROOT_DIR . '/schema.php';
632 dbDelta($plugin_queries);
633 }
634 switch_to_blog($old_blog);
635 return;
636 }
637 }
638
639 dbDelta($plugin_queries);
640
641 }
642
643 /**
644 * Load Localisation files.
645 *
646 * Note: the first-loaded translation file overrides any following ones if the same translation is present
647 *
648 * @access public
649 * @return void
650 */
651 public function load_plugin_textdomain() {
652
653 $locale = apply_filters( 'plugin_locale', get_locale(), 'wp_all_export_plugin' );
654
655 load_plugin_textdomain( 'wp_all_export_plugin', false, dirname( plugin_basename( __FILE__ ) ) . "/i18n/languages" );
656 }
657
658 public function fix_db_schema(){
659
660 global $wpdb;
661 $installed_ver = get_option( "wp_all_export_db_version" );
662
663 if ( $installed_ver == PMXE_VERSION ) return true;
664
665 if ( ! empty($wpdb->charset))
666 $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
667 if ( ! empty($wpdb->collate))
668 $charset_collate .= " COLLATE $wpdb->collate";
669
670 $table_prefix = $this->getTablePrefix();
671
672 $wpdb->query("CREATE TABLE IF NOT EXISTS {$table_prefix}templates (
673 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
674 name VARCHAR(200) NOT NULL DEFAULT '',
675 options LONGTEXT,
676 PRIMARY KEY (id)
677 ) $charset_collate;");
678
679 $wpdb->query("CREATE TABLE IF NOT EXISTS {$table_prefix}posts (
680 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
681 post_id BIGINT(20) UNSIGNED NOT NULL,
682 export_id BIGINT(20) UNSIGNED NOT NULL,
683 iteration BIGINT(20) NOT NULL DEFAULT 0,
684 PRIMARY KEY (id)
685 ) $charset_collate;");
686
687 $googleCatsTableExists = $wpdb->query("SHOW TABLES LIKE '{$table_prefix}google_cats'");
688 if(!$googleCatsTableExists) {
689 require_once self::ROOT_DIR . '/schema.php';
690 $wpdb->query($googleCatsQueryCreate);
691 $wpdb->query($googleCatsQueryData);
692 }
693
694 $table = $this->getTablePrefix() . 'exports';
695 $tablefields = $wpdb->get_results("DESCRIBE {$table};");
696 $iteration = false;
697 $parent_id = false;
698 $export_post_type = false;
699
700 // Check if field exists
701 foreach ($tablefields as $tablefield) {
702 if ('iteration' == $tablefield->Field) $iteration = true;
703 if ('parent_id' == $tablefield->Field) $parent_id = true;
704 if ('export_post_type' == $tablefield->Field) $export_post_type = true;
705 }
706
707 if ( ! $iteration ){
708 $wpdb->query("ALTER TABLE {$table} ADD `iteration` BIGINT(20) NOT NULL DEFAULT 0;");
709 }
710 if ( ! $parent_id ){
711 $wpdb->query("ALTER TABLE {$table} ADD `parent_id` BIGINT(20) NOT NULL DEFAULT 0;");
712 }
713 if ( ! $export_post_type ){
714 $wpdb->query("ALTER TABLE {$table} ADD `export_post_type` VARCHAR(64) NOT NULL DEFAULT '';");
715 }
716
717 update_option( "wp_all_export_db_version", PMXE_VERSION );
718 }
719
720 /**
721 * Determine is current export was created before current version
722 */
723 public static function isExistingExport( $checkVersion = false ){
724
725 $input = new PMXE_Input();
726 $export_id = $input->get('id', 0);
727
728 if (empty($export_id)) $export_id = $input->get('export_id', 0);
729
730 // ID not found means this is new export
731 if (empty($export_id)) return false;
732
733 if ( ! $checkVersion ) $checkVersion = PMXE_VERSION;
734
735 $export = new PMXE_Export_Record();
736 $export->getById($export_id);
737 if ( ! $export->isEmpty() && (empty($export->options['created_at_version']) || version_compare($export->options['created_at_version'], $checkVersion) < 0 )){
738 return true;
739 }
740
741 return false;
742 }
743
744 /**
745 * Determine is current export is first time running
746 */
747 public static function isNewExport(){
748
749 $input = new PMXE_Input();
750 $export_id = $input->get('id', 0);
751
752 if (empty($export_id)) $export_id = $input->get('export_id', 0);
753
754 if (empty($export_id)) $export_id = XmlExportEngine::$exportID;
755
756 // ID not found means this is new export
757 if (empty($export_id)) return true;
758
759 $export = new PMXE_Export_Record();
760 $export->getById($export_id);
761 if ( ! $export->isEmpty() && ! $export->iteration ){
762 return true;
763 }
764
765 return false;
766 }
767
768 /**
769 * Method returns default import options, main utility of the method is to avoid warnings when new
770 * option is introduced but already registered imports don't have it
771 */
772 public static function get_default_import_options() {
773 return array(
774 'cpt' => array(),
775 'whereclause' => '',
776 'joinclause' => '',
777 'filter_rules_hierarhy' => '',
778 'product_matching_mode' => 'parent',
779 'order_item_per_row' => 1,
780 'order_item_fill_empty_columns' => 1,
781 'filepath' => '',
782 'current_filepath' => '',
783 'bundlepath' => '',
784 'export_type' => 'specific',
785 'wp_query' => '',
786 'wp_query_selector' => 'wp_query',
787 'is_user_export' => false,
788 'is_comment_export' => false,
789 'export_to' => 'csv',
790 'export_to_sheet' => 'csv',
791 'delimiter' => ',',
792 'encoding' => 'UTF-8',
793 'is_generate_templates' => 1,
794 'is_generate_import' => 1,
795 'import_id' => 0,
796 'template_name' => '',
797 'is_scheduled' => 0,
798 'scheduled_period' => '',
799 'scheduled_email' => '',
800 'cc_label' => array(),
801 'cc_type' => array(),
802 'cc_value' => array(),
803 'cc_name' => array(),
804 'cc_php' => array(),
805 'cc_code' => array(),
806 'cc_sql' => array(),
807 'cc_options' => array(),
808 'cc_settings' => array(),
809 'friendly_name' => '',
810 'fields' => array('default', 'other', 'cf', 'cats'),
811 'ids' => array(),
812 'rules' => array(),
813 'records_per_iteration' => 50,
814 'include_bom' => 0,
815 'include_functions' => 1,
816 'split_large_exports' => 0,
817 'split_large_exports_count' => 10000,
818 'split_files_list' => array(),
819 'main_xml_tag' => 'data',
820 'record_xml_tag' => 'post',
821 'save_template_as' => 0,
822 'name' => '',
823 'export_only_new_stuff' => 0,
824 'export_only_modified_stuff' => 0,
825 'creata_a_new_export_file' => 0,
826 'attachment_list' => array(),
827 'order_include_poducts' => 0,
828 'order_include_all_poducts' => 0,
829 'order_include_coupons' => 0,
830 'order_include_all_coupons' => 0,
831 'order_include_customers' => 0,
832 'order_include_all_customers' => 0,
833 'migration' => '',
834 'xml_template_type' => 'simple',
835 'custom_xml_template' => '',
836 'custom_xml_template_header' => '',
837 'custom_xml_template_loop' => '',
838 'custom_xml_template_footer' => '',
839 'custom_xml_template_options' => array(),
840 'custom_xml_cdata_logic' => 'auto',
841 'show_cdata_in_preview' => 0,
842 'taxonomy_to_export' => '',
843 'created_at_version' => '',
844 'export_variations' => XmlExportEngine::VARIABLE_PRODUCTS_EXPORT_PARENT_AND_VARIATION,
845 'export_variations_title' => XmlExportEngine::VARIATION_USE_PARENT_TITLE,
846 'include_header_row' => 1,
847 'wpml_lang' => 'all',
848 'enable_export_scheduling' => 'false',
849 'scheduling_enable' => false,
850 'scheduling_weekly_days' => '',
851 'scheduling_run_on' => 'weekly',
852 'scheduling_monthly_day' => '',
853 'scheduling_times' => array(),
854 'scheduling_timezone' => 'UTC'
855 );
856 }
857
858 public static function is_ajax(){
859 return (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') ? true : false ;
860 }
861
862 public static function encode( $value ){
863 return base64_encode(md5(AUTH_SALT) . $value . md5(md5(AUTH_SALT)));
864 }
865
866 public static function decode( $encoded ){
867 return preg_match('/^[a-f0-9]{32}$/', $encoded) ? $encoded : str_replace(array(md5(AUTH_SALT), md5(md5(AUTH_SALT))), '', base64_decode($encoded));
868 }
869
870
871 /**
872 * Replace last occurence of string
873 * Used in autoloader, that's not muved in string class
874 *
875 * @param $search
876 * @param $replace
877 * @param $subject
878 * @return mixed
879 */
880 private function lreplace($search, $replace, $subject){
881 $pos = strrpos($subject, $search);
882 if($pos !== false){
883 $subject = substr_replace($subject, $replace, $pos, strlen($search));
884 }
885 return $subject;
886 }
887 }
888
889 PMXE_Plugin::getInstance();
890
891 // Include the api front controller
892 include_once('wpae_api.php');
893
894 }
895
896