Completed
Push — core/custom-css-4.7 ( 5d1584...32fa01 )
by George
58:45 queued 50:15
created

set_content_width()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 8
Ratio 100 %

Importance

Changes 0
Metric Value
cc 4
eloc 4
nc 2
nop 0
dl 8
loc 8
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Class Jetpack_Custom_CSS_Enhancements
5
 */
6
class Jetpack_Custom_CSS_Enhancements {
7
	public static function add_hooks() {
8
		add_action( 'init', array( __CLASS__, 'init' ) );
9
		add_action( 'admin_menu', array( __CLASS__, 'admin_menu' ) );
10
		add_action( 'customize_controls_enqueue_scripts', array( __CLASS__, 'customize_controls_enqueue_scripts' ) );
11
		add_action( 'customize_register', array( __CLASS__, 'customize_register' ) );
12
		add_filter( 'map_meta_cap', array( __CLASS__, 'map_meta_cap' ), 20, 2 );
13
		add_action( 'customize_preview_init', array( __CLASS__, 'customize_preview_init' ) );
14
		add_filter( '_wp_post_revision_fields', array( __CLASS__, '_wp_post_revision_fields' ), 10, 2 );
15
		add_action( 'load-revision.php', array( __CLASS__, 'load_revision_php' ) );
16
17
		add_action( 'wp_enqueue_scripts', array( __CLASS__, 'wp_enqueue_scripts' ) );
18
19
		// Handle Sass/LESS
20
		add_filter( 'customize_value_custom_css', array( __CLASS__, 'customize_value_custom_css' ), 10, 2 );
21
		add_filter( 'customize_update_custom_css_post_content_args', array( __CLASS__, 'customize_update_custom_css_post_content_args' ), 10, 3 );
22
		add_filter( 'update_custom_css_data', array( __CLASS__, 'update_custom_css_data' ), 10, 2 );
23
24
		// Handle Sass/LESS
25
		add_filter( 'customize_value_custom_css', array( __CLASS__, 'customize_value_custom_css' ), 10, 2 );
26
		add_filter( 'customize_update_custom_css_post_content_args', array( __CLASS__, 'customize_update_custom_css_post_content_args' ), 10, 3 );
27
28
		// Stuff for stripping out the theme's default stylesheet...
29
		add_filter( 'stylesheet_uri', array( __CLASS__, 'style_filter' ) );
30
		add_filter( 'safecss_skip_stylesheet', array( __CLASS__, 'preview_skip_stylesheet' ) );
31
32
		// Stuff for overriding content width...
33
		add_action( 'customize_preview_init', array( __CLASS__, 'preview_content_width' ) );
34
		add_filter( 'jetpack_content_width', array( __CLASS__, 'jetpack_content_width' ) );
35
		add_filter( 'editor_max_image_size', array( __CLASS__, 'editor_max_image_size' ), 10, 3 );
36
		add_action( 'template_redirect', array( __CLASS__, 'set_content_width' ) );
37
		add_action( 'admin_init', array( __CLASS__, 'set_content_width' ) );
38
39
		// Stuff?
40
	}
41
42
	public static function init() {
43
		$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...
44
		if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
45
			$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...
46
		}
47
48
		wp_register_style( 'jetpack-codemirror',      plugins_url( "custom-css/css/codemirror.css", __FILE__ ), array(), '20120905' );
49
		wp_register_style( 'jetpack-customizer-css',  plugins_url( 'custom-css/css/customizer-control.css', __FILE__ ), array( 'jetpack-codemirror' ), '20140728' );
50
		wp_register_script( 'jetpack-codemirror',     plugins_url( "custom-css/js/codemirror.min.js", __FILE__ ), array(), '3.16', true );
51
		wp_register_script( 'jetpack-customizer-css', plugins_url( 'custom-css/js/core-customizer-css.js', __FILE__ ), array(  'customize-controls', 'underscore', 'jetpack-codemirror' ), JETPACK__VERSION, true );
52
53
		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 );
54
	}
55
56
	public static function customize_preview_init() {
57
		add_filter( 'wp_get_custom_css', array( __CLASS__, 'customize_preview_wp_get_custom_css' ) );
58
	}
59
60
	public static function map_meta_cap( $caps, $cap ) {
61
		if ( 'edit_css' === $cap ) {
62
			$caps = array( 'edit_theme_options' );
63
		}
64
		return $caps;
65
	}
