PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/opentickets-community-edition/inc/sys/base-widget.class.php

https://gitlab.com/leobelizquierdo/cabotsubmitter-wordpress
PHP | 325 lines | 221 code | 36 blank | 68 comment | 63 complexity | 18e237f5a81a39a587e66809dec87f25 MD5 | raw file
  1. <?php if ( __FILE__ == $_SERVER['SCRIPT_FILENAME'] ) die( header( 'Location: /') );
  2. // allow external plugins to override this class
  3. if (!class_exists('qsot_base_widget')):
  4. /* Creates an even more streamlined base widget. also adds templating. */
  5. abstract class qsot_events_base_widget extends WP_Widget {
  6. protected $_base_dir;
  7. protected $_base_url;
  8. protected $proper_name = ''; // default proper widget name - i18n cannot be used here, see pre_init()
  9. protected $short_name = 'new-widget'; // default short widget name
  10. protected $defaults = array(); // default widget setting defaults
  11. protected $exclude = array(); // default list of setting keys to exclude from the strip tags filter
  12. protected $use_cache = false; // whether to use cache or not
  13. protected $o = array();
  14. private $start_time;
  15. protected static $_templates = array(); // cached templates list
  16. protected static $_template_dirs = array(); // templates dirs list
  17. protected static $all_widget_time = 0;
  18. protected static $usemc = false;
  19. // require the widget to specify a draw function and a settings form function. everything else is optionally overridden
  20. abstract protected function _widget($args, $instance);
  21. abstract protected function _form($inst);
  22. // setup the base class so that it can do what it needs to
  23. public static function pre_init() {
  24. self::$proper_name = __('New Widget','opentickets-community-edition');
  25. }
  26. // wrapper function for core WP widget system to call, that will chain call our widget's form function
  27. public function form($inst) {
  28. $inst = $this->_ni($inst);
  29. return $this->_form($inst);
  30. }
  31. // generic update function. this is called when the admin user hit's 'save' on the widget. it's goal is to normalize the settings that the user selected before they are
  32. // written to the database, in an attempt to eliminate data curruption of the settings
  33. public function update($new_inst, $old_inst) {
  34. // transpose the old instance settings (prior to the save button being hit) over top of the widget default settings
  35. $inst = $this->_ni($old_inst);
  36. // transpose the enw settings that the user just selected overtop of the normalized old widget settings
  37. $inst = wp_parse_args((array)$new_inst, $old_inst);
  38. // strip tags on settings that dont use them
  39. $inst = $this->_st($inst);
  40. return $inst;
  41. }
  42. protected function _clear_cache($keys, $methods=false) {
  43. static $headers = false;
  44. $methods = empty($methods) ? array('header', 'cookie') : $methods;
  45. $valid = array('header', 'cookie', 'post', 'get', 'request');
  46. $ks = $ms = array();
  47. foreach ($keys as $key) $ks[] = trim(strtolower($key));
  48. foreach ($methods as $method) {
  49. $method = trim(strtolower($method));
  50. if (in_array($method, $valid)) $ms[] = $method;
  51. }
  52. if (empty($ms)) return false;
  53. $clear = false;
  54. foreach ($ms as $m) {
  55. switch ($m) {
  56. case 'header':
  57. if ($headers === false) {
  58. $headers = function_exists('getallheaders') ? getallheaders() : array();
  59. $headers = array_change_key_case($headers);
  60. }
  61. foreach ($ks as $k) if (isset($headers[$k])) {
  62. $clear = true;
  63. break 3;
  64. }
  65. break;
  66. case 'cookie':
  67. foreach ($ks as $k) if (isset($_COOKIE[$k]) && $_COOKIE[$k] == 9999) {
  68. $clear = true;
  69. break 3;
  70. }
  71. break;
  72. case 'post':
  73. foreach ($ks as $k) if (isset($_POST[$k]) && $_POST[$k] == 2) {
  74. $clear = true;
  75. break 3;
  76. }
  77. break;
  78. case 'get':
  79. foreach ($ks as $k) if (isset($_GET[$k]) && $_GET[$k] == 2) {
  80. $clear = true;
  81. break 3;
  82. }
  83. break;
  84. case 'request':
  85. foreach ($ks as $k) if (isset($_REQUEST[$k]) && $_REQUEST[$k] == 2) {
  86. $clear = true;
  87. break 3;
  88. }
  89. break;
  90. }
  91. }
  92. return $clear;
  93. }
  94. // wrapper widget function that core WP calls when it is ready to draw the widget. this wrapper contains code that will cache the result of the draw for a period of time,
  95. // in an attempt to improve performance on a site wide scale, since some of the widgets are heavy.
  96. public function widget($args, $instance) {
  97. // start debuggin draw/calculation time
  98. $this->_start_time();
  99. $instance = $this->_ni($instance);
  100. if ($this->use_cache) {
  101. // get the name of this class, which will be used to make the widget cache key name
  102. $class = get_class($this);
  103. // create a cache key name for this widget, and allow other plugins and sub plugins to modify it if needed
  104. $key = apply_filters('widget-cache-key-'.$class, apply_filters('widget-cache-key',
  105. // unique name based on the generic widget info, and the settings that this instance holds, so that each instance can be cached independently.
  106. // the name can be no more than 250 characters, which is a memcache limitiation
  107. substr(substr($this->short_name, 0, 4).md5($this->proper_name.implode('.', array_keys($instance))).implode('.', $instance), 0, 250),
  108. $class
  109. ));
  110. // determine if the widget cache is being forced to be recalculated by the end user
  111. $clear_cache = $this->_clear_cache(array('clear_cache', 'clear_widget_cache'));
  112. $now = time();
  113. $html = '';
  114. $expired = $from_cache = $cache = false;
  115. // if the cache is not being manually cleared
  116. if (!$clear_cache) {
  117. // load the cache for this widget
  118. $cache = self::$usemc ? wp_cache_get($key, 'sidebar-widgets') : get_transient(md5($key));
  119. // if the cache is in the correct format
  120. if (is_array($cache) && isset($cache['html'], $cache['expire'])) {
  121. // and if the cache is about to expire
  122. if ($now > $cache['expire'] - rand(0, 20)) { // if the cache is set to exipre within about 20 seconds from now
  123. // then push the timer back an hour and make this client redraw the cache
  124. $expired = true;
  125. $cache['expire'] = $now + 3600 + rand(0, 300);
  126. self::$usemc ? wp_cache_set($key, $cache, 'sidebar-widgets', 0) : set_transient(md5($key), $cache, 0);
  127. $cache = false;
  128. }
  129. // if the cache is not in the right format, then pretend there is no cache at all
  130. } else $cache = false;
  131. }
  132. if (!$clear_cache && !$expired && $cache !== false && is_array($cache) && isset($cache['html'], $cache['expire'])) {
  133. // if the cache is still good then use the cache
  134. $html = $cache['html'];
  135. $from_cache = true;
  136. } else {
  137. // if the cache is NOT good, manually cleared, or gone, then redraw the cache and use the redraw
  138. ob_start();
  139. // call the widget draw function
  140. $this->_widget($args, $instance);
  141. $html = ob_get_contents();
  142. ob_end_clean();
  143. // setup the cache in the proper format
  144. $cache = array(
  145. 'expire' => $now + 3600 + rand(0, 300),
  146. 'html' => $html,
  147. );
  148. // set the cache with the new cache value
  149. self::$usemc ? wp_cache_set($key, $cache, 'sidebar-widgets', 0) : set_transient(md5($key), $cache, 0);
  150. }
  151. echo $html;
  152. } else {
  153. $this->_widget($args, $instance);
  154. $key = 'non-cached-'.$this->short_name;
  155. $from_cache = false;
  156. }
  157. $this->_end_time($from_cache);
  158. }
  159. // start the timer for drawing this widget
  160. private function _start_time() {
  161. $this->start_time = microtime(true) * 1000;
  162. }
  163. // end the timer for drawing this widget and then draw out some debug info about the time it took and the process it followed
  164. private function _end_time($from_cache=false) {
  165. $end_time = microtime(true) * 1000;
  166. $diff = $end_time - $this->start_time;
  167. self::$all_widget_time += $diff;
  168. echo '<!-- WC:'.($from_cache ? '' : 'NOT-').'FC:'.$this->proper_name.':'.$diff.'ms;'.self::$all_widget_time.'ms; -->';
  169. }
  170. // sets up the base info about a specific widget
  171. protected function _setup_widget($class, $file) {
  172. // first thing, load all the options, and share them with all other parts of the plugin
  173. $settings_class_name = apply_filters('qsot-settings-class-name', '');
  174. $this->o =& call_user_func_array(array($settings_class_name, "instance"), array());
  175. // used for templates and for assets like js/css/imgs
  176. $this->_base_dir = $this->o->core_dir;
  177. $this->_base_url = $this->o->core_url;
  178. // cache the templates for this widget
  179. $this->_cache_templates();
  180. }
  181. // caches the templates for this specific widget
  182. protected function _cache_templates() {
  183. // setup the directory list of the directories that can contain templates for this widget, and allow other plugins, sub plugins, and widgets to control this list
  184. self::$_template_dirs[$this->short_name] = apply_filters($this->o->pre.$this->short_name.'-template-dirs', array(
  185. $this->_base_dir.'templates/widgets/',
  186. get_template_directory().'/templates/widgets/',
  187. get_stylesheet_directory().'/templates/widgets/',
  188. ));
  189. // checksum is used to check if this list has changed since the last time the cache was drawn
  190. $checksum = md5(serialize(self::$_template_dirs[$this->short_name]));
  191. // allow manual clearing of this cache
  192. $clear_cache = $this->_clear_cache(array('clear_cache', 'clear_widget_cache'));
  193. // load the current template cache for this widget
  194. // w(i)dg(e)t f(ile) c(ache)
  195. $ckey = '_wdgtfc_'.$this->short_name;
  196. $templs = get_option($ckey, false);
  197. // if any of the following are true
  198. // : manually clearing cache
  199. // : the cache does not exist
  200. // : the cache is not in the correct format
  201. // : the list of template directories has changed
  202. // : the template list cache has expired
  203. if ($clear_cache || !is_array($templs) || !isset($templs['checksum'], $templs['templates'], $templs['expire'])
  204. || $templs['checksum'] != $checksum || $templs['expire'] < time()) {
  205. // cycle through the list of template dirs for this widget
  206. foreach (self::$_template_dirs[$this->short_name] as $dir) {
  207. $dir = trailingslashit($dir);
  208. if (file_exists($dir) && is_dir($dir) && is_readable($dir)) {
  209. // foreach file in the currect directory
  210. foreach (scandir($dir) as $file) {
  211. if ($file{0} == '.') continue; // skip hidden
  212. if (is_dir($dir.$file)) continue; // skip sub dirs
  213. if (!is_readable($dir.$file)) continue; // skip unreadable
  214. if (!preg_match('#^'.preg_quote($this->short_name).'.#', $file)) continue; // skip files that are not templates for this widget
  215. $parts = explode('.', $file);
  216. $ext = strtolower(trim(array_pop($parts)));
  217. if ($ext != 'php') continue; // skip non-php files
  218. array_shift($parts); // shift off the base name, since we know it is the first part based on the above regex
  219. $label_short = $short = implode('.', $parts);
  220. if ($label_short == '') $label_short = 'default';
  221. if (!is_array(self::$_templates[$this->short_name])) self::$_templates[$this->short_name] = array();
  222. // add the template to the cached list of templates
  223. self::$_templates[$this->short_name] = array_merge(self::$_templates[$this->short_name], array(
  224. $label_short => $dir.$this->short_name.'.'.$short.'.'.$ext,
  225. ));
  226. }
  227. }
  228. }
  229. // update the cache
  230. update_option($ckey, array('checksum' => $checksum, 'templates' => self::$_templates[$this->short_name], 'expire' => time() + (3600 + rand(0,300))));
  231. // if the cache is still valid, then just use the cached templates list
  232. } else {
  233. self::$_templates[$this->short_name] = $templs['templates'];
  234. }
  235. }
  236. // generic function that can be called to load a template and render it
  237. protected function _display_widget($args, $inst) {
  238. // normalize the instance options so that we at least have a template to load
  239. $inst = wp_parse_args($inst, array('template' => 'default'));
  240. // bring all array values into local scope as variables
  241. extract($args);
  242. extract($inst);
  243. // find the template file if it exists
  244. $templ_file = $this->_find_templ($template);
  245. if (empty($templ_file)) return;
  246. // if it does exist then load it
  247. include $templ_file;
  248. }
  249. // locates a template based on the template cache and the template name
  250. protected function _find_templ($templ) {
  251. // first check to see if there is an override template in the theme, regardless of whether the file exists in the cache or not
  252. $loc = locate_template(array('/templates/widgets/'.$this->short_name.'.'.$templ.'.php'), false);
  253. // if there is no override, then check the cache for a file that matches the widget and the template name
  254. if (empty($loc) && isset(self::$_templates[$this->short_name], self::$_templates[$this->short_name][$templ])) $loc = self::$_templates[$this->short_name][$templ];
  255. // return anything found, of nothing if nothing is found
  256. return $loc;
  257. }
  258. // normalize instance, template: makes sure that the template that is selected is one that is available in the cached template list for this widget
  259. protected function _ni_templ($instance, $key='template') {
  260. $instance = wp_parse_args((array)$instance, $this->defaults);
  261. // normalize the template key in a special manner
  262. // make sure that we are using a template that is in the cache
  263. $instance[$key] = is_string($instance[$key]) && isset(self::$_templates[$this->short_name], self::$_templates[$this->short_name][$instance[$key]])
  264. ? $instance[$key]
  265. : 'default';
  266. return $instance;
  267. }
  268. // normalize instance: transposes the instance values over the defaults for this widget
  269. protected function _ni(&$instance) {
  270. $instance = wp_parse_args((array)$instance, $this->defaults);
  271. // handled by the find_templ function now
  272. //$instance = $this->_ni_templ($instance);
  273. $instance = $this->_st($instance);
  274. return $instance;
  275. }
  276. // recursively strip tags from all widget options, except those that exist on this widget's exclusion list. there is an exclusion list because some options could validly have tags
  277. protected function _st($data, $exclude=array()) {
  278. $exclude = array_unique(array_merge($this->exclude, (array)$exclude));
  279. if (is_object($data) || is_array($data)) {
  280. foreach ($data as $key => &$element)
  281. if (!in_array($key, $exclude))
  282. $element = $this->_st($element);
  283. } else $data = strip_tags($data);
  284. return $data;
  285. }
  286. }
  287. if (defined('ABSPATH') && function_exists('add_action')) {
  288. }
  289. endif;