Completed
Push — custom-css-in-customizer ( 1baf74 )
by George
107:50 queued 88:17
created

Jetpack_Custom_Css_Setting   A

Complexity

Total Complexity 1

Size/Duplication

Total Lines 11
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 0
Metric Value
wmc 1
lcom 0
cbo 0
dl 0
loc 11
rs 10

1 Method

Rating   Name   Duplication   Size   Complexity  
A sanitize() 0 3 1
1
<?php
2
3
class Jetpack_Custom_CSS_Customizer {
4
	static $theme_mod_update_counter = 0;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $theme_mod_update_counter.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
5
	static $update_theme_mods = array();
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $update_theme_mods.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
6
	static $setting_order = array();
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $setting_order.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
7
8
	public static function init() {
9
	//	if ( ! CustomDesign::is_active_or_preview() ) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
10
	//		return;
11
	//	}
12
13
		if ( ! apply_filters( 'enable_custom_customizer', true ) ) {
14
			return;
15
		}
16
17
		add_filter( 'theme_mod_jetpack_custom_css', array( __CLASS__, 'theme_mod_override_jetpack_custom_css' ), 100 );
18
		add_filter( 'pre_update_option_theme_mods_' . get_stylesheet(), array( __CLASS__, 'set_theme_mod_override' ), 10, 2 );
19
20
		add_action( 'customize_register', array( __CLASS__, 'customize_register' ) );
21
		add_action( 'customize_preview_init', array( __CLASS__, 'customizer_preview_init' ) );
22
23
		add_action( 'wp_ajax_jetpack_custom_css_preprocess', array( __CLASS__, 'ajax_preprocess' ) );
24
25
		add_action( 'customize_controls_enqueue_scripts', array( __CLASS__, 'customize_controls_enqueue_scripts' ) );
26
27
		add_filter( 'safecss_skip_stylesheet', array( __CLASS__, 'preview_skip_stylesheet' ) );
28
29
		self::preview_content_width();
30
	}
31
32
	/**
33
	 * Add Custom CSS section and controls.
34
	 */
35
	public static function customize_register( $wp_customize ) {
36
		jetpack_custom_css_control_class();
37
38
		$wp_customize->add_setting( new Jetpack_Custom_Css_Setting( $wp_customize, 'jetpack_custom_css[css]', array(
39
			'default' => '',
40
			'transport' => 'postMessage',
41
		) ) );
42
43
		self::$setting_order[] = 'css';
44
45
		$wp_customize->add_setting( 'jetpack_custom_css[preprocessor]', array(
46
			'default' => '',
47
			'transport' => 'postMessage',
48
		) );
49
50
		self::$setting_order[] = 'preprocessor';
51
52
		$wp_customize->add_setting( 'jetpack_custom_css[replace]', array(
53
			'default' => false,
54
			'transport' => 'refresh',
55
		) );
56
57
		self::$setting_order[] = 'replace';
58
59
		$wp_customize->add_setting( 'jetpack_custom_css[content_width]', array(
60
			'default' => '',
61
			'transport' => 'refresh',
62
		) );
63
64
		self::$setting_order[] = 'content_width';
65
66
		$section = new WP_Customize_Section( $wp_customize, 'jetpack_custom_css', array(
67
			'title' => __( 'CSS', 'jetpack' ),
68
			'priority' => 100,
69
		) );
70
71
		$section->category = 'cat-design';
72
73
		$wp_customize->add_section( $section );
74
75
		$wp_customize->add_control( new Jetpack_Custom_CSS_Control( $wp_customize, 'jetpack_custom_css_control', array(
76
			'label' => __( 'Custom CSS', 'jetpack' ),
77
			'section' => 'jetpack_custom_css',
78
			'settings' => 'jetpack_custom_css[css]',
79
		) ) );
80
81
		$wp_customize->add_control( 'wpcom_custom_css_content_width_control', array(
82
			'type' => 'text',
83
			'label' => __( 'Media Width', 'jetpack' ),
84
			'section' => 'jetpack_custom_css',
85
			'settings' => 'jetpack_custom_css[content_width]',
86
		) );
87
88
89
		$wp_customize->add_control( 'jetpack_css_mode_control', array(
90
			'type' => 'checkbox',
91
			'label' => __( 'Don\'t use the theme\'s original CSS.', 'jetpack' ),
92
			'section' => 'jetpack_custom_css',
93
			'settings' => 'jetpack_custom_css[replace]',
94
		) );
95
96
		do_action( 'jetpack_custom_css_customizer_controls', $wp_customize );
97
98
		$preprocessors = apply_filters( 'jetpack_custom_css_preprocessors', array() );
99
100
		if ( ! empty( $preprocessors ) ) {
101
			$preprocessor_choices = array(
102
				'' => __( 'None', 'jetpack' ),
103
			);
104
105
			foreach ( $preprocessors as $preprocessor_key => $processor )
106
				$preprocessor_choices[$preprocessor_key] = $processor['name'];
107
108
			$wp_customize->add_control( 'jetpack_css_preprocessors_control', array(
109
				'type' => 'select',
110
				'choices' => $preprocessor_choices,
111
				'label' => __( 'Preprocessor', 'jetpack' ),
112
				'section' => 'jetpack_custom_css',
113
				'settings' => 'jetpack_custom_css[preprocessor]',
114
			) );
115
		}
116
	}
117
118
	/**
119
	 * JS needed for the admin portion of the Customizer.
120
	 */
121
	public static function customize_controls_enqueue_scripts() {
122
		wp_register_style( 'jetpack-css-codemirror', plugins_url( 'custom-css/css/codemirror.css', __FILE__ ), array(), '20120905' );
123
		wp_enqueue_style( 'jetpack-css-customizer-control', plugins_url( 'custom-css/css/customizer-control.css', __FILE__ ), array( 'jetpack-css-codemirror' ), '20140728' );
124
125
		wp_register_script( 'jetpack-css-codemirror', plugins_url( 'custom-css/js/codemirror.min.js', __FILE__ ), array(), '3.16', true );
126
		wp_enqueue_script( 'jetpack-css-customizer-control', plugins_url( 'custom-css/js/customizer-control.js', __FILE__ ), array( 'customize-controls', 'underscore', 'jetpack-css-codemirror' ), '20140728', true );
127
128
		$content_help = __( 'Set a different content width for full size images.', 'jetpack' );
129
		if ( ! empty( $GLOBALS['content_width'] ) ) {
130
			$current_theme = ( function_exists( 'wp_get_theme' ) ) ? wp_get_theme()->Name : get_current_theme();
131
			$content_help .= sprintf( __( ' The default content width for the <strong>%s</strong> theme is %d pixels.' ), $current_theme, intval( $GLOBALS['content_width'] ) );
132
		}
133
134
		wp_localize_script( 'jetpack-css-customizer-control', '_jp_css_settings', array(
135
			'useRichEditor' => ! jetpack_is_mobile() /*&& ! Jetpack_User_Agent_Info::is_ipad() */ && apply_filters( 'safecss_use_ace', true ),
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
136
			'areThereCssRevisions' => self::are_there_css_revisions(),
137
			'revisionsUrl' => admin_url( 'themes.php?page=editcss' ),
138
			'cssHelpUrl' => '//en.support.wordpress.com/custom-design/editing-css/',
139
			'l10n' => array(
140
				'mode' => __( 'Start Fresh' ),
141
				'mobile' => __( 'On Mobile' ),
142
				'contentWidth' => $content_help,
143
				'revisions' => __( 'CSS Revisions' ),
144
				'css_help_title' => __( 'CSS Help' )
145
			)
146
		));
147
	}
148
149
	public static function are_there_css_revisions() {
150
		$safecss_post = Jetpack_Custom_CSS::get_post();
151
		return ( ! empty( $safecss_post ) && 0 < $safecss_post['ID'] && wp_get_post_revisions( $safecss_post['ID'] ) );
152
	}
153
154
	/**
155
	 * JS needed for the preview portion of the Customizer.
156
	 */
157
	public static function customizer_preview_init() {
158
		wp_enqueue_script( 'jetpack-custom-css-customizer', plugins_url( 'custom-css/js/customize-frontend.js', __FILE__ ), array( 'customize-preview', 'underscore' ), '', true );
159
	}
160
161
	/**
162
	 * API for processing Sass/LESS.
163
	 */
164
	public static function ajax_preprocess() {
165
		echo Jetpack_Custom_CSS::minify( stripslashes( $_POST['css'] ), $_POST['preprocessor'] );
166
		die;
0 ignored issues
show
Coding Style Compatibility introduced by
The method ajax_preprocess() 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...
167
	}
168
169
	/**
170
	 * Override $content_width in customizer previews.
171
	 */
172
	public static function preview_content_width() {
173
		if ( isset( $GLOBALS['wp_customize'] ) ) {
174
			if ( isset( $_POST['customized'] ) && isset( $_POST['customize_messenger_channel'] ) ) {
175
				$customizations = json_decode( stripslashes( $_POST['customized'] ) );
176
177
				if ( isset( $customizations->{'jetpack_custom_css[content_width]'} ) ) {
178
					$width = (int) $customizations->{'jetpack_custom_css[content_width]'};
179
180
					if ( $width ) {
181
						$GLOBALS['content_width'] = $width;
182
					}
183
				}
184
			}
185
		}
186
	}
187
188
	/**
189
	 * Override $content_width in customizer previews.
190
	 */
191
	public static function preview_skip_stylesheet( $skip_value ) {
192
		if ( isset( $GLOBALS['wp_customize'] ) ) {
193
			if ( isset( $_POST['customized'] ) && isset( $_POST['customize_messenger_channel'] ) ) {
194
				$customizations = json_decode( stripslashes( $_POST['customized'] ) );
195
196
				if ( isset( $customizations->{'jetpack_custom_css[replace]'} ) ) {
197
					return $customizations->{'jetpack_custom_css[replace]'};
198
				}
199
			}
200
		}
201
202
		return $skip_value;
203
	}
204
205
	/**
206
	 * Because the Customizer only uses theme_mods or options to store
207
	 * settings, we have to do some fancy footwork to still use the custom css
208
	 * post to store all of the settings.
209
	 *
210
	 * This method overrides all calls to get_theme_mod for the jetpack_custom_css array.
211
	 */
212
	public static function theme_mod_override_jetpack_custom_css( $value ) {
0 ignored issues
show
Unused Code introduced by
The parameter $value 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...
213
		$custom_css_post_ID = Jetpack_Custom_CSS::post_id();
214
215
		$custom_content_width = get_post_meta( $custom_css_post_ID, 'content_width', true );
216
217
		// If custom content width hasn't been overridden and the theme has a content_width value, use that as a default.
218
		if ( $custom_content_width <= 0 && ! empty( $GLOBALS['content_width'] ) )
219
			$custom_content_width = $GLOBALS['content_width'];
220
221 View Code Duplication
		if ( ! $custom_content_width || ( isset( $GLOBALS['content_width'] ) && $custom_content_width == $GLOBALS['content_width'] ) )
222
			$custom_content_width = '';
223
224
		return array(
225
			'css' => Jetpack_Custom_CSS::get_css(),
226
			'replace' => ( get_post_meta( $custom_css_post_ID, 'custom_css_add', true ) == 'no' ),
227
			'preprocessor' => get_post_meta( $custom_css_post_ID, 'custom_css_preprocessor', true ),
228
			'content_width' => $custom_content_width,
229
		);
230
	}
231
232
	/**
233
	 * Like the above override for get_theme_mod, this method intercepts all calls to
234
	 * save the settings in theme_mods.
235
	 */
236
	public static function set_theme_mod_override( $newvalue, $oldvalue ) {
0 ignored issues
show
Unused Code introduced by
The parameter $oldvalue 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...
237
		static $initial_css_settings = null;
238
239
		if ( isset( $newvalue['jetpack_custom_css'] ) ) {
240
241
			if ( is_null( $initial_css_settings ) ) {
242
				add_action( 'customize_save_after', array( __CLASS__, 'complete_theme_mod_override' ), 1, 1 );
243
				$initial_css_settings = self::theme_mod_override_jetpack_custom_css( true ); // Argument is required but meaningless.
244
				self::$update_theme_mods = $initial_css_settings;
245
			}
246
247
			// Because the Customizer makes separate calls to set_theme_mod
248
			// for each key in the jetpack_custom_css array, and in each call,
249
			// only one of the values has changed, we have to track which
250
			// key is currently populated with the new value.
251
252
			foreach ( $initial_css_settings as $key => $initial_value ) {
253
				if ( $newvalue['jetpack_custom_css'][$key] != $initial_value ) {
254
					self::$update_theme_mods[$key] = $newvalue['jetpack_custom_css'][$key];
255
					break;
256
				}
257
			}
258
259
			unset( $newvalue['jetpack_custom_css'] );
260
		}
261
262
		return $newvalue;
263
	}
264
265
	/**
266
	 * After all of the CSS options have been intercepted, save the result.
267
	 */
268
	public static function complete_theme_mod_override( $customizer ) {
0 ignored issues
show
Unused Code introduced by
The parameter $customizer 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...
269
		if ( ! empty( self::$update_theme_mods ) ) {
270
			// All values have been set; save them for good.
271
			Jetpack_Custom_CSS::save( array(
272
				'css' => self::$update_theme_mods['css'],
273
				'preprocessor' => self::$update_theme_mods['preprocessor'],
274
				'add_to_existing' => ! self::$update_theme_mods['replace'],
275
				'content_width' => self::$update_theme_mods['content_width'],
276
			) );
277
		}
278
	}
279
}
280
281
function jetpack_custom_css_control_class() {
282
	if ( class_exists( 'Jetpack_Custom_CSS_Control' ) )
283
		return;
284
285
	class Jetpack_Custom_CSS_Control extends WP_Customize_Control {
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...
286
		public $type = 'jetpackCss';
287
288
		public function __construct( $manager, $id, $args = array() ) {
289
			parent::__construct( $manager, $id, $args );
290
		}
291
292
		public function render_content() {
293
			// silence is golden. do it in JS.
294
		}
295
	}
296
297
	class Jetpack_Custom_Css_Setting extends WP_Customize_Setting {
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...
298
		/**
299
		 * Override this method to prevent egregious stripslashes that are actually harmful
300
		 * to saving CSS.
301
		 * @param  string $value
302
		 * @return string
303
		 */
304
		public function sanitize( $value ) {
305
			return $value;
306
		}
307
	}
308
}
309
310
311
312
add_action( 'init', array( 'Jetpack_Custom_CSS_Customizer', 'init' ) );
313