Wordpress custom SQL to fecth three posts with given meta values - mysql

I have bunch of custom post type footer elements with a meta key footer_element_meta_alignment. Now, I'm trying to fetch three latest posts, which meta_values are 1, 2 and 3. So, one post with each of those values.
How can I achieve this with single SQL Query?
This is my SQL Query so far:
"SELECT wposts.*, meta1.meta_value
FROM $wpdb->posts wposts, $wpdb->postmeta meta1
WHERE 1=1
AND wposts.post_type = 'footer_element'
AND wposts.post_status = 'publish'
AND wposts.ID = meta1.post_id
AND meta1.meta_key = 'footer_element_meta_alignment'
AND (meta1.meta_value = 1 OR meta1.meta_value = 2 OR meta1.meta_value = 3)
ORDER BY meta1.meta_value ASC";
That however fetches all elements with given meta values, and not only the latest one.
ANSWER
Answered my own question.

After struggling few hours I found a solution for this.
SQL
"SELECT *
FROM ( SELECT p.*, m.meta_value AS meta
FROM $wpdb->posts AS p
LEFT JOIN $wpdb->postmeta AS m
ON p.ID = m.post_id
WHERE m.meta_key = 'footer_element_meta_alignment'
AND p.post_status = 'publish'
ORDER BY m.meta_value ASC, p.post_date DESC) AS h
GROUP BY meta";

Fixed (I hope).
SELECT wposts.* FROM $wpdb->posts wposts WHERE
wposts.post_type = 'footer_element'
AND wposts.post_status = 'publish'
AND wposts.ID IN
(SELECT max(meta1.post_id) FROM $wpdb->postmeta meta1
WHERE meta1.meta_value = 1 OR meta1.meta_value = 2 OR meta1.meta_value = 3
GROUP BY meta1.meta_value)

Related

Querying WordPress DB from normal sql

Disclaimer: I am not going to use any other ways I have a specific requirement.
All I want is to Join from posts table to the posts meta so that I can get the featured image per post. I am able to get the post via where clause post type is post and published but I don't know how to write join for MySql to get the featured image of each post
You may try something like this:
$sql = "
SELECT $wpdb->posts.*
FROM $wpdb->posts, $wpdb->postmeta
WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id
AND $wpdb->posts.post_status = 'publish'
AND $wpdb->posts.post_type = 'post'
ORDER BY $wpdb->posts.post_date DESC
";
// Get an array of objects
$posts = $wpdb->get_results($sql, OBJECT);
You may check more here.
If someone else is still looking for the sql needed here you go
SET #term = "someterm"
SELECT DISTINCT
posts.id,
posts.post_author,
posts.post_title,
posts.post_date,
LEFT(posts.post_content,300) post_content,
wpmeta.meta_value thumbnail
FROM wp_posts posts
INNER JOIN wp_postmeta wpm ON posts.id = wpm.post_id
INNER JOIN wp_postmeta wpmeta ON wpm.meta_value = wpmeta.post_id
LEFT JOIN wp_term_relationships rel ON rel.object_id = posts.ID
LEFT JOIN wp_term_taxonomy tax ON tax.term_taxonomy_id = rel.term_taxonomy_id
LEFT JOIN wp_terms t ON t.term_id = tax.term_id
WHERE
post_status = 'publish'
AND posts.post_type = 'post'
AND wpm.meta_key = '_thumbnail_id'
AND wpmeta.meta_key = '_wp_attached_file'
AND 1 =
CASE
WHEN #term IS NULL THEN 1
WHEN #term IS NOT NULL AND t.term_id = #term THEN 1
ELSE 0
END
ORDER BY post_date DESC

Get posts from all categories except one category

