Как получить только определённые поля используя get_posts()
Я пытаюсь получить только нужные мне поля, используя функцию get_posts()
в WordPress. В настоящее время у меня есть следующий код:
$posts_args = array(
'orderby' => 'post_date',
'order' => 'DESC',
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => 5,
'fields' => 'ids'
);
$post_ids_r = get_posts($posts_args);
Это работает нормально, если я хочу получить только id. Но если я хочу получить permalink или заголовок поста вместе с id, я не уверен, что делать. Я уже пробовал следующее:
'fields' => array('ids', 'post_titles')
'fields' => 'ids,post_titles'
'fields' => 'ids,titles'
'fields' => array('ids','titles')
Но ничего не работает, похоже, единственное, что он распознает - это поле ids
. Есть ли другой способ сделать это, если это действительно невозможно сделать с помощью get_posts()
? Заранее спасибо.

get_posts
делегирует основную работу WP_Query
, и если вы посмотрите исходный код этого класса, то увидите, что аргумент fields
имеет ограниченный набор опций. В этом switch
всего три варианта — ids
, id=>parent
и вариант по умолчанию, который возвращает все поля.
Вы можете использовать фильтр posts_fields
, чтобы изменить возвращаемые поля, однако для его работы необходимо передать 'suppress_filters => false
в аргументах запроса. Это должно выглядеть примерно так:
function alter_fields_wpse_108288($fields) {
return 'ID,post_title'; // и т.д.
}
add_filter('posts_fields','alter_fields_wpse_10888');
Однако есть более серьезная проблема. Объекты записей создаются с помощью вызова get_post
, и эта функция не учитывает значения, переданные в исходном запросе. Я также не вижу способа изменить возвращаемые данные ни в get_posts
, ни в самом классе WP_Post
.

Похоже, что параметр 'fields'
был добавлен в версии WP 5.x. Просто используя get_posts(array('fields' => 'ids'))
можно получить посты только с их ID, без необходимости применять фильтр posts_fields
. Поправьте меня, если я ошибаюсь, потому что у меня это сработало в последней версии WordPress (5.2.4) без добавления фильтра. Спасибо!

