Advertisement
Guest User

Untitled

a guest
Mar 5th, 2018
330
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.79 KB | None | 0 0
  1. <?php
  2. // Don't load directly
  3. if ( !defined('ABSPATH') ) { die('-1'); }
  4.  
  5. /*
  6. Description: Allows for asset generation/inclusion like css files and js. Also allows to combine files.
  7. Basic idea: allows us to enqueue scripts and styles and before the files get enqueued individually,
  8. we try to generate a compressed version and enqueue this one instead.
  9.  
  10. Author: Kriesi
  11. Since: 4.2.4
  12. */
  13.  
  14.  
  15. if ( !class_exists( 'aviaAssetManager' ) ) {
  16.  
  17. class aviaAssetManager
  18. {
  19. var $db_prefix = "aviaAsset_";
  20. var $which_files = array('css' => 'avia-module', 'js' => 'avia-module');
  21. var $compress_files = array('css' => true, 'js' => true);
  22. var $exclude_files = array('css' => array('admin-bar','dashicons'), 'js' => array('admin-bar'));
  23. var $deregister_files = array('css' => array(), 'js' => array());
  24. var $testmode = false;
  25.  
  26. public function __construct( $builder )
  27. {
  28. // allow to change the files that should be merged:
  29. // 'none' => merging is deactivated
  30. // 'avia-module' => only module files
  31. // 'avia' => all framework files
  32. // 'all' => all enqueued files
  33. $this->which_files = apply_filters( 'avf_merge_assets' , $this->which_files );
  34.  
  35. // allow to change the files that should be compressed:
  36. // true and false allowed
  37. $this->compress_files = apply_filters( 'avf_compress_assets' , $this->compress_files );
  38.  
  39. // files that are always excluded like admin bar files
  40. // files that are processed are added to this list as well, in case another file should be generated
  41. $this->exclude_files = apply_filters( 'avf_exclude_assets' , $this->exclude_files );
  42.  
  43.  
  44. //before enqueuing the css and js files check if we can serve a compressed version (only frontend)
  45. add_action('wp_enqueue_scripts', array(&$this, 'try_minifying_scripts') , 999999 );
  46.  
  47. //if we got any compressed/combined scripts remove the default registered files
  48. add_action('wp_enqueue_scripts', array(&$this, 'try_deregister_scripts') , 9999999 );
  49.  
  50.  
  51. }
  52.  
  53.  
  54.  
  55.  
  56. //default calling of the merging/compression script. the "merge" function can in theory also be called from outside
  57. public function try_minifying_scripts()
  58. {
  59. // check if we got a compressed version that includes all the elements that we need.
  60. // generate a new version if the theme version changes or the css files that are included change
  61. // compare by hash if a new version is required
  62.  
  63.  
  64. //compresses css files and stores them in a file called avia-merged-styles-HASH_ID.css
  65. $this->merge('css', 'avia-merged-styles');
  66.  
  67. //compresses JS files and stores them in a file called avia-head-scripts-HASH_ID.js/avia-footer-scripts-HASH_ID.js// - footer scripts attr: (group 1)
  68.  
  69. //$this->merge('js', 'avia-head-scripts', array('groups'=>0));
  70. $this->merge('js', 'avia-footer-scripts', array('groups'=>1));
  71. }
  72.  
  73. //function that checks if we can merge a group of files based on the passed params
  74. public function merge( $file_type , $prefix , $conditions = array())
  75. {
  76. if($this->which_files[$file_type] == "none" ) return;
  77.  
  78. if($this->which_files[$file_type] == "all" )
  79. {
  80. //we need a file for logged in and logged out users.
  81. //this is only necessary when "all" files are included and we no longer have control over files
  82. $prefix .= is_user_logged_in() ? "-user" : "-guest";
  83. }
  84.  
  85.  
  86. //hook into all enqueued styles
  87. global $wp_styles, $wp_scripts;
  88.  
  89. //get the data of the file we would generate
  90. $enqueued = ($file_type == "css") ? $wp_styles : $wp_scripts;
  91. $data = $this->get_file_data( $file_type , $prefix, $enqueued , $conditions );
  92.  
  93. //check if we got a db entry with this hash. if so, no further merging needed and we can remove the registered files from the enque array
  94. $file_exists = get_option( $this->db_prefix.$prefix.$file_type );
  95.  
  96. //if the file does not exist try to generate it
  97. if(($file_exists != $data['hash'] && $file_exists !== 'error-generating-file') || $this->testmode)
  98. {
  99. $file_exists = $this->generate_file( $file_type, $data , $enqueued);
  100. }
  101.  
  102. //if the file exists and was properly generated at one time in the past, enque the new file and remove all the others. otherwise do nothing
  103. if($file_exists && $file_exists !== "error-generating-file")
  104. {
  105. if(is_array($data['remove']))
  106. {
  107. foreach($data['remove'] as $remove)
  108. {
  109. //for future iterations, exlude all files we used here
  110. $this->exclude_files[$file_type][] = $remove['name'];
  111. $this->deregister_files[$file_type][] = $remove['name'];
  112. }
  113. }
  114.  
  115. $avia_dyn_file_url = $this->get_file_url($data, $file_type);
  116.  
  117. //if file exists enque it
  118. if($file_type == 'css')
  119. {
  120. wp_enqueue_style( $prefix , $avia_dyn_file_url, array(), false, 'all' );
  121. }
  122. else
  123. {
  124. $footer = isset($conditions['groups']) ? $conditions['groups'] : true;
  125.  
  126. wp_enqueue_script( $prefix , $avia_dyn_file_url, array(), false, $footer );
  127. }
  128. }
  129.  
  130. //store that we tried to generate the file but it did not work. therefore no more future tries but simple enqueuing of the single files
  131. if(!$file_exists)
  132. {
  133. update_option( $this->db_prefix.$prefix.$file_type , 'error-generating-file' );
  134. }
  135. }
  136.  
  137. public function get_file_url($data, $file_type)
  138. {
  139. $avia_upload_dir = wp_upload_dir();
  140. if(is_ssl()) $avia_upload_dir['baseurl'] = str_replace("http://", "https://", $avia_upload_dir['baseurl']);
  141.  
  142. $url = $avia_upload_dir['baseurl'] . '/dynamic_avia/'.$data['hash'].'.'.$file_type;
  143.  
  144. return $url;
  145. }
  146.  
  147.  
  148. // returns a file data array with hash, version number and scripts we need to dequeue.
  149. // the hash we generate consists of parent theme version, child theme version and files to include. if any of this changes we create a new file
  150. public function get_file_data( $file_type , $prefix, $enqueued , $conditions)
  151. {
  152. $data = array('hash' => '' , 'version' => '' , 'remove' => array(), 'prefix' => $prefix);
  153.  
  154. //generate the version number
  155. $theme = wp_get_theme();
  156. $data['version']= $theme->get( 'Version' );
  157.  
  158. if( false !== $theme->parent() )
  159. {
  160. $theme = $theme->parent();
  161. $data['version'] = $theme->get( 'Version' ) . '-' . $data['version'];
  162. }
  163.  
  164. //set up the to_do array which has the proper dependencies
  165. $enqueued->all_deps( $enqueued->queue );
  166.  
  167.  
  168. //generate the name string for all the files included. store the data of those files so we can properly include them later and then dequeue them
  169. foreach($enqueued->to_do as $file)
  170. {
  171. // check which files to include based on the $which_files setting (all, none, modules only, all framework files)
  172. if( ('all' == $this->which_files[$file_type] ) ||
  173. ('avia-module' == $this->which_files[$file_type] && strpos($file, 'avia-module') !== false ) ||
  174. ('avia' == $this->which_files[$file_type] && strpos($file, 'avia') !== false ) )
  175. {
  176. //dont use excluded files like admin bar or already used files
  177. if(in_array($file, $this->exclude_files[$file_type])) continue;
  178.  
  179. //dont use print stylesheets
  180. if($enqueued->registered[$file]->args == 'print') continue;
  181.  
  182. //if a group condition is set check if the file matches
  183. if(isset($conditions['groups']) && $enqueued->groups[$file] != $conditions['groups']) continue;
  184.  
  185. //the file string we need to generate the final hash
  186. $data['hash'] .= $file;
  187.  
  188. //set up correct path
  189. //all the files we need to remove from the worpdress queue once we verified that a compressed version is available
  190. $data['remove'][] = array(
  191. 'name' => $file,
  192. 'url' => $enqueued->registered[$file]->src,
  193. 'path' => $this->set_path($enqueued->registered[$file]->src)
  194. );
  195.  
  196. }
  197. }
  198.  
  199.  
  200.  
  201. //clean up the todo list
  202. $enqueued->to_do = array();
  203.  
  204. //generate a unique hash based on file name string and version number
  205. $data['hash'] = $prefix .'-'. md5( $data['hash'] . $data['version'] );
  206.  
  207. return $data;
  208. }
  209.  
  210.  
  211.  
  212. //generates the merged and compressed file
  213. public function generate_file( $file_type , $data , $enqueued)
  214. {
  215. $file_created = false;
  216.  
  217. //try to create a new folder if necessary
  218. $wp_upload_dir = wp_upload_dir();
  219. $stylesheet_dir = $wp_upload_dir['basedir'].'/dynamic_avia';
  220. $stylesheet_dir = str_replace('\\', '/', $stylesheet_dir);
  221. $stylesheet_dir = apply_filters('avia_dyn_stylesheet_dir_path', $stylesheet_dir);
  222. $isdir = avia_backend_create_folder($stylesheet_dir);
  223.  
  224. //check if we got a folder (either created one or there already was one). if we got one proceed
  225. if(!$isdir) return false;
  226.  
  227. //clean up existing styles with the same prefix group
  228. foreach(glob($stylesheet_dir.'/'.$data['prefix']."*.".$file_type) as $file)
  229. {
  230. unlink($file);
  231. }
  232.  
  233. $content = "";
  234.  
  235. //iterate over existing styles and save the content so we can add it to the compressed file
  236. if(is_array($data['remove']))
  237. {
  238. foreach($data['remove'] as $remove)
  239. {
  240. if($remove['path'] != "")
  241. {
  242. $new_content = file_get_contents( trailingslashit( ABSPATH ) . $remove['path'] );
  243. $new_content = $this->compress_content($new_content , $file_type, $remove);
  244. $content .= $new_content;
  245. }
  246. }
  247. }
  248.  
  249. //create a new file if we got any content
  250. if(trim($content) != "")
  251. {
  252. $file_path = trailingslashit($stylesheet_dir).$data['hash'].".".$file_type;
  253. $file_created = avia_backend_create_file($file_path, $content);
  254.  
  255. //double check if the file can be accessed
  256. if(is_readable($file_path))
  257. {
  258. $handle = fopen($file_path, "r");
  259. $filecontent = fread($handle, filesize($file_path));
  260. fclose( $handle );
  261.  
  262. $file = $this->get_file_url($data, $file_type);
  263. $request = wp_remote_get($file);
  264.  
  265. $file_created = false;
  266. if( ( ! $request instanceof WP_Error ) && is_array( $request ) && isset( $request['body'] ) )
  267. {
  268. $request['body'] = trim($request['body']);
  269. $filecontent = trim($filecontent);
  270.  
  271. //if the content does not match the file is not accessible
  272. if($filecontent == $request['body'])
  273. {
  274. $file_created = true;
  275. }
  276. }
  277. }
  278. }
  279.  
  280. //file creation failed
  281. if(!$file_created) return false;
  282.  
  283. //file creation succeeded, store the url of the file
  284. update_option( $this->db_prefix.$data['prefix'].$file_type , $data['hash']);
  285.  
  286. //if everything worked out return the new file hash, otherwise return false
  287. return true;
  288. }
  289.  
  290.  
  291. //function that removes whitespace and comments, fixes relative urls etc
  292. public function compress_content( $content , $file_type , $current_file)
  293. {
  294. if('css' == $file_type)
  295. {
  296. $content = $this->rel_to_abs_url($content, $current_file);
  297.  
  298. if($this->compress_files[$file_type])
  299. {
  300. $content = $this->css_strip_whitespace($content);
  301. }
  302. }
  303. else
  304. {
  305. if($this->compress_files[$file_type])
  306. {
  307. if(version_compare(phpversion(), '5.3', '>='))
  308. {
  309. include_once 'external/JSqueeze.php';
  310.  
  311. $jz = new JSqueeze();
  312.  
  313. $content = $jz->squeeze(
  314. $content,
  315. true, // $singleLine
  316. false, // $keepImportantComments
  317. false // $specialVarRx
  318. );
  319. }
  320. }
  321. }
  322.  
  323. return $content;
  324. }
  325.  
  326. #################
  327. //switch relative urls in the stylesheet to absolute urls
  328. public function rel_to_abs_url($content, $current_file)
  329. {
  330.  
  331. // test drive for the regexp : https://regexr.com/3kq8q
  332.  
  333. $this->base_url = trailingslashit(dirname( get_site_url(NULL, $current_file['path']) ));
  334. $reg_exUrl = '/url\s*?\([\"|\'|\s|\/]*([^\:]+?)[\"|\'|\s]*\)/im';
  335.  
  336. $content = preg_replace_callback($reg_exUrl, array($this, '_url_callback'), $content);
  337.  
  338. return $content;
  339. }
  340.  
  341.  
  342. //callback function. todo once wp switches to 5.3: make it anonymous again
  343. //remove ../../ from urls and iterate into higher folder from the baseurl
  344. public function _url_callback( $match )
  345. {
  346. $current_base = $this->base_url;
  347. $segments = explode("../", $match[1]);
  348. $seg_count = count($segments) - 1;
  349.  
  350. for($i = $seg_count; $i > 0; $i--)
  351. {
  352. $current_base = dirname($current_base);
  353. }
  354.  
  355. $new_url = trailingslashit($current_base) . end($segments);
  356.  
  357. return "url('".$new_url."')";
  358. }
  359.  
  360. #################
  361.  
  362.  
  363.  
  364. public function css_strip_whitespace($css)
  365. {
  366. $replace = array(
  367. "#/\*.*?\*/#s" => "", // Strip C style comments.
  368. "#\s\s+#" => " ", // Strip excess whitespace.
  369. "#\t#" => ""
  370. );
  371. $search = array_keys($replace);
  372. $css = preg_replace($search, $replace, $css);
  373.  
  374. $replace = array(
  375. ": " => ":",
  376. "; " => ";",
  377. " {" => "{",
  378. " }" => "}",
  379. ", " => ",",
  380. "{ " => "{",
  381. "{ " => "{",
  382. ";\n" => ";", // Put all rules from one selector into one line
  383. ";}" => "}", // Strip optional semicolons.
  384. ",\n" => ",", // Don't wrap multiple selectors.
  385. "\n}" => "}", // Don't wrap closing braces.
  386. "{\n" => "{", // Don't wrap the first rule of a selector.
  387. "} " => "}\n", // Put each rule on it's own line.
  388. );
  389. $search = array_keys($replace);
  390. $css = str_replace($search, $replace, $css);
  391.  
  392. return trim($css);
  393. }
  394.  
  395. //remove all db keys starting with the $this->db_prefix - this way all files will be generated new on next pageload
  396. public function reset_files()
  397. {
  398. global $wpdb;
  399. $results = $wpdb->get_results( "SELECT option_name FROM {$wpdb->prefix}options WHERE option_name LIKE '{$this->db_prefix}%'", OBJECT );
  400.  
  401. foreach($results as $result)
  402. {
  403. delete_option($result->option_name);
  404. }
  405.  
  406. }
  407.  
  408. //dequeue and deregister scripts
  409. public function try_deregister_scripts()
  410. {
  411. foreach($this->deregister_files as $file_type => $files)
  412. {
  413. foreach($files as $remove)
  414. {
  415. if($file_type == 'css')
  416. {
  417. wp_dequeue_style( $remove );
  418. wp_deregister_style( $remove );
  419. }
  420. else
  421. {
  422. wp_dequeue_script( $remove );
  423. wp_deregister_script( $remove );
  424. }
  425. }
  426. }
  427. }
  428.  
  429. public function set_path( $registered_path )
  430. {
  431. $path = str_replace(site_url(), "", $registered_path);
  432.  
  433. if(strpos($path, "//") === 0) //if the path starts with // - eg: used by plugins like woocommerce
  434. {
  435. $remove = explode("//", site_url());
  436. $path = str_replace("//" . $remove[1], "", $registered_path);
  437. }
  438.  
  439. return $path;
  440.  
  441. }
  442.  
  443.  
  444.  
  445.  
  446. } // end class
  447.  
  448. } // end if !class_exists
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement