Sorting Issue
-
Bug report: “Order By = Meta Field Value” is ignored when “Posts Source = Manual Selection”
Plugin: Unlimited Elements for Elementor (free)
Affected: 2.0.15 and 2.0.16 (current). Last known good: 2.0.7
Type: Regression
Severity: Sorting silently falls back topost_date DESC— no error, no warning SummaryWhen a posts widget is configured with
Posts Source = Manual SelectionandOrder By = Meta Field Value(orMeta Field Value (numeric)), the meta key is
never passed toWP_Query. The query ends up withorderby => meta_valuebut nometa_key, which WP_Query cannot resolve, so nopostmetaJOIN is built and the
result falls back topost_date DESC.The same settings work correctly for every other Posts Source. Only the Manual
Selection path is affected.Because the failure is silent, this is easy to miss: the list still renders, it is
simply in the wrong order. Steps to reproduce- Add any posts widget (e.g. Post List) to a page.
Posts Source= Manual Selection, pick a handful of posts.Order By= Meta Field Value,Custom Field Name= any meta key that all
selected posts have.Show Query Debug= Yes.
Expected: the debug array contains
[meta_key] => <your key>and the list is
sorted by that meta value.Actual: the debug array contains
[orderby_meta_key] => <your key>and nometa_key. The list is sorted by post date, descending.Debug output from a live site (2.0.16, shortened):
[post__in] => Array( … 26 IDs … ) [ignore_sticky_posts] => 1 [posts_per_page] => 1000 [suppress_filters] => 1 [post_status] => "publish, private" [orderby] => meta_value [order] => DESC [orderby_meta_key] => nachname <-- not a WP_Query argumentRoot cause
All line numbers verified against 2.0.16.
getPostListData_addOrderBy()inprovider/provider_params_processor.class.php
(lines 1075–1104) serves two callers and uses an$isArgsflag to switch between
filter-array key names and WP_Query-argument key names:// provider/provider_params_processor.class.php:1075 private function getPostListData_addOrderBy($filters, $value, $name, $isArgs = false){ $keyOrderBy = "orderby"; $keyOrderDir = "orderdir"; $keyMeta = "orderby_meta_key"; // :1079 if($isArgs == true){ $keyOrderDir = "order"; // :1082 <-- $keyMeta is not switched here } … if($orderBy == UniteFunctionsWPUC::SORTBY_META_VALUE || $orderBy == UniteFunctionsWPUC::SORTBY_META_VALUE_NUM){ $filters[$keyMeta] = UniteFunctionsUC::getVal($value, "{$name}_orderby_meta_key1"); // :1100 }The two callers: Caller
$isArgsDestination Result:1807falsefilter array →getPostsArgs()OK — translated atfunctions_wordpress.class.php:2719:3199trueis already the WP_Query args arraybroken — key name never translatedThe second caller sits inside
getPostListData_manualSelection()
(provider/provider_params_processor.class.php:3112–3305), which hands the array
straight toWP_Queryat:3227without ever passing throughgetPostsArgs():// :3195-3199 $args["suppress_filters"] = true; $args["post_status"] = "publish, private"; $args = $this->getPostListData_addOrderBy($args, $value, $name, true); … $query = new WP_Query($args); // :3227So
orderby_meta_keylands in aWP_Queryargument array, where it is not a
recognised argument and is discarded.$keyMetawas simply not included in the$isArgsswitch when the key was renamed. Why it is a regressionIn 2.0.7 the same function hard-coded the WP_Query key name, so both callers
produced a usable array:// 2.0.7, provider/provider_params_processor.class.php:1077 and :1099 $keyMeta = "meta_key"; … $filters["meta_key"] = UniteFunctionsUC::getVal($value, "{$name}_orderby_meta_key1");and
getPostsArgs()read it back under the same name
(2.0.7, provider/functions_wordpress.class.php:2689).In 2.0.15 the filter key was renamed to
orderby_meta_keyand the translation was
added atprovider/functions_wordpress.class.php:2719. That covers thegetPostsArgs()path correctly — but not the Manual Selection path, which bypasses
it.getPostListData_manualSelection()itself is byte-identical between 2.0.7 and 2.0.16.
The behaviour change comes entirely from the helper.We diffed 2.0.15 against 2.0.16:
provider/provider_params_processor.class.phphas
exactly one changed hunk, at line 6034, unrelated to this. The defect is unchanged
in the current release. Suggested fixOne line — restores 2.0.7 behaviour for the
$isArgscaller and leaves the filter
path untouched:--- a/provider/provider_params_processor.class.php +++ b/provider/provider_params_processor.class.php @@ -1078,7 +1078,10 @@ $keyOrderDir = "orderdir"; $keyMeta = "orderby_meta_key"; if($isArgs == true){ $keyOrderDir = "order"; + $keyMeta = "meta_key"; }Optional, for consistency with the taxonomy paths (
:4977,:5289), which already
do this:trim()the meta key before using it. A trailing space in the widget field
currently produces a key that silently matches nothing. Note on hooksue_modify_posts_query_argscannot be used to work around this from outside the
plugin: it is applied at:2560and:3002only, neither of which is in the Manual
Selection path.posts_clauses/posts_orderbyare also unavailable there, because
the path setssuppress_filters = trueat:3195.The only usable extension point is
pre_get_posts, which is what we are currently
using as a temporary workaround. ImpactOn the affected installation, 437 of 438 widgets that use meta-field ordering run
through the Manual Selection path. The lists render normally and are simply sorted by
date, so the problem went unnoticed for a while. Additional observationsThese are separate from the bug above and only noted in passing, from the same debug
output.post_statusis passed as"publish, private"(:3197), a comma-separated
string with a space after the comma.WP_Querysplitspost_statuson commas
without trimming the parts, so the second value arrives as" private"and
matches no registered status. If private posts are meant to be included here, the
value should be an array —array("publish", "private")— or at least have no
space. We have not tested this in isolation; it just looks unintended.post_typeis set to every searchable post type (:3185-3192) rather than the
types of the selected posts. Withpost__inthis is functionally harmless, but it
widens the query more than necessary.posts_per_pageis hard-limited to 1000 (:3136-3150). Fine as a safety net;
just noting that a manual selection larger than 1000 would be silently truncated.
Environment
- WordPress with Elementor Pro
- Unlimited Elements for Elementor, free version
- Verified by diffing unpacked plugin releases 2.0.7, 2.0.15 and 2.0.16
- Reproduced in the frontend with
Show Query Debugenabled
You must be logged in to reply to this topic.