WP scheint den Wert meiner Abfragevariablen zu entfernen, bevor er zum Filtern der Benutzerliste verwendet wird.
Diese Funktion fügt meiner Users-Tabelle in /wp-admin/users.php
eine benutzerdefinierte Spalte hinzu:
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' );
Diese Funktion teilt WP mit, wie die Werte in der Spalte gefüllt werden sollen:
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' );
Dies fügt ein Dropdown-Menü und die Schaltfläche Filter
über der Tabelle Users hinzu:
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' );
Diese Funktion ändert die Benutzerabfrage, um meinen meta_query
hinzuzufügen:
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' );
Es erstellt meine Dropdown richtig. Wenn ich einen Kursabschnitt auswähle und auf Filter
klicke, wird die Seite aktualisiert und course_section
wird in der URL angezeigt, aber es ist kein Wert zugeordnet. Wenn ich die HTTP-Anforderungen überprüfe, wird angezeigt, dass sie mit dem korrekten Variablenwert gesendet wurden, aber dann gibt es einen 302 Redirect
, der den von mir ausgewählten Wert zu entfernen scheint.
Wenn ich die Variable course_section
durch direkte Eingabe in die URL übermittle, funktioniert der Filter wie erwartet.
Mein Code basiert ungefähr auf diesem Code von Dave Court .
Ich habe auch versucht, meine Abfragevariable mit diesem Code auf die Positivliste zu setzen, aber ohne Erfolg:
function add_course_section_query_var( $qvars ) {
$qvars[] = 'course_section';
return $qvars;
}
add_filter( 'query_vars', 'add_course_section_query_var' );
Ich verwende WP 4.4. Irgendwelche Ideen, warum mein Filter nicht funktioniert?
Während der folgende Code meistens gut funktioniert, ist hier eine Umschreibung des Codes für WP> = 4.6.0 (unter Verwendung von PHP 7):
function add_course_section_filter( $which ) {
// create sprintf templates for <select> and <option>s
$st = '<select name="course_section_%s" style="float:none;"><option value="">%s</option>%s</select>';
$ot = '<option value="%s" %s>Section %s</option>';
// determine which filter button was clicked, if any and set section
$button = key( array_filter( $_GET, function($v) { return __( 'Filter' ) === $v; } ) );
$section = $_GET[ 'course_section_' . $button ] ?? -1;
// generate <option> and <select> code
$options = implode( '', array_map( function($i) use ( $ot, $section ) {
return sprintf( $ot, $i, selected( $i, $section, false ), $i );
}, range( 1, 3 ) ));
$select = sprintf( $st, $which, __( 'Course Section...' ), $options );
// output <select> and submit button
echo $select;
submit_button(__( 'Filter' ), null, $which, false);
}
add_action('restrict_manage_users', 'add_course_section_filter');
function filter_users_by_course_section($query)
{
global $pagenow;
if (is_admin() && 'users.php' == $pagenow) {
$button = key( array_filter( $_GET, function($v) { return __( 'Filter' ) === $v; } ) );
if ($section = $_GET[ 'course_section_' . $button ]) {
$meta_query = [['key' => 'courses','value' => $section, 'compare' => 'LIKE']];
$query->set('meta_key', 'courses');
$query->set('meta_query', $meta_query);
}
}
}
add_filter('pre_get_users', 'filter_users_by_course_section');
Ich habe einige Ideen von @birgire und @cale_b aufgenommen, die auch Lösungen anbieten, die es wert sind, gelesen zu werden. Insbesondere ich:
$which
, die in v4.6.0
hinzugefügt wurde__( 'Filter' )
array_map()
, array_filter()
und range()
sprintf()
zum Generieren der Markup-Vorlagen verwendetarray()
Zuletzt entdeckte ich einen Fehler in meinen früheren Lösungen. Diese Lösungen bevorzugen immer den TOP <select>
gegenüber dem BOTTOM <select>
. Wenn Sie also eine Filteroption aus der oberen Dropdown-Liste ausgewählt und anschließend eine aus der unteren Dropdown-Liste ausgewählt haben, verwendet der Filter immer noch nur den Wert, der oben oben angegeben wurde (sofern er nicht leer ist). Diese neue Version behebt diesen Fehler.
Dieses Problem wurde behoben seit WP 4.6.0 und die Änderungen sind in den offiziellen Dokumenten dokumentiert . Die unten stehende Lösung funktioniert jedoch immer noch.
Das Problem bestand darin, dass die Aktion restrict_manage_users
zweimal aufgerufen wurde: einmal ÜBER der Tabelle Users und einmal UNTER dieser. Dies bedeutet, dass ZWEI select
Dropdowns mit dem gleichen Namen erstellt werden. Wenn auf die Schaltfläche Filter
geklickt wird, überschreibt der Wert im zweiten Element select
(d. H. Unter der Tabelle) den Wert im ersten Element, d. H. Den Wert über der Tabelle.
Wenn Sie in die Quelle WP eintauchen möchten, wird die Aktion restrict_manage_users
innerhalb von WP_Users_List_Table::extra_tablenav($which)
ausgelöst. Diese Funktion erstellt das systemeigene Dropdown-Menü, um die Rolle eines Benutzers zu ändern. Diese Funktion verfügt über die $which
-Variable, die angibt, ob der select
über oder unter dem Formular erstellt wird, und die es ermöglicht, den beiden Dropdowns unterschiedliche name
-Attribute zuzuweisen. Leider wird die Variable $which
nicht an die Aktion restrict_manage_users
übergeben, daher müssen wir uns eine andere Methode ausdenken, um unsere eigenen benutzerdefinierten Elemente zu unterscheiden.
Eine Möglichkeit, dies zu tun, besteht, wie @Linnea oben vorschlägt, darin, JavaScript hinzuzufügen, um den Klick Filter
abzufangen und die Werte der beiden Dropdowns zu synchronisieren. Ich entschied mich für eine reine PHP-Lösung, die ich jetzt beschreiben werde.
Sie können die Möglichkeit nutzen, HTML-Eingaben in Felder mit Werten umzuwandeln und das Feld dann zu filtern, um nicht definierte Werte zu entfernen. Hier ist der Code:
function add_course_section_filter() {
if ( isset( $_GET[ 'course_section' ]) ) {
$section = $_GET[ 'course_section' ];
$section = !empty( $section[ 0 ] ) ? $section[ 0 ] : $section[ 1 ];
} else {
$section = -1;
}
echo ' <select name="course_section[]" style="float:none;"><option value="">Course Section...</option>';
for ( $i = 1; $i <= 3; ++$i ) {
$selected = $i == $section ? ' selected="selected"' : '';
echo '<option value="' . $i . '"' . $selected . '>Section ' . $i . '</option>';
}
echo '<input type="submit" class="button" value="Filter">';
}
add_action( 'restrict_manage_users', 'add_course_section_filter' );
function filter_users_by_course_section( $query ) {
global $pagenow;
if ( is_admin() &&
'users.php' == $pagenow &&
isset( $_GET[ 'course_section' ] ) &&
is_array( $_GET[ 'course_section' ] )
) {
$section = $_GET[ 'course_section' ];
$section = !empty( $section[ 0 ] ) ? $section[ 0 ] : $section[ 1 ];
$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' );
Da ich von PHP 7 begeistert bin, ist hier für den Fall, dass Sie WP auf einem PHP 7-Server ausführen, eine kürzere, aufreizendere Version mit der Option null Vereinigungsoperator ??
:
function add_course_section_filter() {
$section = $_GET[ 'course_section' ][ 0 ] ?? $_GET[ 'course_section' ][ 1 ] ?? -1;
echo ' <select name="course_section[]" style="float:none;"><option value="">Course Section...</option>';
for ( $i = 1; $i <= 3; ++$i ) {
$selected = $i == $section ? ' selected="selected"' : '';
echo '<option value="' . $i . '"' . $selected . '>Section ' . $i . '</option>';
}
echo '<input type="submit" class="button" value="Filter">';
}
add_action( 'restrict_manage_users', 'add_course_section_filter' );
function filter_users_by_course_section( $query ) {
global $pagenow;
if ( is_admin() && 'users.php' == $pagenow) {
$section = $_GET[ 'course_section' ][ 0 ] ?? $_GET[ 'course_section' ][ 1 ] ?? null;
if ( null !== $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' );
Genießen!
Ich habe Ihren Code sowohl in Wordpress 4.4 als auch in Wordpress 4.3.1 getestet. Mit Version 4.4 stoße ich genau auf dasselbe Problem wie Sie. Ihr Code funktioniert jedoch in Version 4.3.1 korrekt!
Ich denke, das ist ein Wordpress-Bug. Ich weiß nicht, ob es schon gemeldet wurde. Ich denke, der Grund für den Fehler könnte sein, dass die Senden-Schaltfläche die Abfrage-Variablen zweimal sendet. Wenn Sie sich die Abfragevariablen ansehen, werden Sie feststellen, dass course_section zweimal aufgeführt wird, einmal mit dem richtigen Wert und einmal leer.
Fügen Sie dies einfach zur Datei functions.php Ihres Themas hinzu und ändern Sie NAME_OF_YOUR_INPUT_FIELD in den Namen Ihres Eingabefelds! Da WordPress jQuery automatisch auf der Administratorseite lädt, müssen Sie keine Skripte in die Warteschlange stellen. Dieser Codeausschnitt fügt den Dropdown-Eingaben einfach einen Änderungslistener hinzu und aktualisiert dann die andere Dropdown-Liste automatisch so, dass sie mit demselben Wert übereinstimmt. Mehr Erklärung hier.
add_action( 'in_admin_footer', function() {
?>
<script type="text/javascript">
var el = jQuery("[name='NAME_OF_YOUR_INPUT_FIELD']");
el.change(function() {
el.val(jQuery(this).val());
});
</script>
<?php
} );
Hoffe das hilft!
Im Kern sind die bottom eingegebenen Namen mit der Instanznummer gekennzeichnet, z. new_role
(oben) und new_role2
(unten). Hier sind zwei Ansätze für eine ähnliche Namenskonvention, nämlich course_section1
(oben) und course_section2
(unten):
Da die Variable $which
( top , bottom ) nicht an den Hook restrict_manage_users
übergeben wird, können wir dies umgehen, indem wir eine eigene Version dieses Hooks erstellen:
Erstellen wir den Aktions-Hook wpse_restrict_manage_users
, der Zugriff auf eine $which
-Variable hat:
add_action( 'restrict_manage_users', function()
{
static $instance = 0;
do_action( 'wpse_restrict_manage_users', 1 === ++$instance ? 'top' : 'bottom' );
} );
Dann können wir es haken mit:
add_action( 'wpse_restrict_manage_users', function( $which )
{
$name = 'top' === $which ? 'course_section1' : 'course_section2';
// your stuff here
} );
wo wir jetzt $name
als course_section1
am top und course_section2
am bottom haben.
Lassen Sie uns restrict_manage_users
aufrufen, um Dropdowns mit einem anderen Namen für jede Instanz anzuzeigen:
function add_course_section_filter()
{
static $instance= 0;
// Dropdown options
$options = '';
foreach( range( 1, 3 ) as $rng )
{
$options = sprintf(
'<option value="%1$d" %2$s>Section %1$d</option>',
$rng,
selected( $rng, get_selected_course_section(), 0 )
);
}
// Display dropdown with a different name for each instance
printf(
'<select name="%s" style="float:none;"><option value="0">%s</option>%s</select>',
'course_section' . ++$instance,
__( 'Course Section...' ),
$options
);
// Button
printf (
'<input id="post-query-submit" type="submit" class="button" value="%s" name="">',
__( 'Filter' )
);
}
add_action( 'restrict_manage_users', 'add_course_section_filter' );
wo wir die Kernfunktion selected()
und die Hilfsfunktion benutzt haben:
/**
* Get the selected course section
* @return int $course_section
*/
function get_selected_course_section()
{
foreach( range( 1, 2) as $rng )
$course_section = ! empty( $_GET[ 'course_section' . $rng ] )
? $_GET[ 'course_section' . $rng ]
: -1; // default
return (int) $course_section;
}
Dies können wir auch verwenden, wenn wir im Aktionsrückruf pre_get_users
nach dem ausgewählten Kursabschnitt suchen.
Dies ist eine andere Javascript-Lösung, die für einige Leute hilfreich sein kann. In meinem Fall habe ich einfach die 2. (untere) Auswahlliste komplett entfernt. Ich finde, dass ich die unteren Eingänge sowieso nie benutze ...
add_action( 'in_admin_footer', function() {
?>
<script type="text/javascript">
jQuery(".tablenav.bottom select[name='course_section']").remove();
jQuery(".tablenav.bottom input#post-query-submit").remove();
</script>
<?php
} );
Geben Sie dem select einen Namen, der "array-style" ist, wie folgt:
echo '<select name="course_section[]" style="float:none;">';
Dann werden BEIDE Parameter übergeben (von oben und unten in der Tabelle) und jetzt in einem bekannten Array-Format.
Dann kann der Wert wie folgt in der Funktion pre_get_users
verwendet werden:
function filter_users_by_course_section( $query ) {
global $pagenow;
// if not on users page in admin, get out
if ( ! is_admin() || 'users.php' != $pagenow ) {
return;
}
// if no section selected, get out
if ( empty( $_GET['course_section'] ) ) {
return;
}
// course_section is known to be set now, so load it
$section = $_GET['course_section'];
// the value is an array, and one of the two select boxes was likely
// not set to anything, so use array_filter to eliminate empty elements
$section = array_filter( $section );
// the value is still an array, so get the first value
$section = reset( $section );
// now the value is a single value, such as 1
$meta_query = array(
array(
'key' => 'course_section',
'value' => $section
)
);
$query->set( 'meta_key', 'course_section' );
$query->set( 'meta_query', $meta_query );
}
sie können Ihr Filterauswahlfeld in eine separate Datei wie user_list_filter.php
einfügen.
und benutze require_once 'user_list_filter.php'
in deiner Action Callback Funktion
user_list_filter.php
Datei:
<select name="course_section" style="float:none;">
<option value="">Course Section...</option>
<?php for ( $i = 1; $i <= 3; ++$i ) {
if ( $i == $_GET[ 'course_section' ] ) { ?>
<option value="<?=$i?>" selected="selected">Section <?=$i?></option>
<?php } else { ?>
<option value="<?=$i?>">Section <?=$i?></option>
<?php }
}?>
</select>
<input id="post-query-submit" type="submit" class="button" value="Filter" name="">
und in Ihrer Aktion Rückruf:
function add_course_section_filter() {
require_once 'user_list_filter.php';
}