This page shows how the internal API works and how to create and fetch all kinds of entities in Tainacan: Collections, items, taxnomies, metadata, filters, terms, item metadata and logs.
Its important that you first get familiar with the [key concepts](key-concepts.md) of tainacan.
## Overview
Tainacan adds a tiny layer of abstraction over WordPress to handle all its entities, but at the end of the day, everything is stored as a post of a specific post type (except terms). So for someone used to the way WordPress works, the data structure have no misteries at all.
This layer is based on a Repository pattern. Each entity Tainacan deals with have a correspondent Repository class and a correspondent Entity class.
Repositories are the classes that comunicate with the database and know where everything is stored and how to find things. It is a singleton class, so it have only one instance available to be used by any part of the application.
For example, Metadata have many attributes, such as `name` and `required` (indicating wether this metadatum is required or not). As mentioned before, Metadata are stored as posts of a special post type called `tainacan-metadatum`. The name of the metadatum is, of course, the `post_title` and this `required` attribute is stored as a `post_meta`.
Tainacan will automatically map the values of the attributes to and from where they are stored.
When you want to fetch entities from the database, this abstraction layer steps aside and let you use all the power and flexibility of `WP_Query`, which you know and love. For example:
The `fetch` method from the repositories accept exactly the same arguments accepted by `WP_Query` and uses it internally. In fact, you could use `WP_Query` directly if you prefer, but using the repository class gives you some advantages. You dont have to know the name of the post type, you can also fetch by some mapped attribute calling it directly, without having to use `meta_query` (or even know wether a property is stored as a post attribute or post_meta). See more details in the Fetch section below.
Every repository have a `fetch()` method to fetch data from the database. Some repositories may have other fetch methods, such as `fetch_by_collection`, please refer to their reference to find out.
### Getting one single individual
If you have the ID or the `WP_Post` object, you can get the item by initializing a new instance of the Entity class:
```PHP
$collection = new Tainacan\Entities\Collection($collection_post);
$collection = new Tainacan\Entities\Collection($collection_id);
This will have the same effect as calling the `fetch` method from the repository passing an integer as argument. The repository will assume it is the collection ID.
To fetch collections (or any other entity) based on a query search, you may call the `fetch` method from the repository and use any paramater of the `WP_Query` class.
> the only exception for this are terms, which are saved as WordPress terms and gets paramaters from the `get_terms()` function instead
$collections = $repo->fetch(); // get all public collections (or any private collections current user can view. It works exactly the same way WP_Query)
/**
* fetch all items with title equal to 'test'
*/
$items = $items_repo->fetch([
'post_title' => 'test'
]);
/**
* fetch all items with title equal to 'test'
* but using the mapped property name instead of the real name
*/
$items = $items_repo->fetch([
'title' => 'test'
]);
```
Note that you can use the mapped attribute names to build your query, but it is just fine if you want to use the native WordPress names. The same can be achievied with attributes stored as post_meta:
All repositories have an `insert()` method that gets an Entity as argument and save it in the database. If the entity has an ID, this method will update the entity. (yes, the same way `wp_insert_post` works)
Each repository will get as a parameter an instace of its correspondent entity. For example, Collections repository `insert()` will get an instace of `Tainacan\Entities\Collection` and return the updated entity.
However, before insertion, you must validate the entity, calling the `validate()` method every entity has. You can only insert valid entities.
So this is a typical routine for creating an entity:
echo 'I still have the same ID! ' . $insertedCollection->get_id();
} else {
$errors = $insertedCollection->get_errors();
}
} else {
$validationErrors = $collection->get_errors();
// Do something!
}
```
> IMPORTANT: Repositories `insert()` methods do not check for user permissions. If you call it, it will save entities to the database no matter who is logged in (or even if some is logged in). Again, this works the same way WordPress works with its internal functions. All permission checks must be done before you call the insertion methods. See "checking for permissions" section below.
The example above shows how to create and update a Collection, but it applies to every entity. They all work in the very same way.
Well, Item Metadata Entity is slightly different.
### Handling Item Metadata
`Item Metada` is a special kind of entity, because it is not an actual entity itself. Rather, it is the relationship between an Item and a Field. And this relationship has a value.
So imagine a Collection of pens has a Metadata called "color". This means that an item of this collection will have a relationship with this metadatum, and this relation will have a value. "Red", for example.
So the Item Metadata Entity constructor gets two entities: an item and a metadatum. Lets see an example, considering I alredy have a collection with metadata and an item.
> Note: "Multiple" Metadata, which can have more than one value for the same item, work exactly the same way, with the difference that its value is an array of values, and not just one single value.
If you want to iterate over all metadata of an item or a collection, there are 2 usefull methods you can use. Metadata repository have a `fetch_by_collection()` method that will fetch all metadata from a given collection and return them in the right order.
Validate Field -> call validate_options() of the Field type
## Checking for permissions
Each entity type is stored as a post type and has its own set of capabilities. For example, Collections are posts of the `tainacan-collection` post type, and have associated capabilities such as `edit_tainacan-collections` and `edit_others_tainacan-collections`.
If you are familiar with WordPress Roles and capabilities and, more specifically, with custom post types capabilities, this is very easy to understand. If you are not, its best if you first learn how WordPress handles custom post types capabilities and you will easily understand how tainacan works with it.
To see a complete list of tainacan capabilities see [Tainacan Permissions](permissions.md).
When you use WordPress custom post types, you dont need to know the exact name of the capabilities of a post type to check for them. The post type object has a property called `cap` that informs you what are the specific capabilities that the post type have for the post type actions.
For example, for a post type called `book`, that have capabilities such as `edit_books`, you could:
```PHP
if (current_user_can('edit_books'))
// do something
```
OR
```PHP
$book_cpt = get_post_type_object('book');
if (current_user_can( $book_cpt->cap->edit_posts ))
// do something
```
This makes life easier and Tainacan works exacty the same way.
```PHP
$collection = new \Tainacan\Entities\Collection(23);
var_dump( $collection->get_capabilities() ); // all capabilities of the collections post type
```
This is specially usefull when handling Items, because they are posts of dynamic created post types, and it would cost too much to find out the correct capabilties names.
Also, every entity implement 3 methods to check for the Meta Capabilities `edit_post`, `delete_post` and `read_post`, so intead of: