Completed
Push — develop ( 6cbd2d...94cfba )
by Aristeides
18s
created

Kirki_Modules_PostMessage::script_var_array()   F

Complexity

Conditions 15
Paths 2176

Size

Total Lines 64
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 38
nc 2176
nop 1
dl 0
loc 64
rs 2.8022
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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
 * Automatic postMessage scripts calculation for Kirki controls.
4
 *
5
 * @package     Kirki
6
 * @category    Modules
7
 * @author      Aristeides Stathopoulos
8
 * @copyright   Copyright (c) 2017, Aristeides Stathopoulos
9
 * @license     http://opensource.org/licenses/https://opensource.org/licenses/MIT
10
 * @since       3.0.0
11
 */
12
13
// Exit if accessed directly.
14
if ( ! defined( 'ABSPATH' ) ) {
15
	exit;
16
}
17
18
/**
19
 * Adds styles to the customizer.
20
 */
21
class Kirki_Modules_PostMessage {
22
23
	/**
24
	 * The script.
25
	 *
26
	 * @access protected
27
	 * @since 3.0.0
28
	 * @var string
29
	 */
30
	protected $script = '';
31
32
	/**
33
	 * Constructor.
34
	 *
35
	 * @access public
36
	 * @since 3.0.0
37
	 */
38
	public function __construct() {
39
		add_action( 'customize_preview_init', array( $this, 'postmessage' ) );
40
	}
41
42
	/**
43
	 * Enqueues the postMessage script
44
	 * and adds variables to it using the wp_localize_script function.
45
	 * The rest is handled via JS.
46
	 */
47
	public function postmessage() {
48
49
		wp_enqueue_script( 'kirki_auto_postmessage', trailingslashit( Kirki::$url ) . 'modules/postmessage/postmessage.js', array( 'jquery', 'customize-preview' ), false, true );
50
		$fields = Kirki::$fields;
51
		foreach ( $fields as $field ) {
52
			if ( isset( $field['transport'] ) && 'postMessage' === $field['transport'] && isset( $field['js_vars'] ) && ! empty( $field['js_vars'] ) && is_array( $field['js_vars'] ) && isset( $field['settings'] ) ) {
53
				$this->script .= $this->script( $field );
54
			}
55
		}
56
		$this->script = apply_filters( 'kirki/postmessage/script', $this->script );
57
		wp_add_inline_script( 'kirki_auto_postmessage', $this->script, 'after' );
58
59
	}
60
61
	/**
62
	 * Generates script for a single field.
63
	 *
64
	 * @access protected
65
	 * @since 3.0.0
66
	 * @param array $args The arguments.
67
	 */
68
	protected function script( $args ) {
69
70
		$script = 'wp.customize(\'' . $args['settings'] . '\',function(value){value.bind(function(newval){';
71
		// append unique style tag if not exist
72
		// The style ID.
73
		$style_id = 'kirki-postmessage-' . str_replace( array( '[', ']' ), '', $args['settings'] );
74
		$script .= 'if(!jQuery(\'' . $style_id . '\').size()){jQuery(\'head\').append(\'<style id="' . $style_id . '"></style>\');}';
75
76
		// Add anything we need before the main script.
77
		$script .= $this->before_script( $args );
78
79
		$field = array(
80
			'scripts' => array(),
81
		);
82
		// Loop through the js_vars and generate the script.
83
		foreach ( $args['js_vars'] as $key => $js_var ) {
84
			if ( isset( $js_var['function'] ) && 'html' === $js_var['function'] ) {
85
				$script .= $this->script_html_var( $js_var );
86
				continue;
87
			}
88
			$js_var['index_key'] = $key;
89
			if ( isset( $args['function'] ) && 'html' !== $args['function'] ) {
90
				$callback = $this->get_callback( $args );
91
				if ( is_callable( $callback ) ) {
92
					$field['scripts'][ $key ] = call_user_func_array( $callback, array( $js_var, $args ) );
93
					continue;
94
				}
95
				$field['scripts'][ $key ] = $this->script_var( $js_var );
96
			}
97
		}
98
		$combo_extra_script = '';
99
		$combo_css_script   = '';
100
		foreach ( $field['scripts'] as $script_array ) {
101
			$combo_extra_script .= $script_array['script'];
102
			$combo_css_script   .= ( 'css' !== $combo_css_script ) ? $script_array['css'] : '';
103
		}
104
		$text = ( 'css' === $combo_css_script ) ? 'css' : '\'' . $combo_css_script . '\'';
105
		$script .= $combo_extra_script . 'jQuery(\'#' . $style_id . '\').text(' . $text . ');';
106
		$script .= '});});';
107
		return $script;
108
	}
109
110
	/**
111
	 * Generates script for a single js_var when using "html" as function.
112
	 *
113
	 * @access protected
114
	 * @since 3.0.0
115
	 * @param array $args  The arguments for this js_var.
116
	 */
117
	protected function script_html_var( $args ) {
118
119
		$script  = ( isset( $args['choice'] ) ) ? 'newval=newval[\'' . $args['choice'] . '\'];' : '';
120
		$script .= 'jQuery(\'' . $args['element'] . '\').html(newval);';
121
		if ( isset( $args['attr'] ) ) {
122
			$script = 'jQuery(\'' . $args['element'] . '\').attr(\'' . $args['attr'] . '\',newval);';
123
		}
124
		return $script;
125
	}
126
127
	/**
128
	 * Generates script for a single js_var.
129
	 *
130
	 * @access protected
131
	 * @since 3.0.0
132
	 * @param array $args  The arguments for this js_var.
133
	 */
134
	protected function script_var( $args ) {
135
		$script = '';
136
		$property_script = '';
137
138
		$value_key = 'newval' . $args['index_key'];
139
		$property_script .= $value_key . '=newval;';
140
141
		$args = $this->get_args( $args );
142
143
		// Apply callback to the value if a callback is defined.
144
		if ( ! empty( $args['js_callback'][0] ) ) {
145
			$script .= $value_key . '=' . $args['js_callback'][0] . '(' . $value_key . ',' . $args['js_callback'][1] . ');';
146
		}
147
148
		// Apply the value_pattern.
149
		if ( '' !== $args['value_pattern'] ) {
150
			$script .= $this->value_pattern_replacements( $value_key, $args );
151
		}
152
153
		// Tweak to add url() for background-images.
154
		if ( 'background-image' === $args['property'] ) {
155
			$script .= 'if(-1===' . $value_key . '.indexOf(\'url(\')){' . $value_key . '=\'url("\'+' . $value_key . '+\'");}';
156
		}
157
158
		// Apply prefix.
159
		$value = $value_key;
160
		if ( '' !== $args['prefix'] ) {
161
			$value = $args['prefix'] . '+' . $value_key;
162
		}
163
164
		return array(
165
			'script' => $property_script . $script,
166
			'css'    => $args['element'] . '{' . $args['property'] . ':\'+' . $value . '+\'' . $args['units'] . $args['suffix'] . ';}',
167
		);
168
	}
169
170
	/**
171
	 * Processes script generation for fields that save an array.
172
	 *
173
	 * @access protected
174
	 * @since 3.0.0
175
	 * @param array $args  The arguments for this js_var.
176
	 */
177
	protected function script_var_array( $args ) {
178
179
		$script = 'css=\'\';';
180
		$property_script = '';
181
182
		// Define choice.
183
		$choice  = ( isset( $args['choice'] ) && '' !== $args['choice'] ) ? $args['choice'] : '';
184
		$script .= ( '' !== $choice ) ? 'choice=\'' . $choice . '\';' : '';
185
186
		$value_key = 'newval' . $args['index_key'];
187
		$property_script .= $value_key . '=newval;';
188
189
		$args = $this->get_args( $args );
190
191
		// Apply callback to the value if a callback is defined.
192
		if ( ! empty( $args['js_callback'][0] ) ) {
193
			$script .= $value_key . '=' . $args['js_callback'][0] . '(' . $value_key . ',' . $args['js_callback'][1] . ');';
194
		}
195
		$script .= '_.each(' . $value_key . ', function(subValue,subKey){';
196
197
		// Apply the value_pattern.
198
		if ( '' !== $args['value_pattern'] ) {
199
			$script .= $this->value_pattern_replacements( 'subValue', $args );
200
		}
201
202
		// Tweak to add url() for background-images.
203
		if ( '' === $choice || 'background-image' === $choice ) {
204
			$script .= 'if(\'background-image\'===\'' . $args['property'] . '\'||\'background-image\'===subKey){';
205
			$script .= 'if(-1===subValue.indexOf(\'url(\')){subValue=\'url("\'+subValue+\'")\';}';
206
			$script .= '}';
207
		}
208
209
		// Apply prefix.
210
		$value = $value_key;
211
		if ( '' !== $args['prefix'] ) {
212
			$value = '\'' . $args['prefix'] . '\'+subValue';
213
		}
214
215
		// Mostly used for padding, margin & position properties.
216
		$direction_script  = 'if(_.contains([\'top\',\'bottom\',\'left\',\'right\'],subKey)){';
217
		$direction_script .= 'css+=\'' . $args['element'] . '{' . $args['property'] . '-\'+subKey+\':\'+subValue+\'' . $args['units'] . $args['suffix'] . ';}\';}';
218
		// Allows us to apply this just for a specific choice in the array of the values.
219
		if ( '' !== $choice ) {
220
			$choice_is_direction = ( false !== strpos( $choice, 'top' ) || false !== strpos( $choice, 'bottom' ) || false !== strpos( $choice, 'left' ) || false !== strpos( $choice, 'right' ) );
221
			$script .= 'choice=\'' . $choice . '\';';
222
			$script .= 'if(\'' . $choice . '\'===subKey){';
223
			$script .= ( $choice_is_direction ) ? $direction_script . 'else{' : '';
224
			$script .= 'css+=\'' . $args['element'] . '{' . $args['property'] . ':\'+subValue+\';}\';';
225
			$script .= ( $choice_is_direction ) ? '}' : '';
226
			$script .= '}';
227
		} else {
228
			$script .= $direction_script . 'else{';
229
230
			// This is where most object-based fields will go.
231
			$script .= 'css+=\'' . $args['element'] . '{\'+subKey+\':\'+subValue+\'' . $args['units'] . $args['suffix'] . ';}\';';
232
			$script .= '}';
233
		}
234
		$script .= '});';
235
236
		return array(
237
			'script' => $property_script . $script,
238
			'css'    => 'css',
239
		);
240
	}
241
242
	/**
243
	 * Processes script generation for typography fields.
244
	 *
245
	 * @access protected
246
	 * @since 3.0.0
247
	 * @param array $args  The arguments for this js_var.
248
	 */
249
	protected function script_var_typography( $args ) {
250
251
		$script = '';
252
		$css    = '';
253
254
		// Load the font using WenFontloader.
255
		// This is a bit ugly because wp_add_inline_script doesn't allow adding <script> directly.
256
		$webfont_loader = 'sc=\'a\';jQuery(\'head\').append(sc.replace(\'a\',\'<\')+\'script>if(!_.isUndefined(WebFont)){WebFont.load({google:{families:["\'+fontFamily+\':\'+variant+subsetsString+\'"]}});}\'+sc.replace(\'a\',\'<\')+\'/script>\');';
257
258
		// Add the css.
259
		$css_build_array = array(
260
			'font-family'    => 'fontFamily',
261
			'font-size'      => 'fontSize',
262
			'line-height'    => 'lineHeight',
263
			'letter-spacing' => 'letterSpacing',
264
			'word-spacing'   => 'wordSpacing',
265
			'text-align'     => 'textAlign',
266
			'text-transform' => 'textTransform',
267
			'color'          => 'color',
268
			'font-weight'    => 'fontWeight',
269
			'font-style'     => 'fontStyle',
270
		);
271
		$choice_condition = ( isset( $args['choice'] ) && '' !== $args['choice'] && isset( $css_build_array[ $args['choice'] ] ) );
272
		$script .= ( ! $choice_condition ) ? $webfont_loader : '';
273
		foreach ( $css_build_array as $property => $var ) {
274
			if ( $choice_condition && $property !== $args['choice'] ) {
275
				continue;
276
			}
277
			$script .= ( $choice_condition && 'font-family' === $args['choice'] ) ? $webfont_loader : '';
278
			$css .= 'css+=(\'\'!==' . $var . ')?\'' . $args['element'] . '\'+\'{' . $property . ':\'+' . $var . '+\'}\':\'\';';
279
		}
280
281
		$script .= $css;
282
		return array(
283
			'script' => $script,
284
			'css'    => 'css',
285
		);
286
	}
287
288
	/**
289
	 * Adds anything we need before the main script.
290
	 *
291
	 * @access private
292
	 * @since 3.0.0
293
	 * @param array $args The field args.
294
	 * @return string;
0 ignored issues
show
Documentation introduced by
The doc-type string; could not be parsed: Expected "|" or "end of type", but got ";" at position 6. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
295
	 */
296
	private function before_script( $args ) {
297
298
		$script = '';
299
300
		if ( isset( $args['type'] ) ) {
301
			switch ( $args['type'] ) {
302
				case 'kirki-typography':
303
					$script .= 'fontFamily=(_.isUndefined(newval[\'font-family\']))?\'\':newval[\'font-family\'];';
304
					$script .= 'variant=(_.isUndefined(newval.variant))?400:newval.variant;';
305
					$script .= 'subsets=(_.isUndefined(newval.subsets))?[]:newval.subsets;';
306
					$script .= 'subsetsString=(_.isObject(newval.subsets))?\':\'+newval.subsets.join(\',\'):\'\';';
307
					$script .= 'fontSize=(_.isUndefined(newval[\'font-size\']))?\'\':newval[\'font-size\'];';
308
					$script .= 'lineHeight=(_.isUndefined(newval[\'line-height\']))?\'\':newval[\'line-height\'];';
309
					$script .= 'letterSpacing=(_.isUndefined(newval[\'letter-spacing\']))?\'\':newval[\'letter-spacing\'];';
310
					$script .= 'wordSpacing=(_.isUndefined(newval[\'word-spacing\']))?\'\':newval[\'word-spacing\'];';
311
					$script .= 'textAlign=(_.isUndefined(newval[\'text-align\']))?\'\':newval[\'text-align\'];';
312
					$script .= 'textTransform=(_.isUndefined(newval[\'text-transform\']))?\'\':newval[\'text-transform\'];';
313
					$script .= 'color=(_.isUndefined(newval.color))?\'\':newval.color;';
314
					$script .= 'fontWeight=(!_.isObject(variant.match(/\d/g)))?400:variant.match(/\d/g).join(\'\');';
315
					$script .= 'fontStyle=(-1!==newval.variant.indexOf(\'italic\'))?\'italic\':\'normal\';';
316
					$script .= 'css=\'\';';
317
					break;
318
			}
319
		}
320
		return $script;
321
	}
322
323
	/**
324
	 * Sanitizes the arguments and makes sure they are all there.
325
	 *
326
	 * @access private
327
	 * @since 3.0.0
328
	 * @param array $args The arguments.
329
	 * @return array
330
	 */
331
	private function get_args( $args ) {
332
333
		// Make sure everything is defined to avoid "undefined index" errors.
334
		$args = wp_parse_args( $args, array(
335
			'element'       => '',
336
			'property'      => '',
337
			'prefix'        => '',
338
			'suffix'        => '',
339
			'units'         => '',
340
			'js_callback'   => array( '', '' ),
341
			'value_pattern' => '',
342
		));
343
344
		// Element should be a string.
345
		if ( is_array( $args['element'] ) ) {
346
			$args['element'] = implode( ',', $args['element'] );
347
		}
348
349
		// Make sure arguments that are passed-on to callbacks are strings.
350
		if ( is_array( $args['js_callback'] ) && isset( $args['js_callback'][1] ) && is_array( $args['js_callback'][1] ) ) {
351
			$args['js_callback'][1] = wp_json_encode( $args['js_callback'][1] );
352
		}
353
		return $args;
354
355
	}
356
357
	/**
358
	 * Returns script for value_pattern & replacements.
359
	 *
360
	 * @access private
361
	 * @since 3.0.0
362
	 * @param string $value   The value placeholder.
363
	 * @param array  $js_vars The js_vars argument.
364
	 * @return string         The script.
365
	 */
366
	private function value_pattern_replacements( $value, $js_vars ) {
367
		$script = '';
368
		$alias  = $value;
369
		if ( isset( $js_vars['replacements'] ) ) {
370
			$script .= 'settings=window.wp.customize.get();';
371
			foreach ( $js_vars['replacements'] as $search => $replace ) {
372
				$replace = '\'+settings["' . $replace . '"]+\'';
373
				$value = str_replace( $search, $replace, $js_vars['value_pattern'] );
374
				$value = trim( $value, '+' );
375
			}
376
		}
377
		$value_compiled = str_replace( '$', '\'+' . $alias . '+\'', $value );
378
		$value_compiled = trim( $value_compiled, '+' );
379
		return $script . $alias . '=\'' . $value_compiled . '\';';
380
	}
381
382
	/**
383
	 * Get the callback function/method we're going to use for this field.
384
	 *
385
	 * @access private
386
	 * @since 3.0.0
387
	 * @param array $args The field args.
388
	 * @return string|array A callable function or method.
389
	 */
390
	protected function get_callback( $args ) {
391
392
		switch ( $args['type'] ) {
393
			case 'kirki-background':
394
			case 'kirki-dimensions':
395
			case 'kirki-multicolor':
396
			case 'kirki-sortable':
397
				$callback = array( $this, 'script_var_array' );
398
				break;
399
			case 'kirki-typography':
400
				$callback = array( $this, 'script_var_typography' );
401
				break;
402
			default:
403
				$callback = array( $this, 'script_var' );
404
		}
405
		return $callback;
406
	}
407
}
408