Completed
Pull Request — master (#776)
by Jared
07:31
created

timber.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/*
3
Plugin Name: Timber
4
Description: The WordPress Timber Library allows you to write themes using the power Twig templates.
5
Plugin URI: http://timber.upstatement.com
6
Author: Jared Novack + Upstatement
7
Version: 0.22.2
8
Author URI: http://upstatement.com/
9
*/
10
11
global $wp_version;
12
global $timber;
13
14
// we look for Composer files first in the plugins dir.
15
// then in the wp-content dir (site install).
16
// and finally in the current themes directories.
17
if (   file_exists( $composer_autoload = __DIR__ . '/vendor/autoload.php' ) /* check in self */
18
	|| file_exists( $composer_autoload = WP_CONTENT_DIR.'/vendor/autoload.php') /* check in wp-content */
19
	|| file_exists( $composer_autoload = plugin_dir_path( __FILE__ ).'vendor/autoload.php') /* check in plugin directory */
20
	|| file_exists( $composer_autoload = get_stylesheet_directory().'/vendor/autoload.php') /* check in child theme */
21
	|| file_exists( $composer_autoload = get_template_directory().'/vendor/autoload.php') /* check in parent theme */
22
	) {
23
	require_once $composer_autoload;
24
}
25
26
$timber = new Timber();
27
Timber::$dirname = 'views';
28
29
/**
30
 * Timber Class.
31
 *
32
 * Main class called Timber for this plugin.
33
 *
34
 * Usage:
35
 *  $posts = Timber::get_posts();
36
 *  $posts = Timber::get_posts('post_type = article')
37
 *  $posts = Timber::get_posts(array('post_type' => 'article', 'category_name' => 'sports')); // uses wp_query format.
38
 *  $posts = Timber::get_posts(array(23,24,35,67), 'InkwellArticle');
39
 *
40
 *  $context = Timber::get_context(); // returns wp favorites!
41
 *  $context['posts'] = $posts;
42
 *  Timber::render('index.twig', $context);
43
 */
44
class Timber {
45
46
	public static $locations;
47
	public static $dirname;
48
	public static $twig_cache = false;
49
	public static $cache = false;
50
	public static $auto_meta = true;
51
	public static $autoescape = false;
52
53
	public function __construct() {
54
		if ( !defined('ABSPATH') ) {
55
			return;
56
		}
57
		$this->test_compatibility();
58
		$this->init_constants();
59
		$this->init();
60
	}
61
62
	protected function test_compatibility() {
63
		if ( is_admin() || $_SERVER['PHP_SELF'] == '/wp-login.php' ) {
64
			return;
65
		}
66
		if ( version_compare( phpversion(), '5.3.0', '<' ) && !is_admin() ) {
67
			trigger_error( 'Timber requires PHP 5.3.0 or greater. You have '.phpversion(), E_USER_ERROR );
68
		}
69
		if ( !class_exists( 'Twig_Autoloader' ) ) {
70
			trigger_error( 'You have not run "composer install" to download required dependencies for Timber, you can read more on https://github.com/jarednova/timber#installation', E_USER_ERROR );
71
		}
72
	}
73
74
	function init_constants() {
75
		defined( "TIMBER_LOC" ) or define( "TIMBER_LOC", realpath( __DIR__ ) );
76
	}
77
78
	protected function init() {
79
		TimberTwig::init();
80
		TimberRoutes::init( $this );
81
		TimberImageHelper::init();
82
		TimberAdmin::init();
83
		TimberIntegrations::init();
84
	}
85
86
	/* Post Retrieval Routine
87
	================================ */
88
89
	/**
90
	 * Get post.
91
	 *
92
	 * @param mixed   $query
93
	 * @param string  $PostClass
94
	 * @return array|bool|null
95
	 */
96
	public static function get_post( $query = false, $PostClass = 'TimberPost' ) {
97
		return TimberPostGetter::get_post( $query, $PostClass );
98
	}
99
100
	/**
101
	 * Get posts.
102
	 *
103
	 * @param mixed   $query
104
	 * @param string  $PostClass
105
	 * @return array|bool|null
106
	 */
107
	public static function get_posts( $query = false, $PostClass = 'TimberPost', $return_collection = false ) {
108
		return TimberPostGetter::get_posts( $query, $PostClass, $return_collection );
109
	}
110
111
	/**
112
	 * Query post.
113
	 *
114
	 * @param mixed   $query
115
	 * @param string  $PostClass
116
	 * @return array|bool|null
117
	 */
118
	public static function query_post( $query = false, $PostClass = 'TimberPost' ) {
119
		return TimberPostGetter::query_post( $query, $PostClass );
120
	}
121
122
	/**
123
	 * Query posts.
124
	 *
125
	 * @param mixed   $query
126
	 * @param string  $PostClass
127
	 * @return array|bool|null
128
	 */
129
	public static function query_posts( $query = false, $PostClass = 'TimberPost' ) {
130
		return TimberPostGetter::query_posts( $query, $PostClass );
131
	}
132
133
	/**
134
	 * Get pids.
135
	 *
136
	 * @param array|string $query
137
	 * @return array
138
	 * @deprecated since 0.20.0
139
	 */
140
	static function get_pids( $query = null ) {
141
		return TimberPostGetter::get_pids( $query );
142
	}
143
144
	/**
145
	 * Get posts from loop.
146
	 *
147
	 * @param string  $PostClass
148
	 * @return array
149
	 * @deprecated since 0.20.0
150
	 */
151
	static function get_posts_from_loop( $PostClass ) {
152
		return TimberPostGetter::get_posts( $PostClass );
153
	}
154
155
	/**
156
	 * Get posts from slug.
157
	 *
158
	 * @param string  $slug
159
	 * @param string  $PostClass
160
	 * @return array
161
	 * @deprecated since 0.20.0
162
	 */
163
	static function get_posts_from_slug( $slug, $PostClass = 'TimberPost' ) {
164
		return TimberPostGetter::get_posts( $slug, $PostClass );
165
	}
166
167
	/**
168
	 * Get posts from WP_Query.
169
	 *
170
	 * @param array   $query
171
	 * @param string  $PostClass
172
	 * @return array
173
	 * @deprecated since 0.20.0
174
	 */
175
	static function get_posts_from_wp_query( $query = array(), $PostClass = 'TimberPost' ) {
176
		return TimberPostGetter::query_posts( $query, $PostClass );
177
	}
178
179
	/**
180
	 * Get posts from array of ids.
181
	 *
182
	 * @param array   $query
183
	 * @param string  $PostClass
184
	 * @return array|null
185
	 * @deprecated since 0.20.0
186
	 */
187
	static function get_posts_from_array_of_ids( $query = array(), $PostClass = 'TimberPost' ) {
188
		return TimberPostGetter::get_posts( $query, $PostClass );
189
	}
190
191
	/**
192
	 * Get pid.
193
	 *
194
	 * @param unknown $query
195
	 * @return int
196
	 * @deprecated since 0.20.0
197
	 */
198
	static function get_pid( $query ) {
199
		$pids = TimberPostGetter::get_pids( $query );
200
		if ( is_array( $pids ) && count( $pids ) ) {
201
			return $pids[0];
202
		}
203
	}
204
205
	/**
206
	 * WP_Query has posts.
207
	 *
208
	 * @return bool
209
	 * @deprecated since 0.20.0
210
	 */
211
	static function wp_query_has_posts() {
212
		return TimberPostGetter::wp_query_has_posts();
213
	}
214
215
	/* Term Retrieval
216
	================================ */
217
218
	/**
219
	 * Get terms.
220
	 *
221
	 * @param string|array $args
222
	 * @param array   $maybe_args
223
	 * @param string  $TermClass
224
	 * @return mixed
225
	 */
226
	public static function get_terms( $args = null, $maybe_args = array(), $TermClass = 'TimberTerm' ) {
227
		return TimberTermGetter::get_terms( $args, $maybe_args, $TermClass );
228
	}
229
230
	/* Site Retrieval
231
	================================ */
232
233
	/**
234
	 * Get sites.
235
	 *
236
	 * @param array|bool $blog_ids
237
	 * @return array
238
	 */
239
	public static function get_sites( $blog_ids = false ) {
240
		if ( !is_array( $blog_ids ) ) {
241
			global $wpdb;
242
			$blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs ORDER BY blog_id ASC" );
243
		}
244
		$return = array();
245
		foreach ( $blog_ids as $blog_id ) {
246
			$return[] = new TimberSite( $blog_id );
247
		}
248
		return $return;
249
	}
250
251
252
	/*  Template Setup and Display
253
	================================ */
254
255
	/**
256
	 * Get context.
257
	 *
258
	 * @return array
259
	 */
260
	public static function get_context() {
261
		$data = array();
262
		$data['http_host'] = 'http://' . TimberURLHelper::get_host();
263
		$data['wp_title'] = TimberHelper::get_wp_title();
264
		$data['wp_head'] = TimberHelper::function_wrapper( 'wp_head' );
265
		$data['wp_footer'] = TimberHelper::function_wrapper( 'wp_footer' );
266
		$data['body_class'] = implode( ' ', get_body_class() );
267
268
		$data['site'] = new TimberSite();
269
		$data['theme'] = $data['site']->theme;
270
		//deprecated, these should be fetched via TimberSite or TimberTheme
271
		$data['theme_dir'] = WP_CONTENT_SUBDIR.str_replace( WP_CONTENT_DIR, '', get_stylesheet_directory() );
272
		$data['language_attributes'] = TimberHelper::function_wrapper( 'language_attributes' );
273
		$data['stylesheet_uri'] = get_stylesheet_uri();
274
		$data['template_uri'] = get_template_directory_uri();
275
276
		$data['posts'] = Timber::query_posts();
277
278
		//deprecated, this should be fetched via TimberMenu
279
		if ( function_exists( 'wp_nav_menu' ) ) {
280
			$locations = get_nav_menu_locations();
281
			if ( count( $locations ) ) {
282
				$data['wp_nav_menu'] = wp_nav_menu( array( 'container_class' => 'menu-header', 'echo' => false, 'menu_class' => 'nav-menu' ) );
283
			}
284
		}
285
		$data = apply_filters( 'timber_context', $data );
286
		$data = apply_filters( 'timber/context', $data );
287
		return $data;
288
	}
289
290
	/**
291
	 * Compile function.
292
	 *
293
	 * @param array   $filenames
294
	 * @param array   $data
295
	 * @param bool    $expires
296
	 * @param string  $cache_mode
297
	 * @param bool    $via_render
298
	 * @return bool|string
299
	 */
300
	public static function compile( $filenames, $data = array(), $expires = false, $cache_mode = TimberLoader::CACHE_USE_DEFAULT, $via_render = false ) {
301
		$caller = self::get_calling_script_dir();
302
		$caller_file = self::get_calling_script_file();
303
		$caller_file = apply_filters( 'timber_calling_php_file', $caller_file );
304
		$loader = new TimberLoader( $caller );
305
		$file = $loader->choose_template( $filenames );
306
		$output = '';
307
		if ( is_null( $data ) ) {
308
			$data = array();
309
		}
310
		if ( strlen( $file ) ) {
311
			if ( $via_render ) {
312
				$file = apply_filters( 'timber_render_file', $file );
313
				$data = apply_filters( 'timber_render_data', $data );
314
			} else {
315
				$file = apply_filters( 'timber_compile_file', $file );
316
				$data = apply_filters( 'timber_compile_data', $data );
317
			}
318
			$output = $loader->render( $file, $data, $expires, $cache_mode );
319
		}
320
		do_action( 'timber_compile_done' );
321
		return $output;
322
	}
323
324
	/**
325
	 * Compile string.
326
	 *
327
	 * @param string  $string a string with twig variables.
328
	 * @param array   $data   an array with data in it.
329
	 * @return  bool|string
330
	 */
331
	public static function compile_string( $string, $data = array() ) {
332
		$dummy_loader = new TimberLoader();
333
		$dummy_loader->get_twig();
334
		$loader = new Twig_Loader_String();
335
		$twig = new Twig_Environment( $loader );
336
		$twig = apply_filters( 'timber/twig/filters', $twig );
337
		$twig = apply_filters( 'twig_apply_filters', $twig );
338
		return $twig->render( $string, $data );
339
	}
340
341
	/**
342
	 * Fetch function.
343
	 *
344
	 * @param array   $filenames
345
	 * @param array   $data
346
	 * @param bool    $expires
347
	 * @param string  $cache_mode
348
	 * @return bool|string
349
	 */
350
	public static function fetch( $filenames, $data = array(), $expires = false, $cache_mode = TimberLoader::CACHE_USE_DEFAULT ) {
351
		if ( $expires === true ) {
352
			//if this is reading as true; the user probably is using the old $echo param
353
			//so we should move all vars up by a spot
354
			$expires = $cache_mode;
355
			$cache_mode = TimberLoader::CACHE_USE_DEFAULT;
356
		}
357
		$output = self::compile( $filenames, $data, $expires, $cache_mode, true );
0 ignored issues
show
It seems like $expires defined by $cache_mode on line 354 can also be of type string; however, Timber::compile() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
358
		$output = apply_filters( 'timber_compile_result', $output );
359
		return $output;
360
	}
361
362
	/**
363
	 * Render function.
364
	 *
365
	 * @param array   $filenames
366
	 * @param array   $data
367
	 * @param bool    $expires
368
	 * @param string  $cache_mode
369
	 * @return bool|string
370
	 */
371
	public static function render( $filenames, $data = array(), $expires = false, $cache_mode = TimberLoader::CACHE_USE_DEFAULT ) {
372
		$output = static::fetch( $filenames, $data, $expires, $cache_mode );
373
		echo $output;
374
		return $output;
375
	}
376
377
	/**
378
	 * Render string.
379
	 *
380
	 * @param string  $string a string with twig variables.
381
	 * @param array   $data   an array with data in it.
382
	 * @return  bool|string
383
	 */
384
	public static function render_string( $string, $data = array() ) {
385
		$compiled = self::compile_string( $string, $data );
386
		echo $compiled;
387
		return $compiled;
388
	}
389
390
391
	/*  Sidebar
392
	================================ */
393
394
	/**
395
	 * Get sidebar.
396
	 *
397
	 * @param string  $sidebar
398
	 * @param array   $data
399
	 * @return bool|string
400
	 */
401
	public static function get_sidebar( $sidebar = '', $data = array() ) {
402
		if ( $sidebar == '' ) {
403
			$sidebar = 'sidebar.php';
404
		}
405
		if ( strstr( strtolower( $sidebar ), '.php' ) ) {
406
			return self::get_sidebar_from_php( $sidebar, $data );
407
		}
408
		return self::compile( $sidebar, $data );
409
	}
410
411
	/**
412
	 * Get sidebar from PHP
413
	 *
414
	 * @param string  $sidebar
415
	 * @param array   $data
416
	 * @return string
417
	 */
418
	public static function get_sidebar_from_php( $sidebar = '', $data ) {
419
		$caller = self::get_calling_script_dir();
420
		$loader = new TimberLoader();
421
		$uris = $loader->get_locations( $caller );
422
		ob_start();
423
		$found = false;
424
		foreach ( $uris as $uri ) {
425
			if ( file_exists( trailingslashit( $uri ) . $sidebar ) ) {
426
				include trailingslashit( $uri ) . $sidebar;
427
				$found = true;
428
				break;
429
			}
430
		}
431
		if ( !$found ) {
432
			TimberHelper::error_log( 'error loading your sidebar, check to make sure the file exists' );
433
		}
434
		$ret = ob_get_contents();
435
		ob_end_clean();
436
		return $ret;
437
	}
438
439
	/* Widgets
440
	================================ */
441
442
	/**
443
	 * Get widgets.
444
	 *
445
	 * @param int     $widget_id
446
	 * @return TimberFunctionWrapper
447
	 */
448
	public static function get_widgets( $widget_id ) {
449
		return TimberHelper::function_wrapper( 'dynamic_sidebar', array( $widget_id ), true );
450
	}
451
452
453
	/*  Routes
454
	================================ */
455
456
	/**
457
	 * Add route.
458
	 *
459
	 * @param string  $route
460
	 * @param callable $callback
461
	 * @param array   $args
462
	 * @deprecated since 0.20.0
463
	 */
464
	public static function add_route( $route, $callback, $args = array() ) {
465
		Routes::map( $route, $callback, $args );
466
	}
467
468
	/**
469
	 * @deprecated since 0.22.2
470
	 */
471
	public function cancel_query() {
472
		add_action( 'posts_request', array( $this, 'cancel_query_posts_request' ) );
473
	}
474
475
	/**
476
	 * @deprecated since 0.22.2
477
	 */
478
	function cancel_query_posts_request() {
479
		if ( is_main_query() ) {
480
			wp_reset_query();
481
		}
482
	}
483
484
	/**
485
	 * Load template.
486
	 *
487
	 * @deprecated since 0.20.0
488
	 */
489
	public static function load_template( $template, $query = false, $status_code = 200, $tparams = false ) {
490
		return Routes::load( $template, $tparams, $query, $status_code );
491
	}
492
493
	/**
494
	 * Load view.
495
	 *
496
	 * @deprecated since 0.20.2
497
	 */
498
	public static function load_view( $template, $query = false, $status_code = 200, $tparams = false ) {
499
		return Routes::load( $template, $tparams, $query, $status_code );
500
	}
501
502
503
	/*  Pagination
504
	================================ */
505
506
	/**
507
	 * Get pagination.
508
	 *
509
	 * @param array   $prefs
510
	 * @return array mixed
511
	 */
512
	public static function get_pagination( $prefs = array() ) {
513
		global $wp_query;
514
		global $paged;
515
		global $wp_rewrite;
516
		$args = array();
517
		$args['total'] = ceil( $wp_query->found_posts / $wp_query->query_vars['posts_per_page'] );
518
		if ( $wp_rewrite->using_permalinks() ) {
519
			$url = explode( '?', get_pagenum_link( 0 ) );
520
			if ( isset( $url[1] ) ) {
521
				parse_str( $url[1], $query );
522
				$args['add_args'] = $query;
523
			}
524
			$args['format'] = 'page/%#%';
525
			$args['base'] = trailingslashit( $url[0] ).'%_%';
526
		} else {
527
			$big = 999999999;
528
			$args['base'] = str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) );
529
		}
530
		$args['type'] = 'array';
531
		$args['current'] = max( 1, get_query_var( 'paged' ) );
532
		$args['mid_size'] = max( 9 - $args['current'], 3 );
533
		$args['prev_next'] = false;
534
		if ( is_int( $prefs ) ) {
535
			$args['mid_size'] = $prefs - 2;
536
		} else {
537
			$args = array_merge( $args, $prefs );
538
		}
539
		$data = array();
540
		$data['current'] = $args['current'];
541
		$data['total'] = $args['total'];
542
		$data['pages'] = TimberHelper::paginate_links( $args );
543
		$next = get_next_posts_page_link( $args['total'] );
544
		if ( $next ) {
545
			$data['next'] = array( 'link' => untrailingslashit( $next ), 'class' => 'page-numbers next' );
546
		}
547
		$prev = previous_posts( false );
548
		if ( $prev ) {
549
			$data['prev'] = array( 'link' => untrailingslashit( $prev ), 'class' => 'page-numbers prev' );
550
		}
551
		if ( $paged < 2 ) {
552
			$data['prev'] = '';
553
		}
554
		return $data;
555
	}
