Class Maps
The Class Map is the central hub for Timber to select the right PHP class for post or term objects. Whenever you want to extend existing Timber classes with your custom classes, you’ll have to register them through a Class Map so that Timber will know when to use it.
There are several different Class Maps in Timber:
timber/post/classmap
for poststimber/term/classmap
for termstimber/comment/classmap
for commentstimber/menu/classmap
andtimber/menu/class
for menustimber/menuitem/classmap
andtimber/menuitem/class
for menu item classestimber/user/class
for users
The Post Class Map #
When you extend Timber\Post
, the logic you add is usually for a certain post type. With the timber/post/classmap
filter, you can tell Timber which class it should use for certain post types.
The Post Class Map is used:
- When you get a post through
Timber::get_post()
. - When you get a collection of posts through
Timber::get_posts()
. - When you use a function that returns other posts, like
$post->children()
or$post->thumbnail()
.
functions.php
use Book;
use Page;
add_filter('timber/post/classmap', function ($classmap) {
$custom_classmap = [
'page' => Page::class,
'book' => Book::class,
];
return array_merge($classmap, $custom_classmap);
});
Post types that you don’t list in the Post Class Map will take the default Timber\Post
class.
In case you need more fine-grained control over which class is used for your post object, you can use a callback function:
use Book;
use PreciousBook;
add_filter('timber/post/classmap', function ($classmap) {
$custom_classmap = [
'book' => function (\WP_Post $post) {
if ($post->id === 3) {
return PreciousBook::class;
}
return Book::class;
},
];
return array_merge($classmap, $custom_classmap);
});
The callback function receives a WP_Post
object and should return the name of the class to use.
Here’s another example, where you could use a different attachment class for a featured image that belongs to a certain post type.
use BookAttachment;
use Timber\Attachment;
add_filter('timber/post/classmap', function ($classmap) {
$custom_classmap = [
'attachment' => function (\WP_Post $post) {
if ('book' === get_post_type($post->post_parent)) {
return BookAttachment::class;
}
return Attachment::class;
},
];
return array_merge($classmap, $custom_classmap);
});
The Term Class Map #
When you extend Timber\Term
, the logic you add is usually for a certain taxonomy. With the timber/term/classmap
filter, you can tell Timber which class it should use for certain taxonomies.
The Term Class Map is used:
- When you get a post through
Timber::get_term()
. - When you get a collection of posts through
Timber::get_terms()
. - When you use a function that returns other terms, like
$post->terms()
.
functions.php
use Genre;
add_filter('timber/term/classmap', function ($classmap) {
$custom_classmap = [
'genre' => Genre::class,
];
return array_merge($classmap, $custom_classmap);
});
Taxonomies that you don’t list in the Term Class Map will take the default Timber\Term
class.
When you need more fine-grained control over which class is used for your term object, you can use a callback function:
use ComedyGenre;
use Genre;
add_filter('timber/term/classmap', function ($classmap) {
$custom_classmap = [
'genre' => function (\WP_Term $term) {
if ($term->term_id === 2) {
return ComedyGenre::class;
}
return Genre::class;
},
];
return array_merge($classmap, $custom_classmap);
});
The callback function receives a WP_Term
object and should return the name of the class to use.
The Comment Class Map #
When you extend Timber\Comment
, the logic you add is usually for comments related to a certain post type. With the timber/comment/classmap
filter, you can tell Timber which class it should use for comments that belong to a certain post type.
The Comment Class Map is used:
- When you get a single comment through
Timber::get_comment()
. - When you get the comments for a post through
$post->comments()
.
functions.php
use CommentBook;
use CommentPost;
add_filter('timber/comment/classmap', function ($classmap) {
$custom_classmap = [
'post' => CommentPost::class,
'book' => CommentBook::class,
];
return array_merge($classmap, $custom_classmap);
});
Comments for post types that you don’t list in the Comment Class Map will take the default Timber\Comment
class name as an argument.
When you need more fine-grained control over which class is used for your comment object, you can use a callback function:
use BookChildComment;
use BookComment;
add_filter('timber/comment/classmap', function ($classmap) {
$custom_classmap = [
'book' => function (\WP_Comment $comment) {
$post = get_post($comment->comment_post_ID);
if (0 !== $post->post_parent) {
return BookChildComment::class;
}
return BookComment::class;
},
];
return array_merge($classmap, $custom_classmap);
});
The callback function receives a WP_Comment
object and should return the name of the class to use. If you need the post ID a comment is associated with, you can get that through $comment->comment_post_ID
.
The Menu Class Map #
With the timber/menu/classmap
filter, you can tell Timber which class it should use for menu objects based on the menu location. It’s pretty much the same as the timber/menuitem/classmap
filter, just for menus instead of menu items.
The Menu Class Map is used:
- When you get a menu through
Timber::get_menu()
.
Here’s an example for a basic filter where we select different menu objects based on the primary
and secondary
nav menu locations.
functions.php
add_filter('timber/menu/classmap', function ($classmap) {
$custom_classmap = [
'primary' => MenuPrimary::class,
'secondary' => MenuSecondary::class,
];
return array_merge($classmap, $custom_classmap);
}, 10);
Menu locations that you don’t list in the class map will use Timber\Menu
as a default class. If selecting a menu class based on the location isn’t enough for you, you can further customize the class selection using the timber/menu/class
filter.
The following example demonstrates how you can use custom classes (SingleLevelMenu
or MultiLevelMenu
) based on the depth of the menu.
add_filter('timber/menu/class', function ($class, $term, $args) {
if ($args['depth'] === 1) {
return SingleLevelMenu::class;
}
return MultiLevelMenu::class;
}, 10, 3);
The MenuItem class map filter #
With the timber/menuitem/classmap
filter, you can tell Timber which class it should use for menu items based on the menu location. It’s pretty much the same as the timber/menu/classmap
filter, just for menu items instead of menus.
The Menu Class Map is used:
- When you get a menu through
Timber::get_menu()
.
Here’s an example for a basic filter where we select different menu objects based on the primary
and secondary
nav menu locations.
add_filter('timber/menuitem/classmap', function ($classmap) {
$custom_classmap = [
'primary' => MenuItemFooter::class,
'secondary' => MenuItemHeader::class,
];
return array_merge($classmap, $custom_classmap);
});
Menu locations that you don’t list in the class map will use Timber\MenuItem
as a default class. You can further customize the class that is being used with the timber/menuitem/class
filter.
The MenuItem class filter #
With the timber/menuitem/class
filter, you can tell Timber which class it should use for menu item objects (that is, the actual items within the menu).
The MenuItem class filter is used:
- When you get a menu through
Timber::get_menu()
.
functions.php
add_filter('timber/menuitem/class', function ($class, $item, $menu) {
if ($menu instanceof MenuPrimary) {
return MenuItemPrimary::class;
}
return $class;
}, 10, 3);
In the above example, the MenuItem class filter receives the default Timber\MenuItem
class name, the WordPress menu item (which is an instance of WP_Post
) and the Timber\Menu
object that the item is assigned to. You should be able to decide which class to use based on these parameters. This example demonstrates how you can use a custom class (MenuItemPrimary
) when the parent menu has a (custom) class of MenuPrimary
.
Here’s another example where you would use a different class if the menu item is in a menu assigned to the secondary
menu location.
add_filter('timber/menuitem/class', function ($class, $item, $menu) {
if ('secondary' === $menu->theme_location) {
return MenuItemPrimary::class;
}
return $class;
}, 10, 3);
The Pages Menu Class filter #
With the timber/pages_menu/class
filter, you can tell Timber which class it should use for the pages menu object.
The Pages Menu Class filter is used:
- When you get a menu through
Timber::get_pages_menu()
.
Here’s an a example for a basic filter where you would always return your custom ExtendedMenu
class.
functions.php
use ExtendedPagesMenu;
add_filter('timber/pages_menu/class', function ($class) {
return ExtendedPagesMenu::class;
});
The User class filter #
With the timber/user/class
filter, you can tell Timber which class it should use for user objects.
The User Class Map is used:
- When you get the currently logged-in user through
Timber::get_user()
. - When you get a user by ID through
Timber::get_user( $user_id )
. - When you get a post’s author (or authors) through
$post->author()
or$post->authors()
.
functions.php
use UserExtended;
add_filter('timber/user/class', function ($class, \WP_User $user) {
return UserExtended::class;
}, 10, 2);
In the above example, the User class filter receives the default User class and a WP_User
object as arguments. You should be able to decide which class to use based on that user object.
In case you need a different User class based on the current template you’re displaying, you can use Conditional Tags.
add_filter('timber/user/class', function ($class, \WP_User $user) {
// Use Author class for single post template.
if (is_singular('post')) {
return Author::class;
}
return $class;
}, 10, 2);
If you need to have a special class based on the capabilities a user has, work with $user->has_cap()
.
add_filter('timber/user/class', function ($class, \WP_User $user) {
if ($user->has_cap('manage_options')) {
return Administrator::class;
} elseif ($user->has_cap('edit_pages')) {
return Editor::class;
}
return $class;
}, 10, 2);
If you need to check for user roles, check the $user->roles
array. Don’t work with $user->has_cap()
to check for roles, because it may lead to unreliable results.
add_filter('timber/user/class', function ($class, \WP_User $user) {
if (in_array('editor', $user->roles, true)) {
return Editor::class;
} elseif (in_array('author', $user->roles, true)) {
return Author::class;
}
return $class;
}, 10, 2);