get_posts()WP 1.2.0

Gets an array of posts (pages, attachments, custom post types) from the database. You can specify any criteria for getting the posts.

This function has preset parameters. Sometimes you need to change them so they don't get in the way. Preset parameters:

  • post_type = post ― if we specify a taxonomy output for a post type other than post, the post_type parameter should be changed - it defaults to post.

  • numberposts = 5 ― if we forget to change the numberposts parameter, we may wonder why we output only 5 entries instead of the required 20.

  • suppress_filters = true ― this parameter disables some filters (hooks). Read more.

  • ignore_sticky_posts = true ― can't be changed!
  • no_found_rows = true ― can't be changed!

The $ignore_sticky_posts and $no_found_rows parameters are ignored by this function and both are set to true.

This function is an analogue of query_posts(). It differs in that it does not interfere with global WP query but creates a separate instance of WP_Query class. Read more.

1 time — 0.0036 sec (very slow) | 50000 times — 99.1 sec (very slow)

No Hooks.



  • Empty array if no entries.

  • Array of WP_Post objects. Each object in the array looks like this:

    	[0]=> object(WP_Post)#4692 (24) {
    		["ID"]                    => int(822)
    		["post_author"]           => string(1) "1"
    		["post_date"]             => string(19) "2016-07-07 10:28:57"
    		["post_date_gmt"]         => string(19) "2016-07-07 07:28:57"
    		["post_content"]          => string(6225) "Post content"
    		["post_title"]            => string(37) "Dead Sea (14 photos)"
    		["post_excerpt"]          => string(15) "Quote about the article"
    		["post_status"]           => string(7) "publish"
    		["comment_status"]        => string(4) "open"
    		["ping_status"]           => string(4) "open"
    		["post_password"]         => string(0) ""
    		["post_name"]             => string(95) "dead-sea-14-photos"
    		["to_ping"]               => string(0) ""
    		["pinged"]                => string(0) ""
    		["post_modified"]         => string(19) "2016-07-07 10:28:57"
    		["post_modified_gmt"]     => string(19) "2016-07-07 07:28:57"
    		["post_content_filtered"] => string(0) ""
    		["post_parent"]           => int(0)
    		["guid"]                  => string(0) ""
    		["menu_order"]            => int(0)
    		["post_type"]             => string(4) "post"
    		["post_mime_type"]        => string(0) ""
    		["comment_count"]         => string(1) "0"
    		["filter"]                => string(3) "raw"
    	[1] => object(WP_Post){
    	[2] => object(WP_Post){

Usage Template

$my_posts = get_posts( [
	'numberposts' => 5,
	'category'    => 0,
	'orderby'     => 'date',
	'order'       => 'DESC',
	'include'     => array(),
	'exclude'     => array(),
	'meta_key'    => '',
	'meta_value'  =>'',
	'post_type'   => 'post',
	'suppress_filters' => true, // suppression of filters of SQL query change
] );

foreach( $my_posts as $post ){
	setup_postdata( $post );

	// output: the_title() ...

wp_reset_postdata(); // reset $post


get_posts( $args );
A list of arguments according to which the result will be obtained. See WP_Query::parse_query() for all available arguments.
Default: null - presets

Arguments of the $args parameter

This function is a wrapper for WP_Query, so it can take the same parameters.

The number of output posts. Set to 0 to limit output to the maximum number of posts per page (set in WP settings) or set to -1 to remove output limitations (LIMIT).
Default: 5
Indent from the first post.

Specify the ID of the category from which you want to retrieve posts. You can specify an ID with a minus sign -3, then this category will be excluded (all posts except category 3 will be retrieved). You can specify several IDs separated by commas as a string 3,5,12 or -3,-5,12).

In the value you should pass ID, not category name.

See also description of parameter cat in WP_Query.

Default: 0

Show posts from this category only (specify category name or category slug).
Default: ''

Get posts that have specified tags. It is necessary to specify slug of the tag.

  • tagname,tagname2 - if you specify more than one slug comma-separated, you will get the posts with any of specified slug.
  • tagname tagname2 - if you specify more than one slug spaces-separated, you will get the posts that have all specified slugs.
    Default: ''

The IDs of the posts to be retrieved. If a string is specified, the IDs must be separated by commas or spaces. Example, get 6 posts: '45,63,78,94,128,140'.

Important: Specifying this parameter the following parameters will be ignored: posts_per_page, offset, category, exclude, meta_key, meta_value, post_parent.
Default: ''

The IDs of the posts that you want to exclude from the result. Separate ids with commas or a spaces.
Default: ''

Get posts which have a specified custom field (meta_key) with value (meta_value).

You can to specify meta_key and meta_value, then the posts which have the specified meta field and specified meta value will be retrieved.

Or you can specify only meta_key, then all posts will be retrieved which have this meta field, and it does not matter what value they have.

Default: ''

Selecting posts by custom fields. For more details see. WP_Query (meta_query).
Default: []
Selecting posts by date. For more details see. WP_Query (date_query).
Default: []

Posts of what type should be retrieved. Default: post. But if specify tax_query parameter, the default will be any.

Can be:

  • any - include all types, except revision, and types with exclude_from_search=true parameter specified.
  • attachment - by default WP_Query sets the status 'post_status'=>'publish'. But attachments has status 'post_status'=>'inherit', so to display attachments you need also to change post_status parameter to inherit or any.
  • page
  • post
  • revision
  • custom_type - name (slug) of any custom post type.
  • [ 'post', 'page' ] - several types specified in array.

Default: 'post'


What type of attachment you want to get. You can use this parameter when the post_type = attachment and post_status = inherit only. I.e. only attachments have MIME-type.

You can specify several mime types in an array instead of just one. List of mime types:

  • image/jpeg
  • image/png
  • image/gif
  • image - для любых картинок
  • audio/mpeg
  • application/pdf
  • application/zip
  • See here for a complete list of mime types.

Default: ''


The status of the post. You can pass multiple statuses, separated by commas.

Default is publish, and if user is authorized the private status is also added. If the request is launched from the admin part protected status types are added too: future, draft and pending.

All status types:

  • publish - published post.
  • pending - post on moderation.
  • draft - draft posts.
  • auto-draft - draft saved by WordPress (auto-save).
  • future - scheduled post.
  • private - personal post.
  • inherit - revision or attachment.
  • trash - removed post (in trash). Since 2.9.
  • any - all statuses, except status with parameter exclude_from_search=true. See register_post_status() and get_post_stati().

Default: publish

Get only child posts to the specified ID.
Default: 0
Enable or disable pagination. If true the $numberposts parameter is ignored.
Default: false

The sort direction for the orderby parameter. Can be:

  • ASC - in order, from less to more (1, 2, 3 or a, b, c).
  • DESC - in reverse order, from more to less (3, 2, 1 or c, b, a).
    Default: 'DESC'

Fields on which you can sort posts. Can be:

  • none — do not sort, output as is in the database. Equivalent to sorting by ID. Since 2.8.
  • ID — sort by ID.
  • author — sort by author ID.
  • title — sort by title.
  • name — by post name (post slug).
  • date — sort by publication date.
  • modified — sort by modification date.
  • type — by post type (post_type). Since 4.0.
  • parent — sort by the value of the post_parent field.
  • rand — random order.
  • RAND(x) — in a random order for numeric values. Here "x" is an integer.
  • comment_count — sort by the number of comments. Since 2.9.
  • relevance — by search terms (parameter s) in the following order: 1) whether the entire sentence is matched. 2) all search terms are in the post title. 3) any of the search terms appear in the post title. 4) the full sentence is found in the post content.
  • menu_order — used for pages and attachments. The sequence number is specified on the edit-post admin page.
  • meta_value — by the value of a custom field.

    Important: the meta_key parameter must also be defined. Note: the sorting will be alphabetical, and it's not logical if the values of custom field is a numbers (for example 1, 3, 34, 4, 56, 6 etc., not 1, 3, 4, 6, 34, 56).

  • meta_value_num — sort by custom field whose values are numbers. Since 2.8.
  • array key from meta_query — in this case, the sorting will be based on the value of custom field specified in the meta_query array.
  • post__in — takes into account the order of ID specified in post__in parameter. order parameter is ignored
  • post_name__in — takes into account the order of names specified in the post_name__in parameter. order parameter is ignored
  • post_parent__in — takes into account the order of ID specified in post_parent__in parameter. order parameter is ignored.

