Advertisement
amereservant

WordPress - Combine Javascript Files for fewer HTTP requests

Sep 14th, 2011
214
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 8.23 KB | None | 0 0
  1. <?php
  2. if( !defined('DS') ) define('DS', DIRECTORY_SEPARATOR);
  3.  
  4. define('TC_PATH', realpath(dirname(__FILE__)) . DS);
  5.  
  6. /**
  7.  * Combine CSS/JS File
  8.  *
  9.  * This is used to add the combined file to the $wp_scripts->done property so WordPress
  10.  * knows it has been added already and it also determines the absolute path for the file
  11.  * so it can be accessed via the file system.
  12.  *
  13.  * @filter  tc_combined_js_path Allows filtering of the full js file path.  The filter function
  14.  *                              is passed 3 optional parameters, 'site url' (bloginfo('url')),
  15.  *                              'handle' (the $handle param), and the 'src' value for the script.
  16.  * @filter tc_combined_css_path Allows filtering of the full css file path.  The filter function
  17.  *                              is passed 3 optional parameters, 'site url' (bloginfo('url')),
  18.  *                              'handle' (the $handle param), and the 'src' value for the stylesheet.
  19.  
  20.  * @param   string  $handle     The script/stylesheet's handle it was registered with.
  21.  * @param   string  $type       Valid values are 'css' or 'js'.  This determines which
  22.  *                              type of file we're adding.
  23.  * @return  string              The full path to the file, if it could be determined,
  24.  *                              (bool)false otherwise.
  25.  * @access  private
  26.  */
  27. function _tc_add_combine_file( $handle, $type )
  28. {
  29.     if( $type != 'js' && $type != 'css' ) {
  30.         trigger_error('Invalid file type given!  Must be `css` or `js`.');
  31.         return false;
  32.     }
  33.  
  34.     $siteurl = get_bloginfo('url');
  35.  
  36.     if( $type == 'js' )
  37.     {
  38.         global $wp_scripts;
  39.         // Strip the site URL from the file so we can determine it's path ...
  40.         $uri  = ltrim(str_replace($siteurl, '', $wp_scripts->registered[$handle]->src), '/');
  41.         $path = realpath(ABSPATH . DS . $uri);
  42.         $path = apply_filters('tc_combine_js_path', $path, $siteurl, $handle, $wp_scripts->registered[$handle]->src);
  43.  
  44.         // Only add it to the done queue if a path was found, this way we don't break the theme...
  45.         if( $path )
  46.             $wp_scripts->done[] = $handle;
  47.     }
  48.     else
  49.     {
  50.         global $wp_styles;
  51.         $uri  = ltrim(str_replace($url, '', $wp_styles->registered[$handle]->src), '/');
  52.         $path = realpath(ABSPATH . DS . $uri);
  53.         $path = apply_filters('tc_combine_css_path', $path, $siteurl, $handle, $wp_styles->registered[$handle]->src);
  54.        
  55.         if( $path )
  56.             $wp_styles->done[] = $handle;
  57.     }
  58.     return $path;
  59. }
  60.  
  61. /**
  62.  * Recursive Combine JS Dependencies
  63.  *
  64.  * A function used by _tc_combine_js() to recursively add queued script's dependencies
  65.  * and perform any that are excluded from the combined JS file.
  66.  *
  67.  * @param   string  $hdl        The queued script handle to process the dependencies for.
  68.  * @param   object  $wp_scripts The WP_Scripts object, passed by reference.
  69.  * @param   array   $exclude    An array of script handles to exclude from the combined file.
  70.  * @return  array               An array of all of the dependencies that are included in the combined JS.
  71.  * @access  private
  72.  */
  73. function _tc_recursive_deps( $hdl, &$wp_scripts, $exclude )
  74. {
  75.     $files = array();
  76.    
  77.     foreach($wp_scripts->registered[$hdl]->deps as $dep)
  78.     {
  79.         if( count($wp_scripts->registered[$dep]->deps) )
  80.         {
  81.             $files = array_merge($files, _tc_recursive_deps($dep, $wp_scripts, $exclude));
  82.         }
  83.         else
  84.         {
  85.             // If the dependency is in the excluded array, we must go ahead and add it
  86.             // so the scripts depending on it won't break.
  87.             if( in_array($dep, $exclude) ) {
  88.                 $wp_scripts->do_items(array($dep));
  89.                 continue;
  90.             }
  91.             // Make sure the dependency isn't in the 'done' array so we don't add it twice
  92.             elseif( !in_array($dep, $wp_scripts->done) ) {
  93.                 $path = _tc_add_combine_file( $dep, 'js' );
  94.                 if( $path ) $files[] = $path;
  95.             }
  96.         }
  97.     }
  98.     // Finally, if the passed queue is in the exclude array, we have to go ahead and add it
  99.     // as well, for the same reason mentioned above.
  100.     if( in_array($hdl, $exclude) ) {
  101.         $wp_scripts->do_items(array($dep));
  102.     }
  103.     else
  104.     {
  105.         $path = _tc_add_combine_file( $hdl, 'js' );
  106.         if( $path ) $files[] = $path;
  107.     }
  108.     return $files;
  109. }
  110.  
  111. /**
  112.  * Combine JS Files
  113.  *
  114.  * This combines all of the Javascript files that have been registered/enqueued via
  115.  * WordPress's script queueing system.
  116.  *
  117.  * The filter 'tc_combine_js' allows for exclusions of specific files.
  118.  * Files are grouped together into two groups, header JS and footer JS, this way
  119.  * they still load in the correct places.
  120.  *
  121.  * @param   void
  122.  * @return  void
  123.  * @access  private
  124.  */
  125. function _tc_combine_js()
  126. {
  127.     global $wp_scripts;
  128.     $footer   = array();
  129.     $header   = array();
  130.     $cachefor = apply_filters('tc_combine_js_cache_for', 60*60);
  131.     // Specify any scripts by handle that should be excluded from the combined JS
  132.     $exclude = apply_filters('tc_combine_js_exclude', array('admin-bar'));
  133.    
  134.     // First process the header Javascripts
  135.     foreach($wp_scripts->queue as $queue)
  136.     {
  137.         $curqueue = $wp_scripts->registered[$queue];
  138.        
  139.         // Skip footer scripts and just process header scripts for now...
  140.         if(isset($curqueue->extra['group']) && $curqueue->extra['group'] == '1')
  141.             continue;
  142.         // Recursively add all dependencies
  143.         $header = array_merge($header, _tc_recursive_deps($queue, $wp_scripts, $exclude));
  144.     }
  145.     $header = apply_filters('tc_header_combine_js', $header);
  146.  
  147.     // Now process the footer Javascripts
  148.     foreach($wp_scripts->queue as $queue)
  149.     {
  150.         if( in_array($queue, $wp_scripts->done) ) continue;
  151.        
  152.         $footer = array_merge($footer, _tc_recursive_deps($queue, $wp_scripts, $exclude));
  153.     }
  154.     $footer = apply_filters('tc_footer_combine_js', $footer);
  155.  
  156.     // Use converted MD5 hash to verify all files are included since someone logged in
  157.     // might have different JS that loads than someone who isn't, etc.
  158.     $file_hash    = base_convert(md5(implode('', $header)), 10, 36);
  159.    
  160.     $headjs_cache = apply_filters('tc_headjs_cache_file', 'hjs.cache.'. $file_hash .'.js', $file_hash);
  161.    
  162.     // Determine if we need to create a new cached header js file or not.
  163.     if( !file_exists(TC_PATH . $headjs_cache) || (filemtime(TC_PATH . $headjs_cache)+intval($cachefor)) < time() )
  164.     {
  165.         $hdl = fopen(TC_PATH . $headjs_cache, "w");
  166.  
  167.         foreach($header as $file)
  168.         {
  169.             if( !file_exists($file) )
  170.                 trigger_error('File `'. $file .'` does not exist!', E_USER_WARNING);
  171.             else
  172.                 fwrite($hdl, file_get_contents($file));
  173.         }
  174.         fclose($hdl);
  175.     }
  176.  
  177.     $file_hash    = base_convert(md5(implode('', $footer)), 10, 36);
  178.     $footjs_cache = apply_filters('tc_footjs_cache_file', 'fjs.cache.'. $file_hash .'.js', $file_hash);
  179.    
  180.     // Determine if we need to create a new cached footer js file or not.
  181.     if( !file_exists(TC_PATH . $footjs_cache) || (filemtime(TC_PATH . $footjs_cache)+intval($cachefor)) < time() )
  182.     {
  183.         $hdl = fopen(TC_PATH . $footjs_cache, "w");
  184.        
  185.         foreach($footer as $file)
  186.         {
  187.             if( !file_exists($file) )
  188.                 trigger_error('File `'. $file .'` does not exist!', E_USER_WARNING);
  189.             else
  190.                 fwrite($hdl, file_get_contents($file));
  191.         }
  192.         fclose($hdl);
  193.     }
  194.  
  195.     // Form the URLs and correct slashes for valid URLs.
  196.     $hjs_url = get_bloginfo('template_directory') .'/'. str_replace('\\', '/', $headjs_cache);
  197.     $fjs_url = get_bloginfo('template_directory') .'/'. str_replace('\\', '/', $footjs_cache);
  198.    
  199.     wp_enqueue_script('hjs-cache', $hjs_url);
  200.     wp_enqueue_script('fjs-cache', $fjs_url, false, '', true);
  201. }
  202.  
  203. if( !is_admin() ) add_action('wp_print_scripts', '_tc_combine_js');
  204.  
  205. /////////////////
  206. // Filter Test
  207. /////////////////
  208. function removeit($excluded) {
  209.     return array_merge($excluded, array('jquery'));
  210. }
  211. add_filter('tc_combine_js_exclude', 'removeit', 10, 1);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement