是否将筛选器应用于主查询,而不是创建新查询?

时间:2019-03-07 作者:Michael Rogers

我一直在使用本教程,该教程将分类法过滤器添加到存档中。php和它的工作原理,但输出是一个新的WP查询,与帖子标题相呼应。如何修改函数以使其应用于主查询,而不是创建新查询?是否有此过滤器?我知道pre\\u get\\u帖子,但由于它使用ajax,我不知道如何将其组合在一起。

Html form on archive.php

<form action="<?php echo site_url() ?>/wp-admin/admin-ajax.php" method="POST" id="filter">

    <?php
        if( $terms = get_terms( array( \'taxonomy\' => \'genre\', \'orderby\' => \'name\' ) ) ) : 

            echo \'<select name="genrefilter"><option value="">Select category...</option>\';
            foreach ( $terms as $term ) :
                echo \'<option value="\' . $term->term_id . \'">\' . $term->name . \'</option>\'; // ID of the category as the value of an option
            endforeach;
            echo \'</select>\';
        endif;
    ?>
    <?php
        if( $terms = get_terms( array( \'taxonomy\' => \'language\', \'orderby\' => \'name\' ) ) ) : 

            echo \'<select name="languagefilter"><option value="">Select category...</option>\';
            foreach ( $terms as $term ) :
                echo \'<option value="\' . $term->term_id . \'">\' . $term->name . \'</option>\'; // ID of the category as the value of an option
            endforeach;
            echo \'</select>\';
        endif;
    ?>
    <input type="text" name="price_min" placeholder="Min price" />
    <input type="text" name="price_max" placeholder="Max price" />
    <label>
        <input type="radio" name="date" value="ASC" checked="checked" /> Date: Ascending
    </label>
    <label>
        <input type="radio" name="date" value="DESC" selected="selected" /> Date: Descending
    </label>
    <label>
        <input type="checkbox" name="featured_image" /> Only posts with featured images
    </label>
    <button>Apply filter</button>
    <input type="hidden" name="action" value="myfilter">
    <input type="hidden" name="post_type" value="<?php echo get_post_type();?>">
</form>
<div id="response"></div>

<script>
jQuery(function($){
    $(\'#filter\').submit(function(){
        var filter = $(\'#filter\');
        $.ajax({
            url:filter.attr(\'action\'),
            data:filter.serialize(), // form data
            type:filter.attr(\'method\'), // POST
            beforeSend:function(xhr){
                filter.find(\'button\').text(\'Processing...\'); // changing the button label
            },
            success:function(data){
                filter.find(\'button\').text(\'Apply filter\'); // changing the button label back
                $(\'#response\').html(data); // insert data
            }
        });
        return false;
    });
});
</script>

functions.php

add_action(\'wp_ajax_myfilter\', \'misha_filter_function\'); // wp_ajax_{ACTION HERE} 
add_action(\'wp_ajax_nopriv_myfilter\', \'misha_filter_function\');

function misha_filter_function(){
    $args = array(
        \'post_type\' => $_POST[\'post_type\'],
        \'orderby\' => \'date\', // we will sort posts by date
        \'order\' => $_POST[\'date\'] // ASC or DESC
    );

    // for taxonomies / categories
if( isset( $_POST[\'genrefilter\'] ) && isset( $_POST[\'languagefilter\'] ) ) {
        $args[\'tax_query\'] = array(
            \'relation\' => \'AND\',
            array(
                \'taxonomy\' => \'genre\',
                \'field\' => \'id\',
                \'terms\' => $_POST[\'genrefilter\']
            ),
            array(
                \'taxonomy\' => \'language\',
                \'field\' => \'id\',
                \'terms\' => $_POST[\'languagefilter\']
            ),
        );

    }   


    // create $args[\'meta_query\'] array if one of the following fields is filled
    if( isset( $_POST[\'price_min\'] ) && $_POST[\'price_min\'] || isset( $_POST[\'price_max\'] ) && $_POST[\'price_max\'] || isset( $_POST[\'featured_image\'] ) && $_POST[\'featured_image\'] == \'on\' )
        $args[\'meta_query\'] = array( \'relation\'=>\'AND\' ); // AND means that all conditions of meta_query should be true

    // if both minimum price and maximum price are specified we will use BETWEEN comparison
    if( isset( $_POST[\'price_min\'] ) && $_POST[\'price_min\'] && isset( $_POST[\'price_max\'] ) && $_POST[\'price_max\'] ) {
        $args[\'meta_query\'][] = array(
            \'key\' => \'_price\',
            \'value\' => array( $_POST[\'price_min\'], $_POST[\'price_max\'] ),
            \'type\' => \'numeric\',
            \'compare\' => \'between\'
        );
    } else {
        // if only min price is set
        if( isset( $_POST[\'price_min\'] ) && $_POST[\'price_min\'] )
            $args[\'meta_query\'][] = array(
                \'key\' => \'_price\',
                \'value\' => $_POST[\'price_min\'],
                \'type\' => \'numeric\',
                \'compare\' => \'>\'
            );

        // if only max price is set
        if( isset( $_POST[\'price_max\'] ) && $_POST[\'price_max\'] )
            $args[\'meta_query\'][] = array(
                \'key\' => \'_price\',
                \'value\' => $_POST[\'price_max\'],
                \'type\' => \'numeric\',
                \'compare\' => \'<\'
            );
    }


    // if post thumbnail is set
    if( isset( $_POST[\'featured_image\'] ) && $_POST[\'featured_image\'] == \'on\' )
        $args[\'meta_query\'][] = array(
            \'key\' => \'_thumbnail_id\',
            \'compare\' => \'EXISTS\'
        );
    // if you want to use multiple checkboxed, just duplicate the above 5 lines for each checkbox

    $query = new WP_Query( $args );

    if( $query->have_posts() ) :
        while( $query->have_posts() ): $query->the_post();
            echo \'<h2>\' . $query->post->post_title . \'</h2>\';
        endwhile;
        wp_reset_postdata();
    else :
        echo \'No posts found\';
    endif;

    die();
}

1 个回复
最合适的回答,由SO网友:Krzysiek Dróżdż 整理而成

如果使用AJAX,则不能修改主查询,因为在AJAX请求期间根本没有创建主查询。

另一方面,使用AJAX执行此搜索表单并不是最好的主意,例如,您无法获取筛选列表的URL。

因此,我将删除AJAX部分并这样做:

<form action="" method="GET" id="filter">

    <?php
        if( $terms = get_terms( array( \'taxonomy\' => \'genre\', \'orderby\' => \'name\' ) ) ) : 

            echo \'<select name="genrefilter"><option value="">Select category...</option>\';
            foreach ( $terms as $term ) :
                echo \'<option value="\' . $term->term_id . \'">\' . $term->name . \'</option>\'; // ID of the category as the value of an option
            endforeach;
            echo \'</select>\';
        endif;
    ?>
    <?php
        if( $terms = get_terms( array( \'taxonomy\' => \'language\', \'orderby\' => \'name\' ) ) ) : 

            echo \'<select name="languagefilter"><option value="">Select category...</option>\';
            foreach ( $terms as $term ) :
                echo \'<option value="\' . $term->term_id . \'">\' . $term->name . \'</option>\'; // ID of the category as the value of an option
            endforeach;
            echo \'</select>\';
        endif;
    ?>
    <input type="text" name="price_min" placeholder="Min price" />
    <input type="text" name="price_max" placeholder="Max price" />
    <label>
        <input type="radio" name="date" value="ASC" checked="checked" /> Date: Ascending
    </label>
    <label>
        <input type="radio" name="date" value="DESC" selected="selected" /> Date: Descending
    </label>
    <label>
        <input type="checkbox" name="featured_image" /> Only posts with featured images
    </label>
    <button>Apply filter</button>
    <input type="hidden" name="action" value="myfilter">
    <input type="hidden" name="post_type" value="<?php echo get_post_type();?>">
</form>

<div id="response">
<?php 
    if ( have_posts() ) :
        while( have_posts() ): the_post();
            echo \'<h2>\' . get_the_title() . \'</h2>\';
        endwhile;
    else :
        echo \'No posts found\';
    endif;
?>
</div>
在你的功能中。php

add_action( \'pre_get_posts\', function ( $query ) {
    if ( ! is_admin() && is_archive() && $query->is_main_query() ) {
        // modify the $query according to your needs
        if ( isset( $_GET[\'genrefilter\'] ) && isset( $_GET[\'languagefilter\'] ) ) {
            $query->set( \'tax_query\', array(
                \'relation\' => \'AND\',
                array(
                    \'taxonomy\' => \'genre\',
                    \'field\' => \'term_id\',
                    \'terms\' => $_GET[\'genrefilter\']
                ),
                array(
                    \'taxonomy\' => \'language\',
                    \'field\' => \'term_id\',
                    \'terms\' => $_GET[\'languagefilter\']
                ),
            ) );
        }   
    }

    // put your other filters here 
} );
附言:你不应该使用<?php echo site_url() ?>/wp-admin/admin-ajax.php. 应该是这样的<?php echo esc_attr( admin_url( \'admin-ajax.php\' ) ); ?>