Взгляните на это
function get_posts_fields( $args = array() ) {
$valid_fields = array(
'ID'=>'%d', 'post_author'=>'%d',
'post_type'=>'%s', 'post_mime_type'=>'%s',
'post_title'=>false, 'post_name'=>'%s',
'post_date'=>'%s', 'post_modified'=>'%s',
'menu_order'=>'%d', 'post_parent'=>'%d',
'post_excerpt'=>false, 'post_content'=>false,
'post_status'=>'%s', 'comment_status'=>false, 'ping_status'=>false,
'to_ping'=>false, 'pinged'=>false, 'comment_count'=>'%d'
);
$defaults = array(
'post_type' => 'post',
'post_status' => 'publish',
'orderby' => 'post_date',
'order' => 'DESC',
'posts_per_page' => get_option('posts_per_page'),
);
global $wpdb;
$args = wp_parse_args($args, $defaults);
$where = "";
foreach ( $valid_fields as $field => $can_query ) {
if ( isset($args[$field]) && $can_query ) {
if ( $where != "" ) $where .= " AND ";
$where .= $wpdb->prepare( $field . " = " . $can_query, $args[$field] );
}
}
if ( isset($args['search']) && is_string($args['search']) ) {
if ( $where != "" ) $where .= " AND ";
$where .= $wpdb->prepare("post_title LIKE %s", "%" . $args['search'] . "%");
}
if ( isset($args['include']) ) {
if ( is_string($args['include']) ) $args['include'] = explode(',', $args['include']);
if ( is_array($args['include']) ) {
$args['include'] = array_map('intval', $args['include']);
if ( $where != "" ) $where .= " OR ";
$where .= "ID IN (" . implode(',', $args['include'] ). ")";
}
}
if ( isset($args['exclude']) ) {
if ( is_string($args['exclude']) ) $args['exclude'] = explode(',', $args['exclude']);
if ( is_array($args['exclude']) ) {
$args['exclude'] = array_map('intval', $args['exclude']);
if ( $where != "" ) $where .= " AND ";
$where .= "ID NOT IN (" . implode(',', $args['exclude'] ). ")";
}
}
extract($args);
$iscol = false;
if ( isset($fields) ) {
if ( is_string($fields) ) $fields = explode(',', $fields);
if ( is_array($fields) ) {
$fields = array_intersect($fields, array_keys($valid_fields));
if( count($fields) == 1 ) $iscol = true;
$fields = implode(',', $fields);
}
}
if ( empty($fields) ) $fields = '*';
if ( ! in_array($orderby, $valid_fields) ) $orderby = 'post_date';
if ( ! in_array( strtoupper($order), array('ASC','DESC')) ) $order = 'DESC';
if ( ! intval($posts_per_page) && $posts_per_page != -1)
$posts_per_page = $defaults['posts_per_page'];
if ( $where == "" ) $where = "1";
$q = "SELECT $fields FROM $wpdb->posts WHERE " . $where;
$q .= " ORDER BY $orderby $order";
if ( $posts_per_page != -1) $q .= " LIMIT $posts_per_page";
return $iscol ? $wpdb->get_col($q) : $wpdb->get_results($q);
}
Это функция, которая имитирует get_posts, но с возможностью получать только нужные вам поля. Важно: эта функция не является get_posts и имеет 2 больших ограничения: работает только с таблицей постов, поэтому запросы по таксономиям и метаполям невозможны!
Однако запрос может использовать все поля постов и некоторые 'специальные' аргументы, такие как include
, exclude
и search
.
Хорошая новость: вы можете получать все поля таблицы постов. Просто передайте список или массив в аргументе fields
.
Бонус: при передаче только одного поля возвращается одномерный массив строк или чисел (вместо массива объектов).
Список доступных аргументов:
$available_args = array(
'ID', // int
'post_author', // string
'post_type', // string
'post_mime_type', // string
'post_name', // string
'post_date', // string
'post_modified', // string
'menu_order', // int
'post_parent', // int
'post_status', // string
'comment_status', // string
'comment_count', // int
'orderby', // string, название допустимого поля
'order', // string 'ASC' или 'DESC',
'posts_per_page', // int
'include', // массив (или строка с ID через запятую)
'exclude', // массив (или строка с ID через запятую)
'search', // строка для поиска в заголовке поста
'fields', // массив (или строка через запятую) полей для выборки.
// Если передано только 1 поле - возвращается 'плоский' массив
);
Примеры использования
// Получить дату и заголовок страниц, содержащих 'Hello' в заголовке
$pages_hello = get_posts_fields("post_type=page&search=Hello&fields=post_date,post_title");
// другой пример
$args = array(
'post_type' => 'custom_post',
'posts_per_page' => -1,
'post_parent' => 1,
'include' => array(2,3,4),
'exclude' => '6,8,10',
'fields' => array('post_title', 'comment_status')
);
get_posts_fields($args);
// Ещё один пример, просто для развлечения ;)
$args = array(
'post_type' => 'attachment', 'posts_per_page' => -1,
'post_status' => 'inherit', 'fields' => 'post_mime_type'
);
foreach ( array_count_values ( get_posts_fields($args) ) as $mime => $count ) {
echo "У меня есть $count медиафайлов типа $mime" . PHP_EOL;
}

Вы можете использовать только 'ids'
или 'id=>parent'
для параметра fields
.
Если вы укажете что-то другое, будут возвращены все поля (это поведение по умолчанию).
Однако, было бы удобно, если бы WordPress добавил следующие 2 опции: 'titles'
и 'ids_and_titles'
.
Я не знаю способа передать массив для этого параметра. Также я думаю, что это никогда не произойдет, учитывая ограничения, указанные в ответе G. M.
Подробнее: http://codex.wordpress.org/Class_Reference/WP_Query#Return_Fields_Parameter

Интересно, что это можно сделать с помощью WP REST API, используя параметр _fields
https://yoursite.com/wp-json/wp/v2/posts?_fields=author,id,excerpt,title,link
Подробнее об API можно узнать здесь: https://developer.wordpress.org/rest-api/

