Completed
Push — try/upgrade-react-and-componen... ( 980eb7...de776d )
by
unknown
08:57
created

Jetpack_Custom_CSS_Enhancements::init()   B

Complexity

Conditions 6
Paths 16

Size

Total Lines 33
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 22
nc 16
nop 0
dl 0
loc 33
rs 8.439
c 0
b 0
f 0
1
<?php
2
/**
3
 * Alternate Custom CSS source for 4.7 compat.
4
 *
5
 * @since 4.4.2
6
 *
7
 * @package Jetpack
8
 */
9
10
/**
11
 * Class Jetpack_Custom_CSS_Enhancements
12
 */
13
class Jetpack_Custom_CSS_Enhancements {
14
	/**
15
	 * Set up the actions and filters needed for our compatability layer on top of core's Custom CSS implementation.
16
	 */
17
	public static function add_hooks() {
18
		add_action( 'init', array( __CLASS__, 'init' ) );
19
		add_action( 'admin_menu', array( __CLASS__, 'admin_menu' ) );
20
		add_action( 'customize_controls_enqueue_scripts', array( __CLASS__, 'customize_controls_enqueue_scripts' ) );
21
		add_action( 'customize_register', array( __CLASS__, 'customize_register' ) );
22
		add_filter( 'map_meta_cap', array( __CLASS__, 'map_meta_cap' ), 20, 2 );
23
		add_action( 'customize_preview_init', array( __CLASS__, 'customize_preview_init' ) );
24
		add_filter( '_wp_post_revision_fields', array( __CLASS__, '_wp_post_revision_fields' ), 10, 2 );
25
		add_action( 'load-revision.php', array( __CLASS__, 'load_revision_php' ) );
26
27
		add_action( 'wp_enqueue_scripts', array( __CLASS__, 'wp_enqueue_scripts' ) );
28
29
		// Handle Sass/LESS.
30
		add_filter( 'customize_value_custom_css', array( __CLASS__, 'customize_value_custom_css' ), 10, 2 );
31
		add_filter( 'customize_update_custom_css_post_content_args', array( __CLASS__, 'customize_update_custom_css_post_content_args' ), 10, 3 );
32
		add_filter( 'update_custom_css_data', array( __CLASS__, 'update_custom_css_data' ), 10, 2 );
33
34
		// Handle Sass/LESS.
35
		add_filter( 'customize_value_custom_css', array( __CLASS__, 'customize_value_custom_css' ), 10, 2 );
36
		add_filter( 'customize_update_custom_css_post_content_args', array( __CLASS__, 'customize_update_custom_css_post_content_args' ), 10, 3 );
37
38
		// Stuff for stripping out the theme's default stylesheet...
39
		add_filter( 'stylesheet_uri', array( __CLASS__, 'style_filter' ) );
40
		add_filter( 'safecss_skip_stylesheet', array( __CLASS__, 'preview_skip_stylesheet' ) );
41
42
		// Stuff for overriding content width...
43
		add_action( 'customize_preview_init', array( __CLASS__, 'preview_content_width' ) );
44
		add_filter( 'jetpack_content_width', array( __CLASS__, 'jetpack_content_width' ) );
45
		add_filter( 'editor_max_image_size', array( __CLASS__, 'editor_max_image_size' ), 10, 3 );
46
		add_action( 'template_redirect', array( __CLASS__, 'set_content_width' ) );
47
		add_action( 'admin_init', array( __CLASS__, 'set_content_width' ) );
48
49
		// Stuff?
50
	}
51
52
	/**
53
	 * Things that we do on init.
54
	 */
55
	public static function init() {
56
		$min = '.min';
0 ignored issues
show
Unused Code introduced by
$min is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
57
		if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
58
			$min = '';
0 ignored issues
show
Unused Code introduced by
$min is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
59
		}
60
61
		wp_register_style( 'jetpack-codemirror',      plugins_url( 'custom-css/css/codemirror.css', __FILE__ ), array(), '20120905' );
62
		$deps = array();
63
		if ( ! function_exists( 'wp_enqueue_code_editor' ) ) {
64
			// If Core < 4.9
65
			$deps[] = 'jetpack-codemirror';
66
		}
67
		wp_register_style( 'jetpack-customizer-css',  plugins_url( 'custom-css/css/customizer-control.css', __FILE__ ), $deps, '20140728' );
68
		wp_register_script( 'jetpack-codemirror',     plugins_url( 'custom-css/js/codemirror.min.js', __FILE__ ), array(), '3.16', true );
69
		$deps = array( 'customize-controls', 'underscore' );
70
		$src  = plugins_url( 'custom-css/js/core-customizer-css.core-4.9.js', __FILE__ );
71
		if ( ! function_exists( 'wp_enqueue_code_editor' ) ) {
72
			// If Core < 4.9
73
			$deps[] = 'jetpack-codemirror';
74
			$src = plugins_url( 'custom-css/js/core-customizer-css.js', __FILE__ );
75
		}
76
		wp_register_script( 'jetpack-customizer-css', $src, $deps, JETPACK__VERSION, true );
77
78
		wp_register_script( 'jetpack-customizer-css-preview', plugins_url( 'custom-css/js/core-customizer-css-preview.js', __FILE__ ), array( 'customize-selective-refresh' ), JETPACK__VERSION, true );
79
80
		remove_action( 'wp_head', 'wp_custom_css_cb', 11 ); // 4.7.0 had it at 11, 4.7.1 moved it to 101.
81
		remove_action( 'wp_head', 'wp_custom_css_cb', 101 );
82
		add_action( 'wp_head', array( __CLASS__, 'wp_custom_css_cb' ), 101 );
83
84
		if ( isset( $_GET['custom-css'] ) ) {
85
			self::print_linked_custom_css();
86
		}
87
	}
88
89
	/**
90
	 * Things that we do on init when the Customize Preview is loading.
91
	 */
