How to get certain posts in wordpress - 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);
}

Related

Get meta_value from GDRating

I am trying to get meta value from GD Rating table for each post ID with following sql:
$querystr = "SELECT meta_value FROM $wpdb->gdrts_itemmeta WHERE meta_key LIKE 'stars-rating_rating'";
$ratings = $wpdb->get_results($querystr);
foreach ($ratings as $rating)
{
$rating->meta_value;
}
$ratingku = get_post_meta($post->ID, $rating, true);
But it failed. It return a word: "ARRAY".
How to get meta_value from another table (created by a plugin) for each post by using SQL or Query?
To get the rating value for the post use below query:
global $wpdb;
$querystr = "SELECT meta_value AS rating FROM ".$wpdb->prefix."gdrts_itemmeta INNER JOIN ".$wpdb->prefix."gdrts_items ON ".$wpdb->prefix."gdrts_items.item_id = ".$wpdb->prefix."gdrts_itemmeta.item_id AND ".$wpdb->prefix."gdrts_itemmeta.meta_key = 'stars-rating_rating' AND ".$wpdb->prefix."gdrts_items.id = ".$post->ID;
$result = $wpdb->get_row($querystr);
echo $result->rating;

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

Woocommerce Vendors Set Selling Locations and Manipulate Product Query Loop

I want to only list products that can be shipped to a customer based on their location set in billing/shipping address. (All my users are logged in)
Each of my vendors may ship to certain countries only so I don't want to show products to a user that cannot be shipped to them.
To tackle this problem I have added an extra field in the edit vendor page which saves the countries (via multi select box) they can ship to as a separate term meta.
update_term_meta($term_id, 'vendor_data_shipping_countries', $selected_shipping_countries);
etc...
All that data saves fine and is outputted as follows when I call get_term_meta($term->term_id, 'vendor_data_shipping_countries')[0].
Array
(
[0] => FR
[1] => GB
)
What I am having trouble with now is filtering the product loop query to only show products that can be shipped to the user with the action 'woocommerce_product_query'.
function ac_vendor_show_deliverable_products($query)
{
// magical query filter here...
// if users location matches any of the vendor products ship to countries then output the product to the user
// $query->set(); ... something...
}
add_action('woocommerce_product_query','ac_vendor_show_deliverable_products');
This is where my skill level fails me. I am fairly new to WC and not good at manipulating the query with actions. Better at just writing the full SQL but feel I would mess lots of other things up and filtering is the best way to go.
I expect someone's kunfu is way stronger than mine! Can anyone figure this out?
Hope someone can help.
UPDATE:
I have managed to write exactly what I want to happen in SQL
SELECT SQL_CALC_FOUND_ROWS wp_posts.* FROM wp_posts
LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
LEFT JOIN wp_term_taxonomy ON (wp_term_taxonomy.term_taxonomy_id = wp_term_relationships.term_taxonomy_id)
LEFT JOIN wp_termmeta ON (wp_termmeta.term_id = wp_term_taxonomy.term_id)
WHERE wp_termmeta.meta_key = 'vendor_data_shipping_countries'
AND wp_termmeta.meta_value LIKE '%"GB"%'
AND wp_posts.post_type = 'product'
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
GROUP BY wp_posts.ID
ORDER BY wp_posts.menu_order ASC, wp_posts.post_title ASC LIMIT 0, 12
This only lists products that have added GB as a country they can ship to.
Note the meta_value is stored as a serialized array so the easiest way to match was to perform a LIKE as values are stored as a:2:{i:0;s:2:"FR";i:1;s:2:"GB";} for example.
If anyone can figure out how to put that SQL into the woocommerce_product_query hook then that would be amazing. But I can't for the life of me figure out how this is possible...
Everything on https://codex.wordpress.org/Class_Reference/WP_Query just adds SQL for wp_postmeta not wp_termmeta from what I can see.
Cheers
I managed to get this to work by using the posts_join and posts_where filters instead.
I hope this helps someone else down the line.
/*
* Add the needed term tables
*/
function ac_vendor_sql_join_term_meta($join)
{
global $wp_query, $wpdb;
//only do this is WC product query
if(isset($wp_query->query_vars['wc_query']) && $wp_query->query_vars['wc_query'] == 'product_query')
{
$join .= ' LEFT JOIN '. $wpdb->term_relationships .' tr1 ON (tr1.object_id = '. $wpdb->posts .'.ID)';
$join .= ' LEFT JOIN '. $wpdb->term_taxonomy .' tt1 ON (tt1.term_taxonomy_id = tr1.term_taxonomy_id)';
$join .= ' LEFT JOIN '. $wpdb->termmeta .' tm1 ON (tm1.term_id = tt1.term_id)';
}
return $join;
}
add_filter('posts_join', 'ac_vendor_sql_join_term_meta');
/*
* Add the needed where statements
*/
function ac_vendor_sql_filter_shipping_where($where, $wp_query)
{
//only do this is WC product query
if(isset($wp_query->query_vars['wc_query']) && $wp_query->query_vars['wc_query'] == 'product_query')
{
//get the users billing country code.
if(is_user_logged_in())
{
$billing_country = get_user_meta(get_current_user_id(), 'billing_country', TRUE);
}
else //default to IP location
{
$geo_locate = WC_Geolocation::geolocate_ip($_SERVER['REMOTE_ADDR']);
$billing_country = $geo_locate['country'];
}
$where .= " AND tm1.meta_key = 'vendor_data_shipping_countries'";
$where .= " AND tm1.meta_value LIKE '%\"". $billing_country ."\"%'";
}
return $where;
}
add_filter('posts_where', 'ac_vendor_sql_filter_shipping_where', 10, 2);

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

