PageRenderTime 32ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/includes/plugins/timber-library/lib/timber-loader.php

https://gitlab.com/aristath/maera
PHP | 412 lines | 374 code | 15 blank | 23 comment | 16 complexity | a2425f7e48d84a0a561fa61d00997df6 MD5 | raw file
  1. <?php
  2. class TimberLoader {
  3. const CACHEGROUP = 'timberloader';
  4. const TRANS_KEY_LEN = 50;
  5. const CACHE_NONE = 'none';
  6. const CACHE_OBJECT = 'cache';
  7. const CACHE_TRANSIENT = 'transient';
  8. const CACHE_SITE_TRANSIENT = 'site-transient';
  9. const CACHE_USE_DEFAULT = 'default';
  10. public static $cache_modes = array(
  11. self::CACHE_NONE,
  12. self::CACHE_OBJECT,
  13. self::CACHE_TRANSIENT,
  14. self::CACHE_SITE_TRANSIENT
  15. );
  16. protected $cache_mode = self::CACHE_TRANSIENT;
  17. public $locations;
  18. /**
  19. * @param bool $caller
  20. */
  21. function __construct($caller = false) {
  22. $this->locations = $this->get_locations($caller);
  23. $this->cache_mode = apply_filters('timber_cache_mode', $this->cache_mode);
  24. $this->cache_mode = apply_filters('timber/cache/mode', $this->cache_mode);
  25. }
  26. /**
  27. * @param string $file
  28. * @param array $data
  29. * @param bool $expires
  30. * @param string $cache_mode
  31. * @return bool|string
  32. */
  33. function render($file, $data = null, $expires = false, $cache_mode = self::CACHE_USE_DEFAULT) {
  34. // Different $expires if user is anonymous or logged in
  35. if (is_array($expires)) {
  36. if (is_user_logged_in() && isset($expires[1])) {
  37. $expires = $expires[1];
  38. } else {
  39. $expires = $expires[0];
  40. }
  41. }
  42. $key = null;
  43. $output = false;
  44. if (false !== $expires) {
  45. ksort($data);
  46. $key = md5($file . json_encode($data));
  47. $output = $this->get_cache($key, self::CACHEGROUP, $cache_mode);
  48. }
  49. if (false === $output || null === $output) {
  50. $twig = $this->get_twig();
  51. if (strlen($file)) {
  52. $loader = $this->get_loader();
  53. $result = $loader->getCacheKey($file);
  54. do_action('timber_loader_render_file', $result);
  55. }
  56. $data = apply_filters('timber_loader_render_data', $data);
  57. $data = apply_filters('timber/loader/render_data', $data);
  58. $output = $twig->render($file, $data);
  59. }
  60. if (false !== $output && false !== $expires && null !== $key) {
  61. $this->set_cache($key, $output, self::CACHEGROUP, $expires, $cache_mode);
  62. }
  63. $output = apply_filters('timber_output', $output);
  64. return apply_filters('timber/output', $output);
  65. }
  66. /**
  67. * @param array $filenames
  68. * @return bool
  69. */
  70. function choose_template($filenames) {
  71. if (is_array($filenames)) {
  72. /* its an array so we have to figure out which one the dev wants */
  73. foreach ($filenames as $filename) {
  74. if ($this->template_exists($filename)) {
  75. return $filename;
  76. }
  77. }
  78. return false;
  79. }
  80. return $filenames;
  81. }
  82. /**
  83. * @param string $file
  84. * @return bool
  85. */
  86. function template_exists($file) {
  87. foreach ($this->locations as $dir) {
  88. $look_for = trailingslashit($dir) . $file;
  89. if (file_exists($look_for)) {
  90. return true;
  91. }
  92. }
  93. return false;
  94. }
  95. /**
  96. * @return array
  97. */
  98. function get_locations_theme() {
  99. $theme_locs = array();
  100. $child_loc = get_stylesheet_directory();
  101. $parent_loc = get_template_directory();
  102. if (DIRECTORY_SEPARATOR == '\\') {
  103. $child_loc = str_replace('/', '\\', $child_loc);
  104. $parent_loc = str_replace('/', '\\', $parent_loc);
  105. }
  106. $theme_locs[] = $child_loc;
  107. foreach ($this->get_locations_theme_dir() as $dirname) {
  108. $theme_locs[] = trailingslashit($child_loc) . trailingslashit($dirname);
  109. }
  110. if ($child_loc != $parent_loc) {
  111. $theme_locs[] = $parent_loc;
  112. foreach ($this->get_locations_theme_dir() as $dirname) {
  113. $theme_locs[] = trailingslashit($parent_loc) . trailingslashit($dirname);
  114. }
  115. }
  116. //now make sure theres a trailing slash on everything
  117. $theme_locs = array_map('trailingslashit', $theme_locs);
  118. return $theme_locs;
  119. }
  120. /**
  121. * returns an array of the directory inside themes that holds twig files
  122. * @return string[] the names of directores, ie: array('templats', 'views');
  123. */
  124. private function get_locations_theme_dir() {
  125. if (is_string(Timber::$dirname)) {
  126. return array(Timber::$dirname);
  127. }
  128. return Timber::$dirname;
  129. }
  130. /**
  131. * @return array
  132. */
  133. function get_locations_user() {
  134. $locs = array();
  135. if (isset(Timber::$locations)) {
  136. if (is_string(Timber::$locations)) {
  137. Timber::$locations = array(Timber::$locations);
  138. }
  139. foreach (Timber::$locations as $tloc) {
  140. $tloc = realpath($tloc);
  141. if (is_dir($tloc)) {
  142. $locs[] = $tloc;
  143. }
  144. }
  145. }
  146. return $locs;
  147. }
  148. /**
  149. * @param bool $caller
  150. * @return array
  151. */
  152. function get_locations_caller($caller = false) {
  153. $locs = array();
  154. if ($caller && is_string($caller)) {
  155. $caller = trailingslashit($caller);
  156. if (is_dir($caller)) {
  157. $locs[] = $caller;
  158. }
  159. foreach ($this->get_locations_theme_dir() as $dirname) {
  160. $caller_sub = $caller . trailingslashit($dirname);
  161. if (is_dir($caller_sub)) {
  162. $locs[] = $caller_sub;
  163. }
  164. }
  165. }
  166. return $locs;
  167. }
  168. /**
  169. * @param bool $caller
  170. * @return array
  171. */
  172. function get_locations($caller = false) {
  173. //prioirty: user locations, caller (but not theme), child theme, parent theme, caller
  174. $locs = array();
  175. $locs = array_merge($locs, $this->get_locations_user());
  176. $locs = array_merge($locs, $this->get_locations_caller($caller));
  177. //remove themes from caller
  178. $locs = array_diff($locs, $this->get_locations_theme());
  179. $locs = array_merge($locs, $this->get_locations_theme());
  180. $locs = array_merge($locs, $this->get_locations_caller($caller));
  181. $locs = array_unique($locs);
  182. $locs = apply_filters('timber_locations', $locs);
  183. $locs = apply_filters('timber/locations', $locs);
  184. return $locs;
  185. }
  186. /**
  187. * @return Twig_Loader_Filesystem
  188. */
  189. function get_loader() {
  190. $paths = array();
  191. foreach ($this->locations as $loc) {
  192. $loc = realpath($loc);
  193. if (is_dir($loc)) {
  194. $loc = realpath($loc);
  195. $paths[] = $loc;
  196. } else {
  197. //error_log($loc.' is not a directory');
  198. }
  199. }
  200. if (!ini_get('open_basedir')) {
  201. $paths[] = '/';
  202. } else {
  203. $paths[] = ABSPATH;
  204. }
  205. $paths = apply_filters('timber/loader/paths', $paths);
  206. $loader = new Twig_Loader_Filesystem($paths);
  207. return $loader;
  208. }
  209. /**
  210. * @return Twig_Environment
  211. */
  212. function get_twig() {
  213. $loader = $this->get_loader();
  214. $params = array('debug' => WP_DEBUG, 'autoescape' => false);
  215. if (isset(Timber::$autoescape)) {
  216. $params['autoescape'] = Timber::$autoescape;
  217. }
  218. if (Timber::$cache == true) {
  219. Timber::$twig_cache = true;
  220. }
  221. if (Timber::$twig_cache) {
  222. $twig_cache_loc = apply_filters( 'timber/cache/location', TIMBER_LOC . '/cache/twig' );
  223. if (!file_exists($twig_cache_loc)) {
  224. mkdir($twig_cache_loc, 0777, true);
  225. }
  226. $params['cache'] = $twig_cache_loc;
  227. }
  228. $twig = new Twig_Environment($loader, $params);
  229. if (WP_DEBUG) {
  230. $twig->addExtension(new Twig_Extension_Debug());
  231. }
  232. $twig->addExtension($this->_get_cache_extension());
  233. $twig = apply_filters('twig_apply_filters', $twig);
  234. $twig = apply_filters('timber/loader/twig', $twig);
  235. return $twig;
  236. }
  237. public function clear_cache_timber($cache_mode = self::CACHE_USE_DEFAULT){
  238. //_transient_timberloader
  239. $object_cache = false;
  240. if (isset($GLOBALS['wp_object_cache']) && is_object($GLOBALS['wp_object_cache'])) {
  241. $object_cache = true;
  242. }
  243. $cache_mode = $this->_get_cache_mode($cache_mode);
  244. if (self::CACHE_TRANSIENT === $cache_mode) {
  245. global $wpdb;
  246. $query = $wpdb->prepare("DELETE FROM $wpdb->options WHERE option_name LIKE '%s'", '_transient_timberloader_%');
  247. $wpdb->query( $query );
  248. return true;
  249. } else if (self::CACHE_SITE_TRANSIENT === $cache_mode) {
  250. global $wpdb;
  251. $query = $wpdb->prepare("DELETE FROM $wpdb->options WHERE option_name LIKE '%s'", '_transient_timberloader_%');
  252. $wpdb->query( $query );
  253. return true;
  254. } else if (self::CACHE_OBJECT === $cache_mode && $object_cache) {
  255. global $wp_object_cache;
  256. if (isset($wp_object_cache->cache[self::CACHEGROUP])){
  257. unset($wp_object_cache->cache[self::CACHEGROUP]);
  258. return true;
  259. }
  260. }
  261. return false;
  262. }
  263. public function clear_cache_twig() {
  264. $twig = $this->get_twig();
  265. $twig->clearCacheFiles();
  266. $cache = $twig->getCache();
  267. if ($cache){
  268. self::rrmdir($twig->getCache());
  269. return true;
  270. }
  271. return false;
  272. }
  273. /**
  274. * @param string|false $dirPath
  275. */
  276. public static function rrmdir($dirPath) {
  277. if (! is_dir($dirPath)) {
  278. throw new InvalidArgumentException("$dirPath must be a directory");
  279. }
  280. if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') {
  281. $dirPath .= '/';
  282. }
  283. $files = glob($dirPath . '*', GLOB_MARK);
  284. foreach ($files as $file) {
  285. if (is_dir($file)) {
  286. self::rrmdir($file);
  287. } else {
  288. unlink($file);
  289. }
  290. }
  291. rmdir($dirPath);
  292. }
  293. /**
  294. * @return \Asm89\Twig\CacheExtension\Extension
  295. */
  296. private function _get_cache_extension() {
  297. $key_generator = new \Timber\Cache\KeyGenerator();
  298. $cache_provider = new \Timber\Cache\WPObjectCacheAdapter( $this );
  299. $cache_strategy = new \Asm89\Twig\CacheExtension\CacheStrategy\GenerationalCacheStrategy( $cache_provider, $key_generator );
  300. $cache_extension = new \Asm89\Twig\CacheExtension\Extension( $cache_strategy );
  301. return $cache_extension;
  302. }
  303. /**
  304. * @param string $key
  305. * @param string $group
  306. * @param string $cache_mode
  307. * @return bool
  308. */
  309. public function get_cache($key, $group = self::CACHEGROUP, $cache_mode = self::CACHE_USE_DEFAULT) {
  310. $object_cache = false;
  311. if (isset($GLOBALS['wp_object_cache']) && is_object($GLOBALS['wp_object_cache'])) {
  312. $object_cache = true;
  313. }
  314. $cache_mode = $this->_get_cache_mode($cache_mode);
  315. $value = false;
  316. $trans_key = substr($group . '_' . $key, 0, self::TRANS_KEY_LEN);
  317. if (self::CACHE_TRANSIENT === $cache_mode)
  318. $value = get_transient($trans_key);
  319. elseif (self::CACHE_SITE_TRANSIENT === $cache_mode)
  320. $value = get_site_transient($trans_key);
  321. elseif (self::CACHE_OBJECT === $cache_mode && $object_cache)
  322. $value = wp_cache_get($key, $group);
  323. return $value;
  324. }
  325. /**
  326. * @param string $key
  327. * @param string|boolean $value
  328. * @param string $group
  329. * @param int $expires
  330. * @param string $cache_mode
  331. * @return string|boolean
  332. */
  333. public function set_cache($key, $value, $group = self::CACHEGROUP, $expires = 0, $cache_mode = self::CACHE_USE_DEFAULT) {
  334. $object_cache = false;
  335. if (isset($GLOBALS['wp_object_cache']) && is_object($GLOBALS['wp_object_cache'])) {
  336. $object_cache = true;
  337. }
  338. if ((int)$expires < 1)
  339. $expires = 0;
  340. $cache_mode = self::_get_cache_mode($cache_mode);
  341. $trans_key = substr($group . '_' . $key, 0, self::TRANS_KEY_LEN);
  342. if (self::CACHE_TRANSIENT === $cache_mode)
  343. set_transient($trans_key, $value, $expires);
  344. elseif (self::CACHE_SITE_TRANSIENT === $cache_mode)
  345. set_site_transient($trans_key, $value, $expires);
  346. elseif (self::CACHE_OBJECT === $cache_mode && $object_cache)
  347. wp_cache_set($key, $value, $group, $expires);
  348. return $value;
  349. }
  350. /**
  351. * @param string $cache_mode
  352. * @return string
  353. */
  354. private function _get_cache_mode($cache_mode) {
  355. if (empty($cache_mode) || self::CACHE_USE_DEFAULT === $cache_mode) {
  356. $cache_mode = $this->cache_mode;
  357. }
  358. // Fallback if self::$cache_mode did not get a valid value
  359. if (!in_array($cache_mode, self::$cache_modes)) {
  360. $cache_mode = self::CACHE_OBJECT;
  361. }
  362. return $cache_mode;
  363. }
  364. }