92
	public static function customize_preview_init() {
93
		add_filter( 'wp_get_custom_css', array( __CLASS__, 'customize_preview_wp_get_custom_css' ) );
94
	}
95
96
	/**
97
	 * Print the current Custom CSS. This is for linking instead of printing directly.
98
	 */
99
	public static function print_linked_custom_css() {
100
		header( 'Content-type: text/css' );
101
		header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + YEAR_IN_SECONDS ) . ' GMT' );
102
		echo wp_get_custom_css();
103
		exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method print_linked_custom_css() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
104
	}
105
106
	/**
107
	 * Re-map the Edit CSS capability.
108
	 *
109
	 * Core, by default, restricts this to users that have `unfiltered_html` which
110
	 * would make the feature unusable in multi-site by non-super-admins, due to Core
111
	 * not shipping any solid sanitization.
112
	 *
113
	 * We're expanding who can use it, and then conditionally applying CSSTidy
114
	 * sanitization to users that do not have the `unfiltered_html` capability.
115
	 *
116
	 * @param array  $caps Returns the user's actual capabilities.
117
	 * @param string $cap  Capability name.
118
	 *
119
	 * @return array $caps
120
	 */
121
	public static function map_meta_cap( $caps, $cap ) {
122
		if ( 'edit_css' === $cap ) {
123
			$caps = array( 'edit_theme_options' );
124
		}
125
		return $caps;
126
	}
127
128
	/**
129
	 * Handle our admin menu item and legacy page declaration.
130
	 */
131
	public static function admin_menu() {
132
		// Add in our legacy page to support old bookmarks and such.
133
		add_submenu_page( null, __( 'CSS', 'jetpack' ), __( 'Edit CSS', 'jetpack' ), 'edit_theme_options', 'editcss', array( __CLASS__, 'admin_page' ) );
134
135
		// Add in our new page slug that will redirect to the customizer.
136
		$hook = add_theme_page( __( 'CSS', 'jetpack' ), __( 'Edit CSS', 'jetpack' ), 'edit_theme_options', 'editcss-customizer-redirect', array( __CLASS__, 'admin_page' ) );
137
		add_action( "load-{$hook}", array( __CLASS__, 'customizer_redirect' ) );
138
	}
139
140
	/**
141
	 * Handle the redirect for the customizer.  This is necessary because
142
	 * we can't directly add customizer links to the admin menu.
143
	 *
144
	 * There is a core patch in trac that would make this unnecessary.
145
	 *
146
	 * @link https://core.trac.wordpress.org/ticket/39050
147
	 */
148
	public static function customizer_redirect() {
149
		wp_safe_redirect( self::customizer_link( array(
150
			'return_url' => wp_get_referer(),
151
		) ) );
152
		exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method customizer_redirect() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
153
	}
154
155
	/**
156
	 * Shows Preprocessor code in the Revisions screen, and ensures that post_content_filtered
157
	 * is maintained on revisions
158
	 *
159
	 * @param array $fields  Post fields pertinent to revisions.
160
	 * @param array $post    A post array being processed for insertion as a post revision.
161
	 *
162
	 * @return array $fields Modified array to include post_content_filtered.
163
	 */
164
	public static function _wp_post_revision_fields( $fields, $post ) {
165
		// None of the fields in $post are required to be passed in this filter.
166
		if ( ! isset( $post['post_type'], $post['ID'] ) ) {
167
			return $fields;
168
		}
169
170
		// If we're passed in a revision, go get the main post instead.
171
		if ( 'revision' === $post['post_type'] ) {
172
			$main_post_id = wp_is_post_revision( $post['ID'] );
173
			$post = get_post( $main_post_id, ARRAY_A );
174
		}
175
		if ( 'custom_css' === $post['post_type'] ) {
176
			$fields['post_content'] = __( 'CSS', 'jetpack' );
177
			$fields['post_content_filtered'] = __( 'Preprocessor', 'jetpack' );
178
		}
179
		return $fields;
180
	}
181
182
	/**
183
	 * Get the published custom CSS post.
184
	 *
185
	 * @param string $stylesheet Optional. A theme object stylesheet name. Defaults to the current theme.
186
	 * @return WP_Post|null
187
	 */
188
	public static function get_css_post( $stylesheet = '' ) {
189
		return wp_get_custom_css_post( $stylesheet );
190
	}
191
192
	/**
193
	 * Override Core's `wp_custom_css_cb` method to provide linking to custom css.
194
	 */
195
	public static function wp_custom_css_cb() {
196
		$styles = wp_get_custom_css();
197
		if ( strlen( $styles ) > 2000 && ! is_customize_preview() ) :
198
			// Add a cache buster to the url.
199
			$url = home_url( '/' );
200
			$url = add_query_arg( 'custom-css', substr( md5( $styles ), -10 ), $url );
201
			?>
202
			<link rel="stylesheet" type="text/css" id="wp-custom-css" href="<?php echo esc_url( $url ); ?>" />
203
		<?php elseif ( $styles || is_customize_preview() ) : ?>
204
			<style type="text/css" id="wp-custom-css">
205
				<?php echo strip_tags( $styles ); // Note that esc_html() cannot be used because `div &gt; span` is not interpreted properly. ?>
206
			</style>
207
		<?php endif;
208
	}
209
210
	/**
211
	 * Get the ID of a Custom CSS post tying to a given stylesheet.
212
	 *
213
	 * @param string $stylesheet Stylesheet name.
214
	 *
215
	 * @return int $post_id Post ID.
216
	 */
217
	public static function post_id( $stylesheet = '' ) {
218
		$post = self::get_css_post( $stylesheet );
219
		if ( $post instanceof WP_Post ) {
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
220
			return $post->ID;
221
		}
222
		return 0;
223
	}
224
225
	/**
226
	 * Partial for use in the Customizer.
227
	 */
228
	public static function echo_custom_css_partial() {
229
		echo wp_get_custom_css();
230
	}
