Wordpress meta query - wordpress

I have created a theme with a custom post type of reports. I installed a rating plugin that interacts with this post type, allowing users to rate the reports. It stores the post rating in two fields, sum and count where sum is the total for all ratings, and count is the number of individual ratings.
Example: If a 5 people rated a post as 1, 2, 3, 4, and 5, the sum would be 15 and the count would be 5.
When a user visits the reports archive page, they see a list of all posts of the report post type. However, I want to add a query parameter to filter down to posts with an average rating of 4 or higher. I'm currently trying to use the pre_get_posts hook as follows:
add_filter( 'pre_get_posts', 'filterReports' );
function filterReports( $query ) {
if( is_post_type_archive( 'reports' ) && $_GET['top'] ) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT *
FROM
wp_postmeta AS sum
wp_postmeta AS count
WHERE
sum.meta_key = 'sum' AND
count.meta_key = 'count' AND
sum.meta_value / count.meta_value >= 4"
);
}
}
I'm not entirely sure how to construct my custom query in the above. Any advice would be greatly appreciated.

Use below code will work as per your scenario.
add_filter( 'pre_get_posts', 'filterReports' );
function filterReports( $query ) {
if( is_post_type_archive( 'reports' ) && $_GET['top'] ) {
$reports_meta_query = $query->get('meta_query');
//Add our meta query to the original meta queries
$reports_meta_query[] = array(
'key'=>'count',
'value'=> 4,
'compare'=>'>=',
);
$query->set('meta_query',$reports_meta_query);
// somehow construct a query that checks if sum / count >= 4
}
}

Pretty sure the query you are looking for is something like this:
SELECT
sum.post_id,
sum.meta_value,
count.meta_value,
(sum.meta_value / count.meta_value) as result
FROM
wp_postmeta sum
LEFT JOIN wp_postmeta count USING(post_id)
WHERE
sum.meta_key = 'sum' AND
count.meta_key = 'count'
HAVING
result >= 4
You are basically joining twice the same table based on the post_id, so you can then query by the meta_key of both sum and count, then you look for the result of your math in a Having clause to check if the result would be bigger than 4 as requested.
Hope with this you can get what you were looking for.
Cheers

Related

Override standard request processing for min and max price in WooCommerce filter to get products by price from custom field

The price of the item is recorded in the custom field $ custom_price of the table in the database, which has the item ID and price. Accordingly, when filtering by price on the category page, it filters only by the standard WooCommerce price field. I need to filter products in category by min and max price by custom price field, what is in custom table wp_product_prices. For example: I filtered products by price using woocommerce filter and got results on category page. The probem is: products don't showing because I using not standard field for price in my products https://prnt.sc/w60uj8 Found only the file https://github.com/woocommerce/woocommerce/blob/master/includes/class-wc-query.php, it has request processing by price, function price_filter_post_clauses ($ args, $ wp_query). Maybe there is some kind of hook for overriding or how you can implement it?
My custom prices table to products https://prnt.sc/w60t5p The field "product_id" is equal to product "ID" in wp_posts table.
for change query for min & max price use action "woocommerce_product_query" and deactivate standard filter 'posts_clauses'. Like this:
add_action('woocommerce_product_query', 'min_max_price_handler');
function min_max_price_handler($q) {
global $wpdb, $wp_query;
if (! $wp_query->is_main_query() || ( ! isset($_GET['max_price']) && ! isset($_GET['min_price']))) {
return;
}
// Remove default Woocommerce min/max price request handler
remove_filter('posts_clauses', [WC()->query, 'price_filter_post_clauses'], 10);
$current_min_price = isset($_GET['min_price']) ? floatval(wp_unslash($_GET['min_price'])) : 0;
$current_max_price = isset($_GET['max_price']) ? floatval(wp_unslash($_GET['max_price'])) : PHP_INT_MAX;
$sql = "SELECT DISTINCT product_id FROM wp_product_prices WHERE country=%s AND price >= %f AND price <= %f";
$results = $wpdb->get_results(
$wpdb->prepare(
$sql,
$customer_country,
$current_min_price,
$current_max_price
),
ARRAY_A
);
$results = array_column($results, 'product_id');
if (is_array($results)) {
$q->set('post__in', $results);
}
}

