Completed
Pull Request — master (#789)
by
unknown
05:20
created

timber.php (2 issues)

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 );
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
		if ( is_int( $prefs ) ) {
545
			$args['mid_size'] = $prefs - 2;
546
		} else {
547
			$args = array_merge( $args, $prefs );
548
		}
549
		$data = array();
550
		$data['current'] = $args['current'];
551
		$data['total'] = $args['total'];
552
		$data['pages'] = TimberHelper::paginate_links( $args );
553
		$next = get_next_posts_page_link( $args['total'] );
554
		if ( $next ) {
555
			$data['next'] = array( 'link' => untrailingslashit( $next ), 'class' => 'page-numbers next' );
556
		}
557
		$prev = previous_posts( false );
558
		if ( $prev ) {
559
			$data['prev'] = array( 'link' => untrailingslashit( $prev ), 'class' => 'page-numbers prev' );
560
		}
561
		if ( $paged < 2 ) {
562
			$data['prev'] = '';
563
		}
564
		return $data;
565
	}
566
567
	/*  Utility
568
	================================ */
569
570
	/**
571
	 * Get calling script path.
572
	 *
573
	 * @param int     $offset
574
	 * @return string
575
	 * @deprecated since 0.20.0
576
	 */
577
	public static function get_calling_script_path( $offset = 0 ) {
578
		$dir = self::get_calling_script_dir( $offset );
579
		return str_replace( ABSPATH, '', realpath( $dir ) );
580
	}
581
582
	/**
583
	 * Get calling script dir.
584
	 *
585
	 * @return string
586
	 */
587
	public static function get_calling_script_dir( $offset = 0 ) {
588
		$caller = self::get_calling_script_file( $offset );
589
		if ( !is_null( $caller ) ) {
590
			$pathinfo = pathinfo( $caller );
591
			$dir = $pathinfo['dirname'];
592
			return $dir;
593
		}
594
	}
595
596
	/**
597
	 * Get calling script file.
598
	 *
599
	 * @param int     $offset
600
	 * @return string|null
601
	 * @deprecated since 0.20.0
602
	 */
603
	public static function get_calling_script_file( $offset = 0 ) {
604
		$caller = null;
605
		$backtrace = debug_backtrace();
606
		$i = 0;
607
		foreach ( $backtrace as $trace ) {
608
			if ( array_key_exists('file', $trace) && $trace['file'] != __FILE__ ) {
0 ignored issues
show
Expected 1 spaces after opening bracket; 0 found
Loading history...
Expected 1 spaces before closing bracket; 0 found
Loading history...
609
				$caller = $trace['file'];
610
				break;
611
			}
612
			$i++;
613
		}
614
		if ( $offset ) {
615
			$caller = $backtrace[$i + $offset]['file'];
616
		}
617
		return $caller;
618
	}
619
620
	/**
621
	 * Is post class or class map.
622
	 *
623
	 * @param string|array $args
624
	 * @return bool
625
	 * @deprecated since 0.20.0
626
	 */
627
	public static function is_post_class_or_class_map( $args ) {
628
		return TimberPostGetter::is_post_class_or_class_map( $args );
629
	}
630
631
}
632