Anatomy of a Post
Posts are the building blocks of a typical blog page and the most complex object type in the engine. Let's take a look at the structure of a post. This is what you'll see if you var_export()
a Post object:
Post::__set_state(array(
'belongs_to' =>
array (
0 => 'user',
),
'prev' =>
Post::__set_state(array(
'belongs_to' => 'user',
'prev' => NULL,
'next' => NULL,
'data' =>
array (
),
'no_results' => true,
'has_many' =>
array (
0 => 'comments',
1 => 'likes',
2 => 'pingbacks',
3 => 'views',
),
'has_one' =>
array (
),
)),
'next' =>
Post::__set_state(array(
'belongs_to' => 'user',
'prev' => NULL,
'next' => NULL,
'data' =>
array (
),
'no_results' => true,
'has_many' =>
array (
),
'has_one' =>
array (
),
)),
'data' =>
array (
'id' => '1',
'feather' => 'text',
'clean' => 'my-first-post',
'url' => 'my-first-post',
'pinned' => '0',
'status' => 'public',
'user_id' => '1',
'created_at' => '2022-12-13 18:21:45',
'updated_at' => '0001-01-01 00:00:00',
'attribute_names' =>
array (
0 => 'body',
1 => 'title',
),
'attribute_values' =>
array (
0 => 'This is the body of my first post.',
1 => 'My first post',
),
'queryString' => 'SELECT "posts".*,
"post_attributes".name AS attribute_names,
"post_attributes".value AS attribute_values
FROM "posts"
LEFT JOIN "post_attributes" ON ("post_attributes".post_id = "posts".id)
WHERE ("posts".created_at LIKE \'2022-12-13 __:__:__%\')
AND ("posts".url = \'my-first-post\')
AND ("posts".feather IN (\'text\'))
AND (("posts".status IN (\'public\', \'registered_only\', \'private\', \'scheduled\') OR "posts".status LIKE \'%{1}%\') OR ("posts".status LIKE \'%{%\' AND "posts".user_id = 1))
ORDER BY "posts".id DESC
',
'updated' => false,
'slug' => 'my-first-post',
'filtered' => true,
'attributes' =>
array (
'body' => 'This is the body of my first post.',
'title' => 'My first post',
),
'body' => '<p>This is the body of my first post.</p>
',
'title' => 'My first post',
'title_unfiltered' => 'My first post',
'body_unfiltered' => 'This is the body of my first post.',
),
'no_results' => false,
'has_many' =>
array (
),
'has_one' =>
array (
),
))
A post is constructed by amalgamating data from two database tables: posts
and post_attributes
. The posts
table provides the core attributes that every post has, for example id
, user_id
, created_at
, the unique url
and synonymous slug
values. The post_attributes
table provides the attributes that are specific to a particular feather or added to the post by an enabled module. The SQL statement that was used to construct this post instance is stored in $post->queryString
.
Permissions
By looking at queryString
, we can see that a post's permission system is applied by its model. When a post is instantiated, the visitor's ID and group permissions will determine whether or not the post can be returned for this visitor. This is in contrast to the permission system for pages, which is much simpler and handled by MainController. If you are instantiating a post and you want to skip the permissions check, you can supply the option 'skip_where' => true
to the constructor.
Attributes and Filters
The object property attributes
stores the post attributes as they were fetched from the database; these post attributes are then set as direct properties of the post object, for example $post->attributes['title']
becomes $post->title
. Unless you supply the constructor option 'filter' => false
the attributes will be run through applicable Trigger filters and custom feather filters. The original unfiltered attribute will be retained in e.g. $post->title_unfiltered
. Filtering may result in additional attributes being added to the object.
Object Interrelations
We can see from the property $post->has_many
that multiple modules were enabled at the moment this post object was instantiated, and they have registered their relationship to this post. If we try to get any of these properties, for example $post->pingbacks
, this will result in a query to the pingbacks
database table for rows with a matching post_id
value. You can read more about model interrelations in Working with Model.