Count number of posts have particular meta key or value?

What I want to achieve is display the number of posts which have particular meta key or value I am getting a list of posts and meta key and value but don't know how to display them I'm storing data using repeatable fields. Storing work properly.
Now, for example, I have age meta value in two posts so how can I count no of a post with age. Age = No of post 2.
My Code :
global $wpdb;
$query = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}postmeta WHERE (meta_key = 'repeatable_fields') ");
$array = wp_json_encode($query);
print_r($array);
Outout :
[{"meta_id":"312","post_id":"108","meta_key":"repeatable_fields","meta_value":"a:2:{i:0;a:2:{s:4:\"name\";s:6:\"Zaheer\";s:5:\"phone\";s:3:\"123\";}i:1;a:2:{s:4:\"name\";s:6:\"Sageer\";s:5:\"phone\";s:11:\"09190219218\";}}"},{"meta_id":"323","post_id":"121","meta_key":"repeatable_fields","meta_value":"a:2:{i:0;a:2:{s:9:\"iif_label\";s:4:\"City\";s:11:\"iif_details\";s:7:\"karachi\";}i:1;a:2:{s:9:\"iif_label\";s:3:\"Age\";s:11:\"iif_details\";s:2:\"12\";}}"},{"meta_id":"329","post_id":"126","meta_key":"repeatable_fields","meta_value":"a:1:{i:0;a:2:{s:9:\"iif_label\";s:3:\"Age\";s:11:\"iif_details\";s:2:\"12\";}}"},{"meta_id":"332","post_id":"128","meta_key":"repeatable_fields","meta_value":"a:3:{i:0;a:2:{s:9:\"iif_label\";s:7:\"Country\";s:11:\"iif_details\";s:8:\"Pakistan\";}i:1;a:2:{s:9:\"iif_label\";s:4:\"City\";s:11:\"iif_details\";s:9:\"Islamabad\";}i:2;a:2:{s:9:\"iif_label\";s:3:\"Age\";s:11:\"iif_details\";s:2:\"12\";}}"}]
You could try something like this:
$count_age = $wpdb->get_col( $wpdb->prepare(
"
SELECT count(meta_id)
FROM {$wpdb->prefix}postmeta
WHERE meta_value LIKE '%%%s%%'
",
'Age'
));
More about get_col() here: https://codex.wordpress.org/Class_Reference/wpdb#SELECT_a_Column

wordpress exclude posts from loop if only has one specific category

I have this category which is "community-posts" I don't want it to appear on my homepage loop so I added this to my query
<?php query_posts(array('showposts' => 4,'category__not_in' => $id_communityposts,));?>
This is working fine with me but some "community-posts" I want them to be featured on the homepage loop. (exception)
so I want to only exclude the posts that has one category as "community-posts" if it has this category and more its shows normally.
First thing do not use query_posts - it should never be used as it alter the main query. Use get_posts instead - it's much safer and perform the same task.
To answer your question, let's first imagine how the query would look in SQL (assuming your $id_communityposts is equal to 2) :
SELECT DISTINCT wp_posts.*
FROM wp_posts, wp_postmeta
LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
LEFT JOIN wp_term_taxonomy ON (wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id)
WHERE
wp_posts.ID = wp_postmeta.post_id AND
(
(wp_term_taxonomy.taxonomy = 'category' AND wp_term_taxonomy.term_id NOT IN(2))
OR
(wp_postmeta.meta_key = 'featured' AND wp_postmeta.meta_value = 1)
)
ORDER BY wp_posts.post_date DESC
LIMIT 4
So we query the post, post meta and taxonomy tables and make two possible conditions:
The category ID is not 2, OR
The featured meta key of the post is set to 1 (change this to whatever key / value depending of how you store the "featured" information).
For that kind of specific cases, get_posts isn't really good to play with - querying the DB with WPDB will give you much more flexibility.
$posts = $wpdb->get_results(
"SELECT DISTINCT $wpdb->posts.*
FROM $wpdb->posts, $wpdb->postmeta
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)
WHERE
$wpdb->posts.ID = $wpdb->postmeta.post_id AND
(
($wpdb->term_taxonomy.taxonomy = 'category' AND $wpdb->term_taxonomy.term_id NOT IN(2))
OR
($wpdb->postmeta.meta_key = 'featured' AND $wpdb->postmeta.meta_value = 1)
)
ORDER BY $wpdb->posts.post_date DESC
LIMIT 4"
);
Let me know if you run into any issue as it is an untested query.
If I understood the question correctly , The simplest solution, not involving complicated SQL would be something along the lines of :
// NOT TESTED !
if ( count(get_the_category()) > 1 ) { // this means there are more than single category
// show the desired posts
} else {
// dont show
}
read get_the_category() in codex
Along the same logic lines you could also use wp_get_post_categories

