Completed
Push — master ( fe4038...3ca687 )
by Jared
04:32
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.3
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
	/**
54
	 * @codeCoverageIgnore
55
	 */
56
	public function __construct() {
57
		if ( !defined('ABSPATH') ) {
58
			return;
59
		}
60
		$this->test_compatibility();
61
		$this->init_constants();
62
		$this->init();
63
	}
64
65
	/**
66
	 * Tests whether we can use Timber
67
	 * @codeCoverageIgnore
68
	 * @return
69
	 */
70
	protected function test_compatibility() {
71
		if ( is_admin() || $_SERVER['PHP_SELF'] == '/wp-login.php' ) {
72
			return;
73
		}
74
		if ( version_compare( phpversion(), '5.3.0', '<' ) && !is_admin() ) {
75
			trigger_error( 'Timber requires PHP 5.3.0 or greater. You have '.phpversion(), E_USER_ERROR );
76
		}
77
		if ( !class_exists( 'Twig_Autoloader' ) ) {
78
			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 );
79
		}
80
	}
81
82
	function init_constants() {
83
		defined( "TIMBER_LOC" ) or define( "TIMBER_LOC", realpath( __DIR__ ) );
84
	}
85
86
	/**
87
	 * @codeCoverageIgnore
88
	 */
89
	protected function init() {
90
		TimberTwig::init();
91
		TimberRoutes::init( $this );
92
		TimberImageHelper::init();
93
		TimberAdmin::init();
94
		TimberIntegrations::init();
95
	}
96
97
	/* Post Retrieval Routine
98
	================================ */
99
100
	/**
101
	 * Get post.
102
	 *
103
	 * @param mixed   $query
104
	 * @param string  $PostClass
105
	 * @return array|bool|null
106
	 */
107
	public static function get_post( $query = false, $PostClass = 'TimberPost' ) {
108
		return TimberPostGetter::get_post( $query, $PostClass );
109
	}
110
111
	/**
112
	 * Get posts.
113
	 *
114
	 * @param mixed   $query
115
	 * @param string  $PostClass
116
	 * @return array|bool|null
117
	 */
118
	public static function get_posts( $query = false, $PostClass = 'TimberPost', $return_collection = false ) {
119
		return TimberPostGetter::get_posts( $query, $PostClass, $return_collection );
120
	}
121
122
	/**
123
	 * Query post.
124
	 *
125
	 * @param mixed   $query
126
	 * @param string  $PostClass
127
	 * @return array|bool|null
128
	 */
129
	public static function query_post( $query = false, $PostClass = 'TimberPost' ) {
130
		return TimberPostGetter::query_post( $query, $PostClass );
131
	}
132
133
	/**
134
	 * Query posts.
135
	 *
136
	 * @param mixed   $query
137
	 * @param string  $PostClass
138
	 * @return array|bool|null
139
	 */
140
	public static function query_posts( $query = false, $PostClass = 'TimberPost' ) {
141
		return TimberPostGetter::query_posts( $query, $PostClass );
142
	}
143
144
	/**
145
	 * Get pids.
146
	 *
147
	 * @param array|string $query
148
	 * @return array
149
	 * @deprecated since 0.20.0
150
	 */
151
	static function get_pids( $query = null ) {
152
		return TimberPostGetter::get_pids( $query );
153
	}
154
155
	/**
156
	 * Get posts from loop.
157
	 *
158
	 * @param string  $PostClass
159
	 * @return array
160
	 * @deprecated since 0.20.0
161
	 */
162
	static function get_posts_from_loop( $PostClass ) {
163
		return TimberPostGetter::get_posts( $PostClass );
164
	}
165
166
	/**
167
	 * Get posts from slug.
168
	 *
169
	 * @param string  $slug
170
	 * @param string  $PostClass
171
	 * @return array
172
	 * @deprecated since 0.20.0
173
	 */
174
	static function get_posts_from_slug( $slug, $PostClass = 'TimberPost' ) {
175
		return TimberPostGetter::get_posts( $slug, $PostClass );
176
	}
177
178
	/**
179
	 * Get posts from WP_Query.
180
	 *
181
	 * @param array   $query
182
	 * @param string  $PostClass
183
	 * @return array
184
	 * @deprecated since 0.20.0
185
	 */
186
	static function get_posts_from_wp_query( $query = array(), $PostClass = 'TimberPost' ) {
187
		return TimberPostGetter::query_posts( $query, $PostClass );
188
	}
189
190
	/**
191
	 * Get posts from array of ids.
192
	 *
193
	 * @param array   $query
194
	 * @param string  $PostClass
195
	 * @return array|null
196
	 * @deprecated since 0.20.0
197
	 */
198
	static function get_posts_from_array_of_ids( $query = array(), $PostClass = 'TimberPost' ) {
199
		return TimberPostGetter::get_posts( $query, $PostClass );
200
	}
201
202
	/**
203
	 * Get pid.
204
	 *
205
	 * @param unknown $query
206
	 * @return int
207
	 * @deprecated since 0.20.0
208
	 */
209
	static function get_pid( $query ) {
210
		$pids = TimberPostGetter::get_pids( $query );
211
		if ( is_array( $pids ) && count( $pids ) ) {
212
			return $pids[0];
213
		}
214
	}
215
216
	/**
217
	 * WP_Query has posts.
218
	 *
219
	 * @return bool
220
	 * @deprecated since 0.20.0
221
	 */
222
	static function wp_query_has_posts() {
223
		return TimberPostGetter::wp_query_has_posts();
224
	}
225
226
	/* Term Retrieval
227
	================================ */
228
229
	/**
230
	 * Get terms.
231
	 *
232
	 * @param string|array $args
233
	 * @param array   $maybe_args
234
	 * @param string  $TermClass
235
	 * @return mixed
236
	 */
237
	public static function get_terms( $args = null, $maybe_args = array(), $TermClass = 'TimberTerm' ) {
238
		return TimberTermGetter::get_terms( $args, $maybe_args, $TermClass );
239
	}
240
241
	/* Site Retrieval
242
	================================ */
243
244
	/**
245
	 * Get sites.
246
	 *
247
	 * @param array|bool $blog_ids
248
	 * @return array
249
	 */
250
	public static function get_sites( $blog_ids = false ) {
251
		if ( !is_array( $blog_ids ) ) {
252
			global $wpdb;
253
			$blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs ORDER BY blog_id ASC" );
254
		}
255
		$return = array();
256
		foreach ( $blog_ids as $blog_id ) {
257
			$return[] = new TimberSite( $blog_id );
258
		}
259
		return $return;
260
	}
261
262
263
	/*  Template Setup and Display
264
	================================ */
265
266
	/**
267
	 * Get context.
268
	 *
269
	 * @return array
270
	 */
271
	public static function get_context() {
272
		$data = array();
273
		$data['http_host'] = 'http://' . TimberURLHelper::get_host();
274
		$data['wp_title'] = TimberHelper::get_wp_title();
275
		$data['wp_head'] = TimberHelper::function_wrapper( 'wp_head' );
276
		$data['wp_footer'] = TimberHelper::function_wrapper( 'wp_footer' );
277
		$data['body_class'] = implode( ' ', get_body_class() );
278
279
		$data['site'] = new TimberSite();
280
		$data['theme'] = $data['site']->theme;
281
		//deprecated, these should be fetched via TimberSite or TimberTheme
282
		$data['theme_dir'] = WP_CONTENT_SUBDIR.str_replace( WP_CONTENT_DIR, '', get_stylesheet_directory() );
283
		$data['language_attributes'] = TimberHelper::function_wrapper( 'language_attributes' );
284
		$data['stylesheet_uri'] = get_stylesheet_uri();
285
		$data['template_uri'] = get_template_directory_uri();
286
287
		$data['posts'] = Timber::query_posts();
288
289
		//deprecated, this should be fetched via TimberMenu
290
		if ( function_exists( 'wp_nav_menu' ) ) {
291
			$locations = get_nav_menu_locations();
292
			if ( count( $locations ) ) {
293
				$data['wp_nav_menu'] = wp_nav_menu( array( 'container_class' => 'menu-header', 'echo' => false, 'menu_class' => 'nav-menu' ) );
294
			}
295
		}
296
		$data = apply_filters( 'timber_context', $data );
297
		$data = apply_filters( 'timber/context', $data );
298
		return $data;
299
	}
