Order posts by last comment date in WordPress - php

I am using a combination of get_comments() and get_post() to display a list of posts ordered by comment date.
Ref:
http://codex.wordpress.org/Function_Reference/get_comments
https://codex.wordpress.org/Function_Reference/get_post
My code:
$args = array(
'status' => 'approve',
'order' => 'DESC'
);
$comments = get_comments( $args );
foreach ( $comments as $comment ) {
$post = get_post( $comment->comment_post_ID );
echo $post->post_title;
}
The problem with this approach is the list of posts will contain duplicate post titles if a post has more than one comment.
How can I remove the duplicates?
UPDATE:
This initial approach does a lot of unnecessary legwork. For example, on sites that have lots of posts and comments, the query will pull back lots of unnecessary comments.
UPDATED QUESTION:
How can I order a list of posts by comment date?

This is an interesting approach...but, I suppose you could just fill an array with post ID's and then check them later.
$args = ....
$ids = array();
.....
if(!in_array($post->ID, $ids):
$ids[] = $post->ID;
echo $post->title;
endif;

Related

Wordpress: echo TOTAL amount of posts for post author by meta_key?

Ok, so I know how to echo meta_key value for a post:
<?php
$meta_print_value=get_post_meta(get_the_ID(),'_heart_this',true);
echo($meta_print_value);
?>
I also know how to echo a TOTAL amount of posts with this specific meta_key:
<?php $query = new WP_Query( array( 'meta_key' => '_heart_this' ) )
echo $query->found_posts; ?>
What I need, is the TOTAL amount of posts for this meta_key for a post author.
I know I need to add get_the_author() somewhere in the above code to show the total amount of posts for the post author only, but struggling for a while now.
Any help would be appreciated.
Use Author Parameters in WP_Query(). You can use author id/name/multiple authors. For your case, the query should look like this:
<?php
$query = new WP_Query(
array(
'author' => get_the_author_meta( 'ID' );
'meta_key' => '_heart_this',
),
);
echo $query->found_posts; ?>

Wordpress query that sorts by category and time

I have found this question:
Wordpress outside loop sort by category and time
But there is not a lot of context provided in the question or answer to know if it is applicable to me. I am using the popular genesis framework and a child theme. I don't want to modify any core WP files because they would be overwritten on updates. I think this can be done through my functions.php or front-page.php file.
I have 25 posts listed at a time. Within those 25 posts, I would like to have any post that is from category one be listed on top and those from category two listed afterwards. Within the category one and category two loops, the posts would be listed by time of entry as normal.
What would be the best way to do this?
SDS
You need two loop one for categories and one for posts.
So you can try this type of code
/*category args for listed according to name in assending order*/
$category_arg = array(
'orderby' => 'name',
'order' => 'ASC'
);
$all_cat = get_categories($category_arg);
/*Loop for all category*/
foreach ($all_cat as $key => $cat) {
/*Query for post of perticular category with orderby posted date*/
$args = array(
'cat' => $cat->cat_ID,
'posts_per_page' => -1,
'orderby' => 'date',
'order' => 'DESC',
) ;
query_posts( $args );
echo '
<div class="one-category-block">
<h1>'.$cat->cat_name.'</h1>';
echo '<ul>';
while ( have_posts() ) : the_post();
echo '<li>';
the_title();
echo '</li>
';
endwhile;
echo '</ul>
</div>';
wp_reset_query();
}
Try this type of code , then let me know the result.
Thanks
All right. You won't be able to do that on the query directly, I'm afraid.
However, it's still easy to do. First, get the posts out of the query into an array:
$posts = array();
while ( have_posts() ) {
the_post();
array_push($posts, $post);
}
Then sort that array:
usort($posts, function($a, $b) {
if(has_term("mycategory", "mytaxonomy", $a->ID) && !has_term("mycategory", "mytaxonomy", $b->ID)) return -1;
if(!has_term("mycategory", "mytaxonomy", $a->ID) && has_term("mycategory", "mytaxonomy", $b->ID)) return 1;
return $b->post_date - $a->post_date;
});
I've made it so that posts having mycatgegory in the mytaxonomy taxonomy will be on top, but generally sorted by post date.
Then just use a regular foreach loop to iterate over the (now sorted) posts
foreach($posts as $post) {
setup_postdata($post);
// continue outputting the posts here
}
wp_reset_postdata();
setup_postdata() is there to make sure that you can use get_the_ID(), get_permalink() et cetera without changing your code.

A complicated query combining a WP Courseware function, ACF repeater fields and a meta_query looking for a particular template file

I have a pretty complicated query that I have not been able to get to work the way I need it to.
I have a Wordpress install using the plugins WP Courseware and ACF. I need to display a page of courses associated with the current user. I want the links to lead the user to the course "home" pages that the user should hit prior to starting the course. I have created course "home" pages, but the problem is WP Courseware has no way to associate a page with a course. So I had to use an ACF options repeater that associates the course ID with whatever course pages are necessary. The only way I know that one of those associated pages is the course "home" page is by the template I use for course home pages.
So the loops within loops need to first determine what courses the current user has access to, get those course IDs, loop the ACF options repeater to find the pages associated with those course IDs, then of those pages loop to find out which one (there is only one per course) uses the course home page template. This last loop I discovered needs to be a WP_Query loop as that's the only way to query for a Wordpress template.
I am lost in loops and I'm having the hardest time. I thought it might be simpler and most direct to use the WP_Query to query an array meta_queries of both the Wordpress template and the ACF repeater (to determine is the ACF repeater course ID matches the course ID the user has access to) but my attempts at querying ACF repeater sub fields is not working.
Here's my code:
$user = wp_get_current_user();
$user_id = $user->ID;
$user_course_list = WPCW_users_getUserCourseList($user_id);
$course_association_arr = get_field('course_association', 'option');
// Loop through user's courses
foreach ( $user_course_list as $user_course ) :
$course_id = $user_course->course_id;
$course_title = $user_course->course_title;
// Loop through the ACF course ID/page associations
foreach ( $course_association_arr as $course_association ) :
$assoc_course_id = $course_association['wp_courseware_id'];
if ( $course_id == $assoc_course_id ) :
// Loop through the ACF associated pages
foreach ( $course_association['associated_pages'] as $associated_page ) :
$page_id = $associated_page->ID;
$page_url = $associated_page->guid;
echo '<li>'. $course_title . '</li>';
endforeach;
endif;
endforeach;
endforeach;
This displays all pages associated with a user's courses, not just the ones using the course home template. I somehow have to incorporate a WP_Query with these args in there and nothing I have done has worked:
$args = array(
'post_type' => 'page',
'meta_query' => array(
array(
'key' => '_wp_page_template',
'value' => 'page-course-home.php',
),
)
);
If I could somehow turn the WP query into an if statement (if template = page-course-home.php) I could have that inside the associated pages query to only show course home pages. Or there maybe another more brilliant way to do what I need to do. I appreciate all feedback.
Ok I got something to work! I think spending so much time framing the question here helped me see one way I could do it:
$user = wp_get_current_user();
$user_id = $user->ID;
$user_course_list = WPCW_users_getUserCourseList($user_id);
$course_association_arr = get_field('course_association', 'option');
// Loop through user's courses
foreach ( $user_course_list as $user_course ) :
$course_id = $user_course->course_id;
$course_title = $user_course->course_title;
// Loop through the ACF course ID/page associations
foreach ( $course_association_arr as $course_association ) :
$assoc_course_id = $course_association['wp_courseware_id'];
if ( $course_id == $assoc_course_id ) :
// Loop through the ACF associated pages
foreach ( $course_association['associated_pages'] as $associated_page ) :
$page_id = $associated_page->ID;
$page_url = $associated_page->guid;
$args = array(
'post_type' => 'page',
'page_id' => $page_id,
'meta_query' => array(
array(
'key' => '_wp_page_template',
'value' => 'page-course-home.php',
),
)
);
$course_assoc_pages = new WP_Query( $args );
if( $course_assoc_pages->have_posts() ) :
while ( $course_assoc_pages->have_posts() ) : $course_assoc_pages->the_post();
echo '<li>'. $course_title . '</li>';
endwhile;
endif;
wp_reset_query();
endforeach;
endif;
endforeach;
endforeach;
This seems a bit cumbersome, but it works. I'm not sure if it would be better but it seems more elegant to incorporate the ACF subfield query into the meta query, so could eliminate two of the loops. If anyone has any thoughts on this I would love to hear them.

WooCommerce Display Purchased Items Only

So I have done a bunch of looking around the web and couldn't find a solution for this...
Basically what I am trying to do is display a product loop of all the products the user has purchased in the store just like displaying normal products.
If you still don't understand maybe this will help you get what I mean..
Here is the example product loop on the WooCommerce documentation...
<ul class="products">
<?php
$args = array(
'post_type' => 'product',
'posts_per_page' => 12
);
$loop = new WP_Query( $args );
if ( $loop->have_posts() ) {
while ( $loop->have_posts() ) : $loop->the_post();
woocommerce_get_template_part( 'content', 'product' );
endwhile;
} else {
echo __( 'No products found' );
}
wp_reset_postdata();
?>
</ul><!--/.products-->
So what if I wanted to display basically this same exact product loop however filter it out so that it only displays products that the user has already purchased.
I honestly do not know where to go with this one and I am sure there are others that have done research on this in the past so maybe this will help out a bunch of people!
Thanks in advance!
There are at least two different approaches you can take to solve this problem.
The first is to get the product from each post, and then get the product ID from each product and then use an if statement to filter using wc_customer_bought_product or woocommerce_customer_bought_product (if you are using old WooCommerece).
The second is to pass the correct arguments to filter the WP_Query to only include orders purchased by a user and then filter products only in those orders. More information on the second approach is available at Get All User Orders and Products bought by user in WooCommerce based shop (archive.org).
An example of the first approach is something like
<!-- code started -->
<ul class="products">
<?php
$user_id = get_current_user_id();
$current_user= wp_get_current_user();
$customer_email = $current_user->email;
$args = array(
'post_type' => 'product',
'posts_per_page' => 12
);
$loop = new WP_Query( $args );
if ( $loop->have_posts() ) {
while ( $loop->have_posts() ) : $loop->the_post(); $_product = get_product( $loop->post->ID );
if (wc_customer_bought_product($customer_email, $user_id,$_product->id)){
woocommerce_get_template_part( 'content', 'product' );
}
endwhile;
} else {
echo __( 'No products found' );
}
wp_reset_postdata();
?>
</ul><!--/.products-->
Kudos to Appleman1234 for providing two answers, both of which will work.
ApppleMan1234's first answer that he provided an example for is to loop through all products and then filter them by calling wc_customer_bought_product(). This certainly will work. If you have n products then you are going to make n+1 database queries.
His second suggestion is a link to a post written by Brajesh Singh who, on June 2, 2013, published a solution on fusedpress.com. The original post is no longer available. I found a cached copy at Google.
Brajesh Singh's solution queries the user's orders, then queries the order details, and last queries the product id in the order item's metadata. This solution then is always only 3 queries. Unless your shop only has 1 or 2 products, this solution is far better.
Here is a slightly edited version of Brajesh Singh's code.
/**
* Get all Products Successfully Ordered by the user
* #return bool|array false if no products otherwise array of product ids
*/
function so28362162_get_all_products_ordered_by_user() {
$orders = so28362162_get_all_user_orders(get_current_user_id(), 'completed');
if(empty($orders)) {
return false;
}
$order_list = '(' . join(',', $orders) . ')';//let us make a list for query
//so, we have all the orders made by this user that were completed.
//we need to find the products in these orders and make sure they are downloadable.
global $wpdb;
$query_select_order_items = "SELECT order_item_id as id FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id IN {$order_list}";
$query_select_product_ids = "SELECT meta_value as product_id FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE meta_key=%s AND order_item_id IN ($query_select_order_items)";
$products = $wpdb->get_col($wpdb->prepare($query_select_product_ids, '_product_id'));
return $products;
}
/**
* Returns all the orders made by the user
* #param int $user_id
* #param string $status (completed|processing|canceled|on-hold etc)
* #return array of order ids
*/
function so28362162_get_all_user_orders($user_id, $status = 'completed') {
if(!$user_id) {
return false;
}
$args = array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => $user_id,
'post_type' => 'shop_order',
'post_status' => 'publish',
'tax_query' => array(
array(
'taxonomy' => 'shop_order_status',
'field' => 'slug',
'terms' => $status
)
)
);
$posts = get_posts($args);
//get the post ids as order ids
return wp_list_pluck($posts, 'ID');
}
Combining that with a product loop from the question, plus a non-deprecated wc_get_template_part() and an addition of posts_per_page=-1 gives us
<ul class="products">
<?php
$args = array(
'post_type' => 'product',
'post__in' => so28362162_get_all_products_ordered_by_user(),
'posts_per_page' => -1
);
$loop = new WP_Query($args);
if($loop->have_posts()) {
while($loop->have_posts()) : $loop->the_post();
wc_get_template_part('content', 'product');
endwhile;
}
else {
echo __('No products found');
}
wp_reset_postdata();
?>
</ul><!--/.products-->
Not sure if this helps you out at all, but there is a plugin developed by WooThemes to support purchase history.

