В некоторых случаях на сайтах с заказами, но без использования WooCommerce, возникает необходимость создать собственный список заказов с возможностью удобной фильтрации и поиска. В этой статье разберём, как сделать удобный фильтрованный список заказов на базе собственного типа записей в WordPress и добавить фильтры по статусу, дате и пользователю с помощью пользовательских мета-полей и параметров запроса.
Создание собственного типа записей «Заказы» и добавление мета-полей
Первым шагом создадим кастомный тип записей для заказов, например, wporders_order. Это позволит хранить заказы как отдельные записи с нужными мета-данными.
function wporders_register_order_post_type() {
$labels = array(
'name' => 'Заказы',
'singular_name' => 'Заказ',
'menu_name' => 'Заказы',
'add_new' => 'Добавить заказ',
'add_new_item' => 'Добавить новый заказ',
'edit_item' => 'Редактировать заказ',
'new_item' => 'Новый заказ',
'view_item' => 'Просмотр заказа',
'search_items' => 'Поиск заказов',
'not_found' => 'Заказы не найдены',
'not_found_in_trash' => 'Заказы не найдены в корзине',
);
$args = array(
'labels' => $labels,
'public' => false,
'show_ui' => true,
'show_in_menu' => true,
'capability_type' => 'post',
'supports' => array('title','editor'),
'has_archive' => false,
);
register_post_type('wporders_order', $args);
}
add_action('init', 'wporders_register_order_post_type');
Для хранения информации о статусе заказа, дате оформления и клиенте добавим произвольные поля (мета-поля). Например:
order_status— статус заказа (в обработке, выполнен, отменён и т.д.)order_date— дата заказаorder_customer— ID или имя клиента
Для удобства можно использовать плагин Clearfy Pro для создания и управления мета-полями без программирования.
Вывод списка заказов с фильтрами на фронтенде
Создадим шаблон или шорткод, который выводит таблицу заказов с возможностью фильтрации по параметрам.
Шорткод для вывода фильтрованного списка заказов
function wporders_shortcode_order_list($atts) {
// Получаем параметры фильтра из GET-запроса
$status = isset($_GET['status']) ? sanitize_text_field($_GET['status']) : '';
$customer = isset($_GET['customer']) ? sanitize_text_field($_GET['customer']) : '';
$date_from = isset($_GET['date_from']) ? sanitize_text_field($_GET['date_from']) : '';
$date_to = isset($_GET['date_to']) ? sanitize_text_field($_GET['date_to']) : '';
// Формируем аргументы WP_Query
$meta_query = array('relation' => 'AND');
if ($status) {
$meta_query[] = array(
'key' => 'order_status',
'value' => $status,
);
}
if ($customer) {
$meta_query[] = array(
'key' => 'order_customer',
'value' => $customer,
'compare' => 'LIKE'
);
}
if ($date_from || $date_to) {
$date_query = array('key' => 'order_date');
if ($date_from) {
$date_query['value'][] = $date_from;
$date_query['compare'][] = '>=';
}
if ($date_to) {
$date_query['value'][] = $date_to;
$date_query['compare'][] = '<=';
}
$meta_query[] = $date_query;
}
$args = array(
'post_type' => 'wporders_order',
'posts_per_page' => 20,
'meta_query' => $meta_query,
'orderby' => 'meta_value',
'meta_key' => 'order_date',
'order' => 'DESC',
);
$query = new WP_Query($args);
ob_start();
?>
<form method="get" class="wporders-filter-form">
<label>Статус:
<select name="status">
<option value="">Все</option>
<option value="processing" <?php selected($status, 'processing'); ?>>В обработке</option>
<option value="completed" <?php selected($status, 'completed'); ?>>Выполнен</option>
<option value="cancelled" <?php selected($status, 'cancelled'); ?>>Отменён</option>
</select>
</label>
<label>Клиент:
<input type="text" name="customer" value="<?php echo esc_attr($customer); ?>" placeholder="Имя или ID клиента">
</label>
<label>Дата с:
<input type="date" name="date_from" value="<?php echo esc_attr($date_from); ?>">
</label>
<label>Дата по:
<input type="date" name="date_to" value="<?php echo esc_attr($date_to); ?>">
</label>
<button type="submit">Фильтровать</button>
</form>
<table class="wporders-table" border="1" cellpadding="5" cellspacing="0" style="width:100%; margin-top:15px;">
<thead>
<tr>
<th>ID</th>
<th>Название</th>
<th>Статус</th>
<th>Клиент</th>
<th>Дата</th>
</tr>
</thead>
<tbody>
<?php
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
$status_val = get_post_meta(get_the_ID(), 'order_status', true);
$customer_val = get_post_meta(get_the_ID(), 'order_customer', true);
$date_val = get_post_meta(get_the_ID(), 'order_date', true);
echo '<tr>';
echo '<td>' . get_the_ID() . '</td>';
echo '<td><a href="' . get_edit_post_link() . '">' . get_the_title() . '</a></td>';
echo '<td>' . esc_html($status_val) . '</td>';
echo '<td>' . esc_html($customer_val) . '</td>';
echo '<td>' . esc_html($date_val) . '</td>';
echo '</tr>';
}
} else {
echo '<tr><td colspan="5">Заказы не найдены</td></tr>';
}
wp_reset_postdata();
?></tbody>
</table>
<?php
return ob_get_clean();
}
add_shortcode('wporders_order_list', 'wporders_shortcode_order_list');
Этот шорткод можно вставить в любую страницу или запись для отображения заказов с фильтрами.
Использование AJAX для обновления списка заказов без перезагрузки страницы
Чтобы улучшить UX, можно добавить AJAX-запросы для фильтрации без перезагрузки. Это требует подключения JS и обработки AJAX-запросов на сервере.
Пример обработчика AJAX для фильтрации заказов
add_action('wp_ajax_wporders_filter_orders', 'wporders_ajax_filter_orders');
add_action('wp_ajax_nopriv_wporders_filter_orders', 'wporders_ajax_filter_orders');
function wporders_ajax_filter_orders() {
$status = isset($_POST['status']) ? sanitize_text_field($_POST['status']) : '';
$customer = isset($_POST['customer']) ? sanitize_text_field($_POST['customer']) : '';
$date_from = isset($_POST['date_from']) ? sanitize_text_field($_POST['date_from']) : '';
$date_to = isset($_POST['date_to']) ? sanitize_text_field($_POST['date_to']) : '';
// Аналогично формируем WP_Query с фильтрами, как в шорткоде
$meta_query = array('relation' => 'AND');
if ($status) {
$meta_query[] = array('key' => 'order_status', 'value' => $status);
}
if ($customer) {
$meta_query[] = array('key' => 'order_customer', 'value' => $customer, 'compare' => 'LIKE');
}
if ($date_from || $date_to) {
$date_query = array('key' => 'order_date');
if ($date_from) $date_query['value'][] = $date_from;
if ($date_to) $date_query['value'][] = $date_to;
if ($date_from && $date_to) $date_query['compare'] = 'BETWEEN';
elseif ($date_from) $date_query['compare'] = '>=';
elseif ($date_to) $date_query['compare'] = '<=';
$meta_query[] = $date_query;
}
$args = array(
'post_type' => 'wporders_order',
'posts_per_page' => 20,
'meta_query' => $meta_query,
'orderby' => 'meta_value',
'meta_key' => 'order_date',
'order' => 'DESC',
);
$query = new WP_Query($args);
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
$status_val = get_post_meta(get_the_ID(), 'order_status', true);
$customer_val = get_post_meta(get_the_ID(), 'order_customer', true);
$date_val = get_post_meta(get_the_ID(), 'order_date', true);
echo '<tr>';
echo '<td>' . get_the_ID() . '</td>';
echo '<td>' . get_the_title() . '</td>';
echo '<td>' . esc_html($status_val) . '</td>';
echo '<td>' . esc_html($customer_val) . '</td>';
echo '<td>' . esc_html($date_val) . '</td>';
echo '</tr>';
}
} else {
echo '<tr><td colspan="5">Заказы не найдены</td></tr>';
}
wp_reset_postdata();
wp_die();
}
В JS необходимо отправлять AJAX-запрос на admin-ajax.php с действием wporders_filter_orders и параметрами фильтра. При успешном ответе заменять содержимое таблицы.
Советы по расширению функционала
Можно добавить:
- Пагинацию с AJAX для загрузки следующей страницы заказов
- Экспорт отфильтрованных заказов в CSV
- Добавление кнопок для быстрого изменения статуса заказа в списке
- Использование плагина WPRemark для управления комментариями и заметками по заказам
Также можно интегрировать список с внешними системами, например 1С, через REST API или вебхуки для автоматизации обработки заказов.