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