300
301
	/**
302
	 * Compile function.
303
	 *
304
	 * @param array   $filenames
305
	 * @param array   $data
306
	 * @param bool    $expires
307
	 * @param string  $cache_mode
308
	 * @param bool    $via_render
309
	 * @return bool|string
310
	 */
311
	public static function compile( $filenames, $data = array(), $expires = false, $cache_mode = TimberLoader::CACHE_USE_DEFAULT, $via_render = false ) {
312
		$caller = self::get_calling_script_dir();
313
		$caller_file = self::get_calling_script_file();
314
		$caller_file = apply_filters( 'timber_calling_php_file', $caller_file );
315
		$loader = new TimberLoader( $caller );
316
		$file = $loader->choose_template( $filenames );
317
		$output = '';
318
		if ( is_null( $data ) ) {
319
			$data = array();
320
		}
321
		if ( strlen( $file ) ) {
322
			if ( $via_render ) {
323
				$file = apply_filters( 'timber_render_file', $file );
324
				$data = apply_filters( 'timber_render_data', $data );
325
			} else {
326
				$file = apply_filters( 'timber_compile_file', $file );
327
				$data = apply_filters( 'timber_compile_data', $data );
328
			}
329
			$output = $loader->render( $file, $data, $expires, $cache_mode );
330
		}
331
		do_action( 'timber_compile_done' );
332
		return $output;
333
	}
334
335
	/**
336
	 * Compile string.
337
	 *
338
	 * @param string  $string a string with twig variables.
339
	 * @param array   $data   an array with data in it.
340
	 * @return  bool|string
341
	 */
342
	public static function compile_string( $string, $data = array() ) {
343
		$dummy_loader = new TimberLoader();
344
		$dummy_loader->get_twig();
345
		$loader = new Twig_Loader_String();
346
		$twig = new Twig_Environment( $loader );
347
		$twig = apply_filters( 'timber/twig/filters', $twig );
348
		$twig = apply_filters( 'twig_apply_filters', $twig );
349
		return $twig->render( $string, $data );
350
	}
351
352
	/**
353
	 * Fetch function.
354
	 *
355
	 * @param array   $filenames
356
	 * @param array   $data
357
	 * @param bool    $expires
358
	 * @param string  $cache_mode
359
	 * @return bool|string
360
	 */
361
	public static function fetch( $filenames, $data = array(), $expires = false, $cache_mode = TimberLoader::CACHE_USE_DEFAULT ) {
362
		if ( $expires === true ) {
363
			//if this is reading as true; the user probably is using the old $echo param
364
			//so we should move all vars up by a spot
365
			$expires = $cache_mode;
366
			$cache_mode = TimberLoader::CACHE_USE_DEFAULT;
367
		}
368
		$output = self::compile( $filenames, $data, $expires, $cache_mode, true );
0 ignored issues
show
It seems like $expires defined by $cache_mode on line 365 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...
369
		$output = apply_filters( 'timber_compile_result', $output );
370
		return $output;
371
	}
372
373
	/**
374
	 * Render function.
375
	 *
376
	 * @param array   $filenames
377
	 * @param array   $data
378
	 * @param bool    $expires
379
	 * @param string  $cache_mode
380
	 * @return bool|string
381
	 */
382
	public static function render( $filenames, $data = array(), $expires = false, $cache_mode = TimberLoader::CACHE_USE_DEFAULT ) {
383
		$output = static::fetch( $filenames, $data, $expires, $cache_mode );
384
		echo $output;
385
		return $output;
386
	}
