1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* 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. |
5
|
|
|
* @example |
6
|
|
|
* ```php |
7
|
|
|
* <?php |
8
|
|
|
* // single.php, see connected twig example |
9
|
|
|
* $context = Timber::get_context(); |
10
|
|
|
* $context['post'] = new TimberPost(); // It's a new TimberPost object, but an existing post from WordPress. |
11
|
|
|
* Timber::render('single.twig', $context); |
12
|
|
|
* ?> |
13
|
|
|
* ``` |
14
|
|
|
* ```twig |
15
|
|
|
* {# single.twig #} |
16
|
|
|
* <article> |
17
|
|
|
* <h1 class="headline">{{post.title}}</h1> |
18
|
|
|
* <div class="body"> |
19
|
|
|
* {{post.content}} |
20
|
|
|
* </div> |
21
|
|
|
* </article> |
22
|
|
|
* ``` |
23
|
|
|
* |
24
|
|
|
* ```html |
25
|
|
|
* <article> |
26
|
|
|
* <h1 class="headline">The Empire Strikes Back</h1> |
27
|
|
|
* <div class="body"> |
28
|
|
|
* It is a dark time for the Rebellion. Although the Death Star has been destroyed, Imperial troops have driven the Rebel forces from their hidden base and pursued them across the galaxy. |
29
|
|
|
* </div> |
30
|
|
|
* </article> |
31
|
|
|
* ``` |
32
|
|
|
* |
33
|
|
|
* @package Timber |
34
|
|
|
*/ |
35
|
|
|
class TimberPost extends TimberCore implements TimberCoreInterface { |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @var string $ImageClass the name of the class to handle images by default |
39
|
|
|
*/ |
40
|
|
|
public $ImageClass = 'TimberImage'; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @var string $PostClass the name of the class to handle posts by default |
44
|
|
|
*/ |
45
|
|
|
public $PostClass = 'TimberPost'; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var string $TermClass the name of the class to handle terms by default |
49
|
|
|
*/ |
50
|
|
|
public $TermClass = 'TimberTerm'; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @var string $object_type what does this class represent in WordPress terms? |
54
|
|
|
*/ |
55
|
|
|
public $object_type = 'post'; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* @var string $representation what does this class represent in WordPress terms? |
59
|
|
|
*/ |
60
|
|
|
public static $representation = 'post'; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* @internal |
64
|
|
|
* @var string $_content stores the processed content internally |
65
|
|
|
*/ |
66
|
|
|
protected $_content; |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* @internal |
70
|
|
|
* @var array $_get_terms stores the results of a get_terms method call |
71
|
|
|
* @deprecated |
72
|
|
|
*/ |
73
|
|
|
protected $_get_terms; |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @var string $_permalink the returned permalink from WP's get_permalink function |
77
|
|
|
*/ |
78
|
|
|
protected $_permalink; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @var array $_next stores the results of the next TimberPost in a set inside an array (in order to manage by-taxonomy) |
82
|
|
|
*/ |
83
|
|
|
protected $_next = array(); |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* @var array $_prev stores the results of the previous TimberPost in a set inside an array (in order to manage by-taxonomy) |
87
|
|
|
*/ |
88
|
|
|
protected $_prev = array(); |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @api |
92
|
|
|
* @var string $class stores the CSS classes for the post (ex: "post post-type-book post-123") |
93
|
|
|
*/ |
94
|
|
|
public $class; |
95
|
|
|
|
96
|
|
|
/** |
97
|
|
|
* @api |
98
|
|
|
* @var string $id the numeric WordPress id of a post |
99
|
|
|
*/ |
100
|
|
|
public $id; |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* @var string $ID the numeric WordPress id of a post, capitalized to match WP usage |
104
|
|
|
*/ |
105
|
|
|
public $ID; |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* @var int $post_author the numeric ID of the a post's author corresponding to the wp_user dtable |
109
|
|
|
*/ |
110
|
|
|
public $post_author; |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* @var string $post_content the raw text of a WP post as stored in the database |
114
|
|
|
*/ |
115
|
|
|
public $post_content; |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* @var string $post_date the raw date string as stored in the WP database, ex: 2014-07-05 18:01:39 |
119
|
|
|
*/ |
120
|
|
|
public $post_date; |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* @var string $post_exceprt the raw text of a manual post exceprt as stored in the database |
124
|
|
|
*/ |
125
|
|
|
public $post_excerpt; |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* @var int $post_parent the numeric ID of a post's parent post |
129
|
|
|
*/ |
130
|
|
|
public $post_parent; |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* @api |
134
|
|
|
* @var string $post_status the status of a post ("draft", "publish", etc.) |
135
|
|
|
*/ |
136
|
|
|
public $post_status; |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* @var string $post_title the raw text of a post's title as stored in the database |
140
|
|
|
*/ |
141
|
|
|
public $post_title; |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* @api |
145
|
|
|
* @var string $post_type the name of the post type, this is the machine name (so "my_custom_post_type" as opposed to "My Custom Post Type") |
146
|
|
|
*/ |
147
|
|
|
public $post_type; |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* @api |
151
|
|
|
* @var string $slug the URL-safe slug, this corresponds to the poorly-named "post_name" in the WP database, ex: "hello-world" |
152
|
|
|
*/ |
153
|
|
|
public $slug; |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* If you send the constructor nothing it will try to figure out the current post id based on being inside The_Loop |
157
|
|
|
* @example |
158
|
|
|
* ```php |
159
|
|
|
* $post = new TimberPost(); |
160
|
|
|
* $other_post = new TimberPost($random_post_id); |
161
|
|
|
* ``` |
162
|
|
|
* @param mixed $pid |
163
|
|
|
*/ |
164
|
|
|
public function __construct($pid = null) { |
165
|
|
|
$pid = $this->determine_id( $pid ); |
166
|
|
|
$this->init($pid); |
|
|
|
|
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* tries to figure out what post you want to get if not explictly defined (or if it is, allows it to be passed through) |
171
|
|
|
* @internal |
172
|
|
|
* @param mixed a value to test against |
173
|
|
|
* @return int the numberic id we should be using for this post object |
174
|
|
|
*/ |
175
|
|
|
protected function determine_id($pid) { |
176
|
|
|
global $wp_query; |
177
|
|
|
if ( $pid === null && |
|
|
|
|
178
|
|
|
isset($wp_query->queried_object_id) |
|
|
|
|
179
|
|
|
&& $wp_query->queried_object_id |
180
|
|
|
&& isset($wp_query->queried_object) |
|
|
|
|
181
|
|
|
&& is_object($wp_query->queried_object) |
|
|
|
|
182
|
|
|
&& get_class($wp_query->queried_object) == 'WP_Post' |
|
|
|
|
183
|
|
|
) { |
184
|
|
|
if( isset( $_GET['preview'] ) && isset( $_GET['preview_nonce'] ) && wp_verify_nonce( $_GET['preview_nonce'], 'post_preview_' . $wp_query->queried_object_id ) ) { |
|
|
|
|
185
|
|
|
$pid = $this->get_post_preview_id( $wp_query ); |
186
|
|
|
} else if ( !$pid ) { |
|
|
|
|
187
|
|
|
$pid = $wp_query->queried_object_id; |
188
|
|
|
} |
189
|
|
|
} else if ( $pid === null && $wp_query->is_home && isset($wp_query->queried_object_id) && $wp_query->queried_object_id ) { |
|
|
|
|
190
|
|
|
//hack for static page as home page |
191
|
|
|
$pid = $wp_query->queried_object_id; |
192
|
|
|
} else if ( $pid === null ) { |
193
|
|
|
$gtid = false; |
194
|
|
|
$maybe_post = get_post(); |
195
|
|
|
if ( isset($maybe_post->ID) ){ |
|
|
|
|
196
|
|
|
$gtid = true; |
197
|
|
|
} |
198
|
|
|
if ( $gtid ) { |
199
|
|
|
$pid = get_the_ID(); |
200
|
|
|
} |
201
|
|
|
if ( !$pid ) { |
|
|
|
|
202
|
|
|
global $wp_query; |
203
|
|
|
if ( isset($wp_query->query['p']) ) { |
|
|
|
|
204
|
|
|
$pid = $wp_query->query['p']; |
205
|
|
|
} |
206
|
|
|
} |
207
|
|
|
} |
208
|
|
|
if ( $pid === null && ($pid_from_loop = TimberPostGetter::loop_to_id()) ) { |
209
|
|
|
$pid = $pid_from_loop; |
210
|
|
|
} |
211
|
|
|
return $pid; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Outputs the title of the post if you do something like `<h1>{{post}}</h1>` |
216
|
|
|
* @return string |
217
|
|
|
*/ |
218
|
|
|
public function __toString() { |
219
|
|
|
return $this->title(); |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
protected function get_post_preview_id( $query ) { |
223
|
|
|
$can = array( |
224
|
|
|
'edit_' . $query->queried_object->post_type . 's', |
225
|
|
|
); |
226
|
|
|
|
227
|
|
|
if ( $query->queried_object->author_id !== get_current_user_id() ) { |
228
|
|
|
$can[] = 'edit_others_' . $query->queried_object->post_type . 's'; |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
$can_preview = false; |
232
|
|
|
|
233
|
|
|
foreach( $can as $type ) { |
|
|
|
|
234
|
|
|
if( current_user_can( $type ) ) { |
|
|
|
|
235
|
|
|
$can_preview = true; |
236
|
|
|
break; |
237
|
|
|
} |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
if ( !$can_preview ) { |
|
|
|
|
241
|
|
|
return; |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
$revisions = wp_get_post_revisions( $query->queried_object_id ); |
245
|
|
|
|
246
|
|
|
if( !empty( $revisions ) ) { |
|
|
|
|
247
|
|
|
$last = end($revisions); |
|
|
|
|
248
|
|
|
return $last->ID; |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
return false; |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* Initializes a TimberPost |
256
|
|
|
* @internal |
257
|
|
|
* @param int|bool $pid |
258
|
|
|
*/ |
259
|
|
|
protected function init($pid = false) { |
260
|
|
|
if ( $pid === false ) { |
|
|
|
|
261
|
|
|
$pid = get_the_ID(); |
262
|
|
|
} |
263
|
|
|
if ( is_numeric($pid) ) { |
|
|
|
|
264
|
|
|
$this->ID = $pid; |
|
|
|
|
265
|
|
|
} |
266
|
|
|
$post_info = $this->get_info($pid); |
|
|
|
|
267
|
|
|
$this->import($post_info); |
|
|
|
|
268
|
|
|
//cant have a function, so gots to do it this way |
269
|
|
|
$post_class = $this->post_class(); |
270
|
|
|
$this->class = $post_class; |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* Get the URL that will edit the current post/object |
275
|
|
|
* @internal |
276
|
|
|
* @see TimberPost::edit_link |
277
|
|
|
* @return bool|string |
278
|
|
|
*/ |
279
|
|
|
function get_edit_url() { |
|
|
|
|
280
|
|
|
if ( $this->can_edit() ) { |
281
|
|
|
return get_edit_post_link($this->ID); |
|
|
|
|
282
|
|
|
} |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
/** |
286
|
|
|
* updates the post_meta of the current object with the given value |
287
|
|
|
* @param string $field |
288
|
|
|
* @param mixed $value |
289
|
|
|
*/ |
290
|
|
|
public function update( $field, $value ) { |
291
|
|
|
if ( isset($this->ID) ) { |
|
|
|
|
292
|
|
|
update_post_meta($this->ID, $field, $value); |
|
|
|
|
293
|
|
|
$this->$field = $value; |
294
|
|
|
} |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
|
298
|
|
|
/** |
299
|
|
|
* takes a mix of integer (post ID), string (post slug), |
300
|
|
|
* or object to return a WordPress post object from WP's built-in get_post() function |
301
|
|
|
* @internal |
302
|
|
|
* @param mixed $pid |
303
|
|
|
* @return WP_Post on success |
304
|
|
|
*/ |
305
|
|
|
protected function prepare_post_info( $pid = 0 ) { |
306
|
|
|
if ( is_string($pid) || is_numeric($pid) || (is_object($pid) && !isset($pid->post_title)) || $pid === 0 ) { |
|
|
|
|
307
|
|
|
$pid = self::check_post_id($pid); |
|
|
|
|
308
|
|
|
$post = get_post($pid); |
|
|
|
|
309
|
|
|
if ( $post ) { |
310
|
|
|
return $post; |
311
|
|
|
} |
312
|
|
|
} |
313
|
|
|
//we can skip if already is WP_Post |
314
|
|
|
return $pid; |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
|
318
|
|
|
/** |
319
|
|
|
* helps you find the post id regardless of whether you send a string or whatever |
320
|
|
|
* @param integer $pid ; |
321
|
|
|
* @internal |
322
|
|
|
* @return integer ID number of a post |
323
|
|
|
*/ |
324
|
|
|
protected function check_post_id( $pid ) { |
325
|
|
|
if ( is_numeric($pid) && $pid === 0 ) { |
|
|
|
|
326
|
|
|
$pid = get_the_ID(); |
327
|
|
|
return $pid; |
328
|
|
|
} |
329
|
|
|
if ( !is_numeric($pid) && is_string($pid) ) { |
|
|
|
|
330
|
|
|
$pid = self::get_post_id_by_name($pid); |
|
|
|
|
331
|
|
|
return $pid; |
332
|
|
|
} |
333
|
|
|
if ( !$pid ) { |
|
|
|
|
334
|
|
|
return null; |
335
|
|
|
} |
336
|
|
|
return $pid; |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
|
340
|
|
|
/** |
341
|
|
|
* get_post_id_by_name($post_name) |
342
|
|
|
* @internal |
343
|
|
|
* @param string $post_name |
344
|
|
|
* @return int |
345
|
|
|
*/ |
346
|
|
|
static function get_post_id_by_name($post_name) { |
|
|
|
|
347
|
|
|
global $wpdb; |
348
|
|
|
$query = $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_name = %s LIMIT 1", $post_name); |
|
|
|
|
349
|
|
|
$result = $wpdb->get_row($query); |
|
|
|
|
350
|
|
|
if (!$result) { |
|
|
|
|
351
|
|
|
return null; |
352
|
|
|
} |
353
|
|
|
return $result->ID; |
354
|
|
|
} |
355
|
|
|
|
356
|
|
|
/** |
357
|
|
|
* get a preview of your post, if you have an excerpt it will use that, |
358
|
|
|
* otherwise it will pull from the post_content. |
359
|
|
|
* If there's a <!-- more --> tag it will use that to mark where to pull through. |
360
|
|
|
* @api |
361
|
|
|
* @example |
362
|
|
|
* ```twig |
363
|
|
|
* <p>{{post.get_preview(50)}}</p> |
364
|
|
|
* ``` |
365
|
|
|
* @param int $len The number of words that WP should use to make the tease. (Isn't this better than [this mess](http://wordpress.org/support/topic/changing-the-default-length-of-the_excerpt-1?replies=14)?). If you've set a post_excerpt on a post, we'll use that for the preview text; otherwise the first X words of the post_content |
366
|
|
|
* @param bool $force What happens if your custom post excerpt is longer then the length requested? By default (`$force = false`) it will use the full `post_excerpt`. However, you can set this to true to *force* your excerpt to be of the desired length |
367
|
|
|
* @param string $readmore The text you want to use on the 'readmore' link |
368
|
|
|
* @param bool $strip true for default, false for none, string for list of custom attributes |
369
|
|
|
* @param string $end The text to end the preview with (defaults to ...) |
370
|
|
|
* @return string of the post preview |
371
|
|
|
*/ |
372
|
|
|
function get_preview($len = 50, $force = false, $readmore = 'Read More', $strip = true, $end = '…') { |
|
|
|
|
373
|
|
|
$text = ''; |
374
|
|
|
$trimmed = false; |
375
|
|
|
if ( isset($this->post_excerpt) && strlen($this->post_excerpt) ) { |
|
|
|
|
376
|
|
|
if ( $force ) { |
377
|
|
|
$text = TimberHelper::trim_words($this->post_excerpt, $len, false); |
|
|
|
|
378
|
|
|
$trimmed = true; |
379
|
|
|
} else { |
380
|
|
|
$text = $this->post_excerpt; |
381
|
|
|
} |
382
|
|
|
} |
383
|
|
|
if ( !strlen($text) && preg_match('/<!--\s?more(.*?)?-->/', $this->post_content, $readmore_matches) ) { |
|
|
|
|
384
|
|
|
$pieces = explode($readmore_matches[0], $this->post_content); |
|
|
|
|
385
|
|
|
$text = $pieces[0]; |
386
|
|
|
if ( $force ) { |
387
|
|
|
$text = TimberHelper::trim_words($text, $len, false); |
|
|
|
|
388
|
|
|
$trimmed = true; |
389
|
|
|
} |
390
|
|
|
$text = do_shortcode( $text ); |
391
|
|
|
} |
392
|
|
|
if ( !strlen($text) ) { |
|
|
|
|
393
|
|
|
$text = TimberHelper::trim_words($this->get_content(), $len, false); |
|
|
|
|
394
|
|
|
$trimmed = true; |
395
|
|
|
} |
396
|
|
|
if ( !strlen(trim($text)) ) { |
|
|
|
|
397
|
|
|
return trim($text); |
|
|
|
|
398
|
|
|
} |
399
|
|
|
if ( $strip ) { |
400
|
|
|
$allowable_tags = (is_string($strip)) ? $strip : null; |
|
|
|
|
401
|
|
|
$text = trim(strip_tags($text, $allowable_tags)); |
|
|
|
|
402
|
|
|
} |
403
|
|
|
if ( strlen($text) ) { |
|
|
|
|
404
|
|
|
$text = trim($text); |
|
|
|
|
405
|
|
|
$last = $text[strlen($text) - 1]; |
|
|
|
|
406
|
|
|
if ( $last != '.' && $trimmed ) { |
407
|
|
|
$text .= $end; |
408
|
|
|
} |
409
|
|
|
if ( !$strip ) { |
|
|
|
|
410
|
|
|
$last_p_tag = strrpos($text, '</p>'); |
|
|
|
|
411
|
|
|
if ( $last_p_tag !== false ) { |
|
|
|
|
412
|
|
|
$text = substr($text, 0, $last_p_tag); |
|
|
|
|
413
|
|
|
} |
414
|
|
|
if ( $last != '.' && $trimmed ) { |
415
|
|
|
$text .= $end . ' '; |
416
|
|
|
} |
417
|
|
|
} |
418
|
|
|
$read_more_class = apply_filters('timber/post/get_preview/read_more_class', "read-more"); |
|
|
|
|
419
|
|
|
if ( $readmore && isset($readmore_matches) && !empty($readmore_matches[1]) ) { |
|
|
|
|
420
|
|
|
$text .= ' <a href="' . $this->get_permalink() . '" class="'.$read_more_class .'">' . trim($readmore_matches[1]) . '</a>'; |
|
|
|
|
421
|
|
|
} elseif ( $readmore ) { |
422
|
|
|
$text .= ' <a href="' . $this->get_permalink() . '" class="'.$read_more_class .'">' . trim($readmore) . '</a>'; |
|
|
|
|
423
|
|
|
} |
424
|
|
|
if ( !$strip && $last_p_tag && ( strpos($text, '<p>') || strpos($text, '<p ') ) ) { |
|
|
|
|
425
|
|
|
$text .= '</p>'; |
426
|
|
|
} |
427
|
|
|
} |
428
|
|
|
return trim($text); |
|
|
|
|
429
|
|
|
} |
430
|
|
|
|
431
|
|
|
/** |
432
|
|
|
* gets the post custom and attaches it to the current object |
433
|
|
|
* @internal |
434
|
|
|
* @param bool|int $pid a post ID number |
435
|
|
|
*/ |
436
|
|
|
function import_custom( $pid = false ) { |
|
|
|
|
437
|
|
|
if ( !$pid ) { |
|
|
|
|
438
|
|
|
$pid = $this->ID; |
439
|
|
|
} |
440
|
|
|
$customs = $this->get_post_custom($pid); |
|
|
|
|
441
|
|
|
$this->import($customs); |
|
|
|
|
442
|
|
|
} |
443
|
|
|
|
444
|
|
|
/** |
445
|
|
|
* Used internally to fetch the metadata fields (wp_postmeta table) |
446
|
|
|
* and attach them to our TimberPost object |
447
|
|
|
* @internal |
448
|
|
|
* @param int $pid |
449
|
|
|
* @return array |
450
|
|
|
*/ |
451
|
|
|
protected function get_post_custom( $pid ) { |
452
|
|
|
apply_filters('timber_post_get_meta_pre', array(), $pid, $this); |
|
|
|
|
453
|
|
|
$customs = get_post_custom($pid); |
|
|
|
|
454
|
|
|
if ( !is_array($customs) || empty($customs) ) { |
|
|
|
|
455
|
|
|
return array(); |
456
|
|
|
} |
457
|
|
View Code Duplication |
foreach ( $customs as $key => $value ) { |
|
|
|
|
458
|
|
|
if ( is_array($value) && count($value) == 1 && isset($value[0]) ) { |
|
|
|
|
459
|
|
|
$value = $value[0]; |
460
|
|
|
} |
461
|
|
|
$customs[$key] = maybe_unserialize($value); |
|
|
|
|
462
|
|
|
} |
463
|
|
|
$customs = apply_filters('timber_post_get_meta', $customs, $pid, $this); |
|
|
|
|
464
|
|
|
return $customs; |
465
|
|
|
} |
466
|
|
|
|
467
|
|
|
/** |
468
|
|
|
* @internal |
469
|
|
|
* @see TimberPost::thumbnail |
470
|
|
|
* @return null|TimberImage |
|
|
|
|
471
|
|
|
*/ |
472
|
|
|
function get_thumbnail() { |
|
|
|
|
473
|
|
|
if ( function_exists('get_post_thumbnail_id') ) { |
|
|
|
|
474
|
|
|
$tid = get_post_thumbnail_id($this->ID); |
|
|
|
|
475
|
|
|
if ( $tid ) { |
476
|
|
|
return new $this->ImageClass($tid); |
|
|
|
|
477
|
|
|
} |
478
|
|
|
} |
479
|
|
|
} |
480
|
|
|
|
481
|
|
|
/** |
482
|
|
|
* @internal |
483
|
|
|
* @see TimberPost::link |
484
|
|
|
* @return string |
485
|
|
|
*/ |
486
|
|
|
function get_permalink() { |
|
|
|
|
487
|
|
|
if ( isset($this->_permalink) ) { |
|
|
|
|
488
|
|
|
return $this->_permalink; |
489
|
|
|
} |
490
|
|
|
$this->_permalink = get_permalink($this->ID); |
|
|
|
|
491
|
|
|
return $this->_permalink; |
492
|
|
|
} |
493
|
|
|
|
494
|
|
|
/** |
495
|
|
|
* get the permalink for a post object |
496
|
|
|
* In your templates you should use link: |
497
|
|
|
* <a href="{{post.link}}">Read my post</a> |
498
|
|
|
* @internal |
499
|
|
|
* @return string |
500
|
|
|
*/ |
501
|
|
|
function get_link() { |
|
|
|
|
502
|
|
|
return $this->get_permalink(); |
503
|
|
|
} |
504
|
|
|
|
505
|
|
|
/** |
506
|
|
|
* Get the next post in WordPress's ordering |
507
|
|
|
* @internal |
508
|
|
|
* @param bool $taxonomy |
509
|
|
|
* @return TimberPost|boolean |
510
|
|
|
*/ |
511
|
|
|
function get_next( $taxonomy = false ) { |
|
|
|
|
512
|
|
|
if ( !isset($this->_next) || !isset($this->_next[$taxonomy]) ) { |
|
|
|
|
513
|
|
|
global $post; |
514
|
|
|
$this->_next = array(); |
515
|
|
|
$old_global = $post; |
516
|
|
|
$post = $this; |
|
|
|
|
517
|
|
|
if ( $taxonomy ) { |
518
|
|
|
$adjacent = get_adjacent_post(true, '', false, $taxonomy); |
|
|
|
|
519
|
|
|
} else { |
520
|
|
|
$adjacent = get_adjacent_post(false, '', false); |
|
|
|
|
521
|
|
|
} |
522
|
|
|
|
523
|
|
|
if ( $adjacent ) { |
524
|
|
|
$this->_next[$taxonomy] = new $this->PostClass($adjacent); |
|
|
|
|
525
|
|
|
} else { |
526
|
|
|
$this->_next[$taxonomy] = false; |
|
|
|
|
527
|
|
|
} |
528
|
|
|
$post = $old_global; |
|
|
|
|
529
|
|
|
} |
530
|
|
|
return $this->_next[$taxonomy]; |
|
|
|
|
531
|
|
|
} |
532
|
|
|
|
533
|
|
|
/** |
534
|
|
|
* Get a data array of pagination so you can navigate to the previous/next for a paginated post |
535
|
|
|
* @return array |
536
|
|
|
*/ |
537
|
|
|
public function get_pagination() { |
538
|
|
|
global $post, $page, $numpages, $multipage; |
539
|
|
|
$post = $this; |
|
|
|
|
540
|
|
|
$ret = array(); |
541
|
|
|
if ( $multipage ) { |
542
|
|
|
for ( $i = 1; $i <= $numpages; $i++ ) { |
543
|
|
|
$link = self::get_wp_link_page($i); |
|
|
|
|
544
|
|
|
$data = array('name' => $i, 'title' => $i, 'text' => $i, 'link' => $link); |
|
|
|
|
545
|
|
|
if ( $i == $page ) { |
546
|
|
|
$data['current'] = true; |
547
|
|
|
} |
548
|
|
|
$ret['pages'][] = $data; |
549
|
|
|
} |
550
|
|
|
$i = $page - 1; |
551
|
|
|
if ( $i ) { |
552
|
|
|
$link = self::get_wp_link_page($i); |
|
|
|
|
553
|
|
|
$ret['prev'] = array('link' => $link); |
|
|
|
|
554
|
|
|
} |
555
|
|
|
$i = $page + 1; |
556
|
|
|
if ( $i <= $numpages ) { |
557
|
|
|
$link = self::get_wp_link_page($i); |
|
|
|
|
558
|
|
|
$ret['next'] = array('link' => $link); |
|
|
|
|
559
|
|
|
} |
560
|
|
|
} |
561
|
|
|
return $ret; |
562
|
|
|
} |
563
|
|
|
|
564
|
|
|
/** |
565
|
|
|
* @param int $i |
566
|
|
|
* @return string |
567
|
|
|
*/ |
568
|
|
|
protected static function get_wp_link_page($i) { |
569
|
|
|
$link = _wp_link_page($i); |
|
|
|
|
570
|
|
|
$link = new SimpleXMLElement($link . '</a>'); |
|
|
|
|
571
|
|
|
if ( isset($link['href']) ) { |
|
|
|
|
572
|
|
|
return $link['href']; |
573
|
|
|
} |
574
|
|
|
return ''; |
575
|
|
|
} |
576
|
|
|
|
577
|
|
|
/** |
578
|
|
|
* Get the permalink for a post, but as a relative path |
579
|
|
|
* For example, where {{post.link}} would return "http://example.org/2015/07/04/my-cool-post" |
580
|
|
|
* this will return the relative version: "/2015/07/04/my-cool-post" |
581
|
|
|
* @internal |
582
|
|
|
* @return string |
583
|
|
|
*/ |
584
|
|
|
function get_path() { |
|
|
|
|
585
|
|
|
return TimberURLHelper::get_rel_url($this->get_link()); |
|
|
|
|
586
|
|
|
} |
587
|
|
|
|
588
|
|
|
/** |
589
|
|
|
* Get the next post in WordPress's ordering |
590
|
|
|
* @internal |
591
|
|
|
* @param bool $taxonomy |
592
|
|
|
* @return TimberPost|boolean |
593
|
|
|
*/ |
594
|
|
|
function get_prev( $taxonomy = false ) { |
|
|
|
|
595
|
|
|
if ( isset($this->_prev) && isset($this->_prev[$taxonomy]) ) { |
|
|
|
|
596
|
|
|
return $this->_prev[$taxonomy]; |
|
|
|
|
597
|
|
|
} |
598
|
|
|
global $post; |
599
|
|
|
$old_global = $post; |
600
|
|
|
$post = $this; |
|
|
|
|
601
|
|
|
$within_taxonomy = ($taxonomy) ? $taxonomy : 'category'; |
602
|
|
|
$adjacent = get_adjacent_post(($taxonomy), '', true, $within_taxonomy); |
|
|
|
|
603
|
|
|
$prev_in_taxonomy = false; |
604
|
|
|
if ( $adjacent ) { |
605
|
|
|
$prev_in_taxonomy = new $this->PostClass($adjacent); |
|
|
|
|
606
|
|
|
} |
607
|
|
|
$this->_prev[$taxonomy] = $prev_in_taxonomy; |
|
|
|
|
608
|
|
|
$post = $old_global; |
|
|
|
|
609
|
|
|
return $this->_prev[$taxonomy]; |
|
|
|
|
610
|
|
|
} |
611
|
|
|
|
612
|
|
|
/** |
613
|
|
|
* Get the parent post of the post |
614
|
|
|
* @internal |
615
|
|
|
* @return bool|TimberPost |
|
|
|
|
616
|
|
|
*/ |
617
|
|
|
function get_parent() { |
|
|
|
|
618
|
|
|
if ( !$this->post_parent ) { |
|
|
|
|
619
|
|
|
return false; |
620
|
|
|
} |
621
|
|
|
return new $this->PostClass($this->post_parent); |
|
|
|
|
622
|
|
|
} |
623
|
|
|
|
624
|
|
|
/** |
625
|
|
|
* Gets a User object from the author of the post |
626
|
|
|
* @internal |
627
|
|
|
* @see TimberPost::author |
628
|
|
|
* @return bool|TimberUser |
|
|
|
|
629
|
|
|
*/ |
630
|
|
|
function get_author() { |
|
|
|
|
631
|
|
|
if ( isset($this->post_author) ) { |
|
|
|
|
632
|
|
|
return new TimberUser($this->post_author); |
|
|
|
|
633
|
|
|
} |
634
|
|
|
} |
635
|
|
|
|
636
|
|
|
/** |
637
|
|
|
* @internal |
638
|
|
|
* @return bool|TimberUser |
|
|
|
|
639
|
|
|
*/ |
640
|
|
|
function get_modified_author() { |
|
|
|
|
641
|
|
|
$user_id = get_post_meta($this->ID, '_edit_last', true); |
|
|
|
|
642
|
|
|
return ($user_id ? new TimberUser($user_id) : $this->get_author()); |
|
|
|
|
643
|
|
|
} |
644
|
|
|
|
645
|
|
|
/** |
646
|
|
|
* Used internally by init, etc. to build TimberPost object |
647
|
|
|
* @internal |
648
|
|
|
* @param int $pid |
649
|
|
|
* @return null|object|WP_Post |
650
|
|
|
*/ |
651
|
|
|
protected function get_info($pid) { |
652
|
|
|
$post = $this->prepare_post_info($pid); |
|
|
|
|
653
|
|
|
if ( !isset($post->post_status) ) { |
|
|
|
|
654
|
|
|
return null; |
655
|
|
|
} |
656
|
|
|
$post->status = $post->post_status; |
657
|
|
|
$post->id = $post->ID; |
658
|
|
|
$post->slug = $post->post_name; |
659
|
|
|
$customs = $this->get_post_custom($post->ID); |
|
|
|
|
660
|
|
|
$post->custom = $customs; |
661
|
|
|
$post = (object) array_merge((array)$customs, (array)$post); |
|
|
|
|
662
|
|
|
return $post; |
663
|
|
|
} |
664
|
|
|
|
665
|
|
|
/** |
666
|
|
|
* @internal |
667
|
|
|
* @see TimberPost::date |
668
|
|
|
* @param string $date_format |
669
|
|
|
* @return string |
670
|
|
|
*/ |
671
|
|
|
function get_date( $date_format = '' ) { |
|
|
|
|
672
|
|
|
$df = $date_format ? $date_format : get_option('date_format'); |
|
|
|
|
673
|
|
|
$the_date = (string)mysql2date($df, $this->post_date); |
|
|
|
|
674
|
|
|
return apply_filters('get_the_date', $the_date, $df); |
|
|
|
|
675
|
|
|
} |
676
|
|
|
|
677
|
|
|
/** |
678
|
|
|
* @internal |
679
|
|
|
* @param string $date_format |
680
|
|
|
* @return string |
681
|
|
|
*/ |
682
|
|
|
function get_modified_date( $date_format = '' ) { |
|
|
|
|
683
|
|
|
$df = $date_format ? $date_format : get_option('date_format'); |
|
|
|
|
684
|
|
|
$the_time = $this->get_modified_time($df); |
|
|
|
|
685
|
|
|
return apply_filters('get_the_modified_date', $the_time, $date_format); |
|
|
|
|
686
|
|
|
} |
687
|
|
|
|
688
|
|
|
/** |
689
|
|
|
* @internal |
690
|
|
|
* @param string $time_format |
691
|
|
|
* @return string |
692
|
|
|
*/ |
693
|
|
|
function get_modified_time( $time_format = '' ) { |
|
|
|
|
694
|
|
|
$tf = $time_format ? $time_format : get_option('time_format'); |
|
|
|
|
695
|
|
|
$the_time = get_post_modified_time($tf, false, $this->ID, true); |
|
|
|
|
696
|
|
|
return apply_filters('get_the_modified_time', $the_time, $time_format); |
|
|
|
|
697
|
|
|
} |
698
|
|
|
|
699
|
|
|
/** |
700
|
|
|
* @internal |
701
|
|
|
* @see TimberPost::children |
702
|
|
|
* @param string $post_type |
703
|
|
|
* @param bool|string $childPostClass |
704
|
|
|
* @return array |
705
|
|
|
*/ |
706
|
|
|
function get_children( $post_type = 'any', $childPostClass = false ) { |
|
|
|
|
707
|
|
|
if ( $childPostClass === false ) { |
|
|
|
|
708
|
|
|
$childPostClass = $this->PostClass; |
709
|
|
|
} |
710
|
|
|
if ( $post_type == 'parent' ) { |
|
|
|
|
711
|
|
|
$post_type = $this->post_type; |
712
|
|
|
} |
713
|
|
|
$children = get_children('post_parent=' . $this->ID . '&post_type=' . $post_type . '&numberposts=-1&orderby=menu_order title&order=ASC&post_status=publish'); |
|
|
|
|
714
|
|
|
foreach ( $children as &$child ) { |
715
|
|
|
$child = new $childPostClass($child->ID); |
716
|
|
|
} |
717
|
|
|
$children = array_values($children); |
|
|
|
|
718
|
|
|
return $children; |
719
|
|
|
} |
720
|
|
|
|
721
|
|
|
|
722
|
|
|
/** |
723
|
|
|
* Get the comments for a post |
724
|
|
|
* @internal |
725
|
|
|
* @see TimberPost::comments |
726
|
|
|
* @param int $ct |
727
|
|
|
* @param string $order |
728
|
|
|
* @param string $type |
729
|
|
|
* @param string $status |
730
|
|
|
* @param string $CommentClass |
731
|
|
|
* @return array|mixed |
732
|
|
|
*/ |
733
|
|
|
|
734
|
|
|
function get_comments($ct = 0, $order = 'wp', $type = 'comment', $status = 'approve', $CommentClass = 'TimberComment') { |
|
|
|
|
735
|
|
|
|
736
|
|
|
global $overridden_cpage, $user_ID; |
737
|
|
|
$overridden_cpage = false; |
|
|
|
|
738
|
|
|
|
739
|
|
|
$commenter = wp_get_current_commenter(); |
740
|
|
|
$comment_author_email = $commenter['comment_author_email']; |
741
|
|
|
|
742
|
|
|
$args = array('post_id' => $this->ID, 'status' => $status, 'order' => $order); |
|
|
|
|
743
|
|
|
if ( $ct > 0 ) { |
744
|
|
|
$args['number'] = $ct; |
745
|
|
|
} |
746
|
|
|
if ( strtolower($order) == 'wp' || strtolower($order) == 'wordpress' ) { |
|
|
|
|
747
|
|
|
$args['order'] = get_option('comment_order'); |
|
|
|
|
748
|
|
|
} |
749
|
|
|
|
750
|
|
|
if ( $user_ID ) { |
751
|
|
|
$args['include_unapproved'] = array( $user_ID ); |
752
|
|
|
} elseif ( ! empty( $comment_author_email ) ) { |
753
|
|
|
$args['include_unapproved'] = array( $comment_author_email ); |
754
|
|
|
} |
755
|
|
|
|
756
|
|
|
$comments = get_comments($args); |
|
|
|
|
757
|
|
|
$timber_comments = array(); |
758
|
|
|
|
759
|
|
|
if ( '' == get_query_var('cpage') && get_option('page_comments') ) { |
|
|
|
|
760
|
|
|
set_query_var( 'cpage', 'newest' == get_option('default_comments_page') ? get_comment_pages_count() : 1 ); |
|
|
|
|
761
|
|
|
$overridden_cpage = true; |
|
|
|
|
762
|
|
|
} |
763
|
|
|
|
764
|
|
|
foreach($comments as $key => &$comment) { |
|
|
|
|
765
|
|
|
$timber_comment = new $CommentClass($comment); |
766
|
|
|
$timber_comments[$timber_comment->id] = $timber_comment; |
|
|
|
|
767
|
|
|
} |
768
|
|
|
|
769
|
|
|
// Build a flattened (depth=1) comment tree |
770
|
|
|
$comments_tree = array(); |
771
|
|
|
foreach( $timber_comments as $key => $comment ) { |
|
|
|
|
772
|
|
|
if ( ! $comment->is_child() ) { |
773
|
|
|
continue; |
774
|
|
|
} |
775
|
|
|
|
776
|
|
|
$tree_element = $comment; |
777
|
|
|
do { |
778
|
|
|
$tree_element = $timber_comments[$tree_element->comment_parent]; |
|
|
|
|
779
|
|
|
} while( $tree_element->is_child() ); |
|
|
|
|
780
|
|
|
|
781
|
|
|
$comments_tree[$tree_element->id][] = $comment->id; |
|
|
|
|
782
|
|
|
} |
783
|
|
|
|
784
|
|
|
// Add child comments to the relative "super parents" |
785
|
|
|
foreach($comments_tree as $comment_parent => $comment_children) { |
|
|
|
|
786
|
|
|
foreach($comment_children as $comment_child) { |
|
|
|
|
787
|
|
|
$timber_comments[$comment_parent]->children[] = $timber_comments[$comment_child]; |
|
|
|
|
788
|
|
|
unset($timber_comments[$comment_child]); |
|
|
|
|
789
|
|
|
} |
790
|
|
|
} |
791
|
|
|
|
792
|
|
|
$timber_comments = array_values($timber_comments); |
|
|
|
|
793
|
|
|
|
794
|
|
|
return $timber_comments; |
795
|
|
|
} |
796
|
|
|
|
797
|
|
|
/** |
798
|
|
|
* Get the categories for a post |
799
|
|
|
* @internal |
800
|
|
|
* @see TimberPost::categories |
801
|
|
|
* @return array of TimberTerms |
802
|
|
|
*/ |
803
|
|
|
function get_categories() { |
|
|
|
|
804
|
|
|
return $this->get_terms('category'); |
|
|
|
|
805
|
|
|
} |
806
|
|
|
|
807
|
|
|
/** |
808
|
|
|
* @internal |
809
|
|
|
* @see TimberPost::category |
810
|
|
|
* @return mixed |
811
|
|
|
*/ |
812
|
|
|
function get_category( ) { |
|
|
|
|
813
|
|
|
$cats = $this->get_categories(); |
814
|
|
|
if ( count($cats) && isset($cats[0]) ) { |
|
|
|
|
815
|
|
|
return $cats[0]; |
816
|
|
|
} |
817
|
|
|
} |
818
|
|
|
|
819
|
|
|
/** |
820
|
|
|
* @internal |
821
|
|
|
* @param string|array $tax |
822
|
|
|
* @param bool $merge |
823
|
|
|
* @param string $TermClass |
824
|
|
|
* @return array |
825
|
|
|
*/ |
826
|
|
|
function get_terms( $tax = '', $merge = true, $TermClass = '' ) { |
|
|
|
|
827
|
|
|
|
828
|
|
|
$TermClass = $TermClass ?: $this->TermClass; |
829
|
|
|
|
830
|
|
|
if ( is_string($merge) && class_exists($merge) ) { |
|
|
|
|
831
|
|
|
$TermClass = $merge; |
832
|
|
|
} |
833
|
|
|
if ( is_array($tax) ) { |
|
|
|
|
834
|
|
|
$taxonomies = $tax; |
835
|
|
|
} |
836
|
|
|
if ( is_string($tax) ) { |
|
|
|
|
837
|
|
|
if ( in_array($tax, array('all','any','')) ) { |
|
|
|
|
838
|
|
|
$taxonomies = get_object_taxonomies($this->post_type); |
|
|
|
|
839
|
|
|
} else { |
840
|
|
|
$taxonomies = array($tax); |
|
|
|
|
841
|
|
|
} |
842
|
|
|
} |
843
|
|
|
|
844
|
|
|
$term_class_objects = array(); |
845
|
|
|
|
846
|
|
|
foreach ( $taxonomies as $taxonomy ) { |
|
|
|
|
847
|
|
|
if ( in_array($taxonomy, array('tag','tags')) ) { |
|
|
|
|
848
|
|
|
$taxonomy = 'post_tag'; |
849
|
|
|
} |
850
|
|
|
if ( $taxonomy == 'categories' ) { |
|
|
|
|
851
|
|
|
$taxonomy = 'category'; |
852
|
|
|
} |
853
|
|
|
|
854
|
|
|
$terms = wp_get_post_terms($this->ID, $taxonomy); |
|
|
|
|
855
|
|
|
|
856
|
|
|
if ( is_wp_error($terms) ) { |
|
|
|
|
857
|
|
|
/* @var $terms WP_Error */ |
858
|
|
|
TimberHelper::error_log("Error retrieving terms for taxonomy '$taxonomy' on a post in timber-post.php"); |
|
|
|
|
859
|
|
|
TimberHelper::error_log('tax = ' . print_r($tax, true)); |
|
|
|
|
860
|
|
|
TimberHelper::error_log('WP_Error: ' . $terms->get_error_message()); |
|
|
|
|
861
|
|
|
|
862
|
|
|
return $term_class_objects; |
863
|
|
|
} |
864
|
|
|
|
865
|
|
|
// map over array of wordpress terms, and transform them into instances of the TermClass |
866
|
|
|
$terms = array_map(function($term) use ($TermClass, $taxonomy) { |
867
|
|
|
return call_user_func(array($TermClass, 'from'), $term->term_id, $taxonomy); |
|
|
|
|
868
|
|
|
}, $terms); |
869
|
|
|
|
870
|
|
|
if ( $merge && is_array($terms) ) { |
|
|
|
|
871
|
|
|
$term_class_objects = array_merge($term_class_objects, $terms); |
|
|
|
|
872
|
|
|
} else if ( count($terms) ) { |
|
|
|
|
873
|
|
|
$term_class_objects[$taxonomy] = $terms; |
|
|
|
|
874
|
|
|
} |
875
|
|
|
} |
876
|
|
|
return $term_class_objects; |
877
|
|
|
} |
878
|
|
|
|
879
|
|
|
/** |
880
|
|
|
* @param string|int $term_name_or_id |
881
|
|
|
* @param string $taxonomy |
882
|
|
|
* @return bool |
883
|
|
|
*/ |
884
|
|
|
function has_term( $term_name_or_id, $taxonomy = 'all' ) { |
|
|
|
|
885
|
|
|
if ( $taxonomy == 'all' || $taxonomy == 'any' ) { |
|
|
|
|
886
|
|
|
$taxes = get_object_taxonomies($this->post_type, 'names'); |
|
|
|
|
887
|
|
|
$ret = false; |
888
|
|
|
foreach ( $taxes as $tax ) { |
889
|
|
|
if ( has_term($term_name_or_id, $tax, $this->ID) ) { |
|
|
|
|
890
|
|
|
$ret = true; |
891
|
|
|
break; |
892
|
|
|
} |
893
|
|
|
} |
894
|
|
|
return $ret; |
895
|
|
|
} |
896
|
|
|
return has_term($term_name_or_id, $taxonomy, $this->ID); |
|
|
|
|
897
|
|
|
} |
898
|
|
|
|
899
|
|
|
/** |
900
|
|
|
* @param string $field |
901
|
|
|
* @return TimberImage |
902
|
|
|
*/ |
903
|
|
|
function get_image( $field ) { |
|
|
|
|
904
|
|
|
return new $this->ImageClass($this->$field); |
|
|
|
|
905
|
|
|
} |
906
|
|
|
|
907
|
|
|
/** |
908
|
|
|
* Gets an array of tags for you to use |
909
|
|
|
* @internal |
910
|
|
|
* @example |
911
|
|
|
* ```twig |
912
|
|
|
* <ul class="tags"> |
913
|
|
|
* {% for tag in post.tags %} |
914
|
|
|
* <li>{{tag.name}}</li> |
915
|
|
|
* {% endfor %} |
916
|
|
|
* </ul> |
917
|
|
|
* ``` |
918
|
|
|
* @return array |
919
|
|
|
*/ |
920
|
|
|
function get_tags() { |
|
|
|
|
921
|
|
|
return $this->get_terms('post_tag'); |
|
|
|
|
922
|
|
|
} |
923
|
|
|
|
924
|
|
|
/** |
925
|
|
|
* Outputs the title with filters applied |
926
|
|
|
* @internal |
927
|
|
|
* @example |
928
|
|
|
* ```twig |
929
|
|
|
* <h1>{{post.get_title}}</h1> |
930
|
|
|
* ``` |
931
|
|
|
* ```html |
932
|
|
|
* <h1>Hello World!</h1> |
933
|
|
|
* ``` |
934
|
|
|
* @return string |
935
|
|
|
*/ |
936
|
|
|
function get_title() { |
|
|
|
|
937
|
|
|
return apply_filters('the_title', $this->post_title, $this->ID); |
|
|
|
|
938
|
|
|
} |
939
|
|
|
|
940
|
|
|
/** |
941
|
|
|
* Displays the content of the post with filters, shortcodes and wpautop applied |
942
|
|
|
* @example |
943
|
|
|
* ```twig |
944
|
|
|
* <div class="article-text">{{post.get_content}}</div> |
945
|
|
|
* ``` |
946
|
|
|
* ```html |
947
|
|
|
* <div class="article-text"><p>Blah blah blah</p><p>More blah blah blah.</p></div> |
948
|
|
|
* ``` |
949
|
|
|
* @param int $len |
950
|
|
|
* @param int $page |
951
|
|
|
* @return string |
952
|
|
|
*/ |
953
|
|
|
function get_content( $len = 0, $page = 0 ) { |
|
|
|
|
954
|
|
|
if ( $len == 0 && $page == 0 && $this->_content ) { |
|
|
|
|
955
|
|
|
return $this->_content; |
956
|
|
|
} |
957
|
|
|
$content = $this->post_content; |
958
|
|
|
if ( $len ) { |
959
|
|
|
$content = wp_trim_words($content, $len); |
|
|
|
|
960
|
|
|
} |
961
|
|
|
if ( $page ) { |
962
|
|
|
$contents = explode('<!--nextpage-->', $content); |
|
|
|
|
963
|
|
|
$page--; |
964
|
|
|
if ( count($contents) > $page ) { |
|
|
|
|
965
|
|
|
$content = $contents[$page]; |
|
|
|
|
966
|
|
|
} |
967
|
|
|
} |
968
|
|
|
$content = apply_filters('the_content', ($content)); |
|
|
|
|
969
|
|
|
if ( $len == 0 && $page == 0 ) { |
|
|
|
|
970
|
|
|
$this->_content = $content; |
971
|
|
|
} |
972
|
|
|
return $content; |
973
|
|
|
} |
974
|
|
|
|
975
|
|
|
/** |
976
|
|
|
* @return string |
977
|
|
|
*/ |
978
|
|
|
function get_paged_content() { |
|
|
|
|
979
|
|
|
global $page; |
980
|
|
|
return $this->get_content(0, $page); |
|
|
|
|
981
|
|
|
} |
982
|
|
|
/** |
983
|
|
|
* |
984
|
|
|
* Here is my summary |
985
|
|
|
* @example |
986
|
|
|
* ```twig |
987
|
|
|
* This post is from <span>{{ post.get_post_type.labels.plural }}</span> |
988
|
|
|
* ``` |
989
|
|
|
* |
990
|
|
|
* ```html |
991
|
|
|
* This post is from <span>Recipes</span> |
992
|
|
|
* ``` |
993
|
|
|
* @return mixed |
994
|
|
|
*/ |
995
|
|
|
public function get_post_type() { |
996
|
|
|
return get_post_type_object($this->post_type); |
|
|
|
|
997
|
|
|
} |
998
|
|
|
|
999
|
|
|
/** |
1000
|
|
|
* @return int the number of comments on a post |
1001
|
|
|
*/ |
1002
|
|
|
public function get_comment_count() { |
1003
|
|
|
return get_comments_number($this->ID); |
|
|
|
|
1004
|
|
|
} |
1005
|
|
|
|
1006
|
|
|
/** |
1007
|
|
|
* @param string $field_name |
1008
|
|
|
* @return mixed |
1009
|
|
|
*/ |
1010
|
|
|
public function get_field( $field_name ) { |
1011
|
|
|
$value = apply_filters('timber_post_get_meta_field_pre', null, $this->ID, $field_name, $this); |
|
|
|
|
1012
|
|
|
if ( $value === null ) { |
1013
|
|
|
$value = get_post_meta($this->ID, $field_name); |
|
|
|
|
1014
|
|
|
if ( is_array($value) && count($value) == 1 ) { |
|
|
|
|
1015
|
|
|
$value = $value[0]; |
1016
|
|
|
} |
1017
|
|
|
if ( is_array($value) && count($value) == 0 ) { |
|
|
|
|
1018
|
|
|
$value = null; |
1019
|
|
|
} |
1020
|
|
|
} |
1021
|
|
|
$value = apply_filters('timber_post_get_meta_field', $value, $this->ID, $field_name, $this); |
|
|
|
|
1022
|
|
|
return $value; |
1023
|
|
|
} |
1024
|
|
|
|
1025
|
|
|
/** |
1026
|
|
|
* @param string $field_name |
1027
|
|
|
*/ |
1028
|
|
|
function import_field( $field_name ) { |
|
|
|
|
1029
|
|
|
$this->$field_name = $this->get_field($field_name); |
|
|
|
|
1030
|
|
|
} |
1031
|
|
|
|
1032
|
|
|
/** |
1033
|
|
|
* @internal |
1034
|
|
|
* @return mixed |
1035
|
|
|
*/ |
1036
|
|
|
function get_format() { |
|
|
|
|
1037
|
|
|
return get_post_format($this->ID); |
|
|
|
|
1038
|
|
|
} |
1039
|
|
|
|
1040
|
|
|
/** |
1041
|
|
|
* Get the CSS classes for a post. For usage you should use `{{post.class}}` instead of `{{post.post_class}}` |
1042
|
|
|
* @internal |
1043
|
|
|
* @param string $class additional classes you want to add |
1044
|
|
|
* @see TimberPost::$class |
1045
|
|
|
* @example |
1046
|
|
|
* ```twig |
1047
|
|
|
* <article class="{{ post.class }}"> |
1048
|
|
|
* {# Some stuff here #} |
1049
|
|
|
* </article> |
1050
|
|
|
* ``` |
1051
|
|
|
* |
1052
|
|
|
* ```html |
1053
|
|
|
* <article class="post-2612 post type-post status-publish format-standard has-post-thumbnail hentry category-data tag-charleston-church-shooting tag-dylann-roof tag-gun-violence tag-hate-crimes tag-national-incident-based-reporting-system"> |
1054
|
|
|
* {# Some stuff here #} |
1055
|
|
|
* </article> |
1056
|
|
|
* ``` |
1057
|
|
|
* @return string a space-seperated list of classes |
1058
|
|
|
*/ |
1059
|
|
|
public function post_class( $class='' ) { |
|
|
|
|
1060
|
|
|
global $post; |
1061
|
|
|
$old_global_post = $post; |
1062
|
|
|
$post = $this; |
|
|
|
|
1063
|
|
|
$class_array = get_post_class($class, $this->ID); |
|
|
|
|
1064
|
|
|
$post = $old_global_post; |
|
|
|
|
1065
|
|
|
if ( is_array($class_array) ){ |
|
|
|
|
1066
|
|
|
return implode(' ', $class_array); |
|
|
|
|
1067
|
|
|
} |
1068
|
|
|
return $class_array; |
1069
|
|
|
} |
1070
|
|
|
|
1071
|
|
|
// Docs |
1072
|
|
|
|
1073
|
|
|
/** |
1074
|
|
|
* @return array |
1075
|
|
|
* @codeCoverageIgnore |
1076
|
|
|
*/ |
1077
|
|
|
public function get_method_values() { |
1078
|
|
|
$ret = parent::get_method_values(); |
1079
|
|
|
$ret['author'] = $this->author(); |
1080
|
|
|
$ret['categories'] = $this->categories(); |
1081
|
|
|
$ret['category'] = $this->category(); |
1082
|
|
|
$ret['children'] = $this->children(); |
1083
|
|
|
$ret['comments'] = $this->comments(); |
1084
|
|
|
$ret['content'] = $this->content(); |
1085
|
|
|
$ret['edit_link'] = $this->edit_link(); |
1086
|
|
|
$ret['format'] = $this->format(); |
1087
|
|
|
$ret['link'] = $this->link(); |
1088
|
|
|
$ret['next'] = $this->next(); |
1089
|
|
|
$ret['pagination'] = $this->pagination(); |
1090
|
|
|
$ret['parent'] = $this->parent(); |
1091
|
|
|
$ret['path'] = $this->path(); |
1092
|
|
|
$ret['prev'] = $this->prev(); |
1093
|
|
|
$ret['terms'] = $this->terms(); |
1094
|
|
|
$ret['tags'] = $this->tags(); |
1095
|
|
|
$ret['thumbnail'] = $this->thumbnail(); |
1096
|
|
|
$ret['title'] = $this->title(); |
1097
|
|
|
return $ret; |
1098
|
|
|
} |
1099
|
|
|
|
1100
|
|
|
/** |
1101
|
|
|
* Return the author of a post |
1102
|
|
|
* @api |
1103
|
|
|
* @example |
1104
|
|
|
* ```twig |
1105
|
|
|
* <h1>{{post.title}}</h1> |
1106
|
|
|
* <p class="byline"> |
1107
|
|
|
* <a href="{{post.author.link}}">{{post.author.name}}</a> |
1108
|
|
|
* </p> |
1109
|
|
|
* ``` |
1110
|
|
|
* @return TimberUser|bool A TimberUser object if found, false if not |
|
|
|
|
1111
|
|
|
*/ |
1112
|
|
|
public function author() { |
1113
|
|
|
return $this->get_author(); |
1114
|
|
|
} |
1115
|
|
|
|
1116
|
|
|
/** |
1117
|
|
|
* Get the author (WordPress user) who last modified the post |
1118
|
|
|
* @example |
1119
|
|
|
* ```twig |
1120
|
|
|
* Last updated by {{ post.modified_author.name }} |
1121
|
|
|
* ``` |
1122
|
|
|
* ```html |
1123
|
|
|
* Last updated by Harper Lee |
1124
|
|
|
* ``` |
1125
|
|
|
* @return TimberUser|bool A TimberUser object if found, false if not |
|
|
|
|
1126
|
|
|
*/ |
1127
|
|
|
public function modified_author() { |
1128
|
|
|
return $this->get_modified_author(); |
1129
|
|
|
} |
1130
|
|
|
|
1131
|
|
|
/** |
1132
|
|
|
* Get the categoires on a particular post |
1133
|
|
|
* @api |
1134
|
|
|
* @return array of TimberTerms |
1135
|
|
|
*/ |
1136
|
|
|
public function categories() { |
1137
|
|
|
return $this->get_terms('category'); |
|
|
|
|
1138
|
|
|
} |
1139
|
|
|
|
1140
|
|
|
/** |
1141
|
|
|
* Returns a category attached to a post |
1142
|
|
|
* @api |
1143
|
|
|
* If mulitpuile categories are set, it will return just the first one |
1144
|
|
|
* @return TimberTerm|null |
1145
|
|
|
*/ |
1146
|
|
|
public function category() { |
1147
|
|
|
return $this->get_category(); |
1148
|
|
|
} |
1149
|
|
|
|
1150
|
|
|
/** |
1151
|
|
|
* Returns an array of children on the post as TimberPosts |
1152
|
|
|
* (or other claass as you define). |
1153
|
|
|
* @api |
1154
|
|
|
* @example |
1155
|
|
|
* ```twig |
1156
|
|
|
* {% if post.children %} |
1157
|
|
|
* Here are the child pages: |
1158
|
|
|
* {% for child in page.children %} |
1159
|
|
|
* <a href="{{ child.link }}">{{ child.title }}</a> |
1160
|
|
|
* {% endfor %} |
1161
|
|
|
* {% endif %} |
1162
|
|
|
* ``` |
1163
|
|
|
* @param string $post_type _optional_ use to find children of a particular post type (attachment vs. page for example). You might want to restrict to certain types of children in case other stuff gets all mucked in there. You can use 'parent' to use the parent's post type |
1164
|
|
|
* @param string|bool $childPostClass _optional_ a custom post class (ex: 'MyTimberPost') to return the objects as. By default (false) it will use TimberPost::$post_class value. |
1165
|
|
|
* @return array |
1166
|
|
|
*/ |
1167
|
|
|
public function children( $post_type = 'any', $childPostClass = false ) { |
1168
|
|
|
return $this->get_children( $post_type, $childPostClass ); |
1169
|
|
|
} |
1170
|
|
|
|
1171
|
|
|
/** |
1172
|
|
|
* Gets the comments on a TimberPost and returns them as an array of [TimberComments](#TimberComment) (or whatever comment class you set). |
1173
|
|
|
* @api |
1174
|
|
|
* @param int $count Set the number of comments you want to get. `0` is analogous to "all" |
1175
|
|
|
* @param string $order use ordering set in WordPress admin, or a different scheme |
1176
|
|
|
* @param string $type For when other plugins use the comments table for their own special purposes, might be set to 'liveblog' or other depending on what's stored in yr comments table |
1177
|
|
|
* @param string $status Could be 'pending', etc. |
1178
|
|
|
* @param string $CommentClass What class to use when returning Comment objects. As you become a Timber pro, you might find yourself extending TimberComment for your site or app (obviously, totally optional) |
1179
|
|
|
* @example |
1180
|
|
|
* ```twig |
1181
|
|
|
* {# single.twig #} |
1182
|
|
|
* <h4>Comments:</h4> |
1183
|
|
|
* {% for comment in post.comments %} |
1184
|
|
|
* <div class="comment-{{comment.ID}} comment-order-{{loop.index}}"> |
1185
|
|
|
* <p>{{comment.author.name}} said:</p> |
1186
|
|
|
* <p>{{comment.content}}</p> |
1187
|
|
|
* </div> |
1188
|
|
|
* {% endfor %} |
1189
|
|
|
* ``` |
1190
|
|
|
* @return bool|array |
1191
|
|
|
*/ |
1192
|
|
|
public function comments( $count = 0, $order = 'wp', $type = 'comment', $status = 'approve', $CommentClass = 'TimberComment' ) { |
1193
|
|
|
return $this->get_comments($count, $order, $type, $status, $CommentClass); |
|
|
|
|
1194
|
|
|
} |
1195
|
|
|
|
1196
|
|
|
/** |
1197
|
|
|
* Gets the actual content of a WP Post, as opposed to post_content this will run the hooks/filters attached to the_content. \This guy will return your posts content with WordPress filters run on it (like for shortcodes and wpautop). |
1198
|
|
|
* @api |
1199
|
|
|
* @example |
1200
|
|
|
* ```twig |
1201
|
|
|
* <div class="article"> |
1202
|
|
|
* <h2>{{post.title}}</h2> |
1203
|
|
|
* <div class="content">{{ post.content }}</div> |
1204
|
|
|
* </div> |
1205
|
|
|
* ``` |
1206
|
|
|
* @param int $page |
1207
|
|
|
* @return string |
1208
|
|
|
*/ |
1209
|
|
|
public function content( $page = 0 ) { |
|
|
|
|
1210
|
|
|
return $this->get_content(0, $page); |
|
|
|
|
1211
|
|
|
} |
1212
|
|
|
|
1213
|
|
|
/** |
1214
|
|
|
* @return string |
1215
|
|
|
*/ |
1216
|
|
|
public function paged_content() { |
1217
|
|
|
return $this->get_paged_content(); |
1218
|
|
|
} |
1219
|
|
|
|
1220
|
|
|
/** |
1221
|
|
|
* Get the date to use in your template! |
1222
|
|
|
* @api |
1223
|
|
|
* @example |
1224
|
|
|
* ```twig |
1225
|
|
|
* Published on {{ post.date }} // Uses WP's formatting set in Admin |
1226
|
|
|
* OR |
1227
|
|
|
* Published on {{ post.date | date('F jS') }} // Jan 12th |
1228
|
|
|
* ``` |
1229
|
|
|
* |
1230
|
|
|
* ```html |
1231
|
|
|
* Published on January 12, 2015 |
1232
|
|
|
* OR |
1233
|
|
|
* Published on Jan 12th |
1234
|
|
|
* ``` |
1235
|
|
|
* @param string $date_format |
1236
|
|
|
* @return string |
1237
|
|
|
*/ |
1238
|
|
|
public function date( $date_format = '' ) { |
1239
|
|
|
return $this->get_date($date_format); |
|
|
|
|
1240
|
|
|
} |
1241
|
|
|
|
1242
|
|
|
/** |
1243
|
|
|
* Get the time to use in your template |
1244
|
|
|
* @api |
1245
|
|
|
* @example |
1246
|
|
|
* ```twig |
1247
|
|
|
* Published at {{ post.time }} // Uses WP's formatting set in Admin |
1248
|
|
|
* OR |
1249
|
|
|
* Published at {{ post.time | time('G:i') }} // 13:25 |
1250
|
|
|
* ``` |
1251
|
|
|
* |
1252
|
|
|
* ```html |
1253
|
|
|
* Published at 1:25 pm |
1254
|
|
|
* OR |
1255
|
|
|
* Published at 13:25 |
1256
|
|
|
* ``` |
1257
|
|
|
* @param string $time_format |
1258
|
|
|
* @return string |
1259
|
|
|
*/ |
1260
|
|
|
public function time( $time_format = '' ) { |
1261
|
|
|
$tf = $time_format ? $time_format : get_option('time_format'); |
|
|
|
|
1262
|
|
|
$the_time = (string)mysql2date($tf, $this->post_date); |
|
|
|
|
1263
|
|
|
return apply_filters('get_the_time', $the_time, $tf); |
|
|
|
|
1264
|
|
|
} |
1265
|
|
|
|
1266
|
|
|
/** |
1267
|
|
|
* @return bool|string |
1268
|
|
|
*/ |
1269
|
|
|
public function edit_link() { |
1270
|
|
|
return $this->get_edit_url(); |
1271
|
|
|
} |
1272
|
|
|
|
1273
|
|
|
/** |
1274
|
|
|
* @api |
1275
|
|
|
* @return mixed |
1276
|
|
|
*/ |
1277
|
|
|
public function format() { |
1278
|
|
|
return $this->get_format(); |
1279
|
|
|
} |
1280
|
|
|
|
1281
|
|
|
/** |
1282
|
|
|
* get the permalink for a post object |
1283
|
|
|
* @api |
1284
|
|
|
* @example |
1285
|
|
|
* ```twig |
1286
|
|
|
* <a href="{{post.link}}">Read my post</a> |
1287
|
|
|
* ``` |
1288
|
|
|
* @return string ex: http://example.org/2015/07/my-awesome-post |
1289
|
|
|
*/ |
1290
|
|
|
public function link() { |
1291
|
|
|
return $this->get_permalink(); |
1292
|
|
|
} |
1293
|
|
|
|
1294
|
|
|
/** |
1295
|
|
|
* @param string $field_name |
|
|
|
|
1296
|
|
|
* @return mixed |
1297
|
|
|
*/ |
1298
|
|
|
public function meta( $field_name = null ) { |
1299
|
|
|
if ( $field_name === null ) { |
1300
|
|
|
//on the off-chance the field is actually named meta |
1301
|
|
|
$field_name = 'meta'; |
1302
|
|
|
} |
1303
|
|
|
return $this->get_field($field_name); |
|
|
|
|
1304
|
|
|
} |
1305
|
|
|
|
1306
|
|
|
/** |
1307
|
|
|
* @return string |
1308
|
|
|
*/ |
1309
|
|
|
public function name(){ |
1310
|
|
|
return $this->title(); |
1311
|
|
|
} |
1312
|
|
|
|
1313
|
|
|
/** |
1314
|
|
|
* @param string $date_format |
1315
|
|
|
* @return string |
1316
|
|
|
*/ |
1317
|
|
|
public function modified_date( $date_format = '' ) { |
1318
|
|
|
return $this->get_modified_date($date_format); |
|
|
|
|
1319
|
|
|
} |
1320
|
|
|
|
1321
|
|
|
/** |
1322
|
|
|
* @param string $time_format |
1323
|
|
|
* @return string |
1324
|
|
|
*/ |
1325
|
|
|
public function modified_time( $time_format = '' ) { |
1326
|
|
|
return $this->get_modified_time($time_format); |
|
|
|
|
1327
|
|
|
} |
1328
|
|
|
|
1329
|
|
|
/** |
1330
|
|
|
* @api |
1331
|
|
|
* @param bool $in_same_cat |
1332
|
|
|
* @return mixed |
1333
|
|
|
*/ |
1334
|
|
|
public function next( $in_same_cat = false ) { |
1335
|
|
|
return $this->get_next($in_same_cat); |
|
|
|
|
1336
|
|
|
} |
1337
|
|
|
|
1338
|
|
|
/** |
1339
|
|
|
* @return array |
1340
|
|
|
*/ |
1341
|
|
|
public function pagination() { |
1342
|
|
|
return $this->get_pagination(); |
1343
|
|
|
} |
1344
|
|
|
|
1345
|
|
|
/** |
1346
|
|
|
* Gets the parent (if one exists) from a post as a TimberPost object (or whatever is set in TimberPost::$PostClass) |
1347
|
|
|
* @api |
1348
|
|
|
* @example |
1349
|
|
|
* ```twig |
1350
|
|
|
* Parent page: <a href="{{ post.parent.link }}">{{ post.parent.title }}</a> |
1351
|
|
|
* ``` |
1352
|
|
|
* @return bool|TimberPost |
|
|
|
|
1353
|
|
|
*/ |
1354
|
|
|
public function parent() { |
1355
|
|
|
return $this->get_parent(); |
1356
|
|
|
} |
1357
|
|
|
|
1358
|
|
|
/** |
1359
|
|
|
* Gets the relative path of a WP Post, so while link() will return http://example.org/2015/07/my-cool-post |
1360
|
|
|
* this will return just /2015/07/my-cool-post |
1361
|
|
|
* @api |
1362
|
|
|
* @example |
1363
|
|
|
* ```twig |
1364
|
|
|
* <a href="{{post.path}}">{{post.title}}</a> |
1365
|
|
|
* ``` |
1366
|
|
|
* @return string |
1367
|
|
|
*/ |
1368
|
|
|
public function path() { |
1369
|
|
|
return $this->get_path(); |
1370
|
|
|
} |
1371
|
|
|
|
1372
|
|
|
/** |
1373
|
|
|
* @deprecated 0.20.0 use link() instead |
1374
|
|
|
* @return string |
1375
|
|
|
*/ |
1376
|
|
|
public function permalink() { |
1377
|
|
|
return $this->get_permalink(); |
1378
|
|
|
} |
1379
|
|
|
|
1380
|
|
|
/** |
1381
|
|
|
* Get the previous post in a set |
1382
|
|
|
* @api |
1383
|
|
|
* @example |
1384
|
|
|
* ```twig |
1385
|
|
|
* <h4>Prior Entry:</h4> |
1386
|
|
|
* <h3>{{post.prev.title}}</h3> |
1387
|
|
|
* <p>{{post.prev.get_preview(25)}}</p> |
1388
|
|
|
* ``` |
1389
|
|
|
* @param bool $in_same_cat |
1390
|
|
|
* @return mixed |
1391
|
|
|
*/ |
1392
|
|
|
public function prev( $in_same_cat = false ) { |
1393
|
|
|
return $this->get_prev($in_same_cat); |
|
|
|
|
1394
|
|
|
} |
1395
|
|
|
|
1396
|
|
|
/** |
1397
|
|
|
* Get the terms associated with the post |
1398
|
|
|
* This goes across all taxonomies by default |
1399
|
|
|
* @api |
1400
|
|
|
* @param string|array $tax What taxonom(y|ies) to pull from. Defaults to all registered taxonomies for the post type. You can use custom ones, or built-in WordPress taxonomies (category, tag). Timber plays nice and figures out that tag/tags/post_tag are all the same (and categories/category), for custom taxonomies you're on your own. |
1401
|
|
|
* @param bool $merge Should the resulting array be one big one (true)? Or should it be an array of sub-arrays for each taxonomy (false)? |
1402
|
|
|
* @return array |
1403
|
|
|
*/ |
1404
|
|
|
public function terms( $tax = '', $merge = true ) { |
1405
|
|
|
return $this->get_terms($tax, $merge); |
|
|
|
|
1406
|
|
|
} |
1407
|
|
|
|
1408
|
|
|
/** |
1409
|
|
|
* Gets the tags on a post, uses WP's post_tag taxonomy |
1410
|
|
|
* @api |
1411
|
|
|
* @return array |
1412
|
|
|
*/ |
1413
|
|
|
public function tags() { |
1414
|
|
|
return $this->get_tags(); |
1415
|
|
|
} |
1416
|
|
|
|
1417
|
|
|
/** |
1418
|
|
|
* get the featured image as a TimberImage |
1419
|
|
|
* @api |
1420
|
|
|
* @example |
1421
|
|
|
* ```twig |
1422
|
|
|
* <img src="{{post.thumbnail.src}}" /> |
1423
|
|
|
* ``` |
1424
|
|
|
* @return TimberImage|null of your thumbnail |
|
|
|
|
1425
|
|
|
*/ |
1426
|
|
|
public function thumbnail() { |
1427
|
|
|
return $this->get_thumbnail(); |
1428
|
|
|
} |
1429
|
|
|
|
1430
|
|
|
/** |
1431
|
|
|
* 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. |
1432
|
|
|
* @api |
1433
|
|
|
* @example |
1434
|
|
|
* ```twig |
1435
|
|
|
* <h1>{{ post.title }}</h1> |
1436
|
|
|
* ``` |
1437
|
|
|
* @return string |
1438
|
|
|
*/ |
1439
|
|
|
public function title() { |
1440
|
|
|
return $this->get_title(); |
1441
|
|
|
} |
1442
|
|
|
|
1443
|
|
|
} |
1444
|
|
|
|