Wordpress count_posts() equivalent function non-expensive method - php

I'm looking to count the number of posts in the last week then group them by a custom taxonomy called 'topic' So that in the next get_posts equation I can get topics by the number of posts to that area in the last week.
It can be done like this with get posts, but I am concerned that this is unnecessarily expensive on the server. Is there another way?
function count_posts_by_taxanomy($since,$taxonomy){
global $sincer;
$sincer = $since;
function filter_post_count($where = ''){
global $sincer;
$where .= " AND post_date > '" . date('Y-m-d', strtotime($sincer)) . "'";
return $where;
}
$args = array(
'numberposts' => -1,
'post_type' => 'post',
'suppress_filters' => false
);
add_filter('posts_where','filter_post_count');
$posts = get_posts($args);
remove_filter('posts_where','filter_post_count');
$count_term = array();
foreach($posts as $post){
foreach(get_the_terms($post->ID,'topic') as $term){
$count_term[$term->slug] += 1;
}
}
print_r($count_term);
}
Called like this:
count_posts_by_taxanomy('-5 days','topic');

You would be better using a custom database query. See here for more info on that: http://codex.wordpress.org/Class_Reference/wpdb
I would then suggest you store the result in a transient. You don't need to run the query on every load.
http://codex.wordpress.org/Transients_API

You can use WP_Query and call $wp_query->found_posts to find count of posts. And then do a loop and cache values.
More at : http://codex.wordpress.org/Class_Reference/WP_Query
$query = new WP_Query( array('posts_per_page'=>-1,
'post_type'=>array('post'),
'date_query' => array(array('after' => 'YOUR DATE')),
'tax_query' => array(
array(
'taxonomy' => 'YOUR TAX'
))));

Related

How to check if wp_query results found any custom post_type?

In my WordPress v5.8.1, I have the below query in taxonomy.php to get the list of posts.
$args = array(
'post_type' => array('song', 'dance'),
'post_status' => 'publish',
'posts_per_page' => 10,
);
query_posts($args);
The query return posts from both post_type's.
I would like to create a menu in the same page, where I want to check if the query results has found posts from a specific post_type. The menu looks something like this.
This taxonomy has posts from Song, Dance (if found posts from both post_type's), or
This taxonomy has posts from Song (if found posts from Song post_type only)
Have tried the below within the loop:
$song_count = wp_posts_count('song')->found_posts;
$dance_count = wp_posts_count('dance')->found_posts;
if ($song_count=>0 {
/** code goes here **/
}
Above is returning the count from entire WordPress, not just from current taxonomy.
You can stock result in variable, but did I understand the question correctly?
$args = array(
'post_type' => array('song', 'dance'),
// or 'post_type' => get_post_type($post->ID),
// conditions are no longer necessary
'post_status' => 'publish',
'posts_per_page' => 10,
);
$results = query_posts($args);
if($results) {
$count = 0;
$current_post_type = get_post_type($post->ID);
$current_post_type_name = get_post_type_object(get_post_type())->labels->singular_name); // ajust with 2 variables for multiple results
foreach($results as $result) {
// if request is in a single custom post
if($result->post_type == $current_post_type) {
$count++;
}
}
if($count > 0) {
echo $count . $current_post_type_name;
}
}
else {
// no results
}

Woocommerce how to display relevant tags under category title

I want to display meta tags under each category title. I can see there is this code to display product tag lists for each product, but what I really want is product tags for each category and then display it under the category title in the page.
<?php
global $product;
?>
<div class="product-tags">
<?php
echo wc_get_product_tag_list( $product->get_id(), ', ' );
?>
</div>
Example screenshot:
Well, you already know/have the category name (i.e 'Coffee Equipment'), so you could use that to get the relevant tags, but in order to do so, we'll create a function in the functions.php of your active theme, like so:
The following code goes to your functions.php file of your active theme:
function your_theme_get_tags_based_on_cat($cat_name)
{
$cat_id = get_cat_ID($cat_name);
$tag_query = new WP_Query(array(
'post_type' => 'product',
'posts_per_page' => -1,
'post_status' => 'publish',
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'term_id',
'terms' => $cat_id,
'operator' => 'IN'
)
)
));
$all_tags = array();
while ($tag_query->have_posts()) {
$tag_query->the_post();
$producttags = get_the_tags();
if ($producttags) {
foreach ((array)$producttags as $tag_obj) {
$all_tags[] = $tag_obj->term_id . '-' . $tag_obj->name;
}
}
};
$tags_array = array_unique($all_tags);
$new_array = array_map(function ($val) {
return explode("-", $val);
}, $tags_array);
return new_array;
}
The function above will return an associative array containing tag id and tag name of the corresponding tags of your PRODUCT category.
Side Note:
if you need to use it for the blog posts of your wordpress site, then you could change/modify the query by swapping 'post_type' => 'product' argument with 'post_type' => 'posts'. So your query for blog posts would be something like this:
$blog_tag_query = new WP_Query(array('post_type'=>'post','post_status' =>'publish','cat'=>$cat_id,'posts_per_page'=>-1));
If you decide to use it for your blog posts, also remember to change the get_term_link((int)$tag[0], 'product_tag') with get_term_link((int)$tag[0], 'post_tag') in your template.
Now you have a magical function :) that you can use anywhere that you need a list of tags for a specific category!
So let's use our function in your page template to populate the corresponding tags for the current category, like so:
$cat_name = 'Coffee Equipment';
$tags_array = your_theme_get_tags_based_on_cat($cat_name);
foreach ($tags_array as $tag)
{
echo '<a class="item" href="' . get_term_link((int)$tag[0], 'product_tag') . '">' . $tag[1] . '</a>';
};
Just tested and it works seamlessly fine! Feel free to customize it as needed on your html template/markup.