387
388
	/**
389
	 * Render string.
390
	 *
391
	 * @param string  $string a string with twig variables.
392
	 * @param array   $data   an array with data in it.
393
	 * @return  bool|string
394
	 */
395
	public static function render_string( $string, $data = array() ) {
396
		$compiled = self::compile_string( $string, $data );
397
		echo $compiled;
398
		return $compiled;
399
	}
400
401
402
	/*  Sidebar
403
	================================ */
404
405
	/**
406
	 * Get sidebar.
407
	 *
408
	 * @param string  $sidebar
409
	 * @param array   $data
410
	 * @return bool|string
411
	 */
412
	public static function get_sidebar( $sidebar = '', $data = array() ) {
413
		if ( $sidebar == '' ) {
414
			$sidebar = 'sidebar.php';
415
		}
416
		if ( strstr( strtolower( $sidebar ), '.php' ) ) {
417
			return self::get_sidebar_from_php( $sidebar, $data );
418
		}
419
		return self::compile( $sidebar, $data );
420
	}
421
422
	/**
423
	 * Get sidebar from PHP
424
	 *
425
	 * @param string  $sidebar
426
	 * @param array   $data
427
	 * @return string
428
	 */
429
	public static function get_sidebar_from_php( $sidebar = '', $data ) {
430
		$caller = self::get_calling_script_dir();
431
		$loader = new TimberLoader();
432
		$uris = $loader->get_locations( $caller );
433
		ob_start();
434
		$found = false;
435
		foreach ( $uris as $uri ) {
436
			if ( file_exists( trailingslashit( $uri ) . $sidebar ) ) {
437
				include trailingslashit( $uri ) . $sidebar;
438
				$found = true;
439
				break;
440
			}
441
		}
442
		if ( !$found ) {
443
			TimberHelper::error_log( 'error loading your sidebar, check to make sure the file exists' );
444
		}
445
		$ret = ob_get_contents();
446
		ob_end_clean();
447
		return $ret;
448
	}
449
450
	/* Widgets
451
	================================ */
452
453
	/**
454
	 * Get widgets.
455
	 *
456
	 * @param int     $widget_id
457
	 * @return TimberFunctionWrapper
458
	 */
459
	public static function get_widgets( $widget_id ) {
460
		return TimberHelper::function_wrapper( 'dynamic_sidebar', array( $widget_id ), true );
461
	}
462
463
464
	/*  Routes
465
	================================ */
466
467
	/**
468
	 * Add route.
469
	 *
470
	 * @param string  $route
471
	 * @param callable $callback
472
	 * @param array   $args
473
	 * @deprecated since 0.20.0
474
	 */
475
	public static function add_route( $route, $callback, $args = array() ) {
476
		Routes::map( $route, $callback, $args );
477
	}
478
479
	/**
480
	 * @deprecated since 0.22.2
481
	 */
482
	public function cancel_query() {
483
		add_action( 'posts_request', array( $this, 'cancel_query_posts_request' ) );
484
	}
485
486
	/**
487
	 * @deprecated since 0.22.2
488
	 */
489
	function cancel_query_posts_request() {
490
		if ( is_main_query() ) {
491
			wp_reset_query();
492
		}
493
	}
494
495
	/**
496
	 * Load template.
497
	 *
498
	 * @deprecated since 0.20.0
499
	 */
500
	public static function load_template( $template, $query = false, $status_code = 200, $tparams = false ) {
501
		return Routes::load( $template, $tparams, $query, $status_code );
502
	}
503
504
	/**
505
	 * Load view.
506
	 *
507
	 * @deprecated since 0.20.2
508
	 */
509
	public static function load_view( $template, $query = false, $status_code = 200, $tparams = false ) {
510
		return Routes::load( $template, $tparams, $query, $status_code );
511
	}
512
513
514
	/*  Pagination
515
	================================ */
