title: Filter posts by one meta_key and two meta_value in WordPress using a select element with Ajax
body: <p>THIS POST IS GOING TO BE LONG so bear with me, please!.</p>
  
  <p>I'm trying to build a custom page which will be used as a "directory" for two post types that I have created in the back end.</p>
  
  <p>This is what I'm trying to build:
  <a href="https://i.stack.imgur.com/8f7cV.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/8f7cV.jpg" alt="enter image description here"></a></p>
  
  <p>So far I already have a function which is too large but it does the work(or at least almost).</p>
  
  <p>So I will begin by posting the HTML file and then I will share the functions that I'm using with the custom page:</p>
  
  <pre><code>&lt;?php 
  /*
  Template Name: Buscador Avanzado
  Template Post Type: page
  */
  ?&gt;
  &lt;?php get_header(); ?&gt;
      &lt;div class="container"&gt;
          &lt;div class="row"&gt;
              &lt;?php echo get_breadcrumb(); ?&gt;     
  
  &lt;div id="my-adv-search"&gt;
  &lt;!-- Post Type --&gt;
  &lt;div class="col-md-3"&gt;
      &lt;div class="form-group"&gt;
          &lt;label for="q_post_type"&gt;Tipo&lt;/label&gt;
          &lt;select class="form-control" id="q_post_type"&gt;
              &lt;option selected&gt;Selecciona una opcion&lt;/option&gt;
              &lt;?php
              $args = array(
                  'public'    =&gt; true,
                  '_builtin' =&gt; false,
              );
              $post_types = get_post_types($args);
                  foreach( $post_types as $post_type ) {
                      echo '&lt;option&gt;' . $post_type . '&lt;/option&gt;' ;    
                  }
              ?&gt;
          &lt;/select&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  
  &lt;!-- Genero --&gt;
  &lt;div class="col-md-3"&gt;
      &lt;div class="form-group"&gt;
          &lt;label for="q_taxonomy"&gt;Genero&lt;/label&gt;
          &lt;select class="form-control" multiple id="q_taxonomy"&gt;
              &lt;option value="any" selected&gt;Selecciona una opcion&lt;/option&gt;
              &lt;?php 
              $args = array(
                'public'   =&gt; true,
                '_builtin' =&gt; false
              ); 
              $output = 'names'; // or objects
              $operator = 'and'; // 'and' or 'or'
              $taxonomies = get_taxonomies( $args, $output, $operator ); 
              if ( $taxonomies ) {
                foreach ( $taxonomies  as $taxonomy ) {
                  echo '&lt;option&gt;' . $taxonomy . '&lt;/option&gt;';
                }
              }
              ?&gt;
          &lt;/select&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  
  &lt;!-- Estado --&gt;
  &lt;div class="col-md-3"&gt;
      &lt;div class="form-group"&gt;
          &lt;label for="q_orderby"&gt;Estado&lt;/label&gt;
          &lt;select class="form-control" id="q_orderby"&gt;
              &lt;option value="any" selected&gt;Selecciona una opcion&lt;/option&gt;
              &lt;?php
              foreach ( [
                'author'        =&gt; 'Author',
                'comment_count' =&gt; 'Popularity (# of Comments)',
                //'year'          =&gt; 'Year',
                'en_emision'   =&gt; 'Emision',
                'en_final'   =&gt; 'Finalizado',
                //'views_count'   =&gt; 'Views',
                //'order'         =&gt; 'ASC ? DESC',
              ] as $value =&gt; $label ) {
                printf( '&lt;option value="%s"&gt;%s&lt;/option&gt;',
                  esc_attr( $value ), esc_html( $label ) );
              }
              ?&gt;
          &lt;/select&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  
  
  &lt;!-- Year --&gt;
  &lt;div class="col-md-3"&gt;
      &lt;div class="form-group"&gt;
          &lt;label for="q_year"&gt;Año&lt;/label&gt;
          &lt;select class="form-control" id="q_year"&gt;
              &lt;option value="any" selected&gt;Selecciona una opcion&lt;/option&gt;
              &lt;?php
              $args = array(
                  'public'    =&gt; true,
                  '_builtin'  =&gt; false,
                  'type'      =&gt; 'yearly',
                  'format'    =&gt; 'option',
              );
              wp_get_archives($args);
              ?&gt;
          &lt;/select&gt;
      &lt;/div&gt;
  
  &lt;/div&gt;
  
  
  &lt;!-- Nonce field. --&gt;
  &lt;?php wp_nonce_field( 'my-adv-search', 'q_nonce' ); ?&gt;
  
  &lt;!-- Search Button --&gt;
  &lt;div class="col-md-12"&gt;
      &lt;input type="submit" class="btn btn-success" id="buscar_btn" value="Search"&gt;
      &lt;br&gt;&lt;br&gt;
      &lt;noscript&gt;&lt;b&gt;Tu buscador no soporta Javascript, haciendo imposible mostrar los posts.&lt;/b&gt;&lt;/noscript&gt;
      &lt;div id="resultados"&gt;&lt;div class="cargando_medio"&gt;&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;/div&gt;&lt;!-- End #my-adv-search --&gt;
  
  
  
          &lt;/div&gt;
      &lt;/div&gt;
  
  &lt;?php get_footer(); ?&gt;
  &lt;script type="text/javascript"&gt;
  jQuery( function( $ ){
      var ajaxurl = '/wptests/wp-admin/admin-ajax.php';
  
      function searchPosts( btn ) {
          var _btn_text = btn.value;//, q_order;
  
          btn.disabled = true;
          btn.value = 'Searching..';
  
  //        q_order = $( '#q_order-asc' ).is( ':checked' ) ?
  //            'ASC' : 'DESC';
  
          return $.post( ajaxurl, {
              action: 'my_adv_search',
              q_nonce: $( '#q_nonce' ).val(),
              q_post_type: $( '#q_post_type' ).val(),
              q_taxonomy: $( '#q_taxonomy' ).val(),
              q_year: $( '#q_year' ).val(),
              q_orderby: $( '#q_orderby' ).val(),
  //            q_order: q_order,
          } ).done( function( s ){
              if ( 'session_expired' === s ) {
                  location.reload();
                  return;
              }
  
              $( '#resultados' ).html( s );
          } ).always( function(){
              btn.value = _btn_text;
              btn.disabled = false;
          } );
      }
  
      $( '#buscar_btn', '#my-adv-search' ).on( 'click', function( e ){
          e.preventDefault();
  
          // Run AJAX search.
          searchPosts( this );
  
          // Remove button focus.
          this.blur();
      } );
  } );
  &lt;/script&gt;
  </code></pre>
  
  <p>Now here's the function that works with it(I pointed out where the problem is):</p>
  
  <pre><code>// Buscador Avanzado
  add_action( 'wp_ajax_my_adv_search', 'ajax_my_adv_search' );
  add_action( 'wp_ajax_nopriv_my_adv_search', 'ajax_my_adv_search' );
  function ajax_my_adv_search() {
      if ( ! check_ajax_referer( 'my-adv-search', 'q_nonce', false ) ) {
          echo 'session_expired';
          wp_die();
      }
  
      $post_type = isset( $_POST['q_post_type'] ) ? $_POST['q_post_type'] : '';
      $taxonomy = isset( $_POST['q_taxonomy'] ) ? $_POST['q_taxonomy'] : [];
      $year = isset( $_POST['q_year'] ) ? $_POST['q_year'] : '';
      $orderby = isset( $_POST['q_orderby'] ) ? $_POST['q_orderby'] : [];
      $order = isset( $_POST['q_order'] ) ? $_POST['q_order'] : '';
  
      // Note that if $post_type is 'any', all post statuses will be included. In
      // that case, you may want to set specific post statuses below.
      $post_status = 'publish';
  
      // by Taxonomy
      $taxonomy = array_filter( (array) $taxonomy );
      if ( ! in_array( 'any', $taxonomy ) ) {
          $taxonomy = array_unique( array_map( 'trim', $taxonomy ) );
  
          add_filter( 'posts_join', function( $c ) use ( $taxonomy ) {
              if ( ! empty( $taxonomy ) ) {
                  global $wpdb;
                  // 1 below is one/number and not the lowercase of L
                  $c .= " INNER JOIN {$wpdb-&gt;term_relationships} AS ctr1 ON ctr1.object_id = {$wpdb-&gt;posts}.ID" .
                      " INNER JOIN {$wpdb-&gt;term_taxonomy} AS ctt1 ON ctt1.term_taxonomy_id = ctr1.term_taxonomy_id";
              }
              return $c;
          } );
  
          add_filter( 'posts_where', function( $c ) use ( $taxonomy ) {
              if ( ! empty( $taxonomy ) ) {
                  $tax_list = array_map( 'esc_sql', $taxonomy );
                  $tax_list = "'" . implode( "', '", $tax_list ) . "'";
  
                  // 1 below is one/number and not the lowercase of L
                  $c .= " AND ( ctt1.taxonomy IN ($tax_list) )";
              }
              return $c;
          } );
      }
  
      // by Custom Field Value - Metadata
      $orderby = array_filter( (array) $orderby );
      if ( in_array( 'any', $orderby ) ) {
          // Don't sort by post date.
          $orderby2 = false;
      } else {
          $orderby = array_unique( array_map( 'trim', $orderby ) );
  
          // TRUE if we're sorting by year.
          $ob_year = false;
  
          foreach ( $orderby as $i =&gt; $s ) {
              // Sort posts by year.
              if ( 'year' === $s ) {
                  $ob_year = true;
                  unset( $orderby[ $i ] );
              }
  //// PROBLEM BEGINS HERE
              // Sort posts by meta value en_emision from meta key estado_de_video. Note that this would only return
              // posts that have the custom field 'en_emision'.
              if ( 'en_emision' === $s ) {
                  $meta_key = 'en_emision';
                  $orderby2 = 'meta_value';
                  unset( $orderby[ $i ] );
              }
  
              // Sort posts by meta value en_final from meta key estado_de_video. Note that this would only return
              // posts that have the custom field 'en_final'.
              if ( 'en_final' === $s ) {
                  $meta_key = 'en_final';
                  $orderby2 = 'meta_value';
                  unset( $orderby[ $i ] );
              }
          }
  
  //// PROBLEM ENDS HERE
          add_filter( 'posts_orderby', function( $c, $q ) use ( $ob_year ) {
              if ( $ob_year ) {
                  global $wpdb;
  
                  // Use the value parsed by WP_Query.
                  $order = $q-&gt;get( 'order' );
  
                  $c .= $c ? ', ' : '';
                  $c .= "YEAR({$wpdb-&gt;posts}.post_date) $order";
              }
              return $c;
          }, 10, 2 );
  
          $ok = isset( $orderby2 );
          if ( ! $ok &amp;&amp; empty( $orderby ) ) {
              // Don't sort by post date.
              $orderby2 = false;
          } elseif ( ! $ok ) {
              // Pass to WP_Query as a string.
              $orderby2 = implode( ' ', $orderby );
          }
      }
  
      // by Year
      if ( ! is_numeric( $year ) ) {
          $year = '';
      }
  
  
  
      $q = new WP_Query( [
          'post_status' =&gt; $post_status,
          'post_type'   =&gt; array($post_type),
          'posts_per_page' =&gt; -1,
          'post_parent' =&gt; 0,
          'year'        =&gt; $year,
          'meta_key'    =&gt; isset( $meta_key ) ? $meta_key : '',
          'orderby'     =&gt; $orderby2,
          'order'       =&gt; $order,
  
      ] );
  
      if ( $q-&gt;have_posts() ) {
          echo '&lt;ul&gt;';
          while ( $q-&gt;have_posts() ) {
              $q-&gt;the_post();
              ?&gt;
              &lt;li&gt;&lt;a href="&lt;?php the_permalink(); ?&gt;"&gt;&lt;?php the_title() ?&gt;&lt;/a&gt;&lt;/li&gt;
              &lt;?php
          }
          echo '&lt;/ul&gt;';
      } else {
          echo '&lt;div class="alert alert-danger"&gt;Ningun Resultado&lt;/div&gt;';
      }
  
      wp_die();
  }
  </code></pre>
  
  <p>Now what I'm want is to sort post by one meta_key (estado_de_video) and two meta_values that I created for that meta key (en_emision, en_final).</p>
  
  <p>Right now with the function above I tried doing something similar as if I were sorting by year but it did not work, then I tried changing the WP_Query just a bit: </p>
  
  <p>This suggestion was given to me by someone trying to help:</p>
  
  <pre><code>$q = new WP_Query( [
          'post_status' =&gt; $post_status,
          'post_type'   =&gt; array($post_type),
          'posts_per_page' =&gt; -1,
          'post_parent' =&gt; 0,
          'year'        =&gt; $year,
          'orderby'     =&gt; 'meta_value', //SET THIS AS REQUIRED
          'order'       =&gt; $order,
  
      ] );
  if ( isset( $meta_key ) &amp;&amp; '' != $meta_key ) {
      $q['meta_key'] = 'estado_de_video';
      $q['meta_value'] = $meta_key;
  }
  </code></pre>
  
  <p>for what I've been told this should have worked out somehow or at least it should have returned the posts with the either meta_value (en_emision or en_final) but it didn't, then I tried to change the function by deleting the commented section(see the function snippet above) and deleting this as well:</p>
  
  <pre><code>if ( isset( $meta_key ) &amp;&amp; '' != $meta_key ) {
      $q['meta_key'] = 'estado_de_video';
      $q['meta_value'] = $meta_key;
  }
  </code></pre>
  
  <p>So once those were deleted I tried changing the WP_Query for this:</p>
  
  <pre><code>$q = new WP_Query( [
          'post_status' =&gt; $post_status,
          'post_type'   =&gt; array($post_type),
          'posts_per_page' =&gt; -1,
          'post_parent' =&gt; 0,
          'year'        =&gt; $year,
          'orderby'     =&gt; 'meta_value', //SET THIS AS REQUIRED
  //        'meta_key'    =&gt; $meta_key,
  //        'meta_value'  =&gt; $meta_values,
          'order'       =&gt; $order,
          'meta_query' =&gt; array(
              'relation' =&gt; 'AND',
              array(
                  'key' =&gt; 'estado_de_video',
                  'value' =&gt; array('en_emision', 'en_final'),
                  'compare'   =&gt; 'EXISTS'
              ),
          ),
  
  ] );
  </code></pre>
  
  <p>Still has not worked out. Can somebody guide me through this or at least tell me a better approach?</p>
  
  <p>Thanks in advance.</p>
  
  <blockquote>
    <p>BELOW THIS BLOCKQUOTE IS NOT NECCESARY TO HELP WITH BUT WILL BE
    APPRECIATED IF SOMEBODY DECIDES TO.</p>
  </blockquote>
  
  <p>I need help in the second <code>&lt;select&gt;</code>; I want the taxonomies to appear according to what post type has been selected. Example:</p>
  
  <p><code>&lt;select&gt;</code> 1 for CPTs: Peliculas,</p>
  
  <p><code>&lt;select&gt;</code> 2 : load the categories taxonomies from selected post types.</p>
  
  <p>Lets say I have selected "Peliculas" then I want the all the categories that have been made in the custom taxonomy attached to the "Peliculas".</p>
  
  <p>Right now I have two CPT's one that is called anime and another called peliculas</p>
  
  <p>"anime" has the "categorias_anime" taxonomy,</p>
  
  <p>"peliculas" has the "categorias_movie" taxonomy.</p>
  
  <p>Thanks in advance.</p>