How to manually query posts title, content and image attachment thumbnail? - mysql

I am trying to manually query from an external php file the wordpress database and I want to extract the last 3 posts with: title, content, last (or first) image, and for that image, from wp_postmeta I want to get the thumbnail url.
I managed to get the title, content, image id, but I couldn't figure it out how to add another join for getting image thumbnail. This is what I have:
SELECT a.post_title title, max(c.guid) img_url, a.ID id
FROM wp_posts a
LEFT JOIN
(select post_parent, max(post_date_gmt) as latest_image_date from wp_posts
where post_type='attachment' GROUP BY post_parent) b
on a.id=b.post_parent
LEFT JOIN wp_posts c
on c.post_parent=a.id
and c.post_type='attachment'
and b.latest_image_date = c.post_date_gmt where c.guid IS NOT NULL
GROUP BY a.post_title ORDER BY a.ID
The image thumbnail is in wp_postmeta (meta_id, post_id, meta_key, meta_value) table, looking like this: 58435, 6711, _wp_attachment_metadata, a:6:{s:5:"width";s:4:"1024";s:6:"height";s:3:"683"...
I could see I get the image id in c.id and all it needs is another JOIN to also get data from wp_postmeta for the field where meta_key="_wp_attachment_metadata" and post_id=c.id.
Can anyone help me with completing the query? Thanks!

I know this is an old post, but here to help future answer seekers
Update the query as needed. This current query will select post that have attachments. It returns the attachment ID and guid, the post ID and title along with the category name and term_id.
SELECT DISTINCT p.ID,p.post_title, a.ID as attach_id, a.guid, t.name, t.term_id FROM $wpdb->posts as a
LEFT JOIN $wpdb->posts as p on p.ID = a.post_parent
AND a.post_type = 'attachment' AND a.post_mime_type = 'image/png'
JOIN $wpdb->term_relationships as tr on tr.object_id = p.ID
JOIN $wpdb->terms as t on t.term_id = tr.term_taxonomy_id
JOIN $wpdb->term_taxonomy as tt on tt.term_id = t.term_id
AND tt.taxonomy = 'category'
AND p.post_type = 'post'
AND p.post_status = 'publish';

You should save your time and use wordpress functions :
make a plugin
or include wp-load.php in your script
https://wordpress.stackexchange.com/questions/47049/what-is-the-correct-way-to-use-wordpress-functions-outside-wordpress-files

In the end I chose another solution (at least temporary) because it adds horizontal capabilities: I created a completely empty custom page (I had to manually remove some actions/filters to get it empty) in the other site (the one to be included) which exports data in json format. I get that data and print it as I need in the current site.
<?php
$args= array(
'posts_per_page' => 6
//if there are sticked posts they will also appear beside the 2 if we run this in a separate php file, not included in theme
);
$ii = 0;
query_posts($args);
if( have_posts() ) :
while ( have_posts() ) : the_post();
$permalink = get_permalink();
$titlu = get_the_title();
$excerpt = get_the_excerpt();
$args = array(
'post_type' => 'attachment',
'post_parent' => $post->ID,
'post_status' => 'inherit',
'numberposts' => 1
);
$images = get_posts($args);
$j = 1;
foreach ($images as $i) :
$ii++;//am preluat doar o poza, e ok numaratoarea
$j++;
$poza_thumb = wp_get_attachment_image_src($i->ID, 'thumbnail');
$arr[$ii] = array('titlu' => $titlu, 'url' => $permalink, 'poza_thumb' => "".$poza_thumb[0], 'poza_width' => "".$poza_thumb[1], 'poza_height' => "". $poza_thumb[2], 'articol' => $excerpt);
endforeach;
endwhile;
echo json_encode($arr);//we send json as array
else :
endif;?>

Related

How to query for all posts within custom WordPress categories

I have a WordPress database that I need to query with pure MySQL to select all posts from a custom taxonomy called 'guide_category'. I also want to order the results by the wp_terms.name and within those order by wp_posts.name. A post can reside within multiple categories.
So results should looks something like:
Category_A
Post A
Post B
Post C
Category_B
Post A
Post B
Post C
Category_C
Post A
Post B
Post C
global $wpdb;
$query = "
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->posts.post_status = 'publish'
AND $wpdb->term_taxonomy.taxonomy = 'category'
AND $wpdb->term_taxonomy.term_id = 1
ORDER BY post_date DESC
";
$results = $wpdb->get_results($query);
replace term_taxonomy.term_id = 1 with your texonomy id
may it will work for you
This is what ended up working for me:
SELECT name, post_title
FROM wp_term_taxonomy AS cat_term_taxonomy
INNER JOIN wp_terms AS cat_terms ON cat_term_taxonomy.term_id = cat_terms.term_id
INNER JOIN wp_term_relationships AS cat_term_relationships ON cat_term_taxonomy.term_taxonomy_id = cat_term_relationships.term_taxonomy_id
INNER JOIN wp_posts AS cat_posts ON cat_term_relationships.object_id = cat_posts.ID
INNER JOIN wp_postmeta AS meta ON cat_posts.ID = meta.post_id
WHERE cat_posts.post_status = 'publish'
AND cat_term_taxonomy.taxonomy = 'guide_category'
GROUP BY name, post_title
ORDER BY name, post_title
In looking at the WP_Tax_Query class in /wp-includes/taxonomy.php, I found that there is a 'include_children' option which defaults to true. I modified my original get_posts() call with the following, and it works great:
$pages = get_posts(array(
'post_type' => 'post'
'tax_query' => array(
array(
'taxonomy' => 'taxonomy-name'
)
)
));
List of more query parameters: http://codex.wordpress.org/Class_Reference/WP_Query#Taxonomy_Parameters

Woocommerce query return products, order by total_sales

I've checked the woocommerce reports and products that haven't been sold are being fetched in the query?
Here is the query:
SELECT wp_terms.name as categoryname,v1.meta_value as thevalue, wp_terms.slug as categoryslug, wp_posts.post_title as mytitle, wp_terms.term_id as categoryid,wp_term_taxonomy.parent as categoryparent 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.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id)
INNER JOIN wp_terms ON (wp_term_taxonomy.term_id = wp_terms.term_id)
INNER JOIN wp_postmeta v1 ON (wp_posts.ID = v1.post_id) AND v1.meta_key LIKE 'total_sales'
WHERE wp_posts.post_status = 'publish' AND wp_posts.post_type = 'product' AND wp_terms.slug='garden-lighting' AND wp_posts.post_title NOT LIKE '%cable%' AND v1.meta_value !=0
ORDER BY v1.meta_value DESC
LIMIT 8
I checked the results of the array returned and products that haven't been sold are returning with a total_sales value?
Where did i go wrong? I want products returned for a specific category and ordered by total sales.
Why not use WP_Query instead of trying to write an SQL statement?
If I've understood you correctly, the following should return the first 8 posts in the 'garden-lighting' category sorted by sales and then by title.
$args = array(
'query_id' => 'exclude_cable',
'post_type' => 'product',
'post_status' => 'publish',
'category_name' => 'garden-lighting',
'posts_per_page' => 8,
'orderby' => array( 'meta_value_num' => 'DESC', 'title' => 'ASC' ),
'meta_key' => 'total_sales'
);
$new_query = new WP_Query( $args );
Edit I have added a few extra parameters. One I forgot to designate the product post type! Oops. But additionally, I have added a query_id parameter. WordPress doesn't do anything with this by default, but we can filter the posts_where clause and use it there to only modify the posts_where for this specific query.
add_filter( 'posts_where' , 'so_28478323_posts_where', 10, 2 );
function so_28478323_posts_where( $where, $q ) {
if ( 'exclude_cable' == $q->get( 'query_id', null ) ) {
$where .= " AND wp_posts.post_title NOT LIKE '%cable%'";
}
return $where;
}