231
232
	/**
233
	 * Admin page!
234
	 *
235
	 * This currently has two main uses -- firstly to display the css for an inactive
236
	 * theme if there are no revisions attached it to a legacy bug, and secondly to
237
	 * handle folks that have bookmarkes in their browser going to the old page for
238
	 * managing Custom CSS in Jetpack.
239
	 *
240
	 * If we ever add back in a non-Customizer CSS editor, this would be the place.
241
	 */
242
	public static function admin_page() {
243
		$post = null;
244
		$stylesheet = null;
245
		if ( isset( $_GET['id'] ) ) {
246
			$post_id = absint( $_GET['id'] );
247
			$post = get_post( $post_id );
248
			if ( $post instanceof WP_Post && 'custom_css' === $post->post_type ) {
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
249
				$stylesheet = $post->post_title;
250
			}
251
		}
252
		?>
253
		<div class="wrap">
254
			<?php self::revisions_switcher_box( $stylesheet ); ?>
255
			<h1>
256
				<?php
257
				if ( $post ) {
258
					printf( 'Custom CSS for &#8220;%1$s&#8221;', wp_get_theme( $stylesheet )->Name );
259
				} else {
260
					esc_html_e( 'Custom CSS', 'jetpack' );
261
				}
262
				if ( current_user_can( 'customize' ) ) {
263
					printf(
264
						' <a class="page-title-action hide-if-no-customize" href="%1$s">%2$s</a>',
265
						esc_url( self::customizer_link() ),
266
						esc_html__( 'Manage with Live Preview', 'jetpack' )
267
					);
268
				}
269
				?>
270
			</h1>
271
			<p><?php esc_html_e( 'Custom CSS is now managed in the Customizer.', 'jetpack' ); ?></p>
272
			<?php if ( $post ) : ?>
273
				<div class="revisions">
274
					<h3><?php esc_html_e( 'CSS', 'jetpack' ); ?></h3>
275
					<textarea class="widefat" readonly><?php echo esc_textarea( $post->post_content ); ?></textarea>
276
					<?php if ( $post->post_content_filtered ) : ?>
277
						<h3><?php esc_html_e( 'Preprocessor', 'jetpack' ); ?></h3>
278
						<textarea class="widefat" readonly><?php echo esc_textarea( $post->post_content_filtered ); ?></textarea>
279
					<?php endif; ?>
280
				</div>
281
			<?php endif; ?>
282
		</div>
283
284
		<style>
285
			.other-themes-wrap {
286
				float: right;
287
				background-color: #fff;
288
				-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.1);
289
				box-shadow: 0 1px 3px rgba(0,0,0,0.1);
290
				padding: 5px 10px;
291
				margin-bottom: 10px;
292
			}
293
			.other-themes-wrap label {
294
				display: block;
295
				margin-bottom: 10px;
296
			}
297
			.other-themes-wrap select {
298
				float: left;
299
				width: 77%;
300
			}
301
			.other-themes-wrap button {
302
				float: right;
303
				width: 20%;
304
			}
305
			.revisions {
306
				clear: both;
307
			}
308
			.revisions textarea {
309
				min-height: 300px;
310
				background: #fff;
311
			}
312
		</style>
313
		<script>
314
			(function($){
315
				var $switcher = $('.other-themes-wrap');
316
				$switcher.find('button').on('click', function(e){
317
					e.preventDefault();
318
					if ( $switcher.find('select').val() ) {
319
						window.location.href = $switcher.find('select').val();
320
					}
321
				});
322
			})(jQuery);
323
		</script>
324
		<?php
325
	}
326
327
	/**
328
	 * Build the URL to deep link to the Customizer.
329
	 *
330
	 * You can modify the return url via $args.
331
	 *
332
	 * @param array $args Array of parameters.
333
	 * @return string
334
	 */
335
	public static function customizer_link( $args = array() ) {
336
		$args = wp_parse_args( $args, array(
337
			'return_url' => urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ),
338
		) );
339
340
		return add_query_arg(
341
			array(
342
				array(
343
					'autofocus' => array(
344
						'section' => 'custom_css',
345
					),
346
				),
347
				'return' => $args['return_url'],
348
			),
349
			admin_url( 'customize.php' )
350
		);
351
	}
352
353
	/**
354
	 * Handle the enqueueing and localizing for scripts to be used in the Customizer.
355
	 */
356
	public static function customize_controls_enqueue_scripts() {
357
		wp_enqueue_style( 'jetpack-customizer-css' );
358
		wp_enqueue_script( 'jetpack-customizer-css' );
359
360
		$content_help = __( 'Set a different content width for full size images.', 'jetpack' );
361
		if ( ! empty( $GLOBALS['content_width'] ) ) {
362
			$content_help .= sprintf(
363
				_n( ' The default content width for the <strong>%1$s</strong> theme is %2$d pixel.', ' The default content width for the <strong>%1$s</strong> theme is %2$d pixels.', intval( $GLOBALS['content_width'] ), 'jetpack' ),
364
				wp_get_theme()->Name,
365
				intval( $GLOBALS['content_width'] )
366
			);
367
		}
368
369
		wp_localize_script( 'jetpack-customizer-css', '_jp_css_settings', array(
370
			/** This filter is documented in modules/custom-css/custom-css.php */
371
			'useRichEditor' => ! jetpack_is_mobile() && apply_filters( 'safecss_use_ace', true ),
372
			'areThereCssRevisions' => self::are_there_css_revisions(),
373
			'revisionsUrl' => self::get_revisions_url(),
374
			'cssHelpUrl' => '//en.support.wordpress.com/custom-design/editing-css/',
375
			'l10n' => array(
376
				'mode'           => __( 'Start Fresh', 'jetpack' ),
377
				'mobile'         => __( 'On Mobile', 'jetpack' ),
378
				'contentWidth'   => $content_help,
379
				'revisions'      => _x( 'See full history', 'Toolbar button to see full CSS revision history', 'jetpack' ),
380
				'css_help_title' => _x( 'Help', 'Toolbar button to get help with custom CSS', 'jetpack' ),
381
			),
382
		));
383
	}