WordPress > Getting Average Value of a Numerical Custom Field for Children of A Custom Post Type with a Given Post ID

The situation:
We have a custom post type, let's call it: 'cpt_parent'
We have another custom post type, which is a child of the aformentioned post type, let's call it 'cpt_child'
Our child custom post, 'cpt_child' has a custom field, let's call it 'cpt_child_numeric'
Our custom field 'cpt_child_numeric' holds only 1 value of 5 available values, 1, 2, 3, 5
What we want to do is get the average value of 'cpt_child_numeric' for a specific post_id of cpt_parent. For instance, say 'cpt_parent' has a post id of 33. For this id, we want to 1) count all child posts (cpt_child) 2) sum the value of 'cpt_child_numeric' for each 'cpt_child' post where the parent is ID 33 3) calculate the average.
What's tripping us up is that we don't want to do this within a loop, we want to be able to make the calculation by just having the parent post_id.
More than happy to clarify if need be
Thanks in advance!
You can use wordpress custom query to get all these results like below:
$postID = ''; // your parent post id
1) For getting count of child posts
$wpdb->get_results(" SELECT COUNT( columns_name ) FROM $wpdb->posts WHERE post_parent = $postID ");
2) For getting sum of child posts
$wpdb->get_results(" SELECT SUM( columns_name ) FROM $wpdb->posts WHERE post_parent = $postID ");
3) For getting averageof child posts
$wpdb->get_results(" SELECT AVG( columns_name ) FROM $wpdb->posts WHERE post_parent = $postID ");
I hope this is what you want.
Cheers!!!!

How to get certain posts in wordpress

I want to implement a function to get certain posts in wordpress.
INPUT
page_number
category_name
VARIABLE
items_per_page = 10
OUTPUT
posts array, like the result of the query_posts() function.
Here is my code:
$page_number = $_GET["page_number"]
$category_name = $_GET["category_name"]
function app_get_posts($page_number, $category,$items_per_page = 10)
{
global $wpdb;
$select ="SELECT POSTS FROM wp_posts WHERE CATEGORY = ".$category." LIMIT (".$page_number." - 1) * ".$items_per_page.",".$page_number." * ".$items_per_page; //it didn't work.
return $wpdb->query($select);
}
When I call the function app_get_posts('2','tech'), it will return the 10th~19th posts in the "tech" category, when I call app_get_posts('3','wordpress'), it will return the 20th~29th posts in the "wordpress" category.
So I am wondering if there is a way to figure out this problem.
Thx in advence.
I guess the reason why the above won't work is because the wp_posts table not has a CATEGORY or POSTS field. I modified you code so you can return posts based on taxonomy:
function app_get_posts($page_number, $category,$items_per_page = 10)
{
global $wpdb;
$start = ($page_number-1) * $items_per_page;
$select ="SELECT DISTINCT wp.* FROM wp_posts wp
INNER JOIN wp_term_relationships rs ON rs.object_id = wp.ID
INNER JOIN wp_terms t ON t.term_id = rs.term_taxonomy_id
WHERE t.name = ".$category." LIMIT ".$start.",".$items_per_page;
return $wpdb->query($select);
}

Resources