Como pesquisar todas as meta meta de usuário de users.php no admin


14

O formulário de pesquisa na parte superior da lista de usuários na área Admin (wp-admin / users.php) é limitado e não pesquisa todos os meta-campos do usuário, como biografia, identificadores de mensagens instantâneas, etc. foi capaz de encontrar um plugin que pode adicionar isso.

Alguém está ciente de um plug-in ou de uma função que eu poderia criar que poderia expandir essa pesquisa por toda a data no banco de dados _usermeta - idealmente, mesmo campos extras criados por um plug-in ou função.

Respostas:


24

Olá @ user2041:

Claramente, como você sabe, precisa modificar a pesquisa executada, o que pode ser feito modificando os valores na instância da WP_User_Searchclasse usada para a pesquisa (você pode encontrar o código-fonte /wp-admin/includes/user.phpse quiser estudá-lo.)

O WP_User_SearchObjeto

Veja como é print_r()esse objeto no WordPress 3.0.3 ao pesquisar o termo " TEST" e sem outros plugins que possam afetá-lo:

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] => 
)

The pre_user_searchHook

Para modificar os valores do WP_User_Searchobjeto, você usará o 'pre_user_search'gancho que recebe a instância atual do objeto; Liguei print_r()de dentro desse gancho para ter acesso aos seus valores que exibi acima.

O exemplo a seguir, que você pode copiar no functions.phparquivo do seu tema ou em um arquivo PHP para um plug-in que você está escrevendo, adiciona a capacidade de pesquisar na descrição do usuário, além de poder pesquisar nos outros campos. A função modifica os query_frome as query_wherepropriedades do $user_searchobjeto que você precisa para ser confortável com o SQL de entender.

Modificação cuidadosa de SQL em ganchos

O código na yoursite_pre_user_search()função assume que nenhum outro plugin modificou a query_wherecláusula anterior a ele; se outro plug-in tiver modificado a cláusula where, de modo que a substituição 'WHERE 1=1 AND ('por "WHERE 1=1 AND ({$description_where} OR"não funcione mais, isso também será interrompido. É muito mais difícil escrever uma adição robusta que não possa ser quebrada por outro plug-in ao modificar o SQL como este, mas é o que é.

Adicionar espaços à esquerda e à direita ao inserir SQL em ganchos

Observe também que quando se utiliza SQL como esta em WordPress é sempre uma boa idéia de incluir esquerda e à direita espaços, um com " INNER JOIN {$wpdb->usermeta} ON "outra forma sua consulta SQL pode conter o seguinte, onde não há espaço antes "INNER", o que, naturalmente, falhar: " FROM wp_postsINNER JOIN {$wpdb->usermeta} ON ".

Use em "{$wpdb->table_name"}vez de codificar nomes de tabela

Em seguida, certifique-se de sempre usar as $wpdbpropriedades para fazer referência aos nomes das tabelas, caso o site altere o prefixo da tabela de 'wp_'para outra coisa. Portanto, é melhor consultar "{$wpdb->users}.ID" (com aspas duplas, não aspas simples) em vez de codificar "wp_users.ID".

Limitar a consulta apenas quando existirem termos de pesquisa

Por fim, modifique a consulta apenas quando houver um termo de pesquisa que você possa testar inspecionando a search_termpropriedade do WP_User_Searchobjeto.

A yoursite_pre_user_search()função para'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);    
  }
}

Pesquisando cada par meta-valor-chave requer um SQL JOIN

É claro que o provável motivo pelo qual o WordPress não permite pesquisar campos de meta-usuário é que cada um adiciona um SQL JOINà consulta e uma consulta com muitas junções pode ser lenta. Se você realmente precisar pesquisar em muitos campos, eu criaria um '_search_cache'campo no usermeta que coleta todas as outras informações em um campo do usermeta para exigir apenas uma associação para pesquisar tudo.

Os sublinhados principais em Meta Keys dizem ao WordPress para não ser exibido

Observe que o sublinhado à esquerda '_search_cache'informa ao WordPress que esse é um valor interno e não algo que deve ser exibido ao usuário.

Criar um cache de pesquisa com os ganchos 'profile_update'e'user_register'

Portanto, você precisará conectar ambos 'profile_update'e 'user_register'que são acionados para salvar um usuário e registrar um novo usuário, respectivamente. Você pode pegar todas as meta chaves e seus valores nesses ganchos (mas omitir aqueles com valores serializados ou matrizes codificados por URL) e concatená-los para armazenar como um meta valor longo usando a '_search_cache'chave

Armazenar meta como '|'pares de valor-chave delimitado