sql statement for wordpress query

im trying to extract the following fields from a local wordpress installation
post_title
image_url
post_excerpt
other criteria for the SELECT is:
the status is publish
it's a post item
and the results only come from the projects parent category or any subcategory of project
i've got this far already but am finding it difficult to workout the rest
SELECT DISTINCT wp_posts.post_title, wp_postmeta.meta_value
FROM wp_posts, wp_term_relationships, wp_term_taxonomy, wp_postmeta
WHERE wp_term_relationships.object_id = wp_posts.ID
AND post_status = 'publish'
AND post_type = 'post'
AND wp_postmeta.meta_key = 'image_url'
AND wp_term_taxonomy.parent = 5
ORDER BY wp_posts.post_date DESC
as per the below comment, table for wp_term_taxonomy is:
term_taxonomy_id || term_id || taxonomy || description || parent || count
as per the below comment, table for wp_posts is:
ID || post_author || post_date || post_content || post_title|| post_excerpt || post_status
there are more, but not relevant here
as per the below comment, table for wp_term_relationships is:
object_id ||term_taxonomy_id || term_order
as per the below comment, table for wp_postmeta is:
meta_id || post_id || meta_key || meta_value
Always try to use the functions provided by WordPress to fulfill the requirements. Yes, the images( image urls ) are stored inside wp_posts table as attachments.
<?php
$args = array(
'post_type' => 'attachment',
'post_mime_type' => 'image',
'numberposts' => -1,
'post_status' => null,
'post_parent' => $post->ID
);
$attached_images = get_posts( $args );
?>
use this wordpress function to get post image url pass the post id to function it result the url of image. http://codex.wordpress.org/Function_Reference/wp_get_attachment_url
wp_get_attachment_url( $id );
However, if you want to go against something that is built in, you can try the following, however I must say I have no local version of wordpress to test against at the moment.
SELECT p.post_title as post_title, p.post_excerpt as post_excerpt,( SELECT guid FROM wp_posts WHERE id = m.meta_value ) AS url
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'
Let me know if you need anything more and I will install a local wordpress installation and do it with you through a chat session.