384
385
	/**
386
	 * Check whether there are CSS Revisions for a given theme.
387
	 *
388
	 * Going forward, there should always be, but this was necessitated
389
	 * early on by https://core.trac.wordpress.org/ticket/30854
390
	 *
391
	 * @param string $stylesheet Stylesheet name.
392
	 *
393
	 * @return bool|null|WP_Post
394
	 */
395
	public static function are_there_css_revisions( $stylesheet = '' ) {
396
		$post = wp_get_custom_css_post( $stylesheet );
397
		if ( empty( $post ) ) {
398
			return $post;
399
		}
400
		return (bool) wp_get_post_revisions( $post );
401
	}
402
403
	/**
404
	 * Core doesn't have a function to get the revisions url for a given post ID.
405
	 *
406
	 * @param string $stylesheet Stylesheet name.
407
	 *
408
	 * @return null|string|void
409
	 */
410
	public static function get_revisions_url( $stylesheet = '' ) {
411
		$post = wp_get_custom_css_post( $stylesheet );
412
413
		// If we have any currently saved customizations...
414
		if ( $post instanceof WP_Post ) {
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
415
			$revisions = wp_get_post_revisions( $post->ID, array( 'posts_per_page' => 1 ) );
416
			if ( empty( $revisions ) || is_wp_error( $revisions ) ) {
417
				return admin_url( 'themes.php?page=editcss' );
418
			}
419
			$revision = reset( $revisions );
420
			return get_edit_post_link( $revision->ID );
421
		}
422
423
		return admin_url( 'themes.php?page=editcss' );
424
	}
425
426
	/**
427
	 * Get a map of all theme names and theme stylesheets for mapping stuff.
428
	 *
429
	 * @return array
430
	 */
431
	public static function get_themes() {
432
		$themes = wp_get_themes( array( 'errors' => null ) );
433
		$all = array();
434
		foreach ( $themes as $theme ) {
435
			$all[ $theme->name ] = $theme->stylesheet;
436
		}
437
		return $all;
438
	}
439
440
	/**
441
	 * When we need to get all themes that have Custom CSS saved.
442
	 *
443
	 * @return array
444
	 */
445
	public static function get_all_themes_with_custom_css() {
446
		$themes = self::get_themes();
447
		$custom_css = get_posts( array(
448
			'post_type'   => 'custom_css',
449
			'post_status' => get_post_stati(),
450
			'number'      => -1,
451
			'order'       => 'DESC',
452
			'orderby'     => 'modified',
453
		) );
454
		$return = array();
455
456
		foreach ( $custom_css as $post ) {
457
			$stylesheet = $post->post_title;
458
			$label      = array_search( $stylesheet, $themes );
459
460
			if ( ! $label ) {
461
				continue;
462
			}
463
464
			$return[ $stylesheet ] = array(
465
				'label' => $label,
466
				'post'  => $post,
467
			);
468
		}
469
470
		return $return;
471
	}
472
473
	/**
474
	 * Handle the enqueueing of scripts for customize previews.
475
	 */
476
	public static function wp_enqueue_scripts() {
477
		if ( is_customize_preview() ) {
478
			wp_enqueue_script( 'jetpack-customizer-css-preview' );
479
			wp_localize_script( 'jetpack-customizer-css-preview', 'jpCustomizerCssPreview', array(
480
				/** This filter is documented in modules/custom-css/custom-css.php */
481
				'preprocessors' => apply_filters( 'jetpack_custom_css_preprocessors', array() ),
482
			));
483
		}
484
	}
485
486
	/**
487
	 * Sanitize the CSS for users without `unfiltered_html`.
488
	 *
489
	 * @param string $css  Input CSS.
490
	 * @param array  $args Array of CSS options.
491
	 *
492
	 * @return mixed|string
493
	 */
494
	public static function sanitize_css( $css, $args = array() ) {
495
		$args = wp_parse_args( $args, array(
496
			'force'        => false,
497
			'preprocessor' => null,
498
		) );
499
500
		if ( $args['force'] || ! current_user_can( 'unfiltered_html' ) ) {
501
502
			$warnings = array();
503
504
			safecss_class();
505
			$csstidy = new csstidy();
506
			$csstidy->optimise = new safecss( $csstidy );
0 ignored issues
show
Documentation introduced by
$csstidy is of type object<csstidy>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
507
508
			$csstidy->set_cfg( 'remove_bslash',              false );
509
			$csstidy->set_cfg( 'compress_colors',            false );
510
			$csstidy->set_cfg( 'compress_font-weight',       false );
511
			$csstidy->set_cfg( 'optimise_shorthands',        0 );
512
			$csstidy->set_cfg( 'remove_last_;',              false );
513
			$csstidy->set_cfg( 'case_properties',            false );
514
			$csstidy->set_cfg( 'discard_invalid_properties', true );
515
			$csstidy->set_cfg( 'css_level',                  'CSS3.0' );
516
			$csstidy->set_cfg( 'preserve_css',               true );
517
			$csstidy->set_cfg( 'template',                   dirname( __FILE__ ) . '/csstidy/wordpress-standard.tpl' );
518
519
			// Test for some preg_replace stuff.
520
			{
521
				$prev = $css;
522
				$css = preg_replace( '/\\\\([0-9a-fA-F]{4})/', '\\\\\\\\$1', $css );
523
				// prevent content: '\3434' from turning into '\\3434'.
524
				$css = str_replace( array( '\'\\\\', '"\\\\' ), array( '\'\\', '"\\' ), $css );
525
				if ( $css !== $prev ) {
526
					$warnings[] = 'preg_replace found stuff';
527
				}
528
			}
529
530
			// Some people put weird stuff in their CSS, KSES tends to be greedy.
531
			$css = str_replace( '<=', '&lt;=', $css );
532
533
			// Test for some kses stuff.
534
			{
535
				$prev = $css;
536
				// Why KSES instead of strip_tags?  Who knows?
537
				$css = wp_kses_split( $css, array(), array() );
538
				$css = str_replace( '&gt;', '>', $css ); // kses replaces lone '>' with &gt;
539
				// Why both KSES and strip_tags?  Because we just added some '>'.
540
				$css = strip_tags( $css );
541
542
				if ( $css != $prev ) {
543
					$warnings[] = 'kses found stuff';
544
				}
545
			}
546
547
			// if we're not using a preprocessor.
548 View Code Duplication
			if ( ! $args['preprocessor'] ) {
549
550
				/** This action is documented in modules/custom-css/custom-css.php */
551
				do_action( 'safecss_parse_pre', $csstidy, $css, $args );
552
553
				$csstidy->parse( $css );
554
555
				/** This action is documented in modules/custom-css/custom-css.php */
556
				do_action( 'safecss_parse_post', $csstidy, $warnings, $args );
557
558
				$css = $csstidy->print->plain();
559
			}
560
		}
561
		return $css;
562
	}
