简体   繁体   中英

Filter posts by one meta_key and two meta_value in WordPress using a select element with Ajax

THIS POST IS GOING TO BE LONG so bear with me, please!.

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.

This is what I'm trying to build: 在此处输入图片说明

So far I already have a function which is too large but it does the work(or at least almost).

So I will begin by posting the HTML file and then I will share the functions that I'm using with the custom page:

<?php 
/*
Template Name: Buscador Avanzado
Template Post Type: page
*/
?>
<?php get_header(); ?>
    <div class="container">
        <div class="row">
            <?php echo get_breadcrumb(); ?>     

<div id="my-adv-search">
<!-- Post Type -->
<div class="col-md-3">
    <div class="form-group">
        <label for="q_post_type">Tipo</label>
        <select class="form-control" id="q_post_type">
            <option selected>Selecciona una opcion</option>
            <?php
            $args = array(
                'public'    => true,
                '_builtin' => false,
            );
            $post_types = get_post_types($args);
                foreach( $post_types as $post_type ) {
                    echo '<option>' . $post_type . '</option>' ;    
                }
            ?>
        </select>
    </div>
</div>

<!-- Genero -->
<div class="col-md-3">
    <div class="form-group">
        <label for="q_taxonomy">Genero</label>
        <select class="form-control" multiple id="q_taxonomy">
            <option value="any" selected>Selecciona una opcion</option>
            <?php 
            $args = array(
              'public'   => true,
              '_builtin' => false
            ); 
            $output = 'names'; // or objects
            $operator = 'and'; // 'and' or 'or'
            $taxonomies = get_taxonomies( $args, $output, $operator ); 
            if ( $taxonomies ) {
              foreach ( $taxonomies  as $taxonomy ) {
                echo '<option>' . $taxonomy . '</option>';
              }
            }
            ?>
        </select>
    </div>
</div>

<!-- Estado -->
<div class="col-md-3">
    <div class="form-group">
        <label for="q_orderby">Estado</label>
        <select class="form-control" id="q_orderby">
            <option value="any" selected>Selecciona una opcion</option>
            <?php
            foreach ( [
              'author'        => 'Author',
              'comment_count' => 'Popularity (# of Comments)',
              //'year'          => 'Year',
              'en_emision'   => 'Emision',
              'en_final'   => 'Finalizado',
              //'views_count'   => 'Views',
              //'order'         => 'ASC ? DESC',
            ] as $value => $label ) {
              printf( '<option value="%s">%s</option>',
                esc_attr( $value ), esc_html( $label ) );
            }
            ?>
        </select>
    </div>
</div>


<!-- Year -->
<div class="col-md-3">
    <div class="form-group">
        <label for="q_year">Año</label>
        <select class="form-control" id="q_year">
            <option value="any" selected>Selecciona una opcion</option>
            <?php
            $args = array(
                'public'    => true,
                '_builtin'  => false,
                'type'      => 'yearly',
                'format'    => 'option',
            );
            wp_get_archives($args);
            ?>
        </select>
    </div>

</div>


<!-- Nonce field. -->
<?php wp_nonce_field( 'my-adv-search', 'q_nonce' ); ?>

<!-- Search Button -->
<div class="col-md-12">
    <input type="submit" class="btn btn-success" id="buscar_btn" value="Search">
    <br><br>
    <noscript><b>Tu buscador no soporta Javascript, haciendo imposible mostrar los posts.</b></noscript>
    <div id="resultados"><div class="cargando_medio"></div></div>
</div>
</div><!-- End #my-adv-search -->



        </div>
    </div>

<?php get_footer(); ?>
<script type="text/javascript">
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();
    } );
} );
</script>

Now here's the function that works with it(I pointed out where the problem is):

// 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->term_relationships} AS ctr1 ON ctr1.object_id = {$wpdb->posts}.ID" .
                    " INNER JOIN {$wpdb->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 => $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->get( 'order' );

                $c .= $c ? ', ' : '';
                $c .= "YEAR({$wpdb->posts}.post_date) $order";
            }
            return $c;
        }, 10, 2 );

        $ok = isset( $orderby2 );
        if ( ! $ok && 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' => $post_status,
        'post_type'   => array($post_type),
        'posts_per_page' => -1,
        'post_parent' => 0,
        'year'        => $year,
        'meta_key'    => isset( $meta_key ) ? $meta_key : '',
        'orderby'     => $orderby2,
        'order'       => $order,

    ] );

    if ( $q->have_posts() ) {
        echo '<ul>';
        while ( $q->have_posts() ) {
            $q->the_post();
            ?>
            <li><a href="<?php the_permalink(); ?>"><?php the_title() ?></a></li>
            <?php
        }
        echo '</ul>';
    } else {
        echo '<div class="alert alert-danger">Ningun Resultado</div>';
    }

    wp_die();
}

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).

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:

This suggestion was given to me by someone trying to help:

$q = new WP_Query( [
        'post_status' => $post_status,
        'post_type'   => array($post_type),
        'posts_per_page' => -1,
        'post_parent' => 0,
        'year'        => $year,
        'orderby'     => 'meta_value', //SET THIS AS REQUIRED
        'order'       => $order,

    ] );
if ( isset( $meta_key ) && '' != $meta_key ) {
    $q['meta_key'] = 'estado_de_video';
    $q['meta_value'] = $meta_key;
}

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:

if ( isset( $meta_key ) && '' != $meta_key ) {
    $q['meta_key'] = 'estado_de_video';
    $q['meta_value'] = $meta_key;
}

So once those were deleted I tried changing the WP_Query for this:

$q = new WP_Query( [
        'post_status' => $post_status,
        'post_type'   => array($post_type),
        'posts_per_page' => -1,
        'post_parent' => 0,
        'year'        => $year,
        'orderby'     => 'meta_value', //SET THIS AS REQUIRED
//        'meta_key'    => $meta_key,
//        'meta_value'  => $meta_values,
        'order'       => $order,
        'meta_query' => array(
            'relation' => 'AND',
            array(
                'key' => 'estado_de_video',
                'value' => array('en_emision', 'en_final'),
                'compare'   => 'EXISTS'
            ),
        ),

] );

Still has not worked out. Can somebody guide me through this or at least tell me a better approach?

Thanks in advance.

BELOW THIS BLOCKQUOTE IS NOT NECCESARY TO HELP WITH BUT WILL BE APPRECIATED IF SOMEBODY DECIDES TO.

I need help in the second <select> ; I want the taxonomies to appear according to what post type has been selected. Example:

<select> 1 for CPTs: Peliculas,

<select> 2 : load the categories taxonomies from selected post types.

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".

Right now I have two CPT's one that is called anime and another called peliculas

"anime" has the "categorias_anime" taxonomy,

"peliculas" has the "categorias_movie" taxonomy.

Thanks in advance.

Ordering by one given meta_value is simple, no need for complex queries. I see you mixed up meta key and values in your given codes.

Just use this:

$q = new WP_Query( [
        'post_status' => $post_status,
        'post_type'   => array($post_type),
        'posts_per_page' => -1,
        'post_parent' => 0,
        'year'        => $year,
        'orderby'     => 'meta_value',
        'meta_key' => 'estado_de_video',
        'order'       => $order, //ASC or DESC
    ] );

That's all. No need to set meta_value parameter here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM