Timber - Version 0.22.2

Version Description

  • New .time method for TimberPost and TimberComment (thanks @lggorman)
  • Added support for WordPress's quality filter when resizing (thanks @t-wright)
  • Added support for animated gifs
Download this release

Release Info

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

Code changes from version 0.22.1 to 0.22.2

lib/image/timber-image-operation-letterbox.php CHANGED
@@ -57,6 +57,7 @@ class TimberImageOperationLetterbox extends TimberImageOperation {
57
  $image = wp_get_image_editor( $load_filename );
58
  if ( !is_wp_error( $image ) ) {
59
  $current_size = $image->get_size();
 
60
  $ow = $current_size['width'];
61
  $oh = $current_size['height'];
62
  $new_aspect = $w / $h;
@@ -87,7 +88,7 @@ class TimberImageOperationLetterbox extends TimberImageOperation {
87
  }
88
  $image = $func( $save_filename );
89
  imagecopy( $bg, $image, $x, $y, 0, 0, $owt, $oht );
90
- imagejpeg( $bg, $save_filename );
91
  return true;
92
  } else {
93
  TimberHelper::error_log( $image );
57
  $image = wp_get_image_editor( $load_filename );
58
  if ( !is_wp_error( $image ) ) {
59
  $current_size = $image->get_size();
60
+ $quality = $image->get_quality();
61
  $ow = $current_size['width'];
62
  $oh = $current_size['height'];
63
  $new_aspect = $w / $h;
88
  }
89
  $image = $func( $save_filename );
90
  imagecopy( $bg, $image, $x, $y, 0, 0, $owt, $oht );
91
+ imagejpeg( $bg, $save_filename, $quality );
92
  return true;
93
  } else {
94
  TimberHelper::error_log( $image );
lib/image/timber-image-operation-resize.php CHANGED
@@ -41,6 +41,87 @@ class TimberImageOperationResize extends TimberImageOperation {
41
  return $result;
42
  }
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  /**
45
  * Performs the actual image manipulation,
46
  * including saving the target file.
@@ -52,55 +133,26 @@ class TimberImageOperationResize extends TimberImageOperation {
52
  * @return bool true if everything went fine, false otherwise
53
  */
54
  public function run($load_filename, $save_filename) {
 
 
 
 
 
 
 
 
 
 
55
  $image = wp_get_image_editor( $load_filename );
56
  if ( !is_wp_error( $image ) ) {
57
- $w = $this->w;
58
- $h = $this->h;
59
- $crop = $this->crop;
60
-
61
- $current_size = $image->get_size();
62
- $src_w = $current_size['width'];
63
- $src_h = $current_size['height'];
64
- $src_ratio = $src_w / $src_h;
65
- if ( !$h ) {
66
- $h = round( $w / $src_ratio );
67
- }
68
- if ( !$w ) {
69
- //the user wants to resize based on constant height
70
- $w = round( $h * $src_ratio );
71
- }
72
- // Get ratios
73
- $dest_ratio = $w / $h;
74
- $src_wt = $src_h * $dest_ratio;
75
- $src_ht = $src_w / $dest_ratio;
76
- if ( !$crop ) {
77
- // Always crop, to allow resizing upwards
78
- $image->crop( 0, 0, $src_w, $src_h, $w, $h );
79
- } else {
80
- //start with defaults:
81
- $src_x = $src_w / 2 - $src_wt / 2;
82
- $src_y = ( $src_h - $src_ht ) / 6;
83
- //now specific overrides based on options:
84
- if ( $crop == 'center' ) {
85
- // Get source x and y
86
- $src_x = round( ( $src_w - $src_wt ) / 2 );
87
- $src_y = round( ( $src_h - $src_ht ) / 2 );
88
- } else if ( $crop == 'top' ) {
89
- $src_y = 0;
90
- } else if ( $crop == 'bottom' ) {
91
- $src_y = $src_h - $src_ht;
92
- } else if ( $crop == 'left' ) {
93
- $src_x = 0;
94
- } else if ( $crop == 'right' ) {
95
- $src_x = $src_w - $src_wt;
96
- }
97
- // Crop the image
98
- if ( $dest_ratio > $src_ratio ) {
99
- $image->crop( 0, $src_y, $src_w, $src_ht, $w, $h );
100
- } else {
101
- $image->crop( $src_x, 0, $src_wt, $src_h, $w, $h );
102
- }
103
- }
104
  $result = $image->save( $save_filename );
105
  if ( is_wp_error( $result ) ) {
106
  error_log( 'Error resizing image' );
41
  return $result;
42
  }
43
 
44
+ protected function run_animated_gif( $load_filename, $save_filename ) {
45
+ $image = wp_get_image_editor( $load_filename );
46
+ $current_size = $image->get_size();
47
+ $src_w = $current_size['width'];
48
+ $src_h = $current_size['height'];
49
+ $w = $this->w;
50
+ $h = $this->h;
51
+ if ( !class_exists('Imagick') ) {
52
+ return false;
53
+ }
54
+ $image = new Imagick($load_filename);
55
+ $image = $image->coalesceImages();
56
+ $crop = self::get_target_sizes( $load_filename );
57
+ foreach ($image as $frame) {
58
+ $frame->cropImage($crop['src_w'], $crop['src_h'], $crop['x'], $crop['y']);
59
+ $frame->thumbnailImage($w, $h);
60
+ $frame->setImagePage($w, $h, 0, 0);
61
+ }
62
+ $image = $image->deconstructImages();
63
+ return $image->writeImages($save_filename, true);
64
+ }
65
+
66
+ protected function get_target_sizes( $load_filename ) {
67
+ $image = wp_get_image_editor( $load_filename );
68
+ $w = $this->w;
69
+ $h = $this->h;
70
+ $crop = $this->crop;
71
+
72
+ $current_size = $image->get_size();
73
+ $src_w = $current_size['width'];
74
+ $src_h = $current_size['height'];
75
+ $src_ratio = $src_w / $src_h;
76
+ if ( !$h ) {
77
+ $h = round( $w / $src_ratio );
78
+ }
79
+ if ( !$w ) {
80
+ //the user wants to resize based on constant height
81
+ $w = round( $h * $src_ratio );
82
+ }
83
+ if ( !$crop ) {
84
+ return array(
85
+ 'x' => 0, 'y' => 0,
86
+ 'src_w' => $src_w, 'src_h' => $src_h,
87
+ 'target_w' => $w, 'target_h' => $h
88
+ );
89
+ }
90
+ // Get ratios
91
+ $dest_ratio = $w / $h;
92
+ $src_wt = $src_h * $dest_ratio;
93
+ $src_ht = $src_w / $dest_ratio;
94
+ $src_x = $src_w / 2 - $src_wt / 2;
95
+ $src_y = ( $src_h - $src_ht ) / 6;
96
+ //now specific overrides based on options:
97
+ if ( $crop == 'center' ) {
98
+ // Get source x and y
99
+ $src_x = round( ( $src_w - $src_wt ) / 2 );
100
+ $src_y = round( ( $src_h - $src_ht ) / 2 );
101
+ } else if ( $crop == 'top' ) {
102
+ $src_y = 0;
103
+ } else if ( $crop == 'bottom' ) {
104
+ $src_y = $src_h - $src_ht;
105
+ } else if ( $crop == 'left' ) {
106
+ $src_x = 0;
107
+ } else if ( $crop == 'right' ) {
108
+ $src_x = $src_w - $src_wt;
109
+ }
110
+ // Crop the image
111
+ if ( $dest_ratio > $src_ratio ) {
112
+ return array(
113
+ 'x' => 0, 'y' => $src_y,
114
+ 'src_w' => $src_w, 'src_h' => $src_ht,
115
+ 'target_w' => $w, 'target_h' => $h
116
+ );
117
+ }
118
+ return array(
119
+ 'x' => $src_x, 'y' => 0,
120
+ 'src_w' => $src_wt, 'src_h' => $src_h,
121
+ 'target_w' => $w, 'target_h' => $h
122
+ );
123
+ }
124
+
125
  /**
126
  * Performs the actual image manipulation,
127
  * including saving the target file.
133
  * @return bool true if everything went fine, false otherwise
134
  */
135
  public function run($load_filename, $save_filename) {
136
+ //should be resized by gif resizer
137
+ if ( TimberImageHelper::is_animated_gif($load_filename) ) {
138
+ //attempt to resize
139
+ //return if successful
140
+ //proceed if not
141
+ $gif = self::run_animated_gif($load_filename, $save_filename);
142
+ if ($gif) {
143
+ return true;
144
+ }
145
+ }
146
  $image = wp_get_image_editor( $load_filename );
147
  if ( !is_wp_error( $image ) ) {
148
+ $crop = self::get_target_sizes( $load_filename );
149
+ $image->crop( $crop['x'],
150
+ $crop['y'],
151
+ $crop['src_w'],
152
+ $crop['src_h'],
153
+ $crop['target_w'],
154
+ $crop['target_h']
155
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  $result = $image->save( $save_filename );
157
  if ( is_wp_error( $result ) ) {
158
  error_log( 'Error resizing image' );
lib/timber-archives.php CHANGED
@@ -9,7 +9,7 @@
9
  * <ul>
10
  * {% for item in archives.items %}
11
  * <li><a href="{{item.link}}">{{item.name}}</a></li>
12
- * {% for child item.children %}
13
  * <li class="child"><a href="{{child.link}}">{{child.name}}</a></li>
14
  * {% endfor %}
15
  * {% endfor %}
9
  * <ul>
10
  * {% for item in archives.items %}
11
  * <li><a href="{{item.link}}">{{item.name}}</a></li>
12
+ * {% for child in item.children %}
13
  * <li class="child"><a href="{{child.link}}">{{child.name}}</a></li>
14
  * {% endfor %}
15
  * {% endfor %}
lib/timber-comment.php CHANGED
@@ -185,6 +185,31 @@ class TimberComment extends TimberCore implements TimberCoreInterface {
185
  return apply_filters('get_comment_date ', $the_date, $df);
186
  }
187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  /**
189
  * @param string $field_name
190
  * @return mixed
185
  return apply_filters('get_comment_date ', $the_date, $df);
186
  }
187
 
188
+ /**
189
+ * @api
190
+ * @example
191
+ * ```twig
192
+ * {% for comment in post.comments %}
193
+ * <article class="comment">
194
+ * <p class="date">Posted on {{ comment.date }} at {{comment.time}}:</p>
195
+ * <p class="comment">{{ comment.content }}</p>
196
+ * </article>
197
+ * {% endfor %}
198
+ * ```
199
+ * ```html
200
+ * <article class="comment">
201
+ * <p class="date">Posted on September 28, 2015 at 12:45 am:</p>
202
+ * <p class="comment">Happy Birthday!</p>
203
+ * </article>
204
+ * ```
205
+ * @return string
206
+ */
207
+ public function time( $time_format = '' ) {
208
+ $tf = $time_format ? $time_format : get_option('time_format');
209
+ $the_time = (string)mysql2date($tf, $this->comment_date);
210
+ return apply_filters('get_comment_time', $the_time, $tf);
211
+ }
212
+
213
  /**
214
  * @param string $field_name
215
  * @return mixed
lib/timber-image-helper.php CHANGED
@@ -95,6 +95,38 @@ class TimberImageHelper {
95
  return self::_operate($src, $op, $force);
96
  }
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  /**
99
  * Generate a new image with the specified dimensions.
100
  * New dimensions are achieved by adding colored bands to maintain ratio.
95
  return self::_operate($src, $op, $force);
96
  }
97
 
98
+ /**
99
+ * checks to see if the given file is an aimated gif
100
+ * @param string $file local filepath to a file, not a URL
101
+ * @return boolean true if it's an animated gif, false if not
102
+ */
103
+ public static function is_animated_gif( $file ) {
104
+ if ( strpos(strtolower($file), '.gif') == -1 ) {
105
+ //doesn't have .gif, bail
106
+ return false;
107
+ }
108
+ //its a gif so test
109
+ if(!($fh = @fopen($file, 'rb'))) {
110
+ return false;
111
+ }
112
+ $count = 0;
113
+ //an animated gif contains multiple "frames", with each frame having a
114
+ //header made up of:
115
+ // * a static 4-byte sequence (\x00\x21\xF9\x04)
116
+ // * 4 variable bytes
117
+ // * a static 2-byte sequence (\x00\x2C)
118
+
119
+ // We read through the file til we reach the end of the file, or we've found
120
+ // at least 2 frame headers
121
+ while(!feof($fh) && $count < 2) {
122
+ $chunk = fread($fh, 1024 * 100); //read 100kb at a time
123
+ $count += preg_match_all('#\x00\x21\xF9\x04.{4}\x00[\x2C\x21]#s', $chunk, $matches);
124
+ }
125
+
126
+ fclose($fh);
127
+ return $count > 1;
128
+ }
129
+
130
  /**
131
  * Generate a new image with the specified dimensions.
132
  * New dimensions are achieved by adding colored bands to maintain ratio.
lib/timber-post.php CHANGED
@@ -394,7 +394,7 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
394
  } elseif ( $readmore ) {
395
  $text .= ' <a href="' . $this->get_permalink() . '" class="read-more">' . trim($readmore) . '</a>';
396
  }
397
- if ( !$strip ) {
398
  $text .= '</p>';
399
  }
400
  }
@@ -1205,6 +1205,30 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
1205
  return $this->get_date($date_format);
1206
  }
1207
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1208
  /**
1209
  * @return bool|string
1210
  */
394
  } elseif ( $readmore ) {
395
  $text .= ' <a href="' . $this->get_permalink() . '" class="read-more">' . trim($readmore) . '</a>';
396
  }
397
+ if ( !$strip && $last_p_tag && ( strpos($text, '<p>') || strpos($text, '<p ') ) ) {
398
  $text .= '</p>';
399
  }
400
  }
1205
  return $this->get_date($date_format);
1206
  }
1207
 
1208
+ /**
1209
+ * Get the time to use in your template
1210
+ * @api
1211
+ * @example
1212
+ * ```twig
1213
+ * Published at {{ post.time }} // Uses WP's formatting set in Admin
1214
+ * OR
1215
+ * Published at {{ post.time | time('G:i') }} // 13:25
1216
+ * ```
1217
+ *
1218
+ * ```html
1219
+ * Published at 1:25 pm
1220
+ * OR
1221
+ * Published at 13:25
1222
+ * ```
1223
+ * @param string $time_format
1224
+ * @return string
1225
+ */
1226
+ public function time( $time_format = '' ) {
1227
+ $tf = $time_format ? $time_format : get_option('time_format');
1228
+ $the_time = (string)mysql2date($tf, $this->post_date);
1229
+ return apply_filters('get_the_time', $the_time, $tf);
1230
+ }
1231
+
1232
  /**
1233
  * @return bool|string
1234
  */
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: jarednova
3
  Tags: template engine, templates, twig
4
  Requires at least: 3.7
5
- Stable tag: 0.22.1
6
- Tested up to: 4.2.3
7
  PHP version: 5.3.0 or greater
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -41,6 +41,11 @@ Timber is great for any WordPress developer who cares about writing good, mainta
41
 
42
  == Changelog ==
43
 
 
 
 
 
 
44
  = 0.22.1 =
45
  * Added better support for [post.get_terms](https://github.com/jarednova/timber/pull/737) (thanks @aaemnnosttv)
46
  * Fix for issue with ACF date field (thanks @rpkoller)
2
  Contributors: jarednova
3
  Tags: template engine, templates, twig
4
  Requires at least: 3.7
5
+ Stable tag: 0.22.2
6
+ Tested up to: 4.3.1
7
  PHP version: 5.3.0 or greater
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
41
 
42
  == Changelog ==
43
 
44
+ = 0.22.2 =
45
+ * New .time method for TimberPost and TimberComment (thanks @lggorman)
46
+ * Added support for WordPress's quality filter when resizing (thanks @t-wright)
47
+ * Added support for animated gifs
48
+
49
  = 0.22.1 =
50
  * Added better support for [post.get_terms](https://github.com/jarednova/timber/pull/737) (thanks @aaemnnosttv)
51
  * Fix for issue with ACF date field (thanks @rpkoller)
timber.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: Timber
4
  Description: The WordPress Timber Library allows you to write themes using the power Twig templates.
5
  Plugin URI: http://timber.upstatement.com
6
  Author: Jared Novack + Upstatement
7
- Version: 0.22.1
8
  Author URI: http://upstatement.com/
9
  */
10
 
4
  Description: The WordPress Timber Library allows you to write themes using the power Twig templates.
5
  Plugin URI: http://timber.upstatement.com
6
  Author: Jared Novack + Upstatement
7
+ Version: 0.22.2
8
  Author URI: http://upstatement.com/
9
  */
10
 
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit0c8bebb789915cc09e196c0fd45125c4::getLoader();
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit6e3042e2ec56b2cc1bf8c8c9efe69b8e::getLoader();
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit0c8bebb789915cc09e196c0fd45125c4
6
  {
7
  private static $loader;
8
 
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit0c8bebb789915cc09e196c0fd45125c4
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit0c8bebb789915cc09e196c0fd45125c4', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit0c8bebb789915cc09e196c0fd45125c4', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
@@ -44,7 +44,7 @@ class ComposerAutoloaderInit0c8bebb789915cc09e196c0fd45125c4
44
  }
45
  }
46
 
47
- function composerRequire0c8bebb789915cc09e196c0fd45125c4($file)
48
  {
49
  require $file;
50
  }
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit6e3042e2ec56b2cc1bf8c8c9efe69b8e
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit6e3042e2ec56b2cc1bf8c8c9efe69b8e', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit6e3042e2ec56b2cc1bf8c8c9efe69b8e', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
44
  }
45
  }
46
 
47
+ function composerRequire6e3042e2ec56b2cc1bf8c8c9efe69b8e($file)
48
  {
49
  require $file;
50
  }