Wordpress sort by meta values - php

I have an issue I am trying to solve right now and having an issue finding a way to do it properly.
I have a college lecture series I need to sort I can sort it by a meta field for year just fine. But when I get to sorting by semester it sorts it in alphabetical and so it ends up sorting by Winter,Spring,Fall or Fall,Spring,Winter depending on if I tell it ASC or DESC.
I need to figure out how to do order this in the right order preferably without adding another field to the posts for sort priority
Query args currently written as follows which is obviously a bit messy.
$args = array(
'post_type' => 'mcm_geri-ed',
'posts_per_page' => $posts_per_page,
'meta_query' => array(
'semester' => array(
'key' => 'semester',
),
'year' => array(
'key' => 'year'
)
),
'orderby' => array(
'year' => 'DESC',
'semester' => array(
'value' => 'date'
)
),
'paged' => $paged
);

I don't think there is a way to do this with WP_Query directly. How about using posts_orderby and manipulating the ORDER-part of the SQL to be something like meta_year DESC, meta_semester = 'Spring' DESC, meta_semester = 'Fall' DESC. Look at the generated SQL to see what names you should use for meta_year and meta_semester (or trimester, really).
This isn't as effective as changing semester to a numerical value and adding the name while outputting, but it will work.

This is what I ultimately did. It was something different than what was suggested but using the filter suggested to get the result. The if statement has a couple of other caveats added to it due to the way I've built a sorting system for the page template. I also wrote this in a test environment hence the different post type from the original code.
// Custom Orderby filter to return the correct order for semester values.
add_filter('posts_orderby', 'orderby_pages_callback', 10, 2);
function orderby_pages_callback($orderby_statement, $wp_query) {
//Making sure this only happens when it needs to. Which is the right post type and if it isn't getting sorted by other functions.
if ($wp_query->get("post_type") === "test_semester" && !is_admin() && !isset($_GET['order']) && !isset($_GET['sort'])) {
return "CAST(mt1.meta_value AS CHAR) DESC, wp_postmeta.meta_value = 'Fall' DESC, wp_postmeta.meta_value = 'Winter' DESC, wp_postmeta.meta_value = 'Spring' DESC,wp_postmeta.meta_value = 'Summer' DESC";
} else {
//return your regularly scheduled programming
return $orderby_statement;
}
}

Related

`ORDER BY meta_value ASC` in sql query is not sorting prices correctly

I'm using wordpress, have products in the website and product price is a custom field in the backend.
I have a page where products should be sorted by price from high to low and vice versa.
My Sql query looks like this:
SELECT * FROM `wp_postmeta` WHERE meta_key = 'product_price' ORDER BY meta_value ASC
Above query is not sorting prices from low to high.
But when I try to do it in below way, it works perfectly:
$args = array(
'post_type' => 'product-items',
'meta_key' => 'product_price',
'orderby' => 'meta_value',
'order' => 'ASC',
'post_status' => 'publish',
'posts_per_page'=> -1
);
$productList = get_posts($args);
In the database, I see that meta_value column type is longtext. Maybe this is the issue why it is not sorting properly. But how come it works in second way.
I would go with second option but my code requires to do it via sql query depending on some other things.
meta_value is a string -- that is the nature of EAV models.
In MySQL, I like to use silent conversion for this. That is, just treat the value as a numeric and do arithmetic:
ORDER BY (meta_value + 0) ASC
The advantage of silent conversion is that it does not generate errors for non-numeric values.
Yes, you are right. Meta_value is not numeric, that's why it can't sort it by default.
You can write meta_value*1 as juergen d wrote above.
Or you can use SQL CAST for that:
SELECT * FROM `wp_postmeta`
WHERE meta_key = 'product_price'
ORDER BY CAST(meta_value as unsigned) ASC

Is it possible to query posts in the same order as assigned?

