Как создать автоматический отчет по заказам в WordPress без WooCommerce

Если вы используете 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.

WooCommerce: автоматическое отключение оплаты при повторных неудачных попытках
26.04.2026
Автоматическая синхронизация заказов между WordPress и внешними системами
30.03.2026
Добавление пользовательского поля в форму оформления заказа WooCommerce без плагинов
24.12.2025
Как добавить логирование ошибок при создании и обновлении заказов WooCommerce
04.06.2026
Добавление оценок и отзывов к заказам WooCommerce с примерами кода
01.03.2026