556
557
	/*  Utility
558
	================================ */
559
560
	/**
561
	 * Get calling script path.
562
	 *
563
	 * @param int     $offset
564
	 * @return string
565
	 * @deprecated since 0.20.0
566
	 */
567
	public static function get_calling_script_path( $offset = 0 ) {
568
		$dir = self::get_calling_script_dir( $offset );
569
		return str_replace( ABSPATH, '', realpath( $dir ) );
570
	}
571
572
	/**
573
	 * Get calling script dir.
574
	 *
575
	 * @return boolean|string
576
	 */
577
	public static function get_calling_script_dir( $offset = 0 ) {
578
		$caller = self::get_calling_script_file( $offset );
579
		if ( !is_null( $caller ) ) {
580
			$pathinfo = pathinfo( $caller );
581
			$dir = $pathinfo['dirname'];
582
			return $dir;
583
		}
584
		return null;
585
	}
586
587
	/**
588
	 * Get calling script file.
589
	 *
590
	 * @param int     $offset
591
	 * @return string|null
592
	 * @deprecated since 0.20.0
593
	 */
594
	public static function get_calling_script_file( $offset = 0 ) {
595
		$caller = null;
596
		$backtrace = debug_backtrace();
597
		$i = 0;
598
		foreach ( $backtrace as $trace ) {
599
			if ( $trace['file'] != __FILE__ ) {
600
				$caller = $trace['file'];
601
				break;
602
			}
603
			$i++;
604
		}
605
		if ( $offset ) {
606
			$caller = $backtrace[$i + $offset]['file'];
607
		}
608
		return $caller;
609
	}
610
611
	/**
612
	 * Is post class or class map.
613
	 *
614
	 * @param string|array $args
615
	 * @return bool
616
	 * @deprecated since 0.20.0
617
	 */
618
	public static function is_post_class_or_class_map( $args ) {
619
		return TimberPostGetter::is_post_class_or_class_map( $args );
620
	}
621
622
}
623