Export User Data - Version 0.9.6

Version Description

  • Save, load and delete stored export settings - thanks to @cwjordan
  • Overcome memory outages on large exports - thanks to @grexican
  • Tested on WP 4.0.0 & BP 2.1.0
Download this release

Release Info

Developer qlstudio
Plugin Icon wp plugin Export User Data
Version 0.9.6
Comparing to
See all releases

Code changes from version 0.9.5 to 0.9.6

Files changed (4) hide show
  1. css/export-user-data.css +133 -0
  2. export-user-data.php +648 -119
  3. readme.md +7 -2
  4. readme.txt +7 -2
css/export-user-data.css ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ export-user-data.css
3
+
4
+ @since 0.9.6
5
+ */
6
+
7
+
8
+ /* general layout */
9
+
10
+ .form-table tr.remember div.row:first-child {
11
+ margin-bottom: 10px;
12
+ }
13
+
14
+ .form-table tr.remember input.button-primary {
15
+ margin-left: 5px;
16
+ }
17
+
18
+ .form-table tr.remember select {
19
+ width: 25em;
20
+ }
21
+
22
+ input.error {
23
+ background: #D54E21;
24
+ color: #fff;
25
+ border: 1px solid #CCC;
26
+ }
27
+
28
+ th p.filter {
29
+ width: 100%;
30
+ }
31
+
32
+ /* form inputs */
33
+
34
+
35
+ /* multiselects */
36
+
37
+ .ms-container{
38
+ background: transparent url('../img/switch.png') no-repeat 50% 50%;
39
+ width: 600px;
40
+ }
41
+
42
+ .ms-container:after{
43
+ content: ".";
44
+ display: block;
45
+ height: 0;
46
+ line-height: 0;
47
+ font-size: 0;
48
+ clear: both;
49
+ min-height: 0;
50
+ visibility: hidden;
51
+ }
52
+
53
+ .ms-container .ms-selectable, .ms-container .ms-selection{
54
+ background: #fff;
55
+ color: #555555;
56
+ float: left;
57
+ width: 45%;
58
+ }
59
+
60
+ .ms-container .ms-list{
61
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
62
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
63
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
64
+ -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
65
+ -moz-transition: border linear 0.2s, box-shadow linear 0.2s;
66
+ -ms-transition: border linear 0.2s, box-shadow linear 0.2s;
67
+ -o-transition: border linear 0.2s, box-shadow linear 0.2s;
68
+ transition: border linear 0.2s, box-shadow linear 0.2s;
69
+ border: 1px solid #ccc;
70
+ -webkit-border-radius: 3px;
71
+ -moz-border-radius: 3px;
72
+ border-radius: 3px;
73
+ position: relative;
74
+ height: 200px;
75
+ padding: 0;
76
+ overflow-y: auto;
77
+ }
78
+
79
+ .ms-container .ms-selectable{
80
+ margin-right: 10%;
81
+ }
82
+
83
+ .ms-container .ms-list.ms-focus{
84
+ border-color: rgba(82, 168, 236, 0.8);
85
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
86
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
87
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
88
+ outline: 0;
89
+ outline: thin dotted \9;
90
+ }
91
+
92
+ .ms-container ul{
93
+ margin: 0;
94
+ list-style-type: none;
95
+ padding: 0;
96
+ }
97
+
98
+ .ms-container .ms-optgroup-container{
99
+ width: 100%;
100
+ }
101
+
102
+ .ms-container .ms-optgroup-label{
103
+ margin: 0;
104
+ padding: 5px 0px 0px 5px;
105
+ cursor: pointer;
106
+ color: #999;
107
+ }
108
+
109
+ .ms-container .ms-selectable li.ms-elem-selectable,
110
+ .ms-container .ms-selection li.ms-elem-selection{
111
+ border-bottom: 1px #eee solid;
112
+ padding: 4px 10px;
113
+ color: #555;
114
+ font-size: 14px;
115
+ margin-bottom: 0px;
116
+ }
117
+
118
+ .ms-container .ms-selectable li.ms-hover,
119
+ .ms-container .ms-selection li.ms-hover{
120
+ cursor: pointer;
121
+ color: #fff;
122
+ text-decoration: none;
123
+ background-color: #08c;
124
+ margin-bottom: 0px;
125
+ }
126
+
127
+ .ms-container .ms-selectable li.disabled,
128
+ .ms-container .ms-selection li.disabled{
129
+ background-color: #eee;
130
+ color: #aaa;
131
+ cursor: text;
132
+ margin-bottom: 0px;
133
+ }
export-user-data.php CHANGED
@@ -3,8 +3,8 @@
3
  /*
4
  Plugin Name: Export User Data
5
  Plugin URI: http://qstudio.us/plugins/
6
- Description: Export User data, metadata and BuddyPressX Profile data.
7
- Version: 0.9.5
8
  Author: Q Studio
9
  Author URI: http://qstudio.us
10
  License: GPL2
@@ -14,12 +14,16 @@ Text Domain: export-user-data
14
  // quick check :) ##
15
  defined( 'ABSPATH' ) OR exit;
16
 
 
 
 
 
17
  /* Check for Class */
18
  if ( ! class_exists( 'Q_Export_User_Data' ) )
