Usar el filtro 'parse_query' para mostrar publicaciones que cumplan múltiples criterios

26 ene 2015, 03:40:47
Vistas: 14.9K
Votos: 1

Estoy intentando filtrar la página de Publicaciones en el administrador de WordPress para mostrar posts que cumplan el criterio "A" -o- el criterio "B". He revisado la documentación y no encuentro una buena forma de hacer esto.

Detalles: He limitado los roles de usuario para que los autores solo puedan editar sus propias publicaciones. Sin embargo, he añadido un campo personalizado que permite a los autores seleccionar otros autores para permitirles editar el post también. Esta funcionalidad funciona perfectamente si uso uno u otro en mi filtro 'parse_query', pero si intento habilitar ambos, la consulta piensa que quiero mostrar posts que cumplan TODOS los criterios (lo cual no es ninguno).

Como referencia, aquí está mi código (esto está en functions.php):

add_filter('parse_query', 'show_appropriate_posts');
function show_appropriate_posts($query) {
    if ( strpos($_SERVER[ 'REQUEST_URI' ], '/wp-admin/edit.php') !== false ) {
        if ( !current_user_can('manage_options') ) {
            global $current_user;

            //Solo listar posts de este usuario (A).
            $query->set('author', $current_user->id);

            //Listar posts donde este usuario está "etiquetado" (B).
            $query->set('meta_key', 'add_editing_permission_for');
            $query->set('meta_value', $current_user->id);
            $query->set('meta_compare', 'LIKE');

            //@TODO: Necesito mostrar posts que cumplan (A) -o- (B).
        }
    }
}

Nuevamente, tanto (A) como (B) funcionan cuando se ejecutan por separado.

3
Comentarios

Después de investigar más, creo que podría necesitar una consulta SQL personalizada. Si ese es el caso, agradecería cualquier ayuda para integrarla con el filtro mencionado anteriormente.

GreatBlakes GreatBlakes
26 ene 2015 07:38:44

Echa un vistazo a meta_query (para reemplazar meta_key, meta_value y meta_compare), quizás puedas hacer algo con eso.

David Gard David Gard
26 ene 2015 16:53:34

En realidad, ignora mi comentario anterior, no creo que se pueda hacer de esa manera. Espero haberte proporcionado una respuesta igualmente :)

David Gard David Gard
26 ene 2015 17:34:26
Todas las respuestas a la pregunta 1
8

Ignora mi comentario sobre meta_query. No solo no funciona con $query->set(), sino que tampoco podrías controlar el requisito crítico de "A O B" de la consulta.

En cambio, creo que lo que necesitas es posible mediante una combinación del gancho de acción pre_get_posts y el gancho de filtro posts_where como se muestra a continuación.

add_action('pre_get_posts', 'my_show_appropriate_posts');
function my_show_appropriate_posts($query){

    if(strpos($_SERVER[ 'REQUEST_URI' ], '/wp-admin/edit.php') !== false) :

        if(!current_user_can('manage_options')) :

            /** Anular para poder controlar exactamente dónde se incluye esta parte de la consulta */
            $query->set('author', null);

            /** Asegurar que se incluyan las tablas relevantes necesarias para una consulta de metadatos */
            $query->set('meta_query', array(
                array(
                    'key'       => 'add_editing_permission_for',
                    'value'     => 'dummy', // Esto no puede estar vacío debido a un error en WordPress
                    'compare'   => '='
                )
            ));

            /** Llamar al filtro para modificar la porción '$where' de la consulta */
            add_filter('posts_where', 'my_custom_posts_where');

        endif;

    endif;

}

function my_custom_posts_where( $where = '' ){

    global $wpdb;

    /** Agregar nuestras condiciones requeridas a la porción '$where' de la consulta */
    $where.= sprintf(
        ' AND ( %1$s.post_author = %2$s OR ( %3$s.meta_key = "add_editing_permission_for" AND %3$s.meta_value = %2$s ) )',
        $wpdb->posts,
        get_current_user_id(),
        $wpdb->postmeta
    );

    /** Eliminar el filtro para llamar a esta función, ya que no lo queremos más */
    remove_filter('posts_where', 'my_custom_posts_where');

    return $where;

}

Lectura recomendada

26 ene 2015 17:33:48
Comentarios

Gracias por esto- con algunas modificaciones muy pequeñas esto hizo lo que necesitaba (cambié el primer AND en tu sprintf para que fuera un OR, y edité el meta_query). ¡Gracias de nuevo!

GreatBlakes GreatBlakes
26 ene 2015 21:05:54

No hay problema. Tengo curiosidad por saber por qué tuviste que cambiar el AND a OR. La idea es que estás indicando a la consulta "(cumple todas las condiciones anteriores) AND (asegura que el autor del post sea el usuario actual OR asegura que el usuario actual esté autorizado a editar el post)". Al cambiarlo a OR estás ignorando todas las demás condiciones, como el tipo de post - por ejemplo, puede que usuarios que han creado páginas las vean en la lista, no solo posts.

David Gard David Gard
27 ene 2015 12:43:26

Además, veo que alguien más ha rechazado tu edición de mi respuesta. La razón es que realmente no "arregla" nada. El meta_query por ejemplo no hace ninguna diferencia (que yo sepa), solo tienes que pasar uno a $query->set() para asegurar que se hagan los joins relevantes. Y respecto a cambiar AND a OR, si pudieras explicar por qué lo hiciste en los comentarios para otros usuarios sería genial, y desde ahí puedo editar la respuesta si es necesario. Gracias.

David Gard David Gard
27 ene 2015 12:53:52

Honestamente, pensé que lo había arreglado, pero solo era la ilusión de que funcionaba - jaja. El OR hacía que todo apareciera, lo cual parecía que estaba solucionado. En realidad todavía estoy atascado en esto - estoy seguro de que tu código funcionará, pero no he podido descifrar los detalles específicos todavía. Por alguna razón el resto del SQL no está funcionando correctamente (y no sé por qué porque parece exactamente lo que quiero). Me alegro de que mi edición haya sido rechazada, porque habría llevado a otras personas por el camino equivocado (a donde estoy ahora).

GreatBlakes GreatBlakes
27 ene 2015 20:58:39

Tiene que ver con la parte de meta_key en la consulta SQL. Incluso si intento consultar solo eso, no obtengo resultados. El $query->set de la primera función parece tener algo que ver - siento que quizás no está preparando esas claves correctamente? Ah - necesitarás eliminar la segunda llamada a add_filter('posts_where', 'my_custom_posts_where'); en tu respuesta - de lo contrario se activa en todas las publicaciones (en el frontend también) - esa línea solo debería aparecer dentro de la primera función.

GreatBlakes GreatBlakes
27 ene 2015 21:03:23

¿Por qué estás añadiendo el filtro dos veces (una dentro del callback y otra en el ámbito global)? A primera vista, entonces se ejecutará en cada consulta. +1 por el resto de la respuesta :)

kaiser kaiser
28 ene 2015 02:22:30

Buen ojo, he eliminado el del ámbito global.

David Gard David Gard
28 ene 2015 11:28:24

Vale, ahora ya funciona. Es embarazoso, pero el único cambio adicional que necesitas en tu respuesta es que el '=' después de 'dummy' debe ser un '!='. Fue una forma indirecta de encontrarlo usando phpmyadmin para probar consultas SQL, pero al menos ahora todo está bien.

GreatBlakes GreatBlakes
29 ene 2015 21:55:49
Mostrar los 3 comentarios restantes