Tworzenie przyjaznego dla użytkownika filtra URL
This tutorial shows how to create a user-friendly URL filter for any WordPress post type. Follow our detailed steps to enhance filtering with structured and clean URLs.
Tworzymy filtr oparty na taksonomiach i polach meta dla dowolnego typu wpisu. Ten kod i podejście są uniwersalne i można je zastosować do wszystkich typów wpisów oraz taksonomii — wystarczy podstawić własne dane.
Przykład tworzenia adresu URL:
/{post_type_name}/filter/{taxonomy_name}-in-{term_slug}-or-{second_term_slug}-and-{meta_name}-in-{meta_value}
Separators:
- -and- — separator pierwszego poziomu
- -in- — separator drugiego poziomu
- -or- — separator trzeciego poziomu
Najpierw musimy nadpisać reguły permalinków. W tym celu używamy add_action(‘init’, ‘rewrite_rules’), gdzie bots to mój dedykowany typ wpisu.
/**
* Rewrite rules filter.
*
* @return void
*/
function rewrite_rules(): void {
add_rewrite_rule(
'bots/filter/([-_a-zA-Z0-9+%.:]+)/page/(\d+)/?$',
'index.php?post_type=bots&filter=$matches[1]&paged=$matches[2]',
'top'
); // rule for pagination support
add_rewrite_rule(
'bots/filter/([-_a-zA-Z0-9+%.:]+)/?$',
'index.php?post_type=bots&filter=$matches[1]',
'top'
); // main rule for overriding
}
add_action('init', 'rewrite_rules');
Teraz musimy dodać naszą zmienną do query_vars. Jest to konieczne, aby przechowywać nasze dane w zmiennej globalnej i umożliwić dostęp do nich.
/**
* Add Query vars filter
*
* @param array $vars Vars Query.
*
* @return array
*/
function add_filter_vars( array $vars ): array {
$vars[] = 'filter';
return $vars;
}
add_filter( 'query_vars', 'add_filter_vars' );
Następnie tworzymy formularz filtra. Poniżej znajduje się kod, którego użyłem w jednym z moich projektów.
<form action="<?php echo esc_url(admin_url('admin-post.php')); ?>" method="post" class="filter-form">
<!-- Your HTML form code here -->
<?php wp_nonce_field(TBL_FILTER_ACTION_NAME, 'filter_nonce'); ?>
<input type="hidden" name="action" value="<?php echo esc_attr(TBL_FILTER_ACTION_NAME); ?>">
<input type="hidden" id="sort_by" name="tbl_filter[sort_by]" value="">
<input type="hidden" id="price_sort" name="tbl_filter[price_sort]" value="">
<input class="button" type="submit" value="<?php esc_html_e('Filtered', 'telegram-bots-listing'); ?>">
</form>
Do przetwarzania danych z formularza używam admin-post, który pozwala przetwarzać dane formularza i generować na ich podstawie adres URL, działając na podobnej zasadzie jak standardowy handler żądań AJAX.
/**
* Filter bots handler.
*
* @return void
*/
public function filter_bot_handler(): void {
$filter_nonce = !empty($_POST['filter_nonce']) ? filter_var(wp_unslash($_POST['filter_nonce']), FILTER_SANITIZE_SPECIAL_CHARS) : null; // retrieve and clean data with the nonce code
if (!wp_verify_nonce($filter_nonce, Main::TBL_FILTER_ACTION_NAME)) {
wp_safe_redirect(filter_input(INPUT_POST, '_wp_http_referer', FILTER_SANITIZE_STRING));
die();
} // check the nonce, and if it's not valid, redirect the user back
$filter_args = [
'category' => ['filter' => FILTER_SANITIZE_SPECIAL_CHARS, 'flags' => FILTER_FORCE_ARRAY],
'language' => ['filter' => FILTER_SANITIZE_SPECIAL_CHARS, 'flags' => FILTER_FORCE_ARRAY],
'price' => FILTER_SANITIZE_SPECIAL_CHARS,
'sort_by' => FILTER_SANITIZE_SPECIAL_CHARS,
'price_sort' => FILTER_SANITIZE_SPECIAL_CHARS,
]; // array for cleaning and validating form data
// phpcs:disable
$filter_request = !empty($_POST['tbl_filter']) ? filter_var_array(wp_unslash($_POST['tbl_filter']), $filter_args) : [];
$rating = !empty($_POST['review_rating']) ? filter_var(wp_unslash($_POST['review_rating']), FILTER_SANITIZE_NUMBER_INT) : null;
// phpcs:enable
if (!empty($rating)) {
$filter_request['rating'] = $rating;
}
$param_url = generate_filter_url($filter_request); // pass the array to a function that will generate our URL
wp_safe_redirect($param_url . '/', 301); // redirect the user to our URL
die();
}
add_action('admin_post_nopriv_' . YOUR_ACTION_NAME, 'filter_bot_handler');
add_action('admin_post_' . YOUR_ACTION_NAME, 'filter_bot_handler');
Tablica zamienników znaków specjalnych:
const TBL_CODE_MATCH = [
'"', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '{', '}', '|', ':', '"', '<', '>', '?', '[', ']', ';', "'", '', '.', '/', '', '~', '`', '='
];
Funkcja generująca adres URL filtra:
/**
* Generate filter URL.
*
* @param array $params Params.
* @return string
*/
function generate_filter_url(array $params): string {
$params_array = [];
$redirect = get_bloginfo('url') . '/bots/filter/';
foreach ($params as $key => $item) {
$params_array[$key] = [];
if (is_array($item)) {
foreach ($item as $value) {
$params_array[$key][] = rawurlencode(str_replace(self::TBL_CODE_MATCH, '-', $value)); // clean special characters in the data and replace them with '-'
}
} else {
$params_array[$key][] = rawurlencode(str_replace(self::TBL_CODE_MATCH, '-', $item)); // clean special characters in the data and replace them with '-'
}
}
$i = 0;
foreach ($params_array as $key => $param) {
if (0 === $i && !empty($param[0])) {
$redirect .= $key . '-in-' . implode('-or-', (array) $param);
$i++;
continue;
}
foreach ($param as $index => $item) {
if (!empty($item)) {
$addon = (0 === $index) ? '-and-' . $key . '-in-' : '-or-';
$redirect .= $addon . $item;
}
}
}
return $redirect;
}
Ostatnim krokiem jest sparsowanie tego adresu URL i zmodyfikowanie głównego zapytania za pomocą filtra z wykorzystaniem następującej akcji: add_action(‘pre_get_posts’, ‘add_query_filter’).
/**
* Filter query.
*
* @param WP_Query $query WP Query.
* @return WP_Query
*/
function add_query_filter(WP_Query $query) {
if (
!is_admin() && $query->is_main_query() &&
is_post_type_archive('bots') &&
!empty($query->query_vars['filter'])
) {
// check for main_query and if data is present in query_vars['filter']
$args = [];
$filter_params = parse_url_query($query->query_vars['filter']); // parse our URL
if (empty($filter_params)) {
return $query;
}
foreach ($filter_params as $key => $value) {
switch ($key) {
case 'category':
$args['tax_query'][] = [
'taxonomy' => 'bot-category',
'field' => 'slug',
'terms' => $value,
'operator' => 'IN'
];
break;
case 'language':
$args['tax_query']['relation'] = 'AND';
$args['tax_query'][] = [
'taxonomy' => 'bot-languages',
'field' => 'slug',
'terms' => $value,
'operator' => 'IN'
];
break;
// additional cases...
}
}
foreach ($args as $key => $arg) {
if (!empty($arg)) {
$query->set($key, $arg);
}
}
return $query;
}
return $query;
}
add_action('pre_get_posts', 'add_query_filter');
Funkcja do parsowania adresu URL:
/**
* Parse string URL
*
* @param string $url_query URL Query.
* @return array|false
*/
function parse_url_query(string $url_query) {
$param_string = $url_query;
$query_arg = [];
if (!empty($param_string)) {
$params = explode('-and-', $param_string);
foreach ($params as $param) {
$items = explode('-in-', urldecode($param));
$param_name = $items[0];
unset($items[0]);
if (preg_match('-or-', $items[1])) {
$query_arg[$param_name] = explode('-or-', $items[1]);
} else {
$query_arg[$param_name] = $items;
}
}
return array_filter($query_arg);
} else {
return false;
}
}
Po dodaniu tego kodu filtr powinien działać w szablonie archive_{post_type}, a przefiltrowane dane będą dostępne w standardowej pętli wyświetlającej wyniki.
Gotowy, aby wynieść swój projekt
na wyższy poziom?
Wprowadźmy Twoją wizję w życie dzięki profesjonalnemu tworzeniu stron i dedykowanym rozwiązaniom.
Skontaktuj się z nami już teraz i rozpocznijmy pracę nad przekształceniem Twoich pomysłów w rzeczywistość!