Completed
Push — master ( 50dc3f...5bafee )
by
unknown
49s
created
redux-core/inc/fields/typography/class-redux-typography.php 1 patch
Indentation   +1354 added lines, -1354 removed lines patch added patch discarded remove patch
@@ -12,357 +12,357 @@  discard block
 block discarded – undo
12 12
 
13 13
 if ( ! class_exists( 'Redux_Typography', false ) ) {
14 14
 
15
-	/**
16
-	 * Class Redux_Typography
17
-	 */
18
-	class Redux_Typography extends Redux_Field {
19
-
20
-		/**
21
-		 * Array of data for typography preview.
22
-		 *
23
-		 * @var array
24
-		 */
25
-		private $typography_preview = array();
26
-
27
-		/**
28
-		 *  Standard font array.
29
-		 *
30
-		 * @var array $std_fonts
31
-		 */
32
-		private $std_fonts = array(
33
-			'Arial, Helvetica, sans-serif'            => 'Arial, Helvetica, sans-serif',
34
-			'\'Arial Black\', Gadget, sans-serif'     => '\'Arial Black\', Gadget, sans-serif',
35
-			'\'Bookman Old Style\', serif'            => '\'Bookman Old Style\', serif',
36
-			'\'Comic Sans MS\', cursive'              => '\'Comic Sans MS\', cursive',
37
-			'Courier, monospace'                      => 'Courier, monospace',
38
-			'Garamond, serif'                         => 'Garamond, serif',
39
-			'Georgia, serif'                          => 'Georgia, serif',
40
-			'Impact, Charcoal, sans-serif'            => 'Impact, Charcoal, sans-serif',
41
-			'\'Lucida Console\', Monaco, monospace'   => '\'Lucida Console\', Monaco, monospace',
42
-			'\'Lucida Sans Unicode\', \'Lucida Grande\', sans-serif' => '\'Lucida Sans Unicode\', \'Lucida Grande\', sans-serif',
43
-			'\'MS Sans Serif\', Geneva, sans-serif'   => '\'MS Sans Serif\', Geneva, sans-serif',
44
-			'\'MS Serif\', \'New York\', sans-serif'  => '\'MS Serif\', \'New York\', sans-serif',
45
-			'\'Palatino Linotype\', \'Book Antiqua\', Palatino, serif' => '\'Palatino Linotype\', \'Book Antiqua\', Palatino, serif',
46
-			'Tahoma,Geneva, sans-serif'               => 'Tahoma, Geneva, sans-serif',
47
-			'\'Times New Roman\', Times,serif'        => '\'Times New Roman\', Times, serif',
48
-			'\'Trebuchet MS\', Helvetica, sans-serif' => '\'Trebuchet MS\', Helvetica, sans-serif',
49
-			'Verdana, Geneva, sans-serif'             => 'Verdana, Geneva, sans-serif',
50
-		);
51
-
52
-		/**
53
-		 * Default font weights.
54
-		 *
55
-		 * @var string[]
56
-		 */
57
-		private $default_font_weights = array(
58
-			'400'       => 'Normal 400',
59
-			'700'       => 'Bold 700',
60
-			'400italic' => 'Normal 400 Italic',
61
-			'700italic' => 'Bold 700 Italic',
62
-		);
63
-
64
-		/**
65
-		 * User font array.
66
-		 *
67
-		 * @var bool $user_fonts
68
-		 */
69
-		private $user_fonts = true;
70
-
71
-		/**
72
-		 * Redux_Field constructor.
73
-		 *
74
-		 * @param array  $field  Field array.
75
-		 * @param string $value  Field values.
76
-		 * @param null   $redux  ReduxFramework object pointer.
77
-		 *
78
-		 * @throws ReflectionException Exception.
79
-		 */
80
-		public function __construct( $field = array(), $value = null, $redux = null ) { // phpcs:ignore Generic.CodeAnalysis.UselessOverridingMethod
81
-			parent::__construct( $field, $value, $redux );
82
-
83
-			$this->parent = $redux;
84
-			$this->field  = $field;
85
-			$this->value  = $value;
86
-
87
-			$this->set_defaults();
88
-
89
-			$path_info = Redux_Helpers::path_info( __FILE__ );
90
-			$this->dir = trailingslashit( dirname( $path_info['real_path'] ) );
91
-			$this->url = trailingslashit( dirname( $path_info['url'] ) );
92
-
93
-			$this->timestamp = Redux_Core::$version;
94
-			if ( $redux->args['dev_mode'] ) {
95
-				$this->timestamp .= '.' . time();
96
-			}
97
-		}
98
-
99
-		/**
100
-		 * Sets default values for field.
101
-		 */
102
-		public function set_defaults() {
103
-			// Shim out old arg to new.
104
-			if ( isset( $this->field['all_styles'] ) && ! empty( $this->field['all_styles'] ) ) {
105
-				$this->field['all-styles'] = $this->field['all_styles'];
106
-				unset( $this->field['all_styles'] );
107
-			}
108
-
109
-			$defaults = array(
110
-				'font-family'             => true,
111
-				'font-size'               => true,
112
-				'font-weight'             => true,
113
-				'font-style'              => true,
114
-				'font-backup'             => false,
115
-				'subsets'                 => true,
116
-				'custom_fonts'            => true,
117
-				'text-align'              => true,
118
-				'text-transform'          => false,
119
-				'font-variant'            => false,
120
-				'text-decoration'         => false,
121
-				'color'                   => true,
122
-				'preview'                 => true,
123
-				'line-height'             => true,
124
-				'multi'                   => array(
125
-					'subsets' => false,
126
-					'weight'  => false,
127
-				),
128
-				'word-spacing'            => false,
129
-				'letter-spacing'          => false,
130
-				'google'                  => true,
131
-				'font_family_clear'       => true,
132
-				'allow_empty_line_height' => false,
133
-				'margin-top'              => false,
134
-				'margin-bottom'           => false,
135
-				'text-shadow'             => false,
136
-				'word-spacing-unit'       => '',
137
-				'letter-spacing-unit'     => '',
138
-				'font-size-unit'          => '',
139
-				'margin-top-unit'         => '',
140
-				'margin-bottom-unit'      => '',
141
-			);
142
-
143
-			$this->field = wp_parse_args( $this->field, $defaults );
144
-
145
-			if ( isset( $this->field['color_alpha'] ) ) {
146
-				if ( is_array( $this->field['color_alpha'] ) ) {
147
-					$this->field['color_alpha']['color']        = $this->field['color_alpha']['color'] ?? false;
148
-					$this->field['color_alpha']['shadow-color'] = $this->field['color_alpha']['shadow-color'] ?? false;
149
-				} else {
150
-					$mode                                       = $this->field['color_alpha'];
151
-					$this->field['color_alpha']                 = array();
152
-					$this->field['color_alpha']['color']        = $mode;
153
-					$this->field['color_alpha']['shadow-color'] = $mode;
154
-				}
155
-			} else {
156
-				$this->field['color_alpha']['color']        = false;
157
-				$this->field['color_alpha']['shadow-color'] = false;
158
-			}
159
-
160
-			// Set value defaults.
161
-			$defaults = array(
162
-				'font-family'       => '',
163
-				'font-options'      => '',
164
-				'font-backup'       => '',
165
-				'text-align'        => '',
166
-				'text-transform'    => '',
167
-				'font-variant'      => '',
168
-				'text-decoration'   => '',
169
-				'line-height'       => '',
170
-				'word-spacing'      => '',
171
-				'letter-spacing'    => '',
172
-				'subsets'           => '',
173
-				'google'            => false,
174
-				'font-script'       => '',
175
-				'font-weight'       => '',
176
-				'font-style'        => '',
177
-				'color'             => '',
178
-				'font-size'         => '',
179
-				'margin-top'        => '',
180
-				'margin-bottom'     => '',
181
-				'shadow-color'      => '#000000',
182
-				'shadow-horizontal' => '1',
183
-				'shadow-vertical'   => '1',
184
-				'shadow-blur'       => '4',
185
-			);
186
-
187
-			$this->value = wp_parse_args( $this->value, $defaults );
188
-
189
-			if ( empty( $this->field['units'] ) || ! in_array( $this->field['units'], Redux_Helpers::$array_units, true ) ) {
190
-				$this->field['units'] = 'px';
191
-			}
192
-
193
-			// Get the Google array.
194
-			$this->get_google_array();
195
-
196
-			if ( empty( $this->field['fonts'] ) ) {
197
-				$this->user_fonts     = false;
198
-				$this->field['fonts'] = $this->std_fonts;
199
-			}
200
-
201
-			$this->field['weights'] = $this->field['weights'] ?? $this->default_font_weights;
202
-
203
-			// Localize std fonts.
204
-			$this->localize_std_fonts();
205
-		}
206
-
207
-		/**
208
-		 * Localize font array
209
-		 *
210
-		 * @param array  $field Field array.
211
-		 * @param string $value Value.
212
-		 *
213
-		 * @return array
214
-		 */
215
-		public function localize( array $field, string $value = '' ): array {
216
-			$params = array();
217
-
218
-			if ( true === $this->user_fonts && ! empty( $this->field['fonts'] ) ) {
219
-				$params['std_font'] = $this->field['fonts'];
220
-			}
221
-
222
-			return $params;
223
-		}
224
-
225
-		/**
226
-		 * Field Render Function.
227
-		 * Takes the vars and outputs the HTML for the field in the settings
228
-		 *
229
-		 * @since ReduxFramework 1.0.0
230
-		 */
231
-		public function render() {
232
-			// Since fonts declared is CSS (@font-face) are not rendered in the preview,
233
-			// they can be declared in a CSS file and passed here, so they DO display in
234
-			// font preview.  Do NOT pass style.css in your theme, as that will mess up
235
-			// admin page styling.  It's recommended to pass a CSS file with ONLY font
236
-			// declarations.
237
-			// If field is set and not blank, then enqueue field.
238
-			if ( isset( $this->field['ext-font-css'] ) && '' !== $this->field['ext-font-css'] ) {
239
-				wp_enqueue_style( 'redux-external-fonts', $this->field['ext-font-css'], array(), $this->timestamp );
240
-			}
241
-
242
-			if ( empty( $this->field['units'] ) && ! empty( $this->field['default']['units'] ) ) {
243
-				$this->field['units'] = $this->field['default']['units'];
244
-			}
245
-
246
-			$unit = $this->field['units'];
247
-
248
-			echo '<div id="' . esc_attr( $this->field['id'] ) . '" class="redux-typography-container" data-id="' . esc_attr( $this->field['id'] ) . '" data-units="' . esc_attr( $unit ) . '">';
249
-
250
-			$this->select2_config['allowClear'] = true;
251
-
252
-			if ( isset( $this->field['select2'] ) ) {
253
-				$this->field['select2'] = wp_parse_args( $this->field['select2'], $this->select2_config );
254
-			} else {
255
-				$this->field['select2'] = $this->select2_config;
256
-			}
257
-
258
-			$this->field['select2'] = Redux_Functions::sanitize_camel_case_array_keys( $this->field['select2'] );
259
-
260
-			$select2_data = Redux_Functions::create_data_string( $this->field['select2'] );
261
-
262
-			$google_set     = false;
263
-			$is_google_font = '0';
264
-
265
-			// If no fontFamily array exists, create one and set array 0
266
-			// with font value.
267
-			if ( ! isset( $font_family ) ) {
268
-				$font_family    = array();
269
-				$font_family[0] = $this->value['font-family'];
270
-				$font_family[1] = '';
271
-			}
272
-
273
-			/* Font Family */
274
-			if ( true === $this->field['font-family'] ) {
275
-				if ( filter_var( $this->value['google'], FILTER_VALIDATE_BOOLEAN ) ) {
276
-
277
-					// Divide and conquer.
278
-					$font_family = explode( ', ', $this->value['font-family'], 2 );
279
-
280
-					// If array 0 is empty and array 1 is not.
281
-					if ( empty( $font_family[0] ) && ! empty( $font_family[1] ) ) {
282
-
283
-						// Make array 0 = array 1.
284
-						$font_family[0] = $font_family[1];
285
-					}
286
-				}
287
-
288
-				// Is selected font a Google font.
289
-				if ( isset( Redux_Core::$fonts['google'][ $font_family[0] ] ) ) {
290
-					$is_google_font = '1';
291
-				}
292
-
293
-				// If not a Google font, show all font families.
294
-				if ( '1' !== $is_google_font ) {
295
-					$font_family[0] = $this->value['font-family'];
296
-				}
297
-
298
-				$user_fonts = '0';
299
-				if ( true === $this->user_fonts ) {
300
-					$user_fonts = '1';
301
-				}
302
-
303
-				echo '<input
15
+    /**
16
+     * Class Redux_Typography
17
+     */
18
+    class Redux_Typography extends Redux_Field {
19
+
20
+        /**
21
+         * Array of data for typography preview.
22
+         *
23
+         * @var array
24
+         */
25
+        private $typography_preview = array();
26
+
27
+        /**
28
+         *  Standard font array.
29
+         *
30
+         * @var array $std_fonts
31
+         */
32
+        private $std_fonts = array(
33
+            'Arial, Helvetica, sans-serif'            => 'Arial, Helvetica, sans-serif',
34
+            '\'Arial Black\', Gadget, sans-serif'     => '\'Arial Black\', Gadget, sans-serif',
35
+            '\'Bookman Old Style\', serif'            => '\'Bookman Old Style\', serif',
36
+            '\'Comic Sans MS\', cursive'              => '\'Comic Sans MS\', cursive',
37
+            'Courier, monospace'                      => 'Courier, monospace',
38
+            'Garamond, serif'                         => 'Garamond, serif',
39
+            'Georgia, serif'                          => 'Georgia, serif',
40
+            'Impact, Charcoal, sans-serif'            => 'Impact, Charcoal, sans-serif',
41
+            '\'Lucida Console\', Monaco, monospace'   => '\'Lucida Console\', Monaco, monospace',
42
+            '\'Lucida Sans Unicode\', \'Lucida Grande\', sans-serif' => '\'Lucida Sans Unicode\', \'Lucida Grande\', sans-serif',
43
+            '\'MS Sans Serif\', Geneva, sans-serif'   => '\'MS Sans Serif\', Geneva, sans-serif',
44
+            '\'MS Serif\', \'New York\', sans-serif'  => '\'MS Serif\', \'New York\', sans-serif',
45
+            '\'Palatino Linotype\', \'Book Antiqua\', Palatino, serif' => '\'Palatino Linotype\', \'Book Antiqua\', Palatino, serif',
46
+            'Tahoma,Geneva, sans-serif'               => 'Tahoma, Geneva, sans-serif',
47
+            '\'Times New Roman\', Times,serif'        => '\'Times New Roman\', Times, serif',
48
+            '\'Trebuchet MS\', Helvetica, sans-serif' => '\'Trebuchet MS\', Helvetica, sans-serif',
49
+            'Verdana, Geneva, sans-serif'             => 'Verdana, Geneva, sans-serif',
50
+        );
51
+
52
+        /**
53
+         * Default font weights.
54
+         *
55
+         * @var string[]
56
+         */
57
+        private $default_font_weights = array(
58
+            '400'       => 'Normal 400',
59
+            '700'       => 'Bold 700',
60
+            '400italic' => 'Normal 400 Italic',
61
+            '700italic' => 'Bold 700 Italic',
62
+        );
63
+
64
+        /**
65
+         * User font array.
66
+         *
67
+         * @var bool $user_fonts
68
+         */
69
+        private $user_fonts = true;
70
+
71
+        /**
72
+         * Redux_Field constructor.
73
+         *
74
+         * @param array  $field  Field array.
75
+         * @param string $value  Field values.
76
+         * @param null   $redux  ReduxFramework object pointer.
77
+         *
78
+         * @throws ReflectionException Exception.
79
+         */
80
+        public function __construct( $field = array(), $value = null, $redux = null ) { // phpcs:ignore Generic.CodeAnalysis.UselessOverridingMethod
81
+            parent::__construct( $field, $value, $redux );
82
+
83
+            $this->parent = $redux;
84
+            $this->field  = $field;
85
+            $this->value  = $value;
86
+
87
+            $this->set_defaults();
88
+
89
+            $path_info = Redux_Helpers::path_info( __FILE__ );
90
+            $this->dir = trailingslashit( dirname( $path_info['real_path'] ) );
91
+            $this->url = trailingslashit( dirname( $path_info['url'] ) );
92
+
93
+            $this->timestamp = Redux_Core::$version;
94
+            if ( $redux->args['dev_mode'] ) {
95
+                $this->timestamp .= '.' . time();
96
+            }
97
+        }
98
+
99
+        /**
100
+         * Sets default values for field.
101
+         */
102
+        public function set_defaults() {
103
+            // Shim out old arg to new.
104
+            if ( isset( $this->field['all_styles'] ) && ! empty( $this->field['all_styles'] ) ) {
105
+                $this->field['all-styles'] = $this->field['all_styles'];
106
+                unset( $this->field['all_styles'] );
107
+            }
108
+
109
+            $defaults = array(
110
+                'font-family'             => true,
111
+                'font-size'               => true,
112
+                'font-weight'             => true,
113
+                'font-style'              => true,
114
+                'font-backup'             => false,
115
+                'subsets'                 => true,
116
+                'custom_fonts'            => true,
117
+                'text-align'              => true,
118
+                'text-transform'          => false,
119
+                'font-variant'            => false,
120
+                'text-decoration'         => false,
121
+                'color'                   => true,
122
+                'preview'                 => true,
123
+                'line-height'             => true,
124
+                'multi'                   => array(
125
+                    'subsets' => false,
126
+                    'weight'  => false,
127
+                ),
128
+                'word-spacing'            => false,
129
+                'letter-spacing'          => false,
130
+                'google'                  => true,
131
+                'font_family_clear'       => true,
132
+                'allow_empty_line_height' => false,
133
+                'margin-top'              => false,
134
+                'margin-bottom'           => false,
135
+                'text-shadow'             => false,
136
+                'word-spacing-unit'       => '',
137
+                'letter-spacing-unit'     => '',
138
+                'font-size-unit'          => '',
139
+                'margin-top-unit'         => '',
140
+                'margin-bottom-unit'      => '',
141
+            );
142
+
143
+            $this->field = wp_parse_args( $this->field, $defaults );
144
+
145
+            if ( isset( $this->field['color_alpha'] ) ) {
146
+                if ( is_array( $this->field['color_alpha'] ) ) {
147
+                    $this->field['color_alpha']['color']        = $this->field['color_alpha']['color'] ?? false;
148
+                    $this->field['color_alpha']['shadow-color'] = $this->field['color_alpha']['shadow-color'] ?? false;
149
+                } else {
150
+                    $mode                                       = $this->field['color_alpha'];
151
+                    $this->field['color_alpha']                 = array();
152
+                    $this->field['color_alpha']['color']        = $mode;
153
+                    $this->field['color_alpha']['shadow-color'] = $mode;
154
+                }
155
+            } else {
156
+                $this->field['color_alpha']['color']        = false;
157
+                $this->field['color_alpha']['shadow-color'] = false;
158
+            }
159
+
160
+            // Set value defaults.
161
+            $defaults = array(
162
+                'font-family'       => '',
163
+                'font-options'      => '',
164
+                'font-backup'       => '',
165
+                'text-align'        => '',
166
+                'text-transform'    => '',
167
+                'font-variant'      => '',
168
+                'text-decoration'   => '',
169
+                'line-height'       => '',
170
+                'word-spacing'      => '',
171
+                'letter-spacing'    => '',
172
+                'subsets'           => '',
173
+                'google'            => false,
174
+                'font-script'       => '',
175
+                'font-weight'       => '',
176
+                'font-style'        => '',
177
+                'color'             => '',
178
+                'font-size'         => '',
179
+                'margin-top'        => '',
180
+                'margin-bottom'     => '',
181
+                'shadow-color'      => '#000000',
182
+                'shadow-horizontal' => '1',
183
+                'shadow-vertical'   => '1',
184
+                'shadow-blur'       => '4',
185
+            );
186
+
187
+            $this->value = wp_parse_args( $this->value, $defaults );
188
+
189
+            if ( empty( $this->field['units'] ) || ! in_array( $this->field['units'], Redux_Helpers::$array_units, true ) ) {
190
+                $this->field['units'] = 'px';
191
+            }
192
+
193
+            // Get the Google array.
194
+            $this->get_google_array();
195
+
196
+            if ( empty( $this->field['fonts'] ) ) {
197
+                $this->user_fonts     = false;
198
+                $this->field['fonts'] = $this->std_fonts;
199
+            }
200
+
201
+            $this->field['weights'] = $this->field['weights'] ?? $this->default_font_weights;
202
+
203
+            // Localize std fonts.
204
+            $this->localize_std_fonts();
205
+        }
206
+
207
+        /**
208
+         * Localize font array
209
+         *
210
+         * @param array  $field Field array.
211
+         * @param string $value Value.
212
+         *
213
+         * @return array
214
+         */
215
+        public function localize( array $field, string $value = '' ): array {
216
+            $params = array();
217
+
218
+            if ( true === $this->user_fonts && ! empty( $this->field['fonts'] ) ) {
219
+                $params['std_font'] = $this->field['fonts'];
220
+            }
221
+
222
+            return $params;
223
+        }
224
+
225
+        /**
226
+         * Field Render Function.
227
+         * Takes the vars and outputs the HTML for the field in the settings
228
+         *
229
+         * @since ReduxFramework 1.0.0
230
+         */
231
+        public function render() {
232
+            // Since fonts declared is CSS (@font-face) are not rendered in the preview,
233
+            // they can be declared in a CSS file and passed here, so they DO display in
234
+            // font preview.  Do NOT pass style.css in your theme, as that will mess up
235
+            // admin page styling.  It's recommended to pass a CSS file with ONLY font
236
+            // declarations.
237
+            // If field is set and not blank, then enqueue field.
238
+            if ( isset( $this->field['ext-font-css'] ) && '' !== $this->field['ext-font-css'] ) {
239
+                wp_enqueue_style( 'redux-external-fonts', $this->field['ext-font-css'], array(), $this->timestamp );
240
+            }
241
+
242
+            if ( empty( $this->field['units'] ) && ! empty( $this->field['default']['units'] ) ) {
243
+                $this->field['units'] = $this->field['default']['units'];
244
+            }
245
+
246
+            $unit = $this->field['units'];
247
+
248
+            echo '<div id="' . esc_attr( $this->field['id'] ) . '" class="redux-typography-container" data-id="' . esc_attr( $this->field['id'] ) . '" data-units="' . esc_attr( $unit ) . '">';
249
+
250
+            $this->select2_config['allowClear'] = true;
251
+
252
+            if ( isset( $this->field['select2'] ) ) {
253
+                $this->field['select2'] = wp_parse_args( $this->field['select2'], $this->select2_config );
254
+            } else {
255
+                $this->field['select2'] = $this->select2_config;
256
+            }
257
+
258
+            $this->field['select2'] = Redux_Functions::sanitize_camel_case_array_keys( $this->field['select2'] );
259
+
260
+            $select2_data = Redux_Functions::create_data_string( $this->field['select2'] );
261
+
262
+            $google_set     = false;
263
+            $is_google_font = '0';
264
+
265
+            // If no fontFamily array exists, create one and set array 0
266
+            // with font value.
267
+            if ( ! isset( $font_family ) ) {
268
+                $font_family    = array();
269
+                $font_family[0] = $this->value['font-family'];
270
+                $font_family[1] = '';
271
+            }
272
+
273
+            /* Font Family */
274
+            if ( true === $this->field['font-family'] ) {
275
+                if ( filter_var( $this->value['google'], FILTER_VALIDATE_BOOLEAN ) ) {
276
+
277
+                    // Divide and conquer.
278
+                    $font_family = explode( ', ', $this->value['font-family'], 2 );
279
+
280
+                    // If array 0 is empty and array 1 is not.
281
+                    if ( empty( $font_family[0] ) && ! empty( $font_family[1] ) ) {
282
+
283
+                        // Make array 0 = array 1.
284
+                        $font_family[0] = $font_family[1];
285
+                    }
286
+                }
287
+
288
+                // Is selected font a Google font.
289
+                if ( isset( Redux_Core::$fonts['google'][ $font_family[0] ] ) ) {
290
+                    $is_google_font = '1';
291
+                }
292
+
293
+                // If not a Google font, show all font families.
294
+                if ( '1' !== $is_google_font ) {
295
+                    $font_family[0] = $this->value['font-family'];
296
+                }
297
+
298
+                $user_fonts = '0';
299
+                if ( true === $this->user_fonts ) {
300
+                    $user_fonts = '1';
301
+                }
302
+
303
+                echo '<input
304 304
 						type="hidden"
305 305
 						class="redux-typography-font-family ' . esc_attr( $this->field['class'] ) . '"
306 306
 						data-user-fonts="' . esc_attr( $user_fonts ) . '" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[font-family]"
307 307
 						value="' . esc_attr( $this->value['font-family'] ) . '"
308 308
 						data-id="' . esc_attr( $this->field['id'] ) . '"  />';
309 309
 
310
-				echo '<input
310
+                echo '<input
311 311
 						type="hidden"
312 312
 						class="redux-typography-font-options ' . esc_attr( $this->field['class'] ) . '"
313 313
 						name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[font-options]"
314 314
 						value="' . esc_attr( $this->value['font-options'] ) . '"
315 315
 						data-id="' . esc_attr( $this->field['id'] ) . '"  />';
316 316
 
317
-				echo '<input
317
+                echo '<input
318 318
 						type="hidden"
319 319
 						class="redux-typography-google-font" value="' . esc_attr( $is_google_font ) . '"
320 320
 						id="' . esc_attr( $this->field['id'] ) . '-google-font">';
321 321
 
322
-				echo '<div class="select_wrapper typography-family" style="width: 220px; margin-right: 5px;">';
323
-				echo '<label for="' . esc_attr( $this->field['id'] ) . '-family">' . esc_html__( 'Font Family', 'redux-framework' ) . '</label>';
322
+                echo '<div class="select_wrapper typography-family" style="width: 220px; margin-right: 5px;">';
323
+                echo '<label for="' . esc_attr( $this->field['id'] ) . '-family">' . esc_html__( 'Font Family', 'redux-framework' ) . '</label>';
324 324
 
325
-				$placeholder = esc_html__( 'Font family', 'redux-framework' );
325
+                $placeholder = esc_html__( 'Font family', 'redux-framework' );
326 326
 
327
-				$new_arr                = $this->field['select2'];
328
-				$new_arr['allow-clear'] = $this->field['font_family_clear'];
329
-				$new_data               = Redux_Functions::create_data_string( $new_arr );
327
+                $new_arr                = $this->field['select2'];
328
+                $new_arr['allow-clear'] = $this->field['font_family_clear'];
329
+                $new_data               = Redux_Functions::create_data_string( $new_arr );
330 330
 
331
-				echo '<select class=" redux-typography redux-typography-family select2-container ' . esc_attr( $this->field['class'] ) . '" id="' . esc_attr( $this->field['id'] ) . '-family" data-placeholder="' . esc_attr( $placeholder ) . '" data-id="' . esc_attr( $this->field['id'] ) . '" data-value="' . esc_attr( $font_family[0] ) . '"' . esc_html( $new_data ) . '>';
331
+                echo '<select class=" redux-typography redux-typography-family select2-container ' . esc_attr( $this->field['class'] ) . '" id="' . esc_attr( $this->field['id'] ) . '-family" data-placeholder="' . esc_attr( $placeholder ) . '" data-id="' . esc_attr( $this->field['id'] ) . '" data-value="' . esc_attr( $font_family[0] ) . '"' . esc_html( $new_data ) . '>';
332 332
 
333
-				echo '</select>';
334
-				echo '</div>';
333
+                echo '</select>';
334
+                echo '</div>';
335 335
 
336
-				if ( true === $this->field['google'] ) {
336
+                if ( true === $this->field['google'] ) {
337 337
 
338
-					// Set a flag, so we know to set a header style or not.
339
-					echo '<input
338
+                    // Set a flag, so we know to set a header style or not.
339
+                    echo '<input
340 340
 							type="hidden"
341 341
 							class="redux-typography-google ' . esc_attr( $this->field['class'] ) . '"
342 342
 							id="' . esc_attr( $this->field['id'] ) . '-google" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[google]"
343 343
 							type="text" value="' . esc_attr( $this->field['google'] ) . '"
344 344
 							data-id="' . esc_attr( $this->field['id'] ) . '" />';
345 345
 
346
-					$google_set = true;
347
-				}
348
-			}
346
+                    $google_set = true;
347
+                }
348
+            }
349 349
 
350
-			/* Backup Font */
351
-			if ( true === $this->field['font-family'] && true === $this->field['google'] ) {
352
-				if ( false === $google_set ) {
353
-					// Set a flag, so we know to set a header style or not.
354
-					echo '<input
350
+            /* Backup Font */
351
+            if ( true === $this->field['font-family'] && true === $this->field['google'] ) {
352
+                if ( false === $google_set ) {
353
+                    // Set a flag, so we know to set a header style or not.
354
+                    echo '<input
355 355
 							type="hidden"
356 356
 							class="redux-typography-google ' . esc_attr( $this->field['class'] ) . '"
357 357
 							id="' . esc_attr( $this->field['id'] ) . '-google" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[google]"
358 358
 							type="text" value="' . esc_attr( $this->field['google'] ) . '"
359 359
 							data-id="' . esc_attr( $this->field['id'] ) . '"  />';
360
-				}
360
+                }
361 361
 
362
-				if ( true === $this->field['font-backup'] ) {
363
-					echo '<div class="select_wrapper typography-family-backup" style="width: 220px; margin-right: 5px;">';
364
-					echo '<label for="' . esc_attr( $this->field['id'] ) . '-family-backup">' . esc_html__( 'Backup Font Family', 'redux-framework' ) . '</label>';
365
-					echo '<select
362
+                if ( true === $this->field['font-backup'] ) {
363
+                    echo '<div class="select_wrapper typography-family-backup" style="width: 220px; margin-right: 5px;">';
364
+                    echo '<label for="' . esc_attr( $this->field['id'] ) . '-family-backup">' . esc_html__( 'Backup Font Family', 'redux-framework' ) . '</label>';
365
+                    echo '<select
366 366
 							data-placeholder="' . esc_html__( 'Backup Font Family', 'redux-framework' ) . '"
367 367
 							name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[font-backup]"
368 368
 							class="redux-typography redux-typography-family-backup ' . esc_attr( $this->field['class'] ) . '"
@@ -370,62 +370,62 @@  discard block
 block discarded – undo
370 370
 							data-id="' . esc_attr( $this->field['id'] ) . '"
371 371
 							data-value="' . esc_attr( $this->value['font-backup'] ) . '"' . esc_attr( $select2_data ) . '>';
372 372
 
373
-					echo '<option data-google="false" data-details="" value=""></option>';
373
+                    echo '<option data-google="false" data-details="" value=""></option>';
374 374
 
375
-					foreach ( $this->field['fonts'] as $i => $family ) {
376
-						echo '<option data-google="true" value="' . esc_attr( $i ) . '" ' . selected( $this->value['font-backup'], $i, false ) . '>' . esc_html( $family ) . '</option>';
377
-					}
375
+                    foreach ( $this->field['fonts'] as $i => $family ) {
376
+                        echo '<option data-google="true" value="' . esc_attr( $i ) . '" ' . selected( $this->value['font-backup'], $i, false ) . '>' . esc_html( $family ) . '</option>';
377
+                    }
378 378
 
379
-					echo '</select></div>';
380
-				}
381
-			}
379
+                    echo '</select></div>';
380
+                }
381
+            }
382 382
 
383
-			/* Font Style/Weight */
384
-			if ( true === $this->field['font-style'] || true === $this->field['font-weight'] ) {
385
-				echo '<div data-weights="' . rawurlencode( wp_json_encode( $this->field['weights'] ) ) . '" class="select_wrapper typography-style" original-title="' . esc_html__( 'Font style', 'redux-framework' ) . '">';
386
-				echo '<label for="' . esc_attr( $this->field['id'] ) . '_style">' . esc_html__( 'Font Weight &amp; Style', 'redux-framework' ) . '</label>';
383
+            /* Font Style/Weight */
384
+            if ( true === $this->field['font-style'] || true === $this->field['font-weight'] ) {
385
+                echo '<div data-weights="' . rawurlencode( wp_json_encode( $this->field['weights'] ) ) . '" class="select_wrapper typography-style" original-title="' . esc_html__( 'Font style', 'redux-framework' ) . '">';
386
+                echo '<label for="' . esc_attr( $this->field['id'] ) . '_style">' . esc_html__( 'Font Weight &amp; Style', 'redux-framework' ) . '</label>';
387 387
 
388
-				$style = $this->value['font-weight'] . $this->value['font-style'];
388
+                $style = $this->value['font-weight'] . $this->value['font-style'];
389 389
 
390
-				echo '<input
390
+                echo '<input
391 391
 						type="hidden"
392 392
 						class="typography-font-weight" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[font-weight]"
393 393
 						value="' . esc_attr( $this->value['font-weight'] ) . '"
394 394
 						data-id="' . esc_attr( $this->field['id'] ) . '"  /> ';
395 395
 
396
-				echo '<input
396
+                echo '<input
397 397
 						type="hidden"
398 398
 						class="typography-font-style" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[font-style]"
399 399
 						value="' . esc_attr( $this->value['font-style'] ) . '"
400 400
 						data-id="' . esc_attr( $this->field['id'] ) . '"  /> ';
401
-				$multi = ( isset( $this->field['multi']['weight'] ) && $this->field['multi']['weight'] ) ? ' multiple="multiple"' : '';
402
-				echo '<select' . esc_html( $multi ) . '
401
+                $multi = ( isset( $this->field['multi']['weight'] ) && $this->field['multi']['weight'] ) ? ' multiple="multiple"' : '';
402
+                echo '<select' . esc_html( $multi ) . '
403 403
 				        data-placeholder="' . esc_html__( 'Style', 'redux-framework' ) . '"
404 404
 				        class="redux-typography redux-typography-style select ' . esc_attr( $this->field['class'] ) . '"
405 405
 				        original-title="' . esc_html__( 'Font style', 'redux-framework' ) . '"
406 406
 				        id="' . esc_attr( $this->field['id'] ) . '_style" data-id="' . esc_attr( $this->field['id'] ) . '"
407 407
 				        data-value="' . esc_attr( $style ) . '"' . esc_attr( $select2_data ) . '>';
408 408
 
409
-				if ( empty( $this->value['subsets'] ) || empty( $this->value['font-weight'] ) ) {
410
-					echo '<option value=""></option>';
411
-				}
409
+                if ( empty( $this->value['subsets'] ) || empty( $this->value['font-weight'] ) ) {
410
+                    echo '<option value=""></option>';
411
+                }
412 412
 
413
-				echo '</select></div>';
414
-			}
413
+                echo '</select></div>';
414
+            }
415 415
 
416
-			/* Font Script */
417
-			if ( true === $this->field['font-family'] && true === $this->field['subsets'] && true === $this->field['google'] ) {
418
-				echo '<div class="select_wrapper typography-script tooltip" original-title="' . esc_html__( 'Font subsets', 'redux-framework' ) . '">';
419
-				echo '<input
416
+            /* Font Script */
417
+            if ( true === $this->field['font-family'] && true === $this->field['subsets'] && true === $this->field['google'] ) {
418
+                echo '<div class="select_wrapper typography-script tooltip" original-title="' . esc_html__( 'Font subsets', 'redux-framework' ) . '">';
419
+                echo '<input
420 420
 						type="hidden"
421 421
 						class="typography-subsets"
422 422
 						name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[subsets]"
423 423
 						value="' . esc_attr( $this->value['subsets'] ) . '"
424 424
 						data-id="' . esc_attr( $this->field['id'] ) . '"  /> ';
425 425
 
426
-				echo '<label for="' . esc_attr( $this->field['id'] ) . '-subsets">' . esc_html__( 'Font Subsets', 'redux-framework' ) . '</label>';
427
-				$multi = ( isset( $this->field['multi']['subsets'] ) && $this->field['multi']['subsets'] ) ? ' multiple="multiple"' : '';
428
-				echo '<select' . esc_html( $multi ) . '
426
+                echo '<label for="' . esc_attr( $this->field['id'] ) . '-subsets">' . esc_html__( 'Font Subsets', 'redux-framework' ) . '</label>';
427
+                $multi = ( isset( $this->field['multi']['subsets'] ) && $this->field['multi']['subsets'] ) ? ' multiple="multiple"' : '';
428
+                echo '<select' . esc_html( $multi ) . '
429 429
 						data-placeholder="' . esc_html__( 'Subsets', 'redux-framework' ) . '"
430 430
 						class="redux-typography redux-typography-subsets ' . esc_attr( $this->field['class'] ) . '"
431 431
 						original-title="' . esc_html__( 'Font script', 'redux-framework' ) . '"
@@ -433,18 +433,18 @@  discard block
 block discarded – undo
433 433
 						data-value="' . esc_attr( $this->value['subsets'] ) . '"
434 434
 						data-id="' . esc_attr( $this->field['id'] ) . '"' . esc_attr( $select2_data ) . '>';
435 435
 
436
-				if ( empty( $this->value['subsets'] ) ) {
437
-					echo '<option value=""></option>';
438
-				}
436
+                if ( empty( $this->value['subsets'] ) ) {
437
+                    echo '<option value=""></option>';
438
+                }
439 439
 
440
-				echo '</select></div>';
441
-			}
440
+                echo '</select></div>';
441
+            }
442 442
 
443
-			/* Font Align */
444
-			if ( true === $this->field['text-align'] ) {
445
-				echo '<div class="select_wrapper typography-align tooltip" original-title="' . esc_html__( 'Text Align', 'redux-framework' ) . '">';
446
-				echo '<label for="' . esc_attr( $this->field['id'] ) . '-align">' . esc_html__( 'Text Align', 'redux-framework' ) . '</label>';
447
-				echo '<select
443
+            /* Font Align */
444
+            if ( true === $this->field['text-align'] ) {
445
+                echo '<div class="select_wrapper typography-align tooltip" original-title="' . esc_html__( 'Text Align', 'redux-framework' ) . '">';
446
+                echo '<label for="' . esc_attr( $this->field['id'] ) . '-align">' . esc_html__( 'Text Align', 'redux-framework' ) . '</label>';
447
+                echo '<select
448 448
 						data-placeholder="' . esc_html__( 'Text Align', 'redux-framework' ) . '"
449 449
 						class="redux-typography redux-typography-align ' . esc_attr( $this->field['class'] ) . '"
450 450
 						original-title="' . esc_html__( 'Text Align', 'redux-framework' ) . '"
@@ -453,29 +453,29 @@  discard block
 block discarded – undo
453 453
 						data-value="' . esc_attr( $this->value['text-align'] ) . '"
454 454
 						data-id="' . esc_attr( $this->field['id'] ) . '"' . esc_attr( $select2_data ) . '>';
455 455
 
456
-				echo '<option value=""></option>';
457
-
458
-				$align = array(
459
-					esc_html__( 'inherit', 'redux-framework' ),
460
-					esc_html__( 'left', 'redux-framework' ),
461
-					esc_html__( 'right', 'redux-framework' ),
462
-					esc_html__( 'center', 'redux-framework' ),
463
-					esc_html__( 'justify', 'redux-framework' ),
464
-					esc_html__( 'initial', 'redux-framework' ),
465
-				);
466
-
467
-				foreach ( $align as $v ) {
468
-					echo '<option value="' . esc_attr( $v ) . '" ' . selected( $this->value['text-align'], $v, false ) . '>' . esc_html( ucfirst( $v ) ) . '</option>';
469
-				}
470
-
471
-				echo '</select></div>';
472
-			}
473
-
474
-			/* Text Transform */
475
-			if ( true === $this->field['text-transform'] ) {
476
-				echo '<div class="select_wrapper typography-transform tooltip" original-title="' . esc_html__( 'Text Transform', 'redux-framework' ) . '">';
477
-				echo '<label for="' . esc_attr( $this->field['id'] ) . '-transform">' . esc_html__( 'Text Transform', 'redux-framework' ) . '</label>';
478
-				echo '<select
456
+                echo '<option value=""></option>';
457
+
458
+                $align = array(
459
+                    esc_html__( 'inherit', 'redux-framework' ),
460
+                    esc_html__( 'left', 'redux-framework' ),
461
+                    esc_html__( 'right', 'redux-framework' ),
462
+                    esc_html__( 'center', 'redux-framework' ),
463
+                    esc_html__( 'justify', 'redux-framework' ),
464
+                    esc_html__( 'initial', 'redux-framework' ),
465
+                );
466
+
467
+                foreach ( $align as $v ) {
468
+                    echo '<option value="' . esc_attr( $v ) . '" ' . selected( $this->value['text-align'], $v, false ) . '>' . esc_html( ucfirst( $v ) ) . '</option>';
469
+                }
470
+
471
+                echo '</select></div>';
472
+            }
473
+
474
+            /* Text Transform */
475
+            if ( true === $this->field['text-transform'] ) {
476
+                echo '<div class="select_wrapper typography-transform tooltip" original-title="' . esc_html__( 'Text Transform', 'redux-framework' ) . '">';
477
+                echo '<label for="' . esc_attr( $this->field['id'] ) . '-transform">' . esc_html__( 'Text Transform', 'redux-framework' ) . '</label>';
478
+                echo '<select
479 479
 						data-placeholder="' . esc_html__( 'Text Transform', 'redux-framework' ) . '"
480 480
 						class="redux-typography redux-typography-transform ' . esc_attr( $this->field['class'] ) . '"
481 481
 						original-title="' . esc_html__( 'Text Transform', 'redux-framework' ) . '"
@@ -484,29 +484,29 @@  discard block
 block discarded – undo
484 484
 						data-value="' . esc_attr( $this->value['text-transform'] ) . '"
485 485
 						data-id="' . esc_attr( $this->field['id'] ) . '"' . esc_attr( $select2_data ) . '>';
486 486
 
487
-				echo '<option value=""></option>';
488
-
489
-				$values = array(
490
-					esc_html__( 'none', 'redux-framework' ),
491
-					esc_html__( 'capitalize', 'redux-framework' ),
492
-					esc_html__( 'uppercase', 'redux-framework' ),
493
-					esc_html__( 'lowercase', 'redux-framework' ),
494
-					esc_html__( 'initial', 'redux-framework' ),
495
-					esc_html__( 'inherit', 'redux-framework' ),
496
-				);
497
-
498
-				foreach ( $values as $v ) {
499
-					echo '<option value="' . esc_attr( $v ) . '" ' . selected( $this->value['text-transform'], $v, false ) . '>' . esc_html( ucfirst( $v ) ) . '</option>';
500
-				}
501
-
502
-				echo '</select></div>';
503
-			}
504
-
505
-			/* Font Variant */
506
-			if ( true === $this->field['font-variant'] ) {
507
-				echo '<div class="select_wrapper typography-font-variant tooltip" original-title="' . esc_html__( 'Font Variant', 'redux-framework' ) . '">';
508
-				echo '<label for="' . esc_attr( $this->field['id'] ) . '-font-variant">' . esc_html__( 'Font Variant', 'redux-framework' ) . '</label>';
509
-				echo '<select
487
+                echo '<option value=""></option>';
488
+
489
+                $values = array(
490
+                    esc_html__( 'none', 'redux-framework' ),
491
+                    esc_html__( 'capitalize', 'redux-framework' ),
492
+                    esc_html__( 'uppercase', 'redux-framework' ),
493
+                    esc_html__( 'lowercase', 'redux-framework' ),
494
+                    esc_html__( 'initial', 'redux-framework' ),
495
+                    esc_html__( 'inherit', 'redux-framework' ),
496
+                );
497
+
498
+                foreach ( $values as $v ) {
499
+                    echo '<option value="' . esc_attr( $v ) . '" ' . selected( $this->value['text-transform'], $v, false ) . '>' . esc_html( ucfirst( $v ) ) . '</option>';
500
+                }
501
+
502
+                echo '</select></div>';
503
+            }
504
+
505
+            /* Font Variant */
506
+            if ( true === $this->field['font-variant'] ) {
507
+                echo '<div class="select_wrapper typography-font-variant tooltip" original-title="' . esc_html__( 'Font Variant', 'redux-framework' ) . '">';
508
+                echo '<label for="' . esc_attr( $this->field['id'] ) . '-font-variant">' . esc_html__( 'Font Variant', 'redux-framework' ) . '</label>';
509
+                echo '<select
510 510
 						data-placeholder="' . esc_html__( 'Font Variant', 'redux-framework' ) . '"
511 511
 						class="redux-typography redux-typography-font-variant ' . esc_attr( $this->field['class'] ) . '"
512 512
 						original-title="' . esc_html__( 'Font Variant', 'redux-framework' ) . '"
@@ -515,26 +515,26 @@  discard block
 block discarded – undo
515 515
 						data-value="' . esc_attr( $this->value['font-variant'] ) . '"
516 516
 						data-id="' . esc_attr( $this->field['id'] ) . '"' . esc_attr( $select2_data ) . '>';
517 517
 
518
-				echo '<option value=""></option>';
518
+                echo '<option value=""></option>';
519 519
 
520
-				$values = array(
521
-					esc_html__( 'inherit', 'redux-framework' ),
522
-					esc_html__( 'normal', 'redux-framework' ),
523
-					esc_html__( 'small-caps', 'redux-framework' ),
524
-				);
520
+                $values = array(
521
+                    esc_html__( 'inherit', 'redux-framework' ),
522
+                    esc_html__( 'normal', 'redux-framework' ),
523
+                    esc_html__( 'small-caps', 'redux-framework' ),
524
+                );
525 525
 
526
-				foreach ( $values as $v ) {
527
-					echo '<option value="' . esc_attr( $v ) . '" ' . selected( $this->value['font-variant'], $v, false ) . '>' . esc_attr( ucfirst( $v ) ) . '</option>';
528
-				}
526
+                foreach ( $values as $v ) {
527
+                    echo '<option value="' . esc_attr( $v ) . '" ' . selected( $this->value['font-variant'], $v, false ) . '>' . esc_attr( ucfirst( $v ) ) . '</option>';
528
+                }
529 529
 
530
-				echo '</select></div>';
531
-			}
530
+                echo '</select></div>';
531
+            }
532 532
 
533
-			/* Text Decoration */
534
-			if ( true === $this->field['text-decoration'] ) {
535
-				echo '<div class="select_wrapper typography-decoration tooltip" original-title="' . esc_html__( 'Text Decoration', 'redux-framework' ) . '">';
536
-				echo '<label for="' . esc_attr( $this->field['id'] ) . '-decoration">' . esc_html__( 'Text Decoration', 'redux-framework' ) . '</label>';
537
-				echo '<select
533
+            /* Text Decoration */
534
+            if ( true === $this->field['text-decoration'] ) {
535
+                echo '<div class="select_wrapper typography-decoration tooltip" original-title="' . esc_html__( 'Text Decoration', 'redux-framework' ) . '">';
536
+                echo '<label for="' . esc_attr( $this->field['id'] ) . '-decoration">' . esc_html__( 'Text Decoration', 'redux-framework' ) . '</label>';
537
+                echo '<select
538 538
 						data-placeholder="' . esc_html__( 'Text Decoration', 'redux-framework' ) . '"
539 539
 						class="redux-typography redux-typography-decoration ' . esc_attr( $this->field['class'] ) . '"
540 540
 						original-title="' . esc_html__( 'Text Decoration', 'redux-framework' ) . '"
@@ -543,32 +543,32 @@  discard block
 block discarded – undo
543 543
 						data-value="' . esc_attr( $this->value['text-decoration'] ) . '"
544 544
 						data-id="' . esc_attr( $this->field['id'] ) . '"' . esc_attr( $select2_data ) . '>';
545 545
 
546
-				echo '<option value=""></option>';
546
+                echo '<option value=""></option>';
547 547
 
548
-				$values = array(
549
-					esc_html__( 'none', 'redux-framework' ),
550
-					esc_html__( 'inherit', 'redux-framework' ),
551
-					esc_html__( 'underline', 'redux-framework' ),
552
-					esc_html__( 'overline', 'redux-framework' ),
553
-					esc_html__( 'line-through', 'redux-framework' ),
554
-					esc_html__( 'blink', 'redux-framework' ),
555
-				);
548
+                $values = array(
549
+                    esc_html__( 'none', 'redux-framework' ),
550
+                    esc_html__( 'inherit', 'redux-framework' ),
551
+                    esc_html__( 'underline', 'redux-framework' ),
552
+                    esc_html__( 'overline', 'redux-framework' ),
553
+                    esc_html__( 'line-through', 'redux-framework' ),
554
+                    esc_html__( 'blink', 'redux-framework' ),
555
+                );
556 556
 
557
-				foreach ( $values as $v ) {
558
-					echo '<option value="' . esc_attr( $v ) . '" ' . selected( $this->value['text-decoration'], $v, false ) . '>' . esc_html( ucfirst( $v ) ) . '</option>';
559
-				}
557
+                foreach ( $values as $v ) {
558
+                    echo '<option value="' . esc_attr( $v ) . '" ' . selected( $this->value['text-decoration'], $v, false ) . '>' . esc_html( ucfirst( $v ) ) . '</option>';
559
+                }
560 560
 
561
-				echo '</select></div>';
562
-			}
561
+                echo '</select></div>';
562
+            }
563 563
 
564
-			/* Font Size */
565
-			if ( true === $this->field['font-size'] ) {
566
-				$the_unit = '' !== $this->field['font-size-unit'] ? $this->field['font-size-unit'] : $unit;
564
+            /* Font Size */
565
+            if ( true === $this->field['font-size'] ) {
566
+                $the_unit = '' !== $this->field['font-size-unit'] ? $this->field['font-size-unit'] : $unit;
567 567
 
568
-				echo '<div class="input_wrapper font-size redux-container-typography">';
569
-				echo '<label for="' . esc_attr( $this->field['id'] ) . '-size">' . esc_html__( 'Font Size', 'redux-framework' ) . '</label>';
570
-				echo '<div class="input-append">';
571
-				echo '<input
568
+                echo '<div class="input_wrapper font-size redux-container-typography">';
569
+                echo '<label for="' . esc_attr( $this->field['id'] ) . '-size">' . esc_html__( 'Font Size', 'redux-framework' ) . '</label>';
570
+                echo '<div class="input-append">';
571
+                echo '<input
572 572
 						type="text"
573 573
 						class="span2 redux-typography redux-typography-size mini typography-input ' . esc_attr( $this->field['class'] ) . '"
574 574
 						title="' . esc_html__( 'Font Size', 'redux-framework' ) . '"
@@ -577,20 +577,20 @@  discard block
 block discarded – undo
577 577
 						value="' . esc_attr( str_replace( Redux_Helpers::$array_units, '', $this->value['font-size'] ) ) . '"
578 578
 						data-unit="' . esc_attr( $the_unit ) . '"
579 579
 						data-value="' . esc_attr( str_replace( Redux_Helpers::$array_units, '', $this->value['font-size'] ) ) . '">';
580
-				echo '<span class="add-on">' . esc_html( $the_unit ) . '</span>';
581
-				echo '</div>';
582
-				echo '<input type="hidden" class="typography-font-size" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[font-size]" value="' . esc_attr( $this->value['font-size'] ) . '" data-id="' . esc_attr( $this->field['id'] ) . '"/>';
583
-				echo '</div>';
584
-			}
585
-
586
-			/* Line Height */
587
-			if ( true === $this->field['line-height'] ) {
588
-				$the_unit = $this->field['line-height-unit'] ?? $unit;
589
-
590
-				echo '<div class="input_wrapper line-height redux-container-typography">';
591
-				echo '<label for="' . esc_attr( $this->field['id'] ) . '-height">' . esc_html__( 'Line Height', 'redux-framework' ) . '</label>';
592
-				echo '<div class="input-append">';
593
-				echo '<input
580
+                echo '<span class="add-on">' . esc_html( $the_unit ) . '</span>';
581
+                echo '</div>';
582
+                echo '<input type="hidden" class="typography-font-size" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[font-size]" value="' . esc_attr( $this->value['font-size'] ) . '" data-id="' . esc_attr( $this->field['id'] ) . '"/>';
583
+                echo '</div>';
584
+            }
585
+
586
+            /* Line Height */
587
+            if ( true === $this->field['line-height'] ) {
588
+                $the_unit = $this->field['line-height-unit'] ?? $unit;
589
+
590
+                echo '<div class="input_wrapper line-height redux-container-typography">';
591
+                echo '<label for="' . esc_attr( $this->field['id'] ) . '-height">' . esc_html__( 'Line Height', 'redux-framework' ) . '</label>';
592
+                echo '<div class="input-append">';
593
+                echo '<input
594 594
 						type="text"
595 595
 						class="span2 redux-typography redux-typography-height mini typography-input ' . esc_attr( $this->field['class'] ) . '"
596 596
 						title="' . esc_html__( 'Line Height', 'redux-framework' ) . '"
@@ -600,25 +600,25 @@  discard block
 block discarded – undo
600 600
 						data-allow-empty="' . esc_attr( $this->field['allow_empty_line_height'] ) . '"
601 601
 						data-unit="' . esc_attr( $the_unit ) . '"
602 602
 						data-value="' . esc_attr( str_replace( Redux_Helpers::$array_units, '', $this->value['line-height'] ) ) . '">';
603
-				echo '<span class="add-on">' . esc_html( '' === $the_unit ? '&nbsp;' : $the_unit ) . '</span>';
604
-				echo '</div>';
605
-				echo '<input
603
+                echo '<span class="add-on">' . esc_html( '' === $the_unit ? '&nbsp;' : $the_unit ) . '</span>';
604
+                echo '</div>';
605
+                echo '<input
606 606
 						type="hidden"
607 607
 						class="typography-line-height"
608 608
 						name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[line-height]"
609 609
 						value="' . esc_attr( $this->value['line-height'] ) . '"
610 610
 						data-id="' . esc_attr( $this->field['id'] ) . '"/>';
611
-				echo '</div>';
612
-			}
611
+                echo '</div>';
612
+            }
613 613
 
614
-			/* Word Spacing */
615
-			if ( true === $this->field['word-spacing'] ) {
616
-				$the_unit = '' !== $this->field['word-spacing-unit'] ? $this->field['word-spacing-unit'] : $unit;
614
+            /* Word Spacing */
615
+            if ( true === $this->field['word-spacing'] ) {
616
+                $the_unit = '' !== $this->field['word-spacing-unit'] ? $this->field['word-spacing-unit'] : $unit;
617 617
 
618
-				echo '<div class="input_wrapper word-spacing redux-container-typography">';
619
-				echo '<label for="' . esc_attr( $this->field['id'] ) . '-word">' . esc_html__( 'Word Spacing', 'redux-framework' ) . '</label>';
620
-				echo '<div class="input-append">';
621
-				echo '<input
618
+                echo '<div class="input_wrapper word-spacing redux-container-typography">';
619
+                echo '<label for="' . esc_attr( $this->field['id'] ) . '-word">' . esc_html__( 'Word Spacing', 'redux-framework' ) . '</label>';
620
+                echo '<div class="input-append">';
621
+                echo '<input
622 622
 						type="text"
623 623
 						class="span2 redux-typography redux-typography-word mini typography-input ' . esc_attr( $this->field['class'] ) . '"
624 624
 						title="' . esc_html__( 'Word Spacing', 'redux-framework' ) . '"
@@ -628,20 +628,20 @@  discard block
 block discarded – undo
628 628
 						value="' . esc_attr( str_replace( $the_unit, '', $this->value['word-spacing'] ) ) . '"
629 629
 						data-value="' . esc_attr( str_replace( $the_unit, '', $this->value['word-spacing'] ) ) . '">';
630 630
 
631
-				echo '<span class="add-on">' . esc_html( $the_unit ) . '</span>';
632
-				echo '</div>';
633
-				echo '<input type="hidden" class="typography-word-spacing" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[word-spacing] " value="' . esc_attr( $this->value['word-spacing'] ) . '" data-id="' . esc_attr( $this->field['id'] ) . '"/>';
634
-				echo '</div>';
635
-			}
631
+                echo '<span class="add-on">' . esc_html( $the_unit ) . '</span>';
632
+                echo '</div>';
633
+                echo '<input type="hidden" class="typography-word-spacing" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[word-spacing] " value="' . esc_attr( $this->value['word-spacing'] ) . '" data-id="' . esc_attr( $this->field['id'] ) . '"/>';
634
+                echo '</div>';
635
+            }
636 636
 
637
-			/* Letter Spacing */
638
-			if ( true === $this->field['letter-spacing'] ) {
639
-				$the_unit = '' !== $this->field['letter-spacing-unit'] ? $this->field['letter-spacing-unit'] : $unit;
637
+            /* Letter Spacing */
638
+            if ( true === $this->field['letter-spacing'] ) {
639
+                $the_unit = '' !== $this->field['letter-spacing-unit'] ? $this->field['letter-spacing-unit'] : $unit;
640 640
 
641
-				echo '<div class="input_wrapper letter-spacing redux-container-typography">';
642
-				echo '<label for="' . esc_attr( $this->field['id'] ) . '-letter">' . esc_html__( 'Letter Spacing', 'redux-framework' ) . '</label>';
643
-				echo '<div class="input-append">';
644
-				echo '<input
641
+                echo '<div class="input_wrapper letter-spacing redux-container-typography">';
642
+                echo '<label for="' . esc_attr( $this->field['id'] ) . '-letter">' . esc_html__( 'Letter Spacing', 'redux-framework' ) . '</label>';
643
+                echo '<div class="input-append">';
644
+                echo '<input
645 645
 						type="text"
646 646
 						class="span2 redux-typography redux-typography-letter mini typography-input ' . esc_attr( $this->field['class'] ) . '"
647 647
 						title="' . esc_html__( 'Letter Spacing', 'redux-framework' ) . '"
@@ -651,28 +651,28 @@  discard block
 block discarded – undo
651 651
 						value="' . esc_attr( str_replace( $the_unit, '', $this->value['letter-spacing'] ) ) . '"
652 652
 						data-value="' . esc_attr( str_replace( $the_unit, '', $this->value['letter-spacing'] ) ) . '">';
653 653
 
654
-				echo '<span class="add-on">' . esc_html( $the_unit ) . '</span>';
655
-				echo '</div>';
656
-				echo '<input
654
+                echo '<span class="add-on">' . esc_html( $the_unit ) . '</span>';
655
+                echo '</div>';
656
+                echo '<input
657 657
 						type="hidden"
658 658
 						class="typography-letter-spacing"
659 659
 						name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[letter-spacing]"
660 660
 						value="' . esc_attr( $this->value['letter-spacing'] ) . '"
661 661
 						data-id="' . esc_attr( $this->field['id'] ) . '"  />';
662 662
 
663
-				echo '</div>';
664
-			}
663
+                echo '</div>';
664
+            }
665 665
 
666
-			echo '<div class="clearfix"></div>';
666
+            echo '<div class="clearfix"></div>';
667 667
 
668
-			// Margins.
669
-			if ( $this->field['margin-top'] ) {
670
-				$the_unit = '' !== $this->field['margin-top-unit'] ? $this->field['margin-top-unit'] : $unit;
668
+            // Margins.
669
+            if ( $this->field['margin-top'] ) {
670
+                $the_unit = '' !== $this->field['margin-top-unit'] ? $this->field['margin-top-unit'] : $unit;
671 671
 
672
-				echo '<div class="input_wrapper margin-top redux-container-typography">';
673
-				echo '<label for="' . esc_attr( $this->field['id'] ) . '-margin-top">' . esc_html__( 'Margin Top', 'redux-framework' ) . '</label>';
674
-				echo '<div class="input-append">';
675
-				echo '<input
672
+                echo '<div class="input_wrapper margin-top redux-container-typography">';
673
+                echo '<label for="' . esc_attr( $this->field['id'] ) . '-margin-top">' . esc_html__( 'Margin Top', 'redux-framework' ) . '</label>';
674
+                echo '<div class="input-append">';
675
+                echo '<input
676 676
 						type="text"
677 677
 						class="span2 redux-typography redux-typography-margin-top mini typography-input ' . esc_attr( $this->field['class'] ) . '"
678 678
 						title="' . esc_html__( 'Margin Top', 'redux-framework' ) . '"
@@ -681,25 +681,25 @@  discard block
 block discarded – undo
681 681
 						data-unit="' . esc_attr( $the_unit ) . '"
682 682
 						value="' . esc_attr( str_replace( $the_unit, '', $this->value['margin-top'] ) ) . '"
683 683
 						data-value="' . esc_attr( str_replace( $the_unit, '', $this->value['margin-top'] ) ) . '">';
684
-				echo '<span class="add-on">' . esc_html( $the_unit ) . '</span>';
685
-				echo '</div>';
686
-				echo '<input
684
+                echo '<span class="add-on">' . esc_html( $the_unit ) . '</span>';
685
+                echo '</div>';
686
+                echo '<input
687 687
 						type="hidden"
688 688
 						class="typography-margin-top"
689 689
 						name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[margin-top]"
690 690
 						value="' . esc_attr( $this->value['margin-top'] ) . '"
691 691
 						data-id="' . esc_attr( $this->field['id'] ) . '"  />';
692
-				echo '</div>';
693
-			}
692
+                echo '</div>';
693
+            }
694 694
 
695
-			/* Bottom Margin */
696
-			if ( $this->field['margin-bottom'] ) {
697
-				$the_unit = '' !== $this->field['margin-bottom-unit'] ? $this->field['margin-bottom-unit'] : $unit;
695
+            /* Bottom Margin */
696
+            if ( $this->field['margin-bottom'] ) {
697
+                $the_unit = '' !== $this->field['margin-bottom-unit'] ? $this->field['margin-bottom-unit'] : $unit;
698 698
 
699
-				echo '<div class="input_wrapper margin-bottom redux-container-typography">';
700
-				echo '<label for="' . esc_attr( $this->field['id'] ) . '-margin-bottom">' . esc_html__( 'Margin Bottom', 'redux-framework' ) . '</label>';
701
-				echo '<div class="input-append">';
702
-				echo '<input
699
+                echo '<div class="input_wrapper margin-bottom redux-container-typography">';
700
+                echo '<label for="' . esc_attr( $this->field['id'] ) . '-margin-bottom">' . esc_html__( 'Margin Bottom', 'redux-framework' ) . '</label>';
701
+                echo '<div class="input-append">';
702
+                echo '<input
703 703
 						type="text"
704 704
 						class="span2 redux-typography redux-typography-margin-bottom mini typography-input ' . esc_attr( $this->field['class'] ) . '"
705 705
 						title="' . esc_html__( 'Margin Bottom', 'redux-framework' ) . '"
@@ -708,106 +708,106 @@  discard block
 block discarded – undo
708 708
 						data-unit="' . esc_attr( $the_unit ) . '"
709 709
 						value="' . esc_attr( str_replace( $the_unit, '', $this->value['margin-bottom'] ) ) . '"
710 710
 						data-value="' . esc_attr( str_replace( $the_unit, '', $this->value['margin-bottom'] ) ) . '">';
711
-				echo '<span class="add-on">' . esc_html( $the_unit ) . '</span>';
712
-				echo '</div>';
713
-				echo '<input type="hidden" class="typography-margin-bottom" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[margin-bottom]" value="' . esc_attr( $this->value['margin-bottom'] ) . '" data-id="' . esc_attr( $this->field['id'] ) . '"  />';
714
-				echo '</div>';
715
-			}
716
-
717
-			if ( $this->field['margin-top'] || $this->field['margin-bottom'] ) {
718
-				echo '<div class="clearfix"></div>';
719
-			}
720
-
721
-			/* Font Color */
722
-			if ( true === $this->field['color'] ) {
723
-				$default = '';
724
-
725
-				if ( empty( $this->field['default']['color'] ) && ! empty( $this->field['color'] ) ) {
726
-					$default = $this->value['color'];
727
-				} elseif ( ! empty( $this->field['default']['color'] ) ) {
728
-					$default = $this->field['default']['color'];
729
-				}
730
-
731
-				echo '<div class="picker-wrapper">';
732
-				echo '<label for="' . esc_attr( $this->field['id'] ) . '-color">' . esc_html__( 'Font Color', 'redux-framework' ) . '</label>';
733
-				echo '<div id="' . esc_attr( $this->field['id'] ) . '_color_picker" class="colorSelector typography-color">';
734
-				echo '<div style="background-color: ' . esc_attr( $this->value['color'] ) . '"></div>';
735
-				echo '</div>';
736
-				echo '<input ';
737
-				echo 'data-default-color="' . esc_attr( $default ) . '"';
738
-				echo 'class="color-picker redux-color redux-typography-color ' . esc_attr( $this->field['class'] ) . '"';
739
-				echo 'original-title="' . esc_html__( 'Font color', 'redux-framework' ) . '"';
740
-				echo 'id="' . esc_attr( $this->field['id'] ) . '-color"';
741
-				echo 'name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[color]"';
742
-				echo 'type="text"';
743
-				echo 'value="' . esc_attr( $this->value['color'] ) . '"';
744
-				echo 'data-id="' . esc_attr( $this->field['id'] ) . '"';
745
-
746
-				$data = array(
747
-					'field' => $this->field,
748
-					'index' => 'color',
749
-				);
750
-
751
-				echo Redux_Functions_Ex::output_alpha_data( $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
752
-
753
-				echo '>';
754
-				echo '</div>';
755
-			}
756
-
757
-			echo '<div class="clearfix"></div>';
758
-
759
-			/* Font Preview */
760
-			if ( ! isset( $this->field['preview'] ) || false !== $this->field['preview'] ) {
761
-				$g_text = $this->field['preview']['text'] ?? '1 2 3 4 5 6 7 8 9 0 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z';
762
-
763
-				$style = '';
764
-				if ( isset( $this->field['preview']['always_display'] ) ) {
765
-					if ( true === filter_var( $this->field['preview']['always_display'], FILTER_VALIDATE_BOOLEAN ) ) {
766
-						if ( true === (bool) $is_google_font ) {
767
-							$this->typography_preview[ $font_family[0] ] = array(
768
-								'font-style' => array( $this->value['font-weight'] . $this->value['font-style'] ),
769
-								'subset'     => array( $this->value['subsets'] ),
770
-							);
771
-
772
-							wp_deregister_style( 'redux-typography-preview' );
773
-							wp_dequeue_style( 'redux-typography-preview' );
774
-
775
-							wp_enqueue_style( 'redux-typography-preview', $this->make_google_web_font_link( $this->typography_preview ), array(), $this->timestamp );
776
-						}
777
-
778
-						$style = 'display: block; font-family: ' . esc_attr( $this->value['font-family'] ) . '; font-weight: ' . esc_attr( $this->value['font-weight'] ) . ';';
779
-					}
780
-				}
781
-
782
-				if ( isset( $this->field['preview']['font-size'] ) ) {
783
-					$style .= 'font-size: ' . $this->field['preview']['font-size'] . ';';
784
-					$in_use = '1';
785
-				} else {
786
-					$in_use = '0';
787
-				}
788
-
789
-				// Filter to disable Google font updates.
790
-				if ( apply_filters( "redux/{$this->parent->args['opt_name']}/field/typography/google_font_update", true ) ) { // phpcs:ignored WordPress.NamingConventions.ValidHookName
791
-					if ( Redux_Helpers::google_fonts_update_needed() && ! get_option( 'auto_update_redux_google_fonts', false ) && $this->field['font-family'] && $this->field['google'] ) {
792
-						$nonce = wp_create_nonce( 'redux_update_google_fonts' );
793
-
794
-						echo '<div data-nonce="' . esc_attr( $nonce ) . '" class="redux-update-google-fonts update-message notice inline notice-warning notice-alt">';
795
-						echo '<p>' . esc_html__( 'Your Google Fonts are out of date. To update them, please click one of the following:', 'redux-framework' );
796
-						echo '&nbsp;<a href="#" class="update-google-fonts" data-action="automatic" aria-label="' . esc_attr__( 'Automated updates', 'redux-framework' ) . '">' . esc_html__( 'Automated updates', 'redux-framework' ) . '</a> ' . esc_html__( 'or', 'redux-framework' ) . ' <a href="#" class="update-google-fonts" data-action="manual" aria-label="' . esc_attr__( 'one-time update', 'redux-framework' ) . '">' . esc_html__( 'one-time update', 'redux-framework' ) . '</a>.';
797
-						echo '</p>';
798
-						echo '</div>';
799
-					}
800
-				}
801
-
802
-				echo '<p data-preview-size="' . esc_attr( $in_use ) . '" class="clear ' . esc_attr( $this->field['id'] ) . '_previewer typography-preview" style="' . esc_attr( $style ) . '">' . esc_html( $g_text ) . '</p>';
803
-
804
-				if ( $this->field['text-shadow'] ) {
805
-
806
-					/* Shadow Colour */
807
-					echo '<div class="picker-wrapper">';
808
-					echo '<label for="' . esc_attr( $this->field['id'] ) . '-shadow-color">' . esc_html__( 'Shadow Color', 'redux-framework' ) . '</label>';
809
-					echo '<div id="' . esc_attr( $this->field['id'] ) . '_color_picker" class="colorSelector typography-shadow-color"><div style="background-color: ' . esc_attr( $this->value['color'] ) . '"></div></div>';
810
-					echo '<input
711
+                echo '<span class="add-on">' . esc_html( $the_unit ) . '</span>';
712
+                echo '</div>';
713
+                echo '<input type="hidden" class="typography-margin-bottom" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[margin-bottom]" value="' . esc_attr( $this->value['margin-bottom'] ) . '" data-id="' . esc_attr( $this->field['id'] ) . '"  />';
714
+                echo '</div>';
715
+            }
716
+
717
+            if ( $this->field['margin-top'] || $this->field['margin-bottom'] ) {
718
+                echo '<div class="clearfix"></div>';
719
+            }
720
+
721
+            /* Font Color */
722
+            if ( true === $this->field['color'] ) {
723
+                $default = '';
724
+
725
+                if ( empty( $this->field['default']['color'] ) && ! empty( $this->field['color'] ) ) {
726
+                    $default = $this->value['color'];
727
+                } elseif ( ! empty( $this->field['default']['color'] ) ) {
728
+                    $default = $this->field['default']['color'];
729
+                }
730
+
731
+                echo '<div class="picker-wrapper">';
732
+                echo '<label for="' . esc_attr( $this->field['id'] ) . '-color">' . esc_html__( 'Font Color', 'redux-framework' ) . '</label>';
733
+                echo '<div id="' . esc_attr( $this->field['id'] ) . '_color_picker" class="colorSelector typography-color">';
734
+                echo '<div style="background-color: ' . esc_attr( $this->value['color'] ) . '"></div>';
735
+                echo '</div>';
736
+                echo '<input ';
737
+                echo 'data-default-color="' . esc_attr( $default ) . '"';
738
+                echo 'class="color-picker redux-color redux-typography-color ' . esc_attr( $this->field['class'] ) . '"';
739
+                echo 'original-title="' . esc_html__( 'Font color', 'redux-framework' ) . '"';
740
+                echo 'id="' . esc_attr( $this->field['id'] ) . '-color"';
741
+                echo 'name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[color]"';
742
+                echo 'type="text"';
743
+                echo 'value="' . esc_attr( $this->value['color'] ) . '"';
744
+                echo 'data-id="' . esc_attr( $this->field['id'] ) . '"';
745
+
746
+                $data = array(
747
+                    'field' => $this->field,
748
+                    'index' => 'color',
749
+                );
750
+
751
+                echo Redux_Functions_Ex::output_alpha_data( $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
752
+
753
+                echo '>';
754
+                echo '</div>';
755
+            }
756
+
757
+            echo '<div class="clearfix"></div>';
758
+
759
+            /* Font Preview */
760
+            if ( ! isset( $this->field['preview'] ) || false !== $this->field['preview'] ) {
761
+                $g_text = $this->field['preview']['text'] ?? '1 2 3 4 5 6 7 8 9 0 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z';
762
+
763
+                $style = '';
764
+                if ( isset( $this->field['preview']['always_display'] ) ) {
765
+                    if ( true === filter_var( $this->field['preview']['always_display'], FILTER_VALIDATE_BOOLEAN ) ) {
766
+                        if ( true === (bool) $is_google_font ) {
767
+                            $this->typography_preview[ $font_family[0] ] = array(
768
+                                'font-style' => array( $this->value['font-weight'] . $this->value['font-style'] ),
769
+                                'subset'     => array( $this->value['subsets'] ),
770
+                            );
771
+
772
+                            wp_deregister_style( 'redux-typography-preview' );
773
+                            wp_dequeue_style( 'redux-typography-preview' );
774
+
775
+                            wp_enqueue_style( 'redux-typography-preview', $this->make_google_web_font_link( $this->typography_preview ), array(), $this->timestamp );
776
+                        }
777
+
778
+                        $style = 'display: block; font-family: ' . esc_attr( $this->value['font-family'] ) . '; font-weight: ' . esc_attr( $this->value['font-weight'] ) . ';';
779
+                    }
780
+                }
781
+
782
+                if ( isset( $this->field['preview']['font-size'] ) ) {
783
+                    $style .= 'font-size: ' . $this->field['preview']['font-size'] . ';';
784
+                    $in_use = '1';
785
+                } else {
786
+                    $in_use = '0';
787
+                }
788
+
789
+                // Filter to disable Google font updates.
790
+                if ( apply_filters( "redux/{$this->parent->args['opt_name']}/field/typography/google_font_update", true ) ) { // phpcs:ignored WordPress.NamingConventions.ValidHookName
791
+                    if ( Redux_Helpers::google_fonts_update_needed() && ! get_option( 'auto_update_redux_google_fonts', false ) && $this->field['font-family'] && $this->field['google'] ) {
792
+                        $nonce = wp_create_nonce( 'redux_update_google_fonts' );
793
+
794
+                        echo '<div data-nonce="' . esc_attr( $nonce ) . '" class="redux-update-google-fonts update-message notice inline notice-warning notice-alt">';
795
+                        echo '<p>' . esc_html__( 'Your Google Fonts are out of date. To update them, please click one of the following:', 'redux-framework' );
796
+                        echo '&nbsp;<a href="#" class="update-google-fonts" data-action="automatic" aria-label="' . esc_attr__( 'Automated updates', 'redux-framework' ) . '">' . esc_html__( 'Automated updates', 'redux-framework' ) . '</a> ' . esc_html__( 'or', 'redux-framework' ) . ' <a href="#" class="update-google-fonts" data-action="manual" aria-label="' . esc_attr__( 'one-time update', 'redux-framework' ) . '">' . esc_html__( 'one-time update', 'redux-framework' ) . '</a>.';
797
+                        echo '</p>';
798
+                        echo '</div>';
799
+                    }
800
+                }
801
+
802
+                echo '<p data-preview-size="' . esc_attr( $in_use ) . '" class="clear ' . esc_attr( $this->field['id'] ) . '_previewer typography-preview" style="' . esc_attr( $style ) . '">' . esc_html( $g_text ) . '</p>';
803
+
804
+                if ( $this->field['text-shadow'] ) {
805
+
806
+                    /* Shadow Colour */
807
+                    echo '<div class="picker-wrapper">';
808
+                    echo '<label for="' . esc_attr( $this->field['id'] ) . '-shadow-color">' . esc_html__( 'Shadow Color', 'redux-framework' ) . '</label>';
809
+                    echo '<div id="' . esc_attr( $this->field['id'] ) . '_color_picker" class="colorSelector typography-shadow-color"><div style="background-color: ' . esc_attr( $this->value['color'] ) . '"></div></div>';
810
+                    echo '<input
811 811
 		                    data-default-color="' . esc_attr( $this->value['shadow-color'] ) . '"
812 812
 		                    class="color-picker redux-color redux-typography-shadow-color ' . esc_attr( $this->field['class'] ) . '"
813 813
 		                    original-title="' . esc_html__( 'Shadow color', 'redux-framework' ) . '"
@@ -818,12 +818,12 @@  discard block
 block discarded – undo
818 818
 		                    data-alpha="' . esc_attr( $this->field['color_alpha']['shadow-color'] ) . '"
819 819
 		                    data-id="' . esc_attr( $this->field['id'] ) . '"
820 820
 		                  />';
821
-					echo '</div>';
821
+                    echo '</div>';
822 822
 
823
-					/* Shadow Horizontal Length */
824
-					echo '<div class="input_wrapper shadow-horizontal redux-container-typography" style="top:-60px;margin-left:20px;width:20%">';
825
-					echo '<div class="label">' . esc_html__( 'Horizontal', 'redux-framework' ) . ': <strong>' . esc_attr( $this->value['shadow-horizontal'] ) . 'px</strong></div>';
826
-					echo '<div
823
+                    /* Shadow Horizontal Length */
824
+                    echo '<div class="input_wrapper shadow-horizontal redux-container-typography" style="top:-60px;margin-left:20px;width:20%">';
825
+                    echo '<div class="label">' . esc_html__( 'Horizontal', 'redux-framework' ) . ': <strong>' . esc_attr( $this->value['shadow-horizontal'] ) . 'px</strong></div>';
826
+                    echo '<div
827 827
                             class="redux-typography-slider span2 redux-typography redux-typography-shadow-horizontal mini typography-input ' . esc_attr( $this->field['class'] ) . '"
828 828
                             id="' . esc_attr( $this->field['id'] ) . '"
829 829
                             data-id="' . esc_attr( $this->field['id'] ) . '-h"
@@ -834,13 +834,13 @@  discard block
 block discarded – undo
834 834
                             data-label="' . esc_attr__( 'Horizontal', 'redux-framework' ) . '"
835 835
                             data-default = "' . esc_attr( $this->value['shadow-horizontal'] ) . '">
836 836
                         </div>';
837
-					echo '<input type="hidden" id="redux-slider-value-' . esc_attr( $this->field['id'] ) . '-h" class="typography-shadow-horizontal" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[shadow-horizontal]" value="' . esc_attr( $this->value['shadow-horizontal'] ) . '" data-id="' . esc_attr( $this->field['id'] ) . '"  />';
838
-					echo '</div>';
837
+                    echo '<input type="hidden" id="redux-slider-value-' . esc_attr( $this->field['id'] ) . '-h" class="typography-shadow-horizontal" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[shadow-horizontal]" value="' . esc_attr( $this->value['shadow-horizontal'] ) . '" data-id="' . esc_attr( $this->field['id'] ) . '"  />';
838
+                    echo '</div>';
839 839
 
840
-					/* Shadow Vertical Length */
841
-					echo '<div class="input_wrapper shadow-vertical redux-container-typography" style="top:-60px;margin-left:20px;width:20%">';
842
-					echo '<div>' . esc_html__( 'Vertical', 'redux-framework' ) . ': <strong>' . esc_attr( $this->value['shadow-vertical'] ) . 'px</strong></div>';
843
-					echo '<div
840
+                    /* Shadow Vertical Length */
841
+                    echo '<div class="input_wrapper shadow-vertical redux-container-typography" style="top:-60px;margin-left:20px;width:20%">';
842
+                    echo '<div>' . esc_html__( 'Vertical', 'redux-framework' ) . ': <strong>' . esc_attr( $this->value['shadow-vertical'] ) . 'px</strong></div>';
843
+                    echo '<div
844 844
                             class="redux-typography-slider span2 redux-typography redux-typography-shadow-vertical mini typography-input ' . esc_attr( $this->field['class'] ) . '"
845 845
                             id="' . esc_attr( $this->field['id'] ) . '"
846 846
                             data-id="' . esc_attr( $this->field['id'] ) . '-v"
@@ -851,13 +851,13 @@  discard block
 block discarded – undo
851 851
                             data-label="' . esc_attr__( 'Vertical', 'redux-framework' ) . '"
852 852
                             data-default = "' . esc_attr( $this->value['shadow-vertical'] ) . '">
853 853
                         </div>';
854
-					echo '<input type="hidden" id="redux-slider-value-' . esc_attr( $this->field['id'] ) . '-v" class="typography-shadow-vertical" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[shadow-vertical]" value="' . esc_attr( $this->value['shadow-vertical'] ) . '" data-id="' . esc_attr( $this->field['id'] ) . '"  />';
855
-					echo '</div>';
854
+                    echo '<input type="hidden" id="redux-slider-value-' . esc_attr( $this->field['id'] ) . '-v" class="typography-shadow-vertical" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[shadow-vertical]" value="' . esc_attr( $this->value['shadow-vertical'] ) . '" data-id="' . esc_attr( $this->field['id'] ) . '"  />';
855
+                    echo '</div>';
856 856
 
857
-					/* Shadow Blur */
858
-					echo '<div class="input_wrapper shadow-blur redux-container-typography" style="top:-60px;margin-left:20px;width:20%">';
859
-					echo '<div>' . esc_html__( 'Blur', 'redux-framework' ) . ': <strong>' . esc_attr( $this->value['shadow-blur'] ) . 'px</strong></div>';
860
-					echo '<div
857
+                    /* Shadow Blur */
858
+                    echo '<div class="input_wrapper shadow-blur redux-container-typography" style="top:-60px;margin-left:20px;width:20%">';
859
+                    echo '<div>' . esc_html__( 'Blur', 'redux-framework' ) . ': <strong>' . esc_attr( $this->value['shadow-blur'] ) . 'px</strong></div>';
860
+                    echo '<div
861 861
                             class="redux-typography-slider span2 redux-typography redux-typography-shadow-blur mini typography-input ' . esc_attr( $this->field['class'] ) . '"
862 862
                             id="' . esc_attr( $this->field['id'] ) . '"
863 863
                             data-id="' . esc_attr( $this->field['id'] ) . '-b"
@@ -868,743 +868,743 @@  discard block
 block discarded – undo
868 868
                             data-label="' . esc_attr__( 'Blur', 'redux-framework' ) . '"
869 869
                             data-default = "' . esc_attr( $this->value['shadow-blur'] ) . '">
870 870
                         </div>';
871
-					echo '<input type="hidden" id="redux-slider-value-' . esc_attr( $this->field['id'] ) . '-b" class="typography-shadow-blur" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[shadow-blur]" value="' . esc_attr( $this->value['shadow-blur'] ) . '" data-id="' . esc_attr( $this->field['id'] ) . '"  />';
872
-					echo '</div>';
873
-				}
874
-
875
-				echo '</div>'; // end typography container.
876
-			}
877
-		}
878
-
879
-		/**
880
-		 * Enqueue for every field instance.
881
-		 */
882
-		public function always_enqueue() {
883
-			$min = Redux_Functions::is_min();
884
-
885
-			if ( isset( $this->field['color_alpha'] ) && is_array( $this->field['color_alpha'] ) ) {
886
-				if ( $this->field['color_alpha']['color'] || $this->field['color_alpha']['shadow-color'] ) {
887
-					wp_enqueue_script( 'redux-wp-color-picker-alpha' );
888
-				}
889
-			}
890
-
891
-			if ( ! wp_style_is( 'redux-nouislider' ) && isset( $this->field['text-shadow'] ) && $this->field['text-shadow'] ) {
892
-				wp_enqueue_style(
893
-					'redux-nouislider',
894
-					Redux_Core::$url . "assets/css/vendor/nouislider$min.css",
895
-					array(),
896
-					'5.0.0'
897
-				);
898
-
899
-				wp_enqueue_script(
900
-					'redux-nouislider',
901
-					Redux_Core::$url . "assets/js/vendor/nouislider/redux.jquery.nouislider$min.js",
902
-					array( 'jquery' ),
903
-					'5.0.0',
904
-					true
905
-				);
906
-			}
907
-		}
908
-
909
-		/**
910
-		 * Enqueue Function.
911
-		 * If this field requires any scripts, or CSS define this function and register/enqueue the scripts/css
912
-		 *
913
-		 * @since ReduxFramework 1.0.0
914
-		 */
915
-		public function enqueue() {
916
-			$min = Redux_Functions::is_min();
917
-
918
-			if ( ! wp_style_is( 'select2-css' ) ) {
919
-				wp_enqueue_style( 'select2-css' );
920
-			}
921
-
922
-			if ( ! wp_style_is( 'wp-color-picker' ) ) {
923
-				wp_enqueue_style( 'wp-color-picker' );
924
-			}
925
-
926
-			wp_enqueue_script(
927
-				'redux-webfont',
928
-				'//' . 'ajax' . '.googleapis' . '.com/ajax/libs/webfont/1.6.26/webfont.js', // phpcs:ignore Generic.Strings.UnnecessaryStringConcat
929
-				array(),
930
-				'1.6.26',
931
-				true
932
-			);
933
-
934
-			$dep_array = array( 'jquery', 'wp-color-picker', 'select2-js', 'redux-js', 'redux-webfont' );
935
-
936
-			wp_enqueue_script(
937
-				'redux-field-typography',
938
-				Redux_Core::$url . "inc/fields/typography/redux-typography$min.js",
939
-				$dep_array,
940
-				$this->timestamp,
941
-				true
942
-			);
943
-
944
-			wp_localize_script(
945
-				'redux-field-typography',
946
-				'redux_typography_ajax',
947
-				array(
948
-					'ajaxurl'             => esc_url( admin_url( 'admin-ajax.php' ) ),
949
-					'update_google_fonts' => array(
950
-						'updating' => esc_html__( 'Downloading Google Fonts...', 'redux-framework' ),
951
-						// translators: Aria title, link title.
952
-						'error'    => sprintf( esc_html__( 'Update Failed|msg. %1$s', 'redux-framework' ), sprintf( '<a href="#" class="update-google-fonts" data-action="manual" aria-label="%s">%s</a>', esc_html__( 'Retry?', 'redux-framework' ), esc_html__( 'Retry?', 'redux-framework' ) ) ),
953
-						// translators: Javascript reload command, link title.
954
-						'success'  => sprintf( esc_html__( 'Updated! %1$s to start using your updated fonts.', 'redux-framework' ), sprintf( '<a href="	%1$s">%2$s</a>', 'javascript:location.reload();', esc_html__( 'Reload the page', 'redux-framework' ) ) ),
955
-					),
956
-				)
957
-			);
958
-
959
-			if ( $this->parent->args['dev_mode'] ) {
960
-				wp_enqueue_style( 'redux-color-picker' );
961
-
962
-				wp_enqueue_style(
963
-					'redux-field-typography',
964
-					Redux_Core::$url . 'inc/fields/typography/redux-typography.css',
965
-					array(),
966
-					$this->timestamp
967
-				);
968
-			}
969
-		}
970
-
971
-		/**
972
-		 * Make_google_web_font_link Function.
973
-		 * Creates the Google fonts link.
974
-		 *
975
-		 * @param array $fonts Array of google fonts.
976
-		 *
977
-		 * @return string
978
-		 *
979
-		 * @since ReduxFramework 3.0.0
980
-		 */
981
-		public function make_google_web_font_link( array $fonts ): string {
982
-			$link    = '';
983
-			$subsets = array();
984
-
985
-			foreach ( $fonts as $family => $font ) {
986
-				if ( ! empty( $link ) ) {
987
-					$link .= '|'; // Append a new font to the string.
988
-				}
989
-				$link .= $family;
990
-
991
-				if ( ! empty( $font['font-style'] ) || ! empty( $font['all-styles'] ) ) {
992
-					$link .= ':';
993
-					if ( ! empty( $font['all-styles'] ) ) {
994
-						$link .= implode( ',', $font['all-styles'] );
995
-					} elseif ( ! empty( $font['font-style'] ) ) {
996
-						$link .= implode( ',', $font['font-style'] );
997
-					}
998
-				}
999
-
1000
-				if ( ! empty( $font['subset'] ) || ! empty( $font['all-subsets'] ) ) {
1001
-					if ( ! empty( $font['all-subsets'] ) ) {
1002
-						foreach ( $font['all-subsets'] as $subset ) {
1003
-							if ( ! in_array( $subset, $subsets, true ) ) {
1004
-								$subsets[] = $subset;
1005
-							}
1006
-						}
1007
-					} elseif ( ! empty( $font['subset'] ) ) {
1008
-						foreach ( $font['subset'] as $subset ) {
1009
-							if ( ! in_array( $subset, $subsets, true ) ) {
1010
-								$subsets[] = $subset;
1011
-							}
1012
-						}
1013
-					}
1014
-				}
1015
-			}
1016
-
1017
-			if ( ! empty( $subsets ) ) {
1018
-				$link .= '&subset=' . implode( ',', $subsets );
1019
-			}
1020
-
1021
-			$display = $this->parent->args['font_display'] ?? 'swap';
1022
-
1023
-			$link .= '&display=' . $display;
1024
-
1025
-			// return 'https://fonts.bunny.net/css?family=' . $link;
1026
-			return 'https://fonts.googleapis.com/css?family=' . $link;
1027
-		}
1028
-
1029
-		/**
1030
-		 * Make_google_web_font_string Function.
1031
-		 * Creates the Google fonts link.
1032
-		 *
1033
-		 * @param array $fonts Array of Google fonts.
1034
-		 *
1035
-		 * @return string
1036
-		 *
1037
-		 * @since ReduxFramework 3.1.8
1038
-		 */
1039
-		public function make_google_web_font_string( array $fonts ): string {
1040
-			$link    = '';
1041
-			$subsets = array();
1042
-
1043
-			foreach ( $fonts as $family => $font ) {
1044
-				if ( ! empty( $link ) ) {
1045
-					$link .= "', '"; // Append a new font to the string.
1046
-				}
1047
-				$link .= $family;
1048
-
1049
-				if ( ! empty( $font['font-style'] ) || ! empty( $font['all-styles'] ) ) {
1050
-					$link .= ':';
1051
-					if ( ! empty( $font['all-styles'] ) ) {
1052
-						$link .= implode( ',', $font['all-styles'] );
1053
-					} elseif ( ! empty( $font['font-style'] ) ) {
1054
-						$link .= implode( ',', $font['font-style'] );
1055
-					}
1056
-				}
1057
-
1058
-				if ( ! empty( $font['subset'] ) || ! empty( $font['all-subsets'] ) ) {
1059
-					if ( ! empty( $font['all-subsets'] ) ) {
1060
-						foreach ( $font['all-subsets'] as $subset ) {
1061
-							if ( ! in_array( $subset, $subsets, true ) && ! is_numeric( $subset ) ) {
1062
-								$subsets[] = $subset;
1063
-							}
1064
-						}
1065
-					} elseif ( ! empty( $font['subset'] ) ) {
1066
-						foreach ( $font['subset'] as $subset ) {
1067
-							if ( ! in_array( $subset, $subsets, true ) && ! is_numeric( $subset ) ) {
1068
-								$subsets[] = $subset;
1069
-							}
1070
-						}
1071
-					}
1072
-				}
1073
-			}
1074
-
1075
-			if ( ! empty( $subsets ) ) {
1076
-				$link .= '&subset=' . implode( ',', $subsets );
1077
-			}
1078
-
1079
-			return "'" . $link . "'";
1080
-		}
1081
-
1082
-		/**
1083
-		 * Compiles field CSS for output.
1084
-		 *
1085
-		 * @param array $data Array of data to process.
1086
-		 *
1087
-		 * @return string
1088
-		 */
1089
-		public function css_style( $data ): string {
1090
-			$style = '';
1091
-
1092
-			$font = $data;
1093
-
1094
-			// Shim out old arg to new.
1095
-			if ( isset( $this->field['all_styles'] ) && ! empty( $this->field['all_styles'] ) ) {
1096
-				$this->field['all-styles'] = $this->field['all_styles'];
1097
-				unset( $this->field['all_styles'] );
1098
-			}
1099
-
1100
-			// Check for font-backup.  If it's set, stick it on a variable for
1101
-			// later use.
1102
-			if ( ! empty( $font['font-family'] ) && ! empty( $font['font-backup'] ) ) {
1103
-				$font['font-family'] = str_replace( ', ' . $font['font-backup'], '', $font['font-family'] );
1104
-				$font_backup         = ',' . $font['font-backup'];
1105
-			}
1106
-
1107
-			$font_value_set = false;
1108
-
1109
-			if ( ! empty( $font ) ) {
1110
-				foreach ( $font as $key => $value ) {
1111
-					if ( ! empty( $value ) && in_array( $key, array( 'font-family', 'font-weight' ), true ) ) {
1112
-						$font_value_set = true;
1113
-					}
1114
-				}
1115
-			}
1116
-
1117
-			if ( ! empty( $font ) ) {
1118
-				foreach ( $font as $key => $value ) {
1119
-					if ( 'font-options' === $key ) {
1120
-						continue;
1121
-					}
1122
-
1123
-					// Check for font-family key.
1124
-					if ( 'font-family' === $key ) {
1125
-
1126
-						// Enclose font family in quotes if spaces are in the
1127
-						// name.  This is necessary because if there are numerics
1128
-						// in the font name, they will not render properly.
1129
-						// Google should know better.
1130
-						if ( strpos( $value, ' ' ) && ! strpos( $value, ',' ) ) {
1131
-							$value = '"' . $value . '"';
1132
-						}
1133
-
1134
-						// Ensure fontBackup isn't empty. We already option
1135
-						// checked this earlier.  No need to do it again.
1136
-						if ( ! empty( $font_backup ) ) {
1137
-
1138
-							// Apply the backup font to the font-family element
1139
-							// via the saved variable.  We do this here, so it
1140
-							// doesn't get appended to the Google stuff below.
1141
-							$value .= $font_backup;
1142
-						}
1143
-					}
1144
-
1145
-					if ( empty( $value ) && in_array(
1146
-						$key,
1147
-						array(
1148
-							'font-weight',
1149
-							'font-style',
1150
-						),
1151
-						true
1152
-					) && true === $font_value_set ) {
1153
-						$value = 'normal';
1154
-					}
1155
-
1156
-					if ( 'font-weight' === $key && false === $this->field['font-weight'] ) {
1157
-						continue;
1158
-					}
1159
-
1160
-					if ( 'font-style' === $key && false === $this->field['font-style'] ) {
1161
-						continue;
1162
-					}
1163
-
1164
-					if ( 'google' === $key || 'subsets' === $key || 'font-backup' === $key || empty( $value ) ) {
1165
-						continue;
1166
-					}
1167
-
1168
-					if ( isset( $data['key'] ) ) {
1169
-						return $data;
1170
-					}
1171
-
1172
-					$continue = false;
1173
-
1174
-					if ( 'shadow-horizontal' === $key || 'shadow-vertical' === $key || 'shadow-blur' === $key ) {
1175
-						$continue = true;
1176
-					}
1177
-
1178
-					if ( 'shadow-color' === $key ) {
1179
-						if ( $this->field['text-shadow'] ) {
1180
-							$key   = 'text-shadow';
1181
-							$value = $data['shadow-horizontal'] . 'px ' . $data['shadow-vertical'] . 'px ' . $data['shadow-blur'] . 'px ' . $data['shadow-color'];
1182
-						} else {
1183
-							$continue = true;
1184
-						}
1185
-					}
1186
-
1187
-					if ( $continue ) {
1188
-						continue;
1189
-					}
1190
-
1191
-					$style .= $key . ':' . $value . ';';
1192
-				}
1193
-			}
1194
-
1195
-			return $style;
1196
-		}
1197
-
1198
-		/**
1199
-		 * CSS Output to send to the page.
1200
-		 *
1201
-		 * @param string|null|array $style CSS styles.
1202
-		 */
1203
-		public function output( $style = '' ) {
1204
-			$font = $this->value;
1205
-
1206
-			if ( '' !== $style ) {
1207
-				if ( ! empty( $this->field['output'] ) && ! is_array( $this->field['output'] ) ) {
1208
-					$this->field['output'] = array( $this->field['output'] );
1209
-				}
1210
-
1211
-				if ( ! empty( $this->field['output'] ) && is_array( $this->field['output'] ) ) {
1212
-					$keys                     = implode( ',', $this->field['output'] );
1213
-					$this->parent->outputCSS .= $keys . '{' . $style . '}';
1214
-				}
1215
-
1216
-				if ( ! empty( $this->field['compiler'] ) && ! is_array( $this->field['compiler'] ) ) {
1217
-					$this->field['compiler'] = array( $this->field['compiler'] );
1218
-				}
1219
-
1220
-				if ( ! empty( $this->field['compiler'] ) && is_array( $this->field['compiler'] ) ) {
1221
-					$keys                       = implode( ',', $this->field['compiler'] );
1222
-					$this->parent->compilerCSS .= $keys . '{' . $style . '}';
1223
-				}
1224
-			}
1225
-
1226
-			$this->set_google_fonts( (array) $font );
1227
-		}
1228
-
1229
-		/**
1230
-		 * Set global Google font data for global pointer.
1231
-		 *
1232
-		 * @param array $font Array of font data.
1233
-		 */
1234
-		private function set_google_fonts( array $font ) {
1235
-			// Google only stuff!
1236
-			if ( ! empty( $font['font-family'] ) && ! empty( $this->field['google'] ) && filter_var( $this->field['google'], FILTER_VALIDATE_BOOLEAN ) ) {
1237
-
1238
-				// Added standard font matching check to avoid output to Google fonts call - kp
1239
-				// If no custom font array was supplied, then load it with default
1240
-				// standard fonts.
1241
-				if ( empty( $this->field['fonts'] ) ) {
1242
-					$this->field['fonts'] = $this->std_fonts;
1243
-				}
1244
-
1245
-				// Ensure the fonts array is NOT empty.
1246
-				if ( ! empty( $this->field['fonts'] ) ) {
1247
-
1248
-					// Make the font keys in the array lowercase, for case-insensitive matching.
1249
-					$lc_fonts = array_change_key_case( $this->field['fonts'] );
1250
-
1251
-					// Rebuild font array with all keys stripped of spaces.
1252
-					$arr = array();
1253
-					foreach ( $lc_fonts as $key => $value ) {
1254
-						$key         = str_replace( ', ', ',', $key );
1255
-						$arr[ $key ] = $value;
1256
-					}
1257
-
1258
-					if ( is_array( $this->field['custom_fonts'] ) ) {
1259
-						$lc_fonts = array_change_key_case( $this->field['custom_fonts'] );
1260
-
1261
-						foreach ( $lc_fonts as $font_arr ) {
1262
-							foreach ( $font_arr as $key => $value ) {
1263
-								$arr[ Redux_Core::strtolower( $key ) ] = $key;
1264
-							}
1265
-						}
1266
-					}
1267
-
1268
-					$lc_fonts = $arr;
1269
-
1270
-					unset( $arr );
1271
-
1272
-					// lowercase chosen font for matching purposes.
1273
-					$lc_font = Redux_Core::strtolower( $font['font-family'] );
1274
-
1275
-					// Remove spaces after commas in chosen font for matching purposes.
1276
-					$lc_font = str_replace( ', ', ',', $lc_font );
1277
-
1278
-					// If the lower cased passed font-family is NOT found in the standard font array
1279
-					// Then it's a Google font, so process it for output.
1280
-					if ( ! array_key_exists( $lc_font, $lc_fonts ) ) {
1281
-						$family = $font['font-family'];
1282
-
1283
-						// TODO: This method doesn't respect spaces after commas, hence the reason
1284
-						// Strip out spaces in font names and replace with with plus signs
1285
-						// for the std_font array keys having no spaces after commas.  This could be
1286
-						// fixed with RegEx in the future.
1287
-						$font['font-family'] = str_replace( ' ', '+', $font['font-family'] );
1288
-
1289
-						// Push data to parent typography variable.
1290
-						if ( empty( Redux_Core::$typography[ $font['font-family'] ] ) ) {
1291
-							Redux_Core::$typography[ $font['font-family'] ] = array();
1292
-						}
1293
-
1294
-						if ( isset( $this->field['all-styles'] ) || isset( $this->field['all-subsets'] ) ) {
1295
-							if ( empty( $font['font-options'] ) ) {
1296
-								$this->get_google_array();
1297
-
1298
-								if ( isset( Redux_Core::$google_array ) && ! empty( Redux_Core::$google_array ) && isset( Redux_Core::$google_array[ $family ] ) ) {
1299
-									$font['font-options'] = Redux_Core::$google_array[ $family ];
1300
-								}
1301
-							} else {
1302
-								$font['font-options'] = json_decode( $font['font-options'], true );
1303
-							}
1304
-						}
1305
-
1306
-						if ( isset( $font['font-options'] ) && ! empty( $font['font-options'] ) && isset( $this->field['all-styles'] ) && filter_var( $this->field['all-styles'], FILTER_VALIDATE_BOOLEAN ) ) {
1307
-							if ( ! empty( $font['font-options']['variants'] ) ) {
1308
-								if ( ! isset( Redux_Core::$typography[ $font['font-family'] ]['all-styles'] ) || empty( Redux_Core::$typography[ $font['font-family'] ]['all-styles'] ) ) {
1309
-									Redux_Core::$typography[ $font['font-family'] ]['all-styles'] = array();
1310
-									foreach ( $font['font-options']['variants'] as $variant ) {
1311
-										Redux_Core::$typography[ $font['font-family'] ]['all-styles'][] = $variant['id'];
1312
-									}
1313
-								}
1314
-							}
1315
-						}
1316
-
1317
-						if ( isset( $font['font-options'] ) && ! empty( $font['font-options'] ) && isset( $this->field['all-subsets'] ) && $this->field['all-styles'] ) {
1318
-							if ( ! empty( $font['font-options']['subsets'] ) ) {
1319
-								if ( ! isset( Redux_Core::$typography[ $font['font-family'] ]['all-subsets'] ) || empty( Redux_Core::$typography[ $font['font-family'] ]['all-subsets'] ) ) {
1320
-									Redux_Core::$typography[ $font['font-family'] ]['all-subsets'] = array();
1321
-									foreach ( $font['font-options']['subsets'] as $variant ) {
1322
-										Redux_Core::$typography[ $font['font-family'] ]['all-subsets'][] = $variant['id'];
1323
-									}
1324
-								}
1325
-							}
1326
-						}
1327
-
1328
-						$style = '';
1329
-
1330
-						if ( ! empty( $font['font-weight'] ) ) {
1331
-							if ( empty( Redux_Core::$typography[ $font['font-family'] ]['font-weight'] ) || ! in_array( $font['font-weight'], Redux_Core::$typography[ $font['font-family'] ]['font-weight'], true ) ) {
1332
-								$style = $font['font-weight'];
1333
-							}
1334
-
1335
-							if ( ! empty( $font['font-style'] ) ) {
1336
-								$style .= $font['font-style'];
1337
-							}
1338
-
1339
-							if ( empty( Redux_Core::$typography[ $font['font-family'] ]['font-style'] ) || ! in_array( $style, Redux_Core::$typography[ $font['font-family'] ]['font-style'], true ) ) {
1340
-								Redux_Core::$typography[ $font['font-family'] ]['font-style'][] = $style;
1341
-							}
1342
-						}
1343
-
1344
-						if ( ! empty( $font['subsets'] ) ) {
1345
-							if ( empty( Redux_Core::$typography[ $font['font-family'] ]['subset'] ) || ! in_array( $font['subsets'], Redux_Core::$typography[ $font['font-family'] ]['subset'], true ) ) {
1346
-								Redux_Core::$typography[ $font['font-family'] ]['subset'][] = $font['subsets'];
1347
-							}
1348
-						}
1349
-					}
1350
-				}
1351
-			}
1352
-		}
1353
-
1354
-		/**
1355
-		 * Localize standard, custom and typekit fonts.
1356
-		 */
1357
-		private function localize_std_fonts() {
1358
-			if ( false === $this->user_fonts ) {
1359
-				if ( isset( Redux_Core::$fonts['std'] ) && ! empty( Redux_Core::$fonts['std'] ) ) {
1360
-					return;
1361
-				}
1362
-
1363
-				Redux_Core::$font_groups['std'] = array(
1364
-					'text'     => esc_html__( 'Standard Fonts', 'redux-framework' ),
1365
-					'children' => array(),
1366
-				);
1367
-
1368
-				foreach ( $this->field['fonts'] as $font => $extra ) {
1369
-					Redux_Core::$font_groups['std']['children'][] = array(
1370
-						'id'          => $font,
1371
-						'text'        => $font,
1372
-						'data-google' => 'false',
1373
-					);
1374
-				}
1375
-			}
1376
-
1377
-			if ( false !== $this->field['custom_fonts'] ) {
1378
-				// phpcs:ignored WordPress.NamingConventions.ValidHookName
1379
-				$this->field['custom_fonts'] = apply_filters( "redux/{$this->parent->args['opt_name']}/field/typography/custom_fonts", array() );
1380
-
1381
-				if ( ! empty( $this->field['custom_fonts'] ) ) {
1382
-					foreach ( $this->field['custom_fonts'] as $group => $fonts ) {
1383
-						Redux_Core::$font_groups['customfonts'] = array(
1384
-							'text'     => $group,
1385
-							'children' => array(),
1386
-						);
1387
-
1388
-						foreach ( $fonts as $family => $v ) {
1389
-							Redux_Core::$font_groups['customfonts']['children'][] = array(
1390
-								'id'          => $family,
1391
-								'text'        => $family,
1392
-								'data-google' => 'false',
1393
-							);
1394
-						}
1395
-					}
1396
-				}
1397
-			}
1398
-
1399
-			// Typekit.
1400
-			// phpcs:ignored WordPress.NamingConventions.ValidHookName
1401
-			$typekit_fonts = apply_filters( "redux/{$this->parent->args['opt_name']}/field/typography/typekit_fonts", array() );
1402
-
1403
-			if ( ! empty( $typekit_fonts ) ) {
1404
-				foreach ( $typekit_fonts as $group => $fonts ) {
1405
-					Redux_Core::$font_groups['typekitfonts'] = array(
1406
-						'text'     => $group,
1407
-						'children' => array(),
1408
-					);
1409
-
1410
-					foreach ( $fonts as $family => $v ) {
1411
-						Redux_Core::$font_groups['typekitfonts']['children'][] = array(
1412
-							'text'        => $family,
1413
-							'id'          => $family,
1414
-							'data-google' => 'false',
1415
-						);
1416
-					}
1417
-				}
1418
-			}
1419
-		}
1420
-
1421
-		/**
1422
-		 *   Construct the Google array from the stored JSON/HTML
1423
-		 */
1424
-		private function get_google_array() {
1425
-			if ( ( ( isset( Redux_Core::$fonts['google'] ) && ! empty( Redux_Core::$fonts['google'] ) ) ) || ( isset( Redux_Core::$fonts['google'] ) && false === Redux_Core::$fonts['google'] ) ) {
1426
-				return;
1427
-			}
1428
-
1429
-			$fonts = Redux_Helpers::google_fonts_array( get_option( 'auto_update_redux_google_fonts', false ) );
1430
-			if ( empty( $fonts ) ) {
1431
-				$google_font = __DIR__ . '/googlefonts.php';
1432
-				$fonts       = include $google_font;
1433
-			}
1434
-
1435
-			if ( true === $fonts ) {
1436
-				Redux_Core::$fonts['google'] = false;
1437
-
1438
-				return;
1439
-			}
1440
-
1441
-			if ( isset( $fonts ) && ! empty( $fonts ) && is_array( $fonts ) ) {
1442
-				Redux_Core::$fonts['google'] = $fonts;
1443
-				Redux_Core::$google_array    = $fonts;
1444
-
1445
-				// optgroup.
1446
-				Redux_Core::$font_groups['google'] = array(
1447
-					'text'     => esc_html__( 'Google Webfonts', 'redux-framework' ),
1448
-					'children' => array(),
1449
-				);
1450
-
1451
-				// options.
1452
-				foreach ( Redux_Core::$fonts['google'] as $font => $extra ) {
1453
-					Redux_Core::$font_groups['google']['children'][] = array(
1454
-						'id'          => $font,
1455
-						'text'        => $font,
1456
-						'data-google' => 'true',
1457
-					);
1458
-				}
1459
-			}
1460
-		}
1461
-
1462
-		/**
1463
-		 * Clean up the Google Webfonts subsets to be human-readable
1464
-		 *
1465
-		 * @param array $var Font subset array.
1466
-		 *
1467
-		 * @return array
1468
-		 *
1469
-		 * @since ReduxFramework 0.2.0
1470
-		 */
1471
-		private function get_subsets( array $var ): array {
1472
-			$result = array();
1473
-
1474
-			foreach ( $var as $v ) {
1475
-				if ( strpos( $v, '-ext' ) ) {
1476
-					$name = ucfirst( str_replace( '-ext', ' Extended', $v ) );
1477
-				} else {
1478
-					$name = ucfirst( $v );
1479
-				}
1480
-
1481
-				$result[] = array(
1482
-					'id'   => $v,
1483
-					'name' => $name,
1484
-				);
1485
-			}
1486
-
1487
-			return array_filter( $result );
1488
-		}
1489
-
1490
-		/**
1491
-		 * Clean up the Google Webfonts variants to be human-readable
1492
-		 *
1493
-		 * @param array $var Font variant array.
1494
-		 *
1495
-		 * @return array
1496
-		 *
1497
-		 * @since ReduxFramework 0.2.0
1498
-		 */
1499
-		private function get_variants( array $var ): array {
1500
-			$result = array();
1501
-			$italic = array();
1502
-
1503
-			foreach ( $var as $v ) {
1504
-				$name = '';
1505
-				if ( 1 === $v[0] ) {
1506
-					$name = 'Ultra-Light 100';
1507
-				} elseif ( 2 === $v[0] ) {
1508
-					$name = 'Light 200';
1509
-				} elseif ( 3 === $v[0] ) {
1510
-					$name = 'Book 300';
1511
-				} elseif ( 4 === $v[0] || 'r' === $v[0] || 'i' === $v[0] ) {
1512
-					$name = 'Normal 400';
1513
-				} elseif ( 5 === $v[0] ) {
1514
-					$name = 'Medium 500';
1515
-				} elseif ( 6 === $v[0] ) {
1516
-					$name = 'Semi-Bold 600';
1517
-				} elseif ( 7 === $v[0] ) {
1518
-					$name = 'Bold 700';
1519
-				} elseif ( 8 === $v[0] ) {
1520
-					$name = 'Extra-Bold 800';
1521
-				} elseif ( 9 === $v[0] ) {
1522
-					$name = 'Ultra-Bold 900';
1523
-				}
1524
-
1525
-				if ( 'regular' === $v ) {
1526
-					$v = '400';
1527
-				}
1528
-
1529
-				if ( strpos( $v, 'italic' ) || 'italic' === $v ) {
1530
-					$name .= ' Italic';
1531
-					$name  = trim( $name );
1532
-					if ( 'italic' === $v ) {
1533
-						$v = '400italic';
1534
-					}
1535
-					$italic[] = array(
1536
-						'id'   => $v,
1537
-						'name' => $name,
1538
-					);
1539
-				} else {
1540
-					$result[] = array(
1541
-						'id'   => $v,
1542
-						'name' => $name,
1543
-					);
1544
-				}
1545
-			}
1546
-
1547
-			foreach ( $italic as $item ) {
1548
-				$result[] = $item;
1549
-			}
1550
-
1551
-			return array_filter( $result );
1552
-		}
1553
-
1554
-		/**
1555
-		 * Update google font array via AJAX call.
1556
-		 */
1557
-		public function google_fonts_update_ajax() {
1558
-			if ( ! current_user_can( $this->parent->args['page_permissions'] ) ) {
1559
-				wp_die( esc_html__( 'You do not have permission to perform this action.', 'redux-framework' ), 403 );
1560
-			}
1561
-
1562
-			if ( ! isset( $_POST['nonce'] ) || ( ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'redux_update_google_fonts' ) ) ) {
1563
-				die( 'Security check' );
1564
-			}
1565
-
1566
-			if ( isset( $_POST['data'] ) && 'automatic' === $_POST['data'] ) {
1567
-				update_option( 'auto_update_redux_google_fonts', true );
1568
-			}
1569
-
1570
-			$fonts = Redux_Helpers::google_fonts_array( true );
1571
-
1572
-			if ( ! empty( $fonts ) && ! is_wp_error( $fonts ) ) {
1573
-				echo wp_json_encode(
1574
-					array(
1575
-						'status' => 'success',
1576
-						'fonts'  => $fonts,
1577
-					)
1578
-				);
1579
-			} else {
1580
-				$err_msg = '';
1581
-
1582
-				if ( is_wp_error( $fonts ) ) {
1583
-					$err_msg = $fonts->get_error_code();
1584
-				}
1585
-
1586
-				echo wp_json_encode(
1587
-					array(
1588
-						'status' => 'error',
1589
-						'error'  => $err_msg,
1590
-					)
1591
-				);
1592
-			}
1593
-
1594
-			die();
1595
-		}
1596
-
1597
-		/**
1598
-		 * Enable output_variables to be generated.
1599
-		 *
1600
-		 * @since       4.0.3
1601
-		 * @return void
1602
-		 */
1603
-		public function output_variables() {
1604
-			// No code needed, just defining the method is enough.
1605
-		}
1606
-	}
871
+                    echo '<input type="hidden" id="redux-slider-value-' . esc_attr( $this->field['id'] ) . '-b" class="typography-shadow-blur" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '[shadow-blur]" value="' . esc_attr( $this->value['shadow-blur'] ) . '" data-id="' . esc_attr( $this->field['id'] ) . '"  />';
872
+                    echo '</div>';
873
+                }
874
+
875
+                echo '</div>'; // end typography container.
876
+            }
877
+        }
878
+
879
+        /**
880
+         * Enqueue for every field instance.
881
+         */
882
+        public function always_enqueue() {
883
+            $min = Redux_Functions::is_min();
884
+
885
+            if ( isset( $this->field['color_alpha'] ) && is_array( $this->field['color_alpha'] ) ) {
886
+                if ( $this->field['color_alpha']['color'] || $this->field['color_alpha']['shadow-color'] ) {
887
+                    wp_enqueue_script( 'redux-wp-color-picker-alpha' );
888
+                }
889
+            }
890
+
891
+            if ( ! wp_style_is( 'redux-nouislider' ) && isset( $this->field['text-shadow'] ) && $this->field['text-shadow'] ) {
892
+                wp_enqueue_style(
893
+                    'redux-nouislider',
894
+                    Redux_Core::$url . "assets/css/vendor/nouislider$min.css",
895
+                    array(),
896
+                    '5.0.0'
897
+                );
898
+
899
+                wp_enqueue_script(
900
+                    'redux-nouislider',
901
+                    Redux_Core::$url . "assets/js/vendor/nouislider/redux.jquery.nouislider$min.js",
902
+                    array( 'jquery' ),
903
+                    '5.0.0',
904
+                    true
905
+                );
906
+            }
907
+        }
908
+
909
+        /**
910
+         * Enqueue Function.
911
+         * If this field requires any scripts, or CSS define this function and register/enqueue the scripts/css
912
+         *
913
+         * @since ReduxFramework 1.0.0
914
+         */
915
+        public function enqueue() {
916
+            $min = Redux_Functions::is_min();
917
+
918
+            if ( ! wp_style_is( 'select2-css' ) ) {
919
+                wp_enqueue_style( 'select2-css' );
920
+            }
921
+
922
+            if ( ! wp_style_is( 'wp-color-picker' ) ) {
923
+                wp_enqueue_style( 'wp-color-picker' );
924
+            }
925
+
926
+            wp_enqueue_script(
927
+                'redux-webfont',
928
+                '//' . 'ajax' . '.googleapis' . '.com/ajax/libs/webfont/1.6.26/webfont.js', // phpcs:ignore Generic.Strings.UnnecessaryStringConcat
929
+                array(),
930
+                '1.6.26',
931
+                true
932
+            );
933
+
934
+            $dep_array = array( 'jquery', 'wp-color-picker', 'select2-js', 'redux-js', 'redux-webfont' );
935
+
936
+            wp_enqueue_script(
937
+                'redux-field-typography',
938
+                Redux_Core::$url . "inc/fields/typography/redux-typography$min.js",
939
+                $dep_array,
940
+                $this->timestamp,
941
+                true
942
+            );
943
+
944
+            wp_localize_script(
945
+                'redux-field-typography',
946
+                'redux_typography_ajax',
947
+                array(
948
+                    'ajaxurl'             => esc_url( admin_url( 'admin-ajax.php' ) ),
949
+                    'update_google_fonts' => array(
950
+                        'updating' => esc_html__( 'Downloading Google Fonts...', 'redux-framework' ),
951
+                        // translators: Aria title, link title.
952
+                        'error'    => sprintf( esc_html__( 'Update Failed|msg. %1$s', 'redux-framework' ), sprintf( '<a href="#" class="update-google-fonts" data-action="manual" aria-label="%s">%s</a>', esc_html__( 'Retry?', 'redux-framework' ), esc_html__( 'Retry?', 'redux-framework' ) ) ),
953
+                        // translators: Javascript reload command, link title.
954
+                        'success'  => sprintf( esc_html__( 'Updated! %1$s to start using your updated fonts.', 'redux-framework' ), sprintf( '<a href="	%1$s">%2$s</a>', 'javascript:location.reload();', esc_html__( 'Reload the page', 'redux-framework' ) ) ),
955
+                    ),
956
+                )
957
+            );
958
+
959
+            if ( $this->parent->args['dev_mode'] ) {
960
+                wp_enqueue_style( 'redux-color-picker' );
961
+
962
+                wp_enqueue_style(
963
+                    'redux-field-typography',
964
+                    Redux_Core::$url . 'inc/fields/typography/redux-typography.css',
965
+                    array(),
966
+                    $this->timestamp
967
+                );
968
+            }
969
+        }
970
+
971
+        /**
972
+         * Make_google_web_font_link Function.
973
+         * Creates the Google fonts link.
974
+         *
975
+         * @param array $fonts Array of google fonts.
976
+         *
977
+         * @return string
978
+         *
979
+         * @since ReduxFramework 3.0.0
980
+         */
981
+        public function make_google_web_font_link( array $fonts ): string {
982
+            $link    = '';
983
+            $subsets = array();
984
+
985
+            foreach ( $fonts as $family => $font ) {
986
+                if ( ! empty( $link ) ) {
987
+                    $link .= '|'; // Append a new font to the string.
988
+                }
989
+                $link .= $family;
990
+
991
+                if ( ! empty( $font['font-style'] ) || ! empty( $font['all-styles'] ) ) {
992
+                    $link .= ':';
993
+                    if ( ! empty( $font['all-styles'] ) ) {
994
+                        $link .= implode( ',', $font['all-styles'] );
995
+                    } elseif ( ! empty( $font['font-style'] ) ) {
996
+                        $link .= implode( ',', $font['font-style'] );
997
+                    }
998
+                }
999
+
1000
+                if ( ! empty( $font['subset'] ) || ! empty( $font['all-subsets'] ) ) {
1001
+                    if ( ! empty( $font['all-subsets'] ) ) {
1002
+                        foreach ( $font['all-subsets'] as $subset ) {
1003
+                            if ( ! in_array( $subset, $subsets, true ) ) {
1004
+                                $subsets[] = $subset;
1005
+                            }
1006
+                        }
1007
+                    } elseif ( ! empty( $font['subset'] ) ) {
1008
+                        foreach ( $font['subset'] as $subset ) {
1009
+                            if ( ! in_array( $subset, $subsets, true ) ) {
1010
+                                $subsets[] = $subset;
1011
+                            }
1012
+                        }
1013
+                    }
1014
+                }
1015
+            }
1016
+
1017
+            if ( ! empty( $subsets ) ) {
1018
+                $link .= '&subset=' . implode( ',', $subsets );
1019
+            }
1020
+
1021
+            $display = $this->parent->args['font_display'] ?? 'swap';
1022
+
1023
+            $link .= '&display=' . $display;
1024
+
1025
+            // return 'https://fonts.bunny.net/css?family=' . $link;
1026
+            return 'https://fonts.googleapis.com/css?family=' . $link;
1027
+        }
1028
+
1029
+        /**
1030
+         * Make_google_web_font_string Function.
1031
+         * Creates the Google fonts link.
1032
+         *
1033
+         * @param array $fonts Array of Google fonts.
1034
+         *
1035
+         * @return string
1036
+         *
1037
+         * @since ReduxFramework 3.1.8
1038
+         */
1039
+        public function make_google_web_font_string( array $fonts ): string {
1040
+            $link    = '';
1041
+            $subsets = array();
1042
+
1043
+            foreach ( $fonts as $family => $font ) {
1044
+                if ( ! empty( $link ) ) {
1045
+                    $link .= "', '"; // Append a new font to the string.
1046
+                }
1047
+                $link .= $family;
1048
+
1049
+                if ( ! empty( $font['font-style'] ) || ! empty( $font['all-styles'] ) ) {
1050
+                    $link .= ':';
1051
+                    if ( ! empty( $font['all-styles'] ) ) {
1052
+                        $link .= implode( ',', $font['all-styles'] );
1053
+                    } elseif ( ! empty( $font['font-style'] ) ) {
1054
+                        $link .= implode( ',', $font['font-style'] );
1055
+                    }
1056
+                }
1057
+
1058
+                if ( ! empty( $font['subset'] ) || ! empty( $font['all-subsets'] ) ) {
1059
+                    if ( ! empty( $font['all-subsets'] ) ) {
1060
+                        foreach ( $font['all-subsets'] as $subset ) {
1061
+                            if ( ! in_array( $subset, $subsets, true ) && ! is_numeric( $subset ) ) {
1062
+                                $subsets[] = $subset;
1063
+                            }
1064
+                        }
1065
+                    } elseif ( ! empty( $font['subset'] ) ) {
1066
+                        foreach ( $font['subset'] as $subset ) {
1067
+                            if ( ! in_array( $subset, $subsets, true ) && ! is_numeric( $subset ) ) {
1068
+                                $subsets[] = $subset;
1069
+                            }
1070
+                        }
1071
+                    }
1072
+                }
1073
+            }
1074
+
1075
+            if ( ! empty( $subsets ) ) {
1076
+                $link .= '&subset=' . implode( ',', $subsets );
1077
+            }
1078
+
1079
+            return "'" . $link . "'";
1080
+        }
1081
+
1082
+        /**
1083
+         * Compiles field CSS for output.
1084
+         *
1085
+         * @param array $data Array of data to process.
1086
+         *
1087
+         * @return string
1088
+         */
1089
+        public function css_style( $data ): string {
1090
+            $style = '';
1091
+
1092
+            $font = $data;
1093
+
1094
+            // Shim out old arg to new.
1095
+            if ( isset( $this->field['all_styles'] ) && ! empty( $this->field['all_styles'] ) ) {
1096
+                $this->field['all-styles'] = $this->field['all_styles'];
1097
+                unset( $this->field['all_styles'] );
1098
+            }
1099
+
1100
+            // Check for font-backup.  If it's set, stick it on a variable for
1101
+            // later use.
1102
+            if ( ! empty( $font['font-family'] ) && ! empty( $font['font-backup'] ) ) {
1103
+                $font['font-family'] = str_replace( ', ' . $font['font-backup'], '', $font['font-family'] );
1104
+                $font_backup         = ',' . $font['font-backup'];
1105
+            }
1106
+
1107
+            $font_value_set = false;
1108
+
1109
+            if ( ! empty( $font ) ) {
1110
+                foreach ( $font as $key => $value ) {
1111
+                    if ( ! empty( $value ) && in_array( $key, array( 'font-family', 'font-weight' ), true ) ) {
1112
+                        $font_value_set = true;
1113
+                    }
1114
+                }
1115
+            }
1116
+
1117
+            if ( ! empty( $font ) ) {
1118
+                foreach ( $font as $key => $value ) {
1119
+                    if ( 'font-options' === $key ) {
1120
+                        continue;
1121
+                    }
1122
+
1123
+                    // Check for font-family key.
1124
+                    if ( 'font-family' === $key ) {
1125
+
1126
+                        // Enclose font family in quotes if spaces are in the
1127
+                        // name.  This is necessary because if there are numerics
1128
+                        // in the font name, they will not render properly.
1129
+                        // Google should know better.
1130
+                        if ( strpos( $value, ' ' ) && ! strpos( $value, ',' ) ) {
1131
+                            $value = '"' . $value . '"';
1132
+                        }
1133
+
1134
+                        // Ensure fontBackup isn't empty. We already option
1135
+                        // checked this earlier.  No need to do it again.
1136
+                        if ( ! empty( $font_backup ) ) {
1137
+
1138
+                            // Apply the backup font to the font-family element
1139
+                            // via the saved variable.  We do this here, so it
1140
+                            // doesn't get appended to the Google stuff below.
1141
+                            $value .= $font_backup;
1142
+                        }
1143
+                    }
1144
+
1145
+                    if ( empty( $value ) && in_array(
1146
+                        $key,
1147
+                        array(
1148
+                            'font-weight',
1149
+                            'font-style',
1150
+                        ),
1151
+                        true
1152
+                    ) && true === $font_value_set ) {
1153
+                        $value = 'normal';
1154
+                    }
1155
+
1156
+                    if ( 'font-weight' === $key && false === $this->field['font-weight'] ) {
1157
+                        continue;
1158
+                    }
1159
+
1160
+                    if ( 'font-style' === $key && false === $this->field['font-style'] ) {
1161
+                        continue;
1162
+                    }
1163
+
1164
+                    if ( 'google' === $key || 'subsets' === $key || 'font-backup' === $key || empty( $value ) ) {
1165
+                        continue;
1166
+                    }
1167
+
1168
+                    if ( isset( $data['key'] ) ) {
1169
+                        return $data;
1170
+                    }
1171
+
1172
+                    $continue = false;
1173
+
1174
+                    if ( 'shadow-horizontal' === $key || 'shadow-vertical' === $key || 'shadow-blur' === $key ) {
1175
+                        $continue = true;
1176
+                    }
1177
+
1178
+                    if ( 'shadow-color' === $key ) {
1179
+                        if ( $this->field['text-shadow'] ) {
1180
+                            $key   = 'text-shadow';
1181
+                            $value = $data['shadow-horizontal'] . 'px ' . $data['shadow-vertical'] . 'px ' . $data['shadow-blur'] . 'px ' . $data['shadow-color'];
1182
+                        } else {
1183
+                            $continue = true;
1184
+                        }
1185
+                    }
1186
+
1187
+                    if ( $continue ) {
1188
+                        continue;
1189
+                    }
1190
+
1191
+                    $style .= $key . ':' . $value . ';';
1192
+                }
1193
+            }
1194
+
1195
+            return $style;
1196
+        }
1197
+
1198
+        /**
1199
+         * CSS Output to send to the page.
1200
+         *
1201
+         * @param string|null|array $style CSS styles.
1202
+         */
1203
+        public function output( $style = '' ) {
1204
+            $font = $this->value;
1205
+
1206
+            if ( '' !== $style ) {
1207
+                if ( ! empty( $this->field['output'] ) && ! is_array( $this->field['output'] ) ) {
1208
+                    $this->field['output'] = array( $this->field['output'] );
1209
+                }
1210
+
1211
+                if ( ! empty( $this->field['output'] ) && is_array( $this->field['output'] ) ) {
1212
+                    $keys                     = implode( ',', $this->field['output'] );
1213
+                    $this->parent->outputCSS .= $keys . '{' . $style . '}';
1214
+                }
1215
+
1216
+                if ( ! empty( $this->field['compiler'] ) && ! is_array( $this->field['compiler'] ) ) {
1217
+                    $this->field['compiler'] = array( $this->field['compiler'] );
1218
+                }
1219
+
1220
+                if ( ! empty( $this->field['compiler'] ) && is_array( $this->field['compiler'] ) ) {
1221
+                    $keys                       = implode( ',', $this->field['compiler'] );
1222
+                    $this->parent->compilerCSS .= $keys . '{' . $style . '}';
1223
+                }
1224
+            }
1225
+
1226
+            $this->set_google_fonts( (array) $font );
1227
+        }
1228
+
1229
+        /**
1230
+         * Set global Google font data for global pointer.
1231
+         *
1232
+         * @param array $font Array of font data.
1233
+         */
1234
+        private function set_google_fonts( array $font ) {
1235
+            // Google only stuff!
1236
+            if ( ! empty( $font['font-family'] ) && ! empty( $this->field['google'] ) && filter_var( $this->field['google'], FILTER_VALIDATE_BOOLEAN ) ) {
1237
+
1238
+                // Added standard font matching check to avoid output to Google fonts call - kp
1239
+                // If no custom font array was supplied, then load it with default
1240
+                // standard fonts.
1241
+                if ( empty( $this->field['fonts'] ) ) {
1242
+                    $this->field['fonts'] = $this->std_fonts;
1243
+                }
1244
+
1245
+                // Ensure the fonts array is NOT empty.
1246
+                if ( ! empty( $this->field['fonts'] ) ) {
1247
+
1248
+                    // Make the font keys in the array lowercase, for case-insensitive matching.
1249
+                    $lc_fonts = array_change_key_case( $this->field['fonts'] );
1250
+
1251
+                    // Rebuild font array with all keys stripped of spaces.
1252
+                    $arr = array();
1253
+                    foreach ( $lc_fonts as $key => $value ) {
1254
+                        $key         = str_replace( ', ', ',', $key );
1255
+                        $arr[ $key ] = $value;
1256
+                    }
1257
+
1258
+                    if ( is_array( $this->field['custom_fonts'] ) ) {
1259
+                        $lc_fonts = array_change_key_case( $this->field['custom_fonts'] );
1260
+
1261
+                        foreach ( $lc_fonts as $font_arr ) {
1262
+                            foreach ( $font_arr as $key => $value ) {
1263
+                                $arr[ Redux_Core::strtolower( $key ) ] = $key;
1264
+                            }
1265
+                        }
1266
+                    }
1267
+
1268
+                    $lc_fonts = $arr;
1269
+
1270
+                    unset( $arr );
1271
+
1272
+                    // lowercase chosen font for matching purposes.
1273
+                    $lc_font = Redux_Core::strtolower( $font['font-family'] );
1274
+
1275
+                    // Remove spaces after commas in chosen font for matching purposes.
1276
+                    $lc_font = str_replace( ', ', ',', $lc_font );
1277
+
1278
+                    // If the lower cased passed font-family is NOT found in the standard font array
1279
+                    // Then it's a Google font, so process it for output.
1280
+                    if ( ! array_key_exists( $lc_font, $lc_fonts ) ) {
1281
+                        $family = $font['font-family'];
1282
+
1283
+                        // TODO: This method doesn't respect spaces after commas, hence the reason
1284
+                        // Strip out spaces in font names and replace with with plus signs
1285
+                        // for the std_font array keys having no spaces after commas.  This could be
1286
+                        // fixed with RegEx in the future.
1287
+                        $font['font-family'] = str_replace( ' ', '+', $font['font-family'] );
1288
+
1289
+                        // Push data to parent typography variable.
1290
+                        if ( empty( Redux_Core::$typography[ $font['font-family'] ] ) ) {
1291
+                            Redux_Core::$typography[ $font['font-family'] ] = array();
1292
+                        }
1293
+
1294
+                        if ( isset( $this->field['all-styles'] ) || isset( $this->field['all-subsets'] ) ) {
1295
+                            if ( empty( $font['font-options'] ) ) {
1296
+                                $this->get_google_array();
1297
+
1298
+                                if ( isset( Redux_Core::$google_array ) && ! empty( Redux_Core::$google_array ) && isset( Redux_Core::$google_array[ $family ] ) ) {
1299
+                                    $font['font-options'] = Redux_Core::$google_array[ $family ];
1300
+                                }
1301
+                            } else {
1302
+                                $font['font-options'] = json_decode( $font['font-options'], true );
1303
+                            }
1304
+                        }
1305
+
1306
+                        if ( isset( $font['font-options'] ) && ! empty( $font['font-options'] ) && isset( $this->field['all-styles'] ) && filter_var( $this->field['all-styles'], FILTER_VALIDATE_BOOLEAN ) ) {
1307
+                            if ( ! empty( $font['font-options']['variants'] ) ) {
1308
+                                if ( ! isset( Redux_Core::$typography[ $font['font-family'] ]['all-styles'] ) || empty( Redux_Core::$typography[ $font['font-family'] ]['all-styles'] ) ) {
1309
+                                    Redux_Core::$typography[ $font['font-family'] ]['all-styles'] = array();
1310
+                                    foreach ( $font['font-options']['variants'] as $variant ) {
1311
+                                        Redux_Core::$typography[ $font['font-family'] ]['all-styles'][] = $variant['id'];
1312
+                                    }
1313
+                                }
1314
+                            }
1315
+                        }
1316
+
1317
+                        if ( isset( $font['font-options'] ) && ! empty( $font['font-options'] ) && isset( $this->field['all-subsets'] ) && $this->field['all-styles'] ) {
1318
+                            if ( ! empty( $font['font-options']['subsets'] ) ) {
1319
+                                if ( ! isset( Redux_Core::$typography[ $font['font-family'] ]['all-subsets'] ) || empty( Redux_Core::$typography[ $font['font-family'] ]['all-subsets'] ) ) {
1320
+                                    Redux_Core::$typography[ $font['font-family'] ]['all-subsets'] = array();
1321
+                                    foreach ( $font['font-options']['subsets'] as $variant ) {
1322
+                                        Redux_Core::$typography[ $font['font-family'] ]['all-subsets'][] = $variant['id'];
1323
+                                    }
1324
+                                }
1325
+                            }
1326
+                        }
1327
+
1328
+                        $style = '';
1329
+
1330
+                        if ( ! empty( $font['font-weight'] ) ) {
1331
+                            if ( empty( Redux_Core::$typography[ $font['font-family'] ]['font-weight'] ) || ! in_array( $font['font-weight'], Redux_Core::$typography[ $font['font-family'] ]['font-weight'], true ) ) {
1332
+                                $style = $font['font-weight'];
1333
+                            }
1334
+
1335
+                            if ( ! empty( $font['font-style'] ) ) {
1336
+                                $style .= $font['font-style'];
1337
+                            }
1338
+
1339
+                            if ( empty( Redux_Core::$typography[ $font['font-family'] ]['font-style'] ) || ! in_array( $style, Redux_Core::$typography[ $font['font-family'] ]['font-style'], true ) ) {
1340
+                                Redux_Core::$typography[ $font['font-family'] ]['font-style'][] = $style;
1341
+                            }
1342
+                        }
1343
+
1344
+                        if ( ! empty( $font['subsets'] ) ) {
1345
+                            if ( empty( Redux_Core::$typography[ $font['font-family'] ]['subset'] ) || ! in_array( $font['subsets'], Redux_Core::$typography[ $font['font-family'] ]['subset'], true ) ) {
1346
+                                Redux_Core::$typography[ $font['font-family'] ]['subset'][] = $font['subsets'];
1347
+                            }
1348
+                        }
1349
+                    }
1350
+                }
1351
+            }
1352
+        }
1353
+
1354
+        /**
1355
+         * Localize standard, custom and typekit fonts.
1356
+         */
1357
+        private function localize_std_fonts() {
1358
+            if ( false === $this->user_fonts ) {
1359
+                if ( isset( Redux_Core::$fonts['std'] ) && ! empty( Redux_Core::$fonts['std'] ) ) {
1360
+                    return;
1361
+                }
1362
+
1363
+                Redux_Core::$font_groups['std'] = array(
1364
+                    'text'     => esc_html__( 'Standard Fonts', 'redux-framework' ),
1365
+                    'children' => array(),
1366
+                );
1367
+
1368
+                foreach ( $this->field['fonts'] as $font => $extra ) {
1369
+                    Redux_Core::$font_groups['std']['children'][] = array(
1370
+                        'id'          => $font,
1371
+                        'text'        => $font,
1372
+                        'data-google' => 'false',
1373
+                    );
1374
+                }
1375
+            }
1376
+
1377
+            if ( false !== $this->field['custom_fonts'] ) {
1378
+                // phpcs:ignored WordPress.NamingConventions.ValidHookName
1379
+                $this->field['custom_fonts'] = apply_filters( "redux/{$this->parent->args['opt_name']}/field/typography/custom_fonts", array() );
1380
+
1381
+                if ( ! empty( $this->field['custom_fonts'] ) ) {
1382
+                    foreach ( $this->field['custom_fonts'] as $group => $fonts ) {
1383
+                        Redux_Core::$font_groups['customfonts'] = array(
1384
+                            'text'     => $group,
1385
+                            'children' => array(),
1386
+                        );
1387
+
1388
+                        foreach ( $fonts as $family => $v ) {
1389
+                            Redux_Core::$font_groups['customfonts']['children'][] = array(
1390
+                                'id'          => $family,
1391
+                                'text'        => $family,
1392
+                                'data-google' => 'false',
1393
+                            );
1394
+                        }
1395
+                    }
1396
+                }
1397
+            }
1398
+
1399
+            // Typekit.
1400
+            // phpcs:ignored WordPress.NamingConventions.ValidHookName
1401
+            $typekit_fonts = apply_filters( "redux/{$this->parent->args['opt_name']}/field/typography/typekit_fonts", array() );
1402
+
1403
+            if ( ! empty( $typekit_fonts ) ) {
1404
+                foreach ( $typekit_fonts as $group => $fonts ) {
1405
+                    Redux_Core::$font_groups['typekitfonts'] = array(
1406
+                        'text'     => $group,
1407
+                        'children' => array(),
1408
+                    );
1409
+
1410
+                    foreach ( $fonts as $family => $v ) {
1411
+                        Redux_Core::$font_groups['typekitfonts']['children'][] = array(
1412
+                            'text'        => $family,
1413
+                            'id'          => $family,
1414
+                            'data-google' => 'false',
1415
+                        );
1416
+                    }
1417
+                }
1418
+            }
1419
+        }
1420
+
1421
+        /**
1422
+         *   Construct the Google array from the stored JSON/HTML
1423
+         */
1424
+        private function get_google_array() {
1425
+            if ( ( ( isset( Redux_Core::$fonts['google'] ) && ! empty( Redux_Core::$fonts['google'] ) ) ) || ( isset( Redux_Core::$fonts['google'] ) && false === Redux_Core::$fonts['google'] ) ) {
1426
+                return;
1427
+            }
1428
+
1429
+            $fonts = Redux_Helpers::google_fonts_array( get_option( 'auto_update_redux_google_fonts', false ) );
1430
+            if ( empty( $fonts ) ) {
1431
+                $google_font = __DIR__ . '/googlefonts.php';
1432
+                $fonts       = include $google_font;
1433
+            }
1434
+
1435
+            if ( true === $fonts ) {
1436
+                Redux_Core::$fonts['google'] = false;
1437
+
1438
+                return;
1439
+            }
1440
+
1441
+            if ( isset( $fonts ) && ! empty( $fonts ) && is_array( $fonts ) ) {
1442
+                Redux_Core::$fonts['google'] = $fonts;
1443
+                Redux_Core::$google_array    = $fonts;
1444
+
1445
+                // optgroup.
1446
+                Redux_Core::$font_groups['google'] = array(
1447
+                    'text'     => esc_html__( 'Google Webfonts', 'redux-framework' ),
1448
+                    'children' => array(),
1449
+                );
1450
+
1451
+                // options.
1452
+                foreach ( Redux_Core::$fonts['google'] as $font => $extra ) {
1453
+                    Redux_Core::$font_groups['google']['children'][] = array(
1454
+                        'id'          => $font,
1455
+                        'text'        => $font,
1456
+                        'data-google' => 'true',
1457
+                    );
1458
+                }
1459
+            }
1460
+        }
1461
+
1462
+        /**
1463
+         * Clean up the Google Webfonts subsets to be human-readable
1464
+         *
1465
+         * @param array $var Font subset array.
1466
+         *
1467
+         * @return array
1468
+         *
1469
+         * @since ReduxFramework 0.2.0
1470
+         */
1471
+        private function get_subsets( array $var ): array {
1472
+            $result = array();
1473
+
1474
+            foreach ( $var as $v ) {
1475
+                if ( strpos( $v, '-ext' ) ) {
1476
+                    $name = ucfirst( str_replace( '-ext', ' Extended', $v ) );
1477
+                } else {
1478
+                    $name = ucfirst( $v );
1479
+                }
1480
+
1481
+                $result[] = array(
1482
+                    'id'   => $v,
1483
+                    'name' => $name,
1484
+                );
1485
+            }
1486
+
1487
+            return array_filter( $result );
1488
+        }
1489
+
1490
+        /**
1491
+         * Clean up the Google Webfonts variants to be human-readable
1492
+         *
1493
+         * @param array $var Font variant array.
1494
+         *
1495
+         * @return array
1496
+         *
1497
+         * @since ReduxFramework 0.2.0
1498
+         */
1499
+        private function get_variants( array $var ): array {
1500
+            $result = array();
1501
+            $italic = array();
1502
+
1503
+            foreach ( $var as $v ) {
1504
+                $name = '';
1505
+                if ( 1 === $v[0] ) {
1506
+                    $name = 'Ultra-Light 100';
1507
+                } elseif ( 2 === $v[0] ) {
1508
+                    $name = 'Light 200';
1509
+                } elseif ( 3 === $v[0] ) {
1510
+                    $name = 'Book 300';
1511
+                } elseif ( 4 === $v[0] || 'r' === $v[0] || 'i' === $v[0] ) {
1512
+                    $name = 'Normal 400';
1513
+                } elseif ( 5 === $v[0] ) {
1514
+                    $name = 'Medium 500';
1515
+                } elseif ( 6 === $v[0] ) {
1516
+                    $name = 'Semi-Bold 600';
1517
+                } elseif ( 7 === $v[0] ) {
1518
+                    $name = 'Bold 700';
1519
+                } elseif ( 8 === $v[0] ) {
1520
+                    $name = 'Extra-Bold 800';
1521
+                } elseif ( 9 === $v[0] ) {
1522
+                    $name = 'Ultra-Bold 900';
1523
+                }
1524
+
1525
+                if ( 'regular' === $v ) {
1526
+                    $v = '400';
1527
+                }
1528
+
1529
+                if ( strpos( $v, 'italic' ) || 'italic' === $v ) {
1530
+                    $name .= ' Italic';
1531
+                    $name  = trim( $name );
1532
+                    if ( 'italic' === $v ) {
1533
+                        $v = '400italic';
1534
+                    }
1535
+                    $italic[] = array(
1536
+                        'id'   => $v,
1537
+                        'name' => $name,
1538
+                    );
1539
+                } else {
1540
+                    $result[] = array(
1541
+                        'id'   => $v,
1542
+                        'name' => $name,
1543
+                    );
1544
+                }
1545
+            }
1546
+
1547
+            foreach ( $italic as $item ) {
1548
+                $result[] = $item;
1549
+            }
1550
+
1551
+            return array_filter( $result );
1552
+        }
1553
+
1554
+        /**
1555
+         * Update google font array via AJAX call.
1556
+         */
1557
+        public function google_fonts_update_ajax() {
1558
+            if ( ! current_user_can( $this->parent->args['page_permissions'] ) ) {
1559
+                wp_die( esc_html__( 'You do not have permission to perform this action.', 'redux-framework' ), 403 );
1560
+            }
1561
+
1562
+            if ( ! isset( $_POST['nonce'] ) || ( ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'redux_update_google_fonts' ) ) ) {
1563
+                die( 'Security check' );
1564
+            }
1565
+
1566
+            if ( isset( $_POST['data'] ) && 'automatic' === $_POST['data'] ) {
1567
+                update_option( 'auto_update_redux_google_fonts', true );
1568
+            }
1569
+
1570
+            $fonts = Redux_Helpers::google_fonts_array( true );
1571
+
1572
+            if ( ! empty( $fonts ) && ! is_wp_error( $fonts ) ) {
1573
+                echo wp_json_encode(
1574
+                    array(
1575
+                        'status' => 'success',
1576
+                        'fonts'  => $fonts,
1577
+                    )
1578
+                );
1579
+            } else {
1580
+                $err_msg = '';
1581
+
1582
+                if ( is_wp_error( $fonts ) ) {
1583
+                    $err_msg = $fonts->get_error_code();
1584
+                }
1585
+
1586
+                echo wp_json_encode(
1587
+                    array(
1588
+                        'status' => 'error',
1589
+                        'error'  => $err_msg,
1590
+                    )
1591
+                );
1592
+            }
1593
+
1594
+            die();
1595
+        }
1596
+
1597
+        /**
1598
+         * Enable output_variables to be generated.
1599
+         *
1600
+         * @since       4.0.3
1601
+         * @return void
1602
+         */
1603
+        public function output_variables() {
1604
+            // No code needed, just defining the method is enough.
1605
+        }
1606
+    }
1607 1607
 }
