Timber - Version 1.0.4

Version Description

  • New method for {{ post.type }} this makes it easy to access things like {{post.type.labels.name}} right in Twig https://github.com/timber/timber/pull/1003
  • New method for {{ post.preview }} which makes it easy to customize like {{post.preview.length(50).read_more("Keep Reading").end('........')}} https://github.com/timber/timber/pull/1015
  • Added Timber::get_term (thanks @connorjburton!) 58fe671757b30a8eb9de2589bbb817448662e121
  • Fix for revision issue (thanks @dknoben!) 70de6640c68a1321394aaa95202dea70e0755664
  • Fix for issue with uppercase file extensions (thanks @connorjburton) 5632359329894d1b95cd643470950d319628f4c6
  • Better handling for gifs (thanks @connorjburton) 91c40b852c056e0f096345d976767f2e5e993ce9
  • Fix on some old class names in there (thanks @mrgrain) 63fe60ba18c6fce5d545983334af3f752c7c2755
  • Pagination with post counts (thanks @lggorman) 2bcacbe50c90c7936da61d29238e3b52910a3ff9
  • Remove Timber::get_pids (@jarednova) 4278d11d25aaca0d60cbde32c32783dc0effac6b
  • Fixed deprecation in Twig (thanks @simonmilz) 6c80f1d5fd48b8fcbd335f6c8e9c6fed1b008e26
  • Handle ACF image arrays (thanks @connorjburton) 039be5d880fa7f9c9763f4ebd6c40863f4820e0a
Download this release

Release Info

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

Code changes from version 1.0.3 to 1.0.4

README.md CHANGED
@@ -6,7 +6,7 @@ By Jared Novack (<a href="https://twitter.com/jarednova">@JaredNova</a>) and <a
6
 