563
564
	/**
565
	 * Override $content_width in customizer previews.
566
	 */
567
	public static function preview_content_width() {
568
		global $wp_customize;
569
		if ( ! is_customize_preview() ) {
570
			return;
571
		}
572
573
		$setting = $wp_customize->get_setting( 'jetpack_custom_css[content_width]' );
574
		if ( ! $setting ) {
575
			return;
576
		}
577
578
		$customized_content_width = (int) $setting->post_value();
579
		if ( ! empty( $customized_content_width ) ) {
580
			$GLOBALS['content_width'] = $customized_content_width;
581
		}
582
	}
583
584
	/**
585
	 * Filter the current theme's stylesheet for potentially nullifying it.
586
	 *
587
	 * @param string $current Stylesheet URI for the current theme/child theme.
588
	 *
589
	 * @return mixed|void
590
	 */
591
	static function style_filter( $current ) {
592
		if ( is_admin() ) {
593
			return $current;
594
		} elseif ( self::is_freetrial() && ( ! self::is_preview() || ! current_user_can( 'switch_themes' ) ) ) {
595
			return $current;
596
		} elseif ( self::skip_stylesheet() ) {
597
			/** This filter is documented in modules/custom-css/custom-css.php */
598
			return apply_filters( 'safecss_style_filter_url', plugins_url( 'custom-css/css/blank.css', __FILE__ ) );
599
		}
600
601
		return $current;
602
	}
603
604
	/**
605
	 * Determine whether or not we should have the theme skip its main stylesheet.
606
	 *
607
	 * @return mixed The truthiness of this value determines whether the stylesheet should be skipped.
608
	 */
609
	static function skip_stylesheet() {
610
		/** This filter is documented in modules/custom-css/custom-css.php */
611
		$skip_stylesheet = apply_filters( 'safecss_skip_stylesheet', null );
612
		if ( ! is_null( $skip_stylesheet ) ) {
613
			return $skip_stylesheet;
614
		}
615
616
		$jetpack_custom_css = get_theme_mod( 'jetpack_custom_css', array() );
617
		if ( isset( $jetpack_custom_css['replace'] ) ) {
618
			return $jetpack_custom_css['replace'];
619
		}
620
621
		return false;
622
	}
623
624
	/**
625
	 * Override $content_width in customizer previews.
626
	 *
627
	 * Runs on `safecss_skip_stylesheet` filter.
628
	 *
629
	 * @param bool $skip_value Should the stylesheet be skipped.
630
	 *
631
	 * @return null|bool
632
	 */
633
	public static function preview_skip_stylesheet( $skip_value ) {
634
		global $wp_customize;
635
		if ( ! is_customize_preview() ) {
636
			return $skip_value;
637
		}
638
639
		$setting = $wp_customize->get_setting( 'jetpack_custom_css[replace]' );
640
		if ( ! $setting ) {
641
			return $skip_value;
642
		}
643
644
		$customized_replace = $setting->post_value();
645
		if ( null !== $customized_replace ) {
646
			return $customized_replace;
647
		}
648
649
		return $skip_value;
650
	}
651
652
	/**
653
	 * Add Custom CSS section and controls.
654
	 *
655
	 * @param WP_Customize_Manager $wp_customize WP_Customize_Manager instance.
656
	 */
