Timber - Version 0.21.2

Version Description

  • Fixed GIF handling (thanks @josephbergdoll and @jarednova)
  • Improved handling of diff't image sizes
  • Timber Archives are now tested and much improved (thanks @KLVTZ)
  • Image fixing (thanks @marciojcoelho)
  • More tests and improving coverage to 77%
Download this release

Release Info

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

Code changes from version 0.21.0 to 0.21.2

Files changed (75) hide show
  1. lib/image/timber-image-operation-pngtojpg.php +0 -49
  2. lib/image/timber-image-operation-resize.php +8 -8
  3. lib/image/timber-image-operation-tojpg.php +66 -0
  4. lib/timber-archives.php +24 -30
  5. lib/timber-helper.php +680 -678
  6. lib/timber-image-helper.php +481 -439
  7. lib/timber-image.php +314 -307
  8. lib/timber-menu.php +155 -158
  9. lib/timber-post-getter.php +2 -1
  10. lib/timber-post.php +39 -18
  11. lib/timber-routes.php +5 -0
  12. lib/timber-term.php +8 -3
  13. lib/timber-url-helper.php +9 -3
  14. lib/timber-user.php +188 -187
  15. readme.txt +11 -1
  16. timber.php +8 -4
  17. vendor/autoload.php +1 -1
  18. vendor/composer/autoload_classmap.php +1 -1
  19. vendor/composer/autoload_real.php +4 -4
  20. vendor/composer/installed.json +14 -14
  21. vendor/twig/twig/.travis.yml +10 -0
  22. vendor/twig/twig/CHANGELOG +8 -1
  23. vendor/twig/twig/composer.json +1 -1
  24. vendor/twig/twig/doc/api.rst +3 -1
  25. vendor/twig/twig/doc/deprecated.rst +6 -0
  26. vendor/twig/twig/doc/installation.rst +5 -2
  27. vendor/twig/twig/doc/recipes.rst +0 -50
  28. vendor/twig/twig/ext/twig/php_twig.h +5 -1
  29. vendor/twig/twig/ext/twig/twig.c +58 -96
  30. vendor/twig/twig/lib/Twig/Autoloader.php +3 -3
  31. vendor/twig/twig/lib/Twig/Environment.php +1 -1
  32. vendor/twig/twig/lib/Twig/Error.php +2 -2
  33. vendor/twig/twig/lib/Twig/Extension/Core.php +3 -5
  34. vendor/twig/twig/lib/Twig/Loader/Filesystem.php +4 -3
  35. vendor/twig/twig/lib/Twig/Loader/String.php +2 -0
  36. vendor/twig/twig/lib/Twig/Node/Embed.php +5 -1
  37. vendor/twig/twig/lib/Twig/Node/Expression/Call.php +2 -0
  38. vendor/twig/twig/lib/Twig/Node/Expression/Name.php +1 -1
  39. vendor/twig/twig/lib/Twig/Node/Import.php +5 -1
  40. vendor/twig/twig/lib/Twig/Node/Include.php +8 -5
  41. vendor/twig/twig/lib/Twig/Node/Module.php +21 -14
  42. vendor/twig/twig/lib/Twig/NodeVisitor/Optimizer.php +1 -1
  43. vendor/twig/twig/lib/Twig/Template.php +25 -1
  44. vendor/twig/twig/lib/Twig/Test/NodeTestCase.php +1 -1
  45. vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php +17 -17
  46. vendor/twig/twig/test/Twig/Tests/ExpressionParserTest.php +13 -13
  47. vendor/twig/twig/test/Twig/Tests/FileCachingTest.php +3 -3
  48. vendor/twig/twig/test/Twig/Tests/Fixtures/filters/slice.test +4 -2
  49. vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array_with_empty_name.test +12 -0
  50. vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array_with_null_name.test +12 -0
  51. vendor/twig/twig/test/Twig/Tests/Loader/FilesystemTest.php +26 -0
  52. vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_empty_parent.html.twig +3 -0
  53. vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_nonexistent_parent.html.twig +3 -0
  54. vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_null_parent.html.twig +3 -0
  55. vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_valid_parent.html.twig +3 -0
  56. vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/parent.html.twig +1 -0
  57. vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/spare_parent.html.twig +1 -0
  58. vendor/twig/twig/test/Twig/Tests/NativeExtensionTest.php +2 -2
  59. vendor/twig/twig/test/Twig/Tests/Node/Expression/CallTest.php +10 -0
  60. vendor/twig/twig/test/Twig/Tests/Node/Expression/FilterTest.php +2 -2
  61. vendor/twig/twig/test/Twig/Tests/Node/Expression/FunctionTest.php +2 -2
  62. vendor/twig/twig/test/Twig/Tests/Node/Expression/NameTest.php +1 -1
  63. vendor/twig/twig/test/Twig/Tests/Node/Expression/TestTest.php +2 -2
  64. vendor/twig/twig/test/Twig/Tests/Node/ImportTest.php +1 -1
  65. vendor/twig/twig/test/Twig/Tests/Node/IncludeTest.php +5 -5
  66. vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php +8 -16
  67. vendor/twig/twig/test/Twig/Tests/NodeVisitor/OptimizerTest.php +5 -5
  68. vendor/twig/twig/test/Twig/Tests/Profiler/Dumper/AbstractTest.php +4 -3
  69. vendor/twig/twig/test/Twig/Tests/Profiler/Dumper/HtmlTest.php +1 -1
  70. vendor/twig/twig/test/Twig/Tests/Profiler/Dumper/TextTest.php +1 -1
  71. vendor/twig/twig/test/Twig/Tests/Profiler/ProfileTest.php +2 -1
  72. vendor/upstatement/routes/.coveralls.yml +3 -0
  73. vendor/upstatement/routes/.travis.yml +1 -0
  74. vendor/upstatement/routes/phpunit.xml +5 -6
  75. vendor/upstatement/routes/tests/bootstrap.php +1 -1