66
67
	public static function admin_menu() {
68
		// Add in our legacy page to support old bookmarks and such.
69
		add_theme_page( __( 'CSS', 'jetpack' ), __( 'Edit CSS', 'jetpack' ), 'edit_theme_options', 'editcss', array( __CLASS__, 'admin_page' ) );
70
71
		// Add in our new page slug that will redirect to the customizer.
72
		$hook = add_theme_page( __( 'CSS', 'jetpack' ), __( 'Edit CSS ⚡', 'jetpack' ), 'edit_theme_options', 'editcss-customizer-redirect', array( __CLASS__, 'admin_page' ) );
73
		add_action( "load-{$hook}", array( __CLASS__, 'customizer_redirect' ) );
74
	}
75
76
	public static function customizer_redirect() {
77
		wp_safe_redirect( self::customizer_link( array(
78
			'return_url' => wp_get_referer(),
79
		) ) );
80
	}
81
82
	public static function prettify_post_revisions() {
83
		add_filter( 'the_title', array( __CLASS__, 'post_title' ), 10, 2 );
84
	}
85
86
	/**
87
	 * Shows Preprocessor code in the Revisions screen, and ensures that post_content_filtered
88
	 * is maintained on revisions
89
	 *
90
	 * @param  array $fields  Post fields pertinent to revisions
91
	 * @return array          Modified array to include post_content_filtered
92
	 */
93
	public static function _wp_post_revision_fields( $fields, $post ) {
94
		// If we're passed in a revision, go get the main post instead.
95
		if ( 'revision' === $post['post_type'] ) {
96
			$main_post_id = wp_is_post_revision( $post['ID'] );
97
			$post = get_post( $main_post_id, ARRAY_A );
98
		}
99
		if ( 'custom_css' === $post['post_type'] ) {
100
			$fields['post_content'] = __( 'CSS', 'jetpack' );
101
			$fields['post_content_filtered'] = __( 'Preprocessor', 'jetpack' );
102
		}
103
		return $fields;
104
	}
105
106
	/**
107
	 * Get the published custom CSS post.
108
	 *
109
	 * @param string $stylesheet Optional. A theme object stylesheet name. Defaults to the current theme.
110
	 *
111
	 * @return WP_Post|null
112
	 */
113
	public static function get_css_post( $stylesheet = '' ) {
114
		return wp_get_custom_css_post( $stylesheet );
115
	}
116
117
	public static function post_id( $stylesheet = '' ) {
118
		$post = self::get_css_post( $stylesheet );
119
		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...
120
			return $post->ID;
121
		}
122
		return 0;
123
	}
124
125
	public static function echo_custom_css_partial() {
126
		echo wp_get_custom_css();
127
	}
128
129
	public static function admin_page() {
130
		?>
131
		<div class="wrap">
132
			<h1>
133
				<?php esc_html_e( 'Custom CSS', 'jetpack' );
134
				if ( current_user_can( 'customize' ) ) {
135
					printf(
136
						' <a class="page-title-action hide-if-no-customize" href="%1$s">%2$s</a>',
137
						esc_url( self::customizer_link() ),
138
						__( 'Manage with Live Preview', 'jetpack' )
139
					);
140
				}
141
				?>
142
			</h1>
143
			<p><?php esc_html_e( 'Custom CSS is now managed in the Customizer.', 'jetpack' ); ?></p>
144
145
			<?php self::inactive_themes_revision_links(); ?>
146
		</div>
147
		<?php
148
	}
149
150
	public static function customizer_link( $args = array() ) {
151
		$args = wp_parse_args( $args, array(
152
			'return_url' => urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ),
153
		) );
154
155
		return add_query_arg(
156
			array(
157
				array(
158
					'autofocus' => array(
159
						'section' => 'custom_css'
160
					),
161
				),
162
				'return' => $args['return_url'],
163
			),
164
			admin_url( 'customize.php' )
165
		);
166
	}
