Changing WP_Query params with url Query Var

This code manually sets the order with the 'order' => 'ASC' declaration in the WP_Query arguments.

$loop = new WP_Query( array(
  'post_type' => 'product',
  'meta_key' => 'product_price',
  'orderby' => 'meta_value_num',
  'order' => 'ASC',
  'posts_per_page' => 4,
  'paged' => $paged) );

If we want to pass a url parameter to that we could use something like:

'order' => $_GET['posts_order']

along with a url-pattern, like: /?posts_order=ASC

But that would be a terrible idea… because someone could visit the url: /?posts_order=DROP TABLE IF EXISTS table1 & potentially break things.

So, if we’re going to listen for a variable in the url, we’ll want to sanitize it.

<?php 
if ( ! empty( $_GET['posts_order'] ) ) {
  $posts_order = sanitize_key( $_GET['posts_order'] );  // prevent malicious characters in user-submitted variable
}

or, even better, we can use a whitelist-approach & only allow certain values for

$posts_order="DESC";
if ( ! empty( $_GET['posts_order'] ) ) {
  $posts_order_raw = sanitize_key( $_GET['posts_order'] );
  if ( 'ASC' === $posts_order_raw ) {
    $posts_order="ASC";
  }
}

$loop = new WP_Query( array(
  'post_type' => 'product',
  'meta_key' => 'product_price',
  'orderby' => 'meta_value_num',
  'order' => $posts_order,
  'posts_per_page' => 4,
  'paged' => $paged) ); 

But wait, there’s more!

We could omit the order declaration entirely from the WP_Query

$loop = new WP_Query( array(
  'post_type' => 'product',
  'meta_key' => 'product_price',
  'orderby' => 'meta_value_num',
  // 'order' => $posts_order, # Remove this line #
  'posts_per_page' => 4,
  'paged' => $paged) );

& instead, control the order from the pre_get_posts hook:

<?php
function wp_se_331547( $wp_query ) {

  if ( !is_admin() && is_main_query() ) {
    if( 'product' === get_post_type() ) {
      $posts_order="DESC";
      if ( ! empty( $_GET['posts_order'] ) ) {
        $posts_order_raw = sanitize_key( $_GET['posts_order'] );
        if ( 'ASC' === $posts_order_raw ) {
          $posts_order="ASC";
        }
      }
      $wp_query->set( 'order', $posts_order );
    }
  }

}
add_action('pre_get_posts', 'wp_se_331547');