Если вы используете WordPress для управления заказами, но не хотите или не можете использовать WooCommerce, возникает задача создания удобного и автоматического отчета по заказам. В этой статье мы разберем, как организовать систему хранения заказов на пользовательском типе записей и создавать отчеты с фильтрацией и выгрузкой в CSV, используя чистый PHP и возможности WordPress.
Создание пользовательского типа записей для заказов
Для начала, чтобы хранить заказы вне WooCommerce, создадим отдельный тип записей wporders_order. Это позволит гибко управлять заказами через админку и программно.
function wporders_register_order_post_type() {
$labels = array(
'name' => 'Заказы',
'singular_name' => 'Заказ',
'add_new' => 'Добавить заказ',
'add_new_item' => 'Добавить новый заказ',
'edit_item' => 'Редактировать заказ',
'new_item' => 'Новый заказ',
'view_item' => 'Просмотреть заказ',
'search_items' => 'Поиск заказов',
'not_found' => 'Заказы не найдены',
'not_found_in_trash' => 'В корзине заказы не найдены',
'menu_name' => 'Заказы'
);
$args = array(
'labels' => $labels,
'public' => false,
'show_ui' => true,
'capability_type' => 'post',
'hierarchical' => false,
'menu_position' => 20,
'supports' => array('title','custom-fields'),
'has_archive' => false
);
register_post_type('wporders_order', $args);
}
add_action('init', 'wporders_register_order_post_type');
Теперь в админке WordPress появится раздел «Заказы», где можно добавлять и редактировать заказы вручную.
Добавление метаполей для хранения данных заказа
Каждому заказу нужны дополнительные данные: имя клиента, email, телефон, сумма заказа, статус и другие параметры. Для этого используем метаполя (custom fields). Можно добавить их вручную через админку, но удобнее использовать metabox с кодом:
function wporders_add_order_metabox() {
add_meta_box(
'wporders_order_details',
'Детали заказа',
'wporders_order_metabox_callback',
'wporders_order',
'normal',
'high'
);
}
add_action('add_meta_boxes', 'wporders_add_order_metabox');
function wporders_order_metabox_callback($post) {
wp_nonce_field('wporders_save_order_details', 'wporders_order_nonce');
$customer_name = get_post_meta($post->ID, '_wporders_customer_name', true);
$customer_email = get_post_meta($post->ID, '_wporders_customer_email', true);
$order_amount = get_post_meta($post->ID, '_wporders_order_amount', true);
$order_status = get_post_meta($post->ID, '_wporders_order_status', true);
?>
<p><label>Имя клиента:<br />
<input type="text" name="wporders_customer_name" value="<?php echo esc_attr($customer_name); ?>" size="30" /></label></p>
<p><label>Email клиента:<br />
<input type="email" name="wporders_customer_email" value="<?php echo esc_attr($customer_email); ?>" size="30" /></label></p>
<p><label>Сумма заказа:<br />
<input type="number" step="0.01" name="wporders_order_amount" value="<?php echo esc_attr($order_amount); ?>" size="10" /></label></p>
<p><label>Статус заказа:<br />
<select name="wporders_order_status">
<option value="pending" <?php selected($order_status, 'pending'); ?>>Ожидает</option>
<option value="processing" <?php selected($order_status, 'processing'); ?>>В обработке</option>
<option value="completed" <?php selected($order_status, 'completed'); ?>>Завершен</option>
<option value="cancelled" <?php selected($order_status, 'cancelled'); ?>>Отменен</option>
</select></label></p>
<?php
}
function wporders_save_order_details($post_id) {
if (!isset($_POST['wporders_order_nonce']) || !wp_verify_nonce($_POST['wporders_order_nonce'], 'wporders_save_order_details')) {
return;
}
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if (isset($_POST['wporders_customer_name'])) {
update_post_meta($post_id, '_wporders_customer_name', sanitize_text_field($_POST['wporders_customer_name']));
}
if (isset($_POST['wporders_customer_email'])) {
update_post_meta($post_id, '_wporders_customer_email', sanitize_email($_POST['wporders_customer_email']));
}
if (isset($_POST['wporders_order_amount'])) {
update_post_meta($post_id, '_wporders_order_amount', floatval($_POST['wporders_order_amount']));
}
if (isset($_POST['wporders_order_status'])) {
update_post_meta($post_id, '_wporders_order_status', sanitize_text_field($_POST['wporders_order_status']));
}
}
add_action('save_post_wporders_order', 'wporders_save_order_details');
Теперь при создании или редактировании заказа можно указать все нужные данные.
Вывод отчета по заказам с фильтрацией и экспортом в CSV
Основная задача — получить удобный отчет для анализа. Создадим админ-страницу, где можно выбрать диапазон дат, статус заказа и выгрузить данные в CSV.
Регистрация админ-страницы
function wporders_register_report_page() {
add_submenu_page(
'edit.php?post_type=wporders_order',
'Отчет по заказам',
'Отчет по заказам',
'manage_options',
'wporders_report',
'wporders_report_page_callback'
);
}
add_action('admin_menu', 'wporders_register_report_page');
Вывод формы фильтра и таблицы с результатами
function wporders_report_page_callback() {
if (!current_user_can('manage_options')) {
wp_die('Доступ запрещен');
}
$date_from = isset($_GET['date_from']) ? sanitize_text_field($_GET['date_from']) : '';
$date_to = isset($_GET['date_to']) ? sanitize_text_field($_GET['date_to']) : '';
$status = isset($_GET['status']) ? sanitize_text_field($_GET['status']) : '';
$export = isset($_GET['export']) ? true : false;
$args = array(
'post_type' => 'wporders_order',
'posts_per_page' => -1,
'post_status' => 'publish',
'meta_query' => array(),
'date_query' => array(),
);
if ($status) {
$args['meta_query'][] = array(
'key' => '_wporders_order_status',
'value' => $status,
'compare' => '=',
);
}
if ($date_from) {
$args['date_query'][] = array(
'after' => $date_from,
'inclusive' => true,
);
}
if ($date_to) {
$args['date_query'][] = array(
'before' => $date_to,
'inclusive' => true,
);
}
$query = new WP_Query($args);
if ($export) {
wporders_export_orders_csv($query->posts);
exit;
}
?>
<div class="wrap">
<h1>Отчет по заказам</h1>
<form method="get">
<input type="hidden" name="post_type" value="wporders_order" />
<input type="hidden" name="page" value="wporders_report" />
<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>
<label>Статус:
<select name="status">
<option value="">Все</option>
<option value="pending" <?php selected($status, 'pending'); ?>>Ожидает</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>
<input type="submit" class="button" value="Фильтровать" />
<input type="submit" class="button" name="export" value="Экспорт в CSV" />
</form>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th>ID</th>
<th>Дата</th>
<th>Имя клиента</th>
<th>Email</th>
<th>Сумма</th>
<th>Статус</th>
</tr>
</thead>
<tbody>
<?php if ($query->have_posts()) : ?>
<?php foreach ($query->posts as $post) : ?>
<?php
$customer_name = get_post_meta($post->ID, '_wporders_customer_name', true);
$customer_email = get_post_meta($post->ID, '_wporders_customer_email', true);
$order_amount = get_post_meta($post->ID, '_wporders_order_amount', true);
$order_status = get_post_meta($post->ID, '_wporders_order_status', true);
?>
<tr>
<td><?php echo $post->ID; ?></td>
<td><?php echo get_the_date('Y-m-d', $post); ?></td>
<td><?php echo esc_html($customer_name); ?></td>
<td><?php echo esc_html($customer_email); ?></td>
<td><?php echo number_format(floatval($order_amount), 2, '.', ''); ?></td>
<td><?php echo esc_html($order_status); ?></td>
</tr>
<?php endforeach; ?>
<?php else : ?>
<tr><td colspan="6">Заказы не найдены.</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
<?php
}
function wporders_export_orders_csv($posts) {
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=orders_report.csv');
$output = fopen('php://output', 'w');
fputcsv($output, array('ID', 'Дата', 'Имя клиента', 'Email', 'Сумма', 'Статус'));
foreach ($posts as $post) {
$customer_name = get_post_meta($post->ID, '_wporders_customer_name', true);
$customer_email = get_post_meta($post->ID, '_wporders_customer_email', true);
$order_amount = get_post_meta($post->ID, '_wporders_order_amount', true);
$order_status = get_post_meta($post->ID, '_wporders_order_status', true);
$date = get_the_date('Y-m-d', $post);
fputcsv($output, array($post->ID, $date, $customer_name, $customer_email, $order_amount, $order_status));
}
fclose($output);
}
Такой отчет позволит быстро фильтровать заказы по датам и статусам, а при необходимости выгружать их в CSV для анализа в Excel или других программах.
Автоматизация создания заказов — пример использования REST API
Для полноты картины можно добавить создание заказов через REST API, чтобы интегрировать сайт с внешними системами или мобильными приложениями.
function wporders_register_rest_routes() {
register_rest_route('wporders/v1', '/order', array(
'methods' => 'POST',
'callback' => 'wporders_rest_create_order',
'permission_callback' => function () {
return current_user_can('edit_posts');
}
));
}
add_action('rest_api_init', 'wporders_register_rest_routes');
function wporders_rest_create_order(WP_REST_Request $request) {
$params = $request->get_json_params();
if (empty($params['customer_name']) || empty($params['customer_email']) || empty($params['order_amount'])) {
return new WP_Error('missing_data', 'Не хватает данных для создания заказа', array('status' => 400));
}
$new_order = array(
'post_title' => 'Заказ от ' . sanitize_text_field($params['customer_name']),
'post_type' => 'wporders_order',
'post_status' => 'publish'
);
$post_id = wp_insert_post($new_order);
if (is_wp_error($post_id)) {
return $post_id;
}
update_post_meta($post_id, '_wporders_customer_name', sanitize_text_field($params['customer_name']));
update_post_meta($post_id, '_wporders_customer_email', sanitize_email($params['customer_email']));
update_post_meta($post_id, '_wporders_order_amount', floatval($params['order_amount']));
update_post_meta($post_id, '_wporders_order_status', 'pending');
return array('order_id' => $post_id, 'message' => 'Заказ успешно создан');
}
Теперь внешние приложения могут создавать заказы через POST-запрос на /wp-json/wporders/v1/order с JSON телом:
{
"customer_name": "Иван Иванов",
"customer_email": "ivan@example.com",
"order_amount": 1500.50
}
Дополнительные советы и плагины для расширения функционала
Если вы хотите упростить работу с заказами, рекомендуем обратить внимание на плагины для кастомных полей и метабоксов, например Advanced Custom Fields. Он позволит создавать удобные интерфейсы для ввода данных.
Для автоматизации уведомлений и интеграции с почтой можно использовать Clearfy Pro, который расширяет возможности WordPress и улучшает производительность.
Итог
Использование пользовательского типа записей и метаполей — надежный способ управлять заказами без WooCommerce. Создание отчета с фильтрацией и экспортом в CSV дает удобство анализа, а REST API позволит интегрировать систему с внешними сервисами. Этот подход хорош для кастомных проектов, где WooCommerce избыточен или не подходит.
Если хотите быстро стартовать, рекомендуем использовать готовые решения и плагины с wpshop.ru.