Import users from CSV with meta - Version 1.18

Version Description

  • Export in backend and frontend now works using step by step process using client calls to avoid gateway timeouts and other kind of timing limits in very long process
  • Addon for WP User Manager improved to avoid redirection loop
Download this release

Release Info

Developer carazo
Plugin Icon 128x128 Import users from CSV with meta
Version 1.18
Comparing to
See all releases

Code changes from version 1.17.9 to 1.18

addons/wp-user-manager.php CHANGED
@@ -9,8 +9,9 @@ class ACUI_WP_User_Manager{
9
  function __construct(){
10
  add_filter( 'acui_force_reset_password_edit_profile_url', array( $this, 'force_reset_password_edit_profile_url' ) );
11
  add_filter( 'acui_force_reset_password_redirect_condition', array( $this, 'force_reset_password_redirect_condition' ), 10 , 1 );
12
- add_action( 'wpum_account_page_content', array( $this, 'force_reset_password_notice' ), 0 );
13
  add_action( 'wpum_after_user_password_recovery', array( $this, 'force_reset_save_account_details' ) );
 
14
  }
15
 
16
  function force_reset_password_edit_profile_url(){
@@ -36,5 +37,13 @@ class ACUI_WP_User_Manager{
36
  function force_reset_save_account_details( $user_id ){
37
  delete_user_meta( $user_id, 'acui_force_reset_password' );
38
  }
 
 
 
 
 
 
 
 
39
  }
40
  new ACUI_WP_User_Manager();
9
  function __construct(){
10
  add_filter( 'acui_force_reset_password_edit_profile_url', array( $this, 'force_reset_password_edit_profile_url' ) );
11
  add_filter( 'acui_force_reset_password_redirect_condition', array( $this, 'force_reset_password_redirect_condition' ), 10 , 1 );
12
+ add_action( 'wpum_account_page_content', array( $this, 'force_reset_password_notice' ), 1 );
13
  add_action( 'wpum_after_user_password_recovery', array( $this, 'force_reset_save_account_details' ) );
14
+ add_action( 'wpum_account_page_content', array( $this, 'maybe_force_reset_save_account_details' ), 0 );
15
  }
16
 
17
  function force_reset_password_edit_profile_url(){
37
  function force_reset_save_account_details( $user_id ){
38
  delete_user_meta( $user_id, 'acui_force_reset_password' );
39
  }
40
+
41
+ function maybe_force_reset_save_account_details(){
42
+ if( !isset( $_GET ) || empty( $_GET ) )
43
+ return;
44
+
45
+ if( isset( $_GET['password-updated'] ) && $_GET['password-updated'] == 'success' && isset( $_GET['tab'] ) && $_GET['tab'] == 'password' )
46
+ delete_user_meta( get_current_user_id(), 'acui_force_reset_password' );
47
+ }
48
  }
49
  new ACUI_WP_User_Manager();
assets/export.js ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ;(function ( $, window ) {
2
+ var userExportForm = function( $form ) {
3
+ this.$form = $form;
4
+ this.xhr = false;
5
+
6
+ this.$form.find( '.user-exporter-progress' ).val( 0 );
7
+ this.processStep = this.processStep.bind( this );
8
+ $form.on( 'submit', { userExportForm: this }, this.onSubmit );
9
+ };
10
+
11
+ userExportForm.prototype.onSubmit = function( event ) {
12
+ event.preventDefault();
13
+
14
+ $( "html, body" ).animate({ scrollTop: 0 }, "slow" );
15
+
16
+ var currentDate = new Date(),
17
+ day = currentDate.getDate(),
18
+ month = currentDate.getMonth() + 1,
19
+ year = currentDate.getFullYear(),
20
+ timestamp = currentDate.getTime(),
21
+ filename = 'user-export-' + day + '-' + month + '-' + year + '-' + timestamp + '.csv';
22
+
23
+ event.data.userExportForm.$form.addClass( 'user-exporter__exporting' );
24
+ event.data.userExportForm.$form.find( '.user-exporter-progress' ).val( 0 );
25
+ event.data.userExportForm.$form.find( '.user-exporter-progress-value' ).text( acui_export_js_object.starting_process + " - 0%" );
26
+ event.data.userExportForm.processStep( 1, $( this ).serialize(), '', filename );
27
+ };
28
+
29
+ userExportForm.prototype.processStep = function( step, data, filename ) {
30
+ var $this = this;
31
+ var frontend = $( '[name="acui_frontend_export"]' ).val();
32
+ var convert_timestamp, order_fields_alphabetically, double_encapsulate_serialized_values;
33
+
34
+ if( frontend == 1 ){
35
+ convert_timestamp = $this.$form.find( '[name="convert_timestamp"]' ).val();
36
+ order_fields_alphabetically = $this.$form.find( '[name="order_fields_alphabetically"]' ).val();
37
+ double_encapsulate_serialized_values = $this.$form.find( '[name="double_encapsulate_serialized_values"]' ).val();
38
+ }
39
+ else{
40
+ convert_timestamp = $this.$form.find( '[name="convert_timestamp"]' ).is( ":checked");
41
+ order_fields_alphabetically = $this.$form.find( '[name="order_fields_alphabetically"]' ).is( ":checked");
42
+ double_encapsulate_serialized_values = $this.$form.find( '[name="double_encapsulate_serialized_values"]' ).is( ":checked");
43
+ }
44
+
45
+ $.ajax( {
46
+ type: 'POST',
47
+ url: acui_export_js_object.ajaxurl,
48
+ data: {
49
+ form: data,
50
+ action: 'acui_export_users_csv',
51
+ step: step,
52
+ filename: filename,
53
+ delimiter: $this.$form.find( '[name="delimiter"]' ).val(),
54
+ role: $this.$form.find( '[name="role"]' ).val(),
55
+ from: $this.$form.find( '[name="from"]' ).val(),
56
+ to: $this.$form.find( '[name="to"]' ).val(),
57
+ convert_timestamp: convert_timestamp,
58
+ datetime_format: $this.$form.find( '[name="datetime_format"]' ).val(),
59
+ order_fields_alphabetically: order_fields_alphabetically,
60
+ double_encapsulate_serialized_values: double_encapsulate_serialized_values,
61
+ columns: $this.$form.find( '[name="columns"]' ).val(),
62
+ orderby: $this.$form.find( '[name="orderby"]' ).val(),
63
+ order: $this.$form.find( '[name="order"]' ).val(),
64
+ security: $this.$form.find( '#security' ).val(),
65
+ },
66
+ dataType: 'json',
67
+ success: function( response ) {
68
+ if ( response.success ) {
69
+ if ( 'done' === response.data.step ) {
70
+ $this.$form.find('.user-exporter-progress').val( response.data.percentage );
71
+ $this.$form.find('.user-exporter-progress-value').text( response.data.percentage + "%" );
72
+ window.location = response.data.url;
73
+ setTimeout( function() {
74
+ $this.$form.removeClass( 'user-exporter__exporting' );
75
+ $( '#acui_download_csv_wrapper > td > input' ).prop( 'disabled', false );
76
+ }, 2000 );
77
+ } else {
78
+ $this.$form.find( '.user-exporter-progress' ).val( response.data.percentage );
79
+ $this.$form.find( '.user-exporter-progress-value' ).text( acui_export_js_object.step + " " + response.data.step + " " + acui_export_js_object.of_approximately + " " + response.data.total_steps + " " + acui_export_js_object.steps + " - " + response.data.percentage + "%" );
80
+ $this.processStep( parseInt( response.data.step, 10 ), data, filename );
81
+ }
82
+ }
83
+ }
84
+ } ).fail( function( response ) {
85
+ window.console.log( response );
86
+ } );
87
+ };
88
+
89
+ $.fn.user_export_form = function() {
90
+ new userExportForm( this );
91
+ return this;
92
+ };
93
+
94
+ $( '#acui_exporter' ).user_export_form();
95
+ })( jQuery, window );
assets/style.css CHANGED
@@ -87,4 +87,52 @@
87
  background: none;
88
  line-height: 1;
89
  min-height: 13px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  }
87
  background: none;
88
  line-height: 1;
89
  min-height: 13px;
90
+ }
91
+
92
+ #acui_exporter .user-exporter-progress-wrapper{
93
+ padding: 5px;
94
+ background-color: white;
95
+ width: 80%;
96
+ margin: 0 auto;
97
+ text-align: center;
98
+ }
99
+
100
+ #acui_exporter .user-exporter-progress{
101
+ width: 100%;
102
+ height: 42px;
103
+ border: 0;
104
+ border-radius: 9px;
105
+ }
106
+ .user-exporter-progress::-webkit-progress-bar {
107
+ background-color: #f3f3f3;
108
+ border-radius: 9px;
109
+ }
110
+
111
+ .user-exporter-progress::-webkit-progress-value {
112
+ background: #2271b1;
113
+ border-radius: 9px;
114
+ }
115
+
116
+ .user-exporter-progress::-moz-progress-bar {
117
+ background: #2271b1;
118
+ border-radius: 9px;
119
+ }
120
+
121
+ .user-exporter-progress .progress-value {
122
+ padding: 0px 5px;
123
+ line-height: 20px;
124
+ margin-left: 5px;
125
+ font-size: .8em;
126
+ color: #555;
127
+ height: 18px;
128
+ float: right;
129
+ }
130
+
131
+ #acui_exporter.user-exporter__exporting table,
132
+ #acui_exporter .user-exporter-progress-wrapper{
133
+ display: none;
134
+ }
135
+
136
+ #acui_exporter.user-exporter__exporting .user-exporter-progress-wrapper{
137
+ display: block;
138
  }
