He pasado días sobre este problema ahora. Inicialmente, era cómo almacenar los datos de seguidores de un usuario en la base de datos, para lo cual obtuve un par de buenas recomendaciones aquí en WordPress Answers. Después, siguiendo las recomendaciones, he agregado una nueva tabla como esta:
id leader_id follower_id
1 2 4
2 3 10
3 2 10
En la tabla anterior, la primera fila tiene un usuario con una ID de 2 al que sigue un usuario con una ID de 4. En la segunda fila, un usuario con una ID de 3 es seguido por un usuario con una ID de 10. La misma lógica se aplica para la tercera fila.
Ahora, esencialmente quiero extender WP_Query para poder limitar las publicaciones obtenidas a las de, solo por el líder (s) de un usuario. Entonces, teniendo en cuenta la tabla anterior, si tuviera que pasar la ID de usuario 10 a WP_Query, los resultados solo deberían contener publicaciones por ID de usuario 2 e ID de usuario 3.
He buscado mucho tratando de encontrar una respuesta. Tampoco he visto ningún tutorial que me ayude a comprender cómo extender la clase WP_Query. He visto las respuestas de Mike Schinkel (extendiendo WP_Query) a preguntas similares, pero realmente no he entendido cómo aplicarlo a mis necesidades. Sería genial si alguien pudiera ayudarme con esto.
Enlaces a las respuestas de Mike según lo solicitado: Enlace 1 , Enlace 2
WP_Query
es para obtener publicaciones, y no entiendo cómo se vincula esto con las publicaciones.Respuestas:
Si está haciendo uniones complejas, no puede simplemente usar el filtro posts_where, porque también necesitará modificar la unión, la selección y posiblemente el grupo por u ordenar por secciones de la consulta.
Su mejor opción es usar el filtro 'posts_clauses'. Este es un filtro muy útil (¡no se debe abusar!) Que le permite agregar / modificar las diversas partes del SQL que se generan automáticamente por las muchas líneas de código dentro del núcleo de WordPress. La firma de devolución de llamada del filtro es:
function posts_clauses_filter_cb( $clauses, $query_object ){ }
y espera que regrese$clauses
.Las cláusulas
$clauses
es una matriz que contiene las siguientes claves; cada clave es una cadena SQL que se usará directamente en la declaración SQL final enviada a la base de datos:Si está agregando una tabla a la base de datos (solo haga esto si no puede aprovechar post_meta, user_meta o taxonomías) probablemente necesitará tocar más de una de estas cláusulas, por ejemplo, el
fields
(el "SELECCIONAR" parte de la instrucción SQL),join
(todas sus tablas, excepto la de su cláusula "FROM"), y quizás elorderby
.Modificando las Cláusulas
La mejor manera de hacerlo es subreferenciar la clave relevante de la
$clauses
matriz que obtuvo del filtro:Ahora, si modifica
$join
, en realidad estará modificando directamente,$clauses['join']
por lo que los cambios se realizarán$clauses
cuando lo devuelva.Preservando las Cláusulas Originales
Es probable que (no, en serio, escuche) desee conservar el SQL existente que WordPress generó para usted. De lo contrario, probablemente debería mirar el
posts_request
filtro; esa es la consulta completa de mySQL justo antes de que se envíe a la base de datos, por lo que puede bloquearla totalmente con la suya. Por qué querrías hacer esto? Probablemente no lo hagas.Por lo tanto, para preservar el SQL existente en las cláusulas, recuerde agregar a las cláusulas, no asignarlas (es decir:
$join .= ' {NEW SQL STUFF}';
no usar$join = '{CLOBBER SQL STUFF}';
. Tenga en cuenta que debido a que cada elemento de la$clauses
matriz es una cadena, si desea agregarle, probablemente desee insertar un espacio antes de cualquier otro token de caracteres; de lo contrario, probablemente creará algún error de sintaxis SQL.Puede suponer que siempre habrá algo en cada una de las cláusulas, y recuerde comenzar cada nueva cadena con un espacio, como en:,
$join .= ' my_table
o, siempre puede agregar una pequeña línea que solo agrega un espacio si necesita:Eso es algo estilístico más que cualquier otra cosa. Lo importante para recordar es: ¡ siempre deje un espacio ANTES de su cadena si va a agregar a una cláusula que ya tiene algo de SQL!
Poniendo todo junto
La primera regla del desarrollo de WordPress es tratar de utilizar la mayor cantidad de funciones básicas que pueda. Esta es la mejor manera de preparar su trabajo para el futuro. Supongamos que el equipo central decide que WordPress ahora usará SQLite u Oracle o algún otro lenguaje de base de datos. ¡Cualquier MySQL escrito a mano puede volverse inválido y romper su plugin o tema! Es mejor dejar que WP genere la mayor cantidad de SQL posible por sí mismo, y solo agregue los bits que necesita.
Entonces, el primer orden de negocios es aprovechar
WP_Query
para generar la mayor cantidad posible de su consulta base. El método exacto que usamos para hacer esto depende en gran medida de dónde se supone que debe aparecer esta lista de publicaciones. Si es una subsección de la página (no es su consulta principal) que usaríaget_posts()
; si es la consulta principal, supongo que podría usarlaquery_posts()
y terminar con ella, pero la forma correcta de hacerlo es interceptar la consulta principal antes de que llegue a la base de datos (y consuma los ciclos del servidor), así que use elrequest
filtro.Bien, entonces has generado tu consulta y el SQL está a punto de ser creado. Bueno, de hecho, ha sido creado, simplemente no enviado a la base de datos. Al usar el
posts_clauses
filtro, agregará la tabla de relaciones de sus empleados a la mezcla. Llamemos a esta tabla {$ wpdb-> prefijo}. 'user_relationship', y es una tabla de intersección. (Por cierto, le recomiendo que genere esta estructura de tabla y la convierta en una tabla de intersección adecuada con los siguientes campos: 'relacion_id', 'id_usuario', 'related_user_id', 'relacion_tipo'; esto es mucho más flexible y poderoso. .. pero yo divago).Si entiendo lo que quieres hacer, quieres pasar la identificación de un líder y luego ver solo las publicaciones de los seguidores de ese líder. Espero haber acertado. Si no está bien, tendrá que tomar lo que digo y adaptarlo a sus necesidades. Me quedaré con la estructura de su mesa: tenemos a
leader_id
y afollower_id
. Por lo tanto, JOIN estará{$wpdb->posts}.post_author
activado como una clave foránea para 'follower_id' en su tabla 'user_relationship'.fuente
Estoy respondiendo esta pregunta extremadamente tarde y mis disculpas por lo mismo. Había estado demasiado ocupado con los plazos para atender esto.
Muchas gracias a @ m0r7if3r y @kaiser por proporcionar las soluciones básicas que podría ampliar e implementar en mi aplicación. Esta respuesta proporciona detalles sobre mi adaptación de las soluciones ofrecidas por @ m0r7if3r y @kaiser.
Primero, permítanme explicar por qué se hizo esta pregunta en primer lugar. A partir de la pregunta y sus comentarios, uno podría deducir que estoy tratando de hacer que WP_Query extraiga publicaciones de todos los usuarios (líderes) que sigue un usuario (seguidor) determinado. La relación entre el seguidor y el líder se almacena en una tabla personalizada
follow
. La solución más común a este problema es extraer las ID de usuario de todos los líderes de un seguidor de la tabla siguiente y colocarlas en una matriz. Vea abajo:Una vez que tenga la matriz de líderes, puede pasarla como argumento a WP_Query. Vea abajo:
La solución anterior es la forma más sencilla de lograr los resultados deseados. Sin embargo, no es escalable. En el momento en que tenga un seguidor siguiendo a decenas y miles de líderes, la matriz resultante de ID de líderes se volvería extremadamente grande y obligaría a su sitio de WordPress a usar 100MB - 250MB de memoria en cada carga de página y eventualmente bloquear el sitio. La solución al problema es ejecutar una consulta SQL directamente en la base de datos y buscar publicaciones relevantes. Fue entonces cuando la solución de @ m0r7if3r vino a rescatar. Siguiendo la recomendación de @ kaiser, me propuse probar ambas implementaciones. Importé alrededor de 47K usuarios de un archivo CSV para registrarlos en una nueva instalación de prueba de WordPress. La instalación ejecutaba el tema Twenty Eleven. Después de esto, ejecuté un bucle for para que unos 50 usuarios siguieran a todos los demás usuarios. La diferencia en el tiempo de consulta para la solución de @kaiser y @ m0r7if3r fue asombrosa. La solución de @ kaiser normalmente tomaba de 2 a 5 segundos para cada consulta. La variación que supongo ocurre cuando WordPress almacena en caché las consultas para su uso posterior. Por otro lado, la solución de @ m0r7if3r demostró un tiempo de consulta de 0.02 ms en promedio. Para probar ambas soluciones, tenía la indexación activada para la columna leader_id. Sin indexación hubo un aumento dramático en el tiempo de consulta.
El uso de la memoria cuando se utiliza una solución basada en matriz se situó en torno a 100-150 MB y se redujo a 20 MB al ejecutar un SQL directo.
Llegué a un golpe con la solución de @ m0r7if3r cuando necesitaba pasar la identificación del seguidor a la función de filtro posts_where. Al menos, según mi conocimiento, WordPress no permite pasar una variable a las funciones del archivador. Sin embargo, puede usar variables globales, pero quería evitar los globales. Terminé extendiendo WP_Query para finalmente abordar el problema. Así que aquí está la solución final que implementé (basada en la solución de @ m0r7if3r).
Nota: Finalmente probé la solución anterior con 1.2 millones de entradas en la siguiente tabla. El tiempo promedio de consulta fue de alrededor de 0.060 ms.
fuente
Puede hacer esto con una solución completamente SQL usando el
posts_where
filtro. Aquí hay un ejemplo de eso:Creo que también puede haber una manera de hacer esto
JOIN
, pero no puedo encontrarlo. Seguiré jugando con él y actualizaré la respuesta si lo consigo.Alternativamente, como sugirió @kaiser , puede dividirlo en dos partes: obtener los líderes y hacer la consulta. Tengo la sensación de que esto podría ser menos eficiente, pero sin duda es el camino más comprensible. Tendría que probar la eficiencia por usted mismo para determinar qué método es mejor, ya que las consultas SQL anidadas pueden ser bastante lentas.
DE LOS COMENTARIOS:
Debe poner la función en su
functions.php
y hacer loadd_filter()
correcto antesquery()
de queWP_Query
se llame al método de . Inmediatamente después de eso, debe hacerloremove_filter()
para que no afecte las otras consultas.fuente
prepare()
. Espero que no te importe la edición. Y sí: el rendimiento tiene que ser medido por OP. De todos modos: sigo pensando que esto debería ser simplemente usermeta y nada más.functions.php
y hacer loadd_filter()
correcto antesquery()
de queWP_Query
se llame al método de . Inmediatamente después de eso, debe hacerloremove_filter()
para que no afecte las otras consultas. No estoy seguro de cuál sería el problema con la reescritura de URL, lo he usadoposts_where
en muchas ocasiones y nunca lo vi ...Etiqueta de plantilla
Simplemente coloque ambas funciones en su
functions.php
archivo. Luego ajuste la primera función y agregue su nombre de tabla personalizado. Luego, necesita algún intento / error para deshacerse de la ID de usuario actual dentro de la matriz resultante (ver comentario).Dentro de la plantilla
Aquí puedes hacer lo que quieras con tus resultados.
fuente
JOIN
Es mucho más caro. Además: como mencioné, no tenemos datos de prueba, por lo tanto, pruebe ambas respuestas e ilumínenos con sus resultados.Aquí está el Código OP de los comentarios, para agregar el primer conjunto de usuarios de prueba. Tengo que ser modificado a un ejemplo del mundo real.
Mi respuesta a esta prueba ↑:
También tengo que decir que el seguimiento de tiempo anterior ↑ no se puede medir realmente, ya que también tomaría el tiempo de calcular el ciclo juntos. Mejor sería recorrer el conjunto resultante de ID en un segundo ciclo.
proceso adicional aquí
fuente