Completed
Push — branch-4.4 ( 3609d2...3dd542 )
by
unknown
14:00 queued 06:34
created

Jetpack_Custom_CSS_Enhancements::admin_page()   C

Complexity

Conditions 8
Paths 36

Size

Total Lines 84
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 37
nc 36
nop 0
dl 0
loc 84
rs 5.8442
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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_submenu_page( null, __( '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
		$post = null;
131
		$stylesheet = null;
132
		if ( isset( $_GET['id'] ) ) {
133
			$post_id = absint( $_GET['id'] );
134
			$post = get_post( $post_id );
135
			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...
136
				$stylesheet = $post->post_title;
137
			}
138
		}
139
		?>
140
		<div class="wrap">
141
			<?php self::revisions_switcher_box( $stylesheet ); ?>
142
			<h1>
143
				<?php
144
				if ( $post ) {
145
					printf( 'Custom CSS for &#8220;%1$s&#8221;', wp_get_theme( $stylesheet )->Name );
146
				} else {
147
					esc_html_e( 'Custom CSS', 'jetpack' );
148
				}
149
				if ( current_user_can( 'customize' ) ) {
150
					printf(
151
						' <a class="page-title-action hide-if-no-customize" href="%1$s">%2$s</a>',
152
						esc_url( self::customizer_link() ),
153
						__( 'Manage with Live Preview', 'jetpack' )
154
					);
155
				}
156
				?>
157
			</h1>
158
			<p><?php esc_html_e( 'Custom CSS is now managed in the Customizer.', 'jetpack' ); ?></p>
159
			<?php if ( $post ) : ?>
160
				<div class="revisions">
161
					<h3><?php esc_html_e( 'CSS', 'jetpack' ); ?></h3>
162
					<textarea class="widefat" readonly><?php echo esc_textarea( $post->post_content ); ?></textarea>
163
					<?php if ( $post->post_content_filtered ) : ?>
164
						<h3><?php esc_html_e( 'Preprocessor', 'jetpack' ); ?></h3>
165
						<textarea class="widefat" readonly><?php echo esc_textarea( $post->post_content_filtered ); ?></textarea>
166
					<?php endif; ?>
167
				</div>
168
			<?php endif; ?>
169
		</div>
170
171
		<style>
172
			.other-themes-wrap {
173
				float: right;
174
				background-color: #fff;
175
				-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.1);
176
				box-shadow: 0 1px 3px rgba(0,0,0,0.1);
177
				padding: 5px 10px;
178
				margin-bottom: 10px;
179
			}
180
			.other-themes-wrap label {
181
				display: block;
182
				margin-bottom: 10px;
183
			}
184
			.other-themes-wrap select {
185
				float: left;
186
				width: 77%;
187
			}
188
			.other-themes-wrap button {
189
				float: right;
190
				width: 20%;
191
			}
192
			.revisions {
193
				clear: both;
194
			}
195
			.revisions textarea {
196
				min-height: 300px;
197
				background: #fff;
198
			}
199
		</style>
200
		<script>
201
			(function($){
202
				var $switcher = $('.other-themes-wrap');
203
				$switcher.find('button').on('click', function(e){
204
					e.preventDefault();
205
					if ( $switcher.find('select').val() ) {
206
						window.location.href = $switcher.find('select').val();
207
					}
208
				});
209
			})(jQuery);
210
		</script>
211
		<?php
212
	}
213
214
	public static function customizer_link( $args = array() ) {
215
		$args = wp_parse_args( $args, array(
216
			'return_url' => urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ),
217
		) );
218
219
		return add_query_arg(
220
			array(
221
				array(
222
					'autofocus' => array(
223
						'section' => 'custom_css'
224
					),
225
				),
226
				'return' => $args['return_url'],
227
			),
228
			admin_url( 'customize.php' )
229
		);
230
	}
231
232
	public static function inactive_themes_revision_links() {
233
		$themes = self::get_all_themes_with_custom_css();
234
		$stylesheet = get_stylesheet();
235
		?>
236
237
		<ul>
238
		<?php foreach ( $themes as $theme_stylesheet => $data ) :
239
			if ( $stylesheet === $theme_stylesheet ) {
240
				continue;
241
			}
242
			$revisions = wp_get_post_revisions( $data['post']->ID, array( 'posts_per_page' => 1 ) );
243
			if ( ! $revisions ) {
244
				?>
245
				<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>
246
					<?php printf( esc_html__( 'Last modified: %s', 'jetpack' ), get_the_modified_date( '', $data['post'] ) ); ?></li>
247
				<?php
248
				continue;
249
			}
250
			$revision = array_shift( $revisions );
251
			?>
252
			<li><a href="<?php echo esc_url( get_edit_post_link( $revision->ID ) ); ?>"><?php echo esc_html( $data['label'] ); ?></a>
253
				<?php printf( esc_html__( 'Last modified: %s', 'jetpack' ), get_the_modified_date( '', $data['post'] ) ); ?></li>
254
		<?php endforeach; ?>
255
		</ul>
256
257
		<?php
258
	}
259
260
	public static function customize_controls_enqueue_scripts() {
261
		wp_enqueue_style( 'jetpack-customizer-css' );
262
		wp_enqueue_script( 'jetpack-customizer-css' );
263
264
		$content_help = __( 'Set a different content width for full size images.', 'jetpack' );
265
		if ( ! empty( $GLOBALS['content_width'] ) ) {
266
			$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'] ) );
267
		}
268
269
		wp_localize_script( 'jetpack-customizer-css', '_jp_css_settings', array(
270
			/** This filter is documented in modules/custom-css/custom-css.php */
271
			'useRichEditor' => ! jetpack_is_mobile() && apply_filters( 'safecss_use_ace', true ),
272
			'areThereCssRevisions' => self::are_there_css_revisions(),
273
			'revisionsUrl' => self::get_revisions_url(),
274
			'cssHelpUrl' => '//en.support.wordpress.com/custom-design/editing-css/',
275
			'l10n' => array(
276
				'mode'           => __( 'Start Fresh', 'jetpack' ),
277
				'mobile'         => __( 'On Mobile', 'jetpack' ),
278
				'contentWidth'   => $content_help,
279
				'revisions'      => _x( 'See full history', 'Toolbar button to see full CSS revision history', 'jetpack' ),
280
				'css_help_title' => _x( 'Help', 'Toolbar button to get help with custom CSS', 'jetpack' )
281
			)
282
		));
283
	}
284
285
	public static function are_there_css_revisions( $stylesheet = '' ) {
286
		$post = wp_get_custom_css_post( $stylesheet );
287
		if ( empty( $post ) ) {
288
			return $post;
289
		}
290
		return (bool) wp_get_post_revisions( $post );
291
	}
292
293
	public static function get_revisions_url( $stylesheet = '' ) {
294
		$post = wp_get_custom_css_post( $stylesheet );
295
296
		// If we have any currently saved customizations...
297
		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...
298
			$revisions = wp_get_post_revisions( $post->ID, array( 'posts_per_page' => 1 ) );
299
			$revision = reset( $revisions );
300
			return get_edit_post_link( $revision->ID );
301
		}
302
303
		return admin_url( 'themes.php?page=editcss' );
304
	}
305
306
	public static function get_themes() {
307
		$themes = wp_get_themes( array( 'errors' => null ) );
308
		$all = array();
309
		foreach ( $themes as $theme ) {
310
			$all[ $theme->name ] = $theme->stylesheet;
311
		}
312
		return $all;
313
	}
314
315
	public static function get_all_themes_with_custom_css() {
316
		$themes = self::get_themes();
317
		$custom_css = get_posts( array(
318
			'post_type'   => 'custom_css',
319
			'post_status' => get_post_stati(),
320
			'number'      => -1,
321
			'order'       => 'DESC',
322
			'orderby'     => 'modified',
323
		) );
324
		$return = array();
325
326
		foreach ( $custom_css as $post ) {
327
			$stylesheet = $post->post_title;
328
			$label      = array_search( $stylesheet, $themes );
329
330
			if ( ! $label ) {
331
				continue;
332
			}
333
334
			$return[ $stylesheet ] = array(
335
				'label' => $label,
336
				'post'  => $post,
337
			);
338
		}
339
340
		return $return;
341
	}
342
343
	public static function wp_enqueue_scripts() {
344
		if ( is_customize_preview() ) {
345
			wp_enqueue_script( 'jetpack-customizer-css-preview' );
346
			wp_localize_script( 'jetpack-customizer-css-preview', 'jpCustomizerCssPreview', array(
347
				/** This filter is documented in modules/custom-css/custom-css.php */
348
				'preprocessors' => apply_filters( 'jetpack_custom_css_preprocessors', array() ),
349
			));
350
		}
351
	}
352
353
	public static function sanitize_css( $css, $args = array() ) {
354
		$args = wp_parse_args( $args, array(
355
			'force'        => false,
356
			'preprocessor' => null,
357
		) );
358
359
		if ( $args['force'] || ! current_user_can( 'unfiltered_html' ) ) {
360
361
			$warnings = array();
362
363
			safecss_class();
364
			$csstidy = new csstidy();
365
			$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...
366
367
			$csstidy->set_cfg( 'remove_bslash',              false );
368
			$csstidy->set_cfg( 'compress_colors',            false );
369
			$csstidy->set_cfg( 'compress_font-weight',       false );
370
			$csstidy->set_cfg( 'optimise_shorthands',        0 );
371
			$csstidy->set_cfg( 'remove_last_;',              false );
372
			$csstidy->set_cfg( 'case_properties',            false );
373
			$csstidy->set_cfg( 'discard_invalid_properties', true );
374
			$csstidy->set_cfg( 'css_level',                  'CSS3.0' );
375
			$csstidy->set_cfg( 'preserve_css',               true );
376
			$csstidy->set_cfg( 'template',                   dirname( __FILE__ ) . '/csstidy/wordpress-standard.tpl' );
377
378
			// Test for some preg_replace stuff.
379
			{
380
				$prev = $css;
381
				$css = preg_replace( '/\\\\([0-9a-fA-F]{4})/', '\\\\\\\\$1', $css );
382
				// prevent content: '\3434' from turning into '\\3434'
383
				$css = str_replace( array( '\'\\\\', '"\\\\' ), array( '\'\\', '"\\' ), $css );
384
				if ( $css !== $prev ) {
385
					$warnings[] = 'preg_replace found stuff';
386
				}
387
			}
388
389
			// Some people put weird stuff in their CSS, KSES tends to be greedy
390
			$css = str_replace( '<=', '&lt;=', $css );
391
392
			// Test for some kses stuff.
393
			{
394
				$prev = $css;
395
				// Why KSES instead of strip_tags?  Who knows?
396
				$css = wp_kses_split( $css, array(), array() );
397
				$css = str_replace( '&gt;', '>', $css ); // kses replaces lone '>' with &gt;
398
				// Why both KSES and strip_tags?  Because we just added some '>'.
399
				$css = strip_tags( $css );
400
401
				if ( $css != $prev ) {
402
					$warnings[] = 'kses found stuff';
403
				}
404
			}
405
406
			// if we're not using a preprocessor
407 View Code Duplication
			if ( ! $args['preprocessor'] ) {
408
409
				/**
410
				 * Fires before parsing the css with CSSTidy, but only if
411
				 * the preprocessor is not configured for use.
412
				 *
413
				 * @module custom-css
414
				 *
415
				 * @since 1.7.0
416
				 *
417
				 * @param obj $csstidy The csstidy object.
418
				 * @param string $css Custom CSS.
419
				 * @param array $args Array of custom CSS arguments.
420
				 */
421
				do_action( 'safecss_parse_pre', $csstidy, $css, $args );
422
423
				$csstidy->parse( $css );
424
425
				/**
426
				 * Fires after parsing the css with CSSTidy, but only if
427
				 * the preprocessor is not configured for use.
428
				 *
429
				 * @module custom-css
430
				 *
431
				 * @since 1.7.0
432
				 *
433
				 * @param obj $csstidy The csstidy object.
434
				 * @param array $warnings Array of warnings.
435
				 * @param array $args Array of custom CSS arguments.
436
				 */
437
				do_action( 'safecss_parse_post', $csstidy, $warnings, $args );
438
439
				$css = $csstidy->print->plain();
440
			}
441
		}
442
		return $css;
443
	}
444
445
	/**
446
	 * Override $content_width in customizer previews.
447
	 */
448
	public static function preview_content_width() {
449
		global $wp_customize;
450
		if ( ! is_customize_preview() ) {
451
			return;
452
		}
453
454
		$setting = $wp_customize->get_setting( 'jetpack_custom_css[content_width]' );
455
		if ( ! $setting ) {
456
			return;
457
		}
458
459
		$customized_content_width = (int) $setting->post_value();
460
		if ( ! empty( $customized_content_width ) ) {
461
			$GLOBALS['content_width'] = $customized_content_width;
462
		}
463
	}
464
465
	static function style_filter( $current ) {
466
		if ( is_admin() ) {
467
			return $current;
468
		} elseif ( self::is_freetrial() && ( ! self::is_preview() || ! current_user_can( 'switch_themes' ) ) ) {
469
			return $current;
470
		} elseif ( self::skip_stylesheet() ) {
471
			/** This filter is documented in modules/custom-css/custom-css.php */
472
			return apply_filters( 'safecss_style_filter_url', plugins_url( 'custom-css/css/blank.css', __FILE__ ) );
473
		}
474
475
		return $current;
476
	}
477
478
	/**
479
	 * Determine whether or not we should have the theme skip its main stylesheet.
480
	 *
481
	 * @return mixed The truthiness of this value determines whether the stylesheet should be skipped.
482
	 */
483
	static function skip_stylesheet() {
484
		/** This filter is documented in modules/custom-css/custom-css.php */
485
		$skip_stylesheet = apply_filters( 'safecss_skip_stylesheet', null );
486
		if ( ! is_null( $skip_stylesheet ) ) {
487
			return $skip_stylesheet;
488
		}
489
490
		$jetpack_custom_css = get_theme_mod( 'jetpack_custom_css', array() );
491
		if ( isset( $jetpack_custom_css['replace'] ) ) {
492
			return $jetpack_custom_css['replace'];
493
		}
494
495
		return false;
496
	}
497
498
	/**
499
	 * Override $content_width in customizer previews.
500
	 *
501
	 * Runs on `safecss_skip_stylesheet` filter.
502
	 */
503
	public static function preview_skip_stylesheet( $skip_value ) {
504
		global $wp_customize;
505
		if ( ! is_customize_preview() ) {
506
			return $skip_value;
507
		}
508
509
		$setting = $wp_customize->get_setting( 'jetpack_custom_css[replace]' );
510
		if ( ! $setting ) {
511
			return $skip_value;
512
		}
513
514
		$customized_replace = $setting->post_value();
515
		if ( null !== $customized_replace ) {
516
			return $customized_replace;
517
		}
518
519
		return $skip_value;
520
	}
521
522
	/**
523
	 * Add Custom CSS section and controls.
524
	 */
525
	public static function customize_register( $wp_customize ) {
526
527
		// SETTINGS
528
529
		$wp_customize->add_setting( 'jetpack_custom_css[preprocessor]', array(
530
			'default' => '',
531
			'transport' => 'postMessage',
532
			'sanitize_callback' => array( __CLASS__, 'sanitize_preprocessor' ),
533
		) );
534
535
		$wp_customize->add_setting( 'jetpack_custom_css[replace]', array(
536
			'default' => false,
537
			'transport' => 'refresh',
538
		) );
539
540
		$wp_customize->add_setting( 'jetpack_custom_css[content_width]', array(
541
			'default' => '',
542
			'transport' => 'refresh',
543
			'sanitize_callback' => array( __CLASS__, 'intval_base10' ),
544
		) );
545
546
		// Add custom sanitization to the core css customizer setting.
547
		foreach ( $wp_customize->settings() as $setting ) {
548
			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...
549
				add_filter( "customize_sanitize_{$setting->id}", array( __CLASS__, 'sanitize_css_callback' ), 10, 2 );
550
			}
551
		}
552
553
		// CONTROLS
554
555
		// Overwrite the Core Control.
556
		$core_custom_css = $wp_customize->get_control( 'custom_css' );
557
		if ( $core_custom_css ) {
558
			$wp_customize->remove_control( 'custom_css' );
559
			$core_custom_css->type = 'jetpackCss';
560
			$wp_customize->add_control( $core_custom_css );
561
		}
562
563
		$wp_customize->selective_refresh->add_partial( 'custom_css', array(
564
			'type'                => 'custom_css',
565
			'selector'            => '#wp-custom-css',
566
			'container_inclusive' => false,
567
			'fallback_refresh'    => false,
568
			'settings'            => array(
569
				'custom_css[' . $wp_customize->get_stylesheet() . ']',
570
				'jetpack_custom_css[preprocessor]',
571
			),
572
			'render_callback' => array( __CLASS__, 'echo_custom_css_partial' ),
573
		) );
574
575
		$wp_customize->add_control( 'wpcom_custom_css_content_width_control', array(
576
			'type'     => 'text',
577
			'label'    => __( 'Media Width', 'jetpack' ),
578
			'section'  => 'custom_css',
579
			'settings' => 'jetpack_custom_css[content_width]',
580
		) );
