Le problème
WP semble supprimer la valeur de ma variable de requête avant de l'utiliser pour filtrer la liste des utilisateurs.
Mon code
Cette fonction ajoute une colonne personnalisée à ma table Utilisateurs sur /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' );
Cette fonction indique à WP comment remplir les valeurs dans la colonne:
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' );
Cela ajoute une liste déroulante et un Filter
bouton au-dessus du tableau des utilisateurs:
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' );
Cette fonction modifie la requête de l'utilisateur pour ajouter mon 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' );
les autres informations
Cela crée ma liste déroulante correctement. Lorsque je sélectionne une section de cours et clique sur Filter
la page, elle s'actualise et course_section
apparaît dans l'URL, mais elle n'a aucune valeur associée. Si je vérifie les requêtes HTTP, cela montre qu'elles sont soumises avec la valeur de variable correcte, mais il y en a une 302 Redirect
qui semble supprimer la valeur que j'ai sélectionnée.
Si je soumets la course_section
variable en la tapant directement dans l'URL, le filtre fonctionne comme prévu.
Mon code est à peu près basé sur ce code de Dave Court .
J'ai également essayé de mettre en liste blanche ma requête var en utilisant ce code, mais sans succès:
function add_course_section_query_var( $qvars ) {
$qvars[] = 'course_section';
return $qvars;
}
add_filter( 'query_vars', 'add_course_section_query_var' );
J'utilise WP 4.4. Des idées pourquoi mon filtre ne fonctionne pas?
Réponses:
MISE À JOUR 2018-06-28
Alors que le code ci-dessous fonctionne généralement bien, voici une réécriture du code pour WP> = 4.6.0 (en utilisant PHP 7):
J'ai incorporé plusieurs idées de @birgire et @cale_b qui propose également des solutions ci-dessous qui valent la peine d'être lues. Plus précisément, je:
$which
variable qui a été ajoutée dansv4.6.0
__( 'Filter' )
array_map()
,array_filter()
Etrange()
sprintf()
pour générer les modèles de balisagearray()
Enfin, j'ai découvert un bug dans mes solutions précédentes. Ces solutions privilégient toujours le TOP par
<select>
rapport au BAS<select>
. Donc, si vous avez sélectionné une option de filtre dans la liste déroulante supérieure, puis que vous en avez sélectionné une dans la liste déroulante inférieure, le filtre n'utilisera toujours que la valeur en haut (si elle n'est pas vide). Cette nouvelle version corrige ce bogue.MISE À JOUR 2018-02-14
Ce problème a été corrigé depuis WP 4.6.0 et les modifications sont documentées dans les documents officiels . Cependant, la solution ci-dessous fonctionne toujours.
Qu'est-ce qui a causé le problème (WP <4.6.0)
Le problème était que l'
restrict_manage_users
action est appelée deux fois: une fois au-dessus de la table des utilisateurs et une fois en dessous. Cela signifie que DEUXselect
listes déroulantes sont créées avec le même nom . Lorsque leFilter
bouton est cliqué, la valeur du deuxièmeselect
élément (c'est-à-dire celui EN-DESSOUS du tableau) remplace la valeur du premier, c'est-à-dire celle AU-DESSUS du tableau.Si vous souhaitez plonger dans la source WP, l'
restrict_manage_users
action est déclenchée de l'intérieurWP_Users_List_Table::extra_tablenav($which)
, qui est la fonction qui crée la liste déroulante native pour modifier le rôle d'un utilisateur. Cette fonction a l'aide de la$which
variable qui lui indique si elle crée leselect
dessus ou le dessous du formulaire, et lui permet de donner aux deux listes déroulantes desname
attributs différents . Malheureusement, la$which
variable n'est pas transmise à l'restrict_manage_users
action, nous devons donc trouver une autre façon de différencier nos propres éléments personnalisés.Une façon de le faire, comme le suggère @Linnea , serait d'ajouter du JavaScript pour capturer le
Filter
clic et synchroniser les valeurs des deux listes déroulantes. J'ai choisi une solution PHP uniquement que je vais décrire maintenant.Comment le réparer
Vous pouvez profiter de la possibilité de transformer les entrées HTML en tableaux de valeurs, puis de filtrer le tableau pour éliminer toutes les valeurs non définies. Voici le code:
Bonus: PHP 7 Refactor
Étant donné que je suis enthousiasmé par PHP 7, au cas où vous exécuteriez WP sur un serveur PHP 7, voici une version plus courte et plus sexy utilisant l' opérateur de coalescence nulle
??
:Prendre plaisir!
la source
</select>
J'ai aussi trouvé pour le faire fonctionner que je devais mettre<form method="get">
avant le menu de sélection et</form>
après le bouton de filtre.</select>
balises manquantes ! Je les ai ajoutés. Étrange que vous deviez l'envelopper dans un<form>
car cette page entière est enveloppée dans un grand formulaire, et ce code est injecté au milieu. Heureux que vous l'ayez fait fonctionner, cependant. :)Dans le noyau, les noms d'entrée inférieurs sont marqués du numéro d'instance, par exemple
new_role
(haut) etnew_role2
(bas). Voici deux approches pour une convention de dénomination similaire, à savoircourse_section1
(en haut) etcourse_section2
(en bas):Approche n ° 1
Puisque la
$which
variable ( haut , bas ) n'est pas transmise aurestrict_manage_users
hook, nous pouvons contourner cela en créant notre propre version de ce hook:Créons le hook d'action
wpse_restrict_manage_users
qui a accès à une$which
variable:Ensuite, nous pouvons l'accrocher avec:
où nous avons maintenant
$name
commecourse_section1
en haut etcourse_section2
en bas .Approche n ° 2
Accrochons-nous
restrict_manage_users
, pour afficher les listes déroulantes, avec un nom différent pour chaque instance:où nous avons utilisé la fonction principale
selected()
et la fonction d'aide:Ensuite, nous pourrions également l'utiliser lorsque nous vérifierons la section de cours sélectionnée dans le
pre_get_users
rappel d'action.la source
static
mot clé de cette façon (uniquement dans les classes). Devient$instance
une variable globale lorsque vous faites cela? Avez-vous à vous soucier des collisions de noms de variables? J'aime aussi la technique de création d'une nouvelle action qui s'appuie sur une action existante. Merci!J'ai testé votre code dans Wordpress 4.4 et dans Wordpress 4.3.1. Avec la version 4.4, je rencontre exactement le même problème que vous. Cependant, votre code fonctionne correctement dans la version 4.3.1!
Je pense que c'est un bug Wordpress. Je ne sais pas si cela a encore été signalé. Je pense que la raison du bug pourrait être que le bouton d'envoi envoie deux fois les variables de requête. Si vous regardez les variables de requête, vous verrez que course_section est répertorié deux fois, une fois avec la valeur correcte et une fois vide.
Edit: Ceci est la solution JavaScript
Ajoutez simplement ceci au fichier functions.php de votre thème et remplacez NAME_OF_YOUR_INPUT_FIELD par le nom de votre champ de saisie! Étant donné que WordPress charge automatiquement jQuery du côté administrateur, vous n'avez pas à mettre en file d'attente les scripts. Cet extrait de code ajoute simplement un écouteur de modification aux entrées de la liste déroulante, puis met automatiquement à jour l'autre liste déroulante pour correspondre à la même valeur. Plus d'explications ici.
J'espère que cela t'aides!
la source
Filter
il soumet la valeur correcte, mais redirige ensuite à nouveau vers la page, cette fois en supprimant la valeur. Je suppose qu'il s'agit d'une sorte de "fonctionnalité" de sécurité pour empêcher la soumission de valeurs aléatoires, potentiellement malveillantes, mais je ne sais pas comment contourner ce problème. Soupir.name
attribut. Si j'utilise la liste déroulante EN DESSOUS du tableau pour effectuer le filtrage, cela fonctionne comme prévu. Étant donné que ce champ vient après celui au-dessus, sa valeur nulle remplace le précédent. Hmmm ....Il s'agit d'une solution Javascript différente qui peut être utile pour certaines personnes. Dans mon cas, j'ai simplement supprimé complètement la 2ème liste de sélection (en bas). Je trouve que je n'utilise jamais les entrées du bas de toute façon ...
la source
Solution non JavaScript
Donnez à la sélection un nom de "style tableau", comme ceci:
Ensuite, les DEUX paramètres sont passés (du haut et du bas de la table), et maintenant dans un format de tableau connu.
Ensuite, la valeur peut être utilisée comme ceci dans la
pre_get_users
fonction:la source
une autre solution
vous pouvez mettre votre boîte de sélection de filtre dans un fichier séparé comme
user_list_filter.php
et utiliser
require_once 'user_list_filter.php'
dans votre fonction de rappel d'actionuser_list_filter.php
fichier:et dans votre rappel d'action:
la source