Timber - Version 0.18.1

Version Description

  • Dates now use date_i18n filter (thanks @jamesagreenleaf)
  • The twig |date filter now defaults to your WP Admin settings (thanks @jamesagreenleaf)
  • You can send Timber::$dirname an array to specify multiple locations of twig files within a theme
  • Load views from anywhere on the server (thanks @th3fallen)
  • Load twig files from anywhere on the server using an absolute path
  • Use another version of Twig if you have it loaded (thanks @ButlerPCnet)
  • more tests!
Download this release

Release Info

Developer jarednova
Plugin Icon 128x128 Timber
Version 0.18.1
Comparing to
See all releases

Code changes from version 0.18.0 to 0.18.1

README.md CHANGED
@@ -1,5 +1,5 @@
1
  <div style="text-align:center">
2
- <a href="http://jarednova.github.com/timber"><img src="http://i.imgur.com/f2w7MxZ.jpg" style="display:block; margin:auto;"/></a>
3
  <div>
4
  By Jared Novack (<a href="http://twitter.com/jarednova">@JaredNova</a>) and <a href="http://upstatement.com">Upstatement</a> (<a href="http://twitter.com/upstatement">@Upstatement</a>)</div>
5
  </div>
@@ -17,7 +17,7 @@ This is what Timber's `.twig` files look like:
17
  {% extends "base.twig" %}
18
  {% block content %}
19
  <h1 class="big-title">{{foo}}</h1>
20
- <h2>{{post.title}}</h2>
21
  <img src="{{post.thumbnail.src}}" />
22
  <div class="body">
23
  {{post.content}}
