Sort WordPress posts by numerical custom fields - php

I added a code that allows me to sort WordPress posts by custom fields. I'm trying to sort the posts by prices, but it's sorting by the first number and not the value:
$116.99
$12.95
$149.00
$15.99
Instead of:
$12.95
$15.99
$116.99
$149.00
How can I get it to sort properly?
Here's the code: http://pastebin.com/Pe5yfvrE
I took it from this discussion, but it was left unresolved there..
http://wordpress.org/support/topic/sort-posts-by-custom-field-in-backend

If you would like to do it manually (though the answers referencing WP_Query are better options), a reasonably nice treatment might use array_multisort:
$arr = array(
'$116.99',
'$12.95',
'$149.00',
'$15.99'
);
$keys = array();
foreach ($arr as $value) {
$keys[] = floatval(substr($value, 1));
}
array_multisort($keys, SORT_ASC, $arr);

Use the WP_Query class and the orderby=meta_value_num parameter to sort numerically. Also, make sure you store the price in the custom field as a number without the "$" prepended.
$query = new WP_Query( array ( 'orderby' => 'meta_value_num', 'meta_key' => 'price' ) );
$query then contains rows of posts sorted numerically by price.

I haven't had a look at your code but you this has to do with the numbers being strings in your case. If you sort a string it is sorted like you describe. In order to sort it by it's value you need to remove the $ sign and cast it to a number.

Did you see this technique? - adding zero to the meta value of the to force it to be treated as an integer. The post has been updated various times over the years too so it might help you;
http://wordpress.org/support/topic/order-by-meta_key-where-meta_value-is-number?replies=11

function order($a, $b) {return intval($b) - intval($a);}
uasort($array, 'order');
I wonder that can help you ;)

Related

merging and then sorting 2 arrays in php & wordpress

I'm trying to merge 2 arrays in PHP and then sort them.
I'm pulling data from WordPress database ( tags and categories ) and I need to merge them and sort them properly.
Code looks similar to this:
$categories = [
'<a>WordPress Tips</a>',
'<a>SEO Tips'</a>,
'<a>Development Tips</a>'
];
$tags = [
'<a>WordPress</a>',
'<a>SEO'</a>,
'<a>Development</a>'
];
$taxonomies = array_merge($categories, $tags);
sort($taxonomies);
Since I need to loop through $taxonomies array and print them with anchors included ( every one of those must have a valid URL to itself ), I don't get a proper sorting result. However, as soon as I 'strip out' all the tags around these items, sorting works as it should, but I don't get URLs that I need, only string / text.
Could someone suggest a better sorting algorithm which would sort these items properly with html elements included around them? Thanks!
You need to do custom comaprision to make it work using usort() and strip_tags()
<?php
$taxonomies = array_merge($categories, $tags);
print_r($taxonomies);
function cmp($a, $b){
$data1 = strip_tags($a);
$data2 = strip_tags($b);
return ($data1 < $data2) ? -1 : 1;
}
usort($taxonomies, "cmp");
print_r($taxonomies);
Output:-https://eval.in/934071
Since you mentioned that the tags stripped version works, a simple way might be to use them as the keys in the sort. Something like this, for instance :
$taxonomies = array_merge( $categories, $tags );
$toSort = [];
foreach($taxonomies as $tax) {
$toSort[strip_tags($tax)] = $tax;
}
ksort( $toSort );
print_r( $toSort );
Which will give the sorted array and you can just use the values in there. Maybe there's better options but this comes to mind off the top of my head..
EDIT : uasort with a comparision function that actually compares the stripped versions might be better, after looking at other answers here.

PHP sort objects value but retain original relative order [duplicate]

