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

Kirki_Output::apply_pattern_replace()   C

Complexity

Conditions 21
Paths 151

Size

Total Lines 52
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

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