Soporte » Diseño – Temas y plantillas » Problema con filtros customizados para custom post type

  • Resuelto Enery88

    (@enery88)


    Mi problema es que he creado un custom post y le he agregado dos campos nuevos(año, mes) y un filtro para cada uno de esos campos. La cosa es que si filtro por uno (año o mes)y le doy al botón filtrar me filtra bien y si luego añado el segundo filtro y le doy a filtrar, pasa de mi. Y si pongo los dos filtros desde el principio y le doy a filtrar tampoco me funciona.

    ¿Alguien podría orientarme un poco? Gracias por vuestra ayuda!! 🙂

    Este es el código de uno de los filtros, no pongo los dos porque son iguales a excepción del name del select.

    //crea el filtro select encima de la tabla
    function year_admin_posts_filter_restrict_manage_posts(){
        global $wpdb;
        $type = 'post';
    
      if(isset($_GET['post_type'])) {
          $type = $_GET['post_type'];
      }
    
      if( $type == 'custom-post' ){
            $values = $wpdb->get_results( "SELECT DISTINCT meta_value FROM ".$wpdb->prefix."postmeta WHERE meta_key = '_year_field'");
        ?>
        <select name="admin_filter_year">
                <option value=""><?php _e('Filter by: Year', 'mgm'); ?></option>
            <?php $current_v = isset($_GET['admin_filter_year'])? $_GET['admin_filter_year']:'';
                    foreach ($values as $value) {
                        $s = ($value->meta_value == $current_v)? 'selected="selected"':'';
                        echo '<option value="'.$value->meta_value.'" '.$s.'>'.$value->meta_value.'</option>';
            }
            ?>
        </select>
    <?php }
    }
    add_action( 'restrict_manage_posts', 'year_admin_posts_filter_restrict_manage_posts' );
    
    //Filtro para mostrar por pantalla el listado resultante de la seleccion de select anterior creada
    function audience_year_posts_filter( $query ){
        global $pagenow;
        $type = 'post';
    
        if(isset($_GET['post_type'])) {
            $type = $_GET['post_type'];
        }
    
        if( $type == 'channel' && is_admin() && $pagenow=='edit.php' && isset($_GET['admin_filter_year']) && $_GET['admin_filter_year'] != '') {
            $query->query_vars['meta_key'] = '_year_field';
            $query->query_vars['meta_value'] = $_GET['admin_filter_year'];
      }
    }
    add_filter( 'parse_query', 'audience_year_posts_filter' );
