---
title: "Extending Timber"
menu:
  main:
    parent: "guides"
---

Myth: Timber is for making simple themes. Fact: It's for making incredibly complex themes _look_ easy. But yes, you can also make simple sites from it.

The beauty of Timber is that the object-oriented nature lets you extend it to match the exact requirements of your theme.

## An example that extends TimberPost

Timber's objects like `Timber\Post`, `Timber\Term`, etc. are a great starting point to build your own subclass from. For example, on this project each post was a part of an "issue" of a magazine. I wanted an easy way to reference the issue in the twig file:


```twig
<h1>{{ post.title }}</h1>
<h3>From the {{ post.issue.title }} issue</h3>
```

Of course, `Timber\Post` has no built-in concept of an issue (which I've built as a custom taxonomy called "issues"). So we're going to extend TimberPost to give it one:

```php
<?php
class MySitePost extends Timber\Post {

	var $_issue;

	public function issue() {
		$issues = $this->get_terms('issues');
		if (is_array($issues) && count($issues)) {
			return $issues[0];
		}
	}
}
```

So now I've got an easy way to refer to the {{ post.issue }} in our twig templates. If you want to make this production-ready I recommend a bit of internal caching so that you don't re-query every time you need to get the
issue data:

```php
<?php
class MySitePost extends Timber\Post {

	var $_issue;

	public function issue() {
		if (!$this->_issue) {
			$issues = $this->get_terms('issues');
			if (is_array($issues) && count($issues)) {
				$this->_issue = $issues[0];
			}
		}
		return $this->_issue;
	}
}
```

Right now I'm in the midst of building a complex site for a hybrid foundation and publication. The posts on the site have some very specific requirements that requires a fair amount of logic. I can take the simple `Timber\Post` object and extend it to make it work perfectly for this theme.

For example, I have a plugin that let's people insert manually related posts, but if they don't, WordPress will pull some automatically based on how the post is tagged.

```php
	<?php
	class MySitePost extends Timber\Post {

		function get_related_auto() {
			$tags = $this->tags();
			if (is_array($tags) && count($tags)) {
				$search_tag = $tags[0];
				$related = Timber::get_posts('tag_id='.$search_tag->ID);
				return $related;
			} else {
				//not tagged, cant do related on it
				return false;
			}
		}

		function get_related_manual() {
			if (isset($this->related_manual) && is_array($this->related_manual)){
				foreach($this->related_manual as &$related){
					$related = new MySitePost($related);
				}
				return $this->related_manual;
			}
			return false;
		}

		function related($limit = 3) {
			$related = $this->get_related_manual();
			if (!$related){
				$related = $this->get_related_auto();
			}
			if (is_array($related)) {
				array_splice($related, 0, $limit);
			}
			return $related;
		}
	}
```

These can get pretty complex. And that's the beauty. The complexity lives inside the context of the object, but very simple when it comes to your templates.

## Adding functionality to Twig

You can extend Twig by adding custom functionality like functions or filters. Timber provides its own classes (`Timber\Twig_Function` and `Timber\Twig_Filter`) to provide better compatibility with different versions of Twig.

**functions.php**

```php
<?php

add_filter( 'timber/twig', 'add_to_twig' );

/**
 * Adds functionality to Twig.
 * 
 * @param \Twig\Environment $twig The Twig environment.
 * @return \Twig\Environment
 */
function add_to_twig( $twig ) {
    // Adding a function.
    $twig->addFunction( new Timber\Twig_Function( 'edit_post_link', 'edit_post_link' ) );
    
    // Adding functions as filters.
    $twig->addFilter( new Timber\Twig_Filter( 'whateverify', 'whateverify' ) );
    $twig->addFilter( new Timber\Twig_Filter( 'slugify', function( $title ) {
        return sanitize_title( $title );
    } ) );
    
    return $twig;
}

function whateverify( $text ) {
    $text .= ' or whatever';
    
    return $text;
}
```

This can now be called in your twig files with:

```twig
<h2 id="{{ post.title|slugify }}">{{ post.title|whateverify }}</h2>
```

Which will output:

```twig
<h2 id="hello-world">Hello World! or whatever</h2>
```
