Dev:Retrieving Posts

From Habari Project

Jump to: navigation, search

This page describes the methods you can use to retrieve posts.

Contents

Returning a single post

A single post should be returned by calling Post::get() and passing in the required parameters.

For example, the snippet below will retrieve a page that has the slug pony-rides.

$params = array( 'slug' => 'pony-rides', 'content_type' => Post::type( 'page' ) );
$page = Post::get( $params );

If no posts match the provided parameters, null will be returned.

Next and previous post

You can find the next and previous posts relative to a specific post using the ascend() and descend() methods. By default, these methods will get the nearest post by publication date that has the same status and content type. You can also pass in the same parameters as detailed below.

For example, in a theme's entry template, you could provide a link to the next and previous posts by publication date as follows.

<?php if ( $previous = $post->descend() ): ?>
<div class="previous">
  &laquo; <?php echo "<a href='{$previous->permalink}' title='{$previous->title}'>{$previous->title}</a>"; ?>
</div>
<?php endif; ?>
 
<?php if ( $next = $post->ascend() ): ?>
<div class="next">
  <?php echo "<a href='{$next->permalink}' title='{$next->title}'>{$next->title}</a>"; ?> &raquo;
</div>
<?php endif; ?>

Returning multiple posts

As with a single post, multiple posts should be returned by calling Posts::get() and passing in the required parameters.

The example code below will retrieve all published pages.

$params = array( 'content_type' => Post::type( 'page' ), 'status' => Post::status('published') );
$pages = Posts::get( $params );

Parameters

The same parameters can be used to retrieve single or multiple posts. Possible parameters are described in this section.

Specific posts

A set of specific posts can be retrieved by passing an id, an array of ids, a slug, or an array of slugs.

// Retrieve a specific post by id
$posts = Posts::get(array('id' => 17));
 
// Retrieve specific posts by id
$posts = Posts::get(array('id' => array(17, 23)));

It's unlikely that you would be passing in ids directly, however. It's more likely that the ids would be returned by some other function, such as the post ids associated with a particular tag.

