Completed
Pull Request — master (#1653)
by Aristeides
04:02 queued 01:59
created

Kirki_Output::parse_output()   C

Complexity

Conditions 20
Paths 13

Size

Total Lines 57
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
eloc 29
nc 13
nop 0
dl 0
loc 57
rs 6.4409
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
 * Handles CSS output for fields.
4
 *
5
 * @package     Kirki
6
 * @subpackage  Controls
7
 * @copyright   Copyright (c) 2017, Aristeides Stathopoulos
8
 * @license     http://opensource.org/licenses/https://opensource.org/licenses/MIT
9
 * @since       2.2.0
10
 */
11
12
/**
13
 * Handles field CSS output.
14
 */
15
class Kirki_Output {
16
17
	/**
18
	 * The Kirki configuration used in the field.
19
	 *
20
	 * @access protected
21
	 * @var string
22
	 */
23
	protected $config_id = 'global';
24
25
	/**
26
	 * The field's `output` argument.
27
	 *
28
	 * @access protected
29
	 * @var array
30
	 */
31
	protected $output = array();
32
33
	/**
34
	 * An array of the generated styles.
35
	 *
36
	 * @access protected
37
	 * @var array
38
	 */
39
	protected $styles = array();
40
41
	/**
42
	 * The value.
43
	 *
44
	 * @access protected
45
	 * @var string|array
46
	 */
47
	protected $value;
48
49
	/**
50
	 * The class constructor.
51
	 *
52
	 * @access public
53
	 * @param string       $config_id The config ID.
54
	 * @param array        $output    The output argument.
55
	 * @param string|array $value     The value.
56
	 * @param array        $field     The field.
57
	 */
58
	public function __construct( $config_id, $output, $value, $field ) {
59
60
		$this->config_id = $config_id;
61
		$this->value     = $value;
62
		$this->output    = $output;
63
		$this->field     = $field;
0 ignored issues
show
Bug introduced by
The property field does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
64
65
		$this->parse_output();
66
	}
67
68
	/**
69
	 * If we have a sanitize_callback defined, apply it to the value.
70
	 *
71
	 * @param array        $output The output args.
72
	 * @param string|array $value  The value.
73
	 *
74
	 * @return string|array
75
	 */
76
	protected function apply_sanitize_callback( $output, $value ) {
77
78
		if ( isset( $output['sanitize_callback'] ) && null !== $output['sanitize_callback'] ) {
79
80
			// If the sanitize_callback is invalid, return the value.
81
			if ( ! is_callable( $output['sanitize_callback'] ) ) {
82
				return $value;
83
			}
84
			return call_user_func( $output['sanitize_callback'], $this->value );
85
		}
86
87
		return $value;
88
89
	}
90
91
	/**
92
	 * If we have a value_pattern defined, apply it to the value.
93
	 *
94
	 * @param array        $output The output args.
95
	 * @param string|array $value  The value.
96
	 * @return string|array
97
	 */
98
	protected function apply_value_pattern( $output, $value ) {
99
100
		if ( isset( $output['value_pattern'] ) && ! empty( $output['value_pattern'] ) && is_string( $output['value_pattern'] ) ) {
101
			if ( ! is_array( $value ) ) {
102
				$value = str_replace( '$', $value, $output['value_pattern'] );
103
			}
104
			if ( is_array( $value ) ) {
105
				foreach ( array_keys( $value ) as $value_k ) {
106
					if ( ! is_string( $value[ $value_k ] ) ) {
107
						continue;
108
					}
109
					if ( isset( $output['choice'] ) ) {
110
						if ( $output['choice'] === $value_k ) {
111
							$value[ $output['choice'] ] = str_replace( '$', $value[ $output['choice'] ], $output['value_pattern'] );
112
						}
113
						continue;
114
					}
115
					$value[ $value_k ] = str_replace( '$', $value[ $value_k ], $output['value_pattern'] );
116
				}
117
			}
118
			$value = $this->apply_pattern_replace( $output, $value );
119
		} // End if().
120
		return $value;
121
	}
122
123
	/**
124
	 * If we have a value_pattern defined, apply it to the value.
125
	 *
126
	 * @param array        $output The output args.
127
	 * @param string|array $value  The value.
128
	 * @return string|array
129
	 */
130
	protected function apply_pattern_replace( $output, $value ) {
131
		if ( isset( $output['pattern_replace'] ) && is_array( $output['pattern_replace'] ) ) {
132
			$option_type = ( '' !== Kirki::get_config_param( $this->config_id, 'option_type' ) ) ? Kirki::get_config_param( $this->config_id, 'option_type' ) : 'theme_mod';
133
			$option_name = Kirki::get_config_param( $this->config_id, 'option_name' );
134
			$options     = array();
135
			if ( $option_name ) {
136
				$options = ( 'site_option' === $option_type ) ? get_site_option( $option_name ) : get_option( $option_name );
137
			}
138
			foreach ( $output['pattern_replace'] as $search => $replace ) {
139
				$replacement = '';
140
				switch ( $option_type ) {
141
					case 'option':
142
						if ( is_array( $options ) ) {
143
							if ( $option_name ) {
144
								$subkey = str_replace( array( $option_name, '[', ']' ), '', $replace );
145
								$replacement = ( isset( $options[ $subkey ] ) ) ? $options[ $subkey ] : '';
146
								break;
147
							}
148
							$replacement = ( isset( $options[ $replace ] ) ) ? $options[ $replace ] : '';
149
							break;
150
						}
151
						$replacement = get_option( $replace );
152
						break;
153
					case 'site_option':
154
						$replacement = ( is_array( $options ) && isset( $options[ $replace ] ) ) ? $options[ $replace ] : get_site_option( $replace );
155
						break;
156
					case 'user_meta':
157
						$user_id = get_current_user_id();
158
						if ( $user_id ) {
159
							// @codingStandardsIgnoreLine
160
							$replacement = get_user_meta( $user_id, $replace, true );
161
						}
162
						break;
163
					default:
164
						$replacement = get_theme_mod( $replace );
165
				}
166
				$replacement = ( false === $replacement ) ? '' : $replacement;
167
				if ( is_array( $value ) ) {
168
					foreach ( $value as $k => $v ) {
169
						if ( isset( $value[ $v ] ) ) {
170
							$value[ $k ] = str_replace( $search, $replacement, $value[ $v ] );
171
						} else {
172
							$value[ $k ] = str_replace( $search, $replacement, $v );
173
						}
174
					}
175
					return $value;
176
				}
177
				$value = str_replace( $search, $replacement, $value );
178
			} // End foreach().
179
		} // End if().
180
		return $value;
181
	}
182
183
	/**
184
	 * Parses the output arguments.
185
	 * Calls the process_output method for each of them.
186
	 *
187
	 * @access protected
188
	 */
189
	protected function parse_output() {
190
		foreach ( $this->output as $output ) {
191
			$skip = false;
192
193
			// Apply any sanitization callbacks defined.
194
			$value = $this->apply_sanitize_callback( $output, $this->value );
195
196
			// Skip if value is empty.
197
			if ( '' === $this->value ) {
198
				$skip = true;
199
			}
200
201
			// No need to proceed this if the current value is the same as in the "exclude" value.
202
			if ( isset( $output['exclude'] ) && is_array( $output['exclude'] ) ) {
203
				foreach ( $output['exclude'] as $exclude ) {
204
					if ( is_array( $value ) ) {
205
						if ( is_array( $exclude ) ) {
206
							$diff1 = array_diff( $value, $exclude );
207
							$diff2 = array_diff( $exclude, $value );
208
209
							if ( empty( $diff1 ) && empty( $diff2 ) ) {
210
								$skip = true;
211
							}
212
						}
213
						// If 'choice' is defined check for sub-values too.
214
						// Fixes https://github.com/aristath/kirki/issues/1416.
215
						if ( isset( $output['choice'] ) && isset( $value[ $output['choice'] ] ) && $exclude == $value[ $output['choice'] ] ) {
216
							$skip = true;
217
						}
218
					}
219
					if ( $skip ) {
220
						continue;
221
					}
222
223
					// Skip if value is defined as excluded.
224
					if ( $exclude === $value || ( '' === $exclude && empty( $value ) ) ) {
225
						$skip = true;
226
					}
227
				}
228
			}
229
			if ( $skip ) {
230
				continue;
231
			}
232
233
			// Apply any value patterns defined.
234
			$value = $this->apply_value_pattern( $output, $value );
235
236
			if ( isset( $output['element'] ) && is_array( $output['element'] ) ) {
237
				$output['element'] = array_unique( $output['element'] );
238
				sort( $output['element'] );
239
				$output['element'] = implode( ',', $output['element'] );
240
			}
241
242
			$value = $this->process_value( $value, $output );
243
			$this->process_output( $output, $value );
244
		} // End foreach().
245
	}
246
247
	/**
248
	 * Parses an output and creates the styles array for it.
249
	 *
250
	 * @access protected
251
	 * @param array        $output The field output.
252
	 * @param string|array $value  The value.
253
	 *
254
	 * @return null
255
	 */
256
	protected function process_output( $output, $value ) {
257
		if ( ! isset( $output['element'] ) || ! isset( $output['property'] ) ) {
258
			return;
259
		}
260
		$output['media_query'] = ( isset( $output['media_query'] ) ) ? $output['media_query'] : 'global';
261
		$output['prefix']      = ( isset( $output['prefix'] ) ) ? $output['prefix'] : '';
262
		$output['units']       = ( isset( $output['units'] ) ) ? $output['units'] : '';
263
		$output['suffix']      = ( isset( $output['suffix'] ) ) ? $output['suffix'] : '';
264
265
		// Properties that can accept multiple values.
266
		// Useful for example for gradients where all browsers use the "background-image" property
267
		// and the browser prefixes go in the value_pattern arg.
268
		$accepts_multiple = array(
269
			'background-image',
270
			'background',
271
		);
272
		if ( in_array( $output['property'], $accepts_multiple, true ) ) {
273
			if ( isset( $this->styles[ $output['media_query'] ][ $output['element'] ][ $output['property'] ] ) && ! is_array( $this->styles[ $output['media_query'] ][ $output['element'] ][ $output['property'] ] ) ) {
274
				$this->styles[ $output['media_query'] ][ $output['element'] ][ $output['property'] ] = (array) $this->styles[ $output['media_query'] ][ $output['element'] ][ $output['property'] ];
275
			}
276
			$this->styles[ $output['media_query'] ][ $output['element'] ][ $output['property'] ][] = $output['prefix'] . $value . $output['units'] . $output['suffix'];
277
			return;
278
		}
279
		$this->styles[ $output['media_query'] ][ $output['element'] ][ $output['property'] ] = $output['prefix'] . $this->process_property_value( $output['property'], $value ) . $output['units'] . $output['suffix'];
280
	}
281
282
	/**
283
	 * Some CSS properties are unique.
284
	 * We need to tweak the value to make everything works as expected.
285
	 *
286
	 * @access protected
287
	 * @param string       $property The CSS property.
288
	 * @param string|array $value    The value.
289
	 *
290
	 * @return array
291
	 */
292
	protected function process_property_value( $property, $value ) {
293
		$properties = apply_filters(
294
			"kirki/{$this->config_id}/output/property-classnames", array(
295
				'font-family'         => 'Kirki_Output_Property_Font_Family',
296
				'background-image'    => 'Kirki_Output_Property_Background_Image',
297
				'background-position' => 'Kirki_Output_Property_Background_Position',
298
			)
299
		);
300
		if ( array_key_exists( $property, $properties ) ) {
301
			$classname = $properties[ $property ];
302
			$obj = new $classname( $property, $value );
303
			return $obj->get_value();
304
		}
305
		return $value;
306
	}
307
308
	/**
309
	 * Returns the value.
310
	 *
311
	 * @access protected
312
	 * @param string|array $value The value.
313
	 * @param array        $output The field "output".
314
	 * @return string|array
315
	 */
316
	protected function process_value( $value, $output ) {
317
		if ( isset( $output['property'] ) ) {
318
			return $this->process_property_value( $output['property'], $value );
319
		}
320
		return $value;
321
	}
322
323
	/**
324
	 * Exploses the private $styles property to the world
325
	 *
326
	 * @access protected
327
	 * @return array
328
	 */
329
	public function get_styles() {
330
		return $this->styles;
331
	}
332
}
333