2026-03-02 17:25:21 +03:00
|
|
|
|
<?php
|
|
|
|
|
|
add_action('rest_api_init', function() {
|
|
|
|
|
|
register_rest_route('my/v1', '/author/(?P<slug>[a-zA-Z0-9-]+)', [
|
|
|
|
|
|
'methods' => 'GET',
|
|
|
|
|
|
'callback' => function($request) {
|
|
|
|
|
|
$slug = $request['slug'];
|
|
|
|
|
|
|
|
|
|
|
|
if (!function_exists('get_coauthors')) {
|
|
|
|
|
|
return new WP_Error('no_plugin', 'Co-Authors Plus not active', ['status' => 404]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
global $coauthors_plus;
|
|
|
|
|
|
|
|
|
|
|
|
if (isset($coauthors_plus) && method_exists($coauthors_plus, 'get_coauthor_by')) {
|
|
|
|
|
|
$coauthor = $coauthors_plus->get_coauthor_by('user_nicename', $slug);
|
|
|
|
|
|
|
|
|
|
|
|
if ($coauthor) {
|
2026-03-05 00:25:12 +03:00
|
|
|
|
// Получаем ID записи гостевого автора
|
|
|
|
|
|
$author_post_id = $coauthor->ID;
|
|
|
|
|
|
|
|
|
|
|
|
// ПОЛУЧАЕМ ФОТО ИЗ МИНИАТЮРЫ ЗАПИСИ (post thumbnail)
|
|
|
|
|
|
$photo = null;
|
|
|
|
|
|
$photo_sizes = [];
|
|
|
|
|
|
|
|
|
|
|
|
if (has_post_thumbnail($author_post_id)) {
|
|
|
|
|
|
$photo_id = get_post_thumbnail_id($author_post_id);
|
|
|
|
|
|
|
|
|
|
|
|
// Основные размеры
|
|
|
|
|
|
$photo_sizes = [
|
|
|
|
|
|
'thumbnail' => wp_get_attachment_image_url($photo_id, 'thumbnail'),
|
|
|
|
|
|
'medium' => wp_get_attachment_image_url($photo_id, 'medium'),
|
|
|
|
|
|
'large' => wp_get_attachment_image_url($photo_id, 'large'),
|
|
|
|
|
|
'full' => wp_get_attachment_image_url($photo_id, 'full'),
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
$photo = $photo_sizes['medium'];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-02 17:25:21 +03:00
|
|
|
|
return [
|
|
|
|
|
|
'id' => $coauthor->user_nicename,
|
|
|
|
|
|
'name' => $coauthor->display_name,
|
|
|
|
|
|
'firstName' => $coauthor->first_name ?? '',
|
|
|
|
|
|
'lastName' => $coauthor->last_name ?? '',
|
|
|
|
|
|
'description' => $coauthor->description ?? '',
|
2026-03-05 00:25:12 +03:00
|
|
|
|
|
|
|
|
|
|
// Фото из миниатюры поста (это то, что вам нужно)
|
|
|
|
|
|
'photo' => $photo,
|
|
|
|
|
|
'photo_sizes' => $photo_sizes,
|
|
|
|
|
|
|
|
|
|
|
|
// Оставляем gravatar как запасной вариант, если фото нет
|
|
|
|
|
|
'gravatar' => get_avatar_url($coauthor->user_email, ['size' => 192]),
|
|
|
|
|
|
|
|
|
|
|
|
// Для обратной совместимости
|
|
|
|
|
|
'avatar' => $photo ?: get_avatar_url($coauthor->user_email, ['size' => 192]),
|
|
|
|
|
|
|
2026-03-02 17:25:21 +03:00
|
|
|
|
'url' => get_author_posts_url($coauthor->ID, $coauthor->user_nicename),
|
|
|
|
|
|
'type' => $coauthor->type ?? 'guest-author'
|
|
|
|
|
|
];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return new WP_Error('not_found', 'Author not found', ['status' => 404]);
|
|
|
|
|
|
},
|
|
|
|
|
|
'permission_callback' => '__return_true'
|
|
|
|
|
|
]);
|
2026-03-05 00:25:12 +03:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
add_action('rest_api_init', function() {
|
|
|
|
|
|
register_rest_route('my/v1', '/author/(?P<slug>[a-zA-Z0-9-]+)/posts', [
|
|
|
|
|
|
'methods' => 'GET',
|
|
|
|
|
|
'callback' => function($request) {
|
|
|
|
|
|
$slug = $request['slug'];
|
|
|
|
|
|
$per_page = $request->get_param('per_page') ?: 10;
|
|
|
|
|
|
$cursor = $request->get_param('cursor');
|
|
|
|
|
|
$before = $request->get_param('before');
|
|
|
|
|
|
$after = $request->get_param('after');
|
|
|
|
|
|
|
|
|
|
|
|
// Устанавливаем нужные типы постов
|
|
|
|
|
|
$post_type = ['profile_article', 'anew', 'yellow'];
|
|
|
|
|
|
|
|
|
|
|
|
if (!function_exists('get_coauthors')) {
|
|
|
|
|
|
return new WP_Error('no_plugin', 'Co-Authors Plus not active', ['status' => 404]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
global $coauthors_plus;
|
|
|
|
|
|
|
|
|
|
|
|
// Получаем автора по slug
|
|
|
|
|
|
$coauthor = null;
|
|
|
|
|
|
if (isset($coauthors_plus) && method_exists($coauthors_plus, 'get_coauthor_by')) {
|
|
|
|
|
|
$coauthor = $coauthors_plus->get_coauthor_by('user_nicename', $slug);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!$coauthor) {
|
|
|
|
|
|
return new WP_Error('not_found', 'Author not found', ['status' => 404]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Определяем тип автора и получаем термин таксономии author
|
|
|
|
|
|
$author_term = null;
|
|
|
|
|
|
if ($coauthor->type === 'guest-author') {
|
|
|
|
|
|
$author_term = get_term_by('slug', 'cap-' . $coauthor->user_nicename, 'author');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$author_term = get_term_by('slug', $coauthor->user_nicename, 'author');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!$author_term) {
|
|
|
|
|
|
return new WP_Error('not_found', 'Author term not found', ['status' => 404]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Базовые аргументы запроса
|
|
|
|
|
|
$args = [
|
|
|
|
|
|
'post_type' => $post_type,
|
|
|
|
|
|
'posts_per_page' => $per_page,
|
|
|
|
|
|
'post_status' => 'publish',
|
|
|
|
|
|
'tax_query' => [
|
|
|
|
|
|
[
|
|
|
|
|
|
'taxonomy' => 'author',
|
|
|
|
|
|
'field' => 'term_id',
|
|
|
|
|
|
'terms' => $author_term->term_id,
|
|
|
|
|
|
]
|
|
|
|
|
|
],
|
|
|
|
|
|
'orderby' => 'date',
|
|
|
|
|
|
'order' => 'DESC',
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
// Применяем курсорную пагинацию
|
|
|
|
|
|
if ($after) {
|
|
|
|
|
|
$args['date_query'] = [
|
|
|
|
|
|
[
|
|
|
|
|
|
'column' => 'post_date',
|
|
|
|
|
|
'before' => $after,
|
|
|
|
|
|
'inclusive' => false,
|
|
|
|
|
|
]
|
|
|
|
|
|
];
|
|
|
|
|
|
} elseif ($before) {
|
|
|
|
|
|
$args['date_query'] = [
|
|
|
|
|
|
[
|
|
|
|
|
|
'column' => 'post_date',
|
|
|
|
|
|
'after' => $before,
|
|
|
|
|
|
'inclusive' => false,
|
|
|
|
|
|
]
|
|
|
|
|
|
];
|
|
|
|
|
|
$args['order'] = 'ASC';
|
|
|
|
|
|
} elseif ($cursor) {
|
|
|
|
|
|
$cursor_post = get_post($cursor);
|
|
|
|
|
|
if ($cursor_post) {
|
|
|
|
|
|
$args['date_query'] = [
|
|
|
|
|
|
[
|
|
|
|
|
|
'column' => 'post_date',
|
|
|
|
|
|
'before' => $cursor_post->post_date,
|
|
|
|
|
|
'inclusive' => false,
|
|
|
|
|
|
]
|
|
|
|
|
|
];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$query = new WP_Query($args);
|
|
|
|
|
|
$posts = $query->posts;
|
|
|
|
|
|
|
|
|
|
|
|
if ($before) {
|
|
|
|
|
|
$posts = array_reverse($posts);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Форматируем посты - ТОЛЬКО нужные поля
|
|
|
|
|
|
$formatted_posts = [];
|
|
|
|
|
|
foreach ($posts as $post) {
|
|
|
|
|
|
setup_postdata($post);
|
|
|
|
|
|
|
|
|
|
|
|
// Получаем соавторов
|
|
|
|
|
|
$coauthors = [];
|
|
|
|
|
|
if (function_exists('get_coauthors')) {
|
|
|
|
|
|
$post_coauthors = get_coauthors($post->ID);
|
|
|
|
|
|
foreach ($post_coauthors as $post_coauthor) {
|
|
|
|
|
|
$coauthors[] = [
|
|
|
|
|
|
'id' => $post_coauthor->user_nicename,
|
|
|
|
|
|
'name' => $post_coauthor->display_name,
|
|
|
|
|
|
];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Получаем рубрики/категории
|
|
|
|
|
|
$categories = [];
|
|
|
|
|
|
$taxonomies = ['category', 'rubric'];
|
|
|
|
|
|
|
|
|
|
|
|
foreach ($taxonomies as $taxonomy) {
|
|
|
|
|
|
$terms = get_the_terms($post->ID, $taxonomy);
|
|
|
|
|
|
if ($terms && !is_wp_error($terms)) {
|
|
|
|
|
|
foreach ($terms as $term) {
|
|
|
|
|
|
$categories[] = [
|
|
|
|
|
|
'id' => $term->term_id,
|
|
|
|
|
|
'name' => $term->name,
|
|
|
|
|
|
'slug' => $term->slug,
|
|
|
|
|
|
'taxonomy' => $taxonomy,
|
|
|
|
|
|
];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$formatted_posts[] = [
|
|
|
|
|
|
'id' => $post->ID,
|
|
|
|
|
|
'title' => $post->post_title,
|
|
|
|
|
|
'slug' => $post->post_name,
|
|
|
|
|
|
'type' => $post->post_type,
|
|
|
|
|
|
'date' => $post->post_date,
|
|
|
|
|
|
'link' => get_permalink($post->ID),
|
|
|
|
|
|
|
|
|
|
|
|
// Только картинка (разные размеры)
|
|
|
|
|
|
'featured_image' => [
|
|
|
|
|
|
'full' => get_the_post_thumbnail_url($post->ID, 'full'),
|
|
|
|
|
|
'large' => get_the_post_thumbnail_url($post->ID, 'large'),
|
|
|
|
|
|
'medium' => get_the_post_thumbnail_url($post->ID, 'medium'),
|
|
|
|
|
|
'thumbnail' => get_the_post_thumbnail_url($post->ID, 'thumbnail'),
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
|
|
// Рубрики
|
|
|
|
|
|
'categories' => $categories,
|
|
|
|
|
|
|
|
|
|
|
|
// Соавторы
|
|
|
|
|
|
'coauthors' => $coauthors,
|
|
|
|
|
|
|
|
|
|
|
|
// Курсор для пагинации
|
|
|
|
|
|
'cursor' => $post->post_date,
|
|
|
|
|
|
];
|
|
|
|
|
|
}
|
|
|
|
|
|
wp_reset_postdata();
|
|
|
|
|
|
|
|
|
|
|
|
// ИСПРАВЛЕННАЯ ПАГИНАЦИЯ
|
|
|
|
|
|
$has_next = false;
|
|
|
|
|
|
$next_cursor = null;
|
|
|
|
|
|
$has_previous = false;
|
|
|
|
|
|
$previous_cursor = null;
|
|
|
|
|
|
$first_cursor = null;
|
|
|
|
|
|
$last_cursor = null;
|
|
|
|
|
|
|
|
|
|
|
|
if (!empty($posts)) {
|
|
|
|
|
|
$first_post = reset($posts);
|
|
|
|
|
|
$last_post = end($posts);
|
|
|
|
|
|
|
|
|
|
|
|
$first_cursor = $first_post->post_date;
|
|
|
|
|
|
$last_cursor = $last_post->post_date;
|
|
|
|
|
|
|
|
|
|
|
|
// Простая проверка: если количество найденных постов больше, чем количество на странице
|
|
|
|
|
|
// ИЛИ если есть больше страниц
|
|
|
|
|
|
$has_next = $query->max_num_pages > 1;
|
|
|
|
|
|
|
|
|
|
|
|
// Если есть следующая страница, курсор - дата последнего поста
|
|
|
|
|
|
if ($has_next) {
|
|
|
|
|
|
$next_cursor = $last_post->post_date;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Проверяем предыдущие посты (если это не первая страница)
|
|
|
|
|
|
if ($cursor || $after || $before) {
|
|
|
|
|
|
// Если есть курсор, значит это не первая страница
|
|
|
|
|
|
$has_previous = true;
|
|
|
|
|
|
$previous_cursor = $first_post->post_date;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Добавим отладку (можно убрать после тестирования)
|
|
|
|
|
|
error_log('=== AUTHOR POSTS DEBUG ===');
|
|
|
|
|
|
error_log('Slug: ' . $slug);
|
|
|
|
|
|
error_log('Posts found: ' . count($posts));
|
|
|
|
|
|
error_log('Total posts: ' . $query->found_posts);
|
|
|
|
|
|
error_log('Max num pages: ' . $query->max_num_pages);
|
|
|
|
|
|
error_log('Has next: ' . ($has_next ? 'true' : 'false'));
|
|
|
|
|
|
error_log('Next cursor: ' . ($next_cursor ?? 'null'));
|
|
|
|
|
|
error_log('========================');
|
|
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
|
'data' => $formatted_posts,
|
|
|
|
|
|
'pagination' => [
|
|
|
|
|
|
'total' => $query->found_posts,
|
|
|
|
|
|
'per_page' => (int)$per_page,
|
|
|
|
|
|
'has_next' => $has_next,
|
|
|
|
|
|
'has_previous' => $has_previous,
|
|
|
|
|
|
'next_cursor' => $next_cursor,
|
|
|
|
|
|
'previous_cursor' => $previous_cursor,
|
|
|
|
|
|
'first_cursor' => $first_cursor,
|
|
|
|
|
|
'last_cursor' => $last_cursor,
|
|
|
|
|
|
],
|
|
|
|
|
|
'author' => [
|
|
|
|
|
|
'id' => $coauthor->user_nicename,
|
|
|
|
|
|
'name' => $coauthor->display_name,
|
|
|
|
|
|
]
|
|
|
|
|
|
];
|
|
|
|
|
|
},
|
|
|
|
|
|
'args' => [
|
|
|
|
|
|
'per_page' => [
|
|
|
|
|
|
'type' => 'integer',
|
|
|
|
|
|
'default' => 10,
|
|
|
|
|
|
'minimum' => 1,
|
|
|
|
|
|
'maximum' => 100,
|
|
|
|
|
|
],
|
|
|
|
|
|
'cursor' => [
|
|
|
|
|
|
'type' => 'string',
|
|
|
|
|
|
'description' => 'Cursor for pagination',
|
|
|
|
|
|
],
|
|
|
|
|
|
'after' => [
|
|
|
|
|
|
'type' => 'string',
|
|
|
|
|
|
'description' => 'Get posts after this date',
|
|
|
|
|
|
],
|
|
|
|
|
|
'before' => [
|
|
|
|
|
|
'type' => 'string',
|
|
|
|
|
|
'description' => 'Get posts before this date',
|
|
|
|
|
|
],
|
|
|
|
|
|
],
|
|
|
|
|
|
'permission_callback' => '__return_true'
|
|
|
|
|
|
]);
|
2026-03-02 17:25:21 +03:00
|
|
|
|
});
|