Add incremental parameter value to each post in wordpress query loop

I'm trying to combine several loops into one and sort the final results by relevance.
For the former part, I did this:
// set the variables
$author_id = get_the_author_meta('ID');
$tags_id = wp_get_post_tags($post->ID);
$first_tag = $tags_id[0]->term_id;
$categories_id = wp_get_post_categories($post->ID);
// loop for same author
$by_author = new WP_Query (array(
'author' => $author_id,
'posts_per_page' => '5'
));
// add ids to array
if ($by_author->have_posts()) {
while ($by_author->have_posts()) {
$by_author->the_post();
$add[] = get_the_id();
}
}
// loop for same tag
$by_tag = new WP_Query(array(
'tag__in' => $first_tag,
'posts_per_page' => '5'
));
// add ids to array
if ($by_tag->have_posts()) {
while ($by_tag->have_posts()) {
$by_tag->the_post();
$add[] = get_the_id();
}
}
// loop for same category
$by_category = new WP_Query(array(
'category__in' => $categories_id,
'posts_per_page' => '5'
));
// add ids to array
if ($by_category->have_posts()) {
while ($by_category->have_posts()) {
$by_category->the_post();
$add[] = get_the_id();
}
}
// loop array of combined results
$related = new WP_Query(array(
'post__in' => $add,
'post__not_in' => array($post->ID),
'posts_per_page' => '10',
'orderby' => $weight[$post->ID],
'order' => 'DESC'
));
// show them
if ($related->have_posts()) {
while ($related->have_posts()) {
$related->the_post();
// [template]
}
}
This is working nicely combining the loops into one. For the latter part, what I'm trying to do next is to add an incremental "weight" value to each post as they come up so as to later sort them with something like 'orderby' => $weight,.
For example, if a post comes up in "same author" it gets 3 points, if another one comes up in same tag it gets 2 points and so on. If it comes up in more than one loop, it should get the combined points i.e. 3+2+1=6 hence be boosted to the top of the final query.
I have tried to add a counter to each preliminary loop, like $weight = +3 etc, but this only adds everything up for every post, not individually.
I also tried inserting something like this at the end of each preliminary loop...
$weight = 0;
if ($by_author){
foreach ($by_author as $post){
setup_postdata($post);
$weight = +10;
add_post_meta($post->ID, 'incr_number', $weight, true);
update_post_meta($post->ID, 'incr_number', $weight);
}
}
... and this to the final one
echo get_post_meta($post->ID,'incr_number',true);
But it still doesnt do it right. It assigns a global value, while I want them to be different depending on the actual main posts one is reading.
So is there a way to do this?
If I understand your question right, I think your last solution was close. Instead of a global $weight parameter, however, I think you need to build an array of $weights that's unique to each post:
$weights[$post.id] += 10;
Then, you could sort that array and get your most heavily weighted post IDs from there.

How do i check if a wordpress query has more posts?