Decidi pegar todos os nomes de chave e todos os seus valores e concatená-los em uma grande sequência com dois pontos (":") separando as chaves dos valores e barras verticais ("|") que separam os pares de valores-chave como este (I os agrupamos em várias linhas para que você possa usá-los sem rolar para a direita):

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

Permite pesquisas especializadas no Meta usando key:value

Adicionar a chave e os valores, como fizemos, permite fazer pesquisas como " rich_editing:true" para encontrar todos os que têm edição rica ou procurar " phone:null" para encontrar aqueles sem número de telefone.

Mas cuidado com os artefatos de pesquisa

É claro que o uso dessa técnica cria artefatos de pesquisa possivelmente indesejados, como pesquisa por "negócios", e todos serão listados. Se isso for um problema, talvez você não queira usar um cache tão elaborado.

A yoursite_profile_update()função para 'profile_update'e'user_register'

Para a função yoursite_profile_update(), como yoursite_pre_user_search()acima, pode ser copiado para o functions.phparquivo do seu tema ou você pode usar em um arquivo PHP o plugin que está escrevendo:

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()Função atualizada, habilitando um único SQL JOINpara pesquisar todos os meta-valores interessantes

Obviamente, para yoursite_profile_update()ter algum efeito, você precisará modificar yoursite_pre_user_search()para usar a '_search_cache'meta-chave em vez da descrição, que temos aqui (com as mesmas ressalvas mencionadas acima):

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 Ótima resposta completa! Esta é uma das muitas vezes neste site em que eu gostaria de dar vários upvotes para uma resposta tão bem pesquisada a uma pergunta que não seja de ações.
MathSmath

Obrigado @MathSmath - Aprender que as pessoas apreciam é o que me faz continuar. :)
MikeSchinkel

Mike, obrigado pela resposta completa! Vou trabalhar isso no meu tema hoje mais tarde e ver quem vai.
John Chandler

Mike, estamos perto, mas ..! Claramente, isso está me deixando no começo certo. O uso da função única mencionada primeiro ou das duas funções para utilizar o profile_update está funcionando em termos da capacidade de pesquisar e obter os resultados adequados. Infelizmente, essas funções estão interferindo na listagem quando eu puxo o users.php (que nenhum termo de pesquisa especificado). Não está mostrando todos os usuários. Quando clico no filtro Todos, ele mostra apenas dois (de quatro), um deles sou eu, e quando clico no filtro Administradores, ele não faz nenhum usuário - nem eu! Alguma ideia?
John Chandler

Um pouco mais de informação. Editei a primeira função para pesquisar um campo chamado 'empresa', que adicionei por meio do plug-in extra de detalhes do usuário. Funciona quando procuro um usuário com o nome da empresa. Porém, parece que a classificação por Todos, sem pesquisa, está retornando apenas os dois resultados que possuem dados no campo da empresa e não retornando os usuários que não têm dados no campo da empresa.
John Chandler

5

Eu realmente gostei da abordagem de MikeSchinkel e da explicação completa acima. Isso foi super útil. Não consegui fazê-lo funcionar, pois o pre_user_search foi preterido e, na verdade, não funciona no 3.2. Eu tentei trocá-lo com pre_user_query, mas isso também não funcionou. O problema é que parece que $ user_search-> search_term não funciona mais, então eu apenas usei $ _GET ['s']. Fiz alguns hackers e consegui que isso funcionasse no 3.2. A única coisa que você precisa definir é a sua variedade de metadados pesquisáveis.

//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);    
}

Espero que isso ajude alguém.


Alguém tem alguma experiência recente com isso? Pessoalmente, não consigo trabalhar com nenhum desses códigos, incluindo os mais recentes. Eu tentei algumas outras opções, mas encontrei problemas com a paginação dos resultados .
Robert Andrews


1

Aqui está uma solução para a versão mais recente do wordpress.

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' ] ) . "')";
    }

-1

Isso é o que eu criei para o WordPress 4.7.1, que adiciona a pesquisa curinga a todos os metadados do usuário.


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;
}

Basicamente, estamos apenas juntando as tabelas users e user_meta no ID do usuário e reconstruindo a cláusula WHERE para incluir a pesquisa na coluna meta_value.


1
O que você está sugerindo aqui é altamente perigoso ! Você nunca deve passar o que é fornecido por um usuário para o banco de dados. Eles podem soltar suas tabelas, seqüestrar seu banco de dados - ver injeção SQL como frase de pesquisa - ou simplesmente criptografar todos os seus dados. Faça um em "%".like_escape( $_GET['s'] )."%"vez disso. O mesmo vale para todos os outros dados fornecidos pelo usuário . Caso contrário, seu campo de pesquisa se tornará um gateway aberto para seus dados.
Kaiser
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.