While searching, I want all posts from all categories except one category
This is my search query
SELECT * FROM wp_posts WHERE post_title like '%$search%' AND post_type = 'post' AND post_status = 'publish' ORDER BY post_date DESC
In this query, i don't want book category posts. when i search any keyword, need to display all posts except book category posts
Any help?
Try below :-
14 is the category id
$request = $wpdb->prepare("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)
WHERE ($wpdb->term_taxonomy.term_id <> 14
AND $wpdb->term_taxonomy.taxonomy = 'category'
AND $wpdb->posts.post_type = 'post'
AND $wpdb->posts.post_status = 'publish'
AND post_title like '%$search%'
AND post_date >= '" . date('Y-m-d').")");

MySQL left join needed on Wordpress database

I'm new to MySQL and ended up with this statement on a standard Wordpress database to get the latest articles.
However, the statement below requires that related rows are found in [wp_postmeta] to get the thumbnail belonging to the article.
However, some posts may not have a thumbnail but I still want to select those.
How can I alter the statement to not require a thumbnail value in [wp_postmeta]? I believe I need a left join clause, but don't know how to do it.
SELECT p.*, ( SELECT guid FROM wp_posts WHERE id = m.meta_value ) AS imgurl
FROM wp_posts p, wp_postmeta m
WHERE p.post_type = 'post'
AND p.post_status = 'publish'
AND p.id = m.post_id
AND m.meta_key = '_thumbnail_id'
ORDER BY post_date DESC
Try this with join and ON(p.id = m.post_id AND m.meta_key = '_thumbnail_id' )
SELECT DISTINCT p.*, ( SELECT guid FROM wp_posts WHERE id = m.meta_value LIMIT 1) AS imgurl
FROM wp_posts p
LEFT JOIN wp_postmeta m ON(p.id = m.post_id AND m.meta_key = '_thumbnail_id' )
WHERE p.post_type = 'post'
AND p.post_status = 'publish'
ORDER BY post_date DESC
Use this query it will fetch latest 5 post, you can increase the display limit.
$sql = " SELECT * FROM wp_posts p
WHERE p.post_type = 'post'
AND p.post_status = 'publish'
AND p.post_type = 'post'
ORDER BY p.post_date DESC
LIMIT 5";

MYSQL Query Joining Tables

Here is my query as is for a WP database.
$letters = $wpdb->get_col(
"SELECT DISTINCT LEFT(post_title,1) AS first_letter FROM $wpdb->posts
WHERE post_type = '$post_type' AND post_status = 'publish'
ORDER BY first_letter ASC"
);
It is a baby name database and I want to make a widget to separate male/female so I need to do a query like above but to get posts with only certain postmeta which below is the key and value I am looking for.
Key - spin2
Value - Male
How do I add this into the query since it is in a different table?
Thanks!
You just need to use an INNER JOIN:
SELECT DISTINCT LEFT(posts.post_title,1) AS first_letter
FROM $wpdb->posts AS posts
INNER JOIN $wpdb->postmeta AS meta
ON posts.ID = meta.post_id
WHERE posts.post_type = '$post_type'
AND posts.post_status = 'publish'
AND meta.meta_key = 'spin2'
AND meta.meta_value = 'Male'
ORDER BY first_letter ASC

Filter posts in a query if they have only one certain tag

Querying wordpress posts according to their tags can look like this (if I pieced it together correctly - I removed irrelevant parts from the query):
SELECT wposts.ID AS ID,
wposts.post_title, wposts.post_status, wposts.post_name,
tag_terms.term_id AS tag_id
FROM `wp_posts` AS wposts
INNER JOIN wp_term_relationships AS tag_term_relationships ON (wposts.ID = tag_term_relationships.object_id)
INNER JOIN wp_term_taxonomy AS tag_term_taxonomy ON (tag_term_relationships.term_taxonomy_id = tag_term_taxonomy.term_taxonomy_id AND tag_term_taxonomy.taxonomy = 'post_tag')
INNER JOIN wp_terms AS tag_terms ON (tag_term_taxonomy.term_id = tag_terms.term_id)
WHERE wposts.ID = '12345'
AND wposts.post_type = 'post'
AND wposts.post_status NOT LIKE 'private'
AND tag_terms.term_id = '55'
GROUP BY wposts.ID
ORDER BY wposts.post_date ASC
This should query all posts with tag id 55.
What I need to do is to filter out all posts that only contain this single tag, but no other tags.
So I want to show a post if it has the tags 23,34,55,67
But I don't want to show the post if it has the tag 55 (and no other tags).
Posts that do not contain this certain tag should be included in the query as well.
How do I do this?
Try adding HAVING condition between GROUP BY and ORDER BY:
...
GROUP BY wposts.ID
HAVING COUNT( tag_terms.term_id ) <> 1
OR MAX( tag_terms.term_id ) <> 55
ORDER BY wposts.post_date ASC
and change your WHERE condition to check only for post type and status.
Also if you don't select anything other than tag_id from wp_terms joining it is not necessary as you can just use term_id from wp_term_taxonomy.
If you want all the posts with a certain tag, then why have you specified the post ID in the query ?
This following query will show all posts with the given tag id
SELECT wposts.ID AS ID,
wposts.post_title, wposts.post_status, wposts.post_name,
tag_terms.term_id AS tag_id
FROM `wp_posts` AS wposts
INNER JOIN wp_term_relationships AS tag_term_relationships ON (wposts.ID = tag_term_relationships.object_id)
INNER JOIN wp_term_taxonomy AS tag_term_taxonomy ON (tag_term_relationships.term_taxonomy_id = tag_term_taxonomy.term_taxonomy_id AND tag_term_taxonomy.taxonomy = 'post_tag')
INNER JOIN wp_terms AS tag_terms ON (tag_term_taxonomy.term_id = tag_terms.term_id)
WHERE wposts.post_type = 'post'
AND wposts.post_status NOT LIKE 'private'
AND tag_terms.term_id = '55'
GROUP BY wposts.ID
ORDER BY wposts.post_date ASC
Now, if you want to make sure that these posts have only the given tag id, nest the query as follows :
SELECT wposts.ID AS ID,
wposts.post_title, wposts.post_status, wposts.post_name,
tag_terms.term_id AS tag_id
FROM `wp_posts` AS wposts
INNER JOIN wp_term_relationships AS tag_term_relationships ON (wposts.ID = tag_term_relationships.object_id)
INNER JOIN wp_term_taxonomy AS tag_term_taxonomy ON (tag_term_relationships.term_taxonomy_id = tag_term_taxonomy.term_taxonomy_id AND tag_term_taxonomy.taxonomy = 'post_tag')
INNER JOIN wp_terms AS tag_terms ON (tag_term_taxonomy.term_id = tag_terms.term_id)
WHERE wposts.post_type = 'post'
AND wposts.post_status NOT LIKE 'private'
AND tag_terms.term_id = '55'
GROUP BY wposts.ID
HAVING COUNT( tag_terms.term_id ) <> 1
OR MAX( tag_terms.term_id ) <> 55
ORDER BY wposts.post_date ASC