So i am using ajax to filter and load posts into a container. I want to limit the amount of posts to 6 at a time and add a load more button underneath if there are more than 6 posts, but i don't want to add pages because i have a few containers on the same page that i'm using this same treatment for and my understanding is pages would add a /page-1 or something like that to the url (am i wrong?).
Either way, i just want to know how to check if there are more posts that fit this criteria so i can show the load more button, and then when the load more button fires how do i just load 6 more. Do i have to keep a page variable somewhere? or is there another smarter way.
Here is my query
function ajax_filter_get_posts( $category, $tag )
{
$category = $_POST['category'];
$tag = $_POST['tag'];
if($category)
{
$category_args = array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => $category
);
}
$args = array(
'posts_per_page' => 6,
'post_status' => 'publish',
'tag' => implode(",",$tag),
'tax_query' => array(
$category_args,
),
'category__in' => array(187,186,183,182,184),
);
$query = new WP_Query( $args );
if ( $query->have_posts() ) : while ( $query->have_posts() ) : $query->the_post();
$output = post_factory($post);
$result['response'][] = $output;
$result['status'] = 'success';
endwhile; else:
$result['response'] = '<h2>No posts found</h2>';
$result['status'] = '404';
endif;
$result = json_encode($result);
echo $result;
die();
}
I know this post is about a year old, but in case anyone else needs an answer, here's the solution I'm implementing. I'm using Ajax to pull in a wp_query from a PHP file. The output from that file replaces the content of a div on my page. This is only the relevant code, not my complete code.
On click of the load more button, I use jQuery to count the number of posts on the page and put that count into a variable. Posts have a unique class assigned to them.
current = $('.item').length;
I send the post count to the PHP file using Ajax.
$.get(functions_home.url, { offset: current }, function(data) {
$('.grid').html(data);
}
I pull the post count from jQuery into a variable in the PHP file, and then use that variable to set the wp_query "offset" in $args.
$offset = $_GET['offset'];
$args = array (
'offset' => $offset
);
Once the query ($query) runs, I use $query->found-posts to tell me the total number of relevant posts, and I put that in a variable.
$total = $query->found_posts;
I make a div in my PHP file and use the found posts variable so that it's populated with the total number of relevant posts. I use CSS to hide that div, so that it's never visible on the website.
<div id="total"><?php echo $total; ?></div>
#total {
display: none;
}
I use jQuery to find that div on the page, and get the text from it, which is the total number of relevant posts. I put that in a variable.
total = $('#total').text();
I use jQuery to check whether the number of posts on the page is equal to the total number of posts, and, if it is, I hide the load more button. For my particular situation, I check in both the initial Ajax load and the Ajax call that fires when the load more button is clicked.
current = $('.item').length;
total = $('#total').text();
if ( current == total ) {
$('.load-more').css({
display: 'none'
});
}
I don't know if this is the best solution, or even a good solution, but it's what I've figured out to do, and it's working for me so far.
WP_Query has a parameter max_num_posts which will tell you how many pages in total the query have.
Inside the callback function you can check if there any more pages left in a query and send the value in response. Than you will be able to hide/show "load more" button with JS function based on that value. You can something similar to this:
function ajax_filter_get_posts( $category, $tag, $paged = 1 )
{
$paged = $_POST['paged']; // Pass a number of a page that you want to retrieve. Default is page #1
$category = $_POST['category'];
$tag = $_POST['tag'];
if($category)
{
$category_args = array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => $category
);
}
$args = array(
'posts_per_page' => 6,
'paged' => $paged, // pass required page number to WP_Query
'post_status' => 'publish',
'tag' => implode(",",$tag),
'tax_query' => array(
$category_args,
),
'category__in' => array(187,186,183,182,184),
);
$query = new WP_Query( $args );
if ( $query->have_posts() ) : while ( $query->have_posts() ) : $query->the_post();
$output = post_factory($post);
$result['response'][] = $output;
$result['status'] = 'success';
endwhile; else:
$result['response'] = '<h2>No posts found</h2>';
$result['status'] = '404';
endif;
// Check if there are any more pages to query and pass the boolean value in response
$result['more_pages'] = ( ( $query->max_num_pages - $paged ) > 0 ) ? true : false;
$result = json_encode($result);
echo $result;
die();
}

Concatenate two meta keys?

I have a school timetable as a custom post type. Each post is a school class with a post meta box containing two text fields for specifying the hour and minute that a class starts in 24-hour time format:
_start_hour
_start_minute
I am trying to output the posts in order according to time e.g.
// the args
$args = array(
'post_type' => 'my-cpt',
'meta_key' => '???????',
'orderby' => 'meta_value_num',
'order' => 'ASC',
'posts_per_page' => -1,
);
// The Query
$the_query = new WP_Query( $args );
while ( $the_query->have_posts() ) : $the_query->the_post();
// ordered output according to time
endwhile;
In 'meta_key' is there some way I can concatenate the two meta keys?
I have tried 'meta_key' => '_start_hour' && '_start_minute' but this breaks the query.
Unfortunately no, wordpress doesn't support this feature, you will have to sort it by yourself after fetching it from the database and before the loop.
Disclaimer note
This is extremely ugly by design, but this is Wordpress so you have to play with what you get, you can make it less ugly if you fallback to writing the SQL queries yourself, depends on performance in my opinion, as Wordpress can be a performance degrader beast if not handled properly you should consider making it with SQL queries instead.
// Fetch all posts - (1 SQL Query)
$query = new WP_Query(array(
'post_type' => 'my-cpt',
'order' => 'ASC',
'posts_per_page' => -1,
));
foreach ($query->posts as &$post) { // N queries as the number of posts you have - totally inefficient
$post->meta = get_post_meta($post->ID);
}
usort($query->posts, function($a, $b) {
$a_time = strtotime($a->meta['_start_hour'][0] . ':' . $a->meta['_start_minute'][0]);
$b_time = strtotime($b->meta['_start_hour'][0] . ':' . $b->meta['_start_minute'][0]);
if ($a_time > $b_time)
return 1;
else if ($a_time < $b_time)
return -1;
else
return 0;
}); // Sorting by date
... the_loop ...
note that this is totally untested so it should just give you pointers on hour should you do it, and again I say, you should refactor this to join the meta keys in advance, that way you can perhaps already sort it with the SQL instead of the PHP...

Categories