Wordpress - Show only posts with specific slug

I'm sure this is going to be a silly question... but here it goes.
I currently have a page that only displays posts of a Custom Post Type (car).
I do this by running a query
$args = array(
'post_type' => 'car');
$query = new WP_Query( $args );
On to the loop...
For this Custom Post Type i have a Custom Taxonomy e.g. Subaru, Honda etc...
I'm just trying to work something else out, but if I wanted to show only posts that are Subaru's, how would I query that?
I guess I want to query the 'slug' (subaru), this code doesn't work, but you can see the route I was heading...
$args = array(
'name' => 'subaru',
'post_type' => 'car');
$query = new WP_Query( $args );
On to the loop...
I know name isn't right. What is the correct term to add to my $args array?
Many thanks
Depends on what your taxonomy is called. In my example its called 'brands':
$args = array(
'post_type' => 'car',
'brand' => 'subaru'
);
$query = new WP_Query( $args );
see http://codex.wordpress.org/Class_Reference/WP_Query#Taxonomy_Parameters
What you're trying to do is a taxonomy query. I could tell you how to do that but I think it's important I point out a much bigger mistake first. You shouldn't querying this on a page.
That's what archives are for.
Create a template file called archive-car.php and output there instead. That removes the need to run a custom WP Query.
Then create another file taxonomy-{your-custom-taxonomy-name}.php
Output the cars there as well and your problem is solved without adding any inefficient queries.
I think you need to use get_terms()
$terms = get_terms("Subaru");
if ( !empty( $terms ) && !is_wp_error( $terms ) ){
echo "<ul>";
foreach ( $terms as $term ) {
echo "<li>" . $term->name . "</li>";
}
echo "</ul>";
}
See this http://codex.wordpress.org/Function_Reference/get_terms

Categories