Как получить только определённые поля используя get_posts()

30 июл. 2013 г., 06:21:35
Просмотры: 40.4K
Голосов: 13

Я пытаюсь получить только нужные мне поля, используя функцию 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()? Заранее спасибо.

0
Все ответы на вопрос 6
1

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.

30 июл. 2013 г. 06:50:38
Комментарии

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

AhmadKarim AhmadKarim
25 окт. 2019 г. 18:12:25
0

Взгляните на это

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;
}
31 июл. 2013 г. 07:17:56
1

Вы можете использовать только 'ids' или 'id=>parent' для параметра fields.

Если вы укажете что-то другое, будут возвращены все поля (это поведение по умолчанию).

Однако, было бы удобно, если бы WordPress добавил следующие 2 опции: 'titles' и 'ids_and_titles'.

Я не знаю способа передать массив для этого параметра. Также я думаю, что это никогда не произойдет, учитывая ограничения, указанные в ответе G. M.

Подробнее: http://codex.wordpress.org/Class_Reference/WP_Query#Return_Fields_Parameter

25 янв. 2014 г. 19:43:28
Комментарии

id=>parent не является допустимым аргументом.

kaiser kaiser
25 янв. 2014 г. 20:47:14
0

Интересно, что это можно сделать с помощью 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/

5 июл. 2021 г. 11:20:11
0

Спасибо 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);
18 мар. 2020 г. 22:15:25
1
-1

Если вы хотите отобразить заголовок записи внутри шаблона или в плагине, вы можете использовать:

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

30 июл. 2013 г. 07:53:05
Комментарии

Как это отвечает на вопрос?

anastymous anastymous
10 окт. 2019 г. 04:41:41