lib/image/timber-image-operation-pngtojpg.php DELETED
@@ -1,49 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Implements converting a PNG file to JPG.
5
- * Argument:
6
- * - color to fill transparent zones
7
- */
8
- class TimberImageOperationPngToJpg extends TimberImageOperation {
9
-
10
- private $color;
11
-
12
- /**
13
- * @param string $color hex string of color to use for transparent zones
14
- */
15
- function __construct($color) {
16
- $this->color = $color;
17
- }
18
-
19
- /**
20
- * @param string $src_filename the basename of the file (ex: my-awesome-pic)
21
- * @param string $src_extension ignored
22
- * @return string the final filename to be used (ex: my-awesome-pic.jpg)
23
- */
24
- function filename($src_filename, $src_extension = 'jpg') {
25
- $new_name = $src_filename . '.jpg';
26
- return $new_name;
27
- }
28
-
29
- /**
30
- * Performs the actual image manipulation,
31
- * including saving the target file.
32
- *
33
- * @param string $load_filename filepath (not URL) to source file (ex: /src/var/www/wp-content/uploads/my-pic.jpg)
34
- * @param string $save_filename filepath (not URL) where result file should be saved
35
- * (ex: /src/var/www/wp-content/uploads/my-pic.png)
36
- * @return bool true if everything went fine, false otherwise
37
- */
38
- function run($load_filename, $save_filename){
39
- $input = imagecreatefrompng( $load_filename );
40
- list( $width, $height ) = getimagesize( $load_filename );
41
- $output = imagecreatetruecolor( $width, $height );
42
- $c = self::hexrgb( $this->color );
43
- $color = imagecolorallocate( $output, $c['red'], $c['green'], $c['blue'] );
44
- imagefilledrectangle( $output, 0, 0, $width, $height, $color );
45
- imagecopy( $output, $input, 0, 0, 0, 0, $width, $height );
46
- imagejpeg( $output, $save_filename );
47
- return true;
48
- }
49
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/image/timber-image-operation-resize.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * Changes image to new size, by shrinking/enlarging
4
  * then cropping to respect new ratio.
5
- *
6
  * Arguments:
7
  * - width of new image
8
  * - height of new image
9
- * - crop method
10
  */
11
  class TimberImageOperationResize extends TimberImageOperation {
12
-
13
  private $w, $h, $crop;
14
 
15
  /**
@@ -31,7 +31,7 @@ class TimberImageOperationResize extends TimberImageOperation {
31
  /**
32
  * @param string $src_filename the basename of the file (ex: my-awesome-pic)
33
  * @param string $src_extension the extension (ex: .jpg)
34
- * @return string the final filename to be used (ex: my-awesome-pic-300x200-c-default.jpg)
35
  */
36
  public function filename($src_filename, $src_extension) {
37
  $result = $src_filename . '-' . $this->w . 'x' . $this->h . '-c-' . ( $this->crop ? $this->crop : 'f' ); // Crop will be either user named or f (false)
@@ -44,10 +44,10 @@ class TimberImageOperationResize extends TimberImageOperation {
44
  /**
45
  * Performs the actual image manipulation,
46
  * including saving the target file.
47
- *
48
- * @param string $load_filename filepath (not URL) to source file
49
  * (ex: /src/var/www/wp-content/uploads/my-pic.jpg)
50
- * @param string $save_filename filepath (not URL) where result file should be saved
51
  * (ex: /src/var/www/wp-content/uploads/my-pic-300x200-c-default.jpg)
52
  * @return bool true if everything went fine, false otherwise
53
  */
@@ -116,4 +116,4 @@ class TimberImageOperationResize extends TimberImageOperation {
116
  }
117
  return false;
118
  }
119
- }
2
  /**
3
  * Changes image to new size, by shrinking/enlarging
4
  * then cropping to respect new ratio.
5
+ *
6
  * Arguments:
7
  * - width of new image
8
  * - height of new image
9
+ * - crop method
10
  */
11
  class TimberImageOperationResize extends TimberImageOperation {
12
+
13
  private $w, $h, $crop;
14
 
15
  /**
31
  /**
32
  * @param string $src_filename the basename of the file (ex: my-awesome-pic)
33
  * @param string $src_extension the extension (ex: .jpg)
34
+ * @return string the final filename to be used (ex: my-awesome-pic-300x200-c-default.jpg)
35
  */
36
  public function filename($src_filename, $src_extension) {
37
  $result = $src_filename . '-' . $this->w . 'x' . $this->h . '-c-' . ( $this->crop ? $this->crop : 'f' ); // Crop will be either user named or f (false)
44
  /**
45
  * Performs the actual image manipulation,
46
  * including saving the target file.
47
+ *
48
+ * @param string $load_filename filepath (not URL) to source file
49
  * (ex: /src/var/www/wp-content/uploads/my-pic.jpg)
50
+ * @param string $save_filename filepath (not URL) where result file should be saved
51
  * (ex: /src/var/www/wp-content/uploads/my-pic-300x200-c-default.jpg)
52
  * @return bool true if everything went fine, false otherwise
53
  */
116
  }
117
  return false;
118
  }
119
+ }
lib/image/timber-image-operation-tojpg.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Implements converting a PNG file to JPG.
5
+ * Argument:
6
+ * - color to fill transparent zones
7
+ */
8
+ class TimberImageOperationToJpg extends TimberImageOperation {
9
+
10
+ private $color;
11
+
12
+ /**
13
+ * @param string $color hex string of color to use for transparent zones
14
+ */
15
+ function __construct($color) {
16
+ $this->color = $color;
17
+ }
18
+
19
+ /**
20
+ * @param string $src_filename the basename of the file (ex: my-awesome-pic)
21
+ * @param string $src_extension ignored
22
+ * @return string the final filename to be used (ex: my-awesome-pic.jpg)
23
+ */
24
+ function filename($src_filename, $src_extension = 'jpg') {
25
+ $new_name = $src_filename . '.jpg';
26
+ return $new_name;
27
+ }
28
+
29
+ /**
30
+ * Performs the actual image manipulation,
31
+ * including saving the target file.
32
+ *
33
+ * @param string $load_filename filepath (not URL) to source file (ex: /src/var/www/wp-content/uploads/my-pic.jpg)
34
+ * @param string $save_filename filepath (not URL) where result file should be saved
35
+ * (ex: /src/var/www/wp-content/uploads/my-pic.png)
36
+ * @return bool true if everything went fine, false otherwise
37
+ */
38
+ function run($load_filename, $save_filename){
39
+ $input = self::image_create( $load_filename );
40
+ list( $width, $height ) = getimagesize( $load_filename );
41
+ $output = imagecreatetruecolor( $width, $height );
42
+ $c = self::hexrgb( $this->color );
43
+ $color = imagecolorallocate( $output, $c['red'], $c['green'], $c['blue'] );
44
+ imagefilledrectangle( $output, 0, 0, $width, $height, $color );
45
+ imagecopy( $output, $input, 0, 0, 0, 0, $width, $height );
46
+ imagejpeg( $output, $save_filename );
47
+ return true;
48
+ }
49
+
50
+ /**
51
+ * @return resource an image identifier representing the image obtained from the given filename
52
+ * will return the same data type regardless of whether the source is gif or png
53
+ */
54
+ function image_create( $filename, $ext = 'auto' ) {
55
+ if ( $ext == 'auto' ) {
56
+ $ext = wp_check_filetype($filename);
57
+ if (isset($ext['ext'])) {
58
+ $ext = $ext['ext'];
59
+ }
60
+ }
61
+ if ( $ext == 'gif' ) {
62
+ return imagecreatefromgif($filename);
63
+ }
64
+ return imagecreatefrompng($filename);
65
+ }
66
+ }
lib/timber-archives.php CHANGED
@@ -70,17 +70,15 @@ class TimberArchives extends TimberCore
70
  * @param bool $nested
71
  * @return array
72
  */
73
- function get_items_montly($args, $last_changed, $join, $where, $order, $limit = 1000, $nested = true) {
74
  global $wpdb, $wp_locale;
75
  $output = array();
76
  $defaults = array(
77
- 'show_year' => true,
78
  );
79
  $r = wp_parse_args($args, $defaults);
80
 
81
  $show_year = $r['show_year'];
82
- extract($r, EXTR_SKIP);
83
-
84
  //will need to specify which year we're looking for
85
  $query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts "
86
  . "FROM $wpdb->posts $join $where GROUP BY YEAR(post_date), MONTH(post_date) "
@@ -94,8 +92,6 @@ class TimberArchives extends TimberCore
94
  if ($results) {
95
  foreach ((array)$results as $result) {
96
  $url = get_month_link($result->year, $result->month);
97
- /* translators: 1: month name, 2: 4-digit year */
98
-
99
  if ($show_year && !$nested) {
100
  $text = sprintf(__('%1$s %2$d'), $wp_locale->get_month($result->month), $result->year);
101
  } else {
@@ -126,30 +122,29 @@ class TimberArchives extends TimberCore
126
  global $wpdb;
127
 
128
  $defaults = array(
129
- 'type' => 'monthly', 'limit' => '',
130
- 'format' => 'html', 'before' => '',
131
- 'after' => '', 'show_post_count' => false,
132
  'order' => 'DESC',
133
  'post_type' => 'post',
134
- 'nested' => true
 
135
  );
136
 
137
- $r = wp_parse_args($args, $defaults);
138
- $type = $limit = $order = $post_type = $nested = $format = $before = $after = null;
139
- extract($r, EXTR_SKIP);
140
-
141
- if (empty($order)){
142
- $order = 'DESC';
 
 
143
  }
144
-
145
- if (empty($post_type)){
146
- $post_type = 'post';
147
- }
148
- if (empty($type)) {
149
- $type = 'monthly';
150
  }
151
 
152
- if (!empty($limit)) {
153
  $limit = absint($limit);
154
  $limit = ' LIMIT ' . $limit;
155
  }
@@ -178,25 +173,24 @@ class TimberArchives extends TimberCore
178
  $archive_week_end_date_format = get_option('date_format');
179
  }
180
 
181
- $where = apply_filters('getarchives_where', 'WHERE post_type = "' . $post_type . '" AND post_status = "publish"', $r);
182
- $join = apply_filters('getarchives_join', '', $r);
183
 
184
  $output = array();
185
-
186
  $last_changed = wp_cache_get('last_changed', 'posts');
187
  if (!$last_changed) {
188
  $last_changed = microtime();
189
  wp_cache_set('last_changed', $last_changed, 'posts');
190
  }
191
  if ('monthly' == $type) {
192
- $output = $this->get_items_montly($args, $last_changed, $join, $where, $order, $limit, $nested);
193
  } elseif ('yearly' == $type) {
194
  $output = $this->get_items_yearly($args, $last_changed, $join, $where, $order, $limit);
195
- } elseif ('yearlymonthly' == $type || 'yearmonth' == $type) {
196
  $years = $this->get_items_yearly($args, $last_changed, $join, $where, $order, $limit);
197
  foreach ($years as &$year) {
198
  $args = array('show_year' => false);
199
- $year['children'] = $this->get_items_montly($args, $last_changed, $join, $where, $order, $limit);
200
  }
201
  $output = $years;
202
  } elseif ('daily' == $type) {
@@ -261,7 +255,7 @@ class TimberArchives extends TimberCore
261
  } else {
262
  $text = $result->ID;
263
  }
264
- $output .= get_archives_link($url, $text, $format, $before, $after);
265
  }
266
  }
267
  }
70
  * @param bool $nested
71
  * @return array
72
  */
73
+ function get_items_monthly($args, $last_changed, $join, $where, $order, $limit = 1000, $nested = true) {
74
  global $wpdb, $wp_locale;
75
  $output = array();
76
  $defaults = array(
77
+ 'show_year' => false,
78
  );
79
  $r = wp_parse_args($args, $defaults);
80
 
81
  $show_year = $r['show_year'];
 
 
82
  //will need to specify which year we're looking for
83
  $query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts "
84
  . "FROM $wpdb->posts $join $where GROUP BY YEAR(post_date), MONTH(post_date) "
92
  if ($results) {
93
  foreach ((array)$results as $result) {
94
  $url = get_month_link($result->year, $result->month);
 
 
95
  if ($show_year && !$nested) {
96
  $text = sprintf(__('%1$s %2$d'), $wp_locale->get_month($result->month), $result->year);
97
  } else {
122
  global $wpdb;
123
 
124
  $defaults = array(
125
+ 'type' => 'monthly-nested',
126
+ 'limit' => '',
127
+ 'show_post_count' => false,
128
  'order' => 'DESC',
129
  'post_type' => 'post',
130
+ 'show_year' => false,
131
+ 'nested' => false
132
  );
133
 
134
+ $args = wp_parse_args($args, $defaults);
135
+ $post_type = $args['post_type'];
136
+ $order = $args['order'];
137
+ $nested = $args['nested'];
138
+ $type = $args['type'];
139
+ $limit = '';
140
+ if ( $type == 'yearlymonthly' || $type == 'yearmonth' ) {
141
+ $type = 'monthly-nested';
142
  }
143
+ if ( $type == 'monthly-nested' ) {
144
+ $nested = true;
 
 
 
 
145
  }
146
 
147
+ if (!empty($args['limit'])) {
148
  $limit = absint($limit);
149
  $limit = ' LIMIT ' . $limit;
150
  }
173
  $archive_week_end_date_format = get_option('date_format');
174
  }
175
 
176
+ $where = apply_filters('getarchives_where', 'WHERE post_type = "' . $post_type . '" AND post_status = "publish"', $args);
177
+ $join = apply_filters('getarchives_join', '', $args);
178
 
179
  $output = array();
 
180
  $last_changed = wp_cache_get('last_changed', 'posts');
181
  if (!$last_changed) {
182
  $last_changed = microtime();
183
  wp_cache_set('last_changed', $last_changed, 'posts');
184
  }
185
  if ('monthly' == $type) {
186
+ $output = $this->get_items_monthly($args, $last_changed, $join, $where, $order, $limit, $nested);
187
  } elseif ('yearly' == $type) {
188
  $output = $this->get_items_yearly($args, $last_changed, $join, $where, $order, $limit);
189
+ } elseif ('monthly-nested' == $type) {
190
  $years = $this->get_items_yearly($args, $last_changed, $join, $where, $order, $limit);
191
  foreach ($years as &$year) {
192
  $args = array('show_year' => false);
193
+ $year['children'] = $this->get_items_monthly($args, $last_changed, $join, $where, $order, $limit);
194
  }
195
  $output = $years;
196
  } elseif ('daily' == $type) {
255
  } else {
256
  $text = $result->ID;
257
  }
258
+ $output[] = $this->get_archives_link($url, $text);
259
  }
260
  }
261
  }
lib/timber-helper.php CHANGED
@@ -2,683 +2,685 @@
2
 
3
  class TimberHelper {
4
 
5
- /**
6
- *
7
- *
8
- * @param string $slug Unique identifier for transient
9
- * @param callable $callback Callback that generates the data that's to be cached
10
- * @param int $transient_time (optional) Expiration of transients in seconds
11
- * @param int $lock_timeout (optional) How long to lock the transient to prevent race conditions
12
- * @param bool $force (optional) Force callback to be executed when transient is locked
13
- * @return mixed
14
- */
15
- public static function transient( $slug, $callback, $transient_time = 0, $lock_timeout = 5, $force = false ) {
16
-
17
- $enable_transients = ( $transient_time === false || ( defined( 'WP_DISABLE_TRANSIENTS' ) && WP_DISABLE_TRANSIENTS ) ) ? false : true;
18
- $data = $enable_transients ? get_transient( $slug ) : false;
19
-
20
- if ( false === $data ) {
21
-
22
- if ( $enable_transients && self::_is_transient_locked( $slug ) ) {
23
-
24
- $force = apply_filters( 'timber_force_transients', $force );
25
- $force = apply_filters( 'timber_force_transient_' . $slug, $force );
26
-
27
- if ( !$force ) {
28
- //the server is currently executing the process.
29
- //We're just gonna dump these users. Sorry!
30
- return false;
31
- }
32
-
33
- $enable_transients = false;
34
- }
35
-
36
- // lock timeout shouldn't be higher than 5 seconds, unless
37
- // remote calls with high timeouts are made here
38
- if ( $enable_transients )
39
- self::_lock_transient( $slug, $lock_timeout );
40
-
41
- $data = $callback();
42
-
43
- if ( $enable_transients ) {
44
- set_transient( $slug, $data, $transient_time );
45
- self::_unlock_transient( $slug );
46
- }
47
-
48
- }
49
-
50
- return $data;
51
-
52
- }
53
-
54
- /**
55
- * @param string $slug
56
- * @param integer $lock_timeout
57
- */
58
- public static function _lock_transient( $slug, $lock_timeout ) {
59
- set_transient( $slug . '_lock', true, $lock_timeout );
60
- }
61
-
62
- /**
63
- * @param string $slug
64
- */
65
- public static function _unlock_transient( $slug ) {
66
- delete_transient( $slug . '_lock', true );
67
- }
68
-
69
- /**
70
- * @param string $slug
71
- */
72
- public static function _is_transient_locked( $slug ) {
73
- return (bool)get_transient( $slug . '_lock' );
74
- }
75
-
76
- /* These are for measuring page render time */
77
-
78
- /**
79
- *
80
- *
81
- * @return float
82
- */
83
- public static function start_timer() {
84
- $time = microtime();
85
- $time = explode( ' ', $time );
86
- $time = $time[1] + $time[0];
87
- return $time;
88
- }
89
-
90
- /**
91
- *
92
- *
93
- * @param int $start
94
- * @return string
95
- */
96
- public static function stop_timer( $start ) {
97
- $time = microtime();
98
- $time = explode( ' ', $time );
99
- $time = $time[1] + $time[0];
100
- $finish = $time;
101
- $total_time = round( ( $finish - $start ), 4 );
102
- return $total_time . ' seconds.';
103
- }
104
-
105
- /* Function Utilities
106
- ======================== */
107
-
108
- /**
109
- *
110
- *
111
- * @param callback $function
112
- * @param array $args
113
- * @return string
114
- */
115
- public static function ob_function( $function, $args = array( null ) ) {
116
- ob_start();
117
- call_user_func_array( $function, $args );
118
- $data = ob_get_contents();
119
- ob_end_clean();
120
- return $data;
121
- }
122
-
123
- /**
124
- *
125
- *
126
- * @param string $function_name
127
- * @param integer[] $defaults
128
- * @param bool $return_output_buffer
129
- * @return TimberFunctionWrapper
130
- */
131
- public static function function_wrapper( $function_name, $defaults = array(), $return_output_buffer = false ) {
132
- return new TimberFunctionWrapper( $function_name, $defaults, $return_output_buffer );
133
- }
134
-
135
- /**
136
- *
137
- *
138
- * @param unknown $arg
139
- * @return void
140
- */
141
- public static function error_log( $arg ) {
142
- if ( !WP_DEBUG ) {
143
- return;
144
- }
145
- if ( is_object( $arg ) || is_array( $arg ) ) {
146
- $arg = print_r( $arg, true );
147
- }
148
- error_log( $arg );
149
- }
150
-
151
- /**
152
- *
153
- *
154
- * @param string $separator
155
- * @param string $seplocation
156
- * @return string
157
- */
158
- public static function get_wp_title( $separator = ' ', $seplocation = 'left' ) {
159
- $separator = apply_filters( 'timber_wp_title_seperator', $separator );
160
- return trim( wp_title( $separator, false, $seplocation ) );
161
- }
162
-
163
- /* Text Utilities
164
- ======================== */
165
-
166
- /**
167
- *
168
- *
169
- * @param string $text
170
- * @param int $num_words
171
- * @param string $more
172
- * @param string $allowed_tags
173
- * @return string
174
- */
175
- public static function trim_words( $text, $num_words = 55, $more = null, $allowed_tags = 'p a span b i br' ) {
176
- if ( null === $more ) {
177
- $more = __( '&hellip;' );
178
- }
179
- $original_text = $text;
180
- $allowed_tag_string = '';
181
- foreach ( explode( ' ', $allowed_tags ) as $tag ) {
182
- $allowed_tag_string .= '<' . $tag . '>';
183
- }
184
- $text = strip_tags( $text, $allowed_tag_string );
185
- /* translators: If your word count is based on single characters (East Asian characters),
186
- enter 'characters'. Otherwise, enter 'words'. Do not translate into your own language. */
187
- if ( 'characters' == _x( 'words', 'word count: words or characters?' ) && preg_match( '/^utf\-?8$/i', get_option( 'blog_charset' ) ) ) {
188
- $text = trim( preg_replace( "/[\n\r\t ]+/", ' ', $text ), ' ' );
189
- preg_match_all( '/./u', $text, $words_array );
190
- $words_array = array_slice( $words_array[0], 0, $num_words + 1 );
191
- $sep = '';
192
- } else {
193
- $words_array = preg_split( "/[\n\r\t ]+/", $text, $num_words + 1, PREG_SPLIT_NO_EMPTY );
194
- $sep = ' ';
195
- }
196
- if ( count( $words_array ) > $num_words ) {
197
- array_pop( $words_array );
198
- $text = implode( $sep, $words_array );
199
- $text = $text . $more;
200
- } else {
201
- $text = implode( $sep, $words_array );
202
- }
203
- $text = self::close_tags( $text );
204
- return apply_filters( 'wp_trim_words', $text, $num_words, $more, $original_text );
205
- }
206
-
207
- /**
208
- *
209
- *
210
- * @param string $html
211
- * @return string
212
- */
213
- public static function close_tags( $html ) {
214
- //put all opened tags into an array
215
- preg_match_all( '#<([a-z]+)(?: .*)?(?<![/|/ ])>#iU', $html, $result );
216
- $openedtags = $result[1];
217
- //put all closed tags into an array
218
- preg_match_all( '#</([a-z]+)>#iU', $html, $result );
219
- $closedtags = $result[1];
220
- $len_opened = count( $openedtags );
221
- // all tags are closed
222
- if ( count( $closedtags ) == $len_opened ) {
223
- return $html;
224
- }
225
- $openedtags = array_reverse( $openedtags );
226
- // close tags
227
- for ( $i = 0; $i < $len_opened; $i++ ) {
228
- if ( !in_array( $openedtags[$i], $closedtags ) ) {
229
- $html .= '</' . $openedtags[$i] . '>';
230
- } else {
231
- unset( $closedtags[array_search( $openedtags[$i], $closedtags )] );
232
- }
233
- }
234
- $html = str_replace(array('</br>','</hr>','</wbr>'), '', $html);
235
- $html = str_replace(array('<br>','<hr>','<wbr>'), array('<br />','<hr />','<wbr />'), $html);
236
- return $html;
237
- }
238
-
239
- /**
240
- *
241
- *
242
- * @param string $ret
243
- * @return string
244
- * @deprecated since 0.20.0
245
- */
246
- public static function twitterify( $ret ) {
247
- $ret = preg_replace( "#(^|[\n ])([\w]+?://[\w]+[^ \"\n\r\t< ]*)#", "\\1<a href=\"\\2\" target=\"_blank\">\\2</a>", $ret );
248
- $ret = preg_replace( "#(^|[\n ])((www|ftp)\.[^ \"\t\n\r< ]*)#", "\\1<a href=\"http://\\2\" target=\"_blank\">\\2</a>", $ret );
249
- $pattern = '#([0-9a-z]([-_.]?[0-9a-z])*@[0-9a-z]([-.]?[0-9a-z])*\\.';
250
- $pattern .= '[a-wyz][a-z](fo|g|l|m|mes|o|op|pa|ro|seum|t|u|v|z)?)#i';
251
- $ret = preg_replace( $pattern, '<a href="mailto:\\1">\\1</a>', $ret );
252
- $ret = preg_replace( "/\B@(\w+)/", " <a href=\"http://www.twitter.com/\\1\" target=\"_blank\">@\\1</a>", $ret );
253
- $ret = preg_replace( "/\B#(\w+)/", " <a href=\"http://twitter.com/search?q=\\1\" target=\"_blank\">#\\1</a>", $ret );
254
- return $ret;
255
- }
256
-
257
- /* WordPress Query Utilities
258
- ======================== */
259
-
260
- /**
261
- *
262
- *
263
- * @param string $key
264
- * @param string $value
265
- * @return array|int
266
- * @deprecated since 0.20.0
267
- */
268
- public static function get_posts_by_meta( $key, $value ) {
269
- global $wpdb;
270
- $query = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %s", $key, $value );
271
- $results = $wpdb->get_col( $query );
272
- $pids = array();
273
- foreach ( $results as $result ) {
274
- if ( get_post( $result ) ) {
275
- $pids[] = $result;
276
- }
277
- }
278
- if ( count( $pids ) ) {
279
- return $pids;
280
- }
281
- return 0;
282
- }
283
-
284
- /**
285
- *
286
- *
287
- * @param string $key
288
- * @param string $value
289
- * @return int
290
- * @deprecated since 0.20.0
291
- */
292
- public static function get_post_by_meta( $key, $value ) {
293
- global $wpdb;
294
- $query = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %s ORDER BY post_id", $key, $value );
295
- $results = $wpdb->get_col( $query );
296
- foreach ( $results as $result ) {
297
- if ( $result && get_post( $result ) ) {
298
- return $result;
299
- }
300
- }
301
- return 0;
302
- }
303
-
304
- /**
305
- *
306
- *
307
- * @param int $ttid
308
- * @return mixed
309
- */
310
- public static function get_term_id_by_term_taxonomy_id( $ttid ) {
311
- global $wpdb;
312
- $query = $wpdb->prepare( "SELECT term_id FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %s", $ttid );
313
- return $wpdb->get_var( $query );
314
- }
315
-
316
- /* Object Utilities
317
- ======================== */
318
-
319
- /**
320
- *
321
- *
322
- * @param array $array
323
- * @param string $prop
324
- * @return void
325
- */
326
- public static function osort( &$array, $prop ) {
327
- usort( $array, function ( $a, $b ) use ( $prop ) {
328
- return $a->$prop > $b->$prop ? 1 : -1;
329
- } );
330
- }
331
-
332
- /**
333
- *
334
- *
335
- * @param array $arr
336
- * @return bool
337
- */
338
- public static function is_array_assoc( $arr ) {
339
- if ( !is_array( $arr ) ) {
340
- return false;
341
- }
342
- return (bool)count( array_filter( array_keys( $arr ), 'is_string' ) );
343
- }
344
-
345
- /**
346
- *
347
- *
348
- * @param array $array
349
- * @return stdClass
350
- */
351
- public static function array_to_object( $array ) {
352
- $obj = new stdClass;
353
- foreach ( $array as $k => $v ) {
354
- if ( is_array( $v ) ) {
355
- $obj->{$k} = self::array_to_object( $v ); //RECURSION
356
- } else {
357
- $obj->{$k} = $v;
358
- }
359
- }
360
- return $obj;
361
- }
362
-
363
- /**
364
- *
365
- *
366
- * @param array $array
367
- * @param string $key
368
- * @param mixed $value
369
- * @return bool|int
370
- */
371
- public static function get_object_index_by_property( $array, $key, $value ) {
372
- if ( is_array( $array ) ) {
373
- $i = 0;
374
- foreach ( $array as $arr ) {
375
- if ( is_array( $arr ) ) {
376
- if ( $arr[$key] == $value ) {
377
- return $i;
378
- }
379
- } else {
380
- if ( $arr->$key == $value ) {
381
- return $i;
382
- }
383
- }
384
- $i++;
385
- }
386
- }
387
- return false;
388
- }
389
-
390
- /**
391
- *
392
- *
393
- * @param array $array
394
- * @param string $key
395
- * @param mixed $value
396
- * @return array|null
397
- * @throws Exception
398
- */
399
- public static function get_object_by_property( $array, $key, $value ) {
400
- if ( is_array( $array ) ) {
401
- foreach ( $array as $arr ) {
402
- if ( $arr->$key == $value ) {
403
- return $arr;
404
- }
405
- }
406
- } else {
407
- throw new Exception( '$array is not an array, given value: ' . $array );
408
- }
409
- return null;
410
- }
411
-
412
- /**
413
- *
414
- *
415
- * @param array $array
416
- * @param int $len
417
- * @return array
418
- */
419
- public static function array_truncate( $array, $len ) {
420
- if ( sizeof( $array ) > $len ) {
421
- $array = array_splice( $array, 0, $len );
422
- }
423
- return $array;
424
- }
425
-
426
- /* Bool Utilities
427
- ======================== */
428
-
429
- /**
430
- *
431
- *
432
- * @param mixed $property
433
- * @return bool
434
- */
435
- public static function is_true( $property ) {
436
- if ( isset( $property ) ) {
437
- if ( $property == 'true' || $property == 1 || $property == '1' || $property == true ) {
438
- return true;
439
- }
440
- }
441
- return false;
442
- }
443
-
444
- /**
445
- *
446
- *
447
- * @param int $i
448
- * @return bool
449
- */
450
- public static function iseven( $i ) {
451
- return ( $i % 2 ) == 0;
452
- }
453
-
454
- /**
455
- *
456
- *
457
- * @param int $i
458
- * @return bool
459
- */
460
- public static function isodd( $i ) {
461
- return ( $i % 2 ) != 0;
462
- }
463
-
464
- /* Links, Forms, Etc. Utilities
465
- ======================== */
466
-
467
- /* this $args thing is a fucking mess, fix at some point:
468
-
469
- http://codex.wordpress.org/Function_Reference/comment_form */
470
-
471
- /**
472
- *
473
- *
474
- * @param int $post_id
475
- * @param array $args
476
- * @return string
477
- */
478
- public static function get_comment_form( $post_id = null, $args = array() ) {
479
- return self::ob_function( 'comment_form', array( $args, $post_id ) );
480
- }
481
-
482
- /**
483
- *
484
- *
485
- * @param string $args
486
- * @return array
487
- */
488
- public static function paginate_links( $args = '' ) {
489
- $defaults = array(
490
- 'base' => '%_%', // http://example.com/all_posts.php%_% : %_% is replaced by format (below)
491
- 'format' => '?page=%#%', // ?page=%#% : %#% is replaced by the page number
492
- 'total' => 1,
493
- 'current' => 0,
494
- 'show_all' => false,
495
- 'prev_next' => true,
496
- 'prev_text' => __( '&laquo; Previous' ),
497
- 'next_text' => __( 'Next &raquo;' ),
498
- 'end_size' => 1,
499
- 'mid_size' => 2,
500
- 'type' => 'array',
501
- 'add_args' => false, // array of query args to add
502
- 'add_fragment' => ''
503
- );
504
- $args = wp_parse_args( $args, $defaults );
505
- // Who knows what else people pass in $args
506
- $args['total'] = intval( (int)$args['total'] );
507
- if ( $args['total'] < 2 ) {
508
- return array();
509
- }
510
- $args['current'] = (int)$args['current'];
511
- $args['end_size'] = 0 < (int)$args['end_size'] ? (int)$args['end_size'] : 1; // Out of bounds? Make it the default.
512
- $args['mid_size'] = 0 <= (int)$args['mid_size'] ? (int)$args['mid_size'] : 2;
513
- $args['add_args'] = is_array( $args['add_args'] ) ? $args['add_args'] : false;
514
- $page_links = array();
515
- $dots = false;
516
- if ( $args['prev_next'] && $args['current'] && 1 < $args['current'] ) {
517
- $link = str_replace( '%_%', 2 == $args['current'] ? '' : $args['format'], $args['base'] );
518
- $link = str_replace( '%#%', $args['current'] - 1, $link );
519
- if ( $args['add_args'] ) {
520
- $link = add_query_arg( $args['add_args'], $link );
521
- }
522
- $link .= $args['add_fragment'];
523
- $link = untrailingslashit( $link );
524
- $page_links[] = array(
525
- 'class' => 'prev page-numbers',
526
- 'link' => esc_url( apply_filters( 'paginate_links', $link ) ),
527
- 'title' => $args['prev_text']
528
- );
529
- }
530
- for ( $n = 1; $n <= $args['total']; $n++ ) {
531
- $n_display = number_format_i18n( $n );
532
- if ( $n == $args['current'] ) {
533
- $page_links[] = array(
534
- 'class' => 'page-number page-numbers current',
535
- 'title' => $n_display,
536
- 'text' => $n_display,
537
- 'name' => $n_display,
538
- 'current' => true
539
- );
540
- $dots = true;
541
- } else {
542
- if ( $args['show_all'] || ( $n <= $args['end_size'] || ( $args['current'] && $n >= $args['current'] - $args['mid_size'] && $n <= $args['current'] + $args['mid_size'] ) || $n > $args['total'] - $args['end_size'] ) ) {
543
- $link = str_replace( '%_%', 1 == $n ? '' : $args['format'], $args['base'] );
544
- $link = str_replace( '%#%', $n, $link );
545
- $link = trailingslashit( $link ) . ltrim( $args['add_fragment'], '/' );
546
- if ( $args['add_args'] ) {
547
- $link = rtrim( add_query_arg( $args['add_args'], $link ), '/' );
548
- }
549
- $link = str_replace(' ', '+', $link);
550
- $link = untrailingslashit( $link );
551
- $page_links[] = array(
552
- 'class' => 'page-number page-numbers',
553
- 'link' => esc_url( apply_filters( 'paginate_links', $link ) ),
554
- 'title' => $n_display,
555
- 'name' => $n_display,
556
- 'current' => $args['current'] == $n
557
- );
558
- $dots = true;
559
- } elseif ( $dots && !$args['show_all'] ) {
560
- $page_links[] = array(
561
- 'class' => 'dots',
562
- 'title' => __( '&hellip;' )
563
- );
564
- $dots = false;
565
- }
566
- }
567
- }
568
- if ( $args['prev_next'] && $args['current'] && ( $args['current'] < $args['total'] || -1 == $args['total'] ) ) {
569
- $link = str_replace( '%_%', $args['format'], $args['base'] );
570
- $link = str_replace( '%#%', $args['current'] + 1, $link );
571
- if ( $args['add_args'] ) {
572
- $link = add_query_arg( $args['add_args'], $link );
573
- }
574
- $link = untrailingslashit( trailingslashit( $link ) . $args['add_fragment'] );
575
- $page_links[] = array(
576
- 'class' => 'next page-numbers',
577
- 'link' => esc_url( apply_filters( 'paginate_links', $link ) ),
578
- 'title' => $args['next_text']
579
- );
580
- }
581
- return $page_links;
582
- }
583
-
584
- /* LEGACY These have since been re-organized; but keeping linkages for backwards-compatibility */
585
-
586
- /**
587
- * @deprecated
588
- */
589
- static function get_image_path( $iid ) {
590
- return TimberImageHelper::get_image_path( $iid );
591
- }
592
-
593
- /**
594
- * @deprecated
595
- */
596
- static function get_current_url() {
597
- return TimberURLHelper::get_current_url();
598
- }
599
-
600
- /**
601
- * @deprecated
602
- */
603
- static function is_url( $url ) {
604
- return TimberURLHelper::is_url( $url );
605
- }
606
-
607
- /**
608
- * @deprecated
609
- */
610
- static function get_path_base() {
611
- return TimberURLHelper::get_path_base();
612
- }
613
-
614
- /**
615
- * @deprecated
616
- */
617
- static function get_rel_url( $url, $force = false ) {
618
- return TimberURLHelper::get_rel_url( $url, $force );
619
- }
620
-
621
- /**
622
- * @deprecated
623
- */
624
- static function is_local( $url ) {
625
- return TimberURLHelper::is_local( $url );
626
- }
627
-
628
- /**
629
- * @deprecated
630
- */
631
- static function get_full_path( $src ) {
632
- return TimberURLHelper::get_full_path( $src );
633
- }
634
-
635
- /**
636
- * @deprecated
637
- */
638
- static function get_rel_path( $src ) {
639
- return TimberURLHelper::get_rel_path( $src );
640
- }
641
-
642
- /**
643
- * @deprecated
644
- */
645
- static function remove_double_slashes( $url ) {
646
- return TimberURLHelper::remove_double_slashes( $url );
647
- }
648
-
649
- /**
650
- * @deprecated
651
- */
652
- static function prepend_to_url( $url, $path ) {
653
- return TimberURLHelper::prepend_to_url( $url, $path );
654
- }
655
-
656
- /**
657
- * @deprecated
658
- */
659
- static function preslashit( $path ) {
660
- return TimberURLHelper::preslashit( $path );
661
- }
662
-
663
- /**
664
- * @deprecated
665
- */
666
- static function is_external( $url ) {
667
- return TimberURLHelper::is_external( $url );
668
- }
669
-
670
- /**
671
- * @deprecated
672
- */
673
- static function download_url( $url, $timeout = 300 ) {
674
- return TimberURLHelper::download_url( $url, $timeout );
675
- }
676
-
677
- /**
678
- * @deprecated
679
- */
680
- static function get_params( $i = -1 ) {
681
- return TimberURLHelper::get_params( $i );
682
- }
 
 
683
 
684
  }
2
 
3
  class TimberHelper {
4
 
5
+ /**
6
+ *
7
+ *
8
+ * @param string $slug Unique identifier for transient
9
+ * @param callable $callback Callback that generates the data that's to be cached
10
+ * @param int $transient_time (optional) Expiration of transients in seconds
11
+ * @param int $lock_timeout (optional) How long to lock the transient to prevent race conditions
12
+ * @param bool $force (optional) Force callback to be executed when transient is locked
13
+ * @return mixed
14
+ */
15
+ public static function transient( $slug, $callback, $transient_time = 0, $lock_timeout = 5, $force = false ) {
16
+
17
+ $enable_transients = ( $transient_time === false || ( defined( 'WP_DISABLE_TRANSIENTS' ) && WP_DISABLE_TRANSIENTS ) ) ? false : true;
18
+ $data = $enable_transients ? get_transient( $slug ) : false;
19
+
20
+ if ( false === $data ) {
21
+
22
+ if ( $enable_transients && self::_is_transient_locked( $slug ) ) {
23
+
24
+ $force = apply_filters( 'timber_force_transients', $force );
25
+ $force = apply_filters( 'timber_force_transient_' . $slug, $force );
26
+
27
+ if ( !$force ) {
28
+ //the server is currently executing the process.
29
+ //We're just gonna dump these users. Sorry!
30
+ return false;
31
+ }
32
+
33
+ $enable_transients = false;
34
+ }
35
+
36
+ // lock timeout shouldn't be higher than 5 seconds, unless
37
+ // remote calls with high timeouts are made here
38
+ if ( $enable_transients )
39
+ self::_lock_transient( $slug, $lock_timeout );
40
+
41
+ $data = $callback();
42
+
43
+ if ( $enable_transients ) {
44
+ set_transient( $slug, $data, $transient_time );
45
+ self::_unlock_transient( $slug );
46
+ }
47
+
48
+ }
49
+
50
+ return $data;
51
+
52
+ }
53
+
54
+ /**
55
+ * @param string $slug
56
+ * @param integer $lock_timeout
57
+ */
58
+ public static function _lock_transient( $slug, $lock_timeout ) {
59
+ set_transient( $slug . '_lock', true, $lock_timeout );
60
+ }
61
+
62
+ /**
63
+ * @param string $slug
64
+ */
65
+ public static function _unlock_transient( $slug ) {
66
+ delete_transient( $slug . '_lock', true );
67
+ }
68
+
69
+ /**
70
+ * @param string $slug
71
+ */
72
+ public static function _is_transient_locked( $slug ) {
73
+ return (bool)get_transient( $slug . '_lock' );
74
+ }
75
+
76
+ /* These are for measuring page render time */
77
+
78
+ /**
79
+ *
80
+ *
81
+ * @return float
82
+ */
83
+ public static function start_timer() {
84
+ $time = microtime();
85
+ $time = explode( ' ', $time );
86
+ $time = $time[1] + $time[0];
87
+ return $time;
88
+ }
89
+
90
+ /**
91
+ *
92
+ *
93
+ * @param int $start
94
+ * @return string
95
+ */
96
+ public static function stop_timer( $start ) {
97
+ $time = microtime();
98
+ $time = explode( ' ', $time );
99
+ $time = $time[1] + $time[0];
100
+ $finish = $time;
101
+ $total_time = round( ( $finish - $start ), 4 );
102
+ return $total_time . ' seconds.';
103
+ }
104
+
105
+ /* Function Utilities
106
+ ======================== */
107
+
108
+ /**
109
+ *
110
+ *
111
+ * @param callback $function
112
+ * @param array $args
113
+ * @return string
114
+ */
115
+ public static function ob_function( $function, $args = array( null ) ) {
116
+ ob_start();
117
+ call_user_func_array( $function, $args );
118
+ $data = ob_get_contents();
119
+ ob_end_clean();
120
+ return $data;
121
+ }
122
+
123
+ /**
124
+ *
125
+ *
126
+ * @param string $function_name
127
+ * @param integer[] $defaults
128
+ * @param bool $return_output_buffer
129
+ * @return TimberFunctionWrapper
130
+ */
131
+ public static function function_wrapper( $function_name, $defaults = array(), $return_output_buffer = false ) {
132
+ return new TimberFunctionWrapper( $function_name, $defaults, $return_output_buffer );
133
+ }
134
+
135
+ /**
136
+ *
137
+ *
138
+ * @param unknown $arg
139
+ * @return void
140
+ */
141
+ public static function error_log( $arg ) {
142
+ if ( !WP_DEBUG ) {
143
+ return;
144
+ }
145
+ if ( is_object( $arg ) || is_array( $arg ) ) {
146
+ $arg = print_r( $arg, true );
147
+ }
148
+ error_log( $arg );
149
+ }
150
+
151
+ /**
152
+ *
153
+ *
154
+ * @param string $separator
155
+ * @param string $seplocation
156
+ * @return string
157
+ */
158
+ public static function get_wp_title( $separator = ' ', $seplocation = 'left' ) {
159
+ $separator = apply_filters( 'timber_wp_title_seperator', $separator );
160
+ return trim( wp_title( $separator, false, $seplocation ) );
161
+ }
162
+
163
+ /* Text Utilities
164
+ ======================== */
165
+
166
+ /**
167
+ *
168
+ *
169
+ * @param string $text
170
+ * @param int $num_words
171
+ * @param string $more
172
+ * @param string $allowed_tags
173
+ * @return string
174
+ */
175
+ public static function trim_words( $text, $num_words = 55, $more = null, $allowed_tags = 'p a span b i br' ) {
176
+ if ( null === $more ) {
177
+ $more = __( '&hellip;' );
178
+ }
179
+ $original_text = $text;
180
+ $allowed_tag_string = '';
181
+ foreach ( explode( ' ', $allowed_tags ) as $tag ) {
182
+ $allowed_tag_string .= '<' . $tag . '>';
183
+ }
184
+ $text = strip_tags( $text, $allowed_tag_string );
185
+ /* translators: If your word count is based on single characters (East Asian characters),
186
+ enter 'characters'. Otherwise, enter 'words'. Do not translate into your own language. */
187
+ if ( 'characters' == _x( 'words', 'word count: words or characters?' ) && preg_match( '/^utf\-?8$/i', get_option( 'blog_charset' ) ) ) {
188
+ $text = trim( preg_replace( "/[\n\r\t ]+/", ' ', $text ), ' ' );
189
+ preg_match_all( '/./u', $text, $words_array );
190
+ $words_array = array_slice( $words_array[0], 0, $num_words + 1 );
191
+ $sep = '';
192
+ } else {
193
+ $words_array = preg_split( "/[\n\r\t ]+/", $text, $num_words + 1, PREG_SPLIT_NO_EMPTY );
194
+ $sep = ' ';
195
+ }
196
+ if ( count( $words_array ) > $num_words ) {
197
+ array_pop( $words_array );
198
+ $text = implode( $sep, $words_array );
199
+ $text = $text . $more;
200
+ } else {
201
+ $text = implode( $sep, $words_array );
202
+ }
203
+ $text = self::close_tags( $text );
204
+ return apply_filters( 'wp_trim_words', $text, $num_words, $more, $original_text );
205
+ }
206
+
207
+ /**
208
+ *
209
+ *
210
+ * @param string $html
211
+ * @return string
212
+ */
213
+ public static function close_tags( $html ) {
214
+ //put all opened tags into an array
215
+ preg_match_all( '#<([a-z]+)(?: .*)?(?<![/|/ ])>#iU', $html, $result );
216
+ $openedtags = $result[1];
217
+ //put all closed tags into an array
218
+ preg_match_all( '#</([a-z]+)>#iU', $html, $result );
219
+ $closedtags = $result[1];
220
+ $len_opened = count( $openedtags );
221
+ // all tags are closed
222
+ if ( count( $closedtags ) == $len_opened ) {
223
+ return $html;
224
+ }
225
+ $openedtags = array_reverse( $openedtags );
226
+ // close tags
227
+ for ( $i = 0; $i < $len_opened; $i++ ) {
228
+ if ( !in_array( $openedtags[$i], $closedtags ) ) {
229
+ $html .= '</' . $openedtags[$i] . '>';
230
+ } else {
231
+ unset( $closedtags[array_search( $openedtags[$i], $closedtags )] );
232
+ }
233
+ }
234
+ $html = str_replace(array('</br>','</hr>','</wbr>'), '', $html);
235
+ $html = str_replace(array('<br>','<hr>','<wbr>'), array('<br />','<hr />','<wbr />'), $html);
236
+ return $html;
237
+ }
238
+
239
+ /**
240
+ *
241
+ *
242
+ * @param string $ret
243
+ * @return string
244
+ * @deprecated since 0.20.0
245
+ */
246
+ public static function twitterify( $ret ) {
247
+ $ret = preg_replace( "#(^|[\n ])([\w]+?://[\w]+[^ \"\n\r\t< ]*)#", "\\1<a href=\"\\2\" target=\"_blank\">\\2</a>", $ret );
248
+ $ret = preg_replace( "#(^|[\n ])((www|ftp)\.[^ \"\t\n\r< ]*)#", "\\1<a href=\"http://\\2\" target=\"_blank\">\\2</a>", $ret );
249
+ $pattern = '#([0-9a-z]([-_.]?[0-9a-z])*@[0-9a-z]([-.]?[0-9a-z])*\\.';
250
+ $pattern .= '[a-wyz][a-z](fo|g|l|m|mes|o|op|pa|ro|seum|t|u|v|z)?)#i';
251
+ $ret = preg_replace( $pattern, '<a href="mailto:\\1">\\1</a>', $ret );
252
+ $ret = preg_replace( "/\B@(\w+)/", " <a href=\"http://www.twitter.com/\\1\" target=\"_blank\">@\\1</a>", $ret );
253
+ $ret = preg_replace( "/\B#(\w+)/", " <a href=\"http://twitter.com/search?q=\\1\" target=\"_blank\">#\\1</a>", $ret );
254
+ return $ret;
255
+ }
256
+
257
+ /* WordPress Query Utilities
258
+ ======================== */
259
+
260
+ /**
261
+ *
262
+ *
263
+ * @param string $key
264
+ * @param string $value
265
+ * @return array|int
266
+ * @deprecated since 0.20.0
267
+ */
268
+ public static function get_posts_by_meta( $key, $value ) {
269
+ global $wpdb;
270
+ $query = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %s", $key, $value );
271
+ $results = $wpdb->get_col( $query );
272
+ $pids = array();
273
+ foreach ( $results as $result ) {
274
+ if ( get_post( $result ) ) {
275
+ $pids[] = $result;
276
+ }
277
+ }
278
+ if ( count( $pids ) ) {
279
+ return $pids;
280
+ }
281
+ return 0;
282
+ }
283
+
284
+ /**
285
+ *
286
+ *
287
+ * @param string $key
288
+ * @param string $value
289
+ * @return int
290
+ * @deprecated since 0.20.0
291
+ */
292
+ public static function get_post_by_meta( $key, $value ) {
293
+ global $wpdb;
294
+ $query = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %s ORDER BY post_id", $key, $value );
295
+ $results = $wpdb->get_col( $query );
296
+ foreach ( $results as $result ) {
297
+ if ( $result && get_post( $result ) ) {
298
+ return $result;
299
+ }
300
+ }
301
+ return 0;
302
+ }
303
+
304
+ /**
305
+ *
306
+ *
307
+ * @param int $ttid
308
+ * @return mixed
309
+ */
310
+ public static function get_term_id_by_term_taxonomy_id( $ttid ) {
311
+ global $wpdb;
312
+ $query = $wpdb->prepare( "SELECT term_id FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %s", $ttid );
313
+ return $wpdb->get_var( $query );
314
+ }
315
+
316
+ /* Object Utilities
317
+ ======================== */
318
+
319
+ /**
320
+ *
321
+ *
322
+ * @param array $array
323
+ * @param string $prop
324
+ * @return void
325
+ */
326
+ public static function osort( &$array, $prop ) {
327
+ usort( $array, function ( $a, $b ) use ( $prop ) {
328
+ return $a->$prop > $b->$prop ? 1 : -1;
329
+ } );
330
+ }
331
+
332
+ /**
333
+ *
334
+ *
335
+ * @param array $arr
336
+ * @return bool
337
+ */
338
+ public static function is_array_assoc( $arr ) {
339
+ if ( !is_array( $arr ) ) {
340
+ return false;
341
+ }
342
+ return (bool)count( array_filter( array_keys( $arr ), 'is_string' ) );
343
+ }
344
+
345
+ /**
346
+ *
347
+ *
348
+ * @param array $array
349
+ * @return stdClass
350
+ */
351
+ public static function array_to_object( $array ) {
352
+ $obj = new stdClass;
353
+ foreach ( $array as $k => $v ) {
354
+ if ( is_array( $v ) ) {
355
+ $obj->{$k} = self::array_to_object( $v ); //RECURSION
356
+ } else {
357
+ $obj->{$k} = $v;
358
+ }
359
+ }
360
+ return $obj;
361
+ }
362
+
363
+ /**
364
+ *
365
+ *
366
+ * @param array $array
367
+ * @param string $key
368
+ * @param mixed $value
369
+ * @return bool|int
370
+ */
371
+ public static function get_object_index_by_property( $array, $key, $value ) {
372
+ if ( is_array( $array ) ) {
373
+ $i = 0;
374
+ foreach ( $array as $arr ) {
375
+ if ( is_array( $arr ) ) {
376
+ if ( $arr[$key] == $value ) {
377
+ return $i;
378
+ }
379
+ } else {
380
+ if ( $arr->$key == $value ) {
381
+ return $i;
382
+ }
383
+ }
384
+ $i++;
385
+ }
386
+ }
387
+ return false;
388
+ }
389
+
390
+ /**
391
+ *
392
+ *
393
+ * @param array $array
394
+ * @param string $key
395
+ * @param mixed $value
396
+ * @return array|null
397
+ * @throws Exception
398
+ */
399
+ public static function get_object_by_property( $array, $key, $value ) {
400
+ if ( is_array( $array ) ) {
401
+ foreach ( $array as $arr ) {
402
+ if ( $arr->$key == $value ) {
403
+ return $arr;
404
+ }
405
+ }
406
+ } else {
407
+ throw new Exception( '$array is not an array, given value: ' . $array );
408
+ }
409
+ }
410
+
411
+ /**
412
+ *
413
+ *
414
+ * @param array $array
415
+ * @param int $len
416
+ * @return array
417
+ */
418
+ public static function array_truncate( $array, $len ) {
419
+ if ( sizeof( $array ) > $len ) {
420
+ $array = array_splice( $array, 0, $len );
421
+ }
422
+ return $array;
423
+ }
424
+
425
+ /* Bool Utilities
426
+ ======================== */
427
+
428
+ /**
429
+ *
430
+ *
431
+ * @param mixed $value
432
+ * @return bool
433
+ */
434
+ public static function is_true( $value ) {
435
+ if ( isset( $value ) ) {
436
+ if (is_string($value)) {
437
+ $value = strtolower($value);
438
+ }
439
+ if ( ($value == 'true' || $value === 1 || $value === '1' || $value == true) && $value !== false && $value !== 'false') {
440
+ return true;
441
+ }
442
+ }
443
+ return false;
444
+ }
445
+
446
+ /**
447
+ *
448
+ *
449
+ * @param int $i
450
+ * @return bool
451
+ */
452
+ public static function iseven( $i ) {
453
+ return ( $i % 2 ) == 0;
454
+ }
455
+
456
+ /**
457
+ *
458
+ *
459
+ * @param int $i
460
+ * @return bool
461
+ */
462
+ public static function isodd( $i ) {
463
+ return ( $i % 2 ) != 0;
464
+ }
465
+
466
+ /* Links, Forms, Etc. Utilities
467
+ ======================== */
468
+
469
+ /* this $args thing is a fucking mess, fix at some point:
470
+
471
+ http://codex.wordpress.org/Function_Reference/comment_form */
472
+
473
+ /**
474
+ *
475
+ *
476
+ * @param int $post_id
477
+ * @param array $args
478
+ * @return string
479
+ */
480
+ public static function get_comment_form( $post_id = null, $args = array() ) {
481
+ return self::ob_function( 'comment_form', array( $args, $post_id ) );
482
+ }
483
+
484
+ /**
485
+ *
486
+ *
487
+ * @param string $args
488
+ * @return array
489
+ */
490
+ public static function paginate_links( $args = '' ) {
491
+ $defaults = array(
492
+ 'base' => '%_%', // http://example.com/all_posts.php%_% : %_% is replaced by format (below)
493
+ 'format' => '?page=%#%', // ?page=%#% : %#% is replaced by the page number
494
+ 'total' => 1,
495
+ 'current' => 0,
496
+ 'show_all' => false,
497
+ 'prev_next' => true,
498
+ 'prev_text' => __( '&laquo; Previous' ),
499
+ 'next_text' => __( 'Next &raquo;' ),
500
+ 'end_size' => 1,
501
+ 'mid_size' => 2,
502
+ 'type' => 'array',
503
+ 'add_args' => false, // array of query args to add
504
+ 'add_fragment' => ''
505
+ );
506
+ $args = wp_parse_args( $args, $defaults );
507
+ // Who knows what else people pass in $args
508
+ $args['total'] = intval( (int)$args['total'] );
509
+ if ( $args['total'] < 2 ) {
510
+ return array();
511
+ }
512
+ $args['current'] = (int)$args['current'];
513
+ $args['end_size'] = 0 < (int)$args['end_size'] ? (int)$args['end_size'] : 1; // Out of bounds? Make it the default.
514
+ $args['mid_size'] = 0 <= (int)$args['mid_size'] ? (int)$args['mid_size'] : 2;
515
+ $args['add_args'] = is_array( $args['add_args'] ) ? $args['add_args'] : false;
516
+ $page_links = array();
517
+ $dots = false;
518
+ if ( $args['prev_next'] && $args['current'] && 1 < $args['current'] ) {
519
+ $link = str_replace( '%_%', 2 == $args['current'] ? '' : $args['format'], $args['base'] );
520
+ $link = str_replace( '%#%', $args['current'] - 1, $link );
521
+ if ( $args['add_args'] ) {
522
+ $link = add_query_arg( $args['add_args'], $link );
523
+ }
524
+ $link .= $args['add_fragment'];
525
+ $link = untrailingslashit( $link );
526
+ $page_links[] = array(
527
+ 'class' => 'prev page-numbers',
528
+ 'link' => esc_url( apply_filters( 'paginate_links', $link ) ),
529
+ 'title' => $args['prev_text']
530
+ );
531
+ }
532
+ for ( $n = 1; $n <= $args['total']; $n++ ) {
533
+ $n_display = number_format_i18n( $n );
534
+ if ( $n == $args['current'] ) {
535
+ $page_links[] = array(
536
+ 'class' => 'page-number page-numbers current',
537
+ 'title' => $n_display,
538
+ 'text' => $n_display,
539
+ 'name' => $n_display,
540
+ 'current' => true
541
+ );
542
+ $dots = true;
543
+ } else {
544
+ if ( $args['show_all'] || ( $n <= $args['end_size'] || ( $args['current'] && $n >= $args['current'] - $args['mid_size'] && $n <= $args['current'] + $args['mid_size'] ) || $n > $args['total'] - $args['end_size'] ) ) {
545
+ $link = str_replace( '%_%', 1 == $n ? '' : $args['format'], $args['base'] );
546
+ $link = str_replace( '%#%', $n, $link );
547
+ $link = trailingslashit( $link ) . ltrim( $args['add_fragment'], '/' );
548
+ if ( $args['add_args'] ) {
549
+ $link = rtrim( add_query_arg( $args['add_args'], $link ), '/' );
550
+ }
551
+ $link = str_replace(' ', '+', $link);
552
+ $link = untrailingslashit( $link );
553
+ $page_links[] = array(
554
+ 'class' => 'page-number page-numbers',
555
+ 'link' => esc_url( apply_filters( 'paginate_links', $link ) ),
556
+ 'title' => $n_display,
557
+ 'name' => $n_display,
558
+ 'current' => $args['current'] == $n
559
+ );
560
+ $dots = true;
561
+ } elseif ( $dots && !$args['show_all'] ) {
562
+ $page_links[] = array(
563
+ 'class' => 'dots',
564
+ 'title' => __( '&hellip;' )
565
+ );
566
+ $dots = false;
567
+ }
568
+ }
569
+ }
570
+ if ( $args['prev_next'] && $args['current'] && ( $args['current'] < $args['total'] || -1 == $args['total'] ) ) {
571
+ $link = str_replace( '%_%', $args['format'], $args['base'] );
572
+ $link = str_replace( '%#%', $args['current'] + 1, $link );
573
+ if ( $args['add_args'] ) {
574
+ $link = add_query_arg( $args['add_args'], $link );
575
+ }
576
+ $link = untrailingslashit( trailingslashit( $link ) . $args['add_fragment'] );
577
+ $page_links[] = array(
578
+ 'class' => 'next page-numbers',
579
+ 'link' => esc_url( apply_filters( 'paginate_links', $link ) ),
580
+ 'title' => $args['next_text']
581
+ );
582
+ }
583
+ return $page_links;
584
+ }
585
+
586
+ /* LEGACY These have since been re-organized; but keeping linkages for backwards-compatibility */
587
+
588
+ /**
589
+ * @deprecated
590
+ */
591
+ static function get_image_path( $iid ) {
592
+ return TimberImageHelper::get_image_path( $iid );
593
+ }
594
+
595
+ /**
596
+ * @deprecated
597
+ */
598
+ static function get_current_url() {
599
+ return TimberURLHelper::get_current_url();
600
+ }
601
+
602
+ /**
603
+ * @deprecated
604
+ */
605
+ static function is_url( $url ) {
606
+ return TimberURLHelper::is_url( $url );
607
+ }
608
+
609
+ /**
610
+ * @deprecated
611
+ */
612
+ static function get_path_base() {
613
+ return TimberURLHelper::get_path_base();
614
+ }
615
+
616
+ /**
617
+ * @deprecated
618
+ */
619
+ static function get_rel_url( $url, $force = false ) {
620
+ return TimberURLHelper::get_rel_url( $url, $force );
621
+ }
622
+
623
+ /**
624
+ * @deprecated
625
+ */
626
+ static function is_local( $url ) {
627
+ return TimberURLHelper::is_local( $url );
628
+ }
629
+
630
+ /**
631
+ * @deprecated
632
+ */
633
+ static function get_full_path( $src ) {
634
+ return TimberURLHelper::get_full_path( $src );
635
+ }
636
+
637
+ /**
638
+ * @deprecated
639
+ */
640
+ static function get_rel_path( $src ) {
641
+ return TimberURLHelper::get_rel_path( $src );
642
+ }
643
+
644
+ /**
645
+ * @deprecated
646
+ */
647
+ static function remove_double_slashes( $url ) {
648
+ return TimberURLHelper::remove_double_slashes( $url );
649
+ }
650
+
651
+ /**
652
+ * @deprecated
653
+ */
654
+ static function prepend_to_url( $url, $path ) {
655
+ return TimberURLHelper::prepend_to_url( $url, $path );
656
+ }
657
+
658
+ /**
659
+ * @deprecated
660
+ */
661
+ static function preslashit( $path ) {
662
+ return TimberURLHelper::preslashit( $path );
663
+ }
664
+
665
+ /**
666
+ * @deprecated
667
+ */
668
+ static function is_external( $url ) {
669
+ return TimberURLHelper::is_external( $url );
670
+ }
671
+
672
+ /**
673
+ * @deprecated
674
+ */
675
+ static function download_url( $url, $timeout = 300 ) {
676
+ return TimberURLHelper::download_url( $url, $timeout );
677
+ }
678
+
679
+ /**
680
+ * @deprecated
681
+ */
682
+ static function get_params( $i = -1 ) {
683
+ return TimberURLHelper::get_params( $i );
684
+ }
685
 
686
  }
lib/timber-image-helper.php CHANGED
@@ -15,455 +15,497 @@
15
  */
16
  class TimberImageHelper {
17
 
18
- const BASE_UPLOADS = 1;
19
- const BASE_CONTENT = 2;
20
-
21
- public static function init() {
22
- self::add_constants();
23
- self::add_actions();
24
- self::add_filters();
25
- }
26
-
27
- /**
28
- * Generates a new image with the specified dimensions.
29
- * New dimensions are achieved by cropping to maintain ratio.
30
- *
31
- * @param string $src an URL (absolute or relative) to the original image
32
- * @param int $w target width
33
- * @param int $h target heighth
34
- * @param string $crop
35
- * @param bool $force_resize
36
- * @return string (ex: )
37
- */
38
- public static function resize( $src, $w, $h = 0, $crop = 'default', $force = false ) {
39
- $op = new TimberImageOperationResize($w, $h, $crop);
40
- return self::_operate($src, $op, $force);
41
- }
42
-
43
- /**
44
- * Generates a new image with increased size, for display on Retina screens.
45
- *
46
- * @param string $src
47
- * @param float $multiplier
48
- * @param boolean $force
49
- *
50
- * @return string url to the new image
51
- */
52
- public static function retina_resize( $src, $factor = 2, $force = false) {
53
- $op = new TimberImageOperationRetina($factor);
54
- return self::_operate($src, $op, $force);
55
- }
56
-
57
- /**
58
- * Generate a new image with the specified dimensions.
59
- * New dimensions are achieved by adding colored bands to maintain ratio.
60
- *
61
- * @param string $src
62
- * @param int $w
63
- * @param int $h
64
- * @param string $color
65
- * @param bool $force
66
- * @return mixed|null|string
67
- */
68
- public static function letterbox( $src, $w, $h, $color = '#000000', $force = false ) {
69
- $op = new TimberImageOperationLetterbox($w, $h, $color);
70
- return self::_operate($src, $op, $force);
71
- }
72
-
73
- /**
74
- * Generates a new image by converting the source PNG into JPG
75
- *
76
- * @param string $src a url or path to the image (http://example.org/wp-content/uploads/2014/image.jpg) or (/wp-content/uploads/2014/image.jpg)
77
- * @param string $bghex
78
- * @return string
79
- */
80
- public static function img_to_jpg( $src, $bghex = '#FFFFFF', $force = false ) {
81
- $op = new TimberImageOperationPngToJpg($bghex);
82
- return self::_operate($src, $op, $force);
83
- }
84
-
85
- /**
86
- * Deletes all resized versions of an image when the source is deleted
87
- */
88
- static function add_actions() {
89
- add_action( 'delete_post', function ( $post_id ) {
90
- $post = get_post( $post_id );
91
- $image_types = array( 'image/jpeg', 'image/png', 'image/gif', 'image/jpg' );
92
- if ( $post->post_type == 'attachment' && in_array( $post->post_mime_type, $image_types ) ) {
93
- $attachment = new TimberImage( $post_id );
94
- TimberImageHelper::delete_resized_files( $attachment->file_loc );
95
- TimberImageHelper::delete_letterboxed_files( $attachment->file_loc );
96
- }
97
- } );
98
- }
99
-
100
- /**
101
- * Adds a constant defining the path to the content directory relative to the site
102
- * for example /wp-content or /content
103
- */
104
- static function add_constants() {
105
- if ( !defined( 'WP_CONTENT_SUBDIR' ) ) {
106
- $wp_content_path = str_replace( home_url(), '', WP_CONTENT_URL );
107
- define( 'WP_CONTENT_SUBDIR', $wp_content_path );
108
- }
109
- }
110
-
111
- /**
112
- * adds a 'relative' key to wp_upload_dir() result.
113
- * It will contain the relative url to upload dir.
114
- * @return void
115
- */
116
- static function add_filters() {
117
- add_filter( 'upload_dir', function ( $arr ) {
118
- $arr['relative'] = str_replace( home_url(), '', $arr['baseurl'] );
119
- return $arr;
120
- } );
121
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
  //-- end of public methods --//
124
 
125
 
126
 
127
 
128
- /**
129
- * @return boolean true if $path is an external url, false if relative or local.
130
- */
131
- protected static function is_external($path) {
132
- return TimberURLHelper::is_absolute($path) && !strstr($path, home_url());
133
- }
134
-
135
- /**
136
- * Deletes resized versions of the supplied file name.
137
- * So if passed a value like my-pic.jpg, this function will delete my-pic-500x200-c-left.jpg, my-pic-400x400-c-default.jpg, etc.
138
- *
139
- * @param string $local_file ex: /var/www/wp-content/uploads/2015/my-pic.jpg
140
- * ex: http://example.org/wp-content/uploads/2015/foo.png
141
- */
142
- static function delete_resized_files( $local_file ) {
143
- if (TimberURLHelper::is_absolute( $local_file ) ) {
144
- $local_file = TimberURLHelper::url_to_file_system( $local_file );
145
- }
146
- $info = pathinfo( $local_file );
147
- $dir = $info['dirname'];
148
- $ext = $info['extension'];
149
- $filename = $info['filename'];
150
- $searcher = '/' . $filename . '-[0-9999999]*';
151
- foreach ( glob( $dir . $searcher ) as $found_file ) {
152
- $regexdir = str_replace( '/', '\/', $dir );
153
- $pattern = '/' . ( $regexdir ) . '\/' . $filename . '-[0-9]*x[0-9]*-c-[a-z]*.' . $ext . '/';
154
- $match = preg_match( $pattern, $found_file );
155
- //keeping these here so I know what the hell we're matching
156
- //$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);
157
- //$match = preg_match("/\/srv\/www\/wordpress-develop\/src\/wp-content\/uploads\/2014\/05\/arch-[0-9]*x[0-9]*-c-[a-z]*.jpg/", $filename);
158
- if ( $match ) {
159
- unlink( $found_file );
160
- }
161
- }
162
- }
163
-
164
- /**
165
- * Deletes letterboxed versions of the supplied file name
166
- *
167
- * @param string $local_file
168
- */
169
- static function delete_letterboxed_files( $local_file ) {
170
- if (TimberURLHelper::is_absolute( $local_file ) ) {
171
- $local_file = TimberURLHelper::url_to_file_system( $local_file );
172
- }
173
- $info = pathinfo( $local_file );
174
- $dir = $info['dirname'];
175
- $ext = $info['extension'];
176
- $filename = $info['filename'];
177
- $searcher = '/' . $filename . '-lbox-[0-9999999]*';
178
- foreach ( glob( $dir . $searcher ) as $found_file ) {
179
- $regexdir = str_replace( '/', '\/', $dir );
180
- $pattern = '/' . ( $regexdir ) . '\/' . $filename . '-lbox-[0-9]*x[0-9]*-[a-zA-Z0-9]*.' . $ext . '/';
181
- $match = preg_match( $pattern, $found_file );
182
- if ( $match ) {
183
- unlink( $found_file );
184
- }
185
- }
186
- }
187
-
188
-
189
- /**
190
- * Determines the filepath corresponding to a given URL
191
- *
192
- * @param string $url
193
- * @return string
194
- */
195
- public static function get_server_location( $url ) {
196
- // if we're already an absolute dir, just return
197
- if ( 0 === strpos( $url, ABSPATH ) ) {
198
- return $url;
199
- }
200
- // otherwise, analyze URL then build mapping path
201
- $au = self::analyze_url($url);
202
- $result = self::_get_file_path($au['base'], $au['subdir'], $au['basename']);
203
- return $result;
204
- }
205
-
206
- /**
207
- * Determines the filepath where a given external file will be stored.
208
- *
209
- * @param string $file
210
- * @return string
211
- */
212
- public static function get_sideloaded_file_loc( $file ) {
213
- $upload = wp_upload_dir();
214
- $dir = $upload['path'];
215
- $filename = $file;
216
- $file = parse_url( $file );
217
- $path_parts = pathinfo( $file['path'] );
218
- $basename = md5( $filename );
219
- $ext = 'jpg';
220
- if ( isset( $path_parts['extension'] ) ) {
221
- $ext = $path_parts['extension'];
222
- }
223
- return $dir . '/' . $basename . '.' . $ext;
224
- }
225
-
226
- /**
227
- * downloads an external image to the server and stores it on the server
228
- *
229
- * @param string $file the URL to the original file
230
- * @return string the URL to the downloaded file
231
- */
232
- public static function sideload_image( $file ) {
233
- $loc = self::get_sideloaded_file_loc( $file );
234
- if ( file_exists( $loc ) ) {
235
- return TimberURLHelper::preslashit( TimberURLHelper::get_rel_path( $loc ) );
236
- }
237
- // Download file to temp location
238
- if ( !function_exists( 'download_url' ) ) {
239
- require_once ABSPATH . '/wp-admin/includes/file.php';
240
- }
241
- $tmp = download_url( $file );
242
- preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $file, $matches );
243
- $file_array = array();
244
- $file_array['name'] = basename( $matches[0] );
245
- $file_array['tmp_name'] = $tmp;
246
- // If error storing temporarily, unlink
247
- if ( is_wp_error( $tmp ) ) {
248
- @unlink( $file_array['tmp_name'] );
249
- $file_array['tmp_name'] = '';
250
- }
251
- // do the validation and storage stuff
252
- $locinfo = pathinfo( $loc );
253
- $file = wp_upload_bits( $locinfo['basename'], null, file_get_contents( $file_array['tmp_name'] ) );
254
- return $file['url'];
255
- }
256
-
257
- /**
258
- * Takes in an URL and breaks it into components,
259
- * that will then be used in the different steps of image processing.
260
- * The image is expected to be either part of a theme, plugin, or an upload.
261
- *
262
- * @param string $url an URL (absolute or relative) pointing to an image
263
- * @return array an array (see keys in code below)
264
- */
265
- private static function analyze_url($url) {
266
- $result = array(
267
- 'url' => $url, // the initial url
268
- 'absolute' => TimberURLHelper::is_absolute($url), // is the url absolute or relative (to home_url)
269
- 'base' => 0, // is the image in uploads dir, or in content dir (theme or plugin)
270
- 'subdir' => '', // the path between base (uploads or content) and file
271
- 'filename' => '', // the filename, without extension
272
- 'extension' => '', // the file extension
273
- 'basename' => '', // full file name
274
- );
275
- $upload_dir = wp_upload_dir();
276
- $tmp = $url;
277
- if ( 0 === strpos($tmp, ABSPATH) ) { // we've been given a dir, not an url
278
- $result['absolute'] = true;
279
- if ( 0 === strpos($tmp, $upload_dir['basedir']) ) {
280
- $result['base']= self::BASE_UPLOADS; // upload based
281
- $tmp = str_replace($upload_dir['basedir'], '', $tmp);
282
- }
283
- if ( 0 === strpos($tmp, WP_CONTENT_DIR) ) {
284
- $result['base']= self::BASE_CONTENT; // content based
285
- $tmp = str_replace(WP_CONTENT_DIR, '', $tmp);
286
- }
287
- } else {
288
- if (!$result['absolute']) {
289
- $tmp = home_url().$tmp;
290
- }
291
- if (0 === strpos($tmp, $upload_dir['baseurl'])) {
292
- $result['base']= self::BASE_UPLOADS; // upload based
293
- $tmp = str_replace($upload_dir['baseurl'], '', $tmp);
294
- }
295
- if (0 === strpos($tmp, content_url())) {
296
- $result['base']= self::BASE_CONTENT; // content-based
297
- $tmp = str_replace(content_url(), '', $tmp);
298
- }
299
- }
300
- $parts = pathinfo($tmp);
301
- $result['subdir'] = $parts['dirname'];
302
- $result['filename'] = $parts['filename'];
303
- $result['extension'] = $parts['extension'];
304
- $result['basename'] = $parts['basename'];
305
- // todo filename
306
- return $result;
307
- }
308
-
309
- /**
310
- * Builds the public URL of a file based on its different components
311
- *
312
- * @param int $base one of self::BASE_UPLOADS, self::BASE_CONTENT to indicate if file is an upload or a content (theme or plugin)
313
- * @param string $subdir subdirectory in which file is stored, relative to $base root folder
314
- * @param string $filename file name, including extension (but no path)
315
- * @param bool $absolute should the returned URL be absolute (include protocol+host), or relative
316
- * @return string the URL
317
- */
318
- private static function _get_file_url($base, $subdir, $filename, $absolute) {
319
- $url = '';
320
- if( self::BASE_UPLOADS == $base ) {
321
- $upload_dir = wp_upload_dir();
322
- $url = $upload_dir['baseurl'];
323
- }
324
- if( self::BASE_CONTENT == $base ) {
325
- $url = content_url();
326
- }
327
- if(!empty($subdir)) {
328
- $url .= $subdir;
329
- }
330
- $url .= '/'.$filename;
331
- if(!$absolute) {
332
- $url = str_replace(home_url(), '', $url);
333
- }
334
- // $url = TimberURLHelper::remove_double_slashes( $url);
335
- return $url;
336
- }
337
-
338
- /**
339
- * Builds the absolute file system location of a file based on its different components
340
- *
341
- * @param int $base one of self::BASE_UPLOADS, self::BASE_CONTENT to indicate if file is an upload or a content (theme or plugin)
342
- * @param string $subdir subdirectory in which file is stored, relative to $base root folder
343
- * @param string $filename file name, including extension (but no path)
344
- * @return string the file location
345
- */
346
- private static function _get_file_path($base, $subdir, $filename) {
347
- $path = '';
348
- if(self::BASE_UPLOADS == $base) {
349
- $upload_dir = wp_upload_dir();
350
- $path = $upload_dir['basedir'];
351
- }
352
- if(self::BASE_CONTENT == $base) {
353
- $path = WP_CONTENT_DIR;
354
- }
355
- if(!empty($subdir)) {
356
- $path .= $subdir;
357
- }
358
- $path .= '/'.$filename;
359
- return $path;
360
- }
361
-
362
-
363
- /**
364
- * Main method that applies operation to src image:
365
- * 1. break down supplied URL into components
366
- * 2. use components to determine result file and URL
367
- * 3. check if a result file already exists
368
- * 4. otherwise, delegate to supplied TimberImageOperation
369
- *
370
- * @param string $src an URL (absolute or relative) to an image
371
- * @param object $op object of class TimberImageOperation
372
- * @param boolean $force if true, remove any already existing result file and forces file generation
373
- * @return string URL to the new image - or the source one if error
374
- *
375
- */
376
- private static function _operate( $src, $op, $force = false ) {
377
- if ( empty( $src ) ) {
378
- return '';
379
- }
380
- // if external image, load it first
381
- if ( self::is_external( $src ) ) {
382
- $src = self::sideload_image( $src );
383
- }
384
- // break down URL into components
385
- $au = self::analyze_url($src);
386
- // build URL and filenames
387
- $new_url = self::_get_file_url(
388
- $au['base'],
389
- $au['subdir'],
390
- $op->filename($au['filename'], $au['extension']),
391
- $au['absolute']
392
- );
393
- $new_server_path = self::_get_file_path(
394
- $au['base'],
395
- $au['subdir'],
396
- $op->filename($au['filename'], $au['extension'])
397
- );
398
- $old_server_path = self::_get_file_path(
399
- $au['base'],
400
- $au['subdir'],
401
- $au['basename']
402
- );
403
- // if already exists...
404
- if ( file_exists( $new_server_path ) ) {
405
- if ( $force ) {
406
- // Force operation - warning: will regenerate the image on every pageload, use for testing purposes only!
407
- unlink( $new_server_path );
408
- } else {
409
- // return existing file (caching)
410
- return $new_url;
411
- }
412
- }
413
- // otherwise generate result file
414
- if($op->run($old_server_path, $new_server_path)) {
415
- return $new_url;
416
- } else {
417
- // in case of error, we return source file itself
418
- return $src;
419
- }
420
- }
 
 
 
 
421
 
422
 
423
  // -- the below methods are just used for unit testing the URL generation code
424
  //
425
- static function get_letterbox_file_url($url, $w, $h, $color) {
426
- $au = self::analyze_url($url);
427
- $op = new TimberImageOperationLetterbox($w, $h, $color);
428
- $new_url = self::_get_file_url(
429
- $au['base'],
430
- $au['subdir'],
431
- $op->filename($au['filename'], $au['extension']),
432
- $au['absolute']
433
- );
434
- return $new_url;
435
- }
436
- public static function get_letterbox_file_path($url, $w, $h, $color ) {
437
- $au = self::analyze_url($url);
438
- $op = new TimberImageOperationLetterbox($w, $h, $color);
439
- $new_path = self::_get_file_path(
440
- $au['base'],
441
- $au['subdir'],
442
- $op->filename($au['filename'], $au['extension'])
443
- );
444
- return $new_path;
445
- }
446
- static function get_resize_file_url($url, $w, $h, $crop) {
447
- $au = self::analyze_url($url);
448
- $op = new TimberImageOperationResize($w, $h, $crop);
449
- $new_url = self::_get_file_url(
450
- $au['base'],
451
- $au['subdir'],
452
- $op->filename($au['filename'], $au['extension']),
453
- $au['absolute']
454
- );
455
- return $new_url;
456
- }
457
- static function get_resize_file_path($url, $w, $h, $crop) {
458
- $au = self::analyze_url($url);
459
- $op = new TimberImageOperationResize($w, $h, $crop);
460
- $new_path = self::_get_file_path(
461
- $au['base'],
462
- $au['subdir'],
463
- $op->filename($au['filename'], $au['extension'])
464
- );
465
- return $new_path;
466
- }
467
 
468
 
469
  }
15
  */
16
  class TimberImageHelper {
17
 
18
+ const BASE_UPLOADS = 1;
19
+ const BASE_CONTENT = 2;
20
+
21
+ public static function init() {
22
+ self::add_constants();
23
+ self::add_actions();
24
+ self::add_filters();
25
+ }
26
+
27
+ /**
28
+ * Generates a new image with the specified dimensions.
29
+ * New dimensions are achieved by cropping to maintain ratio.
30
+ *
31
+ * @param string $src an URL (absolute or relative) to the original image
32
+ * @param int|string $w target width(int) or WordPress image size (WP-set or user-defined)
33
+ * @param int $h target height (ignored if $w is WP image size)
34
+ * @param string $crop
35
+ * @param bool $force_resize
36
+ * @return string (ex: )
37
+ */
38
+ public static function resize( $src, $w, $h = 0, $crop = 'default', $force = false ) {
39
+ if (!is_numeric($w) && is_string($w)) {
40
+ if ($sizes = self::find_wp_dimensions($w)) {
41
+ $w = $sizes['w'];
42
+ $h = $sizes['h'];
43
+ } else {
44
+ return $src;
45
+ }
46
+ }
47
+ $op = new TimberImageOperationResize($w, $h, $crop);
48
+ return self::_operate($src, $op, $force);
49
+ }
50
+
51
+ /**
52
+ * Find the sizes of an image based on a defined image size
53
+ * @param string $size the image size to search for
54
+ * can be WordPress-defined ("medium")
55
+ * or user-defined ("my-awesome-size")
56
+ * @return array {
57
+ * @type int w
58
+ * @type int h
59
+ * }
60
+ */
61
+ private static function find_wp_dimensions($size) {
62
+
63
+ // if ( in_array( $_size, array( 'thumbnail', 'medium', 'large' ) ) ) {
64
+
65
+ // $sizes[ $_size ]['width'] = get_option( $_size . '_size_w' );
66
+ // $sizes[ $_size ]['height'] = get_option( $_size . '_size_h' );
67
+ global $_wp_additional_image_sizes;
68
+ if (isset($_wp_additional_image_sizes[$size])) {
69
+ $w = $_wp_additional_image_sizes[$size]['width'];
70
+ $h = $_wp_additional_image_sizes[$size]['height'];
71
+ } else if (in_array($size, array('thumbnail', 'medium', 'large'))) {
72
+ $w = get_option($size.'_size_w');
73
+ $h = get_option($size.'_size_h');
74
+ }
75
+ if (isset($w) && isset($h) && ($w || $h)) {
76
+ return array('w' => $w, 'h' => $h);
77
+ }
78
+ return false;
79
+ }
80
+
81
+ /**
82
+ * Generates a new image with increased size, for display on Retina screens.
83
+ *
84
+ * @param string $src
85
+ * @param float $multiplier
86
+ * @param boolean $force
87
+ *
88
+ * @return string url to the new image
89
+ */
90
+ public static function retina_resize( $src, $factor = 2, $force = false) {
91
+ $op = new TimberImageOperationRetina($factor);
92
+ return self::_operate($src, $op, $force);
93
+ }
94
+
95
+ /**
96
+ * Generate a new image with the specified dimensions.
97
+ * New dimensions are achieved by adding colored bands to maintain ratio.
98
+ *
99
+ * @param string $src
100
+ * @param int $w
101
+ * @param int $h
102
+ * @param string $color
103
+ * @param bool $force
104
+ * @return mixed|null|string
105
+ */
106
+ public static function letterbox( $src, $w, $h, $color = '#000000', $force = false ) {
107
+ $op = new TimberImageOperationLetterbox($w, $h, $color);
108
+ return self::_operate($src, $op, $force);
109
+ }
110
+
111
+ /**
112
+ * Generates a new image by converting the source GIF or PNG into JPG
113
+ *
114
+ * @param string $src a url or path to the image (http://example.org/wp-content/uploads/2014/image.jpg) or (/wp-content/uploads/2014/image.jpg)
115
+ * @param string $bghex
116
+ * @return string
117
+ */
118
+ public static function img_to_jpg( $src, $bghex = '#FFFFFF', $force = false ) {
119
+ $op = new TimberImageOperationToJpg($bghex);
120
+ return self::_operate($src, $op, $force);
121
+ }
122
+
123
+ /**
124
+ * Deletes all resized versions of an image when the source is deleted
125
+ */
126
+ static function add_actions() {
127
+ add_action( 'delete_post', function ( $post_id ) {
128
+ $post = get_post( $post_id );
129
+ $image_types = array( 'image/jpeg', 'image/png', 'image/gif', 'image/jpg' );
130
+ if ( $post->post_type == 'attachment' && in_array( $post->post_mime_type, $image_types ) ) {
131
+ $attachment = new TimberImage( $post_id );
132
+ TimberImageHelper::delete_resized_files( $attachment->file_loc );
133
+ TimberImageHelper::delete_letterboxed_files( $attachment->file_loc );
134
+ }
135
+ } );
136
+ }
137
+
138
+ /**
139
+ * Adds a constant defining the path to the content directory relative to the site
140
+ * for example /wp-content or /content
141
+ */
142
+ static function add_constants() {
143
+ if ( !defined( 'WP_CONTENT_SUBDIR' ) ) {
144
+ $wp_content_path = str_replace( home_url(), '', WP_CONTENT_URL );
145
+ define( 'WP_CONTENT_SUBDIR', $wp_content_path );
146
+ }
147
+ }
148
+
149
+ /**
150
+ * adds a 'relative' key to wp_upload_dir() result.
151
+ * It will contain the relative url to upload dir.
152
+ * @return void
153
+ */
154
+ static function add_filters() {
155
+ add_filter( 'upload_dir', function ( $arr ) {
156
+ $arr['relative'] = str_replace( home_url(), '', $arr['baseurl'] );
157
+ return $arr;
158
+ } );
159
+ }
160
 
161
  //-- end of public methods --//
162
 
163
 
164
 
165
 
166
+ /**
167
+ * @return boolean true if $path is an external url, false if relative or local.
168
+ */
169
+ protected static function is_external($path) {
170
+ $is_external = TimberURLHelper::is_absolute($path) && !strstr($path, site_url());
171
+ if ($is_external) {
172
+ $is_external = TimberURLHelper::is_absolute($path) && !strstr($path, home_url());
173
+ }
174
+ return $is_external;
175
+ }
176
+
177
+ /**
178
+ * Deletes resized versions of the supplied file name.
179
+ * So if passed a value like my-pic.jpg, this function will delete my-pic-500x200-c-left.jpg, my-pic-400x400-c-default.jpg, etc.
180
+ *
181
+ * @param string $local_file ex: /var/www/wp-content/uploads/2015/my-pic.jpg
182
+ * ex: http://example.org/wp-content/uploads/2015/foo.png
183
+ */
184
+ static function delete_resized_files( $local_file ) {
185
+ if (TimberURLHelper::is_absolute( $local_file ) ) {
186
+ $local_file = TimberURLHelper::url_to_file_system( $local_file );
187
+ }
188
+ $info = pathinfo( $local_file );
189
+ $dir = $info['dirname'];
190
+ $ext = $info['extension'];
191
+ $filename = $info['filename'];
192
+ $searcher = '/' . $filename . '-[0-9999999]*';
193
+ foreach ( glob( $dir . $searcher ) as $found_file ) {
194
+ $regexdir = str_replace( '/', '\/', $dir );
195
+ $pattern = '/' . ( $regexdir ) . '\/' . $filename . '-[0-9]*x[0-9]*-c-[a-z]*.' . $ext . '/';
196
+ $match = preg_match( $pattern, $found_file );
197
+ //keeping these here so I know what the hell we're matching
198
+ //$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);
199
+ //$match = preg_match("/\/srv\/www\/wordpress-develop\/src\/wp-content\/uploads\/2014\/05\/arch-[0-9]*x[0-9]*-c-[a-z]*.jpg/", $filename);
200
+ if ( $match ) {
201
+ unlink( $found_file );
202
+ }
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Deletes letterboxed versions of the supplied file name
208
+ *
209
+ * @param string $local_file
210
+ */
211
+ static function delete_letterboxed_files( $local_file ) {
212
+ if (TimberURLHelper::is_absolute( $local_file ) ) {
213
+ $local_file = TimberURLHelper::url_to_file_system( $local_file );
214
+ }
215
+ $info = pathinfo( $local_file );
216
+ $dir = $info['dirname'];
217
+ $ext = $info['extension'];
218
+ $filename = $info['filename'];
219
+ $searcher = '/' . $filename . '-lbox-[0-9999999]*';
220
+ foreach ( glob( $dir . $searcher ) as $found_file ) {
221
+ $regexdir = str_replace( '/', '\/', $dir );
222
+ $pattern = '/' . ( $regexdir ) . '\/' . $filename . '-lbox-[0-9]*x[0-9]*-[a-zA-Z0-9]*.' . $ext . '/';
223
+ $match = preg_match( $pattern, $found_file );
224
+ if ( $match ) {
225
+ unlink( $found_file );
226
+ }
227
+ }
228
+ }
229
+
230
+
231
+ /**
232
+ * Determines the filepath corresponding to a given URL
233
+ *
234
+ * @param string $url
235
+ * @return string
236
+ */
237
+ public static function get_server_location( $url ) {
238
+ // if we're already an absolute dir, just return
239
+ if ( 0 === strpos( $url, ABSPATH ) ) {
240
+ return $url;
241
+ }
242
+ // otherwise, analyze URL then build mapping path
243
+ $au = self::analyze_url($url);
244
+ $result = self::_get_file_path($au['base'], $au['subdir'], $au['basename']);
245
+ return $result;
246
+ }
247
+
248
+ /**
249
+ * Determines the filepath where a given external file will be stored.
250
+ *
251
+ * @param string $file
252
+ * @return string
253
+ */
254
+ public static function get_sideloaded_file_loc( $file ) {
255
+ $upload = wp_upload_dir();
256
+ $dir = $upload['path'];
257
+ $filename = $file;
258
+ $file = parse_url( $file );
259
+ $path_parts = pathinfo( $file['path'] );
260
+ $basename = md5( $filename );
261
+ $ext = 'jpg';
262
+ if ( isset( $path_parts['extension'] ) ) {
263
+ $ext = $path_parts['extension'];
264
+ }
265
+ return $dir . '/' . $basename . '.' . $ext;
266
+ }
267
+
268
+ /**
269
+ * downloads an external image to the server and stores it on the server
270
+ *
271
+ * @param string $file the URL to the original file
272
+ * @return string the URL to the downloaded file
273
+ */
274
+ public static function sideload_image( $file ) {
275
+ $loc = self::get_sideloaded_file_loc( $file );
276
+ if ( file_exists( $loc ) ) {
277
+ return TimberURLHelper::preslashit( TimberURLHelper::get_rel_path( $loc ) );
278
+ }
279
+ // Download file to temp location
280
+ if ( !function_exists( 'download_url' ) ) {
281
+ require_once ABSPATH . '/wp-admin/includes/file.php';
282
+ }
283
+ $tmp = download_url( $file );
284
+ preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $file, $matches );
285
+ $file_array = array();
286
+ $file_array['name'] = basename( $matches[0] );
287
+ $file_array['tmp_name'] = $tmp;
288
+ // If error storing temporarily, unlink
289
+ if ( is_wp_error( $tmp ) ) {
290
+ @unlink( $file_array['tmp_name'] );
291
+ $file_array['tmp_name'] = '';
292
+ }
293
+ // do the validation and storage stuff
294
+ $locinfo = pathinfo( $loc );
295
+ $file = wp_upload_bits( $locinfo['basename'], null, file_get_contents( $file_array['tmp_name'] ) );
296
+ return $file['url'];
297
+ }
298
+
299
+ /**
300
+ * Takes in an URL and breaks it into components,
301
+ * that will then be used in the different steps of image processing.
302
+ * The image is expected to be either part of a theme, plugin, or an upload.
303
+ *
304
+ * @param string $url an URL (absolute or relative) pointing to an image
305
+ * @return array an array (see keys in code below)
306
+ */
307
+ private static function analyze_url($url) {
308
+ $result = array(
309
+ 'url' => $url, // the initial url
310
+ 'absolute' => TimberURLHelper::is_absolute($url), // is the url absolute or relative (to home_url)
311
+ 'base' => 0, // is the image in uploads dir, or in content dir (theme or plugin)
312
+ 'subdir' => '', // the path between base (uploads or content) and file
313
+ 'filename' => '', // the filename, without extension
314
+ 'extension' => '', // the file extension
315
+ 'basename' => '', // full file name
316
+ );
317
+ $upload_dir = wp_upload_dir();
318
+ $tmp = $url;
319
+ if ( 0 === strpos($tmp, ABSPATH) ) { // we've been given a dir, not an url
320
+ $result['absolute'] = true;
321
+ if ( 0 === strpos($tmp, $upload_dir['basedir']) ) {
322
+ $result['base']= self::BASE_UPLOADS; // upload based
323
+ $tmp = str_replace($upload_dir['basedir'], '', $tmp);
324
+ }
325
+ if ( 0 === strpos($tmp, WP_CONTENT_DIR) ) {
326
+ $result['base']= self::BASE_CONTENT; // content based
327
+ $tmp = str_replace(WP_CONTENT_DIR, '', $tmp);
328
+ }
329
+ } else {
330
+ if (!$result['absolute']) {
331
+ $tmp = home_url().$tmp;
332
+ }
333
+ if (0 === strpos($tmp, $upload_dir['baseurl'])) {
334
+ $result['base']= self::BASE_UPLOADS; // upload based
335
+ $tmp = str_replace($upload_dir['baseurl'], '', $tmp);
336
+ }
337
+ if (0 === strpos($tmp, content_url())) {
338
+ $result['base']= self::BASE_CONTENT; // content-based
339
+ $tmp = str_replace(content_url(), '', $tmp);
340
+ }
341
+ }
342
+ $parts = pathinfo($tmp);
343
+ $result['subdir'] = $parts['dirname'];
344
+ $result['filename'] = $parts['filename'];
345
+ $result['extension'] = $parts['extension'];
346
+ $result['basename'] = $parts['basename'];
347
+ // todo filename
348
+ return $result;
349
+ }
350
+
351
+ /**
352
+ * Builds the public URL of a file based on its different components
353
+ *
354
+ * @param int $base one of self::BASE_UPLOADS, self::BASE_CONTENT to indicate if file is an upload or a content (theme or plugin)
355
+ * @param string $subdir subdirectory in which file is stored, relative to $base root folder
356
+ * @param string $filename file name, including extension (but no path)
357
+ * @param bool $absolute should the returned URL be absolute (include protocol+host), or relative
358
+ * @return string the URL
359
+ */
360
+ private static function _get_file_url($base, $subdir, $filename, $absolute) {
361
+ $url = '';
362
+ if( self::BASE_UPLOADS == $base ) {
363
+ $upload_dir = wp_upload_dir();
364
+ $url = $upload_dir['baseurl'];
365
+ }
366
+ if( self::BASE_CONTENT == $base ) {
367
+ $url = content_url();
368
+ }
369
+ if(!empty($subdir)) {
370
+ $url .= $subdir;
371
+ }
372
+ $url .= '/'.$filename;
373
+ if(!$absolute) {
374
+ $url = str_replace(home_url(), '', $url);
375
+ }
376
+ // $url = TimberURLHelper::remove_double_slashes( $url);
377
+ return $url;
378
+ }
379
+
380
+ /**
381
+ * Builds the absolute file system location of a file based on its different components
382
+ *
383
+ * @param int $base one of self::BASE_UPLOADS, self::BASE_CONTENT to indicate if file is an upload or a content (theme or plugin)
384
+ * @param string $subdir subdirectory in which file is stored, relative to $base root folder
385
+ * @param string $filename file name, including extension (but no path)
386
+ * @return string the file location
387
+ */
388
+ private static function _get_file_path($base, $subdir, $filename) {
389
+ $path = '';
390
+ if(self::BASE_UPLOADS == $base) {
391
+ $upload_dir = wp_upload_dir();
392
+ $path = $upload_dir['basedir'];
393
+ }
394
+ if(self::BASE_CONTENT == $base) {
395
+ $path = WP_CONTENT_DIR;
396
+ }
397
+ if(!empty($subdir)) {
398
+ $path .= $subdir;
399
+ }
400
+ $path .= '/'.$filename;
401
+ return $path;
402
+ }
403
+
404
+
405
+ /**
406
+ * Main method that applies operation to src image:
407
+ * 1. break down supplied URL into components
408
+ * 2. use components to determine result file and URL
409
+ * 3. check if a result file already exists
410
+ * 4. otherwise, delegate to supplied TimberImageOperation
411
+ *
412
+ * @param string $src an URL (absolute or relative) to an image
413
+ * @param object $op object of class TimberImageOperation
414
+ * @param boolean $force if true, remove any already existing result file and forces file generation
415
+ * @return string URL to the new image - or the source one if error
416
+ *
417
+ */
418
+ private static function _operate( $src, $op, $force = false ) {
419
+ if ( empty( $src ) ) {
420
+ return '';
421
+ }
422
+ // if external image, load it first
423
+ if ( self::is_external( $src ) ) {
424
+ $src = self::sideload_image( $src );
425
+ }
426
+ // break down URL into components
427
+ $au = self::analyze_url($src);
428
+ // build URL and filenames
429
+ $new_url = self::_get_file_url(
430
+ $au['base'],
431
+ $au['subdir'],
432
+ $op->filename($au['filename'], $au['extension']),
433
+ $au['absolute']
434
+ );
435
+ $new_server_path = self::_get_file_path(
436
+ $au['base'],
437
+ $au['subdir'],
438
+ $op->filename($au['filename'], $au['extension'])
439
+ );
440
+ $old_server_path = self::_get_file_path(
441
+ $au['base'],
442
+ $au['subdir'],
443
+ $au['basename']
444
+ );
445
+ // if already exists...
446
+ if ( file_exists( $new_server_path ) ) {
447
+ if ( $force ) {
448
+ // Force operation - warning: will regenerate the image on every pageload, use for testing purposes only!
449
+ unlink( $new_server_path );
450
+ } else {
451
+ // return existing file (caching)
452
+ return $new_url;
453
+ }
454
+ }
455
+ // otherwise generate result file
456
+ if($op->run($old_server_path, $new_server_path)) {
457
+ return $new_url;
458
+ } else {
459
+ // in case of error, we return source file itself
460
+ return $src;
461
+ }
462
+ }
463
 
464
 
465
  // -- the below methods are just used for unit testing the URL generation code
466
  //
467
+ static function get_letterbox_file_url($url, $w, $h, $color) {
468
+ $au = self::analyze_url($url);
469
+ $op = new TimberImageOperationLetterbox($w, $h, $color);
470
+ $new_url = self::_get_file_url(
471
+ $au['base'],
472
+ $au['subdir'],
473
+ $op->filename($au['filename'], $au['extension']),
474
+ $au['absolute']
475
+ );
476
+ return $new_url;
477
+ }
478
+ public static function get_letterbox_file_path($url, $w, $h, $color ) {
479
+ $au = self::analyze_url($url);
480
+ $op = new TimberImageOperationLetterbox($w, $h, $color);
481
+ $new_path = self::_get_file_path(
482
+ $au['base'],
483
+ $au['subdir'],
484
+ $op->filename($au['filename'], $au['extension'])
485
+ );
486
+ return $new_path;
487
+ }
488
+ static function get_resize_file_url($url, $w, $h, $crop) {
489
+ $au = self::analyze_url($url);
490
+ $op = new TimberImageOperationResize($w, $h, $crop);
491
+ $new_url = self::_get_file_url(
492
+ $au['base'],
493
+ $au['subdir'],
494
+ $op->filename($au['filename'], $au['extension']),
495
+ $au['absolute']
496
+ );
497
+ return $new_url;
498
+ }
499
+ static function get_resize_file_path($url, $w, $h, $crop) {
500
+ $au = self::analyze_url($url);
501
+ $op = new TimberImageOperationResize($w, $h, $crop);
502
+ $new_path = self::_get_file_path(
503
+ $au['base'],
504
+ $au['subdir'],
505
+ $op->filename($au['filename'], $au['extension'])
506
+ );
507
+ return $new_path;
508
+ }
509
 
510
 
511
  }
lib/timber-image.php CHANGED
@@ -2,312 +2,319 @@
2
 
3
  class TimberImage extends TimberPost implements TimberCoreInterface {
4
 
5
- public $_can_edit;
6
- public $_dimensions;
7
- public $abs_url;
8
- public $PostClass = 'TimberPost';
9
- public $object_type = 'image';
10
-
11
- public static $representation = 'image';
12
-
13
- public $file_loc;
14
- public $file;
15
- public $sizes = array();
16
- public $post_parent;
17
- public $caption;
18
- public $_wp_attached_file;
19
-
20
- /**
21
- * @param int $iid
22
- */
23
- function __construct($iid) {
24
- $this->init($iid);
25
- }
26
-
27
- /**
28
- * @return string
29
- */
30
- function __toString() {
31
- if ($this->get_src()) {
32
- return $this->get_src();
33
- }
34
- return '';
35
- }
36
-
37
- /**
38
- * @return mixed
39
- */
40
- function get_pathinfo() {
41
- return pathinfo($this->file);
42
- }
43
-
44
- /**
45
- * @param string $dim
46
- * @return array|int
47
- */
48
- function get_dimensions($dim = null) {
49
- if (isset($this->_dimensions)) {
50
- return $this->get_dimensions_loaded($dim);
51
- }
52
- list($width, $height) = getimagesize($this->file_loc);
53
- $this->_dimensions = array();
54
- $this->_dimensions[0] = $width;
55
- $this->_dimensions[1] = $height;
56
- return $this->get_dimensions_loaded($dim);
57
- }
58
-
59
- /**
60
- * @param string $dim
61
- * @return array|int
62
- */
63
- function get_dimensions_loaded($dim) {
64
- if ($dim == null) {
65
- return $this->_dimensions;
66
- }
67
- if ($dim == 'w' || $dim == 'width') {
68
- return $this->_dimensions[0];
69
- }
70
- if ($dim == 'h' || $dim == 'height') {
71
- return $this->_dimensions[1];
72
- }
73
- return null;
74
- }
75
-
76
- /**
77
- * @return int
78
- */
79
- function get_width() {
80
- return $this->get_dimensions('width');
81
- }
82
-
83
- /**
84
- * @return int
85
- */
86
- function get_height() {
87
- return $this->get_dimensions('height');
88
- }
89
-
90
- /**
91
- * @param string $size
92
- * @return bool|string
93
- */
94
- function get_src($size = '') {
95
- if (isset($this->abs_url)) {
96
- return $this->_maybe_secure_url($this->abs_url);
97
- }
98
-
99
- if ($size && is_string($size) && isset($this->sizes[$size])) {
100
- $image = image_downsize($this->ID, $size);
101
- return $this->_maybe_secure_url(reset($image));
102
- }
103
-
104
- if (!isset($this->file) && isset($this->_wp_attached_file)) {
105
- $this->file = $this->_wp_attached_file;
106
- }
107
-
108
- if (!isset($this->file)) {
109
- return false;
110
- }
111
-
112
- $dir = self::wp_upload_dir();
113
- $base = ($dir["baseurl"]);
114
-
115
- $src = trailingslashit($this->_maybe_secure_url($base)) . $this->file;
116
- return apply_filters('timber_image_src', $src);
117
- }
118
-
119
- private static function _maybe_secure_url($url) {
120
- if (is_ssl() && strpos($url, 'https') !== 0 && strpos($url, 'http') === 0) {
121
- $url = 'https' . substr($url, strlen('http'));
122
- }
123
-
124
- return $url;
125
- }
126
-
127
- public static function wp_upload_dir() {
128
- static $wp_upload_dir = false;
129
-
130
- if (!$wp_upload_dir) {
131
- $wp_upload_dir = wp_upload_dir();
132
- }
133
-
134
- return $wp_upload_dir;
135
- }
136
-
137
- /**
138
- * @return string
139
- */
140
- function get_path() {
141
- if (strlen($this->abs_url)) {
142
- return $this->abs_url;
143
- }
144
- return get_permalink($this->ID);
145
- }
146
-
147
- /**
148
- * @return bool|TimberImage
149
- */
150
- function get_parent() {
151
- if (!$this->post_parent) {
152
- return false;
153
- }
154
- return new $this->PostClass($this->post_parent);
155
- }
156
-
157
- function get_alt() {
158
- $alt = trim(strip_tags(get_post_meta($this->ID, '_wp_attachment_image_alt', true)));
159
- return $alt;
160
- }
161
-
162
-
163
- /**
164
- * @param int $iid
165
- */
166
- function init( $iid = false ) {
167
- if ( !is_numeric( $iid ) && is_string( $iid ) ) {
168
- if (strstr($iid, '://')) {
169
- $this->init_with_url($iid);
170
- return;
171
- }
172
- if ( strstr($iid, ABSPATH) ) {
173
- $this->init_with_file_path($iid);
174
- return;
175
- }
176
- if (strstr(strtolower($iid), '.jpg')) {
177
- $this->init_with_relative_path($iid);
178
- return;
179
- }
180
- }
181
-
182
- $image_info = $this->get_image_info($iid);
183
-
184
- $this->import($image_info);
185
- $basedir = self::wp_upload_dir();
186
- $basedir = $basedir['basedir'];
187
- if (isset($this->file)) {
188
- $this->file_loc = $basedir . DIRECTORY_SEPARATOR . $this->file;
189
- } else if (isset($this->_wp_attached_file)) {
190
- $this->file = reset($this->_wp_attached_file);
191
- $this->file_loc = $basedir . DIRECTORY_SEPARATOR . $this->file;
192
- } else if ( isset( $this->guid ) ) {
193
- if ( TimberURLHelper::is_absolute( $this->guid ) ) {
194
- $this->file_loc = TimberURLHelper::url_to_file_system( $this->guid );
195
- }
196
- }
197
- if (isset($image_info['id'])) {
198
- $this->ID = $image_info['id'];
199
- } else if (is_numeric($iid)) {
200
- $this->ID = $iid;
201
- }
202
- if (isset($this->ID)) {
203
- $custom = get_post_custom($this->ID);
204
- foreach ($custom as $key => $value) {
205
- $this->$key = $value[0];
206
- }
207
- } else {
208
- if (is_array($iid)) {
209
- TimberHelper::error_log('Not able to init in TimberImage with iid=');
210
- TimberHelper::error_log($iid);
211
- } else {
212
- TimberHelper::error_log('Not able to init in TimberImage with iid=' . $iid);
213
- }
214
- }
215
- }
216
-
217
- private function get_image_info( $iid ) {
218
- $image_info = $iid;
219
- if (is_numeric($iid)) {
220
- $image_info = wp_get_attachment_metadata($iid);
221
- if (!is_array($image_info)) {
222
- $image_info = array();
223
- }
224
- $image_custom = get_post_custom($iid);
225
- $basic = get_post($iid);
226
- if ($basic) {
227
- if (isset($basic->post_excerpt)) {
228
- $this->caption = $basic->post_excerpt;
229
- }
230
- $image_custom = array_merge($image_custom, get_object_vars($basic));
231
- }
232
- return array_merge($image_info, $image_custom);
233
- }
234
- if (is_array($image_info) && isset($image_info['image'])) {
235
- return $image_info['image'];
236
- }
237
- if (is_object($image_info)) {
238
- return get_object_vars($image_info);
239
- }
240
- return $iid;
241
- }
242
-
243
- private function init_with_relative_path( $relative_path ) {
244
- $this->abs_url = home_url( $relative_path );
245
- $file_path = TimberURLHelper::get_full_path( $relative_path );
246
- $this->file_loc = $file_path;
247
- $this->file = $file_path;
248
- }
249
-
250
- private function init_with_file_path( $file_path ) {
251
- $url = TimberURLHelper::file_system_to_url( $file_path );
252
- $this->abs_url = $url;
253
- $this->file_loc = $file_path;
254
- $this->file = $file_path;
255
- }
256
-
257
- /**
258
- * @param string $url
259
- */
260
- private function init_with_url($url) {
261
- $this->abs_url = $url;
262
- if (TimberURLHelper::is_local($url)) {
263
- $this->file = ABSPATH . TimberURLHelper::get_rel_url($url);
264
- $this->file_loc = ABSPATH . TimberURLHelper::get_rel_url($url);
265
- }
266
- }
267
-
268
- /**
269
- * @deprecated
270
- * @return string
271
- */
272
- function get_url() {
273
- return $this->get_src();
274
- }
275
-
276
- /* Alias */
277
-
278
- /**
279
- * @return float
280
- */
281
- public function aspect() {
282
- $w = intval($this->width());
283
- $h = intval($this->height());
284
- return $w / $h;
285
- }
286
-
287
- /**
288
- * @return int
289
- */
290
- public function height() {
291
- return $this->get_height();
292
- }
293
-
294
- /**
295
- * @param string $size
296
- * @return bool|string
297
- */
298
- public function src($size = '') {
299
- return $this->get_src($size);
300
- }
301
-
302
- /**
303
- * @return int
304
- */
305
- public function width() {
306
- return $this->get_width();
307
- }
308
-
309
- public function alt() {
310
- return $this->get_alt();
311
- }
 
 
 
 
 
 
 
312
 
313
  }
2
 
3
  class TimberImage extends TimberPost implements TimberCoreInterface {
4
 
5
+ public $_can_edit;
6
+ public $_dimensions;
7
+ public $abs_url;
8
+ public $PostClass = 'TimberPost';
9
+ public $object_type = 'image';
10
+
11
+ public static $representation = 'image';
12
+
13
+ public $file_loc;
14
+ public $file;
15
+ public $sizes = array();
16
+ public $post_parent;
17
+ public $caption;
18
+ public $_wp_attached_file;
19
+
20
+ /**
21
+ * @param int $iid
22
+ */
23
+ function __construct($iid) {
24
+ $this->init($iid);
25
+ }
26
+
27
+ /**
28
+ * @return string
29
+ */
30
+ function __toString() {
31
+ if ($this->get_src()) {
32
+ return $this->get_src();
33
+ }
34
+ return '';
35
+ }
36
+
37
+ /**
38
+ * @return mixed
39
+ */
40
+ function get_pathinfo() {
41
+ return pathinfo($this->file);
42
+ }
43
+
44
+ /**
45
+ * @param string $dim
46
+ * @return array|int
47
+ */
48
+ function get_dimensions($dim = null) {
49
+ if (isset($this->_dimensions)) {
50
+ return $this->get_dimensions_loaded($dim);
51
+ }
52
+ list($width, $height) = getimagesize($this->file_loc);
53
+ $this->_dimensions = array();
54
+ $this->_dimensions[0] = $width;
55
+ $this->_dimensions[1] = $height;
56
+ return $this->get_dimensions_loaded($dim);
57
+ }
58
+
59
+ /**
60
+ * @param string $dim
61
+ * @return array|int
62
+ */
63
+ function get_dimensions_loaded($dim) {
64
+ if ($dim == null) {
65
+ return $this->_dimensions;
66
+ }
67
+ if ($dim == 'w' || $dim == 'width') {
68
+ return $this->_dimensions[0];
69
+ }
70
+ if ($dim == 'h' || $dim == 'height') {
71
+ return $this->_dimensions[1];
72
+ }
73
+ return null;
74
+ }
75
+
76
+ /**
77
+ * @return int
78
+ */
79
+ function get_width() {
80
+ return $this->get_dimensions('width');
81
+ }
82
+
83
+ /**
84
+ * @return int
85
+ */
86
+ function get_height() {
87
+ return $this->get_dimensions('height');
88
+ }
89
+
90
+ /**
91
+ * @param string $size
92
+ * @return bool|string
93
+ */
94
+ function get_src( $size = '' ) {
95
+ if (isset($this->abs_url)) {
96
+ return $this->_maybe_secure_url($this->abs_url);
97
+ }
98
+
99
+ if ($size && is_string($size) && isset($this->sizes[$size])) {
100
+ $image = image_downsize($this->ID, $size);
101
+ return $this->_maybe_secure_url(reset($image));
102
+ }
103
+
104
+ if (!isset($this->file) && isset($this->_wp_attached_file)) {
105
+ $this->file = $this->_wp_attached_file;
106
+ }
107
+
108
+ if (!isset($this->file)) {
109
+ return false;
110
+ }
111
+
112
+ $dir = self::wp_upload_dir();
113
+ $base = ($dir["baseurl"]);
114
+
115
+ $src = trailingslashit($this->_maybe_secure_url($base)) . $this->file;
116
+ return apply_filters('timber_image_src', $src);
117
+ }
118
+
119
+ private static function _maybe_secure_url($url) {
120
+ if (is_ssl() && strpos($url, 'https') !== 0 && strpos($url, 'http') === 0) {
121
+ $url = 'https' . substr($url, strlen('http'));
122
+ }
123
+
124
+ return $url;
125
+ }
126
+
127
+ public static function wp_upload_dir() {
128
+ static $wp_upload_dir = false;
129
+
130
+ if (!$wp_upload_dir) {
131
+ $wp_upload_dir = wp_upload_dir();
132
+ }
133
+
134
+ return $wp_upload_dir;
135
+ }
136
+
137
+ /**
138
+ * @return string
139
+ */
140
+ function get_path() {
141
+ if (strlen($this->abs_url)) {
142
+ return $this->abs_url;
143
+ }
144
+ return get_permalink($this->ID);
145
+ }
146
+
147
+ /**
148
+ * @return bool|TimberImage
149
+ */
150
+ function get_parent() {
151
+ if (!$this->post_parent) {
152
+ return false;
153
+ }
154
+ return new $this->PostClass($this->post_parent);
155
+ }
156
+
157
+ function get_alt() {
158
+ $alt = trim(strip_tags(get_post_meta($this->ID, '_wp_attachment_image_alt', true)));
159
+ return $alt;
160
+ }
161
+
162
+
163
+ /**
164
+ * @param int $iid
165
+ */
166
+ function init( $iid = false ) {
167
+ if ( !is_numeric( $iid ) && is_string( $iid ) ) {
168
+ if (strstr($iid, '://')) {
169
+ $this->init_with_url($iid);
170
+ return;
171
+ }
172
+ if ( strstr($iid, ABSPATH) ) {
173
+ $this->init_with_file_path($iid);
174
+ return;
175
+ }
176
+ if (strstr(strtolower($iid), '.jpg')) {
177
+ $this->init_with_relative_path($iid);
178
+ return;
179
+ }
180
+ }
181
+
182
+ $image_info = $this->get_image_info($iid);
183
+
184
+ $this->import($image_info);
185
+ $basedir = self::wp_upload_dir();
186
+ $basedir = $basedir['basedir'];
187
+ if (isset($this->file)) {
188
+ $this->file_loc = $basedir . DIRECTORY_SEPARATOR . $this->file;
189
+ } else if (isset($this->_wp_attached_file)) {
190
+ $this->file = reset($this->_wp_attached_file);
191
+ $this->file_loc = $basedir . DIRECTORY_SEPARATOR . $this->file;
192
+ }
193
+ if (isset($image_info['id'])) {
194
+ $this->ID = $image_info['id'];
195
+ } else if (is_numeric($iid)) {
196
+ $this->ID = $iid;
197
+ }
198
+ if (isset($this->ID)) {
199
+ $custom = get_post_custom($this->ID);
200
+ foreach ($custom as $key => $value) {
201
+ $this->$key = $value[0];
202
+ }
203
+ } else {
204
+ if (is_array($iid) || is_object($iid)) {
205
+ TimberHelper::error_log('Not able to init in TimberImage with iid=');
206
+ TimberHelper::error_log($iid);
207
+ } else {
208
+ TimberHelper::error_log('Not able to init in TimberImage with iid=' . $iid);
209
+ }
210
+ }
211
+ }
212
+
213
+ private function get_image_info( $iid ) {
214
+ $image_info = $iid;
215
+ if (is_numeric($iid)) {
216
+ $image_info = wp_get_attachment_metadata($iid);
217
+ if (!is_array($image_info)) {
218
+ $image_info = array();
219
+ }
220
+ $image_custom = get_post_custom($iid);
221
+ $basic = get_post($iid);
222
+ if ($basic) {
223
+ if (isset($basic->post_excerpt)) {
224
+ $this->caption = $basic->post_excerpt;
225
+ }
226
+ $image_custom = array_merge($image_custom, get_object_vars($basic));
227
+ }
228
+ return array_merge($image_info, $image_custom);
229
+ }
230
+ if (is_array($image_info) && isset($image_info['image'])) {
231
+ return $image_info['image'];
232
+ }
233
+ if (is_object($image_info)) {
234
+ return get_object_vars($image_info);
235
+ }
236
+ return $iid;
237
+ }
238
+
239
+ private function init_with_relative_path( $relative_path ) {
240
+ $this->abs_url = home_url( $relative_path );
241
+ $file_path = TimberURLHelper::get_full_path( $relative_path );
242
+ $this->file_loc = $file_path;
243
+ $this->file = $file_path;
244
+ }
245
+
246
+ private function init_with_file_path( $file_path ) {
247
+ $url = TimberURLHelper::file_system_to_url( $file_path );
248
+ $this->abs_url = $url;
249
+ $this->file_loc = $file_path;
250
+ $this->file = $file_path;
251
+ }
252
+
253
+ /**
254
+ * @param string $url
255
+ */
256
+ private function init_with_url($url) {
257
+ $this->abs_url = $url;
258
+ if (TimberURLHelper::is_local($url)) {
259
+ $this->file = ABSPATH . TimberURLHelper::get_rel_url($url);
260
+ $this->file_loc = ABSPATH . TimberURLHelper::get_rel_url($url);
261
+ }
262
+ }
263
+
264
+ /**
265
+ * @deprecated; use src() instead
266
+ * @return string
267
+ */
268
+ function get_url() {
269
+ return $this->get_src();
270
+ }
271
+
272
+ /**
273
+ * @deprecated; use src() instead
274
+ * @return string
275
+ */
276
+ function url() {
277
+ return $this->get_src();
278
+ }
279
+
280
+ /* Alias */
281
+
282
+ /**
283
+ * @return float
284
+ */
285
+ public function aspect() {
286
+ $w = intval($this->width());
287
+ $h = intval($this->height());
288
+ return $w / $h;
289
+ }
290
+
291
+ /**
292
+ * @return int
293
+ */
294
+ public function height() {
295
+ return $this->get_height();
296
+ }
297
+
298
+ /**
299
+ * @param string $size
300
+ * @return bool|string
301
+ */
302
+ public function src($size = '') {
303
+ return $this->get_src($size);
304
+ }
305
+
306
+ /**
307
+ * @return int
308
+ */
309
+ public function width() {
310
+ return $this->get_width();
311
+ }
312
+
313
+ /**
314
+ * @return string alt text stored in WordPress
315
+ */
316
+ public function alt() {
317
+ return $this->get_alt();
318
+ }
319
 
320
  }
lib/timber-menu.php CHANGED
@@ -2,173 +2,170 @@
2
 
3
  class TimberMenu extends TimberCore {
4
 
5
- public $MenuItemClass = 'TimberMenuItem';
6
- public $PostClass = 'TimberPost';
7
 
8
- public $items = null;
9
- public $id = null;
10
- public $ID = null;
11
- public $name = null;
12
- public $term_id;
13
- public $title;
14
 
15
- /**
16
- * @param int $slug
17
- */
18
- function __construct($slug = 0) {
19
- $locations = get_nav_menu_locations();
20
- if ($slug != 0 && is_numeric($slug)) {
21
- $menu_id = $slug;
22
- } else if (is_array($locations) && count($locations)) {
23
- $menu_id = $this->get_menu_id_from_locations($slug, $locations);
24
- } else if ($slug === false) {
25
- $menu_id = false;
26
- } else {
27
- $menu_id = $this->get_menu_id_from_terms($slug);
28
- }
29
- if ($menu_id) {
30
- $this->init($menu_id);
31
- } else {
32
- $this->init_as_page_menu();
33
- //TimberHelper::error_log("Sorry, the menu you were looking for wasn't found ('" . $slug . "'). Here's what Timber did find:");
34
- }
35
- return null;
36
- }
37
 
38
- /**
39
- * @param int $menu_id
40
- */
41
- private function init($menu_id) {
42
- $menu = wp_get_nav_menu_items($menu_id);
43
- if ($menu) {
44
- _wp_menu_item_classes_by_context($menu);
45
- if (is_array($menu)){
46
- $menu = self::order_children($menu);
47
- }
48
- $this->items = $menu;
49
- $menu_info = wp_get_nav_menu_object($menu_id);
50
- $this->import($menu_info);
51
- $this->ID = $this->term_id;
52
- $this->id = $this->term_id;
53
- $this->title = $this->name;
54
- }
55
- }
56
 
57
- private function init_as_page_menu() {
58
- $menu = get_pages();
59
- if ($menu) {
60
- foreach($menu as $mi) {
61
- $mi->__title = $mi->post_title;
62
- }
63
- _wp_menu_item_classes_by_context($menu);
64
- if (is_array($menu)){
65
- $menu = self::order_children($menu);
66
- }
67
- $this->items = $menu;
68
- }
69
- }
70
 
71
- /**
72
- * @param string $slug
73
- * @param array $locations
74
- * @return integer
75
- */
76
- private function get_menu_id_from_locations($slug, $locations) {
77
- if ($slug === 0) {
78
- $slug = $this->get_menu_id_from_terms($slug);
79
- }
80
- if (is_numeric($slug)) {
81
- $slug = array_search($slug, $locations);
82
- }
83
- if (isset($locations[$slug])) {
84
- return $locations[$slug];
85
- }
86
- return null;
87
- }
88
 
89
- /**
90
- * @param int $slug
91
- * @return int
92
- */
93
- private function get_menu_id_from_terms($slug = 0) {
94
- if (!is_numeric($slug) && is_string($slug)) {
95
- //we have a string so lets search for that
96
- $menu_id = get_term_by('slug', $slug, 'nav_menu');
97
- if ($menu_id) {
98
- return $menu_id;
99
- }
100
- $menu_id = get_term_by('name', $slug, 'nav_menu');
101
- if ($menu_id) {
102
- return $menu_id;
103
- }
104
- }
105
- $menus = get_terms('nav_menu', array('hide_empty' => true));
106
- if (is_array($menus) && count($menus)) {
107
- if (isset($menus[0]->term_id)) {
108
- return $menus[0]->term_id;
109
- }
110
- }
111
- return 0;
112
- }
113
 
114
- /**
115
- * @param array $menu_items
116
- * @param int $parent_id
117
- * @return TimberMenuItem|null
118
- */
119
- function find_parent_item_in_menu($menu_items, $parent_id) {
120
- foreach ($menu_items as &$item) {
121
- if ($item->ID == $parent_id) {
122
- return $item;
123
- }
124
- }
125
- return null;
126
- }
127
 
128
- /**
129
- * @param array $items
130
- * @return array
131
- */
132
- function order_children($items) {
133
- $index = array();
134
- $menu = array();
135
- foreach ($items as $item) {
136
- if (isset($item->title)) {
137
- //items from wp can come with a $title property which conflicts with methods
138
- $item->__title = $item->title;
139
- unset($item->title);
140
- }
141
- if(isset($item->ID)){
142
- if (is_object($item) && get_class($item) == 'WP_Post'){
143
- $old_menu_item = $item;
144
- $item = new $this->PostClass($item);
145
- }
146
- $menu_item = new $this->MenuItemClass($item);
147
- if (isset($old_menu_item)){
148
- $menu_item->import_classes($old_menu_item);
149
- }
150
- $index[$item->ID] = $menu_item;
151
- }
152
- }
153
- foreach ($index as $item) {
154
- if (isset($item->menu_item_parent) && $item->menu_item_parent && isset($index[$item->menu_item_parent])) {
155
- $index[$item->menu_item_parent]->add_child($item);
156
- } else {
157
- $menu[] = $item;
158
- }
159
- }
160
- return $menu;
161
- }
162
 
163
- /**
164
- * @return array
165
- */
166
- function get_items() {
167
- if (is_array($this->items)) {
168
- return $this->items;
169
- }
170
- return array();
171
- }
172
  }
173
 
174
 
2
 
3
  class TimberMenu extends TimberCore {
4
 
5
+ public $MenuItemClass = 'TimberMenuItem';
6
+ public $PostClass = 'TimberPost';
7
 
8
+ public $items = null;
9
+ public $id = null;
10
+ public $ID = null;
11
+ public $name = null;
12
+ public $term_id;
13
+ public $title;
14
 
15
+ /**
16
+ * @param int $slug
17
+ */
18
+ function __construct($slug = 0) {
19
+ $locations = get_nav_menu_locations();
20
+ if ($slug != 0 && is_numeric($slug)) {
21
+ $menu_id = $slug;
22
+ } else if (is_array($locations) && count($locations)) {
23
+ $menu_id = $this->get_menu_id_from_locations($slug, $locations);
24
+ } else if ($slug === false) {
25
+ $menu_id = false;
26
+ } else {
27
+ $menu_id = $this->get_menu_id_from_terms($slug);
28
+ }
29
+ if ($menu_id) {
30
+ $this->init($menu_id);
31
+ } else {
32
+ $this->init_as_page_menu();
33
+ //TimberHelper::error_log("Sorry, the menu you were looking for wasn't found ('" . $slug . "'). Here's what Timber did find:");
34
+ }
35
+ }
 
36
 
37
+ /**
38
+ * @param int $menu_id
39
+ */
40
+ private function init($menu_id) {
41
+ $menu = wp_get_nav_menu_items($menu_id);
42
+ if ($menu) {
43
+ _wp_menu_item_classes_by_context($menu);
44
+ if (is_array($menu)){
45
+ $menu = self::order_children($menu);
46
+ }
47
+ $this->items = $menu;
48
+ $menu_info = wp_get_nav_menu_object($menu_id);
49
+ $this->import($menu_info);
50
+ $this->ID = $this->term_id;
51
+ $this->id = $this->term_id;
52
+ $this->title = $this->name;
53
+ }
54
+ }
55
 
56
+ private function init_as_page_menu() {
57
+ $menu = get_pages();
58
+ if ($menu) {
59
+ foreach($menu as $mi) {
60
+ $mi->__title = $mi->post_title;
61
+ }
62
+ _wp_menu_item_classes_by_context($menu);
63
+ if (is_array($menu)){
64
+ $menu = self::order_children($menu);
65
+ }
66
+ $this->items = $menu;
67
+ }
68
+ }
69
 
70
+ /**
71
+ * @param string $slug
72
+ * @param array $locations
73
+ * @return integer
74
+ */
75
+ private function get_menu_id_from_locations($slug, $locations) {
76
+ if ($slug === 0) {
77
+ $slug = $this->get_menu_id_from_terms($slug);
78
+ }
79
+ if (is_numeric($slug)) {
80
+ $slug = array_search($slug, $locations);
81
+ }
82
+ if (isset($locations[$slug])) {
83
+ return $locations[$slug];
84
+ }
85
+ }
 
86
 
87
+ /**
88
+ * @param int $slug
89
+ * @return int
90
+ */
91
+ private function get_menu_id_from_terms($slug = 0) {
92
+ if (!is_numeric($slug) && is_string($slug)) {
93
+ //we have a string so lets search for that
94
+ $menu_id = get_term_by('slug', $slug, 'nav_menu');
95
+ if ($menu_id) {
96
+ return $menu_id;
97
+ }
98
+ $menu_id = get_term_by('name', $slug, 'nav_menu');
99
+ if ($menu_id) {
100
+ return $menu_id;
101
+ }
102
+ }
103
+ $menus = get_terms('nav_menu', array('hide_empty' => true));
104
+ if (is_array($menus) && count($menus)) {
105
+ if (isset($menus[0]->term_id)) {
106
+ return $menus[0]->term_id;
107
+ }
108
+ }
109
+ return 0;
110
+ }
111
 
112
+ /**
113
+ * @param array $menu_items
114
+ * @param int $parent_id
115
+ * @return TimberMenuItem|null
116
+ */
117
+ function find_parent_item_in_menu($menu_items, $parent_id) {
118
+ foreach ($menu_items as &$item) {
119
+ if ($item->ID == $parent_id) {
120
+ return $item;
121
+ }
122
+ }
123
+ }
 
124
 
125
+ /**
126
+ * @param array $items
127
+ * @return array
128
+ */
129
+ function order_children($items) {
130
+ $index = array();
131
+ $menu = array();
132
+ foreach ($items as $item) {
133
+ if (isset($item->title)) {
134
+ //items from wp can come with a $title property which conflicts with methods
135
+ $item->__title = $item->title;
136
+ unset($item->title);
137
+ }
138
+ if(isset($item->ID)){
139
+ if (is_object($item) && get_class($item) == 'WP_Post'){
140
+ $old_menu_item = $item;
141
+ $item = new $this->PostClass($item);
142
+ }
143
+ $menu_item = new $this->MenuItemClass($item);
144
+ if (isset($old_menu_item)){
145
+ $menu_item->import_classes($old_menu_item);
146
+ }
147
+ $index[$item->ID] = $menu_item;
148
+ }
149
+ }
150
+ foreach ($index as $item) {
151
+ if (isset($item->menu_item_parent) && $item->menu_item_parent && isset($index[$item->menu_item_parent])) {
152
+ $index[$item->menu_item_parent]->add_child($item);
153
+ } else {
154
+ $menu[] = $item;
155
+ }
156
+ }
157
+ return $menu;
158
+ }
159
 
160
+ /**
161
+ * @return array
162
+ */
163
+ function get_items() {
164
+ if (is_array($this->items)) {
165
+ return $this->items;
166
+ }
167
+ return array();
168
+ }
169
  }
170
 
171
 
lib/timber-post-getter.php CHANGED
@@ -20,7 +20,7 @@ class TimberPostGetter {
20
  return apply_filters('timber_post_getter_get_posts', $posts->get_posts( $return_collection ));
21
  }
22
 
23
- static function query_post( $query = false, $PostClass = 'TimberPost' ) {
24
  $posts = self::query_posts( $query, $PostClass );
25
  if ( $post = $posts->current() ) {
26
  return $post;
@@ -69,6 +69,7 @@ class TimberPostGetter {
69
  * @param array $results
70
  * @param string $PostClass
71
  * @return TimberPostsCollection
 
72
  */
73
  static function handle_post_results($results, $PostClass = 'TimberPost') {
74
  $posts = array();
20
  return apply_filters('timber_post_getter_get_posts', $posts->get_posts( $return_collection ));
21
  }
22
 
23
+ static function query_post( $query = false, $PostClass = 'TimberPost' ) {
24
  $posts = self::query_posts( $query, $PostClass );
25
  if ( $post = $posts->current() ) {
26
  return $post;
69
  * @param array $results
70
  * @param string $PostClass
71
  * @return TimberPostsCollection
72
+ * @deprecated since 0.21.1
73
  */
74
  static function handle_post_results($results, $PostClass = 'TimberPost') {
75
  $posts = array();
lib/timber-post.php CHANGED
@@ -33,23 +33,45 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
33
  * @return \TimberPost TimberPost object -- woo!
34
  */
35
  function __construct($pid = null) {
36
- global $wp_query;
37
- if ($pid === null && isset($wp_query->queried_object_id) && $wp_query->queried_object_id) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  $pid = $wp_query->queried_object_id;
39
- $this->ID = $pid;
40
- } else if ($pid === null && get_the_ID()) {
41
- $pid = get_the_ID();
42
- $this->ID = $pid;
43
- } else if ($pid === null && ($pid_from_loop = TimberPostGetter::loop_to_id())) {
44
- $this->ID = $pid_from_loop;
 
 
 
 
 
 
45
  }
46
- if (is_numeric($pid)) {
47
- $this->ID = $pid;
48
  }
49
- $this->init($pid);
50
  }
51
 
52
- /**
53
  * @return string
54
  */
55
  function __toString() {
@@ -64,6 +86,9 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
64
  if ($pid === false) {
65
  $pid = get_the_ID();
66
  }
 
 
 
67
  $post_info = $this->get_info($pid);
68
  $this->import($post_info);
69
  /* deprecated, adding for support for older themes */
@@ -82,7 +107,6 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
82
  if ($this->can_edit()) {
83
  return get_edit_post_link($this->ID);
84
  }
85
- return false;
86
  }
87
 
88
  /**
@@ -122,12 +146,12 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
122
 
123
 
124
  /**
125
- * helps you find the post id regardless of whetehr you send a string or whatever
126
  *
127
  * @param integer $pid ;
128
  * @return integer ID number of a post
129
  */
130
- private function check_post_id($pid) {
131
  if (is_numeric($pid) && $pid === 0) {
132
  $pid = get_the_ID();
133
  return $pid;
@@ -277,7 +301,6 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
277
  return new $this->ImageClass($tid);
278
  }
279
  }
280
- return null;
281
  }
282
 
283
  /**
@@ -419,7 +442,6 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
419
  if (isset($this->post_author)) {
420
  return new TimberUser($this->post_author);
421
  }
422
- return false;
423
  }
424
 
425
  /**
@@ -559,7 +581,6 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
559
  if (count($cats) && isset($cats[0])) {
560
  return $cats[0];
561
  }
562
- return null;
563
  }
564
 
565
  /** # get terms is good
33
  * @return \TimberPost TimberPost object -- woo!
34
  */
35
  function __construct($pid = null) {
36
+ $pid = $this->determine_id( $pid );
37
+ $this->init($pid);
38
+ }
39
+
40
+ /**
41
+ * @param mixed a value to test against
42
+ * @return int the numberic id we should be using for this post object
43
+ */
44
+
45
+ protected function determine_id($pid) {
46
+ global $wp_query;
47
+ if ($pid === null &&
48
+ isset($wp_query->queried_object_id)
49
+ && $wp_query->queried_object_id
50
+ && isset($wp_query->queried_object)
51
+ && is_object($wp_query->queried_object)
52
+ && get_class($wp_query->queried_object) == 'WP_Post'
53
+ ) {
54
  $pid = $wp_query->queried_object_id;
55
+ } else if ($wp_query->is_home && isset($wp_query->queried_object_id) && $wp_query->queried_object_id ) {
56
+ //hack for static page as home page
57
+ $pid = $wp_query->queried_object_id;
58
+ } else if ($pid === null) {
59
+ $gtid = false;
60
+ $maybe_post = get_post();
61
+ if (isset($maybe_post->ID)){
62
+ $gtid = true;
63
+ }
64
+ if ( $gtid ) {
65
+ $pid = get_the_ID();
66
+ }
67
  }
68
+ if ($pid === null && ($pid_from_loop = TimberPostGetter::loop_to_id())) {
69
+ $pid = $pid_from_loop;
70
  }
71
+ return $pid;
72
  }
73
 
74
+ /**
75
  * @return string
76
  */
77
  function __toString() {
86
  if ($pid === false) {
87
  $pid = get_the_ID();
88
  }
89
+ if (is_numeric($pid)) {
90
+ $this->ID = $pid;
91
+ }
92
  $post_info = $this->get_info($pid);
93
  $this->import($post_info);
94
  /* deprecated, adding for support for older themes */
107
  if ($this->can_edit()) {
108
  return get_edit_post_link($this->ID);
109
  }
 
110
  }
111
 
112
  /**
146
 
147
 
148
  /**
149
+ * helps you find the post id regardless of whether you send a string or whatever
150
  *
151
  * @param integer $pid ;
152
  * @return integer ID number of a post
153
  */
154
+ protected function check_post_id($pid) {
155
  if (is_numeric($pid) && $pid === 0) {
156
  $pid = get_the_ID();
157
  return $pid;
301
  return new $this->ImageClass($tid);
302
  }
303
  }
 
304
  }
305
 
306
  /**
442
  if (isset($this->post_author)) {
443
  return new TimberUser($this->post_author);
444
  }
 
445
  }
446
 
447
  /**
581
  if (count($cats) && isset($cats[0])) {
582
  return $cats[0];
583
  }
 
584
  }
585
 
586
  /** # get terms is good
lib/timber-routes.php CHANGED
@@ -2,6 +2,9 @@
2
 
3
  class TimberRoutes {
4
 
 
 
 
5
  public static function init( $timber ) {
6
  // Install ourselves in Timber
7
  $timber->routes = new TimberRoutes();
@@ -10,6 +13,7 @@ class TimberRoutes {
10
  /**
11
  * @param string $route
12
  * @param callable $callback
 
13
  */
14
  public static function add_route($route, $callback, $args = array()) {
15
  Routes::map($route, $callback, $args);
@@ -21,6 +25,7 @@ class TimberRoutes {
21
  * @param int $status_code
22
  * @param bool $tparams
23
  * @return bool
 
24
  */
25
  public static function load_view($template, $query = false, $status_code = 200, $tparams = false) {
26
  Routes::load($template, $tparams, $query, $status_code);
2
 
3
  class TimberRoutes {
4
 
5
+ /**
6
+ * @deprecated since 0.21.1 use Upstatement/routes instead
7
+ */
8
  public static function init( $timber ) {
9
  // Install ourselves in Timber
10
  $timber->routes = new TimberRoutes();
13
  /**
14
  * @param string $route
15
  * @param callable $callback
16
+ * @deprecated since 0.21.1 use Upstatement/routes instead
17
  */
18
  public static function add_route($route, $callback, $args = array()) {
19
  Routes::map($route, $callback, $args);
25
  * @param int $status_code
26
  * @param bool $tparams
27
  * @return bool
28
+ * @deprecated since 0.21.1 use Upstatement/routes instead
29
  */
30
  public static function load_view($template, $query = false, $status_code = 200, $tparams = false) {
31
  Routes::load($template, $tparams, $query, $status_code);
lib/timber-term.php CHANGED
@@ -33,7 +33,7 @@ class TimberTerm extends TimberCore implements TimberCoreInterface {
33
  return $this->name;
34
  }
35
 
36
-
37
 
38
  /* Setup
39
  ===================== */
@@ -43,8 +43,13 @@ class TimberTerm extends TimberCore implements TimberCoreInterface {
43
  */
44
  private function get_term_from_query() {
45
  global $wp_query;
46
- $qo = $wp_query->queried_object;
47
- return $qo->term_id;
 
 
 
 
 
48
  }
49
 
50
  /**
33
  return $this->name;
34
  }
35
 
36
+
37
 
38
  /* Setup
39
  ===================== */
43
  */
44
  private function get_term_from_query() {
45
  global $wp_query;
46
+ if (isset($wp_query->queried_object)) {
47
+ $qo = $wp_query->queried_object;
48
+ return $qo->term_id;
49
+ }
50
+ if (isset($wp_query->tax_query->queries[0]['terms'][0])) {
51
+ return $wp_query->tax_query->queries[0]['terms'][0];
52
+ }
53
  }
54
 
55
  /**
lib/timber-url-helper.php CHANGED
@@ -59,7 +59,7 @@ class TimberURLHelper {
59
  return $url;
60
  }
61
  $link = '';
62
- if (isset($url_info['path'])){
63
  $link = $url_info['path'];
64
  }
65
  if (isset($url_info['query']) && strlen($url_info['query'])) {
@@ -96,7 +96,7 @@ class TimberURLHelper {
96
 
97
  /**
98
  * Takes a url and figures out its place based in the file system based on path
99
- * NOTE: Not fool-proof, makes a lot of assumptions about the file path
100
  * matching the URL path
101
  * @param string $url
102
  * @return string
@@ -148,6 +148,12 @@ class TimberURLHelper {
148
  if (strstr(strtolower($url), 'http')) {
149
  $url_parts = parse_url($url);
150
  $url = $url_parts['scheme'] . '://' . $url_parts['host'] . $path . $url_parts['path'];
 
 
 
 
 
 
151
  } else {
152
  $url = $url . $path;
153
  }
@@ -175,7 +181,7 @@ class TimberURLHelper {
175
  /**
176
  * @param string $url
177
  * @return bool true if $path is an external url, false if relative or local.
178
- * true if it's a subdomain (http://cdn.example.org = true)
179
  */
180
  public static function is_external($url) {
181
  $has_http = strstr(strtolower($url), 'http');
59
  return $url;
60
  }
61
  $link = '';
62
+ if (isset($url_info['path'])){
63
  $link = $url_info['path'];
64
  }
65
  if (isset($url_info['query']) && strlen($url_info['query'])) {
96
 
97
  /**
98
  * Takes a url and figures out its place based in the file system based on path
99
+ * NOTE: Not fool-proof, makes a lot of assumptions about the file path
100
  * matching the URL path
101
  * @param string $url
102
  * @return string
148
  if (strstr(strtolower($url), 'http')) {
149
  $url_parts = parse_url($url);
150
  $url = $url_parts['scheme'] . '://' . $url_parts['host'] . $path . $url_parts['path'];
151
+ if ( isset($url_parts['query']) ) {
152
+ $url .= $url_parts['query'];
153
+ }
154
+ if ( isset($url_parts['fragment']) ) {
155
+ $url .= $url_parts['fragment'];
156
+ }
157
  } else {
158
  $url = $url . $path;
159
  }
181
  /**
182
  * @param string $url
183
  * @return bool true if $path is an external url, false if relative or local.
184
+ * true if it's a subdomain (http://cdn.example.org = true)
185
  */
186
  public static function is_external($url) {
187
  $has_http = strstr(strtolower($url), 'http');
lib/timber-user.php CHANGED
@@ -2,192 +2,193 @@
2
 
3
  class TimberUser extends TimberCore implements TimberCoreInterface {
4
 
5
- public $object_type = 'user';
6
- public static $representation = 'user';
7
-
8
- public $_link;
9
-
10
- public $display_name;
11
- public $id;
12
- public $name;
13
- public $user_nicename;
14
-
15
- /**
16
- * @param int|bool $uid
17
- */
18
- function __construct($uid = false) {
19
- $this->init($uid);
20
- }
21
-
22
- /**
23
- * @return string
24
- */
25
- function __toString() {
26
- $name = $this->name();
27
- if (strlen($name)) {
28
- return $name;
29
- }
30
- if (strlen($this->name)) {
31
- return $this->name;
32
- }
33
- return '';
34
- }
35
-
36
- /**
37
- * @param string $field_name
38
- * @return null
39
- */
40
- function get_meta($field_name) {
41
- return $this->get_meta_field( $field_name );
42
- }
43
-
44
- /**
45
- * @param string $field
46
- * @param mixed $value
47
- */
48
- function __set($field, $value) {
49
- if ($field == 'name') {
50
- $this->display_name = $value;
51
- }
52
- $this->$field = $value;
53
- }
54
-
55
- /**
56
- * @return string
57
- */
58
- public function get_link() {
59
- if (!$this->_link) {
60
- $this->_link = get_author_posts_url($this->ID);
61
- }
62
- return $this->_link;
63
- }
64
-
65
- /**
66
- * @param int|bool $uid
67
- */
68
- function init($uid = false) {
69
- if ($uid === false) {
70
- $uid = get_current_user_id();
71
- }
72
- if (is_object($uid) || is_array($uid)){
73
- $data = $uid;
74
- if (is_array($uid)){
75
- $data = (object) $uid;
76
- }
77
- $uid = $data->ID;
78
- }
79
- if (is_numeric($uid)) {
80
- $data = get_userdata($uid);
81
- }
82
- if (isset($data) && is_object($data)) {
83
- if (isset($data->data)){
84
- $this->import($data->data);
85
- } else {
86
- $this->import($data);
87
- }
88
- }
89
- $this->id = $this->ID;
90
- $this->name = $this->name();
91
- $this->import_custom();
92
- }
93
-
94
- /**
95
- * @param string $field_name
96
- * @return mixed
97
- */
98
- function get_meta_field($field_name) {
99
- $value = null;
100
- $value = apply_filters('timber_user_get_meta_field_pre', $value, $this->ID, $field_name, $this);
101
- if ($value === null) {
102
- $value = get_user_meta($this->ID, $field_name, true);
103
- }
104
- $value = apply_filters('timber_user_get_meta_field', $value, $this->ID, $field_name, $this);
105
- return $value;
106
- }
107
-
108
- /**
109
- * @return array|null
110
- */
111
- function get_custom() {
112
- if ($this->ID) {
113
- $um = array();
114
- $um = apply_filters('timber_user_get_meta_pre', $um, $this->ID, $this);
115
- if (empty($um)) {
116
- $um = get_user_meta($this->ID);
117
- }
118
- $custom = array();
119
- foreach ($um as $key => $value) {
120
- if (is_array($value) && count($value) == 1) {
121
- $value = $value[0];
122
- }
123
- $custom[$key] = maybe_unserialize($value);
124
- }
125
- $custom = apply_filters('timber_user_get_meta', $custom, $this->ID, $this);
126
- return $custom;
127
- }
128
- return null;
129
- }
130
-
131
- function import_custom() {
132
- $custom = $this->get_custom();
133
- $this->import($custom);
134
- }
135
-
136
- /**
137
- * @return string
138
- */
139
- function name() {
140
- return $this->display_name;
141
- }
142
-
143
- /**
144
- * @return string
145
- */
146
- function get_permalink() {
147
- return $this->get_link();
148
- }
149
-
150
- /**
151
- * @return string
152
- */
153
- function permalink() {
154
- return $this->get_link();
155
- }
156
-
157
- /**
158
- * @return string
159
- */
160
- function get_path() {
161
- return $this->get_link();
162
- }
163
-
164
- /**
165
- * @param string $field_name
166
- * @return mixed
167
- */
168
- function meta($field_name) {
169
- return $this->get_meta_field($field_name);
170
- }
171
-
172
- /**
173
- * @return string
174
- */
175
- function path() {
176
- return $this->get_path();
177
- }
178
-
179
- /**
180
- * @return string
181
- */
182
- function slug() {
183
- return $this->user_nicename;
184
- }
185
-
186
- /**
187
- * @return string
188
- */
189
- function link() {
190
- return $this->get_link();
191
- }
 
192
 
193
  }
2
 
3
  class TimberUser extends TimberCore implements TimberCoreInterface {
4
 
5
+ public $object_type = 'user';
6
+ public static $representation = 'user';
7
+
8
+ public $_link;
9
+
10
+ public $description;
11
+ public $display_name;
12
+ public $id;
13
+ public $name;
14
+ public $user_nicename;
15
+
16
+ /**
17
+ * @param int|bool $uid
18
+ */
19
+ function __construct($uid = false) {
20
+ $this->init($uid);
21
+ }
22
+
23
+ /**
24
+ * @return string
25
+ */
26
+ function __toString() {
27
+ $name = $this->name();
28
+ if (strlen($name)) {
29
+ return $name;
30
+ }
31
+ if (strlen($this->name)) {
32
+ return $this->name;
33
+ }
34
+ return '';
35
+ }
36
+
37
+ /**
38
+ * @param string $field_name
39
+ * @return null
40
+ */
41
+ function get_meta($field_name) {
42
+ return $this->get_meta_field( $field_name );
43
+ }
44
+
45
+ /**
46
+ * @param string $field
47
+ * @param mixed $value
48
+ */
49
+ function __set($field, $value) {
50
+ if ($field == 'name') {
51
+ $this->display_name = $value;
52
+ }
53
+ $this->$field = $value;
54
+ }
55
+
56
+ /**
57
+ * @return string
58
+ */
59
+ public function get_link() {
60
+ if (!$this->_link) {
61
+ $this->_link = untrailingslashit(get_author_posts_url($this->ID));
62
+ }
63
+ return $this->_link;
64
+ }
65
+
66
+ /**
67
+ * @param int|bool $uid
68
+ */
69
+ function init($uid = false) {
70
+ if ($uid === false) {
71
+ $uid = get_current_user_id();
72
+ }
73
+ if (is_object($uid) || is_array($uid)){
74
+ $data = $uid;
75
+ if (is_array($uid)){
76
+ $data = (object) $uid;
77
+ }
78
+ $uid = $data->ID;
79
+ }
80
+ if (is_numeric($uid)) {
81
+ $data = get_userdata($uid);
82
+ }
83
+ if (isset($data) && is_object($data)) {
84
+ if (isset($data->data)){
85
+ $this->import($data->data);
86
+ } else {
87
+ $this->import($data);
88
+ }
89
+ }
90
+ $this->id = $this->ID;
91
+ $this->name = $this->name();
92
+ $this->import_custom();
93
+ }
94
+
95
+ /**
96
+ * @param string $field_name
97
+ * @return mixed
98
+ */
99
+ function get_meta_field($field_name) {
100
+ $value = null;
101
+ $value = apply_filters('timber_user_get_meta_field_pre', $value, $this->ID, $field_name, $this);
102
+ if ($value === null) {
103
+ $value = get_user_meta($this->ID, $field_name, true);
104
+ }
105
+ $value = apply_filters('timber_user_get_meta_field', $value, $this->ID, $field_name, $this);
106
+ return $value;
107
+ }
108
+
109
+ /**
110
+ * @return array|null
111
+ */
112
+ function get_custom() {
113
+ if ($this->ID) {
114
+ $um = array();
115
+ $um = apply_filters('timber_user_get_meta_pre', $um, $this->ID, $this);
116
+ if (empty($um)) {
117
+ $um = get_user_meta($this->ID);
118
+ }
119
+ $custom = array();
120
+ foreach ($um as $key => $value) {
121
+ if (is_array($value) && count($value) == 1) {
122
+ $value = $value[0];
123
+ }
124
+ $custom[$key] = maybe_unserialize($value);
125
+ }
126
+ $custom = apply_filters('timber_user_get_meta', $custom, $this->ID, $this);
127
+ return $custom;
128
+ }
129
+ return null;
130
+ }
131
+
132
+ function import_custom() {
133
+ $custom = $this->get_custom();
134
+ $this->import($custom);
135
+ }
136
+
137
+ /**
138
+ * @return string
139
+ */
140
+ function name() {
141
+ return $this->display_name;
142
+ }
143
+
144
+ /**
145
+ * @return string
146
+ */
147
+ function get_permalink() {
148
+ return $this->get_link();
149
+ }
150
+
151
+ /**
152
+ * @return string
153
+ */
154
+ function permalink() {
155
+ return $this->get_permalink();
156
+ }
157
+
158
+ /**
159
+ * @return string ex: /author/lincoln
160
+ */
161
+ function get_path() {
162
+ return TimberURLHelper::get_rel_url($this->get_link());
163
+ }
164
+
165
+ /**
166
+ * @param string $field_name
167
+ * @return mixed
168
+ */
169
+ function meta($field_name) {
170
+ return $this->get_meta_field($field_name);
171
+ }
172
+
173
+ /**
174
+ * @return string
175
+ */
176
+ function path() {
177
+ return $this->get_path();
178
+ }
179
+
180
+ /**
181
+ * @return string
182
+ */
183
+ function slug() {
184
+ return $this->user_nicename;
185
+ }
186
+
187
+ /**
188
+ * @return string
189
+ */
190
+ function link() {
191
+ return $this->get_link();
192
+ }
193
 
194
  }
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.21.0
6
  Tested up to: 4.1
7
  PHP version: 5.3.0 or greater
8
  License: GPLv2 or later
@@ -41,6 +41,16 @@ Timber is great for any WordPress developer who cares about writing good, mainta
41
 
42
  == Changelog ==
43
 
 
 
 
 
 
 
 
 
 
 
44
  = 0.21.0 =
45
  * Routes is now its own independent repo
46
  * Timber Starter Theme is now its own independent repo
2
  Contributors: jarednova
3
  Tags: template engine, templates, twig
4
  Requires at least: 3.7
5
+ Stable tag: 0.21.2
6
  Tested up to: 4.1
7
  PHP version: 5.3.0 or greater
8
  License: GPLv2 or later
41
 
42
  == Changelog ==
43
 
44
+ = 0.21.2 =
45
+ * Fixed GIF handling (thanks @josephbergdoll and @jarednova)
46
+ * Improved handling of diff't image sizes
47
+ * Timber Archives are now tested and much improved (thanks @KLVTZ)
48
+ * Image fixing (thanks @marciojcoelho)
49
+ * More tests and improving coverage to 77%
50
+
51
+ = 0.21.1 =
52
+ * Fixed capitalization problem for WP.org version
53
+
54
  = 0.21.0 =
55
  * Routes is now its own independent repo
56
  * Timber Starter Theme is now its own independent repo
timber.php CHANGED
@@ -4,17 +4,21 @@ 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.21.0
8
  Author URI: http://upstatement.com/
9
  */
10
 
11
  global $wp_version;
12
  global $timber;
13
 
14
- // we look for Composer files first in the theme (theme install)
15
  // then in the wp-content dir (site install)
16
- if ( file_exists( $composer_autoload = __DIR__ . '/vendor/autoload.php' )
17
- || file_exists( $composer_autoload = WP_CONTENT_DIR.'/vendor/autoload.php' ) ) {
 
 
 
 
18
  require_once $composer_autoload;
19
  }
20
 
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.21.2
8
  Author URI: http://upstatement.com/
9
  */
10
 
11
  global $wp_version;
12
  global $timber;
13
 
14
+ // we look for Composer files first in the plugins dir
15
  // then in the wp-content dir (site install)
16
+ // and finally in the current themes directories
17
+ if ( file_exists( $composer_autoload = __DIR__ . '/vendor/autoload.php' ) /* check in self */
18
+ || file_exists( $composer_autoload = WP_CONTENT_DIR.'/vendor/autoload.php') /* check in wp-content */
19
+ || file_exists( $composer_autoload = get_stylesheet_directory().'/vendor/autoload.php') /* check in child theme */
20
+ || file_exists( $composer_autoload = get_template_directory().'/vendor/autoload.php') /* check in parent theme */
21
+ ) {
22
  require_once $composer_autoload;
23
  }
24
 
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit8851ccb6a9a5ab69fbe5af8970be62b2::getLoader();
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInitba544e60fe73a624e4f8eb697a7b6443::getLoader();
vendor/composer/autoload_classmap.php CHANGED
@@ -20,9 +20,9 @@ return array(
20
  'TimberImageHelper' => $baseDir . '/lib/timber-image-helper.php',
21
  'TimberImageOperation' => $baseDir . '/lib/image/timber-image-operation.php',
22
  'TimberImageOperationLetterbox' => $baseDir . '/lib/image/timber-image-operation-letterbox.php',
23
- 'TimberImageOperationPngToJpg' => $baseDir . '/lib/image/timber-image-operation-pngtojpg.php',
24
  'TimberImageOperationResize' => $baseDir . '/lib/image/timber-image-operation-resize.php',
25
  'TimberImageOperationRetina' => $baseDir . '/lib/image/timber-image-operation-retina.php',
 
26
  'TimberIntegrations' => $baseDir . '/lib/timber-integrations.php',
27
  'TimberLoader' => $baseDir . '/lib/timber-loader.php',
28
  'TimberMenu' => $baseDir . '/lib/timber-menu.php',
20
  'TimberImageHelper' => $baseDir . '/lib/timber-image-helper.php',
21
  'TimberImageOperation' => $baseDir . '/lib/image/timber-image-operation.php',
22
  'TimberImageOperationLetterbox' => $baseDir . '/lib/image/timber-image-operation-letterbox.php',
 
23
  'TimberImageOperationResize' => $baseDir . '/lib/image/timber-image-operation-resize.php',
24
  'TimberImageOperationRetina' => $baseDir . '/lib/image/timber-image-operation-retina.php',
25
+ 'TimberImageOperationToJpg' => $baseDir . '/lib/image/timber-image-operation-tojpg.php',
26
  'TimberIntegrations' => $baseDir . '/lib/timber-integrations.php',
27
  'TimberLoader' => $baseDir . '/lib/timber-loader.php',
28
  'TimberMenu' => $baseDir . '/lib/timber-menu.php',
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit8851ccb6a9a5ab69fbe5af8970be62b2
6
  {
7
  private static $loader;
8
 
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit8851ccb6a9a5ab69fbe5af8970be62b2
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit8851ccb6a9a5ab69fbe5af8970be62b2', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit8851ccb6a9a5ab69fbe5af8970be62b2', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
@@ -44,7 +44,7 @@ class ComposerAutoloaderInit8851ccb6a9a5ab69fbe5af8970be62b2
44
  }
45
  }
46
 
47
- function composerRequire8851ccb6a9a5ab69fbe5af8970be62b2($file)
48
  {
49
  require $file;
50
  }
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInitba544e60fe73a624e4f8eb697a7b6443
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInitba544e60fe73a624e4f8eb697a7b6443', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInitba544e60fe73a624e4f8eb697a7b6443', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
44
  }
45
  }
46
 
47
+ function composerRequireba544e60fe73a624e4f8eb697a7b6443($file)
48
  {
49
  require $file;
50
  }
vendor/composer/installed.json CHANGED
@@ -98,23 +98,23 @@
98
  },
99
  {
100
  "name": "twig/twig",
101
- "version": "v1.18.0",
102
- "version_normalized": "1.18.0.0",
103
  "source": {
104
  "type": "git",
105
  "url": "https://github.com/twigphp/Twig.git",
106
- "reference": "4cf7464348e7f9893a93f7096a90b73722be99cf"
107
  },
108
  "dist": {
109
  "type": "zip",
110
- "url": "https://api.github.com/repos/twigphp/Twig/zipball/4cf7464348e7f9893a93f7096a90b73722be99cf",
111
- "reference": "4cf7464348e7f9893a93f7096a90b73722be99cf",
112
  "shasum": ""
113
  },
114
  "require": {
115
- "php": ">=5.2.4"
116
  },
117
- "time": "2015-01-25 17:32:08",
118
  "type": "library",
119
  "extra": {
120
  "branch-alias": {
@@ -264,17 +264,17 @@
264
  },
265
  {
266
  "name": "upstatement/routes",
267
- "version": "dev-master",
268
- "version_normalized": "9999999-dev",
269
  "source": {
270
  "type": "git",
271
  "url": "https://github.com/Upstatement/routes.git",
272
- "reference": "e2711a97c754f2cccf366a8b70106ec27eec933a"
273
  },
274
  "dist": {
275
  "type": "zip",
276
- "url": "https://api.github.com/repos/Upstatement/routes/zipball/e2711a97c754f2cccf366a8b70106ec27eec933a",
277
- "reference": "e2711a97c754f2cccf366a8b70106ec27eec933a",
278
  "shasum": ""
279
  },
280
  "require": {
@@ -287,9 +287,9 @@
287
  "satooshi/php-coveralls": "dev-master",
288
  "wp-cli/wp-cli": "*"
289
  },
290
- "time": "2015-03-05 13:17:27",
291
  "type": "library",
292
- "installation-source": "source",
293
  "autoload": {
294
  "psr-0": {
295
  "Routes": ""
98
  },
99
  {
100
  "name": "twig/twig",
101
+ "version": "v1.18.1",
102
+ "version_normalized": "1.18.1.0",
103
  "source": {
104
  "type": "git",
105
  "url": "https://github.com/twigphp/Twig.git",
106
+ "reference": "9f70492f44398e276d1b81c1b43adfe6751c7b7f"
107
  },
108
  "dist": {
109
  "type": "zip",
110
+ "url": "https://api.github.com/repos/twigphp/Twig/zipball/9f70492f44398e276d1b81c1b43adfe6751c7b7f",
111
+ "reference": "9f70492f44398e276d1b81c1b43adfe6751c7b7f",
112
  "shasum": ""
113
  },
114
  "require": {
115
+ "php": ">=5.2.7"
116
  },
117
+ "time": "2015-04-19 08:30:27",
118
  "type": "library",
119
  "extra": {
120
  "branch-alias": {
264
  },
265
  {
266
  "name": "upstatement/routes",
267
+ "version": "0.3",
268
+ "version_normalized": "0.3.0.0",
269
  "source": {
270
  "type": "git",
271
  "url": "https://github.com/Upstatement/routes.git",
272
+ "reference": "40d003b69c0f5c52fb4b15e5d1fa4d5c522c9475"
273
  },
274
  "dist": {
275
  "type": "zip",
276
+ "url": "https://api.github.com/repos/Upstatement/routes/zipball/40d003b69c0f5c52fb4b15e5d1fa4d5c522c9475",
277
+ "reference": "40d003b69c0f5c52fb4b15e5d1fa4d5c522c9475",
278
  "shasum": ""
279
  },
280
  "require": {
287
  "satooshi/php-coveralls": "dev-master",
288
  "wp-cli/wp-cli": "*"
289
  },
290
+ "time": "2015-03-07 13:41:29",
291
  "type": "library",
292
+ "installation-source": "dist",
293
  "autoload": {
294
  "psr-0": {
295
  "Routes": ""
vendor/twig/twig/.travis.yml CHANGED
@@ -7,6 +7,12 @@ php:
7
  - 5.5
8
  - 5.6
9
  - hhvm
 
 
 
 
 
 
10
 
11
  env:
12
  - TWIG_EXT=no
@@ -20,3 +26,7 @@ matrix:
20
  exclude:
21
  - php: hhvm
22
  env: TWIG_EXT=yes
 
 
 
 
7
  - 5.5
8
  - 5.6
9
  - hhvm
10
+ - nightly
11
+ - hhvm-nightly
12
+
13
+ allow_failures:
14
+ - php: nightly
15
+ - php: hhvm-nightly
16
 
17
  env:
18
  - TWIG_EXT=no
26
  exclude:
27
  - php: hhvm
28
  env: TWIG_EXT=yes
29
+ - php: hhvm-nightly
30
+ env: TWIG_EXT=yes
31
+ - php: nightly
32
+ env: TWIG_EXT=yes
vendor/twig/twig/CHANGELOG CHANGED
@@ -1,4 +1,11 @@
1
- * 1.18.0 (2015-XX-XX)
 
 
 
 
 
 
 
2
 
3
  * fixed some error messages where the line was wrong (unknown variables or argument names)
4
  * added a new way to customize the main Module node (via empty nodes)
1
+ * 1.18.1 (2015-04-19)
2
+
3
+ * fixed memory leaks in the C extension
4
+ * deprecated Twig_Loader_String
5
+ * fixed the slice filter when used with a SimpleXMLElement object
6
+ * fixed filesystem loader when trying to load non-files (like directories)
7
+
8
+ * 1.18.0 (2015-01-25)
9
 
10
  * fixed some error messages where the line was wrong (unknown variables or argument names)
11
  * added a new way to customize the main Module node (via empty nodes)
vendor/twig/twig/composer.json CHANGED
@@ -27,7 +27,7 @@
27
  "forum": "https://groups.google.com/forum/#!forum/twig-users"
28
  },
29
  "require": {
30
- "php": ">=5.2.4"
31
  },
32
  "autoload": {
33
  "psr-0" : {
27
  "forum": "https://groups.google.com/forum/#!forum/twig-users"
28
  },
29
  "require": {
30
+ "php": ">=5.2.7"
31
  },
32
  "autoload": {
33
  "psr-0" : {
vendor/twig/twig/doc/api.rst CHANGED
@@ -106,7 +106,9 @@ The following options are available:
106
  to avoid collision with built-in escaping strategies).
107
 
108
  As of Twig 1.17, the ``filename`` escaping strategy determines the escaping
109
- strategy to use for a template based on the template filename extension.
 
 
110
 
111
  * ``optimizations``: A flag that indicates which optimizations to apply
112
  (default to ``-1`` -- all optimizations are enabled; set it to ``0`` to
106
  to avoid collision with built-in escaping strategies).
107
 
108
  As of Twig 1.17, the ``filename`` escaping strategy determines the escaping
109
+ strategy to use for a template based on the template filename extension (this
110
+ strategy does not incur any overhead at runtime as auto-escaping is done at
111
+ compilation time.)
112
 
113
  * ``optimizations``: A flag that indicates which optimizations to apply
114
  (default to ``-1`` -- all optimizations are enabled; set it to ``0`` to
vendor/twig/twig/doc/deprecated.rst CHANGED
@@ -101,6 +101,12 @@ Interfaces
101
  those constants Twig_Template::ANY_CALL, Twig_Template::ARRAY_CALL,
102
  Twig_Template::METHOD_CALL)
103
 
 
 
 
 
 
 
104
  Globals
105
  -------
106
 
101
  those constants Twig_Template::ANY_CALL, Twig_Template::ARRAY_CALL,
102
  Twig_Template::METHOD_CALL)
103
 
104
+ Loaders
105
+ -------
106
+
107
+ * As of Twig 1.x, ``Twig_Loader_String`` is deprecated and will be removed in
108
+ 2.0.
109
+
110
  Globals
111
  -------
112
 
vendor/twig/twig/doc/installation.rst CHANGED
@@ -50,8 +50,11 @@ Installing the C extension
50
  The C extension was added in Twig 1.4.
51
 
52
  .. note::
53
- The C extension is **optional** but as it brings some nice performance
54
- improvements, you might want to install it in your production environment.
 
 
 
55
 
56
  Twig comes with a C extension that enhances the performance of the Twig
57
  runtime engine; install it like any other PHP extensions:
50
  The C extension was added in Twig 1.4.
51
 
52
  .. note::
53
+
54
+ The C extension is **optional** but it brings some nice performance
55
+ improvements. Note that the extension is not a replacement for the PHP
56
+ code; it only implements a small part of the PHP code to improve the
57
+ performance at runtime; you must still install the regular PHP code.
58
 
59
  Twig comes with a C extension that enhances the performance of the Twig
60
  runtime engine; install it like any other PHP extensions:
vendor/twig/twig/doc/recipes.rst CHANGED
@@ -316,56 +316,6 @@ This can be easily achieved with the following code::
316
  return $node;
317
  }
318
 
319
- Using the Template name to set the default Escaping Strategy
320
- ------------------------------------------------------------
321
-
322
- .. versionadded:: 1.8
323
- This recipe requires Twig 1.8 or later.
324
-
325
- The ``autoescape`` option determines the default escaping strategy to use when
326
- no escaping is applied on a variable. When Twig is used to mostly generate
327
- HTML files, you can set it to ``html`` and explicitly change it to ``js`` when
328
- you have some dynamic JavaScript files thanks to the ``autoescape`` tag:
329
-
330
- .. code-block:: jinja
331
-
332
- {% autoescape 'js' %}
333
- ... some JS ...
334
- {% endautoescape %}
335
-
336
- But if you have many HTML and JS files, and if your template names follow some
337
- conventions, you can instead determine the default escaping strategy to use
338
- based on the template name. Let's say that your template names always end
339
- with ``.html`` for HTML files, ``.js`` for JavaScript ones, and ``.css`` for
340
- stylesheets, here is how you can configure Twig::
341
-
342
- class TwigEscapingGuesser
343
- {
344
- function guess($filename)
345
- {
346
- // get the format
347
- $format = substr($filename, strrpos($filename, '.') + 1);
348
-
349
- switch ($format) {
350
- case 'js':
351
- return 'js';
352
- case 'css':
353
- return 'css';
354
- case 'html':
355
- default:
356
- return 'html';
357
- }
358
- }
359
- }
360
-
361
- $loader = new Twig_Loader_Filesystem('/path/to/templates');
362
- $twig = new Twig_Environment($loader, array(
363
- 'autoescape' => array(new TwigEscapingGuesser(), 'guess'),
364
- ));
365
-
366
- This dynamic strategy does not incur any overhead at runtime as auto-escaping
367
- is done at compilation time.
368
-
369
  Using a Database to store Templates
370
  -----------------------------------
371
 
316
  return $node;
317
  }
318
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
  Using a Database to store Templates
320
  -----------------------------------
321
 
vendor/twig/twig/ext/twig/php_twig.h CHANGED
@@ -15,17 +15,21 @@
15
  #ifndef PHP_TWIG_H
16
  #define PHP_TWIG_H
17
 
18
- #define PHP_TWIG_VERSION "1.18.0"
19
 
20
  #include "php.h"
21
 
22
  extern zend_module_entry twig_module_entry;
23
  #define phpext_twig_ptr &twig_module_entry
 
 
 
24
 
25
  #ifdef ZTS
26
  #include "TSRM.h"
27
  #endif
28
 
29
  PHP_FUNCTION(twig_template_get_attributes);
 
30
 
31
  #endif
15
  #ifndef PHP_TWIG_H
16
  #define PHP_TWIG_H
17
 
18
+ #define PHP_TWIG_VERSION "1.18.1"
19
 
20
  #include "php.h"
21
 
22
  extern zend_module_entry twig_module_entry;
23
  #define phpext_twig_ptr &twig_module_entry
24
+ #ifndef PHP_WIN32
25
+ zend_module_entry *get_module(void);
26
+ #endif
27
 
28
  #ifdef ZTS
29
  #include "TSRM.h"
30
  #endif
31
 
32
  PHP_FUNCTION(twig_template_get_attributes);
33
+ PHP_RSHUTDOWN_FUNCTION(twig);
34
 
35
  #endif
vendor/twig/twig/ext/twig/twig.c CHANGED
@@ -54,11 +54,22 @@ ZEND_BEGIN_ARG_INFO_EX(twig_template_get_attribute_args, ZEND_SEND_BY_VAL, ZEND_
54
  ZEND_ARG_INFO(0, isDefinedTest)
55
  ZEND_END_ARG_INFO()
56
 
57
- zend_function_entry twig_functions[] = {
 
 
 
 
58
  PHP_FE(twig_template_get_attributes, twig_template_get_attribute_args)
59
- {NULL, NULL, NULL}
60
  };
61
 
 
 
 
 
 
 
 
62
 
63
  zend_module_entry twig_module_entry = {
64
  STANDARD_MODULE_HEADER,
@@ -67,7 +78,7 @@ zend_module_entry twig_module_entry = {
67
  NULL,
68
  NULL,
69
  NULL,
70
- NULL,
71
  NULL,
72
  PHP_TWIG_VERSION,
73
  STANDARD_MODULE_PROPERTIES
@@ -78,7 +89,7 @@ zend_module_entry twig_module_entry = {
78
  ZEND_GET_MODULE(twig)
79
  #endif
80
 
81
- int TWIG_ARRAY_KEY_EXISTS(zval *array, zval *key)
82
  {
83
  if (Z_TYPE_P(array) != IS_ARRAY) {
84
  return 0;
@@ -100,7 +111,7 @@ int TWIG_ARRAY_KEY_EXISTS(zval *array, zval *key)
100
  }
101
  }
102
 
103
- int TWIG_INSTANCE_OF(zval *object, zend_class_entry *interface TSRMLS_DC)
104
  {
105
  if (Z_TYPE_P(object) != IS_OBJECT) {
106
  return 0;
@@ -108,7 +119,7 @@ int TWIG_INSTANCE_OF(zval *object, zend_class_entry *interface TSRMLS_DC)
108
  return instanceof_function(Z_OBJCE_P(object), interface TSRMLS_CC);
109
  }
110
 
111
- int TWIG_INSTANCE_OF_USERLAND(zval *object, char *interface TSRMLS_DC)
112
  {
113
  zend_class_entry **pce;
114
  if (Z_TYPE_P(object) != IS_OBJECT) {
@@ -120,7 +131,7 @@ int TWIG_INSTANCE_OF_USERLAND(zval *object, char *interface TSRMLS_DC)
120
  return instanceof_function(Z_OBJCE_P(object), *pce TSRMLS_CC);
121
  }
122
 
123
- zval *TWIG_GET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
124
  {
125
  zend_class_entry *ce = Z_OBJCE_P(object);
126
  zval *retval;
@@ -143,7 +154,7 @@ zval *TWIG_GET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
143
  return NULL;
144
  }
145
 
146
- int TWIG_ISSET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
147
  {
148
  zend_class_entry *ce = Z_OBJCE_P(object);
149
  zval *retval;
@@ -166,7 +177,7 @@ int TWIG_ISSET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
166
  return 0;
167
  }
168
 
169
- char *TWIG_STRTOLOWER(const char *str, int str_len)
170
  {
171
  char *item_dup;
172
 
@@ -175,7 +186,7 @@ char *TWIG_STRTOLOWER(const char *str, int str_len)
175
  return item_dup;
176
  }
177
 
178
- zval *TWIG_CALL_USER_FUNC_ARRAY(zval *object, char *function, zval *arguments TSRMLS_DC)
179
  {
180
  zend_fcall_info fci;
181
  zval ***args = NULL;
@@ -227,7 +238,7 @@ zval *TWIG_CALL_USER_FUNC_ARRAY(zval *object, char *function, zval *arguments TS
227
  return retval_ptr;
228
  }
229
 
230
- int TWIG_CALL_BOOLEAN(zval *object, char *functionName TSRMLS_DC)
231
  {
232
  zval *ret;
233
  int res;
@@ -238,7 +249,7 @@ int TWIG_CALL_BOOLEAN(zval *object, char *functionName TSRMLS_DC)
238
  return res;
239
  }
240
 
241
- zval *TWIG_GET_STATIC_PROPERTY(zval *class, char *prop_name TSRMLS_DC)
242
  {
243
  zval **tmp_zval;
244
  zend_class_entry *ce;
@@ -256,7 +267,7 @@ zval *TWIG_GET_STATIC_PROPERTY(zval *class, char *prop_name TSRMLS_DC)
256
  return *tmp_zval;
257
  }
258
 
259
- zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC)
260
  {
261
  zval **tmp_zval;
262
 
@@ -288,7 +299,7 @@ zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC)
288
  return NULL;
289
  }
290
 
291
- zval *TWIG_GET_ARRAY_ELEMENT(zval *class, char *prop_name, int prop_name_length TSRMLS_DC)
292
  {
293
  zval **tmp_zval;
294
 
@@ -314,7 +325,7 @@ zval *TWIG_GET_ARRAY_ELEMENT(zval *class, char *prop_name, int prop_name_length
314
  return NULL;
315
  }
316
 
317
- zval *TWIG_PROPERTY(zval *object, zval *propname TSRMLS_DC)
318
  {
319
  zval *tmp = NULL;
320
 
@@ -331,7 +342,7 @@ zval *TWIG_PROPERTY(zval *object, zval *propname TSRMLS_DC)
331
  return tmp;
332
  }
333
 
334
- int TWIG_HAS_PROPERTY(zval *object, zval *propname TSRMLS_DC)
335
  {
336
  if (Z_OBJ_HT_P(object)->has_property) {
337
  #if PHP_VERSION_ID >= 50400
@@ -343,7 +354,7 @@ int TWIG_HAS_PROPERTY(zval *object, zval *propname TSRMLS_DC)
343
  return 0;
344
  }
345
 
346
- int TWIG_HAS_DYNAMIC_PROPERTY(zval *object, char *prop, int prop_len TSRMLS_DC)
347
  {
348
  if (Z_OBJ_HT_P(object)->get_properties) {
349
  return zend_hash_quick_exists(
@@ -356,7 +367,7 @@ int TWIG_HAS_DYNAMIC_PROPERTY(zval *object, char *prop, int prop_len TSRMLS_DC)
356
  return 0;
357
  }
358
 
359
- zval *TWIG_PROPERTY_CHAR(zval *object, char *propname TSRMLS_DC)
360
  {
361
  zval *tmp_name_zval, *tmp;
362
 
@@ -367,12 +378,7 @@ zval *TWIG_PROPERTY_CHAR(zval *object, char *propname TSRMLS_DC)
367
  return tmp;
368
  }
369
 
370
- int TWIG_CALL_B_0(zval *object, char *method)
371
- {
372
- return 0;
373
- }
374
-
375
- zval *TWIG_CALL_S(zval *object, char *method, char *arg0 TSRMLS_DC)
376
  {
377
  zend_fcall_info fci;
378
  zval **args[1];
@@ -410,7 +416,7 @@ zval *TWIG_CALL_S(zval *object, char *method, char *arg0 TSRMLS_DC)
410
  return retval_ptr;
411
  }
412
 
413
- int TWIG_CALL_SB(zval *object, char *method, char *arg0 TSRMLS_DC)
414
  {
415
  zval *retval_ptr;
416
  int success;
@@ -425,51 +431,7 @@ int TWIG_CALL_SB(zval *object, char *method, char *arg0 TSRMLS_DC)
425
  return success;
426
  }
427
 
428
- int TWIG_CALL_Z(zval *object, char *method, zval *arg1 TSRMLS_DC)
429
- {
430
- zend_fcall_info fci;
431
- zval **args[1];
432
- zval *zfunction;
433
- zval *retval_ptr;
434
- int success;
435
-
436
- args[0] = &arg1;
437
-
438
- MAKE_STD_ZVAL(zfunction);
439
- ZVAL_STRING(zfunction, method, 1);
440
- fci.size = sizeof(fci);
441
- fci.function_table = EG(function_table);
442
- fci.function_name = zfunction;
443
- fci.symbol_table = NULL;
444
- #if PHP_VERSION_ID >= 50300
445
- fci.object_ptr = object;
446
- #else
447
- fci.object_pp = &object;
448
- #endif
449
- fci.retval_ptr_ptr = &retval_ptr;
450
- fci.param_count = 1;
451
- fci.params = args;
452
- fci.no_separation = 0;
453
-
454
- if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
455
- FREE_DTOR(zfunction);
456
- if (retval_ptr) {
457
- zval_ptr_dtor(&retval_ptr);
458
- }
459
- return 0;
460
- }
461
-
462
- FREE_DTOR(zfunction);
463
-
464
- success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr));
465
- if (retval_ptr) {
466
- zval_ptr_dtor(&retval_ptr);
467
- }
468
-
469
- return success;
470
- }
471
-
472
- int TWIG_CALL_ZZ(zval *object, char *method, zval *arg1, zval *arg2 TSRMLS_DC)
473
  {
474
  zend_fcall_info fci;
475
  zval **args[2];
@@ -516,7 +478,7 @@ int TWIG_CALL_ZZ(zval *object, char *method, zval *arg1, zval *arg2 TSRMLS_DC)
516
  # define Z_UNSET_ISREF_P(pz) pz->is_ref = 0
517
  #endif
518
 
519
- void TWIG_NEW(zval *object, char *class, zval *arg0, zval *arg1 TSRMLS_DC)
520
  {
521
  zend_class_entry **pce;
522
 
@@ -561,7 +523,7 @@ static int twig_add_array_key_to_string(void *pDest APPLY_TSRMLS_DC, int num_arg
561
  return 0;
562
  }
563
 
564
- char *TWIG_IMPLODE_ARRAY_KEYS(char *joiner, zval *array TSRMLS_DC)
565
  {
566
  smart_str collector = { 0, 0, 0 };
567
 
@@ -572,24 +534,6 @@ char *TWIG_IMPLODE_ARRAY_KEYS(char *joiner, zval *array TSRMLS_DC)
572
  return collector.c;
573
  }
574
 
575
- static void TWIG_THROW_EXCEPTION(char *exception_name TSRMLS_DC, char *message, ...)
576
- {
577
- char *buffer;
578
- va_list args;
579
- zend_class_entry **pce;
580
-
581
- if (zend_lookup_class(exception_name, strlen(exception_name), &pce TSRMLS_CC) == FAILURE) {
582
- return;
583
- }
584
-
585
- va_start(args, message);
586
- vspprintf(&buffer, 0, message, args);
587
- va_end(args);
588
-
589
- zend_throw_exception_ex(*pce, 0 TSRMLS_CC, buffer);
590
- efree(buffer);
591
- }
592
-
593
  static void TWIG_RUNTIME_ERROR(zval *template TSRMLS_DC, char *message, ...)
594
  {
595
  char *buffer;
@@ -794,6 +738,7 @@ PHP_FUNCTION(twig_template_get_attributes)
794
  ) {
795
 
796
  if (isDefinedTest) {
 
797
  RETURN_TRUE;
798
  }
799
 
@@ -806,6 +751,7 @@ PHP_FUNCTION(twig_template_get_attributes)
806
  if (free_ret) {
807
  zval_ptr_dtor(&ret);
808
  }
 
809
  return;
810
  }
811
  /*
@@ -819,9 +765,11 @@ PHP_FUNCTION(twig_template_get_attributes)
819
  */
820
  if (strcmp("array", type) == 0 || Z_TYPE_P(object) != IS_OBJECT) {
821
  if (isDefinedTest) {
 
822
  RETURN_FALSE;
823
  }
824
  if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
 
825
  return;
826
  }
827
  /*
@@ -852,7 +800,9 @@ PHP_FUNCTION(twig_template_get_attributes)
852
  if (0 == zend_hash_num_elements(Z_ARRVAL_P(object))) {
853
  TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" does not exist as the array is empty", item);
854
  } else {
855
- TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" for array with keys \"%s\" does not exist", item, TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC));
 
 
856
  }
857
  } else {
858
  char *type_name = zend_zval_type_name(object);
@@ -865,6 +815,7 @@ PHP_FUNCTION(twig_template_get_attributes)
865
  item, type_name, Z_STRVAL_P(object));
866
  zval_ptr_dtor(&object);
867
  }
 
868
  return;
869
  }
870
  }
@@ -878,6 +829,7 @@ PHP_FUNCTION(twig_template_get_attributes)
878
 
879
  if (Z_TYPE_P(object) != IS_OBJECT) {
880
  if (isDefinedTest) {
 
881
  RETURN_FALSE;
882
  }
883
  /*
@@ -888,6 +840,7 @@ PHP_FUNCTION(twig_template_get_attributes)
888
  }
889
  */
890
  if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
 
891
  return;
892
  }
893
 
@@ -898,7 +851,7 @@ PHP_FUNCTION(twig_template_get_attributes)
898
  TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to invoke a method (\"%s\") on a %s variable (\"%s\")", item, type_name, Z_STRVAL_P(object));
899
 
900
  zval_ptr_dtor(&object);
901
-
902
  return;
903
  }
904
  /*
@@ -939,16 +892,19 @@ PHP_FUNCTION(twig_template_get_attributes)
939
 
940
  if (tmp_item || TWIG_HAS_PROPERTY(object, zitem TSRMLS_CC) || TWIG_HAS_DYNAMIC_PROPERTY(object, item, item_len TSRMLS_CC)) {
941
  if (isDefinedTest) {
 
942
  RETURN_TRUE;
943
  }
944
  if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
945
  TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkPropertyAllowed", object, zitem TSRMLS_CC);
946
  }
947
  if (EG(exception)) {
 
948
  return;
949
  }
950
 
951
  ret = TWIG_PROPERTY(object, zitem TSRMLS_CC);
 
952
  RETURN_ZVAL(ret, 1, 0);
953
  }
954
  }
@@ -1021,19 +977,22 @@ PHP_FUNCTION(twig_template_get_attributes)
1021
  efree(lcItem);
1022
 
1023
  if (isDefinedTest) {
 
1024
  RETURN_FALSE;
1025
  }
1026
  if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
 
1027
  return;
1028
  }
1029
  TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Method \"%s\" for object \"%s\" does not exist", item, TWIG_GET_CLASS_NAME(object TSRMLS_CC));
 
1030
  return;
1031
  }
1032
 
1033
  if (isDefinedTest) {
1034
  efree(tmp_method_name_get);
1035
  efree(tmp_method_name_is);
1036
- efree(lcItem);
1037
  RETURN_TRUE;
1038
  }
1039
  /*
@@ -1046,11 +1005,11 @@ PHP_FUNCTION(twig_template_get_attributes)
1046
  if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
1047
  TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkMethodAllowed", object, zmethod TSRMLS_CC);
1048
  }
 
1049
  if (EG(exception)) {
1050
  efree(tmp_method_name_get);
1051
  efree(tmp_method_name_is);
1052
- efree(lcItem);
1053
- zval_ptr_dtor(&zmethod);
1054
  return;
1055
  }
1056
  /*
@@ -1068,6 +1027,9 @@ PHP_FUNCTION(twig_template_get_attributes)
1068
  ret = TWIG_CALL_USER_FUNC_ARRAY(object, method, arguments TSRMLS_CC);
1069
  if (EG(exception) && TWIG_INSTANCE_OF(EG(exception), spl_ce_BadMethodCallException TSRMLS_CC)) {
1070
  if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
 
 
 
1071
  zend_clear_exception(TSRMLS_C);
1072
  return;
1073
  }
@@ -1076,7 +1038,6 @@ PHP_FUNCTION(twig_template_get_attributes)
1076
  efree(tmp_method_name_get);
1077
  efree(tmp_method_name_is);
1078
  efree(lcItem);
1079
- zval_ptr_dtor(&zmethod);
1080
  }
1081
  /*
1082
  // useful when calling a template method from a template
@@ -1087,6 +1048,7 @@ PHP_FUNCTION(twig_template_get_attributes)
1087
 
1088
  return $ret;
1089
  */
 
1090
  // ret can be null, if e.g. the called method throws an exception
1091
  if (ret) {
1092
  if (TWIG_INSTANCE_OF_USERLAND(object, "Twig_TemplateInterface" TSRMLS_CC)) {
54
  ZEND_ARG_INFO(0, isDefinedTest)
55
  ZEND_END_ARG_INFO()
56
 
57
+ #ifndef PHP_FE_END
58
+ #define PHP_FE_END { NULL, NULL, NULL, 0, 0 }
59
+ #endif
60
+
61
+ static const zend_function_entry twig_functions[] = {
62
  PHP_FE(twig_template_get_attributes, twig_template_get_attribute_args)
63
+ PHP_FE_END
64
  };
65
 
66
+ PHP_RSHUTDOWN_FUNCTION(twig)
67
+ {
68
+ #if ZEND_DEBUG
69
+ CG(unclean_shutdown) = 0; /* get rid of PHPUnit's exit() and report memleaks */
70
+ #endif
71
+ return SUCCESS;
72
+ }
73
 
74
  zend_module_entry twig_module_entry = {
75
  STANDARD_MODULE_HEADER,
78
  NULL,
79
  NULL,
80
  NULL,
81
+ PHP_RSHUTDOWN(twig),
82
  NULL,
83
  PHP_TWIG_VERSION,
84
  STANDARD_MODULE_PROPERTIES
89
  ZEND_GET_MODULE(twig)
90
  #endif
91
 
92
+ static int TWIG_ARRAY_KEY_EXISTS(zval *array, zval *key)
93
  {
94
  if (Z_TYPE_P(array) != IS_ARRAY) {
95
  return 0;
111
  }
112
  }
113
 
114
+ static int TWIG_INSTANCE_OF(zval *object, zend_class_entry *interface TSRMLS_DC)
115
  {
116
  if (Z_TYPE_P(object) != IS_OBJECT) {
117
  return 0;
119
  return instanceof_function(Z_OBJCE_P(object), interface TSRMLS_CC);
120
  }
121
 
122
+ static int TWIG_INSTANCE_OF_USERLAND(zval *object, char *interface TSRMLS_DC)
123
  {
124
  zend_class_entry **pce;
125
  if (Z_TYPE_P(object) != IS_OBJECT) {
131
  return instanceof_function(Z_OBJCE_P(object), *pce TSRMLS_CC);
132
  }
133
 
134
+ static zval *TWIG_GET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
135
  {
136
  zend_class_entry *ce = Z_OBJCE_P(object);
137
  zval *retval;
154
  return NULL;
155
  }
156
 
157
+ static int TWIG_ISSET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
158
  {
159
  zend_class_entry *ce = Z_OBJCE_P(object);
160
  zval *retval;
177
  return 0;
178
  }
179
 
180
+ static char *TWIG_STRTOLOWER(const char *str, int str_len)
181
  {
182
  char *item_dup;
183
 
186
  return item_dup;
187
  }
188
 
189
+ static zval *TWIG_CALL_USER_FUNC_ARRAY(zval *object, char *function, zval *arguments TSRMLS_DC)
190
  {
191
  zend_fcall_info fci;
192
  zval ***args = NULL;
238
  return retval_ptr;
239
  }
240
 
241
+ static int TWIG_CALL_BOOLEAN(zval *object, char *functionName TSRMLS_DC)
242
  {
243
  zval *ret;
244
  int res;
249
  return res;
250
  }
251
 
252
+ static zval *TWIG_GET_STATIC_PROPERTY(zval *class, char *prop_name TSRMLS_DC)
253
  {
254
  zval **tmp_zval;
255
  zend_class_entry *ce;
267
  return *tmp_zval;
268
  }
269
 
270
+ static zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC)
271
  {
272
  zval **tmp_zval;
273
 
299
  return NULL;
300
  }
301
 
302
+ static zval *TWIG_GET_ARRAY_ELEMENT(zval *class, char *prop_name, int prop_name_length TSRMLS_DC)
303
  {
304
  zval **tmp_zval;
305
 
325
  return NULL;
326
  }
327
 
328
+ static zval *TWIG_PROPERTY(zval *object, zval *propname TSRMLS_DC)
329
  {
330
  zval *tmp = NULL;
331
 
342
  return tmp;
343
  }
344
 
345
+ static int TWIG_HAS_PROPERTY(zval *object, zval *propname TSRMLS_DC)
346
  {
347
  if (Z_OBJ_HT_P(object)->has_property) {
348
  #if PHP_VERSION_ID >= 50400
354
  return 0;
355
  }
356
 
357
+ static int TWIG_HAS_DYNAMIC_PROPERTY(zval *object, char *prop, int prop_len TSRMLS_DC)
358
  {
359
  if (Z_OBJ_HT_P(object)->get_properties) {
360
  return zend_hash_quick_exists(
367
  return 0;
368
  }
369
 
370
+ static zval *TWIG_PROPERTY_CHAR(zval *object, char *propname TSRMLS_DC)
371
  {
372
  zval *tmp_name_zval, *tmp;
373
 
378
  return tmp;
379
  }
380
 
381
+ static zval *TWIG_CALL_S(zval *object, char *method, char *arg0 TSRMLS_DC)
 
 
 
 
 
382
  {
383
  zend_fcall_info fci;
384
  zval **args[1];
416
  return retval_ptr;
417
  }
418
 
419
+ static int TWIG_CALL_SB(zval *object, char *method, char *arg0 TSRMLS_DC)
420
  {
421
  zval *retval_ptr;
422
  int success;
431
  return success;
432
  }
433
 
434
+ static int TWIG_CALL_ZZ(zval *object, char *method, zval *arg1, zval *arg2 TSRMLS_DC)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
435
  {
436
  zend_fcall_info fci;
437
  zval **args[2];
478
  # define Z_UNSET_ISREF_P(pz) pz->is_ref = 0
479
  #endif
480
 
481
+ static void TWIG_NEW(zval *object, char *class, zval *arg0, zval *arg1 TSRMLS_DC)
482
  {
483
  zend_class_entry **pce;
484
 
523
  return 0;
524
  }
525
 
526
+ static char *TWIG_IMPLODE_ARRAY_KEYS(char *joiner, zval *array TSRMLS_DC)
527
  {
528
  smart_str collector = { 0, 0, 0 };
529
 
534
  return collector.c;
535
  }
536
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
537
  static void TWIG_RUNTIME_ERROR(zval *template TSRMLS_DC, char *message, ...)
538
  {
539
  char *buffer;
738
  ) {
739
 
740
  if (isDefinedTest) {
741
+ efree(item);
742
  RETURN_TRUE;
743
  }
744
 
751
  if (free_ret) {
752
  zval_ptr_dtor(&ret);
753
  }
754
+ efree(item);
755
  return;
756
  }
757
  /*
765
  */
766
  if (strcmp("array", type) == 0 || Z_TYPE_P(object) != IS_OBJECT) {
767
  if (isDefinedTest) {
768
+ efree(item);
769
  RETURN_FALSE;
770
  }
771
  if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
772
+ efree(item);
773
  return;
774
  }
775
  /*
800
  if (0 == zend_hash_num_elements(Z_ARRVAL_P(object))) {
801
  TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" does not exist as the array is empty", item);
802
  } else {
803
+ char *array_keys = TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC);
804
+ TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" for array with keys \"%s\" does not exist", item, array_keys);
805
+ efree(array_keys);
806
  }
807
  } else {
808
  char *type_name = zend_zval_type_name(object);
815
  item, type_name, Z_STRVAL_P(object));
816
  zval_ptr_dtor(&object);
817
  }
818
+ efree(item);
819
  return;
820
  }
821
  }
829
 
830
  if (Z_TYPE_P(object) != IS_OBJECT) {
831
  if (isDefinedTest) {
832
+ efree(item);
833
  RETURN_FALSE;
834
  }
835
  /*
840
  }
841
  */
842
  if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
843
+ efree(item);
844
  return;
845
  }
846
 
851
  TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to invoke a method (\"%s\") on a %s variable (\"%s\")", item, type_name, Z_STRVAL_P(object));
852
 
853
  zval_ptr_dtor(&object);
854
+ efree(item);
855
  return;
856
  }
857
  /*
892
 
893
  if (tmp_item || TWIG_HAS_PROPERTY(object, zitem TSRMLS_CC) || TWIG_HAS_DYNAMIC_PROPERTY(object, item, item_len TSRMLS_CC)) {
894
  if (isDefinedTest) {
895
+ efree(item);
896
  RETURN_TRUE;
897
  }
898
  if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
899
  TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkPropertyAllowed", object, zitem TSRMLS_CC);
900
  }
901
  if (EG(exception)) {
902
+ efree(item);
903
  return;
904
  }
905
 
906
  ret = TWIG_PROPERTY(object, zitem TSRMLS_CC);
907
+ efree(item);
908
  RETURN_ZVAL(ret, 1, 0);
909
  }
910
  }
977
  efree(lcItem);
978
 
979
  if (isDefinedTest) {
980
+ efree(item);
981
  RETURN_FALSE;
982
  }
983
  if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
984
+ efree(item);
985
  return;
986
  }
987
  TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Method \"%s\" for object \"%s\" does not exist", item, TWIG_GET_CLASS_NAME(object TSRMLS_CC));
988
+ efree(item);
989
  return;
990
  }
991
 
992
  if (isDefinedTest) {
993
  efree(tmp_method_name_get);
994
  efree(tmp_method_name_is);
995
+ efree(lcItem);efree(item);
996
  RETURN_TRUE;
997
  }
998
  /*
1005
  if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
1006
  TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkMethodAllowed", object, zmethod TSRMLS_CC);
1007
  }
1008
+ zval_ptr_dtor(&zmethod);
1009
  if (EG(exception)) {
1010
  efree(tmp_method_name_get);
1011
  efree(tmp_method_name_is);
1012
+ efree(lcItem);efree(item);
 
1013
  return;
1014
  }
1015
  /*
1027
  ret = TWIG_CALL_USER_FUNC_ARRAY(object, method, arguments TSRMLS_CC);
1028
  if (EG(exception) && TWIG_INSTANCE_OF(EG(exception), spl_ce_BadMethodCallException TSRMLS_CC)) {
1029
  if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
1030
+ efree(tmp_method_name_get);
1031
+ efree(tmp_method_name_is);
1032
+ efree(lcItem);efree(item);
1033
  zend_clear_exception(TSRMLS_C);
1034
  return;
1035
  }
1038
  efree(tmp_method_name_get);
1039
  efree(tmp_method_name_is);
1040
  efree(lcItem);
 
1041
  }
1042
  /*
1043
  // useful when calling a template method from a template
1048
 
1049
  return $ret;
1050
  */
1051
+ efree(item);
1052
  // ret can be null, if e.g. the called method throws an exception
1053
  if (ret) {
1054
  if (TWIG_INSTANCE_OF_USERLAND(object, "Twig_TemplateInterface" TSRMLS_CC)) {
vendor/twig/twig/lib/Twig/Autoloader.php CHANGED
@@ -23,10 +23,10 @@ class Twig_Autoloader
23
  */
24
  public static function register($prepend = false)
25
  {
26
- if (version_compare(phpversion(), '5.3.0', '>=')) {
27
- spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
28
- } else {
29
  spl_autoload_register(array(__CLASS__, 'autoload'));
 
 
30
  }
31
  }
32
 
23
  */
24
  public static function register($prepend = false)
25
  {
26
+ if (PHP_VERSION_ID < 50300) {
 
 
27
  spl_autoload_register(array(__CLASS__, 'autoload'));
28
+ } else {
29
+ spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
30
  }
31
  }
32
 
vendor/twig/twig/lib/Twig/Environment.php CHANGED
@@ -16,7 +16,7 @@
16
  */
17
  class Twig_Environment
18
  {
19
- const VERSION = '1.18.0';
20
 
21
  protected $charset;
22
  protected $loader;
16
  */
17
  class Twig_Environment
18
  {
19
+ const VERSION = '1.18.1';
20
 
21
  protected $charset;
22
  protected $loader;
vendor/twig/twig/lib/Twig/Error.php CHANGED
@@ -57,7 +57,7 @@ class Twig_Error extends Exception
57
  */
58
  public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
59
  {
60
- if (version_compare(PHP_VERSION, '5.3.0', '<')) {
61
  $this->previous = $previous;
62
  parent::__construct('');
63
  } else {
@@ -188,7 +188,7 @@ class Twig_Error extends Exception
188
  $template = null;
189
  $templateClass = null;
190
 
191
- if (version_compare(phpversion(), '5.3.6', '>=')) {
192
  $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
193
  } else {
194
  $backtrace = debug_backtrace();
57
  */
58
  public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
59
  {
60
+ if (PHP_VERSION_ID < 50300) {
61
  $this->previous = $previous;
62
  parent::__construct('');
63
  } else {
188
  $template = null;
189
  $templateClass = null;
190
 
191
+ if (PHP_VERSION_ID >= 50306) {
192
  $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
193
  } else {
194
  $backtrace = debug_backtrace();
vendor/twig/twig/lib/Twig/Extension/Core.php CHANGED
@@ -617,7 +617,7 @@ function twig_urlencode_filter($url)
617
  return rawurlencode($url);
618
  }
619
 
620
- if (version_compare(PHP_VERSION, '5.3.0', '<')) {
621
  /**
622
  * JSON encodes a variable.
623
  *
@@ -707,7 +707,7 @@ function twig_slice(Twig_Environment $env, $item, $start, $length = null, $prese
707
  $item = $item->getIterator();
708
  }
709
 
710
- if ($start >= 0 && $length >= 0) {
711
  try {
712
  return iterator_to_array(new LimitIterator($item, $start, $length === null ? -1 : $length), $preserveKeys);
713
  } catch (OutOfBoundsException $exception) {
@@ -1073,9 +1073,7 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html',
1073
  return $string;
1074
 
1075
  case 'url':
1076
- // hackish test to avoid version_compare that is much slower, this works unless PHP releases a 5.10.*
1077
- // at that point however PHP 5.2.* support can be removed
1078
- if (PHP_VERSION < '5.3.0') {
1079
  return str_replace('%7E', '~', rawurlencode($string));
1080
  }
1081
 
617
  return rawurlencode($url);
618
  }
619
 
620
+ if (PHP_VERSION_ID < 50300) {
621
  /**
622
  * JSON encodes a variable.
623
  *
707
  $item = $item->getIterator();
708
  }
709
 
710
+ if ($start >= 0 && $length >= 0 && $item instanceof Iterator) {
711
  try {
712
  return iterator_to_array(new LimitIterator($item, $start, $length === null ? -1 : $length), $preserveKeys);
713
  } catch (OutOfBoundsException $exception) {
1073
  return $string;
1074
 
1075
  case 'url':
1076
+ if (PHP_VERSION_ID < 50300) {
 
 
1077
  return str_replace('%7E', '~', rawurlencode($string));
1078
  }
1079
 
vendor/twig/twig/lib/Twig/Loader/Filesystem.php CHANGED
@@ -183,10 +183,11 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
183
  }
184
 
185
  foreach ($this->paths[$namespace] as $path) {
186
- if (false !== $realpath = realpath($path.'/'.$shortname)) {
187
- return $this->cache[$name] = $realpath;
188
- }
189
  if (is_file($path.'/'.$shortname)) {
 
 
 
 
190
  return $this->cache[$name] = $path.'/'.$shortname;
191
  }
192
  }
183
  }
184
 
185
  foreach ($this->paths[$namespace] as $path) {
 
 
 
186
  if (is_file($path.'/'.$shortname)) {
187
+ if (false !== $realpath = realpath($path.'/'.$shortname)) {
188
+ return $this->cache[$name] = $realpath;
189
+ }
190
+
191
  return $this->cache[$name] = $path.'/'.$shortname;
192
  }
193
  }
vendor/twig/twig/lib/Twig/Loader/String.php CHANGED
@@ -19,6 +19,8 @@
19
  * source code of the template). If you don't want to see your cache grows out of
20
  * control, you need to take care of clearing the old cache file by yourself.
21
  *
 
 
22
  * @author Fabien Potencier <fabien@symfony.com>
23
  */
24
  class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
19
  * source code of the template). If you don't want to see your cache grows out of
20
  * control, you need to take care of clearing the old cache file by yourself.
21
  *
22
+ * @deprecated since 1.18.1 (to be removed in 2.0)
23
+ *
24
  * @author Fabien Potencier <fabien@symfony.com>
25
  */
26
  class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
vendor/twig/twig/lib/Twig/Node/Embed.php CHANGED
@@ -28,9 +28,13 @@ class Twig_Node_Embed extends Twig_Node_Include
28
  protected function addGetTemplate(Twig_Compiler $compiler)
29
  {
30
  $compiler
31
- ->write("\$this->env->loadTemplate(")
32
  ->string($this->getAttribute('filename'))
33
  ->raw(', ')
 
 
 
 
34
  ->string($this->getAttribute('index'))
35
  ->raw(")")
36
  ;
28
  protected function addGetTemplate(Twig_Compiler $compiler)
29
  {
30
  $compiler
31
+ ->write("\$this->loadTemplate(")
32
  ->string($this->getAttribute('filename'))
33
  ->raw(', ')
34
+ ->repr($compiler->getFilename())
35
+ ->raw(', ')
36
+ ->repr($this->getLine())
37
+ ->raw(', ')
38
  ->string($this->getAttribute('index'))
39
  ->raw(")")
40
  ;
vendor/twig/twig/lib/Twig/Node/Expression/Call.php CHANGED
@@ -120,6 +120,8 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
120
  } elseif (is_object($callable) && !$callable instanceof Closure) {
121
  $r = new ReflectionObject($callable);
122
  $r = $r->getMethod('__invoke');
 
 
123
  } else {
124
  $r = new ReflectionFunction($callable);
125
  }
120
  } elseif (is_object($callable) && !$callable instanceof Closure) {
121
  $r = new ReflectionObject($callable);
122
  $r = $r->getMethod('__invoke');
123
+ } elseif (is_string($callable) && false !== strpos($callable, '::')) {
124
+ $r = new ReflectionMethod($callable);
125
  } else {
126
  $r = new ReflectionFunction($callable);
127
  }
vendor/twig/twig/lib/Twig/Node/Expression/Name.php CHANGED
@@ -46,7 +46,7 @@ class Twig_Node_Expression_Name extends Twig_Node_Expression
46
  // remove the non-PHP 5.4 version when PHP 5.3 support is dropped
47
  // as the non-optimized version is just a workaround for slow ternary operator
48
  // when the context has a lot of variables
49
- if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
50
  // PHP 5.4 ternary operator performance was optimized
51
  $compiler
52
  ->raw('(isset($context[')
46
  // remove the non-PHP 5.4 version when PHP 5.3 support is dropped
47
  // as the non-optimized version is just a workaround for slow ternary operator
48
  // when the context has a lot of variables
49
+ if (PHP_VERSION_ID >= 50400) {
50
  // PHP 5.4 ternary operator performance was optimized
51
  $compiler
52
  ->raw('(isset($context[')
vendor/twig/twig/lib/Twig/Node/Import.php CHANGED
@@ -39,8 +39,12 @@ class Twig_Node_Import extends Twig_Node
39
  $compiler->raw("\$this");
40
  } else {
41
  $compiler
42
- ->raw('$this->env->loadTemplate(')
43
  ->subcompile($this->getNode('expr'))
 
 
 
 
44
  ->raw(")")
45
  ;
46
  }
39
  $compiler->raw("\$this");
40
  } else {
41
  $compiler
42
+ ->raw('$this->loadTemplate(')
43
  ->subcompile($this->getNode('expr'))
44
+ ->raw(', ')
45
+ ->repr($compiler->getFilename())
46
+ ->raw(', ')
47
+ ->repr($this->getLine())
48
  ->raw(")")
49
  ;
50
  }
vendor/twig/twig/lib/Twig/Node/Include.php CHANGED
@@ -60,12 +60,15 @@ class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface
60
 
61
  protected function addGetTemplate(Twig_Compiler $compiler)
62
  {
63
- $method = $this->getNode('expr') instanceof Twig_Node_Expression_Constant ? 'loadTemplate' : 'resolveTemplate';
64
  $compiler
65
- ->write(sprintf('$this->env->%s(', $method))
66
- ->subcompile($this->getNode('expr'))
67
- ->raw(')')
68
- ;
 
 
 
 
69
  }
70
 
71
  protected function addTemplateArguments(Twig_Compiler $compiler)
60
 
61
  protected function addGetTemplate(Twig_Compiler $compiler)
62
  {
 
63
  $compiler
64
+ ->write("\$this->loadTemplate(")
65
+ ->subcompile($this->getNode('expr'))
66
+ ->raw(', ')
67
+ ->repr($compiler->getFilename())
68
+ ->raw(', ')
69
+ ->repr($this->getLine())
70
+ ->raw(")")
71
+ ;
72
  }
73
 
74
  protected function addTemplateArguments(Twig_Compiler $compiler)
vendor/twig/twig/lib/Twig/Node/Module.php CHANGED
@@ -114,8 +114,12 @@ class Twig_Node_Module extends Twig_Node
114
  $compiler->subcompile($parent);
115
  } else {
116
  $compiler
117
- ->raw("\$this->env->resolveTemplate(")
118
  ->subcompile($parent)
 
 
 
 
119
  ->raw(")")
120
  ;
121
  }
@@ -155,19 +159,13 @@ class Twig_Node_Module extends Twig_Node
155
  } elseif ($parent instanceof Twig_Node_Expression_Constant) {
156
  $compiler
157
  ->addDebugInfo($parent)
158
- ->write("try {\n")
159
- ->indent()
160
- ->write("\$this->parent = \$this->env->loadTemplate(")
161
  ->subcompile($parent)
 
 
 
 
162
  ->raw(");\n")
163
- ->outdent()
164
- ->write("} catch (Twig_Error_Loader \$e) {\n")
165
- ->indent()
166
- ->write("\$e->setTemplateFile(\$this->getTemplateName());\n")
167
- ->write(sprintf("\$e->setTemplateLine(%d);\n\n", $parent->getLine()))
168
- ->write("throw \$e;\n")
169
- ->outdent()
170
- ->write("}\n\n")
171
  ;
172
  }
173
 
@@ -395,8 +393,12 @@ class Twig_Node_Module extends Twig_Node
395
  {
396
  if ($node instanceof Twig_Node_Expression_Constant) {
397
  $compiler
398
- ->write(sprintf("%s = \$this->env->loadTemplate(", $var))
399
  ->subcompile($node)
 
 
 
 
400
  ->raw(");\n")
401
  ;
402
  } else {
@@ -407,7 +409,12 @@ class Twig_Node_Module extends Twig_Node
407
  ->write(sprintf("if (!%s", $var))
408
  ->raw(" instanceof Twig_Template) {\n")
409
  ->indent()
410
- ->write(sprintf("%s = \$this->env->loadTemplate(%s);\n", $var, $var))
 
 
 
 
 
411
  ->outdent()
412
  ->write("}\n")
413
  ;
114
  $compiler->subcompile($parent);
115
  } else {
116
  $compiler
117
+ ->raw("\$this->loadTemplate(")
118
  ->subcompile($parent)
119
+ ->raw(', ')
120
+ ->repr($compiler->getFilename())
121
+ ->raw(', ')
122
+ ->repr($this->getNode('parent')->getLine())
123
  ->raw(")")
124
  ;
125
  }
159
  } elseif ($parent instanceof Twig_Node_Expression_Constant) {
160
  $compiler
161
  ->addDebugInfo($parent)
162
+ ->write("\$this->parent = \$this->loadTemplate(")
 
 
163
  ->subcompile($parent)
164
+ ->raw(', ')
165
+ ->repr($compiler->getFilename())
166
+ ->raw(', ')
167
+ ->repr($this->getNode('parent')->getLine())
168
  ->raw(");\n")
 
 
 
 
 
 
 
 
169
  ;
170
  }
171
 
393
  {
394
  if ($node instanceof Twig_Node_Expression_Constant) {
395
  $compiler
396
+ ->write(sprintf("%s = \$this->loadTemplate(", $var))
397
  ->subcompile($node)
398
+ ->raw(', ')
399
+ ->repr($compiler->getFilename())
400
+ ->raw(', ')
401
+ ->repr($node->getLine())
402
  ->raw(");\n")
403
  ;
404
  } else {
409
  ->write(sprintf("if (!%s", $var))
410
  ->raw(" instanceof Twig_Template) {\n")
411
  ->indent()
412
+ ->write(sprintf("%s = \$this->loadTemplate(%s")
413
+ ->raw(', ')
414
+ ->repr($compiler->getFilename())
415
+ ->raw(', ')
416
+ ->repr($node->getLine())
417
+ ->raw(");\n", $var, $var))
418
  ->outdent()
419
  ->write("}\n")
420
  ;
vendor/twig/twig/lib/Twig/NodeVisitor/Optimizer.php CHANGED
@@ -56,7 +56,7 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
56
  $this->enterOptimizeFor($node, $env);
57
  }
58
 
59
- if (!version_compare(phpversion(), '5.4.0RC1', '>=') && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
60
  if ($this->inABody) {
61
  if (!$node instanceof Twig_Node_Expression) {
62
  if (get_class($node) !== 'Twig_Node') {
56
  $this->enterOptimizeFor($node, $env);
57
  }
58
 
59
+ if (PHP_VERSION_ID < 50400 && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
60
  if ($this->inABody) {
61
  if (!$node instanceof Twig_Node_Expression) {
62
  if (get_class($node) !== 'Twig_Node') {
vendor/twig/twig/lib/Twig/Template.php CHANGED
@@ -78,7 +78,7 @@ abstract class Twig_Template implements Twig_TemplateInterface
78
  }
79
 
80
  if (!isset($this->parents[$parent])) {
81
- $this->parents[$parent] = $this->env->loadTemplate($parent);
82
  }
83
  } catch (Twig_Error_Loader $e) {
84
  $e->setTemplateFile(null);
@@ -240,6 +240,30 @@ abstract class Twig_Template implements Twig_TemplateInterface
240
  return array_keys($this->blocks);
241
  }
242
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  /**
244
  * Returns all blocks.
245
  *
78
  }
79
 
80
  if (!isset($this->parents[$parent])) {
81
+ $this->parents[$parent] = $this->loadTemplate($parent);
82
  }
83
  } catch (Twig_Error_Loader $e) {
84
  $e->setTemplateFile(null);
240
  return array_keys($this->blocks);
241
  }
242
 
243
+ protected function loadTemplate($template, $templateName = null, $line = null, $index = null)
244
+ {
245
+ try {
246
+ if (is_array($template)) {
247
+ return $this->env->resolveTemplate($template);
248
+ }
249
+
250
+ if ($template instanceof Twig_Template) {
251
+ return $template;
252
+ }
253
+
254
+ return $this->env->loadTemplate($template, $index);
255
+ } catch (Twig_Error $e) {
256
+ $e->setTemplateFile($templateName ? $templateName : $this->getTemplateName());
257
+ if (!$line) {
258
+ $e->guess();
259
+ } else {
260
+ $e->setTemplateLine($line);
261
+ }
262
+
263
+ throw $e;
264
+ }
265
+ }
266
+
267
  /**
268
  * Returns all blocks.
269
  *
vendor/twig/twig/lib/Twig/Test/NodeTestCase.php CHANGED
@@ -42,7 +42,7 @@ abstract class Twig_Test_NodeTestCase extends PHPUnit_Framework_TestCase
42
  {
43
  $line = $line > 0 ? "// line {$line}\n" : '';
44
 
45
- if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
46
  return sprintf('%s(isset($context["%s"]) ? $context["%s"] : null)', $line, $name, $name);
47
  }
48
 
42
  {
43
  $line = $line > 0 ? "// line {$line}\n" : '';
44
 
45
+ if (PHP_VERSION_ID >= 50400) {
46
  return sprintf('%s(isset($context["%s"]) ? $context["%s"] : null)', $line, $name, $name);
47
  }
48
 
vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php CHANGED
@@ -46,7 +46,7 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
46
  public function testGlobals()
47
  {
48
  // globals can be added after calling getGlobals
49
- $twig = new Twig_Environment(new Twig_Loader_String());
50
  $twig->addGlobal('foo', 'foo');
51
  $twig->getGlobals();
52
  $twig->addGlobal('foo', 'bar');
@@ -54,7 +54,7 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
54
  $this->assertEquals('bar', $globals['foo']);
55
 
56
  // globals can be modified after runtime init
57
- $twig = new Twig_Environment(new Twig_Loader_String());
58
  $twig->addGlobal('foo', 'foo');
59
  $globals = $twig->getGlobals();
60
  $twig->initRuntime();
@@ -63,7 +63,7 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
63
  $this->assertEquals('bar', $globals['foo']);
64
 
65
  // globals can be modified after extensions init
66
- $twig = new Twig_Environment(new Twig_Loader_String());
67
  $twig->addGlobal('foo', 'foo');
68
  $twig->getGlobals();
69
  $twig->getFunctions();
@@ -72,7 +72,7 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
72
  $this->assertEquals('bar', $globals['foo']);
73
 
74
  // globals can be modified after extensions and runtime init
75
- $twig = new Twig_Environment(new Twig_Loader_String());
76
  $twig->addGlobal('foo', 'foo');
77
  $twig->getGlobals();
78
  $twig->getFunctions();
@@ -81,15 +81,15 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
81
  $globals = $twig->getGlobals();
82
  $this->assertEquals('bar', $globals['foo']);
83
 
84
- $twig = new Twig_Environment(new Twig_Loader_String());
85
  $twig->getGlobals();
86
  $twig->addGlobal('foo', 'bar');
87
- $template = $twig->loadTemplate('{{foo}}');
88
  $this->assertEquals('bar', $template->render(array()));
89
 
90
  /* to be uncomment in Twig 2.0
91
  // globals cannot be added after runtime init
92
- $twig = new Twig_Environment(new Twig_Loader_String());
93
  $twig->addGlobal('foo', 'foo');
94
  $globals = $twig->getGlobals();
95
  $twig->initRuntime();
@@ -101,7 +101,7 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
101
  }
102
 
103
  // globals cannot be added after extensions init
104
- $twig = new Twig_Environment(new Twig_Loader_String());
105
  $twig->addGlobal('foo', 'foo');
106
  $globals = $twig->getGlobals();
107
  $twig->getFunctions();
@@ -113,7 +113,7 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
113
  }
114
 
115
  // globals cannot be added after extensions and runtime init
116
- $twig = new Twig_Environment(new Twig_Loader_String());
117
  $twig->addGlobal('foo', 'foo');
118
  $globals = $twig->getGlobals();
119
  $twig->getFunctions();
@@ -126,7 +126,7 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
126
  }
127
 
128
  // test adding globals after initRuntime without call to getGlobals
129
- $twig = new Twig_Environment(new Twig_Loader_String());
130
  $twig->initRuntime();
131
  try {
132
  $twig->addGlobal('bar', 'bar');
@@ -142,17 +142,17 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
142
  $options = array('cache' => sys_get_temp_dir().'/twig', 'auto_reload' => false, 'debug' => false);
143
 
144
  // force compilation
145
- $twig = new Twig_Environment(new Twig_Loader_String(), $options);
146
- $cache = $twig->getCacheFilename('{{ foo }}');
147
  if (!is_dir(dirname($cache))) {
148
  mkdir(dirname($cache), 0777, true);
149
  }
150
- file_put_contents($cache, $twig->compileSource('{{ foo }}', '{{ foo }}'));
151
 
152
  // check that extensions won't be initialized when rendering a template that is already in the cache
153
  $twig = $this
154
  ->getMockBuilder('Twig_Environment')
155
- ->setConstructorArgs(array(new Twig_Loader_String(), $options))
156
  ->setMethods(array('initExtensions'))
157
  ->getMock()
158
  ;
@@ -160,7 +160,7 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
160
  $twig->expects($this->never())->method('initExtensions');
161
 
162
  // render template
163
- $output = $twig->render('{{ foo }}', array('foo' => 'bar'));
164
  $this->assertEquals('bar', $output);
165
 
166
  unlink($cache);
@@ -168,7 +168,7 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
168
 
169
  public function testAddExtension()
170
  {
171
- $twig = new Twig_Environment(new Twig_Loader_String());
172
  $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension());
173
 
174
  $this->assertArrayHasKey('test', $twig->getTags());
@@ -184,7 +184,7 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
184
 
185
  public function testRemoveExtension()
186
  {
187
- $twig = new Twig_Environment(new Twig_Loader_String());
188
  $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension());
189
  $twig->removeExtension('environment_test');
190
 
46
  public function testGlobals()
47
  {
48
  // globals can be added after calling getGlobals
49
+ $twig = new Twig_Environment($this->getMock('Twig_LoaderInterface'));
50
  $twig->addGlobal('foo', 'foo');
51
  $twig->getGlobals();
52
  $twig->addGlobal('foo', 'bar');
54
  $this->assertEquals('bar', $globals['foo']);
55
 
56
  // globals can be modified after runtime init
57
+ $twig = new Twig_Environment($this->getMock('Twig_LoaderInterface'));
58
  $twig->addGlobal('foo', 'foo');
59
  $globals = $twig->getGlobals();
60
  $twig->initRuntime();
63
  $this->assertEquals('bar', $globals['foo']);
64
 
65
  // globals can be modified after extensions init
66
+ $twig = new Twig_Environment($this->getMock('Twig_LoaderInterface'));
67
  $twig->addGlobal('foo', 'foo');
68
  $twig->getGlobals();
69
  $twig->getFunctions();
72
  $this->assertEquals('bar', $globals['foo']);
73
 
74
  // globals can be modified after extensions and runtime init
75
+ $twig = new Twig_Environment($loader = new Twig_Loader_Array(array('index' => '{{foo}}')));
76
  $twig->addGlobal('foo', 'foo');
77
  $twig->getGlobals();
78
  $twig->getFunctions();
81
  $globals = $twig->getGlobals();
82
  $this->assertEquals('bar', $globals['foo']);
83
 
84
+ $twig = new Twig_Environment($loader);
85
  $twig->getGlobals();
86
  $twig->addGlobal('foo', 'bar');
87
+ $template = $twig->loadTemplate('index');
88
  $this->assertEquals('bar', $template->render(array()));
89
 
90
  /* to be uncomment in Twig 2.0
91
  // globals cannot be added after runtime init
92
+ $twig = new Twig_Environment($this->getMock('Twig_LoaderInterface'));
93
  $twig->addGlobal('foo', 'foo');
94
  $globals = $twig->getGlobals();
95
  $twig->initRuntime();
101
  }
102
 
103
  // globals cannot be added after extensions init
104
+ $twig = new Twig_Environment($this->getMock('Twig_LoaderInterface'));
105
  $twig->addGlobal('foo', 'foo');
106
  $globals = $twig->getGlobals();
107
  $twig->getFunctions();
113
  }
114
 
115
  // globals cannot be added after extensions and runtime init
116
+ $twig = new Twig_Environment($this->getMock('Twig_LoaderInterface'));
117
  $twig->addGlobal('foo', 'foo');
118
  $globals = $twig->getGlobals();
119
  $twig->getFunctions();
126
  }
127
 
128
  // test adding globals after initRuntime without call to getGlobals
129
+ $twig = new Twig_Environment($this->getMock('Twig_LoaderInterface'));
130
  $twig->initRuntime();
131
  try {
132
  $twig->addGlobal('bar', 'bar');
142
  $options = array('cache' => sys_get_temp_dir().'/twig', 'auto_reload' => false, 'debug' => false);
143
 
144
  // force compilation
145
+ $twig = new Twig_Environment($loader = new Twig_Loader_Array(array('index' => '{{ foo }}')), $options);
146
+ $cache = $twig->getCacheFilename('index');
147
  if (!is_dir(dirname($cache))) {
148
  mkdir(dirname($cache), 0777, true);
149
  }
150
+ file_put_contents($cache, $twig->compileSource('{{ foo }}', 'index'));
151
 
152
  // check that extensions won't be initialized when rendering a template that is already in the cache
153
  $twig = $this
154
  ->getMockBuilder('Twig_Environment')
155
+ ->setConstructorArgs(array($loader, $options))
156
  ->setMethods(array('initExtensions'))
157
  ->getMock()
158
  ;
160
  $twig->expects($this->never())->method('initExtensions');
161
 
162
  // render template
163
+ $output = $twig->render('index', array('foo' => 'bar'));
164
  $this->assertEquals('bar', $output);
165
 
166
  unlink($cache);
168
 
169
  public function testAddExtension()
170
  {
171
+ $twig = new Twig_Environment($this->getMock('Twig_LoaderInterface'));
172
  $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension());
173
 
174
  $this->assertArrayHasKey('test', $twig->getTags());
184
 
185
  public function testRemoveExtension()
186
  {
187
+ $twig = new Twig_Environment($this->getMock('Twig_LoaderInterface'));
188
  $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension());
189
  $twig->removeExtension('environment_test');
190
 
vendor/twig/twig/test/Twig/Tests/ExpressionParserTest.php CHANGED
@@ -17,7 +17,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
17
  */
18
  public function testCanOnlyAssignToNames($template)
19
  {
20
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
21
  $parser = new Twig_Parser($env);
22
 
23
  $parser->parse($env->tokenize($template, 'index'));
@@ -41,7 +41,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
41
  */
42
  public function testArrayExpression($template, $expected)
43
  {
44
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
45
  $stream = $env->tokenize($template, 'index');
46
  $parser = new Twig_Parser($env);
47
 
@@ -54,7 +54,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
54
  */
55
  public function testArraySyntaxError($template)
56
  {
57
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
58
  $parser = new Twig_Parser($env);
59
 
60
  $parser->parse($env->tokenize($template, 'index'));
@@ -149,7 +149,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
149
  */
150
  public function testStringExpressionDoesNotConcatenateTwoConsecutiveStrings()
151
  {
152
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
153
  $stream = $env->tokenize('{{ "a" "b" }}', 'index');
154
  $parser = new Twig_Parser($env);
155
 
@@ -161,7 +161,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
161
  */
162
  public function testStringExpression($template, $expected)
163
  {
164
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
165
  $stream = $env->tokenize($template, 'index');
166
  $parser = new Twig_Parser($env);
167
 
@@ -220,7 +220,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
220
  */
221
  public function testAttributeCallDoesNotSupportNamedArguments()
222
  {
223
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
224
  $parser = new Twig_Parser($env);
225
 
226
  $parser->parse($env->tokenize('{{ foo.bar(name="Foo") }}', 'index'));
@@ -231,7 +231,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
231
  */
232
  public function testMacroCallDoesNotSupportNamedArguments()
233
  {
234
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
235
  $parser = new Twig_Parser($env);
236
 
237
  $parser->parse($env->tokenize('{% from _self import foo %}{% macro foo() %}{% endmacro %}{{ foo(name="Foo") }}', 'index'));
@@ -243,7 +243,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
243
  */
244
  public function testMacroDefinitionDoesNotSupportNonNameVariableName()
245
  {
246
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
247
  $parser = new Twig_Parser($env);
248
 
249
  $parser->parse($env->tokenize('{% macro foo("a") %}{% endmacro %}', 'index'));
@@ -256,7 +256,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
256
  */
257
  public function testMacroDefinitionDoesNotSupportNonConstantDefaultValues($template)
258
  {
259
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
260
  $parser = new Twig_Parser($env);
261
 
262
  $parser->parse($env->tokenize($template, 'index'));
@@ -275,7 +275,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
275
  */
276
  public function testMacroDefinitionSupportsConstantDefaultValues($template)
277
  {
278
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
279
  $parser = new Twig_Parser($env);
280
 
281
  $parser->parse($env->tokenize($template, 'index'));
@@ -300,7 +300,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
300
  */
301
  public function testUnknownFunction()
302
  {
303
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
304
  $parser = new Twig_Parser($env);
305
 
306
  $parser->parse($env->tokenize('{{ cycl() }}', 'index'));
@@ -312,7 +312,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
312
  */
313
  public function testUnknownFilter()
314
  {
315
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
316
  $parser = new Twig_Parser($env);
317
 
318
  $parser->parse($env->tokenize('{{ 1|lowe }}', 'index'));
@@ -324,7 +324,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
324
  */
325
  public function testUnknownTest()
326
  {
327
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
328
  $parser = new Twig_Parser($env);
329
 
330
  $parser->parse($env->tokenize('{{ 1 is nul }}', 'index'));
17
  */
18
  public function testCanOnlyAssignToNames($template)
19
  {
20
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false));
21
  $parser = new Twig_Parser($env);
22
 
23
  $parser->parse($env->tokenize($template, 'index'));
41
  */
42
  public function testArrayExpression($template, $expected)
43
  {
44
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false));
45
  $stream = $env->tokenize($template, 'index');
46
  $parser = new Twig_Parser($env);
47
 
54
  */
55
  public function testArraySyntaxError($template)
56
  {
57
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false));
58
  $parser = new Twig_Parser($env);
59
 
60
  $parser->parse($env->tokenize($template, 'index'));
149
  */
150
  public function testStringExpressionDoesNotConcatenateTwoConsecutiveStrings()
151
  {
152
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
153
  $stream = $env->tokenize('{{ "a" "b" }}', 'index');
154
  $parser = new Twig_Parser($env);
155
 
161
  */
162
  public function testStringExpression($template, $expected)
163
  {
164
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
165
  $stream = $env->tokenize($template, 'index');
166
  $parser = new Twig_Parser($env);
167
 
220
  */
221
  public function testAttributeCallDoesNotSupportNamedArguments()
222
  {
223
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false));
224
  $parser = new Twig_Parser($env);
225
 
226
  $parser->parse($env->tokenize('{{ foo.bar(name="Foo") }}', 'index'));
231
  */
232
  public function testMacroCallDoesNotSupportNamedArguments()
233
  {
234
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false));
235
  $parser = new Twig_Parser($env);
236
 
237
  $parser->parse($env->tokenize('{% from _self import foo %}{% macro foo() %}{% endmacro %}{{ foo(name="Foo") }}', 'index'));
243
  */
244
  public function testMacroDefinitionDoesNotSupportNonNameVariableName()
245
  {
246
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false));
247
  $parser = new Twig_Parser($env);
248
 
249
  $parser->parse($env->tokenize('{% macro foo("a") %}{% endmacro %}', 'index'));
256
  */
257
  public function testMacroDefinitionDoesNotSupportNonConstantDefaultValues($template)
258
  {
259
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false));
260
  $parser = new Twig_Parser($env);
261
 
262
  $parser->parse($env->tokenize($template, 'index'));
275
  */
276
  public function testMacroDefinitionSupportsConstantDefaultValues($template)
277
  {
278
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false));
279
  $parser = new Twig_Parser($env);
280
 
281
  $parser->parse($env->tokenize($template, 'index'));
300
  */
301
  public function testUnknownFunction()
302
  {
303
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false));
304
  $parser = new Twig_Parser($env);
305
 
306
  $parser->parse($env->tokenize('{{ cycl() }}', 'index'));
312
  */
313
  public function testUnknownFilter()
314
  {
315
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false));
316
  $parser = new Twig_Parser($env);
317
 
318
  $parser->parse($env->tokenize('{{ 1|lowe }}', 'index'));
324
  */
325
  public function testUnknownTest()
326
  {
327
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false));
328
  $parser = new Twig_Parser($env);
329
 
330
  $parser->parse($env->tokenize('{{ 1 is nul }}', 'index'));
vendor/twig/twig/test/Twig/Tests/FileCachingTest.php CHANGED
@@ -26,7 +26,7 @@ class Twig_Tests_FileCachingTest extends PHPUnit_Framework_TestCase
26
  $this->markTestSkipped(sprintf('Unable to run the tests as "%s" is not writable.', $this->tmpDir));
27
  }
28
 
29
- $this->env = new Twig_Environment(new Twig_Loader_String(), array('cache' => $this->tmpDir));
30
  }
31
 
32
  public function tearDown()
@@ -40,7 +40,7 @@ class Twig_Tests_FileCachingTest extends PHPUnit_Framework_TestCase
40
 
41
  public function testWritingCacheFiles()
42
  {
43
- $name = 'This is just text.';
44
  $this->env->loadTemplate($name);
45
  $cacheFileName = $this->env->getCacheFilename($name);
46
 
@@ -50,7 +50,7 @@ class Twig_Tests_FileCachingTest extends PHPUnit_Framework_TestCase
50
 
51
  public function testClearingCacheFiles()
52
  {
53
- $name = 'I will be deleted.';
54
  $this->env->loadTemplate($name);
55
  $cacheFileName = $this->env->getCacheFilename($name);
56
 
26
  $this->markTestSkipped(sprintf('Unable to run the tests as "%s" is not writable.', $this->tmpDir));
27
  }
28
 
29
+ $this->env = new Twig_Environment(new Twig_Loader_Array(array('index' => 'index', 'index2' => 'index2')), array('cache' => $this->tmpDir));
30
  }
31
 
32
  public function tearDown()
40
 
41
  public function testWritingCacheFiles()
42
  {
43
+ $name = 'index';
44
  $this->env->loadTemplate($name);
45
  $cacheFileName = $this->env->getCacheFilename($name);
46
 
50
 
51
  public function testClearingCacheFiles()
52
  {
53
+ $name = 'index2';
54
  $this->env->loadTemplate($name);
55
  $cacheFileName = $this->env->getCacheFilename($name);
56
 
vendor/twig/twig/test/Twig/Tests/Fixtures/filters/slice.test CHANGED
@@ -24,8 +24,9 @@
24
 
25
  {{ arr|slice(3)|join('') }}
26
  {{ arr[2:]|join('') }}
 
27
  --DATA--
28
- return array('start' => 1, 'length' => 2, 'arr' => new ArrayObject(array(1, 2, 3, 4)))
29
  --EXPECT--
30
  23
31
  23
@@ -49,4 +50,5 @@ bc
49
  1
50
 
51
  4
52
- 34
 
24
 
25
  {{ arr|slice(3)|join('') }}
26
  {{ arr[2:]|join('') }}
27
+ {{ xml|slice(1)|join('')}}
28
  --DATA--
29
+ return array('start' => 1, 'length' => 2, 'arr' => new ArrayObject(array(1, 2, 3, 4)), 'xml' => new SimpleXMLElement('<items><item>1</item><item>2</item></items>'))
30
  --EXPECT--
31
  23
32
  23
50
  1
51
 
52
  4
53
+ 34
54
+ 2
vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array_with_empty_name.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% extends ["", "bar.twig"] %}
5
+ --TEMPLATE(bar.twig)--
6
+ {% block content %}
7
+ foo
8
+ {% endblock %}
9
+ --DATA--
10
+ return array()
11
+ --EXPECT--
12
+ foo
vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array_with_null_name.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% extends [null, "bar.twig"] %}
5
+ --TEMPLATE(bar.twig)--
6
+ {% block content %}
7
+ foo
8
+ {% endblock %}
9
+ --DATA--
10
+ return array()
11
+ --EXPECT--
12
+ foo
vendor/twig/twig/test/Twig/Tests/Loader/FilesystemTest.php CHANGED
@@ -146,4 +146,30 @@ class Twig_Tests_Loader_FilesystemTest extends PHPUnit_Framework_TestCase
146
  $template = $twig->loadTemplate('blocks.html.twig');
147
  $this->assertSame('block from theme 2', $template->renderBlock('b2', array()));
148
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  }
146
  $template = $twig->loadTemplate('blocks.html.twig');
147
  $this->assertSame('block from theme 2', $template->renderBlock('b2', array()));
148
  }
149
+
150
+ public function getArrayInheritanceTests()
151
+ {
152
+ return array(
153
+ 'valid array inheritance' => array('array_inheritance_valid_parent.html.twig'),
154
+ 'array inheritance with null first template' => array('array_inheritance_null_parent.html.twig'),
155
+ 'array inheritance with empty first template' => array('array_inheritance_empty_parent.html.twig'),
156
+ 'array inheritance with non-existent first template' => array('array_inheritance_nonexistent_parent.html.twig'),
157
+ );
158
+ }
159
+
160
+ /**
161
+ * @dataProvider getArrayInheritanceTests
162
+ *
163
+ * @param $templateName string Template name with array inheritance
164
+ */
165
+ public function testArrayInheritance($templateName)
166
+ {
167
+ $loader = new Twig_Loader_Filesystem(array());
168
+ $loader->addPath(dirname(__FILE__).'/Fixtures/inheritance');
169
+
170
+ $twig = new Twig_Environment($loader);
171
+
172
+ $template = $twig->loadTemplate($templateName);
173
+ $this->assertSame('VALID Child', $template->renderBlock('body', array()));
174
+ }
175
  }
vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_empty_parent.html.twig ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ {% extends ['','parent.html.twig'] %}
2
+
3
+ {% block body %}{{ parent() }} Child{% endblock %}
vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_nonexistent_parent.html.twig ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ {% extends ['nonexistent.html.twig','parent.html.twig'] %}
2
+
3
+ {% block body %}{{ parent() }} Child{% endblock %}
vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_null_parent.html.twig ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ {% extends [null,'parent.html.twig'] %}
2
+
3
+ {% block body %}{{ parent() }} Child{% endblock %}
vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_valid_parent.html.twig ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ {% extends ['parent.html.twig','spare_parent.html.twig'] %}
2
+
3
+ {% block body %}{{ parent() }} Child{% endblock %}
vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/parent.html.twig ADDED
@@ -0,0 +1 @@
 
1
+ {% block body %}VALID{% endblock %}
vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/spare_parent.html.twig ADDED
@@ -0,0 +1 @@
 
1
+ {% block body %}SPARE PARENT{% endblock %}
vendor/twig/twig/test/Twig/Tests/NativeExtensionTest.php CHANGED
@@ -17,7 +17,7 @@ class Twig_Tests_NativeExtensionTest extends PHPUnit_Framework_TestCase
17
  $this->markTestSkipped('Skip under HHVM as the behavior is not the same as plain PHP (which is an edge case anyway)');
18
  }
19
 
20
- $twig = new Twig_Environment(new Twig_Loader_String(), array(
21
  'debug' => true,
22
  'cache' => false,
23
  'autoescape' => false,
@@ -25,7 +25,7 @@ class Twig_Tests_NativeExtensionTest extends PHPUnit_Framework_TestCase
25
 
26
  $d1 = new DateTime();
27
  $d2 = new DateTime();
28
- $output = $twig->render('{{ d1.date }}{{ d2.date }}', compact('d1', 'd2'));
29
 
30
  // If it fails, PHP will crash.
31
  $this->assertEquals($output, $d1->date.$d2->date);
17
  $this->markTestSkipped('Skip under HHVM as the behavior is not the same as plain PHP (which is an edge case anyway)');
18
  }
19
 
20
+ $twig = new Twig_Environment(new Twig_Loader_Array(array('index' => '{{ d1.date }}{{ d2.date }}')), array(
21
  'debug' => true,
22
  'cache' => false,
23
  'autoescape' => false,
25
 
26
  $d1 = new DateTime();
27
  $d2 = new DateTime();
28
+ $output = $twig->render('index', compact('d1', 'd2'));
29
 
30
  // If it fails, PHP will crash.
31
  $this->assertEquals($output, $d1->date.$d2->date);
vendor/twig/twig/test/Twig/Tests/Node/Expression/CallTest.php CHANGED
@@ -78,6 +78,16 @@ class Twig_Tests_Node_Expression_CallTest extends PHPUnit_Framework_TestCase
78
  $this->assertEquals(array('arg1'), $node->getArguments(array($this, 'customFunction'), array('arg1' => 'arg1')));
79
  }
80
 
 
 
 
 
 
 
 
 
 
 
81
  public function customFunction($arg1, $arg2 = 'default', $arg3 = array())
82
  {
83
  }
78
  $this->assertEquals(array('arg1'), $node->getArguments(array($this, 'customFunction'), array('arg1' => 'arg1')));
79
  }
80
 
81
+ public function testGetArgumentsForStaticMethod()
82
+ {
83
+ $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'custom_static_function'));
84
+ $this->assertEquals(array('arg1'), $node->getArguments(__CLASS__.'::customStaticFunction', array('arg1' => 'arg1')));
85
+ }
86
+
87
+ public static function customStaticFunction($arg1, $arg2 = 'default', $arg3 = array())
88
+ {
89
+ }
90
+
91
  public function customFunction($arg1, $arg2 = 'default', $arg3 = array())
92
  {
93
  }
vendor/twig/twig/test/Twig/Tests/Node/Expression/FilterTest.php CHANGED
@@ -64,7 +64,7 @@ class Twig_Tests_Node_Expression_FilterTest extends Twig_Test_NodeTestCase
64
  $tests[] = array($node, 'twig_reverse_filter($this->env, "abc", true)');
65
 
66
  // filter as an anonymous function
67
- if (version_compare(phpversion(), '5.3.0', '>=')) {
68
  $node = $this->createFilter(new Twig_Node_Expression_Constant('foo', 1), 'anonymous');
69
  $tests[] = array($node, 'call_user_func_array($this->env->getFilter(\'anonymous\')->getCallable(), array("foo"))');
70
  }
@@ -112,7 +112,7 @@ class Twig_Tests_Node_Expression_FilterTest extends Twig_Test_NodeTestCase
112
 
113
  protected function getEnvironment()
114
  {
115
- if (version_compare(phpversion(), '5.3.0', '>=')) {
116
  return include 'PHP53/FilterInclude.php';
117
  }
118
 
64
  $tests[] = array($node, 'twig_reverse_filter($this->env, "abc", true)');
65
 
66
  // filter as an anonymous function
67
+ if (PHP_VERSION_ID >= 50300) {
68
  $node = $this->createFilter(new Twig_Node_Expression_Constant('foo', 1), 'anonymous');
69
  $tests[] = array($node, 'call_user_func_array($this->env->getFilter(\'anonymous\')->getCallable(), array("foo"))');
70
  }
112
 
113
  protected function getEnvironment()
114
  {
115
+ if (PHP_VERSION_ID >= 50300) {
116
  return include 'PHP53/FilterInclude.php';
117
  }
118
 
vendor/twig/twig/test/Twig/Tests/Node/Expression/FunctionTest.php CHANGED
@@ -63,7 +63,7 @@ class Twig_Tests_Node_Expression_FunctionTest extends Twig_Test_NodeTestCase
63
  $tests[] = array($node, 'twig_date_converter($this->env, 0, "America/Chicago")');
64
 
65
  // function as an anonymous function
66
- if (version_compare(phpversion(), '5.3.0', '>=')) {
67
  $node = $this->createFunction('anonymous', array(new Twig_Node_Expression_Constant('foo', 1)));
68
  $tests[] = array($node, 'call_user_func_array($this->env->getFunction(\'anonymous\')->getCallable(), array("foo"))');
69
  }
@@ -78,7 +78,7 @@ class Twig_Tests_Node_Expression_FunctionTest extends Twig_Test_NodeTestCase
78
 
79
  protected function getEnvironment()
80
  {
81
- if (version_compare(phpversion(), '5.3.0', '>=')) {
82
  return include 'PHP53/FunctionInclude.php';
83
  }
84
 
63
  $tests[] = array($node, 'twig_date_converter($this->env, 0, "America/Chicago")');
64
 
65
  // function as an anonymous function
66
+ if (PHP_VERSION_ID >= 50300) {
67
  $node = $this->createFunction('anonymous', array(new Twig_Node_Expression_Constant('foo', 1)));
68
  $tests[] = array($node, 'call_user_func_array($this->env->getFunction(\'anonymous\')->getCallable(), array("foo"))');
69
  }
78
 
79
  protected function getEnvironment()
80
  {
81
+ if (PHP_VERSION_ID >= 50300) {
82
  return include 'PHP53/FunctionInclude.php';
83
  }
84
 
vendor/twig/twig/test/Twig/Tests/Node/Expression/NameTest.php CHANGED
@@ -28,7 +28,7 @@ class Twig_Tests_Node_Expression_NameTest extends Twig_Test_NodeTestCase
28
  $env1 = new Twig_Environment(null, array('strict_variables' => false));
29
 
30
  return array(
31
- array($node, "// line 1\n".(version_compare(PHP_VERSION, '5.4.0') >= 0 ? '(isset($context["foo"]) ? $context["foo"] : $this->getContext($context, "foo"))' : '$this->getContext($context, "foo")'), $env),
32
  array($node, $this->getVariableGetter('foo', 1), $env1),
33
  array($self, "// line 1\n\$this"),
34
  array($context, "// line 1\n\$context"),
28
  $env1 = new Twig_Environment(null, array('strict_variables' => false));
29
 
30
  return array(
31
+ array($node, "// line 1\n".(PHP_VERSION_ID >= 50400 ? '(isset($context["foo"]) ? $context["foo"] : $this->getContext($context, "foo"))' : '$this->getContext($context, "foo")'), $env),
32
  array($node, $this->getVariableGetter('foo', 1), $env1),
33
  array($self, "// line 1\n\$this"),
34
  array($context, "// line 1\n\$context"),
vendor/twig/twig/test/Twig/Tests/Node/Expression/TestTest.php CHANGED
@@ -32,7 +32,7 @@ class Twig_Tests_Node_Expression_TestTest extends Twig_Test_NodeTestCase
32
  $tests[] = array($node, '(null === "foo")');
33
 
34
  // test as an anonymous function
35
- if (version_compare(phpversion(), '5.3.0', '>=')) {
36
  $node = $this->createTest(new Twig_Node_Expression_Constant('foo', 1), 'anonymous', array(new Twig_Node_Expression_Constant('foo', 1)));
37
  $tests[] = array($node, 'call_user_func_array($this->env->getTest(\'anonymous\')->getCallable(), array("foo", "foo"))');
38
  }
@@ -47,7 +47,7 @@ class Twig_Tests_Node_Expression_TestTest extends Twig_Test_NodeTestCase
47
 
48
  protected function getEnvironment()
49
  {
50
- if (version_compare(phpversion(), '5.3.0', '>=')) {
51
  return include 'PHP53/TestInclude.php';
52
  }
53
 
32
  $tests[] = array($node, '(null === "foo")');
33
 
34
  // test as an anonymous function
35
+ if (PHP_VERSION_ID >= 50300) {
36
  $node = $this->createTest(new Twig_Node_Expression_Constant('foo', 1), 'anonymous', array(new Twig_Node_Expression_Constant('foo', 1)));
37
  $tests[] = array($node, 'call_user_func_array($this->env->getTest(\'anonymous\')->getCallable(), array("foo", "foo"))');
38
  }
47
 
48
  protected function getEnvironment()
49
  {
50
+ if (PHP_VERSION_ID >= 50300) {
51
  return include 'PHP53/TestInclude.php';
52
  }
53
 
vendor/twig/twig/test/Twig/Tests/Node/ImportTest.php CHANGED
@@ -31,7 +31,7 @@ class Twig_Tests_Node_ImportTest extends Twig_Test_NodeTestCase
31
 
32
  $tests[] = array($node, <<<EOF
33
  // line 1
34
- \$context["macro"] = \$this->env->loadTemplate("foo.twig");
35
  EOF
36
  );
37
 
31
 
32
  $tests[] = array($node, <<<EOF
33
  // line 1
34
+ \$context["macro"] = \$this->loadTemplate("foo.twig", null, 1);
35
  EOF
36
  );
37
 
vendor/twig/twig/test/Twig/Tests/Node/IncludeTest.php CHANGED
@@ -34,7 +34,7 @@ class Twig_Tests_Node_IncludeTest extends Twig_Test_NodeTestCase
34
  $node = new Twig_Node_Include($expr, null, false, false, 1);
35
  $tests[] = array($node, <<<EOF
36
  // line 1
37
- \$this->env->loadTemplate("foo.twig")->display(\$context);
38
  EOF
39
  );
40
 
@@ -47,7 +47,7 @@ EOF
47
  $node = new Twig_Node_Include($expr, null, false, false, 1);
48
  $tests[] = array($node, <<<EOF
49
  // line 1
50
- \$this->env->resolveTemplate(((true) ? ("foo") : ("foo")))->display(\$context);
51
  EOF
52
  );
53
 
@@ -56,14 +56,14 @@ EOF
56
  $node = new Twig_Node_Include($expr, $vars, false, false, 1);
57
  $tests[] = array($node, <<<EOF
58
  // line 1
59
- \$this->env->loadTemplate("foo.twig")->display(array_merge(\$context, array("foo" => true)));
60
  EOF
61
  );
62
 
63
  $node = new Twig_Node_Include($expr, $vars, true, false, 1);
64
  $tests[] = array($node, <<<EOF
65
  // line 1
66
- \$this->env->loadTemplate("foo.twig")->display(array("foo" => true));
67
  EOF
68
  );
69
 
@@ -71,7 +71,7 @@ EOF
71
  $tests[] = array($node, <<<EOF
72
  // line 1
73
  try {
74
- \$this->env->loadTemplate("foo.twig")->display(array("foo" => true));
75
  } catch (Twig_Error_Loader \$e) {
76
  // ignore missing template
77
  }
34
  $node = new Twig_Node_Include($expr, null, false, false, 1);
35
  $tests[] = array($node, <<<EOF
36
  // line 1
37
+ \$this->loadTemplate("foo.twig", null, 1)->display(\$context);
38
  EOF
39
  );
40
 
47
  $node = new Twig_Node_Include($expr, null, false, false, 1);
48
  $tests[] = array($node, <<<EOF
49
  // line 1
50
+ \$this->loadTemplate(((true) ? ("foo") : ("foo")), null, 1)->display(\$context);
51
  EOF
52
  );
53
 
56
  $node = new Twig_Node_Include($expr, $vars, false, false, 1);
57
  $tests[] = array($node, <<<EOF
58
  // line 1
59
+ \$this->loadTemplate("foo.twig", null, 1)->display(array_merge(\$context, array("foo" => true)));
60
  EOF
61
  );
62
 
63
  $node = new Twig_Node_Include($expr, $vars, true, false, 1);
64
  $tests[] = array($node, <<<EOF
65
  // line 1
66
+ \$this->loadTemplate("foo.twig", null, 1)->display(array("foo" => true));
67
  EOF
68
  );
69
 
71
  $tests[] = array($node, <<<EOF
72
  // line 1
73
  try {
74
+ \$this->loadTemplate("foo.twig", null, 1)->display(array("foo" => true));
75
  } catch (Twig_Error_Loader \$e) {
76
  // ignore missing template
77
  }
vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php CHANGED
@@ -30,7 +30,7 @@ class Twig_Tests_Node_ModuleTest extends Twig_Test_NodeTestCase
30
 
31
  public function getTests()
32
  {
33
- $twig = new Twig_Environment(new Twig_Loader_String());
34
 
35
  $tests = array();
36
 
@@ -46,7 +46,7 @@ class Twig_Tests_Node_ModuleTest extends Twig_Test_NodeTestCase
46
  <?php
47
 
48
  /* foo.twig */
49
- class __TwigTemplate_a2bfbf7dd6ab85666684fe9297f69363a3fc2046d90f22a317d380c18638df0d extends Twig_Template
50
  {
51
  public function __construct(Twig_Environment \$env)
52
  {
@@ -87,22 +87,14 @@ EOF
87
  <?php
88
 
89
  /* foo.twig */
90
- class __TwigTemplate_a2bfbf7dd6ab85666684fe9297f69363a3fc2046d90f22a317d380c18638df0d extends Twig_Template
91
  {
92
  public function __construct(Twig_Environment \$env)
93
  {
94
  parent::__construct(\$env);
95
 
96
  // line 1
97
- try {
98
- \$this->parent = \$this->env->loadTemplate("layout.twig");
99
- } catch (Twig_Error_Loader \$e) {
100
- \$e->setTemplateFile(\$this->getTemplateName());
101
- \$e->setTemplateLine(1);
102
-
103
- throw \$e;
104
- }
105
-
106
  \$this->blocks = array(
107
  );
108
  }
@@ -115,7 +107,7 @@ class __TwigTemplate_a2bfbf7dd6ab85666684fe9297f69363a3fc2046d90f22a317d380c1863
115
  protected function doDisplay(array \$context, array \$blocks = array())
116
  {
117
  // line 2
118
- \$context["macro"] = \$this->env->loadTemplate("foo.twig");
119
  // line 1
120
  \$this->parent->display(\$context, array_merge(\$this->blocks, \$blocks));
121
  }
@@ -132,7 +124,7 @@ class __TwigTemplate_a2bfbf7dd6ab85666684fe9297f69363a3fc2046d90f22a317d380c1863
132
 
133
  public function getDebugInfo()
134
  {
135
- return array ( 34 => 1, 32 => 2, 11 => 1,);
136
  }
137
  }
138
  EOF
@@ -152,12 +144,12 @@ EOF
152
  <?php
153
 
154
  /* foo.twig */
155
- class __TwigTemplate_a2bfbf7dd6ab85666684fe9297f69363a3fc2046d90f22a317d380c18638df0d extends Twig_Template
156
  {
157
  protected function doGetParent(array \$context)
158
  {
159
  // line 2
160
- return \$this->env->resolveTemplate(((true) ? ("foo") : ("foo")));
161
  }
162
 
163
  protected function doDisplay(array \$context, array \$blocks = array())
30
 
31
  public function getTests()
32
  {
33
+ $twig = new Twig_Environment($this->getMock('Twig_LoaderInterface'));
34
 
35
  $tests = array();
36
 
46
  <?php
47
 
48
  /* foo.twig */
49
+ class __TwigTemplate_e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 extends Twig_Template
50
  {
51
  public function __construct(Twig_Environment \$env)
52
  {
87
  <?php
88
 
89
  /* foo.twig */
90
+ class __TwigTemplate_e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 extends Twig_Template
91
  {
92
  public function __construct(Twig_Environment \$env)
93
  {
94
  parent::__construct(\$env);
95
 
96
  // line 1
97
+ \$this->parent = \$this->loadTemplate("layout.twig", "foo.twig", 1);
 
 
 
 
 
 
 
 
98
  \$this->blocks = array(
99
  );
100
  }
107
  protected function doDisplay(array \$context, array \$blocks = array())
108
  {
109
  // line 2
110
+ \$context["macro"] = \$this->loadTemplate("foo.twig", "foo.twig", 2);
111
  // line 1
112
  \$this->parent->display(\$context, array_merge(\$this->blocks, \$blocks));
113
  }
124
 
125
  public function getDebugInfo()
126
  {
127
+ return array ( 26 => 1, 24 => 2, 11 => 1,);
128
  }
129
  }
130
  EOF
144
  <?php
145
 
146
  /* foo.twig */
147
+ class __TwigTemplate_e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 extends Twig_Template
148
  {
149
  protected function doGetParent(array \$context)
150
  {
151
  // line 2
152
+ return \$this->loadTemplate(((true) ? ("foo") : ("foo")), "foo.twig", 2);
153
  }
154
 
155
  protected function doDisplay(array \$context, array \$blocks = array())
vendor/twig/twig/test/Twig/Tests/NodeVisitor/OptimizerTest.php CHANGED
@@ -12,7 +12,7 @@ class Twig_Tests_NodeVisitor_OptimizerTest extends PHPUnit_Framework_TestCase
12
  {
13
  public function testRenderBlockOptimizer()
14
  {
15
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
16
 
17
  $stream = $env->parse($env->tokenize('{{ block("foo") }}', 'index'));
18
 
@@ -24,7 +24,7 @@ class Twig_Tests_NodeVisitor_OptimizerTest extends PHPUnit_Framework_TestCase
24
 
25
  public function testRenderParentBlockOptimizer()
26
  {
27
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
28
 
29
  $stream = $env->parse($env->tokenize('{% extends "foo" %}{% block content %}{{ parent() }}{% endblock %}', 'index'));
30
 
@@ -36,11 +36,11 @@ class Twig_Tests_NodeVisitor_OptimizerTest extends PHPUnit_Framework_TestCase
36
 
37
  public function testRenderVariableBlockOptimizer()
38
  {
39
- if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
40
  return;
41
  }
42
 
43
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
44
  $stream = $env->parse($env->tokenize('{{ block(name|lower) }}', 'index'));
45
 
46
  $node = $stream->getNode('body')->getNode(0)->getNode(1);
@@ -54,7 +54,7 @@ class Twig_Tests_NodeVisitor_OptimizerTest extends PHPUnit_Framework_TestCase
54
  */
55
  public function testForOptimizer($template, $expected)
56
  {
57
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false));
58
 
59
  $stream = $env->parse($env->tokenize($template, 'index'));
60
 
12
  {
13
  public function testRenderBlockOptimizer()
14
  {
15
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false));
16
 
17
  $stream = $env->parse($env->tokenize('{{ block("foo") }}', 'index'));
18
 
24
 
25
  public function testRenderParentBlockOptimizer()
26
  {
27
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false));
28
 
29
  $stream = $env->parse($env->tokenize('{% extends "foo" %}{% block content %}{{ parent() }}{% endblock %}', 'index'));
30
 
36
 
37
  public function testRenderVariableBlockOptimizer()
38
  {
39
+ if (PHP_VERSION_ID >= 50400) {
40
  return;
41
  }
42
 
43
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false, 'autoescape' => false));
44
  $stream = $env->parse($env->tokenize('{{ block(name|lower) }}', 'index'));
45
 
46
  $node = $stream->getNode('body')->getNode(0)->getNode(1);
54
  */
55
  public function testForOptimizer($template, $expected)
56
  {
57
+ $env = new Twig_Environment($this->getMock('Twig_LoaderInterface'), array('cache' => false));
58
 
59
  $stream = $env->parse($env->tokenize($template, 'index'));
60
 
vendor/twig/twig/test/Twig/Tests/Profiler/Dumper/AbstractTest.php CHANGED
@@ -32,13 +32,14 @@ abstract class Twig_Tests_Profiler_Dumper_AbstractTest extends PHPUnit_Framework
32
 
33
  $embedded = clone $embedded;
34
  $index->addProfile($embedded);
35
- $a = range(1, 1000);
36
  $embedded->leave();
37
- $profile->leave();
38
 
39
- usleep(5000);
40
  $index->leave();
41
 
 
 
42
  return $profile;
43
  }
44
  }
32
 
33
  $embedded = clone $embedded;
34
  $index->addProfile($embedded);
35
+ usleep(500);
36
  $embedded->leave();
 
37
 
38
+ usleep(4500);
39
  $index->leave();
40
 
41
+ $profile->leave();
42
+
43
  return $profile;
44
  }
45
  }
vendor/twig/twig/test/Twig/Tests/Profiler/Dumper/HtmlTest.php CHANGED
@@ -15,7 +15,7 @@ class Twig_Tests_Profiler_Dumper_HtmlTest extends Twig_Tests_Profiler_Dumper_Abs
15
  {
16
  $dumper = new Twig_Profiler_Dumper_Html();
17
  $this->assertStringMatchesFormat(<<<EOF
18
- <pre>main
19
  └ <span style="background-color: #ffd">index.twig</span> <span style="color: #d44">%d.%dms/%d%</span>
20
  └ embedded.twig::block(<span style="background-color: #dfd">body</span>)
21
  └ <span style="background-color: #ffd">embedded.twig</span>
15
  {
16
  $dumper = new Twig_Profiler_Dumper_Html();
17
  $this->assertStringMatchesFormat(<<<EOF
18
+ <pre>main <span style="color: #d44">%d.%dms/%d%</span>
19
  └ <span style="background-color: #ffd">index.twig</span> <span style="color: #d44">%d.%dms/%d%</span>
20
  └ embedded.twig::block(<span style="background-color: #dfd">body</span>)
21
  └ <span style="background-color: #ffd">embedded.twig</span>
vendor/twig/twig/test/Twig/Tests/Profiler/Dumper/TextTest.php CHANGED
@@ -15,7 +15,7 @@ class Twig_Tests_Profiler_Dumper_TextTest extends Twig_Tests_Profiler_Dumper_Abs
15
  {
16
  $dumper = new Twig_Profiler_Dumper_Text();
17
  $this->assertStringMatchesFormat(<<<EOF
18
- main
19
  └ index.twig %d.%dms/%d%
20
  └ embedded.twig::block(body)
21
  └ embedded.twig
15
  {
16
  $dumper = new Twig_Profiler_Dumper_Text();
17
  $this->assertStringMatchesFormat(<<<EOF
18
+ main %d.%dms/%d%
19
  └ index.twig %d.%dms/%d%
20
  └ embedded.twig::block(body)
21
  └ embedded.twig
vendor/twig/twig/test/Twig/Tests/Profiler/ProfileTest.php CHANGED
@@ -69,9 +69,10 @@ class Twig_Tests_Profiler_ProfileTest extends PHPUnit_Framework_TestCase
69
  public function testGetDuration()
70
  {
71
  $profile = new Twig_Profiler_Profile();
 
72
  $profile->leave();
73
 
74
- $this->assertTrue($profile->getDuration() > 0);
75
  }
76
 
77
  public function testSerialize()
69
  public function testGetDuration()
70
  {
71
  $profile = new Twig_Profiler_Profile();
72
+ usleep(1);
73
  $profile->leave();
74
 
75
+ $this->assertTrue($profile->getDuration() > 0, sprintf('Expected duration > 0, got: %f', $profile->getDuration()));
76
  }
77
 
78
  public function testSerialize()
vendor/upstatement/routes/.coveralls.yml ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ coverage_clover: build/logs/clover.xml
2
+ service_name: travis-ci
3
+ src_dir: .
vendor/upstatement/routes/.travis.yml CHANGED
@@ -3,6 +3,7 @@ language: php
3
  php:
4
  - 5.3
5
  - 5.4
 
6
 
7
  env:
8
  - WP_VERSION=latest WP_MULTISITE=0
3
  php:
4
  - 5.3
5
  - 5.4
6
+ - hhvm
7
 
8
  env:
9
  - WP_VERSION=latest WP_MULTISITE=0
vendor/upstatement/routes/phpunit.xml CHANGED
@@ -10,11 +10,10 @@
10
  <testsuite>
11
  <directory prefix="test-" suffix=".php">./tests/</directory>
12
  </testsuite>
13
- <!-- The suite below HAS to be last to run,
14
- as it includes a test that sets some const and would contaminate
15
- the other tests as well. -->
16
- <testsuite>
17
- <directory prefix="testX-" suffix=".php">./tests/</directory>
18
- </testsuite>
19
  </testsuites>
 
 
 
 
 
20
  </phpunit>
10
  <testsuite>
11
  <directory prefix="test-" suffix=".php">./tests/</directory>
12
  </testsuite>
 
 
 
 
 
 
13
  </testsuites>
14
+ <filter>
15
+ <whitelist processUncoveredFilesFromWhitelist="true">
16
+ <file>Routes.php</file>
17
+ </whitelist>
18
+ </filter>
19
  </phpunit>
vendor/upstatement/routes/tests/bootstrap.php CHANGED
@@ -6,7 +6,7 @@ if ( !$_tests_dir ) $_tests_dir = '/tmp/wordpress-tests-lib';
6
  require_once $_tests_dir . '/includes/functions.php';
7
 
8
  function _manually_load_plugin() {
9
- require dirname( __FILE__ ) . '/../routes.php';
10
  }
11
 
12
  tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );
6
  require_once $_tests_dir . '/includes/functions.php';
7
 
8
  function _manually_load_plugin() {
9
+ require dirname( __FILE__ ) . '/../Routes.php';
10
  }
11
 
12
  tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );