Completed
Push — add/asset-cdn ( 3744fe...92b739 )
by
unknown
07:40
created

Asset_CDN::encode_files_param()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 1
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * Plugin Name: Asset CDN
4
 * Description: Speed up Javascript and CSS
5
 * Plugin URI: https://github.com/automattic/jetpack
6
 * Author: Automattic
7
 * Author URI: https://automattic.com
8
 * Version: 0.1.0
9
 * Text Domain: asset-cdn
10
 * Domain Path: /languages/
11
 * License: GPLv2 or later
12
 */
13
14
/**
15
 * TODO
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
16
 * - versioning (combine ver hashes) and cachebusting
17
 * - concat/minify/serve JS too
18
 * - asset inlining for smaller styles?
19
 * - critical CSS support?
20
 * - non-enqueued assets?
21
 */
22
23
class Asset_CDN {
24
	private static $__instance = null;
25
26
	private $cdn_server;
27
	private $concat_style_groups = array();
28
	private $concat_script_groups = array();
29
	private $inject_critical_css = false;
30
31
	/**
32
	 * Singleton implementation
33
	 *
34
	 * @return object
35
	 */
36
	public static function instance() {
37
		if ( ! is_a( self::$__instance, 'Asset_CDN' ) ) {
38
			self::$__instance = new Asset_CDN();
39
		}
40
41
		return self::$__instance;
42
	}
43
44
	private function __construct() {
45
		// $this->cdn_server = 'https://cdn.wpvm.io';
46
		$this->cdn_server = 'http://localhost:8090';
47
48
		// allow smaller CSS by only minifying assets on the page
49
		add_filter( 'jetpack_implode_frontend_css', '__return_false' );
50
51
		// rewrite CSS tags
52
		add_filter( 'script_loader_tag', array( $this, 'register_concat_scripts' ), -100, 3 );
53
		add_filter( 'style_loader_tag', array( $this, 'register_concat_styles' ), -100, 4 );
54
55
		add_action( 'wp_head', array( $this, 'render_concatenated_styles_head' ), PHP_INT_MAX );
56
		add_action( 'wp_head', array( $this, 'render_concatenated_scripts_head' ), PHP_INT_MAX );
57
		add_action( 'wp_footer', array( $this, 'render_concatenated_styles_footer' ), PHP_INT_MAX );
58
		add_action( 'wp_footer', array( $this, 'render_concatenated_scripts_footer' ), PHP_INT_MAX );
59
	}
60
61
	/**
62
	 * Render functions
63
	 */
64
65
	function render_concatenated_styles_head() {
66
		if ( isset( $this->concat_style_groups[0] ) ) {
67
			$this->render_concatenated_styles( $this->concat_style_groups[0] );
68
		}
69
	}
70
71
	function render_concatenated_styles_footer() {
72
		if ( isset( $this->concat_style_groups[1] ) ) {
73
			$this->render_concatenated_styles( $this->concat_style_groups[1] );
74
		}
75
	}
76
77
	private function render_concatenated_styles( $style_groups ) {
78
		// special URL to concatenation service
79
		global $wp_styles;
80
		$site_url = site_url();
81
		foreach( $style_groups as $media => $styles ) {
82
			$urls = array();
83
			$vers = array();
84
85
			foreach( $styles as $style ) {
86
				$urls[] = str_replace( untrailingslashit( $site_url ), '', $style->src );
87
				$vers[] = $style->ver ? $style->ver : $wp_styles->default_version;
88
			}
89
90
			$cdn_url = $this->cdn_server . '/css?b=' .
91
				urlencode( $site_url ) . '&' .
92
				http_build_query( array( 'f' => $urls ) ) . '&' .
93
				http_build_query( array( 'v' => $vers ) );
94
			// if we are injecting critical CSS, load the full CSS async
95
96
			if ( $this->inject_critical_css ) {
97
				echo '<!-- jetpack concat --><link rel="preload" onload="this.rel=\'stylesheet\'" as="style" type="text/css" media="' . $media . '" href="' . esc_attr( $cdn_url ) . '"/>';
98
			} else {
99
				echo '<!-- jetpack concat --><link rel="stylesheet" type="text/css" media="' . $media . '" href="' . esc_attr( $cdn_url ) . '"/>';
100
			}
101
		}
102
	}
103
104
	function render_concatenated_scripts_head() {
105
		if ( isset( $this->concat_script_groups[0] ) ) {
106
			$this->render_concatenated_scripts( $this->concat_script_groups[0] );
107
		}
108
	}
109
110
	function render_concatenated_scripts_footer() {
111
		if ( isset( $this->concat_script_groups[1] ) ) {
112
			$this->render_concatenated_scripts( $this->concat_script_groups[1] );
113
		}
114
	}
115
116
	private function render_concatenated_scripts( $scripts ) {
117
		// special URL to concatenation service
118
		global $wp_scripts;
119
		$site_url = site_url();
120
		$urls = array();
121
		$vers = array();
122
123
		foreach( $scripts as $script ) {
124
			$urls[] = str_replace( untrailingslashit( $site_url ), '', $script->src );
125
			$vers[] = $script->ver ? $script->ver : $wp_scripts->default_version;
126
			if ( isset( $script->extra['before'] ) && $script->extra['before'] ) {
127
				echo sprintf( "<script type='text/javascript'>\n%s\n</script>\n", $script->extra['before'] );
128
			}
129
		}
130
131
		$cdn_url = $this->cdn_server . '/js?b=' .
132
			urlencode( $site_url ) . '&' .
133
			http_build_query( array( 'f' => $urls ) ) . '&' .
134
			http_build_query( array( 'v' => $vers ) );
135
		// TODO: if there is NO inline or external script tags in the body, render async (maybe?)
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
136
		echo '<script type="text/javascript" src="' . esc_attr( $cdn_url ) . '"></script>';
137
138
		foreach( $scripts as $script ) {
139
			if ( isset( $script->extra['after'] ) && $script->extra['after'] ) {
140
				echo sprintf( "<script type='text/javascript'>\n%s\n</script>\n", $script->extra['after'] );
141
			}
142
		}
143
	}
144
145
	/**
146
	 * Asset modification functions
147
	 */
148
149
	/**
150
	 * Scripts
151
	 */
152
153 View Code Duplication
	public function register_concat_scripts( $tag, $handle, $src ) {
154
		global $wp_scripts;
155
156
		// don't do admin for now
157
		if ( is_admin() || ! isset( $wp_scripts->registered[$handle] ) ) {
158
			return $tag;
159
		}
160
161
		$script = $wp_scripts->registered[$handle];
162
163
		if ( $this->should_concat_script( $script ) ) {
164
			$this->buffer_script( $script );
165
			return '';
166
		}
167
168
		return $tag;
169
	}
170
171 View Code Duplication
	private function should_concat_script( $script ) {
172
		// only concat local scripts
173
		$is_local       = $this->is_local_url( $script->src );
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 7 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
174
		// don't concat conditional scripts
175
		$is_conditional = isset( $script->extra['conditional'] );
176
		return apply_filters( 'jetpack_perf_concat_script', $is_local && ! $is_conditional, $script->handle, $script->src );
177
	}
178
179
	private function buffer_script( $script ) {
180
		$group = isset( $script->extra['group'] ) ? $script->extra['group'] : 0;
181
		if ( ! isset( $this->concat_script_groups[$group] ) ) {
182
			$this->concat_script_groups[$group] = array();
183
		}
184
		$this->concat_script_groups[$group][] = $script;
185
	}
186
187
	/**
188
	 * Styles
189
	 */
190
191 View Code Duplication
	public function register_concat_styles( $tag, $handle, $href, $media ) {
192
		global $wp_styles;
193
194
		// don't do admin for now
195
		if ( is_admin() || ! isset( $wp_styles->registered[$handle] ) ) {
196
			return $tag;
197
		}
198
199
		$style = $wp_styles->registered[$handle];
200
201
		if ( $this->should_concat_style( $style ) ) {
202
			$this->buffer_style( $style );
203
			return '';
204
		}
205
206
		return $tag;
207
	}
208
209
	private function buffer_style( $style ) {
210
		$group = isset( $style->extra['group'] ) ? $style->extra['group'] : 0;
211
		$media = $style->args;
212
		if ( ! $media ) {
213
			$media = 'all';
214
		}
215
		if ( ! isset( $this->concat_style_groups[$group] ) ) {
216
			$this->concat_style_groups[$group] = array();
217
		}
218
		if ( ! isset( $this->concat_style_groups[$group][$media] ) ) {
219
			$this->concat_style_groups[$group][$media] = array();
220
		}
221
		$this->concat_style_groups[$group][$media][] = $style;
222
	}
223
224 View Code Duplication
	private function should_concat_style( $style ) {
225
		// only concat local styles
226
		$is_local       = $this->is_local_url( $style->src );
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 7 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
227
		// don't concat conditional styles
228
		$is_conditional = isset( $style->extra['conditional'] );
229
		return apply_filters( 'jetpack_perf_concat_style', $is_local && ! $is_conditional, $style->handle, $style->src );
230
	}
231
232
	private function is_local_url( $url ) {
233
		$site_url = site_url();
234
		return ( strncmp( $url, '/', 1 ) === 0 && strncmp( $url, '//', 2 ) !== 0 )
235
			|| strpos( $url, $site_url ) === 0;
236
	}
237
}