Спасибо gmazzap за эту функцию! Я искал решение для получения некоторых произвольных полей вместе с get_posts, поэтому позволил себе расширить её для пользовательских полей таблицы postmeta:
function get_posts_fields($args = array())
{
$valid_fields = array(
'ID' => '%d',
'post_author' => '%d',
'post_type' => '%s',
'post_mime_type' => '%s',
'post_title' => false,
'post_name' => '%s',
'post_date' => '%s',
'post_modified' => '%s',
'menu_order' => '%d',
'post_parent' => '%d',
'post_excerpt' => false,
'post_content' => false,
'post_status' => '%s',
'comment_status' => false,
'ping_status' => false,
'to_ping' => false,
'pinged' => false,
'comment_count' => '%d',
'custom_fields' => false,
);
$defaults = array(
'post_type' => 'post',
'post_status' => 'publish',
'orderby' => 'post_date',
'order' => 'DESC',
'posts_per_page' => get_option('posts_per_page')
);
global $wpdb;
$args = wp_parse_args($args, $defaults);
$where = "";
$meta = "";
$groupBy = "";
foreach ($valid_fields as $field => $can_query) {
if (isset($args[$field]) && $can_query) {
if ($where != "") {
$where .= " AND ";
}
$where .= $wpdb->prepare(
$wpdb->posts.".".$field . " = " . $can_query,
$args[$field]
);
}
}
if (isset($args['search']) && is_string($args['search'])) {
if ($where != "") {
$where .= " AND ";
}
$where .= $wpdb->prepare(
"post_title LIKE %s",
"%" . $args['search'] . "%"
);
}
if (isset($args['include'])) {
if (is_string($args['include'])) {
$args['include'] = explode(',', $args['include']);
}
if (is_array($args['include'])) {
$args['include'] = array_map('intval', $args['include']);
if ($where != "") {
$where .= " OR ";
}
$where .= $wpdb->posts.".ID IN (" . implode(',', $args['include']) . ")";
}
}
if (isset($args['exclude'])) {
if (is_string($args['exclude'])) {
$args['exclude'] = explode(',', $args['exclude']);
}
if (is_array($args['exclude'])) {
$args['exclude'] = array_map('intval', $args['exclude']);
if ($where != "") {
$where .= " AND ";
}
$where .= $wpdb->posts.".ID NOT IN (" . implode(',', $args['exclude']) . ")";
}
}
extract($args);
$iscol = false;
if (isset($fields)) {
if (is_string($fields)) {
$fields = explode(',', $fields);
}
if (is_array($fields)) {
$fields = array_intersect($fields, array_keys($valid_fields));
if (count($fields) == 1) {
$iscol = true;
}
for($i = 0; $i < count($fields); $i++) {
$fields[$i] = "$wpdb->posts.$fields[$i]";
}
}
}
if (isset($args['custom_fields'])) {
if (is_string($args['custom_fields'])) {
$args['custom_fields'] = explode(',', $args['custom_fields']);
}
if (is_array($args['custom_fields'])) {
foreach( $args['custom_fields'] as $custom_field) {
$fields[] = "MAX(CASE WHEN df_postmeta.meta_key = '$custom_field' then df_postmeta.meta_value ELSE NULL END) as $custom_field";
}
$meta = " LEFT JOIN $wpdb->postmeta ON ( $wpdb->postmeta.post_id = $wpdb->posts.ID)";
$groupBy = " GROUP BY $wpdb->posts.ID, $wpdb->posts.post_title";
}
}
if (empty($fields)) {
$fields = '*';
} else {
$fields = implode(',', $fields);
}
if( in_array($orderby, $valid_fields) ) {
$orderby = $wpdb->posts.'.'.$orderby;
}else if( isset( $args['custom_fields']) && in_array($orderby, $args['custom_fields']) ) {
$orderby = $orderby;
} else {
$orderby = $wpdb->posts.'.post_date';
}
if (!in_array(strtoupper($order), array('ASC', 'DESC'))) {
$order = 'DESC';
}
if (!intval($posts_per_page) && $posts_per_page != -1) {
$posts_per_page = $defaults['posts_per_page'];
}
if ($where == "") {
$where = "1";
}
$q = "SELECT $fields FROM $wpdb->posts " . $meta . " WHERE " . $where;
$q .= $groupBy;
$q .= " ORDER BY $orderby $order";
if ($posts_per_page != -1) {
$q .= " LIMIT $posts_per_page";
}
print $q;
return $iscol ? $wpdb->get_col($q) : $wpdb->get_results($q);
}
Вы также можете использовать сортировку по этим полям. Небольшой пример использования:
$args = array(
'post_type' => 'projects',
'posts_per_page' => -1,
'fields' => array('ID', 'post_title'),
'orderby' => 'project_clients',
'order' => 'DESC',
'custom_fields' => array(
'project_clients',
'project_dop'
),
);
$projects = get_posts_fields($args);

Если вы хотите отобразить заголовок записи внутри шаблона или в плагине, вы можете использовать:
get_the_title($ID)
См. справочник WordPress: http://codex.wordpress.org/Function_Reference/get_the_title
Если вы используете эту функцию вне цикла, параметр $ID обязателен. В любом случае, она будет использоваться примерно так:
Вы также можете использовать:
the_permalink() - для получения постоянной ссылки записи the_title() - для получения заголовка записи
Это все теги шаблонов WordPress. Полный список тегов шаблонов вы можете найти здесь: http://codex.wordpress.org/Template_Tags