Viendo 11 respuestas - de la 1 a la 11 (de un total de 11)
  • Hola @enery88 creo que estás pisando un filtro con el otro. Con el código que tienes gestiona ahí las dos condiciones, comprueba los dos parámetros (podrías comprobar con ! empty y así compruebas que esté definido el parámetro $_GET y también que no esté vacío, ni 0, ni null ni false).

    Después de comprobar ambos valores (año y mes), según las condiciones recibidas construyes el query adecuado y te funcionará.

    En resumen, gestiona ambas condiciones en la misma acción y en el mismo filtro.

    Iniciador del debate Enery88

    (@enery88)

    Muchas gracias @carloslongarela, otra pregunta relacionado con esto. Crees que para hacer la consulta podré realizar la sentencia en mysql directamente con la función get_results() ? o debería hacerlo con el objeto WP_Query? con el objeto wp_query me refiero a la estructura de argumentos que se suele pasar a get_posts(), por ejemplo, no al objeto como tal, porque se que no hay otra forma de sacar los datos sino es a través de wp-query objeto.

    Muchas gracias!!

    • Esta respuesta fue modificada hace 5 años, 9 meses por Enery88.

    Hola @enery88 puedes realizar la sentencia perfectamente con get_results() preferiblemente utiliza $wpdb->prepare por ejemplo:

    $values  = $wpdb->get_col( $wpdb->prepare(
    'SELECT DISTINCT meta_value FROM ' . $wpdb->prefix . 'postmeta WHERE meta_key = %s',
     $meta_key_name
    ) );

    En este caso he utilizado get_col() en vez de get_results() ya que sólo estás devolviendo una columna y no un resultset completo (y get_var() si es un solo valor en vez de una columna)

    Iniciador del debate Enery88

    (@enery88)

    Muchísimas gracias @carloslongarela !! 🙂

    De nada @enery88 😉

    Iniciador del debate Enery88

    (@enery88)

    Hola, @carloslongarela, tengo una duda acerca de la sentencia a la base de datos que tengo que hacer en el código que enseño arriba. Debo abrir nuevo debate o en este puedo hacer la consulta?

    Al tratarse de la misma consulta podrías ponerla aquí sin problema.

    Iniciador del debate Enery88

    (@enery88)

    Gracias @carloslongarela.

    Al final he optado por realizar una condicional para hacer una consulta en función de los filtros. Me explico, finalmente he unido los dos selects en la misma función, y las sentencias a la bbdd las he metido juntas en una función así que en vez de tener 4 funciones, ahora tengo dos. Por una parte tengo la función que muestra los selects y por otra parte la que hace las consultas.

    La duda que me surge ahora es la consulta a la bbdd de wp cuando me llegan ambos campos year y month. Resulta que en la bbdd directamente si me funciona pero cuando en wp empleo ambos filter, no le gusta demasiado la consulta.

    function cpt_posts_filters( $query ){
    	global $wpdb;
    	global $pagenow;
    	$type = 'post';
    
    	if(isset($_GET['post_type'])) {
    		$type = $_GET['post_type'];
    	}
    
    	if( $type == 'cpt' && is_admin() && $pagenow=='edit.php'){
    
    		if( (isset($_GET['admin_filter_year']) && $_GET['admin_filter_year'] != '') && (isset($_GET['admin_filter_month']) && $_GET['admin_filter_month'] != '') ){
    			$query->get_result('SELECT * FROM '.$wpdb->prefix.'posts WHERE EXISTS
    			(SELECT meta_key FROM '.$wpdb->prefix.'postmeta WHERE '.$wpdb->prefix.'postmeta.post_id='.$wpdb->prefix.'posts.ID AND meta_value='.$_GET['admin_filter_month'].')
    			AND EXISTS
    			(SELECT meta_key FROM '.$wpdb->prefix.'postmeta WHERE '.$wpdb->prefix.'postmeta.post_id='.$wpdb->prefix.'posts.ID AND meta_value='.$_GET['admin_filter_year'].')');
    		}
    		else if( isset($_GET['admin_filter_year']) && $_GET['admin_filter_year'] != '' ) {
    			$query->query_vars['meta_key'] = '_year_field';
    			$query->query_vars['meta_value'] = $_GET['admin_filter_year'];
    		}
    		else if( isset($_GET['admin_filter_month']) && $_GET['admin_filter_month'] != '' ){
    			$query->query_vars['meta_key'] = '_month_field';
    			$query->query_vars['meta_value'] = $_GET['admin_filter_month'];
    		}
    
    	}
    }
    add_filter( 'parse_query', 'cpt_posts_filters' );

    ¿Por qué puede ser?

    Hola @enery88 en primer lugar deberías reescribir el código para simplificarlo lo máximo posible y hacerlo compatible con los estándares de WordPress, nunca utilices else if sino elseif comprueba el tipo de las variables === en lugar de == para las sentencias de la BD usa prepare, escapa/sanitiza las posibles entradas de usuario, utiliza nonces en los datos enviados…

    La consulta SQL tiene get_result en lugar de get_results, además, ¿no puedes simplificar la consulta SQL en una consulta simple sin subconsultas? ¿no la puedes sustituir por un SELECT con LEFT JOIN a postmeta con WHERE meta_value = %s OR meta_value = %? prueba a simplificar la consulta y después depurar mostrando el SQL resultante.

    Te pongo tu código con el get_results y conforme a los estándares de WP aunque sin verificación de nonce ya que los debes crear antes del envío:

    function cpt_posts_filters( $query ) {
    	global $wpdb;
    	global $pagenow;
    	$type = 'post';
    
    	if ( ! empty( $_GET['post_type'] ) ) {
    		$type = esc_html( $_GET['post_type'] );
    	}
    
    	if ( 'cpt' === $type && is_admin() && 'edit.php' === $pagenow ) {
    		if ( ( ! empty( $_GET['admin_filter_year'] ) ) && ( ! empty( $_GET['admin_filter_month'] ) ) ) {
    			$query->get_results( $wpdb->prepare(
    				'SELECT * FROM ' . $wpdb->prefix . 'posts
    				WHERE EXISTS
    				( SELECT meta_key FROM ' . $wpdb->prefix . 'postmeta
    				WHERE ' . $wpdb->prefix . 'postmeta.post_id = ' . $wpdb->prefix . 'posts.ID
    				AND meta_value = %s )
    				AND EXISTS
    				( SELECT meta_key FROM ' . $wpdb->prefix . 'postmeta
    				WHERE ' . $wpdb->prefix . 'postmeta.post_id = ' . $wpdb->prefix . 'posts.ID
    				AND meta_value = %s )',
    				array(
    					$_GET['admin_filter_month'],
    					$_GET['admin_filter_year'],
    				)
    			) );
    		} elseif ( ! empty ( $_GET['admin_filter_year'] ) ) {
    			$query->query_vars['meta_key']   = '_year_field';
    			$query->query_vars['meta_value'] = esc_html( $_GET['admin_filter_year'] );
    		} elseif ( ! empty ( $_GET['admin_filter_month'] ) ) {
    			$query->query_vars['meta_key']   = '_month_field';
    			$query->query_vars['meta_value'] = esc_html( $_GET['admin_filter_month'] );
    		}
    	}
    }
    add_filter( 'parse_query', 'cpt_posts_filters' );
    Iniciador del debate Enery88

    (@enery88)

    Hola @carloslongarela!!
    Al final estue mirandoloque me has comentado y tratando de hacer una query menos compleja pero me ha sido dificil y aun asi no me he funcionado, apesar de todos los consejos que me has dado. asi que he pensado. ¿Crees que podría recoger los resultados de una consulta y dentro de esa condicional introducir una consulta sobre los resultados de la consulta anterior? No se si me explico bien, me refiero a guardar los resultados de busqueda de por ejemplo el filtro year y dentro de esa condicional preguntar por el otro campo que es month, y realizar una consulta con los datos de month sobre los resultados que nos da la consulta sobre el campo year.

    Iniciador del debate Enery88

    (@enery88)

    Esta es la solución final a la pregunta de la query con dos postmeta en una sola consulta para filtros.

    $query->set( 'orderby', 'date' );
    			$query->set( 'order', 'DESC' );
    			$meta_query[]= array(
    				array(
    					'key'			=> '_year_field',
    					'value'		=> sanitize_text_field( $_GET['admin_filter_year'] ),
    					'compare'	=> '='
    				),
    				array(
    					'key' 		=> '_month_field',
    					'value'		=> sanitize_text_field( $_GET['admin_filter_month'] ),
    					'compare'	=> '='
    				) );
    
    			$query->set( 'meta_query', $meta_query );
Viendo 11 respuestas - de la 1 a la 11 (de un total de 11)
  • El debate ‘Problema con filtros customizados para custom post type’ está cerrado a nuevas respuestas.