167
168
	public static function inactive_themes_revision_links() {
169
		$themes = self::get_all_themes_with_custom_css();
170
		$stylesheet = get_stylesheet();
171
		?>
172
173
		<ul>
174
		<?php foreach ( $themes as $theme_stylesheet => $data ) :
175
			if ( $stylesheet === $theme_stylesheet ) {
176
				continue;
177
			}
178
			$revisions = wp_get_post_revisions( $data['post']->ID, array( 'posts_per_page' => 1 ) );
179
			if ( ! $revisions ) {
180
				?>
181
				<li><a href="<?php echo esc_url( add_query_arg( 'id', $data['post']->ID, menu_page_url( 'editcss', 0 ) ) ); ?>"><?php echo esc_html( $data['label'] ); ?></a>
182
					<?php printf( esc_html__( 'Last modified: %s', 'jetpack' ), get_the_modified_date( '', $data['post'] ) ); ?></li>
183
				<?php
184
				continue;
185
			}
186
			$revision = array_shift( $revisions );
187
			?>
188
			<li><a href="<?php echo esc_url( get_edit_post_link( $revision->ID ) ); ?>"><?php echo esc_html( $data['label'] ); ?></a>
189
				<?php printf( esc_html__( 'Last modified: %s', 'jetpack' ), get_the_modified_date( '', $data['post'] ) ); ?></li>
190
		<?php endforeach; ?>
191
		</ul>
192
193
		<?php
194
	}
195
196
	public static function customize_controls_enqueue_scripts() {
197
		wp_enqueue_style( 'jetpack-customizer-css' );
198
		wp_enqueue_script( 'jetpack-customizer-css' );
199
200
		$content_help = __( 'Set a different content width for full size images.', 'jetpack' );
201
		if ( ! empty( $GLOBALS['content_width'] ) ) {
202
			$content_help .= sprintf( __( ' The default content width for the <strong>%s</strong> theme is %d pixels.', 'jetpack' ), wp_get_theme()->Name, intval( $GLOBALS['content_width'] ) );
203
		}
204
205
		wp_localize_script( 'jetpack-customizer-css', '_jp_css_settings', array(
206
			/** This filter is documented in modules/custom-css/custom-css.php */
207
			'useRichEditor' => ! jetpack_is_mobile() && apply_filters( 'safecss_use_ace', true ),
208
			'areThereCssRevisions' => self::are_there_css_revisions(),
209
			'revisionsUrl' => self::get_revisions_url(),
210
			'cssHelpUrl' => '//en.support.wordpress.com/custom-design/editing-css/',
211
			'l10n' => array(
212
				'mode'           => __( 'Start Fresh', 'jetpack' ),
213
				'mobile'         => __( 'On Mobile', 'jetpack' ),
214
				'contentWidth'   => $content_help,
215
				'revisions'      => __( 'CSS Revisions', 'jetpack' ),
216
				'css_help_title' => __( 'CSS Help', 'jetpack' )
217
			)
218
		));
219
	}
220
221
	public static function are_there_css_revisions( $stylesheet = '' ) {
222
		$post = wp_get_custom_css_post( $stylesheet );
223
		if ( empty( $post ) ) {
224
			return $post;
225
		}
226
		return (bool) wp_get_post_revisions( $post );
227
	}
228
229
	public static function get_revisions_url( $stylesheet = '' ) {
230
		$post = wp_get_custom_css_post( $stylesheet );
231
232
		// If we have any currently saved customizations...
233
		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...
234
			$revisions = wp_get_post_revisions( $post->ID, array( 'posts_per_page' => 1 ) );
235
			$revision = reset( $revisions );
236
			return get_edit_post_link( $revision->ID );
237
		}
238
239
		return admin_url( 'themes.php?page=editcss' );
240
	}
241
242
	public static function get_themes() {
243
		$themes = wp_get_themes( array( 'errors' => null ) );
244
		$all = array();
245
		foreach ( $themes as $theme ) {
246
			$all[ $theme->name ] = $theme->stylesheet;
247
		}
248
		return $all;
249
	}
250
251
	public static function get_all_themes_with_custom_css() {
252
		$themes = self::get_themes();
253
		$custom_css = get_posts( array(
254
			'post_type'   => 'custom_css',
255
			'post_status' => get_post_stati(),
256
			'number'      => -1,
257
			'order'       => 'DESC',
258
			'orderby'     => 'modified',
259
		) );
260
		$return = array();
261
262
		foreach ( $custom_css as $post ) {
263
			$stylesheet = $post->post_title;
264
			$label      = array_search( $stylesheet, $themes );
265
266
			if ( ! $label ) {
267
				continue;
268
			}
269
270
			$return[ $stylesheet ] = array(
271
				'label' => $label,
272
				'post'  => $post,
273
			);
274
		}
275
276
		return $return;
277
	}
278
279
	public static function wp_enqueue_scripts() {
280
		if ( is_customize_preview() ) {
281
			wp_enqueue_script( 'jetpack-customizer-css-preview' );
282
			wp_localize_script( 'jetpack-customizer-css-preview', 'jpCustomizerCssPreview', array(
283
				/** This filter is documented in modules/custom-css/custom-css.php */
284
				'preprocessors' => apply_filters( 'jetpack_custom_css_preprocessors', array() ),
285
			));
286
		}
287
	}
288
289
	public static function sanitize_css( $css, $args = array() ) {
290
		$args = wp_parse_args( $args, array(
291
			'force'        => false,
292
			'preprocessor' => null,
293
		) );
294
295
		if ( $args['force'] || ! current_user_can( 'unfiltered_html' ) ) {
296
297
			$warnings = array();
298
299
			safecss_class();
300
			$csstidy = new csstidy();
301
			$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...
302
303
			$csstidy->set_cfg( 'remove_bslash',              false );
304
			$csstidy->set_cfg( 'compress_colors',            false );
305
			$csstidy->set_cfg( 'compress_font-weight',       false );
306
			$csstidy->set_cfg( 'optimise_shorthands',        0 );
307
			$csstidy->set_cfg( 'remove_last_;',              false );
308
			$csstidy->set_cfg( 'case_properties',            false );
309
			$csstidy->set_cfg( 'discard_invalid_properties', true );
310
			$csstidy->set_cfg( 'css_level',                  'CSS3.0' );
311
			$csstidy->set_cfg( 'preserve_css',               true );
312
			$csstidy->set_cfg( 'template',                   dirname( __FILE__ ) . '/csstidy/wordpress-standard.tpl' );
313
314
			// Test for some preg_replace stuff.
315
			{
316
				$prev = $css;
317
				$css = preg_replace( '/\\\\([0-9a-fA-F]{4})/', '\\\\\\\\$1', $css );
318
				// prevent content: '\3434' from turning into '\\3434'
319
				$css = str_replace( array( '\'\\\\', '"\\\\' ), array( '\'\\', '"\\' ), $css );
320
				if ( $css !== $prev ) {
321
					$warnings[] = 'preg_replace found stuff';
322
				}
323
			}
324
325
			// Some people put weird stuff in their CSS, KSES tends to be greedy
326
			$css = str_replace( '<=', '&lt;=', $css );
327
328
			// Test for some kses stuff.
329
			{
330
				$prev = $css;
331
				// Why KSES instead of strip_tags?  Who knows?
332
				$css = wp_kses_split( $css, array(), array() );
333
				$css = str_replace( '&gt;', '>', $css ); // kses replaces lone '>' with &gt;
334
				// Why both KSES and strip_tags?  Because we just added some '>'.
335
				$css = strip_tags( $css );
336
337
				if ( $css != $prev ) {
338
					$warnings[] = 'kses found stuff';
339
				}
340
			}
341
342
			// if we're not using a preprocessor
343 View Code Duplication
			if ( ! $args['preprocessor'] ) {
344
345
				/**
346
				 * Fires before parsing the css with CSSTidy, but only if
347
				 * the preprocessor is not configured for use.
348
				 *
349
				 * @module custom-css
350
				 *
351
				 * @since 1.7.0
352
				 *
353
				 * @param obj $csstidy The csstidy object.
354
				 * @param string $css Custom CSS.
355
				 * @param array $args Array of custom CSS arguments.
356
				 */
357
				do_action( 'safecss_parse_pre', $csstidy, $css, $args );
358
359
				$csstidy->parse( $css );
360
361
				/**
362
				 * Fires after parsing the css with CSSTidy, but only if
363
				 * the preprocessor is not configured for use.
364
				 *
365
				 * @module custom-css
366
				 *
367
				 * @since 1.7.0
368
				 *
369
				 * @param obj $csstidy The csstidy object.
370
				 * @param array $warnings Array of warnings.
371
				 * @param array $args Array of custom CSS arguments.
372
				 */
373
				do_action( 'safecss_parse_post', $csstidy, $warnings, $args );
374
375
				$css = $csstidy->print->plain();
376
			}
377
		}
378
		return $css;
379
	}
380
381
	/**
382
	 * Override $content_width in customizer previews.
383
	 */
384
	public static function preview_content_width() {
385
		global $wp_customize;
386
		if ( ! is_customize_preview() ) {
387
			return;
388
		}
389
390
		$setting = $wp_customize->get_setting( 'jetpack_custom_css[content_width]' );
391
		if ( ! $setting ) {
392
			return;
393
		}
394
395
		$customized_content_width = (int) $setting->post_value();
396
		if ( ! empty( $customized_content_width ) ) {
397
			$GLOBALS['content_width'] = $customized_content_width;
398
		}
399
	}
