DISTINCT funciona en todas las columnas en SELECCIONAR, por lo que si está SELECCIONANDO todo, devolverá cada fila distinta y no solo las publicaciones distintas. Para evitar esto, simplemente puede SELECCIONAR los datos de la tabla de publicaciones y luego DISTINTARLOS, es decir,
SELECT DISTINCT posts.*
Pero también dijiste que te gustarían las publicaciones y la información sobre gatos, si es posible. Una forma de hacer esto y mantener una fila por publicación es usar GROUP_CONCAT por lo que su consulta podría terminar algo como esto.
SELECT
posts.*,
GROUP_CONCAT(cats.id SEPARATOR ',') as catsList,
GROUP_CONCAT(tags.id SEPARATOR ',') as tagsList
FROM posts
INNER JOIN termRelations ON ( posts.id = termRelations.postId )
LEFT JOIN cats ON ( termRelations.termId = cats.id AND termRelations.termTypeId = 1 AND cats.id =5 )
LEFT JOIN tags ON ( termRelations.termId = tags.id AND termRelations.termTypeId = 0 AND
(tags.id =2
OR tags.id =1)
)
GROUP BY posts.id
LIMIT 0 , 30
He realizado un par de otros cambios en su consulta original, como cambiar la primera unión a una UNIÓN INTERNA y agregar los filtros de gatos/etiquetas a las condiciones de UNIÓN para las tablas relevantes.
PD:cuando dice que tiene tablas separadas para gatos y etiquetas para acelerar la generación de listas, es posible que encuentre que una tabla indexada correctamente sería igual de rápida y también simplificaría su código.