PluginProbe
TablePress – Tables in WordPress made easy / 2.1.8
TablePress – Tables in WordPress made easy v2.1.8
3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.12 1.14 1.9.2 2.0.4 2.1.7 2.1.8 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3 2.3.1 2.3.2 2.4 2.4.1 2.4.2 2.4.3 2.4.4 All 44 releases
tablepress / classes / class-css.php

class-css.php in TablePress – Tables in WordPress made easy 2.1.8, at classes/class-css.php

458 lines 15.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * TablePress CSS Class
4 *
5 * @package TablePress
6 * @subpackage CSS
7 * @author Tobias Bäthge
8 * @since 1.1.0
9 */
10
11 // Prohibit direct script loading.
12 defined( 'ABSPATH' ) || die( 'No direct script access allowed!' );
13
14 /**
15 * TablePress CSS Class
16 *
17 * @package TablePress
18 * @subpackage CSS
19 * @author Tobias Bäthge
20 * @since 1.1.0
21 */
22 class TablePress_CSS {
23
24 /**
25 * Sanitize and tidy a string of CSS.
26 *
27 * @since 1.1.0
28 *
29 * @param string $css CSS code.
30 * @return string Sanitized and tidied CSS code.
31 */
32 public function sanitize_css( $css ) {
33 $csstidy = TablePress::load_class( 'TablePress_CSSTidy', 'class.csstidy.php', 'libraries/csstidy' );
34
35 // Sanitization and not just tidying for users without enough privileges.
36 if ( ! current_user_can( 'unfiltered_html' ) ) {
37 $csstidy->optimise = new TablePress_CSSTidy_optimise( $csstidy );
38
39 // Let "arrows" survive, otherwise this might be recognized as the beginning of an HTML tag and removed with other stuff behind it.
40 $css = str_replace( '<=', '&lt;=', $css );
41 // Remove all HTML tags.
42 $css = wp_kses( $css, 'strip' );
43 // KSES replaces single ">" with "&gt;", but ">" is valid in CSS selectors.
44 $css = str_replace( '&gt;', '>', $css );
45 // strip_tags again, because of the just added ">" (KSES for a second time would again bring the ">" problem).
46 $css = strip_tags( $css );
47 }
48
49 $csstidy->set_cfg( 'remove_bslash', false );
50 $csstidy->set_cfg( 'compress_colors', false );
51 $csstidy->set_cfg( 'compress_font-weight', false );
52 $csstidy->set_cfg( 'lowercase_s', false );
53 $csstidy->set_cfg( 'optimise_shorthands', false );
54 $csstidy->set_cfg( 'remove_last_;', false );
55 $csstidy->set_cfg( 'case_properties', false );
56 $csstidy->set_cfg( 'sort_properties', false );
57 $csstidy->set_cfg( 'sort_selectors', false );
58 $csstidy->set_cfg( 'discard_invalid_selectors', false );
59 $csstidy->set_cfg( 'discard_invalid_properties', true );
60 $csstidy->set_cfg( 'merge_selectors', false );
61 $csstidy->set_cfg( 'css_level', 'CSS3.0' );
62 $csstidy->set_cfg( 'preserve_css', true );
63 $csstidy->set_cfg( 'timestamp', false );
64 $csstidy->set_cfg( 'template', 'default' );
65
66 $csstidy->parse( $css );
67 return $csstidy->print->plain();
68 }
69
70 /**
71 * Minify a string of CSS code, that should have been sanitized/tidied before.
72 *
73 * @since 1.1.0
74 *
75 * @param string $css CSS code.
76 * @return string Minified CSS code.
77 */
78 public function minify_css( $css ) {
79 $csstidy = TablePress::load_class( 'TablePress_CSSTidy', 'class.csstidy.php', 'libraries/csstidy' );
80 $csstidy->optimise = new TablePress_CSSTidy_optimise( $csstidy );
81 $csstidy->set_cfg( 'remove_bslash', false );
82 $csstidy->set_cfg( 'compress_colors', true );
83 $csstidy->set_cfg( 'compress_font-weight', true );
84 $csstidy->set_cfg( 'lowercase_s', false );
85 $csstidy->set_cfg( 'optimise_shorthands', 1 );
86 $csstidy->set_cfg( 'remove_last_;', true );
87 $csstidy->set_cfg( 'case_properties', false );
88 $csstidy->set_cfg( 'sort_properties', false );
89 $csstidy->set_cfg( 'sort_selectors', false );
90 $csstidy->set_cfg( 'discard_invalid_selectors', false );
91 $csstidy->set_cfg( 'discard_invalid_properties', true );
92 $csstidy->set_cfg( 'merge_selectors', false );
93 $csstidy->set_cfg( 'css_level', 'CSS3.0' );
94 $csstidy->set_cfg( 'preserve_css', false );
95 $csstidy->set_cfg( 'timestamp', false );
96 $csstidy->set_cfg( 'template', 'highest' );
97
98 $csstidy->parse( $css );
99 return $csstidy->print->plain();
100 }
101
102 /**
103 * Get the location (file path or URL) of the "Custom CSS" file, depending on whether it's a Multisite install or not.
104 *
105 * @since 1.0.0
106 *
107 * @param string $type "normal" version, "minified" version, or "combined" (with TablePress Default CSS) version.
108 * @param string $location "path" or "url", for file path or URL.
109 * @return string Full file path or full URL for the "Custom CSS" file.
110 */
111 public function get_custom_css_location( $type, $location ) {
112 switch ( $type ) {
113 case 'combined':
114 $file = 'tablepress-combined.min.css';
115 break;
116 case 'minified':
117 $file = 'tablepress-custom.min.css';
118 break;
119 case 'normal':
120 default:
121 $file = 'tablepress-custom.css';
122 break;
123 }
124
125 if ( is_multisite() ) {
126 // Multisite installation: Use /wp-content/uploads/sites/<ID>/.
127 $upload_location = wp_upload_dir();
128 } else {
129 // Singlesite installation: Use /wp-content/.
130 $upload_location = array(
131 'basedir' => WP_CONTENT_DIR,
132 'baseurl' => content_url(),
133 );
134 }
135
136 switch ( $location ) {
137 case 'url':
138 $url = set_url_scheme( $upload_location['baseurl'] . '/' . $file );
139 /**
140 * Filters the URL from which the "Custom CSS" file is loaded.
141 *
142 * @since 1.0.0
143 *
144 * @param string $url URL of the "Custom CSS" file.
145 * @param string $file File name of the "Custom CSS" file.
146 * @param string $type Type of the "Custom CSS" file ("normal", "minified", or "combined").
147 */
148 $url = apply_filters( 'tablepress_custom_css_url', $url, $file, $type );
149 return $url;
150 // break; // unreachable.
151 case 'path':
152 $path = $upload_location['basedir'] . '/' . $file;
153 /**
154 * Filters the file path on the server from which the "Custom CSS" file is loaded.
155 *
156 * @since 1.0.0
157 *
158 * @param string $path File path of the "Custom CSS" file.
159 * @param string $file File name of the "Custom CSS" file.
160 * @param string $type Type of the "Custom CSS" file ("normal", "minified", or "combined").
161 */
162 $path = apply_filters( 'tablepress_custom_css_file_name', $path, $file, $type );
163 return $path;
164 // break; // unreachable.
165 default:
166 // Return an empty string if no valid location was provided.
167 return '';
168 // break; // unreachable.
169 }
170 }
171
172 /**
173 * Load the contents of the file with the "Custom CSS".
174 *
175 * @since 1.0.0
176 *
177 * @param string $type Optional. Whether to load "normal" version or "minified" version. Default "normal".
178 * @return string|false Custom CSS on success, false on error.
179 */
180 public function load_custom_css_from_file( $type = 'normal' ) {
181 $filename = $this->get_custom_css_location( $type, 'path' );
182 // Check if file name is valid (0 means yes).
183 if ( 0 !== validate_file( $filename ) ) {
184 return false;
185 }
186 if ( ! @is_file( $filename ) ) {
187 return false;
188 }
189 if ( ! @is_readable( $filename ) ) {
190 return false;
191 }
192 return file_get_contents( $filename );
193 }
194
195 /**
196 * Loads the contents of the file with the TablePress Default CSS,
197 * either for left-to-right (LTR) or right-to-left (RTL), in minified form.
198 *
199 * @since 1.1.0
200 * @since 2.0.0 Added the `$load_rtl` parameter.
201 *
202 * @param bool $load_rtl Optional. Whether to load LTR or RTL version. Default LTR.
203 * @return string|false TablePress Default CSS on success, false on error.
204 */
205 public function load_default_css_from_file( $load_rtl = false ) {
206 $rtl = $load_rtl ? '-rtl' : '';
207 $filename = TABLEPRESS_ABSPATH . "css/build/default{$rtl}.css";
208 // Check if file name is valid (0 means yes).
209 if ( 0 !== validate_file( $filename ) ) {
210 return false;
211 }
212 if ( ! @is_file( $filename ) ) {
213 return false;
214 }
215 if ( ! @is_readable( $filename ) ) {
216 return false;
217 }
218 return file_get_contents( $filename );
219 }
220
221 /**
222 * Try to save "Custom CSS" to a file (requires "direct" method in WP_Filesystem, or stored FTP credentials).
223 *
224 * @since 1.1.0
225 *
226 * @param string $custom_css_normal Custom CSS code to be saved.
227 * @param string $custom_css_minified Minified CSS code to be saved.
228 * @return bool True on success, false on failure.
229 */
230 public function save_custom_css_to_file( $custom_css_normal, $custom_css_minified ) {
231 /**
232 * Filters whether the "Custom CSS" code shall be saved to a file on the server.
233 *
234 * @since 1.1.0
235 *
236 * @param bool $save Whether to save the "Custom CSS" to a file. Default true.
237 */
238 if ( ! apply_filters( 'tablepress_save_custom_css_to_file', true ) ) {
239 return false;
240 }
241
242 // Start capturing the output, to later prevent it.
243 ob_start();
244 $credentials = request_filesystem_credentials( '', '', false, '', null, false );
245
246 /*
247 * Do we have credentials already? (Otherwise the form will have been rendered, which is not supported here.)
248 * Or, if we have credentials, are they valid?
249 */
250 if ( false === $credentials || ! WP_Filesystem( $credentials ) ) {
251 ob_end_clean();
252 return false;
253 }
254
255 // We have valid access to the filesystem now -> try to save the files.
256 return $this->_custom_css_save_helper( $custom_css_normal, $custom_css_minified );
257 }
258
259 /**
260 * Save "Custom CSS" to files, delete "Custom CSS" files, or return HTML for the credentials form.
261 *
262 * Only used from "Plugin Options" screen, save_custom_css_to_file() is used in cases where no form output/redirection is possible (e.g. during plugin updates).
263 *
264 * @since 1.0.0
265 *
266 * @param string $custom_css_normal Custom CSS code to be saved. If empty, files will be deleted.
267 * @param string $custom_css_minified Minified CSS code to be saved.
268 * @return bool|string True on success, false on failure, or string of HTML for the credentials form for the WP_Filesystem API, if necessary.
269 */
270 public function save_custom_css_to_file_plugin_options( $custom_css_normal, $custom_css_minified ) {
271 /** This filter is documented in classes/class-css.php */
272 if ( ! apply_filters( 'tablepress_save_custom_css_to_file', true ) ) {
273 return false;
274 }
275
276 // Start capturing the output, to get HTML of the credentials form (if needed).
277 ob_start();
278 $credentials = request_filesystem_credentials( '', '', false, '', null, false );
279 // Do we have credentials already? Otherwise the form will have been rendered already.
280 if ( false === $credentials ) {
281 $form_data = ob_get_clean();
282 $form_data = str_replace( 'name="upgrade" id="upgrade" class="button"', 'name="upgrade" id="upgrade" class="button button-primary button-large"', $form_data );
283 return $form_data;
284 }
285
286 // We have received credentials, but don't know if they are valid yet.
287 if ( ! WP_Filesystem( $credentials ) ) {
288 // Credentials failed, so ask again (with $error flag true).
289 request_filesystem_credentials( '', '', true, '', null, false );
290 $form_data = ob_get_clean();
291 $form_data = str_replace( 'name="upgrade" id="upgrade" class="button"', 'name="upgrade" id="upgrade" class="button button-primary button-large"', $form_data );
292 return $form_data;
293 }
294
295 // We have valid access to the filesystem now -> try to save the files, or delete them if the "Custom CSS" is empty.
296 if ( '' !== $custom_css_normal ) {
297 return $this->_custom_css_save_helper( $custom_css_normal, $custom_css_minified );
298 } else {
299 return $this->_custom_css_delete_helper();
300 }
301 }
302
303 /**
304 * Save "Custom CSS" to files, if validated access to the WP_Filesystem exists.
305 *
306 * Helper function to prevent code duplication.
307 *
308 * @since 1.1.0
309 *
310 * @global WP_Filesystem_* $wp_filesystem WordPress file system abstraction object.
311 * @see save_custom_css_to_file()
312 * @see save_custom_css_to_file_plugin_options()
313 *
314 * @param string $custom_css_normal Custom CSS code to be saved.
315 * @param string $custom_css_minified Minified CSS code to be saved.
316 * @return bool True on success, false on failure.
317 */
318 protected function _custom_css_save_helper( $custom_css_normal, $custom_css_minified ) {
319 global $wp_filesystem;
320
321 /*
322 * WP_CONTENT_DIR and (FTP-)Content-Dir can be different (e.g. if FTP working dir is /).
323 * We need to account for that by replacing the path difference in the filename.
324 */
325 $path_difference = str_replace( $wp_filesystem->wp_content_dir(), '', trailingslashit( WP_CONTENT_DIR ) );
326
327 $css_types = array( 'normal', 'minified', 'combined' );
328
329 $default_css_minified = $this->load_default_css_from_file( false );
330 if ( false === $default_css_minified ) {
331 $default_css_minified = '';
332 } else {
333 // Change relative URLs to web font files to absolute URLs, as combining the CSS files and saving to another directory breaks the relative URLs.
334 $absolute_path = plugins_url( 'css/build/tablepress.', TABLEPRESS__FILE__ );
335 // Make the absolute URL protocol-relative to prevent mixed content warnings.
336 $absolute_path = str_replace( array( 'http:', 'https:' ), '', $absolute_path );
337 $default_css_minified = str_replace( 'url(tablepress.', 'url(' . $absolute_path, $default_css_minified );
338 }
339 $file_content = array(
340 'normal' => $custom_css_normal,
341 'minified' => $custom_css_minified,
342 'combined' => $default_css_minified . $custom_css_minified,
343 );
344
345 $total_result = true; // Whether all files were saved successfully.
346 foreach ( $css_types as $css_type ) {
347 $filename = $this->get_custom_css_location( $css_type, 'path' );
348 // Check if filename is valid (0 means yes).
349 if ( 0 !== validate_file( $filename ) ) {
350 $total_result = false;
351 continue;
352 }
353 if ( '' !== $path_difference ) {
354 $filename = str_replace( $path_difference, '', $filename );
355 }
356 $result = $wp_filesystem->put_contents( $filename, $file_content[ $css_type ], FS_CHMOD_FILE );
357 $total_result = ( $total_result && $result );
358 }
359
360 $this->_flush_caching_plugins_css_minify_caches();
361
362 return $total_result;
363 }
364
365 /**
366 * Delete the "Custom CSS" files, if possible.
367 *
368 * @since 1.0.0
369 *
370 * @return bool True on success, false on failure.
371 */
372 public function delete_custom_css_files() {
373 // Start capturing the output, to later prevent it.
374 ob_start();
375 $credentials = request_filesystem_credentials( '', '', false, '', null, false );
376
377 /*
378 * Do we have credentials already? (Otherwise the form will have been rendered, which is not supported here.)
379 * Or, if we have credentials, are they valid?
380 */
381 if ( false === $credentials || ! WP_Filesystem( $credentials ) ) {
382 ob_end_clean();
383 return false;
384 }
385
386 // We have valid access to the filesystem now -> try to delete the files.
387 return $this->_custom_css_delete_helper();
388 }
389
390 /**
391 * Delete "Custom CSS" files, if validated access to the WP_Filesystem exists.
392 *
393 * Helper function to prevent code duplication
394 *
395 * @since 1.1.0
396 *
397 * @global WP_Filesystem_* $wp_filesystem WordPress file system abstraction object.
398 * @see delete_custom_css_files()
399 * @see save_custom_css_to_file_plugin_options()
400 *
401 * @return bool True on success, false on failure.
402 */
403 protected function _custom_css_delete_helper() {
404 global $wp_filesystem;
405
406 /*
407 * WP_CONTENT_DIR and (FTP-)Content-Dir can be different (e.g. if FTP working dir is /).
408 * We need to account for that by replacing the path difference in the filename.
409 */
410 $path_difference = str_replace( $wp_filesystem->wp_content_dir(), '', trailingslashit( WP_CONTENT_DIR ) );
411
412 $css_types = array( 'normal', 'minified', 'combined' );
413 $total_result = true; // Whether all files were deleted successfully.
414 foreach ( $css_types as $css_type ) {
415 $filename = $this->get_custom_css_location( $css_type, 'path' );
416 // Check if filename is valid (0 means yes).
417 if ( 0 !== validate_file( $filename ) ) {
418 $total_result = false;
419 continue;
420 }
421 if ( '' !== $path_difference ) {
422 $filename = str_replace( $path_difference, '', $filename );
423 }
424 // We have valid access to the filesystem now -> try to delete the file.
425 if ( $wp_filesystem->exists( $filename ) ) {
426 $result = $wp_filesystem->delete( $filename );
427 $total_result = ( $total_result && $result );
428 }
429 }
430
431 $this->_flush_caching_plugins_css_minify_caches();
432
433 return $total_result;
434 }
435
436 /**
437 * Flush the CSS minification caches of common caching plugins.
438 *
439 * @since 1.4.0
440 */
441 protected function _flush_caching_plugins_css_minify_caches() {
442 /** This filter is documented in models/model-table.php */
443 if ( ! apply_filters( 'tablepress_flush_caching_plugins_caches', true ) ) {
444 return;
445 }
446
447 // W3 Total Cache.
448 if ( function_exists( 'w3tc_minify_flush' ) ) {
449 w3tc_minify_flush();
450 }
451 // WP Fastest Cache.
452 if ( isset( $GLOBALS['wp_fastest_cache'] ) && is_callable( array( $GLOBALS['wp_fastest_cache'], 'deleteCache' ) ) ) {
453 $GLOBALS['wp_fastest_cache']->deleteCache( true );
454 }
455 }
456
457 } // class TablePress_CSS
458