I am using wordpress and I have an SQL statement (as below) to gather the tags for a specific category. The only issue with this is that the table names may change (i.e. they will not always be wp_*). The function $pfx = $wpdb->base_prefix; returns what the wordpress database prefix is.
How can I use $pfx inside my SQL statement below (instead of wp_ ).
global $wpdb;
$tags = $wpdb->get_results
("
SELECT DISTINCT terms2.term_id as tag_id, terms2.name as tag_name, null as tag_link, t2.count as post_total
FROM
wp_posts as p1
LEFT JOIN wp_term_relationships as r1 ON p1.ID = r1.object_ID
LEFT JOIN wp_term_taxonomy as t1 ON r1.term_taxonomy_id = t1.term_taxonomy_id
LEFT JOIN wp_terms as terms1 ON t1.term_id = terms1.term_id,
wp_posts as p2
LEFT JOIN wp_term_relationships as r2 ON p2.ID = r2.object_ID
LEFT JOIN wp_term_taxonomy as t2 ON r2.term_taxonomy_id = t2.term_taxonomy_id
LEFT JOIN wp_terms as terms2 ON t2.term_id = terms2.term_id
WHERE
t1.taxonomy = 'category' AND p1.post_status = 'publish' AND terms1.term_id IN (".$args['categories'].") AND
t2.taxonomy = 'post_tag' AND p2.post_status = 'publish'
AND p1.ID = p2.ID
ORDER BY post_total DESC
");
Thanks.
Change for example
LEFT JOIN wp_term_relationships
into
LEFT JOIN ".$pfx."term_relationships
Related
I wish to find products with two different criteria.
The code I used first to search one criteria is;
SELECT rel.object_id, rel.term_taxonomy_id, tt.taxonomy, tt.term_id, ts.name
FROM df1wrmw_term_taxonomy tt
INNER JOIN df1wrmw_term_relationships rel ON tt.term_taxonomy_id = rel.term_taxonomy_id
INNER JOIN df1wrmw_terms ts ON tt.term_id = ts.term_id
WHERE tt.taxonomy = "pa_1_scale"
AND ts.term_id = 400;
This returns all those products (Object_ID) with the attribute "pa_1_scale" and ts.term_id = 400. I can also do this to return all products with product_cat and ts.term_id = 397, using a different WHERE statement
WHERE tt.taxonomy = "product_cat"
AND ts.term_id = 397
UNION ALL just combines the two. How do I get SQL to select both these criteria? I know a WHERE statement combining the two criteria will not work as I think that no table row contains both values?
Any help available would be great.
You can try to use the following that will join duplicated tables with a different variable reference, allowing to combine both queries in one:
SELECT tr.object_id, tr.term_taxonomy_id, tt.taxonomy, t.term_id, t.name,
tr2.term_taxonomy_id as term_taxonomy_id2, tt2.taxonomy as taxonomy2,
t2.term_id as term_id2, t2.name as name2
FROM df1wrmw_term_relationships tr
INNER JOIN df1wrmw_term_taxonomy tt
ON tr.term_taxonomy_id = tt.term_taxonomy_id
INNER JOIN df1wrmw_terms t
ON tt.term_id = t.term_id
INNER JOIN df1wrmw_term_relationships tr2
ON tr.object_id = tr2.object_id
INNER JOIN df1wrmw_term_taxonomy tt2
ON tr2.term_taxonomy_id = tt2.term_taxonomy_id
INNER JOIN df1wrmw_terms t2
ON tt2.term_id = t2.term_id
WHERE tt.taxonomy = 'pa_1_scale'
AND t.term_id = 400
AND tt2.taxonomy = 'product_cat'
AND t2.term_id = 397
Or you can use in WordPress the class WPDB and its methods to get SQL query results in PHP:
global $wpdb;
$results = $wpdb->get_results("
SELECT tr.object_id, tr.term_taxonomy_id, tt.taxonomy, t.term_id, t.name,
tr2.term_taxonomy_id as term_taxonomy_id2, tt2.taxonomy as taxonomy2,
t2.term_id as term_id2, t2.name as name2
FROM {$wpdb->prefix}term_relationships tr
INNER JOIN {$wpdb->prefix}term_taxonomy tt
ON tr.term_taxonomy_id = tt.term_taxonomy_id
INNER JOIN {$wpdb->prefix}terms t
ON tt.term_id = t.term_id
INNER JOIN {$wpdb->prefix}term_relationships tr2
ON tr.object_id = tr2.object_id
INNER JOIN {$wpdb->prefix}term_taxonomy tt2
ON tr2.term_taxonomy_id = tt2.term_taxonomy_id
INNER JOIN {$wpdb->prefix}terms t2
ON tt2.term_id = t2.term_id
WHERE tt.taxonomy = 'pa_1_scale'
AND t.term_id = 400
AND tt2.taxonomy = 'product_cat'
AND t2.term_id = 397
");
// Display preformatted raw output
echo '<pre>' . print_pr($results, true) . '</pre>';
It should work.
How do I modify the following query to delete all posts with the custom post type "listings" that are NOT IN specific Wordpress categories?
Note, I must use $wpdb->query() in my particular situation.
My categories for exclusion are term ID's 21, 22, and 24.
$wpdb->query('DELETE FROM wp_posts WHERE post_type = "listings"');
UPDATE - THIS query brings me a lot closer to what I am after but throws a SQL error.
DELETE FROM wp_posts a
LEFT JOIN wp_term_relationships b ON ( a.ID = b.object_id )
LEFT JOIN wp_postmeta c ON ( a.ID = c.post_id )
LEFT JOIN wp_term_taxonomy d ON ( d.term_taxonomy_id = b.term_taxonomy_id )
LEFT JOIN wp_terms e ON ( e.term_id = d.term_id )
WHERE a.post_type = "listings"
AND e.term_id NOT IN (21,22,24);
Error:
WordPress database error You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'LEFT JOIN wp_term_relationships ON wp_posts.ID = wp_term_relationships.object_id' at line 1 for query DELETE FROM wp_posts LEFT JOIN wp_term_relationships ON wp_posts.ID = wp_term_relationships.object_id LEFT JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id LEFT JOIN wp_term_taxonomy ON wp_term_taxonomy.term_taxonomy_id = wp_term_relationships.term_taxonomy_id LEFT JOIN wp_terms ON wp_terms.term_id = wp_term_taxonomy.term_id WHERE wp_posts.post_type = "listings" AND wp_terms.term_id NOT IN (21,22,24)
$wpdb->query('DELETE wp_posts FROM wp_posts
INNER JOIN wp_term_relationships ON wp_posts.id = wp_term_relationships.object_id
INNER JOIN wp_term_taxonomy ON wp_term_relationships.object_id = wp_term_taxonomy.term_taxonomy_id
WHERE wp_posts.post_type = "listings" AND wp_term_taxonomy.taxonomy NOT IN (taxonomy_1_slug, taxonomy_2_slug, etc.)');
Using category id delete post
delete a,b,c,d
FROM esx_posts a
LEFT JOIN esx_term_relationships b ON ( a.ID = b.object_id )
LEFT JOIN esx_postmeta c ON ( a.ID = c.post_id )
LEFT JOIN esx_term_taxonomy d ON ( d.term_taxonomy_id = b.term_taxonomy_id )
LEFT JOIN esx_terms e ON ( e.term_id = d.term_id )
WHERE e.term_id = 48
In WordPress, there are 2 tables: wp_terms and wp_termmeta.
I currently do the following to get the terms and parents etc:
$query = mysqli_query($mysqli, "
SELECT wp_terms.term_id,wp_terms.name, wp_term_taxonomy.parent
FROM wp_terms INNER JOIN wp_term_taxonomy ON wp_terms.term_id = wp_term_taxonomy.term_id
WHERE wp_term_taxonomy.taxonomy = 'post-categories'
ORDER BY name");
However - I need to access the wp_termmeta table, select a row where the term_id is the same and the meta_key is "order" then order by the meta_value of the wp_termmeta, instead of name as it is currently.
How would I do that with the current query?
I don't have wordpress-specific knowledge, but according to your description the query could look like this (I added table aliases for readability, but they are not necessary):
SELECT t.term_id, t.name, tax.parent
FROM wp_terms t
INNER JOIN wp_term_taxonomy tax ON t.term_id = tax.term_id
INNER JOIN wp_termmeta m ON m.term_id = t.term_id AND m.meta_key = 'order'
WHERE tax.taxonomy = 'post-categories'
ORDER BY m.meta_value
The most interesting part here is the join condition of the second join, which contains two conditions: m.term_id = t.term_id AND m.meta_key = 'order'
It first makes sure the term ids are matching and then assures that the meta key of the joined row is actually "order".
I can get links from the WordPress database that are in a specific category like this (I have added line breaks to the SQL part for clarity):
$category1 = 'stuff';
$category2 = 'other_stuff';
$q = 'select * from wp_links l
inner join wp_term_relationships r on l.link_id = r.object_id
inner join wp_term_taxonomy using (term_taxonomy_id)
inner join wp_terms using (term_id)
where taxonomy = "link_category"
and name = '.$category1;
$results = $wpdb->get_results($q);
How would I retrieve links that are in both $category1 and $category2 (I do mean both categories, not either category)?
On the assumption that the name field you are searching on is in the wp_terms table, there are two principle options.
The first just looks for entities with the first category, then uses another join the find those that also have the second category. This involes using the same table in two different joins, and so uses aliases and avoids the using keyword.
select * from wp_links l
inner join wp_term_relationships r on l.link_id = r.object_id
inner join wp_term_taxonomy t on r.term_taxonomy_id = t.term_taxonomy_id
inner join wp_terms c1 on t.term_id = c1.term_id
inner join wp_terms c2 on t.term_id = c2.term_id
where taxonomy = "link_category"
and c1.name = 'stuff'
and c2.name = 'other_stuff'
The alternative is much more scalable to more than just two catagories, but involves a sub-query...
select
l.*
from
(
select l.id from wp_links l
inner join wp_term_relationships r on l.link_id = r.object_id
inner join wp_term_taxonomy t on r.term_taxonomy_id = t.term_taxonomy_id
inner join wp_terms c on t.term_id = c.term_id
where taxonomy = "link_category"
and c.name IN ('stuff', 'other_stuff')
group by l.id
having count(distinct c.name) = 2
)
subquery
inner join wp_links l ON subquery.id = l.id
The inner query finds all that have one category or the other, but then the having clause only lets through those that have two categories in our list. (In other words, both of them.) [It also assumes that the wp_links table as an id column to use as a unique identifier.]
did you try with the OR?
$q = 'select * from (select * from wp_links l
inner join wp_term_relationships r on l.link_id = r.object_id
inner join wp_term_taxonomy using (term_taxonomy_id)
inner join wp_terms using (term_id)
where taxonomy = "link_category"
and name = '.$category1.') as t1 join (select * from wp_links l
inner join wp_term_relationships r on l.link_id = r.object_id
inner join wp_term_taxonomy using (term_taxonomy_id)
inner join wp_terms using (term_id)
where taxonomy = "link_category"
and name = '.$category2 .') as t2
on t1.term_id=t2.term_id;
I don't think this is the best solution, but you don't give me more details about your structure, tables what you have
This is a very specific question regarding MySQL as implemented in WordPress.
I'm trying to develop a plugin that will show (select) posts that have specific 'tags' and belong to specific 'categories' (both multiple)
I was told it's impossible because of the way categories and tags are stored:
wp_posts contains a list of posts, each post have an "ID"
wp_terms contains a list of terms (both categories and tags). Each term has a TERM_ID
wp_term_taxonomy has a list of terms with their TERM_IDs and has a Taxonomy definition for each one of those (either a Category or a Tag)
wp_term_relationships has associations between terms and posts
How can I join the tables to get all posts with tags "Nuclear" and "Deals" that also belong to the category "Category1"?
I misunderstood you. I thought you wanted Nuclear or Deals. The below should give you only Nuclear and Deals.
select p.*
from wp_posts p, wp_terms t, wp_term_taxonomy tt, wp_term_relationship tr,
wp_terms t2, wp_term_taxonomy tt2, wp_term_relationship tr2
wp_terms t2, wp_term_taxonomy tt2, wp_term_relationship tr2
where p.id = tr.object_id and t.term_id = tt.term_id and tr.term_taxonomy_id = tt.term_taxonomy_id
and p.id = tr2.object_id and t2.term_id = tt2.term_id and tr2.term_taxonomy_id = tt2.term_taxonomy_id
and p.id = tr3.object_id and t3.term_id = tt3.term_id and tr3.term_taxonomy_id = tt3.term_taxonomy_id
and (tt.taxonomy = 'category' and tt.term_id = t.term_id and t.name = 'Category1')
and (tt2.taxonomy = 'post_tag' and tt2.term_id = t2.term_id and t2.name = 'Nuclear')
and (tt3.taxonomy = 'post_tag' and tt3.term_id = t3.term_id and t3.name = 'Deals')
Try this:
select p.*
from wp_posts p,
wp_terms t, wp_term_taxonomy tt, wp_term_relationship tr
wp_terms t2, wp_term_taxonomy tt2, wp_term_relationship tr2
where p.id = tr.object_id
and t.term_id = tt.term_id
and tr.term_taxonomy_id = tt.term_taxonomy_id
and p.id = tr2.object_id
and t2.term_id = tt2.term_id
and tr2.term_taxonomy_id = tt2.term_taxonomy_id
and (tt.taxonomy = 'category' and tt.term_id = t.term_id and t.name = 'Category1')
and (tt2.taxonomy = 'post_tag' and tt2.term_id = t2.term_id and t2.name in ('Nuclear', 'Deals'))
Essentially I'm employing 2 copies of the pertinent child tables - terms, term_taxonomy, and term_relationship. One copy applies the 'Category1' restriction, the other the 'Nuclear' or 'Deals' restriction.
BTW, what kind of project is this with posts all about nuclear deals? You trying to get us on some government list? ;)
What a gross DB structure.
Anyway, I'd do something like this (note I prefer EXISTS to joins, but you can re-write them as joins if you like; most query analyzers will collapse them to the same query plan anyway). You may have to do some additional juggling one way or another to make it work...
SELECT *
FROM wp_posts p
WHERE EXISTS( SELECT *
FROM wp_term_relationship tr
WHERE tr.object_id = p.id
AND EXISTS( SELECT *
FROM wp_term_taxonomy tt
WHERE tt.term_taxonomy_id = tr.term_taxonomy_id
AND tt.taxonomy = 'category'
AND EXISTS( SELECT *
FROM wp_terms t
WHERE t.term_id = tt.term_id
AND t.name = "Category1"
)
)
AND EXISTS( SELECT *
FROM wp_term_taxonomy tt
WHERE tt.term_taxonomy_id = tr.term_taxonomy_id
AND tt.taxonomy = 'post_tag'
AND EXISTS( SELECT *
FROM wp_terms t
WHERE t.term_id = tt.term_id
AND t.name = "Nuclear"
)
AND EXISTS( SELECT *
FROM wp_terms t
WHERE t.term_id = tt.term_id
AND t.name = "Deals"
)
)
)
So I tried both options on my WordPress db. I looked for the category "Tech" in my posts with the tags "Perl" AND "Programming".
Eric's worked once I added a missing comma in the initial select statement. It returned 3 records. The problem is that the section that is looking for the "post_tag" is actually working as an OR option. One of my posts only had one tag not both. Also it would be good to make the SELECT DISTINCT.
I tried Matt's version, but it kept returning an empty set. I may try to "juggle" with it.
Thanks #Eric it works! Just a few code corrections for future reference:
the first select statements misses a coma after wp_term_relationship tr2
In the same select statemt the following must be change:
wp_terms t2, wp_term_taxonomy tt2, wp_term_relationship
tr2
should be
wp_terms t3, wp_term_taxonomy tt3, wp_term_relationship
tr3
Really so great answer .. helped me a lot..
great bcoz., it gave me basic approach to build my complex query !
one small correction, for ready users like me :)
"wp_term_relationship" will give 'doesn't exist error'
.. use wp_term_relationships as it is the correct table name.
Thanks Eric