I'm not entirely sure this is possible but I'm completely out of ideas. The task I'm working on requires that I specifically use WP_Query due to constraints of other efficiency plugins my organization uses.
Pure and simple, I need a way to simulate the following query using WP_Query:
"SELECT YEAR(post_date) FROM wp_posts WHERE post_status = 'publish' GROUP BY YEAR(post_date) DESC"
Before you answer, note again, using the $wpdb global is off the table, and I've attempted to employ the parse_query method from WP_Query but it doesn't seem to respond to the above query in any meaningful way.
Thank you to anyone who takes the time to think this over!
Probably try this:
<?php
//Alter the group by clause
function query_group_by_year_post_date_filter($groupby){
return 'YEAR(wp_posts.post_date) DESC '; //try only post_date if this doesn't work
}
//Alter the select query
function query_select_fields($fields) {
return 'YEAR(wp_posts.post_date)'; //try only post_date if this doesn't work
}
add_filter('posts_fields','query_select_fields');
add_filter('posts_groupby', 'query_group_by_year_post_date_filter');
$allPosts = get_posts(array( //we have to use get_posts instead of WP_Query cause get_posts supports supress_filters
'post_type' => 'post', //specify post_type here or leave it in your case.
'post_status' => 'publish',
'posts_per_page' => -1,
'suppress_filters' => true //this seems to be preset in only get_posts and not WP_Query
));
remove_filter('posts_groupby', 'query_group_by_filter');
remove_filter('posts_fields','query_select_fields');
?>
I've tried not to use $wpdb in 2 functions at the top as per your requirements.
let me know if this worked for you.
Related
I am trying to load a post by ID using query_posts, however it always returns an empty array. I get a post Id at random using SQL as follows;
$randomProdSql = "SELECT ID FROM `posts` WHERE post_status = 'publish' ORDER BY RAND() LIMIT 0,1";
I then load that into a variable using;
$randomPost = $wpdb->get_var($randomProdSql);
This works fine and if I print it out I get an Id. I then call query_posts like this;
$args = array(
'p' => $randomPost
);
$posts = query_posts($args);
I would now expect the $posts variable to contain the post.. however, if I call;
print_r($args);
print_r($posts);
I get:
Array
(
[p] => 778
)
Array
(
)
Can anyone see what I am doing wrong?
Update your code as below:
query_posts('p='.'"$randomPost"');
Also, rather using the query_posts() method to get a single post, you can use get_post() method.
$my_post = get_post($randomPost);
echo $my_post->post_title;
As per your code, you shared you want post id's in random manner. The following code will get the post id's for you in random manner.
By using post_per_page you can control the number of posts returned in result. Also, fields will force the query to return id's of posts. However, in case you want to retrieve any other field also please remove it from here. As, it only supports id field only.
For details please refer to this link:
<?php
$args = array(
'post_status' => 'publish',
'orderby' => 'rand',
'fields' => 'ids',
'posts_per_page' => '1'
);
$posts = query_posts($args);
?>
I have been looking for the error for a while and have no idea what could be causing it.
In about 80% of the time the following code works, but sometimes it just orders completely random:
function filter_where($time, $where = '') {
$where .= " AND post_date > '" . date('Y-m-d H:i:s', strtotime($time)) . "'";
$where .= " AND post_status = 'publish' ";
return $where;
}
add_filter('posts_where', 'filter_where');
$array = array(
'cat' => 2,
'meta_key' => 'ratings_score',
'orderby' => 'meta_value_num',
'order' => 'DESC',
'meta_query' => array(
array(
'key' => 'ratings_score',
),
),
'posts_per_page' => 6
);
filter_where($time);
query_posts($array);
The filter function works. I have tested it with different $time values and post_status's.
Could it just be some kind of lag or have I ordered the code in a wrong manner?
some posts do not have a meta_key of ratings_score, but all posts in cat = 2 do have this meta_key.
Maybe this has something to do with the issue?
First of all, never use query_posts
Note: This function isn't meant to be used by plugins or themes. As explained later, there are better, more performant options to alter the main query. query_posts() is overly simplistic and problematic way to modify main query of a page by replacing it with new instance of the query. It is inefficient (re-runs SQL queries) and will outright fail in some circumstances (especially often when dealing with posts pagination).
You should be using WP_Query or get_posts and only when you cannot achieve the results you are after by modifying the main query with pre_get_posts
You are correctly adding your filter before your query arguments, but then you are again adding the function again after the query arguments. I believe this is one of the big problems here. You should remove the filter after the query arguments, not re-adding them
Replace this line
filter_where($time);
with
remove_filter('posts_where', 'filter_where');
One final note, why are you defining $time but then you doesn't use it at all?
I am getting problem in wordpress using query_posts.
Here is my code:
$args = array('category__in' => array(9),'post_type'=>'banner-slider','post_status'=>'publish');
query_posts( $args );
while ( have_posts() ) : the_post();
the_title();
endwhile;
query_post return following query:
SELECT SQL_CALC_FOUND_ROWS bib_posts.* FROM bib_posts WHERE 1=1 AND 0 = 1 AND bib_posts.post_type = 'banner-slider' AND ((bib_posts.post_status = 'publish')) GROUP BY bib_posts.ID ORDER BY bib_posts.post_date DESC LIMIT 0, 10
In the above query, i am getting 0=1 which is wrong. but when i remove category__in from query post then my query working fine.
Please suggest me where I am wrong.
query_posts is not meant to be used by plugins or themes, more specifically the codex says:
This function isn't meant to be used by plugins or themes. As
explained later, there are better, more performant options to alter
the main query. query_posts() is overly simplistic and problematic way
to modify main query of a page by replacing it with new instance of
the query. It is inefficient (re-runs SQL queries) and will outright
fail in some circumstances (especially often when dealing with posts
pagination). Any modern WP code should use more reliable methods, like
making use of pre_get_posts hook, for this purpose.
Quoted from: http://codex.wordpress.org/Function_Reference/query_posts
The WordPress codex recommends using WP_Query or get_posts(). In your case, I think get_posts() should be sufficient, so this example is going to use that. The below example is actually from the WordPress codex, with a couple of modifications for your category, post_type, and post_status:
<?php
$args = array( 'category' => 9, 'post_type' => 'banner-slider', 'post_status' => 'publish' );
$myposts = get_posts( $args );
foreach ( $myposts as $post ) : setup_postdata( $post ); ?>
<li>
<?php the_title(); ?>
</li>
<?php
endforeach;
wp_reset_postdata();
?>
Codex: http://codex.wordpress.org/Template_Tags/get_posts
I'm querying a series of posts in WP with the following function:
<?php
$thirtydays = date('Y/m/d', strtotime('+30 days'));
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
query_posts( array(
'post_type' => array('post', 'real-estate'),
'meta_key' => 'Time Available',
'meta_compare' => '<=',
'meta_value' => $thirtydays,
'paged' => $paged ));
?>
This part is working fine. It's basically pulling all my Real Estate posts, but only returning results that have a 'Time Available' of 30 days or less.
I need this to also order the posts in ascending order from low to high using the data from another custom field, 'Price.'
Whenever I add the standard 'orderby' => 'meta_value', 'meta_key' => 'Price' it no longer shows results within 30 days.
Is there any way I can combine these two? And is it possible to add a button which re-runs the query and sorts by Price, Bedrooms, etc? Or is this too specific for WP?
I believe this will provide you want you need. It's a class called PostsOrderedByMetaQuery that extends WP_Query and accepts new arguments 'orderby_meta_key' and 'orderby_order':
class PostsOrderedByMetaQuery extends WP_Query {
var $posts_ordered_by_meta = true;
var $orderby_order = 'ASC';
var $orderby_meta_key;
function __construct($args=array()) {
add_filter('posts_join',array(&$this,'posts_join'),10,2);
add_filter('posts_orderby',array(&$this,'posts_orderby'),10,2);
$this->posts_ordered_by_meta = true;
$this->orderby_meta_key = $args['orderby_meta_key'];
unset($args['orderby_meta_key']);
if (!empty($args['orderby_order'])) {
$this->orderby_order = $args['orderby_order'];
unset($args['orderby_order']);
}
parent::query($args);
}
function posts_join($join,$query) {
if (isset($query->posts_ordered_by_meta)) {
global $wpdb;
$join .=<<<SQL
INNER JOIN {$wpdb->postmeta} postmeta_price ON postmeta_price.post_id={$wpdb->posts}.ID
AND postmeta_price.meta_key='{$this->orderby_meta_key}'
SQL;
}
return $join;
}
function posts_orderby($orderby,$query) {
if (isset($query->posts_ordered_by_meta)) {
global $wpdb;
$orderby = "postmeta_price.meta_value {$this->orderby_order}";
}
return $orderby;
}
}
You would call it like this:
$thirtydays = date('Y/m/d', strtotime('+30 days'));
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$query = new PostsOrderedByMetaQuery(array(
'post_type' => array('post', 'real-estate'),
'meta_key' => 'Time Available',
'meta_compare' => '<=',
'meta_value' => $thirtydays,
'paged' => $paged,
'orderby_meta_key' => 'Price',
'orderby_order' => 'DESC',
));
foreach($query->posts as $post) {
echo " {$post->post_title}\n";
}
You can copy the PostsOrderedByMetaQuery class to your theme's functions.php file, or you can use it within a .php file of a plugin you may be writing.
If you want to test it quickly I've posted a self-contained version of the code to Gist which you can download and copy to your web server's root as test.php, modify for your use case, and then request from your browser using a URL like http://example.com/test.php.
Hope this helps.
-Mike
P.S. This answer is very similar to an answer I just gave over at WordPress Answers, which is the sister site of StackOverflow where lots of WordPress enthusiasts like me answer questions daily. You might want to see that answer too because it has a tad more explanation and because you might want to see WordPress Answers. Hope you'll consider posting your WordPress questions over there too in the future?
Because 'orderby' => 'meta_value' requires meta_key, and your meta_key is already in use for a comparison, I don't think you can do this. meta_key only accepts a single value and not an array of options. This is definitely a limitation and I encourage you to open a request if you don't find a solution.
As far as the button to re-run the query, you could simply reload the page and pass a query variable to change the sort. Unfortunately you still have to solve the first part of your question.
UPDATE
You could always sort the returned array yourself using PHP.
Also, not sure what you are checking with time available but you could register a filter that may help you customize the query a bit further add_filter('posts_where', ...); http://codex.wordpress.org/Function_Reference/query_posts
I have the following function that I've added to my functions.php file in WordPress. The idea is that it gathers all of the titles of 'fsmodel' posts (a custom post type that I've created). It then returns these as an array, which I then use to populate a select tag in the custom meta fields for a second custom post type.
Basically, 'fsmodel' will have posts with a boat model, and the 'fsboat' post type will have a drop-down with the names of each of the models to select from.
Now, this appears to works fine in the Dashboard - the drop-down is populated as expected. When I save, however, the post doesn't show up in the Edit list. Also on the website, all pages output as the 404 error page when this function is active.
I'm certain that the problem lies within the following code - does anyone have any idea what I might have done wrong?
function fs_model_array() {
$models_array = array();
$loop = new WP_Query(array(
'post_type' => 'fsmodel',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
'post_status' => 'publish'
));
while ( $loop->have_posts() ) : $loop->the_post();
$models_array[] = get_the_title();
endwhile;
return $models_array;
};
OK, I've come up with a solution (I hope - it's holding up for now).
Instead of creating a loop, I've just used the $wpdb->get_results to search the database for the column with a WHERE filter for the custom post type.
Then run an array builder:
$models_array = array();
$model_db = $wpdb->get_results("SELECT post_title FROM $wpdb->posts WHERE post_type='fsmodel' AND post_status = 'publish'");
foreach ($model_db as $model_db) {
$models_array[] = $model_db->post_title;
}
Thanks again for your time, hsatterwhite! :-)
I think you might find that adding wp_reset_query() to the end of your function will solve your problems :)
I like your solution, but I'd be inclined to say that you need to call the global variable of $post whenever you use the loop like this in a function, as it assigns it to that variable.
function fs_model_array(){
global $post;
$models_array = array();
$loop = new WP_Query(array(
...