diff --git a/admin.css b/admin.css index 5199a48..3c63c93 100644 --- a/admin.css +++ b/admin.css @@ -14,3 +14,16 @@ .fixed .column-expires { width: 12%; } + +.nav-tab-content { + display: none; +} +.form-table th small { + display: block; + clear: both; + color: #999; +} +.form-table td label { + display: block; + clear:both; +} \ No newline at end of file diff --git a/admin.js b/admin.js index e69de29..2b6d574 100644 --- a/admin.js +++ b/admin.js @@ -0,0 +1,20 @@ +jQuery(function($){ + + // Admin page tabs + var $tabs = $('.nav-tab-wrapper'), + $panels = $('.nav-tab-content'), + currentHash = window.location.hash; + + $tabs.on('click', 'a', function(e){ + var hash = $(this).attr('href').replace('#tab-', '#tab-content-'); // prevents page scrolling if hash is present + $panels.hide().filter(hash).show(); + $tabs.find('a').removeClass('nav-tab-active').filter($(this)).addClass('nav-tab-active'); + }); + $tabs.find( currentHash ? 'a[href="'+currentHash+'"]' : ':first').trigger('click'); + + // Fix input-inside-label glitch + $panels.on('click', 'input[type=text]', function(e){ + e.preventDefault(); + }) + +}); \ No newline at end of file diff --git a/dependency-minification.php b/dependency-minification.php index 474d1a2..e8bc78e 100644 --- a/dependency-minification.php +++ b/dependency-minification.php @@ -33,13 +33,14 @@ class Dependency_Minification { protected static $minified_count = 0; static $admin_page_hook; - const DEFAULT_ENDPOINT = '_minify'; - const CRON_MINIFY_ACTION = 'minify_dependencies'; - const CACHE_KEY_PREFIX = 'depmin_cache_'; - const FILENAME_PATTERN = '([^/]+?)\.([0-9a-f]+)(?:\.([0-9a-f]+))?\.(css|js)'; - const AJAX_ACTION = 'dependency_minification'; - const ADMIN_PAGE_SLUG = 'dependency-minification'; - const ADMIN_PARENT_PAGE = 'tools.php'; + const DEFAULT_ENDPOINT = '_minify'; + const CRON_MINIFY_ACTION = 'minify_dependencies'; + const CACHE_KEY_PREFIX = 'depmin_cache_'; + const FILENAME_PATTERN = '([^/]+?)\.([0-9a-f]+)(?:\.([0-9a-f]+))?\.(css|js)'; + const AJAX_ACTION = 'dependency_minification'; + const AJAX_OPTIONS_ACTION = 'dependency_minification_options'; + const ADMIN_PAGE_SLUG = 'dependency-minification'; + const ADMIN_PARENT_PAGE = 'tools.php'; static $query_vars = array( 'depmin_handles', @@ -49,8 +50,7 @@ class Dependency_Minification { ); static function setup() { - self::$options = apply_filters( 'dependency_minification_options', array_merge( - array( + $defaults = array( 'endpoint' => self::DEFAULT_ENDPOINT, 'default_exclude_remote_dependencies' => true, 'cache_control_max_age_cache' => 2629743, // 1 month in seconds @@ -59,16 +59,38 @@ static function setup() { 'admin_page_capability' => 'edit_theme_options', 'show_error_messages' => ( defined( 'WP_DEBUG' ) && WP_DEBUG ), 'disable_if_wp_debug' => true, - ), - self::$options - ) ); + 'exclude_dependencies' => array(), + 'disabled_on_conditions' => array( + 'all' => false, + 'loggedin' => false, + 'admin' => false, + 'queryvar' => false, + ), + ); + $options = get_option( 'dependency_minification_options', array() ); + self::$options = apply_filters( + 'dependency_minification_options', array_merge( + $defaults, + $options + ) + ); $is_frontend = ! ( is_admin() || in_array( $GLOBALS['pagenow'], array( 'wp-login.php', 'wp-register.php' ) ) ); - if ( $is_frontend ) { + $disabled = ( + ( isset( self::$options['disabled_on_conditions']['all'] ) && ! empty( self::$options['disabled_on_conditions']['all'] ) ) + || ( isset( self::$options['disabled_on_conditions']['loggedin'] ) && ! empty( self::$options['disabled_on_conditions']['loggedin'] ) && is_user_logged_in() ) + || ( ! empty( self::$options['disabled_on_conditions']['admin'] ) && is_user_logged_in() && current_user_can( 'manage_options' ) ) + || ( ! empty( self::$options['disabled_on_conditions']['queryvar']['enabled'] ) + && ! empty( self::$options['disabled_on_conditions']['queryvar']['enabled'] ) + && ! empty( $_GET[ self::$options['disabled_on_conditions']['queryvar']['value'] ] ) + ) + ); + + if ( $is_frontend && ! $disabled ) { add_filter( 'print_scripts_array', array( __CLASS__, 'filter_print_scripts_array' ) ); add_filter( 'print_styles_array', array( __CLASS__, 'filter_print_styles_array' ) ); } @@ -78,6 +100,7 @@ static function setup() { add_action( 'admin_notices', array( __CLASS__, 'admin_notices' ) ); add_action( 'admin_enqueue_scripts', array( __CLASS__, 'admin_enqueue_scripts' ) ); add_action( 'wp_ajax_' . self::AJAX_ACTION, array( __CLASS__, 'admin_ajax_handler' ) ); + add_action( 'wp_ajax_' . self::AJAX_OPTIONS_ACTION, array( __CLASS__, 'admin_ajax_options_handler' ) ); add_filter( 'plugin_action_links', array( __CLASS__, 'admin_plugin_action_links' ), 10, 2 ); } @@ -197,7 +220,7 @@ static function admin_notices() { __( 'Permalinks Settings', 'depmin' ) ) ) - ); + ); // xss ok ?>

- +

@@ -269,6 +296,33 @@ static function admin_ajax_handler() { exit; } + /** + * @action wp_ajax_dependency_minification_options + */ + static function admin_ajax_options_handler() { + if ( ! current_user_can( self::$options['admin_page_capability'] ) ) { + wp_die( __( 'You are not allowed to do that.', 'depmin' ) ); + } + if ( ! wp_verify_nonce( $_POST['_wpnonce'], self::AJAX_OPTIONS_ACTION ) ) { + wp_die( __( 'Nonce check failed. Try reloading the previous page.', 'depmin' ) ); + } + $updated_count = 0; + if ( ! empty( $_POST['options'] ) ) { + $options = get_option( 'dependency_minification_options' ); + $options['exclude_dependencies'] = array_filter( preg_split( "#[\n\r]+#", $_POST['options']['exclude_dependencies'] ) ); + $options['disabled_on_conditions'] = $_POST['options']['disabled_on_conditions']; + $options['default_exclude_remote_dependencies'] = isset( $_POST['options']['default_exclude_remote_dependencies'] ); + update_option( 'dependency_minification_options', $options ); + } + + $redirect_url = add_query_arg( 'page', self::ADMIN_PAGE_SLUG, admin_url( self::ADMIN_PARENT_PAGE ) ); + $redirect_url = add_query_arg( 'updated', 1, $redirect_url ); + $redirect_url .= '#tab-settings'; + wp_redirect( $redirect_url ); + + die(); + } + /** * @filter plugin_action_links */ @@ -288,10 +342,13 @@ static function admin_page() { $nonce = wp_create_nonce( self::AJAX_ACTION ); ?>
-

+

- - + + + +
groups[$handle] < $current_group && - !in_array($handle, $wp_deps->done) + ! in_array( $handle, $wp_deps->done ) ) ); @@ -653,13 +776,13 @@ static function filter_print_dependency_array( array $handles, $type ) { $filtered_handles = array_merge( $filtered_handles, $group['handles'] ); } else { self::$minified_count += 1; - $new_handle = sprintf('minified-%d', self::$minified_count); + $new_handle = sprintf( 'minified-%d', self::$minified_count ); $filtered_handles[] = $new_handle; $src = self::get_dependency_minified_url( $deps, $type ); // Deps are registered without versions since the URL includes the version (ver_hash) if ( 'scripts' === $type ) { - $in_footer = !empty( $extra['group'] ); // @todo what if the group is not 0 or 1? + $in_footer = ! empty( $extra['group'] ); // @todo what if the group is not 0 or 1? wp_register_script( $new_handle, $src, array(), null, $in_footer ); } elseif ( 'styles' === $type ) { wp_register_style( $new_handle, $src, array(), null, $extra['media'] ); @@ -717,7 +840,7 @@ static function is_self_hosted_src( $src ) { ( empty( $parsed_url['host'] ) && - substr( $parsed_url['path'], 0, 1) === '/' + substr( $parsed_url['path'], 0, 1 ) === '/' ) || ( @@ -728,6 +851,15 @@ static function is_self_hosted_src( $src ) { ); } + static function is_url_included( $needle, $haystack ) { + foreach ( $haystack as $entry ) { + if ( strpos( $needle, $entry ) !== false ) { + return true; + } + } + return false; + } + /** * @return {array} Two members, the 1st containing external handles and the 2nd containing internal handles */ @@ -739,7 +871,8 @@ static function group_dependencies_by_exclusion( $handles, WP_Dependencies $wp_d foreach ( $handles as $handle ) { $src = $wp_deps->registered[$handle]->src; $is_local = self::is_self_hosted_src( $src ); - $is_excluded = !$is_local && self::$options['default_exclude_remote_dependencies']; + $is_excluded = ! $is_local && self::$options['default_exclude_remote_dependencies']; + $is_excluded = $is_excluded || self::is_url_included( $src, self::$options['exclude_dependencies'] ); $is_excluded = apply_filters( 'dependency_minification_excluded', $is_excluded, $handle, $src ); if ( $last_was_excluded !== $is_excluded ) { @@ -782,8 +915,8 @@ static function group_handles_by_extra( array $handles, WP_Dependencies $wp_deps foreach ( $handles as $handle ) { $dep = &$wp_deps->registered[$handle]; $extra = (array) $dep->extra; - if ( is_a($wp_deps, 'WP_Styles') ) { - $extra['media'] = is_string($dep->args) ? $dep->args : 'all'; + if ( is_a( $wp_deps, 'WP_Styles' ) ) { + $extra['media'] = is_string( $dep->args ) ? $dep->args : 'all'; } unset($extra['suffix']); unset($extra['rtl']); @@ -792,8 +925,8 @@ static function group_handles_by_extra( array $handles, WP_Dependencies $wp_deps if ( is_a( $wp_deps, 'WP_Scripts' ) && empty( $extra['group'] ) && is_int( $dep->args ) ) { $extra['group'] = $dep->args; } - ksort($extra); - $key = serialize($extra); + ksort( $extra ); + $key = serialize( $extra ); $bundles[$key][] = $handle; } return $bundles; @@ -813,10 +946,10 @@ static function minify( $cached ) { try { $is_css = ( 'styles' === $type ); if ( 'scripts' === $type ) { - require_once( dirname(__FILE__) . '/minify/JS/JSMin.php' ); + require_once( dirname( __FILE__ ) . '/minify/JS/JSMin.php' ); } elseif ( 'styles' === $type ) { - require_once( dirname(__FILE__) . '/minify/CSS/UriRewriter.php' ); - require_once( dirname(__FILE__) . '/minify/CSS/Compressor.php' ); + require_once( dirname( __FILE__ ) . '/minify/CSS/UriRewriter.php' ); + require_once( dirname( __FILE__ ) . '/minify/CSS/Compressor.php' ); } $unminified_size = 0; @@ -842,17 +975,17 @@ static function minify( $cached ) { // Dependency is not self-hosted or it the filesystem read failed, so do HTTP request if ( false === $contents ) { $r = wp_remote_get( $src ); - if ( is_wp_error($r) ) { - throw new Exception("Failed to retrieve $src: " . $r->get_error_message()); + if ( is_wp_error( $r ) ) { + throw new Exception( "Failed to retrieve $src: " . $r->get_error_message() ); } elseif ( intval( wp_remote_retrieve_response_code( $r ) ) !== 200 ) { - throw new Dependency_Minification_Exception( sprintf('Request for %s returned with HTTP %d %s', $src, wp_remote_retrieve_response_code( $r ), wp_remote_retrieve_response_message( $r )) ); + throw new Dependency_Minification_Exception( sprintf( 'Request for %s returned with HTTP %d %s', $src, wp_remote_retrieve_response_code( $r ), wp_remote_retrieve_response_message( $r ) ) ); } $contents = wp_remote_retrieve_body( $r ); } $unminified_size += strlen( $contents ); // Remove the BOM - $contents = preg_replace("/^\xEF\xBB\xBF/", '', $contents); + $contents = preg_replace( "/^\xEF\xBB\xBF/", '', $contents ); // Rewrite relative paths in CSS $src_dir_path = dirname( parse_url( $src, PHP_URL_PATH ) ); @@ -866,13 +999,13 @@ static function minify( $cached ) { $contents = ''; // Print a manifest of the dependencies - $contents .= sprintf("/*! This minified dependency bundle includes:\n"); + $contents .= sprintf( "/*! This minified dependency bundle includes:\n" ); $i = 0; foreach ( $srcs as $src ) { $i += 1; $contents .= sprintf( " * %02d. %s\n", $i, $src ); } - $contents .= sprintf(" */\n\n"); + $contents .= sprintf( " */\n\n" ); // Minify // Note: semicolon needed in case a file lacks trailing semicolon @@ -883,13 +1016,13 @@ static function minify( $cached ) { // is the comment-reply.js in WordPress. if ( 'scripts' === $type ) { $minified_contents = join( "\n;;\n", $contents_for_each_dep ); - $minified_contents = JSMin::minify($minified_contents); + $minified_contents = JSMin::minify( $minified_contents ); if ( false === $minified_contents ) { throw new Dependency_Minification_Exception( 'JavaScript parse error' ); } } elseif ( 'styles' === $type ) { $minified_contents = join( "\n\n", $contents_for_each_dep ); - $minified_contents = Minify_CSS_Compressor::process($minified_contents); + $minified_contents = Minify_CSS_Compressor::process( $minified_contents ); } $contents .= $minified_contents; @@ -900,12 +1033,15 @@ static function minify( $cached ) { $cached['error'] = null; } catch (Exception $e) { - error_log( sprintf( '%s in %s: %s for srcs %s', - get_class( $e ), - __FUNCTION__, - $e->getMessage(), - join( ',', $srcs ) - ) ); + error_log( + sprintf( + '%s in %s: %s for srcs %s', + get_class( $e ), + __FUNCTION__, + $e->getMessage(), + join( ',', $srcs ) + ) + ); $cached['error'] = $e->getMessage(); $max_age = apply_filters( 'dependency_minification_cache_control_max_age_error', (int) self::$options['cache_control_max_age_error'], $srcs ); $cached['expires'] = time() + $max_age; @@ -941,7 +1077,7 @@ static function handle_request() { } $cache_option_name = self::get_cache_option_name( $src_hash ); - $cached = get_option($cache_option_name); + $cached = get_option( $cache_option_name ); if ( empty( $cached ) ) { throw new Dependency_Minification_Exception( 'Unknown minified dependency bundle.', 404 ); } @@ -950,9 +1086,9 @@ static function handle_request() { } // Send the response headers for caching - header( 'Expires: ' . str_replace('+0000', 'GMT', gmdate('r', $cached['expires'])) ); + header( 'Expires: ' . str_replace( '+0000', 'GMT', gmdate( 'r', $cached['expires'] ) ) ); if ( ! empty( $cached['last_modified'] ) ) { - header( 'Last-Modified: ' . str_replace('+0000', 'GMT', gmdate('r', $cached['last_modified'])) ); + header( 'Last-Modified: ' . str_replace( '+0000', 'GMT', gmdate( 'r', $cached['last_modified'] ) ) ); } if ( ! empty( $cached['etag'] ) ) { header( 'ETag: ' . $cached['etag'] ); @@ -980,24 +1116,24 @@ static function handle_request() { } if ( $is_not_modified ) { - status_header(304); + status_header( 304 ); } else { - status_header(200); + status_header( 200 ); $out = $cached['contents']; global $compress_scripts, $compress_css; script_concat_settings(); $compress = ( 'js' === $ext ? $compress_scripts : $compress_css ); - $force_gzip = ( $compress && defined('ENFORCE_GZIP') && ENFORCE_GZIP ); + $force_gzip = ( $compress && defined( 'ENFORCE_GZIP' ) && ENFORCE_GZIP ); // Copied from /wp-admin/load-scripts.php - if ( $compress && ! ini_get('zlib.output_compression') && 'ob_gzhandler' != ini_get('output_handler') && isset($_SERVER['HTTP_ACCEPT_ENCODING']) ) { - header('Vary: Accept-Encoding'); // Handle proxies - if ( false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') && function_exists('gzdeflate') && ! $force_gzip ) { - header('Content-Encoding: deflate'); + if ( $compress && ! ini_get( 'zlib.output_compression' ) && 'ob_gzhandler' != ini_get( 'output_handler' ) && isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) ) { + header( 'Vary: Accept-Encoding' ); // Handle proxies + if ( false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate' ) && function_exists( 'gzdeflate' ) && ! $force_gzip ) { + header( 'Content-Encoding: deflate' ); $out = gzdeflate( $out, 3 ); - } elseif ( false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') && function_exists('gzencode') ) { - header('Content-Encoding: gzip'); + } elseif ( false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) && function_exists( 'gzencode' ) ) { + header( 'Content-Encoding: gzip' ); $out = gzencode( $out, 3 ); } } @@ -1014,7 +1150,14 @@ static function handle_request() { $status = $e->getCode(); $message = $e->getMessage(); } else { - error_log( sprintf('%s: %s via URI %s', __METHOD__, $e->getMessage(), esc_url_raw( $_SERVER['REQUEST_URI'] )) ); + error_log( + sprintf( + '%s: %s via URI %s', + __METHOD__, + $e->getMessage(), + esc_url_raw( $_SERVER['REQUEST_URI'] ) + ) + ); $message = 'Unexpected error occurred.'; } if ( empty($status) ) {