The prefix post_ in table fields is omitted for convenience. For example, instead of date you can write post_date, instead of content post_content etc.

orderby = array() - since WP 4.0 you can specify the combination of orderby and order parameters as an array in orderby parameter. it is for sorting by several columns simultaneously. syntax is:

'orderby' => array( 'title' => 'DESC', 'menu_order' => 'ASC' )

Default: 'date'


When true (default) skips all SQL query change hooks. The following hooks will be skipped: posts_* and comment_feed_*.

Which filters are skipped see here.

In WP_Query and query_posts() functions this parameter is disabled by default (= false).

uppress_filters = true has no effect on the pre_get_posts filter.

Disabling filters like this by default can be confusing if there are plugins which affect output of posts via SQL query filters, e.g. WPML. In such cases suppress_filters should be disabled.

Default: true



#1 Get the latest 10 posts:

$args = [
	'numberposts' => 10

$latest_posts = get_posts( $args );

You can also pass the post_type argument if you want to get posts from a Custom Post Type, like:

$args = [
  'numberposts' => 10,
  'post_type'   => 'book'

$latest_books = get_posts( $args );

#2 Array of post IDs

To return ids instead of post objects use the fields argument.

$args = [ 'fields' => 'ids' ];
$posts = get_posts( $args );
// if any posts are found $posts will be an array with their ids

The fields argument can be set to ids, all (default) or id=>parent. The last two (arguments) will return an array of stdClass objects.


#3 Custom Field Parameters

Show posts associated with a certain custom field. Following example displays posts from the product post type that have meta key featured with value yes, using meta_query:

$args = [
	'post_type'  => 'product',
	'meta_query' => [
			'key'   => 'featured',
			'value' => 'yes',

$postslist = get_posts( $args );

Refer to the custom fields parameters section of the WP_Query documentation for more examples.


#4 Access all post data

Some post-related data is not available to get_posts by default, such as post content through the_content(), or the numeric ID. This is resolved by calling an internal function setup_postdata(), with the $post array as its argument:

$lastposts = get_posts( array(
	'posts_per_page' => 3
) );

if ( $lastposts ) {
	foreach ( $lastposts as $post ) :
		setup_postdata( $post ); ?>
		<h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
		<?php the_content(); ?>

To access a post’s ID or content without calling setup_postdata(), or in fact any post-specific data (data retained in the posts table), you can use $post->COLUMN, where COLUMN is the table column name for the data. So $post->ID holds the ID, $post->post_content the content, and so on. To display or print this data on your page use the PHP echo command, like so:

<?php echo $post->ID; ?>

#5 Let's display the entries from the category

Suppose we have a category "Articles" (slug articles) in which posts are added (post_type=post). We need to display 6 such posts on an arbitrary page.

global $post;

$myposts = get_posts( [
	'posts_per_page' => 6,
	'category_name' => 'articles',
	'post_type' => 'post',
] );

foreach( $myposts as $post ){
	setup_postdata( $post );
	<div class="article-elem">
		<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>

#6 Taxonomy Parameters

Show posts associated with certain taxonomy. If specifying a taxonomy registered to a custom post type then instead of using category you would use {custom_taxonomy_name}. For instance, if you had a custom taxonomy called genre and wanted to only show posts from the jazz genre you would use the below code.

$show_albums = get_posts( [
	 'posts_per_page' => 8,
	 'orderby'        => 'rand',
	 'post_type'      => 'albums',
	 'genre'          => 'jazz',
	 'post_status'    => 'publish'
] );

Following example displays posts tagged with jazz, under genre custom taxonomy, using tax_query:

$args = array(
	'tax_query' => array(
			'taxonomy' => 'genre',
			'field'    => 'slug',
			'terms'    => 'jazz'
$postslist = get_posts( $args );

Refer to the taxonomy parameters section of the WP_Query documentation for more examples.


#7 Order by order in include parameter

orderby also accepts the value post__in. If you use include to retrieve specific posts, the posts will be supplied in the order you supplied to include. For example:

$posts = get_posts( array(
	'include'   => '3,8,1,17',
	'post_type' => 'attachment',
	'orderby'   => 'post__in',
) );

#8 Show all attachments

Do this outside any Loops in your template.

$attachments = get_posts( array(
	'post_type'      => 'attachment',
	'posts_per_page' => 500,
	'post_status'    => 'any',
	'post_parent'    => null
) );

if ( $attachments ) {
	foreach ( $attachments as $post ) {
		setup_postdata( $post );
		the_attachment_link( $post->ID, false );

#9 Recent Posts Sorted by Title

Get the latest posts sorted by title in alphabetical order. The following example will output the date, title, and excerpt of the post:

global $post;
$postslist = get_posts( [
	'posts_per_page' => 10,
	'order'=> 'ASC',
	'orderby' => 'title'
] );

foreach( $postslist as $post ){
		<?php the_date(); ?>
		<br />
		<?php the_title(); ?>
		<?php the_excerpt(); ?>


#10 Random posts

We will get 5 random posts, implemented by the orderby'' => 'rand' parameter:

$args = array( 'posts_per_page' => 5, 'orderby' => 'rand' );
$rand_posts = get_posts( $args );
foreach( $rand_posts as $post ) : ?>
	<li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php endforeach; ?>
<?php wp_reset_postdata() ?>

#11 Attached files of a certain post

The code should be used inside the WordPress Loop, where the variable $post->ID:

$args = array(
	'post_type' => 'attachment',
	'posts_per_page' => -1,
	'post_status' => null,
	'post_parent' => $post->ID
$attachments = get_posts( $args );
if ( $attachments ) {
	foreach ( $attachments as $attachment ) {
		echo apply_filters( 'the_title' , $attachment->post_title );
		the_attachment_link( $attachment->ID , false );

#12 Recent posts from the same category

Let's display the list of the most recent posts of the current category, in which the post is located. In doing so, we will exclude the current post:

$category = get_the_category();
rsort( $category );
$cat_add_id = $category[0]->term_id;

$posts = get_posts( array(
	'cat' => $cat_add_id,
	'posts_per_page' => 4,
	'exclude' => $GLOBALS['post']->ID,
) );

foreach( $posts as $post ){
	<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>



Since 1.2.0 Introduced.

Code of get_posts() WP 5.9.3

function get_posts( $args = null ) {
	$defaults = array(
		'numberposts'      => 5,
		'category'         => 0,
		'orderby'          => 'date',
		'order'            => 'DESC',
		'include'          => array(),
		'exclude'          => array(),
		'meta_key'         => '',
		'meta_value'       => '',
		'post_type'        => 'post',
		'suppress_filters' => true,

	$parsed_args = wp_parse_args( $args, $defaults );
	if ( empty( $parsed_args['post_status'] ) ) {
		$parsed_args['post_status'] = ( 'attachment' === $parsed_args['post_type'] ) ? 'inherit' : 'publish';
	if ( ! empty( $parsed_args['numberposts'] ) && empty( $parsed_args['posts_per_page'] ) ) {
		$parsed_args['posts_per_page'] = $parsed_args['numberposts'];
	if ( ! empty( $parsed_args['category'] ) ) {
		$parsed_args['cat'] = $parsed_args['category'];
	if ( ! empty( $parsed_args['include'] ) ) {
		$incposts                      = wp_parse_id_list( $parsed_args['include'] );
		$parsed_args['posts_per_page'] = count( $incposts );  // Only the number of posts included.
		$parsed_args['post__in']       = $incposts;
	} elseif ( ! empty( $parsed_args['exclude'] ) ) {
		$parsed_args['post__not_in'] = wp_parse_id_list( $parsed_args['exclude'] );

	$parsed_args['ignore_sticky_posts'] = true;
	$parsed_args['no_found_rows']       = true;

	$get_posts = new WP_Query;
	return $get_posts->query( $parsed_args );