我有一个定义良好的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按钮的参数中。
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.
从技术上讲,这不是事实,但根据我的经验,在大多数用例中,边缘情况并不重要