581
582
		$wp_customize->add_control( 'jetpack_css_mode_control', array(
583
			'type'     => 'checkbox',
584
			'label'    => __( 'Don\'t use the theme\'s original CSS.', 'jetpack' ),
585
			'section'  => 'custom_css',
586
			'settings' => 'jetpack_custom_css[replace]',
587
		) );
588
589
		/**
590
		 * An action to grab on to if another Jetpack Module would like to add its own controls.
591
		 *
592
		 * @module custom-css
593
		 *
594
		 * @since 4.?.?
595
		 *
596
		 * @param $wp_customize The WP_Customize object.
597
		 */
598
		do_action( 'jetpack_custom_css_customizer_controls', $wp_customize );
599
600
		/** This filter is documented in modules/custom-css/custom-css.php */
601
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
602
		if ( ! empty( $preprocessors ) ) {
603
			$preprocessor_choices = array(
604
				'' => __( 'None', 'jetpack' ),
605
			);
606
607
			foreach ( $preprocessors as $preprocessor_key => $processor ) {
608
				$preprocessor_choices[$preprocessor_key] = $processor['name'];
609
			}
610
611
			$wp_customize->add_control( 'jetpack_css_preprocessors_control', array(
612
				'type'     => 'select',
613
				'choices'  => $preprocessor_choices,
614
				'label'    => __( 'Preprocessor', 'jetpack' ),
615
				'section'  => 'custom_css',
616
				'settings' => 'jetpack_custom_css[preprocessor]',
617
			) );
618
		}
619
620
	}
621
622
	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...
623
		global $wp_customize;
624
		return self::sanitize_css( $css, array(
625
			'preprocessor' => $wp_customize->get_setting('jetpack_custom_css[preprocessor]')->value(),
626
		) );
627
	}
628
629
	public static function is_freetrial() {
630
		return false;
631
	}
632
	public static function is_preview() {
633
		return false;
634
	}
635
	public static function is_customizer_preview() {
636
		return false;
637
	}
638
639
	public static function customize_preview_wp_get_custom_css( $css ) {
640
		global $wp_customize;
641
642
		$preprocessor = $wp_customize->get_setting('jetpack_custom_css[preprocessor]')->value();
643
644
		// If it's empty, just return.
645
		if ( empty( $preprocessor ) ) {
646
			return $css;
647
		}
648
649
		/** This filter is documented in modules/custom-css/custom-css.php */
650
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
651
		if ( isset( $preprocessors[ $preprocessor ] ) ) {
652
			return call_user_func( $preprocessors[ $preprocessor ]['callback'], $css );
653
		}
654
655
		return $css;
656
	}
657
658
	public static function customize_value_custom_css( $css, $setting ) {
659
		// Find the current preprocessor
660
		$jetpack_custom_css = get_theme_mod( 'jetpack_custom_css', array() );
661
		if ( isset( $jetpack_custom_css['preprocessor'] ) ) {
662
			$preprocessor = $jetpack_custom_css['preprocessor'];
663
		}
664
665
		// If it's not supported, just return.
666
		/** This filter is documented in modules/custom-css/custom-css.php */
667
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
668
		if ( ! isset( $preprocessors[ $preprocessor ] ) ) {
669
			return $css;
670
		}
671
672
		// Swap it for the `post_content_filtered` instead.
673
		$post = wp_get_custom_css_post( $setting->stylesheet );
674
		if ( $post && ! empty( $post->post_content_filtered ) ) {
675
			$css = $post->post_content_filtered;
676
		}
677
678
		return $css;
679
	}
680
681
	/**
682
	 * Soon to be deprecated as the filter moves and new function added.
683
	 */
684
	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...
685
		// Find the current preprocessor
686
		$jetpack_custom_css = get_theme_mod( 'jetpack_custom_css', array() );
687
		if ( empty( $jetpack_custom_css['preprocessor'] ) ) {
688
			return $args;
689
		}
690
691
		$preprocessor = $jetpack_custom_css['preprocessor'];
692
		/** This filter is documented in modules/custom-css/custom-css.php */
693
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
694
695
		// If it's empty, just return.
696
		if ( empty( $preprocessor ) ) {
697
			return $args;
698
		}
699
700 View Code Duplication
		if ( isset( $preprocessors[ $preprocessor ] ) ) {
701
			$args['post_content_filtered'] = $css;
702
			$args['post_content'] = call_user_func( $preprocessors[ $preprocessor ]['callback'], $css );
703
		}
704
705
		return $args;
706
	}
707
708
	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...
709
		// Find the current preprocessor
710
		$jetpack_custom_css = get_theme_mod( 'jetpack_custom_css', array() );
711
		if ( empty( $jetpack_custom_css['preprocessor'] ) ) {
712
			return $args;
713
		}
714
715
		/** This filter is documented in modules/custom-css/custom-css.php */
716
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
717
		$preprocessor = $jetpack_custom_css['preprocessor'];
718
719
		// If we have a preprocessor specified ...
720
		if ( isset( $preprocessors[ $preprocessor ] ) ) {
721
			// And no other preprocessor has run ...
722
			if ( empty( $args['preprocessed'] ) ) {
723
				$args['preprocessed'] = $args['css'];
724
				$args['css'] = call_user_func( $preprocessors[ $preprocessor ]['callback'], $args['css'] );
725
			} else {
726
				trigger_error( 'Jetpack CSS Preprocessor specified, but something else has already modified the argument.', E_USER_WARNING );
727
			}
728
		}
729
730
		return $args;
731
	}
732
733
	/**
734
	 * When on the edit screen, make sure the custom content width
735
	 * setting is applied to the large image size.
736
	 */
737 View Code Duplication
	static function editor_max_image_size( $dims, $size = 'medium', $context = null ) {
738
		list( $width, $height ) = $dims;
739
740
		if ( 'large' === $size && 'edit' === $context ) {
741
			$width = Jetpack::get_content_width();
742
		}
743
744
		return array( $width, $height );
745
	}
746
747
	/**
748
	 * Override the content_width with a custom value if one is set.
749
	 */
750
	static function jetpack_content_width( $content_width ) {
751
		$custom_content_width = 0;
752
753
		$jetpack_custom_css = get_theme_mod( 'jetpack_custom_css', array() );
754
		if ( isset( $jetpack_custom_css['content_width'] ) ) {
755
			$custom_content_width = $jetpack_custom_css['content_width'];
756
		}
757
758
		if ( $custom_content_width > 0 ) {
759
			return $custom_content_width;
760
		}
761
762
		return $content_width;
763
	}
764
765
	/**
766
	 * Currently this filter function gets called on
767
	 * 'template_redirect' action and
768
	 * 'admin_init' action
769
	 */
770 View Code Duplication
	static function set_content_width(){
771
		// Don't apply this filter on the Edit CSS page
772
		if ( isset( $_GET['page'] ) && 'editcss' === $_GET['page'] && is_admin() ) {
773
			return;
774
		}
775
776
		$GLOBALS['content_width'] = Jetpack::get_content_width();
777
	}
778
779
	/**
780
	 * Make sure the preprocessor we're saving is one we know about.
781
	 *
782
	 * @param $preprocessor The preprocessor to sanitize.
783
	 * @return null|string
784
	 */
785
	public static function sanitize_preprocessor( $preprocessor ) {
786
		/** This filter is documented in modules/custom-css/custom-css.php */
787
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
788
		if ( empty( $preprocessor ) || array_key_exists( $preprocessor, $preprocessors ) ) {
789
			return $preprocessor;
790
		}
791
		return null;
792
	}
793
794
	/**
795
	 * Get the base10 intval.
796
	 *
797
	 * This is used as a setting's sanitize_callback; we can't use just plain
798
	 * intval because the second argument is not what intval() expects.
799
	 *
800
	 * @access public
801
	 *
802
	 * @param mixed $value Number to convert.
803
	 * @return int Integer.
804
	 */
805
	public static function intval_base10( $value ) {
806
		return intval( $value, 10 );
807
	}
808
809
	public static function load_revision_php() {
810
		add_action( 'admin_footer', array( __CLASS__, 'revision_admin_footer' ) );
811
	}
