PluginProbe
Page Optimize / 0.6.1
Page Optimize v0.6.1
trunk 0.4.2 0.4.3 0.4.4 0.4.6 0.4.7 0.5.0 0.5.1 0.5.2 0.5.3 0.5.4 0.5.5 0.5.6 0.5.7 0.5.8 0.6.0 0.6.1 0.6.2 0.6.3
page-optimize / page-optimize.php

page-optimize.php in Page Optimize 0.6.1, at page-optimize.php

314 lines 8.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Page Optimize
4 Plugin URI: https://wordpress.org/plugins/page-optimize/
5 Description: Optimizes JS and CSS for faster page load and render in the browser.
6 Author: Automattic
7 Version: 0.6.1
8 Author URI: http://automattic.com/
9 */
10
11 // Default cache directory
12 if ( ! defined( 'PAGE_OPTIMIZE_CACHE_DIR' ) ) {
13 define( 'PAGE_OPTIMIZE_CACHE_DIR', WP_CONTENT_DIR . '/cache/page_optimize' );
14 }
15
16 if ( ! defined( 'PAGE_OPTIMIZE_ABSPATH' ) ) {
17 define( 'PAGE_OPTIMIZE_ABSPATH', ABSPATH );
18 }
19
20 if ( ! defined( 'PAGE_OPTIMIZE_CSS_MINIFY' ) ) {
21 define( 'PAGE_OPTIMIZE_CSS_MINIFY', false );
22 }
23
24 define( 'PAGE_OPTIMIZE_CRON_CACHE_CLEANUP_JOB', 'page_optimize_cron_cache_cleanup' );
25
26 // TODO: Copy tests from nginx-http-concat and/or write them
27
28 // TODO: Make concat URL dir configurable
29 if ( isset( $_SERVER['REQUEST_URI'] ) && '/_static/' === substr( $_SERVER['REQUEST_URI'], 0, 9 ) ) {
30 require_once __DIR__ . '/service.php';
31 exit;
32 }
33
34 function page_optimize_cache_cleanup( $cache_folder = false, $file_age = DAY_IN_SECONDS ) {
35 if ( ! is_dir( $cache_folder ) ) {
36 return;
37 }
38
39 // If cache is disabled when the cleanup runs, purge it
40 $using_cache = defined( 'PAGE_OPTIMIZE_CACHE_DIR' ) && ! empty( PAGE_OPTIMIZE_CACHE_DIR );
41 if ( ! $using_cache ) {
42 $file_age = 0;
43 }
44 // If the cache folder changed since queueing, purge it
45 if ( $using_cache && $cache_folder !== PAGE_OPTIMIZE_CACHE_DIR ) {
46 $file_age = 0;
47 }
48
49 // Grab all files in the cache directory
50 $cache_files = glob( $cache_folder . '/page-optimize-cache-*' );
51
52 // Cleanup all files older than $file_age
53 foreach ( $cache_files as $cache_file ) {
54 if ( ! is_file( $cache_file ) ) {
55 continue;
56 }
57
58 if ( ( time() - $file_age ) > filemtime( $cache_file ) ) {
59 unlink( $cache_file );
60 }
61 }
62 }
63 add_action( PAGE_OPTIMIZE_CRON_CACHE_CLEANUP_JOB, 'page_optimize_cache_cleanup' );
64
65 // Unschedule cache cleanup, and purge cache directory
66 function page_optimize_deactivate() {
67 $cache_folder = false;
68 if ( defined( 'PAGE_OPTIMIZE_CACHE_DIR' ) && ! empty( PAGE_OPTIMIZE_CACHE_DIR ) ) {
69 $cache_folder = PAGE_OPTIMIZE_CACHE_DIR;
70 }
71
72 page_optimize_cache_cleanup( $cache_folder, 0 /* max file age in seconds */ );
73
74 wp_clear_scheduled_hook( PAGE_OPTIMIZE_CRON_CACHE_CLEANUP_JOB, [ $cache_folder ] );
75 }
76 register_deactivation_hook( __FILE__, 'page_optimize_deactivate' );
77
78 function page_optimize_uninstall() {
79 // Run cleanup on uninstall. You can uninstall an active plugin w/o deactivation.
80 page_optimize_deactivate();
81
82 // JS
83 delete_option( 'page_optimize-js' );
84 delete_option( 'page_optimize-load-mode' );
85 delete_option( 'page_optimize-js-exclude' );
86 // CSS
87 delete_option( 'page_optimize-css' );
88 delete_option( 'page_optimize-css-exclude' );
89
90 }
91 register_uninstall_hook( __FILE__, 'page_optimize_uninstall' );
92
93 function page_optimize_get_text_domain() {
94 return 'page-optimize';
95 }
96
97 function page_optimize_should_concat_js() {
98 // Support query param for easy testing
99 if ( isset( $_GET['concat-js'] ) ) {
100 return $_GET['concat-js'] !== '0';
101 }
102
103 return !! get_option( 'page_optimize-js', page_optimize_js_default() );
104 }
105
106 // TODO: Support JS load mode regardless of whether concat is enabled
107 function page_optimize_load_mode_js() {
108 // Support query param for easy testing
109 if ( ! empty( $_GET['load-mode-js'] ) ) {
110 $load_mode = page_optimize_sanitize_js_load_mode( $_GET['load-mode-js'] );
111 } else {
112 $load_mode = page_optimize_sanitize_js_load_mode( get_option( 'page_optimize-load-mode', page_optimize_js_load_mode_default() ) );
113 }
114
115 return $load_mode;
116 }
117
118 function page_optimize_should_concat_css() {
119 // Support query param for easy testing
120 if ( isset( $_GET['concat-css'] ) ) {
121 return $_GET['concat-css'] !== '0';
122 }
123
124 return !! get_option( 'page_optimize-css', page_optimize_css_default() );
125 }
126
127 function page_optimize_js_default() {
128 return true;
129 }
130
131 function page_optimize_css_default() {
132 return true;
133 }
134
135 function page_optimize_js_load_mode_default() {
136 return '';
137 }
138
139 function page_optimize_js_exclude_list() {
140 $exclude_list = get_option( 'page_optimize-js-exclude' );
141 if ( false === $exclude_list ) {
142 // Use the default since the option is not set
143 return page_optimize_js_exclude_list_default();
144 }
145 if ( '' === $exclude_list ) {
146 return [];
147 }
148
149 return explode( ',', $exclude_list );
150 }
151
152 function page_optimize_js_exclude_list_default() {
153 // WordPress core stuff, a lot of other plugins depend on it.
154 return [ 'jquery', 'jquery-core', 'underscore', 'backbone' ];
155 }
156
157 function page_optimize_css_exclude_list() {
158 $exclude_list = get_option( 'page_optimize-css-exclude' );
159 if ( false === $exclude_list ) {
160 // Use the default since the option is not set
161 return page_optimize_css_exclude_list_default();
162 }
163 if ( '' === $exclude_list ) {
164 return [];
165 }
166
167 return explode( ',', $exclude_list );
168 }
169
170 function page_optimize_css_exclude_list_default() {
171 // WordPress Core and known conflicting plugins
172 return [ 'admin-bar', 'dashicons', 'elementor-app' ];
173 }
174
175 function page_optimize_sanitize_js_load_mode( $value ) {
176 switch ( $value ) {
177 case 'async':
178 case 'defer':
179 break;
180 default:
181 $value = '';
182 break;
183 }
184
185 return $value;
186 }
187
188 function page_optimize_sanitize_exclude_field( $value ) {
189 if ( empty( $value ) ) {
190 return '';
191 }
192
193 $excluded_strings = explode( ',', sanitize_text_field( $value ) );
194 $sanitized_values = [];
195 foreach ( $excluded_strings as $excluded_string ) {
196 if ( ! empty( $excluded_string ) ) {
197 $sanitized_values[] = trim( $excluded_string );
198 }
199 }
200
201 return implode( ',', $sanitized_values );
202 }
203
204 /**
205 * Determines whether a string starts with another string.
206 */
207 function page_optimize_starts_with( $prefix, $str ) {
208 $prefix_length = strlen( $prefix );
209 if ( strlen( $str ) < $prefix_length ) {
210 return false;
211 }
212
213 return substr( $str, 0, $prefix_length ) === $prefix;
214 }
215
216 /**
217 * Answers whether the plugin should provide concat resource URIs
218 * that are relative to a common ancestor directory. Assuming a common ancestor
219 * allows us to skip resolving resource URIs to filesystem paths later on.
220 */
221 function page_optimize_use_concat_base_dir() {
222 return defined( 'PAGE_OPTIMIZE_CONCAT_BASE_DIR' ) && file_exists( PAGE_OPTIMIZE_CONCAT_BASE_DIR );
223 }
224
225 /**
226 * Get a filesystem path relative to a configured base path for resources
227 * that will be concatenated. Assuming a common ancestor allows us to skip
228 * resolving resource URIs to filesystem paths later on.
229 */
230 function page_optimize_remove_concat_base_prefix( $original_fs_path ) {
231 // Always check longer path first
232 if ( strlen( PAGE_OPTIMIZE_ABSPATH ) > strlen( PAGE_OPTIMIZE_CONCAT_BASE_DIR ) ) {
233 $longer_path = PAGE_OPTIMIZE_ABSPATH;
234 $shorter_path = PAGE_OPTIMIZE_CONCAT_BASE_DIR;
235 } else {
236 $longer_path = PAGE_OPTIMIZE_CONCAT_BASE_DIR;
237 $shorter_path = PAGE_OPTIMIZE_ABSPATH;
238 }
239
240 $prefix_abspath = trailingslashit( $longer_path );
241 if ( page_optimize_starts_with( $prefix_abspath, $original_fs_path ) ) {
242 return substr( $original_fs_path, strlen( $prefix_abspath ) );
243 }
244
245 $prefix_basedir = trailingslashit( $shorter_path );
246 if ( page_optimize_starts_with( $prefix_basedir, $original_fs_path ) ) {
247 return substr( $original_fs_path, strlen( $prefix_basedir ) );
248 }
249
250 // If we end up here, this is a resource we shouldn't have tried to concat in the first place
251 return '/page-optimize-resource-outside-base-path/' . basename( $original_fs_path );
252 }
253
254 function page_optimize_schedule_cache_cleanup() {
255 $cache_folder = false;
256 if ( defined( 'PAGE_OPTIMIZE_CACHE_DIR' ) && ! empty( PAGE_OPTIMIZE_CACHE_DIR ) ) {
257 $cache_folder = PAGE_OPTIMIZE_CACHE_DIR;
258 }
259 $args = [ $cache_folder ];
260
261 // If caching is on, and job isn't queued for current cache folder
262 if( false !== $cache_folder && false === wp_next_scheduled( PAGE_OPTIMIZE_CRON_CACHE_CLEANUP_JOB, $args ) ) {
263 wp_schedule_event( time(), 'daily', PAGE_OPTIMIZE_CRON_CACHE_CLEANUP_JOB, $args );
264 }
265 }
266
267 // Cases when we don't want to concat
268 function page_optimize_bail() {
269 // Bail if we're in customizer
270 global $wp_customize;
271 if ( isset( $wp_customize ) ) {
272 return true;
273 }
274
275 // Bail if we're in any of the excluded pages.
276 global $pagenow;
277 $excluded_pages = array(
278 'post.php',
279 'post-new.php',
280 'site-editor.php',
281 );
282 if ( isset( $pagenow ) && in_array( $pagenow, $excluded_pages ) ) {
283 return true;
284 }
285
286 // Bail if Divi theme is active, and we're in the Divi Front End Builder
287 if ( ! empty( $_GET['et_fb'] ) && 'Divi' === wp_get_theme()->get_template() ) {
288 return true;
289 }
290
291 // Bail if we're editing pages in Brizy Editor
292 if ( class_exists( 'Brizy_Editor' ) && method_exists( 'Brizy_Editor', 'prefix' ) && ( isset( $_GET[ Brizy_Editor::prefix( '-edit-iframe' ) ] ) || isset( $_GET[ Brizy_Editor::prefix( '-edit' ) ] ) ) ) {
293 return true;
294 }
295
296 return false;
297 }
298
299 function page_optimize_init() {
300 if ( page_optimize_bail() ) {
301 return;
302 }
303
304 page_optimize_schedule_cache_cleanup();
305
306 require_once __DIR__ . '/settings.php';
307 require_once __DIR__ . '/concat-css.php';
308 require_once __DIR__ . '/concat-js.php';
309
310 // Disable Jetpack photon-cdn for static JS/CSS
311 add_filter( 'jetpack_force_disable_site_accelerator', '__return_true' );
312 }
313 add_action( 'plugins_loaded', 'page_optimize_init' );
314