400
401
	static function style_filter( $current ) {
402
		if ( is_admin() ) {
403
			return $current;
404
		} elseif ( self::is_freetrial() && ( ! self::is_preview() || ! current_user_can( 'switch_themes' ) ) ) {
405
			return $current;
406
		} elseif ( self::skip_stylesheet() ) {
407
			/** This filter is documented in modules/custom-css/custom-css.php */
408
			return apply_filters( 'safecss_style_filter_url', plugins_url( 'custom-css/css/blank.css', __FILE__ ) );
409
		}
410
411
		return $current;
412
	}
413
414
	/**
415
	 * Determine whether or not we should have the theme skip its main stylesheet.
416
	 *
417
	 * @return mixed The truthiness of this value determines whether the stylesheet should be skipped.
418
	 */
419
	static function skip_stylesheet() {
420
		/** This filter is documented in modules/custom-css/custom-css.php */
421
		$skip_stylesheet = apply_filters( 'safecss_skip_stylesheet', null );
422
		if ( ! is_null( $skip_stylesheet ) ) {
423
			return $skip_stylesheet;
424
		}
425
426
		$jetpack_custom_css = get_theme_mod( 'jetpack_custom_css', array() );
427
		if ( isset( $jetpack_custom_css['replace'] ) ) {
428
			return $jetpack_custom_css['replace'];
429
		}
430
431
		return false;
432
	}
433
434
	/**
435
	 * Override $content_width in customizer previews.
436
	 *
437
	 * Runs on `safecss_skip_stylesheet` filter.
438
	 */
439
	public static function preview_skip_stylesheet( $skip_value ) {
440
		global $wp_customize;
441
		if ( ! is_customize_preview() ) {
442
			return $skip_value;
443
		}
444
445
		$setting = $wp_customize->get_setting( 'jetpack_custom_css[replace]' );
446
		if ( ! $setting ) {
447
			return $skip_value;
448
		}
449
450
		$customized_replace = $setting->post_value();
451
		if ( null !== $customized_replace ) {
452
			return $customized_replace;
453
		}
454
455
		return $skip_value;
456
	}
457
458
	/**
459
	 * Add Custom CSS section and controls.
460
	 */
461
	public static function customize_register( $wp_customize ) {
462
463
		// SETTINGS
464
465
		$wp_customize->add_setting( 'jetpack_custom_css[preprocessor]', array(
466
			'default' => '',
467
			'transport' => 'postMessage',
468
			'sanitize_callback' => array( __CLASS__, 'sanitize_preprocessor' ),
469
		) );
470
471
		$wp_customize->add_setting( 'jetpack_custom_css[replace]', array(
472
			'default' => false,
473
			'transport' => 'refresh',
474
		) );
475
476
		$wp_customize->add_setting( 'jetpack_custom_css[content_width]', array(
477
			'default' => '',
478
			'transport' => 'refresh',
479
			'sanitize_callback' => array( __CLASS__, 'intval_base10' ),
480
		) );
481
482
		// Add custom sanitization to the core css customizer setting.
483
		foreach ( $wp_customize->settings() as $setting ) {
484
			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...
485
				add_filter( "customize_sanitize_{$setting->id}", array( __CLASS__, 'sanitize_css_callback' ), 10, 2 );
486
			}
487
		}
488
489
		// CONTROLS
490
491
		// Overwrite the Core Control.
492
		$core_custom_css = $wp_customize->get_control( 'custom_css' );
493
		if ( $core_custom_css ) {
494
			$wp_customize->remove_control( 'custom_css' );
495
			$core_custom_css->type = 'jetpackCss';
496
			$wp_customize->add_control( $core_custom_css );
497
		}
498
499
		$wp_customize->selective_refresh->add_partial( 'custom_css', array(
500
			'type'                => 'custom_css',
501
			'selector'            => '#wp-custom-css',
502
			'container_inclusive' => false,
503
			'fallback_refresh'    => false,
504
			'settings'            => array(
505
				'custom_css[' . $wp_customize->get_stylesheet() . ']',
506
				'jetpack_custom_css[preprocessor]',
507
			),
508
			'render_callback' => array( __CLASS__, 'echo_custom_css_partial' ),
509
		) );
510
511
		$wp_customize->add_control( 'wpcom_custom_css_content_width_control', array(
512
			'type'     => 'text',
513
			'label'    => __( 'Media Width', 'jetpack' ),
514
			'section'  => 'custom_css',
515
			'settings' => 'jetpack_custom_css[content_width]',
516
		) );