812
813
	public static function revision_admin_footer() {
814
		$post = get_post();
815
		if ( 'custom_css' !== $post->post_type ) {
816
			return;
817
		}
818
		$stylesheet = $post->post_title;
819
		?>
820
<script type="text/html" id="tmpl-other-themes-switcher">
821
	<?php self::revisions_switcher_box( $stylesheet ); ?>
822
</script>
823
<style>
824
.other-themes-wrap {
825
	float: right;
826
	background-color: #fff;
827
	-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.1);
828
	box-shadow: 0 1px 3px rgba(0,0,0,0.1);
829
	padding: 5px 10px;
830
	margin-bottom: 10px;
831
}
832
.other-themes-wrap label {
833
	display: block;
834
	margin-bottom: 10px;
835
}
836
.other-themes-wrap select {
837
	float: left;
838
	width: 77%;
839
}
840
.other-themes-wrap button {
841
	float: right;
842
	width: 20%;
843
}
844
.revisions {
845
	clear: both;
846
}
847
</style>
848
<script>
849
(function($){
850
	var switcher = $('#tmpl-other-themes-switcher').html(),
851
		qty = $( switcher ).find('select option').length,
852
		$switcher;
853
854
	if ( qty >= 3 ) {
855
		$('h1.long-header').before( switcher );
856
		$switcher = $('.other-themes-wrap');
857
		$switcher.find('button').on('click', function(e){
858
			e.preventDefault();
859
			if ( $switcher.find('select').val() ) {
860
				window.location.href = $switcher.find('select').val();
861
			}
862
		})
863
	}
864
})(jQuery);
865
</script>
866
		<?php
867
	}
868
869
	public static function revisions_switcher_box( $stylesheet = '' ) {
870
		$themes = self::get_all_themes_with_custom_css();
871
		?>
872
		<div class="other-themes-wrap">
873
			<label for="other-themes"><?php esc_html_e( 'Would you like to view the revisions of another theme instead?', 'jetpack' ); ?></label>
874
			<select id="other-themes">
875
				<option value=""><?php esc_html_e( 'Select a theme&hellip;', 'jetpack' ); ?></option>
876
				<?php
877
				foreach ( $themes as $theme_stylesheet => $data ) {
878
					$revisions = wp_get_post_revisions( $data['post']->ID, array( 'posts_per_page' => 1 ) );
879
					if ( ! $revisions ) {
880
						?>
881
						<option value="<?php echo esc_url( add_query_arg( 'id', $data['post']->ID, menu_page_url( 'editcss', 0 ) ) ); ?>" <?php disabled( $stylesheet, $theme_stylesheet ); ?>>
882
							<?php echo esc_html( $data['label'] ); ?>
883
							<?php printf( esc_html__( '(modified %s ago)', 'jetpack' ), human_time_diff( strtotime( $data['post']->post_modified_gmt ) ) ); ?></option>
884
						<?php
885
						continue;
886
					}
887
					$revision = array_shift( $revisions );
888
					?>
889
					<option value="<?php echo esc_url( get_edit_post_link( $revision->ID ) ); ?>" <?php disabled( $stylesheet, $theme_stylesheet ); ?>>
890
						<?php echo esc_html( $data['label'] ); ?>
891
						<?php printf( esc_html__( '(modified %s ago)', 'jetpack' ), human_time_diff( strtotime( $data['post']->post_modified_gmt ) ) ); ?></option>
892
					<?php
893
				}
894
				?>
895
			</select>
896
			<button class="button" id="other_theme_custom_css_switcher"><?php esc_html_e( 'Switch', 'jetpack' ); ?></button>
897
		</div>
898
		<?php
899
	}
900
}
901
902
Jetpack_Custom_CSS_Enhancements::add_hooks();
903
904 View Code Duplication
if ( ! function_exists( 'safecss_class' ) ) :
905
function safecss_class() {
906
	// Wrapped so we don't need the parent class just to load the plugin
907
	if ( class_exists('safecss') ) {
908
		return;
909
	}
910
911
	require_once( dirname( __FILE__ ) . '/csstidy/class.csstidy.php' );
912
913
	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...
914
915
		function postparse() {
916
917
			/**
918
			 * Fires after parsing the css.
919
			 *
920
			 * @module custom-css
921
			 *
922
			 * @since 1.8.0
923
			 *
924
			 * @param obj $this CSSTidy object.
925
			 */
926
			do_action( 'csstidy_optimize_postparse', $this );
927
928
			return parent::postparse();
929
		}
930
931
		function subvalue() {
932
933
			/**
934
			 * Fires before optimizing the Custom CSS subvalue.
935
			 *
936
			 * @module custom-css
937
			 *
938
			 * @since 1.8.0
939
			 *
940
			 * @param obj $this CSSTidy object.
941
			 **/
942
			do_action( 'csstidy_optimize_subvalue', $this );
943
944
			return parent::subvalue();
945
		}
946
	}
947
}
948
endif;
949