657
	public static function customize_register( $wp_customize ) {
658
659
		/**
660
		 * SETTINGS.
661
		 */
662
663
		$wp_customize->add_setting( 'jetpack_custom_css[preprocessor]', array(
664
			'default' => '',
665
			'transport' => 'postMessage',
666
			'sanitize_callback' => array( __CLASS__, 'sanitize_preprocessor' ),
667
		) );
668
669
		$wp_customize->add_setting( 'jetpack_custom_css[replace]', array(
670
			'default' => false,
671
			'transport' => 'refresh',
672
		) );
673
674
		$wp_customize->add_setting( 'jetpack_custom_css[content_width]', array(
675
			'default' => '',
676
			'transport' => 'refresh',
677
			'sanitize_callback' => array( __CLASS__, 'intval_base10' ),
678
		) );
679
680
		// Add custom sanitization to the core css customizer setting.
681
		foreach ( $wp_customize->settings() as $setting ) {
682
			if ( $setting instanceof WP_Customize_Custom_CSS_Setting ) {
0 ignored issues
show
Bug introduced by
The class WP_Customize_Custom_CSS_Setting does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
683
				add_filter( "customize_sanitize_{$setting->id}", array( __CLASS__, 'sanitize_css_callback' ), 10, 2 );
684
			}
685
		}
686
687
		/**
688
		 * CONTROLS.
689
		 */
690
691
		// Overwrite or Tweak the Core Control.
692
		$core_custom_css = $wp_customize->get_control( 'custom_css' );
693
		if ( $core_custom_css ) {
694
			if ( $core_custom_css instanceof WP_Customize_Code_Editor_Control ) {
0 ignored issues
show
Bug introduced by
The class WP_Customize_Code_Editor_Control does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
695
				// In WP 4.9, we let the Core CodeMirror control keep running the show, but hook into it to tweak stuff.
696
				$types = array(
697
					'default' => 'text/css',
698
					'less'    => 'text/x-less',
699
					'sass'    => 'text/x-scss',
700
				);
701
				$preprocessor = $wp_customize->get_setting( 'jetpack_custom_css[preprocessor]' )->value();
702
				if ( isset( $types[ $preprocessor ] ) ) {
703
					$core_custom_css->code_type = $types[ $preprocessor ];
704
				}
705
			} else {
706
				// Core < 4.9 Fallback
707
				$core_custom_css->type = 'jetpackCss';
708
			}
709
		}
710
711
		$wp_customize->selective_refresh->add_partial( 'custom_css', array(
712
			'type'                => 'custom_css',
713
			'selector'            => '#wp-custom-css',
714
			'container_inclusive' => false,
715
			'fallback_refresh'    => false,
716
			'settings'            => array(
717
				'custom_css[' . $wp_customize->get_stylesheet() . ']',
718
				'jetpack_custom_css[preprocessor]',
719
			),
720
			'render_callback' => array( __CLASS__, 'echo_custom_css_partial' ),
721
		) );
722
723
		$wp_customize->add_control( 'wpcom_custom_css_content_width_control', array(
724
			'type'     => 'text',
725
			'label'    => __( 'Media Width', 'jetpack' ),
726
			'section'  => 'custom_css',
727
			'settings' => 'jetpack_custom_css[content_width]',
728
		) );
729
730
		$wp_customize->add_control( 'jetpack_css_mode_control', array(
731
			'type'     => 'checkbox',
732
			'label'    => __( 'Don\'t use the theme\'s original CSS.', 'jetpack' ),
733
			'section'  => 'custom_css',
734
			'settings' => 'jetpack_custom_css[replace]',
735
		) );
736
737
		/**
738
		 * An action to grab on to if another Jetpack Module would like to add its own controls.
739
		 *
740
		 * @module custom-css
741
		 *
742
		 * @since 4.4.2
743
		 *
744
		 * @param $wp_customize The WP_Customize object.
745
		 */
746
		do_action( 'jetpack_custom_css_customizer_controls', $wp_customize );
747
748
		/** This filter is documented in modules/custom-css/custom-css.php */
749
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
750
		if ( ! empty( $preprocessors ) ) {
751
			$preprocessor_choices = array(
752
				'' => __( 'None', 'jetpack' ),
753
			);
754
755
			foreach ( $preprocessors as $preprocessor_key => $processor ) {
756
				$preprocessor_choices[ $preprocessor_key ] = $processor['name'];
757
			}
758
759
			$wp_customize->add_control( 'jetpack_css_preprocessors_control', array(
760
				'type'     => 'select',
761
				'choices'  => $preprocessor_choices,
762
				'label'    => __( 'Preprocessor', 'jetpack' ),
763
				'section'  => 'custom_css',
764
				'settings' => 'jetpack_custom_css[preprocessor]',
765
			) );
766
		}
767
768
	}
769
770
	/**
771
	 * The callback to handle sanitizing the CSS. Takes different arguments, hence the proxy function.
772
	 *
773
	 * @param mixed                $css     Value of the setting.
774
	 * @param WP_Customize_Setting $setting WP_Customize_Setting instance.
775
	 *
776
	 * @return mixed|string
777
	 */
778
	public static function sanitize_css_callback( $css, $setting ) {
779
		global $wp_customize;
780
		return self::sanitize_css( $css, array(
781
			'preprocessor' => $wp_customize->get_setting( 'jetpack_custom_css[preprocessor]' )->value(),
782
		) );
783
	}
784
785
	/**
786
	 * Flesh out for wpcom.
787
	 *
788
	 * @todo
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
789
	 *
790
	 * @return bool
791
	 */
792
	public static function is_freetrial() {
793
		return false;
794
	}
795
796
	/**
797
	 * Flesh out for wpcom.
798
	 *
799
	 * @todo
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
800
	 *
801
	 * @return bool
802
	 */
803
	public static function is_preview() {
804
		return false;
805
	}
806
807
	/**
808
	 * Output the custom css for customize preview.
809
	 *
810
	 * @param string $css Custom CSS content.
811
	 *
812
	 * @return mixed
813
	 */
814
	public static function customize_preview_wp_get_custom_css( $css ) {
815
		global $wp_customize;
816
817
		$preprocessor = $wp_customize->get_setting( 'jetpack_custom_css[preprocessor]' )->value();
818
819
		// If it's empty, just return.
820
		if ( empty( $preprocessor ) ) {
821
			return $css;
822
		}
823
824
		/** This filter is documented in modules/custom-css/custom-css.php */
825
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
826
		if ( isset( $preprocessors[ $preprocessor ] ) ) {
827
			return call_user_func( $preprocessors[ $preprocessor ]['callback'], $css );
828
		}
829
830
		return $css;
831
	}
832
833
	/**
834
	 * Add CSS preprocessing to our CSS if it is supported.
835
	 *
836
	 * @param mixed                $css     Value of the setting.
837
	 * @param WP_Customize_Setting $setting WP_Customize_Setting instance.
838
	 *
839
	 * @return string
840
	 */
841
	public static function customize_value_custom_css( $css, $setting ) {
842
		// Find the current preprocessor.
843
		$jetpack_custom_css = get_theme_mod( 'jetpack_custom_css', array() );
844
		if ( isset( $jetpack_custom_css['preprocessor'] ) ) {
845
			$preprocessor = $jetpack_custom_css['preprocessor'];
846
		}
847
848
		// If it's not supported, just return.
849
		/** This filter is documented in modules/custom-css/custom-css.php */
850
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
851
		if ( ! isset( $preprocessors[ $preprocessor ] ) ) {
852
			return $css;
853
		}
854
855
		// Swap it for the `post_content_filtered` instead.
856
		$post = wp_get_custom_css_post( $setting->stylesheet );
857
		if ( $post && ! empty( $post->post_content_filtered ) ) {
858
			$css = $post->post_content_filtered;
859
		}
860
861
		return $css;
862
	}
