• I realize this has been asked before. 4 years ago, in fact: https://wordpress.org/support/topic/reverse-loop-order.

    However I think the answer was extremely unsatisfactory, and unfortunately that thread has been closed.

    Of course I’ve looked up the documentation for WP_Query, however there doesn’t seem to be an option to invert the loop order (‘order’ reverses the query order, but this doesn’t play well with ‘posts_per_page’; I want to reverse the result set, not the query itself. Reversing the query results in a different result set).

    I’m aware this may require the query results to be fully fetched from the database server before reordering, but is there a way to do that without having to throw away The Loop interface? I don’t want to have to modify all my templates just to have them using my reversed posts array instead of the_title(), the_content(), etc.

    Is there a way around that? Can I insert a custom array back into The Loop, for example? Or is there some other way of reversing the result set in the WordPress way?

Viewing 1 replies (of 1 total)
  • Thread Starter guilherme-neo

    (@guilherme-neo)

    I’m not sure this is the way it should be done, but it works well enough.

    function teceduc_query_vars_pre_get_posts_filter($query) {
    	$GLOBALS['teceduc_query_vars'] = $query->query_vars;
    }
    
    function teceduc_reverse_results_posts_request_filter($sql) {
    	$inner_sql = $sql;
    	if(!empty($GLOBALS['teceduc_query_vars']['reverse_result_order'])) {
    		$outer_sql = "SELECT ";
    		$inner_sql = str_replace('SQL_CALC_FOUND_ROWS ', '', $inner_sql, $replacement_count);
    		if($replacement_count >= 1) {
    			$outer_sql .= 'SQL_CALC_FOUND_ROWS ';
    		}
    		$outer_sql .= "* FROM (";
    		if(!preg_match('/ORDER BY (.+\.(.+)) (ASC|DESC)/i', $inner_sql, $inner_order_by_clause)) {
    			return $sql;
    		}
    		$order_by_target = $inner_order_by_clause[1];
    		$order_by_target_column = $inner_order_by_clause[2];
    		$inner_order = strtoupper($inner_order_by_clause[3]);
    		$outer_order = [
    			'ASC' => 'DESC',
    			'DESC' => 'ASC',
    		] [
    			$inner_order
    		];
    		$inner_sql = str_replace('wp_posts.*', "wp_posts.*, $order_by_target AS _reverse_order_filter_target", $inner_sql);
    		$outer_sql .= $inner_sql . ") AS inner_query ORDER BY _reverse_order_filter_target $outer_order";
    		$sql = $outer_sql;
    	}
    	return $sql;
    }
    
    add_filter('pre_get_posts', 'teceduc_query_vars_pre_get_posts_filter');
    add_filter('posts_request', 'teceduc_reverse_results_posts_request_filter');

    If WordPress renames the wp_posts table or adds quotes or backticks around it or around the order by clause, or another plugin creates a subquery that contains another order by clause (like I just did…), or if anything else I didn’t anticipate changes, the query will probably silently fail unless debug mode is enabled… But that’s good enough, I guess, amirite?

    In order to invoke this behavior, WP_Queries must have a ‘reverse_result_order’ option set to true (or another truthy value), like this:

    $query = new WP_Query ([
    	'post_type' => 'agenda',
    	'meta_key' => 'start_date',
    	'meta_compare' => '>=',
    	'meta_value' => date_format(new DateTime('@' . strtotime($start_offset)), "Ymd"),
    	'posts_per_page' => $limit,
    	'orderby' => 'meta_value',
    	'reverse_result_order' => true,
    ]);

    I’m still waiting for someone to tell me of a better way to do this, but if there’s no better way, maybe I should turn this into a nice plugin?

Viewing 1 replies (of 1 total)
  • The topic ‘Reverse loop order.’ is closed to new replies.