Cara mencari semua meta pengguna dari users.php di admin

14

Formulir pencarian di bagian atas daftar pengguna di area Admin (wp-admin / users.php) terbatas dan tidak mencari semua bidang meta pengguna, seperti bio, pegangan instant messenger, dll. Saya belum telah dapat menemukan plugin yang dapat menambahkan ini.

Adakah yang mengetahui plugin atau fungsi yang dapat saya buat yang dapat memperluas pencarian ini untuk semua tanggal di DB _usermeta - idealnya bahkan bidang tambahan dibuat oleh plugin atau fungsi.

John Chandler
sumber

Jawaban:

24

Hai @ user2041:

Jelas Anda tahu bahwa Anda perlu memodifikasi pencarian yang dilakukan yang dapat Anda lakukan dengan memodifikasi nilai-nilai dalam contoh WP_User_Searchkelas yang digunakan untuk pencarian (Anda dapat menemukan kode sumber di/wp-admin/includes/user.php jika Anda ingin mempelajarinya.)

Itu WP_User_Search Object

Beginilah bentuk print_r()objek itu dengan WordPress 3.0.3 saat mencari istilah " TEST" dan tanpa plugin lain yang mungkin memengaruhinya:

WP_User_Search Object
(
  [results] => 
  [search_term] => TEST
  [page] => 1
  [role] => 
  [raw_page] => 
  [users_per_page] => 50
  [first_user] => 0
  [last_user] => 
  [query_limit] =>  LIMIT 0, 50
  [query_orderby] =>  ORDER BY user_login
  [query_from] =>  FROM wp_users
  [query_where] =>  WHERE 1=1 AND (user_login LIKE '%TEST%' OR user_nicename LIKE '%TEST%' OR user_email LIKE '%TEST%' OR user_url LIKE '%TEST%' OR display_name LIKE '%TEST%')
  [total_users_for_query] => 0
  [too_many_total_users] => 
  [search_errors] => 
  [paging_text] => 
)

Itu pre_user_search Hook

Untuk mengubah nilai WP_User_Searchobjek Anda akan menggunakan'pre_user_search' hook yang menerima instance objek saat ini; Saya menelepon print_r()dari dalam kait itu untuk mendapatkan akses ke nilai-nilainya yang saya tampilkan di atas.

Contoh berikut yang dapat Anda salin ke functions.phpfile tema Anda atau Anda dapat menggunakan file PHP untuk plugin yang Anda tulis menambahkan kemampuan untuk mencari di deskripsi pengguna di samping untuk dapat mencari di bidang lain. Fungsi memodifikasi query_fromdan query_whereproperti dari $user_searchobjek yang Anda perlu nyaman dengan SQL untuk mengerti.

Hati-hati Memodifikasi SQL di Hooks

Kode dalam yoursite_pre_user_search()fungsi tersebut mengasumsikan bahwa tidak ada plugin lain yang memodifikasi query_whereklausa sebelumnya; jika plugin lain telah memodifikasi klausa mana yang menggantikan'WHERE 1=1 AND (' dengan yang "WHERE 1=1 AND ({$description_where} OR"tidak berfungsi lagi maka ini akan rusak juga. Jauh lebih sulit untuk menulis tambahan yang kuat yang tidak dapat dipecah oleh plugin lain ketika memodifikasi SQL seperti ini, tetapi ini adalah apa adanya.

Tambahkan Leading and Trailing Spaces saat Memasukkan SQL ke Hooks

Perhatikan juga bahwa ketika menggunakan SQL seperti ini di WordPress selalu merupakan ide yang baik untuk menyertakan spasi awal dan akhir seperti itu " INNER JOIN {$wpdb->usermeta} ON "jika tidak, permintaan SQL Anda mungkin berisi yang berikut di mana tidak ada ruang sebelumnya "INNER", yang tentu saja akan gagal:" FROM wp_postsINNER JOIN {$wpdb->usermeta} ON " .

Menggunakan "{$wpdb->table_name"} sebagai ganti Nama Tabel Hardcoding

Selanjutnya pastikan untuk selalu menggunakan $wpdbproperti untuk merujuk nama tabel jika situs telah mengubah awalan tabel dari yang 'wp_'lain. Jadi lebih baik merujuk "{$wpdb->users}.ID" (dengan tanda kutip ganda, bukan tanda kutip tunggal) daripada hardcoding "wp_users.ID".