863
864
	/**
865
	 * Store the original pre-processed CSS in `post_content_filtered`
866
	 * and then store processed CSS in `post_content`.
867
	 *
868
	 * @param array                           $args    Content post args.
869
	 * @param string                          $css     Original CSS being updated.
870
	 * @param WP_Customize_Custom_CSS_Setting $setting Custom CSS Setting.
871
	 *
872
	 * @return mixed
873
	 */
874
	public static function customize_update_custom_css_post_content_args( $args, $css, $setting ) {
875
		// Find the current preprocessor.
876
		$jetpack_custom_css = get_theme_mod( 'jetpack_custom_css', array() );
877
		if ( empty( $jetpack_custom_css['preprocessor'] ) ) {
878
			return $args;
879
		}
880
881
		$preprocessor = $jetpack_custom_css['preprocessor'];
882
		/** This filter is documented in modules/custom-css/custom-css.php */
883
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
884
885
		// If it's empty, just return.
886
		if ( empty( $preprocessor ) ) {
887
			return $args;
888
		}
889
890 View Code Duplication
		if ( isset( $preprocessors[ $preprocessor ] ) ) {
891
			$args['post_content_filtered'] = $css;
892
			$args['post_content'] = call_user_func( $preprocessors[ $preprocessor ]['callback'], $css );
893
		}
894
895
		return $args;
896
	}
897
898
	/**
899
	 * Filter to handle the processing of preprocessed css on save.
900
	 *
901
	 * @param array  $args       Custom CSS options.
902
	 * @param string $stylesheet Original CSS to be updated.
903
	 *
904
	 * @return mixed
905
	 */
906
	public static function update_custom_css_data( $args, $stylesheet ) {
907
		// Find the current preprocessor.
908
		$jetpack_custom_css = get_theme_mod( 'jetpack_custom_css', array() );
909
		if ( empty( $jetpack_custom_css['preprocessor'] ) ) {
910
			return $args;
911
		}
912
913
		/** This filter is documented in modules/custom-css/custom-css.php */
914
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
915
		$preprocessor = $jetpack_custom_css['preprocessor'];
916
917
		// If we have a preprocessor specified ...
918
		if ( isset( $preprocessors[ $preprocessor ] ) ) {
919
			// And no other preprocessor has run ...
920
			if ( empty( $args['preprocessed'] ) ) {
921
				$args['preprocessed'] = $args['css'];
922
				$args['css'] = call_user_func( $preprocessors[ $preprocessor ]['callback'], $args['css'] );
923
			} else {
924
				trigger_error( 'Jetpack CSS Preprocessor specified, but something else has already modified the argument.', E_USER_WARNING );
925
			}
926
		}
927
928
		return $args;
929
	}
930
931
	/**
932
	 * When on the edit screen, make sure the custom content width
933
	 * setting is applied to the large image size.
934
	 *
935
	 * @param array  $dims    Array of image dimensions (width and height).
936
	 * @param string $size    Size of the resulting image.
937
	 * @param null   $context Context the image is being resized for. `edit` or `display`.
938
	 *
939
	 * @return array
940
	 */
941 View Code Duplication
	static function editor_max_image_size( $dims, $size = 'medium', $context = null ) {
942
		list( $width, $height ) = $dims;
943
944
		if ( 'large' === $size && 'edit' === $context ) {
945
			$width = Jetpack::get_content_width();
946
		}
947
948
		return array( $width, $height );
949
	}
950
951
	/**
952
	 * Override the content_width with a custom value if one is set.
953
	 *
954
	 * @param int $content_width Content Width value to be updated.
955
	 *
956
	 * @return int
957
	 */
958
	static function jetpack_content_width( $content_width ) {
959
		$custom_content_width = 0;
960
961
		$jetpack_custom_css = get_theme_mod( 'jetpack_custom_css', array() );
962
		if ( isset( $jetpack_custom_css['content_width'] ) ) {
963
			$custom_content_width = $jetpack_custom_css['content_width'];
964
		}
965
966
		if ( $custom_content_width > 0 ) {
967
			return $custom_content_width;
968
		}
969
970
		return $content_width;
971
	}
972
973
	/**
974
	 * Currently this filter function gets called on
975
	 * 'template_redirect' action and
976
	 * 'admin_init' action
977
	 */
978 View Code Duplication
	static function set_content_width() {
979
		// Don't apply this filter on the Edit CSS page.
980
		if ( isset( $_GET['page'] ) && 'editcss' === $_GET['page'] && is_admin() ) {
981
			return;
982
		}
983
984
		$GLOBALS['content_width'] = Jetpack::get_content_width();
985
	}
986
987
	/**
988
	 * Make sure the preprocessor we're saving is one we know about.
989
	 *
990
	 * @param string $preprocessor The preprocessor to sanitize.
991
	 *
992
	 * @return null|string
993
	 */
994
	public static function sanitize_preprocessor( $preprocessor ) {
995
		/** This filter is documented in modules/custom-css/custom-css.php */
996
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
997
		if ( empty( $preprocessor ) || array_key_exists( $preprocessor, $preprocessors ) ) {
998
			return $preprocessor;
999
		}
1000
		return null;
1001
	}
1002
1003
	/**
1004
	 * Get the base10 intval.
1005
	 *
1006
	 * This is used as a setting's sanitize_callback; we can't use just plain
1007
	 * intval because the second argument is not what intval() expects.
1008
	 *
1009
	 * @access public
1010
	 *
1011
	 * @param mixed $value Number to convert.
1012
	 * @return int Integer.
1013
	 */
1014
	public static function intval_base10( $value ) {
1015
		return intval( $value, 10 );
1016
	}
