Розробка кастомних REST API ендпоінтів WordPress

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.
Розробка та обслуговування будь-яких видів сайтів:
Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Розробка кастомних REST API ендпоінтів WordPress
Середня
~2-3 робочих дні
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Розробка користувацьких REST API енпоінтів WordPress

WordPress REST API існує з версії 4.4 і покриває стандартні операції з записами, таксономіями, користувачами. Але як тільки потребується нестандартний запит — агреговані дані, бізнес-логіка, інтеграція зі стороннім сервісом — потребується користувацький енпоінт. Розробка набору енпоінтів з автентифікацією і валідацією займає від 2 до 5 днів.

Реєстрація енпоінта

add_action('rest_api_init', function () {
    register_rest_route('my-plugin/v1', '/projects', [
        [
            'methods'             => WP_REST_Server::READABLE,
            'callback'            => 'my_plugin_get_projects',
            'permission_callback' => '__return_true',
            'args'                => [
                'category' => [
                    'type'              => 'string',
                    'sanitize_callback' => 'sanitize_title',
                ],
                'tech'     => [
                    'type'              => 'array',
                    'items'             => ['type' => 'string'],
                    'sanitize_callback' => function ($value) {
                        return array_map('sanitize_title', (array) $value);
                    },
                ],
                'per_page' => [
                    'type'              => 'integer',
                    'default'           => 12,
                    'minimum'           => 1,
                    'maximum'           => 100,
                    'sanitize_callback' => 'absint',
                ],
            ],
        ],
        [
            'methods'             => WP_REST_Server::CREATABLE,
            'callback'            => 'my_plugin_create_project',
            'permission_callback' => function () {
                return current_user_can('edit_posts');
            },
        ],
    ]);

    register_rest_route('my-plugin/v1', '/projects/(?P<id>\d+)', [
        'methods'             => WP_REST_Server::READABLE,
        'callback'            => 'my_plugin_get_project',
        'permission_callback' => '__return_true',
        'args'                => [
            'id' => [
                'validate_callback' => function ($param) {
                    return is_numeric($param) && $param > 0;
                },
            ],
        ],
    ]);
});

Обробник GET-запиту

function my_plugin_get_projects(WP_REST_Request $request): WP_REST_Response|WP_Error {
    $per_page = $request->get_param('per_page');
    $page     = $request->get_param('page');
    $category = $request->get_param('category');

    $query_args = [
        'post_type'      => 'project',
        'post_status'    => 'publish',
        'posts_per_page' => $per_page,
        'paged'          => $page,
    ];

    if ($category) {
        $query_args['tax_query'] = [[
            'taxonomy' => 'project_category',
            'field'    => 'slug',
            'terms'    => $category,
        ]];
    }

    $query    = new WP_Query($query_args);
    $projects = array_map('my_plugin_format_project', $query->posts);

    $response = new WP_REST_Response($projects, 200);
    $response->header('X-WP-Total',      $query->found_posts);
    $response->header('X-WP-TotalPages', $query->max_num_pages);

    return $response;
}

function my_plugin_format_project(WP_Post $post): array {
    $thumbnail_id  = get_post_thumbnail_id($post->ID);
    $thumbnail_url = $thumbnail_id
        ? wp_get_attachment_image_url($thumbnail_id, 'large')
        : null;

    return [
        'id'          => $post->ID,
        'slug'        => $post->post_name,
        'title'       => wp_strip_all_tags($post->post_title),
        'excerpt'     => wp_strip_all_tags(get_the_excerpt($post)),
        'url'         => get_permalink($post->ID),
        'thumbnail'   => $thumbnail_url,
        'client'      => get_post_meta($post->ID, 'project_client', true),
        'year'        => (int) get_post_meta($post->ID, 'project_year', true),
        'modified'    => get_post_modified_time('c', true, $post),
    ];
}

Обробник POST-запиту з валідацією

function my_plugin_create_project(WP_REST_Request $request): WP_REST_Response|WP_Error {
    $body = $request->get_json_params();

    if (empty($body['title'])) {
        return new WP_Error('missing_title', 'Заголовок обов\'язковий', ['status' => 422]);
    }

    $post_id = wp_insert_post([
        'post_type'    => 'project',
        'post_title'   => sanitize_text_field($body['title']),
        'post_content' => wp_kses_post($body['content'] ?? ''),
        'post_status'  => 'draft',
        'post_author'  => get_current_user_id(),
    ], true);

    if (is_wp_error($post_id)) {
        return new WP_Error('insert_failed', $post_id->get_error_message(), ['status' => 500]);
    }

    return new WP_REST_Response(
        ['id' => $post_id, 'url' => get_permalink($post_id)],
        201
    );
}

Автентифікація

WordPress REST API використовує cookie-автентифікацію (для /wp-admin) та Application Passwords (для зовнішніх клієнтів). Для SPA чи мобільного застосунку — JWT через плагін або власну реалізацію:

add_filter('rest_authentication_errors', function ($result) {
    if (!empty($result)) return $result;

    $auth_header = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
    if (!str_starts_with($auth_header, 'Bearer ')) {
        return $result;
    }

    $token = substr($auth_header, 7);
    $user_id = my_plugin_validate_jwt($token);

    if (is_wp_error($user_id)) {
        return $user_id;
    }

    wp_set_current_user($user_id);
    return true;
});

Кешування ответів

Для публічних енпоінтів з важкими запитами — Transients API:

function my_plugin_get_projects(WP_REST_Request $request): WP_REST_Response {
    $cache_key = 'projects_' . md5(serialize($request->get_params()));
    $cached    = get_transient($cache_key);

    if ($cached !== false) {
        $response = new WP_REST_Response($cached['data'], 200);
        $response->header('X-WP-Total', $cached['total']);
        $response->header('X-Cache', 'HIT');
        return $response;
    }

    // ... основна логіка ...

    set_transient($cache_key, ['data' => $projects, 'total' => $total], 5 * MINUTE_IN_SECONDS);
    return $response;
}

Інвалідація при змінені запису:

add_action('save_post_project', function (int $post_id): void {
    global $wpdb;
    $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_projects_%'");
});

Версіонування

Простір імен my-plugin/v1 обов'язковий — він дозволяє в майбутньому додати v2 з breaking changes без поломки існуючих клієнтів. Документуйте ответи через OpenAPI-схему або описи в args.