517
518
		$wp_customize->add_control( 'jetpack_css_mode_control', array(
519
			'type'     => 'checkbox',
520
			'label'    => __( 'Don\'t use the theme\'s original CSS.', 'jetpack' ),
521
			'section'  => 'custom_css',
522
			'settings' => 'jetpack_custom_css[replace]',
523
		) );
524
525
		/**
526
		 * An action to grab on to if another Jetpack Module would like to add its own controls.
527
		 *
528
		 * @module custom-css
529
		 *
530
		 * @since 4.?.?
531
		 *
532
		 * @param $wp_customize The WP_Customize object.
533
		 */
534
		do_action( 'jetpack_custom_css_customizer_controls', $wp_customize );
535
536
		/** This filter is documented in modules/custom-css/custom-css.php */
537
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
538
		if ( ! empty( $preprocessors ) ) {
539
			$preprocessor_choices = array(
540
				'' => __( 'None', 'jetpack' ),
541
			);
542
543
			foreach ( $preprocessors as $preprocessor_key => $processor ) {
544
				$preprocessor_choices[$preprocessor_key] = $processor['name'];
545
			}
546
547
			$wp_customize->add_control( 'jetpack_css_preprocessors_control', array(
548
				'type'     => 'select',
549
				'choices'  => $preprocessor_choices,
550
				'label'    => __( 'Preprocessor', 'jetpack' ),
551
				'section'  => 'custom_css',
552
				'settings' => 'jetpack_custom_css[preprocessor]',
553
			) );
554
		}
555
556
	}
557
558
	public static function sanitize_css_callback( $css, $setting ) {
0 ignored issues
show
Unused Code introduced by
The parameter $setting is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
559
		global $wp_customize;
560
		return self::sanitize_css( $css, array(
561
			'preprocessor' => $wp_customize->get_setting('jetpack_custom_css[preprocessor]')->value(),
562
		) );
563
	}
564
565
	public static function is_freetrial() {
566
		return false;
567
	}
568
	public static function is_preview() {
569
		return false;
570
	}
571
	public static function is_customizer_preview() {
572
		return false;
573
	}
574
575
	public static function customize_preview_wp_get_custom_css( $css ) {
576
		global $wp_customize;
577
578
		$preprocessor = $wp_customize->get_setting('jetpack_custom_css[preprocessor]')->value();
579
580
		// If it's empty, just return.
581
		if ( empty( $preprocessor ) ) {
582
			return $css;
583
		}
584
585
		/** This filter is documented in modules/custom-css/custom-css.php */
586
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
587
		if ( isset( $preprocessors[ $preprocessor ] ) ) {
588
			return call_user_func( $preprocessors[ $preprocessor ]['callback'], $css );
589
		}
590
591
		return $css;
592
	}
593
594
	public static function customize_value_custom_css( $css, $setting ) {
595
		// Find the current preprocessor
596
		$jetpack_custom_css = get_theme_mod( 'jetpack_custom_css', array() );
597
		if ( isset( $jetpack_custom_css['preprocessor'] ) ) {
598
			$preprocessor = $jetpack_custom_css['preprocessor'];
599
		}
600
601
		// If it's not supported, just return.
602
		/** This filter is documented in modules/custom-css/custom-css.php */
603
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
604
		if ( ! isset( $preprocessors[ $preprocessor ] ) ) {
605
			return $css;
606
		}
607
608
		// Swap it for the `post_content_filtered` instead.
609
		$post = wp_get_custom_css_post( $setting->stylesheet );
610
		if ( $post && ! empty( $post->post_content_filtered ) ) {
611
			$css = $post->post_content_filtered;
612
		}
613
614
		return $css;
615
	}
616
617
	/**
618
	 * Soon to be deprecated as the filter moves and new function added.
619
	 */
620
	public static function customize_update_custom_css_post_content_args( $args, $css, $setting ) {
0 ignored issues
show
Unused Code introduced by
The parameter $setting is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
621
		// Find the current preprocessor
622
		$jetpack_custom_css = get_theme_mod( 'jetpack_custom_css', array() );
623
		if ( empty( $jetpack_custom_css['preprocessor'] ) ) {
624
			return $args;
625
		}
626
627
		$preprocessor = $jetpack_custom_css['preprocessor'];
628
		/** This filter is documented in modules/custom-css/custom-css.php */
629
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
630
631
		// If it's empty, just return.
632
		if ( empty( $preprocessor ) ) {
633
			return $args;
634
		}
635
636 View Code Duplication
		if ( isset( $preprocessors[ $preprocessor ] ) ) {
637
			$args['post_content_filtered'] = $css;
638
			$args['post_content'] = call_user_func( $preprocessors[ $preprocessor ]['callback'], $css );
639
		}
640
641
		return $args;
642
	}
