O problema
O WP parece remover o valor da minha variável de consulta antes que ela seja usada para filtrar a lista de usuários.
My Code
Esta função adiciona uma coluna personalizada à minha tabela Usuários em /wp-admin/users.php
:
function add_course_section_to_user_meta( $columns ) {
$columns['course_section'] = 'Section';
return $columns;
}
add_filter( 'manage_users_columns', 'add_course_section_to_user_meta' );
Esta função informa ao WP como preencher valores na coluna:
function manage_users_course_section( $val, $col, $uid ) {
if ( 'course_section' === $col )
return get_the_author_meta( 'course_section', $uid );
}
add_filter( 'manage_users_custom_column', 'manage_users_course_section' );
Isso adiciona um menu suspenso e um Filter
botão acima da tabela Usuários:
function add_course_section_filter() {
echo '<select name="course_section" style="float:none;">';
echo '<option value="">Course Section...</option>';
for ( $i = 1; $i <= 3; ++$i ) {
if ( $i == $_GET[ 'course_section' ] ) {
echo '<option value="'.$i.'" selected="selected">Section '.$i.'</option>';
} else {
echo '<option value="'.$i.'">Section '.$i.'</option>';
}
}
echo '<input id="post-query-submit" type="submit" class="button" value="Filter" name="">';
}
add_action( 'restrict_manage_users', 'add_course_section_filter' );
Esta função altera a consulta do usuário para adicionar meu meta_query
:
function filter_users_by_course_section( $query ) {
global $pagenow;
if ( is_admin() &&
'users.php' == $pagenow &&
isset( $_GET[ 'course_section' ] ) &&
!empty( $_GET[ 'course_section' ] )
) {
$section = $_GET[ 'course_section' ];
$meta_query = array(
array(
'key' => 'course_section',
'value' => $section
)
);
$query->set( 'meta_key', 'course_section' );
$query->set( 'meta_query', $meta_query );
}
}
add_filter( 'pre_get_users', 'filter_users_by_course_section' );
Outra informação
Ele cria meu menu suspenso corretamente. Quando seleciono uma seção do curso e clico Filter
na página, ela é atualizada e course_section
aparece na URL, mas ela não possui nenhum valor associado. Se eu verificar as solicitações HTTP, isso mostra que ele é enviado com o valor de variável correto, mas há um 302 Redirect
que parece remover o valor que eu selecionei.
Se eu enviar a course_section
variável digitando-a diretamente na URL, o filtro funcionará conforme o esperado.
Meu código é basicamente baseado neste código de Dave Court .
Também tentei colocar minha consulta var na lista de permissões usando esse código, mas sem sorte:
function add_course_section_query_var( $qvars ) {
$qvars[] = 'course_section';
return $qvars;
}
add_filter( 'query_vars', 'add_course_section_query_var' );
Estou usando o WP 4.4. Alguma idéia de por que meu filtro não está funcionando?
Respostas:
ATUALIZAÇÃO 28/06/2018
Enquanto o código abaixo funciona principalmente bem, aqui está uma reescrita do código para WP> = 4.6.0 (usando o PHP 7):
Incorporei várias idéias de @birgire e @cale_b, que também oferecem soluções abaixo que valem a pena ser lidas. Especificamente, eu:
$which
variável que foi adicionada emv4.6.0
__( 'Filter' )
array_map()
,array_filter()
Erange()
sprintf()
para gerar os modelos de marcaçãoarray()
Por fim, descobri um bug em minhas soluções anteriores. Essas soluções sempre favorecem o TOP
<select>
sobre o BOTTOM<select>
. Portanto, se você selecionou uma opção de filtro na lista suspensa superior e, em seguida, selecionou uma na lista suspensa inferior, o filtro ainda usará apenas o valor que estiver acima (se não estiver em branco). Esta nova versão corrige esse bug.ATUALIZAÇÃO 14-02-2018
Esse problema foi corrigido desde o WP 4.6.0 e as alterações estão documentadas nos documentos oficiais . A solução abaixo ainda funciona, no entanto.
O que causou o problema (WP <4.6.0)
O problema era que a
restrict_manage_users
ação era chamada duas vezes: uma vez ACIMA da tabela Usuários e uma vez ABAIXO. Isso significa que DUASselect
listas suspensas são criadas com o mesmo nome . Quando oFilter
botão é clicado, qualquer valor que esteja no segundoselect
elemento (ou seja, abaixo da tabela) substitui o valor no primeiro, ou seja, acima da tabela.Caso você queira mergulhar na origem do WP, a
restrict_manage_users
ação é acionada de dentroWP_Users_List_Table::extra_tablenav($which)
, que é a função que cria a lista suspensa nativa para alterar a função de um usuário. Essa função tem a ajuda da$which
variável que informa se está criandoselect
o formulário acima ou abaixo do formulário e permite atribuir aos dois menus suspensosname
atributos diferentes . Infelizmente, a$which
variável não é passada para arestrict_manage_users
ação, portanto, precisamos criar outra maneira de diferenciar nossos próprios elementos personalizados.Uma maneira de fazer isso, como sugere @Linnea , seria adicionar um pouco de JavaScript para capturar o
Filter
clique e sincronizar os valores das duas caixas suspensas. Eu escolhi uma solução somente PHP que descreverei agora.Como corrigi-lo
Você pode tirar proveito da capacidade de transformar entradas HTML em matrizes de valores e filtrar a matriz para se livrar de quaisquer valores indefinidos. Aqui está o código:
Bônus: Refator do PHP 7
Como estou entusiasmado com o PHP 7, caso você esteja executando o WP em um servidor PHP 7, aqui está uma versão mais curta e mais sexy usando o operador coalescente nulo
??
:Aproveitar!
fonte
</select>
. Também achei que para fazê-lo funcionar, tive que colocar<form method="get">
antes do menu de seleção e</form>
depois do botão de filtro.</select>
tags ausentes ! Eu os adicionei. Estranho que você precisava envolvê-lo em uma<form>
vez que esta página inteira está envolvida em uma grande forma e esse código é injetado no meio dela. Ainda bem que você conseguiu. :)No núcleo, os nomes de entrada inferiores são marcados com o número da instância, por exemplo,
new_role
(superior) enew_role2
(inferior). Aqui estão duas abordagens para uma convenção de nomenclatura semelhante, a sabercourse_section1
(em cima) ecourse_section2
(em baixo):Abordagem # 1
Como a
$which
variável ( superior , inferior ) não é passada para orestrict_manage_users
gancho, podemos contornar isso criando nossa própria versão desse gancho:Vamos criar o gancho de ação
wpse_restrict_manage_users
que tem acesso a uma$which
variável:Então podemos conectá-lo com:
onde nós temos agora
$name
comocourse_section1
no topo ecourse_section2
na parte inferior .Abordagem # 2
Vamos nos conectar
restrict_manage_users
, para exibir listas suspensas, com um nome diferente para cada instância:onde usamos a função principal
selected()
e a função auxiliar:Também poderíamos usar isso quando verificamos a seção de curso selecionada no
pre_get_users
retorno de chamada da ação.fonte
static
palavra-chave dessa maneira (apenas dentro das classes). Torna-$instance
se uma variável global quando você faz isso? Você precisa se preocupar com colisões de nomes de variáveis? Também gosto da técnica de criar uma nova ação que se baseia em uma já existente. Obrigado!Testei seu código no Wordpress 4.4 e no Wordpress 4.3.1. Com a versão 4.4, encontro exatamente o mesmo problema que você. No entanto, seu código funciona corretamente na versão 4.3.1!
Eu acho que isso é um bug do Wordpress. Não sei se já foi relatado. Acho que a razão por trás do bug pode ser que o botão enviar está enviando os vars de consulta duas vezes. Se você observar os vars de consulta, verá que course_section é listado duas vezes, uma com o valor correto e uma vez vazio.
Edit: Esta é a solução JavaScript
Simplesmente adicione isso ao arquivo functions.php do seu tema e altere NAME_OF_YOUR_INPUT_FIELD para o nome do seu campo de entrada! Como o WordPress carrega automaticamente o jQuery no lado do administrador, você não precisa enfileirar nenhum script. Esse trecho de código simplesmente adiciona um ouvinte de alterações às entradas suspensas e atualiza automaticamente a outra lista suspensa para corresponder ao mesmo valor. Mais explicações aqui.
Espero que isto ajude!
fonte
Filter
nele, envia o valor correto, mas depois o redireciona novamente para a página, desta vez retirando o valor. Meu palpite é que é algum tipo de "recurso" de segurança para impedir que valores aleatórios, potencialmente maliciosos, sejam enviados, mas não sei como solucionar isso. Suspiro.name
atributo. Se eu usar a lista suspensa ABAIXO da tabela para fazer a filtragem, ela funcionará conforme o esperado. Como esse campo vem após o acima, seu valor nulo substitui o anterior. Hmmm ....Esta é uma solução Javascript diferente que pode ser útil para algumas pessoas. No meu caso, simplesmente removi a segunda lista de seleção (abaixo) por completo. Acho que nunca uso as entradas inferiores ...
fonte
Solução sem JavaScript
Dê ao select um nome que seja "estilo de matriz", assim:
Em seguida, os dois parâmetros são passados (da parte superior e inferior da tabela) e agora em um formato de matriz conhecido.
Então, o valor pode ser usado assim na
pre_get_users
função:fonte
outra solução
você pode colocar sua caixa de seleção de filtro em um arquivo separado, como
user_list_filter.php
e use
require_once 'user_list_filter.php'
em sua função de retorno de chamada de açãouser_list_filter.php
Arquivo:e em sua ação de retorno:
fonte