1017
1018
	/**
1019
	 * Add a footer action on revision.php to print some customizations for the theme switcher.
1020
	 */
1021
	public static function load_revision_php() {
1022
		add_action( 'admin_footer', array( __CLASS__, 'revision_admin_footer' ) );
1023
	}
1024
1025
	/**
1026
	 * Print the theme switcher on revision.php and move it into place.
1027
	 */
1028
	public static function revision_admin_footer() {
1029
		$post = get_post();
1030
		if ( 'custom_css' !== $post->post_type ) {
1031
			return;
1032
		}
1033
		$stylesheet = $post->post_title;
1034
		?>
1035
<script type="text/html" id="tmpl-other-themes-switcher">
1036
	<?php self::revisions_switcher_box( $stylesheet ); ?>
1037
</script>
1038
<style>
1039
.other-themes-wrap {
1040
	float: right;
1041
	background-color: #fff;
1042
	-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.1);
1043
	box-shadow: 0 1px 3px rgba(0,0,0,0.1);
1044
	padding: 5px 10px;
1045
	margin-bottom: 10px;
1046
}
1047
.other-themes-wrap label {
1048
	display: block;
1049
	margin-bottom: 10px;
1050
}
1051
.other-themes-wrap select {
1052
	float: left;
1053
	width: 77%;
1054
}
1055
.other-themes-wrap button {
1056
	float: right;
1057
	width: 20%;
1058
}
1059
.revisions {
1060
	clear: both;
1061
}
1062
/* Hide the back-to-post link */
1063
.long-header + a {
1064
	display: none;
1065
}
1066
</style>
1067
<script>
1068
(function($){
1069
	var switcher = $('#tmpl-other-themes-switcher').html(),
1070
		qty = $( switcher ).find('select option').length,
1071
		$switcher;
1072
1073
	if ( qty >= 3 ) {
1074
		$('h1.long-header').before( switcher );
1075
		$switcher = $('.other-themes-wrap');
1076
		$switcher.find('button').on('click', function(e){
1077
			e.preventDefault();
1078
			if ( $switcher.find('select').val() ) {
1079
				window.location.href = $switcher.find('select').val();
1080
			}
1081
		})
1082
	}
1083
})(jQuery);
1084
</script>
1085
		<?php
1086
	}
1087
1088
	/**
1089
	 * The HTML for the theme revision switcher box.
1090
	 *
1091
	 * @param string $stylesheet Stylesheet name.
1092
	 */
1093
	public static function revisions_switcher_box( $stylesheet = '' ) {
1094
		$themes = self::get_all_themes_with_custom_css();
1095
		?>
1096
		<div class="other-themes-wrap">
1097
			<label for="other-themes"><?php esc_html_e( 'Select another theme to view its custom CSS.', 'jetpack' ); ?></label>
1098
			<select id="other-themes">
1099
				<option value=""><?php esc_html_e( 'Select a theme&hellip;', 'jetpack' ); ?></option>
1100
				<?php
1101
				foreach ( $themes as $theme_stylesheet => $data ) {
1102
					$revisions = wp_get_post_revisions( $data['post']->ID, array( 'posts_per_page' => 1 ) );
1103
					if ( ! $revisions ) {
1104
						?>
1105
						<option value="<?php echo esc_url( add_query_arg( 'id', $data['post']->ID, menu_page_url( 'editcss', 0 ) ) ); ?>" <?php disabled( $stylesheet, $theme_stylesheet ); ?>>
1106
							<?php echo esc_html( $data['label'] ); ?>
1107
							<?php printf( esc_html__( '(modified %s ago)', 'jetpack' ), human_time_diff( strtotime( $data['post']->post_modified_gmt ) ) ); ?></option>
1108
						<?php
1109
						continue;
1110
					}
1111
					$revision = array_shift( $revisions );
1112
					?>
1113
					<option value="<?php echo esc_url( get_edit_post_link( $revision->ID ) ); ?>" <?php disabled( $stylesheet, $theme_stylesheet ); ?>>
1114
						<?php echo esc_html( $data['label'] ); ?>
1115
						<?php printf( esc_html__( '(modified %s ago)', 'jetpack' ), human_time_diff( strtotime( $data['post']->post_modified_gmt ) ) ); ?></option>
1116
					<?php
1117
				}
1118
				?>
1119
			</select>
1120
			<button class="button" id="other_theme_custom_css_switcher"><?php esc_html_e( 'Switch', 'jetpack' ); ?></button>
1121
		</div>
1122
		<?php
1123
	}
1124
}
1125
1126
Jetpack_Custom_CSS_Enhancements::add_hooks();
1127
1128 View Code Duplication
if ( ! function_exists( 'safecss_class' ) ) :
1129
	/**
1130
	 * Load in the class only when needed.  Makes lighter load by having one less class in memory.
1131
	 */
1132
	function safecss_class() {
1133
		// Wrapped so we don't need the parent class just to load the plugin.
1134
		if ( class_exists( 'safecss' ) ) {
1135
			return;
1136
		}
1137
1138
		require_once( dirname( __FILE__ ) . '/csstidy/class.csstidy.php' );
1139
1140
		/**
1141
		 * Class safecss
1142
		 */
1143
		class safecss extends csstidy_optimise {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
1144
1145
			/**
1146
			 * Optimises $css after parsing.
1147
			 */
1148
			function postparse() {
1149
1150
				/** This action is documented in modules/custom-css/custom-css.php */
1151
				do_action( 'csstidy_optimize_postparse', $this );
1152
1153
				return parent::postparse();
1154
			}
1155
1156
			/**
1157
			 * Optimises a sub-value.
1158
			 */
1159
			function subvalue() {
1160
1161
				/** This action is documented in modules/custom-css/custom-css.php */
1162
				do_action( 'csstidy_optimize_subvalue', $this );
1163
1164
				return parent::subvalue();
1165
			}
1166
		}
1167
	}
1168
endif;
1169