7
  [![Build Status](https://img.shields.io/travis/timber/timber/master.svg?style=flat-square)](https://travis-ci.org/timber/timber)
8
  [![Coverage Status](https://img.shields.io/coveralls/timber/timber.svg?style=flat-square)](https://coveralls.io/r/timber/timber?branch=master)
9
- [![Dependency Status](https://img.shields.io/versioneye/d/ruby/rails.svg?style=flat-square)](https://www.versioneye.com/user/projects/54e3c717d1ec5734f4000099)
10
  [![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/timber/timber.svg?style=flat-square)](https://scrutinizer-ci.com/g/timber/timber/?branch=master)
11
  [![Latest Stable Version](https://img.shields.io/packagist/v/timber/timber.svg?style=flat-square)](https://packagist.org/packages/timber/timber)
12
  [![WordPress Download Count](https://img.shields.io/wordpress/plugin/dt/timber-library.svg?style=flat-square)](https://wordpress.org/plugins/timber-library/)
6
 
7
  [![Build Status](https://img.shields.io/travis/timber/timber/master.svg?style=flat-square)](https://travis-ci.org/timber/timber)
8
  [![Coverage Status](https://img.shields.io/coveralls/timber/timber.svg?style=flat-square)](https://coveralls.io/r/timber/timber?branch=master)
9
+ [![Dependency Status](https://img.shields.io/versioneye/d/timber/timber.svg?style=flat-square)](https://www.versioneye.com/user/projects/574e40e6e298f30048059b9f)
10
  [![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/timber/timber.svg?style=flat-square)](https://scrutinizer-ci.com/g/timber/timber/?branch=master)
11
  [![Latest Stable Version](https://img.shields.io/packagist/v/timber/timber.svg?style=flat-square)](https://packagist.org/packages/timber/timber)
12
  [![WordPress Download Count](https://img.shields.io/wordpress/plugin/dt/timber-library.svg?style=flat-square)](https://wordpress.org/plugins/timber-library/)
init.php CHANGED
@@ -3,6 +3,4 @@
3
  use Timber\Timber;
4
 
5
  $timber = new Timber();
6
- Timber::$dirname = 'views';
7
-
8
-
3
  use Timber\Timber;
4
 
5
  $timber = new Timber();
6
+ Timber::$dirname = 'views';
 
 
lib/Admin.php CHANGED
@@ -3,7 +3,7 @@
3
  namespace Timber;
4
 
5
  class Admin {
6
-
7
  public static function init() {
8
  $filter = add_filter('plugin_row_meta', array( __CLASS__, 'meta_links' ), 10, 2);
9
  $action = add_action('in_plugin_update_message-timber-library/timber.php', array( __CLASS__, 'in_plugin_update_message'), 10, 2);
@@ -46,9 +46,9 @@ class Admin {
46
  public static function in_plugin_update_message( $plugin_data, $r ) {
47
  $m = '';
48
 
49
- if ( version_compare("1.0.0", $plugin_data->new_version) <= 0 ) {
50
  //a version of 1.0.0 or greater is availalbe
51
- $m .= '<p><b>Warning:</b> Timber 1.0 removed a number of features and methods. Before upgrading please test your theme on a local or staging site to ensure that your theme will work with the newest version.</p>
52
 
53
  <p><strong>Is your theme in active development?</strong> That is, is someone actively in PHP files writing new code? If you answered "no", then <i>do not upgrade</i>. You will not benefit from Timber 1.0</p>';
54
 
@@ -58,13 +58,13 @@ class Admin {
58
 
59
  }
60
 
61
- if ( version_compare("1.0.0", $plugin_data->Version) <= 0 ) {
62
  $m .= "<p>Are you seeing errors since upgrading to 1.0? Download <b><a href='https://downloads.wordpress.org/plugin/timber-library.0.22.6.zip'>Version 0.22.6</a></b> to bring things back to stability.";
63
  }
64
-
65
  // show message
66
  echo '<br />'.sprintf($m);
67
-
68
  }
69
 
70
  }
3
  namespace Timber;
4
 
5
  class Admin {
6
+
7
  public static function init() {
8
  $filter = add_filter('plugin_row_meta', array( __CLASS__, 'meta_links' ), 10, 2);
9
  $action = add_action('in_plugin_update_message-timber-library/timber.php', array( __CLASS__, 'in_plugin_update_message'), 10, 2);
46
  public static function in_plugin_update_message( $plugin_data, $r ) {
47
  $m = '';
48
 
49
+ if ( version_compare("1.0.0", $plugin_data['new_version']) <= 0 ) {
50
  //a version of 1.0.0 or greater is availalbe
51
+ $m .= '<p><b>Warning:</b> Timber 1.0 removed a number of features and methods. Before upgrading please test your theme on a local or staging site to ensure that your theme will work with the newest version.</p>
52
 
53
  <p><strong>Is your theme in active development?</strong> That is, is someone actively in PHP files writing new code? If you answered "no", then <i>do not upgrade</i>. You will not benefit from Timber 1.0</p>';
54
 
58
 
59
  }
60
 
61
+ if ( version_compare("1.0.0", $plugin_data['Version']) <= 0 ) {
62
  $m .= "<p>Are you seeing errors since upgrading to 1.0? Download <b><a href='https://downloads.wordpress.org/plugin/timber-library.0.22.6.zip'>Version 0.22.6</a></b> to bring things back to stability.";
63
  }
64
+
65
  // show message
66
  echo '<br />'.sprintf($m);
67
+
68
  }
69
 
70
  }
lib/Archives.php CHANGED
@@ -61,7 +61,7 @@ class Archives extends Core {
61
  * }
62
  * @param string $base any additional paths that need to be prepended to the URLs that are generated, for example: "tags"
63
  */
64
- function __construct( $args = null, $base = '' ) {
65
 
66
 
67
  $this->init($args, $base);
@@ -72,7 +72,7 @@ class Archives extends Core {
72
  * @param array|string $args
73
  * @param string $base
74
  */
75
- function init( $args = null, $base = '' ) {
76
  $this->base = $base;
77
  $this->items = $this->get_items($args);
78
  }
@@ -180,7 +180,7 @@ class Archives extends Core {
180
  * @param array|string $args
181
  * @return array|string
182
  */
183
- function get_items( $args = null ) {
184
  global $wpdb;
185
 
186
  $defaults = array(
61
  * }
62
  * @param string $base any additional paths that need to be prepended to the URLs that are generated, for example: "tags"
63
  */
64
+ public function __construct( $args = null, $base = '' ) {
65
 
66
 
67
  $this->init($args, $base);
72
  * @param array|string $args
73
  * @param string $base
74
  */
75
+ public function init( $args = null, $base = '' ) {
76
  $this->base = $base;
77
  $this->items = $this->get_items($args);
78
  }
180
  * @param array|string $args
181
  * @return array|string
182
  */
183
+ public function get_items( $args = null ) {
184
  global $wpdb;
185
 
186
  $defaults = array(
lib/Cache/KeyGenerator.php CHANGED
@@ -10,18 +10,18 @@ class KeyGenerator implements KeyGeneratorInterface {
10
  * @param mixed $value
11
  * @return string
12
  */
13
- public function generateKey($value) {
14
- if (is_a($value, 'TimberKeyGeneratorInterface')) {
15
  return $value->_get_cache_key();
16
  }
17
 
18
- if (is_array($value) && isset($value['_cache_key'])) {
19
  return $value['_cache_key'];
20
  }
21
 
22
  $key = md5(json_encode($value));
23
- if (is_object($value)) {
24
- $key = get_class($value) . '|' . $key;
25
  }
26
 
27
  return $key;
10
  * @param mixed $value
11
  * @return string
12
  */
13
+ public function generateKey( $value ) {
14
+ if ( is_a($value, 'Timber\Cache\TimberKeyGeneratorInterface') ) {
15
  return $value->_get_cache_key();
16
  }
17
 
18
+ if ( is_array($value) && isset($value['_cache_key']) ) {
19
  return $value['_cache_key'];
20
  }
21
 
22
  $key = md5(json_encode($value));
23
+ if ( is_object($value) ) {
24
+ $key = get_class($value).'|'.$key;
25
  }
26
 
27
  return $key;
lib/Comment.php CHANGED
@@ -39,18 +39,19 @@ class Comment extends Core implements CoreInterface {
39
  public $comment_date;
40
  public $comment_ID;
41
  public $user_id;
 
42
  public $comment_author;
43
 
44
- public $children = array();
45
 
46
  /**
47
  * @param int $cid
48
  */
49
- function __construct( $cid ) {
50
  $this->init($cid);
51
  }
52
 
53
- function __toString() {
54
  return $this->content();
55
  }
56
 
@@ -58,7 +59,7 @@ class Comment extends Core implements CoreInterface {
58
  * @internal
59
  * @param integer $cid
60
  */
61
- function init( $cid ) {
62
  $comment_data = $cid;
63
  if ( is_integer($cid) ) {
64
  $comment_data = get_comment($cid);
@@ -150,6 +151,23 @@ class Comment extends Core implements CoreInterface {
150
  return apply_filters('get_comment_text ', $this->comment_content);
151
  }
152
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  /**
154
  * @api
155
  * @example
@@ -163,7 +181,7 @@ class Comment extends Core implements CoreInterface {
163
  * @return boolean
164
  */
165
  public function approved() {
166
- return $this->comment_approved;
167
  }
168
 
169
  /**
39
  public $comment_date;
40
  public $comment_ID;
41
  public $user_id;
42
+ public $post_id;
43
  public $comment_author;
44
 
45
+ protected $children = array();
46
 
47
  /**
48
  * @param int $cid
49
  */
50
+ public function __construct( $cid ) {
51
  $this->init($cid);
52
  }
53
 
54
+ public function __toString() {
55
  return $this->content();
56
  }
57
 
59
  * @internal
60
  * @param integer $cid
61
  */
62
+ public function init( $cid ) {
63
  $comment_data = $cid;
64
  if ( is_integer($cid) ) {
65
  $comment_data = get_comment($cid);
151
  return apply_filters('get_comment_text ', $this->comment_content);
152
  }
153
 
154
+ /**
155
+ * @api
156
+ * @return array Comments
157
+ */
158
+ public function children() {
159
+ return $this->children;
160
+ }
161
+
162
+ /**
163
+ */
164
+ public function add_child( Comment $child_comment ) {
165
+ if ( !is_array($this->children) ) {
166
+ $this->children = array();
167
+ }
168
+ return $this->children[] = $child_comment;
169
+ }
170
+
171
  /**
172
  * @api
173
  * @example
181
  * @return boolean
182
  */
183
  public function approved() {
184
+ return Helper::is_true($this->comment_approved);
185
  }
186
 
187
  /**
lib/Core.php CHANGED
@@ -12,7 +12,7 @@ abstract class Core {
12
  *
13
  * @return boolean
14
  */
15
- function __isset( $field ) {
16
  if ( isset($this->$field) ) {
17
  return $this->$field;
18
  }
@@ -23,7 +23,7 @@ abstract class Core {
23
  * This is helpful for twig to return properties and methods see: https://github.com/fabpot/Twig/issues/2
24
  * @return mixed
25
  */
26
- function __call( $field, $args ) {
27
  return $this->__get($field);
28
  }
29
 
@@ -32,7 +32,7 @@ abstract class Core {
32
  *
33
  * @return mixed
34
  */
35
- function __get( $field ) {
36
  if ( property_exists($this, $field) ) {
37
  return $this->$field;
38
  }
@@ -56,7 +56,7 @@ abstract class Core {
56
  * ```
57
  * @param array|object $info an object or array you want to grab data from to attach to the Timber object
58
  */
59
- function import( $info, $force = false ) {
60
  if ( is_object($info) ) {
61
  $info = get_object_vars($info);
62
  }
@@ -77,7 +77,7 @@ abstract class Core {
77
  * @param string $key
78
  * @param mixed $value
79
  */
80
- function update( $key, $value ) {
81
  update_metadata($this->object_type, $this->ID, $key, $value);
82
  }
83
 
@@ -94,7 +94,7 @@ abstract class Core {
94
  * ```
95
  * @return bool
96
  */
97
- function can_edit() {
98
  if ( !function_exists('current_user_can') ) {
99
  return false;
100
  }
@@ -109,10 +109,9 @@ abstract class Core {
109
  *
110
  * @return array
111
  */
112
- function get_method_values() {
113
  $ret = array();
114
  $ret['can_edit'] = $this->can_edit();
115
  return $ret;
116
  }
117
-
118
- }
12
  *
13
  * @return boolean
14
  */
15
+ public function __isset( $field ) {
16
  if ( isset($this->$field) ) {
17
  return $this->$field;
18
  }
23
  * This is helpful for twig to return properties and methods see: https://github.com/fabpot/Twig/issues/2
24
  * @return mixed
25
  */
26
+ public function __call( $field, $args ) {
27
  return $this->__get($field);
28
  }
29
 
32
  *
33
  * @return mixed
34
  */
35
+ public function __get( $field ) {
36
  if ( property_exists($this, $field) ) {
37
  return $this->$field;
38
  }
56
  * ```
57
  * @param array|object $info an object or array you want to grab data from to attach to the Timber object
58
  */
59
+ public function import( $info, $force = false ) {
60
  if ( is_object($info) ) {
61
  $info = get_object_vars($info);
62
  }
77
  * @param string $key
78
  * @param mixed $value
79
  */
80
+ public function update( $key, $value ) {
81
  update_metadata($this->object_type, $this->ID, $key, $value);
82
  }
83
 
94
  * ```
95
  * @return bool
96
  */
97
+ public function can_edit() {
98
  if ( !function_exists('current_user_can') ) {
99
  return false;
100
  }
109
  *
110
  * @return array
111
  */
112
+ public function get_method_values() {
113
  $ret = array();
114
  $ret['can_edit'] = $this->can_edit();
115
  return $ret;
116
  }
117
+ }
 
lib/CoreInterface.php CHANGED
@@ -15,4 +15,4 @@ interface CoreInterface {
15
 
16
  public function meta( $key );
17
 
18
- }
15
 
16
  public function meta( $key );
17
 
18
+ }
lib/Helper.php CHANGED
@@ -23,11 +23,11 @@ class Helper {
23
  * Timber::render('single.twig', $context);
24
  * ```
25
  *
26
- * @param string $slug Unique identifier for transient
27
- * @param callable $callback Callback that generates the data that's to be cached
28
- * @param int $transient_time (optional) Expiration of transients in seconds
29
- * @param int $lock_timeout (optional) How long (in seconds) to lock the transient to prevent race conditions
30
- * @param bool $force (optional) Force callback to be executed when transient is locked
31
  * @return mixed
32
  */
33
  public static function transient( $slug, $callback, $transient_time = 0, $lock_timeout = 5, $force = false ) {
@@ -37,38 +37,42 @@ class Helper {
37
  $data = $enable_transients ? get_transient($slug) : false;
38
 
39
  if ( false === $data ) {
 
 
 
 
40
 
41
- if ( $enable_transients && self::_is_transient_locked($slug) ) {
42
-
43
- $force = apply_filters('timber_force_transients', $force);
44
- $force = apply_filters('timber_force_transient_'.$slug, $force);
45
-
46
- if ( !$force ) {
47
- //the server is currently executing the process.
48
- //We're just gonna dump these users. Sorry!
49
- return false;
50
- }
51
-
52
- $enable_transients = false;
53
- }
54
-
55
- // lock timeout shouldn't be higher than 5 seconds, unless
56
- // remote calls with high timeouts are made here
57
- if ( $enable_transients ) {
58
- self::_lock_transient($slug, $lock_timeout);
59
- }
60
-
61
- $data = $callback();
62
-
63
- if ( $enable_transients ) {
64
- set_transient($slug, $data, $transient_time);
65
- self::_unlock_transient($slug);
66
  }
67
-
 
 
 
 
 
 
 
 
 
 
68
  }
69
-
70
  return $data;
71
-
72
  }
73
 
74
  /**
@@ -76,7 +80,7 @@ class Helper {
76
  * @param string $slug
77
  * @param integer $lock_timeout
78
  */
79
- static function _lock_transient( $slug, $lock_timeout ) {
80
  set_transient($slug.'_lock', true, $lock_timeout);
81
  }
82
 
@@ -84,7 +88,7 @@ class Helper {
84
  * @internal
85
  * @param string $slug
86
  */
87
- static function _unlock_transient( $slug ) {
88
  delete_transient($slug.'_lock', true);
89
  }
90
 
@@ -92,7 +96,7 @@ class Helper {
92
  * @internal
93
  * @param string $slug
94
  */
95
- static function _is_transient_locked( $slug ) {
96
  return (bool) get_transient($slug.'_lock');
97
  }
98
 
@@ -171,7 +175,7 @@ class Helper {
171
  * @param mixed $function_name or array( $class( string|object ), $function_name )
172
  * @param array (optional) $defaults
173
  * @param bool (optional) $return_output_buffer Return function output instead of return value (default: false)
174
- * @return \TimberFunctionWrapper
175
  */
176
  public static function function_wrapper( $function_name, $defaults = array(), $return_output_buffer = false ) {
177
  return new FunctionWrapper($function_name, $defaults, $return_output_buffer);
@@ -195,7 +199,7 @@ class Helper {
195
 
196
  /**
197
  * @param string $message that you want to output
198
- * @return void
199
  */
200
  public static function warn( $message ) {
201
  return trigger_error($message, E_USER_WARNING);
@@ -321,7 +325,7 @@ class Helper {
321
  *
322
  *
323
  * @param array $array
324
- * @return stdClass
325
  */
326
  public static function array_to_object( $array ) {
327
  $obj = new \stdClass;
@@ -451,7 +455,7 @@ class Helper {
451
  * @return string
452
  */
453
  public static function get_comment_form( $post_id = null, $args = array() ) {
454
- return self::ob_function( 'comment_form', array( $args, $post_id ) );
455
  }
456
 
457
  /**
@@ -530,9 +534,9 @@ class Helper {
530
  }
531
 
532
  /**
533
- *
534
  */
535
- function get_current_url() {
536
  Helper::warn('TimberHelper::get_current_url() is deprecated and will be removed in future versions, use Timber\URLHelper::get_current_url()');
537
  return URLHelper::get_current_url();
538
  }
23
  * Timber::render('single.twig', $context);
24
  * ```
25
  *
26
+ * @param string $slug Unique identifier for transient
27
+ * @param callable $callback Callback that generates the data that's to be cached
28
+ * @param integer $transient_time (optional) Expiration of transients in seconds
29
+ * @param integer $lock_timeout (optional) How long (in seconds) to lock the transient to prevent race conditions
30
+ * @param boolean $force (optional) Force callback to be executed when transient is locked
31
  * @return mixed
32
  */
33
  public static function transient( $slug, $callback, $transient_time = 0, $lock_timeout = 5, $force = false ) {
37
  $data = $enable_transients ? get_transient($slug) : false;
38
 
39
  if ( false === $data ) {
40
+ $data = self::handle_transient_locking($slug, $callback, $transient_time, $lock_timeout, $force, $enable_transients);
41
+ }
42
+ return $data;
43
+ }
44
 
45
+ /**
46
+ * Does the dirty work of locking the transient, running the callback and unlocking
47
+ * @param string $slug
48
+ * @param callable $callback
49
+ * @param integer $transient_time Expiration of transients in seconds
50
+ * @param integer $lock_timeout How long (in seconds) to lock the transient to prevent race conditions
51
+ * @param boolean $force Force callback to be executed when transient is locked
52
+ * @param boolean $enable_transients Force callback to be executed when transient is locked
53
+ */
54
+ protected static function handle_transient_locking( $slug, $callback, $transient_time, $lock_timeout, $force, $enable_transients ) {
55
+ if ( $enable_transients && self::_is_transient_locked($slug) ) {
56
+ $force = apply_filters('timber_force_transients', $force);
57
+ $force = apply_filters('timber_force_transient_'.$slug, $force);
58
+ if ( !$force ) {
59
+ //the server is currently executing the process.
60
+ //We're just gonna dump these users. Sorry!
61
+ return false;
 
 
 
 
 
 
 
 
62
  }
63
+ $enable_transients = false;
64
+ }
65
+ // lock timeout shouldn't be higher than 5 seconds, unless
66
+ // remote calls with high timeouts are made here
67
+ if ( $enable_transients ) {
68
+ self::_lock_transient($slug, $lock_timeout);
69
+ }
70
+ $data = $callback();
71
+ if ( $enable_transients ) {
72
+ set_transient($slug, $data, $transient_time);
73
+ self::_unlock_transient($slug);
74
  }
 
75
  return $data;
 
76
  }
77
 
78
  /**
80
  * @param string $slug
81
  * @param integer $lock_timeout
82
  */
83
+ public static function _lock_transient( $slug, $lock_timeout ) {
84
  set_transient($slug.'_lock', true, $lock_timeout);
85
  }
86
 
88
  * @internal
89
  * @param string $slug
90
  */
91
+ public static function _unlock_transient( $slug ) {
92
  delete_transient($slug.'_lock', true);
93
  }
94
 
96
  * @internal
97
  * @param string $slug
98
  */
99
+ public static function _is_transient_locked( $slug ) {
100
  return (bool) get_transient($slug.'_lock');
101
  }
102
 
175
  * @param mixed $function_name or array( $class( string|object ), $function_name )
176
  * @param array (optional) $defaults
177
  * @param bool (optional) $return_output_buffer Return function output instead of return value (default: false)
178
+ * @return Timber\FunctionWrapper|mixed
179
  */
180
  public static function function_wrapper( $function_name, $defaults = array(), $return_output_buffer = false ) {
181
  return new FunctionWrapper($function_name, $defaults, $return_output_buffer);
199
 
200
  /**
201
  * @param string $message that you want to output
202
+ * @return boolean
203
  */
204
  public static function warn( $message ) {
205
  return trigger_error($message, E_USER_WARNING);
325
  *
326
  *
327
  * @param array $array
328
+ * @return \stdClass
329
  */
330
  public static function array_to_object( $array ) {
331
  $obj = new \stdClass;
455
  * @return string
456
  */
457
  public static function get_comment_form( $post_id = null, $args = array() ) {
458
+ return self::ob_function('comment_form', array($args, $post_id));
459
  }
460
 
461
  /**
534
  }
535
 
536
  /**
537
+ * @return string
538
  */
539
+ public function get_current_url() {
540
  Helper::warn('TimberHelper::get_current_url() is deprecated and will be removed in future versions, use Timber\URLHelper::get_current_url()');
541
  return URLHelper::get_current_url();
542
  }
lib/Image.php CHANGED
@@ -104,8 +104,8 @@ class Image extends Post implements CoreInterface {
104
  * @return string the src of the file
105
  */
106
  public function __toString() {
107
- if ( $this->src() ) {
108
- return $this->src();
109
  }
110
  return '';
111
  }
@@ -114,7 +114,7 @@ class Image extends Post implements CoreInterface {
114
  * Get a PHP array with pathinfo() info from the file
115
  * @return array
116
  */
117
- function get_pathinfo() {
118
  return pathinfo($this->file);
119
  }
120
 
@@ -157,7 +157,7 @@ class Image extends Post implements CoreInterface {
157
  /**
158
  * @return array
159
  */
160
- protected function get_post_custom($iid) {
161
  $pc = get_post_custom($iid);
162
  if ( is_bool($pc) ) {
163
  return array();
@@ -221,11 +221,20 @@ class Image extends Post implements CoreInterface {
221
  * @internal
222
  * @param int $iid
223
  */
224
- function init( $iid = false ) {
 
225
  if ( !$iid ) { Helper::error_log('Initalized TimberImage without providing first parameter.'); return; }
 
 
226
  if ( $iid instanceof self ) {
227
  $iid = (int) $iid->ID;
228
  }
 
 
 
 
 
 
229
  if ( !is_numeric($iid) && is_string($iid) ) {
230
  if ( strstr($iid, '://') ) {
231
  $this->init_with_url($iid);
104
  * @return string the src of the file
105
  */
106
  public function __toString() {
107
+ if ( $src = $this->src() ) {
108
+ return $src;
109
  }
110
  return '';
111
  }
114
  * Get a PHP array with pathinfo() info from the file
115
  * @return array
116
  */
117
+ public function get_pathinfo() {
118
  return pathinfo($this->file);
119
  }
120
 
157
  /**
158
  * @return array
159
  */
160
+ protected function get_post_custom( $iid ) {
161
  $pc = get_post_custom($iid);
162
  if ( is_bool($pc) ) {
163
  return array();
221
  * @internal
222
  * @param int $iid
223
  */
224
+ public function init( $iid = false ) {
225
+ //Make sure we actually have something to work with
226
  if ( !$iid ) { Helper::error_log('Initalized TimberImage without providing first parameter.'); return; }
227
+
228
+ //If passed TimberImage, grab the ID and continue
229
  if ( $iid instanceof self ) {
230
  $iid = (int) $iid->ID;
231
  }
232
+
233
+ //If passed ACF image array
234
+ if ( is_array($iid) && isset($iid['ID']) ) {
235
+ $iid = $iid['ID'];
236
+ }
237
+
238
  if ( !is_numeric($iid) && is_string($iid) ) {
239
  if ( strstr($iid, '://') ) {
240
  $this->init_with_url($iid);
lib/Image/Operation/Letterbox.php CHANGED
@@ -23,7 +23,7 @@ class Letterbox extends ImageOperation {
23
  * @param int $h height
24
  * @param string $color hex string, for color of padding bands
25
  */
26
- function __construct( $w, $h, $color ) {
27
  $this->w = $w;
28
  $this->h = $h;
29
  $this->color = $color;
23
  * @param int $h height
24
  * @param string $color hex string, for color of padding bands
25
  */
26
+ public function __construct( $w, $h, $color ) {
27
  $this->w = $w;
28
  $this->h = $h;
29
  $this->color = $color;
lib/Image/Operation/Resize.php CHANGED
@@ -3,6 +3,7 @@
3
  namespace Timber\Image\Operation;
4
 
5
  use Timber\Helper;
 
6
  use Timber\Image\Operation as ImageOperation;
7
 
8
  /**
@@ -23,7 +24,7 @@ class Resize extends ImageOperation {
23
  * @param int $h height of new image
24
  * @param string $crop cropping method, one of: 'default', 'center', 'top', 'bottom', 'left', 'right', 'top-center', 'bottom-center'.
25
  */
26
- function __construct( $w, $h, $crop ) {
27
  $this->w = $w;
28
  $this->h = $h;
29
  // Sanitize crop position
@@ -59,19 +60,18 @@ class Resize extends ImageOperation {
59
  * @param string $load_filename
60
  * @param string $save_filename
61
  */
62
- protected function run_animated_gif( $load_filename, $save_filename ) {
63
- $image = wp_get_image_editor($load_filename);
64
- $current_size = $image->get_size();
65
  $src_w = $current_size['width'];
66
  $src_h = $current_size['height'];
67
  $w = $this->w;
68
  $h = $this->h;
69
  if ( !class_exists('Imagick') ) {
70
- return false;
71
  }
72
  $image = new \Imagick($load_filename);
73
  $image = $image->coalesceImages();
74
- $crop = self::get_target_sizes($load_filename);
75
  foreach ( $image as $frame ) {
76
  $frame->cropImage($crop['src_w'], $crop['src_h'], $crop['x'], $crop['y']);
77
  $frame->thumbnailImage($w, $h);
@@ -82,10 +82,9 @@ class Resize extends ImageOperation {
82
  }
83
 
84
  /**
85
- * @param string $load_filename
86
  */
87
- protected function get_target_sizes( $load_filename ) {
88
- $image = wp_get_image_editor($load_filename);
89
  $w = $this->w;
90
  $h = $this->h;
91
  $crop = $this->crop;
@@ -171,41 +170,46 @@ class Resize extends ImageOperation {
171
  * @return boolean|null true if everything went fine, false otherwise
172
  */
173
  public function run( $load_filename, $save_filename ) {
174
- //should be resized by gif resizer
175
- if ( \Timber\ImageHelper::is_animated_gif($load_filename) ) {
176
- //attempt to resize
177
- //return if successful
178
- //proceed if not
179
- $gif = self::run_animated_gif($load_filename, $save_filename);
180
- if ( $gif ) {
181
- return true;
 
 
 
182
  }
183
- }
184
- $image = wp_get_image_editor($load_filename);
185
- if ( !is_wp_error($image) ) {
186
- $crop = self::get_target_sizes($load_filename);
187
- $image->crop($crop['x'],
188
  $crop['y'],
189
  $crop['src_w'],
190
  $crop['src_h'],
191
  $crop['target_w'],
192
  $crop['target_h']
193
  );
194
- $result = $image->save($save_filename);
195
- if ( is_wp_error($result) ) {
196
  // @codeCoverageIgnoreStart
197
- Helper::error_log('Error resizing image');
198
- Helper::error_log($result);
199
  return false;
200
  // @codeCoverageIgnoreEnd
201
  } else {
202
  return true;
203
  }
204
- } else if ( isset($image->error_data['error_loading_image']) ) {
205
  // @codeCoverageIgnoreStart
206
- Helper::error_log('Error loading '.$image->error_data['error_loading_image']);
207
  } else {
208
- Helper::error_log($image);
 
 
 
 
209
  // @codeCoverageIgnoreEnd
210
  }
211
  }
3
  namespace Timber\Image\Operation;
4
 
5
  use Timber\Helper;
6
+ use Timber\ImageHelper;
7
  use Timber\Image\Operation as ImageOperation;
8
 
9
  /**
24
  * @param int $h height of new image
25
  * @param string $crop cropping method, one of: 'default', 'center', 'top', 'bottom', 'left', 'right', 'top-center', 'bottom-center'.
26
  */
27
+ public function __construct( $w, $h, $crop ) {
28
  $this->w = $w;
29
  $this->h = $h;
30
  // Sanitize crop position
60
  * @param string $load_filename
61
  * @param string $save_filename
62
  */
63
+ protected function run_animated_gif( $load_filename, $save_filename, $editor ) {
64
+ $current_size = $editor->get_size();
 
65
  $src_w = $current_size['width'];
66
  $src_h = $current_size['height'];
67
  $w = $this->w;
68
  $h = $this->h;
69
  if ( !class_exists('Imagick') ) {
70
+ Helper::error_log( 'Can not resize GIF, Imagick is not installed' );
71
  }
72
  $image = new \Imagick($load_filename);
73
  $image = $image->coalesceImages();
74
+ $crop = self::get_target_sizes($editor);
75
  foreach ( $image as $frame ) {
76
  $frame->cropImage($crop['src_w'], $crop['src_h'], $crop['x'], $crop['y']);
77
  $frame->thumbnailImage($w, $h);
82
  }
83
 
84
  /**
85
+ * @param WP_Image_Editor $image
86
  */
87
+ protected function get_target_sizes( \WP_Image_Editor $image ) {
 
88
  $w = $this->w;
89
  $h = $this->h;
90
  $crop = $this->crop;
170
  * @return boolean|null true if everything went fine, false otherwise
171
  */
172
  public function run( $load_filename, $save_filename ) {
173
+ $image = wp_get_image_editor( $load_filename );
174
+ if ( !is_wp_error( $image ) ) {
175
+ //should be resized by gif resizer
176
+ if ( ImageHelper::is_animated_gif( $load_filename ) ) {
177
+ //attempt to resize
178
+ //return if successful
179
+ //proceed if not
180
+ $gif = self::run_animated_gif( $load_filename, $save_filename, $image );
181
+ if ( $gif ) {
182
+ return true;
183
+ }
184
  }
185
+
186
+ $crop = self::get_target_sizes( $image );
187
+ $image->crop( $crop['x'],
 
 
188
  $crop['y'],
189
  $crop['src_w'],
190
  $crop['src_h'],
191
  $crop['target_w'],
192
  $crop['target_h']
193
  );
194
+ $result = $image->save( $save_filename );
195
+ if ( is_wp_error( $result ) ) {
196
  // @codeCoverageIgnoreStart
197
+ Helper::error_log( 'Error resizing image' );
198
+ Helper::error_log( $result );
199
  return false;
200
  // @codeCoverageIgnoreEnd
201
  } else {
202
  return true;
203
  }
204
+ } else if ( isset( $image->error_data['error_loading_image'] ) ) {
205
  // @codeCoverageIgnoreStart
206
+ Helper::error_log( 'Error loading ' . $image->error_data['error_loading_image'] );
207
  } else {
208
+ if(!extension_loaded('gd')) {
209
+ Helper::error_log( 'Can not resize image, please installed php-gd' );
210
+ } else {
211
+ Helper::error_log( $image );
212
+ }
213
  // @codeCoverageIgnoreEnd
214
  }
215
  }
lib/Image/Operation/Retina.php CHANGED
@@ -23,7 +23,7 @@ class Retina extends ImageOperation {
23
  * Construct our operation
24
  * @param float $factor to multiply original dimensions by
25
  */
26
- function __construct( $factor ) {
27
  $this->factor = $factor;
28
  }
29
 
@@ -34,7 +34,7 @@ class Retina extends ImageOperation {
34
  * @param string $src_extension the extension (ex: .jpg)
35
  * @return string the final filename to be used (ex: my-awesome-pic@2x.jpg)
36
  */
37
- function filename( $src_filename, $src_extension ) {
38
  $newbase = $src_filename.'@'.$this->factor.'x'; // add @2x, @3x, @1.5x, etc.
39
  $new_name = $newbase.'.'.$src_extension;
40
  return $new_name;
@@ -50,7 +50,7 @@ class Retina extends ImageOperation {
50
  * (ex: /src/var/www/wp-content/uploads/my-pic@2x.jpg)
51
  * @return bool true if everything went fine, false otherwise
52
  */
53
- function run( $load_filename, $save_filename ) {
54
  $image = wp_get_image_editor($load_filename);
55
  if ( !is_wp_error($image) ) {
56
  $current_size = $image->get_size();
23
  * Construct our operation
24
  * @param float $factor to multiply original dimensions by
25
  */
26
+ public function __construct( $factor ) {
27
  $this->factor = $factor;
28
  }
29
 
34
  * @param string $src_extension the extension (ex: .jpg)
35
  * @return string the final filename to be used (ex: my-awesome-pic@2x.jpg)
36
  */
37
+ public function filename( $src_filename, $src_extension ) {
38
  $newbase = $src_filename.'@'.$this->factor.'x'; // add @2x, @3x, @1.5x, etc.
39
  $new_name = $newbase.'.'.$src_extension;
40
  return $new_name;
50
  * (ex: /src/var/www/wp-content/uploads/my-pic@2x.jpg)
51
  * @return bool true if everything went fine, false otherwise
52
  */
53
+ public function run( $load_filename, $save_filename ) {
54
  $image = wp_get_image_editor($load_filename);
55
  if ( !is_wp_error($image) ) {
56
  $current_size = $image->get_size();
lib/Image/Operation/ToJpg.php CHANGED
@@ -16,7 +16,7 @@ class ToJpg extends ImageOperation {
16
  /**
17
  * @param string $color hex string of color to use for transparent zones
18
  */
19
- function __construct( $color ) {
20
  $this->color = $color;
21
  }
22
 
@@ -25,7 +25,7 @@ class ToJpg extends ImageOperation {
25
  * @param string $src_extension ignored
26
  * @return string the final filename to be used (ex: my-awesome-pic.jpg)
27
  */
28
- function filename( $src_filename, $src_extension = 'jpg' ) {
29
  $new_name = $src_filename.'.jpg';
30
  return $new_name;
31
  }
@@ -39,7 +39,7 @@ class ToJpg extends ImageOperation {
39
  * (ex: /src/var/www/wp-content/uploads/my-pic.png)
40
  * @return bool true if everything went fine, false otherwise
41
  */
42
- function run( $load_filename, $save_filename ) {
43
  $input = self::image_create($load_filename);
44
  list($width, $height) = getimagesize($load_filename);
45
  $output = imagecreatetruecolor($width, $height);
@@ -56,7 +56,7 @@ class ToJpg extends ImageOperation {
56
  * @return resource an image identifier representing the image obtained from the given filename
57
  * will return the same data type regardless of whether the source is gif or png
58
  */
59
- function image_create( $filename, $ext = 'auto' ) {
60
  if ( $ext == 'auto' ) {
61
  $ext = wp_check_filetype($filename);
62
  if ( isset($ext['ext']) ) {
16
  /**
17
  * @param string $color hex string of color to use for transparent zones
18
  */
19
+ public function __construct( $color ) {
20
  $this->color = $color;
21
  }
22
 
25
  * @param string $src_extension ignored
26
  * @return string the final filename to be used (ex: my-awesome-pic.jpg)
27
  */
28
+ public function filename( $src_filename, $src_extension = 'jpg' ) {
29
  $new_name = $src_filename.'.jpg';
30
  return $new_name;
31
  }
39
  * (ex: /src/var/www/wp-content/uploads/my-pic.png)
40
  * @return bool true if everything went fine, false otherwise
41
  */
42
+ public function run( $load_filename, $save_filename ) {
43
  $input = self::image_create($load_filename);
44
  list($width, $height) = getimagesize($load_filename);
45
  $output = imagecreatetruecolor($width, $height);
56
  * @return resource an image identifier representing the image obtained from the given filename
57
  * will return the same data type regardless of whether the source is gif or png
58
  */
59
+ public function image_create( $filename, $ext = 'auto' ) {
60
  if ( $ext == 'auto' ) {
61
  $ext = wp_check_filetype($filename);
62
  if ( isset($ext['ext']) ) {
lib/ImageHelper.php CHANGED
@@ -146,7 +146,7 @@ class ImageHelper {
146
  * @param int $h
147
  * @param string $color
148
  * @param bool $force
149
- * @return mixed|null|string
150
  */
151
  public static function letterbox( $src, $w, $h, $color = '#000000', $force = false ) {
152
  $op = new Letterbox($w, $h, $color);
@@ -365,7 +365,7 @@ class ImageHelper {
365
  $parts = pathinfo($tmp);
366
  $result['subdir'] = ($parts['dirname'] === '/') ? '' : $parts['dirname'];
367
  $result['filename'] = $parts['filename'];
368
- $result['extension'] = $parts['extension'];
369
  $result['basename'] = $parts['basename'];
370
  // todo filename
371
  return $result;
@@ -394,7 +394,7 @@ class ImageHelper {
394
  }
395
  $url .= '/'.$filename;
396
  if ( !$absolute ) {
397
- $url = str_replace(home_url(), '', $url);
398
  }
399
  // $url = TimberURLHelper::remove_double_slashes( $url);
400
  return $url;
@@ -469,8 +469,8 @@ class ImageHelper {
469
  $au['basename']
470
  );
471
 
472
- $new_url = apply_filters( 'timber/image/new_url', $new_url );
473
- $new_server_path = apply_filters( 'timber/image/new_path', $new_server_path );
474
 
475
  // if already exists...
476
  if ( file_exists($new_server_path) ) {
@@ -484,7 +484,7 @@ class ImageHelper {
484
  }
485
  // otherwise generate result file
486
  if ( $op->run($old_server_path, $new_server_path) ) {
487
- if ( get_class($op) === 'TimberImageOperationResize' && $external ) {
488
  $new_url = strtolower($new_url);
489
  }
490
  return $new_url;
@@ -497,7 +497,7 @@ class ImageHelper {
497
 
498
  // -- the below methods are just used for unit testing the URL generation code
499
  //
500
- static function get_letterbox_file_url( $url, $w, $h, $color ) {
501
  $au = self::analyze_url($url);
502
  $op = new Image\Operation\Letterbox($w, $h, $color);
503
  $new_url = self::_get_file_url(
@@ -508,6 +508,7 @@ class ImageHelper {
508
  );
509
  return $new_url;
510
  }
 
511
  public static function get_letterbox_file_path( $url, $w, $h, $color ) {
512
  $au = self::analyze_url($url);
513
  $op = new Image\Operation\Letterbox($w, $h, $color);
@@ -518,7 +519,8 @@ class ImageHelper {
518
  );
519
  return $new_path;
520
  }
521
- static function get_resize_file_url( $url, $w, $h, $crop ) {
 
522
  $au = self::analyze_url($url);
523
  $op = new Image\Operation\Resize($w, $h, $crop);
524
  $new_url = self::_get_file_url(
@@ -529,7 +531,8 @@ class ImageHelper {
529
  );
530
  return $new_url;
531
  }
532
- static function get_resize_file_path( $url, $w, $h, $crop ) {
 
533
  $au = self::analyze_url($url);
534
  $op = new Image\Operation\Resize($w, $h, $crop);
535
  $new_path = self::_get_file_path(
@@ -539,4 +542,4 @@ class ImageHelper {
539
  );
540
  return $new_path;
541
  }
542
- }
146
  * @param int $h
147
  * @param string $color
148
  * @param bool $force
149
+ * @return string
150
  */
151
  public static function letterbox( $src, $w, $h, $color = '#000000', $force = false ) {
152
  $op = new Letterbox($w, $h, $color);
365
  $parts = pathinfo($tmp);
366
  $result['subdir'] = ($parts['dirname'] === '/') ? '' : $parts['dirname'];
367
  $result['filename'] = $parts['filename'];
368
+ $result['extension'] = strtolower($parts['extension']);
369
  $result['basename'] = $parts['basename'];
370
  // todo filename
371
  return $result;
394
  }
395
  $url .= '/'.$filename;
396
  if ( !$absolute ) {
397
+ $url = str_replace(site_url(), '', $url);
398
  }
399
  // $url = TimberURLHelper::remove_double_slashes( $url);
400
  return $url;
469
  $au['basename']
470
  );
471
 
472
+ $new_url = apply_filters('timber/image/new_url', $new_url);
473
+ $new_server_path = apply_filters('timber/image/new_path', $new_server_path);
474
 
475
  // if already exists...
476
  if ( file_exists($new_server_path) ) {
484
  }
485
  // otherwise generate result file
486
  if ( $op->run($old_server_path, $new_server_path) ) {
487
+ if ( get_class($op) === 'Timber\Image\Operation\Resize' && $external ) {
488
  $new_url = strtolower($new_url);
489
  }
490
  return $new_url;
497
 
498
  // -- the below methods are just used for unit testing the URL generation code
499
  //
500
+ public static function get_letterbox_file_url( $url, $w, $h, $color ) {
501
  $au = self::analyze_url($url);
502
  $op = new Image\Operation\Letterbox($w, $h, $color);
503
  $new_url = self::_get_file_url(
508
  );
509
  return $new_url;
510
  }
511
+
512
  public static function get_letterbox_file_path( $url, $w, $h, $color ) {
513
  $au = self::analyze_url($url);
514
  $op = new Image\Operation\Letterbox($w, $h, $color);
519
  );
520
  return $new_path;
521
  }
522
+
523
+ public static function get_resize_file_url( $url, $w, $h, $crop ) {
524
  $au = self::analyze_url($url);
525
  $op = new Image\Operation\Resize($w, $h, $crop);
526
  $new_url = self::_get_file_url(
531
  );
532
  return $new_url;
533
  }
534
+
535
+ public static function get_resize_file_path( $url, $w, $h, $crop ) {
536
  $au = self::analyze_url($url);
537
  $op = new Image\Operation\Resize($w, $h, $crop);
538
  $new_path = self::_get_file_path(
542
  );
543
  return $new_path;
544
  }
545
+ }
lib/Integrations.php CHANGED
@@ -11,7 +11,6 @@ use Timber\Integrations\ACF;
11
  class Integrations {
12
 
13
  public static function init() {
14
-
15
  add_action( 'init', array( __CLASS__, 'maybe_init_acftimber' ) );
16
 
17
  if ( class_exists( 'WP_CLI_Command' ) ) {
@@ -20,10 +19,8 @@ class Integrations {
20
  }
21
 
22
  public static function maybe_init_acftimber() {
23
-
24
  if ( class_exists( 'ACF' ) ) {
25
  new ACF();
26
  }
27
-
28
  }
29
  }
11
  class Integrations {
12
 
13
  public static function init() {
 
14
  add_action( 'init', array( __CLASS__, 'maybe_init_acftimber' ) );
15
 
16
  if ( class_exists( 'WP_CLI_Command' ) ) {
19
  }
20
 
21
  public static function maybe_init_acftimber() {
 
22
  if ( class_exists( 'ACF' ) ) {
23
  new ACF();
24
  }
 
25
  }
26
  }
lib/Integrations/ACF.php CHANGED
@@ -4,7 +4,7 @@ namespace Timber\Integrations;
4
 
5
  class ACF {
6
 
7
- function __construct() {
8
  add_filter('timber_post_get_meta', array($this, 'post_get_meta'), 10, 2);
9
  add_filter('timber_post_get_meta_field', array($this, 'post_get_meta_field'), 10, 3);
10
  add_filter('timber_term_get_meta', array($this, 'term_get_meta'), 10, 3);
@@ -13,26 +13,26 @@ class ACF {
13
  add_filter('timber_term_set_meta', array($this, 'term_set_meta'), 10, 4);
14
  }
15
 
16
- function post_get_meta( $customs, $post_id ) {
17
  return $customs;
18
  }
19
 
20
- function post_get_meta_field( $value, $post_id, $field_name ) {
21
  return get_field($field_name, $post_id);
22
  }
23
 
24
- function term_get_meta_field( $value, $term_id, $field_name, $term ) {
25
  $searcher = $term->taxonomy."_".$term->ID;
26
  return get_field($field_name, $searcher);
27
  }
28
 
29
- function term_set_meta( $value, $field, $term_id, $term ) {
30
  $searcher = $term->taxonomy."_".$term->ID;
31
  update_field($field, $value, $searcher);
32
  return $value;
33
  }
34
 
35
- function term_get_meta( $fields, $term_id, $term ) {
36
  $searcher = $term->taxonomy."_".$term->ID; // save to a specific category
37
  $fds = get_fields($searcher);
38
  if ( is_array($fds) ) {
@@ -48,13 +48,11 @@ class ACF {
48
  return $fields;
49
  }
50
 
51
- function user_get_meta( $fields, $user_id ) {
52
  return $fields;
53
  }
54
 
55
- function user_get_meta_field( $value, $uid, $field ) {
56
  return get_field($field, 'user_'.$uid);
57
  }
58
- }
59
-
60
-
4
 
5
  class ACF {
6
 
7
+ public function __construct() {
8
  add_filter('timber_post_get_meta', array($this, 'post_get_meta'), 10, 2);
9
  add_filter('timber_post_get_meta_field', array($this, 'post_get_meta_field'), 10, 3);
10
  add_filter('timber_term_get_meta', array($this, 'term_get_meta'), 10, 3);
13
  add_filter('timber_term_set_meta', array($this, 'term_set_meta'), 10, 4);
14
  }
15
 
16
+ public function post_get_meta( $customs, $post_id ) {
17
  return $customs;
18
  }
19
 
20
+ public function post_get_meta_field( $value, $post_id, $field_name ) {
21
  return get_field($field_name, $post_id);
22
  }
23
 
24
+ public function term_get_meta_field( $value, $term_id, $field_name, $term ) {
25
  $searcher = $term->taxonomy."_".$term->ID;
26
  return get_field($field_name, $searcher);
27
  }
28
 
29
+ public function term_set_meta( $value, $field, $term_id, $term ) {
30
  $searcher = $term->taxonomy."_".$term->ID;
31
  update_field($field, $value, $searcher);
32
  return $value;
33
  }
34
 
35
+ public function term_get_meta( $fields, $term_id, $term ) {
36
  $searcher = $term->taxonomy."_".$term->ID; // save to a specific category
37
  $fds = get_fields($searcher);
38
  if ( is_array($fds) ) {
48
  return $fields;
49
  }
50
 
51
+ public function user_get_meta( $fields, $user_id ) {
52
  return $fields;
53
  }
54
 
55
+ public function user_get_meta_field( $value, $uid, $field ) {
56
  return get_field($field, 'user_'.$uid);
57
  }
58
+ }
 
 
lib/Integrations/Command.php CHANGED
@@ -27,12 +27,12 @@ class Command {
27
  }
28
  }
29
 
30
- static function clear_cache_timber() {
31
  $loader = new Loader();
32
  return $loader->clear_cache_timber();
33
  }
34
 
35
- static function clear_cache_twig() {
36
  $loader = new Loader();
37
  return $loader->clear_cache_twig();
38
  }
27
  }
28
  }
29
 
30
+ public static function clear_cache_timber() {
31
  $loader = new Loader();
32
  return $loader->clear_cache_timber();
33
  }
34
 
35
+ public static function clear_cache_twig() {
36
  $loader = new Loader();
37
  return $loader->clear_cache_twig();
38
  }
lib/Integrations/Timber_WP_CLI_Command.php CHANGED
@@ -30,7 +30,7 @@ class Timber_WP_CLI_Command extends \WP_CLI_Command {
30
  * wp timber clear_cache_twig
31
  *
32
  */
33
- function clear_cache_twig() {
34
  $clear = Command::clear_cache_twig();
35
  if ( $clear ) {
36
  WP_CLI::success('Cleared contents of twig cache');
@@ -47,7 +47,7 @@ class Timber_WP_CLI_Command extends \WP_CLI_Command {
47
  * wp timber clear_cache_timber
48
  *
49
  */
50
- function clear_cache_timber() {
51
  $clear = Command::clear_cache_timber();
52
  $message = 'Failed to clear timber cache';
53
  if ( $clear ) {
@@ -58,5 +58,4 @@ class Timber_WP_CLI_Command extends \WP_CLI_Command {
58
  }
59
  return $message;
60
  }
61
-
62
- }
30
  * wp timber clear_cache_twig
31
  *
32
  */
33
+ public function clear_cache_twig() {
34
  $clear = Command::clear_cache_twig();
35
  if ( $clear ) {
36
  WP_CLI::success('Cleared contents of twig cache');
47
  * wp timber clear_cache_timber
48
  *
49
  */
50
+ public function clear_cache_timber() {
51
  $clear = Command::clear_cache_timber();
52
  $message = 'Failed to clear timber cache';
53
  if ( $clear ) {
58
  }
59
  return $message;
60
  }
61
+ }
 
lib/Loader.php CHANGED
@@ -28,7 +28,7 @@ class Loader {
28
  /**
29
  * @param bool|string $caller the calling directory or false
30
  */
31
- function __construct( $caller = false ) {
32
  $this->locations = $this->get_locations($caller);
33
  $this->cache_mode = apply_filters('timber_cache_mode', $this->cache_mode);
34
  $this->cache_mode = apply_filters('timber/cache/mode', $this->cache_mode);
@@ -41,7 +41,7 @@ class Loader {
41
  * @param string $cache_mode
42
  * @return bool|string
43
  */
44
- function render( $file, $data = null, $expires = false, $cache_mode = self::CACHE_USE_DEFAULT ) {
45
  // Different $expires if user is anonymous or logged in
46
  if ( is_array($expires) ) {
47
  if ( is_user_logged_in() && isset($expires[1]) ) {
@@ -112,7 +112,7 @@ class Loader {
112
  /**
113
  * @return array
114
  */
115
- function get_locations_theme() {
116
  $theme_locs = array();
117
  $child_loc = get_stylesheet_directory();
118
  $parent_loc = get_template_directory();
@@ -150,7 +150,7 @@ class Loader {
150
  *
151
  * @return array
152
  */
153
- function get_locations_user() {
154
  $locs = array();
155
  if ( isset(Timber::$locations) ) {
156
  if ( is_string(Timber::$locations) ) {
@@ -170,7 +170,7 @@ class Loader {
170
  * @param bool|string $caller the calling directory
171
  * @return array
172
  */
173
- function get_locations_caller( $caller = false ) {
174
  $locs = array();
175
  if ( $caller && is_string($caller) ) {
176
  $caller = trailingslashit($caller);
@@ -191,7 +191,7 @@ class Loader {
191
  * @param bool|string $caller the calling directory (or false)
192
  * @return array
193
  */
194
- function get_locations( $caller = false ) {
195
  //prioirty: user locations, caller (but not theme), child theme, parent theme, caller
196
  $locs = array();
197
  $locs = array_merge($locs, $this->get_locations_user());
@@ -209,7 +209,7 @@ class Loader {
209
  /**
210
  * @return \Twig_Loader_Filesystem
211
  */
212
- function get_loader() {
213
  $paths = array();
214
  foreach ( $this->locations as $loc ) {
215
  $loc = realpath($loc);
@@ -233,7 +233,7 @@ class Loader {
233
  /**
234
  * @return Twig_Environment
235
  */
236
- function get_twig() {
237
  $loader = $this->get_loader();
238
  $params = array('debug' => WP_DEBUG, 'autoescape' => false);
239
  if ( isset(Timber::$autoescape) ) {
28
  /**
29
  * @param bool|string $caller the calling directory or false
30
  */
31
+ public function __construct( $caller = false ) {
32
  $this->locations = $this->get_locations($caller);
33
  $this->cache_mode = apply_filters('timber_cache_mode', $this->cache_mode);
34
  $this->cache_mode = apply_filters('timber/cache/mode', $this->cache_mode);
41
  * @param string $cache_mode
42
  * @return bool|string
43
  */
44
+ public function render( $file, $data = null, $expires = false, $cache_mode = self::CACHE_USE_DEFAULT ) {
45
  // Different $expires if user is anonymous or logged in
46
  if ( is_array($expires) ) {
47
  if ( is_user_logged_in() && isset($expires[1]) ) {
112
  /**
113
  * @return array
114
  */
115
+ public function get_locations_theme() {
116
  $theme_locs = array();
117
  $child_loc = get_stylesheet_directory();
118
  $parent_loc = get_template_directory();
150
  *
151
  * @return array
152
  */
153
+ public function get_locations_user() {
154
  $locs = array();
155
  if ( isset(Timber::$locations) ) {
156
  if ( is_string(Timber::$locations) ) {
170
  * @param bool|string $caller the calling directory
171
  * @return array
172
  */
173
+ public function get_locations_caller( $caller = false ) {
174
  $locs = array();
175
  if ( $caller && is_string($caller) ) {
176
  $caller = trailingslashit($caller);
191
  * @param bool|string $caller the calling directory (or false)
192
  * @return array
193
  */
194
+ public function get_locations( $caller = false ) {
195
  //prioirty: user locations, caller (but not theme), child theme, parent theme, caller
196
  $locs = array();
197
  $locs = array_merge($locs, $this->get_locations_user());
209
  /**
210
  * @return \Twig_Loader_Filesystem
211
  */
212
+ public function get_loader() {
213
  $paths = array();
214
  foreach ( $this->locations as $loc ) {
215
  $loc = realpath($loc);
233
  /**
234
  * @return Twig_Environment
235
  */
236
+ public function get_twig() {
237
  $loader = $this->get_loader();
238
  $params = array('debug' => WP_DEBUG, 'autoescape' => false);
239
  if ( isset(Timber::$autoescape) ) {
lib/Menu.php CHANGED
@@ -78,9 +78,9 @@ class Menu extends Core {
78
  public $title;
79
 
80
  /**
81
- * @param int|string $slug
82
  */
83
- function __construct( $slug = 0 ) {
84
  $locations = get_nav_menu_locations();
85
  if ( $slug != 0 && is_numeric($slug) ) {
86
  $menu_id = $slug;
@@ -185,7 +185,7 @@ class Menu extends Core {
185
  * @param int $parent_id
186
  * @return TimberMenuItem|null
187
  */
188
- function find_parent_item_in_menu( $menu_items, $parent_id ) {
189
  foreach ( $menu_items as &$item ) {
190
  if ( $item->ID == $parent_id ) {
191
  return $item;
@@ -232,12 +232,10 @@ class Menu extends Core {
232
  /**
233
  * @return array
234
  */
235
- function get_items() {
236
  if ( is_array($this->items) ) {
237
  return $this->items;
238
  }
239
  return array();
240
  }
241
- }
242
-
243
-
78
  public $title;
79
 
80
  /**
81
+ * @param integer|string $slug
82
  */
83
+ public function __construct( $slug = 0 ) {
84
  $locations = get_nav_menu_locations();
85
  if ( $slug != 0 && is_numeric($slug) ) {
86
  $menu_id = $slug;
185
  * @param int $parent_id
186
  * @return TimberMenuItem|null
187
  */
188
+ public function find_parent_item_in_menu( $menu_items, $parent_id ) {
189
  foreach ( $menu_items as &$item ) {
190
  if ( $item->ID == $parent_id ) {
191
  return $item;
232
  /**
233
  * @return array
234
  */
235
+ public function get_items() {
236
  if ( is_array($this->items) ) {
237
  return $this->items;
238
  }
239
  return array();
240
  }
241
+ }
 
 
lib/MenuItem.php CHANGED
@@ -15,10 +15,9 @@ class MenuItem extends Core implements CoreInterface {
15
  public $class = '';
16
  public $level = 0;
17
  public $post_name;
18
- public $type;
19
  public $url;
20
 
21
- public $PostClass = 'TimberPost';
22
 
23
  protected $_name;
24
  protected $_menu_item_object_id;
@@ -114,7 +113,7 @@ class MenuItem extends Core implements CoreInterface {
114
  * @deprecated 1.0
115
  * @return string an absolute URL http://example.org/my-page
116
  */
117
- function get_link() {
118
  return $this->link();
119
  }
120
 
@@ -124,7 +123,7 @@ class MenuItem extends Core implements CoreInterface {
124
  * @deprecated 1.0
125
  * @return string a relative url /my-page
126
  */
127
- function get_path() {
128
  return $this->path();
129
  }
130
 
@@ -133,7 +132,7 @@ class MenuItem extends Core implements CoreInterface {
133
  *
134
  * @param TimberMenuItem $item
135
  */
136
- function add_child( $item ) {
137
  if ( !$this->has_child_class ) {
138
  $this->add_class('menu-item-has-children');
139
  $this->has_child_class = true;
@@ -151,9 +150,9 @@ class MenuItem extends Core implements CoreInterface {
151
  /**
152
  *
153
  * @internal
154
- * @return bool
155
  */
156
- function update_child_levels() {
157
  if ( is_array($this->children) ) {
158
  foreach ( $this->children as $child ) {
159
  $child->level = $this->level + 1;
@@ -168,7 +167,7 @@ class MenuItem extends Core implements CoreInterface {
168
  * @internal
169
  * @param array|object $data
170
  */
171
- function import_classes( $data ) {
172
  if ( is_array($data) ) {
173
  $data = (object) $data;
174
  }
@@ -183,7 +182,7 @@ class MenuItem extends Core implements CoreInterface {
183
  * @internal
184
  * @return array|bool
185
  */
186
- function get_children() {
187
  if ( isset($this->children) ) {
188
  return $this->children;
189
  }
@@ -199,13 +198,22 @@ class MenuItem extends Core implements CoreInterface {
199
  * ```
200
  * @return bool
201
  */
202
- function is_external() {
203
- if ( $this->type != 'custom' ) {
204
  return false;
205
  }
206
  return URLHelper::is_external($this->url);
207
  }
208
 
 
 
 
 
 
 
 
 
 
209
  /**
210
  * @param string $key lookup key
211
  * @return mixed whatever value is storied in the database
@@ -303,4 +311,4 @@ class MenuItem extends Core implements CoreInterface {
303
  return $this->__title;
304
  }
305
  }
306
- }
15
  public $class = '';
16
  public $level = 0;
17
  public $post_name;
 
18
  public $url;
19
 
20
+ public $PostClass = 'Timber\Post';
21
 
22
  protected $_name;
23
  protected $_menu_item_object_id;
113
  * @deprecated 1.0
114
  * @return string an absolute URL http://example.org/my-page
115
  */
116
+ public function get_link() {
117
  return $this->link();
118
  }
119
 
123
  * @deprecated 1.0
124
  * @return string a relative url /my-page
125
  */
126
+ public function get_path() {
127
  return $this->path();
128
  }
129
 
132
  *
133
  * @param TimberMenuItem $item
134
  */
135
+ public function add_child( $item ) {
136
  if ( !$this->has_child_class ) {
137
  $this->add_class('menu-item-has-children');
138
  $this->has_child_class = true;
150
  /**
151
  *
152
  * @internal
153
+ * @return boolean|null
154
  */
155
+ public function update_child_levels() {
156
  if ( is_array($this->children) ) {
157
  foreach ( $this->children as $child ) {
158
  $child->level = $this->level + 1;
167
  * @internal
168
  * @param array|object $data
169
  */
170
+ public function import_classes( $data ) {
171
  if ( is_array($data) ) {
172
  $data = (object) $data;
173
  }
182
  * @internal
183
  * @return array|bool
184
  */
185
+ public function get_children() {
186
  if ( isset($this->children) ) {
187
  return $this->children;
188
  }
198
  * ```
199
  * @return bool
200
  */
201
+ public function is_external() {
202
+ if ( $this->type() != 'custom' ) {
203
  return false;
204
  }
205
  return URLHelper::is_external($this->url);
206
  }
207
 
208
+ /**
209
+ * Return the type of the menu item
210
+ * @since 1.0.4
211
+ * @return string
212
+ */
213
+ public function type() {
214
+ return $this->_menu_item_type;
215
+ }
216
+
217
  /**
218
  * @param string $key lookup key
219
  * @return mixed whatever value is storied in the database
311
  return $this->__title;
312
  }
313
  }
314
+ }
lib/Post.php CHANGED
@@ -11,6 +11,9 @@ use Timber\Image;
11
  use Timber\Helper;
12
  use Timber\URLHelper;
13
  use Timber\PostGetter;
 
 
 
14
 
15
  /**
16
  * This is the object you use to access or extend WordPress posts. Think of it as Timber's (more accessible) version of WP_Post. This is used throughout Timber to represent posts retrieved from WordPress making them available to Twig templates. See the PHP and Twig examples for an example of what it's like to work with this object in your code.
@@ -125,7 +128,7 @@ class Post extends Core implements CoreInterface {
125
  public $post_date;
126
 
127
  /**
128
- * @var string $post_exceprt the raw text of a manual post exceprt as stored in the database
129
  */
130
  public $post_excerpt;
131
 
@@ -157,6 +160,11 @@ class Post extends Core implements CoreInterface {
157
  */
158
  public $slug;
159
 
 
 
 
 
 
160
  /**
161
  * If you send the constructor nothing it will try to figure out the current post id based on being inside The_Loop
162
  * @example
@@ -248,8 +256,8 @@ class Post extends Core implements CoreInterface {
248
  $revisions = wp_get_post_revisions($query->queried_object_id);
249
 
250
  if ( !empty($revisions) ) {
251
- $last = end($revisions);
252
- return $last->ID;
253
  }
254
 
255
  return false;
@@ -258,7 +266,7 @@ class Post extends Core implements CoreInterface {
258
  /**
259
  * Initializes a Post
260
  * @internal
261
- * @param int|bool $pid
262
  */
263
  protected function init( $pid = false ) {
264
  if ( $pid === false ) {
@@ -282,7 +290,7 @@ class Post extends Core implements CoreInterface {
282
  * @see Timber\Post::edit_link
283
  * @return bool|string
284
  */
285
- function get_edit_url() {
286
  return $this->edit_link();
287
  }
288
 
@@ -303,7 +311,7 @@ class Post extends Core implements CoreInterface {
303
  * takes a mix of integer (post ID), string (post slug),
304
  * or object to return a WordPress post object from WP's built-in get_post() function
305
  * @internal
306
- * @param mixed $pid
307
  * @return WP_Post on success
308
  */
309
  protected function prepare_post_info( $pid = 0 ) {
@@ -347,7 +355,7 @@ class Post extends Core implements CoreInterface {
347
  * @param string $post_name
348
  * @return int
349
  */
350
- static function get_post_id_by_name( $post_name ) {
351
  global $wpdb;
352
  $query = $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_name = %s LIMIT 1", $post_name);
353
  $result = $wpdb->get_row($query);
@@ -357,6 +365,13 @@ class Post extends Core implements CoreInterface {
357
  return $result->ID;
358
  }
359
 
 
 
 
 
 
 
 
360
  /**
361
  * get a preview of your post, if you have an excerpt it will use that,
362
  * otherwise it will pull from the post_content.
@@ -373,9 +388,10 @@ class Post extends Core implements CoreInterface {
373
  * @param string $end The text to end the preview with (defaults to ...)
374
  * @return string of the post preview
375
  */
376
- function get_preview( $len = 50, $force = false, $readmore = 'Read More', $strip = true, $end = '&hellip;' ) {
377
  $text = '';
378
  $trimmed = false;
 
379
  if ( isset($this->post_excerpt) && strlen($this->post_excerpt) ) {
380
  if ( $force ) {
381
  $text = Helper::trim_words($this->post_excerpt, $len, false);
@@ -437,7 +453,7 @@ class Post extends Core implements CoreInterface {
437
  * @internal
438
  * @param bool|int $pid a post ID number
439
  */
440
- function import_custom( $pid = false ) {
441
  if ( !$pid ) {
442
  $pid = $this->ID;
443
  }
@@ -524,7 +540,7 @@ class Post extends Core implements CoreInterface {
524
  * @return array
525
  */
526
  public function terms( $tax = '', $merge = true, $TermClass = '' ) {
527
-
528
  $TermClass = $TermClass ?: $this->TermClass;
529
 
530
  if ( is_string($merge) && class_exists($merge) ) {
@@ -581,7 +597,7 @@ class Post extends Core implements CoreInterface {
581
  * @param string $taxonomy
582
  * @return bool
583
  */
584
- function has_term( $term_name_or_id, $taxonomy = 'all' ) {
585
  if ( $taxonomy == 'all' || $taxonomy == 'any' ) {
586
  $taxes = get_object_taxonomies($this->post_type, 'names');
587
  $ret = false;
@@ -599,13 +615,17 @@ class Post extends Core implements CoreInterface {
599
  /**
600
  * @return string
601
  */
602
- function get_paged_content() {
603
  return $this->paged_content();
604
  }
 
 
605
  /**
606
- *
607
- * Here is my summary
 
608
  * @example
 
609
  * ```twig
610
  * This post is from <span>{{ post.get_post_type.labels.plural }}</span>
611
  * ```
@@ -613,12 +633,13 @@ class Post extends Core implements CoreInterface {
613
  * ```html
614
  * This post is from <span>Recipes</span>
615
  * ```
616
- * @return mixed
617
  */
618
  public function get_post_type() {
619
- return get_post_type_object($this->post_type);
620
  }
621
 
 
622
  /**
623
  * @return int the number of comments on a post
624
  */
@@ -626,6 +647,16 @@ class Post extends Core implements CoreInterface {
626
  return get_comments_number($this->ID);
627
  }
628
 
 
 
 
 
 
 
 
 
 
 
629
  /**
630
  * @param string $field_name
631
  * @return mixed
@@ -649,7 +680,7 @@ class Post extends Core implements CoreInterface {
649
  /**
650
  * @param string $field_name
651
  */
652
- function import_field( $field_name ) {
653
  $this->$field_name = $this->get_field($field_name);
654
  }
655
 
@@ -723,7 +754,7 @@ class Post extends Core implements CoreInterface {
723
  * <a href="{{post.author.link}}">{{post.author.name}}</a>
724
  * </p>
725
  * ```
726
- * @return TimberUser|bool A TimberUser object if found, false if not
727
  */
728
  public function author() {
729
  return $this->get_author();
@@ -738,7 +769,7 @@ class Post extends Core implements CoreInterface {
738
  * ```html
739
  * Last updated by Harper Lee
740
  * ```
741
- * @return TimberUser|bool A TimberUser object if found, false if not
742
  */
743
  public function modified_author() {
744
  $user_id = get_post_meta($this->ID, '_edit_last', true);
@@ -817,7 +848,7 @@ class Post extends Core implements CoreInterface {
817
  * ```
818
  * @return bool|array
819
  */
820
- public function comments( $count = 0, $order = 'wp', $type = 'comment', $status = 'approve', $CommentClass = 'TimberComment' ) {
821
  global $overridden_cpage, $user_ID;
822
  $overridden_cpage = false;
823
 
@@ -869,7 +900,7 @@ class Post extends Core implements CoreInterface {
869
  // Add child comments to the relative "super parents"
870
  foreach ( $comments_tree as $comment_parent => $comment_children ) {
871
  foreach ( $comment_children as $comment_child ) {
872
- $timber_comments[$comment_parent]->children[] = $timber_comments[$comment_child];
873
  unset($timber_comments[$comment_child]);
874
  }
875
  }
@@ -970,6 +1001,29 @@ class Post extends Core implements CoreInterface {
970
  return apply_filters('get_the_time', $the_time, $tf);
971
  }
972
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
973
  /**
974
  * Returns the edit URL of a post if the user has access to it
975
  * @return bool|string the edit URL of a post in the WordPress admin
@@ -1044,7 +1098,7 @@ class Post extends Core implements CoreInterface {
1044
 
1045
  /**
1046
  * @api
1047
- * @param bool $in_same_cat
1048
  * @return mixed
1049
  */
1050
  public function next( $in_same_term = false ) {
@@ -1101,10 +1155,10 @@ class Post extends Core implements CoreInterface {
1101
  }
1102
 
1103
 
1104
-
1105
  /**
1106
  * Finds any WP_Post objects and converts them to Timber\Posts
1107
  * @param array $data
 
1108
  */
1109
  public function convert( $data, $class ) {
1110
  if ( is_array($data) ) {
@@ -1123,6 +1177,7 @@ class Post extends Core implements CoreInterface {
1123
  return $data;
1124
  }
1125
 
 
1126
  /**
1127
  * Gets the parent (if one exists) from a post as a Timber\Post object (or whatever is set in Timber\Post::$PostClass)
1128
  * @api
@@ -1131,7 +1186,6 @@ class Post extends Core implements CoreInterface {
1131
  * Parent page: <a href="{{ post.parent.link }}">{{ post.parent.title }}</a>
1132
  * ```
1133
  * @return bool|Timber\Post
1134
- * @param string $field_name
1135
  */
1136
  public function parent() {
1137
  if ( !$this->post_parent ) {
@@ -1140,6 +1194,7 @@ class Post extends Core implements CoreInterface {
1140
  return new $this->PostClass($this->post_parent);
1141
  }
1142
 
 
1143
  /**
1144
  * Gets the relative path of a WP Post, so while link() will return http://example.org/2015/07/my-cool-post
1145
  * this will return just /2015/07/my-cool-post
@@ -1154,6 +1209,7 @@ class Post extends Core implements CoreInterface {
1154
  return URLHelper::get_rel_url($this->get_link());
1155
  }
1156
 
 
1157
  /**
1158
  * Get the previous post in a set
1159
  * @api
@@ -1212,6 +1268,7 @@ class Post extends Core implements CoreInterface {
1212
  }
1213
  }
1214
 
 
1215
  /**
1216
  * Returns the processed title to be used in templates. This returns the title of the post after WP's filters have run. This is analogous to `the_title()` in standard WP template tags.
1217
  * @api
@@ -1225,6 +1282,7 @@ class Post extends Core implements CoreInterface {
1225
  return apply_filters('the_title', $this->post_title, $this->ID);
1226
  }
1227
 
 
1228
  /**
1229
  *
1230
  * ===================================
@@ -1241,7 +1299,7 @@ class Post extends Core implements CoreInterface {
1241
  * @see Timber\Post::categories
1242
  * @return array of TimberTerms
1243
  */
1244
- function get_categories() {
1245
  return $this->get_terms('category');
1246
  }
1247
 
@@ -1252,7 +1310,7 @@ class Post extends Core implements CoreInterface {
1252
  * @see Timber\Post::category
1253
  * @return mixed
1254
  */
1255
- function get_category( ) {
1256
  $cats = $this->get_categories();
1257
  if ( count($cats) && isset($cats[0]) ) {
1258
  return $cats[0];
@@ -1263,7 +1321,7 @@ class Post extends Core implements CoreInterface {
1263
  * @param string $field
1264
  * @return TimberImage
1265
  */
1266
- function get_image( $field ) {
1267
  return new $this->ImageClass($this->$field);
1268
  }
1269
 
@@ -1282,7 +1340,7 @@ class Post extends Core implements CoreInterface {
1282
  * ```
1283
  * @return array
1284
  */
1285
- function get_tags() {
1286
  return $this->get_terms('post_tag');
1287
  }
1288
 
@@ -1300,7 +1358,7 @@ class Post extends Core implements CoreInterface {
1300
  * ```
1301
  * @return string
1302
  */
1303
- function get_title() {
1304
  return $this->title();
1305
  }
1306
 
@@ -1317,7 +1375,7 @@ class Post extends Core implements CoreInterface {
1317
  * @param int $page
1318
  * @return string
1319
  */
1320
- function get_content( $len = -1, $page = 0 ) {
1321
  if ( $len === 0 ) {
1322
  $len = -1;
1323
  }
@@ -1329,7 +1387,7 @@ class Post extends Core implements CoreInterface {
1329
  * @deprecated since 1.0
1330
  * @return mixed
1331
  */
1332
- function get_format() {
1333
  return $this->format();
1334
  }
1335
 
@@ -1365,7 +1423,7 @@ class Post extends Core implements CoreInterface {
1365
  * @param string $date_format
1366
  * @return string
1367
  */
1368
- function get_date( $date_format = '' ) {
1369
  return $this->date($date_format);
1370
  }
1371
 
@@ -1377,7 +1435,7 @@ class Post extends Core implements CoreInterface {
1377
  * @param string $date_format
1378
  * @return string
1379
  */
1380
- function get_modified_date( $date_format = '' ) {
1381
  return $this->modified_date($date_format);
1382
  }
1383
 
@@ -1386,7 +1444,7 @@ class Post extends Core implements CoreInterface {
1386
  * @param string $time_format
1387
  * @return string
1388
  */
1389
- function get_modified_time( $time_format = '' ) {
1390
  $tf = $time_format ? $time_format : get_option('time_format');
1391
  $the_time = get_post_modified_time($tf, false, $this->ID, true);
1392
  return apply_filters('get_the_modified_time', $the_time, $time_format);
@@ -1401,7 +1459,7 @@ class Post extends Core implements CoreInterface {
1401
  * @param bool|string $childPostClass
1402
  * @return array
1403
  */
1404
- function get_children( $post_type = 'any', $childPostClass = false ) {
1405
  return $this->children($post_type, $childPostClass);
1406
  }
1407
 
@@ -1414,7 +1472,7 @@ class Post extends Core implements CoreInterface {
1414
  * @codeCoverageIgnore
1415
  * @return string
1416
  */
1417
- function get_path() {
1418
  return $this->path();
1419
  }
1420
 
@@ -1423,10 +1481,9 @@ class Post extends Core implements CoreInterface {
1423
  * @internal
1424
  * @deprecated since 1.0
1425
  * @codeCoverageIgnore
1426
- * @param bool $taxonomy
1427
  * @return TimberPost|boolean
1428
  */
1429
- function get_prev( $in_same_term = false ) {
1430
  return $this->prev($in_same_term);
1431
  }
1432
 
@@ -1437,7 +1494,7 @@ class Post extends Core implements CoreInterface {
1437
  * @codeCoverageIgnore
1438
  * @return bool|TimberPost
1439
  */
1440
- function get_parent() {
1441
  return $this->parent();
1442
  }
1443
 
@@ -1446,10 +1503,10 @@ class Post extends Core implements CoreInterface {
1446
  * @internal
1447
  * @deprecated since 1.0
1448
  * @codeCoverageIgnore
1449
- * @see TimberPost::author
1450
- * @return bool|TimberUser
1451
  */
1452
- function get_author() {
1453
  if ( isset($this->post_author) ) {
1454
  return new User($this->post_author);
1455
  }
@@ -1459,20 +1516,20 @@ class Post extends Core implements CoreInterface {
1459
  * @internal
1460
  * @deprecated since 1.0
1461
  * @codeCoverageIgnore
1462
- * @return bool|TimberUser
1463
  */
1464
- function get_modified_author() {
1465
  return $this->modified_author();
1466
  }
1467
 
1468
- /**
1469
- * @internal
1470
- * @see TimberPost::thumbnail
1471
- * @deprecated since 1.0
1472
- * @codeCoverageIgnore
1473
- * @return null|TimberImage
1474
- */
1475
- function get_thumbnail() {
1476
  return $this->thumbnail();
1477
  }
1478
 
@@ -1483,7 +1540,7 @@ class Post extends Core implements CoreInterface {
1483
  * @codeCoverageIgnore
1484
  * @return string
1485
  */
1486
- function get_permalink() {
1487
  return $this->link();
1488
  }
1489
 
@@ -1496,7 +1553,7 @@ class Post extends Core implements CoreInterface {
1496
  * @codeCoverageIgnore
1497
  * @return string
1498
  */
1499
- function get_link() {
1500
  return $this->get_permalink();
1501
  }
1502
 
@@ -1508,7 +1565,7 @@ class Post extends Core implements CoreInterface {
1508
  * @param bool $taxonomy
1509
  * @return TimberPost|boolean
1510
  */
1511
- function get_next( $taxonomy = false ) {
1512
  return $this->next($taxonomy);
1513
  }
1514
 
@@ -1536,7 +1593,7 @@ class Post extends Core implements CoreInterface {
1536
  * @param string $CommentClass
1537
  * @return array|mixed
1538
  */
1539
- function get_comments( $count = 0, $order = 'wp', $type = 'comment', $status = 'approve', $CommentClass = 'TimberComment' ) {
1540
  return $this->comments($count, $order, $type, $status, $CommentClass);
1541
  }
1542
 
11
  use Timber\Helper;
12
  use Timber\URLHelper;
13
  use Timber\PostGetter;
14
+ use Timber\PostType;
15
+
16
+ use WP_Post;
17
 
18
  /**
19
  * This is the object you use to access or extend WordPress posts. Think of it as Timber's (more accessible) version of WP_Post. This is used throughout Timber to represent posts retrieved from WordPress making them available to Twig templates. See the PHP and Twig examples for an example of what it's like to work with this object in your code.
128
  public $post_date;
129
 
130
  /**
131
+ * @var string $post_excerpt the raw text of a manual post excerpt as stored in the database
132
  */
133
  public $post_excerpt;
134
 
160
  */
161
  public $slug;
162
 
163
+ /**
164
+ * @var PostType $_type stores the PostType object for the Post
165
+ */
166
+ private $_type;
167
+
168
  /**
169
  * If you send the constructor nothing it will try to figure out the current post id based on being inside The_Loop
170
  * @example
256
  $revisions = wp_get_post_revisions($query->queried_object_id);
257
 
258
  if ( !empty($revisions) ) {
259
+ $revision = reset($revisions);
260
+ return $revision->ID;
261
  }
262
 
263
  return false;
266
  /**
267
  * Initializes a Post
268
  * @internal
269
+ * @param integer $pid
270
  */
271
  protected function init( $pid = false ) {
272
  if ( $pid === false ) {
290
  * @see Timber\Post::edit_link
291
  * @return bool|string
292
  */
293
+ public function get_edit_url() {
294
  return $this->edit_link();
295
  }
296
 
311
  * takes a mix of integer (post ID), string (post slug),
312
  * or object to return a WordPress post object from WP's built-in get_post() function
313
  * @internal
314
+ * @param integer $pid
315
  * @return WP_Post on success
316
  */
317
  protected function prepare_post_info( $pid = 0 ) {
355
  * @param string $post_name
356
  * @return int
357
  */
358
+ public static function get_post_id_by_name( $post_name ) {
359
  global $wpdb;
360
  $query = $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_name = %s LIMIT 1", $post_name);
361
  $result = $wpdb->get_row($query);
365
  return $result->ID;
366
  }
367
 
368
+ /**
369
+ * @return PostPreview
370
+ */
371
+ public function preview() {
372
+ return new PostPreview( $this );
373
+ }
374
+
375
  /**
376
  * get a preview of your post, if you have an excerpt it will use that,
377
  * otherwise it will pull from the post_content.
388
  * @param string $end The text to end the preview with (defaults to ...)
389
  * @return string of the post preview
390
  */
391
+ public function get_preview( $len = 50, $force = false, $readmore = 'Read More', $strip = true, $end = '&hellip;' ) {
392
  $text = '';
393
  $trimmed = false;
394
+ $last_p_tag = null;
395
  if ( isset($this->post_excerpt) && strlen($this->post_excerpt) ) {
396
  if ( $force ) {
397
  $text = Helper::trim_words($this->post_excerpt, $len, false);
453
  * @internal
454
  * @param bool|int $pid a post ID number
455
  */
456
+ public function import_custom( $pid = false ) {
457
  if ( !$pid ) {
458
  $pid = $this->ID;
459
  }
540
  * @return array
541
  */
542
  public function terms( $tax = '', $merge = true, $TermClass = '' ) {
543
+ $taxonomies = array();
544
  $TermClass = $TermClass ?: $this->TermClass;
545
 
546
  if ( is_string($merge) && class_exists($merge) ) {
597
  * @param string $taxonomy
598
  * @return bool
599
  */
600
+ public function has_term( $term_name_or_id, $taxonomy = 'all' ) {
601
  if ( $taxonomy == 'all' || $taxonomy == 'any' ) {
602
  $taxes = get_object_taxonomies($this->post_type, 'names');
603
  $ret = false;
615
  /**
616
  * @return string
617
  */
618
+ public function get_paged_content() {
619
  return $this->paged_content();
620
  }
621
+
622
+
623
  /**
624
+ * Returns the post_type object with labels and other info
625
+ *
626
+ * @deprecated since 1.0.4
627
  * @example
628
+ *
629
  * ```twig
630
  * This post is from <span>{{ post.get_post_type.labels.plural }}</span>
631
  * ```
633
  * ```html
634
  * This post is from <span>Recipes</span>
635
  * ```
636
+ * @return PostType
637
  */
638
  public function get_post_type() {
639
+ return $this->type();
640
  }
641
 
642
+
643
  /**
644
  * @return int the number of comments on a post
645
  */
647
  return get_comments_number($this->ID);
648
  }
649
 
650
+
651
+ /**
652
+ * @param string $field_name
653
+ * @return boolean
654
+ */
655
+ public function has_field( $field_name ) {
656
+ return (!$this->get_field( $field_name )) ? false : true;
657
+ }
658
+
659
+
660
  /**
661
  * @param string $field_name
662
  * @return mixed
680
  /**
681
  * @param string $field_name
682
  */
683
+ public function import_field( $field_name ) {
684
  $this->$field_name = $this->get_field($field_name);
685
  }
686
 
754
  * <a href="{{post.author.link}}">{{post.author.name}}</a>
755
  * </p>
756
  * ```
757
+ * @return User|null A User object if found, false if not
758
  */
759
  public function author() {
760
  return $this->get_author();
769
  * ```html
770
  * Last updated by Harper Lee
771
  * ```
772
+ * @return User|null A User object if found, false if not
773
  */
774
  public function modified_author() {
775
  $user_id = get_post_meta($this->ID, '_edit_last', true);
848
  * ```
849
  * @return bool|array
850
  */
851
+ public function comments( $count = 0, $order = 'wp', $type = 'comment', $status = 'approve', $CommentClass = 'Timber\Comment' ) {
852
  global $overridden_cpage, $user_ID;
853
  $overridden_cpage = false;
854
 
900
  // Add child comments to the relative "super parents"
901
  foreach ( $comments_tree as $comment_parent => $comment_children ) {
902
  foreach ( $comment_children as $comment_child ) {
903
+ $timber_comments[$comment_parent]->add_child( $timber_comments[$comment_child] );
904
  unset($timber_comments[$comment_child]);
905
  }
906
  }
1001
  return apply_filters('get_the_time', $the_time, $tf);
1002
  }
1003
 
1004
+
1005
+ /**
1006
+ * Returns the post_type object with labels and other info
1007
+ *
1008
+ * @since 1.0.4
1009
+ * @example
1010
+ *
1011
+ * ```twig
1012
+ * This post is from <span>{{ post.type.labels.name }}</span>
1013
+ * ```
1014
+ *
1015
+ * ```html
1016
+ * This post is from <span>Recipes</span>
1017
+ * ```
1018
+ * @return PostType
1019
+ */
1020
+ public function type() {
1021
+ if ( !$this->_type instanceof PostType ) {
1022
+ $this->_type = new PostType($this->post_type);
1023
+ }
1024
+ return $this->_type;
1025
+ }
1026
+
1027
  /**
1028
  * Returns the edit URL of a post if the user has access to it
1029
  * @return bool|string the edit URL of a post in the WordPress admin
1098
 
1099
  /**
1100
  * @api
1101
+ * @param bool $in_same_term
1102
  * @return mixed
1103
  */
1104
  public function next( $in_same_term = false ) {
1155
  }
1156
 
1157
 
 
1158
  /**
1159
  * Finds any WP_Post objects and converts them to Timber\Posts
1160
  * @param array $data
1161
+ * @param string $class
1162
  */
1163
  public function convert( $data, $class ) {
1164
  if ( is_array($data) ) {
1177
  return $data;
1178
  }
1179
 
1180
+
1181
  /**
1182
  * Gets the parent (if one exists) from a post as a Timber\Post object (or whatever is set in Timber\Post::$PostClass)
1183
  * @api
1186
  * Parent page: <a href="{{ post.parent.link }}">{{ post.parent.title }}</a>
1187
  * ```
1188
  * @return bool|Timber\Post
 
1189
  */
1190
  public function parent() {
1191
  if ( !$this->post_parent ) {
1194
  return new $this->PostClass($this->post_parent);
1195
  }
1196
 
1197
+
1198
  /**
1199
  * Gets the relative path of a WP Post, so while link() will return http://example.org/2015/07/my-cool-post
1200
  * this will return just /2015/07/my-cool-post
1209
  return URLHelper::get_rel_url($this->get_link());
1210
  }
1211
 
1212
+
1213
  /**
1214
  * Get the previous post in a set
1215
  * @api
1268
  }
1269
  }
1270
 
1271
+
1272
  /**
1273
  * Returns the processed title to be used in templates. This returns the title of the post after WP's filters have run. This is analogous to `the_title()` in standard WP template tags.
1274
  * @api
1282
  return apply_filters('the_title', $this->post_title, $this->ID);
1283
  }
1284
 
1285
+
1286
  /**
1287
  *
1288
  * ===================================
1299
  * @see Timber\Post::categories
1300
  * @return array of TimberTerms
1301
  */
1302
+ public function get_categories() {
1303
  return $this->get_terms('category');
1304
  }
1305
 
1310
  * @see Timber\Post::category
1311
  * @return mixed
1312
  */
1313
+ public function get_category( ) {
1314
  $cats = $this->get_categories();
1315
  if ( count($cats) && isset($cats[0]) ) {
1316
  return $cats[0];
1321
  * @param string $field
1322
  * @return TimberImage
1323
  */
1324
+ public function get_image( $field ) {
1325
  return new $this->ImageClass($this->$field);
1326
  }
1327
 
1340
  * ```
1341
  * @return array
1342
  */
1343
+ public function get_tags() {
1344
  return $this->get_terms('post_tag');
1345
  }
1346
 
1358
  * ```
1359
  * @return string
1360
  */
1361
+ public function get_title() {
1362
  return $this->title();
1363
  }
1364
 
1375
  * @param int $page
1376
  * @return string
1377
  */
1378
+ public function get_content( $len = -1, $page = 0 ) {
1379
  if ( $len === 0 ) {
1380
  $len = -1;
1381
  }
1387
  * @deprecated since 1.0
1388
  * @return mixed
1389
  */
1390
+ public function get_format() {
1391
  return $this->format();
1392
  }
1393
 
1423
  * @param string $date_format
1424
  * @return string
1425
  */
1426
+ public function get_date( $date_format = '' ) {
1427
  return $this->date($date_format);
1428
  }
1429
 
1435
  * @param string $date_format
1436
  * @return string
1437
  */
1438
+ public function get_modified_date( $date_format = '' ) {
1439
  return $this->modified_date($date_format);
1440
  }
1441
 
1444
  * @param string $time_format
1445
  * @return string
1446
  */
1447
+ public function get_modified_time( $time_format = '' ) {
1448
  $tf = $time_format ? $time_format : get_option('time_format');
1449
  $the_time = get_post_modified_time($tf, false, $this->ID, true);
1450
  return apply_filters('get_the_modified_time', $the_time, $time_format);
1459
  * @param bool|string $childPostClass
1460
  * @return array
1461
  */
1462
+ public function get_children( $post_type = 'any', $childPostClass = false ) {
1463
  return $this->children($post_type, $childPostClass);
1464
  }
1465
 
1472
  * @codeCoverageIgnore
1473
  * @return string
1474
  */
1475
+ public function get_path() {
1476
  return $this->path();
1477
  }
1478
 
1481
  * @internal
1482
  * @deprecated since 1.0
1483
  * @codeCoverageIgnore
 
1484
  * @return TimberPost|boolean
1485
  */
1486
+ public function get_prev( $in_same_term = false ) {
1487
  return $this->prev($in_same_term);
1488
  }
1489
 
1494
  * @codeCoverageIgnore
1495
  * @return bool|TimberPost
1496
  */
1497
+ public function get_parent() {
1498
  return $this->parent();
1499
  }
1500
 
1503
  * @internal
1504
  * @deprecated since 1.0
1505
  * @codeCoverageIgnore
1506
+ * @see Timber\Post::author
1507
+ * @return User|null
1508
  */
1509
+ public function get_author() {
1510
  if ( isset($this->post_author) ) {
1511
  return new User($this->post_author);
1512
  }
1516
  * @internal
1517
  * @deprecated since 1.0
1518
  * @codeCoverageIgnore
1519
+ * @return User|null
1520
  */
1521
+ public function get_modified_author() {
1522
  return $this->modified_author();
1523
  }
1524
 
1525
+ /**
1526
+ * @internal
1527
+ * @see TimberPost::thumbnail
1528
+ * @deprecated since 1.0
1529
+ * @codeCoverageIgnore
1530
+ * @return Image|null
1531
+ */
1532
+ public function get_thumbnail() {
1533
  return $this->thumbnail();
1534
  }
1535
 
1540
  * @codeCoverageIgnore
1541
  * @return string
1542
  */
1543
+ public function get_permalink() {
1544
  return $this->link();
1545
  }
1546
 
1553
  * @codeCoverageIgnore
1554
  * @return string
1555
  */
1556
+ public function get_link() {
1557
  return $this->get_permalink();
1558
  }
1559
 
1565
  * @param bool $taxonomy
1566
  * @return TimberPost|boolean
1567
  */
1568
+ public function get_next( $taxonomy = false ) {
1569
  return $this->next($taxonomy);
1570
  }
1571
 
1593
  * @param string $CommentClass
1594
  * @return array|mixed
1595
  */
1596
+ public function get_comments( $count = 0, $order = 'wp', $type = 'comment', $status = 'approve', $CommentClass = 'Timber\Comment' ) {
1597
  return $this->comments($count, $order, $type, $status, $CommentClass);
1598
  }
1599
 
lib/PostGetter.php CHANGED
@@ -12,19 +12,19 @@ class PostGetter {
12
  * @param string $PostClass
13
  * @return array|bool|null
14
  */
15
- static function get_post( $query = false, $PostClass = '\Timber\Post' ) {
16
  $posts = self::get_posts($query, $PostClass);
17
  if ( $post = reset($posts) ) {
18
  return $post;
19
  }
20
  }
21
 
22
- static function get_posts( $query = false, $PostClass = '\Timber\Post', $return_collection = false ) {
23
  $posts = self::query_posts($query, $PostClass);
24
  return apply_filters('timber_post_getter_get_posts', $posts->get_posts($return_collection));
25
  }
26
 
27
- static function query_post( $query = false, $PostClass = '\Timber\Post' ) {
28
  $posts = self::query_posts($query, $PostClass);
29
  if ( method_exists($posts, 'current') && $post = $posts->current() ) {
30
  return $post;
@@ -36,7 +36,7 @@ class PostGetter {
36
  * @param string $PostClass
37
  * @return array|bool|null
38
  */
39
- static function query_posts( $query = false, $PostClass = '\Timber\Post' ) {
40
  if ( $type = self::get_class_for_use_as_timber_post($query) ) {
41
  $PostClass = $type;
42
  if ( self::is_post_class_or_class_map($query) ) {
@@ -59,18 +59,10 @@ class PostGetter {
59
  }
60
  }
61
 
62
- static function get_pids( $query ) {
63
- $posts = self::get_posts($query);
64
- $pids = array();
65
- foreach ( $posts as $post ) {
66
- if ( isset($post->ID) ) {
67
- $pids[] = $post->ID;
68
- }
69
- }
70
- return $pids;
71
- }
72
-
73
- static function loop_to_id() {
74
  if ( !self::wp_query_has_posts() ) { return false; }
75
 
76
  global $wp_query;
@@ -87,16 +79,16 @@ class PostGetter {
87
  /**
88
  * @return bool
89
  */
90
- static function wp_query_has_posts() {
91
  global $wp_query;
92
  return ($wp_query && property_exists($wp_query, 'posts') && $wp_query->posts);
93
  }
94
 
95
  /**
96
  * @param string|array $arg
97
- * @return bool
98
  */
99
- static function is_post_class_or_class_map( $arg ) {
100
  $maybe_type = self::get_class_for_use_as_timber_post($arg);
101
  if ( is_array($arg) && isset($arg['post_type']) ) {
102
  //the user has passed a true WP_Query-style query array that needs to be used later, so the $arg is not a class map or post class
@@ -105,13 +97,14 @@ class PostGetter {
105
  if ( $maybe_type ) {
106
  return true;
107
  }
 
108
  }
109
 
110
  /**
111
  * @param string|array $arg
112
  * @return string|bool if a $type is found; false if not
113
  */
114
- static function get_class_for_use_as_timber_post( $arg ) {
115
  $type = false;
116
 
117
  if ( is_string($arg) ) {
12
  * @param string $PostClass
13
  * @return array|bool|null
14
  */
15
+ public static function get_post( $query = false, $PostClass = '\Timber\Post' ) {
16
  $posts = self::get_posts($query, $PostClass);
17
  if ( $post = reset($posts) ) {
18
  return $post;
19
  }
20
  }
21
 
22
+ public static function get_posts( $query = false, $PostClass = '\Timber\Post', $return_collection = false ) {
23
  $posts = self::query_posts($query, $PostClass);
24
  return apply_filters('timber_post_getter_get_posts', $posts->get_posts($return_collection));
25
  }
26
 
27
+ public static function query_post( $query = false, $PostClass = '\Timber\Post' ) {
28
  $posts = self::query_posts($query, $PostClass);
29
  if ( method_exists($posts, 'current') && $post = $posts->current() ) {
30
  return $post;
36
  * @param string $PostClass
37
  * @return array|bool|null
38
  */
39
+ public static function query_posts( $query = false, $PostClass = '\Timber\Post' ) {
40
  if ( $type = self::get_class_for_use_as_timber_post($query) ) {
41
  $PostClass = $type;
42
  if ( self::is_post_class_or_class_map($query) ) {
59
  }
60
  }
61
 
62
+ /**
63
+ * @return integer the ID of the post in the loop
64
+ */
65
+ public static function loop_to_id() {
 
 
 
 
 
 
 
 
66
  if ( !self::wp_query_has_posts() ) { return false; }
67
 
68
  global $wp_query;
79
  /**
80
  * @return bool
81
  */
82
+ public static function wp_query_has_posts() {
83
  global $wp_query;
84
  return ($wp_query && property_exists($wp_query, 'posts') && $wp_query->posts);
85
  }
86
 
87
  /**
88
  * @param string|array $arg
89
+ * @return boolean
90
  */
91
+ public static function is_post_class_or_class_map( $arg ) {
92
  $maybe_type = self::get_class_for_use_as_timber_post($arg);
93
  if ( is_array($arg) && isset($arg['post_type']) ) {
94
  //the user has passed a true WP_Query-style query array that needs to be used later, so the $arg is not a class map or post class
97
  if ( $maybe_type ) {
98
  return true;
99
  }
100
+ return false;
101
  }
102
 
103
  /**
104
  * @param string|array $arg
105
  * @return string|bool if a $type is found; false if not
106
  */
107
+ public static function get_class_for_use_as_timber_post( $arg ) {
108
  $type = false;
109
 
110
  if ( is_string($arg) ) {
lib/PostPreview.php ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Timber;
4
+
5
+ /**
6
+ * An object that lets a user easily modify the post preview to their
7
+ * liking
8
+ * @since 1.0.4
9
+ */
10
+ class PostPreview {
11
+
12
+ protected $post;
13
+ protected $end = '&hellip;';
14
+ protected $force = false;
15
+ protected $length = 50;
16
+ protected $readmore = 'Read More';
17
+ protected $strip = true;
18
+
19
+ /**
20
+ * @param Post $post
21
+ */
22
+ public function __construct( $post ) {
23
+ $this->post = $post;
24
+ }
25
+
26
+ public function __toString() {
27
+ return $this->run();
28
+ }
29
+
30
+ /**
31
+ * @param integer $length (in words) of the target preview
32
+ */
33
+ public function length( $length = 50 ) {
34
+ $this->length = $length;
35
+ return $this;
36
+ }
37
+
38
+ /**
39
+ * @param string $end how should the text in the preview end
40
+ */
41
+ public function end( $end = '&hellip;' ) {
42
+ $this->end = $end;
43
+ return $this;
44
+ }
45
+
46
+ /**
47
+ * @param boolean $force If the editor wrote a manual excerpt longer than the set length, should it be "forced" to the size specified?
48
+ */
49
+ public function force( $force = true ) {
50
+ $this->force = $force;
51
+ return $this;
52
+ }
53
+
54
+ /**
55
+ * @param string $readmore What the text displays as to the reader inside of the <a> tag
56
+ */
57
+ public function read_more( $readmore = 'Read More' ) {
58
+ $this->readmore = $readmore;
59
+ return $this;
60
+ }
61
+
62
+ /**
63
+ * @param boolean|string $strip strip the tags or what? You can also provide a list of allowed tags
64
+ */
65
+ public function strip( $strip = true ) {
66
+ $this->strip = $strip;
67
+ return $this;
68
+ }
69
+
70
+ /**
71
+ * @param string $text
72
+ * @param array|booelan $readmore_matches
73
+ * @param boolean $trimmed was the text trimmed?
74
+ */
75
+ protected function assemble( $text, $readmore_matches, $trimmed ) {
76
+ $text = trim($text);
77
+ $last = $text[strlen($text) - 1];
78
+ $last_p_tag = null;
79
+ if ( $last != '.' && $trimmed ) {
80
+ $text .= $this->end;
81
+ }
82
+ if ( !$this->strip ) {
83
+ $last_p_tag = strrpos($text, '</p>');
84
+ if ( $last_p_tag !== false ) {
85
+ $text = substr($text, 0, $last_p_tag);
86
+ }
87
+ if ( $last != '.' && $trimmed ) {
88
+ $text .= $this->end.' ';
89
+ }
90
+ }
91
+ $read_more_class = apply_filters('timber/post/preview/read_more_class', "read-more");
92
+ if ( $this->readmore && !empty($readmore_matches) && !empty($readmore_matches[1]) ) {
93
+ $text .= ' <a href="'.$this->post->link().'" class="'.$read_more_class.'">'.trim($readmore_matches[1]).'</a>';
94
+ } elseif ( $this->readmore ) {
95
+ $text .= ' <a href="'.$this->post->link().'" class="'.$read_more_class.'">'.trim($this->readmore).'</a>';
96
+ }
97
+ if ( !$this->strip && $last_p_tag && (strpos($text, '<p>') || strpos($text, '<p ')) ) {
98
+ $text .= '</p>';
99
+ }
100
+ return trim($text);
101
+ }
102
+
103
+ protected function run() {
104
+ $force = $this->force;
105
+ $len = $this->length;
106
+ $strip = $this->strip;
107
+ $readmore_matches = array();
108
+ $text = '';
109
+ $trimmed = false;
110
+ if ( isset($this->post->post_excerpt) && strlen($this->post->post_excerpt) ) {
111
+ if ( $this->force ) {
112
+ $text = Helper::trim_words($this->post->post_excerpt, $len, false);
113
+ $trimmed = true;
114
+ } else {
115
+ $text = $this->post->post_excerpt;
116
+ }
117
+ }
118
+ if ( !strlen($text) && preg_match('/<!--\s?more(.*?)?-->/', $this->post->post_content, $readmore_matches) ) {
119
+ $pieces = explode($readmore_matches[0], $this->post->post_content);
120
+ $text = $pieces[0];
121
+ if ( $force ) {
122
+ $text = Helper::trim_words($text, $len, false);
123
+ $trimmed = true;
124
+ }
125
+ $text = do_shortcode($text);
126
+ }
127
+ if ( !strlen($text) ) {
128
+ $text = Helper::trim_words($this->post->content(), $len, false);
129
+ $trimmed = true;
130
+ }
131
+ if ( !strlen(trim($text)) ) {
132
+ return trim($text);
133
+ }
134
+ if ( $strip ) {
135
+ $allowable_tags = (is_string($strip)) ? $strip : null;
136
+ $text = trim(strip_tags($text, $allowable_tags));
137
+ }
138
+ if ( strlen($text) ) {
139
+ return $this->assemble($text, $readmore_matches, $trimmed);
140
+ }
141
+ return trim($text);
142
+ }
143
+
144
+ }
lib/PostType.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Timber;
4
+
5
+ /**
6
+ * Wrapper for the post_type object provided by WordPress
7
+ * @since 1.0.4
8
+ */
9
+ class PostType {
10
+
11
+ public function __construct( $post_type ) {
12
+ $this->slug = $post_type;
13
+ $this->init( $post_type );
14
+ }
15
+
16
+ public function __toString() {
17
+ return $this->slug;
18
+ }
19
+
20
+ protected function init( $post_type ) {
21
+ $obj = get_post_type_object($post_type);
22
+ foreach (get_object_vars($obj) as $key => $value) {
23
+ $this->$key = $value;
24
+ }
25
+ }
26
+
27
+ }
lib/PostsCollection.php CHANGED
@@ -6,8 +6,9 @@ use Timber\Helper;
6
  use Timber\Post;
7
 
8
  // Exit if accessed directly
9
- if ( !defined('ABSPATH') )
10
  exit;
 
11
 
12
  class PostsCollection extends \ArrayObject {
13
 
@@ -58,7 +59,7 @@ class PostsCollection extends \ArrayObject {
58
  * @param array $posts
59
  * @return array
60
  */
61
- static function maybe_set_preview( $posts ) {
62
  if ( is_array($posts) && isset($_GET['preview']) && $_GET['preview']
63
  && isset($_GET['preview_id']) && $_GET['preview_id']
64
  && current_user_can('edit_post', $_GET['preview_id']) ) {
6
  use Timber\Post;
7
 
8
  // Exit if accessed directly
9
+ if ( !defined('ABSPATH') ) {
10
  exit;
11
+ }
12
 
13
  class PostsCollection extends \ArrayObject {
14
 
59
  * @param array $posts
60
  * @return array
61
  */
62
+ public static function maybe_set_preview( $posts ) {
63
  if ( is_array($posts) && isset($_GET['preview']) && $_GET['preview']
64
  && isset($_GET['preview_id']) && $_GET['preview_id']
65
  && current_user_can('edit_post', $_GET['preview_id']) ) {
lib/QueryIterator.php CHANGED
@@ -6,8 +6,9 @@ use Timber\Helper;
6
  use Timber\PostsCollection;
7
 
8
  // Exit if accessed directly
9
- if ( !defined('ABSPATH') )
10
  exit;
 
11
 
12
  class QueryIterator implements \Iterator {
13
 
@@ -17,9 +18,9 @@ class QueryIterator implements \Iterator {
17
  * @var WP_Query
18
  */
19
  private $_query = null;
20
- private $_posts_class = 'TimberPost';
21
 
22
- public function __construct( $query = false, $posts_class = 'TimberPost' ) {
23
  add_action('pre_get_posts', array($this, 'fix_number_posts_wp_quirk'));
24
  if ( $posts_class )
25
  $this->_posts_class = $posts_class;
@@ -60,6 +61,10 @@ class QueryIterator implements \Iterator {
60
 
61
  }
62
 
 
 
 
 
63
  public function get_posts( $return_collection = false ) {
64
  if ( isset($this->_query->posts) ) {
65
  $posts = new PostsCollection($this->_query->posts, $this->_posts_class);
@@ -137,7 +142,7 @@ class QueryIterator implements \Iterator {
137
  }
138
 
139
  //get_posts users numberposts
140
- static function fix_number_posts_wp_quirk( $query ) {
141
  if ( isset($query->query) && isset($query->query['numberposts'])
142
  && !isset($query->query['posts_per_page']) ) {
143
  $query->set('posts_per_page', $query->query['numberposts']);
@@ -150,7 +155,7 @@ class QueryIterator implements \Iterator {
150
  * @param WP_Query $query the original query recived from WordPress
151
  * @return WP_Query
152
  */
153
- static function handle_maybe_custom_posts_page( $query ) {
154
  if ( $custom_posts_page = get_option('page_for_posts') ) {
155
  if ( isset($query->query['p']) && $query->query['p'] == $custom_posts_page ) {
156
  return new \WP_Query(array('post_type' => 'post'));
6
  use Timber\PostsCollection;
7
 
8
  // Exit if accessed directly
9
+ if ( !defined('ABSPATH') ) {
10
  exit;
11
+ }
12
 
13
  class QueryIterator implements \Iterator {
14
 
18
  * @var WP_Query
19
  */
20
  private $_query = null;
21
+ private $_posts_class = 'Timber\Post';
22
 
23
+ public function __construct( $query = false, $posts_class = 'Timber\Post' ) {
24
  add_action('pre_get_posts', array($this, 'fix_number_posts_wp_quirk'));
25
  if ( $posts_class )
26
  $this->_posts_class = $posts_class;
61
 
62
  }
63
 
64
+ public function post_count() {
65
+ return $this->_query->post_count;
66
+ }
67
+
68
  public function get_posts( $return_collection = false ) {
69
  if ( isset($this->_query->posts) ) {
70
  $posts = new PostsCollection($this->_query->posts, $this->_posts_class);
142
  }
143
 
144
  //get_posts users numberposts
145
+ public static function fix_number_posts_wp_quirk( $query ) {
146
  if ( isset($query->query) && isset($query->query['numberposts'])
147
  && !isset($query->query['posts_per_page']) ) {
148
  $query->set('posts_per_page', $query->query['numberposts']);
155
  * @param WP_Query $query the original query recived from WordPress
156
  * @return WP_Query
157
  */
158
+ public static function handle_maybe_custom_posts_page( $query ) {
159
  if ( $custom_posts_page = get_option('page_for_posts') ) {
160
  if ( isset($query->query['p']) && $query->query['p'] == $custom_posts_page ) {
161
  return new \WP_Query(array('post_type' => 'post'));
lib/Request.php CHANGED
@@ -17,7 +17,7 @@ class Request extends Core implements CoreInterface {
17
  * Constructs a TimberRequest object
18
  * @example
19
  */
20
- function __construct() {
21
  $this->init();
22
  }
23
  /**
@@ -33,7 +33,7 @@ class Request extends Core implements CoreInterface {
33
  public function __get( $field ) {}
34
 
35
  /**
36
- * @return boolean
37
  */
38
  public function __isset( $field ) {}
39
 
17
  * Constructs a TimberRequest object
18
  * @example
19
  */
20
+ public function __construct() {
21
  $this->init();
22
  }
23
  /**
33
  public function __get( $field ) {}
34
 
35
  /**
36
+ * @return boolean|null
37
  */
38
  public function __isset( $field ) {}
39
 
lib/Site.php CHANGED
@@ -109,7 +109,7 @@ class Site extends Core implements CoreInterface {
109
  * ```
110
  * @param string|int $site_name_or_id
111
  */
112
- function __construct( $site_name_or_id = null ) {
113
  $this->init();
114
  if ( is_multisite() ) {
115
  $this->init_as_multisite($site_name_or_id);
@@ -122,7 +122,7 @@ class Site extends Core implements CoreInterface {
122
  * @internal
123
  * @param string|int $site_name_or_id
124
  */
125
- protected function init_as_multisite( $site_name_or_id ) {
126
  if ( $site_name_or_id === null ) {
127
  //this is necessary for some reason, otherwise returns 1 all the time
128
  if ( is_multisite() ) {
@@ -130,18 +130,25 @@ class Site extends Core implements CoreInterface {
130
  $site_name_or_id = get_current_blog_id();
131
  }
132
  }
 
 
133
  $info = get_blog_details($site_name_or_id);
 
 
134
  $this->import($info);
135
  $this->ID = $info->blog_id;
136
  $this->id = $this->ID;
137
  $this->name = $this->blogname;
138
  $this->title = $this->blogname;
139
- $this->url = $this->siteurl;
140
  $theme_slug = get_blog_option($info->blog_id, 'stylesheet');
141
  $this->theme = new Theme($theme_slug);
142
  $this->description = get_blog_option($info->blog_id, 'blogdescription');
143
  $this->admin_email = get_blog_option($info->blog_id, 'admin_email');
144
  $this->multisite = true;
 
 
 
145
  }
146
 
147
  /**
@@ -170,7 +177,7 @@ class Site extends Core implements CoreInterface {
170
  $this->atom = get_bloginfo('atom_url');
171
  $this->language = get_bloginfo('language');
172
  $this->charset = get_bloginfo('charset');
173
- $this->pingback = get_bloginfo('pingback_url');
174
  $this->language_attributes = Helper::function_wrapper('language_attributes');
175
  }
176
 
@@ -180,7 +187,7 @@ class Site extends Core implements CoreInterface {
180
  * @param string $field
181
  * @return mixed
182
  */
183
- function __get( $field ) {
184
  if ( !isset($this->$field) ) {
185
  if ( is_multisite() ) {
186
  $this->$field = get_blog_option($this->ID, $field);
@@ -216,7 +223,7 @@ class Site extends Core implements CoreInterface {
216
  * @internal
217
  * @return string
218
  */
219
- function get_link() {
220
  Helper::warn('{{site.get_link}} is deprecated, use {{site.link}}');
221
  return $this->link();
222
  }
@@ -246,12 +253,11 @@ class Site extends Core implements CoreInterface {
246
  }
247
 
248
  /**
249
- *
250
- * @api
251
  * @see TimberSite::link
252
  * @return string
253
  */
254
- function url() {
255
  return $this->link();
256
  }
257
 
@@ -260,7 +266,7 @@ class Site extends Core implements CoreInterface {
260
  * @internal
261
  * @return string
262
  */
263
- function get_url() {
264
  Helper::warn('{{site.get_url}} is deprecated, use {{site.link}} instead');
265
  return $this->link();
266
  }
109
  * ```
110
  * @param string|int $site_name_or_id
111
  */
112
+ public function __construct( $site_name_or_id = null ) {
113
  $this->init();
114
  if ( is_multisite() ) {
115
  $this->init_as_multisite($site_name_or_id);
122
  * @internal
123
  * @param string|int $site_name_or_id
124
  */
125
+ protected function init_as_multisite( $site_name_or_id = null ) {
126
  if ( $site_name_or_id === null ) {
127
  //this is necessary for some reason, otherwise returns 1 all the time
128
  if ( is_multisite() ) {
130
  $site_name_or_id = get_current_blog_id();
131
  }
132
  }
133
+ /* we need to store the current blog, but switch things to the blog id of the Site object requested */
134
+ $old_id = get_current_blog_id();
135
  $info = get_blog_details($site_name_or_id);
136
+ switch_to_blog($info->blog_id);
137
+
138
  $this->import($info);
139
  $this->ID = $info->blog_id;
140
  $this->id = $this->ID;
141
  $this->name = $this->blogname;
142
  $this->title = $this->blogname;
143
+ $this->url = get_bloginfo('url');
144
  $theme_slug = get_blog_option($info->blog_id, 'stylesheet');
145
  $this->theme = new Theme($theme_slug);
146
  $this->description = get_blog_option($info->blog_id, 'blogdescription');
147
  $this->admin_email = get_blog_option($info->blog_id, 'admin_email');
148
  $this->multisite = true;
149
+
150
+ //switch back to the before time
151
+ switch_to_blog($old_id);
152
  }
153
 
154
  /**
177
  $this->atom = get_bloginfo('atom_url');
178
  $this->language = get_bloginfo('language');
179
  $this->charset = get_bloginfo('charset');
180
+ $this->pingback = $this->pingback_url = get_bloginfo('pingback_url');
181
  $this->language_attributes = Helper::function_wrapper('language_attributes');
182
  }
183
 
187
  * @param string $field
188
  * @return mixed
189
  */
190
+ public function __get( $field ) {
191
  if ( !isset($this->$field) ) {
192
  if ( is_multisite() ) {
193
  $this->$field = get_blog_option($this->ID, $field);
223
  * @internal
224
  * @return string
225
  */
226
+ public function get_link() {
227
  Helper::warn('{{site.get_link}} is deprecated, use {{site.link}}');
228
  return $this->link();
229
  }
253
  }
254
 
255
  /**
256
+ * @deprecated 1.0.4
 
257
  * @see TimberSite::link
258
  * @return string
259
  */
260
+ public function url() {
261
  return $this->link();
262
  }
263
 
266
  * @internal
267
  * @return string
268
  */
269
+ public function get_url() {
270
  Helper::warn('{{site.get_url}} is deprecated, use {{site.link}} instead');
271
  return $this->link();
272
  }
lib/Term.php CHANGED
@@ -56,7 +56,7 @@ class Term extends Core implements CoreInterface {
56
  public $name;
57
  /**
58
  * @api
59
- * @var strng the WordPress taxonomy slug (ex: `post_tag` or `actors`)
60
  */
61
  public $taxonomy;
62
 
@@ -315,7 +315,7 @@ class Term extends Core implements CoreInterface {
315
  * @param string $key
316
  * @param mixed $value
317
  */
318
- function update( $key, $value ) {
319
  $value = apply_filters('timber_term_set_meta', $value, $key, $this->ID, $this);
320
  $this->$key = $value;
321
  }
@@ -337,7 +337,6 @@ class Term extends Core implements CoreInterface {
337
  */
338
  public function description() {
339
  $prefix = '<p>';
340
- $suffix = '</p>';
341
  $desc = term_description($this->ID, $this->taxonomy);
342
  if ( substr($desc, 0, strlen($prefix)) == $prefix ) {
343
  $desc = substr($desc, strlen($prefix));
56
  public $name;
57
  /**
58
  * @api
59
+ * @var string the WordPress taxonomy slug (ex: `post_tag` or `actors`)
60
  */
61
  public $taxonomy;
62
 
315
  * @param string $key
316
  * @param mixed $value
317
  */
318
+ public function update( $key, $value ) {
319
  $value = apply_filters('timber_term_set_meta', $value, $key, $this->ID, $this);
320
  $this->$key = $value;
321
  }
337
  */
338
  public function description() {
339
  $prefix = '<p>';
 
340
  $desc = term_description($this->ID, $this->taxonomy);
341
  if ( substr($desc, 0, strlen($prefix)) == $prefix ) {
342
  $desc = substr($desc, strlen($prefix));
lib/TermGetter.php CHANGED
@@ -6,6 +6,15 @@ use Timber\Term;
6
  use Timber\Helper;
7
 
8
  class TermGetter {
 
 
 
 
 
 
 
 
 
9
 
10
  /**
11
  * @param string|array $args
@@ -77,7 +86,7 @@ class TermGetter {
77
 
78
  /**
79
  * @param string $query_string
80
- * @return stdClass
81
  */
82
  protected static function get_term_query_from_query_string( $query_string ) {
83
  $args = array();
@@ -88,7 +97,7 @@ class TermGetter {
88
 
89
  /**
90
  * @param string $taxs
91
- * @return stdClass
92
  */
93
  protected static function get_term_query_from_string( $taxs ) {
94
  $ret = new \stdClass();
@@ -102,7 +111,7 @@ class TermGetter {
102
 
103
  /**
104
  * @param array $args
105
- * @return stdClass
106
  */
107
  public static function get_term_query_from_assoc_array( $args ) {
108
  $ret = new \stdClass();
@@ -129,7 +138,7 @@ class TermGetter {
129
 
130
  /**
131
  * @param array $args
132
- * @return stdClass
133
  */
134
  public static function get_term_query_from_array( $args ) {
135
  if ( is_array($args) && !empty($args) ) {
@@ -145,7 +154,7 @@ class TermGetter {
145
 
146
  /**
147
  * @param integer[] $args
148
- * @return stdClass
149
  */
150
  public static function get_term_query_from_array_of_ids( $args ) {
151
  $ret = new \stdClass();
@@ -156,7 +165,7 @@ class TermGetter {
156
 
157
  /**
158
  * @param string[] $args
159
- * @return stdClass
160
  */
161
  public static function get_term_query_from_array_of_strings( $args ) {
162
  $ret = new \stdClass();
6
  use Timber\Helper;
7
 
8
  class TermGetter {
9
+ /**
10
+ * @param int|WP_Term|object $term
11
+ * @param string $taxonomy
12
+ * @return Timber\Term|WP_Error|null
13
+ */
14
+ public static function get_term( $term, $taxonomy, $TermClass = 'Term' ) {
15
+ $term = get_term( $term, $taxonomy );
16
+ return new $TermClass( $term->term_id, $term->taxonomy );
17
+ }
18
 
19
  /**
20
  * @param string|array $args
86
 
87
  /**
88
  * @param string $query_string
89
+ * @return \stdClass
90
  */
91
  protected static function get_term_query_from_query_string( $query_string ) {
92
  $args = array();
97
 
98
  /**
99
  * @param string $taxs
100
+ * @return \stdClass
101
  */
102
  protected static function get_term_query_from_string( $taxs ) {
103
  $ret = new \stdClass();
111
 
112
  /**
113
  * @param array $args
114
+ * @return \stdClass
115
  */
116
  public static function get_term_query_from_assoc_array( $args ) {
117
  $ret = new \stdClass();
138
 
139
  /**
140
  * @param array $args
141
+ * @return \stdClass|null
142
  */
143
  public static function get_term_query_from_array( $args ) {
144
  if ( is_array($args) && !empty($args) ) {
154
 
155
  /**
156
  * @param integer[] $args
157
+ * @return \stdClass
158
  */
159
  public static function get_term_query_from_array_of_ids( $args ) {
160
  $ret = new \stdClass();
165
 
166
  /**
167
  * @param string[] $args
168
+ * @return \stdClass
169
  */
170
  public static function get_term_query_from_array_of_strings( $args ) {
171
  $ret = new \stdClass();
lib/Theme.php CHANGED
@@ -68,7 +68,7 @@ class Theme extends Core {
68
  * We are currently using the My Theme theme.
69
  * ```
70
  */
71
- function __construct( $slug = null ) {
72
  $this->init($slug);
73
  }
74
 
68
  * We are currently using the My Theme theme.
69
  * ```
70
  */
71
+ public function __construct( $slug = null ) {
72
  $this->init($slug);
73
  }
74
 
lib/Timber.php CHANGED
@@ -32,6 +32,7 @@ use Timber\Loader;
32
  */
33
  class Timber {
34
 
 
35
  public static $locations;
36
  public static $dirname;
37
  public static $twig_cache = false;
@@ -48,10 +49,12 @@ class Timber {
48
  if ( !defined('ABSPATH') ) {
49
  return;
50
  }
51
- $this->test_compatibility();
52
- $this->backwards_compatibility();
53
- $this->init_constants();
54
- $this->init();
 
 
55
  }
56
 
57
  /**
@@ -76,14 +79,21 @@ class Timber {
76
  //already run, so bail
77
  return;
78
  }
79
- $names = array('Archives', 'Comment', 'Core', 'FunctionWrapper', 'Helper', 'Image', 'ImageHelper', 'Integrations', 'Loader', 'Menu', 'MenuItem', 'Post', 'PostGetter', 'PostsCollection', 'QueryIterator', 'Request', 'Site', 'Term', 'TermGetter', 'Theme', 'Twig', 'URLHelper', 'User');
80
- class_alias(get_class($this), 'Timber');
81
  foreach ( $names as $name ) {
82
- class_alias('Timber\\'.$name, 'Timber'.$name);
 
 
 
 
 
 
 
 
83
  }
84
  }
85
 
86
- function init_constants() {
87
  defined("TIMBER_LOC") or define("TIMBER_LOC", realpath(dirname(__DIR__)));
88
  }
89
 
@@ -91,10 +101,13 @@ class Timber {
91
  * @codeCoverageIgnore
92
  */
93
  protected function init() {
94
- Twig::init();
95
- ImageHelper::init();
96
- Admin::init();
97
- Integrations::init();
 
 
 
98
  }
99
 
100
  /* Post Retrieval Routine
@@ -107,7 +120,7 @@ class Timber {
107
  * @param string $PostClass
108
  * @return array|bool|null
109
  */
110
- public static function get_post( $query = false, $PostClass = 'TimberPost' ) {
111
  return PostGetter::get_post($query, $PostClass);
112
  }
113
 
@@ -124,7 +137,7 @@ class Timber {
124
  * @param string|array $PostClass
125
  * @return array|bool|null
126
  */
127
- public static function get_posts( $query = false, $PostClass = 'TimberPost', $return_collection = false ) {
128
  return PostGetter::get_posts($query, $PostClass, $return_collection);
129
  }
130
 
@@ -135,7 +148,7 @@ class Timber {
135
  * @param string $PostClass
136
  * @return array|bool|null
137
  */
138
- public static function query_post( $query = false, $PostClass = 'TimberPost' ) {
139
  return PostGetter::query_post($query, $PostClass);
140
  }
141
 
@@ -146,7 +159,7 @@ class Timber {
146
  * @param string $PostClass
147
  * @return array|bool|null
148
  */
149
- public static function query_posts( $query = false, $PostClass = 'TimberPost' ) {
150
  return PostGetter::query_posts($query, $PostClass);
151
  }
152
 
@@ -161,10 +174,21 @@ class Timber {
161
  * @param string $TermClass
162
  * @return mixed
163
  */
164
- public static function get_terms( $args = null, $maybe_args = array(), $TermClass = 'TimberTerm' ) {
165
  return TermGetter::get_terms($args, $maybe_args, $TermClass);
166
  }
167
 
 
 
 
 
 
 
 
 
 
 
 
168
  /* Site Retrieval
169
  ================================ */
170
 
@@ -196,26 +220,26 @@ class Timber {
196
  * @return array
197
  */
198
  public static function get_context() {
199
- if( empty(self::$context_cache) ) {
200
  self::$context_cache['http_host'] = 'http://'.URLHelper::get_host();
201
  self::$context_cache['wp_title'] = Helper::get_wp_title();
202
  self::$context_cache['wp_head'] = Helper::function_wrapper('wp_head');
203
  self::$context_cache['wp_footer'] = Helper::function_wrapper('wp_footer');
204
  self::$context_cache['body_class'] = implode(' ', get_body_class());
205
-
206
  self::$context_cache['site'] = new Site();
207
  self::$context_cache['request'] = new Request();
208
  $user = new User();
209
  self::$context_cache['user'] = ($user->ID) ? $user : false;
210
  self::$context_cache['theme'] = self::$context_cache['site']->theme;
211
-
212
  self::$context_cache['posts'] = Timber::query_posts();
213
 
214
  self::$context_cache = apply_filters('timber_context', self::$context_cache);
215
  self::$context_cache = apply_filters('timber/context', self::$context_cache);
216
  }
217
 
218
-
219
  return self::$context_cache;
220
  }
221
 
@@ -230,9 +254,10 @@ class Timber {
230
  * @return bool|string
231
  */
232
  public static function compile( $filenames, $data = array(), $expires = false, $cache_mode = Loader::CACHE_USE_DEFAULT, $via_render = false ) {
 
 
 
233
  $caller = self::get_calling_script_dir();
234
- $caller_file = self::get_calling_script_file();
235
- $caller_file = apply_filters('timber_calling_php_file', $caller_file);
236
  $loader = new Loader($caller);
237
  $file = $loader->choose_template($filenames);
238
  $output = '';
@@ -399,7 +424,7 @@ class Timber {
399
  parse_str($url[1], $query);
400
  $args['add_args'] = $query;
401
  }
402
- $args['format'] = $wp_rewrite->pagination_base . '/%#%';
403
  $args['base'] = trailingslashit($url[0]).'%_%';
404
  } else {
405
  $big = 999999999;
@@ -417,13 +442,14 @@ class Timber {
417
  $data['current'] = $args['current'];
418
  $data['total'] = $args['total'];
419
  $data['pages'] = Helper::paginate_links($args);
420
- $next = get_next_posts_page_link($args['total']);
421
- if ( $next ) {
422
- $data['next'] = array('link' => untrailingslashit($next), 'class' => 'page-numbers next');
 
 
423
  }
424
- $prev = previous_posts(false);
425
- if ( $prev ) {
426
- $data['prev'] = array('link' => untrailingslashit($prev), 'class' => 'page-numbers prev');
427
  }
428
  if ( $paged < 2 ) {
429
  $data['prev'] = '';
@@ -488,4 +514,4 @@ class Timber {
488
  }
489
  return $caller;
490
  }
491
- }
32
  */
33
  class Timber {
34
 
35
+ public static $version = '1.0.3';
36
  public static $locations;
37
  public static $dirname;
38
  public static $twig_cache = false;
49
  if ( !defined('ABSPATH') ) {
50
  return;
51
  }
52
+ if ( class_exists('\WP') && !defined('TIMBER_LOADED') ) {
53
+ $this->test_compatibility();
54
+ $this->backwards_compatibility();
55
+ $this->init_constants();
56
+ $this->init();
57
+ }
58
  }
59
 
60
  /**
79
  //already run, so bail
80
  return;
81
  }
82
+ $names = array('Archives', 'Comment', 'Core', 'FunctionWrapper', 'Helper', 'Image', 'ImageHelper', 'Integrations', 'Loader', 'Menu', 'MenuItem', 'Post', 'PostGetter', 'PostsCollection', 'QueryIterator', 'Request', 'Site', 'Term', 'TermGetter', 'Theme', 'Twig', 'URLHelper', 'User', 'Integrations\Command', 'Integrations\ACF');
 
83
  foreach ( $names as $name ) {
84
+ $old_class_name = 'Timber'.str_replace('Integrations\\', '', $name);
85
+ $new_class_name = 'Timber\\'.$name;
86
+ if ( class_exists($new_class_name) ) {
87
+ class_alias($new_class_name, $old_class_name);
88
+ }
89
+ }
90
+ class_alias(get_class($this), 'Timber');
91
+ if ( class_exists('Timber\\'.'Integrations\Timber_WP_CLI_Command') ) {
92
+ class_alias('Timber\\'.'Integrations\Timber_WP_CLI_Command', 'Timber_WP_CLI_Command');
93
  }
94
  }
95
 
96
+ public function init_constants() {
97
  defined("TIMBER_LOC") or define("TIMBER_LOC", realpath(dirname(__DIR__)));
98
  }
99
 
101
  * @codeCoverageIgnore
102
  */
103
  protected function init() {
104
+ if ( class_exists('\WP') && !defined('TIMBER_LOADED') ) {
105
+ Twig::init();
106
+ ImageHelper::init();
107
+ Admin::init();
108
+ Integrations::init();
109
+ define('TIMBER_LOADED', true);
110
+ }
111
  }
112
 
113
  /* Post Retrieval Routine
120
  * @param string $PostClass
121
  * @return array|bool|null
122
  */
123
+ public static function get_post( $query = false, $PostClass = 'Timber\Post' ) {
124
  return PostGetter::get_post($query, $PostClass);
125
  }
126
 
137
  * @param string|array $PostClass
138
  * @return array|bool|null
139
  */
140
+ public static function get_posts( $query = false, $PostClass = 'Timber\Post', $return_collection = false ) {
141
  return PostGetter::get_posts($query, $PostClass, $return_collection);
142
  }
143
 
148
  * @param string $PostClass
149
  * @return array|bool|null
150
  */
151
+ public static function query_post( $query = false, $PostClass = 'Timber\Post' ) {
152
  return PostGetter::query_post($query, $PostClass);
153
  }
154
 
159
  * @param string $PostClass
160
  * @return array|bool|null
161
  */
162
+ public static function query_posts( $query = false, $PostClass = 'Timber\Post' ) {
163
  return PostGetter::query_posts($query, $PostClass);
164
  }
165
 
174
  * @param string $TermClass
175
  * @return mixed
176
  */
177
+ public static function get_terms( $args = null, $maybe_args = array(), $TermClass = 'Timber\Term' ) {
178
  return TermGetter::get_terms($args, $maybe_args, $TermClass);
179
  }
180
 
181
+ /**
182
+ * Get term.
183
+ *
184
+ * @param int|WP_Term|object $term
185
+ * @param string $taxonomy
186
+ * @return Timber\Term|WP_Error|null
187
+ */
188
+ public static function get_term( $term, $taxonomy = 'post_tag', $TermClass = 'Timber\Term' ) {
189
+ return TermGetter::get_term( $term, $taxonomy, $TermClass );
190
+ }
191
+
192
  /* Site Retrieval
193
  ================================ */
194
 
220
  * @return array
221
  */
222
  public static function get_context() {
223
+ if ( empty(self::$context_cache) ) {
224
  self::$context_cache['http_host'] = 'http://'.URLHelper::get_host();
225
  self::$context_cache['wp_title'] = Helper::get_wp_title();
226
  self::$context_cache['wp_head'] = Helper::function_wrapper('wp_head');
227
  self::$context_cache['wp_footer'] = Helper::function_wrapper('wp_footer');
228
  self::$context_cache['body_class'] = implode(' ', get_body_class());
229
+
230
  self::$context_cache['site'] = new Site();
231
  self::$context_cache['request'] = new Request();
232
  $user = new User();
233
  self::$context_cache['user'] = ($user->ID) ? $user : false;
234
  self::$context_cache['theme'] = self::$context_cache['site']->theme;
235
+
236
  self::$context_cache['posts'] = Timber::query_posts();
237
 
238
  self::$context_cache = apply_filters('timber_context', self::$context_cache);
239
  self::$context_cache = apply_filters('timber/context', self::$context_cache);
240
  }
241
 
242
+
243
  return self::$context_cache;
244
  }
245
 
254
  * @return bool|string
255
  */
256
  public static function compile( $filenames, $data = array(), $expires = false, $cache_mode = Loader::CACHE_USE_DEFAULT, $via_render = false ) {
257
+ if ( !defined('TIMBER_LOADED') ) {
258
+ self::init();
259
+ }
260
  $caller = self::get_calling_script_dir();
 
 
261
  $loader = new Loader($caller);
262
  $file = $loader->choose_template($filenames);
263
  $output = '';
424
  parse_str($url[1], $query);
425
  $args['add_args'] = $query;
426
  }
427
+ $args['format'] = $wp_rewrite->pagination_base.'/%#%';
428
  $args['base'] = trailingslashit($url[0]).'%_%';
429
  } else {
430
  $big = 999999999;
442
  $data['current'] = $args['current'];
443
  $data['total'] = $args['total'];
444
  $data['pages'] = Helper::paginate_links($args);
445
+ // decrement current so that it matches up with the 0 based index used by the pages array
446
+ $current = $data['current'] - 1;
447
+ // set next and prev using pages array generated by paginate links
448
+ if ( isset( $data['pages'][$current + 1] ) ) {
449
+ $data['next'] = array('link' => untrailingslashit( $data['pages'][$current + 1]['link'] ), 'class' => 'page-numbers next');
450
  }
451
+ if ( isset( $data['pages'][$current - 1] ) ) {
452
+ $data['prev'] = array('link' => untrailingslashit( $data['pages'][$current - 1]['link'] ), 'class' => 'page-numbers prev');
 
453
  }
454
  if ( $paged < 2 ) {
455
  $data['prev'] = '';
514
  }
515
  return $caller;
516
  }
517
+ }
lib/Twig.php CHANGED
@@ -24,7 +24,7 @@ class Twig {
24
  /**
25
  * @codeCoverageIgnore
26
  */
27
- function __construct() {
28
  add_action('timber/twig/filters', array($this, 'add_timber_filters'));
29
  }
30
 
@@ -34,7 +34,7 @@ class Twig {
34
  * @param Twig_Environment $twig
35
  * @return Twig_Environment
36
  */
37
- function add_timber_filters( $twig ) {
38
  /* image filters */
39
  $twig->addFilter(new \Twig_SimpleFilter('resize', array('TimberImageHelper', 'resize')));
40
  $twig->addFilter(new \Twig_SimpleFilter('retina', array('TimberImageHelper', 'retina_resize')));
@@ -167,37 +167,37 @@ class Twig {
167
  } ));
168
 
169
  /* bloginfo and translate */
170
- $twig->addFunction('bloginfo', new \Twig_SimpleFunction('bloginfo', function( $show = '', $filter = 'raw' ) {
171
  return get_bloginfo($show, $filter);
172
  } ));
173
- $twig->addFunction('__', new \Twig_SimpleFunction('__', function( $text, $domain = 'default' ) {
174
  return __($text, $domain);
175
  } ));
176
- $twig->addFunction('translate', new \Twig_SimpleFunction('translate', function( $text, $domain = 'default' ) {
177
  return translate($text, $domain);
178
  } ));
179
- $twig->addFunction('_e', new \Twig_SimpleFunction('_e', function( $text, $domain = 'default' ) {
180
  return _e($text, $domain);
181
  } ));
182
- $twig->addFunction('_n', new \Twig_SimpleFunction('_n', function( $single, $plural, $number, $domain = 'default' ) {
183
  return _n($single, $plural, $number, $domain);
184
  } ));
185
- $twig->addFunction('_x', new \Twig_SimpleFunction('_x', function( $text, $context, $domain = 'default' ) {
186
  return _x($text, $context, $domain);
187
  } ));
188
- $twig->addFunction('_ex', new \Twig_SimpleFunction('_ex', function( $text, $context, $domain = 'default' ) {
189
  return _ex($text, $context, $domain);
190
  } ));
191
- $twig->addFunction('_nx', new \Twig_SimpleFunction('_nx', function( $single, $plural, $number, $context, $domain = 'default' ) {
192
  return _nx($single, $plural, $number, $context, $domain);
193
  } ));
194
- $twig->addFunction('_n_noop', new \Twig_SimpleFunction('_n_noop', function( $singular, $plural, $domain = 'default' ) {
195
  return _n_noop($singular, $plural, $domain);
196
  } ));
197
- $twig->addFunction('_nx_noop', new \Twig_SimpleFunction('_nx_noop', function( $singular, $plural, $context, $domain = 'default' ) {
198
  return _nx_noop($singular, $plural, $context, $domain);
199
  } ));
200
- $twig->addFunction('translate_nooped_plural', new \Twig_SimpleFunction('translate_nooped_plural', function( $nooped_plural, $count, $domain = 'default' ) {
201
  return translate_nooped_plural($nooped_plural, $count, $domain);
202
  } ));
203
  $twig = apply_filters('timber/twig', $twig);
@@ -214,7 +214,7 @@ class Twig {
214
  * @param mixed $arr
215
  * @return array
216
  */
217
- function to_array( $arr ) {
218
  if ( is_array($arr) ) {
219
  return $arr;
220
  }
@@ -228,7 +228,7 @@ class Twig {
228
  * @param string $function_name
229
  * @return mixed
230
  */
231
- function exec_function( $function_name ) {
232
  $args = func_get_args();
233
  array_shift($args);
234
  if ( is_string($function_name) ) {
@@ -243,7 +243,7 @@ class Twig {
243
  * @param string $content
244
  * @return string
245
  */
246
- function twig_pretags( $content ) {
247
  return preg_replace_callback('|<pre.*>(.*)</pre|isU', array(&$this, 'convert_pre_entities'), $content);
248
  }
249
 
@@ -253,7 +253,7 @@ class Twig {
253
  * @param array $matches
254
  * @return string
255
  */
256
- function convert_pre_entities( $matches ) {
257
  return str_replace($matches[1], htmlentities($matches[1]), $matches[0]);
258
  }
259
 
@@ -264,7 +264,7 @@ class Twig {
264
  * @param string $format (optional)
265
  * @return string
266
  */
267
- function intl_date( $date, $format = null ) {
268
  if ( $format === null ) {
269
  $format = get_option('date_format');
270
  }
@@ -287,7 +287,7 @@ class Twig {
287
  * @param string $format_future
288
  * @return string
289
  */
290
- function time_ago( $from, $to = null, $format_past = '%s ago', $format_future = '%s from now' ) {
291
  $to = $to === null ? time() : $to;
292
  $to = is_int($to) ? $to : strtotime($to);
293
  $from = is_int($from) ? $from : strtotime($from);
@@ -305,7 +305,7 @@ class Twig {
305
  * @param string $second_delimiter
306
  * @return string
307
  */
308
- function add_list_separators( $arr, $first_delimiter = ',', $second_delimiter = 'and' ) {
309
  $length = count($arr);
310
  $list = '';
311
  foreach ( $arr as $index => $item ) {
24
  /**
25
  * @codeCoverageIgnore
26
  */
27
+ public function __construct() {
28
  add_action('timber/twig/filters', array($this, 'add_timber_filters'));
29
  }
30
 
34
  * @param Twig_Environment $twig
35
  * @return Twig_Environment
36
  */
37
+ public function add_timber_filters( $twig ) {
38
  /* image filters */
39
  $twig->addFilter(new \Twig_SimpleFilter('resize', array('TimberImageHelper', 'resize')));
40
  $twig->addFilter(new \Twig_SimpleFilter('retina', array('TimberImageHelper', 'retina_resize')));
167
  } ));
168
 
169
  /* bloginfo and translate */
170
+ $twig->addFunction(new \Twig_SimpleFunction('bloginfo', function( $show = '', $filter = 'raw' ) {
171
  return get_bloginfo($show, $filter);
172
  } ));
173
+ $twig->addFunction(new \Twig_SimpleFunction('__', function( $text, $domain = 'default' ) {
174
  return __($text, $domain);
175
  } ));
176
+ $twig->addFunction(new \Twig_SimpleFunction('translate', function( $text, $domain = 'default' ) {
177
  return translate($text, $domain);
178
  } ));
179
+ $twig->addFunction(new \Twig_SimpleFunction('_e', function( $text, $domain = 'default' ) {
180
  return _e($text, $domain);
181
  } ));
182
+ $twig->addFunction(new \Twig_SimpleFunction('_n', function( $single, $plural, $number, $domain = 'default' ) {
183
  return _n($single, $plural, $number, $domain);
184
  } ));
185
+ $twig->addFunction(new \Twig_SimpleFunction('_x', function( $text, $context, $domain = 'default' ) {
186
  return _x($text, $context, $domain);
187
  } ));
188
+ $twig->addFunction(new \Twig_SimpleFunction('_ex', function( $text, $context, $domain = 'default' ) {
189
  return _ex($text, $context, $domain);
190
  } ));
191
+ $twig->addFunction(new \Twig_SimpleFunction('_nx', function( $single, $plural, $number, $context, $domain = 'default' ) {
192
  return _nx($single, $plural, $number, $context, $domain);
193
  } ));
194
+ $twig->addFunction(new \Twig_SimpleFunction('_n_noop', function( $singular, $plural, $domain = 'default' ) {
195
  return _n_noop($singular, $plural, $domain);
196
  } ));
197
+ $twig->addFunction(new \Twig_SimpleFunction('_nx_noop', function( $singular, $plural, $context, $domain = 'default' ) {
198
  return _nx_noop($singular, $plural, $context, $domain);
199
  } ));
200
+ $twig->addFunction(new \Twig_SimpleFunction('translate_nooped_plural', function( $nooped_plural, $count, $domain = 'default' ) {
201
  return translate_nooped_plural($nooped_plural, $count, $domain);
202
  } ));
203
  $twig = apply_filters('timber/twig', $twig);
214
  * @param mixed $arr
215
  * @return array
216
  */
217
+ public function to_array( $arr ) {
218
  if ( is_array($arr) ) {
219
  return $arr;
220
  }
228
  * @param string $function_name
229
  * @return mixed
230
  */
231
+ public function exec_function( $function_name ) {
232
  $args = func_get_args();
233
  array_shift($args);
234
  if ( is_string($function_name) ) {
243
  * @param string $content
244
  * @return string
245
  */
246
+ public function twig_pretags( $content ) {
247
  return preg_replace_callback('|<pre.*>(.*)</pre|isU', array(&$this, 'convert_pre_entities'), $content);
248
  }
249
 
253
  * @param array $matches
254
  * @return string
255
  */
256
+ public function convert_pre_entities( $matches ) {
257
  return str_replace($matches[1], htmlentities($matches[1]), $matches[0]);
258
  }
259
 
264
  * @param string $format (optional)
265
  * @return string
266
  */
267
+ public function intl_date( $date, $format = null ) {
268
  if ( $format === null ) {
269
  $format = get_option('date_format');
270
  }
287
  * @param string $format_future
288
  * @return string
289
  */
290
+ public function time_ago( $from, $to = null, $format_past = '%s ago', $format_future = '%s from now' ) {
291
  $to = $to === null ? time() : $to;
292
  $to = is_int($to) ? $to : strtotime($to);
293
  $from = is_int($from) ? $from : strtotime($from);
305
  * @param string $second_delimiter
306
  * @return string
307
  */
308
+ public function add_list_separators( $arr, $first_delimiter = ',', $second_delimiter = 'and' ) {
309
  $length = count($arr);
310
  $list = '';
311
  foreach ( $arr as $index => $item ) {
lib/URLHelper.php CHANGED
@@ -138,6 +138,9 @@ class URLHelper {
138
  return $path;
139
  }
140
 
 
 
 
141
  public static function file_system_to_url( $fs ) {
142
  $relative_path = self::get_rel_path($fs);
143
  $home = home_url('/'.$relative_path);
@@ -212,12 +215,14 @@ class URLHelper {
212
  /**
213
  * This will evaluate wheter a URL is at an aboslute location (like http://example.org/whatever)
214
  *
 
215
  * @return boolean true if $path is an absolute url, false if relative.
216
  */
217
  public static function is_absolute( $path ) {
218
  return (boolean) (strstr($path, 'http'));
219
  }
220
 
 
221
  /**
222
  * This function is slightly different from the one below in the case of:
223
  * an image hosted on the same domain BUT on a different site than the
@@ -232,6 +237,9 @@ class URLHelper {
232
  return $is_external;
233
  }
234
 
 
 
 
235
  private static function is_internal_content( $url ) {
236
  // using content_url() instead of site_url or home_url is IMPORTANT
237
  // otherwise you run into errors with sites that:
@@ -269,8 +277,9 @@ class URLHelper {
269
  * @return string
270
  */
271
  public static function remove_trailing_slash( $link ) {
272
- if ( $link != "/" )
273
  $link = untrailingslashit($link);
 
274
  return $link;
275
  }
276
 
138
  return $path;
139
  }
140
 
141
+ /**
142
+ * @param string $fs
143
+ */
144
  public static function file_system_to_url( $fs ) {
145
  $relative_path = self::get_rel_path($fs);
146
  $home = home_url('/'.$relative_path);
215
  /**
216
  * This will evaluate wheter a URL is at an aboslute location (like http://example.org/whatever)
217
  *
218
+ * @param string $path
219
  * @return boolean true if $path is an absolute url, false if relative.
220
  */
221
  public static function is_absolute( $path ) {
222
  return (boolean) (strstr($path, 'http'));
223
  }
224
 
225
+
226
  /**
227
  * This function is slightly different from the one below in the case of:
228
  * an image hosted on the same domain BUT on a different site than the
237
  return $is_external;
238
  }
239
 
240
+ /**
241
+ * @param string $url
242
+ */
243
  private static function is_internal_content( $url ) {
244
  // using content_url() instead of site_url or home_url is IMPORTANT
245
  // otherwise you run into errors with sites that:
277
  * @return string
278
  */
279
  public static function remove_trailing_slash( $link ) {
280
+ if ( $link != "/" ) {
281
  $link = untrailingslashit($link);
282
+ }
283
  return $link;
284
  }
285
 
lib/User.php CHANGED
@@ -68,7 +68,7 @@ class User extends Core implements CoreInterface {
68
  /**
69
  * @param int|bool $uid
70
  */
71
- function __construct( $uid = false ) {
72
  $this->init($uid);
73
  }
74
 
@@ -83,7 +83,7 @@ class User extends Core implements CoreInterface {
83
  *
84
  * @return string a fallback for TimberUser::name()
85
  */
86
- function __toString() {
87
  $name = $this->name();
88
  if ( strlen($name) ) {
89
  return $name;
@@ -99,7 +99,7 @@ class User extends Core implements CoreInterface {
99
  * @param string $field_name
100
  * @return null
101
  */
102
- function get_meta( $field_name ) {
103
  return $this->get_meta_field($field_name);
104
  }
105
 
@@ -108,7 +108,7 @@ class User extends Core implements CoreInterface {
108
  * @param string $field
109
  * @param mixed $value
110
  */
111
- function __set( $field, $value ) {
112
  if ( $field == 'name' ) {
113
  $this->display_name = $value;
114
  }
@@ -153,7 +153,7 @@ class User extends Core implements CoreInterface {
153
  * @param string $field_name
154
  * @return mixed
155
  */
156
- function get_meta_field( $field_name ) {
157
  $value = null;
158
  $value = apply_filters('timber_user_get_meta_field_pre', $value, $this->ID, $field_name, $this);
159
  if ( $value === null ) {
@@ -166,7 +166,7 @@ class User extends Core implements CoreInterface {
166
  /**
167
  * @return array|null
168
  */
169
- function get_custom() {
170
  if ( $this->ID ) {
171
  $um = array();
172
  $um = apply_filters('timber_user_get_meta_pre', $um, $this->ID, $this);
@@ -201,7 +201,7 @@ class User extends Core implements CoreInterface {
201
  * @api
202
  * @return string the human-friendly name of the user (ex: "Buster Bluth")
203
  */
204
- function name() {
205
  return $this->display_name;
206
  }
207
 
@@ -209,7 +209,7 @@ class User extends Core implements CoreInterface {
209
  * @param string $field_name
210
  * @return mixed
211
  */
212
- function meta( $field_name ) {
213
  return $this->get_meta_field($field_name);
214
  }
215
 
68
  /**
69
  * @param int|bool $uid
70
  */
71
+ public function __construct( $uid = false ) {
72
  $this->init($uid);
73
  }
74
 
83
  *
84
  * @return string a fallback for TimberUser::name()
85
  */
86
+ public function __toString() {
87
  $name = $this->name();
88
  if ( strlen($name) ) {
89
  return $name;
99
  * @param string $field_name
100
  * @return null
101
  */
102
+ public function get_meta( $field_name ) {
103
  return $this->get_meta_field($field_name);
104
  }
105
 
108
  * @param string $field
109
  * @param mixed $value
110
  */
111
+ public function __set( $field, $value ) {
112
  if ( $field == 'name' ) {
113
  $this->display_name = $value;
114
  }
153
  * @param string $field_name
154
  * @return mixed
155
  */
156
+ public function get_meta_field( $field_name ) {
157
  $value = null;
158
  $value = apply_filters('timber_user_get_meta_field_pre', $value, $this->ID, $field_name, $this);
159
  if ( $value === null ) {
166
  /**
167
  * @return array|null
168
  */
169
+ public function get_custom() {
170
  if ( $this->ID ) {
171
  $um = array();
172
  $um = apply_filters('timber_user_get_meta_pre', $um, $this->ID, $this);
201
  * @api
202
  * @return string the human-friendly name of the user (ex: "Buster Bluth")
203
  */
204
+ public function name() {
205
  return $this->display_name;
206
  }
207
 
209
  * @param string $field_name
210
  * @return mixed
211
  */
212
+ public function meta( $field_name ) {
213
  return $this->get_meta_field($field_name);
214
  }
215
 
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Contributors: jarednova, connorjburton, lggorman
3
  Tags: template engine, templates, twig
4
  Requires at least: 3.7
5
- Stable tag: 1.0.3
6
  Tested up to: 4.5.1
7
  PHP version: 5.3.0 or greater
8
  License: GPLv2 or later
@@ -41,8 +41,28 @@ Timber is great for any WordPress developer who cares about writing good, mainta
41
 
42
  == Changelog ==
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  = 1.0.2 =
45
- * Hot fix for PHP 5.3 support
 
 
 
 
46
 
47
  = 1.0.1 =
48
  * {{ user.avatar }} property is now available (thanks @connorjburton) d21eb85
2
  Contributors: jarednova, connorjburton, lggorman
3
  Tags: template engine, templates, twig
4
  Requires at least: 3.7
5
+ Stable tag: 1.0.4
6
  Tested up to: 4.5.1
7
  PHP version: 5.3.0 or greater
8
  License: GPLv2 or later
41
 
42
  == Changelog ==
43
 
44
+ = 1.0.4 =
45
+ * New method for `{{ post.type }}` this makes it easy to access things like `{{post.type.labels.name}}` right in Twig https://github.com/timber/timber/pull/1003
46
+ * New method for `{{ post.preview }}` which makes it easy to customize like `{{post.preview.length(50).read_more("Keep Reading").end('........')}}` https://github.com/timber/timber/pull/1015
47
+ * Added `Timber::get_term` (thanks @connorjburton!) 58fe671757b30a8eb9de2589bbb817448662e121
48
+ * Fix for revision issue (thanks @dknoben!) 70de6640c68a1321394aaa95202dea70e0755664
49
+ * Fix for issue with uppercase file extensions (thanks @connorjburton) 5632359329894d1b95cd643470950d319628f4c6
50
+ * Better handling for gifs (thanks @connorjburton) 91c40b852c056e0f096345d976767f2e5e993ce9
51
+ * Fix on some old class names in there (thanks @mrgrain) 63fe60ba18c6fce5d545983334af3f752c7c2755
52
+ * Pagination with post counts (thanks @lggorman) 2bcacbe50c90c7936da61d29238e3b52910a3ff9
53
+ * Remove `Timber::get_pids` (@jarednova) 4278d11d25aaca0d60cbde32c32783dc0effac6b
54
+ * Fixed deprecation in Twig (thanks @simonmilz) 6c80f1d5fd48b8fcbd335f6c8e9c6fed1b008e26
55
+ * Handle ACF image arrays (thanks @connorjburton) 039be5d880fa7f9c9763f4ebd6c40863f4820e0a
56
+
57
+ = 1.0.3 =
58
+ * Hot fix for PHP 5.3 error
59
+
60
  = 1.0.2 =
61
+ * Fixed possible infinite loop with Timber::get_context (thanks @connorjburton) 376928d59dd5f2dd2f389c61217530ba54e40b24
62
+ * Removed bug in Term (thanks @Jmayhak) a5e3c30b9eb12acea06bc914cd6b3673ead06012
63
+ * {{ user.avatar }} now returns an Image object (thanks @connorjburton) 51dd7329aee6212490daee5742280286e221f2e8
64
+ * Attention Comment Form fans! {{ post.comment_form }} now gives you a friggin' comment form 9009ac12536a0199a1bb071ac41b2e91152bef4d
65
+ * Helper\comment_form also gives you a comment form. 9009ac12536a0199a1bb071ac41b2e91152bef4d
66
 
67
  = 1.0.1 =
68
  * {{ user.avatar }} property is now available (thanks @connorjburton) d21eb85
timber.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: Timber
4
  Description: The WordPress Timber Library allows you to write themes using the power Twig templates.
5
  Plugin URI: http://timber.upstatement.com
6
  Author: Jared Novack + Upstatement
7
- Version: 1.0.3
8
  Author URI: http://upstatement.com/
9
  */
10
  // we look for Composer files first in the plugins dir.
4
  Description: The WordPress Timber Library allows you to write themes using the power Twig templates.
5
  Plugin URI: http://timber.upstatement.com
6
  Author: Jared Novack + Upstatement
7
+ Version: 1.0.4
8
  Author URI: http://upstatement.com/
9
  */
10
  // we look for Composer files first in the plugins dir.
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit7abff383b4787c8ca40e89b5be93c957::getLoader();
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit146647302270f1c55afad439213da448::getLoader();
vendor/composer/autoload_files.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- // autoload_files.php @generated by Composer, it's nice
4
 
5
  $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname($vendorDir);
1
  <?php
2
 
3
+ // autoload_files.php @generated by Composer
4
 
5
  $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname($vendorDir);
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit7abff383b4787c8ca40e89b5be93c957
6
  {
7
  private static $loader;
8
 
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit7abff383b4787c8ca40e89b5be93c957
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit7abff383b4787c8ca40e89b5be93c957', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit7abff383b4787c8ca40e89b5be93c957', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
@@ -42,14 +42,14 @@ class ComposerAutoloaderInit7abff383b4787c8ca40e89b5be93c957
42
 
43
  $includeFiles = require __DIR__ . '/autoload_files.php';
44
  foreach ($includeFiles as $fileIdentifier => $file) {
45
- composerRequire7abff383b4787c8ca40e89b5be93c957($fileIdentifier, $file);
46
  }
47
 
48
  return $loader;
49
  }
50
  }
51
 
52
- function composerRequire7abff383b4787c8ca40e89b5be93c957($fileIdentifier, $file)
53
  {
54
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
55
  require $file;
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit146647302270f1c55afad439213da448
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit146647302270f1c55afad439213da448', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit146647302270f1c55afad439213da448', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
42
 
43
  $includeFiles = require __DIR__ . '/autoload_files.php';
44
  foreach ($includeFiles as $fileIdentifier => $file) {
45
+ composerRequire146647302270f1c55afad439213da448($fileIdentifier, $file);
46
  }
47
 
48
  return $loader;
49
  }
50
  }
51
 
52
+ function composerRequire146647302270f1c55afad439213da448($fileIdentifier, $file)
53
  {
54
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
55
  require $file;