OS : Linux
PHP Version : 7.4.33
Software : true,
// 'public' => false,
// 'publicly_queryable' => false,
// 'show_ui' => false,
'supports' => array( 'revisions' ),
'label' => 'Custom CSS',
'can_export' => false,
'rewrite' => false,
'capabilities' => array(
'edit_post' => 'edit_theme_options',
'read_post' => 'read',
'delete_post' => 'edit_theme_options',
'edit_posts' => 'edit_theme_options',
'edit_others_posts' => 'edit_theme_options',
'publish_posts' => 'edit_theme_options',
'read_private_posts' => 'read'
)
) );
// Short-circuit WP if this is a CSS stylesheet request
if ( isset( $_GET['custom-css'] ) ) {
header( 'Content-Type: text/css', true, 200 );
header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + 31536000) . ' GMT' ); // 1 year
Jetpack_Custom_CSS::print_css();
exit;
}
add_action( 'admin_enqueue_scripts', array( 'Jetpack_Custom_CSS', 'enqueue_scripts' ) );
if ( isset( $_GET['page'] ) && 'editcss' == $_GET['page'] && is_admin() ) {
// Do migration routine if necessary
Jetpack_Custom_CSS::upgrade();
/**
* Allows additional work when migrating safecss from wp_options to wp_post.
*
* @module custom-css
*
* @since 1.7.0
*/
do_action( 'safecss_migrate_post' );
}
/**
* Never embed the style in the head on wpcom.
* Yes, this filter should be added to an unsynced file on wpcom, but
* there is no good syntactically-correct location to put it yet.
* @link https://github.com/Automattic/jetpack/commit/a1be114e9179f64d147124727a58e2cf76c7e5a1#commitcomment-7763921
*/
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
add_filter( 'safecss_embed_style', '__return_false' );
} else {
add_filter( 'safecss_embed_style', array( 'Jetpack_Custom_CSS', 'should_we_inline_custom_css' ), 10, 2 );
}
add_action( 'wp_head', array( 'Jetpack_Custom_CSS', 'link_tag' ), 101 );
add_filter( 'jetpack_content_width', array( 'Jetpack_Custom_CSS', 'jetpack_content_width' ) );
add_filter( 'editor_max_image_size', array( 'Jetpack_Custom_CSS', 'editor_max_image_size' ), 10, 3 );
if ( !current_user_can( 'switch_themes' ) && !is_super_admin() )
return;
add_action( 'admin_menu', array( 'Jetpack_Custom_CSS', 'menu' ) );
if ( isset( $_POST['safecss'] ) && false == strstr( $_SERVER[ 'REQUEST_URI' ], 'options.php' ) ) {
check_admin_referer( 'safecss' );
$save_result = self::save( array(
'css' => stripslashes( $_POST['safecss'] ),
'is_preview' => isset( $_POST['action'] ) && $_POST['action'] == 'preview',
'preprocessor' => isset( $_POST['custom_css_preprocessor'] ) ? $_POST['custom_css_preprocessor'] : '',
'add_to_existing' => isset( $_POST['add_to_existing'] ) ? $_POST['add_to_existing'] == 'true' : true,
'content_width' => isset( $_POST['custom_content_width'] ) ? $_POST['custom_content_width'] : false,
) );
if ( $_POST['action'] == 'preview' ) {
wp_safe_redirect( add_query_arg( 'csspreview', 'true', get_option( 'home' ) ) );
exit;
}
if ( $save_result )
add_action( 'admin_notices', array( 'Jetpack_Custom_CSS', 'saved_message' ) );
}
// Prevent content filters running on CSS when restoring revisions
if ( isset( $_REQUEST[ 'action' ] ) && 'restore' === $_REQUEST[ 'action' ] && false !== strstr( $_SERVER[ 'REQUEST_URI' ], 'revision.php' ) ) {
$parent_post = get_post( wp_get_post_parent_id( intval( $_REQUEST[ 'revision' ] ) ) );
if ( $parent_post && ! is_wp_error( $parent_post ) && 'safecss' === $parent_post->post_type ) {
// Remove wp_filter_post_kses, this causes CSS escaping issues
remove_filter( 'content_save_pre', 'wp_filter_post_kses' );
remove_filter( 'content_filtered_save_pre', 'wp_filter_post_kses' );
remove_all_filters( 'content_save_pre' );
}
}
// Modify all internal links so that preview state persists
if ( Jetpack_Custom_CSS::is_preview() )
ob_start( array( 'Jetpack_Custom_CSS', 'buffer' ) );
}
/**
* Save new custom CSS. This should be the entry point for any third-party code using Jetpack_Custom_CSS
* to save CSS.
*
* @param array $args Array of arguments:
* string $css The CSS (or LESS or Sass)
* bool $is_preview Whether this CSS is preview or published
* string preprocessor Which CSS preprocessor to use
* bool $add_to_existing Whether this CSS replaces the theme's CSS or supplements it.
* int $content_width A custom $content_width to go along with this CSS.
* @return int The post ID of the saved Custom CSS post.
*/
public static function save( $args = array() ) {
$defaults = array(
'css' => '',
'is_preview' => false,
'preprocessor' => '',
'add_to_existing' => true,
'content_width' => false,
);
$args = wp_parse_args( $args, $defaults );
if ( $args['content_width'] && intval( $args['content_width']) > 0 && ( ! isset( $GLOBALS['content_width'] ) || $args['content_width'] != $GLOBALS['content_width'] ) )
$args['content_width'] = intval( $args['content_width'] );
else
$args['content_width'] = false;
// Remove wp_filter_post_kses, this causes CSS escaping issues
remove_filter( 'content_save_pre', 'wp_filter_post_kses' );
remove_filter( 'content_filtered_save_pre', 'wp_filter_post_kses' );
remove_all_filters( 'content_save_pre' );
/**
* Fires prior to saving custom css values. Necessitated because the
* core WordPress save_pre filters were removed:
* - content_save_pre
* - content_filtered_save_pre
*
* @module custom-css
*
* @since 1.7.0
*
* @param array $args {
* Array of custom CSS arguments.
* @type string $css The CSS (or LESS or Sass).
* @type bool $is_preview Whether this CSS is preview or published.
* @type string preprocessor Which CSS preprocessor to use.
* @type bool $add_to_existing Whether this CSS replaces the theme's CSS or supplements it.
* @type int $content_width A custom $content_width to go along with this CSS.
* }
*/
do_action( 'safecss_save_pre', $args );
$warnings = array();
safecss_class();
$csstidy = new csstidy();
$csstidy->optimise = new safecss( $csstidy );
$csstidy->set_cfg( 'remove_bslash', false );
$csstidy->set_cfg( 'compress_colors', false );
$csstidy->set_cfg( 'compress_font-weight', false );
$csstidy->set_cfg( 'optimise_shorthands', 0 );
$csstidy->set_cfg( 'remove_last_;', false );
$csstidy->set_cfg( 'case_properties', false );
$csstidy->set_cfg( 'discard_invalid_properties', true );
$csstidy->set_cfg( 'css_level', 'CSS3.0' );
$csstidy->set_cfg( 'preserve_css', true );
$csstidy->set_cfg( 'template', dirname( __FILE__ ) . '/csstidy/wordpress-standard.tpl' );
$css = $orig = $args['css'];
$css = preg_replace( '/\\\\([0-9a-fA-F]{4})/', '\\\\\\\\$1', $prev = $css );
// prevent content: '\3434' from turning into '\\3434'
$css = str_replace( array( '\'\\\\', '"\\\\' ), array( '\'\\', '"\\' ), $css );
if ( $css != $prev )
$warnings[] = 'preg_replace found stuff';
// Some people put weird stuff in their CSS, KSES tends to be greedy
$css = str_replace( '<=', '<=', $css );
// Why KSES instead of strip_tags? Who knows?
$css = wp_kses_split( $prev = $css, array(), array() );
$css = str_replace( '>', '>', $css ); // kses replaces lone '>' with >
// Why both KSES and strip_tags? Because we just added some '>'.
$css = strip_tags( $css );
if ( $css != $prev )
$warnings[] = 'kses found stuff';
// if we're not using a preprocessor
if ( ! $args['preprocessor'] ) {
/**
* Fires before parsing the css with CSSTidy, but only if
* the preprocessor is not configured for use.
*
* @module custom-css
*
* @since 1.7.0
*
* @param obj $csstidy The csstidy object.
* @param string $css Custom CSS.
* @param array $args Array of custom CSS arguments.
*/
do_action( 'safecss_parse_pre', $csstidy, $css, $args );
$csstidy->parse( $css );
/**
* Fires after parsing the css with CSSTidy, but only if
* the preprocessor is not cinfigured for use.
*
* @module custom-css
*
* @since 1.7.0
*
* @param obj $csstidy The csstidy object.
* @param array $warnings Array of warnings.
* @param array $args Array of custom CSS arguments.
*/
do_action( 'safecss_parse_post', $csstidy, $warnings, $args );
$css = $csstidy->print->plain();
}
if ( $args['add_to_existing'] )
$add_to_existing = 'yes';
else
$add_to_existing = 'no';
if ( $args['is_preview'] || Jetpack_Custom_CSS::is_freetrial() ) {
// Save the CSS
$safecss_revision_id = Jetpack_Custom_CSS::save_revision( $css, true, $args['preprocessor'] );
// Cache Buster
update_option( 'safecss_preview_rev', intval( get_option( 'safecss_preview_rev' ) ) + 1);
update_metadata( 'post', $safecss_revision_id, 'custom_css_add', $add_to_existing );
update_metadata( 'post', $safecss_revision_id, 'content_width', $args['content_width'] );
update_metadata( 'post', $safecss_revision_id, 'custom_css_preprocessor', $args['preprocessor'] );
delete_option( 'safecss_add' );
delete_option( 'safecss_content_width' );
if ( $args['is_preview'] ) {
return $safecss_revision_id;
}
/**
* Fires after saving Custom CSS.
*
* @module custom-css
*
* @since 1.7.0
*/
do_action( 'safecss_save_preview_post' );
}
// Save the CSS
$safecss_post_id = Jetpack_Custom_CSS::save_revision( $css, false, $args['preprocessor'] );
$safecss_post_revision = Jetpack_Custom_CSS::get_current_revision();
update_option( 'safecss_rev', intval( get_option( 'safecss_rev' ) ) + 1 );
update_post_meta( $safecss_post_id, 'custom_css_add', $add_to_existing );
update_post_meta( $safecss_post_id, 'content_width', $args['content_width'] );
update_post_meta( $safecss_post_id, 'custom_css_preprocessor', $args['preprocessor'] );
delete_option( 'safecss_add' );
delete_option( 'safecss_content_width' );
update_metadata( 'post', $safecss_post_revision['ID'], 'custom_css_add', $add_to_existing );
update_metadata( 'post', $safecss_post_revision['ID'], 'content_width', $args['content_width'] );
update_metadata( 'post', $safecss_post_revision['ID'], 'custom_css_preprocessor', $args['preprocessor'] );
delete_option( 'safecss_preview_add' );
return $safecss_post_id;
}
/**
* Get the published custom CSS post.
*
* @return array
*/
static function get_post() {
$custom_css_post_id = Jetpack_Custom_CSS::post_id();
if ( $custom_css_post_id )
return get_post( $custom_css_post_id, ARRAY_A );
return array();
}
/**
* Get the post ID of the published custom CSS post.
*
* @return int|bool The post ID if it exists; false otherwise.
*/
static function post_id() {
/**
* Filter the ID of the post where Custom CSS is stored, before the ID is retrieved.
*
* If the callback function returns a non-null value, then post_id() will immediately
* return that value, instead of retrieving the normal post ID.
*
* @module custom-css
*
* @since 3.8.1
*
* @param null null The ID to return instead of the normal ID.
*/
$custom_css_post_id = apply_filters( 'jetpack_custom_css_pre_post_id', null );
if ( ! is_null( $custom_css_post_id ) ) {
return $custom_css_post_id;
}
$custom_css_post_id = wp_cache_get( 'custom_css_post_id' );
if ( false === $custom_css_post_id ) {
$custom_css_posts = get_posts( array(
'posts_per_page' => 1,
'post_type' => 'safecss',
'post_status' => 'publish',
'orderby' => 'date',
'order' => 'DESC'
) );
if ( count( $custom_css_posts ) > 0 )
$custom_css_post_id = $custom_css_posts[0]->ID;
else
$custom_css_post_id = 0;
// Save post_id=0 to note that no safecss post exists.
wp_cache_set( 'custom_css_post_id', $custom_css_post_id );
}
if ( ! $custom_css_post_id )
return false;
return $custom_css_post_id;
}
/**
* Get the current revision of the original safecss record
*
* @return object
*/
static function get_current_revision() {
$safecss_post = Jetpack_Custom_CSS::get_post();
if ( empty( $safecss_post ) ) {
return false;
}
$revisions = wp_get_post_revisions( $safecss_post['ID'], array( 'posts_per_page' => 1, 'orderby' => 'date', 'order' => 'DESC' ) );
// Empty array if no revisions exist
if ( empty( $revisions ) ) {
// Return original post
return $safecss_post;
} else {
// Return the first entry in $revisions, this will be the current revision
$current_revision = get_object_vars( array_shift( $revisions ) );
return $current_revision;
}
}
/**
* Save new revision of CSS
* Checks to see if content was modified before really saving
*
* @param string $css
* @param bool $is_preview
* @return bool|int If nothing was saved, returns false. If a post
* or revision was saved, returns the post ID.
*/
static function save_revision( $css, $is_preview = false, $preprocessor = '' ) {
$safecss_post = Jetpack_Custom_CSS::get_post();
$compressed_css = Jetpack_Custom_CSS::minify( $css, $preprocessor );
// If null, there was no original safecss record, so create one
if ( null == $safecss_post ) {
if ( ! $css )
return false;
$post = array();
$post['post_content'] = wp_slash( $css );
$post['post_title'] = 'safecss';
$post['post_status'] = 'publish';
$post['post_type'] = 'safecss';
$post['post_content_filtered'] = wp_slash( $compressed_css );
// Set excerpt to current theme, for display in revisions list
$current_theme = wp_get_theme();
$post['post_excerpt'] = $current_theme->Name;
// Insert the CSS into wp_posts
$post_id = wp_insert_post( $post );
wp_cache_set( 'custom_css_post_id', $post_id );
return $post_id;
}
// Update CSS in post array with new value passed to this function
$safecss_post['post_content'] = $css;
$safecss_post['post_content_filtered'] = $compressed_css;
// Set excerpt to current theme, for display in revisions list
$current_theme = wp_get_theme();
$safecss_post['post_excerpt'] = $current_theme->Name;
// Don't carry over last revision's timestamps, otherwise revisions all have matching timestamps
unset( $safecss_post['post_date'] );
unset( $safecss_post['post_date_gmt'] );
unset( $safecss_post['post_modified'] );
unset( $safecss_post['post_modified_gmt'] );
// Do not update post if we are only saving a preview
if ( false === $is_preview ) {
$safecss_post['post_content'] = wp_slash( $safecss_post['post_content'] );
$safecss_post['post_content_filtered'] = wp_slash( $safecss_post['post_content_filtered'] );
$post_id = wp_update_post( $safecss_post );
wp_cache_set( 'custom_css_post_id', $post_id );
return $post_id;
}
else if ( ! defined( 'DOING_MIGRATE' ) ) {
return _wp_put_post_revision( $safecss_post );
}
}
static function skip_stylesheet() {
/**
* Prevent the Custom CSS stylesheet from being enqueued.
*
* @module custom-css
*
* @since 2.2.1
*
* @param null Should the stylesheet be skipped. Default to null. Anything else will force the stylesheet to be skipped.
*/
$skip_stylesheet = apply_filters( 'safecss_skip_stylesheet', null );
if ( null !== $skip_stylesheet ) {
return $skip_stylesheet;
} elseif ( Jetpack_Custom_CSS::is_customizer_preview() ) {
return false;
} else {
if ( Jetpack_Custom_CSS::is_preview() ) {
$safecss_post = Jetpack_Custom_CSS::get_current_revision();
if ( $safecss_post )
return (bool) ( get_post_meta( $safecss_post['ID'], 'custom_css_add', true ) == 'no' );
else
return (bool) ( get_option( 'safecss_preview_add' ) == 'no' );
}
else {
$custom_css_post_id = Jetpack_Custom_CSS::post_id();
if ( $custom_css_post_id ) {
$custom_css_add = get_post_meta( $custom_css_post_id, 'custom_css_add', true );
// It is possible for the CSS to be stored in a post but for the safecss_add option
// to have not been upgraded yet if the user hasn't opened their Custom CSS editor
// since October 2012.
if ( ! empty( $custom_css_add ) )
return (bool) ( $custom_css_add === 'no' );
}
return (bool) ( Jetpack_Options::get_option_and_ensure_autoload( 'safecss_add', '' ) == 'no' );
}
}
}
static function is_preview() {
return isset( $_GET['csspreview'] ) && $_GET['csspreview'] === 'true';
}
/**
* Currently this filter function gets called on
* 'template_redirect' action and
* 'admin_init' action
*/
static function set_content_width(){
// Don't apply this filter on the Edit CSS page
if ( isset( $_GET ) && isset( $_GET['page'] ) && 'editcss' == $_GET['page'] && is_admin() ) {
return;
}
$GLOBALS['content_width'] = Jetpack::get_content_width();
}
/*
* False when the site has the Custom Design upgrade.
* Used only on WordPress.com.
*/
static function is_freetrial() {
/**
* Determine if a WordPress.com site uses a Free trial of the Custom Design Upgrade.
* Used only on WordPress.com.
*
* @module custom-css
*
* @since 1.7.0
*
* @param bool false Does the site use a Free trial of the Custom Design Upgrade. Default to false.
*/
return apply_filters( 'safecss_is_freetrial', false );
}
static function get_preprocessor_key() {
$safecss_post = Jetpack_Custom_CSS::get_current_revision();
return get_post_meta( $safecss_post['ID'], 'custom_css_preprocessor', true );
}
static function get_preprocessor() {
/** This filter is documented in modules/custom-css/custom-css.php */
$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
$selected_preprocessor_key = self::get_preprocessor_key();
$selected_preprocessor = isset( $preprocessors[ $selected_preprocessor_key ] ) ? $preprocessors[ $selected_preprocessor_key ] : null;
return $selected_preprocessor;
}
static function get_css( $compressed = false ) {
/**
* Filter the Custom CSS returned.
* Can be used to return an error, or no CSS at all.
*
* @module custom-css
*
* @since 1.7.0
*
* @param bool false Should we return an error instead of the Custom CSS. Default to false.
*/
$default_css = apply_filters( 'safecss_get_css_error', false );
if ( $default_css !== false )
return $default_css;
$option = ( Jetpack_Custom_CSS::is_preview() || Jetpack_Custom_CSS::is_freetrial() ) ? 'safecss_preview' : 'safecss';
$css = '';
if ( 'safecss' == $option ) {
// Don't bother checking for a migrated 'safecss' option if it never existed.
if ( false === get_option( 'safecss' ) || get_option( 'safecss_revision_migrated' ) ) {
$safecss_post = Jetpack_Custom_CSS::get_post();
if ( ! empty( $safecss_post ) ) {
$css = ( $compressed && $safecss_post['post_content_filtered'] ) ? $safecss_post['post_content_filtered'] : $safecss_post['post_content'];
}
} else {
$current_revision = Jetpack_Custom_CSS::get_current_revision();
if ( false === $current_revision ) {
$css = '';
} else {
$css = ( $compressed && $current_revision['post_content_filtered'] ) ? $current_revision['post_content_filtered'] : $current_revision['post_content'];
}
}
// Fix for un-migrated Custom CSS
if ( empty( $safecss_post ) ) {
$_css = get_option( 'safecss' );
if ( !empty( $_css ) ) {
$css = $_css;
}
}
}
else if ( 'safecss_preview' == $option ) {
$safecss_post = Jetpack_Custom_CSS::get_current_revision();
$css = $safecss_post['post_content'];
$css = Jetpack_Custom_CSS::minify( $css, get_post_meta( $safecss_post['ID'], 'custom_css_preprocessor', true ) );
}
$css = str_replace( array( '\\\00BB \\\0020', '\0BB \020', '0BB 020' ), '\00BB \0020', $css );
if ( empty( $css ) ) {
$css = "/*\n"
. wordwrap(
/**
* Filter the default message displayed in the Custom CSS editor.
*
* @module custom-css
*
* @since 1.7.0
*
* @param string $str Default Custom CSS editor content.
*/
apply_filters(
'safecss_default_css',
__(
"Welcome to Custom CSS!\n\nTo learn how this works, see https://wp.me/PEmnE-Bt",
'jetpack'
)
)
)
. "\n*/";
}
/**
* Filter the Custom CSS returned from the editor.
*
* @module custom-css
*
* @since 1.7.0
*
* @param string $css Custom CSS.
*/
$css = apply_filters( 'safecss_css', $css );
return $css;
}
static function replace_insecure_urls( $css ) {
if ( ! function_exists( '_sa_get_frontend_https_url_replacement_map' ) ) {
return $css;
}
list( $http_urls, $secure_urls ) = _sa_get_frontend_https_url_replacement_map();
return str_replace( $http_urls, $secure_urls, $css );
}
static function print_css() {
/**
* Fires right before printing the custom CSS inside the element.
*
* @module custom-css
*
* @since 1.7.0
*/
do_action( 'safecss_print_pre' );
$css = Jetpack_Custom_CSS::get_css( true );
echo self::replace_insecure_urls( $css );
}
static function should_we_inline_custom_css( $should_we, $css ) {
// If the CSS is less than 2,000 characters, inline it! otherwise return what was passed in.
return ( strlen( $css ) < 2000 ) ? true : $should_we;
}
static function link_tag() {
global $blog_id, $current_blog;
if (
/**
* Do not include any CSS on the page if the CSS includes an error.
* Setting this filter to true stops any Custom CSS from being enqueued.
*
* @module custom-css
*
* @since 1.7.0
*
* @param bool false Does the CSS include an error. Default to false.
*/
apply_filters( 'safecss_style_error', false )
) {
return;
}
if ( ! is_super_admin() && isset( $current_blog ) && ( 1 == $current_blog->spam || 1 == $current_blog->deleted ) )
return;
if ( Jetpack_Custom_CSS::is_customizer_preview() )
return;
$css = '';
$option = Jetpack_Custom_CSS::is_preview() ? 'safecss_preview' : 'safecss';
if ( 'safecss' == $option ) {
if ( Jetpack_Options::get_option_and_ensure_autoload( 'safecss_revision_migrated', '0' ) ) {
$safecss_post = Jetpack_Custom_CSS::get_post();
if ( ! empty( $safecss_post['post_content'] ) ) {
$css = $safecss_post['post_content'];
}
} else {
$current_revision = Jetpack_Custom_CSS::get_current_revision();
if ( ! empty( $current_revision['post_content'] ) ) {
$css = $current_revision['post_content'];
}
}
// Fix for un-migrated Custom CSS
if ( empty( $safecss_post ) ) {
$_css = Jetpack_Options::get_option_and_ensure_autoload( 'safecss', '' );
if ( !empty( $_css ) ) {
$css = $_css;
}
}
}
if ( 'safecss_preview' == $option ) {
$safecss_post = Jetpack_Custom_CSS::get_current_revision();
if ( !empty( $safecss_post['post_content'] ) ) {
$css = $safecss_post['post_content'];
}
}
$css = str_replace( array( '\\\00BB \\\0020', '\0BB \020', '0BB 020' ), '\00BB \0020', $css );
if ( $css == '' )
return;
if (
/**
* Allow inserting CSS inline instead of through a separate file.
*
* @module custom-css
*
* @since 3.4.0
*
* @param bool false Should the CSS be added inline instead of through a separate file. Default to false.
* @param string $css Custom CSS.
*/
apply_filters( 'safecss_embed_style', false, $css )
) {
echo "\r\n" . '\r\n";
} else {
$href = home_url( '/' );
$href = add_query_arg( 'custom-css', 1, $href );
$href = add_query_arg( 'csblog', $blog_id, $href );
$href = add_query_arg( 'cscache', 6, $href );
$href = add_query_arg( 'csrev', (int) get_option( $option . '_rev' ), $href );
/**
* Filter the Custom CSS link enqueued in the head.
*
* @module custom-css
*
* @since 1.7.0
*
* @param string $href Custom CSS link enqueued in the head.
* @param string $blog_id Blog ID.
*/
$href = apply_filters( 'safecss_href', $href, $blog_id );
if ( Jetpack_Custom_CSS::is_preview() )
$href = add_query_arg( 'csspreview', 'true', $href );
?>
in the element for the custom css stylesheet.
*
* @module custom-css
*
* @since 2.2.2
*/
do_action( 'safecss_link_tag_post' );
}
static function style_filter( $current ) {
if ( Jetpack_Custom_CSS::is_freetrial() && ( ! Jetpack_Custom_CSS::is_preview() || ! current_user_can( 'switch_themes' ) ) )
return $current;
else if ( Jetpack_Custom_CSS::skip_stylesheet() )
/**
* Filter the default blank Custom CSS URL.
*
* @module custom-css
*
* @since 2.2.1
*
* @param string $url Default blank Custom CSS URL.
*/
return apply_filters( 'safecss_style_filter_url', plugins_url( 'custom-css/css/blank.css', __FILE__ ) );
return $current;
}
static function buffer( $html ) {
$html = str_replace( '', Jetpack_Custom_CSS::preview_flag(), $html );
return preg_replace_callback( '!href=([\'"])(.*?)\\1!', array( 'Jetpack_Custom_CSS', 'preview_links' ), $html );
}
static function preview_links( $matches ) {
if ( 0 !== strpos( $matches[2], get_option( 'home' ) ) )
return $matches[0];
$link = wp_specialchars_decode( $matches[2] );
$link = add_query_arg( 'csspreview', 'true', $link );
$link = esc_url( $link );
return "href={$matches[1]}$link{$matches[1]}";
}
/**
* Places a black bar above every preview page
*/
static function preview_flag() {
if ( is_admin() )
return;
$message = esc_html__( 'Preview: changes must be saved or they will be lost', 'jetpack' );
/**
* Filter the Preview message displayed on the site when previewing custom CSS, before to save it.
*
* @module custom-css
*
* @since 1.7.0
*
* @param string $message Custom CSS preview message.
*/
$message = apply_filters( 'safecss_preview_message', $message );
$preview_flag_js = "var flag = document.createElement('div');
flag.innerHTML = " . json_encode( $message ) . ";
flag.style.background = '#FF6600';
flag.style.color = 'white';
flag.style.textAlign = 'center';
flag.style.fontSize = '15px';
flag.style.padding = '2px';
flag.style.fontFamily = 'sans-serif';
document.body.style.paddingTop = '0px';
document.body.insertBefore(flag, document.body.childNodes[0]);
";
/**
* Filter the Custom CSS preview message JS styling.
*
* @module custom-css
*
* @since 1.7.0
*
* @param string $preview_flag_js Custom CSS preview message JS styling.
*/
$preview_flag_js = apply_filters( 'safecss_preview_flag_js', $preview_flag_js );
if ( $preview_flag_js ) {
$preview_flag_js = '';
}
return $preview_flag_js;
}
static function menu() {
$parent = 'themes.php';
$title = __( 'Edit CSS', 'jetpack' );
$hook = add_theme_page( $title, $title, 'edit_theme_options', 'editcss', array( 'Jetpack_Custom_CSS', 'admin' ) );
add_action( "load-revision.php", array( 'Jetpack_Custom_CSS', 'prettify_post_revisions' ) );
add_action( "load-$hook", array( 'Jetpack_Custom_CSS', 'update_title' ) );
}
/**
* Adds a menu item in the appearance section for this plugin's administration
* page. Also adds hooks to enqueue the CSS and JS for the admin page.
*/
static function update_title() {
global $title;
$title = __( 'CSS', 'jetpack' );
}
static function prettify_post_revisions() {
add_filter( 'the_title', array( 'Jetpack_Custom_CSS', 'post_title' ), 10, 2 );
}
static function post_title( $title, $post_id ) {
if ( !$post_id = (int) $post_id ) {
return $title;
}
if ( !$post = get_post( $post_id ) ) {
return $title;
}
if ( 'safecss' != $post->post_type ) {
return $title;
}
return __( 'Custom CSS Stylesheet', 'jetpack' );
}
static function enqueue_scripts( $hook ) {
if ( 'appearance_page_editcss' != $hook )
return;
wp_enqueue_script( 'postbox' );
wp_enqueue_script(
'custom-css-editor',
Assets::get_file_url_for_environment(
'_inc/build/custom-css/custom-css/js/css-editor.min.js',
'modules/custom-css/custom-css/js/css-editor.js'
),
'jquery',
'20130325',
true
);
wp_enqueue_style( 'custom-css-editor', plugins_url( 'custom-css/css/css-editor.css', __FILE__ ) );
if ( defined( 'SAFECSS_USE_ACE' ) && SAFECSS_USE_ACE ) {
wp_register_style( 'jetpack-css-codemirror', plugins_url( 'custom-css/css/codemirror.css', __FILE__ ), array(), '20120905' );
wp_enqueue_style( 'jetpack-css-use-codemirror', plugins_url( 'custom-css/css/use-codemirror.css', __FILE__ ), array( 'jetpack-css-codemirror' ), '20120905' );
wp_register_script( 'jetpack-css-codemirror', plugins_url( 'custom-css/js/codemirror.min.js', __FILE__ ), array(), '3.16', true );
wp_enqueue_script(
'jetpack-css-use-codemirror',
Assets::get_file_url_for_environment(
'_inc/build/custom-css/custom-css/js/use-codemirror.min.js',
'modules/custom-css/custom-css/js/use-codemirror.js'
),
array( 'jquery', 'underscore', 'jetpack-css-codemirror' ),
'20131009',
true
);
}
}
static function saved_message() {
echo ' ' . __( 'Stylesheet saved.', 'jetpack' ) . 'have_posts() ) :
$revisions->the_post();
?>
found_posts > 6 && !$show_all_revisions ) {
?>
is_theme_active();
return false;
}
static function minify( $css, $preprocessor = '' ) {
if ( ! $css )
return '';
if ( $preprocessor ) {
/** This filter is documented in modules/custom-css/custom-css.php */
$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
if ( isset( $preprocessors[$preprocessor] ) ) {
$css = call_user_func( $preprocessors[$preprocessor]['callback'], $css );
}
}
safecss_class();
$csstidy = new csstidy();
$csstidy->optimise = new safecss( $csstidy );
$csstidy->set_cfg( 'remove_bslash', false );
$csstidy->set_cfg( 'compress_colors', true );
$csstidy->set_cfg( 'compress_font-weight', true );
$csstidy->set_cfg( 'remove_last_;', true );
$csstidy->set_cfg( 'case_properties', true );
$csstidy->set_cfg( 'discard_invalid_properties', true );
$csstidy->set_cfg( 'css_level', 'CSS3.0' );
$csstidy->set_cfg( 'template', 'highest');
$csstidy->parse( $css );
return $csstidy->print->plain();
}
/**
* When restoring a SafeCSS post revision, also copy over the
* content_width and custom_css_add post metadata.
*/
static function restore_revision( $_post_id, $_revision_id ) {
$_post = get_post( $_post_id );
if ( 'safecss' != $_post->post_type )
return;
$safecss_revision = Jetpack_Custom_CSS::get_current_revision();
$content_width = get_post_meta( $_revision_id, 'content_width', true );
$custom_css_add = get_post_meta( $_revision_id, 'custom_css_add', true );
$preprocessor = get_post_meta( $_revision_id, 'custom_css_preprocessor', true );
update_metadata( 'post', $safecss_revision['ID'], 'content_width', $content_width );
update_metadata( 'post', $safecss_revision['ID'], 'custom_css_add', $custom_css_add );
update_metadata( 'post', $safecss_revision['ID'], 'custom_css_preprocessor', $preprocessor );
delete_option( 'safecss_add' );
delete_option( 'safecss_content_width' );
update_post_meta( $_post->ID, 'content_width', $content_width );
update_post_meta( $_post->ID, 'custom_css_add', $custom_css_add );
update_post_meta( $_post->ID, 'custom_css_preprocessor', $preprocessor );
delete_option( 'safecss_preview_add' );
}
/**
* Migration routine for moving safecss from wp_options to wp_posts to support revisions
*
* @return void
*/
static function upgrade() {
$css = get_option( 'safecss' );
if ( get_option( 'safecss_revision_migrated' ) ) {
return false;
}
// Check if CSS is stored in wp_options
if ( $css ) {
// Remove the async actions from publish_post
remove_action( 'publish_post', 'queue_publish_post' );
$post = array();
$post['post_content'] = $css;
$post['post_title'] = 'safecss';
$post['post_status'] = 'publish';
$post['post_type'] = 'safecss';
// Insert the CSS into wp_posts
$post_id = wp_insert_post( $post );
// Check for errors
if ( !$post_id or is_wp_error( $post_id ) )
die( $post_id->get_error_message() );
// Delete safecss option
delete_option( 'safecss' );
}
unset( $css );
// Check if we have already done this
if ( !get_option( 'safecss_revision_migrated' ) ) {
define( 'DOING_MIGRATE', true );
// Get hashes of safecss post and current revision
$safecss_post = Jetpack_Custom_CSS::get_post();
if ( empty( $safecss_post ) )
return;
$safecss_post_hash = md5( $safecss_post['post_content'] );
$current_revision = Jetpack_Custom_CSS::get_current_revision();
if ( null == $current_revision )
return;
$current_revision_hash = md5( $current_revision['post_content'] );
// If hashes are not equal, set safecss post with content from current revision
if ( $safecss_post_hash !== $current_revision_hash ) {
Jetpack_Custom_CSS::save_revision( $current_revision['post_content'] );
// Reset post_content to display the migrated revsion
$safecss_post['post_content'] = $current_revision['post_content'];
}
// Set option so that we dont keep doing this
update_option( 'safecss_revision_migrated', time() );
}
$newest_safecss_post = Jetpack_Custom_CSS::get_current_revision();
if ( $newest_safecss_post ) {
if ( get_option( 'safecss_content_width' ) ) {
// Add the meta to the post and the latest revision.
update_post_meta( $newest_safecss_post['ID'], 'content_width', get_option( 'safecss_content_width' ) );
update_metadata( 'post', $newest_safecss_post['ID'], 'content_width', get_option( 'safecss_content_width' ) );
delete_option( 'safecss_content_width' );
}
if ( get_option( 'safecss_add' ) ) {
update_post_meta( $newest_safecss_post['ID'], 'custom_css_add', get_option( 'safecss_add' ) );
update_metadata( 'post', $newest_safecss_post['ID'], 'custom_css_add', get_option( 'safecss_add' ) );
delete_option( 'safecss_add' );
}
}
}
/**
* Adds a filter to the redirect location in `wp-admin/revisions.php`.
*/
static function add_revision_redirect() {
add_filter( 'wp_redirect', array( __CLASS__, 'revision_redirect' ) );
}
/**
* Filters the redirect location in `wp-admin/revisions.php`.
*
* @param string $location The path to redirect to.
* @return string
*/
static function revision_redirect( $location ) {
$post = get_post();
if ( ! empty( $post->post_type ) && 'safecss' == $post->post_type ) {
$location = 'themes.php?page=editcss';
if ( 'edit.php' == $location ) {
$location = '';
}
}
return $location;
}
static function revision_post_link( $post_link, $post_id, $context ) {
if ( !$post_id = (int) $post_id ) {
return $post_link;
}
if ( !$post = get_post( $post_id ) ) {
return $post_link;
}
if ( 'safecss' != $post->post_type ) {
return $post_link;
}
$post_link = admin_url( 'themes.php?page=editcss' );
if ( 'display' == $context ) {
return esc_url( $post_link );
}
return esc_url_raw( $post_link );
}
/**
* When on the edit screen, make sure the custom content width
* setting is applied to the large image size.
*/
static function editor_max_image_size( $dims, $size = 'medium', $context = null ) {
list( $width, $height ) = $dims;
if ( 'large' == $size && 'edit' == $context )
$width = Jetpack::get_content_width();
return array( $width, $height );
}
/**
* Override the content_width with a custom value if one is set.
*/
static function jetpack_content_width( $content_width ) {
$custom_content_width = 0;
if ( Jetpack_Custom_CSS::is_preview() ) {
$safecss_post = Jetpack_Custom_CSS::get_current_revision();
$custom_content_width = intval( get_post_meta( $safecss_post['ID'], 'content_width', true ) );
} else if ( ! Jetpack_Custom_CSS::is_freetrial() ) {
$custom_css_post_id = Jetpack_Custom_CSS::post_id();
if ( $custom_css_post_id )
$custom_content_width = intval( get_post_meta( $custom_css_post_id, 'content_width', true ) );
}
if ( $custom_content_width > 0 )
$content_width = $custom_content_width;
return $content_width;
}
}
class Jetpack_Safe_CSS {
static function filter_attr( $css, $element = 'div' ) {
safecss_class();
$css = $element . ' {' . $css . '}';
$csstidy = new csstidy();
$csstidy->optimise = new safecss( $csstidy );
$csstidy->set_cfg( 'remove_bslash', false );
$csstidy->set_cfg( 'compress_colors', false );
$csstidy->set_cfg( 'compress_font-weight', false );
$csstidy->set_cfg( 'discard_invalid_properties', true );
$csstidy->set_cfg( 'merge_selectors', false );
$csstidy->set_cfg( 'remove_last_;', false );
$csstidy->set_cfg( 'css_level', 'CSS3.0' );
$css = preg_replace( '/\\\\([0-9a-fA-F]{4})/', '\\\\\\\\$1', $css );
$css = wp_kses_split( $css, array(), array() );
$csstidy->parse( $css );
$css = $csstidy->print->plain();
$css = str_replace( array( "\n","\r","\t" ), '', $css );
preg_match( "/^{$element}\s*{(.*)}\s*$/", $css, $matches );
if ( empty( $matches[1] ) )
return '';
return $matches[1];
}
}
function migrate() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::upgrade()' );
return Jetpack_Custom_CSS::upgrade();
}
function safecss_revision_redirect( $redirect ) {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::revision_redirect()' );
return Jetpack_Custom_CSS::revision_redirect( $redirect );
}
function safecss_revision_post_link( $post_link, $post_id, $context ) {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::revision_post_link()' );
return Jetpack_Custom_CSS::revision_post_link( $post_link, $post_id, $context );
}
function get_safecss_post() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::get_post()' );
return Jetpack_Custom_CSS::get_post();
}
function custom_css_post_id() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::post_id()' );
return Jetpack_Custom_CSS::post_id();
}
function get_current_revision() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::get_current_revision()' );
return Jetpack_Custom_CSS::get_current_revision();
}
function save_revision( $css, $is_preview = false, $preprocessor = '' ) {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::save_revision()' );
return Jetpack_Custom_CSS::save_revision( $css, $is_preview, $preprocessor );
}
function safecss_skip_stylesheet() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::skip_stylesheet()' );
return Jetpack_Custom_CSS::skip_stylesheet();
}
function safecss_init() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::init()' );
return Jetpack_Custom_CSS::init();
}
function safecss_is_preview() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::is_preview()' );
return Jetpack_Custom_CSS::is_preview();
}
function safecss_is_freetrial() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::is_freetrial()' );
return Jetpack_Custom_CSS::is_freetrial();
}
function safecss( $compressed = false ) {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::get_css()' );
return Jetpack_Custom_CSS::get_css( $compressed );
}
function safecss_print() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::print_css()' );
return Jetpack_Custom_CSS::print_css();
}
function safecss_style() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::link_tag()' );
return Jetpack_Custom_CSS::link_tag();
}
function safecss_style_filter( $current ) {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::style_filter()' );
return Jetpack_Custom_CSS::style_filter( $current );
}
function safecss_buffer( $html ) {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::buffer()' );
return Jetpack_Custom_CSS::buffer( $html );
}
function safecss_preview_links( $matches ) {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::preview_links()' );
return Jetpack_Custom_CSS::preview_links( $matches );
}
function safecss_preview_flag() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::preview_flag()' );
return Jetpack_Custom_CSS::preview_flag();
}
function safecss_menu() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::menu()' );
return Jetpack_Custom_CSS::menu();
}
function update_title() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::update_title()' );
return Jetpack_Custom_CSS::update_title();
}
function safecss_prettify_post_revisions() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::prettify_post_revisions()' );
return Jetpack_Custom_CSS::prettify_post_revisions();
}
function safecss_remove_title_excerpt_from_revisions() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::remove_title_excerpt_from_revisions()' );
return Jetpack_Custom_CSS::remove_title_excerpt_from_revisions();
}
function safecss_post_title( $title, $post_id ) {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::post_title()' );
return Jetpack_Custom_CSS::post_title( $title, $post_id );
}
function safe_css_enqueue_scripts() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::enqueue_scripts()' );
return Jetpack_Custom_CSS::enqueue_scripts( null );
}
function safecss_admin_head() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::admin_head()' );
return Jetpack_Custom_CSS::admin_head();
}
function safecss_saved() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::saved_message()' );
return Jetpack_Custom_CSS::saved_message();
}
function safecss_admin() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::admin()' );
return Jetpack_Custom_CSS::admin();
}
function custom_css_meta_box() {
_deprecated_function( __FUNCTION__, '2.1', 'add_meta_box( $id, $title, $callback, \'editcss\', \'side\' )' );
}
function custom_css_post_revisions_meta_box( $safecss_post ) {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::revisions_meta_box()' );
return Jetpack_Custom_CSS::revisions_meta_box( $safecss_post );
}
function disable_safecss_style() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::disable()' );
return Jetpack_Custom_CSS::disable();
}
function custom_css_reset() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::reset()' );
return Jetpack_Custom_CSS::reset();
}
function custom_css_is_customizer_preview() {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::is_customizer_preview()' );
return Jetpack_Custom_CSS::is_customizer_preview();
}
function custom_css_minify( $css, $preprocessor = '' ) {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::minify()' );
return Jetpack_Custom_CSS::minify( $css, $preprocessor );
}
function custom_css_restore_revision( $_post_id, $_revision_id ) {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::restore_revision()' );
return Jetpack_Custom_CSS::restore_revision( $_post_id, $_revision_id );
}
if ( ! function_exists( 'safecss_class' ) ) :
function safecss_class() {
// Wrapped so we don't need the parent class just to load the plugin
if ( class_exists('safecss') )
return;
require_once( dirname( __FILE__ ) . '/csstidy/class.csstidy.php' );
class safecss extends csstidy_optimise {
function postparse() {
/**
* Fires after parsing the css.
*
* @module custom-css
*
* @since 1.8.0
*
* @param obj $this CSSTidy object.
*/
do_action( 'csstidy_optimize_postparse', $this );
return parent::postparse();
}
function subvalue() {
/**
* Fires before optimizing the Custom CSS subvalue.
*
* @module custom-css
*
* @since 1.8.0
*
* @param obj $this CSSTidy object.
**/
do_action( 'csstidy_optimize_subvalue', $this );
return parent::subvalue();
}
}
}
endif;
if ( ! function_exists( 'safecss_filter_attr' ) ) {
function safecss_filter_attr( $css, $element = 'div' ) {
return Jetpack_Safe_CSS::filter_attr( $css, $element );
}
}
include_once dirname( __FILE__ ) . '/custom-css/preprocessors.php';