将URL参数的AJAX筛选器从POST更改为GET

时间:2020-01-22 作者:user2115227

我有一个定义良好的AJAX过滤器,分为两部分,一部分用于加载更多按钮,另一部分用于选择下拉过滤器。两者都在AJAX中在前端重新加载属性列表,并协同工作(例如,如果我在下拉列表中选择“最低价格”、“最高价格”和“床位数”,列表将刷新,“加载更多”按钮将正常工作)。

然而,我想对此进行增强,以便它也将一个参数推送到URL中,并让AJAX查看该参数。例如,如果我从下拉列表中选择“最低价格:100000,最高价格5000000”和“床位3”,AJax将正常运行,但URL也会更改为:

mydomain.com/?min_price=100000&max_price=5000000&beds=3 
反过来,可以直接输入这个URL,并在下拉菜单和AJAX调用中预选过滤器。

这是我的代码:

JS公司:

jQuery(function($){


 // AJAX Stuff for filters + load more button

/*
 * Load More
 */
$(\'#prop_loadmore\').click(function(){

    $.ajax({
        url : prop_loadmore_params.ajaxurl, 
        data : {
            \'action\': \'loadmorebutton\',
            \'query\': prop_loadmore_params.posts, // loop parameters passed by wp_localize_script()
            \'page\' : prop_loadmore_params.current_page, // Get the current page

        },
        type : \'POST\',
        beforeSend : function ( xhr ) {
            $(\'#prop_loadmore\').text( \'Loading...\' ); 
            $(\'#prop_loadmore\').addClass( \'loading\' );

        },
        success : function( posts ){
            if( posts ) {
                $(\'#prop_loadmore\').removeClass( \'loading\' );
                $(\'#prop_loadmore\').text( \'More Listings\' );
                $(\'#main_posts\').append( posts ); 
            //    $(".price-txt").digits(); // Add the commas!
                localStorage.setItem("posts", posts);
                prop_loadmore_params.current_page++; // Increase current page by 1

                var params = new URLSearchParams(location.search);
                params.set(\'page\', prop_loadmore_params.current_page);
                window.history.replaceState({}, "", decodeURIComponent(`${location.pathname}?${params}`));


                if ( prop_loadmore_params.current_page == prop_loadmore_params.max_page ) 
                    $(\'#prop_loadmore\').hide(); // if last page, hide loadmore

            } else {
                $(\'#prop_loadmore\').hide(); // if no properties, hide loadmore
            }
        }
    });
    return false;
});

/*
 * Filter
 */
$(\'#filter\').change(function(){

    $.ajaxSetup({cache: false});

    $.ajax({
        url : prop_loadmore_params.ajaxurl,
        data : $(\'#filter\').serialize(), 
        dataType : \'json\',

        success : function( data ){

            // reset current page to 1 when filters on
            prop_loadmore_params.current_page = 1;

            prop_loadmore_params.posts = data.posts;

            // set max page
            prop_loadmore_params.max_page = data.max_page;

            found_posts = data.found_posts 

            //First pull out the empty strings

            var formData = $(\'#filter\').serializeArray().filter(function (i) {
                if(i.value != \'prop_filters\') {
                    return i.value;
                }
            });

            //Now push formData to URL
            window.history.pushState(\'\', \'title\', \'?\' + $.param(formData) + \'&page=\' + prop_loadmore_params.current_page);

            $(\'#main_posts\').html(data.content);
            $(\'.listings-count\').text( found_posts + \' Real Estate Listings for Sale\' );


            if (found_posts > 9) {
                $(\'#prop_loadmore\').show();
            }
             if ( prop_loadmore_params.current_page == prop_loadmore_params.max_page ) 
                    $(\'#prop_loadmore\').hide(); // if last page, hide loadmore




            // If not enough posts for 2nd page, hide loadmore
            if ( data.max_page < 2 ) {
                $(\'#prop_loadmore\').hide();
            } else {
                $(\'#prop_loadmore\').show();
            }
        }
    });

    return false;

});

});
功能。php:

add_action( \'wp_enqueue_scripts\', \'properties_script_and_styles\');

function properties_script_and_styles() {
global $wp_query;

wp_register_script( \'property_scripts\', get_stylesheet_directory_uri() . \'/assets/js/properties.js\', array(\'jquery\') );


$the_page = $wp_query->query_vars[\'paged\'] ? $wp_query->query_vars[\'paged\'] : 1;

if (!empty($_GET[\'page\'])) {
    $the_page = $_GET[\'page\'];
}

wp_localize_script( \'property_scripts\', \'prop_loadmore_params\', array(
    \'ajaxurl\' => site_url() . \'/wp-admin/admin-ajax.php\', 
    \'posts\' => $wp_query->query_vars,
    \'current_page\' => $the_page,
    \'max_page\' => $wp_query->max_num_pages,
    \'found_posts\' => $wp_query->found_posts,

) );

wp_enqueue_script( \'property_scripts\' );
}

add_action(\'wp_ajax_loadmorebutton\', \'prop_loadmore_ajax_handler\');
add_action(\'wp_ajax_nopriv_loadmorebutton\', \'prop_loadmore_ajax_handler\');

function prop_loadmore_ajax_handler(){

$args = json_decode(  $_POST[\'query\'] ); 
$args[\'paged\'] = $_POST[\'page\'] + 1; 
 if (!is_user_logged_in()) {
    $args[\'post_status\'] = \'publish\';
}
else {
    $args[\'post_status\'] = array(\'publish\', \'private\');
}
query_posts( $args );

if( have_posts() ) :


    while( have_posts() ): the_post();

        get_template_part( \'template-parts/post/content\', get_post_format() );

    endwhile;
endif;
die;
}


function prepare_property_filters(array $args): array {

/** Price Args**/

if (!empty($_REQUEST[\'price_min\']) || !empty($_REQUEST[\'price_max\'])) 
{
    $args[\'meta_query\'] = [\'relation\'=>\'AND\'];
}

// If Both
if( !empty( $_REQUEST[\'price_min\'] ) && !empty( $_REQUEST[\'price_max\'] )) {
    $args[\'meta_query\'][] = array(
        \'key\' => \'price\',
        \'value\' => array( $_REQUEST[\'price_min\'], 
$_REQUEST[\'price_max\'] ),
        \'type\' => \'numeric\',
        \'compare\' => \'between\'
    );
} else {
    // if only min price
    if( !empty( $_REQUEST[\'price_min\'] ) ) {
        $args[\'meta_query\'][] = array(
            \'key\' => \'price\',
            \'value\' => $_REQUEST[\'price_min\'],
            \'type\' => \'numeric\',
            \'compare\' => \'>\'
        );
    }
}

    // if only max price
    if( !empty( $_REQUEST[\'price_max\'] ) ) {
        $args[\'meta_query\'][] = array(
            \'key\' => \'price\',
            \'value\' => $_REQUEST[\'price_max\'],
            \'type\' => \'numeric\',
            \'compare\' => \'<\'
        );
    }

//* 
// Bedrooms Arg
//*
    if( !empty( $_REQUEST[\'beds\'] ) ) {
        $args[\'meta_query\'][] = array(
            \'key\' => \'bedrooms\',
            \'value\' => $_REQUEST[\'beds\'],
            \'type\' => \'numeric\',
            \'compare\' => \'>=\'
        );
    }

//* 
// Property Type Arg
//*
    if( !empty( $_REQUEST[\'type\'] ) ) {
        $args[\'meta_query\'][] = array(
            \'key\' => \'property_type\',
            \'value\' => $_REQUEST[\'type\'],
            \'compare\' => \'IN\'
        );
    }

return $args;
}


add_action(\'wp_ajax_prop_filters\', \'property_filters\'); 
add_action(\'wp_ajax_nopriv_prop_filters\', \'property_filters\');

function property_filters() {
//*
// Sort by Args
//*

    if( $_REQUEST[\'sort_by\'] === \'price-desc\' ) {
        $orderby = \'meta_value_num\'; 
        $order = \'DESC\';
        $meta_key = \'price\';
    }

    elseif( $_REQUEST[\'sort_by\'] === \'price-asc\' ) {
        $orderby = \'meta_value_num\'; 
        $order = \'ASC\';
        $meta_key = \'price\';
    }
    elseif( $_REQUEST[\'sort_by\'] === \'bedrooms-desc\' ) {
        $orderby = \'meta_value_num\'; 
        $order = \'DESC\';
        $meta_key = \'bedrooms\';
    }
    elseif( $_REQUEST["sort_by"] === \'bedrooms-asc\' ) {
        $orderby = \'meta_value_num\'; 
        $order = \'ASC\';
        $meta_key = \'bedrooms\';
    }
    else {
        $orderby = \'date\'; 
        $order = \'DESC\';
        $meta_key = \'\';
    }
$args = prepare_property_filters([
    \'posts_per_page\' => 9, 
    \'post_status\' => is_user_logged_in() ? [\'publish\', \'private\'] : [\'publish\'],
    \'paged\' => $_POST[\'page\'],
    \'meta_key\' => $meta_key,
    \'orderby\' => $orderby,
    \'order\' => $order
]);
query_posts( $args );

    global $wp_query;

    if( have_posts() ) :

        ob_start();

        while( have_posts() ): the_post();

            get_template_part( \'template-parts/post/content\', get_post_format() );

        endwhile;

        $posts_html = ob_get_contents(); 
        ob_end_clean(); 
    else:
        $posts_html = \'<p>Nothing found for your criteria.</p>\';
    endif;

    echo json_encode( array(
        \'posts\' => json_encode( $wp_query->query_vars ),
        \'max_page\' => $wp_query->max_num_pages,
        \'found_posts\' => $wp_query->found_posts,
        \'content\' => $posts_html,
    ) );

    die();
}
以及HTML:

<input id="filter_toggle"  type="checkbox">
<?php //We need to save the varaibles in arrays, so we can then check them against the URL and populate the dropdowns

$price_min = [
\'\' => \'Any Price\',
\'100000\' => \'$100,000\',
\'150000\' => \'$150,000\',
\'200000\' => \'$200,000\',
\'250000\' => \'$250,000\',
//etc
];

$price_max = [
\'\' => \'Any Price\',
\'100000\' => \'$100,000\',
\'150000\' => \'$150,000\',
\'200000\' => \'$200,000\',
\'250000\' => \'$250,000\',
//etc
];

$beds = [
\'\' => \'All Beds\',
\'1\' => \'1+\',
\'2\' => \'2+\',
\'3\' => \'3+\',
\'4\' => \'4+\',
\'5\' => \'5+\'
];

$property_type = [
\'\' => \'All Property Types\',
\'single-family-home\' => \'Single Family Home\',
\'condo\' => \'Condo\',
\'land\' => \'Land\',
\'townhouse\' => \'Townhouse\'
];

$sort_by = [
\'newest\' => \'Sort by Newest\',
\'price-desc\' => \'Sort by Price (High to Low)\',
\'price-asc\' => \'Sort by Price (Low to High)\',
\'bedrooms-desc\' => \'Sort by Beds (Most to Least)\',
\'bedrooms-asc\' => \'Sort by Beds (Least to Most)\'
];
?>

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

  <select name="price_min" class="min_max_select">
    <option disabled="disabled" selected="" value="">Minimum Price</option>
    <?php foreach ($price_min as $key => $value) {
         $selected = \'\';
         if ($_GET[\'price_min\'] == $key) {
             $selected = \' selected="selected"\';
         }
         printf(
             \'<option value="%s"%s>%s</option>\',
             $key,
             $selected,
             $value
         );
     } ?>
  </select>

  <select name="price_max" class="min_max_select">
    <option disabled="disabled" selected="selected" value="">Maximum Price</option>
    <?php foreach ($price_max as $key => $value) {
         $selected = \'\';
         if ($_GET[\'price_max\'] == $key) {
             $selected = \' selected="selected"\';
         }
         printf(
             \'<option value="%s"%s>%s</option>\',
             $key,
             $selected,
             $value
         );
     } ?>
  </select>

  <select name="beds" class="select_beds">
    <option disabled="disabled" selected="selected" value="">Bedrooms</option>
    <?php foreach ($beds as $key => $value) {
         $selected = \'\';
         if ($_GET[\'beds\'] == $key) {
             $selected = \' selected="selected"\';
         }
         printf(
             \'<option value="%s"%s>%s</option>\',
             $key,
             $selected,
             $value
         );
     } ?>
  </select>

  <!-- <select>
    <option disabled="disabled" selected="selected" value="">Bathrooms</option>
    <option value="">All Baths</option>
    <option value="1+">1+</option>
    <option value="1+">2+</option>
    <option value="1+">3+</option>
    <option value="1+">4+</option>
    <option value="1+">5+</option>
  </select> -->

  <select name="type" class="sort_by_property_type">
    <option disabled="disabled" selected="selected" value="">Property Type</option>
    <?php foreach ($property_type as $key => $value) {
         $selected = \'\';
         if ($_GET[\'type\'] == $key) {
             $selected = \' selected="selected"\';
         }
         printf(
             \'<option value="%s"%s>%s</option>\',
             $key,
             $selected,
             $value
         );
     } ?>
  </select>

  <!-- <select>
    <option disabled="disabled" selected="selected" value="">Property View</option>
    <option value="">All Property Views</option>
    <option value="Golf View">Golf View</option>
    <option value="Ocean View">Ocean View</option>
    <option value="Ocean Front">Ocean Front</option>
  </select> -->

  <select name="sort_by" class="sort_by_dropdown">
    <?php
     foreach ($sort_by as $key => $value) {
         $selected = \'\';
         if ($_GET[\'sort_by\'] == $key) {
             $selected = \' selected="selected"\';
         }
         printf(
             \'<option value="%s"%s>%s</option>\',
             $key,
             $selected,
             $value
         );
     }
     ?>
  </select>

<input type="hidden" name="action" value="prop_filters" />
</div>

 <span class="reset_btn reset">reset</span>
<label class="done_btn" for="filter_toggle">Done</label>
</form> 
</div>

<ul id="main_posts" class="item-listings">
<?php 

//*
// Sort by Args
//*

    if( $_GET[\'sort_by\'] === \'price-desc\' ) {
        $orderby = \'meta_value_num\'; 
        $order = \'DESC\';
        $meta_key = \'price\';
    }

    elseif( $_GET[\'sort_by\'] === \'price-asc\' ) {
        $orderby = \'meta_value_num\'; 
        $order = \'ASC\';
        $meta_key = \'price\';
    }
    elseif( $_GET[\'sort_by\'] === \'bedrooms-desc\' ) {
        $orderby = \'meta_value_num\'; 
        $order = \'DESC\';
        $meta_key = \'bedrooms\';
    }
    elseif( $_GET["sort_by"] === \'bedrooms-asc\' ) {
        $orderby = \'meta_value_num\'; 
        $order = \'ASC\';
        $meta_key = \'bedrooms\';
    }
    else {
        $orderby = \'date\'; 
        $order = \'DESC\';
        $meta_key = \'\';
    }

    $per_page = 9;

    if(!empty( $_GET[\'page\'])) {
        $per_page = $_GET[\'page\'] * 9;
    }

// Build the inital Loop
$args = prepare_property_filters([
    \'posts_per_page\' => $per_page,
    \'paged\' => $_POST[\'page\'],
    \'meta_key\' => $meta_key,
    \'orderby\' => $orderby,
    \'order\' => $order
]);

query_posts($args);

if( have_posts() ) :

    while( have_posts() ): the_post();

        get_template_part( \'template-parts/post/content\', get_post_format() );

        $count_posts = $wp_query->found_posts; 

    endwhile;
endif;

?>
</ul>


<?php if (  $wp_query->max_num_pages > 1 ) :
    echo \'<div id="prop_loadmore">More Listings</div>\';
endif;?>

<span class="listings-count"><?php echo $count_posts;?> Real Estate Listings for Sale</span>
<!-- <span class="reset">reset</span> -->
编辑:删除了加载更多代码,因为它与此处无关。

EDIT2:添加了分页,因为它是相关的。。。

EDIT3:我很快就能让这一切正常运作了。我已经更新了上面的代码。唯一不起作用的是直接从URL加载时的“加载更多分页”按钮(例如,使用设置的参数刷新页面)。如果加载URL为:

mydomain。com/?最低价格=100000(&U);最高价格=5000000(&U);床=3?页码=3

它将正确加载所有属性,包括立即显示3页属性。单击“加载更多”按钮,它会更改?页码=3至?第=4页,但它附加了unfiltered 属性集。。。由于某些原因,在加载页面时,参数不会保存到单击时运行loadmore按钮的参数中。

1 个回复
SO网友:kero

我将把你的问题分为两部分:

使用查询参数作为页面加载过滤器的默认参数实现1。您首先需要提取要构建的逻辑$args 在里面property_filters() 因此可用于初始荷载:

function prepare_property_filters(array $args): array {
    if (!empty($_REQUEST[\'price_min\']) || !empty($_REQUEST[\'price_max\'])) {
        $args[\'meta_query\'] = [\'relation\'=>\'AND\'];
    }
    // etc.
    return $args;
}
我对您的代码进行了一些其他更改:

添加type declarations.isset($foo) && $foo 到!empty($foo) 这基本上是一样的*使用short array syntax.$_POST 到$_REQUEST, 这里的好处是,您不必区分$_GET$_POST.

功能。php

function property_filters() {
    $order = explode( \'-\', $_POST[\'sort_by_dropdown\'] );

    $args = prepare_property_filters([
        \'posts_per_page\' => 9, 
        \'post_status\' => is_user_logged_in() ? [\'publish\', \'private\'] : [\'publish\'],
        \'paged\' => $_POST[\'page\']
    ]);
    query_posts( $args );

    global $wp_query;
    if( have_posts() ) :
       // etc.
HTML

<ul id="main_posts" class="item-listings">
<?php 
// Build the inital Loop
$args = prepare_property_filters([
    \'posts_per_page\' => 9,
    \'paged\' => $paged
]);

query_posts($args);
// etc.

Now on the initial page load and with the query parameters, you should see the list properly filtered.

但是用户不会预先选择这些值,所以请像这样更新表单HTML

<?php
$price_min = [
    \'\' => \'Any Price\',
    \'100000\' => \'$100,000\',
    //etc.
];
?>
<select name="price_min" class="min_max_select">
    <option disabled="disabled" selected="selected" value="">Minimum Price</option>
     <?php
     foreach ($price_min as $key => $value) {
         $selected = \'\';
         if (!empty($_GET[$key]) && $_GET[$key] === $value) {
             $selected = \' selected="selected"\';
         }
         printf(
             \'<option value="%s"%s>%s</option>\',
             $key,
             $selected,
             $value
         );
     }
     ?>
</select>
Now we truly solved problem #1. 如果存在查询参数,则将对列表进行预筛选,并且已在表单中选择适当的筛选器。

至于问题#2,这可以归结为“在不重新加载的情况下更改到新URL”,这已经有了很好的答案,如this one. 通常的想法是window.history.pushState(). (检查MDN docs for the History API 要了解这一点,请查看。)

$(\'#filter\').change(function(){

    $.ajax({
        url : prop_loadmore_params.ajaxurl,
        data : $(\'#filter\').serialize(), 
        dataType : \'json\',
        type : \'POST\',
        beforeSend : function(xhr){
            $(\'#filter\').find(\'button\').text(\'Filtering...\');
        },
        success : function( data ){
            // set HTML, variables, etc. as you currently do

            window.history.pushState($(\'#filter\'), \'title\', \'?\' + $(\'#filter\').serialize());
        }
    });

    return false;
});
我不完全确定,如果使用title(第二个参数),您可能也可以通过localize传递它。

这应该更改URL以反映更改的表单。And this solves problem #2.

从技术上讲,这不是事实,但根据我的经验,在大多数用例中,边缘情况并不重要

相关推荐

如何处理多个AJAX WordPress查询?

我对两个ajax操作有问题。我有一个post grid,它有一个前端排序“ASC”和“DESC”。因此,如果我单击“DESC”,它会将WordPress查询参数“order by”更改为“DESC”。它起作用了。但我有加载更多按钮,这也是ajax。它也可以工作,但不考虑上面的情况,因为它的查询参数与initial保持相同。因此,如果我单击DESC按钮并单击load more,它将加载第二个页面,而不考虑DESC。有任何可能的解决方法吗?