PluginProbe ʕ •ᴥ•ʔ
WP All Export – Drag & Drop Export to Any Custom CSV, XML & Excel / trunk
WP All Export – Drag & Drop Export to Any Custom CSV, XML & Excel vtrunk
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 1 month ago addon-api 1 month ago classes 1 month ago config 1 month ago controllers 1 month ago dist 4 years ago filters 1 month ago helpers 1 month ago i18n 1 month ago libraries 1 month ago models 1 month ago sessions 10 years ago shortcodes 10 years ago src 1 month ago static 1 month ago views 1 month ago banner-772x250.png 12 years ago readme.txt 1 month ago schema.php 1 month ago screenshot-1.png 10 years ago screenshot-2.png 10 years ago wp-all-export.php 1 month ago wpae_api.php 1 month ago
wp-all-export.php
1075 lines
1 <?php
2
3 // phpcs:ignoreFile WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound,WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound,WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound -- legitimate plugin prefixes (pmxe/PMXE/wpae/Wpae/wp_all_export/wpallexport/XmlExport/CdataStrategy/VariableProductTitle/Soflyy/GF_Export); Plugin Check does not honor phpcs.xml prefix declaration
4 defined( 'ABSPATH' ) || exit;
5
6 /*
7 Plugin Name: WP All Export
8 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
9 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.
10 License: GPLv2 or later
11 License URI: https://www.gnu.org/licenses/gpl-2.0.html
12 Version: 1.5.0
13 Author: Soflyy
14 */
15
16 require_once(__DIR__.'/classes/CdataStrategyFactory.php');
17
18 if( ! defined( 'PMXE_SESSION_COOKIE' ) )
19 define( 'PMXE_SESSION_COOKIE', '_pmxe_session' );
20
21 // Enable error reporting in development
22 if(getenv('WPAE_DEV')) {
23 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.prevent_path_disclosure_error_reporting -- only in dev mode
24 error_reporting(E_ALL ^ E_DEPRECATED );
25 // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- only in dev mode
26 ini_set('display_errors', 1);
27 // xdebug_disable();
28 }
29
30 /**
31 * Plugin root dir with forward slashes as directory separator regardless of actuall DIRECTORY_SEPARATOR value
32 * @var string
33 */
34 define('PMXE_ROOT_DIR', str_replace('\\', '/', dirname(__FILE__)));
35 /**
36 * Plugin root url for referencing static content
37 * @var string
38 */
39 define('PMXE_ROOT_URL', rtrim(plugin_dir_url(__FILE__), '/'));
40
41 if ( class_exists('PMXE_Plugin') and PMXE_EDITION == "paid"){
42
43 function pmxe_notice(){
44
45 ?>
46 <div class="error">
47 <p>
48 <?php printf(esc_html__('Please de-activate and remove the free version of the WP All Export before activating the paid version.', 'wp-all-export')); ?>
49 </p>
50 </div>
51 <?php
52
53 deactivate_plugins( str_replace('\\', '/', dirname(__FILE__)) . '/wp-all-export.php');
54
55 }
56
57 add_action('admin_notices', 'pmxe_notice');
58
59 }
60 else {
61
62 /**
63 * Plugin prefix for making names unique (be aware that this variable is used in conjunction with naming convention,
64 * i.e. in order to change it one must not only modify this constant but also rename all constants, classes and functions which
65 * names composed using this prefix)
66 * @var string
67 */
68 define('PMXE_PREFIX', 'pmxe_');
69
70 define('PMXE_VERSION', '1.5.0');
71
72 define('PMXE_ASSETS_VERSION', '-1.0.3');
73
74 define('PMXE_EDITION', 'free');
75
76 /**
77 * Plugin root uploads folder name
78 * @var string
79 */
80 define('WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY', 'wpallexport');
81 /**
82 * Plugin uploads folder name
83 * @var string
84 */
85 define('WP_ALL_EXPORT_UPLOADS_DIRECTORY', WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'exports');
86
87 /**
88 * Plugin temp folder name
89 * @var string
90 */
91 define('WP_ALL_EXPORT_TEMP_DIRECTORY', WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'temp');
92
93 /**
94 * Plugin temp folder name
95 * @var string
96 */
97 define('WP_ALL_EXPORT_CRON_DIRECTORY', WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY . DIRECTORY_SEPARATOR . 'exports');
98
99 /**
100 * Main plugin file, Introduces MVC pattern
101 *
102 * @singletone
103 * @author Pavel Kulbakin <p.kulbakin@gmail.com>
104 */
105 final class PMXE_Plugin {
106 /**
107 * Singletone instance
108 * @var PMXE_Plugin
109 */
110 protected static $instance;
111
112 /**
113 * Plugin options
114 * @var array
115 */
116 protected $options = array();
117
118 /**
119 * Plugin root dir
120 * @var string
121 */
122 const ROOT_DIR = PMXE_ROOT_DIR;
123 /**
124 * Plugin root URL
125 * @var string
126 */
127 const ROOT_URL = PMXE_ROOT_URL;
128 /**
129 * Prefix used for names of shortcodes, action handlers, filter functions etc.
130 * @var string
131 */
132 const PREFIX = PMXE_PREFIX;
133 /**
134 * Plugin file path
135 * @var string
136 */
137 const FILE = __FILE__;
138 /**
139 * Max allowed file size (bytes) to import in default mode
140 * @var int
141 */
142 const LARGE_SIZE = 0; // all files will importing in large import mode
143
144 /**
145 * WP All Import temp folder
146 * @var string
147 */
148 const TEMP_DIRECTORY = WP_ALL_EXPORT_TEMP_DIRECTORY;
149 /**
150 * WP All Import uploads folder
151 * @var string
152 */
153 const UPLOADS_DIRECTORY = WP_ALL_EXPORT_UPLOADS_DIRECTORY;
154 /**
155 * WP All Import uploads folder
156 * @var string
157 */
158 const CRON_DIRECTORY = WP_ALL_EXPORT_CRON_DIRECTORY;
159
160 const LANGUAGE_DOMAIN = 'wp-all-export';
161
162 public static $session = null;
163
164 public static $capabilities = 'setup_network';
165
166 private static $hasActiveSchedulingLicense = null;
167
168 /** @var \Wpae\App\Service\Addons\AddonService */
169 private $addons;
170
171 public static $cache_key = '';
172
173 /**
174 * Class constructor containing dispatching logic
175 * @param string $rootDir Plugin root dir
176 * @param string $pluginFilePath Plugin main file
177 */
178 protected function __construct() {
179
180 if(defined('WPAI_WPAE_ALLOW_INSECURE_MULTISITE') && 1 === WPAI_WPAE_ALLOW_INSECURE_MULTISITE){
181 self::$capabilities = 'manage_options';
182 }
183
184 require_once (self::ROOT_DIR . '/classes/installer.php');
185
186 $installer = new PMXE_Installer();
187 $installer->checkActivationConditions();
188
189 $plugin_basename = plugin_basename( __FILE__ );
190
191 self::$cache_key = md5( 'edd_plugin_' . sanitize_key( $plugin_basename ) . '_version_info' );
192
193 // uncaught exception doesn't prevent plugin from being activated, therefore replace it with fatal error so it does
194 //set_exception_handler(create_function('$e', 'trigger_error($e->getMessage(), E_USER_ERROR);'));
195
196 // register autoloading method
197 spl_autoload_register(array($this, 'autoload'));
198
199 require_once self::ROOT_DIR . '/addon-api/autoload.php';
200
201 // register helpers
202 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) {
203 require_once $filePath;
204 }
205
206 $this->addons = new \Wpae\App\Service\Addons\AddonService();
207
208 // init plugin options
209 $option_name = get_class($this) . '_Options';
210 $options_default = PMXE_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray();
211 $current_options = get_option($option_name, array());
212 $this->options = array_intersect_key($current_options, $options_default) + $options_default;
213 $this->options = array_intersect_key($options_default, array_flip(array('info_api_url'))) + $this->options; // make sure hidden options apply upon plugin reactivation
214 if ('' == $this->options['cron_job_key']) $this->options['cron_job_key'] = wp_all_export_url_title(wp_all_export_rand_char(12));
215
216 if ($current_options !== $this->options) {
217 update_option($option_name, $this->options);
218 }
219 register_activation_hook(self::FILE, array($this, 'activation'));
220
221 // register action handlers
222 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) {
223 require_once $filePath;
224 $function = $actionName = basename($filePath, '.php');
225 if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
226 $actionName = $m[1];
227 $priority = intval($m[2]);
228 } else {
229 $priority = 10;
230 }
231 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)
232 }
233
234 add_action("admin_enqueue_scripts", [$this, 'add_admin_scripts']);
235
236 // register filter handlers
237 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) {
238 require_once $filePath;
239 $function = $actionName = basename($filePath, '.php');
240 if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
241 $actionName = $m[1];
242 $priority = intval($m[2]);
243 } else {
244 $priority = 10;
245 }
246 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)
247 }
248
249 // register shortcodes handlers
250 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) {
251 $tag = strtolower(str_replace('/', '_', preg_replace('%^' . preg_quote(self::ROOT_DIR . '/shortcodes/', '%') . '|\.php$%', '', $filePath)));
252 add_shortcode($tag, array($this, 'shortcodeDispatcher'));
253 }
254
255 // register admin page pre-dispatcher
256 add_action('admin_init', array($this, 'adminInit'), 11);
257 add_action('admin_init', array($this, 'fix_db_schema'), 10);
258 add_action('init', array($this, 'init'), 10);
259 }
260
261 public function add_admin_scripts() {
262 $cm_settings['codeEditor'] = wp_enqueue_code_editor(['type' => 'php']);
263
264 // Use our modified function if user has disabled the syntax editor.
265 if(false === $cm_settings['codeEditor']){
266 $cm_settings['codeEditor'] = wpae_wp_enqueue_code_editor(['type' => 'php']);
267 }
268
269 wp_localize_script('jquery', 'wpae_cm_settings', $cm_settings);
270 }
271
272 /**
273 * Return singletone instance
274 * @return PMXE_Plugin
275 */
276 static public function getInstance() {
277 if (self::$instance == NULL) {
278 self::$instance = new self();
279 }
280 return self::$instance;
281 }
282
283 static public function getSchedulingName(){
284 return 'Automatic Scheduling';
285 }
286
287 static public function hasActiveSchedulingLicense() {
288
289 if(is_null(self::$hasActiveSchedulingLicense)) {
290 $scheduling = \Wpae\Scheduling\Scheduling::create();
291 $hasActiveSchedulingLicense = $scheduling->checkLicense();
292 self::$hasActiveSchedulingLicense = $hasActiveSchedulingLicense;
293 }
294
295 return self::$hasActiveSchedulingLicense;
296 }
297
298 /**
299 * Common logic for requestin plugin info fields
300 */
301 public function __call($method, $args) {
302 if (preg_match('%^get(.+)%i', $method, $mtch)) {
303 $info = get_plugin_data(self::FILE);
304 if (isset($info[$mtch[1]])) {
305 return $info[$mtch[1]];
306 }
307 }
308 throw new Exception( esc_html( "Requested method " . get_class($this) . "::$method doesn't exist." ) );
309 }
310
311 /**
312 * Get path to plagin dir relative to wordpress root
313 * @param bool[optional] $noForwardSlash Whether path should be returned withot forwarding slash
314 * @return string
315 */
316 public function getRelativePath($noForwardSlash = false) {
317 $wp_root = str_replace('\\', '/', ABSPATH);
318 return ($noForwardSlash ? '' : '/') . str_replace($wp_root, '', self::ROOT_DIR);
319 }
320
321 /**
322 * Check whether plugin is activated as network one
323 * @return bool
324 */
325 public function isNetwork() {
326 if ( !is_multisite() )
327 return false;
328
329 $plugins = get_site_option('active_sitewide_plugins');
330 if (isset($plugins[plugin_basename(self::FILE)]))
331 return true;
332
333 return false;
334 }
335
336 /**
337 * Check whether permalinks is enabled
338 * @return bool
339 */
340 public function isPermalinks() {
341 global $wp_rewrite;
342
343 return $wp_rewrite->using_permalinks();
344 }
345
346 /**
347 * Return prefix for plugin database tables
348 * @return string
349 */
350 public function getTablePrefix() {
351 global $wpdb;
352
353 //return ($this->isNetwork() ? $wpdb->base_prefix : $wpdb->prefix) . self::PREFIX;
354 return $wpdb->prefix . self::PREFIX;
355 }
356
357 /**
358 * Return prefix for wordpress database tables
359 * @return string
360 */
361 public function getWPPrefix() {
362 global $wpdb;
363 return ($this->isNetwork()) ? $wpdb->base_prefix : $wpdb->prefix;
364 }
365
366 public function init(){
367 $this->load_plugin_textdomain();
368 }
369
370 public function showNoticeAndDisablePlugin($message){
371 $this->showNotice($message);
372 deactivate_plugins( str_replace('\\', '/', dirname(__FILE__)) . '/wp-all-export.php');
373 }
374
375 public function showNotice($message)
376 {
377 $notice = new \Wpae\WordPress\AdminErrorNotice($message);
378 $notice->render();
379 }
380
381 public function showDismissibleNotice($message, $noticeId)
382 {
383 $notice = new \Wpae\WordPress\SitewideAdminDismissibleNotice($message, $noticeId);
384 if (!$notice->isDismissed()) {
385 $notice->render();
386 }
387 }
388
389 /**
390 * pre-dispatching logic for admin page controllers
391 */
392 public function adminInit() {
393
394 if(!wp_doing_ajax()) {
395
396 // create history folder
397 $uploads = wp_upload_dir();
398
399 $wpallimportDirs = array(WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY, self::TEMP_DIRECTORY, self::UPLOADS_DIRECTORY, self::CRON_DIRECTORY);
400
401 foreach ($wpallimportDirs as $destination) {
402
403 $dir = $uploads['basedir'] . DIRECTORY_SEPARATOR . $destination;
404
405 if (!is_dir($dir)) wp_mkdir_p($dir);
406
407 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_touch -- export plugin reads/writes its own files in uploads dir, WP_Filesystem not viable for streamed CSV/XML output
408 if (!@file_exists($dir . DIRECTORY_SEPARATOR . 'index.php')) @touch($dir . DIRECTORY_SEPARATOR . 'index.php');
409
410 }
411
412 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable -- export plugin reads/writes its own files in uploads dir, WP_Filesystem not viable for streamed CSV/XML output
413 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)) {
414 /* translators: %s: uploads folder path */
415 $this->showNoticeAndDisablePlugin(sprintf(esc_html__('Uploads folder %s must be writable', 'wp-all-export'), $uploads['basedir'] . DIRECTORY_SEPARATOR . WP_ALL_EXPORT_UPLOADS_BASE_DIRECTORY));
416 }
417
418 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable -- export plugin reads/writes its own files in uploads dir, WP_Filesystem not viable for streamed CSV/XML output
419 if (!is_dir($uploads['basedir'] . DIRECTORY_SEPARATOR . self::UPLOADS_DIRECTORY) or !is_writable($uploads['basedir'] . DIRECTORY_SEPARATOR . self::UPLOADS_DIRECTORY)) {
420 /* translators: %s: uploads folder path */
421 $this->showNoticeAndDisablePlugin(sprintf(esc_html__('Uploads folder %s must be writable', 'wp-all-export'), $uploads['basedir'] . DIRECTORY_SEPARATOR . self::UPLOADS_DIRECTORY));
422 }
423
424 if ($this->addons->userExportsExistAndAddonNotInstalled() && current_user_can(self::$capabilities)) {
425 $this->showDismissibleNotice(__('<strong style="font-size:16px">A Configured Export Requires the User Export Add-On</strong><p>Your User exports will not be able to run until you install the User Export Add-On. That add-on is available from <a href="https://wordpress.org/plugins/export-wp-users-xml-csv/" target="_blank">wordpress.org</a>.</p>', 'wp-all-export'), 'wpae_user_addon_not_installed_notice');
426 }
427
428 if ($this->addons->wooCommerceExportsExistAndAddonNotInstalled() && current_user_can(self::$capabilities) && \class_exists('WooCommerce')) {
429 $this->showDismissibleNotice(__('<strong style="font-size:16px">A Configured Export Requires the WooCommerce Export Add-On Pro</strong><p>Your Products, Orders, and Coupons exports will not be able to run until you install the WooCommerce Export Add-On Pro.</p>', 'wp-all-export')
430 . '<p><a class="button button-primary" href="https://wpallimport.com/portal/downloads" target="_blank">' . __('Download Add-On', 'wp-all-export') . '</a></p>', 'wpae_woocommerce_addon_not_installed_notice');
431 }
432
433 if ($this->addons->acfExportsExistAndNotInstalled() && current_user_can(self::$capabilities)) {
434 $this->showDismissibleNotice(__('<strong style="font-size:16px">A Configured Export Requires the ACF Export Add-On Pro</strong><p>Exports that contain ACF fields will not be able to run until you install the ACF Export Add-On Pro.</p>', 'wp-all-export')
435 . '<p><a class="button button-primary" href="https://wpallimport.com/portal/downloads" target="_blank">' . __('Download Add-On', 'wp-all-export') . '</a></p>', 'wpae_acf_addon_not_installed_notice');
436 }
437 }
438
439 self::$session = new PMXE_Handler();
440
441 $input = new PMXE_Input();
442 $page = strtolower($input->getpost('page', ''));
443
444 if (preg_match('%^' . preg_quote(str_replace('_', '-', self::PREFIX), '%') . '([\w-]+)$%', $page)) {
445
446 $action = strtolower($input->getpost('action', 'index'));
447
448 // capitalize prefix and first letters of class name parts
449 $controllerName = preg_replace_callback('%(^' . preg_quote(self::PREFIX, '%') . '|_).%', array($this, "replace_callback"),str_replace('-', '_', $page));
450 $actionName = str_replace('-', '_', $action);
451 if (method_exists($controllerName, $actionName)) {
452
453 if ( ! get_current_user_id() or ! current_user_can(self::$capabilities)) {
454 // This nonce is not valid.
455 die( 'Security check' );
456
457 } else {
458
459 $this->_admin_current_screen = (object)array(
460 'id' => $controllerName,
461 'base' => $controllerName,
462 'action' => $actionName,
463 'is_ajax' => isset( $_SERVER["HTTP_ACCEPT"] ) && strpos( sanitize_text_field( wp_unslash( $_SERVER["HTTP_ACCEPT"] ) ), 'json') !== false,
464 'is_network' => is_network_admin(),
465 'is_user' => is_user_admin(),
466 );
467 add_filter('current_screen', array($this, 'getAdminCurrentScreen'));
468 add_filter('admin_body_class',
469 function($admin_body_class) {
470 return $admin_body_class.' wpallexport-plugin';
471 }
472 );
473
474 $controller = new $controllerName();
475 if ( ! $controller instanceof PMXE_Controller_Admin) {
476 throw new Exception( esc_html( "Administration page `$page` matches to a wrong controller type." ) );
477 }
478
479 $reviewsUI = new \Wpae\Reviews\ReviewsUI();
480
481 add_action('admin_notices', [$reviewsUI, 'render']);
482
483 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only request inspection
484 if($controller instanceof PMXE_Admin_Manage && ($action == 'update' || $action == 'template' || $action == 'options') && isset($_GET['id'])) {
485 $addons = new \Wpae\App\Service\Addons\AddonService();
486 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only request inspection
487 $exportId = intval($_GET['id']);
488
489 $export = new \PMXE_Export_Record();
490 $export->getById($exportId);
491
492 $cpt = $export->options['cpt'];
493 if (!is_array($cpt)) {
494 $cpt = array($cpt);
495 }
496
497 if(isset($export->options['export_type']) && $export->options['export_type'] === 'advanced') {
498
499 if(!XmlExportEngine::get_addons_service()->isWooCommerceAddonActive() && strpos($export->options['wp_query'], 'product') !== false && \class_exists('WooCommerce')) {
500 die(wp_kses_post(\__('The WooCommerce Export Add-On Pro is required to run this export. If you already own it, you can download the add-on here: <a href="http://www.wpallimport.com/portal/downloads" target="_blank">http://www.wpallimport.com/portal/downloads</a>', 'wp-all-export')));
501 }
502 else if( (!XmlExportEngine::get_addons_service()->isWooCommerceAddonActive() && !XmlExportEngine::get_addons_service()->isWooCommerceOrderAddonActive() ) && strpos($export->options['wp_query'], 'shop_order') !== false) {
503 die(wp_kses_post(\__('The WooCommerce Export Add-On Pro is required to run this export. If you already own it, you can download the add-on here: <a href="http://www.wpallimport.com/portal/downloads" target="_blank">http://www.wpallimport.com/portal/downloads</a>', 'wp-all-export')));
504 }
505 else if(!XmlExportEngine::get_addons_service()->isWooCommerceAddonActive() && strpos($export->options['wp_query'], 'shop_coupon') !== false) {
506 die(wp_kses_post(\__('The WooCommerce Export Add-On Pro is required to run this export. If you already own it, you can download the add-on here: <a href="http://www.wpallimport.com/portal/downloads" target="_blank">http://www.wpallimport.com/portal/downloads</a>', 'wp-all-export')));
507 }
508 }
509
510 if (
511 ((in_array('users', $cpt) || in_array('shop_customer', $cpt)) && !$addons->isUserAddonActive()) ||
512 ($export->options['export_type'] == 'advanced' && $export->options['wp_query_selector'] == 'wp_user_query' && !$addons->isUserAddonActive())
513 ) {
514 die(wp_kses_post(\__('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>', 'wp-all-export')));
515 }
516
517 if (
518 (
519 (
520 ( in_array( 'product', $cpt ) && \class_exists('WooCommerce') && ! XmlExportEngine::get_addons_service()->isWooCommerceProductAddonActive() ) ||
521 ( in_array( 'shop_order', $cpt ) && ! XmlExportEngine::get_addons_service()->isWooCommerceOrderAddonActive() ) ||
522 in_array( 'shop_review', $cpt ) ||
523 in_array( 'shop_coupon', $cpt )
524 ) && ! $addons->isWooCommerceAddonActive()
525 ) ||
526 ( $export->options['export_type'] == 'advanced' && $export->options['wp_query_selector'] == 'wp_user_query' && ! $addons->isUserAddonActive() )
527 ) {
528 die(wp_kses_post(\__( 'The WooCommerce 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>', 'wp-all-export' )) );
529 }
530
531 if ( in_array('comments', $cpt) || in_array('shop_review', $cpt) ) { // exporting comments
532 die(wp_kses_post(\__('WP All Export Pro is required to run this export. If you already own it, you can download it here: <a href="http://www.wpallimport.com/portal/downloads" target="_blank">http://www.wpallimport.com/portal/downloads</a>', 'wp-all-export')));
533 }
534
535 if(in_array('acf', $export->options['cc_type']) && !$addons->isAcfAddonActive()) {
536 die(wp_kses_post(\__('The ACF 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>', 'wp-all-export')));
537 }
538 }
539
540
541 if ($this->_admin_current_screen->is_ajax) { // ajax request
542 $controller->$action();
543 do_action('wpallexport_action_after');
544 die(); // stop processing since we want to output only what controller is randered, nothing in addition
545 } elseif ( ! $controller->isInline) {
546 @ob_start();
547 $controller->$action();
548 self::$buffer = @ob_get_clean();
549 } else {
550 self::$buffer_callback = array($controller, $action);
551 }
552 }
553
554 } else { // redirect to dashboard if requested page and/or action don't exist
555 wp_safe_redirect(admin_url()); die();
556 }
557
558 }
559 }
560
561
562 /**
563 * Dispatch shorttag: create corresponding controller instance and call its index method
564 * @param array $args Shortcode tag attributes
565 * @param string $content Shortcode tag content
566 * @param string $tag Shortcode tag name which is being dispatched
567 * @return string
568 * @throws Exception
569 */
570 public function shortcodeDispatcher($args, $content, $tag) {
571
572 $controllerName = self::PREFIX . preg_replace_callback('%(^|_).%', array($this, "replace_callback"), $tag);// capitalize first letters of class name parts and add prefix
573 $controller = new $controllerName();
574 if ( ! $controller instanceof PMXE_Controller) {
575 throw new Exception( esc_html( "Shortcode `$tag` matches to a wrong controller type." ) );
576 }
577 ob_start();
578 $controller->index($args, $content);
579 return ob_get_clean();
580 }
581
582 static $buffer = NULL;
583 static $buffer_callback = NULL;
584
585 /**
586 * Dispatch admin page: call corresponding controller based on get parameter `page`
587 * The method is called twice: 1st time as handler `parse_header` action and then as admin menu item handler
588 * @param string $page
589 * @param string $action
590 * @throws Exception
591 * @internal param $string [optional] $page When $page set to empty string ealier buffered content is outputted, otherwise controller is called based on $page value
592 */
593 public function adminDispatcher($page = '', $action = 'index') {
594 if ('' === $page) {
595 if ( ! is_null(self::$buffer)) {
596 echo '<div class="wrap">';
597 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- buffer holds rendered controller output sanitized at the view layer
598 echo self::$buffer;
599 do_action('wpallexport_action_after');
600 echo '</div>';
601 } elseif ( ! is_null(self::$buffer_callback)) {
602 echo '<div class="wrap">';
603 call_user_func(self::$buffer_callback);
604 do_action('wpallexport_action_after');
605 echo '</div>';
606 } else {
607 throw new Exception('There is no previousely buffered content to display.');
608 }
609 }
610 }
611
612 public function replace_callback($matches){
613 return strtoupper($matches[0]);
614 }
615
616 protected $_admin_current_screen = NULL;
617 public function getAdminCurrentScreen()
618 {
619 return $this->_admin_current_screen;
620 }
621
622 /**
623 * Autoloader
624 * It's assumed class name consists of prefix folloed by its name which in turn corresponds to location of source file
625 * if `_` symbols replaced by directory path separator. File name consists of prefix folloed by last part in class name (i.e.
626 * symbols after last `_` in class name)
627 * When class has prefix it's source is looked in `models`, `controllers`, `shortcodes` folders, otherwise it looked in `core` or `library` folder
628 *
629 * @param string $className
630 * @return bool
631 */
632 public function autoload($className) {
633
634 $is_prefix = false;
635 $filePath = str_replace('_', '/', preg_replace('%^' . preg_quote(self::PREFIX, '%') . '%', '', strtolower($className), 1, $is_prefix)) . '.php';
636 if ( ! $is_prefix) { // also check file with original letter case
637 $filePathAlt = $className . '.php';
638 }
639 foreach ($is_prefix ? array('models', 'controllers', 'shortcodes', 'classes') : array('libraries') as $subdir) {
640 $path = self::ROOT_DIR . '/' . $subdir . '/' . $filePath;
641 if (is_file($path)) {
642 require_once $path;
643 return TRUE;
644 }
645 if (!$is_prefix) {
646 if (strpos($className, '_') !== false) {
647 $filePathAlt = $this->lreplace('_', DIRECTORY_SEPARATOR, $filePathAlt);
648 }
649
650 $pathAlt = self::ROOT_DIR . DIRECTORY_SEPARATOR . $subdir . DIRECTORY_SEPARATOR . $filePathAlt;
651
652 if (is_file($pathAlt)) {
653 require_once $pathAlt;
654 return TRUE;
655 }
656 }
657 }
658 if($className === 'CdataStrategyFactory') {
659 //TODO: Move this to a namespace
660 require_once (self::ROOT_DIR . '/classes/CdataStrategyFactory.php');
661 }
662
663
664 if(strpos($className, '\\') !== false){
665
666 // project-specific namespace prefix
667 $prefix = 'Wpae\\';
668
669 // base directory for the namespace prefix
670 $base_dir = self::ROOT_DIR . '/src/';
671
672 // does the class use the namespace prefix?
673 $len = strlen($prefix);
674 if (strncmp($prefix, $className, $len) !== 0) {
675 // no, move to the next registered autoloader
676 return false;
677 }
678
679 // get the relative class name
680 $relative_class = substr($className, $len);
681
682 // replace the namespace prefix with the base directory, replace namespace
683 // separators with directory separators in the relative class name, append
684 // with .php
685 $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
686
687 // if the file exists, require it
688 if (file_exists($file)) {
689 require_once $file;
690 }
691 }
692
693 return FALSE;
694 }
695
696 /**
697 * Get plugin option
698 * @param string [optional] $option Parameter to return, all array of options is returned if not set
699 * @return mixed
700 * @throws Exception
701 */
702 public function getOption($option = NULL) {
703 $options = apply_filters('wp_all_export_config_options', $this->options);
704 if (is_null($option)) {
705 return $options;
706 } else if (isset($options[$option])) {
707 return $options[$option];
708 } else {
709 throw new Exception("Specified option is not defined for the plugin");
710 }
711 }
712
713 /**
714 * Update plugin option value
715 * @param string $option Parameter name or array of name => value pairs
716 * @param null $value
717 * @return array
718 * @throws Exception
719 * @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
720 */
721 public function updateOption($option, $value = NULL) {
722 is_null($value) or $option = array($option => $value);
723 if (array_diff_key($option, $this->options)) {
724 throw new Exception("Specified option is not defined for the plugin");
725 }
726 $this->options = $option + $this->options;
727 update_option(get_class($this) . '_Options', $this->options);
728
729 return $this->options;
730 }
731
732 /**
733 * Plugin activation logic
734 */
735 public function activation() {
736 // uncaught exception doesn't prevent plugin from being activated, therefore replace it with fatal error so it does
737 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error,WordPress.Security.EscapeOutput.OutputNotEscaped -- intentional runtime warning routed to PHP error log, not HTML output
738 set_exception_handler(function($e) {trigger_error($e->getMessage(), E_USER_ERROR); });
739
740 // create plugin options
741 $option_name = get_class($this) . '_Options';
742 $options_default = PMXE_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray();
743 $wpai_options = get_option($option_name, false);
744 if ( ! $wpai_options ) update_option($option_name, $options_default);
745
746 // create/update required database tables
747 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
748 require self::ROOT_DIR . '/schema.php';
749 global $wpdb;
750
751 if (function_exists('is_multisite') && is_multisite()) {
752 // check if it is a network activation - if so, run the activation function for each blog id
753 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only network activation check during plugin activation
754 if (isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
755 $old_blog = $wpdb->blogid;
756 // Get all blog ids
757 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- multisite plugin schema migration; enumerates blog ids from $wpdb->blogs to run dbDelta() on each site
758 $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
759 foreach ($blogids as $blog_id) {
760 switch_to_blog($blog_id);
761 require self::ROOT_DIR . '/schema.php';
762 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange -- plugin schema migration via dbDelta() on per-site activation
763 dbDelta($plugin_queries);
764 }
765 switch_to_blog($old_blog);
766 return;
767 }
768 }
769
770 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange -- plugin schema migration via dbDelta() on activation
771 dbDelta($plugin_queries);
772
773 }
774
775 /**
776 * Load Localisation files.
777 *
778 * Note: the first-loaded translation file overrides any following ones if the same translation is present
779 *
780 * @access public
781 * @return void
782 */
783 public function load_plugin_textdomain() {
784
785 $locale = apply_filters( 'plugin_locale', get_locale(), 'wp-all-export' );
786
787 // phpcs:ignore PluginCheck.CodeAnalysis.DiscouragedFunctions.load_plugin_textdomainFound -- needed to load bundled translations
788 load_plugin_textdomain( 'wp-all-export', false, dirname( plugin_basename( __FILE__ ) ) . "/i18n/languages" );
789 }
790
791 public function fix_db_schema(){
792
793 global $wpdb;
794
795 $db_version_old = get_option('wp_all_export_db_version');
796 $installed_ver = get_option('wp_all_export_free_db_version');
797
798 // We leave the old option so if it doesn't exist then this was installed after the export addons release.
799 // If it does exist we make sure it's not a Pro version.
800 if(!$db_version_old || version_compare($db_version_old, '1.2.10') == 1) {
801 update_option("wp_all_export_free_addons_not_included", true);
802 }
803
804 if ( $installed_ver == PMXE_VERSION ) return true;
805
806 // Declare variable to avoid nuisance notices when charset and collate aren't set.
807 $charset_collate = '';
808
809 if ( ! empty($wpdb->charset))
810 $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
811 if ( ! empty($wpdb->collate))
812 $charset_collate .= " COLLATE $wpdb->collate";
813
814 $table_prefix = $this->getTablePrefix();
815
816 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange,PluginCheck.Security.DirectDB.UnescapedDBParameter -- DDL with identifiers/charset that prepare() cannot parameterize; $table_prefix from $wpdb->prefix, $charset_collate from $wpdb->charset/$wpdb->collate
817 $wpdb->query("CREATE TABLE IF NOT EXISTS {$table_prefix}templates (
818 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
819 name VARCHAR(200) NOT NULL DEFAULT '',
820 options LONGTEXT,
821 PRIMARY KEY (id)
822 ) $charset_collate;");
823
824 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange,PluginCheck.Security.DirectDB.UnescapedDBParameter -- DDL with identifiers/charset that prepare() cannot parameterize; $table_prefix from $wpdb->prefix, $charset_collate from $wpdb->charset/$wpdb->collate
825 $wpdb->query("CREATE TABLE IF NOT EXISTS {$table_prefix}posts (
826 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
827 post_id BIGINT(20) UNSIGNED NOT NULL,
828 export_id BIGINT(20) UNSIGNED NOT NULL,
829 iteration BIGINT(20) NOT NULL DEFAULT 0,
830 PRIMARY KEY (id)
831 ) $charset_collate;");
832
833 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter -- SHOW TABLES LIKE with identifier built from $wpdb->prefix
834 $googleCatsTableExists = $wpdb->query("SHOW TABLES LIKE '{$table_prefix}google_cats'");
835 if(!$googleCatsTableExists) {
836 require_once self::ROOT_DIR . '/schema.php';
837 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange,PluginCheck.Security.DirectDB.UnescapedDBParameter -- CREATE TABLE DDL from bundled schema.php; identifiers cannot be parameterized
838 $wpdb->query($googleCatsQueryCreate);
839 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter -- bulk INSERT seed data from bundled schema.php; static plugin-shipped content
840 $wpdb->query($googleCatsQueryData);
841 }
842
843 $table = $this->getTablePrefix() . 'exports';
844 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter -- DESCRIBE with identifier built from $wpdb->prefix
845 $tablefields = $wpdb->get_results("DESCRIBE {$table};");
846 $iteration = false;
847 $parent_id = false;
848 $export_post_type = false;
849 $created_at = false;
850
851 // Check if field exists
852 foreach ($tablefields as $tablefield) {
853 if ('iteration' == $tablefield->Field) $iteration = true;
854 if ('parent_id' == $tablefield->Field) $parent_id = true;
855 if ('export_post_type' == $tablefield->Field) $export_post_type = true;
856 if ('created_at' == $tablefield->Field) $created_at = true;
857 }
858
859 if ( ! $iteration ){
860 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange,PluginCheck.Security.DirectDB.UnescapedDBParameter -- DDL with identifier from $wpdb->prefix; cannot parameterize
861 $wpdb->query("ALTER TABLE {$table} ADD `iteration` BIGINT(20) NOT NULL DEFAULT 0;");
862 }
863 if ( ! $parent_id ){
864 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange,PluginCheck.Security.DirectDB.UnescapedDBParameter -- DDL with identifier from $wpdb->prefix; cannot parameterize
865 $wpdb->query("ALTER TABLE {$table} ADD `parent_id` BIGINT(20) NOT NULL DEFAULT 0;");
866 }
867 if ( ! $export_post_type ){
868 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange,PluginCheck.Security.DirectDB.UnescapedDBParameter -- DDL with identifier from $wpdb->prefix; cannot parameterize
869 $wpdb->query("ALTER TABLE {$table} ADD `export_post_type` TEXT NOT NULL DEFAULT '';");
870 }
871
872 if ( ! $created_at ){
873 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange,PluginCheck.Security.DirectDB.UnescapedDBParameter -- DDL with identifier from $wpdb->prefix; cannot parameterize
874 $wpdb->query("ALTER TABLE {$table} ADD `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;");
875 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter -- table identifier from $wpdb->prefix; copies registered_on column to created_at column
876 $wpdb->query("UPDATE {$table} SET `created_at` = `registered_on` WHERE 1");
877 }
878
879
880 update_option( "wp_all_export_free_db_version", PMXE_VERSION );
881 }
882
883 /**
884 * Determine is current export was created before current version
885 */
886 public static function isExistingExport( $checkVersion = false ){
887
888 $input = new PMXE_Input();
889 $export_id = $input->get('id', 0);
890
891 if (empty($export_id)) $export_id = $input->get('export_id', 0);
892
893 // ID not found means this is new export
894 if (empty($export_id)) return false;
895
896 if ( ! $checkVersion ) $checkVersion = PMXE_VERSION;
897
898 $export = new PMXE_Export_Record();
899 $export->getById($export_id);
900 if ( ! $export->isEmpty() && (empty($export->options['created_at_version']) || version_compare($export->options['created_at_version'], $checkVersion) < 0 )){
901 return true;
902 }
903
904 return false;
905 }
906
907 /**
908 * Determine is current export is first time running
909 */
910 public static function isNewExport(){
911
912 $input = new PMXE_Input();
913 $export_id = $input->get('id', 0);
914
915 if (empty($export_id)) $export_id = $input->get('export_id', 0);
916
917 if (empty($export_id)) $export_id = XmlExportEngine::$exportID;
918
919 // ID not found means this is new export
920 if (empty($export_id)) return true;
921
922 $export = new PMXE_Export_Record();
923 $export->getById($export_id);
924 if ( ! $export->isEmpty() && ! $export->iteration ){
925 return true;
926 }
927
928 return false;
929 }
930
931 /**
932 * Method returns default import options, main utility of the method is to avoid warnings when new
933 * option is introduced but already registered imports don't have it
934 */
935 public static function get_default_import_options() {
936 return array(
937 'cpt' => array(),
938 'whereclause' => '',
939 'joinclause' => '',
940 'filter_rules_hierarhy' => '',
941 'product_matching_mode' => 'parent',
942 'order_item_per_row' => 1,
943 'order_item_fill_empty_columns' => 1,
944 'filepath' => '',
945 'current_filepath' => '',
946 'bundlepath' => '',
947 'export_type' => 'specific',
948 'wp_query' => '',
949 'wp_query_selector' => 'wp_query',
950 'is_user_export' => false,
951 'is_comment_export' => false,
952 'export_to' => 'csv',
953 'export_to_sheet' => 'csv',
954 'delimiter' => ',',
955 'encoding' => 'UTF-8',
956 'is_generate_templates' => 1,
957 'is_generate_import' => 1,
958 'import_id' => 0,
959 'template_name' => '',
960 'is_scheduled' => 0,
961 'scheduled_period' => '',
962 'scheduled_email' => '',
963 'cc_label' => array(),
964 'cc_type' => array(),
965 'cc_value' => array(),
966 'cc_name' => array(),
967 'cc_php' => array(),
968 'cc_code' => array(),
969 'cc_sql' => array(),
970 'cc_options' => array(),
971 'cc_settings' => array(),
972 'friendly_name' => '',
973 'fields' => array('default', 'other', 'cf', 'cats'),
974 'ids' => array(),
975 'rules' => array(),
976 'records_per_iteration' => 50,
977 'include_bom' => 1,
978 'include_functions' => 1,
979 'split_large_exports' => 0,
980 'split_large_exports_count' => 10000,
981 'split_files_list' => array(),
982 'main_xml_tag' => 'data',
983 'record_xml_tag' => 'post',
984 'save_template_as' => 0,
985 'name' => '',
986 'export_only_new_stuff' => 0,
987 'export_only_modified_stuff' => 0,
988 'creata_a_new_export_file' => 0,
989 'attachment_list' => array(),
990 'order_include_poducts' => 0,
991 'order_include_all_poducts' => 0,
992 'order_include_coupons' => 0,
993 'order_include_all_coupons' => 0,
994 'order_include_customers' => 0,
995 'order_include_all_customers' => 0,
996 'migration' => '',
997 'xml_template_type' => 'simple',
998 'custom_xml_template' => '',
999 'custom_xml_template_header' => '',
1000 'custom_xml_template_loop' => '',
1001 'custom_xml_template_footer' => '',
1002 'custom_xml_template_options' => array(),
1003 'custom_xml_cdata_logic' => 'auto',
1004 'show_cdata_in_preview' => 0,
1005 'taxonomy_to_export' => '',
1006 'created_at_version' => '',
1007 'export_variations' => XmlExportEngine::VARIABLE_PRODUCTS_EXPORT_PARENT_AND_VARIATION,
1008 'export_variations_title' => XmlExportEngine::VARIATION_USE_PARENT_TITLE,
1009 'include_header_row' => 1,
1010 'wpml_lang' => 'all',
1011 'enable_export_scheduling' => 'false',
1012 'scheduling_enable' => false,
1013 'scheduling_weekly_days' => '',
1014 'scheduling_run_on' => 'weekly',
1015 'scheduling_monthly_day' => '',
1016 'scheduling_times' => array(),
1017 'scheduling_timezone' => 'UTC',
1018 'sub_post_type_to_export' => ''
1019
1020 );
1021 }
1022
1023 public static function is_ajax(){
1024 return (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower( sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_REQUESTED_WITH'] ) ) ) == 'xmlhttprequest') ? true : false ;
1025 }
1026
1027 /**
1028 * @param $value
1029 * @return string
1030 */
1031 public static function encode($value){
1032 $salt = defined('AUTH_SALT') ? AUTH_SALT : wp_salt();
1033 return base64_encode(md5($salt) . $value . md5(md5($salt)));
1034 }
1035
1036 /**
1037 * @param $encoded
1038 * @return mixed
1039 */
1040 public static function decode($encoded){
1041 $salt = defined('AUTH_SALT') ? AUTH_SALT : wp_salt();
1042 return preg_match('/^[a-f0-9]{32}$/', $encoded) ? $encoded : str_replace(array(md5($salt), md5(md5($salt))), '', base64_decode($encoded));
1043 }
1044
1045 /**
1046 * Replace last occurence of string
1047 * Used in autoloader, that's not muved in string class
1048 *
1049 * @param $search
1050 * @param $replace
1051 * @param $subject
1052 * @return mixed
1053 */
1054 private function lreplace($search, $replace, $subject){
1055 $pos = strrpos($subject, $search);
1056 if($pos !== false){
1057 $subject = substr_replace($subject, $replace, $pos, strlen($search));
1058 }
1059 return $subject;
1060 }
1061
1062 public static function hposEnabled()
1063 {
1064 return class_exists('Automattic\WooCommerce\Utilities\OrderUtil') && \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled();
1065 }
1066 }
1067
1068 PMXE_Plugin::getInstance();
1069
1070 // Include the api front controller
1071 include_once('wpae_api.php');
1072
1073 }
1074
1075