643
644
	public static function update_custom_css_data( $args, $stylesheet ) {
0 ignored issues
show
Unused Code introduced by
The parameter $stylesheet is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
645
		// Find the current preprocessor
646
		$jetpack_custom_css = get_theme_mod( 'jetpack_custom_css', array() );
647
		if ( empty( $jetpack_custom_css['preprocessor'] ) ) {
648
			return $args;
649
		}
650
651
		/** This filter is documented in modules/custom-css/custom-css.php */
652
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
653
		$preprocessor = $jetpack_custom_css['preprocessor'];
654
655
		// If we have a preprocessor specified ...
656
		if ( isset( $preprocessors[ $preprocessor ] ) ) {
657
			// And no other preprocessor has run ...
658
			if ( empty( $args['preprocessed'] ) ) {
659
				$args['preprocessed'] = $args['css'];
660
				$args['css'] = call_user_func( $preprocessors[ $preprocessor ]['callback'], $args['css'] );
661
			} else {
662
				trigger_error( 'Jetpack CSS Preprocessor specified, but something else has already modified the argument.', E_USER_WARNING );
663
			}
664
		}
665
666
		return $args;
667
	}
668
669
	/**
670
	 * When on the edit screen, make sure the custom content width
671
	 * setting is applied to the large image size.
672
	 */
673 View Code Duplication
	static function editor_max_image_size( $dims, $size = 'medium', $context = null ) {
674
		list( $width, $height ) = $dims;
675
676
		if ( 'large' === $size && 'edit' === $context ) {
677
			$width = Jetpack::get_content_width();
678
		}
679
680
		return array( $width, $height );
681
	}
682
683
	/**
684
	 * Override the content_width with a custom value if one is set.
685
	 */
686
	static function jetpack_content_width( $content_width ) {
687
		$custom_content_width = 0;
688
689
		$jetpack_custom_css = get_theme_mod( 'jetpack_custom_css', array() );
690
		if ( isset( $jetpack_custom_css['content_width'] ) ) {
691
			$custom_content_width = $jetpack_custom_css['content_width'];
692
		}
693
694
		if ( $custom_content_width > 0 ) {
695
			return $custom_content_width;
696
		}
697
698
		return $content_width;
699
	}
700
701
	/**
702
	 * Currently this filter function gets called on
703
	 * 'template_redirect' action and
704
	 * 'admin_init' action
705
	 */
706 View Code Duplication
	static function set_content_width(){
707
		// Don't apply this filter on the Edit CSS page
708
		if ( isset( $_GET['page'] ) && 'editcss' === $_GET['page'] && is_admin() ) {
709
			return;
710
		}
711
712
		$GLOBALS['content_width'] = Jetpack::get_content_width();
713
	}
714
715
	/**
716
	 * Make sure the preprocessor we're saving is one we know about.
717
	 *
718
	 * @param $preprocessor The preprocessor to sanitize.
719
	 * @return null|string
720
	 */
721
	public static function sanitize_preprocessor( $preprocessor ) {
722
		/** This filter is documented in modules/custom-css/custom-css.php */
723
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
724
		if ( empty( $preprocessor ) || array_key_exists( $preprocessor, $preprocessors ) ) {
725
			return $preprocessor;
726
		}
727
		return null;
728
	}
729
730
	/**
731
	 * Get the base10 intval.
732
	 *
733
	 * This is used as a setting's sanitize_callback; we can't use just plain
734
	 * intval because the second argument is not what intval() expects.
735
	 *
736
	 * @access public
737
	 *
738
	 * @param mixed $value Number to convert.
739
	 * @return int Integer.
740
	 */
741
	public static function intval_base10( $value ) {
742
		return intval( $value, 10 );
743
	}
744
745
	public static function load_revision_php() {
746
		add_action( 'admin_footer', array( __CLASS__, 'revision_admin_footer' ) );
747
	}
