I created a custom taxonomy named 'technologies' but cannot query multiple terms like I can with categories or tags.
These querys DO work:
query_posts('tag=goldfish,airplanes');
query_posts('technologies=php');
However, neither of the following work correctly:
query_posts('technologies=php,sql');
query_posts('technologies=php&technologies=sql');
My objective: Show all posts with a technology of 'php' and all posts with a technology of 'sql'
Any ideas? Is this even possible? Thanks!
Apparently query_posts cannot help in this specific situation. (Hopefully it will be added in future versions of Wordpress!) The solution is to use a custom select query like the following:
SELECT *
FROM $wpdb->posts
LEFT JOIN $wpdb->term_relationships ON($wpdb->posts.ID = $wpdb->term_relationships.object_id)
LEFT JOIN $wpdb->term_taxonomy ON($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)
LEFT JOIN $wpdb->terms ON($wpdb->term_taxonomy.term_id = $wpdb->terms.term_id)
WHERE $wpdb->posts.post_type = 'post'
AND $wpdb->posts.post_status = 'publish'
AND $wpdb->term_taxonomy.taxonomy = 'technologies'
AND $wpdb->terms.slug = 'php' OR $wpdb->terms.slug = 'css'
ORDER BY $wpdb->posts.post_date DESC
More information can be found at the Wordpress Codex:
http://codex.wordpress.org/Displaying_Posts_Using_a_Custom_Select_Query
This is a bit of a delayed reply, but it's first on Google at the moment for "wordpress related posts by multiple terms" so thought I'd contribute my findings.
Since this question was posted Wordpress has been changed to allow for this type of query. This will give you a list of posts related by any of the custom taxonomy terms assigned to an object:
$post_cats = wp_get_object_terms(get_the_ID(), 'video_category', array('fields' => 'ids'));
$args=array(
"tax_query" => array(
array(
"taxonomy" => "video_category",
"field" => "id",
"terms" => $post_cats
)
),
'post__not_in' => array(get_the_ID()),
'post_type' => 'video',
'posts_per_page' => 8,
'caller_get_posts' => 1
);
$related_by_cats = new WP_Query($args);
This is my first contribution to SO, I hope it's up to standards.
You can use this plugin:
http://scribu.net/wordpress/query-multiple-taxonomies/
Does this work? query_posts('tag=bread+baking+recipe')
From: http://codex.wordpress.org/Template_Tags/query_posts
OK, so here is my crack at this. It's a little hacky, but it works. The big downside is that any other query variables need to be re-added, as when multiple terms are invoked, the fail strips out all of the query vars.
Also, I did not test this against querying across multiple taxonomies. This only works within a specific taxonomy. Use at your own risk.
function multi_tax_terms($where) {
global $wp_query;
if ( strpos($wp_query->query_vars['term'], ',') !== false && strpos($where, "AND 0") !== false ) {
// it's failing because taxonomies can't handle multiple terms
//first, get the terms
$term_arr = explode(",", $wp_query->query_vars['term']);
foreach($term_arr as $term_item) {
$terms[] = get_terms($wp_query->query_vars['taxonomy'], array('slug' => $term_item));
}
//next, get the id of posts with that term in that tax
foreach ( $terms as $term ) {
$term_ids[] = $term[0]->term_id;
}
$post_ids = get_objects_in_term($term_ids, $wp_query->query_vars['taxonomy']);
if ( !is_wp_error($post_ids) && count($post_ids) ) {
// build the new query
$new_where = " AND wp_posts.ID IN (" . implode(', ', $post_ids) . ") ";
// re-add any other query vars via concatenation on the $new_where string below here
// now, sub out the bad where with the good
$where = str_replace("AND 0", $new_where, $where);
} else {
// give up
}
}
return $where;
}
add_filter("posts_where", "multi_tax_terms");
It's somehow silly that after implementing custom taxonomies in WP there are no built-in functions to use them at will, and the documentation is close to non-existent. I was looking for a solution, this query solves it (and made my day). Thanks.
Still, sadly I'm too dumb (OOP blind) to make it into a function so I don't repeat it all over.
I get: **Fatal error**: Call to a member function get_results() on a non-object
I guess I don't know how to call $wpdb from within a function.
it should be like this:
global $wp_query;
query_posts(
array_merge(
array('taxonomy' => 'technologies', 'term' => array('sql', 'php')),
$wp_query->query
)
);
that works for custom post_types, at least.
Hey, I also faced the same problem once. If you don't have many multiple values, then you can do it in the following way, rather than writing a raw SQL query:
$loop = new WP_Query(array('technologies' => 'php','technologies' => 'sql'));
Then you can loop through the wp_query object created here.
Though this is a very old post and am sure you have already solved the problem. :)
//equivalent to get_posts
function brand_get_posts($args=array()){
global $wpdb;
$sql = "SELECT p.* ";
$sql.= " FROM $wpdb->posts p";
$sql.= " LEFT JOIN $wpdb->term_relationships term_r ON(p.ID = term_r.object_id)";
$sql.= " LEFT JOIN $wpdb->term_taxonomy term_t ON(term_r.term_taxonomy_id = term_t.term_taxonomy_id)";
$sql.= " LEFT JOIN $wpdb->terms terms ON(term_t.term_id = terms.term_id)";
$sql.= " WHERE 1=1 ";
if(!empty($args['post_type'])){
$sql.= " AND p.post_type = '".$args['post_type']."'";
}
$sql.= " AND p.post_status = 'publish'";
if(!empty($args['taxonomy'])){
$sql.= " AND term_t.taxonomy = '".$args['taxonomy']."'";
}
if(!empty($args['terms'])&&is_array($args['terms'])){
$sql.= " AND terms.slug IN ('".implode(",",$args['terms'])."')";
}
$sql.= " ORDER BY p.post_date DESC";
if(!empty($args['posts_per_page'])){
$sql.=" LIMIT ".$args['posts_per_page'];
}
if(!empty($args['offset'])){
$sql.=" OFFSET ".$args['offset'];
}
//echo '<h1>'.$sql.'</h1>';
return $wpdb->get_results($sql);
}
Related
I'm using the DevBridge jQuery Autocomplete plugin with the ajax option (using serviceURL instead NOT lookup). I have a php file that queries the db (WordPress FYI) and gets all the results just fine. So when users type into my autocomplete field, it's showing ALL the results with their query highlighted. Apparently my server-side script is supposed to handle the searching and return ONLY the filtered results based on the user's on-the-fly input. I'm just not sure how to go about doing that.
I've found a ton of posts online stating this is how it's supposed to work but can't find any working examples of a serviceURL file that returns filtered results based on what the user is typing.
Here's the code I have so far...
My jQuery...
$('#product_sku_autocomplete').autocomplete({
serviceUrl: '/blah/blah/ajax-product-sku.php',
minChars: 1,
onSelect: function (suggestion) {
alert('You selected: ' + suggestion.value + ', ' + suggestion.data);
}
});
the contents of my ajax-product-sku.php file. This gets all the various meta values for a custom field (sku) across all 'products'
if ( ! defined('ABSPATH') ) {
require_once( '../../../../wp-load.php' );
}
global $wpdb;
$term = $_GET['query'];
$query = $wpdb->get_col( $wpdb->prepare( "
SELECT pm.meta_value FROM {$wpdb->postmeta} pm
LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
WHERE pm.meta_key = %s
AND p.post_status = %s
AND p.post_type = %s
", 'sku', 'publish', 'products' ) );
$reply = array();
$reply['query'] = $term;
$reply['suggestions'] = array();
foreach ($query as $sku) {
$reply['suggestions'][] = array(
"value" => $sku,
"data" => $sku
);
}
echo json_encode($reply);
The results if I access ajax-product-sku.php directly...
{"query":null,"suggestions":[{"value":"52N242","data":"52N242"},{"value":"52F230","data":"52F230"},{"value":"52F235","data":"52F235"}]}
So I'm getting my full list of results (properly formatted as far as I can tell) and the autocomplete field retrieves those BUT when you type into the autocomplete field it's showing ALL the results not just the ones that match what the user has typed in.
I suspect that I need to add the $term var somewhere within my db $query statement but not sure how. Any help is greatly appreciated.
I think I've got it. Pretty simple solution but my sql chops are lacking obviously. Need to add a LIKE condition to the sql statement. Here's the revised ajax-product-sku.php file contents.
If anyone has a more efficient way to handle this from a coding or performance standpoint, I'd welcome the knowledge...
ajax-product-sku.php
if ( ! defined('ABSPATH') ) {
require_once( '../../../../wp-load.php' );
}
global $wpdb;
$term = $_GET['query']; // this is the var that autocomplete sends as users type.
//$term = '1';
$query = $wpdb->get_col( $wpdb->prepare( "
SELECT pm.meta_value FROM {$wpdb->postmeta} pm
LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
WHERE pm.meta_key = %s
AND p.post_status = %s
AND p.post_type = %s
AND pm.meta_value LIKE '%{$term}%'
", 'sku', 'publish', 'products' ) );
$reply = array();
$reply['query'] = $term;
$reply['suggestions'] = array();
foreach ($query as $sku) {
$reply['suggestions'][] = array(
"value" => $sku,
"data" => $sku
);
}
echo json_encode($reply);
I'm trying to get the ranking the number of meta_key at specific custom post type.
But I'm not great at SQL so therefor not great with using $wpdb.
For example, if I write something like this,
<?php
$tarms = array( ‘sweet, sour’ );
echo get_count_ranking( $tarms );
?>
Then I would like to display rankings from comment("custom post of reply") of "custom post of fluits" with "term of sweet" and "term of sour" in order of "meta_key of count".
Here is my code:
function get_count_ranking( $tarms ){
global $wpdb;
$counts = $wpdb->get_results( $wpdb->prepare( "
SELECT p.post_author AS user_id, sum(m.meta_value) AS SumUser
FROM $wpdb->posts AS p, $wpdb->postmeta AS m
WHERE p.ID = m.post_ID
AND p.ID IN (
SELECT tr.object_id
FROM $wpdb->term_relationships AS tr, $wpdb->posts AS p, $wpdb->term_taxonomy AS tt
WHERE p.post_type = 'reply'
AND tt.term_id = %s
AND p.id = tr.object_id
AND tr.term_taxonomy_id = tt.term_taxonomy_id
)
AND p.post_status = 'publish'
AND m.meta_key = 'count'
GROUP BY p.post_author
ORDER BY m.meta_value DESC LIMIT 10
", $tarms ) );
$result = '';
foreach ( $counts as $count ) {
$result .= '<li><img>'.get_avatar($count->user_id, 30).'<span></span></li>';
}
return $result;
}
I am sorry that my English is so bad.
So I attach that image for your reference.
Thanks.
enter image description here
--
Updated code:
function get_count_ranking( $tarms ){
$customPostArg = array(
'posts_per_page' => 5,
'post_type' => 'fluits',
'tax_query' => array(
array(
'taxonomy' => 'taste-tag',
'field' => 'slug',
'terms' => $tarms
)
)
);
$array_with_post_ids = get_posts($customPostArg);
$argsp = array(
'post__in' => $array_with_post_ids
);
$commentsp = get_comments( $argsp );
$needed_data_array = array();
foreach ($comments as $key => $comment) {
$ranking = get_comment_meta($comment->ID, 'count', $return_single_value = true);
$author_id = $comment->user_id;
// make sure we have an author id
if($author_id) {
$needed_data_array[$author_id][] = $ranking;
}
}
}
$tarms = array( ‘sweet, sour’ );
echo get_count_ranking( $tarms );
I would not use $wpdb for this.
Also, it looks like you save rankings to a POST meta field, I would use a comment meta field.
Please NOTE, i'm not going to help you write everything, but here are
some pointers how I would accomplish this.
Register the custom post types with comment capability.
Extend the add comment to include a ranking setter. Save this ranking data in a comment_meta field. Now the comment and ranking meta are linked. When you remove the comment, the ranking meta data is also removed from the DB.
Now post comments and rankings are saved.
Collecting data
WP has a get_comments() function, this function accepts many arguments. Sadly, I miss an argument to get comments from posts with a certain taxonomy. So we have to collect all the posts first:
Collect all the posts with 'sweet' and/or 'sour' taxonomy, use get_posts().
Build an array with post id's.
Use get_comments() to get all comments connected to the posts.
Example:
$args = array(
'post__in' => $array_with_post_ids,
);
$comments = get_comments( $args );
Now you have all the comments you need for creating overviews, I would loop (iterate) through them and build an array with author_names and their rankings.
Example:
$needed_data_array = array();
foreach ($comments as $key => $comment) {
$ranking = get_comment_meta($comment->ID, 'ranking_meta_key', $return_single_value = true);
$author_id = $comment->user_id;
// make sure we have an author id
if($author_id) {
$needed_data_array[$author_id][] = $ranking;
}
}
//
// Now the $needed_data_array holds all authors
// and their post rankings, you can count them
// to get ranking totals for each comment-author.
//
Solved: Here is the solution code.
//Extend Category queries to support "latest_post" for orderby parameter
function filter_term_sort_by_latest_post_clauses( $pieces, $taxonomies, $args )
{
global $wpdb;
if ( in_array('category', $taxonomies) && $args['orderby'] == 'latest_post' )
{
$pieces['fields'] .= ", MAX(p.post_date) AS last_date";
$pieces['join'] .= " JOIN $wpdb->term_relationships AS tr JOIN $wpdb->posts AS p ON p.ID=tr.object_id AND tr.term_taxonomy_id=tt.term_taxonomy_id";
$pieces['where'] .= " AND p.post_status='publish' GROUP BY t.term_id";
$pieces['orderby'] = "ORDER BY last_date";
$pieces['order'] = "DESC"; // DESC or ASC
}
return $pieces;
}
add_filter('terms_clauses', 'filter_term_sort_by_latest_post_clauses', 10, 3);
Original question:
I have added the following function & filter hook in a WordPress site that allows me to list the categories, sorted by the most recent post in each category. The function works as expected, except that draft posts are included, and will move that particular category to the top of the list.
//Extend Category queries to support "latest_post" for orderby parameter
function filter_term_sort_by_latest_post_clauses( $pieces, $taxonomies, $args )
{
global $wpdb;
if ( in_array('category', $taxonomies) && $args['orderby'] == 'latest_post' )
{
$pieces['fields'] .= ", MAX(p.post_date) AS last_date";
$pieces['join'] .= " JOIN $wpdb->term_relationships AS tr JOIN $wpdb->posts AS p ON p.ID=tr.object_id AND tr.term_taxonomy_id=tt.term_taxonomy_id";
$pieces['where'] .= " GROUP BY t.term_id";
$pieces['orderby'] = "ORDER BY last_date";
$pieces['order'] = "DESC"; // DESC or ASC
}
return $pieces;
}
add_filter('terms_clauses', 'filter_term_sort_by_latest_post_clauses', 10, 3);
I would like to be make the select clause "MAX(p.post_date) AS last_date" only include values from published posts ( WHERE p.post_status=publish" )
How can I accomplish this?
Thanks!
What about adding the statement to where clause: $pieces['where'] .= " WHERE p.post_status='publish' GROUP BY t.term_id"; . Unless i missed something this should be an easy fix. Hope this helps.
In "category.php" file I need to order my posts in this strange way:
First all the posts where author is different than "admin" (in alphabetical order by title)
Than all the post by "admin" (in the same alphabetical order)
Here is the standard code I use to do my query:
<?php global
$wp_query;
query_posts(
array_merge(
array('orderby' => 'title', 'order' => 'ASC'),
$wp_query->query
)
);
?>
Any idea about how to accomplish it without nesting two queries?
Thanks in advance!
EDIT: Following is some code that was tried, as suggested by Sepster in a previous version of his answer. But at the moment this code starts showing all the posts from 'admin' (instead of the others) until the posts with author different than 'admin' come. At that point it breaks the results and jump to the next page of results.
<?php
global $wp_query;
query_posts(
array_merge(
array('orderby' => 'title', 'order' => 'ASC'),
$wp_query->query
)
);
$adminPosts = false;
for ($i=1; $i<=2; $i++) {
while ( $wp_query->have_posts() ) {
$wp_query->the_post();
$author = get_the_author();
if ($author == 'admin' && $adminPosts == false) break;
if ($author != 'admin' && $adminPosts == true) break;
// ALL MY STUFF
} // end while
rewind_posts();
$adminPosts=true;
} // end FOR
?>
Update:
I've finally come up with a somewhat workable solution for this, but it's fair to say this really is an excercise in academics; Yes, it's do-able without executing a second loop, but really, it's pretty convoluted.
The solution is, in summary
Develop a custom SQL statement that will return the rows in the order required.
This is because in SQL, the only way to get the results in the order you need is by doing a UNION of your two subsets. To my knowledge there's no way of doing that using the "normal" WP query operations.
Execute this query, and loop over its results rather than a standard "the loop".
This is because we're getting back a recordset, rather than a WP_Query object.
Set the "Blog pages show at most X posts" setting to 1.
(on /wp-admin/options-reading.php)
A common complaint is pagination breaking when using custom queries (incidentally, the query_posts() method you're using is susceptible to this issue).
There are numerous turorials on how to do this properly, eg:
https://codex.wordpress.org/Making_Custom_Queries_using_Offset_and_Pagination
https://codex.wordpress.org/Pagination#Troubleshooting_Broken_Pagination
The first of those recommends the implementation of "Offset and Manual Pagination".
The closest I've found to an implementation of this in conjunction with a custom SQL statement is this https://wordpress.stackexchange.com/a/28717. I've borrowed heavily from this answer (and so I recommend you go over and give it an up-vote!).
However, this technique (among other more "standard" custom query approaches) suffers from a known behaviour where WP produces a 404 on the final page (if I understand correctly, because WP is still using its own query and associated max-page=posts-per-page/posts calculations to map between the page number in the URL and the delivered content).
Refer http://wordpress.org/support/topic/explanation-and-workaround-for-error-404-on-category-pagination?replies=14 for details about this issue, and a proposed solution (which unfortunately won't work for our custom SQL approach).
A known "work-around" for this issue is to reduce the number of posts-per-page to 1, as per eg http://wordpress.org/support/topic/custom-post-type-pagination-404-on-last-page
So, assuming you're happy with a global setting of 1 posts-per-page (remember you'd need to override this manually in your custom queries), here's the code:
functions.php:
...
function get_users_posts_last($userDisplayName = 'Admin', $categoryName = '') {
global $wpdb, $paged, $max_num_pages;
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$post_per_page = 5;
$offset = ($paged - 1)*$post_per_page;
$sql = "
SELECT SQL_CALC_FOUND_ROWS q.* FROM
(
(
SELECT
p.*
FROM
{$wpdb->posts} p
INNER JOIN {$wpdb->users} u ON p.post_author = u.ID
LEFT JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id
LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
LEFT JOIN {$wpdb->terms} t ON tt.term_id = t.term_id
WHERE
tt.taxonomy = 'category'
AND p.post_status = 'publish'
AND p.post_type = 'post'
AND u.display_name != '{$userDisplayName}'
" . ( $categoryName != '' ? "AND t.name = '{$categoryName}'" : "" ) . "
ORDER BY
p.post_title ASC
)
UNION
(
SELECT
p.*
FROM
{$wpdb->posts} p
INNER JOIN {$wpdb->users} u ON p.post_author = u.ID
LEFT JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id
LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
LEFT JOIN {$wpdb->terms} t ON tt.term_id = t.term_id
WHERE
tt.taxonomy = 'category'
AND p.post_status = 'publish'
AND p.post_type = 'post'
AND u.display_name = '{$userDisplayName}'
" . ( $categoryName != '' ? "AND t.name = '{$categoryName}'" : "" ) . "
ORDER BY
p.post_title ASC
)
) q
LIMIT {$offset}, {$post_per_page};
";
$sql_result = $wpdb->get_results( $sql, OBJECT);
$sql_posts_total = $wpdb->get_var( "SELECT FOUND_ROWS();" );
$max_num_pages = ceil($sql_posts_total / $post_per_page);
return $sql_result;
}
...
category.php:
...
$postList = get_users_posts_last('admin'); // Note you can also pass a category name if necessary
if($postList) {
global $post;
foreach( $postList as $key=>$post ) {
setup_postdata($post);
// Render the post here
?>
<header class='entry-header'><h1 class='entry-title'><?php the_title(); ?></h1></header>
<div class='entry-content'><?php the_content(); ?></div>
<?php
}
// Render pagination here
?>
<div class="navigation">
<div class="previous panel"><?php previous_posts_link('« Previous page',$max_num_pages) ?></div>
<div class="next panel"><?php next_posts_link('Next page »',$max_num_pages) ?></div>
</div>
<?php
}
...
Or, just set up two separate queries ;-)
I'm wanting to order Wordpress posts by the most recent comment. To the best of my knowledge this isn't possible using the WP_Query object, and would require a custom $wpdb query, which I can easily write. However, I then don't know how to setup the loop to run off this object.
Can anyone help?
Assign
select wp_posts.*, max(comment_date) as max_comment_date
from $wpdb->posts wp_posts
right join $wpdb->comments
on id = comment_post_id
group by ID
order by max_comment_date desc
limit 10
to some variable $query. You can fiddle around with the 10 or the query itself. (I'm no SQL optimization ninja.) Then your code will look something like
<?php
$results = $wpdb->get_results($query) or die('!');
foreach ($results as $result):
?>
[insert template here]
<?php endforeach ?>
This pattern is covered in more depth by the Codex.
I used a simpler, portion of a native WP in function. hope it helps and some one can continue to develop. Here is a simplified version that shows the title & excerpt of the post along with the comment content & author from the latest commented posts using get_comments.
$args = array(
'status' => 'approve',
'number' => 6,
'order' => 'DESC'
);
$comments = get_comments($args);
foreach($comments as $comment) : $count++;
$post_args = array(
'post_type' => 'post',
'p' => $comment->comment_post_ID,
'posts_per_page' => 1
);
$posts = get_posts($post_args);
foreach($posts as $post) : setup_postdata($post);
the_title();
the_excerpt();
endforeach;
echo $comment->comment_content;
echo $comment->comment_author;
endforeach;
OK guys,
A lot of great answers here, but obviously nobody's taken the time to test them.
Hao Lian gets the credit for the first best original answer, but unfortunately his code doesn't show posts without comments.
Captain Keytar is on the right track, but his code will display every single post and attachment as a separate result.
Here is a modified version of Captain Keytar but it limits the results to the type 'post'.. that has been published (to avoid getting drafts!!)
select wp_posts.*,
coalesce(
(
select max(comment_date)
from $wpdb->comments wpc
where wpc.comment_post_id = wp_posts.id
),
wp_posts.post_date
) as mcomment_date
from $wpdb->posts wp_posts
where post_type = 'post'
and post_status = 'publish'
order by mcomment_date desc
limit 10
This is an old question, but I had the same issue and found a much cleaner way to do this, so I'm posting it here in case it helps anyone.
If you use the posts_clauses filter you can then just modify the main query and still use The Loop and all the regular loop functions.
function intercept_query_clauses( $pieces ) {
global $wpdb;
$pieces['fields'] = "wp_posts.*,
(
select max(comment_date)
from " . $wpdb->comments ." wpc
where wpc.comment_post_id = wp_posts.id AND wpc.comment_approved = 1
) as mcomment_date";
$pieces['orderby'] = "mcomment_date desc";
return $pieces;
}
add_filter( 'posts_clauses', 'intercept_query_clauses', 20, 1 );
Note that I changed the sql slightly for my own purposes, but the general concept is the same.
As an addendum to Hao Lian's answer, if you use the following query:
select wp_posts.*,
coalesce(
(
select max(comment_date)
from $wpdb->comments wpc
where wpc.comment_post_id = wp_posts.id
),
wp_posts.post_date
) as mcomment_date
from $wpdb->posts wp_posts
order by mcomment_date desc
limit 10
This mixes in posts that don't have comments yet, and sorts them by post_date and max(comment_date).
Code suggested by Hao Lian works perfect except for the fact that we should add the following WHERE clause to avoid pulling POST with comment_count = 0, this situation is caused by spam comments.
The WHERE clause to add is as follows:
WHERE comment_approved = '1' AND comment_type = '' AND post_password = ''
Complete code after adding the where clause shoud look like following:
select wp_posts.*, max(comment_date) as comment_date
from wp_posts
right join wp_comments on id = comment_post_id
WHERE comment_approved = '1' AND comment_type = '' AND post_password = ''
group by ID
order by comment_date desc
limit 6
This can be done by combining WP_Comment_Query with WP_Query, like this:
// For performance, limit the number of queried comments,
// but make it be something big enough to account for "duplicate" posts.
$comments_query = new WP_Comment_Query;
$comments = $comments_query->query( array( 'number' => '100' ) );
if ( $comments ) {
foreach ( $comments as $comment ) {
// You'll want to convert the dates from string to integer so you can sort them out later
$comment_utf = strtotime($comment->comment_date);
// Build an array of post IDs with the date of the last published comment
$latest_comments[$comment->comment_post_ID] = $comment_utf;
}}
// Sort the array by date
arsort($latest_comments); foreach ($latest_comments as $key => $value) { $posts_ordered[] = $key; }
// The nice thing is that WP_Query will remove duplicates by default
$args = array ( 'posts_per_page' => '10', 'post__in' => $posts_ordered, 'orderby' => 'post__in');
$query = new WP_Query( $args );
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
// Do your stuff (add the template or whatever)
// If you want to add the comment itself, use this:
$comments = get_comments(array('number' => '1', 'post_id' => $post->ID));
foreach($comments as $comment) :
echo $comment->comment_content;
endforeach;
// That's about it
}}
wp_reset_postdata();
I'm thinking that adding in the max function will screw up your results. MySQL isn't going to pull the max from each one. It's going to pull the max from the full set. This is the query that'll get you your results:
select wp_posts.*, comment_date
from $wpdb->posts wp_posts
right join $wpdb->comments
on id = comment_post_id
group by ID
order by comment_date desc
limit 10
After that, if you want to follow WP convention, use this, and then you can use the functions that most of your templates are using (based on the loop):
$results = $wpdb->get_results($query) or die('!');
foreach ($results as $post):
setup_postdata($post);
Get 3 newest comments for custom post type 'question' regardless of approvement:
global $wpdb;
$results = $wpdb->get_results(
"
SELECT wp_posts.ID, MAX(comment_date) AS max_comment_date
FROM wp_posts
RIGHT JOIN wp_comments
ON id = comment_post_id
WHERE wp_posts.post_type = 'question'
AND wp_posts.post_status = 'publish'
GROUP BY ID
ORDER BY max_comment_date DESC
LIMIT 3
"
);
foreach ($results as $result) {
$posts_arr[] = $result->ID;
}
$args = array(
'post_type' => 'question',
'post__in' => $posts_arr,
'orderby' => 'post__in',
);
$the_query = new WP_Query( $args );
Using Lucian's BEAUTIFUL solution, I needed to alter/filter the existing WP_Query to sort posts by the latest comment. Here's the code, tested & works perfectly:
$comments_query = new WP_Comment_Query;
$comments = $comments_query->query( array( 'number' => '100' ) );
if ( $comments ) {
foreach ( $comments as $comment ) {
$comment_utf = strtotime($comment->comment_date);
$latest_comments[$comment->comment_post_ID] = $comment_utf;
}
// Sort the array by date
arsort( $latest_comments );
foreach( $latest_comments as $key => $value ) {
$posts_ordered[] = $key;
}
$query->set( 'post__in', $posts_ordered );
$query->set( 'orderby', 'post__in' );
}