// Retrieve a specific post by slug
$posts = Posts::get(array('slug' => Utils::slugify('Pony rides!'));
 
// Retrieve specific posts by slug
$posts = Posts::get(array('slug' => array(Utils::slugify('Pony rides!'), Utils::slugify('Dry ponies!'));

Specific posts can also be excluded by id.

// Retrieve pages, but exclude some
$posts = Posts::get(array('content_type' => Post::type( 'page' ) 'not:id' => array(17, 29)));


Post content type

Using the content_type parameter, you can retrieve posts of a specific content type, any content type (useful for overriding a default that uses a specific content type), or a set of content types.

// Retrieve entries
$posts = Posts::get(array('content_type' => Post::type('entry'));
 
// Retrieve podcasts and pages
$posts = Posts::get(array(
  'content_type' => array(Post::type('podcast'), Post::type('page'))
));
 
// Retrieve posts of any content type
$posts = Posts::get(array('content_type' => Post::type('any')));

The content_type parameter actually uses an integer that represents the content type. The call to Post::type() is used to convert the string representation of the content type to an integer.

Post status

Often you'll only want to retrieve posts with a specific status, such as those that have been published. You can do this using the status parameter, which can either be a single status type or an array of status types.

// Retrieve published posts
$posts = Posts::get(array('status' => Post::status('published'));
 
// Retrieve published and draft posts
$posts = Posts::get(array(
  'status') => array(Post::status('published'), Post::status('draft'))
));
 
// Retrieve posts with any status
$posts = Posts::get(array('status' => Post::status('any'));

As with the content_type parameter, status uses an integer that represents the status. The call to Post::status() is used to convert the string representation of the status to an integer.

Post author

The posts of a specifc author or set of authors can be retrieved using their user ids.

A user id or array of ids.

// Get the current user, and get their posts if they're logged in
$user = User::identify();
 
if ( $user->loggedin) {
  // Retrieve posts they've written
  $posts = Posts::get(array('user_id' => $user->id);
}
 
// Retrieve published posts for some specific users
$posts = Posts::get(array(
  'status' => Post::status('published'),
  'user_id' => array(1, 2, 3)
));

You probably don't want to rely on magic id numbers like that though. See Retrieving Users for how to retrieve the users you want.

Post vocabulary

The Taxonomy system allows posts to be associated with Terms in one or more Vocabularies. The vocabulary parameter was introduced in order to allow the retrieval of posts associated with Terms in any combination of one or more Vocabularies. It is more complex than most other possible parameters because of this.

There is an object based syntax and a property based syntax for retrieving posts using this parameter. In either case, the basic syntax to use the vocabulary parameter is

Posts::get( array( 'vocabulary' => array() ) );

Object Based Syntax

With this syntax, arrays of Term objects are passed directly in the vocabulary parameter in one of three arrays. Using this syntax, the vocabulary is not included in the call since Terms are implicitly associated with a vocabulary. The three possible arrays are as follows.

any
The posts retrieved will be associated with any one of the Terms in this array.
all
The posts retrieved must be associated will all of the Terms in this array.
not
The posts retrieved must not be associated with any of the Terms in this array.

Property Based Syntax

Passed in the array can be one or more of the following.

vocabulary_name:term
term denotes the slug that is associated with the Term. The parameter associated with it can be a string, or an array. Any of the terms passed can be associated with the posts.
vocabulary_name:term_display
term_display denotes the display text that is associated with the Term. The parameter associated with it can be a string or an array. Any of the term_displays passed can be associated with the posts
vocabulary_name:not:term
not denotes none of the Term terms passed can be associated with the posts.
vocabulary_name:not:term_display
not denotes none of the Term term_displays passed can be associated with the posts.
vocabulary_name:all:term
all denotes that all the Term slugs passed must be associated with the posts.
vocabulary_name:all:term_display
all denotes that all the Term term_termdisplays passed must be associated with the posts.

Note that vocabulary_name is to be replaced with the actual name of the vocabulary whose terms you are using, so if you are retrieving posts based on the tag terms associated with it, you would use

tags:term

Examples

$asides = Posts::get( array( 'vocabulary' => array( 'tags:term' => 'asides' ), 'limit' => 5 ) );

This code will get the five most recent posts that are associated with the asides term in the tags vocabulary.

$posts = Posts::get( array( 'vocabulary' => array( 'tags:term_display' => array( 'Habari', 'PHP' ) ), 'nolimit' => 1 ) );

This code will get all posts that are associated with any of the Terms with a term_display of Habari or PHP in the tags vocabulary.

$posts = Posts::get( array( 'vocabulary' => array( 'tags:all:term_display' => array( 'Habari', 'PHP' ) ), 'nolimit' => 1 ) );

This code will get all posts that are associated with all of the Terms with a term_display of Habari or PHP in the tags vocabulary. Note that this is more restrictive than the previous example, in which the posts could be associated with any of the Terms.

$posts = Posts::get( array( 'vocabulary' => array( 'tags:not:term_display' => 'Asides' ), 'nolimit' => 1 ) );

This code will get all posts that are not associated with the Term with a term_display of Habari in the tags vocabulary.

$posts = Posts::get( array( 'vocabulary' => array( 'menu:term' => 'plugins', 'tags:not:term' => 'asides' ), 'nolimit' => 1 ) );

This code will get all posts that are associated with the Term with a term of plugins in the menu vocabulary that are not associated with Terms that have a term of asides in the tags vocabulary.

Associated tags

Tags can be associated with posts in order to organise them. These tags can also be used to retrieve posts, such as when using tags to put asides in a sidebar.

Internally, tags are simply a vocabulary, so you can retrieve them as described above.

$posts = Posts::get(array(
  'vocabulary' => array(
    'tags:term' => array( 'habari', 'php' )
  ),
  'nolimit' => 1
));

The tags:term parameter tells Habari to retrieve posts based on the term value in the tags vocabulary, and can be either a string or an array of the tags. Similarly, tags:term_display can be either a string or array of the tag display values. For both these parameters, if a post has any of the passed tags, it will be returned.

Post content

The criteria parameter is used to search for post content. It returns posts whose content contains an exact match to the parameter's value.

Post info data

Metadata can be associated with posts using PostInfo, and posts can also be retrieved using this metadata.

Matching keys

You can use the has:info parameter to match posts that have particular post info fields.

  // Return posts that have an info field named views
  $posts = Posts::get(array(
    'has:info' => 'views',
  ));

It can also be used to match a set of info fields.

  // Return posts that have info fields named views or year or pony
  $posts = Posts::get(array(
    'has:info' => array('views', 'year', 'pony'),
  ));

Matching key and value pairs

It's often useful to narrow down the match by info field value. The all:info and any:info do just that.

Using all:info returns posts that match all of the passed info.

  // Return posts that have BOTH an info field named views with the value 7 AND year with the value 2009
  $posts = Posts::get(array(
    'all:info' => array('views' => 7), array('year' => 2009)
  ));

Using any:info returns posts that match any of the passed info.

  // Return posts that have EITHER an info field named views with the value 7 OR year with the value 2009
  $posts = Posts::get(array(
    'any:info' => array('views' => 7), array('year' => 2009)
  ));

These parameters can be negated using not:all:info and not:any:info.

Publication date

Posts can be retrieved by their publication date by specifying year, month and day parameters. The month parameter will be ignored without year, and day will be ignored without both month and year.

// Get posts from 2010
$posts_2010 = Posts::get(array('year' => 2010));
 
// Get posts from December 2010
$posts_december = Posts::get(array('year' => 2010, 'month' => 12));
 
// Get posts from Christmas day 2010
$posts_xmas = Posts::get(array('year' => 2010, 'month' => 12, 'day' => 25));

You can also return posts published before or after a particular date using the before and after parameters. The value passed in should be a Unix timestamp.

// Get posts more than a week old
$posts = Posts::get(array('before' => strtotime('-1 week')));

Ordering posts

By default, when posts are retrieved they are ordered by their publication date. This order can be controlled using the orderby parameter.

// Order posts alphabetically by their title
$posts = Posts::get(array(
  'content_type' => 'entry',
  'orderby' => 'title',
));

This will order the posts in ascending order of their title. You can use ASC or DESC to force ascending or descending ordering.

// Order posts by their title in reverse alphabetical order
$posts = Posts::get(array(
  'content_type' => 'entry',
  'orderby' => 'title DESC',
));

Ordering by post info

Since revision 4773, the old ordering method using the ABS function is no longer supported by Habari as it caused problems with PostgreSQL. The following code works for all databases. Important: For MySQL, use unsigned instead of integer.

/**
 * Display a template with the popular entries
 */
public function theme_popular_posts($theme, $limit = 5)
{
  $theme->popular_posts = Posts::get(array(
    'content_type' => 'entry',
    'has:info' => 'views',
    'orderby' => "cast(hipi1.value as integer) DESC",
    'limit' => $limit
  ));
  return $theme->display( 'popular_posts' );
}

You could also use this code.

/**
 * Display a template with the popular entries
 */
public function theme_popular_posts($theme, $limit = 5)
{
  $theme->popular_posts = Posts::get(array(
    'content_type' => 'entry',
    'has:info' => 'views',
    'add_select' => array("cast(hipi1.value as integer) as order1"),
    'orderby' => 'order1 DESC',
    'limit' => $limit
  ));
  return $theme->display( 'popular_posts' );
}

The disadvantage of these approaches is that you have to know the real name of the column Habari will use in the SQL, hipi1 above. Future versions of Habari will work around this shortcoming of PostgreSQL.

Since revision 5014, you can view the query Habari uses to find out the columns name. To do so, add

'fetch_fn' => 'get_query'

to your parameters. Important: You have to remove that parameter again before you retrieve posts, otherwise the Posts::get will not return any posts.

Limiting the number of posts

When requesting specific posts by id or slug, all requested posts will be returned. However, in many cases, the maximum number of posts returned by a call to Posts::get() is controlled implicitly by the pagination option, which can be set on the blog's options page under 'items per page'.

The maximum number of posts returned can be explicitly set using the limit parameter.

// Return 20 entries
$posts = Posts::get(array('contet_type' => Post::type('entry'), 'limit' => 20));

The implicit limit can be turned off completely to return all matching posts using the nolimit parameter.

Pagination

The page option can be used to automatically manage the limit and offset parameters required to page through large sets of results.

In the following example, if the pagination option is set to 5 and the value of the variable $current_page is 3, $next_posts will contain posts 16 to 20 and $prev_posts will contain posts 6 to 10.

// Retrieve the next page of results
$next_posts = Posts::get(array('page' => $current_page + 1);
// Retrieve the previous page of results
$prev_posts = Posts::get(array('page' => $current_page - 1);

Complex conditions

The where parameter is used to manipulate the WHERE clause of the constructed SQL. It can be used in two ways, by passing either a string on array. The effects of each method are described below.

Passing a string to the where parameter

If the value of the where parameter is a string, then the string will be used as a where condition of the query. This does not cause Posts::get() to omit other query parameters, such as ordering, limiting, or grouping. Using the where parameter will obviate other where parameters, such as content_type, id, user_id, etc. Permissions will always be applied, whether using where or the usual query parameters.

Passing an array to the where parameter

If the value of the where parameter is an array, then each element of the array is used to construct a separate WHERE clause for the same query, and these causes are OR'ed within the query.

For example, the following code would retrieve posts authored by the user with id 1 or that are of content type entry.

// Specify an entire WHERE clause
$posts = Posts::get(array('where' => array(
  array('user_id' => 1),
  array('content_type' => Post::type('entry'))
)));

This produces a WHERE clause that includes this:

( ({posts}.user_id = :posts_user_id) OR ({posts}.content_type = :posts_content_type) )

When multiple values are passed as the value for the where parameter, they must be passed as arrays and not strings. In other words, if a single string is passed, it can be a string with multiple arguments that will be inserted in the query, but the individual elements passed in an array must be key and value pairs, not strings.

You can use the Utils::get_params() method to build array elements from strings. The following code produces the same query output as above, converting strings into arrays before passing them:

$posts = Posts::get(array('where' => array(
  Utils::get_params('user_id=1'),
  Utils::get_params('content_type='.Post::type('entry'))
)));

)));

Adding to SELECT

Though rarely required, you can add a clause directly to the SELECT portion of the SQL generated by Habari using the add_select parameter.

Counting posts

Habari provides several ways to count posts. The simplest ways are to use the static helper methods from the Posts class.

The Posts::count_total() method simply counts the total number of posts. It has an optional status parameter which acts in exactly the same way as the status parameter that can be passed to Posts::get().

// Count the total posts
$post_count = Posts::count_total();
 
// Count draft posts
$draft_count = Posts::count_total(Post::status('draft'));

You can also count the posts made by a particular author, by id, or that have a particular tag associated with them. Again, both helpers can take a status parameter.

// How many posts has Barry written?
$barry_post_count = Posts::count_by_author(User::get_by_name('barry')->id);
 
// How many posts has Barry published?
$barry_pub_post_count = Posts::count_by_author(User::get_by_name('barry')->id, Post::status('published'));
 
// How many posts tagged 'pony'?
$pony_posts = Posts::count_by_tag('pony');
 
// How many of them are still in draft?
$pony_draft_posts = Posts::count_by_tag('pony', Post::status('draft'));

The final helper method is Posts::count_all(), which returns the number of posts that were matched by the last call to Posts::get() that didn't return a single post. This is useful for things like paging through particular kinds of posts or creating archive pages.

$posts = Posts::get( array( 'content_type' => Post::type( 'entry' ), 'status' => Post::status('published'), 'year' => 2010, 'month' => 12 ) );
$count = $posts->count_all();

Often it will be useful to count posts using more complex parameters. This can be done by passing the count parameter to Posts::get(). Its value is simply the value that will be used in the final SQL statement's COUNT clause.

// Return the number of posts of type <tt>print</tt> that have an info field of <tt>soldout</tt> with the value FALSE
$unsold_print_count = Posts::get(array(
  'content_type' => Post::type('print'),
  'all:info' => 'all:info' => array('soldout' => FALSE)
  'count' => '*'
));

Random posts

Random posts can be retrieved by passing the function RAND() as the value of the orderby parameter.

// Return random entries
$entries = Posts::get(array(
  'content_type' => Post::type('entry'),
  'orderby' => 'RAND()'
));

The number of entries returned can be controlled using the limit parameter.

Retrieving posts from the database

Posts should only be retrieved directly from the database when functionality not supported by the above APIs is needed.

The preferred method of retrieving posts is to call the Post or Posts get() methods.

Personal tools