¿Puedo excluir una entrada por meta key usando la función pre_get_posts?

10 nov 2012, 01:55:57
Vistas: 36.3K
Votos: 33

Veo que mucha gente prefiere usar el hook pre_get_posts en lugar de query_posts. El código siguiente funciona y muestra todas las entradas que tienen la meta key "featured"

function show_featured_posts ( $query ) {
    if ( $query->is_main_query() ) {
       $query->set( 'meta_key', 'featured' );
       $query->set( 'meta_value', 'yes' );
    }
}

add_action( 'pre_get_posts', 'show_featured_posts' );

Pero quiero que las entradas que tienen la meta_key 'featured' sean excluidas de la consulta principal. ¿Hay alguna manera fácil de hacer esto?

0
Todas las respuestas a la pregunta 3
4
46

Veo que muchas personas prefieren usar el hook pre_get_posts en lugar de query_posts

¡Sí!

El pre_get_posts filtra un objeto WP_Query, lo que significa que cualquier cosa que puedas hacer con query_posts() puedes hacerlo mediante $query->set() y $query->get(). En particular podemos hacer uso del atributo meta_query (ver Codex):

$meta_query = array(
                 array(
                    'key'=>'featured',
                    'value'=>'yes',
                    'compare'=>'!=',
                 ),
);
$query->set('meta_query',$meta_query);

Pero... esto reemplaza la 'meta query' original (si tenía una). Así que a menos que quieras reemplazar completamente la meta query original, sugiero:

//Obtener la meta query original
$meta_query = $query->get('meta_query');

//Añadir nuestra meta query a las meta queries existentes
$meta_query[] = array(
                    'key'=>'featured',
                    'value'=>'yes',
                    'compare'=>'!=',
                );
$query->set('meta_query',$meta_query);

De esta manera añadimos nuestra meta query junto con las meta queries existentes.

Puedes o no querer establecer la propiedad relation de $meta_query como AND o OR (para devolver posts que cumplan todas, o al menos una, de las meta queries).

* Nota: Este tipo de consulta devolverá posts con la meta clave 'featured', pero cuyo valor no sea yes. No incluirá posts donde la meta clave 'featured' no exista. Podrás hacer esto en la versión 3.5.

10 nov 2012 12:32:19
Comentarios

¿Entonces no hay manera de verificar si un meta_key para un post existe o no / está vacío o no? Tendré que esperar hasta la 3.5 entonces. Gracias por tu respuesta.

Carlisle Carlisle
10 nov 2012 14:57:03

Simplemente crearé un meta box con opciones y No donde 'No' estará seleccionado por defecto. Cuando quiera destacar un post seleccionaré . Sin embargo, quiero que los últimos 5 posts se mantengan destacados y los demás aparezcan en la consulta principal. No quiero tener que volver y cambiar la selección cada vez, así que debo encontrar una manera de excluir solo los 5 posts más recientes. Veo muchas preguntas similares en stackexchange y debería haber una forma sencilla de manejar esos posts destacados. (una forma que no afecte el rendimiento general, no cree muchas consultas o requiera consultas SQL mixtas)

Carlisle Carlisle
10 nov 2012 15:38:45

Por cierto, no estoy seguro de que sea buena idea crear un meta_key adicional con valor o No para todos los posts. Sería genial poder excluir aquellos posts que simplemente no tengan la clave featured.

Carlisle Carlisle
10 nov 2012 15:44:55

Esta función dejó de funcionar en mi sitio después de actualizar a PHP 7, mostrando un error Uncaught Error: [] operator not supported for strings ya que el meta_query original estaba devolviendo null. Puedes solucionarlo recurriendo a un array vacío si no existe ninguno, reemplazando $meta_query = $query->get('meta_query'); por $meta_query = ( is_array( $query->get('meta_query') ) ) ? $query->get('meta_query') : [];.

Kevin Nugent Kevin Nugent
22 feb 2018 13:59:06
0

Quiero compartir mi solución temporal para publicaciones destacadas por si a alguien le resulta útil. No estoy usando el hook pre_get_posts aquí, pero tampoco estoy usando query_posts. El problema es que tengo que trabajar con la consulta principal y ejecutar una parte de la consulta SQL. Sería genial si algún experto pudiera revisar el código y decirme si está bien y no causará problemas de rendimiento. También sería estupendo si alguien tiene un enfoque mejor y lo comparte con nosotros.

Crear consulta para publicaciones destacadas

<?php 

$featured_query = new WP_query( array(
    'meta_key'       =>'featured', 
    'meta_value'     =>'yes', 
    'posts_per_page' => 5, 
    'no_found_rows'  => true
    )
);

while ($featured_query->have_posts()) : 

    $featured_query->the_post(); 
    //Contenido...

endwhile; 
wp_reset_postdata(); 

?>

Crear la consulta principal, excluyendo las publicaciones que tienen el meta_key 'featured', limitar la exclusión a las 5 publicaciones más recientes y mostrar todas las demás.

<?php 

$excludeposts = $wpdb->get_col( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'featured' AND meta_value != '' ORDER BY post_id DESC LIMIT 0, 5" );

$main_query = new WP_Query( array(
    'post__not_in' => $excludeposts, 
    'paged' => $paged 
    ) 
);  

while ($main_query->have_posts()) : 

    $main_query->the_post();
    //Contenido...

endwhile;

?>
10 nov 2012 18:27:34
0

En respuesta a @Carlisle, si deseas excluir los 5 posts más recientes marcados como destacados, podrías hacer lo siguiente. Cambia posts_per_page por la cantidad que quieras excluir, y meta_query por cómo estás designando la categoría destacada.

function cmp_exclude_featured_posts($query) {
    $exclude = array();  //Crea un array vacío para los IDs de posts a excluir
    if ( $query->is_main_query() ) {
            $featured = get_posts(array(
                'post_type' => 'post',
                'meta_query' => array(
                    array(
                        'key' => 'featured',
                        'value' => '1',
                        'compare' => '==',
                    ),
                ),
                'posts_per_page' => 2
            ));

            foreach($featured as $hide) {
                $exclude[] = $hide->ID;
            }   

            $query->set('post__not_in', $exclude);
        }
}

add_filter( 'pre_get_posts', 'cmp_exclude_featured_posts' );
29 abr 2015 21:21:09