classes/batch_exporter.php ADDED
@@ -0,0 +1,654 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit;
5
+ }
6
+
7
+ class ACUI_Batch_Exporter{
8
+ protected $filename = 'user-export.csv';
9
+ protected $limit = 50;
10
+ protected $exported_row_count = 0;
11
+ protected $row_data = array();
12
+ protected $total_rows = 0;
13
+ protected $columns_to_export = array();
14
+
15
+ protected $page = 1;
16
+ protected $delimiter = ',';
17
+ protected $role = '';
18
+ protected $from = '';
19
+ protected $to = '';
20
+ protected $convert_timestamp = false;
21
+ protected $datetime_format;
22
+ protected $order_fields_alphabetically = false;
23
+ protected $double_encapsulate_serialized_values = false;
24
+ protected $filtered_columns = array();
25
+ protected $orderby = '';
26
+ protected $order = '';
27
+
28
+ protected $user_data;
29
+ protected $accepted_order_by;
30
+ protected $woocommerce_default_user_meta_keys;
31
+ protected $other_non_date_keys;
32
+
33
+ function __construct() {
34
+ add_filter( 'acui_export_non_date_keys', array( $this, 'get_non_date_keys' ), 1, 1 );
35
+ add_filter( 'acui_export_columns', array( $this, 'maybe_order_columns_alphabetacally' ), 10, 2 );
36
+ add_filter( 'acui_export_get_key_user_data', array( $this, 'filter_key_user_id' ) );
37
+ add_filter( 'acui_export_columns', array( $this, 'maybe_order_columns_filtered_columns_parameter' ), 11, 2 );
38
+ add_filter( 'acui_export_data', array( $this, 'maybe_double_encapsulate_serialized_values' ), 9 - 1, 5 );
39
+ add_filter( 'acui_export_data', array( $this, 'maybe_order_row_alphabetically' ), 10, 5 );
40
+ add_filter( 'acui_export_data', array( $this, 'maybe_order_row_filtered_columns_parameter' ), 11, 5 );
41
+
42
+ $this->user_data = array( "user_login", "user_email", "source_user_id", "user_pass", "user_nicename", "user_url", "user_registered", "display_name" );
43
+ $this->accepted_order_by = array( 'ID', 'display_name', 'name', 'user_name', 'login', 'user_login', 'nicename', 'user_nicename', 'email', 'user_email', 'url', 'user_url', 'registered', 'user_registered', 'post_count' );
44
+ $this->woocommerce_default_user_meta_keys = array( 'billing_first_name', 'billing_last_name', 'billing_email', 'billing_phone', 'billing_country', 'billing_address_1', 'billing_city', 'billing_state', 'billing_postcode', 'shipping_first_name', 'shipping_last_name', 'shipping_country', 'shipping_address_1', 'shipping_address_2', 'shipping_city', 'shipping_state', 'shipping_postcode' );
45
+ $this->other_non_date_keys = array( 'shipping_phone', '_vat_number', '_billing_vat_number' );
46
+ $this->total_rows = $this->get_total_rows();
47
+ }
48
+
49
+ function get_non_date_keys( $non_date_keys ){
50
+ return array_merge( $non_date_keys, $this->user_data, $this->woocommerce_default_user_meta_keys, $this->other_non_date_keys );
51
+ }
52
+
53
+ function maybe_order_columns_alphabetacally( $row, $args ){
54
+ if( !$args['order_fields_alphabetically'] )
55
+ return $row;
56
+
57
+ $first_two_columns = array_slice( $row, 0, 2 );
58
+ $to_order_columns = array_unique( array_slice( $row, 2 ) );
59
+ sort( $to_order_columns, SORT_LOCALE_STRING );
60
+
61
+ return array_merge( $first_two_columns, $to_order_columns );
62
+ }
63
+
64
+ function filter_key_user_id( $key ){
65
+ return ( $key == 'source_user_id' ) ? 'ID' : $key;
66
+ }
67
+
68
+ function maybe_order_columns_filtered_columns_parameter( $row, $args ){
69
+ return ( !is_array( $args['filtered_columns'] ) || count( $args['filtered_columns'] ) == 0 ) ? $row : $args['filtered_columns'];
70
+ }
71
+
72
+ function maybe_order_row_alphabetically( $row, $user, $datetime_format, $columns, $args ){
73
+ if( !$args['order_fields_alphabetically'] )
74
+ return $row;
75
+
76
+ $row_sorted = array();
77
+ foreach( $columns as $field ){
78
+ $row_sorted[ $field ] = $row[ $field ];
79
+ }
80
+
81
+ return $row_sorted;
82
+ }
83
+
84
+ function maybe_order_row_filtered_columns_parameter( $row, $user, $datetime_format, $columns, $args ){
85
+ if( !is_array( $args['filtered_columns'] ) || count( $args['filtered_columns'] ) == 0 )
86
+ return $row;
87
+
88
+ $row_sorted = array();
89
+ foreach( $args['filtered_columns'] as $field ){
90
+ $row_sorted[ $field ] = $row[ $field ];
91
+ }
92
+
93
+ return $row_sorted;
94
+ }
95
+
96
+ function maybe_double_encapsulate_serialized_values( $row, $user, $datetime_format, $columns, $args ){
97
+ if( !$args['double_encapsulate_serialized_values'] )
98
+ return $row;
99
+
100
+ foreach( $columns as $field ){
101
+ if( is_serialized( $row[ $field ] ) )
102
+ $row[ $field ] = '"' . $row[ $field ] . '"';
103
+ }
104
+
105
+ return $row;
106
+ }
107
+
108
+ function load_columns(){
109
+ $row = array();
110
+
111
+ foreach ( $this->get_user_data() as $key ) {
112
+ $row[] = $key;
113
+ }
114
+
115
+ if( count( $this->get_filtered_columns() ) == 0 || in_array( 'role', $this->get_filtered_columns() ) )
116
+ $row[] = "role";
117
+
118
+ foreach ( $this->get_user_meta_keys() as $key ) {
119
+ $row[] = $key;
120
+ }
121
+
122
+ $this->set_columns_to_export( apply_filters( 'acui_export_columns', $row, array( 'order_fields_alphabetically' => $this->get_order_fields_alphabetically(), 'double_encapsulate_serialized_values' => $this->get_double_encapsulate_serialized_values(), 'filtered_columns' => $this->get_filtered_columns() ) ) );
123
+ }
124
+
125
+ function set_columns_to_export( $columns ) {
126
+ $this->columns_to_export = $columns;
127
+ }
128
+
129
+ function get_columns_to_export() {
130
+ return $this->columns_to_export;
131
+ }
132
+
133
+ function set_delimiter( $delimiter ){
134
+ switch ( $delimiter ) {
135
+ case 'COMMA':
136
+ $this->delimiter = ",";
137
+ break;
138
+
139
+ case 'COLON':
140
+ $this->delimiter = ":";
141
+ break;
142
+
143
+ case 'SEMICOLON':
144
+ $this->delimiter = ";";
145
+ break;
146
+
147
+ case 'TAB':
148
+ $this->delimiter = "\t";
149
+ break;
150
+
151
+ default:
152
+ $this->delimiter = ",";
153
+ break;
154
+ }
155
+ }
156
+
157
+ function get_delimiter() {
158
+ return $this->delimiter;
159
+ }
160
+
161
+ function set_role( $role ){
162
+ $this->role = $role;
163
+ }
164
+
165
+ function get_role(){
166
+ return $this->role;
167
+ }
168
+
169
+ function set_from( $from ){
170
+ $this->from = $from;
171
+ }
172
+
173
+ function get_from(){
174
+ return $this->from;
175
+ }
176
+
177
+ function set_to( $to ){
178
+ $this->to = $to;
179
+ }
180
+
181
+ function get_to(){
182
+ return $this->to;
183
+ }
184
+
185
+ function set_convert_timestamp( $convert_timestamp ){
186
+ $this->convert_timestamp = filter_var( $convert_timestamp, FILTER_VALIDATE_BOOLEAN );
187
+ }
188
+
189
+ function get_convert_timestamp(){
190
+ return $this->convert_timestamp;
191
+ }
192
+
193
+ function set_datetime_format( $datetime_format ){
194
+ $this->datetime_format = $datetime_format;
195
+ }
196
+
197
+ function get_datetime_format(){
198
+ return $this->datetime_format;
199
+ }
200
+
201
+ function set_order_fields_alphabetically( $order_fields_alphabetically ){
202
+ $this->order_fields_alphabetically = filter_var( $order_fields_alphabetically, FILTER_VALIDATE_BOOLEAN );
203
+ }
204
+
205
+ function get_order_fields_alphabetically(){
206
+ return $this->order_fields_alphabetically;
207
+ }
208
+
209
+ function set_double_encapsulate_serialized_values( $double_encapsulate_serialized_values ){
210
+ $this->double_encapsulate_serialized_values = filter_var( $double_encapsulate_serialized_values, FILTER_VALIDATE_BOOLEAN );
211
+ }
212
+
213
+ function get_double_encapsulate_serialized_values(){
214
+ return $this->double_encapsulate_serialized_values;
215
+ }
216
+
217
+ function set_filtered_columns( $filtered_columns ){
218
+ $filtered_columns = ( is_array( $filtered_columns ) ) ? array_walk( $filtered_columns, 'sanitize_text_field' ) : explode( ',', sanitize_text_field( $filtered_columns ) );
219
+
220
+ if( empty( $filtered_columns[0] ) )
221
+ $filtered_columns = array();
222
+
223
+ $this->filtered_columns = $filtered_columns;
224
+ }
225
+
226
+ function get_filtered_columns(){
227
+ return $this->filtered_columns;
228
+ }
229
+
230
+ function set_orderby( $orderby ){
231
+ $this->orderby = $orderby;
232
+ }
233
+
234
+ function get_orderby(){
235
+ return $this->orderby;
236
+ }
237
+
238
+ function set_order( $order ){
239
+ $this->order = $order;
240
+ }
241
+
242
+ function get_order(){
243
+ return $this->order;
244
+ }
245
+
246
+ function get_total_rows(){
247
+ $total_rows = get_transient( 'acui_export_total_rows' );
248
+
249
+ if( empty( $total_rows ) ){
250
+ $this->total_rows = $this->calculate_total();
251
+ }
252
+ else{
253
+ $this->total_rows = $total_rows;
254
+ }
255
+
256
+ return $this->total_rows;
257
+ }
258
+
259
+ function get_total_steps(){
260
+ return floor( $this->get_total_rows() / $this->get_limit() ) + 1;
261
+ }
262
+
263
+ function set_time_limit( $limit = 0 ) {
264
+ if ( function_exists( 'set_time_limit' ) && false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) { // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved
265
+ @set_time_limit( $limit );
266
+ }
267
+ }
268
+
269
+ function send_headers() {
270
+ if ( function_exists( 'gc_enable' ) ) {
271
+ gc_enable();
272
+ }
273
+ if ( function_exists( 'apache_setenv' ) ) {
274
+ @apache_setenv( 'no-gzip', 1 );
275
+ }
276
+ @ini_set( 'zlib.output_compression', 'Off' );
277
+ @ini_set( 'output_buffering', 'Off' );
278
+ @ini_set( 'output_handler', '' );
279
+ ignore_user_abort( true );
280
+ $this->set_time_limit( 0 );
281
+ wc_nocache_headers();
282
+ header( 'Content-Type: text/csv; charset=utf-8' );
283
+ header( 'Content-Disposition: attachment; filename=' . $this->get_filename() );
284
+ header( 'Pragma: no-cache' );
285
+ header( 'Expires: 0' );
286
+ }
287
+
288
+ function set_filename( $filename ) {
289
+ $this->filename = sanitize_file_name( str_replace( '.csv', '', $filename ) . '.csv' );
290
+ }
291
+
292
+ function get_filename() {
293
+ return sanitize_file_name( $this->filename );
294
+ }
295
+
296
+ function send_content( $csv_data ) {
297
+ echo $csv_data;
298
+ }
299
+
300
+ protected function get_csv_data() {
301
+ return $this->export_rows();
302
+ }
303
+
304
+ protected function export_column_headers() {
305
+ $columns = $this->get_columns_to_export();
306
+ $export_row = array();
307
+ $buffer = fopen( 'php://output', 'w' );
308
+ ob_start();
309
+
310
+ foreach ( $columns as $column_name ) {
311
+ $export_row[] = $this->format_data( $column_name );
312
+ }
313
+
314
+ $this->fputcsv( $buffer, $export_row );
315
+
316
+ return ob_get_clean();
317
+ }
318
+
319
+ protected function get_data_to_export() {
320
+ return $this->row_data;
321
+ }
322
+
323
+ protected function export_rows() {
324
+ $data = $this->get_data_to_export();
325
+ $buffer = fopen( 'php://output', 'w' );
326
+ ob_start();
327
+
328
+ array_walk( $data, array( $this, 'export_row' ), $buffer );
329
+
330
+ return ob_get_clean();
331
+ }
332
+
333
+ protected function export_row( $row_data, $key, $buffer ) {
334
+ $this->fputcsv( $buffer, $row_data );
335
+ ++ $this->exported_row_count;
336
+ }
337
+
338
+ function get_limit() {
339
+ return $this->limit;
340
+ }
341
+
342
+ function set_limit( $limit ) {
343
+ $this->limit = absint( $limit );
344
+ }
345
+
346
+ function escape_data( $data ) {
347
+ $active_content_triggers = array( '=', '+', '-', '@' );
348
+
349
+ if ( in_array( mb_substr( $data, 0, 1 ), $active_content_triggers, true ) ) {
350
+ $data = "'" . $data;
351
+ }
352
+
353
+ return $data;
354
+ }
355
+
356
+ function format_data( $data ) {
357
+ if ( is_bool( $data ) ) {
358
+ $data = $data ? 1 : 0;
359
+ }
360
+
361
+ $use_mb = function_exists( 'mb_convert_encoding' );
362
+ if ( $use_mb ) {
363
+ $encoding = mb_detect_encoding( $data, 'UTF-8, ISO-8859-1', true );
364
+ $data = 'UTF-8' === $encoding ? $data : utf8_encode( $data );
365
+ }
366
+
367
+ return $this->escape_data( $data );
368
+ }
369
+
370
+ protected function implode_values( $values ) {
371
+ $values_to_implode = array();
372
+
373
+ foreach ( $values as $value ) {
374
+ $value = (string) is_scalar( $value ) ? $value : '';
375
+ $values_to_implode[] = str_replace( ',', '\\,', $value );
376
+ }
377
+
378
+ return implode( ', ', $values_to_implode );
379
+ }
380
+
381
+ protected function fputcsv( $buffer, $export_row ) {
382
+ if ( version_compare( PHP_VERSION, '5.5.4', '<' ) ) {
383
+ ob_start();
384
+ $temp = fopen( 'php://output', 'w' );
385
+ fputcsv( $temp, $export_row, $this->get_delimiter(), '"' );
386
+ fclose( $temp );
387
+ $row = ob_get_clean();
388
+ $row = str_replace( '\\"', '\\""', $row );
389
+ fwrite( $buffer, $row );
390
+ } else {
391
+ fputcsv( $buffer, $export_row, $this->get_delimiter(), '"', "\0" );
392
+ }
393
+ }
394
+
395
+ protected function get_file_path() {
396
+ $upload_dir = wp_upload_dir();
397
+ return trailingslashit( $upload_dir['basedir'] ) . $this->get_filename();
398
+ }
399
+
400
+ protected function get_headers_row_file_path() {
401
+ return $this->get_file_path() . '.headers';
402
+ }
403
+
404
+ function get_headers_row_file() {
405
+ $file = chr( 239 ) . chr( 187 ) . chr( 191 ) . $this->export_column_headers();
406
+
407
+ if ( @file_exists( $this->get_headers_row_file_path() ) ){
408
+ $file = @file_get_contents( $this->get_headers_row_file_path() );
409
+ }
410
+
411
+ return $file;
412
+ }
413
+
414
+ function get_file() {
415
+ $file = '';
416
+ if ( @file_exists( $this->get_file_path() ) ){
417
+ $file = @file_get_contents( $this->get_file_path() );
418
+ } else {
419
+ @file_put_contents( $this->get_file_path(), '' );
420
+ @chmod( $this->get_file_path(), 0664 );
421
+ }
422
+ return $file;
423
+ }
424
+
425
+ function export() {
426
+ $this->send_headers();
427
+ $this->send_content( $this->get_headers_row_file() . $this->get_file() );
428
+ @unlink( $this->get_file_path() );
429
+ @unlink( $this->get_headers_row_file_path() );
430
+ die();
431
+ }
432
+
433
+ function generate_file() {
434
+ if( 1 === $this->get_page() ){
435
+ @unlink( $this->get_file_path() );
436
+
437
+ $this->get_file();
438
+ }
439
+ $this->prepare_data_to_export();
440
+ $this->write_csv_data( $this->get_csv_data() );
441
+ }
442
+
443
+ function calculate_total(){
444
+ $total_rows = count( $this->get_user_id_list( true ) );
445
+ set_transient( 'acui_export_total_rows', $total_rows, HOUR_IN_SECONDS );
446
+
447
+ return $total_rows;
448
+ }
449
+
450
+ protected function write_csv_data( $data ) {
451
+ if ( ! file_exists( $this->get_file_path() ) || ! is_writeable( $this->get_file_path() ) ) {
452
+ return false;
453
+ }
454
+
455
+ $fp = fopen( $this->get_file_path(), 'a+' );
456
+
457
+ if ( $fp ) {
458
+ fwrite( $fp, $data );
459
+ fclose( $fp );
460
+ }
461
+
462
+ if ( 100 <= $this->get_percent_complete() ) {
463
+ $header = chr( 239 ) . chr( 187 ) . chr( 191 ) . $this->export_column_headers();
464
+
465
+ @file_put_contents( $this->get_headers_row_file_path(), $header );
466
+ }
467
+
468
+ }
469
+
470
+ function get_page() {
471
+ return $this->page;
472
+ }
473
+
474
+ function set_page( $page ) {
475
+ $this->page = absint( $page );
476
+ }
477
+
478
+ function get_total_exported() {
479
+ return ( ( $this->get_page() - 1 ) * $this->get_limit() ) + $this->exported_row_count;
480
+ }
481
+
482
+ function get_percent_complete() {
483
+ return $this->get_total_rows() ? floor( ( $this->get_total_exported() / $this->get_total_rows() ) * 100 ) : 100;
484
+ }
485
+
486
+ function get_user_data(){
487
+ if( count( $this->get_filtered_columns() ) == 0 )
488
+ return $this->user_data;
489
+
490
+ $result = array();
491
+ foreach( $this->user_data as $column ){
492
+ if( in_array( $column, $this->get_filtered_columns() ) )
493
+ $result[] = $column;
494
+ }
495
+
496
+ return $result;
497
+ }
498
+
499
+ function get_user_id_list( $calculate_total = false ){
500
+ $args = array( 'fields' => array( 'ID' ), 'order' => $this->get_order() );
501
+
502
+ if( !$calculate_total ){
503
+ $args['number' ] = $this->get_limit();
504
+ $args['offset'] = ($this->get_page() - 1) * $this->get_limit();
505
+ }
506
+
507
+ if( !empty( $this->get_role() ) )
508
+ $args['role'] = $this->get_role();
509
+
510
+ $date_query = array();
511
+
512
+ if( !empty( $this->get_from() ) )
513
+ $date_query[] = array( 'after' => $this->get_from() );
514
+
515
+ if( !empty( $this->get_to() ) )
516
+ $date_query[] = array( 'before' => $this->get_to() );
517
+
518
+ if( !empty( $date_query ) ){
519
+ $date_query['inclusive'] = true;
520
+ $args['date_query'] = $date_query;
521
+ }
522
+
523
+ if( !empty( $this->get_orderby() ) ){
524
+ if( in_array( $this->get_orderby(), $this->accepted_order_by ) )
525
+ $args['orderby'] = $this->get_orderby();
526
+ else{
527
+ $args['orderby'] = "meta_value";
528
+ $args['meta_key'] = $this->get_orderby();
529
+ }
530
+ }
531
+
532
+ $users = get_users( $args );
533
+
534
+ if( $calculate_total )
535
+ return $users;
536
+
537
+ $list = array();
538
+
539
+ foreach ( $users as $user ) {
540
+ $list[] = $user->ID;
541
+ }
542
+
543
+ return $list;
544
+ }
545
+
546
+ function prepare_data_to_export() {
547
+ $users = $this->get_user_id_list();
548
+ $this->row_data = array();
549
+
550
+ foreach ( $users as $user ) {
551
+ $row = array();
552
+ $userdata = get_userdata( $user );
553
+
554
+ foreach ( $this->get_user_data( $this->get_filtered_columns() ) as $key ) {
555
+ $key = apply_filters( 'acui_export_get_key_user_data', $key );
556
+ $row[ $key ] = $this->prepare( $key, $userdata->data->{$key}, $this->get_datetime_format(), $user );
557
+ }
558
+
559
+ if( count( $this->get_filtered_columns() ) == 0 || in_array( 'role', $this->get_filtered_columns() ) )
560
+ $row[] = $this->get_role( $user );
561
+
562
+ foreach ( $this->get_user_meta_keys( $this->get_filtered_columns() ) as $key ) {
563
+ $row[ $key ] = $this->prepare( $key, get_user_meta( $user, $key, true ), $this->get_datetime_format(), $user );
564
+ }
565
+
566
+ if( count( $this->get_filtered_columns() ) == 0 || in_array( 'user_email', $this->get_filtered_columns() ) || in_array( 'user_login', $this->get_filtered_columns() ) )
567
+ $row = $this->maybe_fill_empty_data( $row, $user, $this->get_filtered_columns() );
568
+
569
+ $row = apply_filters( 'acui_export_data', $row, $user, $this->get_datetime_format(), $this->get_columns_to_export(), array( 'order_fields_alphabetically' => $this->get_order_fields_alphabetically(), 'double_encapsulate_serialized_values' => $this->get_double_encapsulate_serialized_values(), 'filtered_columns' => $this->get_filtered_columns() ));
570
+
571
+ $this->row_data[] = array_values( $row );
572
+ }
573
+ }
574
+
575
+ function prepare( $key, $value, $datetime_format, $user = 0 ){
576
+ $timestamp_keys = apply_filters( 'acui_export_timestamp_keys', array( 'wc_last_active' ) );
577
+ $non_date_keys = apply_filters( 'acui_export_non_date_keys', array() );
578
+ $original_value = $value;
579
+
580
+ if( $key == 'role' ){
581
+ return $this->get_role( $user );
582
+ }
583
+ if( is_array( $value ) || is_object( $value ) ){
584
+ return serialize( $value );
585
+ }
586
+ elseif( in_array( $key, $non_date_keys ) || empty( $datetime_format ) ){
587
+ return $this->clean_bad_characters_formulas( $value );
588
+ }
589
+ elseif( strtotime( $value ) ){ // dates in datetime format
590
+ return date( $datetime_format, strtotime( $value ) );
591
+ }
592
+ elseif( is_int( $value ) && ( ( $this->is_valid_timestamp( $value ) && strlen( $value ) > 4 ) || in_array( $key, $timestamp_keys) ) ){ // dates in timestamp format
593
+ return date( $datetime_format, $value );
594
+ }
595
+ else{
596
+ return apply_filters( 'acui_export_prepare', $this->clean_bad_characters_formulas( $value ), $original_value );
597
+ }
598
+ }
599
+
600
+ function clean_bad_characters_formulas( $value ){
601
+ if( strlen( $value ) == 0 )
602
+ return $value;
603
+
604
+ $bad_characters = array( '+', '-', '=', '@' );
605
+ $first_character = substr( $value, 0, 1 );
606
+ if( in_array( $first_character, $bad_characters ) )
607
+ $value = "\\" . $first_character . substr( $value, 1 );
608
+
609
+ return $value;
610
+ }
611
+
612
+ function is_valid_timestamp( $timestamp ){
613
+ return ( (string) (int) $timestamp === $timestamp ) && ( $timestamp <= PHP_INT_MAX ) && ( $timestamp >= ~PHP_INT_MAX );
614
+ }
615
+
616
+ function maybe_fill_empty_data( $row, $user_id, $filtered_columns ){
617
+ if( empty( $row['user_login'] ) || empty( $row['user_email'] ) ){
618
+ $user = new WP_User( $user_id );
619
+
620
+ if( $user->ID == 0 )
621
+ return $row;
622
+
623
+ if( count( $filtered_columns ) == 0 || in_array( 'user_login', $filtered_columns ) )
624
+ $row['user_login'] = $user->user_login;
625
+
626
+ if( count( $filtered_columns ) == 0 || in_array( 'user_email', $filtered_columns ) )
627
+ $row['user_email'] = $user->user_email;
628
+ }
629
+
630
+ return $row;
631
+ }
632
+
633
+ function get_user_meta_keys() {
634
+ global $wpdb;
635
+ $meta_keys = array();
636
+
637
+ $usermeta = get_transient( 'acui_export_user_meta_keys' );
638
+
639
+ if( empty( $usermeta ) ){
640
+ $usermeta = $wpdb->get_results( "SELECT distinct $wpdb->usermeta.meta_key FROM $wpdb->usermeta", ARRAY_A );
641
+ set_transient( 'acui_export_user_meta_keys', $usermeta, HOUR_IN_SECONDS );
642
+ }
643
+
644
+ foreach( $usermeta as $key => $value) {
645
+ if( $value["meta_key"] == 'role' )
646
+ continue;
647
+
648
+ if( count( $this->get_filtered_columns() ) == 0 || in_array( $value["meta_key"], $this->get_filtered_columns() ) )
649
+ $meta_keys[] = $value["meta_key"];
650
+ }
651
+
652
+ return apply_filters( 'acui_export_get_user_meta_keys', $meta_keys );
653
+ }
654
+ }
classes/export.php CHANGED
@@ -17,21 +17,81 @@ class ACUI_Exporter{
17
  $this->woocommerce_default_user_meta_keys = array( 'billing_first_name', 'billing_last_name', 'billing_email', 'billing_phone', 'billing_country', 'billing_address_1', 'billing_city', 'billing_state', 'billing_postcode', 'shipping_first_name', 'shipping_last_name', 'shipping_country', 'shipping_address_1', 'shipping_address_2', 'shipping_city', 'shipping_state', 'shipping_postcode' );
18
  $this->other_non_date_keys = array( 'shipping_phone' );
19
 
 
 
20
  add_action( 'wp_ajax_acui_export_users_csv', array( $this, 'export_users_csv' ) );
21
- add_filter( 'acui_export_get_key_user_data', array( $this, 'filter_key_user_id' ) );
22
- add_filter( 'acui_export_non_date_keys', array( $this, 'get_non_date_keys' ), 1, 1 );
23
- add_filter( 'acui_export_columns', array( $this, 'maybe_order_columns_alphabetacally' ), 10, 2 );
24
- add_filter( 'acui_export_columns', array( $this, 'maybe_order_columns_filtered_columns_parameter' ), 11, 2 );
25
- add_filter( 'acui_export_data', array( $this, 'maybe_double_encapsulate_serialized_values' ), 9 - 1, 5 );
26
- add_filter( 'acui_export_data', array( $this, 'maybe_order_row_alphabetically' ), 10, 5 );
27
- add_filter( 'acui_export_data', array( $this, 'maybe_order_row_filtered_columns_parameter' ), 11, 5 );
28
  }