I have a custom field named type, which is a a "radio button" data type and it has some choices. This custom field, is assigned to a custom post type named pproduct.
For example here are the choices of this custom field :
RED
BLUE
YELLOW
WHITE
BLACK
Only one can be selected from the above.
The below $args :
$args = array(
'post_type' => 'pproduct',
'posts_per_page' => -1,
'post_status'=>array('publish'),
'product' => $category->slug ,
'meta_query' => array(
'relation' => 'AND',
'type_clause' => array(
'key' => 'type',
),
'order_clause' => array(
'key' => 'order',
),
),
'orderby' => array(
'type_clause' => 'DESC',
'order_clause' => 'ASC',
),
);
will query all posts of post type pproduct, and it will sort it by two custom fields. Type and order . It will sort it in an alphabetical order.
Is it possible to modify this and sort it by the same order as the types are assigned? Does anyone know what happens if i don't use order by? I can see it brings the posts but what is the "default order" if it's not assigned by me.
EDIT 1 : Something like this
UPDATE:
I missunderstood your demand. If i get it right now, you want to make order as you assigned it in setting, simply like you write
RED
BLUE
YELLOW
WHITE
BLACK
That couldn't be achieved with WP query args, you will have to write your own database query to achieve this because query must know the order rules which is set by you (it does know alpabetical, numeric, date order etc. which can be simply derivated from field).
However if you could change values ACF to numeric (like u've posted in comment link) you win, then you will have to create translation array (to translate number to color name) if u will need to use value as color name/slug.
So in ACF settings choices:
1 : RED
2 : BLUE
3 : YELLOW
4 : WHITE
5 : BLACK
Query args will remain same (except type ordering DESC->ASC) and if you need to get the name from number, use this in loop:
$field = get_field_object( 'type' );
$value = $field['value'];
$color_name = $field['choices'][ $value ]; // this will be formated
$unformated_slug = sanitize_title( $color_name ); // change to lowercase and remove whitespaces etc..
// then you can work with $unformated_slug like your original field value eg:
if( $unformated_slug == 'red' ) {
/* do something here */
}
Changing choice values to numbers is the most simplier way, anything other will be too complicated.
--
Default order of posts is by date. If you want to set your order automatically for all queries or only for custom post type queries, see https://codex.wordpress.org/Plugin_API/Action_Reference/pre_get_posts

data escaping remove for specific filed in cakephp

I am using subquery for id field.
$db = $this->AccountRequest->getDataSource();
$subQuery = $db->buildStatement(
array(
'fields' => array('MAX(id)'),
'table' => $db->fullTableName($this->AccountRequest),
'alias' => 'MaxRecord',
'limit' => null,
'offset' => null,
'order' => null,
'group' => array("user_id")
),
$this->AccountRequest
);
$searching_parameters = array(
#"AccountRequest.id IN " => "(SELECT MAX( id ) FROM `account_requests` GROUP BY user_id)"
"AccountRequest.id IN " => "(".$subQuery.")"
);
$this->Paginator->settings = array(
#'fields' => array('AccountRequest.*'),
'conditions' => $searching_parameters,
'limit' => $limit,
'page' => $page_number,
#'group' => array("AccountRequest.user_id"),
'order' => array(
'AccountRequest.id' => 'DESC'
)
);
$data = $this->Paginator->paginate('AccountRequest');
This structure is producing a query is:
SELECT
`AccountRequest`.`id`,
`AccountRequest`.`user_id`,
`AccountRequest`.`email`,
`AccountRequest`.`emailchange`,
`AccountRequest`.`email_previously_changed`,
`AccountRequest`.`first_name`,
`AccountRequest`.`first_namechange`,
`AccountRequest`.`f_name_previously_changed`,
`AccountRequest`.`last_name`,
`AccountRequest`.`last_namechange`,
`AccountRequest`.`l_name_previously_changed`,
`AccountRequest`.`reason`,
`AccountRequest`.`status`,
`AccountRequest`.`created`,
`AccountRequest`.`modified`
FROM
`syonserv_meetauto`.`account_requests` AS `AccountRequest`
WHERE
`AccountRequest`.`id` IN '(SELECT MAX(id) FROM `syonserv_meetauto`.`account_requests` AS `MaxRecord` WHERE 1 = 1 GROUP BY user_id)'
ORDER BY
`AccountRequest`.`id` DESC
LIMIT 25
In the subquery, its add an extra single quote so it's producing an error.
So, How can I remove these single quotes from this subquery?
Thanks
What are you trying to achieve with the sub query?
The MAX(id) just means it will pull the id with the largest value AKA the most recent insert. The sub query is completely redundant when you can just ORDER BY id DESC.
using MAX() will return only one record, if this is what you want to achieve you can replicate by adding LIMIT 1
If the sub query is just an example and is meant to be from another table I would just run the query that gets the most recent id before running the main query. Getting the last inserted id in a separate query is very quick and I cant see much of a performance loss. I think it will result in cleaner code that`s easier to follow to.
edit 1: From the comments it sounds like all your trying to get is a particular users latest account_requests.
You dont need the sub query at all. My query below will get the most recent account record for the user id you choose.
$this->Paginator->settings = array(
'fields' => array('AccountRequest.*'),
'conditions' => array(
'AccountRequest.user_id' => $userID // you need to set the $userID
)
'page' => $page_number,
'order' => array(
'AccountRequest.id DESC' //shows most recent first
),
'limit' => 1 // set however many you want the maximum to be
);
The other thing you cold be meaning is to get multiple entries from multiple users and display them in order of user first and then the order of recent to old for that user. MYSQL lets you order by more than one field, in that case try:
$this->Paginator->settings = array(
'conditions' => array(
'AccountRequest.user_id' => $userID // you need to set the $userID
)
'page' => $page_number,
'order' => array(
'AccountRequest.user_id', //order by the users first
'AccountRequest.id DESC' //then order there requests by recent to old
)
);
If the example data you have added into the question is irrelevant and you are only concerned about how to do nested subqueries it has already been answered here
CakePHP nesting two select queries
However I still think based on the data in the question you can avoid using a nested query.

CakePHP order not working

Hi i am using CakePHP version - 2.5.5.
I have a table name chat_ategory_mages I want to get Average number of Frequency Order by Descending. Know about the Frequency please check - How to get Average hits between current date to posted date in MySQL?
chat_ategory_mages
id chat_category_id hits created
------------------------------------------------
1 5 10 2014-11-07 11:07:57
2 5 8 2014-11-10 05:10:20
3 5 70 2014-10-04 08:04:22
Code
$order=array('Frequency' => 'DESC');
$fields=array(
'ChatCategoryImage.id',
'ChatCategoryImage.chat_category_id',
'ChatCategoryImage.created',
'ChatCategoryImage.hits',
'hits/(DATEDIFF(NOW(),created)) AS Frequency',
);
QUERY-1
$rndQry=$this->ChatCategoryImage->find('all',array('conditions'=>array('ChatCategoryImage.chat_category_id'=>$cetegory_id), 'fields'=>$fields, 'order'=>$order, 'limit'=>10));
pr($rndQry); //WORKING FINE
QUERY-2
//THIS IS NOT WORKING
$this->Paginator->settings = array(
'conditions'=>array('ChatCategoryImage.chat_category_id'=>$cetegory_id),
'fields'=>$fields,
'limit' => 10,
'order' => $order,
);
$getCategoryImages = $this->Paginator->paginate('ChatCategoryImage');
pr($getCategoryImages); //NOT WORKING
Above table if i write simple cakephp query the order is working fine but when i am using cakephp pagination it is not working. If i am using $order=array('hits' => 'DESC'); this its woring perfect. Showing result 70,10,8 consistently but when i am adding Frequency it the result not coming the descending order.
Mysql Query
QUERY-1 :
SELECT ChatCategoryImage.id, ChatCategoryImage.chat_category_id, ChatCategoryImage.hits, ChatCategoryImage.created, hits/(DATEDIFF(NOW(),created)) AS Frequency, FROM myshowcam.chat_category_images AS ChatCategoryImage WHERE ChatCategoryImage.chat_category_id = 5 ORDER BY Frequency DESC LIMIT 10
QUERY-2 :
SELECT ChatCategoryImage.id, ChatCategoryImage.chat_category_id, ChatCategoryImage.hits, ChatCategoryImage.created, hits/(DATEDIFF(NOW(),created)) AS Frequency, FROM myshowcam.chat_category_images AS ChatCategoryImage WHERE ChatCategoryImage.chat_category_id = 5 LIMIT 10
What is the problem and why its not coming ORDER BY Frequency in the second query?
Thanks
chinu
You can use virtualFields
$this->ChatCategoryImage->virtualFields = array('Frequency' => 'hits/(DATEDIFF(NOW(),created))');
changing the way of order
$order = array('Frequency' => 'desc');
This happened to me to. You have to add to the paginate function the third parameter $whitelist. For example.
$this->Paginator->settings = array(
'conditions'=>array('ChatCategoryImage.chat_category_id'=>$cetegory_id),
'fields'=>$fields,
'limit' => 10,
'order' => $order,
);
$scope = array();
$whitelist = array('ChatCategoryImage.id', ...); //The fields you want to allow ordering.
$getCategoryImages = $this->Paginator->paginate('ChatCategoryImage', $scope, $whitelist);
pr($getCategoryImages);
I do not know why this is happening. I tried to see the code inside the paginate function but i could not figure it out.
Your code was lil wrong
$this->paginate = array(
'conditions' => array('ChatCategoryImage.chat_category_id'=>$cetegory_id),
'limit' => 10, 'order' => 'Frequency' => 'DESC');
$getAllCourses = $this->paginate('ChatCategoryImage');

Paginate do not sort DESC

I can't display Agreements with agreement_number less than 7 and order it by agreement_number DESC.
I have read Pagination CakePHP Cook Book and can't find where my code is wrong. It display only less than 7, but always ASC. I have found similar question here, [that works],(CakePHP paginate and order by) and do not know why. Agreement.agreement_number is int(4).
$this->Agreement->recursive = 0;
$agreements = $this->Paginator->paginate('Agreement', array(
'Agreement.agreement_number <' => '7'
), array(
'Agreement.agreement_number' => 'desc'
)
);
$this->set('agreements', $agreements);
}
Exact cake version is 2.5.2.
... Where did you read that that was the correct syntax?
The paginate function's third parameter is for sorting (and I mean, within the table... with those down and up arrows).
List of allowed fields for ordering. This allows you to prevent
ordering on non-indexed, or undesirable columns.
You have the exact link used for documentation of the API, but you don't seem to be following it (like, from here and here)
$this->Paginator->settings = array(
'Agreement' => array(
'order' => array('Agreement.agreement_number' => 'desc')
)
);
$agreements = $this->Paginator->paginate('Agreement', array(
'Agreement.agreement_number <' => '7'));

Categories