ACTUALIZACIÓN 2018-06-28
Si bien el siguiente código funciona bien, aquí hay una reescritura del código para WP> = 4.6.0 (usando 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');
Incorporé varias ideas de @birgire y @cale_b que también ofrecen soluciones a continuación que vale la pena leer. Específicamente, yo:
- Usó la
$which
variable que se agregó env4.6.0
- Se utilizan las mejores prácticas para i18n mediante el uso de cadenas traducibles, p. Ej.
__( 'Filter' )
- Bucles intercambiado por el (más de moda?)
array_map()
, array_filter()
Yrange()
- Se usa
sprintf()
para generar las plantillas de marcado
- Se utilizó la notación de matriz de corchetes en lugar de
array()
Por último, descubrí un error en mis soluciones anteriores. Esas soluciones siempre favorecen lo SUPERIOR <select>
sobre lo INFERIOR <select>
. Entonces, si seleccionó una opción de filtro en el menú desplegable superior y luego selecciona una del menú desplegable inferior, el filtro solo usará el valor que esté arriba (si no está en blanco). Esta nueva versión corrige ese error.
ACTUALIZACIÓN 2018-02-14
Este problema ha sido parcheado desde WP 4.6.0 y los cambios están documentados en los documentos oficiales . Sin embargo, la solución a continuación todavía funciona.
Qué causó el problema (WP <4.6.0)
El problema era que la restrict_manage_users
acción se llamaba dos veces: una vez POR ENCIMA de la tabla Usuarios, y una vez POR DEBAJO. Esto significa que select
se crean DOS menús desplegables con el mismo nombre . Cuando Filter
se hace clic en el botón, cualquier valor que esté en el segundo select
elemento (es decir, el DEBAJO de la tabla) anula el valor en el primero, es decir, el que está SOBRE LA tabla.
En caso de que desee sumergirse en la fuente WP, la restrict_manage_users
acción se activa desde dentro WP_Users_List_Table::extra_tablenav($which)
, que es la función que crea el menú desplegable nativo para cambiar la función de un usuario. Esa función tiene la ayuda de la $which
variable que le dice si está creando select
el formulario anterior o inferior, y le permite otorgar a los dos menús desplegables name
atributos diferentes . Desafortunadamente, la $which
variable no se pasa a la restrict_manage_users
acción, por lo que tenemos que encontrar otra forma de diferenciar nuestros propios elementos personalizados.
Una forma de hacerlo, como sugiere @Linnea , sería agregar algo de JavaScript para captar el Filter
clic y sincronizar los valores de los dos menús desplegables. Elegí una solución solo para PHP que describiré ahora.
Como arreglarlo
Puede aprovechar la capacidad de convertir las entradas HTML en matrices de valores y luego filtrar la matriz para deshacerse de los valores indefinidos. Aquí está el código:
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 '</select>';
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' );
Bonus: PHP 7 Refactor
Como estoy entusiasmado con PHP 7, en caso de que esté ejecutando WP en un servidor PHP 7, aquí hay una versión más corta y más sexy que utiliza el operador de fusión nula??
:
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 '</select>';
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' );
¡Disfrutar!