29
 
30
- public static function admin_gui(){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  $roles = ACUI_Helper::get_editable_roles();
32
  ?>
33
  <h3 id="acui_export_users_header"><?php _e( 'Export users', 'import-users-from-csv-with-meta' ); ?></h3>
34
- <form id="acui_export_users_wrapper" method="POST" target="_blank" enctype="multipart/form-data" action="<?php echo admin_url( 'admin-ajax.php' ); ?>">
35
  <table class="form-table">
36
  <tbody>
37
  <tr id="acui_role_wrapper" valign="top">
@@ -94,7 +154,12 @@ class ACUI_Exporter{
94
  </tbody>
95
  </table>
96
  <input type="hidden" name="action" value="acui_export_users_csv"/>
97
- <?php wp_nonce_field( 'codection-security', 'security' ); ?>
 
 
 
 
 
98
  </form>
99
 
100
  <script type="text/javascript">
@@ -119,331 +184,69 @@ class ACUI_Exporter{
119
  <?php
120
  }
121
 
122
- static function is_valid_timestamp( $timestamp ){
123
- return ( (string) (int) $timestamp === $timestamp ) && ( $timestamp <= PHP_INT_MAX ) && ( $timestamp >= ~PHP_INT_MAX );
124
- }
125
-
126
- function get_non_date_keys( $non_date_keys ){
127
- return array_merge( $non_date_keys, $this->user_data, $this->woocommerce_default_user_meta_keys, $this->other_non_date_keys );
128
- }
129
-
130
- function maybe_order_columns_alphabetacally( $row, $args ){
131
- if( !$args['order_fields_alphabetically'] )
132
- return $row;
133
-
134
- $first_two_columns = array_slice( $row, 0, 2 );
135
- $to_order_columns = array_unique( array_slice( $row, 2 ) );
136
- sort( $to_order_columns, SORT_LOCALE_STRING );
137
-
138
- return array_merge( $first_two_columns, $to_order_columns );
139
- }
140
-
141
- function maybe_order_columns_filtered_columns_parameter( $row, $args ){
142
- return ( !is_array( $args['filtered_columns'] ) || count( $args['filtered_columns'] ) == 0 ) ? $row : $args['filtered_columns'];
143
- }
144
-
145
- function maybe_order_row_alphabetically( $row, $user, $datetime_format, $columns, $args ){
146
- if( !$args['order_fields_alphabetically'] )
147
- return $row;
148
-
149
- $row_sorted = array();
150
- foreach( $columns as $field ){
151
- $row_sorted[ $field ] = $row[ $field ];
152
- }
153
 
154
- return $row_sorted;
155
- }
156
-
157
- function maybe_order_row_filtered_columns_parameter( $row, $user, $datetime_format, $columns, $args ){
158
- if( !is_array( $args['filtered_columns'] ) || count( $args['filtered_columns'] ) == 0 )
159
- return $row;
160
-
161
- $row_sorted = array();
162
- foreach( $args['filtered_columns'] as $field ){
163
- $row_sorted[ $field ] = $row[ $field ];
164
- }
165
-
166
- return $row_sorted;
167
- }
168
-
169
- function maybe_double_encapsulate_serialized_values( $row, $user, $datetime_format, $columns, $args ){
170
- if( !$args['double_encapsulate_serialized_values'] )
171
- return $row;
172
-
173
- foreach( $columns as $field ){
174
- if( is_serialized( $row[ $field ] ) )
175
- $row[ $field ] = '"' . $row[ $field ] . '"';
176
- }
177
-
178
- return $row;
179
- }
180
-
181
- static function clean_bad_characters_formulas( $value ){
182
- if( strlen( $value ) == 0 )
183
- return $value;
184
-
185
- $bad_characters = array( '+', '-', '=', '@' );
186
- $first_character = substr( $value, 0, 1 );
187
- if( in_array( $first_character, $bad_characters ) )
188
- $value = "\\" . $first_character . substr( $value, 1 );
189
-
190
- return $value;
191
- }
192
-
193
- static function prepare( $key, $value, $datetime_format, $user = 0 ){
194
- $timestamp_keys = apply_filters( 'acui_export_timestamp_keys', array( 'wc_last_active' ) );
195
- $non_date_keys = apply_filters( 'acui_export_non_date_keys', array() );
196
- $original_value = $value;
197
 
198
- if( $key == 'role' ){
199
- return self::get_role( $user );
200
- }
201
- if( is_array( $value ) || is_object( $value ) ){
202
- return serialize( $value );
203
- }
204
- elseif( in_array( $key, $non_date_keys ) || empty( $datetime_format ) ){
205
- return self::clean_bad_characters_formulas( $value );
206
- }
207
- elseif( strtotime( $value ) ){ // dates in datetime format
208
- return date( $datetime_format, strtotime( $value ) );
209
  }
210
- elseif( is_int( $value ) && ( ( self::is_valid_timestamp( $value ) && strlen( $value ) > 4 ) || in_array( $key, $timestamp_keys) ) ){ // dates in timestamp format
211
- return date( $datetime_format, $value );
212
- }
213
- else{
214
- return apply_filters( 'acui_export_prepare', self::clean_bad_characters_formulas( $value ), $original_value );
215
- }
216
- }
217
-
218
- static function get_role( $user_id ){
219
- $user = get_user_by( 'id', $user_id );
220
- return implode( ',', $user->roles );
221
  }
222
 
223
- function manage_filtered_columns( $filtered_columns ){
224
- $filtered_columns = ( is_array( $filtered_columns ) ) ? array_walk( $filtered_columns, 'sanitize_text_field' ) : explode( ',', sanitize_text_field( $filtered_columns ) );
225
-
226
- if( empty( $filtered_columns[0] ) )
227
- $filtered_columns = array();
228
-
229
- return $filtered_columns;
230
- }
231
-
232
- function export_users_csv(){
233
- check_ajax_referer( 'codection-security', 'security' );
234
 
235
  if( !current_user_can( apply_filters( 'acui_capability', 'create_users' ) ) )
236
  wp_die( __( 'Only users who are able to create users can export them.', 'import-users-from-csv-with-meta' ) );
237
 
238
- $role = sanitize_text_field( $_POST['role'] );
239
- $from = sanitize_text_field( $_POST['from'] );
240
- $to = sanitize_text_field( $_POST['to'] );
241
- $delimiter = sanitize_text_field( $_POST['delimiter'] );
242
- $convert_timestamp = isset( $_POST['convert_timestamp'] ) && !empty( $_POST['convert_timestamp'] );
243
- $datetime_format = ( $convert_timestamp ) ? sanitize_text_field( $_POST['datetime_format'] ) : '';
244
- $order_fields_alphabetically = isset( $_POST['order_fields_alphabetically'] ) && !empty( $_POST['order_fields_alphabetically'] );
245
- $double_encapsulate_serialized_values = isset( $_POST['double_encapsulate_serialized_values'] ) && !empty( $_POST['double_encapsulate_serialized_values'] );
246
- $filtered_columns = ( isset( $_POST['columns'] ) && !empty( $_POST['columns'] ) ) ? $_POST['columns'] : array();
247
- $filtered_columns = $this->manage_filtered_columns( $filtered_columns );
248
- $orderby = ( isset( $_POST['orderby'] ) && !empty( $_POST['orderby'] ) ) ? sanitize_text_field( $_POST['orderby'] ) : '';
249
- $order = ( isset( $_POST['order'] ) && !empty( $_POST['order'] ) ) ? sanitize_text_field( $_POST['order'] ) : '';
250
-
251
- switch ( $delimiter ) {
252
- case 'COMMA':
253
- $delimiter = ",";
254
- break;
255
-
256
- case 'COLON':
257
- $delimiter = ":";
258
- break;
259
-
260
- case 'SEMICOLON':
261
- $delimiter = ";";
262
- break;
263
-
264
- case 'TAB':
265
- $delimiter = "\t";
266
- break;
267
-
268
- default:
269
- $delimiter = ",";
270
- break;
271
- }
272
-
273
- $data = array();
274
- $row = array();
275
-
276
- // header
277
- foreach ( $this->get_user_data( $filtered_columns ) as $key ) {
278
- $row[] = $key;
279
- }
280
-
281
- if( count( $filtered_columns ) == 0 || in_array( 'role', $filtered_columns ) )
282
- $row[] = "role";
283
-
284
- foreach ( $this->get_user_meta_keys( $filtered_columns ) as $key ) {
285
- $row[] = $key;
286
- }
287
-
288
- $row = apply_filters( 'acui_export_columns', $row, array( 'order_fields_alphabetically' => $order_fields_alphabetically, 'double_encapsulate_serialized_values' => $double_encapsulate_serialized_values, 'filtered_columns' => $filtered_columns ) );
289
- $from = apply_filters( 'acui_export_user_registered_from_date', $from );
290
- $to = apply_filters( 'acui_export_user_registered_to_date', $to );
291
-
292
- $columns = $row;
293
- $data[] = $row;
294
- $row = array();
295
-
296
- // data
297
- $users = $this->get_user_id_list( $role, $from, $to, $orderby, $order );
298
- foreach ( $users as $user ) {
299
- $userdata = get_userdata( $user );
300
-
301
- foreach ( $this->get_user_data( $filtered_columns ) as $key ) {
302
- $key = apply_filters( 'acui_export_get_key_user_data', $key );
303
- $row[ $key ] = self::prepare( $key, $userdata->data->{$key}, $datetime_format, $user );
304
- }
305
-
306
- if( count( $filtered_columns ) == 0 || in_array( 'role', $filtered_columns ) )
307
- $row[] = $this->get_role( $user );
308
-
309
- foreach ( $this->get_user_meta_keys( $filtered_columns ) as $key ) {
310
- $row[ $key ] = self::prepare( $key, get_user_meta( $user, $key, true ), $datetime_format, $user );
311
- }
312
-
313
- if( count( $filtered_columns ) == 0 || in_array( 'user_email', $filtered_columns ) || in_array( 'user_login', $filtered_columns ) )
314
- $row = $this->maybe_fill_empty_data( $row, $user, $filtered_columns );
315
-
316
- $row = apply_filters( 'acui_export_data', $row, $user, $datetime_format, $columns, array( 'order_fields_alphabetically' => $order_fields_alphabetically, 'double_encapsulate_serialized_values' => $double_encapsulate_serialized_values, 'filtered_columns' => $filtered_columns ));
317
- $data[] = array_values( $row );
318
- $row = array();
319
- }
320
-
321
- // export to csv
322
- $file = fopen( $this->path_csv, "w" );
323
-
324
- foreach ( $data as $line ) {
325
- fputcsv( $file, $line, $delimiter );
326
- }
327
-
328
- fclose( $file );
329
-
330
- $fsize = filesize( $this->path_csv ) + 3;
331
- $path_parts = pathinfo( $this->path_csv );
332
- header( "Content-type: text/csv;charset=utf-8" );
333
- header( "Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"" );
334
- header( "Content-length: $fsize" );
335
- header( "Cache-control: privfilefleate" );
336
- header( "Content-Description: File Transfer" );
337
- header( "Content-Transfer-Encoding: binary" );
338
- header( "Expires: 0" );
339
- header( "Cache-Control: must-revalidate" );
340
- header( "Pragma: public" );
341
-
342
- ob_clean();
343
- flush();
344
-
345
- echo "\xEF\xBB\xBF";
346
- readfile( $this->path_csv );
347
-
348
- unlink( $this->path_csv );
349
-
350
- wp_die();
351
- }
352
-
353
- function get_user_data( $filtered_columns ){
354
- if( count( $filtered_columns ) == 0 )
355
- return $this->user_data;
356
 
357
- var_export( $filtered_columns );
358
-
359
- $result = array();
360
- foreach( $this->user_data as $column ){
361
- if( in_array( $column, $filtered_columns ) )
362
- $result[] = $column;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
  }
364
-
365
- return $result;
366
  }
367
-
368
- function get_user_meta_keys( $filtered_columns ) {
369
- global $wpdb;
370
- $meta_keys = array();
371
-
372
- $select = "SELECT distinct $wpdb->usermeta.meta_key FROM $wpdb->usermeta";
373
- $usermeta = $wpdb->get_results( $select, ARRAY_A );
374
-
375
- foreach ($usermeta as $key => $value) {
376
- if( $value["meta_key"] == 'role' )
377
- continue;
378
-
379
- if( count( $filtered_columns ) == 0 || in_array( $value["meta_key"], $filtered_columns ) )
380
- $meta_keys[] = $value["meta_key"];
381
- }
382
-
383
- return apply_filters( 'acui_export_get_user_meta_keys', $meta_keys );
384
- }
385
-
386
- function get_user_id_list( $role, $from, $to, $orderby = '', $order = 'ASC' ){
387
- $args = array( 'fields' => array( 'ID' ), 'order' => $order );
388
-
389
- if( !empty( $role ) )
390
- $args['role'] = $role;
391
-
392
- $date_query = array();
393
-
394
- if( !empty( $from ) )
395
- $date_query[] = array( 'after' => $from );
396
-
397
- if( !empty( $to ) )
398
- $date_query[] = array( 'before' => $to );
399
-
400
- if( !empty( $date_query ) ){
401
- $date_query['inclusive'] = true;
402
- $args['date_query'] = $date_query;
403
- }
404
-
405
- if( !empty( $orderby ) ){
406
- if( in_array( $orderby, $this->accepted_order_by ) )
407
- $args['orderby'] = $orderby;
408
- else{
409
- $args['orderby'] = "meta_value";
410
- $args['meta_key'] = $orderby;
411
- }
412
-
413
- if( !empty( $order ) )
414
- $args['order'] = $order;
415
- }
416
-
417
- $users = get_users( $args );
418
- $list = array();
419
-
420
- foreach ( $users as $user ) {
421
- $list[] = $user->ID;
422
- }
423
-
424
- return $list;
425
- }
426
-
427
- function filter_key_user_id( $key ){
428
- return ( $key == 'source_user_id' ) ? 'ID' : $key;
429
- }
430
-
431
- function maybe_fill_empty_data( $row, $user_id, $filtered_columns ){
432
- if( empty( $row['user_login'] ) || empty( $row['user_email'] ) ){
433
- $user = new WP_User( $user_id );
434
-
435
- if( $user->ID == 0 )
436
- return $row;
437
-
438
- if( count( $filtered_columns ) == 0 || in_array( 'user_login', $filtered_columns ) )
439
- $row['user_login'] = $user->user_login;
440
-
441
- if( count( $filtered_columns ) == 0 || in_array( 'user_email', $filtered_columns ) )
442
- $row['user_email'] = $user->user_email;
443
- }
444
-
445
- return $row;
446
- }
447
  }
448
 
449
  $acui_exporter = new ACUI_Exporter();
17
  $this->woocommerce_default_user_meta_keys = array( 'billing_first_name', 'billing_last_name', 'billing_email', 'billing_phone', 'billing_country', 'billing_address_1', 'billing_city', 'billing_state', 'billing_postcode', 'shipping_first_name', 'shipping_last_name', 'shipping_country', 'shipping_address_1', 'shipping_address_2', 'shipping_city', 'shipping_state', 'shipping_postcode' );
18
  $this->other_non_date_keys = array( 'shipping_phone' );
19
 
20
+ add_action( 'init', array( $this, 'download_export_file' ) );
21
+ add_action( 'admin_init', array( $this, 'download_export_file' ) );
22
  add_action( 'wp_ajax_acui_export_users_csv', array( $this, 'export_users_csv' ) );
 
 
 
 
 
 
 
23
  }
24
 
25
+ static function enqueue(){
26
+ wp_enqueue_script( 'acui_export_js', plugins_url( 'assets/export.js', dirname( __FILE__ ) ), false, time(), true );
27
+ wp_localize_script( 'acui_export_js', 'acui_export_js_object', array(
28
+ 'ajaxurl' => admin_url( 'admin-ajax.php' ),
29
+ 'starting_process' => __( 'Starting process', 'import-users-from-csv-with-meta' ),
30
+ 'step' => __( 'Step', 'import-users-from-csv-with-meta' ),
31
+ 'of_approximately' => __( 'of approximately', 'import-users-from-csv-with-meta' ),
32
+ 'steps' => __( 'steps', 'import-users-from-csv-with-meta' ),
33
+ ) );
34
+ }
35
+
36
+ static function styles(){
37
+ ?>
38
+ <style>
39
+ #acui_exporter .user-exporter-progress-wrapper{
40
+ padding: 5px;
41
+ background-color: white;
42
+ width: 80%;
43
+ margin: 0 auto;
44
+ text-align: center;
45
+ }
46
+
47
+ #acui_exporter .user-exporter-progress{
48
+ width: 100%;
49
+ height: 42px;
50
+ border: 0;
51
+ border-radius: 9px;
52
+ }
53
+ .user-exporter-progress::-webkit-progress-bar {
54
+ background-color: #f3f3f3;
55
+ border-radius: 9px;
56
+ }
57
+
58
+ .user-exporter-progress::-webkit-progress-value {
59
+ background: #2271b1;
60
+ border-radius: 9px;
61
+ }
62
+
63
+ .user-exporter-progress::-moz-progress-bar {
64
+ background: #2271b1;
65
+ border-radius: 9px;
66
+ }
67
+
68
+ .user-exporter-progress .progress-value {
69
+ padding: 0px 5px;
70
+ line-height: 20px;
71
+ margin-left: 5px;
72
+ font-size: .8em;
73
+ color: #555;
74
+ height: 18px;
75
+ float: right;
76
+ }
77
+
78
+ #acui_exporter.user-exporter__exporting table,
79
+ #acui_exporter .user-exporter-progress-wrapper{
80
+ display: none;
81
+ }
82
+
83
+ #acui_exporter.user-exporter__exporting .user-exporter-progress-wrapper{
84
+ display: block;
85
+ }
86
+ </style>
87
+ <?php
88
+ }
89
+
90
+ static function admin_gui(){
91
  $roles = ACUI_Helper::get_editable_roles();
92
  ?>
93
  <h3 id="acui_export_users_header"><?php _e( 'Export users', 'import-users-from-csv-with-meta' ); ?></h3>
94
+ <form id="acui_exporter">
95
  <table class="form-table">
96
  <tbody>
97
  <tr id="acui_role_wrapper" valign="top">
154
  </tbody>
155
  </table>
156
  <input type="hidden" name="action" value="acui_export_users_csv"/>
157
+ <?php wp_nonce_field( 'codection-security', 'security' ); ?>
158
+
159
+ <div class="user-exporter-progress-wrapper">
160
+ <progress class="user-exporter-progress" value="0" max="100"></progress>
161
+ <span class="user-exporter-progress-value">0%</span>
162
+ </div>
163
  </form>
164
 
165
  <script type="text/javascript">
184
  <?php
185
  }
