wordpress-themingcustom-wordpress-pagestimber

Custom post class for custom page Template (Timber V 2.X)


In 1.X version of Timber I was able to create a custom class to extend a Timber\Post:

class MyPage extends \Timber\Post {
  public function __construct($pid = null) {
    parent::__construct($pid);
    // my construct function
  }
  
  // other functions...
}

Then I'd add the MyPage class to Timber's classmap.

Then if I needed a custom page template, with a custom class, I could do:

class MyCustomPage extends MyPage {
  public function __construct($pid = null) {
    parent::__construct($pid);
    // my child construct function
  }

  // other functions...
}

and in template-custom-page.php I could do:

$context = \Timber::get_context(); // now is \Timber::context();
$context['post'] = new MyCustomPage();

If you do that in timber 2.x it returns an "empty" object.

What's the correct way to have "custom" classes for custom page templates in timber 2.x?


Solution

  • In Timber 2, you would use Post Class Maps for this.

    First, you register your MyPage class in the post class map:

    add_filter('timber/post/classmap', function ($classmap) {
        $classmap['page'] = MyPage::class;
    
        return $classmap;
    });
    

    Then, you will have to update your MyPage class not use a constructor. Instead, you can use the build method to update your post, if needed:

    class MyPage extends \Timber\Post {
      public static function build(WP_Post $wp_post): static {
        $post = parent::build($wp_post);
    
        // Do something with $post.
        
      }
      
      // other functions...
    }
    

    And then, in your PHP template, you will not directly instantiate MyPage or MyCustomPage, but you will always call Timber::get_post().

    use Timber\Timber;
    
    $context = Timber::context();
    $context['post'] = Timber::get_post();
    

    Be aware though that Timber will already fill in post in $context on singular templates. Usually, you can just delete $context['post'] = Timber::get_post();.

    Now, internally, Timber will use the Class Map to determine which class to build your post with.

    The only thing we need to do now is to tell Timber when to use MyCustomPage instead of MyPage. For this, we need to revisit the `` filter.

    As mentioned in the Post Class Maps documentation, we can also use a callback function to determine when to use which class. In that callback, we receive a $post variable. We use this to get the name of the template using get_post_meta($post->ID, '_wp_page_template', true). And then, if the post uses your custom template, you can select MyCustomPage.

    add_filter('timber/post/classmap', function ($classmap) {
        $classmap['page'] = function (\WP_Post $post) {
            $template = get_post_meta($post->ID, '_wp_page_template', true);
    
            if ($template === 'Your custom template') {
                return MyCustomPage::class;
            }
    
            return MyPage::class;
        };
    
        return $classmap;
    });