Filtrar por campo personalizado en tipo de entrada personalizada en página de administración
He usado Advanced Custom Fields para crear campos personalizados para nombre de Competición, respuestas, etc. He creado un tipo de entrada personalizada para competiciones como se muestra en la imagen y utilicé functions.php de WordPress para crear las columnas con los valores de mis campos personalizados.
Estoy tratando de obtener un cuadro desplegable "Filtrar por" con los diferentes nombres/etiquetas de las competiciones como se muestra abajo, pero solo encuentro soluciones usando taxonomías, las cuales prefiero no usar si es posible porque he usado campos personalizados para todo lo demás.
¿Es posible crear un desplegable "Filtrar por" personalizado usando solo campos personalizados?
Y para mostrar el resultado del Filtro, prueba este código
add_filter( 'parse_query', 'prefix_parse_filter' );
function prefix_parse_filter($query) {
global $pagenow;
$current_page = isset( $_GET['post_type'] ) ? $_GET['post_type'] : '';
if ( is_admin() &&
'competition' == $current_page &&
'edit.php' == $pagenow &&
isset( $_GET['competition-name'] ) &&
$_GET['competition-name'] != '' ) {
$competition_name = $_GET['competition-name'];
$query->query_vars['meta_key'] = 'competition_name';
$query->query_vars['meta_value'] = $competition_name;
$query->query_vars['meta_compare'] = '=';
}
}
Cambia la meta clave y el meta valor según sea necesario. He tomado "competition_name" como meta_key y "competition-name" como nombre del menú desplegable.

La acción restrict_manage_posts activa la función add_extra_tablenav()
, que es como agregas menús desplegables adicionales a tu List Table deseada.
En el ejemplo a continuación, primero nos aseguramos de que el Tipo de Entrada sea el correcto, y luego obtenemos todos los valores de la base de datos almacenados con la clave competition_name
en la tabla postmeta
(debes cambiar el nombre de la clave según sea necesario). La consulta es bastante básica y solo verifica si la Competencia está publicada, toma solo valores únicos (no quieres duplicados en el menú desplegable) y luego los ordena alfabéticamente.
Luego verificamos si hay resultados (no tiene sentido mostrar el menú desplegable si no hay nada), y construimos las opciones (incluyendo una opción predeterminada para mostrar todo). Finalmente, mostramos el menú desplegable.
Como mencioné en mi comentario, esto no es todo; necesitarás algo de lógica para decirle al List Table que solo muestre los resultados deseados cuando el filtro esté activo, pero te dejaré investigar eso y luego puedes hacer otra pregunta si necesitas más ayuda. Pista - revisa el archivo /wp-admin/includes/class-wp-posts-list-table.php
, y su padre .../wp-class-list-table.php
/**
* Agrega menús desplegables adicionales a las List Tables
*
* @param required string $post_type El Tipo de Entrada que se está mostrando
*/
add_action('restrict_manage_posts', 'add_extra_tablenav');
function add_extra_tablenav($post_type){
global $wpdb;
/** Asegurar que este es el Tipo de Entrada correcto */
if($post_type !== 'competition')
return;
/** Obtener los resultados de la base de datos */
$query = $wpdb->prepare('
SELECT DISTINCT pm.meta_valor FROM %1$s pm
LEFT JOIN %2$s p ON p.ID = pm.post_id
WHERE pm.meta_clave = "%3$s"
AND p.post_status = "%4$s"
AND p.post_type = "%5$s"
ORDER BY "%6$s"',
$wpdb->postmeta,
$wpdb->posts,
'competition_name', // Tu meta clave - cambia según sea necesario
'publish', // Estado de la entrada - cambia según sea necesario
$post_type,
'competition_name'
);
$resultados = $wpdb->get_col($query);
/** Asegurarse de que hay opciones para mostrar */
if(empty($resultados))
return;
// obtener la opción seleccionada si hay una seleccionada
if (isset( $_GET['competition-name'] ) && $_GET['competition-name'] != '') {
$nombreSeleccionado = $_GET['competition-name'];
} else {
$nombreSeleccionado = -1;
}
/** Obtener todas las opciones que deberían mostrarse */
$opciones[] = sprintf('<option value="-1">%1$s</option>', __('Todas las Competencias', 'tu-dominio-de-texto'));
foreach($resultados as $resultado) :
if ($resultado == $nombreSeleccionado) {
$opciones[] = sprintf('<option value="%1$s" selected>%2$s</option>', esc_attr($resultado), $resultado);
} else {
$opciones[] = sprintf('<option value="%1$s">%2$s</option>', esc_attr($resultado), $resultado);
}
endforeach;
/** Mostrar el menú desplegable */
echo '<select class="" id="competition-name" name="competition-name">';
echo join("\n", $opciones);
echo '</select>';
}

Al usar esto, obtengo el error Notice: wpdb::prepare fue llamado incorrectamente. La consulta no contiene el número correcto de marcadores de posición (6) para la cantidad de argumentos pasados (5). Por favor, consulta Depuración en WordPress para más información. (Este mensaje fue agregado en la versión 4.8.3.) en /[...]/wp-includes/functions.php en la línea 4773

Si esto no funciona para alguien, mi solución fue necesitar agregar la columna que estaba intentando filtrar a la lista de columnas ordenables para mi tipo de publicación personalizada.
// Hacer que las columnas personalizadas del Tipo de Publicación Personalizada sean ordenables
function cpt_custom_columns_sortable( $columns ) {
// Añadir nuestras columnas al array $columns
$columns['item_number'] = 'item_number';
$columns['coat_school'] = 'coat_school';
return $columns;
} add_filter( 'manage_edit-your-custom-post-type-slug_sortable_columns', 'cpt_custom_columns_sortable' );

Reemplaza la consulta a continuación para corregir el error wpdb:prepare:
$query = $wpdb->prepare('
SELECT DISTINCT pm.meta_value FROM %1$s pm
LEFT JOIN %2$s p ON p.ID = pm.post_id
WHERE pm.meta_key = "%3$s"
AND p.post_status = "%4$s"
AND p.post_type = "%5$s"
ORDER BY "%3$s"',
$wpdb->postmeta,
$wpdb->posts,
'competition_name', // Tu clave meta - cambia según sea necesario
'publish', // Estado del post - cambia según sea necesario
$post_type,
'competition_name' //esto se necesita una segunda vez para definir "%3$s" en ORDER BY
);

Me encontré con el mismo problema al intentar filtrar un tipo de entrada personalizado (custom-post-type) con un campo personalizado (custom-field)
pero resolví este problema siguiendo estos pasos.
Convertí el nombre del campo personalizado de writer
a _writer
y luego actualicé el siguiente código dentro de la función de callback
del hook parse_query
para poder agregar la meta_query del campo personalizado así:
$query->set( 'meta_query', array(
array(
'key' => '_writer',
'compare' => '=',
'value' => $_GET['_writer'],
'type' => 'numeric',
)
) );
Esta solución anterior funcionó para mí.
Documentación https://developer.wordpress.org/reference/hooks/pre_get_posts/
Enlaces útiles https://developer.wordpress.org/reference/hooks/pre_get_posts/#comment-2571
https://stackoverflow.com/questions/47869905/how-can-i-filter-records-in-custom-post-type-list-in-admin-based-on-user-id-that