Batasi Kueri untuk Hanya Saat Persyaratan Pencarian Ada

Terakhir adalah dengan hanya memodifikasi kueri ketika ada istilah pencarian yang dapat Anda uji dengan memeriksa search_termproperti WP_User_Searchobjek.

The yoursite_pre_user_search()Fungsi untuk'pre_user_search'

add_action('pre_user_search','yoursite_pre_user_search');
function yoursite_pre_user_search($user_search) {
  global $wpdb;
  if (!is_null($user_search->search_term)) {
    $user_search->query_from .= " INNER JOIN {$wpdb->usermeta} ON " . 
      "{$wpdb->users}.ID={$wpdb->usermeta}.user_id AND " .
      "{$wpdb->usermeta}.meta_key='description' ";
    $description_where = $wpdb->prepare("{$wpdb->usermeta}.meta_value LIKE '%s'",
      "%{$user_search->search_term}%");
    $user_search->query_where = str_replace('WHERE 1=1 AND (',
      "WHERE 1=1 AND ({$description_where} OR ",$user_search->query_where);    
  }
}

Mencari Setiap Pasangan Nilai Kunci Meta Memerlukan SQL JOIN

Tentu saja kemungkinan alasan WordPress tidak membiarkan Anda mencari di bidang usermeta adalah karena masing-masing menambahkan SQL JOINke kueri dan ke kueri dengan terlalu banyak gabungan bisa memang lambat. Jika Anda benar-benar perlu mencari di banyak bidang maka saya akan membuat '_search_cache'bidang di usermeta yang mengumpulkan semua informasi lain ke dalam satu bidang usermeta sehingga hanya perlu satu bergabung untuk mencari semuanya.

Memimpin Garis Bawah di Meta Keys memberi tahu WordPress untuk Tidak Ditampilkan

Perhatikan bahwa memimpin garis bawah di '_search_cache'memberi tahu WordPress bahwa ini adalah nilai internal dan bukan sesuatu yang pernah ditampilkan kepada pengguna.

Buat Cache Pencarian dengan 'profile_update'dan 'user_register'Hooks

Jadi, Anda harus menghubungkan keduanya 'profile_update'dan 'user_register'yang dipicu untuk masing-masing menyimpan pengguna dan mendaftarkan pengguna baru. Anda bisa mengambil semua kunci meta dan nilainya di dalam kait tersebut (tetapi mengabaikannya dengan nilai-nilai yang serial atau array yang dikodekan URL) lalu menggabungkannya untuk menyimpan sebagai satu nilai meta panjang menggunakan'_search_cache' kunci tersebut.

Simpan Meta sebagai '|'Pasangan Nilai Kunci yang Dibatasi

Saya memutuskan untuk mengambil semua nama kunci dan semua nilainya dan menggabungkannya menjadi satu string besar dengan titik dua (":") memisahkan kunci dari nilai dan bar vertikal ("|") memisahkan pasangan nilai kunci seperti ini (saya telah membungkusnya di beberapa baris sehingga Anda dapat melakukannya tanpa menggulir ke kanan):

nickname:mikeschinkel|first_name:mikeschinkel|description:This is my bio|
rich_editing:true|comment_shortcuts:false|admin_color:fresh|use_ssl:null|
wp_user_level:10|last_activity:2010-07-28 01:25:46|screen_layout_dashboard:2|
plugins_last_view:recent|screen_layout_post:2|screen_layout_page:2|
business_name:NewClarity LLC|business_description:WordPress Plugin Consulting|
phone:null|last_name:null|aim:null|yim:null|jabber:null|
people_lists_linkedin_url:null

Aktifkan Pencarian Khusus di Meta Menggunakan key:value

Menambahkan kunci dan nilai seperti yang kami lakukan memungkinkan Anda melakukan pencarian seperti " rich_editing:true" untuk menemukan semua orang yang memiliki banyak pengeditan, atau mencari " phone:null" untuk menemukan mereka yang tidak memiliki nomor telepon.

Tapi Waspadalah terhadap Artefak Pencarian

Tentu saja menggunakan teknik ini menciptakan kemungkinan artefak pencarian yang tidak diinginkan seperti pencarian "bisnis" dan semua orang akan terdaftar. Jika ini masalah maka Anda mungkin tidak ingin menggunakan cache yang rumit.

The yoursite_profile_update()Fungsi untuk 'profile_update'dan'user_register'