19
  {
20
 
21
  // plugin version
22
- define( 'Q_EXPORT_USER_DATA_VERSION', '0.9.5' ); // version ##
23
 
24
  // instatiate class via hook, only if inside admin
25
  if ( is_admin() ) {
@@ -43,8 +47,17 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
43
 
44
  /* properties */
45
  public $text_domain = 'export-user-data'; // for translation ##
46
- #public $q_eud_options = array(); // export settings ##
47
-
 
 
 
 
 
 
 
 
 
48
 
49
  /**
50
  * Creates or returns an instance of this class.
@@ -70,16 +83,20 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
70
  private function __construct()
71
  {
72
 
73
- if (is_admin() ) {
74
 
75
- add_action( 'init', array( $this, 'load_plugin_textdomain' ) );
 
76
  add_action( 'admin_menu', array( $this, 'add_admin_pages' ) );
77
- add_action( 'init', array( $this, 'generate_data' ) );
78
  add_filter( 'q_eud_exclude_data', array( $this, 'exclude_data' ) );
79
  add_action( 'admin_enqueue_scripts', array( $this, 'add_css_and_js' ), 1 );
80
  add_action( 'admin_footer', array( $this, 'jquery' ), 100000 );
81
  add_action( 'admin_footer', array( $this, 'css' ), 100000 );
82
-
 
 
 
83
  }
84
 
85
  }
@@ -117,16 +134,48 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
117
  public function add_css_and_js( $hook )
118
  {
119
 
120
- // load the scripts on only the plugin admin page
121
- if (isset( $_GET['page'] ) && ( $_GET['page'] == $this->text_domain ) ) {
122
 
123
- wp_register_style('q_eud_multi_select_css', plugins_url('css/multi-select.css',__FILE__ ));
124
- wp_enqueue_style('q_eud_multi_select_css');
125
- wp_enqueue_script('q_eud_multi_select_js', plugins_url('js/jquery.multi-select.js',__FILE__ ), array('jquery'), '0.9.8', false );
126
 
127
  }
128
 
129
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
 
132
  /**
@@ -144,83 +193,283 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
144
 
145
 
146
  /**
147
- * Check for a retrieve stored user options
148
- *
149
- * @since 0.9.3
150
- * @return Mixed false on error OR array of saved options
151
  */
152
- public function get_user_options()
153
  {
154
 
155
- // check if the user wants to, or has previously saved the export field list ##
156
- $user_ID = get_current_user_id();
157
 
158
- // no user - go return false ##
159
- if ( ! $user_ID ) { return false; }
160
-
161
- // return an empty array, if nothing found ##
162
- return get_option( 'q_eud_options_'.$user_ID, array() );
163
 
164
  }
165
 
166
 
167
  /**
168
- * method to store user options
169
- *
170
- * @since 0.9.3
171
- * @return Boolean
172
  */
173
- public function set_user_options( $value = null )
174
  {
175
 
176
- // nothing cooking ##
177
- if ( is_null( $value ) ) {
 
 
 
178
 
179
- return false;
180
 
181
  }
182
 
183
- // add value to property ##
184
- $this->q_eud_options[] = $value;
 
 
 
 
 
 
 
 
 
 
185
 
 
 
 
186
  }
187
 
188
 
 
189
  /**
190
- * method to save / update / delete user options
191
  *
192
  * @since 0.9.3
193
- * @return Boolean
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  */
195
- public function manage_user_options( $action = null )
196
  {
197
 
198
- // nothing cooking ##
199
- if ( is_null( $action ) ) {
200
 
 
201
  return false;
202
 
203
  }
204
 
205
- // check if the user wants to, or has previously saved the export field list ##
206
- $user_ID = get_current_user_id();
207
 
208
- // no user - go return false ##
209
- if ( ! $user_ID ) { return false; }
 
 
 
 
 
210
 
211
- // what action to take ##
212
- switch ( $action ) {
213
 
214
- case ( 'save' ):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
 
216
- update_option( 'q_eud_options_'.$user_ID, $this->q_eud_options );
217
 
218
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  }
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
 
 
 
 
 
224
 
225
 
226
  /**
@@ -231,24 +480,23 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
231
  public function generate_data()
232
  {
233
 
234
- #if ( ! current_user_can( 'list_users' ) ) {
235
-
236
- #wp_die( __( 'You do not have sufficient permissions to access this page.', $this->text_domain ) );
237
-
238
- #}
239
-
240
- if ( ! isset( $_POST['_wpnonce-q-eud-export-user-page_export'] ) ) {
241
-
 
 
242
  return false;
243
 
244
  }
245
-
246
  // check admin referer ##
247
  check_admin_referer( 'q-eud-export-user-page_export', '_wpnonce-q-eud-export-user-page_export' );
248
 
249
- // check for a retrieve user's stored options ##
250
- #$q_eud_options = $this->get_user_options();
251
-
252
  // build argument array ##
253
  $args = array(
254
  #'fields' => 'all_with_meta',
@@ -275,8 +523,14 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
275
  if ( is_int( $limit_offset ) && is_int( $limit_total ) ) {
276
 
277
  $args['offset'] = $limit_offset;
278
- $args['number'] = $limit_total - $limit_offset;
279
-
 
 
 
 
 
 
280
  #wp_die(pr($args));
281
 
282
  }
@@ -448,22 +702,6 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
448
  // compile final fields list ##
449
  $fields = array_merge( $data_keys, $usermeta_fields, $bp_fields_passed, $bp_fields_update_passed );
450
 
451
- // should we include the user's role in the export ##
452
- /*
453
- if ( isset( $_POST['q_eud_role'] ) && $_POST['q_eud_role'] != '' ) {
454
-
455
- // save this to stored options ( 'group', 'field', 'value' )##
456
- $this->set_user_options( array( 'role' => array ( 'q_eud_role' => array ( 'yes' ) ) ) );
457
-
458
- // save options ##
459
- $this->manage_user_options( 'save' );
460
-
461
- // add "Role" to the fields array ##
462
- $fields[]["role"] = _e( 'Role', $this->text_domain );
463
-
464
- }
465
- */
466
-
467
  // build the document headers ##
468
  $headers = array();
469
 
@@ -494,8 +732,33 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
494
  }
495
 
496
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
497
 
498
- //open doc wrapper..
499
  echo $doc_begin;
500
 
501
  // echo headers ##
@@ -503,14 +766,23 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
503
 
504
  // build row values for each user ##
505
  foreach ( $users as $user ) {
 
 
 
 
 
 
506
 
 
507
  $data = array();
508
 
509
  // BP loaded ? ##
510
  if ( function_exists ('bp_is_active') ) {
511
- $bp_data = BP_XProfile_ProfileData::get_all_for_user($user->ID);
 
512
  }
513
 
 
514
  foreach ( $fields as $field ) {
515
 
516
  // check if this is a BP field ##
@@ -523,6 +795,20 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
523
  $value = maybe_unserialize($value['field_data']); // suggested by @grexican ##
524
  #$value = $value['field_data'];
525
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
526
  }
527
 
528
  $value = $this->sanitize($value);
@@ -534,13 +820,23 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
534
 
535
  $real_field = str_replace(" Update Date", "", $field);
536
  $field_id = xprofile_get_field_id_from_name( $real_field );
537
- $value = $wpdb->get_var ($wpdb->prepare( "SELECT last_updated FROM {$bp->profile->table_name_data} WHERE user_id = %d AND field_id = %d", $user->ID, $field_id ) );
 
 
 
 
 
 
 
 
 
 
538
 
539
  // include the user's role in the export ##
540
  } elseif ( isset( $_POST['q_eud_role'] ) && $_POST['q_eud_role'] != '' && $field == 'role' ){
541
 
542
  // add "Role" as $value ##
543
- $value = $user->roles[0] ? $user->roles[0] : '' ; // empty value if no role found ##
544
 
545
  // user data or usermeta ##
546
  } else {
@@ -587,15 +883,100 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
587
  public function users_page()
588
  {
589
 
 
590
  if ( ! current_user_can( 'list_users' ) ) {
 
591
  wp_die( __( 'You do not have sufficient permissions to access this page.', $this->text_domain ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
592
  }
593
 
594
- // check for a retrieve user's stroed options ##
595
- #$q_eud_options = $this->get_user_options();
 
 
 
 
 
 
 
 
596
 
597
  ?>
598
- <div class="wrap">
599
  <h2><?php _e( 'Export User Data', $this->text_domain ); ?></h2>
600
  <?php
601
 
@@ -661,6 +1042,9 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
661
  <p class="filter" style="margin: 10px 0 0;">
662
  <?php _e('Filter', $this->text_domain); ?>: <a href="#" class="usermeta-all"><?php _e('All', $this->text_domain); ?></a> | <a href="#" class="usermeta-common"><?php _e('Common', $this->text_domain); ?></a>
663
  </p>
 
 
 
664
  </th>
665
  <td>
666
  <select multiple="multiple" id="usermeta" name="usermeta[]">
@@ -690,7 +1074,6 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
690
 
691
  if ( strpos( $key, $drop ) !== false ) {
692
 
693
- #echo 'FOUND -- '.$drop.' in '.$key.'<br />';
694
  // https://wordpress.org/support/topic/bugfix-numbers-in-export-headers?replies=1
695
  // removed $key = assignment, as not required ##
696
  if ( ( array_search( $key, $meta_keys ) ) !== false ) {
@@ -740,7 +1123,12 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
740
 
741
  ?>
742
  <tr valign="top">
743
- <th scope="row"><label for="q_eud_xprofile"><?php _e( 'BP xProfile Fields', $this->text_domain ); ?></label></th>
 
 
 
 
 
744
  <td>
745
  <select multiple="multiple" id="bp_fields" name="bp_fields[]">
746
  <?php
@@ -774,6 +1162,9 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
774
  <tr valign="top" class="toggleable">
775
  <th scope="row">
776
  <label for="q_eud_xprofile"><?php _e( 'BP xProfile Fields Update Time', $this->text_domain ); ?></label>
 
 
 
777
  </th>
778
  <td>
779
  <select multiple="multiple" id="bp_fields_update_time" name="bp_fields_update_time[]">
@@ -808,9 +1199,14 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
808
  echo '<option value="">' . __( 'All Roles', $this->text_domain ) . '</option>';
809
  global $wp_roles;
810
  foreach ( $wp_roles->role_names as $role => $name ) {
 
 
 
811
  echo "\n\t<option value='" . esc_attr( $role ) . "'>$name</option>";
 
812
  }
813
 
 
814
  ?>
815
  </select>
816
  <p class="description"><?php
@@ -859,11 +1255,11 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
859
  <td>
860
  <select name="start_date" id="q_eud_users_start_date">
861
  <option value="0"><?php _e( 'Start Date', $this->text_domain ); ?></option>
862
- <?php $this->export_date_options(); ?>
863
  </select>
864
  <select name="end_date" id="q_eud_users_end_date">
865
  <option value="0"><?php _e( 'End Date', $this->text_domain ); ?></option>
866
- <?php $this->export_date_options(); ?>
867
  </select>
868
  <p class="description"><?php
869
  printf(
@@ -876,8 +1272,8 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
876
  <tr valign="top" class="toggleable">
877
  <th scope="row"><label><?php _e( 'Limit Range', $this->text_domain ); ?></label></th>
878
  <td>
879
- <input name="limit_offset" type="text" id="q_eud_users_limit_offset" value="" class="regular-text code numeric" style="width: 136px;" placeholder="<?php _e( 'Offset', $this->text_domain ); ?>">
880
- <input name="limit_total" type="text" id="q_eud_users_limit_total" value="" class="regular-text code numeric" style="width: 136px;" placeholder="<?php _e( 'Total', $this->text_domain ); ?>">
881
  <p class="description"><?php
882
  printf(
883
  __( 'Enter an offset start number and a total number of users to export. <a href="%s" target="_blank">%s</a>', $this->text_domain )
@@ -901,29 +1297,21 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
901
  </tr>
902
  </tr>
903
 
904
- <tr valign="top" class="hidden">
905
- <th scope="row">
906
- <label for="q_eud_options"><?php _e( 'Remember Options', $this->text_domain ); ?>
907
- </th>
908
- <td>
909
- <input id='q_eud_options' type='checkbox' name='q_eud_options' value=''/></label>
910
- <p class="description"><?php
911
- printf(
912
- __( 'Checking this option will save and reload your selected options for future exports.', $this->text_domain )
913
- );
914
- ?></p>
915
- </td>
916
- </tr>
917
-
918
  <tr valign="top">
919
  <th scope="row"><label for="q_eud_users_format"><?php _e( 'Format', $this->text_domain ); ?></label></th>
920
  <td>
921
  <select name="format" id="q_eud_users_format">
922
  <?php
923
-
924
- echo '<option value="excel">' . __( 'Excel', $this->text_domain ) . '</option>';
925
- echo '<option value="csv">' . __( 'CSV', $this->text_domain ) . '</option>';
926
-
 
 
 
 
 
 
927
  ?>
928
  </select>
929
  <p class="description"><?php
@@ -934,6 +1322,61 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
934
  </td>
935
  </tr>
936
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
937
  <tr valign="top">
938
  <th scope="row">
939
  <label for="q_eud_xprofile"><?php _e( 'Advanced Options', $this->text_domain ); ?></label>
@@ -948,9 +1391,10 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
948
  </table>
949
  <p class="submit">
950
  <input type="hidden" name="_wp_http_referer" value="<?php echo $_SERVER['REQUEST_URI'] ?>" />
951
- <input type="submit" class="button-primary" value="<?php _e( 'Export', $this->text_domain ); ?>" />
952
  </p>
953
  </form>
 
954
 
955
  <?php
956
  }
@@ -973,6 +1417,11 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
973
 
974
  // build super multiselect ##
975
  jQuery('#usermeta, #bp_fields, #bp_fields_update_time').multiSelect();
 
 
 
 
 
976
 
977
  // show only common ##
978
  jQuery('.usermeta-common').click(function(e){
@@ -986,6 +1435,19 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
986
  jQuery('#ms-usermeta .ms-selectable li').show();
987
  });
988
 
 
 
 
 
 
 
 
 
 
 
 
 
 
989
  // validate number inputs ##
990
  $("input.numeric").blur(function() {
991
 
@@ -1017,7 +1479,30 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
1017
  jQuery(this).text("<?php _e( 'Show', $this->text_domain ); ?>");
1018
  }
1019
  });
1020
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1021
  });
1022
 
1023
  </script>
@@ -1086,11 +1571,12 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
1086
  /**
1087
  * Export Date Options
1088
  *
1089
- * @global type $wpdb
1090
- * @global type $wp_locale
1091
- * @return type
 
1092
  */
1093
- private function export_date_options()
1094
  {
1095
 
1096
  global $wpdb, $wp_locale;
@@ -1110,11 +1596,54 @@ if ( ! class_exists( 'Q_Export_User_Data' ) )
1110
  continue;
1111
 
1112
  $month = zeroise( $date->month, 2 );
1113
- echo '<option value="' . $date->year . '-' . $month . '">' . $wp_locale->get_month( $month ) . ' ' . $date->year . '</option>';
 
 
 
 
 
 
1114
  }
1115
 
1116
  }
1117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1118
  }
1119
 
1120
- }
3
  /*
4
  Plugin Name: Export User Data
5
  Plugin URI: http://qstudio.us/plugins/
6
+ Description: Export User data, metadata and BuddyPress X-Profile data.
7
+ Version: 0.9.6
8
  Author: Q Studio
9
  Author URI: http://qstudio.us
10
  License: GPL2
14
  // quick check :) ##
15
  defined( 'ABSPATH' ) OR exit;
16
 
17
+ // Increase maximum execution time to prevent "Maximum execution time
18
+ // exceeded" error
19
+ ini_set('max_execution_time', 3600);
20
+
21
  /* Check for Class */
22
  if ( ! class_exists( 'Q_Export_User_Data' ) )
23
  {
24
 
25
  // plugin version
26
+ define( 'Q_EXPORT_USER_DATA_VERSION', '0.9.6' ); // version ##
27
 
28
  // instatiate class via hook, only if inside admin
29
  if ( is_admin() ) {
47
 
48
  /* properties */
49
  public $text_domain = 'export-user-data'; // for translation ##
50
+ private $q_eud_exports = ''; // export settings ##
51
+ private $usermeta_saved_fields = array();
52
+ private $bp_fields_saved_fields = array();
53
+ private $bp_fields_update_time_saved_fields = array();
54
+ private $role = '';
55
+ private $start_date = '';
56
+ private $end_date = '';
57
+ private $limit_offset = '';
58
+ private $limit_total = '';
59
+ private $format = '';
60
+
61
 
62
  /**
63
  * Creates or returns an instance of this class.
83
  private function __construct()
84
  {
85
 
86
+ if ( is_admin() ) {
87
 
88
+ add_action( 'init', array( $this, 'load_plugin_textdomain' ), 1 );
89
+ add_action( 'init', array( $this, 'load_user_options' ), 2 );
90
  add_action( 'admin_menu', array( $this, 'add_admin_pages' ) );
91
+ add_action( 'init', array( $this, 'generate_data' ), 3 );
92
  add_filter( 'q_eud_exclude_data', array( $this, 'exclude_data' ) );
93
  add_action( 'admin_enqueue_scripts', array( $this, 'add_css_and_js' ), 1 );
94
  add_action( 'admin_footer', array( $this, 'jquery' ), 100000 );
95
  add_action( 'admin_footer', array( $this, 'css' ), 100000 );
96
+
97
+ // check for saved settings, default to empty array ##
98
+
99
+
100
  }
101
 
102
  }
134
  public function add_css_and_js( $hook )
135
  {
136
 
137
+ // load the scripts on only the plugin admin page ##
138
+ if ( isset( $_GET['page'] ) && ( $_GET['page'] == $this->text_domain ) ) {
139
 
140
+ wp_register_style( 'q_export_user_data', plugins_url( 'css/export-user-data.css' ,__FILE__ ));
141
+ wp_enqueue_style( 'q_export_user_data' );
142
+ wp_enqueue_script( 'q_eud_multi_select_js', plugins_url( 'js/jquery.multi-select.js', __FILE__ ), array('jquery'), '0.9.8', false );
143
 
144
  }
145
 
146
  }
147
+
148
+
149
+ /**
150
+ * Return Byte count of $val
151
+ *
152
+ * @link http://wordpress.org/support/topic/how-to-exporting-a-lot-of-data-out-of-memory-issue?replies=2
153
+ * @since 0.9.6
154
+ */
155
+ public function return_bytes( $val )
156
+ {
157
+
158
+ $val = trim( $val );
159
+ $last = strtolower($val[strlen($val)-1]);
160
+ switch( $last ) {
161
+
162
+ // The 'G' modifier is available since PHP 5.1.0
163
+ case 'g':
164
+
165
+ $val *= 1024;
166
+
167
+ case 'm':
168
+
169
+ $val *= 1024;
170
+
171
+ case 'k':
172
+
173
+ $val *= 1024;
174
+
175
+ }
176
+
177
+ return $val;
178
+ }
179
 
180
 
181
  /**
193
 
194
 
195
  /**
196
+ * Load up saved exports for this user
197
+ *
198
+ * @since 0.9.6
199
+ * @return Array of saved exports
200
  */
201
+ public function load_user_options()
202
  {
203
 
 
 
204
 
205
+ $this->q_eud_exports = get_user_meta( get_current_user_id(), 'q_eud_exports' ) ? get_user_meta( get_current_user_id(), 'q_eud_exports', true ) : array() ;
206
+ #var_dump( $this->q_eud_exports );
 
 
 
207
 
208
  }
209
 
210
 
211
  /**
212
+ * Get list of saved exports for this user
213
+ *
214
+ * @since 0.9.4
215
+ * @return Array of saved exports
216
  */
217
+ public function get_user_options()
218
  {
219
 
220
+ // get the stored options - filter empty array items ##
221
+ $q_eud_exports = array_filter( $this->q_eud_exports );
222
+
223
+ // quick check if the array is empty ##
224
+ if ( empty ( $q_eud_exports ) ) {
225
 
226
+ return false;
227
 
228
  }
229
 
230
+ // test the array of saved exports ##
231
+ #$this->pr( $q_eud_exports );
232
+
233
+ // start with an empty array ##
234
+ $exports = array();
235
+
236
+ // loop over each saved export and grab each key ##
237
+ foreach ( $q_eud_exports as $key => $value ) {
238
+
239
+ $exports[] = $key;
240
+
241
+ }
242
 
243
+ // kick back array ##
244
+ return( $exports );
245
+
246
  }
247
 
248
 
249
+
250
  /**
251
+ * Check for and load stored user options
252
  *
253
  * @since 0.9.3
254
+ * @return void
255
+ */
256
+ public function get_user_options_by_export( $export = null )
257
+ {
258
+
259
+ // sanity check ##
260
+ if ( is_null ( $export ) ) { return false; }
261
+
262
+ if ( isset( $this->q_eud_exports[$export] ) ) {
263
+
264
+ $this->usermeta_saved_fields = $this->q_eud_exports[$export]['usermeta_saved_fields'];
265
+ $this->bp_fields_saved_fields = $this->q_eud_exports[$export]['bp_fields_saved_fields'];
266
+ $this->bp_fields_update_time_saved_fields = $this->q_eud_exports[$export]['bp_fields_update_time_saved_fields'];
267
+ $this->role = $this->q_eud_exports[$export]['role'];
268
+ $this->start_date = $this->q_eud_exports[$export]['start_date'];
269
+ $this->end_date = $this->q_eud_exports[$export]['end_date'];
270
+ $this->limit_offset = $this->q_eud_exports[$export]['limit_offset'];
271
+ $this->limit_total = $this->q_eud_exports[$export]['limit_total'];
272
+ $this->format = $this->q_eud_exports[$export]['format'];
273
+
274
+ } else {
275
+
276
+ $this->usermeta_saved_fields = array();
277
+ $this->bp_fields_saved_fields = array();
278
+ $this->bp_fields_update_time_saved_fields = array();
279
+ $this->role = '';
280
+ $this->start_date = '';
281
+ $this->end_date = '';
282
+ $this->limit_offset = '';
283
+ $this->limit_total = '';
284
+ $this->format = '';
285
+
286
+ }
287
+
288
+ }
289
+
290
+
291
+
292
+ /**
293
+ * method to store user options
294
+ *
295
+ * @todo sanitizing function is not correct - yet... ##
296
+ * @param string $save_export Export Key name
297
+ * @param array $save_options Array of export options to save
298
+ * @since 0.9.3
299
+ * @return void
300
  */
301
+ public function set_user_options( $key = null, $options = null )
302
  {
303
 
304
+ // sanity check ##
305
+ if ( is_null ( $key ) || is_null ( $options ) ) {
306
 
307
+ #$this->pr( 'missing save values' );
308
  return false;
309
 
310
  }
311
 
312
+ #$this->pr( $key );
313
+ #$this->pr( $options );
314
 
315
+ // for now, I'm simply allowing keys to be resaved - but this is not so logical ##
316
+ if ( array_key_exists( $key, $this->q_eud_exports ) ) {
317
+
318
+ #$this->pr( 'key exists, skipping save' );
319
+ #return false;
320
+
321
+ }
322
 
323
+ if ( isset( $options ) && is_array( $options ) ) {
 
324
 
325
+ // @todo - sanitizing function is not correct - yet... ##
326
+ /*
327
+ // update_option sanitizes the option name but not the option value ##
328
+ foreach ( $options as $field_name => $field_value ) {
329
+
330
+ // so do that here. ##
331
+ if ( is_array( $field_value ) ) {
332
+
333
+ foreach ( $field_value as $field_array_key => $field_array_value ) {
334
+
335
+ $options[$key][$field_name][$field_array_key] = sanitize_text_field( $field_array_value );
336
+
337
+ }
338
+
339
+ } else {
340
+
341
+ $options[$key][$field_name] = sanitize_text_field( $field_value );
342
 
343
+ }
344
 
345
+ }
346
+ */
347
+
348
+ // update_option sanitizes the option name but not the option value ##
349
+ foreach ( $options as $field_name => $field_value ) {
350
+
351
+ // so do that here. ##
352
+ if ( is_array( $field_value ) ) {
353
+
354
+ foreach ( $field_value as $field_array_key => $field_array_value ) {
355
+
356
+ $options[$field_name][$field_array_key] = sanitize_text_field( $field_array_value );
357
+
358
+ }
359
+
360
+ } else {
361
+
362
+ $options[$field_name] = sanitize_text_field( $field_value );
363
+
364
+ }
365
+
366
+ }
367
+
368
+ // assign the sanitized array of values to the class property $q_eud_exports as a new array with key $key ##
369
+ $this->q_eud_exports[$key] = $options;
370
 
371
+ // update stored user_meta values, if previous key found ##
372
+ if ( get_user_meta( get_current_user_id(), 'q_eud_exports' ) !== false ) {
373
+
374
+ #update_option( 'q_eud_exports', $this->q_eud_exports );
375
+ update_user_meta( get_current_user_id(), 'q_eud_exports', $this->q_eud_exports );
376
+
377
+ // create new user meta key ##
378
+ } else {
379
+
380
+ #add_option( 'q_eud_exports', $this->q_eud_exports, $deprecated, $autoload );
381
+ add_user_meta( get_current_user_id(), 'q_eud_exports', $this->q_eud_exports );
382
+
383
+ }
384
+
385
  }
386
 
387
+ }
388
+
389
+
390
+
391
+ /**
392
+ * method to delete user options
393
+ *
394
+ * @param $key String Key name to drop from property
395
+ * @since 0.9.3
396
+ * @return void
397
+ */
398
+ public function delete_user_options( $key = null )
399
+ {
400
+
401
+ // sanity check ##
402
+ if ( is_null ( $key ) || ! array_key_exists( $key, $this->q_eud_exports ) ) { return false; }
403
+
404
+ // clean it up ##
405
+ $key = sanitize_text_field( $key );
406
+
407
+ // check it out ##
408
+ #$this->pr( $key );
409
+
410
+ // drop the array by it's key name from the class property ##
411
+ unset( $this->q_eud_exports[$key] );
412
+
413
+ // update the saved data ##
414
+ update_user_meta( get_current_user_id(), 'q_eud_exports', $this->q_eud_exports );
415
+
416
  }
417
+
418
+
419
+ /**
420
+ * Copy of BP_XProfile_ProfileData::get_all_for_user() from BP version 2.0?
421
+ * Get all of the profile information for a specific user.
422
+ *
423
+ * @param $user_id Integer ID of specific user
424
+ * @since 0.9.6
425
+ * @return Array User profile fields
426
+ */
427
+ private static function get_all_for_user( $user_id = null ) {
428
+
429
+ // sanity check ##
430
+ if ( is_null( $user_id ) ) { return false; }
431
+
432
+ global $wpdb, $bp;
433
+
434
+ $results = $wpdb->get_results(
435
+ $wpdb->prepare(
436
+ "
437
+ SELECT g.id as field_group_id, g.name as field_group_name, f.id as field_id, f.name as field_name, f.type as field_type, d.value as field_data, u.user_login, u.user_nicename, u.user_email
438
+ FROM {$bp->profile->table_name_groups} g
439
+ LEFT JOIN {$bp->profile->table_name_fields} f ON g.id = f.group_id
440
+ INNER JOIN {$bp->profile->table_name_data} d ON f.id = d.field_id LEFT JOIN {$wpdb->users} u ON d.user_id = u.ID
441
+ WHERE d.user_id = %d AND d.value != ''
442
+ "
443
+ , $user_id
444
+ )
445
+ );
446
+
447
+ $profile_data = array();
448
+
449
+ if ( ! empty( $results ) ) {
450
+
451
+ $profile_data['user_login'] = $results[0]->user_login;
452
+ $profile_data['user_nicename'] = $results[0]->user_nicename;
453
+ $profile_data['user_email'] = $results[0]->user_email;
454
+
455
+ foreach( (array) $results as $field ) {
456
+
457
+ $profile_data[$field->field_name] = array(
458
+ 'field_group_id' => $field->field_group_id,
459
+ 'field_group_name' => $field->field_group_name,
460
+ 'field_id' => $field->field_id,
461
+ 'field_type' => $field->field_type,
462
+ 'field_data' => $field->field_data
463
+ );
464
+
465
+ }
466
+
467
+ }
468
 
469
+ return $profile_data;
470
+
471
+ }
472
+
473
 
474
 
475
  /**
480
  public function generate_data()
481
  {
482
 
483
+ // This function runs before we display the admin page, so we need to skip
484
+ // the rest of this function if the user didn't click on the
485
+ // Save, Load, or Delete Settings buttons
486
+ if (
487
+ ! isset( $_POST['_wpnonce-q-eud-export-user-page_export'] )
488
+ || isset( $_POST['load_export'] )
489
+ || isset( $_POST['save_export'] )
490
+ || isset( $_POST['delete_export'] ) )
491
+ {
492
+
493
  return false;
494
 
495
  }
496
+
497
  // check admin referer ##
498
  check_admin_referer( 'q-eud-export-user-page_export', '_wpnonce-q-eud-export-user-page_export' );
499
 
 
 
 
500
  // build argument array ##
501
  $args = array(
502
  #'fields' => 'all_with_meta',
523
  if ( is_int( $limit_offset ) && is_int( $limit_total ) ) {
524
 
525
  $args['offset'] = $limit_offset;
526
+ /* cwjordan codex says:
527
+ * number - Limit the total number of users returned
528
+ * so don't subtract the offset, like as not
529
+ * that will give us a negative number for $args['number']
530
+ * e.g. offset of 1000 total of 100 */
531
+ $args['number'] = $limit_total;
532
+ // $args['number'] = $limit_total - $limit_offset;
533
+
534
  #wp_die(pr($args));
535
 
536
  }
702
  // compile final fields list ##
703
  $fields = array_merge( $data_keys, $usermeta_fields, $bp_fields_passed, $bp_fields_update_passed );
704
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
705
  // build the document headers ##
706
  $headers = array();
707
 
732
  }
733
 
734
  }
735
+
736
+ // no more buffering while spitting back the export data ##
737
+ ob_end_flush();
738
+
739
+ // get the value in bytes allocated for Memory via php.ini ##
740
+ // @link http://wordpress.org/support/topic/how-to-exporting-a-lot-of-data-out-of-memory-issue?replies=2
741
+ $memory_limit = $this->return_bytes( ini_get('memory_limit') ) * .75;
742
+
743
+ // we need to disable caching while exporting because we export so much data that it could blow the memory cache
744
+ // if we can't override the cache here, we'll have to clear it later...
745
+ if ( function_exists( 'override_function' ) ) {
746
+
747
+ override_function('wp_cache_add', '$key, $data, $group="", $expire=0', '');
748
+ override_function('wp_cache_set', '$key, $data, $group="", $expire=0', '');
749
+ override_function('wp_cache_replace', '$key, $data, $group="", $expire=0', '');
750
+ override_function('wp_cache_add_non_persistent_groups', '$key, $data, $group="", $expire=0', '');
751
+
752
+ } elseif ( function_exists( 'runkit_function_redefine' ) ) {
753
+
754
+ runkit_function_redefine('wp_cache_add', '$key, $data, $group="", $expire=0', '');
755
+ runkit_function_redefine('wp_cache_set', '$key, $data, $group="", $expire=0', '');
756
+ runkit_function_redefine('wp_cache_replace', '$key, $data, $group="", $expire=0', '');
757
+ runkit_function_redefine('wp_cache_add_non_persistent_groups', '$key, $data, $group="", $expire=0', '');
758
+
759
+ }
760
 
761
+ // open doc wrapper.. ##
762
  echo $doc_begin;
763
 
764
  // echo headers ##
766
 
767
  // build row values for each user ##
768
  foreach ( $users as $user ) {
769
+
770
+ // check if we're hitting any Memory limits, if so flush them out ##
771
+ // per http://wordpress.org/support/topic/how-to-exporting-a-lot-of-data-out-of-memory-issue?replies=2
772
+ if ( memory_get_usage( true ) > $memory_limit ) {
773
+ wp_cache_flush();
774
+ }
775
 
776
+ // open up a new empty array ##
777
  $data = array();
778
 
779
  // BP loaded ? ##
780
  if ( function_exists ('bp_is_active') ) {
781
+ #$bp_data = BP_XProfile_ProfileData::get_all_for_user( $user->ID );
782
+ $bp_data = self::get_all_for_user( $user->ID ); // take from old BP method ##
783
  }
784
 
785
+ // loop over each field ##
786
  foreach ( $fields as $field ) {
787
 
788
  // check if this is a BP field ##
795
  $value = maybe_unserialize($value['field_data']); // suggested by @grexican ##
796
  #$value = $value['field_data'];
797
 
798
+ /**
799
+ * cwjordan
800
+ * after unserializing it we then
801
+ * need to implode it so
802
+ * that we have something readable?
803
+ * Going to use :: as a separator
804
+ * because that's what Buddypress Members Import
805
+ * expects, but we might want to make that
806
+ * configurable.
807
+ */
808
+ if ( is_array( $value ) ) {
809
+ $value = implode("::", $value );
810
+ }
811
+
812
  }
813
 
814
  $value = $this->sanitize($value);
820
 
821
  $real_field = str_replace(" Update Date", "", $field);
822
  $field_id = xprofile_get_field_id_from_name( $real_field );
823
+ $value = $wpdb->get_var (
824
+ $wpdb->prepare(
825
+ "
826
+ SELECT last_updated
827
+ FROM {$bp->profile->table_name_data}
828
+ WHERE user_id = %d AND field_id = %d
829
+ "
830
+ , $user->ID
831
+ , $field_id
832
+ )
833
+ );
834
 
835
  // include the user's role in the export ##
836
  } elseif ( isset( $_POST['q_eud_role'] ) && $_POST['q_eud_role'] != '' && $field == 'role' ){
837
 
838
  // add "Role" as $value ##
839
+ $value = $user->roles[0] ? $user->roles[0] : '' ; // empty value if no role found - note: we only take the first role assigned to the user ##
840
 
841
  // user data or usermeta ##
842
  } else {
883
  public function users_page()
884
  {
885
 
886
+ // quick security check ##
887
  if ( ! current_user_can( 'list_users' ) ) {
888
+
889
  wp_die( __( 'You do not have sufficient permissions to access this page.', $this->text_domain ) );
890
+
891
+ }
892
+
893
+ // Save settings button was pressed ##
894
+ if (
895
+ isset( $_POST['save_export'] )
896
+ && check_admin_referer( 'q-eud-export-user-page_export', '_wpnonce-q-eud-export-user-page_export' )
897
+ ) {
898
+
899
+ // start with an empty variable ##
900
+ $save_export = "";
901
+
902
+ if ( ! empty( $_POST['save_new_export_name'] ) ) {
903
+
904
+ // assign value ##
905
+ $save_export = $_POST['save_new_export_name'];
906
+
907
+ } elseif ( ! empty( $_POST['export_name'] ) ) {
908
+
909
+ $save_export = $_POST['export_name'];
910
+
911
+ }
912
+
913
+ // clean up $save_export ##
914
+ $save_export = sanitize_text_field( $save_export );
915
+
916
+ // Build array of $options to save and save them ##
917
+ if ( $save_export != "" ) {
918
+
919
+ // prepare all array values ##
920
+ $usermeta = isset( $_POST['usermeta'] ) ? $_POST['usermeta']: '' ;
921
+ $bp_fields = isset( $_POST['bp_fields'] ) ? $_POST['bp_fields'] : '' ;
922
+ $bp_fields_update = isset( $_POST['bp_fields_update_time'] ) ? $_POST['bp_fields_update_time'] : '' ;
923
+ $format = isset( $_POST['format'] ) ? $_POST['format'] : '' ;
924
+ $role = isset( $_POST['role'] ) ? $_POST['role'] : '' ;
925
+ $start_date = isset( $_POST['start_date'] ) ? $_POST['start_date'] : '' ;
926
+ $end_date = isset( $_POST['end_date'] ) ? $_POST['end_date'] : '' ;
927
+ $limit_offset = isset( $_POST['limit_offset'] ) ? $_POST['limit_offset'] : '' ;
928
+ $limit_total = isset( $_POST['limit_total'] ) ? $_POST['limit_total'] : '' ;
929
+
930
+ // assign all values to a multidimensional array with $save_export as the key of the upper array ##
931
+ #$options = array (
932
+ $save_array = array (
933
+ 'usermeta_saved_fields' => $usermeta,
934
+ 'bp_fields_saved_fields' => $bp_fields,
935
+ 'bp_fields_update_time_saved_fields' => $bp_fields_update,
936
+ 'role' => $role,
937
+ 'start_date' => $start_date,
938
+ 'end_date' => $end_date,
939
+ 'limit_offset' => $limit_offset,
940
+ 'limit_total' => $limit_total,
941
+ 'format' => $format
942
+ );
943
+ #);
944
+
945
+ // store the options, for next load ##
946
+ $this->set_user_options( $save_export, $save_array );
947
+
948
+ // Display the settings the user just saved instead of blanking the form ##
949
+ $_POST['load_export'] = 'Load Settings';
950
+ $_POST['export_name'] = $save_export;
951
+
952
+ }
953
+
954
+ }
955
+
956
+ // Load settings button was pressed ( or option saved and $_POST variables hijacked )##
957
+ if (
958
+ isset( $_POST['load_export'] )
959
+ && isset( $_POST['export_name'] )
960
+ && check_admin_referer( 'q-eud-export-user-page_export', '_wpnonce-q-eud-export-user-page_export' )
961
+ ) {
962
+
963
+ $this->get_user_options_by_export( sanitize_text_field( $_POST['export_name'] ) );
964
+
965
  }
966
 
967
+ // Delete settings button was pressed ##
968
+ if (
969
+ isset( $_POST['delete_export'] )
970
+ && isset( $_POST['export_name'] )
971
+ && check_admin_referer( 'q-eud-export-user-page_export', '_wpnonce-q-eud-export-user-page_export' )
972
+ ) {
973
+
974
+ $this->delete_user_options( sanitize_text_field( $_POST['export_name'] ) );
975
+
976
+ }
977
 
978
  ?>
979
+ <div class="wrap">
980
  <h2><?php _e( 'Export User Data', $this->text_domain ); ?></h2>
981
  <?php
982
 
1042
  <p class="filter" style="margin: 10px 0 0;">
1043
  <?php _e('Filter', $this->text_domain); ?>: <a href="#" class="usermeta-all"><?php _e('All', $this->text_domain); ?></a> | <a href="#" class="usermeta-common"><?php _e('Common', $this->text_domain); ?></a>
1044
  </p>
1045
+ <p class="filter" style="margin: 10px 0 0;">
1046
+ <?php _e('Select', $this->text_domain); ?>: <a href="#" class="select-all"><?php _e('All', $this->text_domain); ?></a> | <a href="#" class="select-none"><?php _e('None', $this->text_domain); ?></a>
1047
+ </p>
1048
  </th>
1049
  <td>
1050
  <select multiple="multiple" id="usermeta" name="usermeta[]">
1074
 
1075
  if ( strpos( $key, $drop ) !== false ) {
1076
 
 
1077
  // https://wordpress.org/support/topic/bugfix-numbers-in-export-headers?replies=1
1078
  // removed $key = assignment, as not required ##
1079
  if ( ( array_search( $key, $meta_keys ) ) !== false ) {
1123
 
1124
  ?>
1125
  <tr valign="top">
1126
+ <th scope="row">
1127
+ <label for="q_eud_xprofile"><?php _e( 'BP xProfile Fields', $this->text_domain ); ?></label>
1128
+ <p class="filter" style="margin: 10px 0 0;">
1129
+ <?php _e('Select', $this->text_domain); ?>: <a href="#" class="select-all"><?php _e('All', $this->text_domain); ?></a> | <a href="#" class="select-none"><?php _e('None', $this->text_domain); ?></a>
1130
+ </p>
1131
+ </th>
1132
  <td>
1133
  <select multiple="multiple" id="bp_fields" name="bp_fields[]">
1134
  <?php
1162
  <tr valign="top" class="toggleable">
1163
  <th scope="row">
1164
  <label for="q_eud_xprofile"><?php _e( 'BP xProfile Fields Update Time', $this->text_domain ); ?></label>
1165
+ <p class="filter" style="margin: 10px 0 0;">
1166
+ <?php _e('Select', $this->text_domain); ?>: <a href="#" class="select-all"><?php _e('All', $this->text_domain); ?></a> | <a href="#" class="select-none"><?php _e('None', $this->text_domain); ?></a>
1167
+ </p>
1168
  </th>
1169
  <td>
1170
  <select multiple="multiple" id="bp_fields_update_time" name="bp_fields_update_time[]">
1199
  echo '<option value="">' . __( 'All Roles', $this->text_domain ) . '</option>';
1200
  global $wp_roles;
1201
  foreach ( $wp_roles->role_names as $role => $name ) {
1202
+ if ( isset ( $this->role ) && ( $this->role == $role ) ) {
1203
+ echo "\n\t<option selected value='" . esc_attr( $role ) . "'>$name</option>";
1204
+ } else {
1205
  echo "\n\t<option value='" . esc_attr( $role ) . "'>$name</option>";
1206
+ }
1207
  }
1208
 
1209
+
1210
  ?>
1211
  </select>
1212
  <p class="description"><?php
1255
  <td>
1256
  <select name="start_date" id="q_eud_users_start_date">
1257
  <option value="0"><?php _e( 'Start Date', $this->text_domain ); ?></option>
1258
+ <?php $this->export_date_options($this->start_date); ?>
1259
  </select>
1260
  <select name="end_date" id="q_eud_users_end_date">
1261
  <option value="0"><?php _e( 'End Date', $this->text_domain ); ?></option>
1262
+ <?php $this->export_date_options($this->end_date); ?>
1263
  </select>
1264
  <p class="description"><?php
1265
  printf(
1272
  <tr valign="top" class="toggleable">
1273
  <th scope="row"><label><?php _e( 'Limit Range', $this->text_domain ); ?></label></th>
1274
  <td>
1275
+ <input name="limit_offset" type="text" id="q_eud_users_limit_offset" value="<?php echo( $this->limit_offset ); ?>" class="regular-text code numeric" style="width: 136px;" placeholder="<?php _e( 'Offset', $this->text_domain ); ?>">
1276
+ <input name="limit_total" type="text" id="q_eud_users_limit_total" value="<?php echo ( $this->limit_total ); ?>" class="regular-text code numeric" style="width: 136px;" placeholder="<?php _e( 'Total', $this->text_domain ); ?>">
1277
  <p class="description"><?php
1278
  printf(
1279
  __( 'Enter an offset start number and a total number of users to export. <a href="%s" target="_blank">%s</a>', $this->text_domain )
1297
  </tr>
1298
  </tr>
1299
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1300
  <tr valign="top">
1301
  <th scope="row"><label for="q_eud_users_format"><?php _e( 'Format', $this->text_domain ); ?></label></th>
1302
  <td>
1303
  <select name="format" id="q_eud_users_format">
1304
  <?php
1305
+ if ( isset ( $this->format ) && ( $this->format == 'excel' ) ) {
1306
+ echo '<option selected value="excel">' . __( 'Excel', $this->text_domain ) . '</option>';
1307
+ } else {
1308
+ echo '<option value="excel">' . __( 'Excel', $this->text_domain ) . '</option>';
1309
+ }
1310
+ if ( isset ( $this->format ) && ( $this->format == 'csv' ) ) {
1311
+ echo '<option selected value="csv">' . __( 'CSV', $this->text_domain ) . '</option>';
1312
+ } else {
1313
+ echo '<option value="csv">' . __( 'CSV', $this->text_domain ) . '</option>';
1314
+ }
1315
  ?>
1316
  </select>
1317
  <p class="description"><?php
1322
  </td>
1323
  </tr>
1324
 
1325
+ <tr valign="top" class="remember">
1326
+ <th scope="row"><label for="q_eud_save_options"><?php _e( 'Stored Options', $this->text_domain ); ?></label></th>
1327
+ <td>
1328
+
1329
+ <div class="row">
1330
+ <input type="text" class="regular-text" name="save_new_export_name" id="q_eud_save_options_new_export" placeholder="<?php _e( 'Export Name', $this->text_domain ); ?>">
1331
+ <input type="submit" id="save_export" class="button-primary" name="save_export" value="<?php _e( 'Save', $this->text_domain ); ?>" />
1332
+ </div>
1333
+ <?php
1334
+
1335
+ // check if the user has any saved exports ##
1336
+ if ( $this->get_user_options() ) {
1337
+
1338
+ ?>
1339
+ <div class="row">
1340
+ <select name="export_name" id="q_eud_save_options" class="regular-text">
1341
+ <?php
1342
+
1343
+ // loop over each saved export ##
1344
+ foreach( $this->get_user_options() as $export ) {
1345
+
1346
+ // select Loaded export name, if selected ##
1347
+ if (
1348
+ isset( $_POST['load_export'] )
1349
+ && isset( $_POST['export_name'] )
1350
+ && ( $_POST['export_name'] == $export )
1351
+ ) {
1352
+
1353
+ echo "<option selected value='$export'>$export</option>";
1354
+
1355
+ // just list previous export name ##
1356
+ } else {
1357
+
1358
+ echo "<option value='$export'>$export</option>";
1359
+
1360
+ }
1361
+
1362
+ }
1363
+
1364
+ ?>
1365
+ </select>
1366
+
1367
+ <input type="submit" id="load_export" class="button-primary" name="load_export" value="<?php _e( 'Load', $this->text_domain ); ?>" />
1368
+ <input type="submit" id="delete_export" class="button-primary" name="delete_export" value="<?php _e( 'Delete', $this->text_domain ); ?>" />
1369
+ <?php
1370
+
1371
+ }
1372
+
1373
+ ?>
1374
+ </div>
1375
+ <p class="description"><?php _e( 'Save, load or delete your stored export options.', $this->text_domain ); ?></p>
1376
+
1377
+ </td>
1378
+ </tr>
1379
+
1380
  <tr valign="top">
1381
  <th scope="row">
1382
  <label for="q_eud_xprofile"><?php _e( 'Advanced Options', $this->text_domain ); ?></label>
1391
  </table>
1392
  <p class="submit">
1393
  <input type="hidden" name="_wp_http_referer" value="<?php echo $_SERVER['REQUEST_URI'] ?>" />
1394
+ <input type="submit" class="button-primary" value="<?php _e( 'Run Export', $this->text_domain ); ?>" />
1395
  </p>
1396
  </form>
1397
+ </div>
1398
 
1399
  <?php
1400
  }
1417
 
1418
  // build super multiselect ##
1419
  jQuery('#usermeta, #bp_fields, #bp_fields_update_time').multiSelect();
1420
+
1421
+ //Select any fields from saved settings ##
1422
+ jQuery('#usermeta').multiSelect('select',([<?php echo( $this->quote_array( $this->usermeta_saved_fields ) ); ?>]));
1423
+ jQuery('#bp_fields').multiSelect('select',([<?php echo( $this->quote_array($this->bp_fields_saved_fields ) ); ?>]));
1424
+ jQuery('#bp_fields_update_time').multiSelect('select',([<?php echo( $this->quote_array( $this->bp_fields_update_time_saved_fields ) ); ?>]));
1425
 
1426
  // show only common ##
1427
  jQuery('.usermeta-common').click(function(e){
1435
  jQuery('#ms-usermeta .ms-selectable li').show();
1436
  });
1437
 
1438
+ // select all ##
1439
+ jQuery('.select-all').click(function(e){
1440
+ e.preventDefault();
1441
+ jQuery( jQuery(this).parent().parent().parent().find( 'select' ) ).multiSelect( 'select_all' );
1442
+ });
1443
+
1444
+ // select none ##
1445
+ jQuery('.select-none').click(function(e){
1446
+ e.preventDefault();
1447
+ jQuery( jQuery(this).parent().parent().parent().find( 'select' ) ).multiSelect( 'deselect_all' );
1448
+ });
1449
+
1450
+
1451
  // validate number inputs ##
1452
  $("input.numeric").blur(function() {
1453
 
1479
  jQuery(this).text("<?php _e( 'Show', $this->text_domain ); ?>");
1480
  }
1481
  });
1482
+
1483
+ // @todo - probably we're going to require more validation on these buttons ##
1484
+ // validate save button ##
1485
+ jQuery("#save_export").click( function(e) {
1486
+
1487
+ // grab the value of the input ##
1488
+ var q_eud_save_options_new_export = jQuery('#q_eud_save_options_new_export').val();
1489
+
1490
+ if ( ! q_eud_save_options_new_export || q_eud_save_options_new_export == '' ) {
1491
+
1492
+ e.preventDefault(); // stop things here ##
1493
+ jQuery('#q_eud_save_options_new_export').addClass("error");
1494
+
1495
+ }
1496
+
1497
+ });
1498
+
1499
+ // remove validation on focus ##
1500
+ jQuery("body").on( 'focus', '#q_eud_save_options_new_export', function(e) {
1501
+
1502
+ jQuery(this).removeClass("error");
1503
+
1504
+ });
1505
+
1506
  });
1507
 
1508
  </script>
1571
  /**
1572
  * Export Date Options
1573
  *
1574
+ * @since 0.9.6
1575
+ * @global type $wpdb
1576
+ * @global type $wp_locale
1577
+ * @return void
1578
  */
1579
+ private function export_date_options( $selected_date)
1580
  {
1581
 
1582
  global $wpdb, $wp_locale;
1596
  continue;
1597
 
1598
  $month = zeroise( $date->month, 2 );
1599
+ $date_string = $date->year . '-' . $month;
1600
+ if ( $selected_date == $date_string ) {
1601
+ echo( '<option selected value="' . $date_string . '">' . $wp_locale->get_month( $month ) . ' ' . $date->year . '</option>' );
1602
+ } else {
1603
+ echo( '<option value="' . $date_string . '">' . $wp_locale->get_month( $month ) . ' ' . $date->year . '</option>' );
1604
+ }
1605
+
1606
  }
1607
 
1608
  }
1609
 
1610
+ /**
1611
+ * Quote array elements and separate with commas
1612
+ *
1613
+ * @since 0.9.6
1614
+ * @return String
1615
+ */
1616
+ private function quote_array( $array )
1617
+ {
1618
+
1619
+ $prefix = ''; // starts empty ##
1620
+ $elementlist = '';
1621
+ if ( is_array( $array ) ) {
1622
+ foreach( $array as $element ) {
1623
+ $elementlist .= $prefix . "'" . $element . "'";
1624
+ $prefix = ','; // prefix all remaining items with a comma ##
1625
+ }
1626
+ }
1627
+
1628
+ // kick back string to function caller ##
1629
+ return( $elementlist );
1630
+
1631
+ }
1632
+
1633
+
1634
+ /**
1635
+ * Nicer var_dump
1636
+ *
1637
+ * @since 0.9.6
1638
+ */
1639
+ function pr ($thing)
1640
+ {
1641
+ echo '<pre>';
1642
+ print_r ($thing);
1643
+ echo '</pre>';
1644
+ }
1645
+
1646
+
1647
  }
1648
 
1649
+ }
readme.md CHANGED
@@ -2,8 +2,8 @@
2
  **Contributors:** qlstudio
3
  **Tags:** user, users, xprofile, usermeta csv, excel, batch, export, save, download
4
  **Requires at least:** 3.2
5
- **Tested up to:** 3.9.2
6
- **Stable tag:** 0.9.5
7
  **License:** GPLv2
8
 
9
  Export users data, metadata and buddypress xprofile data to a csv or Excel file
@@ -59,6 +59,11 @@ Click on the 'Export User Data' link in the 'Users' menu, choose the role and th
59
 
60
  ## Changelog ##
61
 
 
 
 
 
 
62
  ### 0.9.5 ###
63
  * BP Serialized data fixes - thanks to @nicmare & @grexican
64
  * Tested on WP 3.9.2 & BP 2.0.2
2
  **Contributors:** qlstudio
3
  **Tags:** user, users, xprofile, usermeta csv, excel, batch, export, save, download
4
  **Requires at least:** 3.2
5
+ **Tested up to:** 4.0.0
6
+ **Stable tag:** 0.9.6
7
  **License:** GPLv2
8
 
9
  Export users data, metadata and buddypress xprofile data to a csv or Excel file
59
 
60
  ## Changelog ##
61
 
62
+ ### 0.9.6 ###
63
+ * Save, load and delete stored export settings - thanks to @cwjordan
64
+ * Overcome memory outages on large exports - thanks to @grexican
65
+ * Tested on WP 4.0.0 & BP 2.1.0
66
+
67
  ### 0.9.5 ###
68
  * BP Serialized data fixes - thanks to @nicmare & @grexican
69
  * Tested on WP 3.9.2 & BP 2.0.2
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: qlstudio
3
  Tags: user, users, xprofile, usermeta csv, excel, batch, export, save, download
4
  Requires at least: 3.2
5
- Tested up to: 3.9.2
6
- Stable tag: 0.9.5
7
  License: GPLv2
8
 
9
  Export users data, metadata and buddypress xprofile data to a csv or Excel file
@@ -58,6 +58,11 @@ Click on the 'Export User Data' link in the 'Users' menu, choose the role and th
58
 
59
  == Changelog ==
60
 
 
 
 
 
 
61
  = 0.9.5 =
62
  * BP Serialized data fixes - thanks to @nicmare & @grexican
63
  * Tested on WP 3.9.2 & BP 2.0.2
2
  Contributors: qlstudio
3
  Tags: user, users, xprofile, usermeta csv, excel, batch, export, save, download
4
  Requires at least: 3.2
5
+ Tested up to: 4.0.0
6
+ Stable tag: 0.9.6
7
  License: GPLv2
8
 
9
  Export users data, metadata and buddypress xprofile data to a csv or Excel file
58
 
59
  == Changelog ==
60
 
61
+ = 0.9.6 =
62
+ * Save, load and delete stored export settings - thanks to @cwjordan
63
+ * Overcome memory outages on large exports - thanks to @grexican
64
+ * Tested on WP 4.0.0 & BP 2.1.0
65
+
66
  = 0.9.5 =
67
  * BP Serialized data fixes - thanks to @nicmare & @grexican
68
  * Tested on WP 3.9.2 & BP 2.0.2