PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/timber.php

https://gitlab.com/aristath/timber
PHP | 495 lines | 245 code | 47 blank | 203 comment | 32 complexity | 69ceedb7291d1149b4c8f122774fe47f MD5 | raw file
  1. <?php
  2. /**
  3. * Timber Class.
  4. *
  5. * Main class called Timber for this plugin.
  6. *
  7. * Usage:
  8. * $posts = Timber::get_posts();
  9. * $posts = Timber::get_posts('post_type = article')
  10. * $posts = Timber::get_posts(array('post_type' => 'article', 'category_name' => 'sports')); // uses wp_query format.
  11. * $posts = Timber::get_posts(array(23,24,35,67), 'InkwellArticle');
  12. *
  13. * $context = Timber::get_context(); // returns wp favorites!
  14. * $context['posts'] = $posts;
  15. * Timber::render('index.twig', $context);
  16. */
  17. class Timber {
  18. public static $locations;
  19. public static $dirname;
  20. public static $twig_cache = false;
  21. public static $cache = false;
  22. public static $auto_meta = true;
  23. public static $autoescape = false;
  24. /**
  25. * @codeCoverageIgnore
  26. */
  27. public function __construct() {
  28. if ( !defined('ABSPATH') ) {
  29. return;
  30. }
  31. $this->test_compatibility();
  32. $this->init_constants();
  33. $this->init();
  34. }
  35. /**
  36. * Tests whether we can use Timber
  37. * @codeCoverageIgnore
  38. * @return
  39. */
  40. protected function test_compatibility() {
  41. if ( is_admin() || $_SERVER['PHP_SELF'] == '/wp-login.php' ) {
  42. return;
  43. }
  44. if ( version_compare( phpversion(), '5.3.0', '<' ) && !is_admin() ) {
  45. trigger_error( 'Timber requires PHP 5.3.0 or greater. You have '.phpversion(), E_USER_ERROR );
  46. }
  47. if ( !class_exists( 'Twig_Autoloader' ) ) {
  48. trigger_error( 'You have not run "composer install" to download required dependencies for Timber, you can read more on https://github.com/timber/timber#installation', E_USER_ERROR );
  49. }
  50. }
  51. function init_constants() {
  52. defined( "TIMBER_LOC" ) or define( "TIMBER_LOC", realpath( dirname(__DIR__) ) );
  53. }
  54. /**
  55. * @codeCoverageIgnore
  56. */
  57. protected function init() {
  58. TimberTwig::init();
  59. TimberRoutes::init( $this );
  60. TimberImageHelper::init();
  61. TimberAdmin::init();
  62. TimberIntegrations::init();
  63. }
  64. /* Post Retrieval Routine
  65. ================================ */
  66. /**
  67. * Get post.
  68. *
  69. * @param mixed $query
  70. * @param string $PostClass
  71. * @return array|bool|null
  72. */
  73. public static function get_post( $query = false, $PostClass = 'TimberPost' ) {
  74. return TimberPostGetter::get_post( $query, $PostClass );
  75. }
  76. /**
  77. * Get posts.
  78. * @example
  79. * ```php
  80. * $posts = Timber::get_posts();
  81. * $posts = Timber::get_posts('post_type = article')
  82. * $posts = Timber::get_posts(array('post_type' => 'article', 'category_name' => 'sports')); // uses wp_query format.
  83. * $posts = Timber::get_posts('post_type=any', array('portfolio' => 'MyPortfolioClass', 'alert' => 'MyAlertClass')); //use a classmap for the $PostClass
  84. * ```
  85. * @param mixed $query
  86. * @param string|array $PostClass
  87. * @return array|bool|null
  88. */
  89. public static function get_posts( $query = false, $PostClass = 'TimberPost', $return_collection = false ) {
  90. return TimberPostGetter::get_posts( $query, $PostClass, $return_collection );
  91. }
  92. /**
  93. * Query post.
  94. *
  95. * @param mixed $query
  96. * @param string $PostClass
  97. * @return array|bool|null
  98. */
  99. public static function query_post( $query = false, $PostClass = 'TimberPost' ) {
  100. return TimberPostGetter::query_post( $query, $PostClass );
  101. }
  102. /**
  103. * Query posts.
  104. *
  105. * @param mixed $query
  106. * @param string $PostClass
  107. * @return array|bool|null
  108. */
  109. public static function query_posts( $query = false, $PostClass = 'TimberPost' ) {
  110. return TimberPostGetter::query_posts( $query, $PostClass );
  111. }
  112. /**
  113. * WP_Query has posts.
  114. *
  115. * @return bool
  116. * @deprecated since 0.20.0
  117. */
  118. static function wp_query_has_posts() {
  119. return TimberPostGetter::wp_query_has_posts();
  120. }
  121. /* Term Retrieval
  122. ================================ */
  123. /**
  124. * Get terms.
  125. *
  126. * @param string|array $args
  127. * @param array $maybe_args
  128. * @param string $TermClass
  129. * @return mixed
  130. */
  131. public static function get_terms( $args = null, $maybe_args = array(), $TermClass = 'TimberTerm' ) {
  132. return TimberTermGetter::get_terms( $args, $maybe_args, $TermClass );
  133. }
  134. /* Site Retrieval
  135. ================================ */
  136. /**
  137. * Get sites.
  138. *
  139. * @param array|bool $blog_ids
  140. * @return array
  141. */
  142. public static function get_sites( $blog_ids = false ) {
  143. if ( !is_array( $blog_ids ) ) {
  144. global $wpdb;
  145. $blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs ORDER BY blog_id ASC" );
  146. }
  147. $return = array();
  148. foreach ( $blog_ids as $blog_id ) {
  149. $return[] = new TimberSite( $blog_id );
  150. }
  151. return $return;
  152. }
  153. /* Template Setup and Display
  154. ================================ */
  155. /**
  156. * Get context.
  157. *
  158. * @return array
  159. */
  160. public static function get_context() {
  161. $data = array();
  162. $data['http_host'] = 'http://' . TimberURLHelper::get_host();
  163. $data['wp_title'] = TimberHelper::get_wp_title();
  164. $data['wp_head'] = TimberHelper::function_wrapper( 'wp_head' );
  165. $data['wp_footer'] = TimberHelper::function_wrapper( 'wp_footer' );
  166. $data['body_class'] = implode( ' ', get_body_class() );
  167. $data['site'] = new TimberSite();
  168. $data['request'] = new TimberRequest();
  169. $user = new TimberUser();
  170. $data['user'] = ($user->ID) ? $user : false;
  171. $data['theme'] = $data['site']->theme;
  172. $data['posts'] = Timber::query_posts();
  173. $data = apply_filters( 'timber_context', $data );
  174. $data = apply_filters( 'timber/context', $data );
  175. return $data;
  176. }
  177. /**
  178. * Compile function.
  179. *
  180. * @param array $filenames
  181. * @param array $data
  182. * @param bool $expires
  183. * @param string $cache_mode
  184. * @param bool $via_render
  185. * @return bool|string
  186. */
  187. public static function compile( $filenames, $data = array(), $expires = false, $cache_mode = TimberLoader::CACHE_USE_DEFAULT, $via_render = false ) {
  188. $caller = self::get_calling_script_dir();
  189. $caller_file = self::get_calling_script_file();
  190. $caller_file = apply_filters( 'timber_calling_php_file', $caller_file );
  191. $loader = new TimberLoader( $caller );
  192. $file = $loader->choose_template( $filenames );
  193. $output = '';
  194. if ( is_null( $data ) ) {
  195. $data = array();
  196. }
  197. if ( strlen( $file ) ) {
  198. if ( $via_render ) {
  199. $file = apply_filters( 'timber_render_file', $file );
  200. $data = apply_filters( 'timber_render_data', $data );
  201. } else {
  202. $file = apply_filters( 'timber_compile_file', $file );
  203. $data = apply_filters( 'timber_compile_data', $data );
  204. }
  205. $output = $loader->render( $file, $data, $expires, $cache_mode );
  206. }
  207. do_action( 'timber_compile_done' );
  208. return $output;
  209. }
  210. /**
  211. * Compile string.
  212. *
  213. * @param string $string a string with twig variables.
  214. * @param array $data an array with data in it.
  215. * @return bool|string
  216. */
  217. public static function compile_string( $string, $data = array() ) {
  218. $dummy_loader = new TimberLoader();
  219. $twig = $dummy_loader->get_twig();
  220. $template = $twig->createTemplate($string);
  221. return $template->render( $data );
  222. }
  223. /**
  224. * Fetch function.
  225. *
  226. * @param array $filenames
  227. * @param array $data
  228. * @param bool $expires
  229. * @param string $cache_mode
  230. * @return bool|string
  231. */
  232. public static function fetch( $filenames, $data = array(), $expires = false, $cache_mode = TimberLoader::CACHE_USE_DEFAULT ) {
  233. if ( $expires === true ) {
  234. //if this is reading as true; the user probably is using the old $echo param
  235. //so we should move all vars up by a spot
  236. $expires = $cache_mode;
  237. $cache_mode = TimberLoader::CACHE_USE_DEFAULT;
  238. }
  239. $output = self::compile( $filenames, $data, $expires, $cache_mode, true );
  240. $output = apply_filters( 'timber_compile_result', $output );
  241. return $output;
  242. }
  243. /**
  244. * Render function.
  245. *
  246. * @param array $filenames
  247. * @param array $data
  248. * @param bool $expires
  249. * @param string $cache_mode
  250. * @return bool|string
  251. */
  252. public static function render( $filenames, $data = array(), $expires = false, $cache_mode = TimberLoader::CACHE_USE_DEFAULT ) {
  253. $output = static::fetch( $filenames, $data, $expires, $cache_mode );
  254. echo $output;
  255. return $output;
  256. }
  257. /**
  258. * Render string.
  259. *
  260. * @param string $string a string with twig variables.
  261. * @param array $data an array with data in it.
  262. * @return bool|string
  263. */
  264. public static function render_string( $string, $data = array() ) {
  265. $compiled = self::compile_string( $string, $data );
  266. echo $compiled;
  267. return $compiled;
  268. }
  269. /* Sidebar
  270. ================================ */
  271. /**
  272. * Get sidebar.
  273. *
  274. * @param string $sidebar
  275. * @param array $data
  276. * @return bool|string
  277. */
  278. public static function get_sidebar( $sidebar = '', $data = array() ) {
  279. if ( $sidebar == '' ) {
  280. $sidebar = 'sidebar.php';
  281. }
  282. if ( strstr( strtolower( $sidebar ), '.php' ) ) {
  283. return self::get_sidebar_from_php( $sidebar, $data );
  284. }
  285. return self::compile( $sidebar, $data );
  286. }
  287. /**
  288. * Get sidebar from PHP
  289. *
  290. * @param string $sidebar
  291. * @param array $data
  292. * @return string
  293. */
  294. public static function get_sidebar_from_php( $sidebar = '', $data ) {
  295. $caller = self::get_calling_script_dir();
  296. $loader = new TimberLoader();
  297. $uris = $loader->get_locations( $caller );
  298. ob_start();
  299. $found = false;
  300. foreach ( $uris as $uri ) {
  301. if ( file_exists( trailingslashit( $uri ) . $sidebar ) ) {
  302. include trailingslashit( $uri ) . $sidebar;
  303. $found = true;
  304. break;
  305. }
  306. }
  307. if ( !$found ) {
  308. TimberHelper::error_log( 'error loading your sidebar, check to make sure the file exists' );
  309. }
  310. $ret = ob_get_contents();
  311. ob_end_clean();
  312. return $ret;
  313. }
  314. /* Widgets
  315. ================================ */
  316. /**
  317. * Get widgets.
  318. *
  319. * @param int $widget_id
  320. * @return TimberFunctionWrapper
  321. */
  322. public static function get_widgets( $widget_id ) {
  323. return trim( TimberHelper::function_wrapper( 'dynamic_sidebar', array( $widget_id ), true ) );
  324. }
  325. /* Routes
  326. ================================ */
  327. /**
  328. * Add route.
  329. *
  330. * @param string $route
  331. * @param callable $callback
  332. * @param array $args
  333. * @deprecated since 0.20.0
  334. */
  335. public static function add_route( $route, $callback, $args = array() ) {
  336. Routes::map( $route, $callback, $args );
  337. }
  338. /**
  339. * Load template.
  340. *
  341. * @deprecated since 0.20.0
  342. */
  343. public static function load_template( $template, $query = false, $status_code = 200, $tparams = false ) {
  344. return Routes::load( $template, $tparams, $query, $status_code );
  345. }
  346. /**
  347. * Load view.
  348. *
  349. * @deprecated since 0.20.2
  350. */
  351. public static function load_view( $template, $query = false, $status_code = 200, $tparams = false ) {
  352. return Routes::load( $template, $tparams, $query, $status_code );
  353. }
  354. /* Pagination
  355. ================================ */
  356. /**
  357. * Get pagination.
  358. *
  359. * @param array $prefs
  360. * @return array mixed
  361. */
  362. public static function get_pagination( $prefs = array() ) {
  363. global $wp_query;
  364. global $paged;
  365. global $wp_rewrite;
  366. $args = array();
  367. $args['total'] = ceil( $wp_query->found_posts / $wp_query->query_vars['posts_per_page'] );
  368. if ( $wp_rewrite->using_permalinks() ) {
  369. $url = explode( '?', get_pagenum_link( 0 ) );
  370. if ( isset( $url[1] ) ) {
  371. parse_str( $url[1], $query );
  372. $args['add_args'] = $query;
  373. }
  374. $args['format'] = 'page/%#%';
  375. $args['base'] = trailingslashit( $url[0] ).'%_%';
  376. } else {
  377. $big = 999999999;
  378. $args['base'] = str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) );
  379. }
  380. $args['type'] = 'array';
  381. $args['current'] = max( 1, get_query_var( 'paged' ) );
  382. $args['mid_size'] = max( 9 - $args['current'], 3 );
  383. if ( is_int( $prefs ) ) {
  384. $args['mid_size'] = $prefs - 2;
  385. } else {
  386. $args = array_merge( $args, $prefs );
  387. }
  388. $data = array();
  389. $data['current'] = $args['current'];
  390. $data['total'] = $args['total'];
  391. $data['pages'] = TimberHelper::paginate_links( $args );
  392. $next = get_next_posts_page_link( $args['total'] );
  393. if ( $next ) {
  394. $data['next'] = array( 'link' => untrailingslashit( $next ), 'class' => 'page-numbers next' );
  395. }
  396. $prev = previous_posts( false );
  397. if ( $prev ) {
  398. $data['prev'] = array( 'link' => untrailingslashit( $prev ), 'class' => 'page-numbers prev' );
  399. }
  400. if ( $paged < 2 ) {
  401. $data['prev'] = '';
  402. }
  403. if ( $data['total'] === ( double ) 0 ) {
  404. $data['next'] = '';
  405. }
  406. return $data;
  407. }
  408. /* Utility
  409. ================================ */
  410. /**
  411. * Get calling script dir.
  412. *
  413. * @return string
  414. */
  415. public static function get_calling_script_dir( $offset = 0 ) {
  416. $caller = self::get_calling_script_file( $offset );
  417. if ( !is_null( $caller ) ) {
  418. $pathinfo = pathinfo( $caller );
  419. $dir = $pathinfo['dirname'];
  420. return $dir;
  421. }
  422. }
  423. /**
  424. * Get calling script file.
  425. *
  426. * @param int $offset
  427. * @return string|null
  428. * @deprecated since 0.20.0
  429. */
  430. public static function get_calling_script_file( $offset = 0 ) {
  431. $caller = null;
  432. $backtrace = debug_backtrace();
  433. $i = 0;
  434. foreach ( $backtrace as $trace ) {
  435. if ( array_key_exists('file', $trace) && $trace['file'] != __FILE__ ) {
  436. $caller = $trace['file'];
  437. break;
  438. }
  439. $i++;
  440. }
  441. if ( $offset ) {
  442. $caller = $backtrace[$i + $offset]['file'];
  443. }
  444. return $caller;
  445. }
  446. }
  447. $timber = new Timber();
  448. Timber::$dirname = 'views';