516
517
	/**
518
	 * Get pagination.
519
	 *
520
	 * @param array   $prefs
521
	 * @return array mixed
522
	 */
523
	public static function get_pagination( $prefs = array() ) {
524
		global $wp_query;
525
		global $paged;
526
		global $wp_rewrite;
527
		$args = array();
528
		$args['total'] = ceil( $wp_query->found_posts / $wp_query->query_vars['posts_per_page'] );
529
		if ( $wp_rewrite->using_permalinks() ) {
530
			$url = explode( '?', get_pagenum_link( 0 ) );
531
			if ( isset( $url[1] ) ) {
532
				parse_str( $url[1], $query );
533
				$args['add_args'] = $query;
534
			}
535
			$args['format'] = 'page/%#%';
536
			$args['base'] = trailingslashit( $url[0] ).'%_%';
537
		} else {
538
			$big = 999999999;
539
			$args['base'] = str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) );
540
		}
541
		$args['type'] = 'array';
542
		$args['current'] = max( 1, get_query_var( 'paged' ) );
543
		$args['mid_size'] = max( 9 - $args['current'], 3 );
544
		$args['prev_next'] = false;
545
		if ( is_int( $prefs ) ) {
546
			$args['mid_size'] = $prefs - 2;
547
		} else {
548
			$args = array_merge( $args, $prefs );
549
		}
550
		$data = array();
551
		$data['current'] = $args['current'];
552
		$data['total'] = $args['total'];
553
		$data['pages'] = TimberHelper::paginate_links( $args );
554
		$next = get_next_posts_page_link( $args['total'] );
555
		if ( $next ) {
556
			$data['next'] = array( 'link' => untrailingslashit( $next ), 'class' => 'page-numbers next' );
557
		}
558
		$prev = previous_posts( false );
559
		if ( $prev ) {
560
			$data['prev'] = array( 'link' => untrailingslashit( $prev ), 'class' => 'page-numbers prev' );
561
		}
562
		if ( $paged < 2 ) {
563
			$data['prev'] = '';
564
		}
565
		return $data;
566
	}
567
568
	/*  Utility
569
	================================ */
570
571
	/**
572
	 * Get calling script path.
573
	 *
574
	 * @param int     $offset
575
	 * @return string
576
	 * @deprecated since 0.20.0
577
	 */
578
	public static function get_calling_script_path( $offset = 0 ) {
579
		$dir = self::get_calling_script_dir( $offset );
580
		return str_replace( ABSPATH, '', realpath( $dir ) );
581
	}
582
583
	/**
584
	 * Get calling script dir.
585
	 *
586
	 * @return string
587
	 */
588
	public static function get_calling_script_dir( $offset = 0 ) {
589
		$caller = self::get_calling_script_file( $offset );
590
		if ( !is_null( $caller ) ) {
591
			$pathinfo = pathinfo( $caller );
592
			$dir = $pathinfo['dirname'];
593
			return $dir;
594
		}
595
	}
596
597
	/**
598
	 * Get calling script file.
599
	 *
600
	 * @param int     $offset
601
	 * @return string|null
602
	 * @deprecated since 0.20.0
603
	 */
604
	public static function get_calling_script_file( $offset = 0 ) {
605
		$caller = null;
606
		$backtrace = debug_backtrace();
607
		$i = 0;
608
		foreach ( $backtrace as $trace ) {
609
			if ( $trace['file'] != __FILE__ ) {
610
				$caller = $trace['file'];
611
				break;
612
			}
613
			$i++;
614
		}
615
		if ( $offset ) {
616
			$caller = $backtrace[$i + $offset]['file'];
617
		}
618
		return $caller;
619
	}
620
621
	/**
622
	 * Is post class or class map.
623
	 *
624
	 * @param string|array $args
625
	 * @return bool
626
	 * @deprecated since 0.20.0
627
	 */
628
	public static function is_post_class_or_class_map( $args ) {
629
		return TimberPostGetter::is_post_class_or_class_map( $args );
630
	}
631
632
}
633