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