/product-csv-import.php

https://github.com/claytoncollie/WooCommerce-Product-CSV-Import-Suite · PHP · 835 lines · 546 code · 191 blank · 98 comment · 107 complexity · 5ec6811205927569d177c0ff2436f1f2 MD5 · raw file

  1. <?php
  2. /*
  3. Plugin Name: WooCommerce Product CSV Import Suite
  4. Plugin URI: http://woothemes.com/woocommerce/
  5. Description: Import and export products and variations straight from WordPress admin. Go to WooCommerce > CSV Import Suite to get started. Supports post fields, product data, custom post types, taxonomies, and images. More woocommerce extensions download from <a href="http://www.96down.com/">96down.com</a>.
  6. Author: Mike Jolley
  7. Author URI: http://mikejolley.com
  8. Version: 1.2.2
  9. Text Domain: wc_csv_importer
  10. Copyright: Š 2009-2011 WooThemes.
  11. License: GNU General Public License v3.0
  12. License URI: http://www.gnu.org/licenses/gpl-3.0.html
  13. Adapted from the WordPress post importer by the WordPress team
  14. */
  15. /**
  16. * Required functions
  17. */
  18. if ( ! function_exists( 'woothemes_queue_update' ) )
  19. require_once( 'woo-includes/woo-functions.php' );
  20. /**
  21. * Plugin updates
  22. */
  23. woothemes_queue_update( plugin_basename( __FILE__ ), '7ac9b00a1fe980fb61d28ab54d167d0d', '18680' );
  24. /**
  25. * Check WooCommerce exists
  26. */
  27. if ( is_woocommerce_active() ) {
  28. if ( ! is_admin() ) return;
  29. /**
  30. * Localisation
  31. **/
  32. load_plugin_textdomain( 'wc_csv_import', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
  33. /**
  34. * WC_CSV_Import_Suite class
  35. **/
  36. if ( ! class_exists( 'WC_Product_CSV_Import_Suite' ) ) {
  37. class WC_Product_CSV_Import_Suite {
  38. var $post_columns;
  39. var $variation_columns;
  40. var $errors = array();
  41. public function __construct() {
  42. add_action( 'admin_init', array( $this, 'init_fields' ), 5 );
  43. add_action( 'admin_init', array( $this, 'admin_init' ) );
  44. add_action( 'admin_menu', array( $this, 'admin_menu' ) );
  45. add_action( 'admin_print_styles', array( $this, 'admin_scripts' ) );
  46. }
  47. function init_fields() {
  48. // Post data to export
  49. $this->post_columns = apply_filters('woocommerce_csv_product_post_columns', array(
  50. 'post_title' => 'post_title',
  51. 'post_name' => 'post_name',
  52. 'ID' => 'ID',
  53. 'post_excerpt' => 'post_excerpt',
  54. 'post_content' => 'post_content',
  55. 'post_status' => 'post_status',
  56. 'menu_order' => 'menu_order',
  57. 'post_date' => 'post_date',
  58. 'post_parent' => 'post_parent',
  59. 'comment_status' => 'comment_status',
  60. // Meta
  61. '_sku' => 'sku',
  62. '_downloadable' => 'downloadable',
  63. '_virtual' => 'virtual',
  64. '_visibility' => 'visibility',
  65. '_stock' => 'stock',
  66. '_stock_status' => 'stock_status',
  67. '_backorders' => 'backorders',
  68. '_manage_stock' => 'manage_stock',
  69. '_regular_price' => 'regular_price',
  70. '_sale_price' => 'sale_price',
  71. '_weight' => 'weight',
  72. '_length' => 'length',
  73. '_width' => 'width',
  74. '_height' => 'height',
  75. '_tax_status' => 'tax_status',
  76. '_tax_class' => 'tax_class',
  77. '_upsell_ids' => 'upsell_ids',
  78. '_crosssell_ids' => 'crosssell_ids',
  79. '_featured' => 'featured',
  80. '_sale_price_dates_from' => 'sale_price_dates_from',
  81. '_sale_price_dates_to' => 'sale_price_dates_to',
  82. // Downloadable products
  83. '_file_path' => 'file_path',
  84. '_file_paths' => 'file_paths',
  85. '_download_limit' => 'download_limit',
  86. '_download_expiry' => 'download_expiry',
  87. // Virtual products
  88. '_product_url' => 'product_url',
  89. '_button_text' => 'button_text',
  90. // YOAST
  91. '_yoast_wpseo_focuskw' => 'meta:_yoast_wpseo_focuskw',
  92. '_yoast_wpseo_title' => 'meta:_yoast_wpseo_title',
  93. '_yoast_wpseo_metadesc' => 'meta:_yoast_wpseo_metadesc',
  94. '_yoast_wpseo_metakeywords' => 'meta:_yoast_wpseo_metakeywords',
  95. ));
  96. // Post data to export
  97. $this->variation_columns = apply_filters('woocommerce_csv_product_variation_post_columns', array(
  98. 'post_parent' => 'post_parent',
  99. 'ID' => 'ID',
  100. 'post_status' => 'post_status',
  101. // Core product data
  102. '_sku' => 'sku',
  103. '_downloadable' => 'downloadable',
  104. '_virtual' => 'virtual',
  105. '_stock' => 'stock',
  106. '_price' => 'price',
  107. '_regular_price' => 'regular_price',
  108. '_sale_price' => 'sale_price',
  109. '_weight' => 'weight',
  110. '_length' => 'length',
  111. '_width' => 'width',
  112. '_height' => 'height',
  113. // Downloadable products
  114. '_file_path' => 'file_path',
  115. '_file_paths' => 'file_paths',
  116. '_download_limit' => 'download_limit',
  117. ));
  118. // 2.0
  119. if ( version_compare( WOOCOMMERCE_VERSION, "2.0.0", ">=" ) ) {
  120. unset( $this->variation_columns['_price'] );
  121. } else {
  122. unset( $this->variation_columns['_regular_price'] );
  123. }
  124. }
  125. /**
  126. * Admin Init
  127. */
  128. function admin_init() {
  129. register_importer( 'woocommerce_csv', 'WooCommerce Products (CSV)', __('Import <strong>products</strong> to your store via a csv file.', 'wc_csv_import'), array( $this, 'product_importer' ) );
  130. register_importer( 'woocommerce_variation_csv', 'WooCommerce Product Variations (CSV)', __('Import <strong>product variations</strong> to your store via a csv file.', 'wc_csv_import'), array( $this, 'variation_importer' ) );
  131. if (!empty($_GET['action']) && !empty($_GET['page']) && $_GET['page']=='woocommerce_csv_import_suite') {
  132. switch ($_GET['action']) {
  133. case "export" :
  134. $this->product_exporter( 'product' );
  135. break;
  136. case "export_variations" :
  137. $this->product_exporter( 'product_variation' );
  138. break;
  139. }
  140. }
  141. }
  142. /**
  143. * Admin Menu
  144. */
  145. function admin_menu() {
  146. $page = add_submenu_page('woocommerce', __( 'CSV Import Suite', 'wc_csv_import' ), __( 'CSV Import Suite', 'wc_csv_import' ), 'manage_woocommerce', 'woocommerce_csv_import_suite', array($this, 'admin_page') );
  147. //add_action('admin_print_styles-' . $page, array($this, 'admin_scripts'));
  148. }
  149. /**
  150. * Admin Page
  151. */
  152. function admin_scripts() {
  153. global $woocommerce;
  154. wp_enqueue_script( 'woocommerce_admin' );
  155. wp_enqueue_script( 'chosen' );
  156. wp_enqueue_style( 'woocommerce_admin_styles', $woocommerce->plugin_url() . '/assets/css/admin.css' );
  157. wp_register_style( 'woocommerce-csv_importer', plugins_url( basename( plugin_dir_path(__FILE__) ) . '/css/style.css', basename( __FILE__ ) ), '', '1.0.0', 'screen' );
  158. wp_enqueue_style( 'woocommerce-csv_importer' );
  159. }
  160. /**
  161. * Admin Page
  162. */
  163. function admin_page() {
  164. global $woocommerce;
  165. $tab = ( !empty($_GET['tab']) && $_GET['tab'] == 'export' ) ? 'export' : 'import';
  166. ?>
  167. <div class="wrap woocommerce">
  168. <div class="icon32" id="icon-woocommerce-importer"><br></div>
  169. <h2 class="nav-tab-wrapper woo-nav-tab-wrapper">
  170. <a href="<?php echo admin_url('admin.php?page=woocommerce_csv_import_suite') ?>" class="nav-tab <?php echo ($tab == 'import') ? 'nav-tab-active' : ''; ?>"><?php _e('Import Products', 'wc_csv_import'); ?></a><a href="<?php echo admin_url('admin.php?page=woocommerce_csv_import_suite&tab=export') ?>" class="nav-tab <?php echo ($tab == 'export') ? 'nav-tab-active' : ''; ?>"><?php _e('Export Products', 'wc_csv_import'); ?></a>
  171. </h2>
  172. <?php
  173. switch ($tab) {
  174. case "export" :
  175. $this->admin_export_page();
  176. break;
  177. default :
  178. $this->admin_import_page();
  179. break;
  180. }
  181. ?>
  182. </div>
  183. <script type="text/javascript">
  184. jQuery("select.chosen_select").chosen();
  185. </script>
  186. <?php
  187. }
  188. function admin_import_page() {
  189. global $woocommerce;
  190. ?>
  191. <div id="message" class="updated woocommerce-message wc-connect">
  192. <div class="squeezer">
  193. <h4><?php _e( '<strong>Product CSV Import Suite</strong> &#8211; Before getting started prepare your CSV files', 'woocommerce' ); ?></h4>
  194. <p class="submit"><a href="http://www.woothemes.com/woocommerce-docs/user-guide/extensions/product-csv-import-suite/" class="button-primary"><?php _e( 'Documentation', 'woocommerce' ); ?></a> <a class="docs button-primary" href="<?php echo plugins_url( 'sample.csv', __FILE__ ); ?>"><?php _e('Sample CSV', 'woocommerce'); ?></a></p>
  195. <p>
  196. </div>
  197. </div>
  198. <div class="tool-box">
  199. <h3 class="title"><?php _e('Import Product CSV', 'wc_csv_import'); ?></h3>
  200. <p><?php _e('Import simple, grouped, external and variable products into WooCommerce using this tool.', 'wc_csv_import'); ?></p>
  201. <p class="description"><?php _e('Upload a CSV from your computer. Click import to import your CSV as new products (existing products will be skipped), or click merge to merge products, ninja style. Importing requires the <code>post_title</code> column, whilst merging requires <code>sku</code> or <code>id</code>.', 'wc_csv_import'); ?></p>
  202. <p class="submit"><a class="button" href="<?php echo admin_url('admin.php?import=woocommerce_csv'); ?>"><?php _e('Import Products', 'wc_csv_import'); ?></a> <a class="button" href="<?php echo admin_url('admin.php?import=woocommerce_csv&merge=1'); ?>"><?php _e('Merge Products', 'wc_csv_import'); ?></a></p>
  203. </div>
  204. <div class="tool-box">
  205. <h3 class="title"><?php _e('Import Product Variations CSV', 'wc_csv_import'); ?></h3>
  206. <p><?php _e('Import and add variations to your variable products using this tool.', 'wc_csv_import'); ?></p>
  207. <p class="description"><?php _e('Each row must be mapped to a variable product via a <code>post_parent</code> or <code>parent_sku</code> column in order to import successfully. Merging also requires a <code>sku</code> or <code>id</code> column.', 'wc_csv_import'); ?></p>
  208. <p class="submit"><a class="button" href="<?php echo admin_url('admin.php?import=woocommerce_variation_csv'); ?>"><?php _e('Import Variations', 'wc_csv_import'); ?></a> <a class="button" href="<?php echo admin_url('admin.php?import=woocommerce_variation_csv&merge=1'); ?>"><?php _e('Merge Variations', 'wc_csv_import'); ?></a></p>
  209. </div>
  210. <?php
  211. }
  212. function admin_export_page() {
  213. global $woocommerce;
  214. ?>
  215. <div class="tool-box">
  216. <h3 class="title"><?php _e('Export Product CSV', 'wc_csv_import'); ?></h3>
  217. <p><?php _e('Export your products using this tool. This exported CSV will be in an importable format.', 'wc_csv_import'); ?></p>
  218. <p class="description"><?php _e('Click export to save your products to your computer.', 'wc_csv_import'); ?></p>
  219. <form action="<?php echo admin_url('admin.php?page=woocommerce_csv_import_suite&action=export'); ?>" method="post">
  220. <table class="form-table">
  221. <tr>
  222. <th>
  223. <label for="v_limit"><?php _e( 'Limit', 'wc_csv_import' ); ?></label>
  224. </th>
  225. <td>
  226. <input type="text" name="limit" id="v_limit" placeholder="<?php _e('Unlimited', 'wc_csv_import'); ?>" class="input-text" />
  227. </td>
  228. </tr>
  229. <tr>
  230. <th>
  231. <label for="v_offset"><?php _e( 'Offset', 'wc_csv_import' ); ?></label>
  232. </th>
  233. <td>
  234. <input type="text" name="offset" id="v_offset" placeholder="<?php _e('0', 'wc_csv_import'); ?>" class="input-text" />
  235. </td>
  236. </tr>
  237. <tr>
  238. <th>
  239. <label for="v_columns"><?php _e( 'Columns', 'wc_csv_import' ); ?></label>
  240. </th>
  241. <td>
  242. <select id="v_columns" name="columns[]" data-placeholder="<?php _e('All Columns', 'wc_csv_import'); ?>" class="chosen_select" multiple="multiple">
  243. <?php
  244. foreach ($this->post_columns as $key => $column) {
  245. echo '<option value="'.$key.'">'.$column.'</option>';
  246. }
  247. echo '<option value="images">'.__('Images (featured and gallery)', 'wc_csv_import').'</option>';
  248. echo '<option value="taxonomies">'.__('Taxonomies (cat/tags/shipping-class)', 'wc_csv_import').'</option>';
  249. echo '<option value="attributes">'.__('Attributes', 'wc_csv_import').'</option>';
  250. echo '<option value="meta">'.__('Meta (custom fields)', 'wc_csv_import').'</option>';
  251. ?>
  252. </select>
  253. </td>
  254. </tr>
  255. </table>
  256. <p class="submit"><input type="submit" class="button" value="<?php _e('Export Products', 'wc_csv_import'); ?>" /></p>
  257. </form>
  258. </div>
  259. <div class="tool-box">
  260. <h3 class="title"><?php _e('Export Product Variations CSV', 'wc_csv_import'); ?></h3>
  261. <p><?php _e('Export your product variations using this tool. This exported CSV will be in an importable format.', 'wc_csv_import'); ?></p>
  262. <p class="description"><?php _e('Click export to save your products variations to your computer.', 'wc_csv_import'); ?></p>
  263. <form action="<?php echo admin_url('admin.php?page=woocommerce_csv_import_suite&action=export_variations'); ?>" method="post">
  264. <table class="form-table">
  265. <tr>
  266. <th>
  267. <label for="limit"><?php _e( 'Limit', 'wc_csv_import' ); ?></label>
  268. </th>
  269. <td>
  270. <input type="text" name="limit" id="limit" placeholder="<?php _e('Unlimited', 'wc_csv_import'); ?>" class="input-text" />
  271. </td>
  272. </tr>
  273. <tr>
  274. <th>
  275. <label for="offset"><?php _e( 'Offset', 'wc_csv_import' ); ?></label>
  276. </th>
  277. <td>
  278. <input type="text" name="offset" id="offset" placeholder="<?php _e('0', 'wc_csv_import'); ?>" class="input-text" />
  279. </td>
  280. </tr>
  281. <tr>
  282. <th>
  283. <label for="columns"><?php _e( 'Columns', 'wc_csv_import' ); ?></label>
  284. </th>
  285. <td>
  286. <select id="columns" name="columns[]" data-placeholder="<?php _e('All Columns', 'wc_csv_import'); ?>" class="chosen_select" multiple="multiple">
  287. <?php
  288. foreach ($this->variation_columns as $key => $column) {
  289. echo '<option value="'.$key.'">'.$column.'</option>';
  290. }
  291. echo '<option value="images">'.__('Images (featured and gallery)', 'wc_csv_import').'</option>';
  292. echo '<option value="taxonomies">'.__('Taxonomies (cat/tags/shipping-class)', 'wc_csv_import').'</option>';
  293. echo '<option value="meta">'.__('Meta (custom fields)', 'wc_csv_import').'</option>';
  294. ?>
  295. </select>
  296. </td>
  297. </tr>
  298. </table>
  299. <p class="submit"><input type="submit" class="button" value="<?php _e('Export Variations', 'wc_csv_import'); ?>" /></p>
  300. </form>
  301. </div>
  302. <?php
  303. }
  304. /**
  305. * Product Importer Tool
  306. */
  307. function product_importer() {
  308. if ( ! defined( 'WP_LOAD_IMPORTERS' ) ) return;
  309. // Load Importer API
  310. require_once ABSPATH . 'wp-admin/includes/import.php';
  311. if ( ! class_exists( 'WP_Importer' ) ) {
  312. $class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php';
  313. if ( file_exists( $class_wp_importer ) ) require $class_wp_importer;
  314. }
  315. /**
  316. * Variation Importer Tool
  317. */
  318. function variation_importer() {
  319. if ( ! defined( 'WP_LOAD_IMPORTERS' ) ) return;
  320. // Load Importer API
  321. require_once ABSPATH . 'wp-admin/includes/import.php';
  322. if ( ! class_exists( 'WP_Importer' ) ) {
  323. $class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php';
  324. if ( file_exists( $class_wp_importer ) ) require $class_wp_importer;
  325. }
  326. // includes
  327. require dirname( __FILE__ ) . '/classes/class-wc-product-import.php';
  328. require dirname( __FILE__ ) . '/classes/class-wc-product_variation-import.php';
  329. require dirname( __FILE__ ) . '/classes/class-wc-csv-parser.php';
  330. require dirname( __FILE__ ) . '/classes/class-wc-csv-log.php';
  331. // Dispatch
  332. global $WC_CSV_Product_Import;
  333. $WC_CSV_Product_Import = new WC_CSV_Product_Variation_Import();
  334. $WC_CSV_Product_Import->dispatch();
  335. }
  336. /**
  337. * Product Exporter Tool
  338. */
  339. function product_exporter( $post_type = 'product' ) {
  340. global $wpdb;
  341. $csv_columns = ( $post_type == 'product' ) ? $this->post_columns : $this->variation_columns;
  342. $product_taxonomies = get_object_taxonomies( $post_type, 'name' );
  343. $export_columns = ( ! empty($_POST['columns'] ) ) ? $_POST['columns'] : '';
  344. $product_args = array(
  345. 'numberposts' => ( ! empty($_POST['limit'] ) ) ? intval( $_POST['limit'] ) : -1,
  346. 'post_status' => array( 'publish', 'pending', 'private', 'draft' ),
  347. 'post_type' => $post_type,
  348. 'orderby' => 'ID',
  349. 'order' => 'ASC',
  350. 'offset' => ( ! empty($_POST['offset'] ) ) ? intval( $_POST['offset'] ) : 0
  351. );
  352. if ( $post_type == 'product_variation' ) {
  353. $product_args['orderby'] = 'post_parent menu_order';
  354. }
  355. $products = get_posts( $product_args );
  356. if ( ! $products || is_wp_error( $products ) ) {
  357. $this->errors[] = __('Nothing found to export', 'wc_csv_import');
  358. return;
  359. }
  360. // Get all metadata
  361. $all_meta_keys = $this->get_all_metakeys( $post_type );
  362. $found_attributes = $this->get_all_product_attributes( $post_type );
  363. $wpdb->hide_errors();
  364. @set_time_limit(0);
  365. @ob_clean();
  366. header( 'Content-Type: text/csv; charset=UTF-8' );
  367. header( 'Content-Disposition: attachment; filename=woocommerce-product-export.csv' );
  368. header( 'Pragma: no-cache' );
  369. header( 'Expires: 0' );
  370. $fp = fopen('php://output', 'w');
  371. // Loop products and load meta data
  372. $found_product_meta = array();
  373. // Some of the values may not be usable (e.g. arrays of arrays) but the worse
  374. // that can happen is we get an empty column.
  375. foreach ( $all_meta_keys as $meta ) {
  376. if ( ! $meta ) continue;
  377. if ( ! in_array( $meta, array_keys( $csv_columns ) ) && substr( $meta, 0, 1 ) == '_' ) continue;
  378. $found_product_meta[] = $meta;
  379. }
  380. // Loop products
  381. foreach ( $products as $product ) {
  382. $meta_data = get_post_custom( $product->ID );
  383. $product->meta = new stdClass;
  384. $product->attributes = new stdClass;
  385. // Meta data
  386. foreach ( $meta_data as $meta => $value ) {
  387. if ( ! $meta ) continue;
  388. if ( ! in_array( $meta, array_keys( $csv_columns ) ) && substr( $meta, 0, 1 ) == '_' ) continue;
  389. $meta_value = maybe_unserialize( maybe_unserialize( $value[0] ) );
  390. if ( is_array( $meta_value ) ) {
  391. if ( ! isset( $meta_value[0] ) || is_array( $meta_value[0] ) )
  392. continue; // Can't handle multidimensional arrays
  393. $meta_value = implode( '|', $meta_value );
  394. }
  395. $product->meta->$meta = $this->format_export_meta( $meta_value, $meta );
  396. }
  397. // Product attributes
  398. if ( isset( $meta_data['_product_attributes'][0] ) ) {
  399. $attributes = maybe_unserialize(maybe_unserialize( $meta_data['_product_attributes'][0] ));
  400. if ( ! empty( $attributes ) && is_array( $attributes ) ) foreach ( $attributes as $key => $attribute ) {
  401. if ( ! $key || ! isset( $attribute['position'] ) || ! isset( $attribute['is_visible'] ) || ! isset( $attribute['is_variation'] ) ) continue;
  402. if ( $attribute['is_taxonomy'] == 1 ) {
  403. $terms = wp_get_post_terms( $product->ID, $key, array("fields" => "names") );
  404. if ( !is_wp_error( $terms ) ) {
  405. $attribute_value = implode( '|', $terms );
  406. } else {
  407. $attribute_value = '';
  408. }
  409. } else {
  410. $key = $attribute['name'];
  411. $attribute_value = $attribute['value'];
  412. }
  413. $attribute_data = $attribute['position'] . '|' . $attribute['is_visible'] . '|' . $attribute['is_variation'];
  414. $_default_attributes = isset( $meta_data['_default_attributes'][0] ) ? maybe_unserialize( maybe_unserialize( $meta_data['_default_attributes'][0] ) ) : '';
  415. if ( is_array( $_default_attributes ) ) {
  416. $_default_attribute = isset( $_default_attributes[ $key ] ) ? $_default_attributes[ $key ] : '';
  417. } else {
  418. $_default_attribute = '';
  419. }
  420. $product->attributes->$key = array(
  421. 'value' => $attribute_value,
  422. 'data' => $attribute_data,
  423. 'default' => $_default_attribute
  424. );
  425. }
  426. }
  427. // GPF
  428. if ( isset( $meta_data['_woocommerce_gpf_data'][0] ) ) {
  429. $product->gpf_data = $meta_data['_woocommerce_gpf_data'][0];
  430. }
  431. }
  432. $found_product_meta = array_diff( $found_product_meta, array_keys( $csv_columns ) );
  433. // Variable to hold the CSV data we're exporting
  434. $row = array();
  435. if ( $post_type == 'product_variation' ) {
  436. $row[] = 'Parent';
  437. $row[] = 'parent_sku';
  438. }
  439. // Export header rows
  440. foreach ( $csv_columns as $column => $value ) {
  441. if ( ! $export_columns || in_array( $column, $export_columns ) ) $row[] = esc_attr( $value );
  442. }
  443. // Handle special fields like taxonomies
  444. if ( ! $export_columns || in_array( 'images', $export_columns ) ) {
  445. $row[] = 'images';
  446. }
  447. if ( ! $export_columns || in_array( 'taxonomies', $export_columns ) ) {
  448. foreach ( $product_taxonomies as $taxonomy ) {
  449. if ( strstr( $taxonomy->name, 'pa_' ) ) continue; // Skip attributes
  450. $row[] = 'tax:' . $this->format_data( $taxonomy->name );
  451. }
  452. }
  453. if ( ! $export_columns || in_array( 'meta', $export_columns ) ) {
  454. foreach ( $found_product_meta as $product_meta ) {
  455. $row[] = 'meta:' . $this->format_data( $product_meta );
  456. }
  457. }
  458. if ( ! $export_columns || in_array( 'attributes', $export_columns ) ) {
  459. foreach ( $found_attributes as $attribute ) {
  460. $row[] = 'attribute:' . $this->format_data( $attribute );
  461. $row[] = 'attribute_data:' . $this->format_data( $attribute );
  462. $row[] = 'attribute_default:' . $this->format_data( $attribute );
  463. }
  464. }
  465. if ( function_exists( 'woocommerce_gpf_install' ) ) {
  466. $row[] = 'gpf:availability';
  467. $row[] = 'gpf:condition';
  468. $row[] = 'gpf:brand';
  469. $row[] = 'gpf:product_type';
  470. $row[] = 'gpf:google_product_category';
  471. $row[] = 'gpf:gtin';
  472. $row[] = 'gpf:mpn';
  473. $row[] = 'gpf:gender';
  474. $row[] = 'gpf:age_group';
  475. $row[] = 'gpf:color';
  476. $row[] = 'gpf:size';
  477. }
  478. //$headers[] = '"' . implode( '","', $row ) . '"';
  479. $row = array_map( array( $this, 'wrap_column' ), $row );
  480. fwrite( $fp, implode( ',', $row ) . "\n" );
  481. //fputcsv( $fp, $row, ',', '"' );
  482. unset( $row );
  483. // Loop products
  484. foreach ( $products as $product ) {
  485. $row = array();
  486. if ( $post_type == 'product_variation' ) {
  487. $post_parent_title = get_the_title( $product->post_parent );
  488. if ( ! $post_parent_title ) continue;
  489. $row[] = $this->format_data( $post_parent_title );
  490. $parent_sku = get_post_meta( $product->post_parent, '_sku', true );
  491. $row[] = $parent_sku;
  492. }
  493. // Get column values
  494. foreach ( $csv_columns as $column => $value ) {
  495. if ( ! $export_columns || in_array( $column, $export_columns ) ) {
  496. if ( $post_type == 'product_variation' && $column == '_regular_price' && empty( $product->meta->$column ) )
  497. $column = '_price';
  498. if ( isset( $product->meta->$column ) ) {
  499. $row[] = $this->format_data( $product->meta->$column );
  500. } elseif ( isset( $product->$column ) && ! is_array( $product->$column ) ) {
  501. $row[] = $this->format_data( $product->$column );
  502. } else {
  503. $row[] = '';
  504. }
  505. }
  506. }
  507. // Export images/gallery
  508. if ( ! $export_columns || in_array( 'images', $export_columns ) ) {
  509. $image_file_names = array();
  510. // Featured image
  511. if ( $featured_image_id = get_post_thumbnail_id( $product->ID ) ) {
  512. $image_file_names[] = current( wp_get_attachment_image_src( $featured_image_id, 'full' ) );
  513. }
  514. // Images
  515. $images = get_children( array('post_parent' => $product->ID, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order ID') );
  516. $results = array();
  517. if ( $images ) {
  518. foreach ( $images as $image ) {
  519. if ( $featured_image_id==$image->ID ) continue;
  520. $image_file_names[] = current( wp_get_attachment_image_src( $image->ID, 'full' ) );
  521. }
  522. }
  523. $row[] = implode( '|', $image_file_names );
  524. }
  525. // Export taxonomies
  526. if ( ! $export_columns || in_array( 'taxonomies', $export_columns ) ) {
  527. foreach ( $product_taxonomies as $taxonomy ) {
  528. if ( strstr( $taxonomy->name, 'pa_' ) ) continue; // Skip attributes
  529. $terms = wp_get_post_terms( $product->ID, $taxonomy->name, array("fields" => "names") );
  530. $row[] = $this->format_data( implode( '|', $terms ) );
  531. }
  532. }
  533. // Find and export attributes
  534. if ( ! $export_columns || in_array( 'attributes', $export_columns ) ) {
  535. foreach ( $found_attributes as $attribute ) {
  536. if ( isset( $product->attributes ) && isset( $product->attributes->$attribute ) ) {
  537. $values = $product->attributes->$attribute;
  538. $row[] = $this->format_data( $values['value'] );
  539. $row[] = $this->format_data( $values['data'] );
  540. $row[] = $this->format_data( $values['default'] );
  541. } else {
  542. $row[] = '';
  543. $row[] = '';
  544. $row[] = '';
  545. }
  546. }
  547. }
  548. // Export GPF
  549. if ( function_exists( 'woocommerce_gpf_install' ) ) {
  550. $gpf_data = empty( $product->gpf_data ) ? '' : maybe_unserialize( $product->gpf_data );
  551. $row[] = empty( $gpf_data['availability'] ) ? '' : $gpf_data['availability'];
  552. $row[] = empty( $gpf_data['condition'] ) ? '' : $gpf_data['condition'];
  553. $row[] = empty( $gpf_data['brand'] ) ? '' : $gpf_data['brand'];
  554. $row[] = empty( $gpf_data['product_type'] ) ? '' : $gpf_data['product_type'];
  555. $row[] = empty( $gpf_data['google_product_category'] ) ? '' : $gpf_data['google_product_category'];
  556. $row[] = empty( $gpf_data['gtin'] ) ? '' : $gpf_data['gtin'];
  557. $row[] = empty( $gpf_data['mpn'] ) ? '' : $gpf_data['mpn'];
  558. $row[] = empty( $gpf_data['gender'] ) ? '' : $gpf_data['gender'];
  559. $row[] = empty( $gpf_data['age_group'] ) ? '' : $gpf_data['age_group'];
  560. $row[] = empty( $gpf_data['color'] ) ? '' : $gpf_data['color'];
  561. $row[] = empty( $gpf_data['size'] ) ? '' : $gpf_data['size'];
  562. }
  563. // Add to csv
  564. //$csv[] = '"' . implode( '","', $row ) . '"';
  565. $row = array_map( array( $this, 'wrap_column' ), $row );
  566. fwrite( $fp, implode( ',', $row ) . "\n" );
  567. //fputcsv( $fp, $row, ',', '"' );
  568. unset( $row );
  569. }
  570. fclose( $fp );
  571. exit;
  572. }
  573. function format_export_meta( $meta_value, $meta ) {
  574. if ( $meta == '_sale_price_dates_from' || $meta == '_sale_price_dates_to' ) {
  575. if ( $meta_value ) return date( 'Y-m-d', $meta_value );
  576. }
  577. return $meta_value;
  578. }
  579. function format_data( $data ) {
  580. $data = (string) $data;
  581. $enc = mb_detect_encoding( $data, 'UTF-8, ISO-8859-1', true );
  582. $data = ( $enc == 'UTF-8' ) ? $data : utf8_encode( $data );
  583. return $data;
  584. }
  585. function wrap_column( $data ) {
  586. return '"' . str_replace( '"', '""', $data ) . '"';
  587. }
  588. /**
  589. * Get a list of all the meta keys for a post type. This includes all public, private,
  590. * used, no-longer used etc. They will be sorted once fetched.
  591. */
  592. function get_all_metakeys( $post_type = 'product' ) {
  593. global $wpdb;
  594. $meta = $wpdb->get_col( $wpdb->prepare(
  595. "SELECT DISTINCT pm.meta_key
  596. FROM {$wpdb->postmeta} AS pm
  597. LEFT JOIN {$wpdb->posts} AS p ON p.ID = pm.post_id
  598. WHERE p.post_type = %s
  599. AND p.post_status IN ( 'publish', 'pending', 'private', 'draft' )",
  600. $post_type
  601. ) );
  602. sort( $meta );
  603. return $meta;
  604. }
  605. /**
  606. * Get a list of all the product attributes for a post type.
  607. * These require a bit more digging into the values.
  608. */
  609. function get_all_product_attributes( $post_type = 'product' ) {
  610. global $wpdb;
  611. $results = $wpdb->get_col( $wpdb->prepare(
  612. "SELECT DISTINCT pm.meta_value
  613. FROM {$wpdb->postmeta} AS pm
  614. LEFT JOIN {$wpdb->posts} AS p ON p.ID = pm.post_id
  615. WHERE p.post_type = %s
  616. AND p.post_status IN ( 'publish', 'pending', 'private', 'draft' )
  617. AND pm.meta_key = '_product_attributes'",
  618. $post_type
  619. ) );
  620. // Go through each result, and look at the attribute keys within them.
  621. $result = array();
  622. if ( ! empty( $results ) ) {
  623. foreach( $results as $_product_attributes ) {
  624. $attributes = maybe_unserialize( maybe_unserialize( $_product_attributes ) );
  625. if ( ! empty( $attributes ) && is_array( $attributes ) ) {
  626. foreach( $attributes as $key => $attribute ) {
  627. if ( ! $key || ! isset( $attribute['position'] ) || ! isset( $attribute['is_visible'] ) || ! isset( $attribute['is_variation'] ) )
  628. continue;
  629. if ( ! strstr( $key, 'pa_' ) )
  630. $key = $attribute['name'];
  631. $result[ $key ] = $key;
  632. }
  633. }
  634. }
  635. }
  636. sort( $result );
  637. return $result;
  638. }
  639. }
  640. }
  641. $GLOBALS['wc_product_csv_import'] = new WC_Product_CSV_Import_Suite();
  642. }