186
 
187
+ function download_export_file() {
188
+ if ( current_user_can( apply_filters( 'acui_capability', 'create_users' ) ) && isset( $_GET['action'], $_GET['nonce'] ) && wp_verify_nonce( wp_unslash( $_GET['nonce'] ), 'codection-security' ) && 'download_user_csv' === wp_unslash( $_GET['action'] ) ) {
189
+ $exporter = new ACUI_Batch_Exporter();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
 
191
+ if ( !empty( $_GET['filename'] ) ){
192
+ $exporter->set_filename( wp_unslash( $_GET['filename'] ) );
193
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
 
195
+ $exporter->export();
 
 
 
 
 
 
 
 
 
 
196
  }
 
 
 
 
 
 
 
 
 
 
 
197
  }
198
 
199
+ function export_users_csv(){
200
+ check_ajax_referer( 'codection-security', 'security' );
 
 
 
 
 
 
 
 
 
201
 
202
  if( !current_user_can( apply_filters( 'acui_capability', 'create_users' ) ) )
203
  wp_die( __( 'Only users who are able to create users can export them.', 'import-users-from-csv-with-meta' ) );
204
 
205
+
206
+ $step = isset( $_POST['step'] ) ? absint( $_POST['step'] ) : 1;
207
+
208
+ $exporter = new ACUI_Batch_Exporter();
209
+
210
+ $exporter->set_page( $step );
211
+ $exporter->set_delimiter( sanitize_text_field( $_POST['delimiter'] ) );
212
+ $exporter->set_role( sanitize_text_field( $_POST['role'] ) );
213
+ $exporter->set_from( sanitize_text_field( $_POST['from'] ) );
214
+ $exporter->set_to( sanitize_text_field( $_POST['to'] ) );
215
+ $exporter->set_convert_timestamp( $_POST['convert_timestamp'] );
216
+ $exporter->set_datetime_format( sanitize_text_field( $_POST['datetime_format'] ) );
217
+ $exporter->set_order_fields_alphabetically( $_POST['order_fields_alphabetically'] );
218
+ $exporter->set_double_encapsulate_serialized_values( $_POST['double_encapsulate_serialized_values'] );
219
+ $exporter->set_filtered_columns( ( isset( $_POST['columns'] ) && !empty( $_POST['columns'] ) ) ? $_POST['columns'] : array() );
220
+ $exporter->set_orderby( ( isset( $_POST['orderby'] ) && !empty( $_POST['orderby'] ) ) ? sanitize_text_field( $_POST['orderby'] ) : '' );
221
+ $exporter->set_order( ( isset( $_POST['order'] ) && !empty( $_POST['order'] ) ) ? sanitize_text_field( $_POST['order'] ) : 'ASC' );
222
+ $exporter->load_columns();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
 
224
+ $exporter->generate_file();
225
+
226
+ if ( 100 <= $exporter->get_percent_complete() ) {
227
+ $query_args = array(
228
+ 'nonce' => wp_create_nonce( 'codection-security' ),
229
+ 'action' => 'download_user_csv',
230
+ 'filename' => $exporter->get_filename()
231
+ );
232
+
233
+ wp_send_json_success(
234
+ array(
235
+ 'step' => 'done',
236
+ 'percentage' => 100,
237
+ 'url' => add_query_arg( $query_args, admin_url( 'tools.php?page=acui&tab=export' ) ),
238
+ )
239
+ );
240
+ } else {
241
+ wp_send_json_success(
242
+ array(
243
+ 'step' => ++$step,
244
+ 'total_steps' => $exporter->get_total_steps(),
245
+ 'percentage' => $exporter->get_percent_complete(),
246
+ )
247
+ );
248
  }
 
 
249
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250
  }
251
 
252
  $acui_exporter = new ACUI_Exporter();
classes/frontend.php CHANGED
@@ -382,7 +382,7 @@ class ACUI_Frontend{
382
  wp_mail( $send_mail_admin_adress_list_frontend, '[Import and export users and customers] Frontend import has been executed', $body_mail, array( 'Content-Type: text/html; charset=UTF-8' ) );
383
  }
384
 
385
- function shortcode_import( $atts ) {
386
  $atts = shortcode_atts( array( 'role' => '', 'delete-only-specified-role' => false ), $atts );
387
 
388
  ob_start();
@@ -474,23 +474,32 @@ class ACUI_Frontend{
474
  }
475
 
476
  function shortcode_export( $atts ) {
477
- $atts = shortcode_atts( array( 'role' => '', 'from' => '', 'to' => '', 'delimiter' => '', 'order-alphabetically' => '', 'columns' => '', 'orderby' => '', 'order' => '' ), $atts );
478
 
479
  ob_start();
480
 
481
  if( !current_user_can( apply_filters( 'acui_capability', 'create_users' ) ) )
482
  wp_die( __( 'Only users who are able to create users can export them.', 'import-users-from-csv-with-meta' ) );
483
- ?>
484
- <form method="POST" action="<?php echo admin_url( 'admin-ajax.php' ); ?>" class="acui_frontend_form">
485
- <input type="hidden" name="action" value="acui_export_users_csv"/>
486
 
487
- <?php foreach( $atts as $key => $value ): ?>
 
 
 
 
 
 
 
488
  <input type="hidden" name="<?php echo $key; ?>" value="<?php echo $value; ?>"/>
489
  <?php endforeach; ?>
490
 
491
  <input class="acui_frontend_submit" type="submit" value="<?php _e( 'Export', 'import-users-from-csv-with-meta' ); ?>"/>
492
 
493
  <?php wp_nonce_field( 'codection-security', 'security' ); ?>
 
 
 
 
 
494
  </form>
495
  <?php
496
  return ob_get_clean();
382
  wp_mail( $send_mail_admin_adress_list_frontend, '[Import and export users and customers] Frontend import has been executed', $body_mail, array( 'Content-Type: text/html; charset=UTF-8' ) );
383
  }
384
 
385
+ function shortcode_import( $atts ) {
386
  $atts = shortcode_atts( array( 'role' => '', 'delete-only-specified-role' => false ), $atts );
387
 
388
  ob_start();
474
  }
475
 
476
  function shortcode_export( $atts ) {
477
+ $atts = shortcode_atts( array( 'role' => '', 'from' => '', 'to' => '', 'delimiter' => '', 'order-alphabetically' => '', 'columns' => '', 'orderby' => '', 'order' => '' ), $atts );
478
 
479
  ob_start();
480
 
481
  if( !current_user_can( apply_filters( 'acui_capability', 'create_users' ) ) )
482
  wp_die( __( 'Only users who are able to create users can export them.', 'import-users-from-csv-with-meta' ) );
 
 
 
483
 
484
+ ACUI_Exporter::enqueue();
485
+ ACUI_Exporter::styles();
486
+ ?>
487
+
488
+ <form method="POST" class="acui_frontend_form" id="acui_exporter">
489
+ <input type="hidden" name="acui_frontend_export" value="1"/>
490
+
491
+ <?php foreach( $atts as $key => $value ): ?>
492
  <input type="hidden" name="<?php echo $key; ?>" value="<?php echo $value; ?>"/>
493
  <?php endforeach; ?>
494
 
495
  <input class="acui_frontend_submit" type="submit" value="<?php _e( 'Export', 'import-users-from-csv-with-meta' ); ?>"/>
496
 
497
  <?php wp_nonce_field( 'codection-security', 'security' ); ?>
498
+
499
+ <div class="user-exporter-progress-wrapper">
500
+ <progress class="user-exporter-progress" value="0" max="100"></progress>
501
+ <span class="user-exporter-progress-value">0%</span>
502
+ </div>
503
  </form>
504
  <?php
505
  return ob_get_clean();
classes/settings.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) exit;
3
+
4
+ class ACUI_Settings{
5
+ var $settings;
6
+
7
+ function __construct(){
8
+ $settings = array(
9
+ 'common' => array(
10
+ 'default_role',
11
+
12
+ )
13
+ );
14
+ }
15
+ }
import-users-from-csv-with-meta.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Import and export users and customers
4
  Plugin URI: https://www.codection.com
5
  Description: Using this plugin you will be able to import and export users or customers choosing many options and interacting with lots of other plugins
6
- Version: 1.17.9
7
  Author: codection
8
  Author URI: https://codection.com
9
  License: GPL2
@@ -91,6 +91,10 @@ class ImportExportUsersCustomers{
91
  wp_enqueue_style( 'datatable', '//cdn.datatables.net/1.10.24/css/jquery.dataTables.min.css' );
92
  wp_enqueue_script( 'datatable', '//cdn.datatables.net/1.10.24/js/jquery.dataTables.min.js' );
93
  //wp_enqueue_script( 'datatable-select', '//cdn.datatables.net/select/1.3.3/js/dataTables.select.min.js' );
 
 
 
 
94
  }
95
 
96
  function action_links( $links, $file ) {
3
  Plugin Name: Import and export users and customers
4
  Plugin URI: https://www.codection.com
5
  Description: Using this plugin you will be able to import and export users or customers choosing many options and interacting with lots of other plugins
6
+ Version: 1.18
7
  Author: codection
8
  Author URI: https://codection.com
9
  License: GPL2
91
  wp_enqueue_style( 'datatable', '//cdn.datatables.net/1.10.24/css/jquery.dataTables.min.css' );
92
  wp_enqueue_script( 'datatable', '//cdn.datatables.net/1.10.24/js/jquery.dataTables.min.js' );
93
  //wp_enqueue_script( 'datatable-select', '//cdn.datatables.net/select/1.3.3/js/dataTables.select.min.js' );
94
+
95
+ if( isset( $_GET['tab'] ) && $_GET['tab'] == 'export' ){
96
+ ACUI_Exporter::enqueue();
97
+ }
98
  }
99
 
100
  function action_links( $links, $file ) {
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://codection.com/go/donate-import-users-from-csv-with-meta/
4
  Tags: csv, import, importer, meta data, meta, user, users, user meta, editor, profile, custom, fields, delimiter, update, insert
5
  Requires at least: 3.4
6
  Tested up to: 5.8
7
- Stable tag: 1.17.8.4
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -103,8 +103,12 @@ Plugin will automatically detect:
103
 
104
  == Changelog ==
105
 
 
 
 
 
106
  = 1.17.9 =
107
- * Export now can be ordered using an attribute in the shortcode, attributes are orderby and order, how to use them it is explained there
108
 
109
  = 1.17.8.4 =
110
  * Bug fixed in WP User Manager addon
4
  Tags: csv, import, importer, meta data, meta, user, users, user meta, editor, profile, custom, fields, delimiter, update, insert
5
  Requires at least: 3.4
6
  Tested up to: 5.8
7
+ Stable tag: 1.18
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
103
 
104
  == Changelog ==
105
 
106
+ = 1.18 =
107
+ * Export in backend and frontend now works using step by step process using client calls to avoid gateway timeouts and other kind of timing limits in very long process
108
+ * Addon for WP User Manager improved to avoid redirection loop
109
+
110
  = 1.17.9 =
111
+ * Export now can be ordered using an attribute in the shortcode
112
 
113
  = 1.17.8.4 =
114
  * Bug fixed in WP User Manager addon