• 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 to post_date DESC — no error, no warning Summary

    When a posts widget is configured with Posts Source = Manual Selection and
    Order By = Meta Field Value (or Meta Field Value (numeric)), the meta key is
    never passed to WP_Query. The query ends up with orderby => meta_value but no
    meta_key, which WP_Query cannot resolve, so no postmeta JOIN is built and the
    result falls back to post_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

    1. Add any posts widget (e.g. Post List) to a page.
    2. Posts Source = Manual Selection, pick a handful of posts.
    3. Order By = Meta Field Value, Custom Field Name = any meta key that all
      selected posts have.
    4. 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 no
    meta_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 argument

    Root cause

    All line numbers verified against 2.0.16.

    getPostListData_addOrderBy() in provider/provider_params_processor.class.php
    (lines 1075–1104) serves two callers and uses an $isArgs flag 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 $isArgs Destination Result :1807false filter array → getPostsArgs()OK — translated at functions_wordpress.class.php:2719:3199trueis already the WP_Query args arraybroken — key name never translated

    The second caller sits inside getPostListData_manualSelection()
    (provider/provider_params_processor.class.php:3112–3305), which hands the array
    straight to WP_Query at :3227 without ever passing through getPostsArgs():

    // :3195-3199
    $args["suppress_filters"] = true;
    $args["post_status"]      = "publish, private";
    $args = $this->getPostListData_addOrderBy($args, $value, $name, true);
    …
    $query = new WP_Query($args);   // :3227

    So orderby_meta_key lands in a WP_Query argument array, where it is not a
    recognised argument and is discarded.

    $keyMeta was simply not included in the $isArgs switch when the key was renamed. Why it is a regression

    In 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_key and the translation was
    added at provider/functions_wordpress.class.php:2719. That covers the
    getPostsArgs() 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.php has
    exactly one changed hunk, at line 6034, unrelated to this. The defect is unchanged
    in the current release. Suggested fix

    One line — restores 2.0.7 behaviour for the $isArgs caller 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 hooks

    ue_modify_posts_query_args cannot be used to work around this from outside the
    plugin: it is applied at :2560 and :3002 only, neither of which is in the Manual
    Selection path. posts_clauses / posts_orderby are also unavailable there, because
    the path sets suppress_filters = true at :3195.

    The only usable extension point is pre_get_posts, which is what we are currently
    using as a temporary workaround. Impact

    On 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 observations

    These are separate from the bug above and only noted in passing, from the same debug
    output.

    1. post_status is passed as "publish, private" (:3197), a comma-separated
      string with a space after the comma. WP_Query splits post_status on 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.
    2. post_type is set to every searchable post type (:3185-3192) rather than the
      types of the selected posts. With post__in this is functionally harmless, but it
      widens the query more than necessary.
    3. posts_per_page is 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 Debug enabled
Viewing 1 replies (of 1 total)
  • Plugin Author Denys Odintsov

    (@odin9den)

    Hi @krizkroz,

    our apologies for the delay with the answer. Thank you for the detailed report.

    We released 2.0.17 version recently, please try to update your plugin version and check if the issue is solved. I was unable to reproduce it in the latest version.

    Please let me know if you have any questions,

    be well,
    Denys from UE team.

Viewing 1 replies (of 1 total)

You must be logged in to reply to this topic.