1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Override field methods |
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.7 |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* Field overrides. |
14
|
|
|
*/ |
15
|
|
|
class Kirki_Field_Typography extends Kirki_Field { |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Sets the control type. |
19
|
|
|
* |
20
|
|
|
* @access protected |
21
|
|
|
*/ |
22
|
|
|
protected function set_type() { |
23
|
|
|
|
24
|
|
|
$this->type = 'kirki-typography'; |
25
|
|
|
|
26
|
|
|
} |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* Helper for the static sanitization. |
30
|
|
|
* |
31
|
|
|
* @static |
32
|
|
|
* @since 3.0.10 |
33
|
|
|
* @var array |
34
|
|
|
*/ |
35
|
|
|
private static $static_default = array(); |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* The class constructor. |
39
|
|
|
* Parses and sanitizes all field arguments. |
40
|
|
|
* Then it adds the field to Kirki::$fields. |
41
|
|
|
* |
42
|
|
|
* @access public |
43
|
|
|
* @param string $config_id The ID of the config we want to use. |
44
|
|
|
* Defaults to "global". |
45
|
|
|
* Configs are handled by the Kirki_Config class. |
46
|
|
|
* @param array $args The arguments of the field. |
47
|
|
|
*/ |
48
|
|
|
public function __construct( $config_id = 'global', $args = array() ) { |
49
|
|
|
parent::__construct( $config_id, $args ); |
50
|
|
|
$this->set_default(); |
51
|
|
|
self::$static_default = $this->default; |
|
|
|
|
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* Sets the default value. |
56
|
|
|
* |
57
|
|
|
* @access protected |
58
|
|
|
*/ |
59
|
|
|
protected function set_default() { |
60
|
|
|
|
61
|
|
|
// Accomodate the use of font-weight and convert to variant. |
62
|
|
|
if ( isset( $this->default['font-weight'] ) ) { |
63
|
|
|
$this->default['variant'] = ( 'regular' === $this->default['font-weight'] ) ? 400 : (string) intval( $this->default['font-weight'] ); |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
// Make sure letter-spacing has units. |
67
|
|
|
if ( isset( $this->default['letter-spacing'] ) && is_numeric( $this->default['letter-spacing'] ) && $this->default['letter-spacing'] ) { |
68
|
|
|
$this->default['letter-spacing'] .= 'px'; |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
// Make sure we use "subsets" instead of "subset". |
72
|
|
|
if ( isset( $this->default['subset'] ) && ! empty( $this->default['subset'] ) && ( ! isset( $this->default['subsets'] ) || empty( $this->default['subsets'] ) ) ) { |
73
|
|
|
$this->default['subsets'] = $this->default['subset']; |
74
|
|
|
} |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* Sets the $sanitize_callback |
79
|
|
|
* |
80
|
|
|
* @access protected |
81
|
|
|
*/ |
82
|
|
|
protected function set_sanitize_callback() { |
83
|
|
|
|
84
|
|
|
// If a custom sanitize_callback has been defined, |
85
|
|
|
// then we don't need to proceed any further. |
86
|
|
|
if ( ! empty( $this->sanitize_callback ) ) { |
87
|
|
|
return; |
88
|
|
|
} |
89
|
|
|
$this->sanitize_callback = array( __CLASS__, 'sanitize' ); |
90
|
|
|
|
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* Sets the $js_vars |
95
|
|
|
* |
96
|
|
|
* @access protected |
97
|
|
|
*/ |
98
|
|
|
protected function set_js_vars() { |
99
|
|
|
|
100
|
|
|
if ( ! is_array( $this->js_vars ) ) { |
101
|
|
|
$this->js_vars = array(); |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
// Check if transport is set to auto. |
105
|
|
|
// If not, then skip the auto-calculations and exit early. |
106
|
|
|
if ( 'auto' !== $this->transport ) { |
107
|
|
|
return; |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
// Set transport to refresh initially. |
111
|
|
|
// Serves as a fallback in case we failt to auto-calculate js_vars. |
112
|
|
|
$this->transport = 'refresh'; |
113
|
|
|
|
114
|
|
|
$js_vars = array(); |
115
|
|
|
|
116
|
|
|
// Try to auto-generate js_vars. |
117
|
|
|
// First we need to check if js_vars are empty, and that output is not empty. |
118
|
|
|
if ( ! empty( $this->output ) ) { |
119
|
|
|
|
120
|
|
|
// Start going through each item in the $output array. |
121
|
|
|
foreach ( $this->output as $output ) { |
122
|
|
|
|
123
|
|
|
// If 'element' or 'property' are not defined, skip this. |
124
|
|
|
if ( ! isset( $output['element'] ) ) { |
125
|
|
|
continue; |
126
|
|
|
} |
127
|
|
|
if ( is_array( $output['element'] ) ) { |
128
|
|
|
$output['element'] = implode( ',', $output['element'] ); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
// If we got this far, it's safe to add this. |
132
|
|
|
$js_vars[] = $output; |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
// Did we manage to get all the items from 'output'? |
136
|
|
|
// If not, then we're missing something so don't add this. |
137
|
|
|
if ( count( $js_vars ) !== count( $this->output ) ) { |
138
|
|
|
return; |
139
|
|
|
} |
140
|
|
|
$this->js_vars = $js_vars; |
141
|
|
|
$this->transport = 'postMessage'; |
142
|
|
|
|
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* Sanitizes typography controls |
149
|
|
|
* |
150
|
|
|
* @static |
151
|
|
|
* @since 2.2.0 |
152
|
|
|
* @param array $value The value. |
153
|
|
|
* @return array |
154
|
|
|
*/ |
155
|
|
|
public static function sanitize( $value ) { |
156
|
|
|
|
157
|
|
|
if ( ! is_array( $value ) ) { |
158
|
|
|
return array(); |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
foreach ( $value as $key => $val ) { |
162
|
|
|
switch ( $key ) { |
163
|
|
|
case 'font-family': |
164
|
|
|
$value['font-family'] = esc_attr( $val ); |
165
|
|
|
break; |
166
|
|
|
case 'font-weight': |
167
|
|
|
if ( isset( $value['variant'] ) ) { |
168
|
|
|
break; |
169
|
|
|
} |
170
|
|
|
$value['variant'] = $val; |
171
|
|
|
if ( isset( $value['font-style'] ) && 'italic' === $value['font-style'] ) { |
172
|
|
|
$value['variant'] = ( '400' !== $val || 400 !== $val ) ? $value['variant'] . 'italic' : 'italic'; |
173
|
|
|
} |
174
|
|
|
break; |
175
|
|
|
case 'variant': |
176
|
|
|
// Use 'regular' instead of 400 for font-variant. |
177
|
|
|
$value['variant'] = ( 400 === $val || '400' === $val ) ? 'regular' : $val; |
178
|
|
|
// Get font-weight from variant. |
179
|
|
|
$value['font-weight'] = filter_var( $value['variant'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION ); |
180
|
|
|
$value['font-weight'] = ( 'regular' === $value['variant'] || 'italic' === $value['variant'] ) ? 400 : absint( $value['font-weight'] ); |
181
|
|
|
// Get font-style from variant. |
182
|
|
|
if ( ! isset( $value['font-style'] ) ) { |
183
|
|
|
$value['font-style'] = ( false === strpos( $value['variant'], 'italic' ) ) ? 'normal' : 'italic'; |
184
|
|
|
} |
185
|
|
|
break; |
186
|
|
|
case 'subset': |
187
|
|
|
// Make sure the saved value is "subsets" (plural) and not "subset". |
188
|
|
|
// This is for compatibility with older versions. |
189
|
|
|
if ( ! empty( $value['subset'] ) && ! isset( $value['subsets'] ) || empty( $value['subset'] ) ) { |
190
|
|
|
$value['subsets'] = $value['subset']; |
191
|
|
|
} |
192
|
|
|
unset( $value['subset'] ); |
193
|
|
|
// Make sure we're using a valid subset. |
194
|
|
|
$valid_subsets = Kirki_Fonts::get_google_font_subsets(); |
195
|
|
|
$subsets_ok = array(); |
196
|
|
|
$value['subsets'] = (array) $value['subsets']; |
197
|
|
|
foreach ( $value['subsets'] as $subset ) { |
198
|
|
|
if ( array_key_exists( $subset, $valid_subsets ) ) { |
199
|
|
|
$subsets_ok[] = $subset; |
200
|
|
|
} |
201
|
|
|
} |
202
|
|
|
$value['subsets'] = $subsets_ok; |
203
|
|
|
break; |
204
|
|
|
case 'font-size': |
205
|
|
|
case 'letter-spacing': |
206
|
|
|
case 'word-spacing': |
207
|
|
|
case 'line-height': |
208
|
|
|
$value[ $key ] = Kirki_Sanitize_Values::css_dimension( $val ); |
209
|
|
|
break; |
210
|
|
|
case 'text-align': |
211
|
|
|
if ( ! in_array( $val, array( 'inherit', 'left', 'center', 'right', 'justify' ), true ) ) { |
212
|
|
|
$value['text-align'] = 'inherit'; |
213
|
|
|
} |
214
|
|
|
break; |
215
|
|
|
case 'text-transform': |
216
|
|
|
if ( ! in_array( $val, array( 'none', 'capitalize', 'uppercase', 'lowercase', 'initial', 'inherit' ), true ) ) { |
217
|
|
|
$value['text-transform'] = 'none'; |
218
|
|
|
} |
219
|
|
|
break; |
220
|
|
|
case 'color': |
221
|
|
|
$value['color'] = ariColor::newColor( $val )->toCSS( 'hex' ); |
222
|
|
|
break; |
223
|
|
|
} // End switch(). |
224
|
|
|
} // End foreach(). |
225
|
|
|
|
226
|
|
|
foreach ( array( 'font-size', 'letter-spacing', 'word-spacing', 'line-height', 'text-align', 'color' ) as $property ) { |
227
|
|
|
if ( is_array( self::$static_default ) && ! isset( self::$static_default[ $property ] ) ) { |
228
|
|
|
unset( $value[ $property ] ); |
229
|
|
|
} |
230
|
|
|
} |
231
|
|
|
return $value; |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* Sets the $choices |
236
|
|
|
* |
237
|
|
|
* @access protected |
238
|
|
|
* @since 3.0.0 |
239
|
|
|
*/ |
240
|
|
|
protected function set_choices() { |
241
|
|
|
|
242
|
|
|
if ( ! is_customize_preview() ) { |
243
|
|
|
return; |
244
|
|
|
} |
245
|
|
|
if ( ! is_array( $this->choices ) ) { |
246
|
|
|
$this->choices = array(); |
247
|
|
|
} |
248
|
|
|
$this->choices = wp_parse_args( |
249
|
|
|
$this->choices, array( |
250
|
|
|
'variant' => array(), |
251
|
|
|
'fonts' => array( |
252
|
|
|
'standard' => array(), |
253
|
|
|
'google' => array(), |
254
|
|
|
), |
255
|
|
|
) |
256
|
|
|
); |
257
|
|
|
} |
258
|
|
|
} |
259
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.