usermeta .
' ON ' . $wpdb->users
. '.ID = ' . $wpdb->usermeta . '.user_id ';
// 20170201 No, must get all users if it is network admin WHERE ' . $wpdb->usermeta .'.meta_key =\'' . $wpdb->prefix . 'capabilities\'' ;
$where2 = $where1;
// not using
/*
$wheremeta = " WHERE ".$wpdb->usermeta.".user_id IN ".
"(SELECT distinct user_id FROM ".$wpdb->usermeta
." WHERE ".$wpdb->usermeta .".meta_key ='" . $wpdb->prefix . "capabilities')";
*/
}
else { // is multi site but not network admin - limit the users to those who have capabilities in this system
$where1 = ' INNER JOIN ' . $wpdb->users.' ON '
. $wpdb->users.'.ID = '.$wpdb->usermeta.'.user_id WHERE '
.$wpdb->usermeta.'.meta_key =\'' . $wpdb->prefix . 'capabilities\'' ;
// if getting users who might not have other user meta ?
$where2 = ' INNER JOIN ' . $wpdb->usermeta.' ON '
. $wpdb->users.'.ID = '.$wpdb->usermeta.'.user_id WHERE '
.$wpdb->usermeta.'.meta_key =\'' . $wpdb->prefix . 'capabilities\'' ;
}
}
//add other criteria
$where = apply_filters('amr-users-users-where',$where1); // 20150820 NOtinUse?
//$wpdb->show_errors();
//track_progress('Start amr get users');
//$query = $wpdb->prepare( "SELECT * FROM $wpdb->usermeta".$where); // WHERE meta_key = %s", $meta_key );
$query = "SELECT umeta_id, user_id, meta_key, meta_value FROM $wpdb->usermeta ".$where; // we controlled the input so prepare not necessary
$metalist = $wpdb->get_results($query, OBJECT_K);
// arghh - sometimes we need usrs that do not have the meta values, so does this mean we have to get all users ?
//$query = $wpdb->prepare( "SELECT ID, user_login, user_nicename, user_email, user_url, user_registered, display_name FROM $wpdb->users".$where); // WHERE meta_key = %s", $meta_key );
$query = "SELECT ID, user_login, user_nicename, user_email, user_url, user_registered, display_name FROM $wpdb->users ".$where2; //201702
//if (WP_DEBUG) echo $query;
$users = $wpdb->get_results($query, OBJECT_K); // so returns id as key - NOT WORKING IN EVERY SITE
foreach ($users as $i => $u) {
if (isset($metalist[$i])) {
$users[$i] = (object) array_merge((array) $u, (array) $metalist[$i]);
unset($metalist[$i]);
}
}
//track_progress('After combining users with their meta');
return ($users);
}
function amr_get_alluserdata( $list ) { /* get all user data and attempt to extract out any object values into arrays for listing */
global $excluded_nicenames,
$amain,
$aopt, // the list options (selected, included, excluded)
$orig_mk, // original meta key mapping - nicename key to original metakey
$amr_current_list;
$amr_current_list = $list;
$main_fields = amr_get_usermasterfields(); // mainwpuser fields less any excluded in nice names
// maybe use, but no major improvement for normal usage add_filter( 'pre_user_query', 'amr_add_where');
if (!$orig_mk = ausers_get_option('amr-users-original-keys'))
$orig_mk = array();
//
// track_progress ('Meta fields we could use to improve selection: '.print_r($orig_mk, true));
$combofields = amr_get_combo_fields($list);
$role = '';
$mkeys = array();
if (!empty($aopt['list'][$list]['included'])) {
// if we have fields that are in main user table, we could add - but unliket as selection criteria - more in search
foreach ($aopt['list'][$list]['included'] as $newk=> $choose ) {
if (isset ($orig_mk[$newk]))
$keys[$orig_mk[$newk]] = true;
if ($newk == 'first_role') {
if (is_array($choose))
$role = array_pop($choose);
else
$role = $choose;
}
if (isset ($orig_mk[$newk]) and ($newk == $orig_mk[$newk])) {// ie it is an original meta field
if (is_array($choose)) {
if (count($choose) == 1) {
$choose = array_pop($choose);
$compare = '=';
}
else $compare = 'IN';
}
else $compare = '=';
$meta_query[] = array (
'key' => $newk,
'value' => $choose,
'compare' => $compare
);
}
}
}
// now try for exclusions
if (!empty($aopt['list'][$list]['excluded'])) {
foreach ($aopt['list'][$list]['excluded'] as $newk=> $choose ) {
if (isset ($orig_mk[$newk])) {
$keys[$orig_mk[$newk]] = true; // we need to fetch a meta value
if ($newk == $orig_mk[$newk]) {// ie it is an original meta field 1 to 1
if (is_array($choose)) {
if (count($choose) == 1) {
$choose = array_pop($choose);
$compare = '!=';
}
else $compare = 'NOT IN';
}
else $compare = '!=';
$meta_query[] = array (
'key' => $newk,
'value' => $choose,
'compare' => $compare
);
}
}
} // end for each
}
// now need to make sure we find all the meta keys we need
foreach (array('selected','excludeifblank','includeonlyifblank' ,'sortby' ) as $v) {
if (!empty($aopt['list'][$list][$v])) {
foreach ($aopt['list'][$list][$v] as $newk=> $choose ) {
if (isset ($orig_mk[$newk])) {// ie it is FROM an original meta field
$keys[$orig_mk[$newk]] = true;
}
}
}
}
if (!empty($aopt['list'][$list]['grouping'])) {
foreach ($aopt['list'][$list]['grouping'] as $i=> $newk ) {
if (isset ($orig_mk[$newk])) {// ie it is FROM an original meta field
$keys[$orig_mk[$newk]] = true;
}
}
}
$args = array();
$users = array(); // to handle in weird situation of no users - eg if db corrupt!
if (!empty ($role) ) $args['role'] = $role;
if (!empty ($meta_query) ) $args['meta_query'] = $meta_query;
//if (!empty ($fields) ) $args['fields'] = $fields;
//$args['fields'] = 'all_with_meta'; //might be too huge , but fast - DOES NOT GET META DATA ?? and/or only gets single values
//track_progress ('Simple meta selections to pass to query: '.print_r($args, true));
if (is_network_admin() or amr_is_network_admin() ) {
//if (WP_DEBUG) {echo '
';if (is_network_admin()) echo 'network admin'; else echo 'NOT network admin but treating as is';}
$args['blog_id'] = '0';
}
$args = apply_filters('amr-users-args',$args); // 20150820
// wordpress does not load the admin translation file in the front end and so roles do not translate
if ( ! is_admin() ) {
$locale = get_locale();
if (!($locale === 'en_US')) {
if (amr_need_the_field($amr_current_list, 'first_role') or
amr_need_the_field($amr_current_list, 'roles')) {
load_textdomain( 'default', WP_LANG_DIR . '/admin-' . get_locale() . '.mo' );
}
}
}
if (isset($amain['use_wp_query']) and ($amain['use_wp_query'])) { //check which kind
$all = get_users($args); // later - add selection if possible here to reduce memory requirements
//if (WP_DEBUG) {echo '
Fetched with wordpress query. No. of records found: '.count($all).'
using args: '; var_dump($all); }
}
else {
//if (WP_DEBUG) echo '
if WP_DEBUG: Fetching with own query ';
$all = amru_get_users($args); // later - add selection if possible here to reduce memory requirements
//if (WP_DEBUG) {echo '
Fetched with own query. No. of records found: '.count($all).''; }
}
//track_progress('after get wp users, we have '.count($all));
foreach ($all as $i => $userobj) { // build our user array and add any missing meta
// save the main data, toss the rest
foreach ($main_fields as $i2=>$v2) {
//$users[$i][$v2] = $userobj->$v2;
if (!empty($userobj->$v2))
$users[$userobj->ID][$v2] = $userobj->$v2; //OBJECT_K does not always seem to key the array correctly
}
// -------------------------------------------------------------------
// we just need to expand the meta data
if (!empty($keys)) { // - the list of metadata keys. If we have some meta data requested, and most of the time we will
foreach ($keys as $i2 => $v2) {
//if (!isset($userobj->$i2)) { // in some versions the overloading does not work - only fetches 1
//$userobj->$i2 = get_user_meta($userobj->ID, $i2, false);
//wordpress does some kind of overloading to fetch meta data BUT above only fetches single
$test = get_user_meta($userobj->ID, $i2, false); // get as array in case there are multiple values
//$test = maybe_unserialize($test); // because weirdly gf stores serialised data even though wp serialise it anyway, so it's doubly done
if (!empty($test)) {
//if (WP_DEBUG) echo 'i2='.$i2;var_dump($test);
if (is_array($test)) { // because we are now checking for multiple values so it returns an array
if (count($test) == 1) { // one record, single value returned
$temp = current($test); // there is only one - get it without taking it out of array
//$temp = array_pop($test); // get that one record
//if (WP_DEBUG) {var_dump($temp);}
// oh dear next code broke those nasty complex s2membercustom fields
// but it's the way to deal with non associative arrays
if (is_array($temp)) { // if that one record is an array - hope to hell that's the end of the nested arrays, but now it wont be
if (!amr_is_assoc($temp)) { // if it is a numeric keyed array, cannot handle as per associative array
// ideally no spaces here BUT if there is no custom formatting routine to explode and re-implode, then folks complain about lack of space between. NB Check impact on filter values. (explode with spaces perhaps?)
//$temp = implode (',',$temp); // 20140305 space sinformatting only - not here
if (is_array(current($temp))) {
if (WP_DEBUG) {echo 'We have another level array - custom handling required, first entry listed only';}
$temp = implode (', ',current($temp));
}
else $temp = implode (', ',$temp); // must be a list of values ? implode here or later?
// or should we force it into a mulit meta array ?
}
// else leave as is for further processing
//else var_dump($temp);
}
$userobj->$i2 = $temp; // save it as our value
//$userobj->$i2 = array_pop($test); // cannot indirectly update an overloaded value
//if (WP_DEBUG) {echo '
save obj: ';var_dump($userobj->$i2);}
}
else {
// we got multple meta records - ASSUME for now it is a good implementation and the values are 'simple'
// otherwise they really should create their meta data a better way. Can't solve everyones problems.
$userobj->$i2 = implode(', ',$test);
}
}
else {
$userobj->$i2 = $test;
}
//only exists for gravity forms emergency contact - get rid of 201501
//$temp = maybe_unserialize ($userobj->$i2); // in case anyone done anything weird
//$temp = maybe_unserialize ($temp); // in case anyone done anything weird
//gravity forms has weird serialised nested array - argghh
//if (WP_DEBUG) {echo '
attempted unserialise'; var_dump($temp);}
$key = str_replace(' ','_', $i2); /* html does not like spaces in the names*/
if (!empty($temp)) {
$temp = objectToArray ($temp); /* must do all so can cope with incomplete objects eg: if the creating plugin has been uninstalled*/
if (is_array($temp) ) {
if (count($temp) == 1) { // one record, single value returned - will fix that annoying gravity form emergency contact thing
// oh dear but broke the single capability thing
if ((!current($temp) == true) and (!current($temp) == '1')) // ie not a capability thing
$temp = array_pop($temp); // its a usable value and
}
}
if (is_array($temp) ) { // if it is still an array inside
//if (WP_DEBUG) {echo '
Got an array'; var_dump($temp);}
foreach ($temp as $i3 => $v3) {
$key = $i2.'-'.str_replace(' ','_', $i3);/* html does not like spaces in the names*/
//if (WP_DEBUG) {echo '
Got an array - key'; var_dump($key);}
if (is_array($v3)) {
//if (WP_DEBUG) {echo '
Got an nested array'; }
// code just in case another plugin nests deeper, until we know tehre is one, let us be more efficient
if (amr_is_assoc($v3)) { // does not yet handle, just dump values for now
// really shouldn't be nested this deep associativey - bad
$users[$i][$key] = implode(", ", $v3);
//if (WP_DEBUG) {echo '
Got associative array:'.$i2.' '.$i3; var_dump($users[$i][$key]);}
}
else { // is numeric array eg s2member custom multi choice
$users[$userobj->ID][$key] = implode(", ", $v3);
}
}
else {
$users[$userobj->ID][$key] = $v3;
}
}
}
else {
$users[$userobj->ID][$key] = $temp;
//if (WP_DEBUG) {echo '
Not an array'; var_dump($temp);}
}
unset($temp);
// we could add some include / exclude checking here?
//if (WP_DEBUG) var_dump($users[$userobj->ID]);
}
}
} /// end for each keys
} //
unset($all[$i]);
} // end for each all
unset($all);
$users = apply_filters('amr_get_users', $users);
// allow addition or removal of normal wp users who will have userid, and /or any other data
//track_progress('after get users meta check '.(count($users)));
$post_types=get_post_types();
/* get the extra count data */
if (amr_need_the_field($list,'comment_count'))
$c = get_commentnumbers_by_author();
else
$c= array();
//track_progress('after get comments check');
if (!empty($users)) {
foreach ($users as $iu => $u) {
// do the comments
if (isset($u['ID']) and isset ($c[$u['ID']])) {
$users[$iu]['comment_count'] = $c[$u['ID']]++;
/*** would like to cope with situation of no userid, but awkward here */
}
// do the post counts
foreach ( $post_types as $post_type ) {
if (amr_need_the_field($list,$post_type.'_count')) {
$users[$iu][$post_type.'_count'] = amr_count_user_posts($u['ID'], $post_type);
// if ()WP_DEBUG) echo '
**'.$post_type.' '.$list[$iu][$post_type.'_count'];
// $list[$iu]['post_count'] = get_usernumposts($u['ID']); /* wordpress function */
if ($users[$iu][$post_type.'_count'] == 0) unset($users[$iu][$post_type.'_count']);
}
}
if (amr_need_the_field($list,'first_role')) {
$user_object = new WP_User($u['ID']);
if (!empty($user_object->roles))
$users[$iu]['first_role'] = amr_which_role($user_object);
if (empty ($users[$iu]['first_role'] ))
unset($users[$iu]['first_role']);
}
}
}
//track_progress('after post types and roles:'.count($users));
unset($c);
$users = apply_filters('amr_get_users_with_meta', $users); // allow addition of users from other tables with own meta data
//track_progress('after user filter, have'.count($users));
if (empty($users)) return (false);
return ($users);
}
function amr_get_userdata($id){
$data = get_userdata($id);
//if (!($data) and WP_DEBUG) {echo 'Unexpected data for get user with '.$id;var_dump($data); }
if (!empty($data->data))
return($data->data); // will not have meta data
else
return ($data);
};
function ameta_cache_enable () {
/* Create a cache table if t does not exist */
global $wpdb, $charset_collate;
/* if the cache table does not exist, then create it . be VERY VERY CAREFUL about editing this sql */
/* if (empty($charset_collate))
$cachecollation = ' DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci ';
else
$cachecollation = $charset_collate;
*/
$cachecollation = $wpdb->get_charset_collate(); //20170227 new func from wp 3.5
$table_name = ameta_cachetable_name();
if($wpdb->get_var("show tables like '$table_name'") != $table_name) {
$sql = "CREATE TABLE " . $table_name . " (
id bigint NOT NULL AUTO_INCREMENT,
reportid varchar(20) NOT NULL,
line bigint(20) NOT NULL,
csvcontent text NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY reportid (reportid,line ) )
".$cachecollation." ;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
if($wpdb->get_var("show tables like '$table_name'") != $table_name) {
error_log($table_name.' not created');
return false;
}
else return true;
}
return true;
}
function ameta_cachelogtable_name() {
global $wpdb;
global $table_prefix;
if (is_network_admin() or amr_is_network_admin())
$table_name = $wpdb->base_prefix . "network_amr_reportcachelogging";
else
$table_name = $wpdb->prefix . "amr_reportcachelogging";
return($table_name);
}
function ameta_cachetable_name() {
global $wpdb;
global $table_prefix;
if (is_network_admin() or amr_is_network_admin())
$table_name = $wpdb->base_prefix . "network_amr_reportcache";
else
$table_name = $wpdb->prefix . "amr_reportcache";
return($table_name);
}
function ameta_cachelogging_enable() {
/* Create a cache logging register table if t does not exist */
global $wpdb, $charset_collate;
if (empty($charset_collate))
$cachecollation = ' DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci ';
else
$cachecollation = $charset_collate;
/* if the cache table does not exist, then create it . be VERY VERY CAREFUL about editing this sql */
$table_name = ameta_cachelogtable_name();
if ($wpdb->get_var("show tables like '$table_name'") != $table_name) {
$sql = "CREATE TABLE " . $table_name . " (
id bigint NOT NULL AUTO_INCREMENT,
eventtime datetime NOT NULL,
eventdescription text NOT NULL,
PRIMARY KEY (id) )
".$cachecollation. "
;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
if($wpdb->get_var("show tables like '$table_name'") != $table_name) {
error_log($table_name.' not created');
return false;
}
else return true;
}
return true;
}
function amr_if_values_in_user_field ($in, $field) {
// field could be csv multiple values maybe?
// should not be looking for matched values of long text that has a comma ?
// so if comma, assume csv? or test for csv and still check whole value?
// inclusions an array,
foreach ($in as $i) {
if (!empty($i)) { // only happens if has actual value
if ($field == $i) return true;
//oh dear we have some addons or fields with comma space and some with comma
if (strpos($field, ', ')) { // we have a comma and more - is it csv multiple values?
$values = explode (', ', $field);
foreach ($values as $v) {
if ($v == $i) return true;
}
}
else { // not comma space
if (strpos($field, ',')) { // we have a comma and more - is it csv multiple values?
$values = explode (',', $field);
foreach ($values as $v) {
if ($v == $i) return true;
}
}
};
//$instr = strpos($field, $i);
//if (!($instr === false)) {
// return true;
//}
}
}
return false;
}
function amr_build_user_data_maybe_cache($ulist='1') { //returns the lines of data, including the headings
global $amr_refreshed_heading; // seems heading not used right when we are filtering. workaround for now.
/* Get the fields to use for the chosen list type */
global $aopt, $amrusers_fieldfiltering;
global $amain;
global $wp_post_types;
global $time_start;
global $cache;
global $amr_current_list;
$amr_current_list = $ulist;
if (get_transient('amr_users_cache_'.$ulist)) {
track_progress('Stop - run for '.$ulist.' in progress already according to transient');
return false;
}
//else track_progress('Set in progress flag for '.$ulist);
set_transient('amr_users_cache_'.$ulist,true, 10); // 10 seconds allowed for now
$network = ausers_job_prefix();
// track_progress('Getting data for network='.$network);
register_shutdown_function('amr_shutdown');
set_time_limit(360); // should we make this an option....
$time_start = microtime(true);
ameta_options();
$date_format = get_option('date_format');
$time_format = get_option('time_format');
add_filter('pub_priv_sql_capability', 'amr_allow_count');// checked by the get_posts_by_author_sql
if (!isset($amrusers_fieldfiltering))
$amrusers_fieldfiltering = false;
if (function_exists('amr_check_for_realtime_filtering'))
amr_check_for_realtime_filtering($ulist);
//else /*if (WP_DEBUG)*/ return ('NO Realtime Filtering');
if (empty($aopt['list'][$ulist])) {
track_progress('No configuration for list '.$ulist);
return false;
}
$l = $aopt['list'][$ulist]; /* *get the config with any additional filtering */
$rptid = amr_rptid($ulist);
if (!$amrusers_fieldfiltering) { // then do cache stuff
/* now record the cache attempt */
$cache = new adb_cache();
$r = $cache->clear_cache($rptid);
// If (!($r)) echo '
Cache does not exist or not cleared for '.$rptid;
$r = $cache->record_cache_start($rptid, $amain['names'][$ulist]);
// If (!($r)) echo '
Cache start not recorded '.$rptid;
// $cache->log_cache_event(sprintf(__('Started cacheing report %s','amr-users'),$rptid));
}// end cache
//track_progress('before get all users needed');
$list = amr_get_alluserdata($ulist); /* keyed by user id, and only the non excluded main fields and the ones that we asked for */
$total = count($list);
//track_progress('after get all user data'.$total);
$head = '';
$tablecaption = '';
if ($total > 0) {
if (isset ($l['selected']) and (count($l['selected']) > 0)) {
$head .= PHP_EOL.'