Cómo retornar solo campos específicos usando get_posts()

30 jul 2013, 06:21:35
Vistas: 40.4K
Votos: 13

Estoy tratando de obtener solo los campos que necesito usando la función get_posts() en WordPress. Actualmente tengo el siguiente código:

    $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);

Esto funciona bien si solo quiero obtener el ID. Pero si quiero obtener el permalink o el título del post junto con los IDs, es ahí donde no estoy seguro de qué hacer. Ya intenté lo siguiente:

'fields' => array('ids', 'post_titles')
'fields' => 'ids,post_titles'
'fields' => 'ids,titles'
'fields' => array('ids','titles')

Pero nada funciona, supongo que el único que reconoce es el campo ids. ¿Hay alguna otra manera de hacer esto si realmente no es posible hacerlo usando get_posts()? Gracias de antemano.

0
Todas las respuestas a la pregunta 6
1

get_posts delega el trabajo pesado a WP_Query y si miras el código fuente de esa clase, puedes ver que hay solo un número limitado de opciones con ese argumento fields. Solo hay tres opciones en ese switch: ids, id=>parent y el caso por defecto, que devuelve todo.

Puedes usar el filtro posts_fields para alterar los campos que se devuelven, aunque parece que necesitas pasar 'suppress_filters => false en los argumentos para que ese filtro se ejecute. Debería verse algo así:

function alter_fields_wpse_108288($fields) {
  return 'ID,post_title'; // etc
}
add_filter('posts_fields','alter_fields_wpse_10888');

Sin embargo, hay un problema mayor. Los objetos de entrada que se devuelven son creados por una llamada a get_post y no respeta los valores pasados en la consulta original, y no veo una forma de cambiar lo que se devuelve ni en get_posts ni en la clase WP_Post misma.

30 jul 2013 06:50:38
Comentarios

Parece que el parámetro 'fields' fue introducido en una versión 5.x de WP. Simplemente haciendo get_posts(array('fields' => 'ids')) obtendrías los posts con solo los IDs sin necesidad de usar el filtro posts_fields. Por favor corrígeme si estoy equivocado, porque funcionó para mí en la última versión de wp (5.2.4) sin agregar el filtro. ¡Gracias!

AhmadKarim AhmadKarim
25 oct 2019 18:12:25
0

Echa un vistazo a esto

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);
}

Es una función que imita get_posts pero con la capacidad de obtener los campos que desees. Ten en cuenta: esta función no es get_posts y tiene 2 grandes limitaciones: solo funciona en la tabla de posts, por lo que no se pueden ejecutar consultas de taxonomía ni de metadatos.

Sin embargo, la consulta puede basarse en todos los campos de los posts y en algunos argumentos 'especiales' como include, exclude y search.

La parte buena es esta: los campos que puedes recuperar son todos los campos de la tabla de posts. Simplemente pasa una lista o un array en el argumento fields. Bonus: si pasas solo un campo, se devuelve un array unidimensional de strings o integers (en lugar de un array de objetos).

Lista de argumentos disponibles:

$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, un nombre de campo válido
  'order', // string 'ASC', o 'DESC',
  'posts_per_page', // int
  'include', // array (o string separado por comas) de IDs de posts
  'exclude', // array (o string separado por comas) de IDs de posts
  'search', // string si se pasa buscará en el título del post
  'fields', // array (o string separado por comas) de campos a recuperar.
            // Si solo se pasa 1 campo se devuelve un array 'plano'
);

Ejemplos de uso

// Recuperar la fecha y el título de páginas que contengan 'Hola' en el título
$pages_hello = get_posts_fields("post_type=page&search=Hola&fields=post_date,post_title");


// otro ejemplo
$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);


// Uno más, solo por diversión ;)
$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 "Tengo $count medios del tipo $mime" . PHP_EOL;
}
31 jul 2013 07:17:56
1

Solo puedes usar 'ids' o 'id=>parent' para el parámetro fields.

Si pasas cualquier otra cosa, devolverá todos los campos (este es el valor por defecto).

Sin embargo, sería bueno si WordPress pudiera añadir las siguientes 2 opciones: 'titles' y 'ids_and_titles'.

No estoy al tanto de una forma de pasar un array para este parámetro. También creo que nunca sucederá, debido a los límites de la respuesta dada por G. M.

Más información: http://codex.wordpress.org/Class_Reference/WP_Query#Return_Fields_Parameter

25 ene 2014 19:43:28
Comentarios

id=>parent no es un argumento válido.

kaiser kaiser
25 ene 2014 20:47:14
0

Curiosamente, puedes hacer esto con la API REST de WP usando el parámetro _fields

https://tusitio.com/wp-json/wp/v2/posts?_fields=author,id,excerpt,title,link

Más información sobre la API aquí: https://developer.wordpress.org/rest-api/

5 jul 2021 11:20:11
0

¡Gracias gmazzap por esa función! Estaba buscando una solución para obtener algunos campos personalizados junto con get_posts, así que me tomé la libertad de extenderla para incluir campos personalizados de la tabla 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);
}

También puedes usar el parámetro orderby con esos campos. Un pequeño ejemplo:

$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 mar 2020 22:15:25
1
-1

Si deseas mostrar el título de una publicación dentro de una plantilla o en un plugin, puedes usar:

get_the_title($ID)

Consulta la referencia de WordPress: http://codex.wordpress.org/Function_Reference/get_the_title

Si lo estás usando fuera del loop, el parámetro $ID es obligatorio. De cualquier forma, probablemente se usará así:

También puedes usar:

the_permalink() - para obtener el enlace permanente de la publicación the_title() - para obtener el título de la publicación

Estas son todas etiquetas de plantilla de WordPress. Una lista completa de etiquetas de plantilla que puedes usar se encuentra aquí: http://codex.wordpress.org/Template_Tags

30 jul 2013 07:53:05
Comentarios

¿Cómo responde esto a la pregunta?

anastymous anastymous
10 oct 2019 04:41:41