Untuk fungsi yoursite_profile_update(), seperti di yoursite_pre_user_search()atas dapat disalin ke functions.phpfile tema Anda atau Anda dapat menggunakan file PHP untuk plugin yang Anda tulis:

add_action('profile_update','yoursite_profile_update');
add_action('user_register','yoursite_profile_update');
function yoursite_profile_update($user_id) {
  $metavalues = get_user_metavalues(array($user_id));
  $skip_keys = array(
    'wp_user-settings-time',
    'nav_menu_recently_edited',
    'wp_dashboard_quick_press_last_post_id',
  );
  foreach($metavalues[$user_id] as $index => $meta) {
    if (preg_match('#^a:[0-9]+:{.*}$#ms',$meta->meta_value))
      unset($metavalues[$index]); // Remove any serialized arrays
    else if (preg_match_all('#[^=]+=[^&]\&#',"{$meta->meta_value}&",$m)>0)
      unset($metavalues[$index]); // Remove any URL encoded arrays
    else if (in_array($meta->meta_key,$skip_keys))
      unset($metavalues[$index]); // Skip and uninteresting keys
    else if (empty($meta->meta_value)) // Allow searching for empty
      $metavalues[$index] = "{$meta->meta_key }:null";
    else if ($meta->meta_key!='_search_cache') // Allow searching for everything else
      $metavalues[$index] = "{$meta->meta_key }:{$meta->meta_value}";
  }
  $search_cache = implode('|',$metavalues);
  update_user_meta($user_id,'_search_cache',$search_cache);
}

yoursite_pre_user_search()Fungsi yang Diperbarui memungkinkan SQL Tunggal JOINuntuk Mencari Semua Nilai Meta yang Menarik

Tentu saja untuk yoursite_profile_update()mendapatkan efek apa pun, Anda perlu memodifikasi yoursite_pre_user_search()untuk menggunakan '_search_cache'kunci meta alih-alih deskripsi, yang kami miliki di sini (dengan peringatan yang sama seperti disebutkan di atas):

add_action('pre_user_search','yoursite_pre_user_search');
function yoursite_pre_user_search($user_search) {
  global $wpdb;
  if (!is_null($user_search->search_term)) {
    $user_search->query_from .= " INNER JOIN {$wpdb->usermeta} ON " . 
      "{$wpdb->users}.ID={$wpdb->usermeta}.user_id AND " . 
      "{$wpdb->usermeta}.meta_key='_search_cache' ";
    $meta_where = $wpdb->prepare("{$wpdb->usermeta}.meta_value LIKE '%s'",
      "%{$user_search->search_term}%");
    $user_search->query_where = str_replace('WHERE 1=1 AND (',
      "WHERE 1=1 AND ({$meta_where} OR ",$user_search->query_where);
  }
}
MikeSchinkel
sumber
@ MikeSchinkel Jawaban yang bagus dan teliti! Ini adalah salah satu dari banyak kali di situs ini di mana saya berharap saya bisa memberikan beberapa upvotes untuk jawaban yang diteliti dengan baik untuk pertanyaan non-stok.
MathSmath
Terima kasih @MathSmath - Mempelajari bahwa orang-orang menghargai itu yang membuat saya terus maju. :)
MikeSchinkel
Mike, Terima kasih atas jawabannya! Saya akan mengerjakan ini ke dalam tema saya hari ini dan melihat siapa yang pergi.
John Chandler
Mike, Kami dekat, tapi ..! Jelas ini membuat saya memulai dengan benar. Menggunakan salah satu fungsi yang Anda sebutkan pertama, atau dua fungsi untuk memanfaatkan profile_update berfungsi dalam hal kemampuan untuk mencari dan mendapatkan hasil yang tepat. Sayangnya, fungsi-fungsi ini mengacaukan daftar ketika saya pertama kali menarik users.php (yang tidak ditentukan istilah pencarian). Itu tidak menunjukkan semua pengguna. Ketika saya mengklik pada filter Semua, itu hanya menampilkan dua (dari empat), salah satunya adalah saya, dan ketika saya mengklik pada filter Administrator itu tidak ada pengguna - bahkan saya! Ada ide?
John Chandler
Sedikit info lagi. Saya mengedit fungsi pertama untuk mencari bidang yang disebut 'perusahaan' yang saya tambahkan melalui plugin detail pengguna tambahan. Ini berfungsi ketika saya mencari pengguna dengan nama perusahaan. Namun, tampaknya pengurutan menurut Semua, tanpa pencarian, hanya mengembalikan dua hasil yang memiliki data di bidang perusahaan, dan tidak mengembalikan pengguna yang tidak memiliki data di bidang perusahaan.
John Chandler
5