This question already has answers here:
Preserve key order (stable sort) when sorting with PHP's uasort
(6 answers)
Closed 5 months ago.
I'm using usort to sort an array of objects, but really I want this to act as a kind of "group by" function without disturbing the original relative order of the rows.
Say I have this:
MASTER_CODE, CONFIG_ITEM
foo1, opt_ray
foo2, opt_ray
foo1, opt_fah
foo2, opt_doe
From that data, an array of objects is constructed with an anonymous key. That is, each row is parsed as an object. The objects are collected into an array.
What I want to do is sort the array by the MASTER_CODE value, but without disturbing the order.
That is, the final order should be:
MASTER_CODE, CONFIG_ITEM
foo1, opt_ray
foo1, opt_fah
foo2, opt_ray
foo2, opt_doe
We don't add a sort order, because the data comes from an external source.
I can use usort to order by the master code, but it messes up the original relative order.
Any suggestions?
This is one option - it's not the most elegant solution. It will take the unique values from the first column of your array (the one you want to filter by), sort that, then loop it and add entries from your original array with the same first value.
// Get an unique array of values to use for sorting
$sorting = array_unique(array_column($a, 0));
sort($sorting);
$sorted = [];
foreach ($sorting as $sortValue) {
$sorted = array_merge(
$sorted,
array_filter(
$a,
function($row) use ($sortValue) {
// Find values that have the same first value as each sort value
return ($sortValue === $row[0]);
}
)
);
}
Example
Note: This will work on PHP 5.5. Since you also tagged PHP 5.3, you may need to replace the array_column function. Try something like this:
$sorting = array_unique(array_map(function($row) { return $row[0]; }, $a));

PHP foreach get table value and change

Here is the situation, I am getting data from a WordPress plugin database. I need to grab that "products" from the database, find the "name" value, remove some charafters from it and then finally sort it by "name" length. Here is what is going on
//The plug in queries the database
$products = $product->getModelsNames($where="", $orderBy='order by name', $limit=null);
//I added this to take that query and make changes to the 'name' field
foreach ($products as $p) {
//Characters I need removed
$characters = array("a", "b", "c", "d", ".", "-");
$p->name = str_replace($characters, "", $p->name);
//Re sort by name now without characters and save back to $products. not sure what to do here
}
//now start the loop for the products
<?php foreach($products as $p): ?>
The main issue is I have products with names like: 8.2-1, 8.2-2, 8.2-2-A, 8.2-10 and so on and I can not get them to sort right. I figure the only way is to remove all the characters to just have the numbers and then sort by length or else I get my products listed like 8.2-1, 8.2-10, 8.2-2, 8.2-2-A or 8.2-1, 8.2-2, 8.2-10, 8.2-2-A. On top of that I need to echo the names in the second loop as they were before I removed the characters. At a real loss on how to get this done. Seemed simple enough since products often go by number and character but can not get them sorted right.
What you are looking for is called natural ordering. PHP has a function for this:
$products = array(
'8.2-10',
'8.2-2',
'8.2-1',
'8.2-2-A'
);
natsort($products);
foreach ($products as $product) {
echo $product . "<BR>";
}
Output:
8.2-1
8.2-2
8.2-2-A
8.2-10
EDIT! missed the fact that $products was actually an array of objects. You can use a different technique using strnatcmp:
usort($products, function($a, $b) {
return strnatcmp($a->name, $b->name);
});
Note that if you wanted to keep the same keys for some reason, just change it to uasort instead.

Numerical sort on custom field which includes letters