Wordpress Query order by custom field missing posts

This is my current query:
query_posts(array_merge(array('tag' => $pagetag,'meta_key'=>priority,'orderby' =>meta_value, 'order' =>'ASC','paged' => get_query_var('paged'))));
My problem is that the query shows me only the post that has values for my 'meta_key' meaning that 'priority' is not NULL.
How can I improve this query so that it will still orderby my meta_key but will show all the posts that aren't NULL as well?
Thanks in advance!
The problem is that WordPress adds an INNER JOIN to the wp_postmeta table as soon as you mention meta_key in your conditions. One way around the problem is to add a filter on the order by clause, something like this:
function so_orderby_priority($original_orderby_statement) {
global $wpdb;
return "(SELECT $wpdb->postmeta.meta_value
FROM $wpdb->postmeta
WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id
AND $wpdb->postmeta.meta_key = 'priority') ASC";
}
add_filter('posts_orderby', 'so_orderby_priority');
query_posts(
array(
'tag' => $pagetag,
'paged' => get_query_var('paged')
)
);
remove_filter('posts_orderby', 'so_orderby_priority');
Note MySQL sorts NULLs first - if you want them sorted last, try something like this (assuming all your priorities come before ZZZZZ alphabetically):
function so_orderby_priority($original_orderby_statement) {
global $wpdb;
return "IFNULL(
(SELECT $wpdb->postmeta.meta_value
FROM $wpdb->postmeta
WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id
AND $wpdb->postmeta.meta_key = 'priority'),
'ZZZZZ') ASC";
}
Edit
Here's a bit more explanation, which assumes you understand SQL at least a bit.
Your original query_posts resulted in the following query running against the database:
SELECT wp_posts.*
FROM wp_posts
INNER JOIN wp_term_relationships ON ( wp_posts.id = wp_term_relationships.object_id )
INNER JOIN wp_postmeta ON ( wp_posts.id = wp_postmeta.post_id )
WHERE 1 = 1
AND ( wp_term_relationships.term_taxonomy_id IN ( 3 ) )
AND wp_posts.post_type = 'post'
AND ( wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'private' )
AND ( wp_postmeta.meta_key = 'priority' )
GROUP BY wp_posts.id
ORDER BY wp_postmeta.meta_value ASC
LIMIT 0, 10;
That INNER JOIN wp_postmeta is what removed any posts without a priority from your results.
Removing the meta_* related conditions from your query_posts:
query_posts(
array(
'tag' => $pagetag,
'paged' => get_query_var('paged')
)
);
solved that problem, but the sort order is still wrong. The new SQL is
SELECT wp_posts.*
FROM wp_posts
INNER JOIN wp_term_relationships ON ( wp_posts.id = wp_term_relationships.object_id )
WHERE 1 = 1
AND ( wp_term_relationships.term_taxonomy_id IN ( 3 ) )
AND wp_posts.post_type = 'post'
AND ( wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'private' )
GROUP BY wp_posts.id
ORDER BY wp_posts.post_date DESC
LIMIT 0, 10;
The posts_orderby filter allows us to change the ORDER BY clause: wp_posts.post_date DESC gets replaced by what the filter returns. The final SQL becomes:
SELECT wp_posts.*
FROM wp_posts
INNER JOIN wp_term_relationships ON ( wp_posts.id = wp_term_relationships.object_id )
WHERE 1 = 1
AND ( wp_term_relationships.term_taxonomy_id IN ( 3 ) )
AND wp_posts.post_type = 'post'
AND ( wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'private' )
GROUP BY wp_posts.id
ORDER BY (SELECT wp_postmeta.meta_value
FROM wp_postmeta
WHERE wp_posts.id = wp_postmeta.post_id
AND wp_postmeta.meta_key = 'priority') ASC
LIMIT 0, 10
which does what you're after.
I needed to perform a similar task on the users.php page for a custom column I added and used the following code that I modified from Hobo
add_action('pre_user_query', 'qd_users_column_orderby');
function qd_users_column_orderby($userquery){
if('my_last_login'==$userquery->query_vars['orderby']) { //check if my cusomt meta_key is the column being sorted
global $wpdb;
$userquery->query_orderby = " ORDER BY(SELECT $wpdb->usermeta.meta_value
FROM $wpdb->usermeta
WHERE $wpdb->users.ID = $wpdb->usermeta.user_id
AND $wpdb->usermeta.meta_key = 'my_last_login') ".($userquery->query_vars["order"] == "ASC" ? "asc " : "desc ")." , wp_users.user_login ".($userquery->query_vars["order"] == "ASC" ? "asc " : "desc ");
}
}
Hopefully this helps somebody in need of this information.
In an effort of being throughout, the remainder of the necessary code to complete my individual task is below.
add_filter('manage_users_columns', 'qd_add_user_login_column');
function qd_add_user_login_column($columns) {
$columns['my_last_login'] = 'Last Logged In';
return $columns;
}
add_action('manage_users_custom_column', 'qd_show_user_login_column_content', 10, 3);
function qd_show_user_login_column_content($value, $column_name, $user_id) {
$user = get_userdata( $user_id );
if ( 'my_last_login' == $column_name ){
$lastLogin = get_the_author_meta('my_last_login', $user_id);
if(!$lastLogin){
return "Never";
}else{
date_default_timezone_set(get_option('timezone_string'));
return date('m/d/y g:ia', $lastLogin);
}
}
return $value;
}
add_filter( 'manage_users_sortable_columns', 'qd_users_table_sorting' );
function qd_users_table_sorting( $columns ) {
$columns['my_last_login'] = 'my_last_login';
return $columns;
}
The Issue: Sorting by a custom field without excluding posts that don't have a value set for that custom field.
Hobo's answer explains this well. Here I'm just going to offer a simpler alternative that ended up being easier in my case (Please note this won't work correctly if pagination is needed).
I decided to do the sorting in PHP after the query is made.
The nice part is that I have better control over where the posts with null values end up (I wanted them to show up last).
$query = new WP_Query($args);
//sort by rank
function customSort($a, $b)
{
$a = get_field("sort_ranking", $a);
$b = get_field("sort_ranking", $b);
//handle nulls
$a = is_numeric($a) ? $a : 9999;
$b = is_numeric($b) ? $b : 9999;
if ($a == $b) return 0;
return ($a < $b) ? -1 : 1;
}
usort($query->posts, "customSort");
Here I have a numeric custom field called sort_ranking and I'm using it to sort ASC. Posts with a null value for this field are assigned 9999 so that they end up at the end. (Note: I'm using ACF, hence the get_field function)
Hope this helps someone!
The easiest way to do this is to insert the custom field using save_post action, so every post published will have its own meta_key with a default value.
Use a MySQL query for add post_meta to all posts has not the meta. Thats it.
If you/anyone need code help on this, just reply :)
UPDATE
As Timusan asked, add this code in your functions.php file after changing the meta-key name :
add_action('save_post', 'sidati_post_views_metakey');
function sidati_post_views_metakey ($post_id){
/*
* $post_id = is the post ID
* 'sidati_post_views' => is your metakey name (sidati is prefix always nice to add your prefix)
* 0 => the inital value
* true => (bool) add true if you want this metakkey become unique
*/
add_post_meta($post_id, 'sidati_post_views', 0, true);
}
// THIS ACTION MUST RUN ONLY ONE TIME
add_action('init', 'sidati_allposts_must_have_this');
function sidati_allposts_must_have_this(){
/* Call the WordPress DataBase class */
global $wpdb;
/* This Query will get us all the posts and pages without "sidati_post_views" metakey. */
$ids = $wpdb->get_row("SELECT ID FROM wpdb->posts WHERE post_type IN ('post', 'page') AND post_status = 'publish' AND ID NOT IN (SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'sidati_post_views')");
/* After get all posts/pages, now you need to add the meta keys (this may take a few munites if you have many posts/pages)*/
foreach ($ids as $post_id) {
add_post_meta($post_id, 'sidati_post_views', 0, true);
}
}