748
749
	public static function revision_admin_footer() {
750
		$post = get_post();
751
		if ( 'custom_css' !== $post->post_type ) {
752
			return;
753
		}
754
		$stylesheet = $post->post_title;
755
		?>
756
<script type="text/html" id="tmpl-other-themes-switcher">
757
	<?php self::revisions_switcher_box( $stylesheet ); ?>
758
</script>
759
<style>
760
.other-themes-wrap {
761
	float: right;
762
	background-color: #fff;
763
	-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.1);
764
	box-shadow: 0 1px 3px rgba(0,0,0,0.1);
765
	padding: 5px 10px;
766
	margin-bottom: 10px;
767
}
768
.other-themes-wrap label {
769
	display: block;
770
	margin-bottom: 10px;
771
}
772
.other-themes-wrap select {
773
	float: left;
774
	width: 77%;
775
}
776
.other-themes-wrap button {
777
	float: right;
778
	width: 20%;
779
}
780
.revisions {
781
	clear: both;
782
}
783
</style>
784
<script>
785
(function($){
786
	var switcher = $('#tmpl-other-themes-switcher').html(),
787
		qty = $( switcher ).find('select option').length,
788
		$switcher;
789
790
	if ( qty >= 3 ) {
791
		$('h1.long-header').before( switcher );
792
		$switcher = $('.other-themes-wrap');
793
		$switcher.find('button').on('click', function(e){
794
			e.preventDefault();
795
			if ( $switcher.find('select').val() ) {
796
				window.location.href = $switcher.find('select').val();
797
			}
798
		})
799
	}
800
})(jQuery);
801
</script>
802
		<?php
803
	}
804
805
	public static function revisions_switcher_box( $stylesheet = '' ) {
806
		$themes = self::get_all_themes_with_custom_css();
807
		?>
808
		<div class="other-themes-wrap">
809
			<label for="other-themes"><?php esc_html_e( 'Would you like to view the revisions of another theme instead?', 'jetpack' ); ?></label>
810
			<select id="other-themes">
811
				<option value=""><?php esc_html_e( 'Select a theme&hellip;', 'jetpack' ); ?></option>
812
				<?php
813
				foreach ( $themes as $theme_stylesheet => $data ) {
814
					$revisions = wp_get_post_revisions( $data['post']->ID, array( 'posts_per_page' => 1 ) );
815
					if ( ! $revisions ) {
816
						?>
817
						<option value="<?php echo esc_url( add_query_arg( 'id', $data['post']->ID, menu_page_url( 'editcss', 0 ) ) ); ?>" <?php disabled( $stylesheet, $theme_stylesheet ); ?>>
818
							<?php echo esc_html( $data['label'] ); ?>
819
							<?php printf( esc_html__( '(modified %s ago)', 'jetpack' ), human_time_diff( strtotime( $data['post']->post_modified_gmt ) ) ); ?></option>
820
						<?php
821
						continue;
822
					}
823
					$revision = array_shift( $revisions );
824
					?>
825
					<option value="<?php echo esc_url( get_edit_post_link( $revision->ID ) ); ?>" <?php disabled( $stylesheet, $theme_stylesheet ); ?>>
826
						<?php echo esc_html( $data['label'] ); ?>
827
						<?php printf( esc_html__( '(modified %s ago)', 'jetpack' ), human_time_diff( strtotime( $data['post']->post_modified_gmt ) ) ); ?></option>
828
					<?php
829
				}
830
				?>
831
			</select>
832
			<button class="button" id="other_theme_custom_css_switcher"><?php esc_html_e( 'Switch', 'jetpack' ); ?></button>
833
		</div>
834
		<?php
835
	}
836
}
837
838
Jetpack_Custom_CSS_Enhancements::add_hooks();
839
840 View Code Duplication
if ( ! function_exists( 'safecss_class' ) ) :
841
function safecss_class() {
842
	// Wrapped so we don't need the parent class just to load the plugin
843
	if ( class_exists('safecss') ) {
844
		return;
845
	}
846
847
	require_once( dirname( __FILE__ ) . '/csstidy/class.csstidy.php' );
848
849
	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...
850
851
		function postparse() {
852
853
			/**
854
			 * Fires after parsing the css.
855
			 *
856
			 * @module custom-css
857
			 *
858
			 * @since 1.8.0
859
			 *
860
			 * @param obj $this CSSTidy object.
861
			 */
862
			do_action( 'csstidy_optimize_postparse', $this );
863
864
			return parent::postparse();
865
		}
866
867
		function subvalue() {
868
869
			/**
870
			 * Fires before optimizing the Custom CSS subvalue.
871
			 *
872
			 * @module custom-css
873
			 *
874
			 * @since 1.8.0
875
			 *
876
			 * @param obj $this CSSTidy object.
877
			 **/
878
			do_action( 'csstidy_optimize_subvalue', $this );
879
880
			return parent::subvalue();
881
		}
882
	}
883
}
884
endif;
885