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 if ( function_exists( 'wp_get_theme' ) ) { $current_theme = wp_get_theme(); $post['post_excerpt'] = $current_theme->Name; } else { $post['post_excerpt'] = get_current_theme(); } // 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 if ( function_exists( 'wp_get_theme' ) ) { $current_theme = wp_get_theme(); $safecss_post['post_excerpt'] = $current_theme->Name; } else { $safecss_post['post_excerpt'] = get_current_theme(); } // 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) ( get_option( '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 http://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 ( get_option( 'safecss_revision_migrated' ) ) { $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 = get_option( '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', plugins_url( 'custom-css/js/css-editor.js', __FILE__ ), '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', plugins_url( 'custom-css/js/use-codemirror.js', __FILE__ ), array( 'jquery', 'underscore', 'jetpack-css-codemirror' ), '20131009', true ); } } static function saved_message() { echo '' . __( 'Stylesheet saved.', 'jetpack' ) . '