Delete posts with custom field date older than current date via cronjob

I want to make a cron job witch deletes all posts older than the date in a custom field of the post. I got following function within my functions.php My custom field name is bewerbungs_frist.
function foobar_truncate_posts(){
global $wpdb;
$currenttime = new DateTime();
$currenttime_string = $currenttime->format('Ymd');
# Set your threshold of max posts and post_type name
$post_type = 'job';
# Query post type
$query = "
SELECT ID FROM $wpdb->posts
WHERE post_type = '$post_type'
AND post_status = 'publish'
ORDER BY post_modified DESC
";
$results = $wpdb->get_results($query);
# Check if there are any results
if(count($results)){
foreach($results as $post){
$customfield = get_field('bewerbungs_frist', $post->ID);
$customfield_object = new DateTime($customfield);
$customfield_string = $customfield_object->format('Ymd');
if ( $customfield_string < $currenttime_string ) {
echo "The value of the custom date field is in the past";
echo $customfield_string;
$purge = wp_delete_post($post->ID);
}
}
}
}
foobar_truncate_posts();
I use a plugin to handle my cronjobs. The Hock name is: foobar_truncate_posts and Arguments is []
The cronjob works but it does not delete those post with the date of the customfield older than todays date. The two variables are the same.
$currenttime_string 20130820
$customfield_string 20130820
there's a typo in your code, you're missing an 's' at the end of $result.
This:
foreach($result as $post){
Should be this:
foreach($results as $post){
I just tried it out. Once you make that fix the wp_delete_post() works great.
EDIT
I'm really unclear on what you're trying to do. You want to check if the custom field is set to some time in the past? What purpose does the continue serve? Also, I'm guessing you're using Advanced Custom Fields (ACF). Using the jquery Date Picker, you can format your date to Ymd by default so you don't have to convert it to a DateTime object.
At any rate, this function should explain how to properly set and compare time values, you should be able to take it from there:
function foobar_truncate_posts(){
global $wpdb;
$currenttime = new DateTime();
$currenttime_string = $currenttime->format('Ymd');
# Set your threshold of max posts and post_type name
$post_type = 'post_type_job';
# Query post type
$query = "
SELECT ID FROM $wpdb->posts
WHERE post_type = '$post_type'
AND post_status = 'publish'
ORDER BY post_modified DESC
";
$results = $wpdb->get_results($query);
# Check if there are any results
if(count($results)){
foreach($results as $post){
$customfield = get_field('bewerbungs_frist', $post->ID);
$customfield_object = new DateTime($customfield);
$customfield_string = $customfield_object->format('Ymd');
if ( $customfield_string < $currenttime_string ) {
echo "The value of the custom date field is in the past";
$purge = wp_delete_post($post->ID);
}
}
}
}
foobar_truncate_posts();

Resources