Completed
Push — develop ( 2776d0...d2057c )
by Aristeides
02:18
created

Kirki_Fonts_Google::create_link()   C

Complexity

Conditions 10
Paths 43

Size

Total Lines 49
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 24
nc 43
nop 0
dl 0
loc 49
rs 5.5471
c 0
b 0
f 0

How to fix   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
 * Processes typography-related fields
4
 * and generates the google-font link.
5
 *
6
 * @package     Kirki
7
 * @category    Core
8
 * @author      Aristeides Stathopoulos
9
 * @copyright   Copyright (c) 2016, Aristeides Stathopoulos
10
 * @license     http://opensource.org/licenses/https://opensource.org/licenses/MIT
11
 * @since       1.0
12
 */
13
14
if ( ! class_exists( 'Kirki_Fonts_Google' ) ) {
15
16
	/**
17
	 * Manages the way Google Fonts are enqueued.
18
	 */
19
	final class Kirki_Fonts_Google {
20
21
		/**
22
		 * The Kirki_Fonts_Google instance.
23
		 * We use the singleton pattern here to avoid loading the google-font array multiple times.
24
		 * This is mostly a performance tweak.
25
		 *
26
		 * @access private
27
		 * @var null|object
28
		 */
29
		private static $instance = null;
30
31
		/**
32
		 * If set to true, forces loading ALL variants.
33
		 *
34
		 * @static
35
		 * @access public
36
		 * @var bool
37
		 */
38
		public static $force_load_all_variants = false;
39
40
		/**
41
		 * If set to true, forces loading ALL subsets.
42
		 *
43
		 * @static
44
		 * @access public
45
		 * @var bool
46
		 */
47
		public static $force_load_all_subsets = false;
48
49
		/**
50
		 * The array of fonts
51
		 *
52
		 * @access private
53
		 * @var array
54
		 */
55
		private $fonts = array();
56
57
		/**
58
		 * An array of all google fonts.
59
		 *
60
		 * @access private
61
		 * @var array
62
		 */
63
		private $google_fonts = array();
64
65
		/**
66
		 * The array of subsets
67
		 *
68
		 * @access private
69
		 * @var array
70
		 */
71
		private $subsets = array();
72
73
		/**
74
		 * The google link
75
		 *
76
		 * @access private
77
		 * @var string
78
		 */
79
		private $link = '';
80
81
		/**
82
		 * The class constructor.
83
		 */
84
		private function __construct() {
85
86
			$config = apply_filters( 'kirki/config', array() );
87
88
			// If we have set $config['disable_google_fonts'] to true then do not proceed any further.
89
			if ( isset( $config['disable_google_fonts'] ) && true === $config['disable_google_fonts'] ) {
90
				return;
91
			}
92
93
			// Populate the array of google fonts.
94
			$this->google_fonts = Kirki_Fonts::get_google_fonts();
95
96
			// Enqueue link.
97
			add_action( 'wp_enqueue_scripts', array( $this, 'enqueue' ), 105 );
98
99
		}
100
101
		/**
102
		 * Get the one, true instance of this class.
103
		 * Prevents performance issues since this is only loaded once.
104
		 *
105
		 * @return object Kirki_Fonts_Google
106
		 */
107
		public static function get_instance() {
108
			if ( null === self::$instance ) {
109
				self::$instance = new Kirki_Fonts_Google();
110
			}
111
			return self::$instance;
112
		}
113
114
		/**
115
		 * Calls all the other necessary methods to populate and create the link.
116
		 */
117
		public function enqueue() {
118
119
			// Go through our fields and populate $this->fonts.
120
			$this->loop_fields();
121
122
			$this->fonts = apply_filters( 'kirki/enqueue_google_fonts', $this->fonts );
123
124
			// Goes through $this->fonts and adds or removes things as needed.
125
			$this->process_fonts();
126
127
			// Go through $this->fonts and populate $this->link.
128
			$this->create_link();
129
130
			// If $this->link is not empty then enqueue it.
131
			if ( '' !== $this->link ) {
132
				wp_enqueue_style( 'kirki_google_fonts', $this->link, array(), null );
133
			}
134
		}
135
136
		/**
137
		 * Goes through all our fields and then populates the $this->fonts property.
138
		 */
139
		private function loop_fields() {
140
			foreach ( Kirki::$fields as $field ) {
141
				$this->generate_google_font( $field );
142
			}
143
		}
144
145
		/**
146
		 * Processes the arguments of a field
147
		 * determines if it's a typography field
148
		 * and if it is, then takes appropriate actions.
149
		 *
150
		 * @param array $args The field arguments.
151
		 */
152
		private function generate_google_font( $args ) {
153
154
			// Process typography fields.
155
			if ( isset( $args['type'] ) && 'kirki-typography' === $args['type'] ) {
156
157
				// Get the value.
158
				$value = Kirki_Values::get_sanitized_field_value( $args );
159
160
				// If we don't have a font-family then we can skip this.
161
				if ( ! isset( $value['font-family'] ) ) {
162
					return;
163
				}
164
165
				// Add support for older formats of the typography control.
166
				// We used to have font-weight instead of variant.
167
				if ( isset( $value['font-weight'] ) && ( ! isset( $value['variant'] ) || empty( $value['variant'] ) ) ) {
168
					$value['variant'] = $value['font-weight'];
169
				}
170
171
				// Set a default value for variants.
172
				if ( ! isset( $value['variant'] ) ) {
173
					$value['variant'] = 'regular';
174
				}
175
				if ( isset( $value['subsets'] ) ) {
176
177
					// Add the subset directly to the array of subsets in the Kirki_GoogleFonts_Manager object.
178
					// Subsets must be applied to ALL fonts if possible.
179
					if ( ! is_array( $value['subsets'] ) ) {
180
						$this->subsets[] = $value['subsets'];
181
					} else {
182
						foreach ( $value['subsets'] as $subset ) {
183
							$this->subsets[] = $subset;
184
						}
185
					}
186
				}
187
188
				// Add the requested google-font.
189
				if ( ! isset( $this->fonts[ $value['font-family'] ] ) ) {
190
					$this->fonts[ $value['font-family'] ] = array();
191
				}
192
				if ( ! in_array( $value['variant'], $this->fonts[ $value['font-family'] ], true ) ) {
193
					$this->fonts[ $value['font-family'] ][] = $value['variant'];
194
				}
195
			} else {
196
197
				// Process non-typography fields.
198
				if ( isset( $args['output'] ) && is_array( $args['output'] ) ) {
199
					foreach ( $args['output'] as $output ) {
200
201
						// If we don't have a typography-related output argument we can skip this.
202
						if ( ! isset( $output['property'] ) || ! in_array( $output['property'], array( 'font-family', 'font-weight', 'font-subset', 'subset', 'subsets' ), true ) ) {
203
							continue;
204
						}
205
206
						// Get the value.
207
						$value = Kirki_Values::get_sanitized_field_value( $args );
208
209
						if ( 'font-family' === $output['property'] ) {
210
							if ( ! array_key_exists( $value, $this->fonts ) ) {
211
								$this->fonts[ $value ] = array();
212
							}
213
						} elseif ( 'font-weight' === $output['property'] ) {
214
							foreach ( $this->fonts as $font => $variants ) {
215
								if ( ! in_array( $value, $variants, true ) ) {
216
									$this->fonts[ $font ][] = $value;
217
								}
218
							}
219
						} elseif ( 'font-subset' === $output['property'] || 'subset' === $output['property'] || 'subsets' === $output['property'] ) {
220
							if ( ! is_array( $value ) ) {
221
								if ( ! in_array( $value, $this->subsets, true ) ) {
222
									$this->subsets[] = $value;
223
								}
224
							} else {
225
								foreach ( $value as $subset ) {
226
									if ( ! in_array( $subset, $this->subsets, true ) ) {
227
										$this->subsets[] = $subset;
228
									}
229
								}
230
							}
231
						}
232
					}
233
				}
234
			}
235
		}
236
237
		/**
238
		 * Determines the vbalidity of the selected font as well as its properties.
239
		 * This is vital to make sure that the google-font script that we'll generate later
240
		 * does not contain any invalid options.
241
		 */
242
		private function process_fonts() {
243
244
			// Early exit if font-family is empty.
245
			if ( empty( $this->fonts ) ) {
246
				return;
247
			}
248
249
			$valid_subsets = array();
250
			foreach ( $this->fonts as $font => $variants ) {
251
252
				// Determine if this is indeed a google font or not.
253
				// If it's not, then just remove it from the array.
254
				if ( ! array_key_exists( $font, $this->google_fonts ) ) {
255
					unset( $this->fonts[ $font ] );
256
					continue;
257
				}
258
259
				// Get all valid font variants for this font.
260
				$font_variants = array();
261
				if ( isset( $this->google_fonts[ $font ]['variants'] ) ) {
262
					$font_variants = $this->google_fonts[ $font ]['variants'];
263
				}
264
				foreach ( $variants as $variant ) {
265
266
					// If this is not a valid variant for this font-family
267
					// then unset it and move on to the next one.
268
					if ( ! in_array( $variant, $font_variants, true ) ) {
269
						$variant_key = array_search( $variant, $this->fonts[ $font ] );
270
						unset( $this->fonts[ $font ][ $variant_key ] );
271
						continue;
272
					}
273
				}
274
275
				// Check if the selected subsets exist, even in one of the selected fonts.
276
				// If they don't, then they have to be removed otherwise the link will fail.
277
				if ( isset( $this->google_fonts[ $font ]['subsets'] ) ) {
278
					foreach ( $this->subsets as $subset ) {
279
						if ( in_array( $subset, $this->google_fonts[ $font ]['subsets'], true ) ) {
280
							$valid_subsets[] = $subset;
281
						}
282
					}
283
				}
284
			}
285
			$this->subsets = $valid_subsets;
286
		}
287
288
		/**
289
		 * Creates the google-fonts link.
290
		 */
291
		private function create_link() {
292
293
			// If we don't have any fonts then we can exit.
294
			if ( empty( $this->fonts ) ) {
295
				return;
296
			}
297
298
			// Add a fallback to Roboto.
299
			$font = 'Roboto';
300
301
			// Get font-family + subsets.
302
			$link_fonts = array();
303
			foreach ( $this->fonts as $font => $variants ) {
304
305
				// Are we force-loading all variants?
306
				if ( true === self::$force_load_all_variants ) {
307
					if ( isset( $this->google_fonts[ $font ]['variants'] ) ) {
308
						$variants = $this->google_fonts[ $font ]['variants'];
309
					}
310
				}
311
				$variants = implode( ',', $variants );
312
313
				$link_font = str_replace( ' ', '+', $font );
314
				if ( ! empty( $variants ) ) {
315
					$link_font .= ':' . $variants;
316
				}
317
				$link_fonts[] = $link_font;
318
			}
319
320
			// Are we force-loading all subsets?
321
			if ( true === self::$force_load_all_subsets ) {
322
323
				if ( isset( $this->google_fonts[ $font ]['subsets'] ) ) {
324
					foreach ( $this->google_fonts[ $font ]['subsets'] as $subset ) {
325
						$this->subsets[] = $subset;
326
					}
327
				}
328
			}
329
330
			if ( ! empty( $this->subsets ) ) {
331
				$this->subsets = array_unique( $this->subsets );
332
			}
333
334
			$this->link = add_query_arg( array(
335
				'family' => str_replace( '%2B', '+', urlencode( implode( '|', $link_fonts ) ) ),
336
				'subset' => urlencode( implode( ',', $this->subsets ) ),
337
			), 'https://fonts.googleapis.com/css' );
338
339
		}
340
	}
341
}
342