PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 7.1
Jetpack – WP Security, Backup, Speed, & Growth v7.1
16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
jetpack / modules / custom-css / custom-css.php
custom-css.php
1,867 lines 59.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class Jetpack_Custom_CSS {
4 static function init() {
5 add_action( 'switch_theme', array( __CLASS__, 'reset' ) );
6 add_action( 'wp_restore_post_revision', array( __CLASS__, 'restore_revision' ), 10, 2 );
7
8 // Save revisions for posts of type safecss.
9 add_action( 'load-revision.php', array( __CLASS__, 'add_revision_redirect' ) );
10
11 // Override the edit link, the default link causes a redirect loop
12 add_filter( 'get_edit_post_link', array( __CLASS__, 'revision_post_link' ), 10, 3 );
13
14 // Overwrite the content width global variable if one is set in the custom css
15 add_action( 'template_redirect', array( __CLASS__, 'set_content_width' ) );
16 add_action( 'admin_init', array( __CLASS__, 'set_content_width' ) );
17
18 if ( ! is_admin() )
19 add_filter( 'stylesheet_uri', array( __CLASS__, 'style_filter' ) );
20
21 define(
22 'SAFECSS_USE_ACE',
23 ! jetpack_is_mobile() &&
24 ! Jetpack_User_Agent_Info::is_ipad() &&
25 /**
26 * Should the Custom CSS module use ACE to process CSS.
27 * @see http://ace.c9.io/
28 *
29 * @module custom-css
30 *
31 * @since 1.7.0
32 *
33 * @param bool true Use ACE to process the Custom CSS. Default to true.
34 */
35 apply_filters( 'safecss_use_ace', true )
36 );
37
38 // Register safecss as a custom post_type
39 // Explicit capability definitions are largely unnecessary because the posts are manipulated in code via an options page, managing CSS revisions does check the capabilities, so let's ensure that the proper caps are checked.
40 register_post_type( 'safecss', array(
41 // These are the defaults
42 // 'exclude_from_search' => true,
43 // 'public' => false,
44 // 'publicly_queryable' => false,
45 // 'show_ui' => false,
46 'supports' => array( 'revisions' ),
47 'label' => 'Custom CSS',
48 'can_export' => false,
49 'rewrite' => false,
50 'capabilities' => array(
51 'edit_post' => 'edit_theme_options',
52 'read_post' => 'read',
53 'delete_post' => 'edit_theme_options',
54 'edit_posts' => 'edit_theme_options',
55 'edit_others_posts' => 'edit_theme_options',
56 'publish_posts' => 'edit_theme_options',
57 'read_private_posts' => 'read'
58 )
59 ) );
60
61 // Short-circuit WP if this is a CSS stylesheet request
62 if ( isset( $_GET['custom-css'] ) ) {
63 header( 'Content-Type: text/css', true, 200 );
64 header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + 31536000) . ' GMT' ); // 1 year
65 Jetpack_Custom_CSS::print_css();
66 exit;
67 }
68
69 add_action( 'admin_enqueue_scripts', array( 'Jetpack_Custom_CSS', 'enqueue_scripts' ) );
70
71 if ( isset( $_GET['page'] ) && 'editcss' == $_GET['page'] && is_admin() ) {
72 // Do migration routine if necessary
73 Jetpack_Custom_CSS::upgrade();
74
75 /**
76 * Allows additional work when migrating safecss from wp_options to wp_post.
77 *
78 * @module custom-css
79 *
80 * @since 1.7.0
81 */
82 do_action( 'safecss_migrate_post' );
83 }
84
85 /**
86 * Never embed the style in the head on wpcom.
87 * Yes, this filter should be added to an unsynced file on wpcom, but
88 * there is no good syntactically-correct location to put it yet.
89 * @link https://github.com/Automattic/jetpack/commit/a1be114e9179f64d147124727a58e2cf76c7e5a1#commitcomment-7763921
90 */
91 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
92 add_filter( 'safecss_embed_style', '__return_false' );
93 } else {
94 add_filter( 'safecss_embed_style', array( 'Jetpack_Custom_CSS', 'should_we_inline_custom_css' ), 10, 2 );
95 }
96
97 add_action( 'wp_head', array( 'Jetpack_Custom_CSS', 'link_tag' ), 101 );
98
99 add_filter( 'jetpack_content_width', array( 'Jetpack_Custom_CSS', 'jetpack_content_width' ) );
100 add_filter( 'editor_max_image_size', array( 'Jetpack_Custom_CSS', 'editor_max_image_size' ), 10, 3 );
101
102 if ( !current_user_can( 'switch_themes' ) && !is_super_admin() )
103 return;
104
105 add_action( 'admin_menu', array( 'Jetpack_Custom_CSS', 'menu' ) );
106
107 if ( isset( $_POST['safecss'] ) && false == strstr( $_SERVER[ 'REQUEST_URI' ], 'options.php' ) ) {
108 check_admin_referer( 'safecss' );
109
110 $save_result = self::save( array(
111 'css' => stripslashes( $_POST['safecss'] ),
112 'is_preview' => isset( $_POST['action'] ) && $_POST['action'] == 'preview',
113 'preprocessor' => isset( $_POST['custom_css_preprocessor'] ) ? $_POST['custom_css_preprocessor'] : '',
114 'add_to_existing' => isset( $_POST['add_to_existing'] ) ? $_POST['add_to_existing'] == 'true' : true,
115 'content_width' => isset( $_POST['custom_content_width'] ) ? $_POST['custom_content_width'] : false,
116 ) );
117
118 if ( $_POST['action'] == 'preview' ) {
119 wp_safe_redirect( add_query_arg( 'csspreview', 'true', get_option( 'home' ) ) );
120 exit;
121 }
122
123 if ( $save_result )
124 add_action( 'admin_notices', array( 'Jetpack_Custom_CSS', 'saved_message' ) );
125 }
126
127 // Prevent content filters running on CSS when restoring revisions
128 if ( isset( $_REQUEST[ 'action' ] ) && 'restore' === $_REQUEST[ 'action' ] && false !== strstr( $_SERVER[ 'REQUEST_URI' ], 'revision.php' ) ) {
129 $parent_post = get_post( wp_get_post_parent_id( intval( $_REQUEST[ 'revision' ] ) ) );
130 if ( $parent_post && ! is_wp_error( $parent_post ) && 'safecss' === $parent_post->post_type ) {
131 // Remove wp_filter_post_kses, this causes CSS escaping issues
132 remove_filter( 'content_save_pre', 'wp_filter_post_kses' );
133 remove_filter( 'content_filtered_save_pre', 'wp_filter_post_kses' );
134 remove_all_filters( 'content_save_pre' );
135 }
136 }
137
138 // Modify all internal links so that preview state persists
139 if ( Jetpack_Custom_CSS::is_preview() )
140 ob_start( array( 'Jetpack_Custom_CSS', 'buffer' ) );
141 }
142
143 /**
144 * Save new custom CSS. This should be the entry point for any third-party code using Jetpack_Custom_CSS
145 * to save CSS.
146 *
147 * @param array $args Array of arguments:
148 * string $css The CSS (or LESS or Sass)
149 * bool $is_preview Whether this CSS is preview or published
150 * string preprocessor Which CSS preprocessor to use
151 * bool $add_to_existing Whether this CSS replaces the theme's CSS or supplements it.
152 * int $content_width A custom $content_width to go along with this CSS.
153 * @return int The post ID of the saved Custom CSS post.
154 */
155 public static function save( $args = array() ) {
156 $defaults = array(
157 'css' => '',
158 'is_preview' => false,
159 'preprocessor' => '',
160 'add_to_existing' => true,
161 'content_width' => false,
162 );
163
164 $args = wp_parse_args( $args, $defaults );
165
166 if ( $args['content_width'] && intval( $args['content_width']) > 0 && ( ! isset( $GLOBALS['content_width'] ) || $args['content_width'] != $GLOBALS['content_width'] ) )
167 $args['content_width'] = intval( $args['content_width'] );
168 else
169 $args['content_width'] = false;
170
171 // Remove wp_filter_post_kses, this causes CSS escaping issues
172 remove_filter( 'content_save_pre', 'wp_filter_post_kses' );
173 remove_filter( 'content_filtered_save_pre', 'wp_filter_post_kses' );
174 remove_all_filters( 'content_save_pre' );
175
176 /**
177 * Fires prior to saving custom css values. Necessitated because the
178 * core WordPress save_pre filters were removed:
179 * - content_save_pre
180 * - content_filtered_save_pre
181 *
182 * @module custom-css
183 *
184 * @since 1.7.0
185 *
186 * @param array $args {
187 * Array of custom CSS arguments.
188 * @type string $css The CSS (or LESS or Sass).
189 * @type bool $is_preview Whether this CSS is preview or published.
190 * @type string preprocessor Which CSS preprocessor to use.
191 * @type bool $add_to_existing Whether this CSS replaces the theme's CSS or supplements it.
192 * @type int $content_width A custom $content_width to go along with this CSS.
193 * }
194 */
195 do_action( 'safecss_save_pre', $args );
196
197 $warnings = array();
198
199 safecss_class();
200 $csstidy = new csstidy();
201 $csstidy->optimise = new safecss( $csstidy );
202
203 $csstidy->set_cfg( 'remove_bslash', false );
204 $csstidy->set_cfg( 'compress_colors', false );
205 $csstidy->set_cfg( 'compress_font-weight', false );
206 $csstidy->set_cfg( 'optimise_shorthands', 0 );
207 $csstidy->set_cfg( 'remove_last_;', false );
208 $csstidy->set_cfg( 'case_properties', false );
209 $csstidy->set_cfg( 'discard_invalid_properties', true );
210 $csstidy->set_cfg( 'css_level', 'CSS3.0' );
211 $csstidy->set_cfg( 'preserve_css', true );
212 $csstidy->set_cfg( 'template', dirname( __FILE__ ) . '/csstidy/wordpress-standard.tpl' );
213
214 $css = $orig = $args['css'];
215
216 $css = preg_replace( '/\\\\([0-9a-fA-F]{4})/', '\\\\\\\\$1', $prev = $css );
217 // prevent content: '\3434' from turning into '\\3434'
218 $css = str_replace( array( '\'\\\\', '"\\\\' ), array( '\'\\', '"\\' ), $css );
219
220 if ( $css != $prev )
221 $warnings[] = 'preg_replace found stuff';
222
223 // Some people put weird stuff in their CSS, KSES tends to be greedy
224 $css = str_replace( '<=', '&lt;=', $css );
225 // Why KSES instead of strip_tags? Who knows?
226 $css = wp_kses_split( $prev = $css, array(), array() );
227 $css = str_replace( '&gt;', '>', $css ); // kses replaces lone '>' with &gt;
228 // Why both KSES and strip_tags? Because we just added some '>'.
229 $css = strip_tags( $css );
230
231 if ( $css != $prev )
232 $warnings[] = 'kses found stuff';
233
234 // if we're not using a preprocessor
235 if ( ! $args['preprocessor'] ) {
236
237 /**
238 * Fires before parsing the css with CSSTidy, but only if
239 * the preprocessor is not configured for use.
240 *
241 * @module custom-css
242 *
243 * @since 1.7.0
244 *
245 * @param obj $csstidy The csstidy object.
246 * @param string $css Custom CSS.
247 * @param array $args Array of custom CSS arguments.
248 */
249 do_action( 'safecss_parse_pre', $csstidy, $css, $args );
250
251 $csstidy->parse( $css );
252
253 /**
254 * Fires after parsing the css with CSSTidy, but only if
255 * the preprocessor is not cinfigured for use.
256 *
257 * @module custom-css
258 *
259 * @since 1.7.0
260 *
261 * @param obj $csstidy The csstidy object.
262 * @param array $warnings Array of warnings.
263 * @param array $args Array of custom CSS arguments.
264 */
265 do_action( 'safecss_parse_post', $csstidy, $warnings, $args );
266
267 $css = $csstidy->print->plain();
268 }
269
270 if ( $args['add_to_existing'] )
271 $add_to_existing = 'yes';
272 else
273 $add_to_existing = 'no';
274
275 if ( $args['is_preview'] || Jetpack_Custom_CSS::is_freetrial() ) {
276 // Save the CSS
277 $safecss_revision_id = Jetpack_Custom_CSS::save_revision( $css, true, $args['preprocessor'] );
278
279 // Cache Buster
280 update_option( 'safecss_preview_rev', intval( get_option( 'safecss_preview_rev' ) ) + 1);
281
282 update_metadata( 'post', $safecss_revision_id, 'custom_css_add', $add_to_existing );
283 update_metadata( 'post', $safecss_revision_id, 'content_width', $args['content_width'] );
284 update_metadata( 'post', $safecss_revision_id, 'custom_css_preprocessor', $args['preprocessor'] );
285
286 delete_option( 'safecss_add' );
287 delete_option( 'safecss_content_width' );
288
289 if ( $args['is_preview'] ) {
290 return $safecss_revision_id;
291 }
292
293 /**
294 * Fires after saving Custom CSS.
295 *
296 * @module custom-css
297 *
298 * @since 1.7.0
299 */
300 do_action( 'safecss_save_preview_post' );
301 }
302
303 // Save the CSS
304 $safecss_post_id = Jetpack_Custom_CSS::save_revision( $css, false, $args['preprocessor'] );
305
306 $safecss_post_revision = Jetpack_Custom_CSS::get_current_revision();
307
308 update_option( 'safecss_rev', intval( get_option( 'safecss_rev' ) ) + 1 );
309
310 update_post_meta( $safecss_post_id, 'custom_css_add', $add_to_existing );
311 update_post_meta( $safecss_post_id, 'content_width', $args['content_width'] );
312 update_post_meta( $safecss_post_id, 'custom_css_preprocessor', $args['preprocessor'] );
313
314 delete_option( 'safecss_add' );
315 delete_option( 'safecss_content_width' );
316
317 update_metadata( 'post', $safecss_post_revision['ID'], 'custom_css_add', $add_to_existing );
318 update_metadata( 'post', $safecss_post_revision['ID'], 'content_width', $args['content_width'] );
319 update_metadata( 'post', $safecss_post_revision['ID'], 'custom_css_preprocessor', $args['preprocessor'] );
320
321 delete_option( 'safecss_preview_add' );
322
323 return $safecss_post_id;
324 }
325
326 /**
327 * Get the published custom CSS post.
328 *
329 * @return array
330 */
331 static function get_post() {
332 $custom_css_post_id = Jetpack_Custom_CSS::post_id();
333
334 if ( $custom_css_post_id )
335 return get_post( $custom_css_post_id, ARRAY_A );
336
337 return array();
338 }
339
340 /**
341 * Get the post ID of the published custom CSS post.
342 *
343 * @return int|bool The post ID if it exists; false otherwise.
344 */
345 static function post_id() {
346 /**
347 * Filter the ID of the post where Custom CSS is stored, before the ID is retrieved.
348 *
349 * If the callback function returns a non-null value, then post_id() will immediately
350 * return that value, instead of retrieving the normal post ID.
351 *
352 * @module custom-css
353 *
354 * @since 3.8.1
355 *
356 * @param null null The ID to return instead of the normal ID.
357 */
358 $custom_css_post_id = apply_filters( 'jetpack_custom_css_pre_post_id', null );
359 if ( ! is_null( $custom_css_post_id ) ) {
360 return $custom_css_post_id;
361 }
362
363 $custom_css_post_id = wp_cache_get( 'custom_css_post_id' );
364
365 if ( false === $custom_css_post_id ) {
366 $custom_css_posts = get_posts( array(
367 'posts_per_page' => 1,
368 'post_type' => 'safecss',
369 'post_status' => 'publish',
370 'orderby' => 'date',
371 'order' => 'DESC'
372 ) );
373
374 if ( count( $custom_css_posts ) > 0 )
375 $custom_css_post_id = $custom_css_posts[0]->ID;
376 else
377 $custom_css_post_id = 0;
378
379 // Save post_id=0 to note that no safecss post exists.
380 wp_cache_set( 'custom_css_post_id', $custom_css_post_id );
381 }
382
383 if ( ! $custom_css_post_id )
384 return false;
385
386 return $custom_css_post_id;
387 }
388
389 /**
390 * Get the current revision of the original safecss record
391 *
392 * @return object
393 */
394 static function get_current_revision() {
395 $safecss_post = Jetpack_Custom_CSS::get_post();
396
397 if ( empty( $safecss_post ) ) {
398 return false;
399 }
400
401 $revisions = wp_get_post_revisions( $safecss_post['ID'], array( 'posts_per_page' => 1, 'orderby' => 'date', 'order' => 'DESC' ) );
402
403 // Empty array if no revisions exist
404 if ( empty( $revisions ) ) {
405 // Return original post
406 return $safecss_post;
407 } else {
408 // Return the first entry in $revisions, this will be the current revision
409 $current_revision = get_object_vars( array_shift( $revisions ) );
410 return $current_revision;
411 }
412 }
413
414 /**
415 * Save new revision of CSS
416 * Checks to see if content was modified before really saving
417 *
418 * @param string $css
419 * @param bool $is_preview
420 * @return bool|int If nothing was saved, returns false. If a post
421 * or revision was saved, returns the post ID.
422 */
423 static function save_revision( $css, $is_preview = false, $preprocessor = '' ) {
424 $safecss_post = Jetpack_Custom_CSS::get_post();
425
426 $compressed_css = Jetpack_Custom_CSS::minify( $css, $preprocessor );
427
428 // If null, there was no original safecss record, so create one
429 if ( null == $safecss_post ) {
430 if ( ! $css )
431 return false;
432
433 $post = array();
434 $post['post_content'] = wp_slash( $css );
435 $post['post_title'] = 'safecss';
436 $post['post_status'] = 'publish';
437 $post['post_type'] = 'safecss';
438 $post['post_content_filtered'] = wp_slash( $compressed_css );
439
440 // Set excerpt to current theme, for display in revisions list
441 $current_theme = wp_get_theme();
442 $post['post_excerpt'] = $current_theme->Name;
443
444 // Insert the CSS into wp_posts
445 $post_id = wp_insert_post( $post );
446 wp_cache_set( 'custom_css_post_id', $post_id );
447 return $post_id;
448 }
449
450 // Update CSS in post array with new value passed to this function
451 $safecss_post['post_content'] = $css;
452 $safecss_post['post_content_filtered'] = $compressed_css;
453
454 // Set excerpt to current theme, for display in revisions list
455 $current_theme = wp_get_theme();
456 $safecss_post['post_excerpt'] = $current_theme->Name;
457
458 // Don't carry over last revision's timestamps, otherwise revisions all have matching timestamps
459 unset( $safecss_post['post_date'] );
460 unset( $safecss_post['post_date_gmt'] );
461 unset( $safecss_post['post_modified'] );
462 unset( $safecss_post['post_modified_gmt'] );
463
464 // Do not update post if we are only saving a preview
465 if ( false === $is_preview ) {
466 $safecss_post['post_content'] = wp_slash( $safecss_post['post_content'] );
467 $safecss_post['post_content_filtered'] = wp_slash( $safecss_post['post_content_filtered'] );
468 $post_id = wp_update_post( $safecss_post );
469 wp_cache_set( 'custom_css_post_id', $post_id );
470 return $post_id;
471 }
472 else if ( ! defined( 'DOING_MIGRATE' ) ) {
473 return _wp_put_post_revision( $safecss_post );
474 }
475 }
476
477 static function skip_stylesheet() {
478 /**
479 * Prevent the Custom CSS stylesheet from being enqueued.
480 *
481 * @module custom-css
482 *
483 * @since 2.2.1
484 *
485 * @param null Should the stylesheet be skipped. Default to null. Anything else will force the stylesheet to be skipped.
486 */
487 $skip_stylesheet = apply_filters( 'safecss_skip_stylesheet', null );
488
489 if ( null !== $skip_stylesheet ) {
490 return $skip_stylesheet;
491 } elseif ( Jetpack_Custom_CSS::is_customizer_preview() ) {
492 return false;
493 } else {
494 if ( Jetpack_Custom_CSS::is_preview() ) {
495 $safecss_post = Jetpack_Custom_CSS::get_current_revision();
496
497 if ( $safecss_post )
498 return (bool) ( get_post_meta( $safecss_post['ID'], 'custom_css_add', true ) == 'no' );
499 else
500 return (bool) ( get_option( 'safecss_preview_add' ) == 'no' );
501 }
502 else {
503 $custom_css_post_id = Jetpack_Custom_CSS::post_id();
504
505 if ( $custom_css_post_id ) {
506 $custom_css_add = get_post_meta( $custom_css_post_id, 'custom_css_add', true );
507
508 // It is possible for the CSS to be stored in a post but for the safecss_add option
509 // to have not been upgraded yet if the user hasn't opened their Custom CSS editor
510 // since October 2012.
511 if ( ! empty( $custom_css_add ) )
512 return (bool) ( $custom_css_add === 'no' );
513 }
514
515 return (bool) ( Jetpack_Options::get_option_and_ensure_autoload( 'safecss_add', '' ) == 'no' );
516 }
517 }
518 }
519
520 static function is_preview() {
521 return isset( $_GET['csspreview'] ) && $_GET['csspreview'] === 'true';
522 }
523
524 /**
525 * Currently this filter function gets called on
526 * 'template_redirect' action and
527 * 'admin_init' action
528 */
529 static function set_content_width(){
530 // Don't apply this filter on the Edit CSS page
531 if ( isset( $_GET ) && isset( $_GET['page'] ) && 'editcss' == $_GET['page'] && is_admin() ) {
532 return;
533 }
534
535 $GLOBALS['content_width'] = Jetpack::get_content_width();
536 }
537
538 /*
539 * False when the site has the Custom Design upgrade.
540 * Used only on WordPress.com.
541 */
542 static function is_freetrial() {
543 /**
544 * Determine if a WordPress.com site uses a Free trial of the Custom Design Upgrade.
545 * Used only on WordPress.com.
546 *
547 * @module custom-css
548 *
549 * @since 1.7.0
550 *
551 * @param bool false Does the site use a Free trial of the Custom Design Upgrade. Default to false.
552 */
553 return apply_filters( 'safecss_is_freetrial', false );
554 }
555
556 static function get_preprocessor_key() {
557 $safecss_post = Jetpack_Custom_CSS::get_current_revision();
558 return get_post_meta( $safecss_post['ID'], 'custom_css_preprocessor', true );
559 }
560
561 static function get_preprocessor() {
562 /** This filter is documented in modules/custom-css/custom-css.php */
563 $preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
564 $selected_preprocessor_key = self::get_preprocessor_key();
565 $selected_preprocessor = isset( $preprocessors[ $selected_preprocessor_key ] ) ? $preprocessors[ $selected_preprocessor_key ] : null;
566 return $selected_preprocessor;
567 }
568
569 static function get_css( $compressed = false ) {
570 /**
571 * Filter the Custom CSS returned.
572 * Can be used to return an error, or no CSS at all.
573 *
574 * @module custom-css
575 *
576 * @since 1.7.0
577 *
578 * @param bool false Should we return an error instead of the Custom CSS. Default to false.
579 */
580 $default_css = apply_filters( 'safecss_get_css_error', false );
581
582 if ( $default_css !== false )
583 return $default_css;
584
585 $option = ( Jetpack_Custom_CSS::is_preview() || Jetpack_Custom_CSS::is_freetrial() ) ? 'safecss_preview' : 'safecss';
586 $css = '';
587
588 if ( 'safecss' == $option ) {
589 // Don't bother checking for a migrated 'safecss' option if it never existed.
590 if ( false === get_option( 'safecss' ) || get_option( 'safecss_revision_migrated' ) ) {
591 $safecss_post = Jetpack_Custom_CSS::get_post();
592 if ( ! empty( $safecss_post ) ) {
593 $css = ( $compressed && $safecss_post['post_content_filtered'] ) ? $safecss_post['post_content_filtered'] : $safecss_post['post_content'];
594 }
595 } else {
596 $current_revision = Jetpack_Custom_CSS::get_current_revision();
597 if ( false === $current_revision ) {
598 $css = '';
599 } else {
600 $css = ( $compressed && $current_revision['post_content_filtered'] ) ? $current_revision['post_content_filtered'] : $current_revision['post_content'];
601 }
602 }
603
604 // Fix for un-migrated Custom CSS
605 if ( empty( $safecss_post ) ) {
606 $_css = get_option( 'safecss' );
607 if ( !empty( $_css ) ) {
608 $css = $_css;
609 }
610 }
611 }
612 else if ( 'safecss_preview' == $option ) {
613 $safecss_post = Jetpack_Custom_CSS::get_current_revision();
614 $css = $safecss_post['post_content'];
615 $css = Jetpack_Custom_CSS::minify( $css, get_post_meta( $safecss_post['ID'], 'custom_css_preprocessor', true ) );
616 }
617
618 $css = str_replace( array( '\\\00BB \\\0020', '\0BB \020', '0BB 020' ), '\00BB \0020', $css );
619
620 if ( empty( $css ) ) {
621 $css = "/*\n"
622 . wordwrap(
623 /**
624 * Filter the default message displayed in the Custom CSS editor.
625 *
626 * @module custom-css
627 *
628 * @since 1.7.0
629 *
630 * @param string $str Default Custom CSS editor content.
631 */
632 apply_filters(
633 'safecss_default_css',
634 __(
635 "Welcome to Custom CSS!\n\nTo learn how this works, see http://wp.me/PEmnE-Bt",
636 'jetpack'
637 )
638 )
639 )
640 . "\n*/";
641 }
642
643 /**
644 * Filter the Custom CSS returned from the editor.
645 *
646 * @module custom-css
647 *
648 * @since 1.7.0
649 *
650 * @param string $css Custom CSS.
651 */
652 $css = apply_filters( 'safecss_css', $css );
653
654 return $css;
655 }
656
657 static function replace_insecure_urls( $css ) {
658 if ( ! function_exists( '_sa_get_frontend_https_url_replacement_map' ) ) {
659 return $css;
660 }
661 list( $http_urls, $secure_urls ) = _sa_get_frontend_https_url_replacement_map();
662
663 return str_replace( $http_urls, $secure_urls, $css );
664 }
665
666 static function print_css() {
667
668 /**
669 * Fires right before printing the custom CSS inside the <head> element.
670 *
671 * @module custom-css
672 *
673 * @since 1.7.0
674 */
675 do_action( 'safecss_print_pre' );
676 $css = Jetpack_Custom_CSS::get_css( true );
677 echo self::replace_insecure_urls( $css );
678 }
679
680 static function should_we_inline_custom_css( $should_we, $css ) {
681 // If the CSS is less than 2,000 characters, inline it! otherwise return what was passed in.
682 return ( strlen( $css ) < 2000 ) ? true : $should_we;
683 }
684
685 static function link_tag() {
686 global $blog_id, $current_blog;
687
688 if (
689 /**
690 * Do not include any CSS on the page if the CSS includes an error.
691 * Setting this filter to true stops any Custom CSS from being enqueued.
692 *
693 * @module custom-css
694 *
695 * @since 1.7.0
696 *
697 * @param bool false Does the CSS include an error. Default to false.
698 */
699 apply_filters( 'safecss_style_error', false )
700 ) {
701 return;
702 }
703
704 if ( ! is_super_admin() && isset( $current_blog ) && ( 1 == $current_blog->spam || 1 == $current_blog->deleted ) )
705 return;
706
707 if ( Jetpack_Custom_CSS::is_customizer_preview() )
708 return;
709
710 $css = '';
711 $option = Jetpack_Custom_CSS::is_preview() ? 'safecss_preview' : 'safecss';
712
713 if ( 'safecss' == $option ) {
714 if ( Jetpack_Options::get_option_and_ensure_autoload( 'safecss_revision_migrated', '0' ) ) {
715 $safecss_post = Jetpack_Custom_CSS::get_post();
716
717 if ( ! empty( $safecss_post['post_content'] ) ) {
718 $css = $safecss_post['post_content'];
719 }
720 } else {
721 $current_revision = Jetpack_Custom_CSS::get_current_revision();
722
723 if ( ! empty( $current_revision['post_content'] ) ) {
724 $css = $current_revision['post_content'];
725 }
726 }
727
728 // Fix for un-migrated Custom CSS
729 if ( empty( $safecss_post ) ) {
730 $_css = Jetpack_Options::get_option_and_ensure_autoload( 'safecss', '' );
731 if ( !empty( $_css ) ) {
732 $css = $_css;
733 }
734 }
735 }
736
737 if ( 'safecss_preview' == $option ) {
738 $safecss_post = Jetpack_Custom_CSS::get_current_revision();
739
740 if ( !empty( $safecss_post['post_content'] ) ) {
741 $css = $safecss_post['post_content'];
742 }
743 }
744
745 $css = str_replace( array( '\\\00BB \\\0020', '\0BB \020', '0BB 020' ), '\00BB \0020', $css );
746
747 if ( $css == '' )
748 return;
749
750 if (
751 /**
752 * Allow inserting CSS inline instead of through a separate file.
753 *
754 * @module custom-css
755 *
756 * @since 3.4.0
757 *
758 * @param bool false Should the CSS be added inline instead of through a separate file. Default to false.
759 * @param string $css Custom CSS.
760 */
761 apply_filters( 'safecss_embed_style', false, $css )
762 ) {
763
764 echo "\r\n" . '<style id="custom-css-css">' . Jetpack_Custom_CSS::get_css( true ) . "</style>\r\n";
765
766 } else {
767
768 $href = home_url( '/' );
769 $href = add_query_arg( 'custom-css', 1, $href );
770 $href = add_query_arg( 'csblog', $blog_id, $href );
771 $href = add_query_arg( 'cscache', 6, $href );
772 $href = add_query_arg( 'csrev', (int) get_option( $option . '_rev' ), $href );
773
774 /**
775 * Filter the Custom CSS link enqueued in the head.
776 *
777 * @module custom-css
778 *
779 * @since 1.7.0
780 *
781 * @param string $href Custom CSS link enqueued in the head.
782 * @param string $blog_id Blog ID.
783 */
784 $href = apply_filters( 'safecss_href', $href, $blog_id );
785
786 if ( Jetpack_Custom_CSS::is_preview() )
787 $href = add_query_arg( 'csspreview', 'true', $href );
788
789 ?>
790 <link rel="stylesheet" id="custom-css-css" type="text/css" href="<?php echo esc_url( $href ); ?>" />
791 <?php
792
793 }
794
795 /**
796 * Fires after creating the <link> in the <head> element for the custom css stylesheet.
797 *
798 * @module custom-css
799 *
800 * @since 2.2.2
801 */
802 do_action( 'safecss_link_tag_post' );
803 }
804
805 static function style_filter( $current ) {
806 if ( Jetpack_Custom_CSS::is_freetrial() && ( ! Jetpack_Custom_CSS::is_preview() || ! current_user_can( 'switch_themes' ) ) )
807 return $current;
808 else if ( Jetpack_Custom_CSS::skip_stylesheet() )
809 /**
810 * Filter the default blank Custom CSS URL.
811 *
812 * @module custom-css
813 *
814 * @since 2.2.1
815 *
816 * @param string $url Default blank Custom CSS URL.
817 */
818 return apply_filters( 'safecss_style_filter_url', plugins_url( 'custom-css/css/blank.css', __FILE__ ) );
819
820 return $current;
821 }
822
823 static function buffer( $html ) {
824 $html = str_replace( '</body>', Jetpack_Custom_CSS::preview_flag(), $html );
825 return preg_replace_callback( '!href=([\'"])(.*?)\\1!', array( 'Jetpack_Custom_CSS', 'preview_links' ), $html );
826 }
827
828 static function preview_links( $matches ) {
829 if ( 0 !== strpos( $matches[2], get_option( 'home' ) ) )
830 return $matches[0];
831
832 $link = wp_specialchars_decode( $matches[2] );
833 $link = add_query_arg( 'csspreview', 'true', $link );
834 $link = esc_url( $link );
835 return "href={$matches[1]}$link{$matches[1]}";
836 }
837
838 /**
839 * Places a black bar above every preview page
840 */
841 static function preview_flag() {
842 if ( is_admin() )
843 return;
844
845 $message = esc_html__( 'Preview: changes must be saved or they will be lost', 'jetpack' );
846 /**
847 * Filter the Preview message displayed on the site when previewing custom CSS, before to save it.
848 *
849 * @module custom-css
850 *
851 * @since 1.7.0
852 *
853 * @param string $message Custom CSS preview message.
854 */
855 $message = apply_filters( 'safecss_preview_message', $message );
856
857 $preview_flag_js = "var flag = document.createElement('div');
858 flag.innerHTML = " . json_encode( $message ) . ";
859 flag.style.background = '#FF6600';
860 flag.style.color = 'white';
861 flag.style.textAlign = 'center';
862 flag.style.fontSize = '15px';
863 flag.style.padding = '2px';
864 flag.style.fontFamily = 'sans-serif';
865 document.body.style.paddingTop = '0px';
866 document.body.insertBefore(flag, document.body.childNodes[0]);
867 ";
868
869 /**
870 * Filter the Custom CSS preview message JS styling.
871 *
872 * @module custom-css
873 *
874 * @since 1.7.0
875 *
876 * @param string $preview_flag_js Custom CSS preview message JS styling.
877 */
878 $preview_flag_js = apply_filters( 'safecss_preview_flag_js', $preview_flag_js );
879 if ( $preview_flag_js ) {
880 $preview_flag_js = '<script type="text/javascript">
881 // <![CDATA[
882 ' . $preview_flag_js . '
883 // ]]>
884 </script>';
885 }
886
887 return $preview_flag_js;
888 }
889
890 static function menu() {
891 $parent = 'themes.php';
892 $title = __( 'Edit CSS', 'jetpack' );
893 $hook = add_theme_page( $title, $title, 'edit_theme_options', 'editcss', array( 'Jetpack_Custom_CSS', 'admin' ) );
894
895 add_action( "load-revision.php", array( 'Jetpack_Custom_CSS', 'prettify_post_revisions' ) );
896 add_action( "load-$hook", array( 'Jetpack_Custom_CSS', 'update_title' ) );
897 }
898
899 /**
900 * Adds a menu item in the appearance section for this plugin's administration
901 * page. Also adds hooks to enqueue the CSS and JS for the admin page.
902 */
903 static function update_title() {
904 global $title;
905 $title = __( 'CSS', 'jetpack' );
906 }
907
908 static function prettify_post_revisions() {
909 add_filter( 'the_title', array( 'Jetpack_Custom_CSS', 'post_title' ), 10, 2 );
910 }
911
912 static function post_title( $title, $post_id ) {
913 if ( !$post_id = (int) $post_id ) {
914 return $title;
915 }
916
917 if ( !$post = get_post( $post_id ) ) {
918 return $title;
919 }
920
921 if ( 'safecss' != $post->post_type ) {
922 return $title;
923 }
924
925 return __( 'Custom CSS Stylesheet', 'jetpack' );
926 }
927
928 static function enqueue_scripts( $hook ) {
929 if ( 'appearance_page_editcss' != $hook )
930 return;
931
932 wp_enqueue_script( 'postbox' );
933 wp_enqueue_script(
934 'custom-css-editor',
935 Jetpack::get_file_url_for_environment(
936 '_inc/build/custom-css/custom-css/js/css-editor.min.js',
937 'modules/custom-css/custom-css/js/css-editor.js'
938 ),
939 'jquery',
940 '20130325',
941 true
942 );
943 wp_enqueue_style( 'custom-css-editor', plugins_url( 'custom-css/css/css-editor.css', __FILE__ ) );
944
945 if ( defined( 'SAFECSS_USE_ACE' ) && SAFECSS_USE_ACE ) {
946 wp_register_style( 'jetpack-css-codemirror', plugins_url( 'custom-css/css/codemirror.css', __FILE__ ), array(), '20120905' );
947 wp_enqueue_style( 'jetpack-css-use-codemirror', plugins_url( 'custom-css/css/use-codemirror.css', __FILE__ ), array( 'jetpack-css-codemirror' ), '20120905' );
948
949 wp_register_script( 'jetpack-css-codemirror', plugins_url( 'custom-css/js/codemirror.min.js', __FILE__ ), array(), '3.16', true );
950 wp_enqueue_script(
951 'jetpack-css-use-codemirror',
952 Jetpack::get_file_url_for_environment(
953 '_inc/build/custom-css/custom-css/js/use-codemirror.min.js',
954 'modules/custom-css/custom-css/js/use-codemirror.js'
955 ),
956 array( 'jquery', 'underscore', 'jetpack-css-codemirror' ),
957 '20131009',
958 true
959 );
960 }
961 }
962
963 static function saved_message() {
964 echo '<div id="message" class="updated fade"><p><strong>' . __( 'Stylesheet saved.', 'jetpack' ) . '</strong></p></div>';
965 }
966
967 static function admin() {
968 add_meta_box( 'submitdiv', __( 'Publish', 'jetpack' ), array( __CLASS__, 'publish_box' ), 'editcss', 'side' );
969 add_action( 'custom_css_submitbox_misc_actions', array( __CLASS__, 'content_width_settings' ) );
970
971 $safecss_post = Jetpack_Custom_CSS::get_post();
972
973 if ( ! empty( $safecss_post ) && 0 < $safecss_post['ID'] && wp_get_post_revisions( $safecss_post['ID'], array( 'posts_per_page' => 1 ) ) )
974 add_meta_box( 'revisionsdiv', __( 'CSS Revisions', 'jetpack' ), array( __CLASS__, 'revisions_meta_box' ), 'editcss', 'side' );
975 ?>
976 <div class="wrap">
977 <?php
978
979 /**
980 * Fires right before the custom css page begins.
981 *
982 * @module custom-css
983 *
984 * @since 1.7.0
985 */
986 do_action( 'custom_design_header' );
987
988 ?>
989 <h1><?php _e( 'CSS Stylesheet Editor', 'jetpack' ); ?></h1>
990 <form id="safecssform" action="" method="post">
991 <?php wp_nonce_field( 'safecss' ) ?>
992 <?php wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false ); ?>
993 <?php wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false ); ?>
994 <input type="hidden" name="action" value="save" />
995 <div id="poststuff">
996 <p class="css-support">
997 <?php
998 /**
999 * Filter the intro text appearing above the Custom CSS Editor.
1000 *
1001 * @module custom-css
1002 *
1003 * @since 1.7.0
1004 *
1005 * @param string $str Intro text appearing above the Custom CSS editor.
1006 */
1007 echo apply_filters( 'safecss_intro_text', __( 'New to CSS? Start with a <a href="http://www.htmldog.com/guides/cssbeginner/" rel="noopener noreferrer" target="_blank">beginner tutorial</a>. Questions?
1008 Ask in the <a href="https://wordpress.org/support/forum/themes-and-templates" rel="noopener noreferrer" target="_blank">Themes and Templates forum</a>.', 'jetpack' ) );
1009 ?></p>
1010 <p class="css-support"><?php echo __( 'Note: Custom CSS will be reset when changing themes.', 'jetpack' ); ?></p>
1011
1012 <div id="post-body" class="metabox-holder columns-2">
1013 <div id="post-body-content">
1014 <div class="postarea">
1015 <textarea id="safecss" name="safecss"<?php if ( SAFECSS_USE_ACE ) echo ' class="hide-if-js"'; ?>><?php echo esc_textarea( Jetpack_Custom_CSS::get_css() ); ?></textarea>
1016 <div class="clear"></div>
1017 </div>
1018 </div>
1019 <div id="postbox-container-1" class="postbox-container">
1020 <?php do_meta_boxes( 'editcss', 'side', $safecss_post ); ?>
1021 </div>
1022 </div>
1023 <br class="clear" />
1024 </div>
1025 </form>
1026 </div>
1027 <?php
1028 }
1029
1030 /**
1031 * Content width setting callback
1032 */
1033 static function content_width_settings() {
1034 $safecss_post = Jetpack_Custom_CSS::get_current_revision();
1035
1036 $custom_content_width = get_post_meta( $safecss_post['ID'], 'content_width', true );
1037
1038 // If custom content width hasn't been overridden and the theme has a content_width value, use that as a default.
1039 if ( $custom_content_width <= 0 && ! empty( $GLOBALS['content_width'] ) )
1040 $custom_content_width = $GLOBALS['content_width'];
1041
1042 if ( ! $custom_content_width || ( isset( $GLOBALS['content_width'] ) && $custom_content_width == $GLOBALS['content_width'] ) )
1043 $custom_content_width = '';
1044
1045 ?>
1046 <div class="misc-pub-section">
1047 <label><?php esc_html_e( 'Media Width:', 'jetpack' ); ?></label>
1048 <span id="content-width-display" data-default-text="<?php esc_attr_e( 'Default', 'jetpack' ); ?>" data-custom-text="<?php esc_attr_e( '%s px', 'jetpack' ); ?>"><?php echo $custom_content_width ? sprintf( esc_html__( '%s px', 'jetpack' ), $custom_content_width ) : esc_html_e( 'Default', 'jetpack' ); ?></span>
1049 <a class="edit-content-width hide-if-no-js" href="#content-width"><?php echo esc_html_e( 'Edit', 'jetpack' ); ?></a>
1050 <div id="content-width-select" class="hide-if-js">
1051 <input type="hidden" name="custom_content_width" id="custom_content_width" value="<?php echo esc_attr( $custom_content_width ); ?>" />
1052 <p>
1053 <?php
1054
1055 printf( /* translators: %1$s is replaced with an input field for numbers. */
1056 __( 'Limit width to %1$s pixels for full size images. (<a href="%2$s" rel="noopener noreferrer" target="_blank">More info</a>.)', 'jetpack' ),
1057 '<input type="text" id="custom_content_width_visible" value="' . esc_attr( $custom_content_width ) . '" size="4" />',
1058 /**
1059 * Filter the Custom CSS limited width's support doc URL.
1060 *
1061 * @module custom-css
1062 *
1063 * @since 2.2.3
1064 *
1065 * @param string $url Custom CSS limited width's support doc URL.
1066 */
1067 apply_filters( 'safecss_limit_width_link', 'http://jetpack.com/support/custom-css/#limited-width' )
1068 );
1069
1070 ?>
1071 </p>
1072 <?php
1073
1074 if (
1075 ! empty( $GLOBALS['content_width'] )
1076 && $custom_content_width != $GLOBALS['content_width']
1077 ) {
1078 $current_theme = wp_get_theme()->Name;
1079
1080 ?>
1081 <p><?php printf( _n( 'The default content width for the %s theme is %d pixel.', 'The default content width for the %s theme is %d pixels.', intval( $GLOBALS['content_width'] ), 'jetpack' ), $current_theme, intval( $GLOBALS['content_width'] ) ); ?></p>
1082 <?php
1083 }
1084
1085 ?>
1086 <a class="save-content-width hide-if-no-js button" href="#content-width"><?php esc_html_e( 'OK', 'jetpack' ); ?></a>
1087 <a class="cancel-content-width hide-if-no-js" href="#content-width"><?php esc_html_e( 'Cancel', 'jetpack' ); ?></a>
1088 </div>
1089 <script type="text/javascript">
1090 jQuery( function ( $ ) {
1091 var defaultContentWidth = <?php echo isset( $GLOBALS['content_width'] ) ? json_encode( intval( $GLOBALS['content_width'] ) ) : 0; ?>;
1092
1093 $( '.edit-content-width' ).bind( 'click', function ( e ) {
1094 e.preventDefault();
1095
1096 $( '#content-width-select' ).slideDown();
1097 $( this ).hide();
1098 } );
1099
1100 $( '.cancel-content-width' ).bind( 'click', function ( e ) {
1101 e.preventDefault();
1102
1103 $( '#content-width-select' ).slideUp( function () {
1104 $( '.edit-content-width' ).show();
1105 $( '#custom_content_width_visible' ).val( $( '#custom_content_width' ).val() );
1106 } );
1107 } );
1108
1109 $( '.save-content-width' ).bind( 'click', function ( e ) {
1110 e.preventDefault();
1111
1112 $( '#content-width-select' ).slideUp();
1113
1114 var newContentWidth = parseInt( $( '#custom_content_width_visible' ).val(), 10 );
1115
1116 if ( newContentWidth && newContentWidth != defaultContentWidth ) {
1117 $( '#content-width-display' ).text(
1118 $( '#content-width-display' )
1119 .data( 'custom-text' )
1120 .replace( '%s', $( '#custom_content_width_visible' ).val() )
1121 );
1122 }
1123 else {
1124 $( '#content-width-display' ).text( $( '#content-width-display' ).data( 'default-text' ) );
1125 }
1126
1127 $( '#custom_content_width' ).val( $( '#custom_content_width_visible' ).val() );
1128 $( '.edit-content-width' ).show();
1129 } );
1130 } );
1131 </script>
1132 </div>
1133 <?php
1134 }
1135
1136 static function publish_box() {
1137 ?>
1138 <div id="minor-publishing">
1139 <div id="misc-publishing-actions">
1140 <?php
1141
1142 /**
1143 * Filter the array of available Custom CSS preprocessors.
1144 *
1145 * @module custom-css
1146 *
1147 * @since 2.0.3
1148 *
1149 * @param array array() Empty by default.
1150 */
1151 $preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
1152
1153 if ( ! empty( $preprocessors ) ) {
1154 $safecss_post = Jetpack_Custom_CSS::get_current_revision();
1155 $selected_preprocessor_key = get_post_meta( $safecss_post['ID'], 'custom_css_preprocessor', true );
1156 $selected_preprocessor = isset( $preprocessors[$selected_preprocessor_key] ) ? $preprocessors[$selected_preprocessor_key] : null;
1157
1158 ?>
1159 <div class="misc-pub-section">
1160 <label><?php esc_html_e( 'Preprocessor:', 'jetpack' ); ?></label>
1161 <span id="preprocessor-display"><?php echo esc_html( $selected_preprocessor ? $selected_preprocessor['name'] : __( 'None', 'jetpack' ) ); ?></span>
1162 <a class="edit-preprocessor hide-if-no-js" href="#preprocessor"><?php echo esc_html_e( 'Edit', 'jetpack' ); ?></a>
1163 <div id="preprocessor-select" class="hide-if-js">
1164 <input type="hidden" name="custom_css_preprocessor" id="custom_css_preprocessor" value="<?php echo esc_attr( $selected_preprocessor_key ); ?>" />
1165 <select id="preprocessor_choices">
1166 <option value=""><?php esc_html_e( 'None', 'jetpack' ); ?></option>
1167 <?php
1168
1169 foreach ( $preprocessors as $preprocessor_key => $preprocessor ) {
1170 ?>
1171 <option value="<?php echo esc_attr( $preprocessor_key ); ?>" <?php selected( $selected_preprocessor_key, $preprocessor_key ); ?>><?php echo esc_html( $preprocessor['name'] ); ?></option>
1172 <?php
1173 }
1174
1175 ?>
1176 </select>
1177 <a class="save-preprocessor hide-if-no-js button" href="#preprocessor"><?php esc_html_e( 'OK', 'jetpack' ); ?></a>
1178 <a class="cancel-preprocessor hide-if-no-js" href="#preprocessor"><?php esc_html_e( 'Cancel', 'jetpack' ); ?></a>
1179 </div>
1180 </div>
1181 <?php
1182 }
1183
1184 $safecss_post = Jetpack_Custom_CSS::get_current_revision();
1185
1186 $add_css = ( get_post_meta( $safecss_post['ID'], 'custom_css_add', true ) != 'no' );
1187
1188 ?>
1189 <div class="misc-pub-section">
1190 <label><?php esc_html_e( 'Mode:', 'jetpack' ); ?></label>
1191 <span id="css-mode-display"><?php echo esc_html( $add_css ? __( 'Add-on', 'jetpack' ) : __( 'Replacement', 'jetpack' ) ); ?></span>
1192 <a class="edit-css-mode hide-if-no-js" href="#css-mode"><?php echo esc_html_e( 'Edit', 'jetpack' ); ?></a>
1193 <div id="css-mode-select" class="hide-if-js">
1194 <input type="hidden" name="add_to_existing" id="add_to_existing" value="<?php echo $add_css ? 'true' : 'false'; ?>" />
1195 <p>
1196 <label>
1197 <input type="radio" name="add_to_existing_display" value="true" <?php checked( $add_css ); ?>/>
1198 <?php _e( 'Add-on CSS <b>(Recommended)</b>', 'jetpack' ); ?>
1199 </label>
1200 <br />
1201 <label>
1202 <input type="radio" name="add_to_existing_display" value="false" <?php checked( ! $add_css ); ?>/>
1203 <?php printf(
1204 __( 'Replace <a href="%s">theme\'s CSS</a> <b>(Advanced)</b>', 'jetpack' ),
1205 /**
1206 * Filter the theme's stylesheet URL.
1207 *
1208 * @module custom-css
1209 *
1210 * @since 1.7.0
1211 *
1212 * @param string $url Active theme's stylesheet URL. Default to get_stylesheet_uri().
1213 */
1214 apply_filters( 'safecss_theme_stylesheet_url', get_stylesheet_uri() )
1215 ); ?>
1216 </label>
1217 </p>
1218 <a class="save-css-mode hide-if-no-js button" href="#css-mode"><?php esc_html_e( 'OK', 'jetpack' ); ?></a>
1219 <a class="cancel-css-mode hide-if-no-js" href="#css-mode"><?php esc_html_e( 'Cancel', 'jetpack' ); ?></a>
1220 </div>
1221 </div>
1222 <?php
1223
1224 /**
1225 * Allows addition of elements to the submit box for custom css on the wp-admin side.
1226 *
1227 * @module custom-css
1228 *
1229 * @since 2.0.3
1230 */
1231 do_action( 'custom_css_submitbox_misc_actions' );
1232
1233 ?>
1234 </div>
1235 </div>
1236 <div id="major-publishing-actions">
1237 <input type="button" class="button" id="preview" name="preview" value="<?php esc_attr_e( 'Preview', 'jetpack' ) ?>" />
1238 <div id="publishing-action">
1239 <input type="submit" class="button-primary" id="save" name="save" value="<?php ( Jetpack_Custom_CSS::is_freetrial() ) ? esc_attr_e( 'Save &amp; Buy Upgrade', 'jetpack' ) : esc_attr_e( 'Save Stylesheet', 'jetpack' ); ?>" />
1240 </div>
1241 </div>
1242 <?php
1243 }
1244
1245 /**
1246 * Render metabox listing CSS revisions and the themes that correspond to the revisions.
1247 * Called by safecss_admin
1248 *
1249 * @global $post
1250 * @param array $safecss_post
1251 * @uses wp_revisions_to_keep
1252 * @uses WP_Query
1253 * @uses wp_post_revision_title
1254 * @uses esc_html
1255 * @uses add_query_arg
1256 * @uses menu_page_url
1257 * @uses wp_reset_query
1258 * @return string
1259 */
1260 static function revisions_meta_box( $safecss_post ) {
1261
1262 $show_all_revisions = isset( $_GET['show_all_rev'] );
1263
1264 if ( function_exists( 'wp_revisions_to_keep' ) ) {
1265 $max_revisions = wp_revisions_to_keep( (object) $safecss_post );
1266 } else {
1267 $max_revisions = defined( 'WP_POST_REVISIONS' ) && is_numeric( WP_POST_REVISIONS ) ? (int) WP_POST_REVISIONS : 25;
1268 }
1269
1270 $posts_per_page = $show_all_revisions ? $max_revisions : 6;
1271
1272 $revisions = new WP_Query( array(
1273 'posts_per_page' => $posts_per_page,
1274 'post_type' => 'revision',
1275 'post_status' => 'inherit',
1276 'post_parent' => $safecss_post['ID'],
1277 'orderby' => 'date',
1278 'order' => 'DESC'
1279 ) );
1280
1281 if ( $revisions->have_posts() ) { ?>
1282 <ul class="post-revisions"><?php
1283
1284 global $post;
1285
1286 while ( $revisions->have_posts() ) :
1287 $revisions->the_post();
1288
1289 ?><li>
1290 <?php
1291 echo wp_post_revision_title( $post );
1292
1293 if ( ! empty( $post->post_excerpt ) )
1294 echo ' (' . esc_html( $post->post_excerpt ) . ')';
1295 ?>
1296 </li><?php
1297
1298 endwhile;
1299
1300 ?></ul><?php
1301
1302 if ( $revisions->found_posts > 6 && !$show_all_revisions ) {
1303 ?>
1304 <br>
1305 <a href="<?php echo add_query_arg( 'show_all_rev', 'true', menu_page_url( 'editcss', false ) ); ?>"><?php esc_html_e( 'Show all', 'jetpack' ); ?></a>
1306 <?php
1307 }
1308 }
1309
1310 wp_reset_query();
1311 }
1312
1313 /**
1314 * Hook in init at priority 11 to disable custom CSS.
1315 */
1316 static function disable() {
1317 remove_action( 'wp_head', array( 'Jetpack_Custom_CSS', 'link_tag' ), 101 );
1318 remove_filter( 'stylesheet_uri', array( 'Jetpack_Custom_CSS', 'style_filter' ) );
1319 }
1320
1321 /**
1322 * Reset all aspects of Custom CSS on a theme switch so that changing
1323 * themes is a sure-fire way to get a clean start.
1324 */
1325 static function reset() {
1326 $safecss_post_id = Jetpack_Custom_CSS::save_revision( '' );
1327 $safecss_revision = Jetpack_Custom_CSS::get_current_revision();
1328
1329 update_option( 'safecss_rev', intval( get_option( 'safecss_rev' ) ) + 1 );
1330
1331 update_post_meta( $safecss_post_id, 'custom_css_add', 'yes' );
1332 update_post_meta( $safecss_post_id, 'content_width', false );
1333 update_post_meta( $safecss_post_id, 'custom_css_preprocessor', '' );
1334
1335 delete_option( 'safecss_add' );
1336 delete_option( 'safecss_content_width' );
1337
1338 update_metadata( 'post', $safecss_revision['ID'], 'custom_css_add', 'yes' );
1339 update_metadata( 'post', $safecss_revision['ID'], 'content_width', false );
1340 update_metadata( 'post', $safecss_revision['ID'], 'custom_css_preprocessor', '' );
1341
1342 delete_option( 'safecss_preview_add' );
1343 }
1344
1345 static function is_customizer_preview() {
1346 if ( isset ( $GLOBALS['wp_customize'] ) )
1347 return ! $GLOBALS['wp_customize']->is_theme_active();
1348
1349 return false;
1350 }
1351
1352 static function minify( $css, $preprocessor = '' ) {
1353 if ( ! $css )
1354 return '';
1355
1356 if ( $preprocessor ) {
1357 /** This filter is documented in modules/custom-css/custom-css.php */
1358 $preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
1359
1360 if ( isset( $preprocessors[$preprocessor] ) ) {
1361 $css = call_user_func( $preprocessors[$preprocessor]['callback'], $css );
1362 }
1363 }
1364
1365 safecss_class();
1366 $csstidy = new csstidy();
1367 $csstidy->optimise = new safecss( $csstidy );
1368
1369 $csstidy->set_cfg( 'remove_bslash', false );
1370 $csstidy->set_cfg( 'compress_colors', true );
1371 $csstidy->set_cfg( 'compress_font-weight', true );
1372 $csstidy->set_cfg( 'remove_last_;', true );
1373 $csstidy->set_cfg( 'case_properties', true );
1374 $csstidy->set_cfg( 'discard_invalid_properties', true );
1375 $csstidy->set_cfg( 'css_level', 'CSS3.0' );
1376 $csstidy->set_cfg( 'template', 'highest');
1377 $csstidy->parse( $css );
1378
1379 return $csstidy->print->plain();
1380 }
1381
1382 /**
1383 * When restoring a SafeCSS post revision, also copy over the
1384 * content_width and custom_css_add post metadata.
1385 */
1386 static function restore_revision( $_post_id, $_revision_id ) {
1387 $_post = get_post( $_post_id );
1388
1389 if ( 'safecss' != $_post->post_type )
1390 return;
1391
1392 $safecss_revision = Jetpack_Custom_CSS::get_current_revision();
1393
1394 $content_width = get_post_meta( $_revision_id, 'content_width', true );
1395 $custom_css_add = get_post_meta( $_revision_id, 'custom_css_add', true );
1396 $preprocessor = get_post_meta( $_revision_id, 'custom_css_preprocessor', true );
1397
1398 update_metadata( 'post', $safecss_revision['ID'], 'content_width', $content_width );
1399 update_metadata( 'post', $safecss_revision['ID'], 'custom_css_add', $custom_css_add );
1400 update_metadata( 'post', $safecss_revision['ID'], 'custom_css_preprocessor', $preprocessor );
1401
1402 delete_option( 'safecss_add' );
1403 delete_option( 'safecss_content_width' );
1404
1405 update_post_meta( $_post->ID, 'content_width', $content_width );
1406 update_post_meta( $_post->ID, 'custom_css_add', $custom_css_add );
1407 update_post_meta( $_post->ID, 'custom_css_preprocessor', $preprocessor );
1408
1409 delete_option( 'safecss_preview_add' );
1410 }
1411
1412 /**
1413 * Migration routine for moving safecss from wp_options to wp_posts to support revisions
1414 *
1415 * @return void
1416 */
1417 static function upgrade() {
1418 $css = get_option( 'safecss' );
1419
1420 if ( get_option( 'safecss_revision_migrated' ) ) {
1421 return false;
1422 }
1423
1424 // Check if CSS is stored in wp_options
1425 if ( $css ) {
1426 // Remove the async actions from publish_post
1427 remove_action( 'publish_post', 'queue_publish_post' );
1428
1429 $post = array();
1430 $post['post_content'] = $css;
1431 $post['post_title'] = 'safecss';
1432 $post['post_status'] = 'publish';
1433 $post['post_type'] = 'safecss';
1434
1435 // Insert the CSS into wp_posts
1436 $post_id = wp_insert_post( $post );
1437 // Check for errors
1438 if ( !$post_id or is_wp_error( $post_id ) )
1439 die( $post_id->get_error_message() );
1440
1441 // Delete safecss option
1442 delete_option( 'safecss' );
1443 }
1444
1445 unset( $css );
1446
1447 // Check if we have already done this
1448 if ( !get_option( 'safecss_revision_migrated' ) ) {
1449 define( 'DOING_MIGRATE', true );
1450
1451 // Get hashes of safecss post and current revision
1452 $safecss_post = Jetpack_Custom_CSS::get_post();
1453
1454 if ( empty( $safecss_post ) )
1455 return;
1456
1457 $safecss_post_hash = md5( $safecss_post['post_content'] );
1458 $current_revision = Jetpack_Custom_CSS::get_current_revision();
1459
1460 if ( null == $current_revision )
1461 return;
1462
1463 $current_revision_hash = md5( $current_revision['post_content'] );
1464
1465 // If hashes are not equal, set safecss post with content from current revision
1466 if ( $safecss_post_hash !== $current_revision_hash ) {
1467 Jetpack_Custom_CSS::save_revision( $current_revision['post_content'] );
1468 // Reset post_content to display the migrated revsion
1469 $safecss_post['post_content'] = $current_revision['post_content'];
1470 }
1471
1472 // Set option so that we dont keep doing this
1473 update_option( 'safecss_revision_migrated', time() );
1474 }
1475
1476 $newest_safecss_post = Jetpack_Custom_CSS::get_current_revision();
1477
1478 if ( $newest_safecss_post ) {
1479 if ( get_option( 'safecss_content_width' ) ) {
1480 // Add the meta to the post and the latest revision.
1481 update_post_meta( $newest_safecss_post['ID'], 'content_width', get_option( 'safecss_content_width' ) );
1482 update_metadata( 'post', $newest_safecss_post['ID'], 'content_width', get_option( 'safecss_content_width' ) );
1483
1484 delete_option( 'safecss_content_width' );
1485 }
1486
1487 if ( get_option( 'safecss_add' ) ) {
1488 update_post_meta( $newest_safecss_post['ID'], 'custom_css_add', get_option( 'safecss_add' ) );
1489 update_metadata( 'post', $newest_safecss_post['ID'], 'custom_css_add', get_option( 'safecss_add' ) );
1490
1491 delete_option( 'safecss_add' );
1492 }
1493 }
1494 }
1495
1496 /**
1497 * Adds a filter to the redirect location in `wp-admin/revisions.php`.
1498 */
1499 static function add_revision_redirect() {
1500 add_filter( 'wp_redirect', array( __CLASS__, 'revision_redirect' ) );
1501 }
1502
1503 /**
1504 * Filters the redirect location in `wp-admin/revisions.php`.
1505 *
1506 * @param string $location The path to redirect to.
1507 * @return string
1508 */
1509 static function revision_redirect( $location ) {
1510 $post = get_post();
1511
1512 if ( ! empty( $post->post_type ) && 'safecss' == $post->post_type ) {
1513 $location = 'themes.php?page=editcss';
1514
1515 if ( 'edit.php' == $location ) {
1516 $location = '';
1517 }
1518 }
1519
1520 return $location;
1521 }
1522
1523 static function revision_post_link( $post_link, $post_id, $context ) {
1524 if ( !$post_id = (int) $post_id ) {
1525 return $post_link;
1526 }
1527
1528 if ( !$post = get_post( $post_id ) ) {
1529 return $post_link;
1530 }
1531
1532 if ( 'safecss' != $post->post_type ) {
1533 return $post_link;
1534 }
1535
1536 $post_link = admin_url( 'themes.php?page=editcss' );
1537
1538 if ( 'display' == $context ) {
1539 return esc_url( $post_link );
1540 }
1541
1542 return esc_url_raw( $post_link );
1543 }
1544
1545 /**
1546 * When on the edit screen, make sure the custom content width
1547 * setting is applied to the large image size.
1548 */
1549 static function editor_max_image_size( $dims, $size = 'medium', $context = null ) {
1550 list( $width, $height ) = $dims;
1551
1552 if ( 'large' == $size && 'edit' == $context )
1553 $width = Jetpack::get_content_width();
1554
1555 return array( $width, $height );
1556 }
1557
1558 /**
1559 * Override the content_width with a custom value if one is set.
1560 */
1561 static function jetpack_content_width( $content_width ) {
1562 $custom_content_width = 0;
1563
1564 if ( Jetpack_Custom_CSS::is_preview() ) {
1565 $safecss_post = Jetpack_Custom_CSS::get_current_revision();
1566 $custom_content_width = intval( get_post_meta( $safecss_post['ID'], 'content_width', true ) );
1567 } else if ( ! Jetpack_Custom_CSS::is_freetrial() ) {
1568 $custom_css_post_id = Jetpack_Custom_CSS::post_id();
1569 if ( $custom_css_post_id )
1570 $custom_content_width = intval( get_post_meta( $custom_css_post_id, 'content_width', true ) );
1571 }
1572
1573 if ( $custom_content_width > 0 )
1574 $content_width = $custom_content_width;
1575
1576 return $content_width;
1577 }
1578 }
1579
1580 class Jetpack_Safe_CSS {
1581 static function filter_attr( $css, $element = 'div' ) {
1582 safecss_class();
1583
1584 $css = $element . ' {' . $css . '}';
1585
1586 $csstidy = new csstidy();
1587 $csstidy->optimise = new safecss( $csstidy );
1588 $csstidy->set_cfg( 'remove_bslash', false );
1589 $csstidy->set_cfg( 'compress_colors', false );
1590 $csstidy->set_cfg( 'compress_font-weight', false );
1591 $csstidy->set_cfg( 'discard_invalid_properties', true );
1592 $csstidy->set_cfg( 'merge_selectors', false );
1593 $csstidy->set_cfg( 'remove_last_;', false );
1594 $csstidy->set_cfg( 'css_level', 'CSS3.0' );
1595
1596 $css = preg_replace( '/\\\\([0-9a-fA-F]{4})/', '\\\\\\\\$1', $css );
1597 $css = wp_kses_split( $css, array(), array() );
1598 $csstidy->parse( $css );
1599
1600 $css = $csstidy->print->plain();
1601
1602 $css = str_replace( array( "\n","\r","\t" ), '', $css );
1603
1604 preg_match( "/^{$element}\s*{(.*)}\s*$/", $css, $matches );
1605
1606 if ( empty( $matches[1] ) )
1607 return '';
1608
1609 return $matches[1];
1610 }
1611 }
1612
1613 function migrate() {
1614 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::upgrade()' );
1615
1616 return Jetpack_Custom_CSS::upgrade();
1617 }
1618
1619 function safecss_revision_redirect( $redirect ) {
1620 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::revision_redirect()' );
1621
1622 return Jetpack_Custom_CSS::revision_redirect( $redirect );
1623 }
1624
1625 function safecss_revision_post_link( $post_link, $post_id, $context ) {
1626 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::revision_post_link()' );
1627
1628 return Jetpack_Custom_CSS::revision_post_link( $post_link, $post_id, $context );
1629 }
1630
1631 function get_safecss_post() {
1632 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::get_post()' );
1633
1634 return Jetpack_Custom_CSS::get_post();
1635 }
1636
1637 function custom_css_post_id() {
1638 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::post_id()' );
1639
1640 return Jetpack_Custom_CSS::post_id();
1641 }
1642
1643 function get_current_revision() {
1644 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::get_current_revision()' );
1645
1646 return Jetpack_Custom_CSS::get_current_revision();
1647 }
1648
1649 function save_revision( $css, $is_preview = false, $preprocessor = '' ) {
1650 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::save_revision()' );
1651
1652 return Jetpack_Custom_CSS::save_revision( $css, $is_preview, $preprocessor );
1653 }
1654
1655 function safecss_skip_stylesheet() {
1656 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::skip_stylesheet()' );
1657
1658 return Jetpack_Custom_CSS::skip_stylesheet();
1659 }
1660
1661 function safecss_init() {
1662 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::init()' );
1663
1664 return Jetpack_Custom_CSS::init();
1665 }
1666
1667 function safecss_is_preview() {
1668 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::is_preview()' );
1669
1670 return Jetpack_Custom_CSS::is_preview();
1671 }
1672
1673 function safecss_is_freetrial() {
1674 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::is_freetrial()' );
1675
1676 return Jetpack_Custom_CSS::is_freetrial();
1677 }
1678
1679 function safecss( $compressed = false ) {
1680 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::get_css()' );
1681
1682 return Jetpack_Custom_CSS::get_css( $compressed );
1683 }
1684
1685 function safecss_print() {
1686 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::print_css()' );
1687
1688 return Jetpack_Custom_CSS::print_css();
1689 }
1690
1691 function safecss_style() {
1692 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::link_tag()' );
1693
1694 return Jetpack_Custom_CSS::link_tag();
1695 }
1696
1697 function safecss_style_filter( $current ) {
1698 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::style_filter()' );
1699
1700 return Jetpack_Custom_CSS::style_filter( $current );
1701 }
1702
1703 function safecss_buffer( $html ) {
1704 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::buffer()' );
1705
1706 return Jetpack_Custom_CSS::buffer( $html );
1707 }
1708
1709 function safecss_preview_links( $matches ) {
1710 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::preview_links()' );
1711
1712 return Jetpack_Custom_CSS::preview_links( $matches );
1713 }
1714
1715 function safecss_preview_flag() {
1716 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::preview_flag()' );
1717
1718 return Jetpack_Custom_CSS::preview_flag();
1719 }
1720
1721 function safecss_menu() {
1722 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::menu()' );
1723
1724 return Jetpack_Custom_CSS::menu();
1725 }
1726
1727 function update_title() {
1728 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::update_title()' );
1729
1730 return Jetpack_Custom_CSS::update_title();
1731 }
1732
1733 function safecss_prettify_post_revisions() {
1734 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::prettify_post_revisions()' );
1735
1736 return Jetpack_Custom_CSS::prettify_post_revisions();
1737 }
1738
1739 function safecss_remove_title_excerpt_from_revisions() {
1740 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::remove_title_excerpt_from_revisions()' );
1741
1742 return Jetpack_Custom_CSS::remove_title_excerpt_from_revisions();
1743 }
1744
1745 function safecss_post_title( $title, $post_id ) {
1746 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::post_title()' );
1747
1748 return Jetpack_Custom_CSS::post_title( $title, $post_id );
1749 }
1750
1751 function safe_css_enqueue_scripts() {
1752 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::enqueue_scripts()' );
1753
1754 return Jetpack_Custom_CSS::enqueue_scripts( null );
1755 }
1756
1757 function safecss_admin_head() {
1758 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::admin_head()' );
1759
1760 return Jetpack_Custom_CSS::admin_head();
1761 }
1762
1763 function safecss_saved() {
1764 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::saved_message()' );
1765
1766 return Jetpack_Custom_CSS::saved_message();
1767 }
1768
1769 function safecss_admin() {
1770 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::admin()' );
1771
1772 return Jetpack_Custom_CSS::admin();
1773 }
1774
1775 function custom_css_meta_box() {
1776 _deprecated_function( __FUNCTION__, '2.1', 'add_meta_box( $id, $title, $callback, \'editcss\', \'side\' )' );
1777 }
1778
1779 function custom_css_post_revisions_meta_box( $safecss_post ) {
1780 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::revisions_meta_box()' );
1781
1782 return Jetpack_Custom_CSS::revisions_meta_box( $safecss_post );
1783 }
1784
1785 function disable_safecss_style() {
1786 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::disable()' );
1787
1788 return Jetpack_Custom_CSS::disable();
1789 }
1790
1791 function custom_css_reset() {
1792 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::reset()' );
1793
1794 return Jetpack_Custom_CSS::reset();
1795 }
1796
1797 function custom_css_is_customizer_preview() {
1798 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::is_customizer_preview()' );
1799
1800 return Jetpack_Custom_CSS::is_customizer_preview();
1801 }
1802
1803 function custom_css_minify( $css, $preprocessor = '' ) {
1804 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::minify()' );
1805
1806 return Jetpack_Custom_CSS::minify( $css, $preprocessor );
1807 }
1808
1809 function custom_css_restore_revision( $_post_id, $_revision_id ) {
1810 _deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::restore_revision()' );
1811
1812 return Jetpack_Custom_CSS::restore_revision( $_post_id, $_revision_id );
1813 }
1814
1815 if ( ! function_exists( 'safecss_class' ) ) :
1816 function safecss_class() {
1817 // Wrapped so we don't need the parent class just to load the plugin
1818 if ( class_exists('safecss') )
1819 return;
1820
1821 require_once( dirname( __FILE__ ) . '/csstidy/class.csstidy.php' );
1822
1823 class safecss extends csstidy_optimise {
1824
1825 function postparse() {
1826
1827 /**
1828 * Fires after parsing the css.
1829 *
1830 * @module custom-css
1831 *
1832 * @since 1.8.0
1833 *
1834 * @param obj $this CSSTidy object.
1835 */
1836 do_action( 'csstidy_optimize_postparse', $this );
1837
1838 return parent::postparse();
1839 }
1840
1841 function subvalue() {
1842
1843 /**
1844 * Fires before optimizing the Custom CSS subvalue.
1845 *
1846 * @module custom-css
1847 *
1848 * @since 1.8.0
1849 *
1850 * @param obj $this CSSTidy object.
1851 **/
1852 do_action( 'csstidy_optimize_subvalue', $this );
1853
1854 return parent::subvalue();
1855 }
1856 }
1857 }
1858 endif;
1859
1860 if ( ! function_exists( 'safecss_filter_attr' ) ) {
1861 function safecss_filter_attr( $css, $element = 'div' ) {
1862 return Jetpack_Safe_CSS::filter_attr( $css, $element );
1863 }
1864 }
1865
1866 include_once dirname( __FILE__ ) . '/custom-css/preprocessors.php';
1867