Wordpress query to inner join posts -> custom table -> post meta where metakey = metavalue

I need to join POSTS with CUSTOM TABLE and POSTMETA. I am keeping track of popular posts in the custom table but I only want posts returned that have a specific postmeta value.
I searched and could not find a tut.
Here is what I 'think' I should do... but it doesn't work when done by hand in phpmyadmin.
SELECT (post info) FROM posts p INNER
JOIN custom_table t ON p.ID = t.ID
INNER JOIN post_meta m ON p.ID = m.ID
WHERE m.metakey = 'mykey' AND
post_type = 'post' AND post_date <
'$now' AND post_date > '$lastmonth'
ORDER BY postcount DESC LIMIT 5");
Do I need to inner join the post meta as a separate sub query?
If I might suggest, try using WP_Query(). It'll be a bit clumsy, since you'll need to add a filter for the post date range and then remove it, but it'll otherwise be predictably functional without a three-layer SQL join.
<?php
include_once( "wp-config.php" );
function filter_date_range( $where = '' ) {
$lastmonth = date("Y-m-d 00:00:00", strtotime("-1 month"));
$where .= " and post_date<now() and post_date>'{$lastmonth}'";
return( $where );
}
add_filter( 'posts_where', 'filter_date_range' );
$q = new WP_Query(array(
"post_status" => "publish",
"post_type" => "post",
"posts_per_page" => 5,
"meta_query" => array(array(
"key" => "mykey",
"value" => "my_preferred_value"
))
));
remove_filter( 'filter_date_range' );
var_dump( $q->posts );
?>