jarednova/timber — pull request #77 by mgmartel (2013-10-07 18:55:18+00:00)
Title: Alternative functions API

This started as a way to call template functions (wp_footer, wp_header) only at the moment taht they are called in view files, but it turned into a whole alternative functions api..

## The problem ##

Currently, template functions (primarily, wp_header and wp_footer) are called when the Twig context is generated. This means that they are always called before any parts of the template have actually rendered. In cases like wp_footer, this could be disadvantageous.

Practical example: in plugins, I generally avoid enqueueing footer scripts, unless the plugin's 'render' method has actually been called at least once (to avoid loading resources unnecessarily). Using Timber, wp_footer has already been generated by the time render is called, so the footer script is never added.

Quick fix would be using `{{ function('wp_footer') }}` or `{% do action('wp_footer') %}` instead. But I figured that's not the most elegant way out ;)

## Enter the Function Wrapper ##

The function wrapper only actually executes the function when it's called in the template. Otherwise, it will function exactly the same as ob_function does currently. This means that we can simply substitute all WPHelper::ob_function calls in place without breaking a thing.

## Function API ##

Functions that have been added using the function wrapper are also added as full-fledged Twig functions, accepting all their ordinary arguments, but with defaults as defined when set up in the function wrapper. Functions added like this look far more elegant than the normal function api (#71) and can only be called if they are added to the context (encouraging good practice). The normal function api would then be more of a last resort.

# Usage #
```php
/**
* @param string $function_name
* @param array (optional) $defaults
* @param bool (optional) $return_output_buffer Return function output instead of return value (default: false)
* @return \TimberFunctionWrapper
*/
WPHelper::function_wrapper( $function_name, $defaults = array(), $return_output_buffer = false );
```

#### Examples ####

```php
/* single.php */
$data = Timber::get_context();
$data['post'] = new TimberPost();
$data['edit_post_link'] = WPHelper::function_wrapper( 'edit_post_link', array( __( 'Edit' ), '', '' ) );
Timber::render('single.twig', $data);
```

```
{# single.twig #}

{{edit_post_link}}

{# Calls edit_post_link using default arguments #}
```

```
{# single-my-post-type.twig #}

{{edit_post_link(null, '')}}

{# Calls edit_post_link with all defaults, except for second argument #}
```

Let me know what your thoughts are!