1608 1608
 if ( ! class_exists( 'ReduxFramework_Typography' ) ) {
1609
-	class_alias( 'Redux_Typography', 'ReduxFramework_Typography' );
1609
+    class_alias( 'Redux_Typography', 'ReduxFramework_Typography' );
1610 1610
 }
Please login to merge, or discard this patch.
inc/extensions/color_scheme/class-redux-extension-color-scheme.php 1 patch
Indentation   +764 added lines, -764 removed lines patch added patch discarded remove patch
@@ -16,775 +16,775 @@
 block discarded – undo
16 16
 // Don't duplicate me!
17 17
 if ( ! class_exists( 'Redux_Extension_Color_Scheme' ) ) {
18 18
 
19
-	/**
20
-	 * Class Redux_Extension_Color_Scheme
21
-	 */
22
-	class Redux_Extension_Color_Scheme extends Redux_Extension_Abstract {
23
-
24
-		/**
25
-		 * Extension version.
26
-		 *
27
-		 * @var string
28
-		 */
29
-		public static $version = '4.5.10';
30
-
31
-		/**
32
-		 * Extension friendly name.
33
-		 *
34
-		 * @var string
35
-		 */
36
-		public string $extension_name = 'Color Schemes';
37
-
38
-		/**
39
-		 * Field ID.
40
-		 *
41
-		 * @var string
42
-		 */
43
-		public $field_id = '';
44
-
45
-		/**
46
-		 * Transparent output bit.
47
-		 *
48
-		 * @var bool
49
-		 */
50
-		public bool $output_transparent = false;
51
-
52
-		/**
53
-		 * Extension field name.
54
-		 *
55
-		 * @var string
56
-		 */
57
-		public string $field_name = '';
58
-
59
-		/**
60
-		 * Class Constructor. Defines the args for the extensions class
61
-		 *
62
-		 * @since       1.0.0
63
-		 * @access      public
64
-		 *
65
-		 * @param       object $redux Parent settings.
66
-		 *
67
-		 * @return      void
68
-		 */
69
-		public function __construct( $redux ) {
70
-			parent::__construct( $redux, __FILE__ );
19
+    /**
20
+     * Class Redux_Extension_Color_Scheme
21
+     */
22
+    class Redux_Extension_Color_Scheme extends Redux_Extension_Abstract {
23
+
24
+        /**
25
+         * Extension version.
26
+         *
27
+         * @var string
28
+         */
29
+        public static $version = '4.5.10';
30
+
31
+        /**
32
+         * Extension friendly name.
33
+         *
34
+         * @var string
35
+         */
36
+        public string $extension_name = 'Color Schemes';
37
+
38
+        /**
39
+         * Field ID.
40
+         *
41
+         * @var string
42
+         */
43
+        public $field_id = '';
44
+
45
+        /**
46
+         * Transparent output bit.
47
+         *
48
+         * @var bool
49
+         */
50
+        public bool $output_transparent = false;
51
+
52
+        /**
53
+         * Extension field name.
54
+         *
55
+         * @var string
56
+         */
57
+        public string $field_name = '';
58
+
59
+        /**
60
+         * Class Constructor. Defines the args for the extensions class
61
+         *
62
+         * @since       1.0.0
63
+         * @access      public
64
+         *
65
+         * @param       object $redux Parent settings.
66
+         *
67
+         * @return      void
68
+         */
69
+        public function __construct( $redux ) {
70
+            parent::__construct( $redux, __FILE__ );
71 71
 
72
-			$this->add_field( 'color_scheme' );
73
-			$this->field_name = 'color_scheme';
72
+            $this->add_field( 'color_scheme' );
73
+            $this->field_name = 'color_scheme';
74 74
 
75
-			add_filter( "redux/options/{$this->parent->args['opt_name']}/defaults", array( $this, 'set_defaults' ) );
75
+            add_filter( "redux/options/{$this->parent->args['opt_name']}/defaults", array( $this, 'set_defaults' ) );
76 76
 
77
-			// Ajax hooks.
78
-			add_action( 'wp_ajax_redux_color_schemes', array( $this, 'parse_ajax' ) );
79
-
80
-			// Reset hooks.
81
-			add_action( 'redux/validate/' . $this->parent->args['opt_name'] . '/defaults', array( $this, 'reset_defaults' ), 0, 3 );
82
-			add_action( 'redux/validate/' . $this->parent->args['opt_name'] . '/defaults_section', array( $this, 'reset_defaults_section' ), 0, 3 );
83
-
84
-			// Save filter.
85
-			add_action( 'redux/validate/' . $this->parent->args['opt_name'] . '/before_validation', array( $this, 'save_hook' ), 0, 3 );
86
-
87
-			// Register hook - to get field id and prep helper.
88
-			add_action( 'redux/options/' . $this->parent->args['opt_name'] . '/field/' . $this->field_name . '/register', array( $this, 'register_field' ) );
89
-
90
-			include_once $this->extension_dir . 'color_scheme/inc/class-redux-color-scheme-functions.php';
91
-			Redux_Color_Scheme_Functions::init( $redux );
92
-
93
-			$field = Redux_Color_Scheme_Functions::get_field( $redux );
94
-
95
-			if ( ! is_array( $field ) ) {
96
-				return;
97
-			}
98
-
99
-			$this->field_id = $field['id'];
100
-
101
-			// Prep storage.
102
-			$upload_dir = Redux_Color_Scheme_Functions::$upload_dir;
103
-
104
-			// Create uploads/redux_scheme_colors/ folder.
105
-			if ( ! is_dir( $upload_dir ) ) {
106
-				Redux_Core::$filesystem->execute( 'mkdir', $upload_dir );
107
-			}
108
-		}
77
+            // Ajax hooks.
78
+            add_action( 'wp_ajax_redux_color_schemes', array( $this, 'parse_ajax' ) );
79
+
80
+            // Reset hooks.
81
+            add_action( 'redux/validate/' . $this->parent->args['opt_name'] . '/defaults', array( $this, 'reset_defaults' ), 0, 3 );
82
+            add_action( 'redux/validate/' . $this->parent->args['opt_name'] . '/defaults_section', array( $this, 'reset_defaults_section' ), 0, 3 );
83
+
84
+            // Save filter.
85
+            add_action( 'redux/validate/' . $this->parent->args['opt_name'] . '/before_validation', array( $this, 'save_hook' ), 0, 3 );
86
+
87
+            // Register hook - to get field id and prep helper.
88
+            add_action( 'redux/options/' . $this->parent->args['opt_name'] . '/field/' . $this->field_name . '/register', array( $this, 'register_field' ) );
89
+
90
+            include_once $this->extension_dir . 'color_scheme/inc/class-redux-color-scheme-functions.php';
91
+            Redux_Color_Scheme_Functions::init( $redux );
92
+
93
+            $field = Redux_Color_Scheme_Functions::get_field( $redux );
94
+
95
+            if ( ! is_array( $field ) ) {
96
+                return;
97
+            }
98
+
99
+            $this->field_id = $field['id'];
100
+
101
+            // Prep storage.
102
+            $upload_dir = Redux_Color_Scheme_Functions::$upload_dir;
103
+
104
+            // Create uploads/redux_scheme_colors/ folder.
105
+            if ( ! is_dir( $upload_dir ) ) {
106
+                Redux_Core::$filesystem->execute( 'mkdir', $upload_dir );
107
+            }
108
+        }
109 109
 
110
-		/**
111
-		 * Set default values after reset.
112
-		 *
113
-		 * @param array $defaults Default values.
114
-		 *
115
-		 * @return array
116
-		 */
117
-		public function set_defaults( array $defaults = array() ): array {
118
-			if ( ! Redux_Helpers::is_field_in_use( $this->parent, 'color_scheme' ) ) {
119
-				return $defaults;
120
-			}
121
-
122
-			if ( empty( $this->field_id ) ) {
123
-				return $defaults;
124
-			}
125
-
126
-			$x            = get_option( $this->parent->args['opt_name'] );
127
-			$color_opts   = $x[ $this->field_id ] ?? array();
128
-			$wrong_format = false;
129
-
130
-			if ( ! isset( $color_opts['color_scheme_name'] ) ) {
131
-				$wrong_format = true;
132
-
133
-				$data = Redux_Color_Scheme_Functions::data_array_from_scheme( 'Default' );
134
-
135
-				if ( ! empty( $data ) && isset( $x[ $this->field_id ] ) ) {
136
-					$x[ $this->field_id ] = $data;
137
-
138
-					update_option( $this->parent->args['opt_name'], $x );
139
-				}
140
-			}
141
-
142
-			Redux_Color_Scheme_Functions::$parent = $this->parent;
143
-
144
-			$ot_val                   = Redux_Color_Scheme_Functions::get_output_transparent_val();
145
-			$this->output_transparent = $ot_val;
146
-
147
-			Redux_Color_Scheme_Functions::convert_to_db();
148
-
149
-			$scheme_key  = Redux_Color_Scheme_Functions::get_scheme_key();
150
-			$scheme_data = get_option( $scheme_key );
151
-
152
-			$scheme_data_exists = ! empty( $scheme_data );
153
-
154
-			$default_exists = in_array( 'default', array_map( 'strtolower', Redux_Color_Scheme_Functions::get_scheme_names() ), true );
155
-
156
-			if ( ! $scheme_data_exists || ! $default_exists || $wrong_format ) {
157
-				$data = $this->get_default_data();
158
-
159
-				// Add to (and/or create) JSON scheme file.
160
-				Redux_Color_Scheme_Functions::set_scheme_data( 'Default', $data );
161
-
162
-				// Set default scheme.
163
-				Redux_Color_Scheme_Functions::set_current_scheme_id( 'Default' );
164
-
165
-				$data = Redux_Color_Scheme_Functions::data_array_from_scheme( 'Default' );
166
-
167
-				$this->parent->options[ $this->field_id ] = $data;
168
-
169
-				$defaults[ $this->field_id ] = $data;
170
-			}
171
-
172
-			return $defaults;
173
-		}
174
-
175
-		/**
176
-		 * Field Register. Sets the whole smash up.
177
-		 *
178
-		 * @param       array $data Field data.
179
-		 *
180
-		 * @return      array
181
-		 * @since       1.0.0
182
-		 * @access      public
183
-		 */
184
-		public function register_field( array $data ): array {
185
-
186
-			// Include color_scheme helper.
187
-			include_once $this->extension_dir . 'color_scheme/inc/class-redux-color-scheme-functions.php';
188
-
189
-			if ( isset( $data['output_transparent'] ) ) {
190
-				$this->output_transparent = $data['output_transparent'];
191
-			}
110
+        /**
111
+         * Set default values after reset.
112
+         *
113
+         * @param array $defaults Default values.
114
+         *
115
+         * @return array
116
+         */
117
+        public function set_defaults( array $defaults = array() ): array {
118
+            if ( ! Redux_Helpers::is_field_in_use( $this->parent, 'color_scheme' ) ) {
119
+                return $defaults;
120
+            }
121
+
122
+            if ( empty( $this->field_id ) ) {
123
+                return $defaults;
124
+            }
125
+
126
+            $x            = get_option( $this->parent->args['opt_name'] );
127
+            $color_opts   = $x[ $this->field_id ] ?? array();
128
+            $wrong_format = false;
129
+
130
+            if ( ! isset( $color_opts['color_scheme_name'] ) ) {
131
+                $wrong_format = true;
132
+
133
+                $data = Redux_Color_Scheme_Functions::data_array_from_scheme( 'Default' );
134
+
135
+                if ( ! empty( $data ) && isset( $x[ $this->field_id ] ) ) {
136
+                    $x[ $this->field_id ] = $data;
137
+
138
+                    update_option( $this->parent->args['opt_name'], $x );
139
+                }
140
+            }
141
+
142
+            Redux_Color_Scheme_Functions::$parent = $this->parent;
143
+
144
+            $ot_val                   = Redux_Color_Scheme_Functions::get_output_transparent_val();
145
+            $this->output_transparent = $ot_val;
146
+
147
+            Redux_Color_Scheme_Functions::convert_to_db();
148
+
149
+            $scheme_key  = Redux_Color_Scheme_Functions::get_scheme_key();
150
+            $scheme_data = get_option( $scheme_key );
151
+
152
+            $scheme_data_exists = ! empty( $scheme_data );
153
+
154
+            $default_exists = in_array( 'default', array_map( 'strtolower', Redux_Color_Scheme_Functions::get_scheme_names() ), true );
155
+
156
+            if ( ! $scheme_data_exists || ! $default_exists || $wrong_format ) {
157
+                $data = $this->get_default_data();
158
+
159
+                // Add to (and/or create) JSON scheme file.
160
+                Redux_Color_Scheme_Functions::set_scheme_data( 'Default', $data );
161
+
162
+                // Set default scheme.
163
+                Redux_Color_Scheme_Functions::set_current_scheme_id( 'Default' );
164
+
165
+                $data = Redux_Color_Scheme_Functions::data_array_from_scheme( 'Default' );
166
+
167
+                $this->parent->options[ $this->field_id ] = $data;
168
+
169
+                $defaults[ $this->field_id ] = $data;
170
+            }
171
+
172
+            return $defaults;
173
+        }
174
+
175
+        /**
176
+         * Field Register. Sets the whole smash up.
177
+         *
178
+         * @param       array $data Field data.
179
+         *
180
+         * @return      array
181
+         * @since       1.0.0
182
+         * @access      public
183
+         */
184
+        public function register_field( array $data ): array {
185
+
186
+            // Include color_scheme helper.
187
+            include_once $this->extension_dir . 'color_scheme/inc/class-redux-color-scheme-functions.php';
188
+
189
+            if ( isset( $data['output_transparent'] ) ) {
190
+                $this->output_transparent = $data['output_transparent'];
191
+            }
192 192
 
193
-			$this->field_id                         = $data['id'];
194
-			Redux_Color_Scheme_Functions::$field_id = $data['id'];
195
-
196
-			// Set helper parent object.
197
-			Redux_Color_Scheme_Functions::$parent = $this->parent;
198
-
199
-			// Prep storage.
200
-			$upload_dir = Redux_Color_Scheme_Functions::$upload_dir;
201
-
202
-			// Set upload_dir cookie.
203
-			setcookie( 'redux_color_scheme_upload_dir', $upload_dir, 0, '/' );
204
-
205
-			return $data;
206
-		}
207
-
208
-		/**
209
-		 * Reset defaults.
210
-		 *
211
-		 * @param array $defaults Default values.
212
-		 *
213
-		 * @return array
214
-		 */
215
-		public function reset_defaults( array $defaults = array() ): array {
216
-			if ( Redux_Helpers::is_field_in_use( $this->parent, 'color_scheme' ) ) {
217
-				// Check if reset_all was fired.
218
-				$this->reset_all();
219
-				$defaults[ $this->field_id ] = Redux_Color_Scheme_Functions::data_array_from_scheme( 'Default' );
220
-			}
193
+            $this->field_id                         = $data['id'];
194
+            Redux_Color_Scheme_Functions::$field_id = $data['id'];
195
+
196
+            // Set helper parent object.
197
+            Redux_Color_Scheme_Functions::$parent = $this->parent;
198
+
199
+            // Prep storage.
200
+            $upload_dir = Redux_Color_Scheme_Functions::$upload_dir;
201
+
202
+            // Set upload_dir cookie.
203
+            setcookie( 'redux_color_scheme_upload_dir', $upload_dir, 0, '/' );
204
+
205
+            return $data;
206
+        }
207
+
208
+        /**
209
+         * Reset defaults.
210
+         *
211
+         * @param array $defaults Default values.
212
+         *
213
+         * @return array
214
+         */
215
+        public function reset_defaults( array $defaults = array() ): array {
216
+            if ( Redux_Helpers::is_field_in_use( $this->parent, 'color_scheme' ) ) {
217
+                // Check if reset_all was fired.
218
+                $this->reset_all();
219
+                $defaults[ $this->field_id ] = Redux_Color_Scheme_Functions::data_array_from_scheme( 'Default' );
220
+            }
221 221
 
222
-			return $defaults;
223
-		}
222
+            return $defaults;
223
+        }
224 224
 
225
-		/**
226
-		 * Reset section defaults.
227
-		 *
228
-		 * @param array $defaults Default values.
229
-		 *
230
-		 * @return array
231
-		 */
232
-		public function reset_defaults_section( array $defaults = array() ): array {
233
-			if ( Redux_Helpers::is_field_in_use( $this->parent, 'color_scheme' ) ) {
234
-				// Get the current tab/section number.
235
-				if ( isset( $_COOKIE['redux_current_tab'] ) ) {
236
-					$cur_tab = sanitize_text_field( wp_unslash( $_COOKIE['redux_current_tab'] ) );
237
-
238
-					// Get the tab/section number field is used on.
239
-					$tab_num = $this->parent->field_sections['color_scheme'][ $this->field_id ];
240
-
241
-					// Match...
242
-					if ( $cur_tab === $tab_num ) {
243
-
244
-						// Reset data.
245
-						$this->reset_all();
246
-					}
247
-					$defaults[ $this->field_id ] = Redux_Color_Scheme_Functions::data_array_from_scheme( 'Default' );
248
-				}
249
-			}
250
-
251
-			return $defaults;
252
-		}
253
-
254
-		/**
255
-		 * Save Changes Hook. What to do when changes are saved
256
-		 *
257
-		 * @param array $saved_options Saved data.
258
-		 * @param array $old_options   Previous data.
259
-		 *
260
-		 * @return      array
261
-		 * @since       1.0.0
262
-		 * @access      public
263
-		 */
264
-		public function save_hook( array $saved_options = array(), array $old_options = array() ): array {
265
-			if ( ! isset( $saved_options[ $this->field_id ] ) || empty( $saved_options[ $this->field_id ] ) || ( is_array( $saved_options[ $this->field_id ] ) && $old_options === $saved_options ) || ! array_key_exists( $this->field_id, $saved_options ) ) {
266
-				return $saved_options;
267
-			}
268
-
269
-			// We'll use the reset hook instead.
270
-			if ( ! empty( $saved_options['defaults'] ) || ! empty( $saved_options['defaults-section'] ) ) {
271
-				return $saved_options;
272
-			}
273
-
274
-			$first_value = reset( $saved_options[ $this->field_id ] ); // First Element's Value.
275
-
276
-			// Parse the JSON to an array.
277
-			if ( isset( $first_value['data'] ) ) {
278
-
279
-				Redux_Color_Scheme_Functions::$parent   = $this->parent;
280
-				Redux_Color_Scheme_Functions::$field_id = $this->field_id;
281
-
282
-				Redux_Color_Scheme_Functions::set_current_scheme_id( $saved_options['redux-scheme-select'] );
283
-
284
-				// Get the current field ID.
285
-				$raw_data = $saved_options[ $this->field_id ];
286
-
287
-				// Create a new array.
288
-				$save_data = array();
289
-
290
-				// Enum through saved data.
291
-				foreach ( $raw_data as $id => $val ) {
292
-
293
-					if ( 'color_scheme_name' !== $id ) {
294
-						if ( is_array( $val ) ) {
295
-
296
-							if ( ! isset( $val['data'] ) ) {
297
-								continue;
298
-							}
299
-
300
-							$data = json_decode( rawurldecode( $val['data'] ), true );
301
-
302
-							// Sanitize everything.
303
-							$color = $data['color'] ?? '';
304
-							$alpha = $data['alpha'] ?? 1;
305
-
306
-							$id    = $data['id'] ?? $id;
307
-							$title = $data['title'] ?? $id;
308
-
309
-							$grp = $data['group'] ?? '';
310
-
311
-							if ( '' === $color || 'transparent' === $color ) {
312
-								$rgba = $this->output_transparent ? 'transparent' : '';
313
-							} else {
314
-								$rgba = Redux_Helpers::hex2rgba( $color, $alpha );
315
-							}
316
-
317
-							// Create an array of saved data.
318
-							$save_data[] = array(
319
-								'id'    => $id,
320
-								'title' => $title,
321
-								'color' => $color,
322
-								'alpha' => $alpha,
323
-								'group' => $grp,
324
-								'rgba'  => $rgba,
325
-							);
326
-						} else {
327
-							$save_data[] = array(
328
-								'id'    => $id,
329
-								'value' => $val,
330
-								'type'  => 'select',
331
-							);
332
-						}
333
-					}
334
-				}
335
-
336
-				$new_scheme = array();
337
-
338
-				$new_scheme['color_scheme_name'] = Redux_Color_Scheme_Functions::get_current_scheme_id();
339
-
340
-				// Enum through values and assign them to a new array.
341
-				foreach ( $save_data as $val ) {
342
-					if ( isset( $val['id'] ) ) {
343
-						$new_scheme[ $val['id'] ] = $val;
344
-					}
345
-				}
346
-
347
-				// Filter for DB save
348
-				// Doesn't need to save select arrays to a database,
349
-				// just the id => value.
350
-				$database_data = $new_scheme;
351
-
352
-				foreach ( $database_data as $k => $v ) {
353
-					if ( isset( $v['type'] ) ) {
354
-						$val = $v['value'];
355
-
356
-						unset( $database_data[ $k ] );
357
-
358
-						$database_data[ $k ] = $val;
359
-					}
360
-				}
361
-
362
-				$saved_options[ $this->field_id ] = $database_data;
363
-
364
-				// Check if we should save this compared to the old data.
365
-				$save_scheme = false;
366
-
367
-				// Doesn't exist or is empty.
368
-				if ( ! isset( $old_options[ $this->field_id ] ) || ( isset( $old_options[ $this->field_id ] ) && ! empty( $old_options[ $this->field_id ] ) ) ) {
369
-					$save_scheme = true;
370
-				}
371
-
372
-				// Isn't empty and isn't the same as the new array.
373
-				if ( ! empty( $old_options[ $this->field_id ] ) && $saved_options[ $this->field_id ] !== $old_options[ $this->field_id ] ) {
374
-					$save_scheme = true;
375
-				}
376
-
377
-				if ( $save_scheme ) {
378
-					$scheme = Redux_Color_Scheme_Functions::get_current_scheme_id();
379
-					Redux_Color_Scheme_Functions::set_scheme_data( $scheme, $save_data );
380
-				}
381
-			}
382
-
383
-			return $saved_options;
384
-		}
385
-
386
-		/**
387
-		 * Reset data. Restores colour picker to default values
388
-		 *
389
-		 * @since       1.0.0
390
-		 * @access      private
391
-		 * @return      void
392
-		 */
393
-		private function reset_data() {
394
-			Redux_Color_Scheme_Functions::$parent   = $this->parent;
395
-			Redux_Color_Scheme_Functions::$field_id = $this->field_id;
396
-
397
-			// Get default data.
398
-			$data = $this->get_default_data();
399
-
400
-			// Add to (and/or create) JSON scheme file.
401
-			Redux_Color_Scheme_Functions::set_scheme_data( 'Default', $data );
402
-
403
-			// Set default scheme.
404
-			Redux_Color_Scheme_Functions::set_current_scheme_id( 'Default' );
405
-		}
406
-
407
-		/**
408
-		 * Reset All Hook. Todo list when all data is reset
409
-		 *
410
-		 * @return      void
411
-		 * @since       1.0.0
412
-		 * @access      public
413
-		 */
414
-		public function reset_all() {
415
-			if ( ! empty( $this->field_id ) && isset( $this->parent->options_defaults[ $this->field_id ] ) && ! empty( $this->parent->options_defaults[ $this->field_id ] ) ) {
416
-				Redux_Color_Scheme_Functions::$parent   = $this->parent;
417
-				Redux_Color_Scheme_Functions::$field_id = $this->field_id;
418
-
419
-				$this->reset_data();
420
-			}
421
-		}
422
-
423
-		/**
424
-		 * AJAX evaluator. Determine course of action based on AJAX callback
425
-		 *
426
-		 * @since       1.0.0
427
-		 * @access      public
428
-		 * @return      void
429
-		 */
430
-		public function parse_ajax() {
431
-			if ( ! is_admin() ) {
432
-				wp_die();
433
-			}
434
-
435
-			if ( ! current_user_can( $this->parent->args['page_permissions'] ) ) {
436
-				wp_die( esc_html__( 'You do not have permission to perform this action.', 'redux-framework' ) );
437
-			}
438
-
439
-			$opt_name = $this->parent->args['opt_name'];
440
-			$parent   = $this->parent;
441
-
442
-			$nonce = isset( $_REQUEST['nonce'] ) ? sanitize_key( wp_unslash( $_REQUEST['nonce'] ) ) : '';
443
-			if ( ! wp_verify_nonce( $nonce, 'redux_' . $opt_name . '_color_schemes' ) ) {
444
-				wp_die( esc_html__( 'Invalid Security Credentials. Please reload the page and try again.', 'redux-framework' ) );
445
-			}
446
-
447
-			$type = isset( $_REQUEST['type'] ) ? sanitize_key( wp_unslash( $_REQUEST['type'] ) ) : '';
448
-			if ( ! in_array( $type, array( 'save', 'delete', 'update', 'export', 'import' ), true ) ) {
449
-				wp_die( esc_html__( 'Invalid request.', 'redux-framework' ) );
450
-			}
451
-
452
-			if ( 'save' === $type ) {
453
-				$this->save_scheme( $parent );
454
-			} elseif ( 'delete' === $type ) {
455
-				$this->delete_scheme( $parent );
456
-			} elseif ( 'update' === $type ) {
457
-				$this->get_scheme_html( $parent );
458
-			} elseif ( 'export' === $type ) {
459
-				$this->download_schemes();
460
-			} elseif ( 'import' === $type ) {
461
-				$this->import_schemes();
462
-			}
463
-		}
464
-
465
-		/**
466
-		 * Download Scheme File.
467
-		 *
468
-		 * @since       4.4.18
469
-		 * @access      private
470
-		 * @return      void
471
-		 */
472
-		private function import_schemes() {
473
-			if ( isset( $_REQUEST['content'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
474
-				$content = wp_unslash( $_REQUEST['content'] ); // phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
475
-				$content = is_array( $content ) ? array_map( 'stripslashes_deep', $content ) : stripslashes( $content );
476
-				$content = json_decode( $content, true );
477
-
478
-				if ( is_null( $content ) ) {
479
-					$result = array(
480
-						'result' => false,
481
-						'data'   => esc_html__( 'Import unsuccessful! Malformed JSON data detected.', 'redux-framework' ),
482
-					);
483
-
484
-					$result = wp_json_encode( $result );
485
-
486
-					echo $result; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
487
-
488
-					die;
489
-				}
490
-
491
-				if ( isset( $content['Default']['color_scheme_name'] ) ) {
492
-					$content = wp_json_encode( $content );
493
-
494
-					$param_array = array(
495
-						'content'   => $content,
496
-						'overwrite' => true,
497
-						'chmod'     => FS_CHMOD_FILE,
498
-					);
499
-
500
-					$import_file = Redux_Color_Scheme_Functions::$upload_dir . Redux_Color_Scheme_Functions::$parent->args['opt_name'] . '_' . Redux_Color_Scheme_Functions::$field_id . '.json';
501
-
502
-					if ( true === Redux_Core::$filesystem->execute( 'put_contents', $import_file, $param_array ) ) {
503
-						$result = array(
504
-							'result' => true,
505
-							// translators: %s = HTML content.
506
-							'data'   => sprintf( esc_html__( 'Import successful! Click %s to refresh.', 'redux-framework' ), '<strong>' . esc_html__( 'OK', 'redux-framework' ) . '</strong>' ),
507
-						);
508
-					} else {
509
-						$result = array(
510
-							'result' => false,
511
-							'data'   => esc_html__( 'Import unsuccessful! File permission error: Could not write import data to server.', 'redux-framework' ),
512
-						);
513
-					}
514
-				} else {
515
-					$result = array(
516
-						'result' => false,
517
-						'data'   => esc_html__( 'Import unsuccessful! The selected file is not a valid color scheme file.', 'redux-framework' ),
518
-					);
519
-				}
520
-			} else {
521
-				$result = array(
522
-					'result' => false,
523
-					'data'   => esc_html__( 'Import unsuccessful! No data detected in the import file.', 'redux-framework' ),
524
-				);
525
-			}
526
-
527
-			$result = wp_json_encode( $result );
528
-
529
-			echo $result; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
530
-
531
-			die;
532
-		}
533
-
534
-		/**
535
-		 * Download Scheme File.
536
-		 *
537
-		 * @since       1.0.0
538
-		 * @access      private
539
-		 * @return      void
540
-		 */
541
-		private function download_schemes() {
542
-			Redux_Color_Scheme_Functions::$parent   = $this->parent;
543
-			Redux_Color_Scheme_Functions::$field_id = $this->field_id;
544
-
545
-			// Read contents of scheme file.
546
-			$content = Redux_Color_Scheme_Functions::read_scheme_file();
547
-			$content = wp_json_encode( $content );
548
-
549
-			// Set header info.
550
-			header( 'Content-Description: File Transfer' );
551
-			header( 'Content-type: application/txt' );
552
-			header( 'Content-Disposition: attachment; filename="redux_schemes_' . $this->parent->args['opt_name'] . '_' . $this->field_id . '_' . gmdate( 'm-d-Y' ) . '.json"' );
553
-			header( 'Content-Transfer-Encoding: binary' );
554
-			header( 'Expires: 0' );
555
-			header( 'Cache-Control: must-revalidate' );
556
-			header( 'Pragma: public' );
557
-
558
-			// File download.
559
-			echo $content; // phpcs:ignore WordPress.Security.EscapeOutput
560
-
561
-			// 2B ~! 2B
562
-			die;
563
-		}
564
-
565
-		/**
566
-		 * Save Scheme. Saved an individual scheme to JSON scheme file.
567
-		 *
568
-		 * @param ReduxFramework $redux ReduxFramework object.
569
-		 *
570
-		 * @return      void
571
-		 * @since       1.0.0
572
-		 * @access      private
573
-		 */
574
-		private function save_scheme( ReduxFramework $redux ) {
575
-			Redux_Color_Scheme_Functions::$parent   = $redux;
576
-			Redux_Color_Scheme_Functions::$field_id = $this->field_id;
577
-
578
-			// Get the scheme name.
579
-			if ( isset( $_REQUEST['scheme_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
580
-				$scheme_name = sanitize_text_field( wp_unslash( $_REQUEST['scheme_name'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
581
-
582
-				// Check for duplicates.
583
-				$names = Redux_Color_Scheme_Functions::get_scheme_names();
584
-				foreach ( $names as $name ) {
585
-					$name     = strtolower( $name );
586
-					$tmp_name = strtolower( $scheme_name );
587
-
588
-					if ( $name === $tmp_name ) {
589
-						echo 'fail';
590
-						die();
591
-					}
592
-				}
593
-
594
-				// Get scheme data.
595
-				if ( isset( $_REQUEST['scheme_data'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
596
-					$scheme_data = wp_unslash( $_REQUEST['scheme_data'] ); // phpcs:ignore WordPress.Security
597
-
598
-					// Get field ID.
599
-					if ( isset( $_REQUEST['field_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
600
-						$scheme_data = rawurldecode( $scheme_data );
601
-						$scheme_data = json_decode( $scheme_data, true );
602
-
603
-						// Save scheme to file.  If successful...
604
-						if ( true === Redux_Color_Scheme_Functions::set_scheme_data( $scheme_name, $scheme_data ) ) {
605
-
606
-							// Update scheme selector.
607
-							echo Redux_Color_Scheme_Functions::get_scheme_select_html( $scheme_name ); // phpcs:ignore WordPress.Security.EscapeOutput
608
-						}
609
-					}
610
-				}
611
-			}
612
-
613
-			die(); // a horrible death!
614
-		}
615
-
616
-		/**
617
-		 * Delete Scheme. Delete individual scheme from JSON scheme file.
618
-		 *
619
-		 * @param ReduxFramework $redux ReduxFramework object.
620
-		 *
621
-		 * @return      void
622
-		 * @since       1.0.0
623
-		 * @access      private
624
-		 */
625
-		private function delete_scheme( ReduxFramework $redux ) {
626
-
627
-			// Get deleted scheme ID.
628
-			if ( isset( $_REQUEST['scheme_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
629
-				$scheme_id = sanitize_text_field( wp_unslash( $_REQUEST['scheme_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
630
-
631
-				// Get field ID.
632
-				if ( isset( $_REQUEST['field_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
633
-					$field_id = sanitize_text_field( wp_unslash( $_REQUEST['field_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
634
-
635
-					// If scheme ID was passed (and why wouldn't it be?? Hmm??).
636
-					if ( $scheme_id ) {
637
-						Redux_Color_Scheme_Functions::$field_id = $field_id;
638
-						Redux_Color_Scheme_Functions::$parent   = $redux;
639
-
640
-						// Get the entire scheme file.
641
-						$schemes = Redux_Color_Scheme_Functions::read_scheme_file();
642
-
643
-						// If we got a good read...
644
-						if ( false !== $schemes ) {
645
-
646
-							// If scheme name exists...
647
-							if ( isset( $schemes[ $scheme_id ] ) ) {
648
-
649
-								// Unset it.
650
-								unset( $schemes[ $scheme_id ] );
651
-
652
-								// Save the scheme data, minus the deleted scheme.  Upon success...
653
-								if ( true === Redux_Color_Scheme_Functions::write_scheme_file( $schemes ) ) {
654
-
655
-									// Set default scheme.
656
-									Redux_Color_Scheme_Functions::set_current_scheme_id( 'Default' );
657
-
658
-									// Update field ID.
659
-									Redux_Color_Scheme_Functions::$field_id = $field_id;
660
-
661
-									// Meh TODO.
662
-									Redux_Color_Scheme_Functions::set_database_data();
663
-
664
-									echo 'success';
665
-								} else {
666
-									echo 'Failed to write JSON file to server.';
667
-								}
668
-							} else {
669
-								echo 'Scheme name does not exist in JSON string.  Aborting.';
670
-							}
671
-						} else {
672
-							echo 'Failed to read JSON scheme file, or file is empty.';
673
-						}
674
-					} else {
675
-						echo 'No scheme ID passed.  Aborting.';
676
-					}
677
-				}
678
-			}
679
-
680
-			die(); // rolled a two.
681
-		}
682
-
683
-		/**
684
-		 * Gets the new scheme based on selection.
685
-		 *
686
-		 * @param ReduxFramework $redux ReduxFramework object.
687
-		 *
688
-		 * @return      void
689
-		 * @since       1.0.0
690
-		 * @access      private
691
-		 */
692
-		private function get_scheme_html( ReduxFramework $redux ) {
693
-			if ( isset( $_POST['scheme_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
694
-
695
-				// Get the selected scheme name.
696
-				$scheme_id = sanitize_text_field( wp_unslash( $_POST['scheme_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
697
-
698
-				if ( isset( $_POST['field_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
699
-
700
-					// Get the field ID.
701
-					$field_id = sanitize_text_field( wp_unslash( $_POST['field_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
702
-
703
-					// Get the field class.
704
-					$field_class = isset( $_POST['field_class'] ) ? sanitize_text_field( wp_unslash( $_POST['field_class'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
705
-
706
-					Redux_Color_Scheme_Functions::$parent = $redux;
707
-
708
-					// Set the updated field ID.
709
-					Redux_Color_Scheme_Functions::$field_id = $field_id;
710
-
711
-					// Set the updated field class.
712
-					Redux_Color_Scheme_Functions::$field_class = $field_class;
713
-
714
-					// Get the color picket layout HTML.
715
-					$html = Redux_Color_Scheme_Functions::get_current_color_scheme_html( $scheme_id );
716
-
717
-					// Print!
718
-					echo $html; // phpcs:ignore WordPress.Security.EscapeOutput
719
-				}
720
-			}
721
-
722
-			die(); // another day.
723
-		}
724
-
725
-
726
-		/**
727
-		 * Retrieves an array of default data for color picker.
728
-		 *
729
-		 * @since       1.0.0
730
-		 * @access      private
731
-		 * @return      array Default values from config.
732
-		 */
733
-		private function get_default_data(): array {
734
-			$def_opts = $this->parent->options_defaults[ $this->field_id ];
735
-
736
-			if ( isset( $def_opts['color_scheme_name'] ) ) {
737
-				return array();
738
-			}
739
-
740
-			$sections = $this->parent->sections;
741
-			$data     = array();
742
-
743
-			foreach ( $sections as $arr ) {
744
-				if ( isset( $arr['fields'] ) ) {
745
-					foreach ( $arr['fields'] as $arr2 ) {
746
-						if ( $arr2['id'] === $this->field_id ) {
747
-
748
-							// Select fields.
749
-							if ( isset( $arr2['select'] ) ) {
750
-								foreach ( $arr2['select'] as $v ) {
751
-									$data[] = array(
752
-										'id'    => $v['id'],
753
-										'value' => $v['default'],
754
-										'type'  => 'select',
755
-									);
756
-								}
757
-							}
758
-						}
759
-					}
760
-				}
761
-			}
762
-
763
-			foreach ( $def_opts as $v ) {
764
-				$title = $v['title'] ?? $v['id'];
765
-				$color = $v['color'] ?? '';
766
-				$alpha = $v['alpha'] ?? 1;
767
-				$grp   = $v['group'] ?? '';
768
-
769
-				if ( '' === $color || 'transparent' === $color ) {
770
-					$rgba = $this->output_transparent ? 'transparent' : '';
771
-				} else {
772
-					$rgba = Redux_Helpers::hex2rgba( $color, $alpha );
773
-				}
774
-
775
-				$data[] = array(
776
-					'id'    => $v['id'],
777
-					'title' => $title,
778
-					'color' => $color,
779
-					'alpha' => $alpha,
780
-					'group' => $grp,
781
-					'rgba'  => $rgba,
782
-				);
783
-			}
784
-
785
-			return $data;
786
-		}
787
-	}
788
-
789
-	class_alias( Redux_Extension_Color_Scheme::class, 'ReduxFramework_Extension_Color_Scheme' );
225
+        /**
226
+         * Reset section defaults.
227
+         *
228
+         * @param array $defaults Default values.
229
+         *
230
+         * @return array
231
+         */
232
+        public function reset_defaults_section( array $defaults = array() ): array {
233
+            if ( Redux_Helpers::is_field_in_use( $this->parent, 'color_scheme' ) ) {
234
+                // Get the current tab/section number.
235
+                if ( isset( $_COOKIE['redux_current_tab'] ) ) {
236
+                    $cur_tab = sanitize_text_field( wp_unslash( $_COOKIE['redux_current_tab'] ) );
237
+
238
+                    // Get the tab/section number field is used on.
239
+                    $tab_num = $this->parent->field_sections['color_scheme'][ $this->field_id ];
240
+
241
+                    // Match...
242
+                    if ( $cur_tab === $tab_num ) {
243
+
244
+                        // Reset data.
245
+                        $this->reset_all();
246
+                    }
247
+                    $defaults[ $this->field_id ] = Redux_Color_Scheme_Functions::data_array_from_scheme( 'Default' );
248
+                }
249
+            }
250
+
251
+            return $defaults;
252
+        }
253
+
254
+        /**
255
+         * Save Changes Hook. What to do when changes are saved
256
+         *
257
+         * @param array $saved_options Saved data.
258
+         * @param array $old_options   Previous data.
259
+         *
260
+         * @return      array
261
+         * @since       1.0.0
262
+         * @access      public
263
+         */
264
+        public function save_hook( array $saved_options = array(), array $old_options = array() ): array {
265
+            if ( ! isset( $saved_options[ $this->field_id ] ) || empty( $saved_options[ $this->field_id ] ) || ( is_array( $saved_options[ $this->field_id ] ) && $old_options === $saved_options ) || ! array_key_exists( $this->field_id, $saved_options ) ) {
266
+                return $saved_options;
267
+            }
268
+
269
+            // We'll use the reset hook instead.
270
+            if ( ! empty( $saved_options['defaults'] ) || ! empty( $saved_options['defaults-section'] ) ) {
271
+                return $saved_options;
272
+            }
273
+
274
+            $first_value = reset( $saved_options[ $this->field_id ] ); // First Element's Value.
275
+
276
+            // Parse the JSON to an array.
277
+            if ( isset( $first_value['data'] ) ) {
278
+
279
+                Redux_Color_Scheme_Functions::$parent   = $this->parent;
280
+                Redux_Color_Scheme_Functions::$field_id = $this->field_id;
281
+
282
+                Redux_Color_Scheme_Functions::set_current_scheme_id( $saved_options['redux-scheme-select'] );
283
+
284
+                // Get the current field ID.
285
+                $raw_data = $saved_options[ $this->field_id ];
286
+
287
+                // Create a new array.
288
+                $save_data = array();
289
+
290
+                // Enum through saved data.
291
+                foreach ( $raw_data as $id => $val ) {
292
+
293
+                    if ( 'color_scheme_name' !== $id ) {
294
+                        if ( is_array( $val ) ) {
295
+
296
+                            if ( ! isset( $val['data'] ) ) {
297
+                                continue;
298
+                            }
299
+
300
+                            $data = json_decode( rawurldecode( $val['data'] ), true );
301
+
302
+                            // Sanitize everything.
303
+                            $color = $data['color'] ?? '';
304
+                            $alpha = $data['alpha'] ?? 1;
305
+
306
+                            $id    = $data['id'] ?? $id;
307
+                            $title = $data['title'] ?? $id;
308
+
309
+                            $grp = $data['group'] ?? '';
310
+
311
+                            if ( '' === $color || 'transparent' === $color ) {
312
+                                $rgba = $this->output_transparent ? 'transparent' : '';
313
+                            } else {
314
+                                $rgba = Redux_Helpers::hex2rgba( $color, $alpha );
315
+                            }
316
+
317
+                            // Create an array of saved data.
318
+                            $save_data[] = array(
319
+                                'id'    => $id,
320
+                                'title' => $title,
321
+                                'color' => $color,
322
+                                'alpha' => $alpha,
323
+                                'group' => $grp,
324
+                                'rgba'  => $rgba,
325
+                            );
326
+                        } else {
327
+                            $save_data[] = array(
328
+                                'id'    => $id,
329
+                                'value' => $val,
330
+                                'type'  => 'select',
331
+                            );
332
+                        }
333
+                    }
334
+                }
335
+
336
+                $new_scheme = array();
337
+
338
+                $new_scheme['color_scheme_name'] = Redux_Color_Scheme_Functions::get_current_scheme_id();
339
+
340
+                // Enum through values and assign them to a new array.
341
+                foreach ( $save_data as $val ) {
342
+                    if ( isset( $val['id'] ) ) {
343
+                        $new_scheme[ $val['id'] ] = $val;
344
+                    }
345
+                }
346
+
347
+                // Filter for DB save
348
+                // Doesn't need to save select arrays to a database,
349
+                // just the id => value.
350
+                $database_data = $new_scheme;
351
+
352
+                foreach ( $database_data as $k => $v ) {
353
+                    if ( isset( $v['type'] ) ) {
354
+                        $val = $v['value'];
355
+
356
+                        unset( $database_data[ $k ] );
357
+
358
+                        $database_data[ $k ] = $val;
359
+                    }
360
+                }
361
+
362
+                $saved_options[ $this->field_id ] = $database_data;
363
+
364
+                // Check if we should save this compared to the old data.
365
+                $save_scheme = false;
366
+
367
+                // Doesn't exist or is empty.
368
+                if ( ! isset( $old_options[ $this->field_id ] ) || ( isset( $old_options[ $this->field_id ] ) && ! empty( $old_options[ $this->field_id ] ) ) ) {
369
+                    $save_scheme = true;
370
+                }
371
+
372
+                // Isn't empty and isn't the same as the new array.
373
+                if ( ! empty( $old_options[ $this->field_id ] ) && $saved_options[ $this->field_id ] !== $old_options[ $this->field_id ] ) {
374
+                    $save_scheme = true;
375
+                }
376
+
377
+                if ( $save_scheme ) {
378
+                    $scheme = Redux_Color_Scheme_Functions::get_current_scheme_id();
379
+                    Redux_Color_Scheme_Functions::set_scheme_data( $scheme, $save_data );
380
+                }
381
+            }
382
+
383
+            return $saved_options;
384
+        }
385
+
386
+        /**
387
+         * Reset data. Restores colour picker to default values
388
+         *
389
+         * @since       1.0.0
390
+         * @access      private
391
+         * @return      void
392
+         */
393
+        private function reset_data() {
394
+            Redux_Color_Scheme_Functions::$parent   = $this->parent;
395
+            Redux_Color_Scheme_Functions::$field_id = $this->field_id;
396
+
397
+            // Get default data.
398
+            $data = $this->get_default_data();
399
+
400
+            // Add to (and/or create) JSON scheme file.
401
+            Redux_Color_Scheme_Functions::set_scheme_data( 'Default', $data );
402
+
403
+            // Set default scheme.
404
+            Redux_Color_Scheme_Functions::set_current_scheme_id( 'Default' );
405
+        }
406
+
407
+        /**
408
+         * Reset All Hook. Todo list when all data is reset
409
+         *
410
+         * @return      void
411
+         * @since       1.0.0
412
+         * @access      public
413
+         */
414
+        public function reset_all() {
415
+            if ( ! empty( $this->field_id ) && isset( $this->parent->options_defaults[ $this->field_id ] ) && ! empty( $this->parent->options_defaults[ $this->field_id ] ) ) {
416
+                Redux_Color_Scheme_Functions::$parent   = $this->parent;
417
+                Redux_Color_Scheme_Functions::$field_id = $this->field_id;
418
+
419
+                $this->reset_data();
420
+            }
421
+        }
422
+
423
+        /**
424
+         * AJAX evaluator. Determine course of action based on AJAX callback
425
+         *
426
+         * @since       1.0.0
427
+         * @access      public
428
+         * @return      void
429
+         */
430
+        public function parse_ajax() {
431
+            if ( ! is_admin() ) {
432
+                wp_die();
433
+            }
434
+
435
+            if ( ! current_user_can( $this->parent->args['page_permissions'] ) ) {
436
+                wp_die( esc_html__( 'You do not have permission to perform this action.', 'redux-framework' ) );
437
+            }
438
+
439
+            $opt_name = $this->parent->args['opt_name'];
440
+            $parent   = $this->parent;
441
+
442
+            $nonce = isset( $_REQUEST['nonce'] ) ? sanitize_key( wp_unslash( $_REQUEST['nonce'] ) ) : '';
443
+            if ( ! wp_verify_nonce( $nonce, 'redux_' . $opt_name . '_color_schemes' ) ) {
444
+                wp_die( esc_html__( 'Invalid Security Credentials. Please reload the page and try again.', 'redux-framework' ) );
445
+            }
446
+
447
+            $type = isset( $_REQUEST['type'] ) ? sanitize_key( wp_unslash( $_REQUEST['type'] ) ) : '';
448
+            if ( ! in_array( $type, array( 'save', 'delete', 'update', 'export', 'import' ), true ) ) {
449
+                wp_die( esc_html__( 'Invalid request.', 'redux-framework' ) );
450
+            }
451
+
452
+            if ( 'save' === $type ) {
453
+                $this->save_scheme( $parent );
454
+            } elseif ( 'delete' === $type ) {
455
+                $this->delete_scheme( $parent );
456
+            } elseif ( 'update' === $type ) {
457
+                $this->get_scheme_html( $parent );
458
+            } elseif ( 'export' === $type ) {
459
+                $this->download_schemes();
460
+            } elseif ( 'import' === $type ) {
461
+                $this->import_schemes();
462
+            }
463
+        }
464
+
465
+        /**
466
+         * Download Scheme File.
467
+         *
468
+         * @since       4.4.18
469
+         * @access      private
470
+         * @return      void
471
+         */
472
+        private function import_schemes() {
473
+            if ( isset( $_REQUEST['content'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
474
+                $content = wp_unslash( $_REQUEST['content'] ); // phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
475
+                $content = is_array( $content ) ? array_map( 'stripslashes_deep', $content ) : stripslashes( $content );
476
+                $content = json_decode( $content, true );
477
+
478
+                if ( is_null( $content ) ) {
479
+                    $result = array(
480
+                        'result' => false,
481
+                        'data'   => esc_html__( 'Import unsuccessful! Malformed JSON data detected.', 'redux-framework' ),
482
+                    );
483
+
484
+                    $result = wp_json_encode( $result );
485
+
486
+                    echo $result; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
487
+
488
+                    die;
489
+                }
490
+
491
+                if ( isset( $content['Default']['color_scheme_name'] ) ) {
492
+                    $content = wp_json_encode( $content );
493
+
494
+                    $param_array = array(
495
+                        'content'   => $content,
496
+                        'overwrite' => true,
497
+                        'chmod'     => FS_CHMOD_FILE,
498
+                    );
499
+
500
+                    $import_file = Redux_Color_Scheme_Functions::$upload_dir . Redux_Color_Scheme_Functions::$parent->args['opt_name'] . '_' . Redux_Color_Scheme_Functions::$field_id . '.json';
501
+
502
+                    if ( true === Redux_Core::$filesystem->execute( 'put_contents', $import_file, $param_array ) ) {
503
+                        $result = array(
504
+                            'result' => true,
505
+                            // translators: %s = HTML content.
506
+                            'data'   => sprintf( esc_html__( 'Import successful! Click %s to refresh.', 'redux-framework' ), '<strong>' . esc_html__( 'OK', 'redux-framework' ) . '</strong>' ),
507
+                        );
508
+                    } else {
509
+                        $result = array(
510
+                            'result' => false,
511
+                            'data'   => esc_html__( 'Import unsuccessful! File permission error: Could not write import data to server.', 'redux-framework' ),
512
+                        );
513
+                    }
514
+                } else {
515
+                    $result = array(
516
+                        'result' => false,
517
+                        'data'   => esc_html__( 'Import unsuccessful! The selected file is not a valid color scheme file.', 'redux-framework' ),
518
+                    );
519
+                }
520
+            } else {
521
+                $result = array(
522
+                    'result' => false,
523
+                    'data'   => esc_html__( 'Import unsuccessful! No data detected in the import file.', 'redux-framework' ),
524
+                );
525
+            }
526
+
527
+            $result = wp_json_encode( $result );
528
+
529
+            echo $result; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
530
+
531
+            die;
532
+        }
533
+
534
+        /**
535
+         * Download Scheme File.
536
+         *
537
+         * @since       1.0.0
538
+         * @access      private
539
+         * @return      void
540
+         */
541
+        private function download_schemes() {
542
+            Redux_Color_Scheme_Functions::$parent   = $this->parent;
543
+            Redux_Color_Scheme_Functions::$field_id = $this->field_id;
544
+
545
+            // Read contents of scheme file.
546
+            $content = Redux_Color_Scheme_Functions::read_scheme_file();
547
+            $content = wp_json_encode( $content );
548
+
549
+            // Set header info.
550
+            header( 'Content-Description: File Transfer' );
551
+            header( 'Content-type: application/txt' );
552
+            header( 'Content-Disposition: attachment; filename="redux_schemes_' . $this->parent->args['opt_name'] . '_' . $this->field_id . '_' . gmdate( 'm-d-Y' ) . '.json"' );
553
+            header( 'Content-Transfer-Encoding: binary' );
554
+            header( 'Expires: 0' );
555
+            header( 'Cache-Control: must-revalidate' );
556
+            header( 'Pragma: public' );
557
+
558
+            // File download.
559
+            echo $content; // phpcs:ignore WordPress.Security.EscapeOutput
560
+
561
+            // 2B ~! 2B
562
+            die;
563
+        }
564
+
565
+        /**
566
+         * Save Scheme. Saved an individual scheme to JSON scheme file.
567
+         *
568
+         * @param ReduxFramework $redux ReduxFramework object.
569
+         *
570
+         * @return      void
571
+         * @since       1.0.0
572
+         * @access      private
573
+         */
574
+        private function save_scheme( ReduxFramework $redux ) {
575
+            Redux_Color_Scheme_Functions::$parent   = $redux;
576
+            Redux_Color_Scheme_Functions::$field_id = $this->field_id;
577
+
578
+            // Get the scheme name.
579
+            if ( isset( $_REQUEST['scheme_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
580
+                $scheme_name = sanitize_text_field( wp_unslash( $_REQUEST['scheme_name'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
581
+
582
+                // Check for duplicates.
583
+                $names = Redux_Color_Scheme_Functions::get_scheme_names();
584
+                foreach ( $names as $name ) {
585
+                    $name     = strtolower( $name );
586
+                    $tmp_name = strtolower( $scheme_name );
587
+
588
+                    if ( $name === $tmp_name ) {
589
+                        echo 'fail';
590
+                        die();
591
+                    }
592
+                }
593
+
594
+                // Get scheme data.
595
+                if ( isset( $_REQUEST['scheme_data'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
596
+                    $scheme_data = wp_unslash( $_REQUEST['scheme_data'] ); // phpcs:ignore WordPress.Security
597
+
598
+                    // Get field ID.
599
+                    if ( isset( $_REQUEST['field_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
600
+                        $scheme_data = rawurldecode( $scheme_data );
601
+                        $scheme_data = json_decode( $scheme_data, true );
602
+
603
+                        // Save scheme to file.  If successful...
604
+                        if ( true === Redux_Color_Scheme_Functions::set_scheme_data( $scheme_name, $scheme_data ) ) {
605
+
606
+                            // Update scheme selector.
607
+                            echo Redux_Color_Scheme_Functions::get_scheme_select_html( $scheme_name ); // phpcs:ignore WordPress.Security.EscapeOutput
608
+                        }
609
+                    }
610
+                }
611
+            }
612
+
613
+            die(); // a horrible death!
614
+        }
615
+
616
+        /**
617
+         * Delete Scheme. Delete individual scheme from JSON scheme file.
618
+         *
619
+         * @param ReduxFramework $redux ReduxFramework object.
620
+         *
621
+         * @return      void
622
+         * @since       1.0.0
623
+         * @access      private
624
+         */
625
+        private function delete_scheme( ReduxFramework $redux ) {
626
+
627
+            // Get deleted scheme ID.
628
+            if ( isset( $_REQUEST['scheme_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
629
+                $scheme_id = sanitize_text_field( wp_unslash( $_REQUEST['scheme_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
630
+
631
+                // Get field ID.
632
+                if ( isset( $_REQUEST['field_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
633
+                    $field_id = sanitize_text_field( wp_unslash( $_REQUEST['field_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
634
+
635
+                    // If scheme ID was passed (and why wouldn't it be?? Hmm??).
636
+                    if ( $scheme_id ) {
637
+                        Redux_Color_Scheme_Functions::$field_id = $field_id;
638
+                        Redux_Color_Scheme_Functions::$parent   = $redux;
639
+
640
+                        // Get the entire scheme file.
641
+                        $schemes = Redux_Color_Scheme_Functions::read_scheme_file();
642
+
643
+                        // If we got a good read...
644
+                        if ( false !== $schemes ) {
645
+
646
+                            // If scheme name exists...
647
+                            if ( isset( $schemes[ $scheme_id ] ) ) {
648
+
649
+                                // Unset it.
650
+                                unset( $schemes[ $scheme_id ] );
651
+
652
+                                // Save the scheme data, minus the deleted scheme.  Upon success...
653
+                                if ( true === Redux_Color_Scheme_Functions::write_scheme_file( $schemes ) ) {
654
+
655
+                                    // Set default scheme.
656
+                                    Redux_Color_Scheme_Functions::set_current_scheme_id( 'Default' );
657
+
658
+                                    // Update field ID.
659
+                                    Redux_Color_Scheme_Functions::$field_id = $field_id;
660
+
661
+                                    // Meh TODO.
662
+                                    Redux_Color_Scheme_Functions::set_database_data();
663
+
664
+                                    echo 'success';
665
+                                } else {
666
+                                    echo 'Failed to write JSON file to server.';
667
+                                }
668
+                            } else {
669
+                                echo 'Scheme name does not exist in JSON string.  Aborting.';
670
+                            }
671
+                        } else {
672
+                            echo 'Failed to read JSON scheme file, or file is empty.';
673
+                        }
674
+                    } else {
675
+                        echo 'No scheme ID passed.  Aborting.';
676
+                    }
677
+                }
678
+            }
679
+
680
+            die(); // rolled a two.
681
+        }
682
+
683
+        /**
684
+         * Gets the new scheme based on selection.
685
+         *
686
+         * @param ReduxFramework $redux ReduxFramework object.
687
+         *
688
+         * @return      void
689
+         * @since       1.0.0
690
+         * @access      private
691
+         */
692
+        private function get_scheme_html( ReduxFramework $redux ) {
693
+            if ( isset( $_POST['scheme_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
694
+
695
+                // Get the selected scheme name.
696
+                $scheme_id = sanitize_text_field( wp_unslash( $_POST['scheme_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
697
+
698
+                if ( isset( $_POST['field_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
699
+
700
+                    // Get the field ID.
701
+                    $field_id = sanitize_text_field( wp_unslash( $_POST['field_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
702
+
703
+                    // Get the field class.
704
+                    $field_class = isset( $_POST['field_class'] ) ? sanitize_text_field( wp_unslash( $_POST['field_class'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
705
+
706
+                    Redux_Color_Scheme_Functions::$parent = $redux;
707
+
708
+                    // Set the updated field ID.
709
+                    Redux_Color_Scheme_Functions::$field_id = $field_id;
710
+
711
+                    // Set the updated field class.
712
+                    Redux_Color_Scheme_Functions::$field_class = $field_class;
713
+
714
+                    // Get the color picket layout HTML.
715
+                    $html = Redux_Color_Scheme_Functions::get_current_color_scheme_html( $scheme_id );
716
+
717
+                    // Print!
718
+                    echo $html; // phpcs:ignore WordPress.Security.EscapeOutput
719
+                }
720
+            }
721
+
722
+            die(); // another day.
723
+        }
724
+
725
+
726
+        /**
727
+         * Retrieves an array of default data for color picker.
728
+         *
729
+         * @since       1.0.0
730
+         * @access      private
731
+         * @return      array Default values from config.
732
+         */
733
+        private function get_default_data(): array {
734
+            $def_opts = $this->parent->options_defaults[ $this->field_id ];
735
+
736
+            if ( isset( $def_opts['color_scheme_name'] ) ) {
737
+                return array();
738
+            }
739
+
740
+            $sections = $this->parent->sections;
741
+            $data     = array();
742
+
743
+            foreach ( $sections as $arr ) {
744
+                if ( isset( $arr['fields'] ) ) {
745
+                    foreach ( $arr['fields'] as $arr2 ) {
746
+                        if ( $arr2['id'] === $this->field_id ) {
747
+
748
+                            // Select fields.
749
+                            if ( isset( $arr2['select'] ) ) {
750
+                                foreach ( $arr2['select'] as $v ) {
751
+                                    $data[] = array(
752
+                                        'id'    => $v['id'],
753
+                                        'value' => $v['default'],
754
+                                        'type'  => 'select',
755
+                                    );
756
+                                }
757
+                            }
758
+                        }
759
+                    }
760
+                }
761
+            }
762
+
763
+            foreach ( $def_opts as $v ) {
764
+                $title = $v['title'] ?? $v['id'];
765
+                $color = $v['color'] ?? '';
766
+                $alpha = $v['alpha'] ?? 1;
767
+                $grp   = $v['group'] ?? '';
768
+
769
+                if ( '' === $color || 'transparent' === $color ) {
770
+                    $rgba = $this->output_transparent ? 'transparent' : '';
771
+                } else {
772
+                    $rgba = Redux_Helpers::hex2rgba( $color, $alpha );
773
+                }
774
+
775
+                $data[] = array(
776
+                    'id'    => $v['id'],
777
+                    'title' => $title,
778
+                    'color' => $color,
779
+                    'alpha' => $alpha,
780
+                    'group' => $grp,
781
+                    'rgba'  => $rgba,
782
+                );
783
+            }
784
+
785
+            return $data;
786
+        }
787
+    }
788
+
789
+    class_alias( Redux_Extension_Color_Scheme::class, 'ReduxFramework_Extension_Color_Scheme' );
790 790
 }
Please login to merge, or discard this patch.
inc/extensions/custom_fonts/class-redux-extension-custom-fonts.php 1 patch
Indentation   +975 added lines, -975 removed lines patch added patch discarded remove patch
@@ -16,979 +16,979 @@
 block discarded – undo
16 16
 
17 17
 if ( ! class_exists( 'Redux_Extension_Custom_Fonts' ) ) {
18 18
 
19
-	/**
20
-	 * Class Redux_Extension_Custom_Fonts
21
-	 */
22
-	class Redux_Extension_Custom_Fonts extends Redux_Extension_Abstract {
23
-
24
-		/**
25
-		 * Extension version.
26
-		 *
27
-		 * @var string
28
-		 */
29
-		public static $version = '4.5.10';
30
-
31
-		/**
32
-		 * Extension friendly name.
33
-		 *
34
-		 * @var string
35
-		 */
36
-		public string $extension_name = 'Custom Fonts';
37
-		/**
38
-		 * Class instance.
39
-		 *
40
-		 * @var object|null
41
-		 */
42
-		public static ?object $instance;
43
-
44
-		/**
45
-		 * Custom fonts array.
46
-		 *
47
-		 * @var array|null
48
-		 */
49
-		public ?array $custom_fonts = array();
50
-
51
-		/**
52
-		 * WordPress upload directory.
53
-		 *
54
-		 * @var string|null
55
-		 */
56
-		public ?string $upload_dir = '';
57
-
58
-		/**
59
-		 * WordPress upload URI.
60
-		 *
61
-		 * @var string|null
62
-		 */
63
-		public ?string $upload_url = '';
64
-
65
-		/**
66
-		 * Subfolder name.
67
-		 *
68
-		 * @var string
69
-		 */
70
-		public string $subfolder = 'custom/';
71
-
72
-		/**
73
-		 * Font folder.
74
-		 *
75
-		 * @var string|null
76
-		 */
77
-		public ?string $font_folder = '';
78
-
79
-		/**
80
-		 * Font Filename.
81
-		 *
82
-		 * @var string|null
83
-		 */
84
-		public ?string $font_filename = '';
85
-
86
-		/**
87
-		 * File selected in media upload.
88
-		 *
89
-		 * @var string|null
90
-		 */
91
-		public ?string $selected_file = '';
92
-
93
-		/**
94
-		 * Is font conversation service available?
95
-		 *
96
-		 * @var bool
97
-		 */
98
-		private bool $can_convert;
99
-
100
-		/**
101
-		 * Class Constructor. Defines the args for the extensions class
102
-		 *
103
-		 * @param ReduxFramework $redux ReduxFramework pointer.
104
-		 *
105
-		 * @return      void
106
-		 * @since       1.0.0
107
-		 * @access      public
108
-		 */
109
-		public function __construct( $redux ) {
110
-			if ( false === $redux->args['custom_fonts'] ) {
111
-				return;
112
-			}
113
-
114
-			parent::__construct( $redux, __FILE__ );
115
-
116
-			self::$instance = parent::get_instance();
117
-
118
-			$this->add_field( 'custom_fonts' );
119
-
120
-			$this->upload_dir = Redux_Core::$upload_dir . 'custom-fonts/';
121
-			$this->upload_url = Redux_Core::$upload_url . 'custom-fonts/';
122
-
123
-			if ( ! is_dir( $this->upload_dir ) ) {
124
-				Redux_Core::$filesystem->execute( 'mkdir', $this->upload_dir );
125
-			}
126
-
127
-			if ( ! is_dir( $this->upload_dir . '/custom' ) ) {
128
-				Redux_Core::$filesystem->execute( 'mkdir', $this->upload_dir . '/custom' );
129
-			}
130
-
131
-			$this->get_fonts();
132
-
133
-			if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
134
-				if ( filemtime( $this->upload_dir . 'custom' ) > ( filemtime( $this->upload_dir . 'fonts.css' ) + 10 ) ) {
135
-					$this->generate_css();
136
-				}
137
-			} else {
138
-				$this->generate_css();
139
-			}
140
-
141
-			add_action( 'wp_ajax_redux_custom_fonts', array( $this, 'ajax' ) );
142
-			add_action( 'wp_ajax_redux_custom_font_timer', array( $this, 'timer' ) );
143
-
144
-			add_filter( "redux/{$this->parent->args['opt_name']}/field/typography/custom_fonts", array( $this, 'add_custom_fonts' ) );
145
-
146
-			// phpcs:disable
147
-			// $this->is_field = Redux_Helpers::is_field_in_use( $parent, 'custom_fonts' );
148
-
149
-			// if ( ! $this->is_field ) {
150
-			// 	$this->add_section();
151
-			// }
152
-
153
-			add_filter( "redux/options/{$this->parent->args['opt_name']}/section/redux_dynamic_font_control", array( $this, 'remove_dynamic_section' ) ); // phpcs:ignore WordPress.NamingConventions.ValidHookName
154
-			add_filter( 'upload_mimes', array( $this, 'custom_upload_mimes' ) );
155
-			add_action( 'wp_head', array( $this, 'enqueue_output' ), 150 );
156
-			add_filter( 'tiny_mce_before_init', array( $this, 'extend_tinymce_dropdown' ) );
157
-
158
-			$this->can_convert = true; // has_filter( 'redux/' . $this->parent->args['opt_name'] . '/extensions/custom_fonts/api_url' );
159
-			// phpcs:enable
160
-		}
161
-
162
-		/**
163
-		 * Timer.
164
-		 */
165
-		public function timer() {
166
-			if ( ! current_user_can( $this->parent->args['page_permissions'] ) ) {
167
-				wp_die( esc_html__( 'You do not have permission to perform this action.', 'redux-framework' ), 403 );
168
-			}
169
-
170
-			if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'redux_custom_fonts' ) ) {
171
-				die( 0 );
172
-			}
173
-
174
-			$name = get_option( 'redux_custom_font_current' );
175
-
176
-			if ( ! empty( $name ) ) {
177
-				echo esc_html( $name );
178
-			}
179
-
180
-			die();
181
-		}
182
-
183
-		/**
184
-		 * Remove the dynamically added section if the field was used elsewhere
185
-		 *
186
-		 * @param array $section Section array.
187
-		 *
188
-		 * @return array
189
-		 * @since  Redux_Framework 3.1.1
190
-		 */
191
-		public function remove_dynamic_section( array $section ): array {
192
-			if ( isset( $this->parent->field_types['custom_fonts'] ) ) {
193
-				$section = array();
194
-			}
195
-
196
-			return $section;
197
-		}
198
-
199
-		/**
200
-		 * Adds FontMeister fonts to the TinyMCE drop-down.
201
-		 * Typekit's fonts don't render properly in the drop-down and in the editor,
202
-		 * because Typekit needs JS and TinyMCE doesn't support that.
203
-		 *
204
-		 * @param array $opt Option array.
205
-		 *
206
-		 * @return array
207
-		 */
208
-		public function extend_tinymce_dropdown( array $opt ): array {
209
-			if ( ! is_admin() ) {
210
-				return $opt;
211
-			}
212
-
213
-			if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
214
-				$theme_advanced_fonts = $opt['font_formats'] ?? 'Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats';
215
-				$custom_fonts         = '';
216
-
217
-				$stylesheet = $this->upload_url . 'fonts.css';
218
-
219
-				if ( empty( $opt['content_css'] ) ) {
220
-					$opt['content_css'] = $stylesheet;
221
-				} else {
222
-					$opt['content_css'] = $opt['content_css'] . ',' . $stylesheet;
223
-				}
224
-
225
-				foreach ( $this->custom_fonts as $arr ) {
226
-					foreach ( $arr as $font => $pieces ) {
227
-						$custom_fonts .= ';' . $font . '=' . $font;
228
-					}
229
-				}
230
-
231
-				$opt['font_formats'] = $theme_advanced_fonts . $custom_fonts;
232
-			}
233
-
234
-			return $opt;
235
-		}
236
-
237
-
238
-		/**
239
-		 * Function to enqueue the custom fonts css
240
-		 */
241
-		public function enqueue_output() {
242
-			if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
243
-				wp_enqueue_style(
244
-					'redux-custom-fonts',
245
-					$this->upload_url . 'fonts.css',
246
-					array(),
247
-					filemtime( $this->upload_dir . 'fonts.css' )
248
-				);
249
-			}
250
-		}
251
-
252
-		/**
253
-		 * Adds the appropriate mime types to WordPress
254
-		 *
255
-		 * @param array $existing_mimes Mine array.
256
-		 *
257
-		 * @return array
258
-		 */
259
-		public function custom_upload_mimes( array $existing_mimes = array() ): array {
260
-			$existing_mimes['ttf']   = 'font/ttf';
261
-			$existing_mimes['otf']   = 'font/otf';
262
-			$existing_mimes['eot']   = 'application/vnd.ms-fontobject';
263
-			$existing_mimes['woff']  = 'application/font-woff';
264
-			$existing_mimes['woff2'] = 'application/font-woff2';
265
-			$existing_mimes['svg']   = 'image/svg+xml';
266
-			$existing_mimes['zip']   = 'application/zip';
267
-
268
-			return $existing_mimes;
269
-		}
270
-
271
-		/**
272
-		 * Gets all the fonts in the custom_fonts directory
273
-		 */
274
-		public function get_fonts() {
275
-			if ( empty( $this->custom_fonts ) ) {
276
-				$params = array(
277
-					'include_hidden' => false,
278
-					'recursive'      => true,
279
-				);
280
-
281
-				$fonts = Redux_Core::$filesystem->execute( 'dirlist', $this->upload_dir, $params );
282
-
283
-				if ( ! empty( $fonts ) ) {
284
-					foreach ( $fonts as $section ) {
285
-						if ( 'd' === $section['type'] && ! empty( $section['name'] ) ) {
286
-							if ( 'custom' === $section['name'] ) {
287
-								$section['name'] = esc_html__( 'Custom Fonts', 'redux-framework' );
288
-							}
289
-
290
-							if ( empty( $section['files'] ) ) {
291
-								continue;
292
-							}
293
-
294
-							$this->custom_fonts[ $section['name'] ] = $this->custom_fonts[ $section['name'] ] ?? array();
295
-
296
-							foreach ( $section['files'] as $font ) {
297
-								if ( ! empty( $font['name'] ) ) {
298
-									if ( empty( $font['files'] ) ) {
299
-										continue;
300
-									}
301
-
302
-									$kinds = array();
303
-
304
-									foreach ( $font['files'] as $f ) {
305
-										$valid = $this->check_font_name( $f );
306
-										if ( $valid ) {
307
-											$kinds[] = $valid;
308
-										}
309
-									}
310
-
311
-									$this->custom_fonts[ $section['name'] ][ $font['name'] ] = $kinds;
312
-								}
313
-							}
314
-						}
315
-					}
316
-				}
317
-			}
318
-		}
319
-
320
-		/**
321
-		 * Add custom fonts.
322
-		 *
323
-		 * @param mixed $custom_fonts Custom fonts.
324
-		 *
325
-		 * @return array
326
-		 */
327
-		public function add_custom_fonts( $custom_fonts ): array {
328
-			if ( empty( $custom_fonts ) ) {
329
-				$custom_fonts = array();
330
-			}
331
-
332
-			return wp_parse_args( $custom_fonts, $this->custom_fonts );
333
-		}
334
-
335
-		/**
336
-		 * Ajax used within the panel to add and process the fonts
337
-		 */
338
-		public function ajax() {
339
-			if ( ! current_user_can( $this->parent->args['page_permissions'] ) ) {
340
-				wp_die( esc_html__( 'You do not have permission to perform this action.', 'redux-framework' ), 403 );
341
-			}
342
-
343
-			if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'redux_custom_fonts' ) ) {
344
-				die( 0 );
345
-			}
346
-
347
-			if ( isset( $_POST['type'] ) && 'delete' === $_POST['type'] ) {
348
-				if ( isset( $_POST['section'] ) ) {
349
-					if ( esc_html__( 'Custom Fonts', 'redux-framework' ) === $_POST['section'] ) {
350
-						$_POST['section'] = 'custom';
351
-					}
352
-				}
353
-
354
-				try {
355
-					if ( isset( $_POST['section'] ) || isset( $_POST['name'] ) ) {
356
-						$ret = Redux_Core::$filesystem->execute( 'rmdir', $this->upload_dir . sanitize_file_name( wp_unslash( $_POST['section'] ) ) . '/' . sanitize_file_name( wp_unslash( $_POST['name'] ) ) . '/', array( 'recursive' => true ) );
357
-
358
-						if ( true === $ret ) {
359
-							$result = array( 'type' => 'success' );
360
-						} else {
361
-							$result = array(
362
-								'type' => 'error',
363
-								'msg'  => esc_html__( 'File system failure. Could not delete temp dir.', 'redux-framework' ),
364
-							);
365
-						}
366
-
367
-						echo wp_json_encode( $result );
368
-					}
369
-				} catch ( Exception $e ) {
370
-					echo wp_json_encode(
371
-						array(
372
-							'type' => 'error',
373
-							'msg'  => esc_html__( 'Unable to delete font file(s).', 'redux-framework' ),
374
-						)
375
-					);
376
-				}
377
-
378
-				die();
379
-			}
380
-
381
-			if ( ! isset( $_POST['title'] ) ) {
382
-				$_POST['title'] = '';
383
-			}
384
-
385
-			if ( ! isset( $_POST['filename'] ) ) {
386
-				$_POST['filename'] = '';
387
-			}
388
-
389
-			$this->font_folder   = sanitize_file_name( wp_unslash( $_POST['title'] ) );
390
-			$this->font_filename = sanitize_file_name( wp_unslash( $_POST['filename'] ) );
391
-
392
-			if ( ! empty( $_POST['attachment_id'] ) ) {
393
-				if ( isset( $_POST['title'] ) || isset( $_POST['mime'] ) ) {
394
-					$msg = $this->process_web_font( sanitize_key( wp_unslash( $_POST['attachment_id'] ) ), sanitize_text_field( wp_unslash( $_POST['mime'] ) ) );
395
-
396
-					if ( empty( $msg ) ) {
397
-						$msg = '';
398
-					}
399
-
400
-					$result = array(
401
-						'type' => 'success',
402
-						'msg'  => $msg,
403
-					);
404
-
405
-					echo wp_json_encode( $result );
406
-				}
407
-			}
408
-
409
-			die();
410
-		}
411
-
412
-		/**
413
-		 * Get only valid files. Ensure everything is proper for processing.
414
-		 *
415
-		 * @param string $path Path.
416
-		 *
417
-		 * @return array
418
-		 */
419
-		public function get_valid_files( string $path ): array {
420
-			$output = array();
421
-			$path   = trailingslashit( $path );
422
-
423
-			$params = array(
424
-				'include_hidden' => false,
425
-				'recursive'      => true,
426
-			);
427
-
428
-			$files = Redux_Core::$filesystem->execute( 'dirlist', $path, $params );
429
-
430
-			foreach ( $files as $file ) {
431
-				if ( 'd' === $file['type'] ) {
432
-					$output = array_merge( $output, $this->get_valid_files( $path . $file['name'] ) );
433
-				} elseif ( 'f' === $file['type'] ) {
434
-					$valid = $this->check_font_name( $file );
435
-					if ( $valid ) {
436
-						$output[ $valid ] = trailingslashit( $path ) . $file['name'];
437
-					}
438
-				}
439
-			}
440
-
441
-			return $output;
442
-		}
443
-
444
-		/**
445
-		 * Take a valid web font and process the missing pieces.
446
-		 *
447
-		 * @param string $attachment_id ID.
448
-		 * @param string $mime_type     Mine type.
449
-		 */
450
-		public function process_web_font( string $attachment_id, string $mime_type ) {
451
-			// phpcs:ignore WordPress.Security.NonceVerification
452
-			if ( ! isset( $_POST['conversion'] ) ) {
453
-				$_POST['conversion'] = 'false';
454
-			}
455
-
456
-			// phpcs:ignore WordPress.Security.NonceVerification
457
-			$conversion = sanitize_text_field( wp_unslash( $_POST['conversion'] ) );
458
-
459
-			$missing = array();
460
-
461
-			$complete = array(
462
-				'ttf',
463
-				'woff',
464
-				'woff2',
465
-				'eot',
466
-				'svg',
467
-				'otf',
468
-			);
469
-
470
-			$subtype = explode( '/', $mime_type );
471
-			$subtype = trim( max( $subtype ) );
472
-
473
-			if ( ! is_dir( $this->upload_dir ) ) {
474
-				Redux_Core::$filesystem->execute( 'mkdir', $this->upload_dir );
475
-			}
476
-
477
-			if ( ! is_dir( $this->upload_dir . $this->subfolder ) ) {
478
-				Redux_Core::$filesystem->execute( 'mkdir', $this->upload_dir . $this->subfolder );
479
-			}
480
-
481
-			$temp                = $this->upload_dir . 'temp';
482
-			$this->selected_file = get_attached_file( $attachment_id );
483
-
484
-			if ( empty( $this->selected_file ) ) {
485
-				echo wp_json_encode(
486
-					array(
487
-						'type' => 'error',
488
-						'msg'  => esc_html__( 'Attachment does not exist.', 'redux-framework' ),
489
-					)
490
-				);
491
-
492
-				die();
493
-			}
494
-
495
-			$filename = explode( '/', $this->selected_file );
496
-
497
-			$filename = $filename[ ( count( $filename ) - 1 ) ];
498
-
499
-			$fontname = ucfirst(
500
-				str_replace(
501
-					array(
502
-						'.zip',
503
-						'.ttf',
504
-						'.woff',
505
-						'.woff2',
506
-						'.eot',
507
-						'.svg',
508
-						'.otf',
509
-					),
510
-					'',
511
-					strtolower( $filename )
512
-				)
513
-			);
514
-
515
-			if ( empty( $this->font_folder ) ) {
516
-				$this->font_folder = $fontname;
517
-			}
518
-
519
-			$ret = array();
520
-
521
-			if ( ! is_dir( $temp ) ) {
522
-				Redux_Core::$filesystem->execute( 'mkdir', $temp );
523
-			}
524
-
525
-			if ( 'zip' === $subtype ) {
526
-				$unzipfile = unzip_file( $this->selected_file, $temp );
527
-
528
-				if ( is_wp_error( $unzipfile ) ) {
529
-					echo wp_json_encode(
530
-						array(
531
-							'type' => 'error',
532
-							'msg'  => $unzipfile->get_error_message() . '<br><br>' . esc_html__( 'Unzipping failed.', 'redux-framework' ),
533
-						)
534
-					);
535
-
536
-					die();
537
-				}
538
-
539
-				$output = $this->get_valid_files( $temp );
540
-
541
-				if ( ! empty( $output ) ) {
542
-					foreach ( $complete as $test ) {
543
-						if ( ! isset( $output[ $test ] ) ) {
544
-							$missing[] = $test;
545
-						}
546
-					}
547
-
548
-					if ( ! is_dir( $this->upload_dir . $this->subfolder . $this->font_folder . '/' ) ) {
549
-						Redux_Core::$filesystem->execute( 'mkdir', $this->upload_dir . $this->subfolder . $this->font_folder . '/' );
550
-					}
551
-
552
-					foreach ( $output as $key => $value ) {
553
-						$param_array = array(
554
-							'destination' => $this->upload_dir . $this->subfolder . $this->font_folder . '/' . $fontname . '.' . $key,
555
-							'overwrite'   => true,
556
-							'chmod'       => 755,
557
-						);
558
-
559
-						Redux_Core::$filesystem->execute( 'copy', $value, $param_array );
560
-					}
561
-
562
-					if ( true === $this->can_convert && 'true' === $conversion ) {
563
-						$ret = $this->get_missing_files( $fontname, $missing, $output );
564
-					}
565
-				}
566
-
567
-				Redux_Core::$filesystem->execute( 'rmdir', $temp, array( 'recursive' => true ) );
568
-
569
-				$this->generate_css();
570
-
571
-				wp_delete_attachment( $attachment_id, true );
572
-			} elseif ( 'svg+xml' === $subtype || 'vnd.ms-fontobject' === $subtype || 'x-font-ttf' === $subtype || 'ttf' === $subtype || 'otf' === $subtype || 'font-woff' === $subtype || 'font-woff2' === $subtype || 'application-octet-stream' === $subtype || 'octet-stream' === $subtype ) {
573
-				foreach ( $complete as $test ) {
574
-					if ( $subtype !== $test ) {
575
-						if ( ! isset( $output[ $test ] ) ) {
576
-							$missing[] = $test;
577
-						}
578
-					}
579
-				}
580
-
581
-				if ( ! is_dir( $this->upload_dir . $this->subfolder . $this->font_folder . '/' ) ) {
582
-					Redux_Core::$filesystem->execute( 'mkdir', $this->upload_dir . $this->subfolder . $this->font_folder . '/' );
583
-				}
584
-
585
-				$output = array( $subtype => $this->selected_file );
586
-
587
-				if ( true === $this->can_convert && 'true' === $conversion ) {
588
-					$ret = $this->get_missing_files( $fontname, $missing, $output );
589
-
590
-					if ( false === $ret ) {
591
-						if ( false === $this->convert_local_font() ) {
592
-							echo wp_json_encode(
593
-								array(
594
-									'type' => 'error',
595
-									'msg'  => esc_html__( 'File permission error. Local file could not be installed.', 'redux-framework' ) . ' ' . $subtype,
596
-								)
597
-							);
598
-
599
-							die;
600
-						}
601
-					}
602
-				} elseif ( false === $this->convert_local_font() ) {
603
-						echo wp_json_encode(
604
-							array(
605
-								'type' => 'error',
606
-								'msg'  => esc_html__( 'File permission error. Local file could not be installed.', 'redux-framework' ) . ' ' . $subtype,
607
-							)
608
-						);
609
-
610
-						die;
611
-				}
612
-
613
-				Redux_Core::$filesystem->execute( 'rmdir', $temp, array( 'recursive' => true ) );
614
-
615
-				$this->generate_css();
616
-
617
-				wp_delete_attachment( $attachment_id, true );
618
-			} else {
619
-				echo wp_json_encode(
620
-					array(
621
-						'type' => 'error',
622
-						'msg'  => esc_html__( 'File type not recognized.', 'redux-framework' ) . ' ' . $subtype,
623
-					)
624
-				);
625
-
626
-				die();
627
-			}
628
-
629
-			if ( is_array( $ret ) && ! empty( $ret ) ) {
630
-				$msg = esc_html__( 'Unidentified error.', 'redux-framework' );
631
-
632
-				if ( isset( $ret['msg'] ) ) {
633
-					$msg = $ret['msg'];
634
-				}
635
-
636
-				return $msg;
637
-			}
638
-
639
-			return '';
640
-		}
641
-
642
-		/**
643
-		 * Install selected file into Custom Fonts.
644
-		 *
645
-		 * @return bool
646
-		 */
647
-		private function convert_local_font(): bool {
648
-			$param_array = array(
649
-				'destination' => $this->upload_dir . $this->subfolder . '/' . $this->font_folder . '/' . $this->font_filename,
650
-				'overwrite'   => true,
651
-				'chmod'       => 755,
652
-			);
653
-
654
-			return Redux_Core::$filesystem->execute( 'copy', $this->selected_file, $param_array );
655
-		}
656
-
657
-		/**
658
-		 * Ping the WebFontOMatic API to get the missing files.
659
-		 *
660
-		 * @param string $fontname  Font name.
661
-		 * @param array  $missing   Missing.
662
-		 * @param array  $output    Output.
663
-		 */
664
-		private function get_missing_files( string $fontname, array $missing, array $output ) {
665
-			if ( ! empty( $this->font_folder ) && ! empty( $missing ) ) {
666
-				$temp = $this->upload_dir . 'temp';
667
-
668
-				$font_ext = pathinfo( $this->font_filename, PATHINFO_EXTENSION );
669
-
670
-				$unsupported = array( 'eot', 'woff', 'woff2' );
671
-
672
-				// Find a file to convert from.
673
-				foreach ( $output as $key => $value ) {
674
-					if ( 'eot' === $key ) {
675
-						continue;
676
-					} else {
677
-						$main = $key;
678
-						break;
679
-					}
680
-				}
681
-
682
-				if ( ! isset( $main ) ) {
683
-					echo wp_json_encode(
684
-						array(
685
-							'type' => 'error',
686
-							'msg'  => esc_html__( 'No valid font file was found.', 'redux-framework' ),
687
-						)
688
-					);
689
-
690
-					Redux_Core::$filesystem->execute( 'rmdir', $temp, array( 'recursive' => true ) );
691
-					Redux_Core::$filesystem->execute( 'rmdir', $this->upload_dir . $this->subfolder . $this->font_folder . '/', array( 'recursive' => true ) );
692
-
693
-					die();
694
-				}
695
-
696
-				update_option( 'redux_custom_font_current', $this->font_folder . '.zip' );
697
-
698
-				$boundary = wp_generate_password( 24 );
699
-
700
-				$headers = array(
701
-					'content-type' => 'multipart/form-data; boundary=' . $boundary,
702
-					'user-agent'   => 'redux-custom-fonts-' . self::$version . ' using ' . wp_get_theme(),
703
-				);
704
-
705
-				$payload  = '--' . $boundary;
706
-				$payload .= "\r\n";
707
-				$payload .= 'Content-Disposition: form-data; name="md5"' . "\r\n\r\n";
708
-				$payload .= md5( 'redux_custom_font' );
709
-				$payload .= "\r\n";
710
-
711
-				if ( $output[ $main ] ) {
712
-					$payload .= '--' . $boundary;
713
-					$payload .= "\r\n";
714
-					$payload .= 'Content-Disposition: form-data; name="convert"; filename="' . basename( $output[ $main ] ) . '"' . "\r\n";
715
-					$payload .= "\r\n";
716
-					$payload .= Redux_Core::$filesystem->execute( 'get_contents', $output[ $main ] );
717
-					$payload .= "\r\n";
718
-				}
719
-
720
-				$payload .= '--' . $boundary . '--';
721
-
722
-				$args = array(
723
-					'headers'    => $headers,
724
-					'body'       => $payload,
725
-					'user-agent' => $headers['user-agent'],
726
-					'timeout'    => 300,
727
-					'sslverify'  => true,
728
-				);
729
-
730
-				// phpcs:disable WordPress.NamingConventions.ValidHookName
731
-				$api_url = apply_filters( 'redux/' . $this->parent->args['opt_name'] . '/extensions/custom_fonts/api_url', 'https://redux.io/fonts' );
732
-
733
-				$response = wp_remote_post( $api_url, $args );
734
-
735
-				if ( is_wp_error( $response ) ) {
736
-					return array(
737
-						'type' => 'error',
738
-						'msg'  => $response->get_error_message() . '<br><br>' . esc_html__( 'Your font could not be converted at this time. Please try again later.', 'redux-framework' ),
739
-					);
740
-				} elseif ( isset( $response['body'] ) ) {
741
-					if ( null !== json_decode( $response['body'] ) ) {
742
-						return json_decode( $response['body'], true );
743
-					}
744
-				}
745
-
746
-				$param_array = array(
747
-					'content'   => $response['body'],
748
-					'overwrite' => true,
749
-					'chmod'     => FS_CHMOD_FILE,
750
-				);
751
-
752
-				$zip_file = $temp . DIRECTORY_SEPARATOR . $fontname . '.zip';
753
-
754
-				Redux_Core::$filesystem->execute( 'put_contents', $zip_file, $param_array );
755
-
756
-				if ( 0 === filesize( $zip_file ) ) {
757
-					return false;
758
-				}
759
-
760
-				$zip = unzip_file( $zip_file, $temp );
761
-
762
-				if ( ! is_wp_error( $zip ) ) {
763
-					$params = array(
764
-						'include_hidden' => false,
765
-						'recursive'      => false,
766
-					);
767
-
768
-					$files = Redux_Core::$filesystem->execute( 'dirlist', $temp . DIRECTORY_SEPARATOR . 'fonts' . DIRECTORY_SEPARATOR, $params );
769
-
770
-					foreach ( $files as $file ) {
771
-						$param_array = array(
772
-							'destination' => $this->upload_dir . $this->subfolder . $this->font_folder . DIRECTORY_SEPARATOR . sanitize_file_name( $file['name'] ),
773
-							'overwrite'   => true,
774
-							'chmod'       => 755,
775
-						);
776
-
777
-						Redux_Core::$filesystem->execute( 'move', $temp . DIRECTORY_SEPARATOR . 'fonts' . DIRECTORY_SEPARATOR . ( $file['name'] ), $param_array );
778
-					}
779
-				} else {
780
-					$path_parts = pathinfo( $output[ $main ] );
781
-
782
-					$param_array = array(
783
-						'destination' => $this->upload_dir . $this->subfolder . $this->font_folder . DIRECTORY_SEPARATOR . sanitize_file_name( $path_parts['basename'] ),
784
-						'overwrite'   => true,
785
-						'chmod'       => 755,
786
-					);
787
-
788
-					Redux_Core::$filesystem->execute( 'move', $output[ $main ], $param_array );
789
-
790
-					if ( in_array( $font_ext, $unsupported, true ) ) {
791
-						return array(
792
-							'type' => 'error',
793
-							// translators: %s = font extension.
794
-							'msg'  => $zip->get_error_message() . '<br><br>' . sprintf( esc_html__( 'The font converter does not support %s fonts.', 'redux-framework' ), $font_ext ),
795
-						);
796
-					} else {
797
-						return array(
798
-							'type' => 'error',
799
-							'msg'  => $zip->get_error_message() . '<br><br>' . esc_html__( 'ZIP error. Your font could not be converted at this time. Please try again later.', 'redux-framework' ),
800
-						);
801
-					}
802
-				}
803
-
804
-				delete_option( 'redux_custom_font_current' );
805
-			}
806
-
807
-			return true;
808
-		}
809
-
810
-		/**
811
-		 * Check if the file name is a valid font file.
812
-		 *
813
-		 * @param array $file File.
814
-		 *
815
-		 * @return bool|string
816
-		 */
817
-		private function check_font_name( array $file ) {
818
-			if ( '.woff' === strtolower( substr( $file['name'], - 5 ) ) ) {
819
-				return 'woff';
820
-			}
821
-
822
-			if ( '.woff2' === strtolower( substr( $file['name'], - 6 ) ) ) {
823
-				return 'woff2';
824
-			}
825
-
826
-			$sub = strtolower( substr( $file['name'], - 4 ) );
827
-
828
-			if ( '.ttf' === $sub ) {
829
-				return 'ttf';
830
-			}
831
-
832
-			if ( '.eot' === $sub ) {
833
-				return 'eot';
834
-			}
835
-
836
-			if ( '.svg' === $sub ) {
837
-				return 'svg';
838
-			}
839
-
840
-			if ( '.otf' === $sub ) {
841
-				return 'otf';
842
-			}
843
-
844
-			return false;
845
-		}
846
-
847
-		/**
848
-		 * Generate a new custom CSS file for enqueuing on the frontend and backend.
849
-		 */
850
-		private function generate_css() {
851
-			$params = array(
852
-				'include_hidden' => false,
853
-				'recursive'      => true,
854
-			);
855
-
856
-			$fonts = Redux_Core::$filesystem->execute( 'dirlist', $this->upload_dir . 'custom' . DIRECTORY_SEPARATOR, $params );
857
-
858
-			if ( empty( $fonts ) || ! is_array( $fonts ) ) {
859
-				return;
860
-			}
861
-
862
-			foreach ( $fonts as $font ) {
863
-				if ( 'd' === $font['type'] ) {
864
-					break;
865
-				}
866
-
867
-				if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
868
-					Redux_Core::$filesystem->execute( 'delete', $this->upload_dir . 'fonts.css' );
869
-				}
870
-
871
-				return;
872
-			}
873
-
874
-			$css = '';
875
-
876
-			foreach ( $fonts as $font ) {
877
-				if ( 'd' === $font['type'] ) {
878
-					$css .= $this->generate_font_css( $font['name'], $this->upload_dir . 'custom' . DIRECTORY_SEPARATOR );
879
-				}
880
-			}
881
-
882
-			if ( '' !== $css ) {
883
-				$param_array = array(
884
-					'content' => $css,
885
-					'chmod'   => FS_CHMOD_FILE,
886
-				);
887
-
888
-				Redux_Core::$filesystem->execute( 'put_contents', $this->upload_dir . 'fonts.css', $param_array );
889
-			}
890
-		}
891
-
892
-		/**
893
-		 * Process to actually construct the custom font css file.
894
-		 *
895
-		 * @param string $name Name.
896
-		 * @param string $dir  Directory.
897
-		 *
898
-		 * @return string
899
-		 */
900
-		private function generate_font_css( string $name, string $dir ): ?string {
901
-			$path = $dir . $name;
902
-
903
-			$params = array(
904
-				'include_hidden' => false,
905
-				'recursive'      => true,
906
-			);
907
-
908
-			$files = Redux_Core::$filesystem->execute( 'dirlist', $path, $params );
909
-
910
-			if ( empty( $files ) ) {
911
-				return null;
912
-			}
913
-
914
-			$output = array();
915
-
916
-			foreach ( $files as $file ) {
917
-				$output[ $this->check_font_name( $file ) ] = $file['name'];
918
-			}
919
-
920
-			$css = '@font-face {';
921
-
922
-			$css .= 'font-family:"' . $name . '";';
923
-
924
-			$src = array();
925
-
926
-			if ( isset( $output['eot'] ) ) {
927
-				$src[] = "url('{$this->upload_url}custom/$name/{$output['eot']}?#iefix') format('embedded-opentype')";
928
-			}
929
-
930
-			if ( isset( $output['woff'] ) ) {
931
-				$src[] = "url('{$this->upload_url}custom/$name/{$output['woff']}') format('woff')";
932
-			}
933
-
934
-			if ( isset( $output['woff2'] ) ) {
935
-				$src[] = "url('{$this->upload_url}custom/$name/{$output['woff2']}') format('woff2')";
936
-			}
937
-
938
-			if ( isset( $output['ttf'] ) ) {
939
-				$src[] = "url('{$this->upload_url}custom/$name/{$output['ttf']}') format('truetype')";
940
-			}
941
-
942
-			if ( isset( $output['svg'] ) ) {
943
-				$src[] = "url('{$this->upload_url}custom/$name/{$output['svg']}#svg$name') format('svg')";
944
-			}
945
-
946
-			if ( ! empty( $src ) ) {
947
-				$css .= 'src:' . implode( ', ', $src ) . ';';
948
-			}
949
-
950
-			// Replace font weight and style with sub-sets.
951
-			$css .= 'font-weight: normal;';
952
-
953
-			$css .= 'font-style: normal;';
954
-
955
-			$css .= '}';
956
-
957
-			return $css;
958
-		}
959
-
960
-		/**
961
-		 * Custom function for filtering the section array.
962
-		 * Good for child themes to override or add to the sections.
963
-		 * Simply include this function in the child themes functions.php file.
964
-		 * NOTE: the defined constants for URLs and directories will NOT be available at this point in a child theme,
965
-		 * so you must use get_template_directory_uri() if you want to use any of the built-in icons
966
-		 */
967
-		public function add_section() {
968
-			if ( ! isset( $this->parent->fontControl ) ) {
969
-				$this->parent->sections[] = array(
970
-					'title'  => esc_html__( 'Font Control', 'redux-framework' ),
971
-					'desc'   => '<p class="description"></p>',
972
-					'icon'   => 'el-icon-font',
973
-					'id'     => 'redux_dynamic_font_control',
974
-					// Leave this as a blank section, no options just some intro text set above.
975
-					'fields' => array(),
976
-				);
977
-
978
-				for ( $i = count( $this->parent->sections ); $i >= 1; $i-- ) {
979
-					if ( isset( $this->parent->sections[ $i ] ) && isset( $this->parent->sections[ $i ]['title'] ) && esc_html__( 'Font Control', 'redux-framework' ) === $this->parent->sections[ $i ]['title'] ) {
980
-						$this->parent->fontControl                                        = $i;
981
-						$this->parent->sections[ $this->parent->fontControl ]['fields'][] = array(
982
-							'id'   => 'redux_font_control',
983
-							'type' => 'custom_fonts',
984
-						);
985
-
986
-						break;
987
-					}
988
-				}
989
-			}
990
-		}
991
-	}
992
-
993
-	class_alias( Redux_Extension_Custom_Fonts::class, 'ReduxFramework_Extension_custom_fonts' );
19
+    /**
20
+     * Class Redux_Extension_Custom_Fonts
21
+     */
22
+    class Redux_Extension_Custom_Fonts extends Redux_Extension_Abstract {
23
+
24
+        /**
25
+         * Extension version.
26
+         *
27
+         * @var string
28
+         */
29
+        public static $version = '4.5.10';
30
+
31
+        /**
32
+         * Extension friendly name.
33
+         *
34
+         * @var string
35
+         */
36
+        public string $extension_name = 'Custom Fonts';
37
+        /**
38
+         * Class instance.
39
+         *
40
+         * @var object|null
41
+         */
42
+        public static ?object $instance;
43
+
44
+        /**
45
+         * Custom fonts array.
46
+         *
47
+         * @var array|null
48
+         */
49
+        public ?array $custom_fonts = array();
50
+
51
+        /**
52
+         * WordPress upload directory.
53
+         *
54
+         * @var string|null
55
+         */
56
+        public ?string $upload_dir = '';
57
+
58
+        /**
59
+         * WordPress upload URI.
60
+         *
61
+         * @var string|null
62
+         */
63
+        public ?string $upload_url = '';
64
+
65
+        /**
66
+         * Subfolder name.
67
+         *
68
+         * @var string
69
+         */
70
+        public string $subfolder = 'custom/';
71
+
72
+        /**
73
+         * Font folder.
74
+         *
75
+         * @var string|null
76
+         */
77
+        public ?string $font_folder = '';
78
+
79
+        /**
80
+         * Font Filename.
81
+         *
82
+         * @var string|null
83
+         */
84
+        public ?string $font_filename = '';
85
+
86
+        /**
87
+         * File selected in media upload.
88
+         *
89
+         * @var string|null
90
+         */
91
+        public ?string $selected_file = '';
92
+
93
+        /**
94
+         * Is font conversation service available?
95
+         *
96
+         * @var bool
97
+         */
98
+        private bool $can_convert;
99
+
100
+        /**
101
+         * Class Constructor. Defines the args for the extensions class
102
+         *
103
+         * @param ReduxFramework $redux ReduxFramework pointer.
104
+         *
105
+         * @return      void
106
+         * @since       1.0.0
107
+         * @access      public
108
+         */
109
+        public function __construct( $redux ) {
110
+            if ( false === $redux->args['custom_fonts'] ) {
111
+                return;
112
+            }
113
+
114
+            parent::__construct( $redux, __FILE__ );
115
+
116
+            self::$instance = parent::get_instance();
117
+
118
+            $this->add_field( 'custom_fonts' );
119
+
120
+            $this->upload_dir = Redux_Core::$upload_dir . 'custom-fonts/';
121
+            $this->upload_url = Redux_Core::$upload_url . 'custom-fonts/';
122
+
123
+            if ( ! is_dir( $this->upload_dir ) ) {
124
+                Redux_Core::$filesystem->execute( 'mkdir', $this->upload_dir );
125
+            }
126
+
127
+            if ( ! is_dir( $this->upload_dir . '/custom' ) ) {
128
+                Redux_Core::$filesystem->execute( 'mkdir', $this->upload_dir . '/custom' );
129
+            }
130
+
131
+            $this->get_fonts();
132
+
133
+            if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
134
+                if ( filemtime( $this->upload_dir . 'custom' ) > ( filemtime( $this->upload_dir . 'fonts.css' ) + 10 ) ) {
135
+                    $this->generate_css();
136
+                }
137
+            } else {
138
+                $this->generate_css();
139
+            }
140
+
141
+            add_action( 'wp_ajax_redux_custom_fonts', array( $this, 'ajax' ) );
142
+            add_action( 'wp_ajax_redux_custom_font_timer', array( $this, 'timer' ) );
143
+
144
+            add_filter( "redux/{$this->parent->args['opt_name']}/field/typography/custom_fonts", array( $this, 'add_custom_fonts' ) );
145
+
146
+            // phpcs:disable
147
+            // $this->is_field = Redux_Helpers::is_field_in_use( $parent, 'custom_fonts' );
148
+
149
+            // if ( ! $this->is_field ) {
150
+            // 	$this->add_section();
151
+            // }
152
+
153
+            add_filter( "redux/options/{$this->parent->args['opt_name']}/section/redux_dynamic_font_control", array( $this, 'remove_dynamic_section' ) ); // phpcs:ignore WordPress.NamingConventions.ValidHookName
154
+            add_filter( 'upload_mimes', array( $this, 'custom_upload_mimes' ) );
155
+            add_action( 'wp_head', array( $this, 'enqueue_output' ), 150 );
156
+            add_filter( 'tiny_mce_before_init', array( $this, 'extend_tinymce_dropdown' ) );
157
+
158
+            $this->can_convert = true; // has_filter( 'redux/' . $this->parent->args['opt_name'] . '/extensions/custom_fonts/api_url' );
159
+            // phpcs:enable
160
+        }
161
+
162
+        /**
163
+         * Timer.
164
+         */
165
+        public function timer() {
166
+            if ( ! current_user_can( $this->parent->args['page_permissions'] ) ) {
167
+                wp_die( esc_html__( 'You do not have permission to perform this action.', 'redux-framework' ), 403 );
168
+            }
169
+
170
+            if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'redux_custom_fonts' ) ) {
171
+                die( 0 );
172
+            }
173
+
174
+            $name = get_option( 'redux_custom_font_current' );
175
+
176
+            if ( ! empty( $name ) ) {
177
+                echo esc_html( $name );
178
+            }
179
+
180
+            die();
181
+        }
182
+
183
+        /**
184
+         * Remove the dynamically added section if the field was used elsewhere
185
+         *
186
+         * @param array $section Section array.
187
+         *
188
+         * @return array
189
+         * @since  Redux_Framework 3.1.1
190
+         */
191
+        public function remove_dynamic_section( array $section ): array {
192
+            if ( isset( $this->parent->field_types['custom_fonts'] ) ) {
193
+                $section = array();
194
+            }
195
+
196
+            return $section;
197
+        }
198
+
199
+        /**
200
+         * Adds FontMeister fonts to the TinyMCE drop-down.
201
+         * Typekit's fonts don't render properly in the drop-down and in the editor,
202
+         * because Typekit needs JS and TinyMCE doesn't support that.
203
+         *
204
+         * @param array $opt Option array.
205
+         *
206
+         * @return array
207
+         */
208
+        public function extend_tinymce_dropdown( array $opt ): array {
209
+            if ( ! is_admin() ) {
210
+                return $opt;
211
+            }
212
+
213
+            if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
214
+                $theme_advanced_fonts = $opt['font_formats'] ?? 'Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats';
215
+                $custom_fonts         = '';
216
+
217
+                $stylesheet = $this->upload_url . 'fonts.css';
218
+
219
+                if ( empty( $opt['content_css'] ) ) {
220
+                    $opt['content_css'] = $stylesheet;
221
+                } else {
222
+                    $opt['content_css'] = $opt['content_css'] . ',' . $stylesheet;
223
+                }
224
+
225
+                foreach ( $this->custom_fonts as $arr ) {
226
+                    foreach ( $arr as $font => $pieces ) {
227
+                        $custom_fonts .= ';' . $font . '=' . $font;
228
+                    }
229
+                }
230
+
231
+                $opt['font_formats'] = $theme_advanced_fonts . $custom_fonts;
232
+            }
233
+
234
+            return $opt;
235
+        }
236
+
237
+
238
+        /**
239
+         * Function to enqueue the custom fonts css
240
+         */
241
+        public function enqueue_output() {
242
+            if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
243
+                wp_enqueue_style(
244
+                    'redux-custom-fonts',
245
+                    $this->upload_url . 'fonts.css',
246
+                    array(),
247
+                    filemtime( $this->upload_dir . 'fonts.css' )
248
+                );
249
+            }
250
+        }
251
+
252
+        /**
253
+         * Adds the appropriate mime types to WordPress
254
+         *
255
+         * @param array $existing_mimes Mine array.
256
+         *
257
+         * @return array
258
+         */
259
+        public function custom_upload_mimes( array $existing_mimes = array() ): array {
260
+            $existing_mimes['ttf']   = 'font/ttf';
261
+            $existing_mimes['otf']   = 'font/otf';
262
+            $existing_mimes['eot']   = 'application/vnd.ms-fontobject';
263
+            $existing_mimes['woff']  = 'application/font-woff';
264
+            $existing_mimes['woff2'] = 'application/font-woff2';
265
+            $existing_mimes['svg']   = 'image/svg+xml';
266
+            $existing_mimes['zip']   = 'application/zip';
267
+
268
+            return $existing_mimes;
269
+        }
270
+
271
+        /**
272
+         * Gets all the fonts in the custom_fonts directory
273
+         */
274
+        public function get_fonts() {
275
+            if ( empty( $this->custom_fonts ) ) {
276
+                $params = array(
277
+                    'include_hidden' => false,
278
+                    'recursive'      => true,
279
+                );
280
+
281
+                $fonts = Redux_Core::$filesystem->execute( 'dirlist', $this->upload_dir, $params );
282
+
283
+                if ( ! empty( $fonts ) ) {
284
+                    foreach ( $fonts as $section ) {
285
+                        if ( 'd' === $section['type'] && ! empty( $section['name'] ) ) {
286
+                            if ( 'custom' === $section['name'] ) {
287
+                                $section['name'] = esc_html__( 'Custom Fonts', 'redux-framework' );
288
+                            }
289
+
290
+                            if ( empty( $section['files'] ) ) {
291
+                                continue;
292
+                            }
293
+
294
+                            $this->custom_fonts[ $section['name'] ] = $this->custom_fonts[ $section['name'] ] ?? array();
295
+
296
+                            foreach ( $section['files'] as $font ) {
297
+                                if ( ! empty( $font['name'] ) ) {
298
+                                    if ( empty( $font['files'] ) ) {
299
+                                        continue;
300
+                                    }
301
+
302
+                                    $kinds = array();
303
+
304
+                                    foreach ( $font['files'] as $f ) {
305
+                                        $valid = $this->check_font_name( $f );
306
+                                        if ( $valid ) {
307
+                                            $kinds[] = $valid;
308
+                                        }
309
+                                    }
310
+
311
+                                    $this->custom_fonts[ $section['name'] ][ $font['name'] ] = $kinds;
312
+                                }
313
+                            }
314
+                        }
315
+                    }
316
+                }
317
+            }
318
+        }
319
+
320
+        /**
321
+         * Add custom fonts.
322
+         *
323
+         * @param mixed $custom_fonts Custom fonts.
324
+         *
325
+         * @return array
326
+         */
327
+        public function add_custom_fonts( $custom_fonts ): array {
328
+            if ( empty( $custom_fonts ) ) {
329
+                $custom_fonts = array();
330
+            }
331
+
332
+            return wp_parse_args( $custom_fonts, $this->custom_fonts );
333
+        }
334
+
335
+        /**
336
+         * Ajax used within the panel to add and process the fonts
337
+         */
338
+        public function ajax() {
339
+            if ( ! current_user_can( $this->parent->args['page_permissions'] ) ) {
340
+                wp_die( esc_html__( 'You do not have permission to perform this action.', 'redux-framework' ), 403 );
341
+            }
342
+
343
+            if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'redux_custom_fonts' ) ) {
344
+                die( 0 );
345
+            }
346
+
347
+            if ( isset( $_POST['type'] ) && 'delete' === $_POST['type'] ) {
348
+                if ( isset( $_POST['section'] ) ) {
349
+                    if ( esc_html__( 'Custom Fonts', 'redux-framework' ) === $_POST['section'] ) {
350
+                        $_POST['section'] = 'custom';
351
+                    }
352
+                }
353
+
354
+                try {
355
+                    if ( isset( $_POST['section'] ) || isset( $_POST['name'] ) ) {
356
+                        $ret = Redux_Core::$filesystem->execute( 'rmdir', $this->upload_dir . sanitize_file_name( wp_unslash( $_POST['section'] ) ) . '/' . sanitize_file_name( wp_unslash( $_POST['name'] ) ) . '/', array( 'recursive' => true ) );
357
+
358
+                        if ( true === $ret ) {
359
+                            $result = array( 'type' => 'success' );
360
+                        } else {
361
+                            $result = array(
362
+                                'type' => 'error',
363
+                                'msg'  => esc_html__( 'File system failure. Could not delete temp dir.', 'redux-framework' ),
364
+                            );
365
+                        }
366
+
367
+                        echo wp_json_encode( $result );
368
+                    }
369
+                } catch ( Exception $e ) {
370
+                    echo wp_json_encode(
371
+                        array(
372
+                            'type' => 'error',
373
+                            'msg'  => esc_html__( 'Unable to delete font file(s).', 'redux-framework' ),
374
+                        )
375
+                    );
376
+                }
377
+
378
+                die();
379
+            }
380
+
381
+            if ( ! isset( $_POST['title'] ) ) {
382
+                $_POST['title'] = '';
383
+            }
384
+
385
+            if ( ! isset( $_POST['filename'] ) ) {
386
+                $_POST['filename'] = '';
387
+            }
388
+
389
+            $this->font_folder   = sanitize_file_name( wp_unslash( $_POST['title'] ) );
390
+            $this->font_filename = sanitize_file_name( wp_unslash( $_POST['filename'] ) );
391
+
392
+            if ( ! empty( $_POST['attachment_id'] ) ) {
393
+                if ( isset( $_POST['title'] ) || isset( $_POST['mime'] ) ) {
394
+                    $msg = $this->process_web_font( sanitize_key( wp_unslash( $_POST['attachment_id'] ) ), sanitize_text_field( wp_unslash( $_POST['mime'] ) ) );
395
+
396
+                    if ( empty( $msg ) ) {
397
+                        $msg = '';
398
+                    }
399
+
400
+                    $result = array(
401
+                        'type' => 'success',
402
+                        'msg'  => $msg,
403
+                    );
404
+
405
+                    echo wp_json_encode( $result );
406
+                }
407
+            }
408
+
409
+            die();
410
+        }
411
+
412
+        /**
413
+         * Get only valid files. Ensure everything is proper for processing.
414
+         *
415
+         * @param string $path Path.
416
+         *
417
+         * @return array
418
+         */
419
+        public function get_valid_files( string $path ): array {
420
+            $output = array();
421
+            $path   = trailingslashit( $path );
422
+
423
+            $params = array(
424
+                'include_hidden' => false,
425
+                'recursive'      => true,
426
+            );
427
+
428
+            $files = Redux_Core::$filesystem->execute( 'dirlist', $path, $params );
429
+
430
+            foreach ( $files as $file ) {
431
+                if ( 'd' === $file['type'] ) {
432
+                    $output = array_merge( $output, $this->get_valid_files( $path . $file['name'] ) );
433
+                } elseif ( 'f' === $file['type'] ) {
434
+                    $valid = $this->check_font_name( $file );
435
+                    if ( $valid ) {
436
+                        $output[ $valid ] = trailingslashit( $path ) . $file['name'];
437
+                    }
438
+                }
439
+            }
440
+
441
+            return $output;
442
+        }
443
+
444
+        /**
445
+         * Take a valid web font and process the missing pieces.
446
+         *
447
+         * @param string $attachment_id ID.
448
+         * @param string $mime_type     Mine type.
449
+         */
450
+        public function process_web_font( string $attachment_id, string $mime_type ) {
451
+            // phpcs:ignore WordPress.Security.NonceVerification
452
+            if ( ! isset( $_POST['conversion'] ) ) {
453
+                $_POST['conversion'] = 'false';
454
+            }
455
+
456
+            // phpcs:ignore WordPress.Security.NonceVerification
457
+            $conversion = sanitize_text_field( wp_unslash( $_POST['conversion'] ) );
458
+
459
+            $missing = array();
460
+
461
+            $complete = array(
462
+                'ttf',
463
+                'woff',
464
+                'woff2',
465
+                'eot',
466
+                'svg',
467
+                'otf',
468
+            );
469
+
470
+            $subtype = explode( '/', $mime_type );
471
+            $subtype = trim( max( $subtype ) );
472
+
473
+            if ( ! is_dir( $this->upload_dir ) ) {
474
+                Redux_Core::$filesystem->execute( 'mkdir', $this->upload_dir );
475
+            }
476
+
477
+            if ( ! is_dir( $this->upload_dir . $this->subfolder ) ) {
478
+                Redux_Core::$filesystem->execute( 'mkdir', $this->upload_dir . $this->subfolder );
479
+            }
480
+
481
+            $temp                = $this->upload_dir . 'temp';
482
+            $this->selected_file = get_attached_file( $attachment_id );
483
+
484
+            if ( empty( $this->selected_file ) ) {
485
+                echo wp_json_encode(
486
+                    array(
487
+                        'type' => 'error',
488
+                        'msg'  => esc_html__( 'Attachment does not exist.', 'redux-framework' ),
489
+                    )
490
+                );
491
+
492
+                die();
493
+            }
494
+
495
+            $filename = explode( '/', $this->selected_file );
496
+
497
+            $filename = $filename[ ( count( $filename ) - 1 ) ];
498
+
499
+            $fontname = ucfirst(
500
+                str_replace(
501
+                    array(
502
+                        '.zip',
503
+                        '.ttf',
504
+                        '.woff',
505
+                        '.woff2',
506
+                        '.eot',
507
+                        '.svg',
508
+                        '.otf',
509
+                    ),
510
+                    '',
511
+                    strtolower( $filename )
512
+                )
513
+            );
514
+
515
+            if ( empty( $this->font_folder ) ) {
516
+                $this->font_folder = $fontname;
517
+            }
518
+
519
+            $ret = array();
520
+
521
+            if ( ! is_dir( $temp ) ) {
522
+                Redux_Core::$filesystem->execute( 'mkdir', $temp );
523
+            }
524
+
525
+            if ( 'zip' === $subtype ) {
526
+                $unzipfile = unzip_file( $this->selected_file, $temp );
527
+
528
+                if ( is_wp_error( $unzipfile ) ) {
529
+                    echo wp_json_encode(
530
+                        array(
531
+                            'type' => 'error',
532
+                            'msg'  => $unzipfile->get_error_message() . '<br><br>' . esc_html__( 'Unzipping failed.', 'redux-framework' ),
533
+                        )
534
+                    );
535
+
536
+                    die();
537
+                }
538
+
539
+                $output = $this->get_valid_files( $temp );
540
+
541
+                if ( ! empty( $output ) ) {
542
+                    foreach ( $complete as $test ) {
543
+                        if ( ! isset( $output[ $test ] ) ) {
544
+                            $missing[] = $test;
545
+                        }
546
+                    }
547
+
548
+                    if ( ! is_dir( $this->upload_dir . $this->subfolder . $this->font_folder . '/' ) ) {
549
+                        Redux_Core::$filesystem->execute( 'mkdir', $this->upload_dir . $this->subfolder . $this->font_folder . '/' );
550
+                    }
551
+
552
+                    foreach ( $output as $key => $value ) {
553
+                        $param_array = array(
554
+                            'destination' => $this->upload_dir . $this->subfolder . $this->font_folder . '/' . $fontname . '.' . $key,
555
+                            'overwrite'   => true,
556
+                            'chmod'       => 755,
557
+                        );
558
+
559
+                        Redux_Core::$filesystem->execute( 'copy', $value, $param_array );
560
+                    }
561
+
562
+                    if ( true === $this->can_convert && 'true' === $conversion ) {
563
+                        $ret = $this->get_missing_files( $fontname, $missing, $output );
564
+                    }
565
+                }
566
+
567
+                Redux_Core::$filesystem->execute( 'rmdir', $temp, array( 'recursive' => true ) );
568
+
569
+                $this->generate_css();
570
+
571
+                wp_delete_attachment( $attachment_id, true );
572
+            } elseif ( 'svg+xml' === $subtype || 'vnd.ms-fontobject' === $subtype || 'x-font-ttf' === $subtype || 'ttf' === $subtype || 'otf' === $subtype || 'font-woff' === $subtype || 'font-woff2' === $subtype || 'application-octet-stream' === $subtype || 'octet-stream' === $subtype ) {
573
+                foreach ( $complete as $test ) {
574
+                    if ( $subtype !== $test ) {
575
+                        if ( ! isset( $output[ $test ] ) ) {
576
+                            $missing[] = $test;
577
+                        }
578
+                    }
579
+                }
580
+
581
+                if ( ! is_dir( $this->upload_dir . $this->subfolder . $this->font_folder . '/' ) ) {
582
+                    Redux_Core::$filesystem->execute( 'mkdir', $this->upload_dir . $this->subfolder . $this->font_folder . '/' );
583
+                }
584
+
585
+                $output = array( $subtype => $this->selected_file );
586
+
587
+                if ( true === $this->can_convert && 'true' === $conversion ) {
588
+                    $ret = $this->get_missing_files( $fontname, $missing, $output );
589
+
590
+                    if ( false === $ret ) {
591
+                        if ( false === $this->convert_local_font() ) {
592
+                            echo wp_json_encode(
593
+                                array(
594
+                                    'type' => 'error',
595
+                                    'msg'  => esc_html__( 'File permission error. Local file could not be installed.', 'redux-framework' ) . ' ' . $subtype,
596
+                                )
597
+                            );
598
+
599
+                            die;
600
+                        }
601
+                    }
602
+                } elseif ( false === $this->convert_local_font() ) {
603
+                        echo wp_json_encode(
604
+                            array(
605
+                                'type' => 'error',
606
+                                'msg'  => esc_html__( 'File permission error. Local file could not be installed.', 'redux-framework' ) . ' ' . $subtype,
607
+                            )
608
+                        );
609
+
610
+                        die;
611
+                }
612
+
613
+                Redux_Core::$filesystem->execute( 'rmdir', $temp, array( 'recursive' => true ) );
614
+
615
+                $this->generate_css();
616
+
617
+                wp_delete_attachment( $attachment_id, true );
618
+            } else {
619
+                echo wp_json_encode(
620
+                    array(
621
+                        'type' => 'error',
622
+                        'msg'  => esc_html__( 'File type not recognized.', 'redux-framework' ) . ' ' . $subtype,
623
+                    )
624
+                );
625
+
626
+                die();
627
+            }
628
+
629
+            if ( is_array( $ret ) && ! empty( $ret ) ) {
630
+                $msg = esc_html__( 'Unidentified error.', 'redux-framework' );
631
+
632
+                if ( isset( $ret['msg'] ) ) {
633
+                    $msg = $ret['msg'];
634
+                }
635
+
636
+                return $msg;
637
+            }
638
+
639
+            return '';
640
+        }
641
+
642
+        /**
643
+         * Install selected file into Custom Fonts.
644
+         *
645
+         * @return bool
646
+         */
647
+        private function convert_local_font(): bool {
648
+            $param_array = array(
649
+                'destination' => $this->upload_dir . $this->subfolder . '/' . $this->font_folder . '/' . $this->font_filename,
650
+                'overwrite'   => true,
651
+                'chmod'       => 755,
652
+            );
653
+
654
+            return Redux_Core::$filesystem->execute( 'copy', $this->selected_file, $param_array );
655
+        }
656
+
657
+        /**
658
+         * Ping the WebFontOMatic API to get the missing files.
659
+         *
660
+         * @param string $fontname  Font name.
661
+         * @param array  $missing   Missing.
662
+         * @param array  $output    Output.
663
+         */
664
+        private function get_missing_files( string $fontname, array $missing, array $output ) {
665
+            if ( ! empty( $this->font_folder ) && ! empty( $missing ) ) {
666
+                $temp = $this->upload_dir . 'temp';
667
+
668
+                $font_ext = pathinfo( $this->font_filename, PATHINFO_EXTENSION );
669
+
670
+                $unsupported = array( 'eot', 'woff', 'woff2' );
671
+
672
+                // Find a file to convert from.
673
+                foreach ( $output as $key => $value ) {
674
+                    if ( 'eot' === $key ) {
675
+                        continue;
676
+                    } else {
677
+                        $main = $key;
678
+                        break;
679
+                    }
680
+                }
681
+
682
+                if ( ! isset( $main ) ) {
683
+                    echo wp_json_encode(
684
+                        array(
685
+                            'type' => 'error',
686
+                            'msg'  => esc_html__( 'No valid font file was found.', 'redux-framework' ),
687
+                        )
688
+                    );
689
+
690
+                    Redux_Core::$filesystem->execute( 'rmdir', $temp, array( 'recursive' => true ) );
691
+                    Redux_Core::$filesystem->execute( 'rmdir', $this->upload_dir . $this->subfolder . $this->font_folder . '/', array( 'recursive' => true ) );
692
+
693
+                    die();
694
+                }
695
+
696
+                update_option( 'redux_custom_font_current', $this->font_folder . '.zip' );
697
+
698
+                $boundary = wp_generate_password( 24 );
699
+
700
+                $headers = array(
701
+                    'content-type' => 'multipart/form-data; boundary=' . $boundary,
702
+                    'user-agent'   => 'redux-custom-fonts-' . self::$version . ' using ' . wp_get_theme(),
703
+                );
704
+
705
+                $payload  = '--' . $boundary;
706
+                $payload .= "\r\n";
707
+                $payload .= 'Content-Disposition: form-data; name="md5"' . "\r\n\r\n";
708
+                $payload .= md5( 'redux_custom_font' );
709
+                $payload .= "\r\n";
710
+
711
+                if ( $output[ $main ] ) {
712
+                    $payload .= '--' . $boundary;
713
+                    $payload .= "\r\n";
714
+                    $payload .= 'Content-Disposition: form-data; name="convert"; filename="' . basename( $output[ $main ] ) . '"' . "\r\n";
715
+                    $payload .= "\r\n";
716
+                    $payload .= Redux_Core::$filesystem->execute( 'get_contents', $output[ $main ] );
717
+                    $payload .= "\r\n";
718
+                }
719
+
720
+                $payload .= '--' . $boundary . '--';
721
+
722
+                $args = array(
723
+                    'headers'    => $headers,
724
+                    'body'       => $payload,
725
+                    'user-agent' => $headers['user-agent'],
726
+                    'timeout'    => 300,
727
+                    'sslverify'  => true,
728
+                );
729
+
730
+                // phpcs:disable WordPress.NamingConventions.ValidHookName
731
+                $api_url = apply_filters( 'redux/' . $this->parent->args['opt_name'] . '/extensions/custom_fonts/api_url', 'https://redux.io/fonts' );
732
+
733
+                $response = wp_remote_post( $api_url, $args );
734
+
735
+                if ( is_wp_error( $response ) ) {
736
+                    return array(
737
+                        'type' => 'error',
738
+                        'msg'  => $response->get_error_message() . '<br><br>' . esc_html__( 'Your font could not be converted at this time. Please try again later.', 'redux-framework' ),
739
+                    );
740
+                } elseif ( isset( $response['body'] ) ) {
741
+                    if ( null !== json_decode( $response['body'] ) ) {
742
+                        return json_decode( $response['body'], true );
743
+                    }
744
+                }
745
+
746
+                $param_array = array(
747
+                    'content'   => $response['body'],
748
+                    'overwrite' => true,
749
+                    'chmod'     => FS_CHMOD_FILE,
750
+                );
751
+
752
+                $zip_file = $temp . DIRECTORY_SEPARATOR . $fontname . '.zip';
753
+
754
+                Redux_Core::$filesystem->execute( 'put_contents', $zip_file, $param_array );
755
+
756
+                if ( 0 === filesize( $zip_file ) ) {
757
+                    return false;
758
+                }
759
+
760
+                $zip = unzip_file( $zip_file, $temp );
761
+
762
+                if ( ! is_wp_error( $zip ) ) {
763
+                    $params = array(
764
+                        'include_hidden' => false,
765
+                        'recursive'      => false,
766
+                    );
767
+
768
+                    $files = Redux_Core::$filesystem->execute( 'dirlist', $temp . DIRECTORY_SEPARATOR . 'fonts' . DIRECTORY_SEPARATOR, $params );
769
+
770
+                    foreach ( $files as $file ) {
771
+                        $param_array = array(
772
+                            'destination' => $this->upload_dir . $this->subfolder . $this->font_folder . DIRECTORY_SEPARATOR . sanitize_file_name( $file['name'] ),
773
+                            'overwrite'   => true,
774
+                            'chmod'       => 755,
775
+                        );
776
+
777
+                        Redux_Core::$filesystem->execute( 'move', $temp . DIRECTORY_SEPARATOR . 'fonts' . DIRECTORY_SEPARATOR . ( $file['name'] ), $param_array );
778
+                    }
779
+                } else {
780
+                    $path_parts = pathinfo( $output[ $main ] );
781
+
782
+                    $param_array = array(
783
+                        'destination' => $this->upload_dir . $this->subfolder . $this->font_folder . DIRECTORY_SEPARATOR . sanitize_file_name( $path_parts['basename'] ),
784
+                        'overwrite'   => true,
785
+                        'chmod'       => 755,
786
+                    );
787
+
788
+                    Redux_Core::$filesystem->execute( 'move', $output[ $main ], $param_array );
789
+
790
+                    if ( in_array( $font_ext, $unsupported, true ) ) {
791
+                        return array(
792
+                            'type' => 'error',
793
+                            // translators: %s = font extension.
794
+                            'msg'  => $zip->get_error_message() . '<br><br>' . sprintf( esc_html__( 'The font converter does not support %s fonts.', 'redux-framework' ), $font_ext ),
795
+                        );
796
+                    } else {
797
+                        return array(
798
+                            'type' => 'error',
799
+                            'msg'  => $zip->get_error_message() . '<br><br>' . esc_html__( 'ZIP error. Your font could not be converted at this time. Please try again later.', 'redux-framework' ),
800
+                        );
801
+                    }
802
+                }
803
+
804
+                delete_option( 'redux_custom_font_current' );
805
+            }
806
+
807
+            return true;
808
+        }
809
+
810
+        /**
811
+         * Check if the file name is a valid font file.
812
+         *
813
+         * @param array $file File.
814
+         *
815
+         * @return bool|string
816
+         */
817
+        private function check_font_name( array $file ) {
818
+            if ( '.woff' === strtolower( substr( $file['name'], - 5 ) ) ) {
819
+                return 'woff';
820
+            }
821
+
822
+            if ( '.woff2' === strtolower( substr( $file['name'], - 6 ) ) ) {
823
+                return 'woff2';
824
+            }
825
+
826
+            $sub = strtolower( substr( $file['name'], - 4 ) );
827
+
828
+            if ( '.ttf' === $sub ) {
829
+                return 'ttf';
830
+            }
831
+
832
+            if ( '.eot' === $sub ) {
833
+                return 'eot';
834
+            }
835
+
836
+            if ( '.svg' === $sub ) {
837
+                return 'svg';
838
+            }
839
+
840
+            if ( '.otf' === $sub ) {
841
+                return 'otf';
842
+            }
843
+
844
+            return false;
845
+        }
846
+
847
+        /**
848
+         * Generate a new custom CSS file for enqueuing on the frontend and backend.
849
+         */
850
+        private function generate_css() {
851
+            $params = array(
852
+                'include_hidden' => false,
853
+                'recursive'      => true,
854
+            );
855
+
856
+            $fonts = Redux_Core::$filesystem->execute( 'dirlist', $this->upload_dir . 'custom' . DIRECTORY_SEPARATOR, $params );
857
+
858
+            if ( empty( $fonts ) || ! is_array( $fonts ) ) {
859
+                return;
860
+            }
861
+
862
+            foreach ( $fonts as $font ) {
863
+                if ( 'd' === $font['type'] ) {
864
+                    break;
865
+                }
866
+
867
+                if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
868
+                    Redux_Core::$filesystem->execute( 'delete', $this->upload_dir . 'fonts.css' );
869
+                }
870
+
871
+                return;
872
+            }
873
+
874
+            $css = '';
875
+
876
+            foreach ( $fonts as $font ) {
877
+                if ( 'd' === $font['type'] ) {
878
+                    $css .= $this->generate_font_css( $font['name'], $this->upload_dir . 'custom' . DIRECTORY_SEPARATOR );
879
+                }
880
+            }
881
+
882
+            if ( '' !== $css ) {
883
+                $param_array = array(
884
+                    'content' => $css,
885
+                    'chmod'   => FS_CHMOD_FILE,
886
+                );
887
+
888
+                Redux_Core::$filesystem->execute( 'put_contents', $this->upload_dir . 'fonts.css', $param_array );
889
+            }
890
+        }
891
+
892
+        /**
893
+         * Process to actually construct the custom font css file.
894
+         *
895
+         * @param string $name Name.
896
+         * @param string $dir  Directory.
897
+         *
898
+         * @return string
899
+         */
900
+        private function generate_font_css( string $name, string $dir ): ?string {
901
+            $path = $dir . $name;
902
+
903
+            $params = array(
904
+                'include_hidden' => false,
905
+                'recursive'      => true,
906
+            );
907
+
908
+            $files = Redux_Core::$filesystem->execute( 'dirlist', $path, $params );
909
+
910
+            if ( empty( $files ) ) {
911
+                return null;
912
+            }
913
+
914
+            $output = array();
915
+
916
+            foreach ( $files as $file ) {
917
+                $output[ $this->check_font_name( $file ) ] = $file['name'];
918
+            }
919
+
920
+            $css = '@font-face {';
921
+
922
+            $css .= 'font-family:"' . $name . '";';
923
+
924
+            $src = array();
925
+
926
+            if ( isset( $output['eot'] ) ) {
927
+                $src[] = "url('{$this->upload_url}custom/$name/{$output['eot']}?#iefix') format('embedded-opentype')";
928
+            }
929
+
930
+            if ( isset( $output['woff'] ) ) {
931
+                $src[] = "url('{$this->upload_url}custom/$name/{$output['woff']}') format('woff')";
932
+            }
933
+
934
+            if ( isset( $output['woff2'] ) ) {
935
+                $src[] = "url('{$this->upload_url}custom/$name/{$output['woff2']}') format('woff2')";
936
+            }
937
+
938
+            if ( isset( $output['ttf'] ) ) {
939
+                $src[] = "url('{$this->upload_url}custom/$name/{$output['ttf']}') format('truetype')";
940
+            }
941
+
942
+            if ( isset( $output['svg'] ) ) {
943
+                $src[] = "url('{$this->upload_url}custom/$name/{$output['svg']}#svg$name') format('svg')";
944
+            }
945
+
946
+            if ( ! empty( $src ) ) {
947
+                $css .= 'src:' . implode( ', ', $src ) . ';';
948
+            }
949
+
950
+            // Replace font weight and style with sub-sets.
951
+            $css .= 'font-weight: normal;';
952
+
953
+            $css .= 'font-style: normal;';
954
+
955
+            $css .= '}';
956
+
957
+            return $css;
958
+        }
959
+
960
+        /**
961
+         * Custom function for filtering the section array.
962
+         * Good for child themes to override or add to the sections.
963
+         * Simply include this function in the child themes functions.php file.
964
+         * NOTE: the defined constants for URLs and directories will NOT be available at this point in a child theme,
965
+         * so you must use get_template_directory_uri() if you want to use any of the built-in icons
966
+         */
967
+        public function add_section() {
968
+            if ( ! isset( $this->parent->fontControl ) ) {
969
+                $this->parent->sections[] = array(
970
+                    'title'  => esc_html__( 'Font Control', 'redux-framework' ),
971
+                    'desc'   => '<p class="description"></p>',
972
+                    'icon'   => 'el-icon-font',
973
+                    'id'     => 'redux_dynamic_font_control',
974
+                    // Leave this as a blank section, no options just some intro text set above.
975
+                    'fields' => array(),
976
+                );
977
+
978
+                for ( $i = count( $this->parent->sections ); $i >= 1; $i-- ) {
979
+                    if ( isset( $this->parent->sections[ $i ] ) && isset( $this->parent->sections[ $i ]['title'] ) && esc_html__( 'Font Control', 'redux-framework' ) === $this->parent->sections[ $i ]['title'] ) {
980
+                        $this->parent->fontControl                                        = $i;
981
+                        $this->parent->sections[ $this->parent->fontControl ]['fields'][] = array(
982
+                            'id'   => 'redux_font_control',
983
+                            'type' => 'custom_fonts',
984
+                        );
985
+
986
+                        break;
987
+                    }
988
+                }
989
+            }
990
+        }
991
+    }
992
+
993
+    class_alias( Redux_Extension_Custom_Fonts::class, 'ReduxFramework_Extension_custom_fonts' );
994 994
 }
Please login to merge, or discard this patch.
inc/extensions/import_export/class-redux-extension-import-export.php 1 patch
Indentation   +146 added lines, -146 removed lines patch added patch discarded remove patch
@@ -14,153 +14,153 @@
 block discarded – undo
14 14
 // Don't duplicate me!
15 15
 if ( ! class_exists( 'Redux_Extension_Import_Export', false ) ) {
16 16
 
17
-	/**
18
-	 * Main ReduxFramework import_export extension class
19
-	 *
20
-	 * @since       3.1.6
21
-	 */
22
-	class Redux_Extension_Import_Export extends Redux_Extension_Abstract {
23
-
24
-		/**
25
-		 * Ext version.
26
-		 *
27
-		 * @var string
28
-		 */
29
-		public static $version = '4.5.10';
30
-
31
-		/**
32
-		 * Is field bit.
33
-		 *
34
-		 * @var bool
35
-		 */
36
-		public bool $is_field = false;
37
-
38
-		/**
39
-		 * Class Constructor. Defines the args for the extensions class
40
-		 *
41
-		 * @param object $redux ReduxFramework object.
42
-		 *
43
-		 * @return      void
44
-		 * @since       1.0.0
45
-		 * @access      public
46
-		 */
47
-		public function __construct( $redux ) {
48
-			parent::__construct( $redux, __FILE__ );
49
-
50
-			$this->add_field( 'import_export' );
51
-
52
-			add_action( 'wp_ajax_redux_download_options-' . $this->parent->args['opt_name'], array( $this, 'download_options' ) );
53
-
54
-			// phpcs:ignore WordPress.NamingConventions.ValidHookName
55
-			do_action( 'redux/options/' . $this->parent->args['opt_name'] . '/import', array( $this, 'remove_cookie' ) );
56
-
57
-			$this->is_field = Redux_Helpers::is_field_in_use( $redux, 'import_export' );
58
-
59
-			if ( ! $this->is_field && $this->parent->args['show_import_export'] ) {
60
-				$this->add_section();
61
-			}
62
-
63
-			add_filter( 'upload_mimes', array( $this, 'custom_upload_mimes' ) );
64
-		}
65
-
66
-		/**
67
-		 * Adds the appropriate mime types to WordPress
68
-		 *
69
-		 * @param array|null $existing_mimes .
70
-		 *
71
-		 * @return array
72
-		 */
73
-		public function custom_upload_mimes( ?array $existing_mimes = array() ): array {
74
-			$existing_mimes['redux'] = 'application/redux';
75
-
76
-			return $existing_mimes;
77
-		}
78
-
79
-		/**
80
-		 * Add section to panel.
81
-		 */
82
-		public function add_section() {
83
-			$this->parent->sections[] = array(
84
-				'id'         => 'import/export',
85
-				'title'      => esc_html__( 'Import / Export', 'redux-framework' ),
86
-				'heading'    => '',
87
-				'icon'       => 'el el-refresh',
88
-				'customizer' => false,
89
-				'fields'     => array(
90
-					array(
91
-						'id'         => 'redux_import_export',
92
-						'type'       => 'import_export',
93
-						'full_width' => true,
94
-					),
95
-				),
96
-			);
97
-		}
98
-
99
-		/**
100
-		 * Import download options.
101
-		 */
102
-		public function download_options() {
103
-			if ( ! is_admin() ) {
104
-				wp_die();
105
-			}
106
-
107
-			if ( ! current_user_can( $this->parent->args['page_permissions'] ) ) {
108
-				wp_die( esc_html__( 'You do not have permission to export options.', 'redux-framework' ) );
109
-			}
110
-
111
-			if ( ! isset( $_GET['secret'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_GET['secret'] ) ), 'redux_io_' . $this->parent->args['opt_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
112
-				wp_die( 'Invalid secret for options use.' );
113
-			}
114
-
115
-			$this->parent->options_class->get();
116
-			$backup_options                 = $this->parent->options;
117
-			$backup_options['redux-backup'] = 1;
118
-
119
-			if ( isset( $backup_options['REDUX_imported'] ) ) {
120
-				unset( $backup_options['REDUX_imported'] );
121
-			}
122
-
123
-			// No need to escape this, as it's been properly escaped previously and through json_encode.
124
-			$content = wp_json_encode( $backup_options );
125
-
126
-			if ( isset( $_GET['action'] ) && 'redux_download_options-' . $this->parent->args['opt_name'] === $_GET['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification
127
-				header( 'Content-Description: File Transfer' );
128
-				header( 'Content-type: application/txt' );
129
-				header( 'Content-Disposition: attachment; filename="redux_options_"' . $this->parent->args['opt_name'] . '_backup_' . gmdate( 'm-d-Y' ) . '.json' );
130
-				header( 'Content-Transfer-Encoding: binary' );
131
-				header( 'Expires: 0' );
132
-				header( 'Cache-Control: must-revalidate' );
133
-				header( 'Pragma: public' );
134
-			} else {
135
-				header( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' );
136
-				header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . 'GMT' );
137
-				header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' );
138
-				header( 'Cache-Control: no-store, no-cache, must-revalidate' );
139
-				header( 'Cache-Control: post-check=0, pre-check=0', false );
140
-				header( 'Pragma: no-cache' );
141
-
142
-				// Can't include the type. Thanks old Firefox and IE. BAH.
143
-				// header('Content-type: application/json');.
144
-			}
145
-
146
-			// phpcs:ignore WordPress.Security.EscapeOutput
147
-			echo( $content );
148
-			exit;
149
-		}
150
-
151
-		/**
152
-		 * Remove current tab cookie.
153
-		 */
154
-		public function remove_cookie() {
155
-			// Remove the import/export tab cookie.
156
-			if ( isset( $_COOKIE[ 'redux_current_tab_' . $this->parent->args['opt_name'] ] ) && 'import_export_default' === $_COOKIE[ 'redux_current_tab_' . $this->parent->args['opt_name'] ] ) {
157
-				setcookie( 'redux_current_tab_' . $this->parent->args['opt_name'], '', 1, '/' );
158
-				$_COOKIE[ 'redux_current_tab_' . $this->parent->args['opt_name'] ] = 1;
159
-			}
160
-		}
161
-	}
17
+    /**
18
+     * Main ReduxFramework import_export extension class
19
+     *
20
+     * @since       3.1.6
21
+     */
22
+    class Redux_Extension_Import_Export extends Redux_Extension_Abstract {
23
+
24
+        /**
25
+         * Ext version.
26
+         *
27
+         * @var string
28
+         */
29
+        public static $version = '4.5.10';
30
+
31
+        /**
32
+         * Is field bit.
33
+         *
34
+         * @var bool
35
+         */
36
+        public bool $is_field = false;
37
+
38
+        /**
39
+         * Class Constructor. Defines the args for the extensions class
40
+         *
41
+         * @param object $redux ReduxFramework object.
42
+         *
43
+         * @return      void
44
+         * @since       1.0.0
45
+         * @access      public
46
+         */
47
+        public function __construct( $redux ) {
48
+            parent::__construct( $redux, __FILE__ );
49
+
50
+            $this->add_field( 'import_export' );
51
+
52
+            add_action( 'wp_ajax_redux_download_options-' . $this->parent->args['opt_name'], array( $this, 'download_options' ) );
53
+
54
+            // phpcs:ignore WordPress.NamingConventions.ValidHookName
55
+            do_action( 'redux/options/' . $this->parent->args['opt_name'] . '/import', array( $this, 'remove_cookie' ) );
56
+
57
+            $this->is_field = Redux_Helpers::is_field_in_use( $redux, 'import_export' );
58
+
59
+            if ( ! $this->is_field && $this->parent->args['show_import_export'] ) {
60
+                $this->add_section();
61
+            }
62
+
63
+            add_filter( 'upload_mimes', array( $this, 'custom_upload_mimes' ) );
64
+        }
65
+
66
+        /**
67
+         * Adds the appropriate mime types to WordPress
68
+         *
69
+         * @param array|null $existing_mimes .
70
+         *
71
+         * @return array
72
+         */
73
+        public function custom_upload_mimes( ?array $existing_mimes = array() ): array {
74
+            $existing_mimes['redux'] = 'application/redux';
75
+
76
+            return $existing_mimes;
77
+        }
78
+
79
+        /**
80
+         * Add section to panel.
81
+         */
82
+        public function add_section() {
83
+            $this->parent->sections[] = array(
84
+                'id'         => 'import/export',
85
+                'title'      => esc_html__( 'Import / Export', 'redux-framework' ),
86
+                'heading'    => '',
87
+                'icon'       => 'el el-refresh',
88
+                'customizer' => false,
89
+                'fields'     => array(
90
+                    array(
91
+                        'id'         => 'redux_import_export',
92
+                        'type'       => 'import_export',
93
+                        'full_width' => true,
94
+                    ),
95
+                ),
96
+            );
97
+        }
98
+
99
+        /**
100
+         * Import download options.
101
+         */
102
+        public function download_options() {
103
+            if ( ! is_admin() ) {
104
+                wp_die();
105
+            }
106
+
107
+            if ( ! current_user_can( $this->parent->args['page_permissions'] ) ) {
108
+                wp_die( esc_html__( 'You do not have permission to export options.', 'redux-framework' ) );
109
+            }
110
+
111
+            if ( ! isset( $_GET['secret'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_GET['secret'] ) ), 'redux_io_' . $this->parent->args['opt_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
112
+                wp_die( 'Invalid secret for options use.' );
113
+            }
114
+
115
+            $this->parent->options_class->get();
116
+            $backup_options                 = $this->parent->options;
117
+            $backup_options['redux-backup'] = 1;
118
+
119
+            if ( isset( $backup_options['REDUX_imported'] ) ) {
120
+                unset( $backup_options['REDUX_imported'] );
121
+            }
122
+
123
+            // No need to escape this, as it's been properly escaped previously and through json_encode.
124
+            $content = wp_json_encode( $backup_options );
125
+
126
+            if ( isset( $_GET['action'] ) && 'redux_download_options-' . $this->parent->args['opt_name'] === $_GET['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification
127
+                header( 'Content-Description: File Transfer' );
128
+                header( 'Content-type: application/txt' );
129
+                header( 'Content-Disposition: attachment; filename="redux_options_"' . $this->parent->args['opt_name'] . '_backup_' . gmdate( 'm-d-Y' ) . '.json' );
130
+                header( 'Content-Transfer-Encoding: binary' );
131
+                header( 'Expires: 0' );
132
+                header( 'Cache-Control: must-revalidate' );
133
+                header( 'Pragma: public' );
134
+            } else {
135
+                header( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' );
136
+                header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . 'GMT' );
137
+                header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' );
138
+                header( 'Cache-Control: no-store, no-cache, must-revalidate' );
139
+                header( 'Cache-Control: post-check=0, pre-check=0', false );
140
+                header( 'Pragma: no-cache' );
141
+
142
+                // Can't include the type. Thanks old Firefox and IE. BAH.
143
+                // header('Content-type: application/json');.
144
+            }
145
+
146
+            // phpcs:ignore WordPress.Security.EscapeOutput
147
+            echo( $content );
148
+            exit;
149
+        }
150
+
151
+        /**
152
+         * Remove current tab cookie.
153
+         */
154
+        public function remove_cookie() {
155
+            // Remove the import/export tab cookie.
156
+            if ( isset( $_COOKIE[ 'redux_current_tab_' . $this->parent->args['opt_name'] ] ) && 'import_export_default' === $_COOKIE[ 'redux_current_tab_' . $this->parent->args['opt_name'] ] ) {
157
+                setcookie( 'redux_current_tab_' . $this->parent->args['opt_name'], '', 1, '/' );
158
+                $_COOKIE[ 'redux_current_tab_' . $this->parent->args['opt_name'] ] = 1;
159
+            }
160
+        }
161
+    }
162 162
 }
163 163
 
164 164
 if ( ! class_exists( 'ReduxFramework_extension_import_export' ) ) {
165
-	class_alias( 'Redux_Extension_Import_Export', 'ReduxFramework_extension_import_export' );
165
+    class_alias( 'Redux_Extension_Import_Export', 'ReduxFramework_extension_import_export' );
166 166
 }
Please login to merge, or discard this patch.
redux-core/inc/classes/class-redux-ajax-typography.php 1 patch
Indentation   +46 added lines, -46 removed lines patch added patch discarded remove patch
@@ -11,50 +11,50 @@
 block discarded – undo
11 11
 
12 12
 if ( ! class_exists( 'Redux_AJAX_Typography', false ) ) {
13 13
 
14
-	/**
15
-	 * Class Redux_AJAX_Typography
16
-	 */
17
-	class Redux_AJAX_Typography extends Redux_Class {
18
-
19
-		/**
20
-		 * Redux_AJAX_Typography constructor.
21
-		 *
22
-		 * @param object $redux ReduxFramework object.
23
-		 */
24
-		public function __construct( $redux ) {
25
-			parent::__construct( $redux );
26
-			add_action( 'wp_ajax_redux_update_google_fonts', array( $this, 'google_fonts_update' ) );
27
-		}
28
-
29
-		/**
30
-		 * Google font AJAX callback
31
-		 *
32
-		 * @return void
33
-		 */
34
-		public function google_fonts_update() {
35
-			if ( ! current_user_can( $this->parent->args['page_permissions'] ) ) {
36
-				wp_die( esc_html__( 'You do not have permission to perform this action.', 'redux-framework' ), 403 );
37
-			}
38
-
39
-			$field_class = 'Redux_typography';
40
-
41
-			if ( ! class_exists( $field_class ) ) {
42
-				$dir = str_replace( '/classes', '', Redux_Functions_Ex::wp_normalize_path( __DIR__ ) );
43
-
44
-				// phpcs:ignore WordPress.NamingConventions.ValidHookName
45
-				$class_file = apply_filters( 'redux-typeclass-load', $dir . '/fields/typography/class-redux-typography.php', $field_class );
46
-				if ( $class_file ) {
47
-					require_once $class_file;
48
-				}
49
-			}
50
-
51
-			if ( class_exists( $field_class ) && method_exists( $field_class, 'google_fonts_update_ajax' ) ) {
52
-				$f = new $field_class( array(), '', $this->parent );
53
-
54
-				$f->google_fonts_update_ajax();
55
-			}
56
-
57
-			die();
58
-		}
59
-	}
14
+    /**
15
+     * Class Redux_AJAX_Typography
16
+     */
17
+    class Redux_AJAX_Typography extends Redux_Class {
18
+
19
+        /**
20
+         * Redux_AJAX_Typography constructor.
21
+         *
22
+         * @param object $redux ReduxFramework object.
23
+         */
24
+        public function __construct( $redux ) {
25
+            parent::__construct( $redux );
26
+            add_action( 'wp_ajax_redux_update_google_fonts', array( $this, 'google_fonts_update' ) );
27
+        }
28
+
29
+        /**
30
+         * Google font AJAX callback
31
+         *
32
+         * @return void
33
+         */
34
+        public function google_fonts_update() {
35
+            if ( ! current_user_can( $this->parent->args['page_permissions'] ) ) {
36
+                wp_die( esc_html__( 'You do not have permission to perform this action.', 'redux-framework' ), 403 );
37
+            }
38
+
39
+            $field_class = 'Redux_typography';
40
+
41
+            if ( ! class_exists( $field_class ) ) {
42
+                $dir = str_replace( '/classes', '', Redux_Functions_Ex::wp_normalize_path( __DIR__ ) );
43
+
44
+                // phpcs:ignore WordPress.NamingConventions.ValidHookName
45
+                $class_file = apply_filters( 'redux-typeclass-load', $dir . '/fields/typography/class-redux-typography.php', $field_class );
46
+                if ( $class_file ) {
47
+                    require_once $class_file;
48
+                }
49
+            }
50
+
51
+            if ( class_exists( $field_class ) && method_exists( $field_class, 'google_fonts_update_ajax' ) ) {
52
+                $f = new $field_class( array(), '', $this->parent );
53
+
54
+                $f->google_fonts_update_ajax();
55
+            }
56
+
57
+            die();
58
+        }
59
+    }
60 60
 }
Please login to merge, or discard this patch.