根据自定义 post 类型的最低和最高价格过滤查询
Filter query based on min and max price for custom post type
我有一个名为 price
的 ACF 字段。 price
分配给 vehicle
post 类型。
我还有一个过滤器,允许用户根据定义的 min price
和 max price
.
显示 vehicle
我正在尝试展示介于定义的 min price
和 max price
范围之间的 vehicle
的结果。
这是我目前的情况:
<?php
// get data from url
$min_price = $_GET['min-price'];
$max_price = $_GET['max-price'];
global $post;
$args = array(
'post_type' => 'vehicle',
'post_status' => 'publish',
'orderby' => 'publish_date',
'order' => 'DESC',
'meta_query' => array(
array(
'key' => 'price',
'value' => array($min_price, $max_price),
'compare' => 'BETWEEN',
'type' => 'numeric',
)
),
);
$query = new WP_Query( $args );
if($query->have_posts() ) :
while ( $query->have_posts() ) : $query->the_post();
$price = get_field("price");
$price = preg_replace("/[^0-9]/", "", $price);
echo the_title();
endwhile; wp_reset_postdata();
else : ?>
<h2><?php _e("no posts found"); ?></h2>
<?php endif; ?>
?>
A var_dump($price)
returns string(0) ""
。我显然需要在 while
循环中定义 $price
,但不确定在那种情况下我将如何在上面查询它?我只想 return 那个范围内的 post。
因为您将数字数据存储为字符串,所以随着时间的推移,您将 运行 在很多地方遇到问题。即使是像排序这样简单的事情现在也变得困难了。 (而且我不是在判断,它就是这样。)如果您可以将此数据存储为真正的数字并在其他地方处理格式,那么您的代码将更容易维护 运行.
不幸的是,由于上述限制,本机 WordPress 查询将无法让您到达目的地。然而,WordPress 有大量的钩子,特别是 post_clauses
允许您修改 SQL 查询的 WHERE
子句以满足您的需要。 (实际上有很多,我通常更喜欢在这个特定的地方做。)
首先,我将通过添加一个附加参数来调整您的 $args
。只要不和别的东西冲突就行,我用的是FIX_RANGE_QUERY
.
$args =
[
'FIX_RANGE_QUERY' => true,
'post_type' => 'vehicle',
'post_status' => 'publish',
'orderby' => 'publish_date',
'order' => 'DESC',
'meta_query' => [
[
'key' => 'price',
'value' => [$min_price, $max_price],
'compare' => 'BETWEEN',
'type' => 'numeric',
]
],
];
$query = new WP_Query($args);
这本身不会改变任何东西,你还需要一个过滤器,它可能应该在 之前 上面,最好在 functions.php
或类似的。我已经在这段代码中添加了一堆注释,希望能遍历它所做的一切,但要点是它修改了 SQL 查询的 WHERE
子句,以包含一个正则表达式来删除非数字在进行转换和比较之前。
add_filter(
'posts_clauses',
static function ($clauses, WP_Query $query) {
// Look for our magic variable so that we only modify our certain query
if (true === ($query->query['FIX_RANGE_QUERY'] ?? false)) {
// Make sure that we've got something in the WHERE position
$where = $clauses['where'] ?? null;
if ($where) {
// We need this in order to get the prefix so that we are safe if this code is migrated
global $wpdb;
// The CAST() stuff is WordPress because the query specifies a NUMERIC type
$searchString = "CAST({$wpdb->prefix}postmeta.meta_value AS SIGNED)";
// Replace the above with an inner regex that removes everything except digits
$replaceString = "CAST(REGEXP_REPLACE({$wpdb->prefix}postmeta.meta_value, '[^0-9]+', '') AS SIGNED)";
// Reset the main clause
$clauses['where'] = str_replace($searchString, $replaceString, $where);
}
}
// No matter what, we must return this, otherwise EVERY query will break.
return $clauses;
},
9999,
2
);
以上代码将 WordPress 查询更改为:
AND (
( wp_postmeta.meta_key = 'price' AND CAST(wp_postmeta.meta_value AS SIGNED) BETWEEN '5' AND '100' )
) AND wp_posts.post_type = 'vehicle' AND ((wp_posts.post_status = 'publish'))
为此:
AND (
( wp_postmeta.meta_key = 'price' AND CAST(REGEXP_REPLACE(wp_postmeta.meta_value, '[^0-9]+', '') AS SIGNED) BETWEEN '5' AND '100' )
) AND wp_posts.post_type = 'vehicle' AND ((wp_posts.post_status = 'publish'))
此代码有点脆弱,仅供参考。如果任何间距关闭,str_replace
将找不到它要查找的内容。但总的来说应该还是很一致的。
我有一个名为 price
的 ACF 字段。 price
分配给 vehicle
post 类型。
我还有一个过滤器,允许用户根据定义的 min price
和 max price
.
vehicle
我正在尝试展示介于定义的 min price
和 max price
范围之间的 vehicle
的结果。
这是我目前的情况:
<?php
// get data from url
$min_price = $_GET['min-price'];
$max_price = $_GET['max-price'];
global $post;
$args = array(
'post_type' => 'vehicle',
'post_status' => 'publish',
'orderby' => 'publish_date',
'order' => 'DESC',
'meta_query' => array(
array(
'key' => 'price',
'value' => array($min_price, $max_price),
'compare' => 'BETWEEN',
'type' => 'numeric',
)
),
);
$query = new WP_Query( $args );
if($query->have_posts() ) :
while ( $query->have_posts() ) : $query->the_post();
$price = get_field("price");
$price = preg_replace("/[^0-9]/", "", $price);
echo the_title();
endwhile; wp_reset_postdata();
else : ?>
<h2><?php _e("no posts found"); ?></h2>
<?php endif; ?>
?>
A var_dump($price)
returns string(0) ""
。我显然需要在 while
循环中定义 $price
,但不确定在那种情况下我将如何在上面查询它?我只想 return 那个范围内的 post。
因为您将数字数据存储为字符串,所以随着时间的推移,您将 运行 在很多地方遇到问题。即使是像排序这样简单的事情现在也变得困难了。 (而且我不是在判断,它就是这样。)如果您可以将此数据存储为真正的数字并在其他地方处理格式,那么您的代码将更容易维护 运行.
不幸的是,由于上述限制,本机 WordPress 查询将无法让您到达目的地。然而,WordPress 有大量的钩子,特别是 post_clauses
允许您修改 SQL 查询的 WHERE
子句以满足您的需要。 (实际上有很多,我通常更喜欢在这个特定的地方做。)
首先,我将通过添加一个附加参数来调整您的 $args
。只要不和别的东西冲突就行,我用的是FIX_RANGE_QUERY
.
$args =
[
'FIX_RANGE_QUERY' => true,
'post_type' => 'vehicle',
'post_status' => 'publish',
'orderby' => 'publish_date',
'order' => 'DESC',
'meta_query' => [
[
'key' => 'price',
'value' => [$min_price, $max_price],
'compare' => 'BETWEEN',
'type' => 'numeric',
]
],
];
$query = new WP_Query($args);
这本身不会改变任何东西,你还需要一个过滤器,它可能应该在 之前 上面,最好在 functions.php
或类似的。我已经在这段代码中添加了一堆注释,希望能遍历它所做的一切,但要点是它修改了 SQL 查询的 WHERE
子句,以包含一个正则表达式来删除非数字在进行转换和比较之前。
add_filter(
'posts_clauses',
static function ($clauses, WP_Query $query) {
// Look for our magic variable so that we only modify our certain query
if (true === ($query->query['FIX_RANGE_QUERY'] ?? false)) {
// Make sure that we've got something in the WHERE position
$where = $clauses['where'] ?? null;
if ($where) {
// We need this in order to get the prefix so that we are safe if this code is migrated
global $wpdb;
// The CAST() stuff is WordPress because the query specifies a NUMERIC type
$searchString = "CAST({$wpdb->prefix}postmeta.meta_value AS SIGNED)";
// Replace the above with an inner regex that removes everything except digits
$replaceString = "CAST(REGEXP_REPLACE({$wpdb->prefix}postmeta.meta_value, '[^0-9]+', '') AS SIGNED)";
// Reset the main clause
$clauses['where'] = str_replace($searchString, $replaceString, $where);
}
}
// No matter what, we must return this, otherwise EVERY query will break.
return $clauses;
},
9999,
2
);
以上代码将 WordPress 查询更改为:
AND (
( wp_postmeta.meta_key = 'price' AND CAST(wp_postmeta.meta_value AS SIGNED) BETWEEN '5' AND '100' )
) AND wp_posts.post_type = 'vehicle' AND ((wp_posts.post_status = 'publish'))
为此:
AND (
( wp_postmeta.meta_key = 'price' AND CAST(REGEXP_REPLACE(wp_postmeta.meta_value, '[^0-9]+', '') AS SIGNED) BETWEEN '5' AND '100' )
) AND wp_posts.post_type = 'vehicle' AND ((wp_posts.post_status = 'publish'))
此代码有点脆弱,仅供参考。如果任何间距关闭,str_replace
将找不到它要查找的内容。但总的来说应该还是很一致的。