Saya sangat menghargai pendekatan MikeSchinkel dan penjelasan menyeluruh di atas. Ini sangat membantu. Saya tidak dapat mengaktifkannya karena pre_user_search sudah usang dan tidak benar-benar berfungsi di 3.2. Saya mencoba hanya beralih dengan pre_user_query tapi itu tidak berhasil. Masalahnya, tampaknya $ user_search-> search_term tidak berfungsi lagi jadi saya hanya menggunakan $ _GET ['s']. Saya melakukan peretasan dan berhasil menjalankannya di 3.2. Satu-satunya hal yang perlu Anda atur adalah array metadata yang bisa dicari.

//Searching Meta Data in Admin
add_action('pre_user_query','yoursite_pre_user_search');
function yoursite_pre_user_search($user_search) {
    global $wpdb;
    if (!isset($_GET['s'])) return;

    //Enter Your Meta Fields To Query
    $search_array = array("customer_id", "postal_code", "churchorganization_name", "first_name", "last_name");

    $user_search->query_from .= " INNER JOIN {$wpdb->usermeta} ON {$wpdb->users}.ID={$wpdb->usermeta}.user_id AND (";
    for($i=0;$i<count($search_array);$i++) {
        if ($i > 0) $user_search->query_from .= " OR ";
            $user_search->query_from .= "{$wpdb->usermeta}.meta_key='" . $search_array[$i] . "'";
        }
    $user_search->query_from .= ")";        
    $custom_where = $wpdb->prepare("{$wpdb->usermeta}.meta_value LIKE '%s'", "%" . $_GET['s'] . "%");
    $user_search->query_where = str_replace('WHERE 1=1 AND (', "WHERE 1=1 AND ({$custom_where} OR ",$user_search->query_where);    
}

Semoga ini bisa membantu seseorang.

David
sumber
Adakah yang punya pengalaman baru-baru ini dengan semua ini? Secara pribadi, saya tidak bisa mendapatkan bit kode ini bekerja, termasuk yang terbaru. Saya telah mencoba beberapa opsi lain, tetapi telah menemukan masalah dengan hasil pagination .
Robert Andrews
1

Ini adalah solusi untuk wordpress versi terbaru.

add_action( 'pre_user_query', 'yoursite_pre_user_search'  );
    function yoursite_pre_user_search( $query ) {
        $query->query_where .= "YOUR QUERY '" . str_replace("*", "%", $query->query_vars[ 'search' ] ) . "')";
    }
Patrik Grinsvall
sumber
-1

Inilah yang saya buat untuk WordPress 4.7.1 yang menambahkan pencarian wildcard ke semua data meta pengguna.


add_action( 'pre_user_query', 'ds_pre_user_search'  );
function ds_pre_user_search( $query ) {
    global $wpdb;

    if( empty($_REQUEST['s']) ){return;}
    $query->query_from .= ' LEFT JOIN '.$wpdb->usermeta.' ON '.$wpdb->usermeta.'.user_id = '.$wpdb->users.'.ID';
    $query->query_where = "WHERE 1=1 AND (user_login LIKE '%".$_REQUEST['s']."%' OR ID = '".$_REQUEST['s']."' OR meta_value LIKE '%".$_REQUEST['s']."%')";
    return $query;
}

Pada dasarnya kami hanya bergabung dengan tabel users dan user_meta pada id pengguna dan membangun kembali klausa WHERE untuk memasukkan pencarian pada kolom meta_value.

wagontrader
sumber
1
Apa yang Anda sarankan di sini sangat berbahaya ! Anda seharusnya tidak pernah melewatkan apa pun yang disediakan oleh pengguna ke dalam DB. Mereka bisa menjatuhkan tabel Anda, membajak basis data Anda — lihat injeksi SQL sebagai frasa pencarian — atau cukup enkripsi semua data Anda. Lakukan "%".like_escape( $_GET['s'] )."%"sebaliknya. Hal yang sama berlaku untuk semua data yang disediakan pengguna lain . Lepaskan bidang pencarian Anda menjadi pintu gerbang terbuka ke data Anda.
kaiser