@@ -49,16 +49,14 @@ Timber is a tool for developers who want to translate their HTML into high-quali
49
  Nothing. Timber is meant for you to build a theme on. Like the [Starkers](https://github.com/viewportindustries/starkers) or [Boilerplate theme](https://github.com/zencoder/html5-boilerplate-for-wordpress) it comes style-free, because you're the style expert. Instead, Timber handles the logic you need to make a kick-ass looking site.
50
 
51
  #### Who is it good for?
52
- Timber is great for any WordPress developer who cares about writing good, maintainable code. It helps teams of designers and developers working together. At [Upstatement](http://upstatement.com) we made Timber because not everyone knows the ins-and-outs of the_loop(), WordPress codex and PHP (nor should they). With Timber your best WordPress dev can focus on building the .php files with requests from WordPress and pass the data into .twig files. Once there, designers can easily mark-up data and build out a site's look-and-feel.
53
 
54
  #### Related Projects
55
  * [**Timber Debug Bar**](https://github.com/upstatement/debug-bar-timber) Adds a debug bar panel that will show you want template is in-use and the data sent to your twig file.
 
56
  * [**Twig**](https://github.com/fabpot/Twig) The template language used by Timber.
57
 
58
  #### Should I use it?
59
- Well, it's **free**! And it's GPL-licensed, so use in personal or commercial work. Just don't re-sell it. Timber is still in development. While much has been stabalized since the first major push back in June 2013, you should expect some breaking changes as development progresses towards a version 1.0.
60
-
61
- [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/jarednova/timber/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
62
-
63
 
64
 
1
  <div style="text-align:center">
2
+ <a href="http://jarednova.github.com/timber"><img src="http://i.imgur.com/oM1AHrz.jpg" style="display:block; margin:auto; width:100%; max-width:100%"/></a>
3
  <div>
4
  By Jared Novack (<a href="http://twitter.com/jarednova">@JaredNova</a>) and <a href="http://upstatement.com">Upstatement</a> (<a href="http://twitter.com/upstatement">@Upstatement</a>)</div>
5
  </div>
17
  {% extends "base.twig" %}
18
  {% block content %}
19
  <h1 class="big-title">{{foo}}</h1>
20
+ <h2 class="post-title">{{post.title}}</h2>
21
  <img src="{{post.thumbnail.src}}" />
22
  <div class="body">
23
  {{post.content}}
49
  Nothing. Timber is meant for you to build a theme on. Like the [Starkers](https://github.com/viewportindustries/starkers) or [Boilerplate theme](https://github.com/zencoder/html5-boilerplate-for-wordpress) it comes style-free, because you're the style expert. Instead, Timber handles the logic you need to make a kick-ass looking site.
50
 
51
  #### Who is it good for?
52
+ Timber is great for any WordPress developer who cares about writing good, maintainable code. It helps teams of designers and developers working together. At [Upstatement](http://upstatement.com) we made Timber because while our entire team needs to participate in building WordPress sites, not everyone knows the ins-and-outs of the_loop(), codex and PHP (nor should they). With Timber your best WordPress dev can focus on building the .php files with requests from WordPress and pass the data into .twig files. Once there, designers can easily mark-up data and build out a site's look-and-feel.
53
 
54
  #### Related Projects
55
  * [**Timber Debug Bar**](https://github.com/upstatement/debug-bar-timber) Adds a debug bar panel that will show you want template is in-use and the data sent to your twig file.
56
+ * [**TimberPhoton**](https://github.com/slimndap/TimberPhoton) Plug-in to use JetPack's free Photon image maninpulation and CDN with Timber.
57
  * [**Twig**](https://github.com/fabpot/Twig) The template language used by Timber.
58
 
59
  #### Should I use it?
60
+ It's GPL-licensed, so please use in personal or commercial work. Just don't re-sell it. While Timber is still in development, it's also in-use on [hundreds of sites](http://jarednova.github.io/timber/#showcase). While much has been stabalized since the first major push back in June 2013, you should expect some breaking changes as development progresses towards a version 1.0.
 
 
 
61
 
62
 
functions/functions-twig.php CHANGED
@@ -41,15 +41,20 @@ class TimberTwig {
41
  $twig->addFilter('relative', new Twig_Filter_Function(function($link){
42
  return TimberURLHelper::get_rel_url($link, true);
43
  }));
 
44
 
45
  $twig->addFilter('truncate', new Twig_Filter_Function(function($text, $len){
46
  return TimberHelper::trim_words($text, $len);
47
  }));
48
 
49
  /* actions and filters */
50
- $twig->addFunction(new Twig_SimpleFunction('action', function(){
51
- call_user_func_array('do_action', func_get_args());
52
- }));
 
 
 
 
53
  $twig->addFilter( new Twig_SimpleFilter('apply_filters', function(){
54
  $args = func_get_args();
55
  $tag = current(array_splice($args, 1, 1));
@@ -231,6 +236,18 @@ function twig_body_class($body_classes) {
231
  return $return;
232
  }
233
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  /**
235
  * @param string $string
236
  * @param array $data
41
  $twig->addFilter('relative', new Twig_Filter_Function(function($link){
42
  return TimberURLHelper::get_rel_url($link, true);
43
  }));
44
+ $twig->addFilter('date', new Twig_Filter_Function('twig_intl_date'));
45
 
46
  $twig->addFilter('truncate', new Twig_Filter_Function(function($text, $len){
47
  return TimberHelper::trim_words($text, $len);
48
  }));
49
 
50
  /* actions and filters */
51
+ $twig->addFunction( new Twig_SimpleFunction('action', function($context){
52
+ $args = func_get_args();
53
+ array_shift($args);
54
+ $args[] = $context;
55
+ call_user_func_array('do_action', $args);
56
+ }, array('needs_context' => true)));
57
+
58
  $twig->addFilter( new Twig_SimpleFilter('apply_filters', function(){
59
  $args = func_get_args();
60
  $tag = current(array_splice($args, 1, 1));
236
  return $return;
237
  }
238
 
239
+ /**
240
+ * @param string $date
241
+ * @param string $format (optional)
242
+ * @return string
243
+ */
244
+ function twig_intl_date($date, $format = null) {
245
+ if ($format === null) {
246
+ $format = get_option('date_format');
247
+ }
248
+ return date_i18n($format, strtotime($date));
249
+ }
250
+
251
  /**
252
  * @param string $string
253
  * @param array $data
functions/integrations/wpcli-timber.php CHANGED
@@ -3,32 +3,74 @@
3
  class Timber_Command extends WP_CLI_Command{
4
 
5
  /**
6
- * Clears Twig's Cache
7
  *
8
  * ## EXAMPLES
9
  *
10
- * wp clear_cache
11
  *
12
- * @synopsis <nothing>
13
  */
14
- function clear_cache(){
15
- $files = glob('../../twig-cache/*');
16
- foreach($files as $file){
17
- if (is_file($file)) {
18
- unlink($file);
19
- }
 
 
 
 
 
20
  }
21
  }
22
 
23
  /**
 
 
24
  * ## EXAMPLES
25
- * wp timber poop
 
 
26
  */
27
 
28
- function poop(){
29
- WP_CLI::success('HEllo!!! poopy pants');
30
  }
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  }
33
 
34
- WP_CLI::add_command( 'timber', 'Timber_Command' );
3
  class Timber_Command extends WP_CLI_Command{
4
 
5
  /**
6
+ * Clears Timber and Twig's Cache
7
  *
8
  * ## EXAMPLES
9
  *
10
+ * wp timber clear_cache
11
  *
 
12
  */
13
+
14
+ function clear_cache($mode = 'all'){
15
+ WP_CLI::line('#mode = '.print_r($mode, true));
16
+ if ($mode == 'all'){
17
+ self::clear_cache_twig();
18
+ self::clear_cache_timber();
19
+ }
20
+ if ($mode == 'twig'){
21
+ }
22
+ if ($mode == 'timber'){
23
+
24
  }
25
  }
26
 
27
  /**
28
+ * Clears Timber's Cache
29
+ *
30
  * ## EXAMPLES
31
+ *
32
+ * wp timber clear_cache_timber
33
+ *
34
  */
35
 
36
+ function clear_cache_timber(){
37
+ WP_CLI::success('Cleared contents of Timbers Cache');
38
  }
39
 
40
+ /**
41
+ * Clears Twig's Cache
42
+ *
43
+ * ## EXAMPLES
44
+ *
45
+ * wp timber clear_cache_twig
46
+ *
47
+ */
48
+
49
+ function clear_cache_twig(){
50
+ $loader = new TimberLoader();
51
+ $twig = $loader->get_twig();
52
+ $twig->clearCacheFiles();
53
+ self::rrmdir($twig->getCache());
54
+ WP_CLI::success('Cleared contents of '.$twig->getCache());
55
+ }
56
+
57
+ private function rrmdir($dir) {
58
+ if (is_dir($dir)) {
59
+ $objects = scandir($dir);
60
+ foreach ($objects as $object) {
61
+ if ($object != "." && $object != "..") {
62
+ if (filetype($dir."/".$object) == "dir"){
63
+ self::rrmdir($dir."/".$object);
64
+ rmdir($dir."/".$object);
65
+ } else {
66
+ unlink($dir."/".$object);
67
+ }
68
+ }
69
+ }
70
+ reset($objects);
71
+ }
72
+ }
73
+
74
  }
75
 
76
+ WP_CLI::add_command( 'timber', 'Timber_Command' );
functions/timber-helper.php CHANGED
@@ -460,6 +460,7 @@ class TimberHelper {
460
  $link = add_query_arg( $add_args, $link );
461
  }
462
  $link .= $add_fragment;
 
463
  $page_links[] = array('class' => 'prev page-numbers', 'link' => esc_url( apply_filters( 'paginate_links', $link )), 'title' => $prev_text);
464
  }
465
  for ( $n = 1; $n <= $total; $n++ ) {
@@ -475,6 +476,7 @@ class TimberHelper {
475
  if ( $add_args ) {
476
  $link = rtrim(add_query_arg( $add_args, $link ), '/');
477
  }
 
478
  $page_links[] = array('class' => 'page-number page-numbers', 'link' => esc_url( apply_filters( 'paginate_links', $link ) ), 'title' => $n_display, 'current' => $current == $n);
479
  $dots = true;
480
  } elseif ( $dots && !$show_all ) {
@@ -489,7 +491,7 @@ class TimberHelper {
489
  if ( $add_args ) {
490
  $link = add_query_arg( $add_args, $link );
491
  }
492
- $link = trailingslashit($link).$add_fragment;
493
  $page_links[] = array('class' => 'next page-numbers', 'link' => esc_url( apply_filters( 'paginate_links', $link ) ), 'title' => $next_text);
494
  }
495
  return $page_links;
460
  $link = add_query_arg( $add_args, $link );
461
  }
462
  $link .= $add_fragment;
463
+ $link = untrailingslashit($link);
464
  $page_links[] = array('class' => 'prev page-numbers', 'link' => esc_url( apply_filters( 'paginate_links', $link )), 'title' => $prev_text);
465
  }
466
  for ( $n = 1; $n <= $total; $n++ ) {
476
  if ( $add_args ) {
477
  $link = rtrim(add_query_arg( $add_args, $link ), '/');
478
  }
479
+ $link = untrailingslashit($link);
480
  $page_links[] = array('class' => 'page-number page-numbers', 'link' => esc_url( apply_filters( 'paginate_links', $link ) ), 'title' => $n_display, 'current' => $current == $n);
481
  $dots = true;
482
  } elseif ( $dots && !$show_all ) {
491
  if ( $add_args ) {
492
  $link = add_query_arg( $add_args, $link );
493
  }
494
+ $link = untrailingslashit(trailingslashit($link).$add_fragment);
495
  $page_links[] = array('class' => 'next page-numbers', 'link' => esc_url( apply_filters( 'paginate_links', $link ) ), 'title' => $next_text);
496
  }
497
  return $page_links;
functions/timber-image-helper.php CHANGED
@@ -2,6 +2,17 @@
2
 
3
  class TimberImageHelper {
4
 
 
 
 
 
 
 
 
 
 
 
 
5
  /**
6
  * @param string $hexstr
7
  * @return array
@@ -17,6 +28,50 @@
17
  return array("red" => 0xFF & ($int >> 0x10), "green" => 0xFF & ($int >> 0x8), "blue" => 0xFF & $int);
18
  }
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  /**
21
  * @param string $src
22
  * @param int $w
@@ -32,6 +87,7 @@
32
  $color = str_replace('#', '', $color);
33
  $newbase = $basename . '-lbox-' . $w . 'x' . $h . '-' . $color;
34
  $new_path = $dir . '/' . $newbase . '.' . $ext;
 
35
  return $new_path;
36
  }
37
 
@@ -43,18 +99,44 @@
43
  * @return string
44
  */
45
  public static function get_letterbox_file_path($src, $w, $h, $color) {
46
- $path_parts = pathinfo($src);
47
- $basename = $path_parts['filename'];
48
- $ext = $path_parts['extension'];
49
- $dir = $path_parts['dirname'];
50
- $color = str_replace('#', '', $color);
51
- $newbase = $basename . '-lbox-' . $w . 'x' . $h . '-' . $color;
52
- $new_path = $dir . '/' . $newbase . '.' . $ext;
53
  $new_root_path = ABSPATH . $new_path;
54
  $new_root_path = str_replace('//', '/', $new_root_path);
55
  return $new_root_path;
56
  }
57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  /**
59
  * @param int $iid
60
  * @return string
@@ -74,24 +156,31 @@
74
  * @return mixed|null|string
75
  */
76
  public static function letterbox($src, $w, $h, $color = '#000000', $force = false) {
77
- $abspath = substr(ABSPATH, 0, -1);
78
- $urlinfo = parse_url($src);
79
- if( $_SERVER['DOCUMENT_ROOT'] != $abspath ) {
80
- $subdir = str_replace($_SERVER['DOCUMENT_ROOT'].'/', '', $abspath);
81
- $urlinfo['path'] = str_replace('/'.$subdir.'/', '', $urlinfo['path']);
 
82
  }
83
- $old_file = ABSPATH.$urlinfo['path'];
84
- $new_file = self::get_letterbox_file_path($urlinfo['path'], $w, $h, $color);
 
 
 
85
  $urlinfo = parse_url($src);
86
- $new_file_rel = self::get_letterbox_file_rel($urlinfo['path'], $w, $h, $color);
87
- if (file_exists($new_file_rel) && !$force) {
88
- return $new_file_rel;
 
 
 
89
  }
90
  $bg = imagecreatetruecolor($w, $h);
91
  $c = self::hexrgb($color);
92
  $white = imagecolorallocate($bg, $c['red'], $c['green'], $c['blue']);
93
  imagefill($bg, 0, 0, $white);
94
- $image = wp_get_image_editor($old_file);
95
  if (!is_wp_error($image)) {
96
  $current_size = $image->get_size();
97
  $ow = $current_size['width'];
@@ -114,18 +203,18 @@
114
  $owt = $w;
115
  $image->crop(0, 0, $ow, $oh, $owt, $oht);
116
  }
117
- $image->save($new_file);
118
  $func = 'imagecreatefromjpeg';
119
- $ext = pathinfo($new_file, PATHINFO_EXTENSION);
120
  if ($ext == 'gif') {
121
  $func = 'imagecreatefromgif';
122
  } else if ($ext == 'png') {
123
  $func = 'imagecreatefrompng';
124
  }
125
- $image = $func($new_file);
126
  imagecopy($bg, $image, $x, $y, 0, 0, $owt, $oht);
127
- imagejpeg($bg, $new_file);
128
- return TimberURLHelper::get_rel_path($new_file);
129
  } else {
130
  TimberHelper::error_log($image);
131
  }
@@ -138,7 +227,7 @@
138
  * @return string
139
  */
140
  public static function img_to_jpg($src, $bghex = '#FFFFFF'){
141
- $src = str_replace(site_url(), '', $src);
142
  $output = str_replace('.png', '.jpg', $src);
143
  $input_file = ABSPATH . $src;
144
  $output_file = ABSPATH . $output;
@@ -215,7 +304,7 @@
215
  if (empty($src)){
216
  return '';
217
  }
218
- if (strstr($src, 'http') && !strstr($src, content_url())) {
219
  $src = self::sideload_image($src);
220
  }
221
  $abs = false;
@@ -228,31 +317,29 @@
228
  $crop = $allowed_crop_positions[ 0 ];
229
  }
230
  //oh good, it's a relative image in the uploads folder!
231
- $path_parts = pathinfo($src);
232
- $basename = $path_parts['filename'];
233
- $ext = $path_parts['extension'];
234
- $dir = $path_parts['dirname'];
235
- $newbase = $basename . '-' . $w . 'x' . $h . '-c-' . ( $crop ? $crop : 'f' ); // Crop will be either d (default), c (center) or f (false)
236
- $new_path = $dir . '/' . $newbase . '.' . $ext;
237
- $new_path = str_replace(content_url(), '', $new_path);
238
- $new_root_path = WP_CONTENT_DIR . $new_path;
239
- $old_root_path = WP_CONTENT_DIR . str_replace(content_url(), '', $src);
240
- $old_root_path = str_replace('//', '/', $old_root_path);
241
- $new_root_path = str_replace('//', '/', $new_root_path);
242
  if ( file_exists($new_root_path) ) {
243
  if ( $force_resize ) {
244
  // Force resize - warning: will regenerate the image on every pageload, use for testing purposes only!
245
  unlink( $new_root_path );
246
  } else {
247
  if ($abs){
248
- return untrailingslashit(content_url()).$new_path;
249
  } else {
250
- return TimberURLHelper::preslashit($new_path);
 
251
  }
252
  return $new_path;
253
  }
254
  }
255
-
256
  $image = wp_get_image_editor($old_root_path);
257
 
258
  if (!is_wp_error($image)) {
@@ -285,8 +372,6 @@
285
  $src_x = round( ( $src_w - $src_wt ) / 2 );
286
  $src_y = round( ( $src_h - $src_ht ) / 2 );
287
  } else if ($crop == 'top') {
288
-
289
- error_log('found it on top');
290
  $src_y = 0;
291
  } else if ($crop == 'bottom') {
292
  $src_y = $src_h - $src_ht;
@@ -311,7 +396,7 @@
311
  error_log(print_r($result, true));
312
  }
313
  if ($abs){
314
- return untrailingslashit(content_url()).$new_path;
315
  }
316
  return $new_path;
317
  } else if (isset($image->error_data['error_loading_image'])) {
@@ -322,3 +407,5 @@
322
  return $src;
323
  }
324
  }
 
 
2
 
3
  class TimberImageHelper {
4
 
5
+ public static function add_actions(){
6
+ add_action('delete_post', function($post_id){
7
+ $post = get_post($post_id);
8
+ $image_types = array('image/jpeg', 'image/png', 'image/gif', 'image/jpg');
9
+ if ($post->post_type == 'attachment' && in_array($post->post_mime_type, $image_types)){
10
+ self::delete_resized_files_from_url($post->guid);
11
+ self::delete_letterboxed_files_from_url($post->guid);
12
+ }
13
+ });
14
+ }
15
+
16
  /**
17
  * @param string $hexstr
18
  * @return array
28
  return array("red" => 0xFF & ($int >> 0x10), "green" => 0xFF & ($int >> 0x8), "blue" => 0xFF & $int);
29
  }
30
 
31
+ private static function delete_resized_files_from_url($src){
32
+ $local = TimberURLHelper::url_to_file_system($src);
33
+ self::delete_resized_files($local);
34
+ }
35
+
36
+ private static function delete_letterboxed_files_from_url($src){
37
+ $local = TimberURLHelper::url_to_file_system($src);
38
+ self::delete_letterboxed_files($local);
39
+ }
40
+
41
+ static function delete_resized_files($local_file){
42
+ $info = pathinfo($local_file);
43
+ $dir = $info['dirname'];
44
+ $ext = $info['extension'];
45
+ $filename = $info['filename'];
46
+ $searcher = '/'.$filename.'-[0-9999999]*';
47
+ foreach (glob($dir.$searcher) as $found_file){
48
+ $regexdir = str_replace('/', '\/', $dir);
49
+ $pattern = '/'.($regexdir).'\/'.$filename.'-[0-9]*x[0-9]*-c-[a-z]*.'.$ext.'/';
50
+ $match = preg_match($pattern, $found_file);
51
+ //$match = preg_match("/\/srv\/www\/wordpress-develop\/src\/wp-content\/uploads\/2014\/05\/$filename-[0-9]*x[0-9]*-c-[a-z]*.jpg/", $found_file);
52
+ //$match = preg_match("/\/srv\/www\/wordpress-develop\/src\/wp-content\/uploads\/2014\/05\/arch-[0-9]*x[0-9]*-c-[a-z]*.jpg/", $filename);
53
+ if ($match){
54
+ unlink($found_file);
55
+ }
56
+ }
57
+ }
58
+
59
+ static function delete_letterboxed_files($local_file){
60
+ $info = pathinfo($local_file);
61
+ $dir = $info['dirname'];
62
+ $ext = $info['extension'];
63
+ $filename = $info['filename'];
64
+ $searcher = '/'.$filename.'-lbox-[0-9999999]*';
65
+ foreach (glob($dir.$searcher) as $found_file){
66
+ $regexdir = str_replace('/', '\/', $dir);
67
+ $pattern = '/'.($regexdir).'\/'.$filename.'-lbox-[0-9]*x[0-9]*-[a-zA-Z0-9]*.'.$ext.'/';
68
+ $match = preg_match($pattern, $found_file);
69
+ if ($match){
70
+ unlink($found_file);
71
+ }
72
+ }
73
+ }
74
+
75
  /**
76
  * @param string $src
77
  * @param int $w
87
  $color = str_replace('#', '', $color);
88
  $newbase = $basename . '-lbox-' . $w . 'x' . $h . '-' . $color;
89
  $new_path = $dir . '/' . $newbase . '.' . $ext;
90
+ $new_path = str_replace(home_url(), '', $new_path);
91
  return $new_path;
92
  }
93
 
99
  * @return string
100
  */
101
  public static function get_letterbox_file_path($src, $w, $h, $color) {
102
+ $new_path = self::get_letterbox_file_rel($src, $w, $h, $color);
 
 
 
 
 
 
103
  $new_root_path = ABSPATH . $new_path;
104
  $new_root_path = str_replace('//', '/', $new_root_path);
105
  return $new_root_path;
106
  }
107
 
108
+ /**
109
+ * @param string $src
110
+ * @param int $w
111
+ * @param int $h
112
+ * @param string $crop
113
+ * @return string
114
+ */
115
+ public static function get_resize_file_rel($src, $w, $h, $crop){
116
+ $path_parts = pathinfo($src);
117
+ $basename = $path_parts['filename'];
118
+ $ext = $path_parts['extension'];
119
+ $dir = $path_parts['dirname'];
120
+ $newbase = $basename . '-' . $w . 'x' . $h . '-c-' . ( $crop ? $crop : 'f' ); // Crop will be either user named or f (false)
121
+ $new_path = $dir . '/' . $newbase . '.' . $ext;
122
+ $new_path = str_replace(home_url(), '', $new_path);
123
+ return $new_path;
124
+ }
125
+
126
+ /**
127
+ * @param string $src
128
+ * @param int $w
129
+ * @param int $h
130
+ * @param string $crop
131
+ * @return string
132
+ */
133
+ public static function get_resize_file_path($src, $w, $h, $crop){
134
+ $new_path = self::get_resize_file_rel($src, $w, $h, $crop);
135
+ $new_root_path = ABSPATH . $new_path;
136
+ $new_root_path = TimberURLHelper::remove_double_slashes($new_root_path);
137
+ return $new_root_path;
138
+ }
139
+
140
  /**
141
  * @param int $iid
142
  * @return string
156
  * @return mixed|null|string
157
  */
158
  public static function letterbox($src, $w, $h, $color = '#000000', $force = false) {
159
+ if (strstr($src, 'http') && !strstr($src, home_url())) {
160
+ $src = self::sideload_image($src);
161
+ }
162
+ $abs = false;
163
+ if (strstr($src, 'http')){
164
+ $abs = true;
165
  }
166
+ $new_file_rel = self::get_letterbox_file_rel($src, $w, $h, $color);
167
+ $new_root_path = self::get_letterbox_file_path($src, $w, $h, $color);
168
+ $old_root_path = ABSPATH . str_replace(home_url(), '', $src);
169
+ $old_root_path = str_replace('//', '/', $old_root_path);
170
+ $new_root_path = str_replace('//', '/', $new_root_path);
171
  $urlinfo = parse_url($src);
172
+ if (file_exists($new_root_path) && !$force) {
173
+ if ($abs){
174
+ return untrailingslashit(home_url()).$new_file_rel;
175
+ } else {
176
+ return TimberURLHelper::preslashit($new_file_rel);
177
+ }
178
  }
179
  $bg = imagecreatetruecolor($w, $h);
180
  $c = self::hexrgb($color);
181
  $white = imagecolorallocate($bg, $c['red'], $c['green'], $c['blue']);
182
  imagefill($bg, 0, 0, $white);
183
+ $image = wp_get_image_editor($old_root_path);
184
  if (!is_wp_error($image)) {
185
  $current_size = $image->get_size();
186
  $ow = $current_size['width'];
203
  $owt = $w;
204
  $image->crop(0, 0, $ow, $oh, $owt, $oht);
205
  }
206
+ $image->save($new_root_path);
207
  $func = 'imagecreatefromjpeg';
208
+ $ext = pathinfo($new_root_path, PATHINFO_EXTENSION);
209
  if ($ext == 'gif') {
210
  $func = 'imagecreatefromgif';
211
  } else if ($ext == 'png') {
212
  $func = 'imagecreatefrompng';
213
  }
214
+ $image = $func($new_root_path);
215
  imagecopy($bg, $image, $x, $y, 0, 0, $owt, $oht);
216
+ imagejpeg($bg, $new_root_path);
217
+ return TimberURLHelper::get_rel_path($new_root_path);
218
  } else {
219
  TimberHelper::error_log($image);
220
  }
227
  * @return string
228
  */
229
  public static function img_to_jpg($src, $bghex = '#FFFFFF'){
230
+ $src = str_replace(home_url(), '', $src);
231
  $output = str_replace('.png', '.jpg', $src);
232
  $input_file = ABSPATH . $src;
233
  $output_file = ABSPATH . $output;
304
  if (empty($src)){
305
  return '';
306
  }
307
+ if (strstr($src, 'http') && !strstr($src, home_url())) {
308
  $src = self::sideload_image($src);
309
  }
310
  $abs = false;
317
  $crop = $allowed_crop_positions[ 0 ];
318
  }
319
  //oh good, it's a relative image in the uploads folder!
320
+ $new_path = self::get_resize_file_rel($src, $w, $h, $crop);
321
+ $new_root_path = self::get_resize_file_path($src, $w, $h, $crop);
322
+ if ($abs){
323
+ $old_root_path = ABSPATH . str_replace(home_url(), '', $src);
324
+ } else {
325
+ $old_root_path = ABSPATH . $src;
326
+ }
327
+ $old_root_path = TimberURLHelper::remove_double_slashes($old_root_path);
328
+ $new_root_path = TimberURLHelper::remove_double_slashes($new_root_path);
 
 
329
  if ( file_exists($new_root_path) ) {
330
  if ( $force_resize ) {
331
  // Force resize - warning: will regenerate the image on every pageload, use for testing purposes only!
332
  unlink( $new_root_path );
333
  } else {
334
  if ($abs){
335
+ return untrailingslashit(home_url()).$new_path;
336
  } else {
337
+ $returning = TimberURLHelper::preslashit($new_path);
338
+ return $returning;
339
  }
340
  return $new_path;
341
  }
342
  }
 
343
  $image = wp_get_image_editor($old_root_path);
344
 
345
  if (!is_wp_error($image)) {
372
  $src_x = round( ( $src_w - $src_wt ) / 2 );
373
  $src_y = round( ( $src_h - $src_ht ) / 2 );
374
  } else if ($crop == 'top') {
 
 
375
  $src_y = 0;
376
  } else if ($crop == 'bottom') {
377
  $src_y = $src_h - $src_ht;
396
  error_log(print_r($result, true));
397
  }
398
  if ($abs){
399
+ return untrailingslashit(home_url()).$new_path;
400
  }
401
  return $new_path;
402
  } else if (isset($image->error_data['error_loading_image'])) {
407
  return $src;
408
  }
409
  }
410
+
411
+ TimberImageHelper::add_actions();
functions/timber-image.php CHANGED
@@ -104,7 +104,8 @@ class TimberImage extends TimberCore {
104
  $dir = self::wp_upload_dir();
105
  $base = ($dir["baseurl"]);
106
 
107
- return trailingslashit( $this->_maybe_secure_url( $base ) ) . $this->file;
 
108
  }
109
 
110
  private static function _maybe_secure_url( $url ) {
104
  $dir = self::wp_upload_dir();
105
  $base = ($dir["baseurl"]);
106
 
107
+ $src = trailingslashit( $this->_maybe_secure_url( $base ) ) . $this->file;
108
+ return apply_filters('timber_image_src', $src);
109
  }
110
 
111
  private static function _maybe_secure_url( $url ) {
functions/timber-loader.php CHANGED
@@ -116,18 +116,31 @@ class TimberLoader {
116
  $parent_loc = str_replace('/', '\\', $parent_loc);
117
  }
118
  $theme_locs[] = $child_loc;
119
- $theme_locs[] = trailingslashit($child_loc) . trailingslashit(Timber::$dirname);
 
 
120
  if ($child_loc != $parent_loc) {
121
  $theme_locs[] = $parent_loc;
122
- $theme_locs[] = trailingslashit($parent_loc) . trailingslashit(Timber::$dirname);
 
 
123
  }
124
  //now make sure theres a trailing slash on everything
125
- foreach ($theme_locs as &$tl) {
126
- $tl = trailingslashit($tl);
127
- }
128
  return $theme_locs;
129
  }
130
 
 
 
 
 
 
 
 
 
 
 
 
131
  /**
132
  * @return array
133
  */
@@ -158,10 +171,12 @@ class TimberLoader {
158
  if (is_dir($caller)) {
159
  $locs[] = $caller;
160
  }
161
- $caller_sub = $caller . trailingslashit(Timber::$dirname);
162
- if (is_dir($caller_sub)) {
163
- $locs[] = $caller_sub;
164
- }
 
 
165
  }
166
  return $locs;
167
  }
@@ -179,6 +194,7 @@ class TimberLoader {
179
  $locs = array_diff($locs, $this->get_locations_theme());
180
  $locs = array_merge($locs, $this->get_locations_theme());
181
  $locs = array_merge($locs, $this->get_locations_caller($caller));
 
182
  $locs = array_unique($locs);
183
  $locs = apply_filters('timber_locations', $locs);
184
  return $locs;
@@ -206,20 +222,27 @@ class TimberLoader {
206
  * @return Twig_Environment
207
  */
208
  function get_twig() {
209
- $loader_loc = trailingslashit(TIMBER_LOC) . 'Twig/lib/Twig/Autoloader.php';
210
- require_once($loader_loc);
211
- Twig_Autoloader::register();
 
 
212
 
213
  $loader = $this->get_loader();
214
  $params = array('debug' => WP_DEBUG, 'autoescape' => false);
215
  if (isset(Timber::$autoescape)){
216
  $params['autoescape'] = Timber::$autoescape;
217
  }
218
- if (Timber::$cache) {
 
 
 
219
  $params['cache'] = TIMBER_LOC . '/twig-cache';
220
  }
221
  $twig = new Twig_Environment($loader, $params);
222
- $twig->addExtension(new Twig_Extension_Debug());
 
 
223
  $twig->addExtension($this->_get_cache_extension());
224
 
225
  $twig = apply_filters('twig_apply_filters', $twig);
116
  $parent_loc = str_replace('/', '\\', $parent_loc);
117
  }
118
  $theme_locs[] = $child_loc;
119
+ foreach($this->get_locations_theme_dir() as $dirname){
120
+ $theme_locs[] = trailingslashit($child_loc) . trailingslashit($dirname);
121
+ }
122
  if ($child_loc != $parent_loc) {
123
  $theme_locs[] = $parent_loc;
124
+ foreach($this->get_locations_theme_dir() as $dirname){
125
+ $theme_locs[] = trailingslashit($parent_loc) . trailingslashit($dirname);
126
+ }
127
  }
128
  //now make sure theres a trailing slash on everything
129
+ $theme_locs = array_map('trailingslashit', $theme_locs);
 
 
130
  return $theme_locs;
131
  }
132
 
133
+ /**
134
+ * returns an array of the directory inside themes that holds twig files
135
+ * @return array the names of directores, ie: array('templats', 'views');
136
+ */
137
+ private function get_locations_theme_dir(){
138
+ if (is_string(Timber::$dirname)){
139
+ return array(Timber::$dirname);
140
+ }
141
+ return Timber::$dirname;
142
+ }
143
+
144
  /**
145
  * @return array
146
  */
171
  if (is_dir($caller)) {
172
  $locs[] = $caller;
173
  }
174
+ foreach($this->get_locations_theme_dir() as $dirname){
175
+ $caller_sub = $caller . trailingslashit($dirname);
176
+ if (is_dir($caller_sub)) {
177
+ $locs[] = $caller_sub;
178
+ }
179
+ }
180
  }
181
  return $locs;
182
  }
194
  $locs = array_diff($locs, $this->get_locations_theme());
195
  $locs = array_merge($locs, $this->get_locations_theme());
196
  $locs = array_merge($locs, $this->get_locations_caller($caller));
197
+ //$locs[] = '/';
198
  $locs = array_unique($locs);
199
  $locs = apply_filters('timber_locations', $locs);
200
  return $locs;
222
  * @return Twig_Environment
223
  */
224
  function get_twig() {
225
+ if (!class_exists('Twig_Autoloader')) {
226
+ $loader_loc = trailingslashit(TIMBER_LOC) . 'Twig/lib/Twig/Autoloader.php';
227
+ require_once($loader_loc);
228
+ Twig_Autoloader::register();
229
+ }
230
 
231
  $loader = $this->get_loader();
232
  $params = array('debug' => WP_DEBUG, 'autoescape' => false);
233
  if (isset(Timber::$autoescape)){
234
  $params['autoescape'] = Timber::$autoescape;
235
  }
236
+ if (Timber::$cache == true){
237
+ Timber::$twig_cache = true;
238
+ }
239
+ if (Timber::$twig_cache) {
240
  $params['cache'] = TIMBER_LOC . '/twig-cache';
241
  }
242
  $twig = new Twig_Environment($loader, $params);
243
+ if (WP_DEBUG){
244
+ $twig->addExtension(new Twig_Extension_Debug());
245
+ }
246
  $twig->addExtension($this->_get_cache_extension());
247
 
248
  $twig = apply_filters('twig_apply_filters', $twig);
functions/timber-post.php CHANGED
@@ -46,7 +46,8 @@ class TimberPost extends TimberCore {
46
  $post_info = $this->get_info($pid);
47
  $this->import($post_info);
48
  //cant have a function, so gots to do it this way
49
- $this->class = $this->post_class();
 
50
  }
51
 
52
  /**
@@ -68,7 +69,7 @@ class TimberPost extends TimberCore {
68
  * @param string $field
69
  * @param mixed $value
70
  */
71
- function update($field, $value) {
72
  if (isset($this->ID)) {
73
  update_post_meta($this->ID, $field, $value);
74
  $this->$field = $value;
@@ -675,6 +676,9 @@ class TimberPost extends TimberCore {
675
  if (is_array($value) && count($value) == 1){
676
  $value = $value[0];
677
  }
 
 
 
678
  }
679
  $value = apply_filters('timber_post_get_meta_field', $value, $this->ID, $field_name, $this);
680
  return $value;
@@ -798,7 +802,10 @@ class TimberPost extends TimberCore {
798
  * @param string $field_name
799
  * @return mixed
800
  */
801
- public function meta($field_name){
 
 
 
802
  return $this->get_field($field_name);
803
  }
804
 
@@ -880,8 +887,11 @@ class TimberPost extends TimberCore {
880
  * @return string
881
  */
882
  public function post_class($class='') {
883
- $pid = $this->ID;
884
- $class_array = get_post_class($class, $pid);
 
 
 
885
  return implode(' ', $class_array);
886
  }
887
 
46
  $post_info = $this->get_info($pid);
47
  $this->import($post_info);
48
  //cant have a function, so gots to do it this way
49
+ $post_class = $this->post_class();
50
+ $this->class = $post_class;
51
  }
52
 
53
  /**
69
  * @param string $field
70
  * @param mixed $value
71
  */
72
+ public function update($field, $value) {
73
  if (isset($this->ID)) {
74
  update_post_meta($this->ID, $field, $value);
75
  $this->$field = $value;
676
  if (is_array($value) && count($value) == 1){
677
  $value = $value[0];
678
  }
679
+ if (is_array($value) && count($value) == 0){
680
+ $value = null;
681
+ }
682
  }
683
  $value = apply_filters('timber_post_get_meta_field', $value, $this->ID, $field_name, $this);
684
  return $value;
802
  * @param string $field_name
803
  * @return mixed
804
  */
805
+ public function meta($field_name = null){
806
+ if ($field_name == null){
807
+ $field_name = 'meta';
808
+ }
809
  return $this->get_field($field_name);
810
  }
811
 
887
  * @return string
888
  */
889
  public function post_class($class='') {
890
+ global $post;
891
+ $old_global_post = $post;
892
+ $post = $this;
893
+ $class_array = get_post_class($class, $this->ID);
894
+ $post = $old_global_post;
895
  return implode(' ', $class_array);
896
  }
897
 
functions/timber-site.php CHANGED
@@ -30,6 +30,7 @@ class TimberSite extends TimberCore {
30
  $this->name = $this->blogname;
31
  $this->title = $this->blogname;
32
  $this->url = $this->siteurl;
 
33
  $theme_slug = get_blog_option($info->blog_id, 'stylesheet');
34
  $this->theme = new TimberTheme($theme_slug);
35
  $this->description = get_blog_option($info->blog_id, 'blogdescription');
@@ -84,4 +85,4 @@ class TimberSite extends TimberCore {
84
  function url(){
85
  return $this->get_link();
86
  }
87
- }
30
  $this->name = $this->blogname;
31
  $this->title = $this->blogname;
32
  $this->url = $this->siteurl;
33
+ $this->id = $this->ID;
34
  $theme_slug = get_blog_option($info->blog_id, 'stylesheet');
35
  $this->theme = new TimberTheme($theme_slug);
36
  $this->description = get_blog_option($info->blog_id, 'blogdescription');
85
  function url(){
86
  return $this->get_link();
87
  }
88
+ }
functions/timber-url-helper.php CHANGED
@@ -62,6 +62,7 @@
62
  if (isset($url_info['query']) && strlen($url_info['query'])){
63
  $link .= '?'.$url_info['query'];
64
  }
 
65
  return $link;
66
  }
67
 
@@ -87,6 +88,13 @@
87
  return $old_root_path;
88
  }
89
 
 
 
 
 
 
 
 
90
  /**
91
  * @param string $src
92
  * @return string
62
  if (isset($url_info['query']) && strlen($url_info['query'])){
63
  $link .= '?'.$url_info['query'];
64
  }
65
+ $link = TimberURLHelper::remove_double_slashes($link);
66
  return $link;
67
  }
68
 
88
  return $old_root_path;
89
  }
90
 
91
+ public static function url_to_file_system($url){
92
+ $url_parts = parse_url($url);
93
+ $path = ABSPATH . $url_parts['path'];
94
+ $path = str_replace('//', '/', $path);
95
+ return $path;
96
+ }
97
+
98
  /**
99
  * @param string $src
100
  * @return string
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Contributors: jarednova
3
  Tags: template engine, templates, twig
4
  Requires at least: 3.7
5
- Stable tag: 0.18.0
6
  Tested up to: 3.9
7
  PHP version: 5.3.0 or greater
8
  License: GPLv2 or later
@@ -41,6 +41,15 @@ Timber is great for any WordPress developer who cares about writing good, mainta
41
 
42
  == Changelog ==
43
 
 
 
 
 
 
 
 
 
 
44
  = 0.18.0 =
45
  * BREAKING CHANGE ALERT wp_title no longer appends bloginfo('name') to end of string (thanks @aduth)
46
  * BREAKING CHANGE ALERT get_preview now respects <!-- more --> tag (thanks @jnweaver)
2
  Contributors: jarednova
3
  Tags: template engine, templates, twig
4
  Requires at least: 3.7
5
+ Stable tag: 0.18.1
6
  Tested up to: 3.9
7
  PHP version: 5.3.0 or greater
8
  License: GPLv2 or later
41
 
42
  == Changelog ==
43
 
44
+ = 0.18.1 =
45
+ * Dates now use date_i18n filter (thanks @jamesagreenleaf)
46
+ * The twig |date filter now defaults to your WP Admin settings (thanks @jamesagreenleaf)
47
+ * You can send Timber::$dirname an array to specify multiple locations of twig files within a theme
48
+ * Load views from anywhere on the server (thanks @th3fallen)
49
+ * Load twig files from anywhere on the server using an absolute path
50
+ * Use another version of Twig if you have it loaded (thanks @ButlerPCnet)
51
+ * more tests!
52
+
53
  = 0.18.0 =
54
  * BREAKING CHANGE ALERT wp_title no longer appends bloginfo('name') to end of string (thanks @aduth)
55
  * BREAKING CHANGE ALERT get_preview now respects <!-- more --> tag (thanks @jnweaver)
timber-starter-theme/single.php CHANGED
@@ -15,4 +15,10 @@ $context['post'] = $post;
15
  $context['wp_title'] .= ' - ' . $post->title();
16
  $context['comment_form'] = TimberHelper::get_comment_form();
17
 
18
- Timber::render(array('single-' . $post->ID . '.twig', 'single-' . $post->post_type . '.twig', 'single.twig'), $context);
 
 
 
 
 
 
15
  $context['wp_title'] .= ' - ' . $post->title();
16
  $context['comment_form'] = TimberHelper::get_comment_form();
17
 
18
+ if (post_password_required($post->ID)){
19
+ Timber::render('single-password.twig', $context);
20
+ } else {
21
+ Timber::render(array('single-' . $post->ID . '.twig', 'single-' . $post->post_type . '.twig', 'single.twig'), $context);
22
+ }
23
+
24
+
timber-starter-theme/views/base.twig CHANGED
@@ -1,14 +1,16 @@
1
- {% include 'html-header.twig' %}
2
- {% block head %}
 
 
 
3
  {% endblock %}
4
- </head>
5
- <body class="{{body_class}}" data-source="base.twig">
6
  <header class="header" >
7
  {% block header %}
8
  <div class="wrapper">
9
 
10
  <h1 class="hdr-logo" role="banner">
11
- <a class="hdr-logo-link" href="/" title="Timber" rel="home">{{bloginfo('name')}}</a>
12
  </h1>
13
  <nav id="access" class="main-navigation" role="navigation">
14
  <ul>
@@ -39,9 +41,11 @@
39
  {% endif %}
40
  </section>
41
 
42
- <footer id="footer">
43
- {% include 'footer.twig' %}
44
- </footer>
45
- {{ function('wp_footer') }}
 
 
46
  </body>
47
- </html>
1
+ {% block html_head_container %}
2
+ {% include 'html-header.twig' %}
3
+ {% block head %}
4
+ {% endblock %}
5
+ </head>
6
  {% endblock %}
7
+ <body class="{{body_class}}" data-template="base.twig">
 
8
  <header class="header" >
9
  {% block header %}
10
  <div class="wrapper">
11
 
12
  <h1 class="hdr-logo" role="banner">
13
+ <a class="hdr-logo-link" href="/" title="Timber" rel="home">{{site.name}}</a>
14
  </h1>
15
  <nav id="access" class="main-navigation" role="navigation">
16
  <ul>
41
  {% endif %}
42
  </section>
43
 
44
+ {% block footer %}
45
+ <footer id="footer">
46
+ {% include 'footer.twig' %}
47
+ </footer>
48
+ {{ function('wp_footer') }}
49
+ {% endblock %}
50
  </body>
51
+ </html>
timber-starter-theme/views/single-password.twig ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ {% extends "base.twig" %}
2
+ {% block content %}
3
+ <form class="password-form" action="/wp-login.php?action=postpass" method="post">
4
+ <label for="pwbox-{{post.ID}}">Password:</label>
5
+ <input class="password-box" name="post_password" id="pwbox-{{post.ID}}" type="password" placeholder="Password" size="20" maxlength="20" />
6
+ <input class="password-btn" type="submit" name="Submit" value="Submit" />
7
+ </form>
8
+ {% endblock %}
timber-starter-theme/views/single.twig CHANGED
@@ -8,7 +8,7 @@
8
  <h1 class="article-h1">{{post.title}}</h1>
9
 
10
  <p class="blog-author">
11
- <span>By</span><a href="{{post.author.path}}"> {{ post.author.name }} </a><span>&bull;</span> {{ post.display_date }}
12
  </p>
13
 
14
  <div class="article-body">
@@ -33,4 +33,4 @@
33
  </article>
34
  </div> <!-- /content-wrapper -->
35
 
36
- {% endblock %}
8
  <h1 class="article-h1">{{post.title}}</h1>
9
 
10
  <p class="blog-author">
11
+ <span>By</span><a href="{{post.author.path}}"> {{ post.author.name }} </a><span>&bull;</span> {{ post.post_date|date}}
12
  </p>
13
 
14
  <div class="article-body">
33
  </article>
34
  </div> <!-- /content-wrapper -->
35
 
36
+ {% endblock %}
timber.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: Timber
4
  Plugin URI: http://timber.upstatement.com
5
  Description: The WordPress Timber Library allows you to write themes using the power Twig templates
6
  Author: Jared Novack + Upstatement
7
- Version: 0.18.0
8
  Author URI: http://upstatement.com/
9
  */
10
 
@@ -57,7 +57,8 @@ require_once(__DIR__ . '/functions/timber-admin.php');
57
  class Timber {
58
 
59
  public static $locations;
60
- public static $dirname = 'views';
 
61
  public static $cache = false;
62
  public static $auto_meta = true;
63
  public static $autoescape = false;
@@ -80,17 +81,6 @@ class Timber {
80
  }
81
 
82
  protected function init_constants() {
83
- $timber_loc = str_replace(realpath(ABSPATH), '', realpath(__DIR__));
84
- $plugin_url_path = str_replace($_SERVER['HTTP_HOST'], '', plugins_url());
85
- $plugin_url_path = str_replace('https://', '', $plugin_url_path);
86
- $plugin_url_path = str_replace('http://', '', $plugin_url_path);
87
- $timber_dirs = dirname(__FILE__);
88
- $timber_dirs = str_replace('\\', '/', $timber_dirs);
89
- $timber_dirs = explode('/', $timber_dirs);
90
- $timber_dirname = array_pop($timber_dirs);
91
- define("TIMBER", $timber_loc);
92
- define("TIMBER_URL_PATH", trailingslashit($plugin_url_path) . trailingslashit($timber_dirname));
93
- define("TIMBER_URL", 'http://' . $_SERVER["HTTP_HOST"] . TIMBER);
94
  define("TIMBER_LOC", realpath(__DIR__));
95
  }
96
 
@@ -485,9 +475,24 @@ class Timber {
485
  }
486
  $output = $loader->render($file, $data, $expires, $cache_mode);
487
  }
 
488
  return $output;
489
  }
490
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
  /**
492
  * @param array $filenames
493
  * @param array $data
@@ -508,6 +513,17 @@ class Timber {
508
  return $output;
509
  }
510
 
 
 
 
 
 
 
 
 
 
 
 
511
 
512
  /* Sidebar
513
  ================================ */
@@ -610,11 +626,13 @@ class Timber {
610
  }
611
 
612
  public static function cancel_query(){
613
- add_action('posts_request', function(){
614
- if (is_main_query()){
615
- wp_reset_query();
616
- }
617
- });
 
 
618
  }
619
 
620
  /**
@@ -624,7 +642,11 @@ class Timber {
624
  * @param bool $tparams
625
  */
626
  public static function load_template($template, $query = false, $force_header = 0, $tparams = false) {
627
- $template = locate_template($template);
 
 
 
 
628
  if ($tparams){
629
  global $params;
630
  $params = $tparams;
@@ -651,7 +673,6 @@ class Timber {
651
  if ($query) {
652
  add_action('do_parse_request', function() use ($query) {
653
  global $wp;
654
-
655
  if ( is_callable($query) )
656
  $query = call_user_func($query);
657
 
@@ -672,7 +693,9 @@ class Timber {
672
  load_template($template);
673
  die;
674
  });
 
675
  }
 
676
  }
677
 
678
  /* Pagination
@@ -685,8 +708,9 @@ class Timber {
685
  public static function get_pagination($prefs = array()){
686
  global $wp_query;
687
  global $paged;
 
688
  $args['total'] = ceil($wp_query->found_posts / $wp_query->query_vars['posts_per_page']);
689
- if (strlen(trim(get_option('permalink_structure')))){
690
  $url = explode('?', get_pagenum_link(0));
691
  if (isset($url[1])){
692
  parse_str($url[1], $query);
@@ -699,7 +723,6 @@ class Timber {
699
  $args['base'] = str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) );
700
  }
701
  $args['type'] = 'array';
702
-
703
  $args['current'] = max( 1, get_query_var('paged') );
704
  $args['mid_size'] = max(9 - $args['current'], 3);
705
  $args['prev_next'] = false;
@@ -709,13 +732,13 @@ class Timber {
709
  $args = array_merge($args, $prefs);
710
  }
711
  $data['pages'] = TimberHelper::paginate_links($args);
712
- $next = next_posts($args['total'], false);
713
  if ($next){
714
- $data['next'] = array('link' => $next, 'class' => 'page-numbers next');
715
  }
716
  $prev = previous_posts(false);
717
  if ($prev){
718
- $data['prev'] = array('link' => $prev, 'class' => 'page-numbers prev');
719
  }
720
  if ($paged < 2){
721
  $data['prev'] = '';
@@ -783,3 +806,4 @@ class Timber {
783
 
784
  $timber = new Timber();
785
  $GLOBALS['timber'] = $timber;
 
4
  Plugin URI: http://timber.upstatement.com
5
  Description: The WordPress Timber Library allows you to write themes using the power Twig templates
6
  Author: Jared Novack + Upstatement
7
+ Version: 0.18.1
8
  Author URI: http://upstatement.com/
9
  */
10
 
57
  class Timber {
58
 
59
  public static $locations;
60
+ public static $dirname;
61
+ public static $twig_cache = false;
62
  public static $cache = false;
63
  public static $auto_meta = true;
64
  public static $autoescape = false;
81
  }
82
 
83
  protected function init_constants() {
 
 
 
 
 
 
 
 
 
 
 
84
  define("TIMBER_LOC", realpath(__DIR__));
85
  }
86
 
475
  }
476
  $output = $loader->render($file, $data, $expires, $cache_mode);
477
  }
478
+ do_action('timber_compile_done');
479
  return $output;
480
  }
481
 
482
+ /**
483
+ * @param array $string a string with twig variables
484
+ * @param array $data an array with data in it
485
+ * @return bool|string
486
+ */
487
+ public static function compile_string($string, $data = array()){
488
+ $dummy_loader = new TimberLoader();
489
+ $dummy_loader->get_twig();
490
+ $loader = new Twig_Loader_String();
491
+ $twig = new Twig_Environment($loader);
492
+ $twig = apply_filters('twig_apply_filters', $twig);
493
+ return $twig->render($string, $data);
494
+ }
495
+
496
  /**
497
  * @param array $filenames
498
  * @param array $data
513
  return $output;
514
  }
515
 
516
+ /**
517
+ * @param array $string a string with twig variables
518
+ * @param array $data an array with data in it
519
+ * @return bool|string
520
+ */
521
+ public static function render_string($string, $data = array()){
522
+ $compiled = self::compile_string($string, $data);
523
+ echo $compiled;
524
+ return $compiled;
525
+ }
526
+
527
 
528
  /* Sidebar
529
  ================================ */
626
  }
627
 
628
  public static function cancel_query(){
629
+ add_action('posts_request', array($this, 'cancel_query_posts_request'));
630
+ }
631
+
632
+ function cancel_query_posts_request(){
633
+ if (is_main_query()){
634
+ wp_reset_query();
635
+ }
636
  }
637
 
638
  /**
642
  * @param bool $tparams
643
  */
644
  public static function load_template($template, $query = false, $force_header = 0, $tparams = false) {
645
+
646
+ $fullPath = is_readable($template);
647
+ if (!$fullPath) {
648
+ $template = locate_template($template);
649
+ }
650
  if ($tparams){
651
  global $params;
652
  $params = $tparams;
673
  if ($query) {
674
  add_action('do_parse_request', function() use ($query) {
675
  global $wp;
 
676
  if ( is_callable($query) )
677
  $query = call_user_func($query);
678
 
693
  load_template($template);
694
  die;
695
  });
696
+ return true;
697
  }
698
+ return false;
699
  }
700
 
701
  /* Pagination
708
  public static function get_pagination($prefs = array()){
709
  global $wp_query;
710
  global $paged;
711
+ global $wp_rewrite;
712
  $args['total'] = ceil($wp_query->found_posts / $wp_query->query_vars['posts_per_page']);
713
+ if ($wp_rewrite->using_permalinks()){
714
  $url = explode('?', get_pagenum_link(0));
715
  if (isset($url[1])){
716
  parse_str($url[1], $query);
723
  $args['base'] = str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) );
724
  }
725
  $args['type'] = 'array';
 
726
  $args['current'] = max( 1, get_query_var('paged') );
727
  $args['mid_size'] = max(9 - $args['current'], 3);
728
  $args['prev_next'] = false;
732
  $args = array_merge($args, $prefs);
733
  }
734
  $data['pages'] = TimberHelper::paginate_links($args);
735
+ $next = get_next_posts_page_link($args['total']);
736
  if ($next){
737
+ $data['next'] = array('link' => untrailingslashit($next), 'class' => 'page-numbers next');
738
  }
739
  $prev = previous_posts(false);
740
  if ($prev){
741
+ $data['prev'] = array('link' => untrailingslashit($prev), 'class' => 'page-numbers prev');
742
  }
743
  if ($paged < 2){
744
  $data['prev'] = '';
806
 
807
  $timber = new Timber();
808
  $GLOBALS['timber'] = $timber;
809
+ Timber::$dirname = 'views';