I'm trying to do a sort in my WP_Query on a custom field. The custom field contains strings such as "E100", "E500" and "E123b". I would like to sort numerically on these values, i.e. sort on the custom field as if the characters weren't there.
My query looks like this:
$subpages = new WP_Query(array(
"post_type" => "page",
"meta_key" => "[customFieldNameHere]",
"orderby" => "meta_value_num",
"order" => "ASC",
"posts_per_page" => 5000
));
But it doesn't work. It does some sort of sort, but it's not numerical. Is it possible to strip all characters/letters from the field, and then do a numerical sort on the remaining values, or is there some other way to solve this?
You can't sort a string with letters as if it were all numbers. If you try you will get a alphanumerical sort-- more or less what you'd do if you were alphabetizing something but it makes numbers look odd because it matches up all the first characters, then the second, and so on making numbers look like:
1
10
101
2
20
I don't know of anything built into MySQL that will do what you want, nor does WP_Query have any such feature. The best solution I have is to pull your results unsorted, and sort them later. You want to pull unsorted so the database doesn't do extra work.
$subpages = new WP_Query(array(
"post_type" => "page",
"meta_key" => "[customFieldNameHere]",
"posts_per_page" => 5000
));
$sorted = array();
foreach ($subpages as $s) {
$kname = preg_replace('/[^0-9]+/','',$s->customFieldNameHere]);
$sorted[$kname] = $s;
}
// you may need
// ksort($sorted);
var_dump($sorted);
One problem is going to be collisions. If you end up with two matching $knames you will clobber data, and frankly, that seems pretty likely if you have a lot of data.
I ended up removing the leading E from all strings. Doesn't really solve the original problem, with numerical sorting of strings, but at least it works now.

Making 2 Arrays Random in the same way with php

I'm new to the stackoverflow so feel free to delete this question if it's stupid:
The main purpose of doing this is to display a list of details on a page randomly everytime it refreshes, but the details are in different arrays, so i have 2 arrays which i have to randomize in the same way,
Example:
$Name[0]=John;
$Name[1]=Lucy;
$Name[2]=Mike;
$Age[0]=18;
$Age[1]=20;
$Age[2]=25;
after being randomize becomes :
$Name[2]=Mike;
$Name[0]=John;
$Name[1]=Lucy;
$Age[2]=25;
$Age[0]=18;
$Age[1]=20;
I tried using "->", For example:
$Array[0]->name = 'John';
$Array[0]->age = '18';
$Array[1]->name = 'Lucy';
$Array[1]->age = '20';
shuffle($Array);
but my teacher wasn't thrilled because the code was messy since there's alot of transfer (Details into the new array before the randomizing and new array back into details after randomizing). He wants me to do it only with the 2 arrays.
What you are doing, is sort of the right way of doing things. Look at it this way. What exactly are you trying to achieve? You want a set of data sorted randomly (ok, sorting is not the right word here, but you get it). Whenever you talk about any kind of reordering of data, we talk about changing the order that the elements appear in. Your element here is neither 'name', nor 'age'. Your element here is 'person'. So, your data list should be a list of 'person's, which you would reorder and not in two loosely-coupled arrays.
Anyways, if you absolutely MUST do it this way. This is what I suggest.
Let there be two arrays $A and $B. Let them both have N elements. What you do is, create an array $nums, which has elements from 0 to N-1 i.e.
$nums = array(0, 1, 2 ... N-1)
Now, shuffle the $sums array. So, let's say we have something like:
$num = (3, 4, 1, 2)
Ok, so we have created a mapping here,
$num[0] = 3
means that the 0th element is 3, which you can interpret as in the new array, the 0th element should be the 3rd element of the old array. To do this, run a simple loop:
for($i=0; $i<N; $i++) {
$A2[$i] = $A[$num[$i]];
$B2[$i] = $B[$num[$i]];
}
It is a slightly challenging task if you insist on this being an online solution (a solution that modifies the original data structure and not build a new one), but I'll leave that ask to you (think of swapping data elements according to the map we just created). Also, you could extend it easily to more than 2 arrays, or an array of arrays in case you're not sure how many arrays one has to deal with. Feel free to ask any question you might have...
You should use an associative array.
$people = array('John' => 18, 'Lucy' => 20, 'Mike' => 25);
return shuffle_assoc($people);
function shuffle_assoc( $array )
{
$keys = array_keys( $array );
shuffle( $keys );
return array_merge( array_flip( $keys ) , $array );
}

Categories