Customify – A Theme Customizer Booster - Version 1.7.1

Version Description

  • Fixed issue with Color Palettes overwriting custom colors in Live Preview
Download this release

Release Info

Developer pixelgrade
Plugin Icon Customify – A Theme Customizer Booster
Version 1.7.1
Comparing to
See all releases

Code changes from version 1.7.0 to 1.7.1

class-pixcustomify.php CHANGED
@@ -280,12 +280,12 @@ class PixCustomifyPlugin {
280
  */
281
  function load_plugin_configs() {
282
 
283
- // allow themes or other plugins to filter the config
284
  $this->customizer_config = apply_filters( 'customify_filter_fields', $this->customizer_config );
285
  $this->opt_name = $this->localized['options_name'] = $this->customizer_config['opt-name'];
286
  $this->options_list = $this->get_options();
287
 
288
- // Load the current options values
289
  $this->current_values = $this->get_current_values();
290
 
291
  if ( $this->import_button_exists() ) {
@@ -944,13 +944,64 @@ class PixCustomifyPlugin {
944
 
945
  $this_property_output = $css_property['selector'] . ' { ' . $css_property['property'] . ': ' . $this_value . $unit . "; }" . PHP_EOL;
946
 
947
- if ( isset( $css_property['callback_filter'] ) && function_exists( $css_property['callback_filter'] ) ) {
 
 
 
 
 
 
948
  $this_property_output = call_user_func( $css_property['callback_filter'], $this_value, $css_property['selector'], $css_property['property'], $unit );
949
  }
950
 
951
  return $this_property_output;
952
  }
953
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
954
  protected function process_custom_background_field_output( $option_id, $options ) {
955
  $selector = $output = '';
956
 
@@ -1277,6 +1328,7 @@ class PixCustomifyPlugin {
1277
  }
1278
 
1279
  // Add the option config to the localized array so we can pass the info to JS.
 
1280
  $this->localized['settings'][ $setting_id ] = $option_config;
1281
 
1282
  // Generate a safe option ID (not the final setting ID) to us in HTML attributes like ID or class
@@ -1752,8 +1804,12 @@ class PixCustomifyPlugin {
1752
  continue;
1753
  }
1754
 
1755
- // We will need to determine if the connected field specifies a setting ID or we need to determine it.
1756
- if ( ! empty( $options[ $connected_field_id ] ) && ! empty( $options[ $connected_field_id ]['setting_id'] ) ) {
 
 
 
 
1757
  $connected_field_data['setting_id'] = $options[ $connected_field_id ]['setting_id'];
1758
  } else {
1759
  $connected_field_data['setting_id'] = $options_name . '[' . $connected_field_id . ']';
280
  */
281
  function load_plugin_configs() {
282
 
283
+ // Allow themes or other plugins to filter the config.
284
  $this->customizer_config = apply_filters( 'customify_filter_fields', $this->customizer_config );
285
  $this->opt_name = $this->localized['options_name'] = $this->customizer_config['opt-name'];
286
  $this->options_list = $this->get_options();
287
 
288
+ // Load the current options values.
289
  $this->current_values = $this->get_current_values();
290
 
291
  if ( $this->import_button_exists() ) {
944
 
945
  $this_property_output = $css_property['selector'] . ' { ' . $css_property['property'] . ': ' . $this_value . $unit . "; }" . PHP_EOL;
946
 
947
+ // Handle the value filter callback.
948
+ if ( isset( $css_property['filter_value_cb'] ) ) {
949
+ $this_value = $this->maybe_apply_filter( $css_property['filter_value_cb'], $this_value );
950
+ }
951
+
952
+ // Handle output callback.
953
+ if ( isset( $css_property['callback_filter'] ) && is_callable( $css_property['callback_filter'] ) ) {
954
  $this_property_output = call_user_func( $css_property['callback_filter'], $this_value, $css_property['selector'], $css_property['property'], $unit );
955
  }
956
 
957
  return $this_property_output;
958
  }
959
 
960
+ /**
961
+ * Apply a filter (config) to a value.
962
+ *
963
+ * We currently handle filters like these:
964
+ * // Elaborate filter config
965
+ * array(
966
+ * 'callback' => 'is_post_type_archive',
967
+ * // The arguments we should pass to the check function.
968
+ * // Think post types, taxonomies, or nothing if that is the case.
969
+ * // It can be an array of values or a single value.
970
+ * 'args' => array(
971
+ * 'jetpack-portfolio',
972
+ * ),
973
+ * ),
974
+ * // Simple filter - just the function name
975
+ * 'is_404',
976
+ *
977
+ * @param array|string $filter
978
+ * @param mixed $value The value to apply the filter to.
979
+ *
980
+ * @return mixed The filtered value.
981
+ */
982
+ public function maybe_apply_filter( $filter, $value ) {
983
+ // Let's get some obvious things off the table.
984
+ // On invalid data, we just return what we've received.
985
+ if ( empty( $filter ) ) {
986
+ return $value;
987
+ }
988
+
989
+ // First, we handle the shorthand version: just a function name
990
+ if ( is_string( $filter ) && is_callable( $filter ) ) {
991
+ $value = call_user_func( $filter );
992
+ } elseif ( is_array( $filter ) && ! empty( $filter['callback'] ) && is_callable( $filter['callback'] ) ) {
993
+ if ( empty( $filter['args'] ) ) {
994
+ $filter['args'] = array();
995
+ }
996
+ // The value is always the first argument.
997
+ $filter['args'] = array( $value ) + $filter['args'];
998
+
999
+ $value = call_user_func_array( $filter['callback'], $filter['args'] );
1000
+ }
1001
+
1002
+ return $value;
1003
+ }
1004
+
1005
  protected function process_custom_background_field_output( $option_id, $options ) {
1006
  $selector = $output = '';
1007
 
1328
  }
1329
 
1330
  // Add the option config to the localized array so we can pass the info to JS.
1331
+ // @todo Maybe we should ensure that the connected_fields configs passed here follow the same format and logic as the ones in ::customize_pane_settings_additional_data() thus maybe having the data in the same place.
1332
  $this->localized['settings'][ $setting_id ] = $option_config;
1333
 
1334
  // Generate a safe option ID (not the final setting ID) to us in HTML attributes like ID or class
1804
  continue;
1805
  }
1806
 
1807
+ // If the connected setting is not one of our's, we will use it's ID as it is.
1808
+ if ( ! array_key_exists( $connected_field_id, $options ) ) {
1809
+ $connected_field_data['setting_id'] = $connected_field_id;
1810
+ }
1811
+ // If the connected setting specifies a setting ID, we will not prefix it and use it as it is.
1812
+ elseif ( ! empty( $options[ $connected_field_id ] ) && ! empty( $options[ $connected_field_id ]['setting_id'] ) ) {
1813
  $connected_field_data['setting_id'] = $options[ $connected_field_id ]['setting_id'];
1814
  } else {
1815
  $connected_field_data['setting_id'] = $options_name . '[' . $connected_field_id . ']';
customify.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Customify
4
  Plugin URI: https://wordpress.org/plugins/customify/
5
  Description: A Theme Customizer Booster
6
- Version: 1.7.0
7
  Author: Pixelgrade
8
  Author URI: https://pixelgrade.com
9
  Author Email: contact@pixelgrade.com
@@ -23,12 +23,15 @@ if ( ! defined('EXT')) {
23
  define('EXT', '.php');
24
  }
25
 
26
- require 'core/bootstrap'.EXT;
27
 
28
- $config = include 'plugin-config'.EXT;
 
 
 
29
 
30
  // set textdomain
31
- pixcustomify::settextdomain('customify');
32
 
33
  // Ensure Test Data
34
  // ----------------
@@ -69,4 +72,4 @@ $pixcustomify_plugin = PixCustomifyPlugin();
69
 
70
  // Load custom modules
71
  require_once( 'features/class-CSS_Editor.php' );
72
- require_once( 'features/class-Font_Selector.php' );
3
  Plugin Name: Customify
4
  Plugin URI: https://wordpress.org/plugins/customify/
5
  Description: A Theme Customizer Booster
6
+ Version: 1.7.1
7
  Author: Pixelgrade
8
  Author URI: https://pixelgrade.com
9
  Author Email: contact@pixelgrade.com
23
  define('EXT', '.php');
24
  }
25
 
26
+ require 'core/bootstrap' . EXT;
27
 
28
+ // Include our helper array class.
29
+ require 'includes/class-customify-array' . EXT;
30
+
31
+ $config = include 'plugin-config' . EXT;
32
 
33
  // set textdomain
34
+ pixcustomify::settextdomain( 'customify' );
35
 
36
  // Ensure Test Data
37
  // ----------------
72
 
73
  // Load custom modules
74
  require_once( 'features/class-CSS_Editor.php' );
75
+ require_once( 'features/class-Font_Selector.php' );
customify_config.php CHANGED
@@ -350,4 +350,4 @@ if ( ! function_exists('add_customify_base_options') ) {
350
  return $config;
351
  }
352
  }
353
- add_filter( 'customify_filter_fields', 'add_customify_base_options' );
350
  return $config;
351
  }
352
  }
353
+ add_filter( 'customify_filter_fields', 'add_customify_base_options', 5, 1 );
includes/class-customify-array.php ADDED
@@ -0,0 +1,320 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is a utility class that groups all our array related helper functions.
4
+ *
5
+ * @see https://pixelgrade.com
6
+ * @author Pixelgrade
7
+ * @version 1.0.0
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit; // Exit if accessed directly
12
+ }
13
+
14
+ if ( ! class_exists( 'Customify_Array' ) ) :
15
+
16
+ class Customify_Array {
17
+ /**
18
+ * Insert a value or key/value pair before a specific key in an array. If key doesn't exist, value is prepended
19
+ * at the beginning of the array.
20
+ *
21
+ * @param array $array
22
+ * @param string $key
23
+ * @param mixed $insert
24
+ *
25
+ * @return array
26
+ */
27
+ public static function insertBeforeKey( $array, $key, $insert ) {
28
+ $keys = array_keys( $array );
29
+ $index = array_search( $key, $keys );
30
+ $pos = ( ( false === $index ) ? 0 : $index );
31
+ if ( ! is_array( $insert ) ) {
32
+ $insert = array( $insert );
33
+ }
34
+ return array_merge( array_slice( $array, 0, $pos ), $insert, array_slice( $array, $pos ) );
35
+ }
36
+
37
+ /**
38
+ * Insert a value (array included) or key/value pair after a specific key in an array. If key doesn't exist, value is appended
39
+ * to the end of the array.
40
+ *
41
+ * @param array $array
42
+ * @param string $key
43
+ * @param mixed $insert
44
+ *
45
+ * @return array
46
+ */
47
+ public static function insertAfterKey( $array, $key, $insert ) {
48
+ $keys = array_keys( $array );
49
+ $index = array_search( $key, $keys );
50
+ $pos = ( ( false === $index ) ? count( $array ) : $index + 1 );
51
+ if ( ! is_array( $insert ) ) {
52
+ $insert = array( $insert );
53
+ }
54
+ return array_merge( array_slice( $array, 0, $pos ), $insert, array_slice( $array, $pos ) );
55
+ }
56
+
57
+ /**
58
+ * Find a subarray that has the desired key=>value. We will only go one level deep.
59
+ *
60
+ * For example, given the following array:
61
+ * array( array( 'two' => 'value1' ), array( 'two' => 'value2' ) )
62
+ * you can search for the key of the subarray containing the 'two' key with the 'value2', that is 1
63
+ *
64
+ * @param array $array The array in which to search
65
+ * @param string $key The key to search for
66
+ * @param mixed $value The value to search for
67
+ *
68
+ * @return mixed|false
69
+ */
70
+ public static function findSubarrayByKeyValue( $array, $key, $value ) {
71
+ // Bail if it's not array
72
+ if ( ! is_array( $array ) ) {
73
+ return false;
74
+ }
75
+
76
+ foreach ( $array as $k => $v ) {
77
+ if ( isset( $v[ $key ] ) && $value == $v[ $key ] ) {
78
+ return $k;
79
+ }
80
+ }
81
+
82
+ return false;
83
+ }
84
+
85
+ /**
86
+ * Search an array of objects for a certain property value and return the index where it was found.
87
+ *
88
+ * @param array $array
89
+ * @param string $property
90
+ * @param mixed $value
91
+ *
92
+ * @return int|string|false
93
+ */
94
+ public static function objArraySearch( $array, $property, $value ) {
95
+ foreach ( $array as $key => $array_inf ) {
96
+ if ( property_exists( $array_inf, $property ) && $array_inf->{$property} == $value ) {
97
+ return $key;
98
+ }
99
+ }
100
+ return false;
101
+ }
102
+
103
+ /**
104
+ * Get the difference between two associative arrays, recursively.
105
+ *
106
+ * @link http://be2.php.net/manual/en/function.array-diff-assoc.php#114297
107
+ *
108
+ * @param array $array1
109
+ * @param array $array2
110
+ *
111
+ * @return bool|array
112
+ */
113
+ public static function arrayDiffAssocRecursive( $array1, $array2 ) {
114
+ foreach ( $array1 as $key => $value ) {
115
+ if ( is_array( $value ) ) {
116
+ if ( ! isset( $array2[ $key ] ) ) {
117
+ $difference[ $key ] = $value;
118
+ } elseif ( ! is_array( $array2[ $key ] ) ) {
119
+ $difference[ $key ] = $value;
120
+ } else {
121
+ $new_diff = self::arrayDiffAssocRecursive( $value, $array2[ $key ] );
122
+ if ( false !== $new_diff ) {
123
+ $difference[ $key ] = $new_diff;
124
+ }
125
+ }
126
+ } elseif ( ! array_key_exists( $key, $array2 ) || $array2[ $key ] != $value ) {
127
+ $difference[ $key ] = $value;
128
+ }
129
+ }
130
+
131
+ return ! isset( $difference ) ? false : $difference;
132
+ }
133
+
134
+ /**
135
+ * Searches for an array entry that partially matches the needle and returns the first found key
136
+ *
137
+ * @param string $needle
138
+ * @param array $haystack
139
+ *
140
+ * @return bool|int|string The first key whose value matched the partial needle. False on failure or invalid input.
141
+ */
142
+ public static function strArraySearch( $needle, $haystack ) {
143
+ if ( empty( $haystack ) ) {
144
+ return false;
145
+ }
146
+
147
+ if ( ! is_array( $haystack ) ) {
148
+ return false;
149
+ }
150
+
151
+ foreach ( $haystack as $key => $value ) {
152
+ if ( ! is_string( $value ) ) {
153
+ return false;
154
+ }
155
+
156
+ if ( false !== strpos( $value, $needle ) ) {
157
+ return $key;
158
+ }
159
+ }
160
+
161
+ return false;
162
+ }
163
+
164
+ /**
165
+ * Searches in reverse order for an array entry that partially matches the needle and returns the first found key
166
+ *
167
+ * @param string $needle
168
+ * @param array $haystack
169
+ *
170
+ * @return bool|int|string The first key whose value matched the partial needle. False on failure or invalid input.
171
+ */
172
+ public static function strrArraySearch( $needle, $haystack ) {
173
+ if ( empty( $haystack ) ) {
174
+ return false;
175
+ }
176
+
177
+ if ( ! is_array( $haystack ) ) {
178
+ return false;
179
+ }
180
+
181
+ $haystack = array_reverse( $haystack, true );
182
+
183
+ foreach ( $haystack as $key => $value ) {
184
+ if ( ! is_string( $value ) ) {
185
+ return false;
186
+ }
187
+
188
+ if ( false !== strpos( $value, $needle ) ) {
189
+ return $key;
190
+ }
191
+ }
192
+
193
+ return false;
194
+ }
195
+
196
+ /**
197
+ * Detaches a specified item from an array and returns that item.
198
+ *
199
+ * @param array $array The array from which you want to detach an item (by reference).
200
+ * @param mixed $key The key to detach and return.
201
+ *
202
+ * @return mixed|false Returns the key that was detached, or false if no key was found.
203
+ */
204
+ public static function detach( array &$array, $key ) {
205
+ if ( ! array_key_exists( $key, $array ) ) {
206
+ return false;
207
+ }
208
+ $value = $array[ $key ];
209
+ unset( $array[ $key ] );
210
+ return $value;
211
+ }
212
+
213
+ /**
214
+ * Detaches a specified item from an array by value and returns that item.
215
+ *
216
+ * @param array $array The array from which you want to detach an item (by reference).
217
+ * @param mixed $value The value to find, detach, and return.
218
+ *
219
+ * @return mixed|false
220
+ */
221
+ public static function detach_by_value( array &$array, $value ) {
222
+ $key = array_search( $value, $array );
223
+ if ( ! $key ) {
224
+ return false;
225
+ }
226
+ return self::detach( $array, $key );
227
+ }
228
+
229
+ /**
230
+ * Moves an item from one position in an array to another position in the array.
231
+ *
232
+ * @param $array
233
+ * @param $old_index
234
+ * @param $new_index
235
+ *
236
+ * @return mixed
237
+ */
238
+ public static function reorder( $array, $old_index, $new_index ) {
239
+ array_splice(
240
+ $array,
241
+ $new_index,
242
+ count( $array ),
243
+ array_merge(
244
+ array_splice( $array, $old_index, 1 ),
245
+ array_slice( $array, $new_index, count( $array ) )
246
+ )
247
+ );
248
+ return $array;
249
+ }
250
+
251
+ /**
252
+ * Great answer from here: http://be2.php.net/manual/en/function.array-merge-recursive.php#92195
253
+ *
254
+ * array_merge_recursive does indeed merge arrays, but it converts values with duplicate
255
+ * keys to arrays rather than overwriting the value in the first array with the duplicate
256
+ * value in the second array, as array_merge does. I.e., with array_merge_recursive,
257
+ * this happens (documented behavior):
258
+ *
259
+ * array_merge_recursive(array('key' => 'org value'), array('key' => 'new value'));
260
+ * => array('key' => array('org value', 'new value'));
261
+ *
262
+ * array_merge_recursive_distinct does not change the datatypes of the values in the arrays.
263
+ * Matching keys' values in the second array overwrite those in the first array, as is the
264
+ * case with array_merge, i.e.:
265
+ *
266
+ * array_merge_recursive_distinct(array('key' => 'org value'), array('key' => 'new value'));
267
+ * => array('key' => array('new value'));
268
+ *
269
+ * Parameters are passed by reference, though only for performance reasons. They're not
270
+ * altered by this function.
271
+ *
272
+ * @param array $array1
273
+ * @param array $array2
274
+ * @return array
275
+ * @author Daniel <daniel (at) danielsmedegaardbuus (dot) dk>
276
+ * @author Gabriel Sobrinho <gabriel (dot) sobrinho (at) gmail (dot) com>
277
+ */
278
+ public static function array_merge_recursive_distinct( array &$array1, array &$array2 ) {
279
+ $merged = $array1;
280
+
281
+ foreach ( $array2 as $key => &$value ) {
282
+ if ( is_array( $value ) && isset( $merged [ $key ] ) && is_array( $merged [ $key ] ) ) {
283
+ $merged [ $key ] = self::array_merge_recursive_distinct( $merged [ $key ], $value );
284
+ } else {
285
+ $merged [ $key ] = $value;
286
+ }
287
+ }
288
+
289
+ return $merged;
290
+ }
291
+
292
+ /**
293
+ * Orders an associative array by several keys values, each with its own order.
294
+ *
295
+ * See array_multisort() for flags.
296
+ *
297
+ * Taken from here: http://docs.php.net/manual/en/function.array-multisort.php#100534
298
+ *
299
+ * @return array
300
+ */
301
+ public static function array_orderby() {
302
+ $args = func_get_args();
303
+ $data = array_shift( $args );
304
+ foreach ( $args as $n => $field ) {
305
+ if ( is_string( $field ) ) {
306
+ $tmp = array();
307
+ foreach ( $data as $key => $row ) {
308
+ $tmp[ $key ] = $row[ $field ];
309
+ }
310
+ $args[ $n ] = $tmp;
311
+ }
312
+ }
313
+ $args[] = &$data;
314
+ call_user_func_array( 'array_multisort', $args );
315
+
316
+ return array_pop( $args );
317
+ }
318
+ }
319
+
320
+ endif;
includes/class-customify-style-manager.php CHANGED
@@ -34,6 +34,14 @@ class Customify_Style_Manager {
34
  */
35
  public $design_assets = null;
36
 
 
 
 
 
 
 
 
 
37
  /**
38
  * Constructor.
39
  *
@@ -71,18 +79,41 @@ class Customify_Style_Manager {
71
  * @since 1.7.0
72
  */
73
  public function add_hooks() {
74
- // Handle the Customizer Style Manager config.
75
- add_filter( 'customify_filter_fields', array( $this, 'style_manager_section_config' ), 12, 1 );
76
- add_filter( 'customify_filter_fields', array( $this, 'add_current_color_palette_control' ), 20, 1 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
- // Handle the logic on settings update/save.
 
 
79
  add_action( 'customize_save_after', array( $this, 'update_custom_palette_in_use' ), 10, 1 );
80
 
81
- // Handle the logic for user feedback.
 
 
82
  add_action( 'customize_controls_print_footer_scripts', array( $this, 'output_user_feedback_modal' ) );
83
  add_action( 'wp_ajax_customify_style_manager_user_feedback', array( $this, 'user_feedback_callback' ) );
84
 
85
- // Scripts enqueued in the Customizer
 
 
86
  add_action( 'customize_controls_init', array( $this, 'register_admin_customizer_scripts' ), 10 );
87
  add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_admin_customizer_scripts' ), 10 );
88
  }
@@ -122,14 +153,17 @@ class Customify_Style_Manager {
122
  }
123
 
124
  /**
125
- * Setup the Style Manager Customizer section config.
 
 
 
126
  *
127
  * @since 1.7.0
128
  *
129
  * @param array $config This holds required keys for the plugin config like 'opt-name', 'panels', 'settings'
130
  * @return array
131
  */
132
- public function style_manager_section_config( $config ) {
133
  // If there is no style manager support, bail early.
134
  if ( ! $this->is_supported() ) {
135
  return $config;
@@ -143,6 +177,7 @@ class Customify_Style_Manager {
143
  $config['sections']['style_manager_section'] = array_replace_recursive( $config['sections']['style_manager_section'], array(
144
  'title' => esc_html__( 'Style Manager', 'customify' ),
145
  'section_id' => 'style_manager_section', // We will force this section id preventing prefixing and other regular processing.
 
146
  'options' => array(
147
  'sm_color_palette' => array(
148
  'type' => 'preset',
@@ -382,8 +417,207 @@ class Customify_Style_Manager {
382
  return $config;
383
  }
384
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
385
  /**
386
  * Get the color palettes configuration.
 
387
  * @since 1.7.0
388
  *
389
  * @param bool $skip_cache Optional. Whether to use the cached config or fetch a new one.
@@ -401,6 +635,26 @@ class Customify_Style_Manager {
401
  return apply_filters( 'customify_get_color_palettes', $color_palettes_config );
402
  }
403
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
404
  /**
405
  * Get the design assets configuration.
406
  *
@@ -648,6 +902,68 @@ class Customify_Style_Manager {
648
  return apply_filters( 'customify_style_manager_default_color_palettes', $default_color_palettes );
649
  }
650
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
651
  /**
652
  * Get the active theme data.
653
  *
34
  */
35
  public $design_assets = null;
36
 
37
+ /**
38
+ * The external theme config.
39
+ * @var array
40
+ * @access public
41
+ * @since 1.7.5
42
+ */
43
+ public $external_theme_config = null;
44
+
45
  /**
46
  * Constructor.
47
  *
79
  * @since 1.7.0
80
  */
81
  public function add_hooks() {
82
+ /*
83
+ * Handle the Customizer Style Manager base config.
84
+ */
85
+ add_filter( 'customify_filter_fields', array( $this, 'style_manager_section_base_config' ), 12, 1 );
86
+ // This needs to come after the external theme config has been applied
87
+ add_filter( 'customify_filter_fields', array( $this, 'add_current_color_palette_control' ), 110, 1 );
88
+
89
+ /*
90
+ * Handle the external theme configuration logic. We use a late priority to be able to overwrite if we have to.
91
+ */
92
+ add_filter( 'customify_filter_fields', array( $this, 'maybe_activate_external_theme_config' ), 10, 1 );
93
+ add_filter( 'customify_filter_fields', array( $this, 'maybe_apply_external_theme_config' ), 100, 1 );
94
+ // Maybe the theme has instructed us to do things like removing sections or controls.
95
+ add_action( 'customize_register', array( $this, 'maybe_process_external_theme_config_extras' ), 11 );
96
+
97
+ // Determine if we should use the config in the theme root and skip the external config.
98
+ if ( defined('CUSTOMIFY_SM_LOAD_THEME_ROOT_CONFIG') && true === CUSTOMIFY_SM_LOAD_THEME_ROOT_CONFIG ) {
99
+ add_filter( 'customify_style_manager_maybe_fetch_design_assets', array( $this, 'maybe_load_external_config_from_theme_root' ), 10, 1 );
100
+ add_filter( 'customize_controls_print_styles', array( $this, 'maybe_output_json_external_config_from_theme_root' ), 0 );
101
+ }
102
 
103
+ /*
104
+ * Handle the logic on settings update/save.
105
+ */
106
  add_action( 'customize_save_after', array( $this, 'update_custom_palette_in_use' ), 10, 1 );
107
 
108
+ /*
109
+ * Handle the logic for user feedback.
110
+ */
111
  add_action( 'customize_controls_print_footer_scripts', array( $this, 'output_user_feedback_modal' ) );
112
  add_action( 'wp_ajax_customify_style_manager_user_feedback', array( $this, 'user_feedback_callback' ) );
113
 
114
+ /*
115
+ * Scripts enqueued in the Customizer.
116
+ */
117
  add_action( 'customize_controls_init', array( $this, 'register_admin_customizer_scripts' ), 10 );
118
  add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_admin_customizer_scripts' ), 10 );
119
  }
153
  }
154
 
155
  /**
156
+ * Setup the Style Manager Customizer section base config.
157
+ *
158
+ * This handles the base configuration for the controls in the Style Manager section. We expect other parties (e.g. the theme),
159
+ * to come and fill up the missing details (e.g. connected fields).
160
  *
161
  * @since 1.7.0
162
  *
163
  * @param array $config This holds required keys for the plugin config like 'opt-name', 'panels', 'settings'
164
  * @return array
165
  */
166
+ public function style_manager_section_base_config( $config ) {
167
  // If there is no style manager support, bail early.
168
  if ( ! $this->is_supported() ) {
169
  return $config;
177
  $config['sections']['style_manager_section'] = array_replace_recursive( $config['sections']['style_manager_section'], array(
178
  'title' => esc_html__( 'Style Manager', 'customify' ),
179
  'section_id' => 'style_manager_section', // We will force this section id preventing prefixing and other regular processing.
180
+ 'priority' => 1,
181
  'options' => array(
182
  'sm_color_palette' => array(
183
  'type' => 'preset',
417
  return $config;
418
  }
419
 
420
+ /**
421
+ * Maybe activate an external theme config.
422
+ *
423
+ * If the conditions are met, activate an external theme config by declaring support for the style manager and saving the config.
424
+ *
425
+ * @since 1.7.5
426
+ *
427
+ * @param array $config This holds required keys for the plugin config like 'opt-name', 'panels', 'settings'
428
+ * @return array
429
+ */
430
+ public function maybe_activate_external_theme_config( $config ) {
431
+ // If somebody else already declared support for the Style Manager, we stop and let them have it.
432
+ if ( $this->is_supported() ) {
433
+ return $config;
434
+ }
435
+
436
+ $external_theme_config = false;
437
+
438
+ // First gather details about the current (parent) theme.
439
+ $theme = wp_get_theme( get_template() );
440
+ // Bail if for some strange reason we couldn't find the theme.
441
+ if ( ! $theme->exists() ) {
442
+ return $config;
443
+ }
444
+
445
+ // Now determine if we have a theme config for the current theme.
446
+ $design_assets = $this->get_design_assets();
447
+ if ( empty( $design_assets['theme_configs'] ) || ! is_array( $design_assets['theme_configs'] ) ) {
448
+ return $config;
449
+ }
450
+
451
+ $theme_configs = $design_assets['theme_configs'];
452
+
453
+ // We will go through every theme config and determine it's match score
454
+ foreach ( $theme_configs as $hashid => $theme_config ) {
455
+ // Loose matching means that the theme doesn't have to match all the conditions.
456
+ $loose_match = false;
457
+ if ( ! empty( $theme_config['loose_match'] ) ) {
458
+ $loose_match = true;
459
+ }
460
+
461
+ $matches = 0;
462
+ $total = 0;
463
+ if ( ! empty( $theme_config['name'] ) && $theme_config['name'] == $theme->get('Name') ) {
464
+ $matches++;
465
+ $total++;
466
+ }
467
+ if ( ! empty( $theme_config['slug'] ) && $theme_config['slug'] == $theme->get_stylesheet() ) {
468
+ $matches++;
469
+ $total++;
470
+ }
471
+ if ( ! empty( $theme_config['txtd'] ) && $theme_config['txtd'] == $theme->get('TextDomain') ) {
472
+ $matches++;
473
+ $total++;
474
+ }
475
+
476
+ $theme_configs[ $hashid ]['match_score'] = 0;
477
+ if ( true === $loose_match ) {
478
+ $theme_configs[ $hashid ]['match_score'] = $matches;
479
+ } elseif( $matches === $total ) {
480
+ $theme_configs[ $hashid ]['match_score'] = $matches;
481
+ }
482
+ }
483
+
484
+ // Now we will order the theme configs by match scores, descending and get the highest matching candidate, if any.
485
+ $theme_configs = Customify_Array::array_orderby( $theme_configs, 'match_score', SORT_DESC );
486
+ $external_theme_config = array_shift( $theme_configs );
487
+ // If we've ended up with a theme config with a zero match score, bail.
488
+ if ( empty( $external_theme_config['match_score'] ) || empty( $external_theme_config['config']['sections'] ) ) {
489
+ return $config;
490
+ }
491
+
492
+ // Now we have a theme config to work with. Save it for later use.
493
+ $this->external_theme_config = $external_theme_config;
494
+
495
+ // Declare support for the Style Manager if there is such a section in the config
496
+ if ( isset( $external_theme_config['config']['sections']['style_manager_section'] ) ) {
497
+ add_theme_support( 'customizer_style_manager' );
498
+ }
499
+
500
+ return $config;
501
+ }
502
+
503
+ /**
504
+ * Maybe apply an external theme config.
505
+ *
506
+ * If the conditions are met, apply an external theme config. Right now we are only handling sections and their controls.
507
+ *
508
+ * @since 1.7.5
509
+ *
510
+ * @param array $config This holds required keys for the plugin config like 'opt-name', 'panels', 'settings'
511
+ * @return array
512
+ */
513
+ public function maybe_apply_external_theme_config( $config ) {
514
+ // Bail if we have no external theme config data.
515
+ if ( empty( $this->external_theme_config ) ) {
516
+ return $config;
517
+ }
518
+
519
+ // Apply the theme config.
520
+ // If we are dealing with the Customify default config, we need a clean slate, sort of.
521
+ if ( 'customify_defaults' === $config['opt-name'] ) {
522
+ // We will save the Style Manager config so we can merge with it. But the rest goes away.
523
+ $style_manager_section = array();
524
+ if ( isset( $config['sections']['style_manager_section'] ) ) {
525
+ $style_manager_section = $config['sections']['style_manager_section'];
526
+ }
527
+
528
+ $config['opt-name'] = get_template() . '_options';
529
+ if ( ! empty( $this->external_theme_config['config']['opt-name'] ) ) {
530
+ $config['opt-name'] = $this->external_theme_config['config']['opt-name'];
531
+ }
532
+
533
+ $config['sections'] = array(
534
+ 'style_manager_section' => $style_manager_section,
535
+ );
536
+ }
537
+
538
+ // Now merge things.
539
+ $config['sections'] = Customify_Array::array_merge_recursive_distinct( $config['sections'],$this->external_theme_config['config']['sections'] );
540
+
541
+ return $config;
542
+ }
543
+
544
+ /**
545
+ * Maybe process certain "commands" from the external theme config.
546
+ *
547
+ * Mainly things like removing sections, controls, etc.
548
+ *
549
+ * @since 1.7.5
550
+ *
551
+ * @param WP_Customize_Manager $wp_customize
552
+ */
553
+ public function maybe_process_external_theme_config_extras( $wp_customize ) {
554
+ // Bail if we have no external theme config data.
555
+ if ( empty( $this->external_theme_config ) ) {
556
+ return;
557
+ }
558
+
559
+ // Maybe remove panels
560
+ if ( ! empty( $this->external_theme_config['config']['remove_panels'] ) ) {
561
+ // Standardize it.
562
+ if ( is_string( $this->external_theme_config['config']['remove_panels'] ) ) {
563
+ $this->external_theme_config['config']['remove_panels'] = array( $this->external_theme_config['config']['remove_panels'] );
564
+ }
565
+
566
+ foreach ( $this->external_theme_config['config']['remove_panels'] as $panel_id ) {
567
+ $wp_customize->remove_panel( $panel_id );
568
+ }
569
+ }
570
+
571
+ // Maybe remove sections
572
+ if ( ! empty( $this->external_theme_config['config']['remove_sections'] ) ) {
573
+ // Standardize it.
574
+ if ( is_string( $this->external_theme_config['config']['remove_sections'] ) ) {
575
+ $this->external_theme_config['config']['remove_sections'] = array( $this->external_theme_config['config']['remove_sections'] );
576
+ }
577
+
578
+ foreach ( $this->external_theme_config['config']['remove_sections'] as $section_id ) {
579
+
580
+ if ( 'widgets' === $section_id ) {
581
+ global $wp_registered_sidebars;
582
+
583
+ foreach ( $wp_registered_sidebars as $widget => $settings ) {
584
+ $wp_customize->remove_section( 'sidebar-widgets-' . $widget );
585
+ }
586
+ continue;
587
+ }
588
+
589
+ $wp_customize->remove_section( $section_id );
590
+ }
591
+ }
592
+
593
+ // Maybe remove settings
594
+ if ( ! empty( $this->external_theme_config['config']['remove_settings'] ) ) {
595
+ // Standardize it.
596
+ if ( is_string( $this->external_theme_config['config']['remove_settings'] ) ) {
597
+ $this->external_theme_config['config']['remove_settings'] = array( $this->external_theme_config['config']['remove_settings'] );
598
+ }
599
+
600
+ foreach ( $this->external_theme_config['config']['remove_settings'] as $setting_id ) {
601
+ $wp_customize->remove_setting( $setting_id );
602
+ }
603
+ }
604
+
605
+ // Maybe remove controls
606
+ if ( ! empty( $this->external_theme_config['config']['remove_controls'] ) ) {
607
+ // Standardize it.
608
+ if ( is_string( $this->external_theme_config['config']['remove_controls'] ) ) {
609
+ $this->external_theme_config['config']['remove_controls'] = array( $this->external_theme_config['config']['remove_controls'] );
610
+ }
611
+
612
+ foreach ( $this->external_theme_config['config']['remove_controls'] as $control_id ) {
613
+ $wp_customize->remove_control( $control_id );
614
+ }
615
+ }
616
+ }
617
+
618
  /**
619
  * Get the color palettes configuration.
620
+ *
621
  * @since 1.7.0
622
  *
623
  * @param bool $skip_cache Optional. Whether to use the cached config or fetch a new one.
635
  return apply_filters( 'customify_get_color_palettes', $color_palettes_config );
636
  }
637
 
638
+ /**
639
+ * Get the themes configuration.
640
+ *
641
+ * @since 1.7.5
642
+ *
643
+ * @param bool $skip_cache Optional. Whether to use the cached config or fetch a new one.
644
+ * @return array
645
+ */
646
+ protected function get_theme_configs( $skip_cache = false ) {
647
+ // Get the design assets data.
648
+ $design_assets = $this->get_design_assets( $skip_cache );
649
+ if ( false === $design_assets || empty( $design_assets['theme_configs'] ) ) {
650
+ $theme_configs = $this->get_default_color_palettes_config();
651
+ } else {
652
+ $theme_configs = $design_assets['theme_configs'];
653
+ }
654
+
655
+ return apply_filters( 'customify_get_theme_configs', $theme_configs );
656
+ }
657
+
658
  /**
659
  * Get the design assets configuration.
660
  *
902
  return apply_filters( 'customify_style_manager_default_color_palettes', $default_color_palettes );
903
  }
904
 
905
+ /**
906
+ * Include the customify "external" config file in the theme root and overwrite the existing theme configs.
907
+ *
908
+ * @param array $design_assets
909
+ *
910
+ * @return array
911
+ */
912
+ public function maybe_load_external_config_from_theme_root( $design_assets ) {
913
+ $file_name = 'customify_theme_root.php';
914
+
915
+ // First gather details about the current (parent) theme.
916
+ $theme = wp_get_theme( get_template() );
917
+ // Bail if for some strange reason we couldn't find the theme.
918
+ if ( ! $theme->exists() ) {
919
+ return $design_assets;
920
+ }
921
+
922
+ $file = trailingslashit( $theme->get_template_directory() ) . $file_name;
923
+ if ( ! file_exists( $file ) ) {
924
+ return $design_assets;
925
+ }
926
+
927
+ // We expect to get from the file include a $config variable with the entire Customify (partial) config.
928
+ include $file;
929
+
930
+ if ( ! isset( $config ) || ! is_array( $config ) || empty( $config['sections'] ) ) {
931
+ // Alert the developers that things are not alright.
932
+ _doing_it_wrong( __METHOD__, 'The Customify theme root config is not good! Please check it! We will not apply it.', null );
933
+
934
+ return $design_assets;
935
+ }
936
+
937
+ // Construct the pseudo-external theme config.
938
+ // Start with a clean slate.
939
+ $design_assets['theme_configs'] = array();
940
+
941
+ $design_assets['theme_configs']['theme_root'] = array(
942
+ 'id' => 1,
943
+ 'name' => $theme->get( 'Name' ),
944
+ 'slug' => $theme->get_stylesheet(),
945
+ 'txtd' => $theme->get( 'TextDomain' ),
946
+ 'loose_match' => true,
947
+ 'config' => $config,
948
+ 'created' => '2018-05-16 15:13:58',
949
+ 'last_modified' => '2018-05-16 15:13:58',
950
+ 'hashid' => 'theme_root',
951
+ );
952
+
953
+ return $design_assets;
954
+ }
955
+
956
+ /**
957
+ * Output the theme root JSON in the Customizer page source.
958
+ */
959
+ public function maybe_output_json_external_config_from_theme_root() {
960
+ if ( ! empty( $this->external_theme_config['config'] ) ) {
961
+ // Also output the JSON in a special hidden div for easy copy pasting.
962
+ // Also remove any multiple tabs.
963
+ echo PHP_EOL . '<!--' . PHP_EOL . 'Just copy&paste this:' . PHP_EOL . PHP_EOL . trim( str_replace( '\t\t', '', json_encode( $this->external_theme_config['config'] ) ) ) . PHP_EOL . PHP_EOL . '-->' . PHP_EOL;
964
+ }
965
+ }
966
+
967
  /**
968
  * Get the active theme data.
969
  *
includes/customify_theme_root.php ADDED
@@ -0,0 +1,808 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is the PHP file that allows you to play with the Customify config that would normally come from Pixelgrade Cloud.
4
+ *
5
+ * This is file is automatically detected by Customify and loaded when the CUSTOMIFY_SM_LOAD_THEME_ROOT_CONFIG constant is true.
6
+ *
7
+ * Keep the name of this file like you've received it from Pixelgrade Cloud.
8
+ */
9
+
10
+ // This is where the final config should reside.
11
+ // Start with some sane default. We expect to have a sections entry.
12
+ $config = [
13
+ 'sections' => [],
14
+ ];
15
+
16
+ $config['sections'] = [
17
+
18
+ /**
19
+ * COLORS - This section will handle all elements colors (eg. links, headings)
20
+ */
21
+ 'colors_section' => [
22
+ 'title' => __( 'Colors', 'customify' ),
23
+ 'priority' => 2, // This will put this section right after Style Manager that has a priority of 1.
24
+ 'options' => [
25
+ /**
26
+ * Header Section
27
+ */
28
+ 'header_section' => [
29
+ 'type' => 'html',
30
+ 'html' => '<span id="section-title-blog-fonts" class="separator section label large">' . esc_html__( 'Header', 'storefront' ) . '</span>',
31
+ ],
32
+ 'header_navigation_text_color' => [
33
+ 'type' => 'color',
34
+ 'label' => __( 'Header Text Color', 'customify' ),
35
+ 'live' => true,
36
+ 'default' => '#404040',
37
+ 'css' => [
38
+ [
39
+ 'property' => 'color',
40
+ 'selector' => 'p.site-description,
41
+ .site-header,
42
+ .storefront-handheld-footer-bar',
43
+ ],
44
+ [
45
+ 'media' => 'screen and ( min-width: 768px )',
46
+ 'property' => 'color',
47
+ 'selector' => '.secondary-navigation ul.menu a:hover',
48
+ 'filter_value_cb' => [
49
+ 'callback' => 'pixcloud_adjust_color_brightness',
50
+ 'args' => [
51
+ - 25,
52
+ ],
53
+ ],
54
+ ],
55
+ [
56
+ 'media' => 'screen and ( min-width: 768px )',
57
+ 'property' => 'color',
58
+ 'selector' => '.secondary-navigation ul.menu a,
59
+ .site-header-cart .widget_shopping_cart,
60
+ .site-header .product_list_widget li .quantity',
61
+ ],
62
+ ],
63
+ ],
64
+ 'header_navigation_links_color' => [
65
+ 'type' => 'color',
66
+ 'label' => __( 'Navigation Links Color', 'customify' ),
67
+ 'live' => true,
68
+ 'default' => '#333333',
69
+ 'css' => [
70
+ [
71
+ 'property' => 'color',
72
+ 'selector' => '.main-navigation ul li a,
73
+ .site-title a,
74
+ ul.menu li a,
75
+ .site-branding h1 a,
76
+ .site-footer .storefront-handheld-footer-bar a:not(.button],
77
+ button.menu-toggle,
78
+ button.menu-toggle:hover,
79
+
80
+ .storefront-sticky-add-to-cart a:not(.button],
81
+ a.cart-contents,
82
+ .site-header-cart .widget_shopping_cart a',
83
+ ],
84
+ [
85
+ 'property' => 'border-color',
86
+ 'selector' => 'button.menu-toggle,
87
+ button.menu-toggle:hover',
88
+ ],
89
+ [
90
+ 'property' => 'background-color',
91
+ 'selector' => '.storefront-handheld-footer-bar ul li.cart .count,
92
+ button.menu-toggle:after,
93
+ button.menu-toggle:before,
94
+ button.menu-toggle span:before',
95
+ ],
96
+ ],
97
+ ],
98
+ 'header_navigation_links_active_color' => [
99
+ 'type' => 'color',
100
+ 'label' => __( 'Links Active Color', 'customify' ),
101
+ 'live' => true,
102
+ 'default' => '#282828',
103
+ 'css' => [
104
+ [
105
+ 'property' => 'color',
106
+ 'selector' => '.main-navigation ul li a:hover,
107
+ .main-navigation ul li:hover > a,
108
+ .site-title a:hover,
109
+ a.cart-contents:hover,
110
+ .site-header-cart .widget_shopping_cart a:hover,
111
+ .site-header-cart:hover > li > a,
112
+ .site-header ul.menu li.current-menu-item > a',
113
+ ],
114
+ ],
115
+ ],
116
+ 'header_background_color' => [
117
+ 'type' => 'color',
118
+ 'label' => __( 'Header Background', 'customify' ),
119
+ 'live' => true,
120
+ 'default' => '#ffffff',
121
+ 'css' => [
122
+ [
123
+ 'property' => 'background-color',
124
+ 'selector' => '.site-header,
125
+ .secondary-navigation ul ul,
126
+ .main-navigation ul.menu > li.menu-item-has-children:after,
127
+ .secondary-navigation ul.menu ul,
128
+ .storefront-handheld-footer-bar,
129
+ .storefront-handheld-footer-bar ul li > a,
130
+ .storefront-handheld-footer-bar ul li.search .site-search,
131
+ button.menu-toggle,
132
+ button.menu-toggle:hover',
133
+ ],
134
+ [
135
+ 'property' => 'color',
136
+ 'selector' => '.storefront-handheld-footer-bar ul li.cart .count',
137
+ ],
138
+ [
139
+ 'property' => 'border-color',
140
+ 'selector' => '.storefront-handheld-footer-bar ul li.cart .count',
141
+ ],
142
+ [
143
+ 'media' => 'screen and ( min-width: 768px )',
144
+ 'property' => 'background-color',
145
+ 'selector' => '.site-header-cart .widget_shopping_cart,
146
+ .main-navigation ul.menu ul.sub-menu,
147
+ .main-navigation ul.nav-menu ul.children',
148
+ 'filter_value_cb' => [
149
+ 'callback' => 'pixcloud_adjust_color_brightness',
150
+ 'args' => [
151
+ - 15,
152
+ ],
153
+ ],
154
+ ],
155
+ [
156
+ 'media' => 'screen and ( min-width: 768px )',
157
+ 'property' => 'background-color',
158
+ 'selector' => '.site-header-cart .widget_shopping_cart .buttons,
159
+ .site-header-cart .widget_shopping_cart .total',
160
+ 'filter_value_cb' => [
161
+ 'callback' => 'pixcloud_adjust_color_brightness',
162
+ 'args' => [
163
+ - 10,
164
+ ],
165
+ ],
166
+ ],
167
+ [
168
+ 'media' => 'screen and ( min-width: 768px )',
169
+ 'property' => 'border-bottom-color',
170
+ 'selector' => '.site-header',
171
+ 'filter_value_cb' => [
172
+ 'callback' => 'pixcloud_adjust_color_brightness',
173
+ 'args' => [
174
+ - 15,
175
+ ],
176
+ ],
177
+ ],
178
+ ],
179
+ ],
180
+
181
+
182
+ /**
183
+ * Main Content
184
+ */
185
+ 'main_content_section' => [
186
+ 'type' => 'html',
187
+ 'html' => '<span id="section-title-blog-fonts" class="separator section label large">' . esc_html__( 'Main Content', 'storefront' ) . '</span>',
188
+ ],
189
+ 'page_title_color' => [
190
+ 'type' => 'color',
191
+ 'label' => __( 'Page Title Color', 'customify' ),
192
+ 'live' => true,
193
+ 'default' => '#282828',
194
+ 'css' => [
195
+ [
196
+ 'property' => 'color',
197
+ 'selector' => '.entry-title,
198
+ .page-template-template-homepage.has-post-thumbnail .type-page.has-post-thumbnail .entry-title',
199
+ ],
200
+ ],
201
+ ],
202
+ 'body_text_color' => [
203
+ 'type' => 'color',
204
+ 'label' => __( 'Body Text Color', 'customify' ),
205
+ 'live' => true,
206
+ 'default' => '#6d6d6d',
207
+ 'css' => [
208
+ [
209
+ 'property' => 'color',
210
+ 'selector' => 'button,input,textarea,
211
+ .input-text,input[type=email],input[type=password],input[type=search],input[type=text],input[type=url],textarea,
212
+ .pagination .page-numbers li .page-numbers,.woocommerce-pagination .page-numbers li .page-numbers,
213
+ ul.menu li.current-menu-item>a,
214
+
215
+ body,
216
+ .secondary-navigation a,
217
+ .onsale,
218
+ .pagination .page-numbers li .page-numbers:not(.current], .woocommerce-pagination .page-numbers li .page-numbers:not(.current)
219
+
220
+ .page-template-template-homepage.has-post-thumbnail .type-page.has-post-thumbnail .entry-content,
221
+
222
+ p.stars a:before,
223
+ p.stars a:hover~a:before,
224
+ p.stars.selected a.active~a:before,
225
+
226
+ .storefront-product-pagination a,
227
+ .storefront-sticky-add-to-cart,
228
+
229
+ .woocommerce-tabs ul.tabs li.active a,
230
+ ul.products li.product .price,
231
+ .onsale,
232
+ .widget_search form:before,
233
+ .widget_product_search form:before,
234
+
235
+ mark',
236
+ ],
237
+ [
238
+ 'property' => 'color',
239
+ 'selector' => '.widget-area .widget a,
240
+ .hentry .entry-header .posted-on a,
241
+ .hentry .entry-header .byline a,
242
+
243
+ .woocommerce-breadcrumb a,
244
+ a.woocommerce-review-link,
245
+ .product_meta a',
246
+ 'filter_value_cb' => [
247
+ 'callback' => 'pixcloud_adjust_color_brightness',
248
+ 'args' => [
249
+ 5,
250
+ ],
251
+ ],
252
+ ],
253
+ [
254
+ 'property' => 'color',
255
+ 'selector' => '.pagination .page-numbers li .page-numbers.current, .woocommerce-pagination .page-numbers li .page-numbers.current',
256
+ 'filter_value_cb' => [
257
+ 'callback' => 'pixcloud_adjust_color_brightness',
258
+ 'args' => [
259
+ 10,
260
+ ],
261
+ ],
262
+ ],
263
+ [
264
+ 'property' => 'border-color',
265
+ 'selector' => '.onsale',
266
+ ],
267
+ ],
268
+ ],
269
+ 'body_link_color' => [
270
+ 'type' => 'color',
271
+ 'label' => __( 'Body Link Color', 'customify' ),
272
+ 'live' => true,
273
+ 'default' => '#96588A',
274
+ 'css' => [
275
+ [
276
+ 'property' => 'color',
277
+ 'selector' => 'a,
278
+ .star-rating span:before,
279
+ .quantity .plus, .quantity .minus,
280
+ p.stars a:hover:after,
281
+ p.stars a:after,
282
+ .star-rating span:before,
283
+ #payment .payment_methods li input[type=radio]:first-child:checked+label:before,
284
+
285
+ p.stars.selected a.active:before,
286
+ p.stars:hover a:before,
287
+ p.stars.selected a:not(.active):before,
288
+ p.stars.selected a.active:before',
289
+ ],
290
+ [
291
+ 'property' => 'outline-color',
292
+ 'selector' => 'a:focus,
293
+ .button:focus,
294
+ .button.alt:focus,
295
+ .button.added_to_cart:focus,
296
+ .button.wc-forward:focus,
297
+ button:focus,
298
+ input[type="button"]:focus,
299
+ input[type="reset"]:focus,
300
+ input[type="submit"]:focus',
301
+ ],
302
+ [
303
+ 'property' => 'background-color',
304
+ 'selector' => '.widget_price_filter .ui-slider .ui-slider-range,
305
+ .widget_price_filter .ui-slider .ui-slider-handle',
306
+ ],
307
+ ],
308
+ ],
309
+ 'body_link_active_color' => [
310
+ 'type' => 'color',
311
+ 'label' => __( 'Body Link Active Color', 'customify' ),
312
+ 'live' => true,
313
+ 'default' => '#282828',
314
+ 'css' => [
315
+ [
316
+ 'property' => 'color',
317
+ 'selector' => 'a:hover',
318
+ ],
319
+ ],
320
+ ],
321
+
322
+ // [Sub Section] Headings Colors
323
+ 'main_content_title_headings_color_section' => [
324
+ 'type' => 'html',
325
+ 'html' => '<span class="separator sub-section label">' . esc_html__( 'Headings Color', 'patch' ) . '</span>',
326
+ ],
327
+ 'main_content_heading_1_color' => [
328
+ 'type' => 'color',
329
+ 'label' => esc_html__( 'Heading 1', 'patch' ),
330
+ 'live' => true,
331
+ 'default' => '#131315',
332
+ 'css' => [
333
+ [
334
+ 'property' => 'color',
335
+ 'selector' => 'h1, .site-title a',
336
+ ],
337
+ ],
338
+ ],
339
+ 'main_content_heading_2_color' => [
340
+ 'type' => 'color',
341
+ 'label' => esc_html__( 'Heading 2', 'patch' ),
342
+ 'live' => true,
343
+ 'default' => '#131315',
344
+ 'css' => [
345
+ [
346
+ 'property' => 'color',
347
+ 'selector' => 'h2, blockquote',
348
+ ],
349
+ ],
350
+ ],
351
+ 'main_content_heading_3_color' => [
352
+ 'type' => 'color',
353
+ 'label' => esc_html__( 'Heading 3', 'patch' ),
354
+ 'live' => true,
355
+ 'default' => '#131315',
356
+ 'css' => [
357
+ [
358
+ 'property' => 'color',
359
+ 'selector' => 'h3',
360
+ ],
361
+ ],
362
+ ],
363
+ 'main_content_heading_4_color' => [
364
+ 'type' => 'color',
365
+ 'label' => esc_html__( 'Heading 4', 'patch' ),
366
+ 'live' => true,
367
+ 'default' => '#131315',
368
+ 'css' => [
369
+ [
370
+ 'property' => 'color',
371
+ 'selector' => 'h4',
372
+ ],
373
+ ],
374
+ ],
375
+ 'main_content_heading_5_color' => [
376
+ 'type' => 'color',
377
+ 'label' => esc_html__( 'Heading 5', 'patch' ),
378
+ 'live' => true,
379
+ 'default' => '#131315',
380
+ 'css' => [
381
+ [
382
+ 'property' => 'color',
383
+ 'selector' => 'h5',
384
+ ],
385
+ ],
386
+ ],
387
+ 'main_content_heading_6_color' => [
388
+ 'type' => 'color',
389
+ 'label' => esc_html__( 'Heading 6', 'patch' ),
390
+ 'live' => true,
391
+ 'default' => '#131315',
392
+ 'css' => [
393
+ [
394
+ 'property' => 'color',
395
+ 'selector' => 'h6',
396
+ ],
397
+ ],
398
+ ],
399
+
400
+ // [Sub Section] Backgrounds
401
+ 'main_content_title_backgrounds_color_section' => [
402
+ 'type' => 'html',
403
+ 'html' => '<span class="separator sub-section label">' . esc_html__( 'Backgrounds', 'patch' ) . '</span>',
404
+ ],
405
+
406
+ 'main_content_content_background_color' => [
407
+ 'type' => 'color',
408
+ 'label' => esc_html__( 'Content Background Color', 'patch' ),
409
+ 'live' => true,
410
+ 'default' => '#ffffff',
411
+ 'css' => [
412
+ [
413
+ 'property' => 'background-color',
414
+ 'selector' => 'body,
415
+ #order_review,
416
+ .storefront-product-pagination a,
417
+ .storefront-sticky-add-to-cart',
418
+ ],
419
+ [
420
+ 'property' => 'background-color',
421
+ 'selector' => 'table th,
422
+ #comments .comment-list .comment-content .comment-text,
423
+ .order_details',
424
+ 'filter_value_cb' => [
425
+ 'callback' => 'pixcloud_adjust_color_brightness',
426
+ 'args' => [
427
+ - 7,
428
+ ],
429
+ ],
430
+ ],
431
+ [
432
+ 'property' => 'background-color',
433
+ 'selector' => 'table tbody td ',
434
+ 'filter_value_cb' => [
435
+ 'callback' => 'pixcloud_adjust_color_brightness',
436
+ 'args' => [
437
+ - 2,
438
+ ],
439
+ ],
440
+ ],
441
+ [
442
+ 'property' => 'background-color',
443
+ 'selector' => 'table tbody tr:nth-child(2n) td,
444
+ fieldset,
445
+ fieldset legend',
446
+ 'filter_value_cb' => [
447
+ 'callback' => 'pixcloud_adjust_color_brightness',
448
+ 'args' => [
449
+ - 4,
450
+ ],
451
+ ],
452
+ ],
453
+ [
454
+ 'property' => 'background-color',
455
+ 'selector' => '#payment .payment_methods > li .payment_box,
456
+ #payment .place-order,
457
+
458
+ .input-text, input[type=email], input[type=password], input[type=search], input[type=text], input[type=url], textarea',
459
+ 'filter_value_cb' => [
460
+ 'callback' => 'pixcloud_adjust_color_brightness',
461
+ 'args' => [
462
+ - 5,
463
+ ],
464
+ ],
465
+ ],
466
+ [
467
+ 'property' => 'background-color',
468
+ 'selector' => '#payment .payment_methods > li:not(.woocommerce-notice)',
469
+ 'filter_value_cb' => [
470
+ 'callback' => 'pixcloud_adjust_color_brightness',
471
+ 'args' => [
472
+ - 10,
473
+ ],
474
+ ],
475
+ ],
476
+ [
477
+ 'property' => 'background-color',
478
+ 'selector' => '#payment .payment_methods > li:not(.woocommerce-notice):hover',
479
+ 'filter_value_cb' => [
480
+ 'callback' => 'pixcloud_adjust_color_brightness',
481
+ 'args' => [
482
+ - 15,
483
+ ],
484
+ ],
485
+ ],
486
+ [
487
+ 'property' => 'background-color',
488
+ 'selector' => '.pagination .page-numbers li .page-numbers.current, .woocommerce-pagination .page-numbers li .page-numbers.current',
489
+ 'filter_value_cb' => [
490
+ 'callback' => 'pixcloud_adjust_color_brightness',
491
+ 'args' => [
492
+ - 25,
493
+ ],
494
+ ],
495
+ ],
496
+ [
497
+ 'property' => 'border-bottom-color',
498
+ 'selector' => '.order_details > li',
499
+ 'filter_value_cb' => [
500
+ 'callback' => 'pixcloud_adjust_color_brightness',
501
+ 'args' => [
502
+ - 28,
503
+ ],
504
+ ],
505
+ ],
506
+ [
507
+ 'property' => 'border-top-color',
508
+ 'selector' => 'table.cart td.product-remove,
509
+ table.cart td.actions',
510
+ ],
511
+ [
512
+ 'property' => 'background',
513
+ 'selector' => '.order_details:before,
514
+ .order_details:after',
515
+ // 'callback_filter' => 'gradient()'
516
+ ],
517
+ [
518
+ 'property' => 'color',
519
+ 'selector' => '.woocommerce-info, .woocommerce-message, .woocommerce-noreviews, p.no-comments,
520
+
521
+ .woocommerce-info a ,.woocommerce-message a, .woocommerce-noreviews a, p.no-comments a,
522
+ .woocommerce-info a:hover, .woocommerce-message a:hover, .woocommerce-noreviews a:hover, p.no-comments a:hover',
523
+ ],
524
+ ],
525
+ ],
526
+
527
+
528
+ /**
529
+ * Buttons
530
+ */
531
+ 'buttons_section' => [
532
+ 'type' => 'html',
533
+ 'html' => '<span id="section-title-blog-fonts" class="separator section label large">' . esc_html__( 'Buttons', 'storefront' ) . '</span>',
534
+ ],
535
+ 'buttons_text_color' => [
536
+ 'type' => 'color',
537
+ 'label' => __( 'Text Color', 'customify' ),
538
+ 'live' => true,
539
+ 'default' => '#333333',
540
+ 'css' => [
541
+ [
542
+ 'property' => 'color',
543
+ 'selector' => 'button, input[type="button"], input[type="reset"], input[type="submit"], .button, .added_to_cart, .widget a.button, .site-header-cart .widget_shopping_cart a.button,
544
+
545
+ button:hover, input[type="button"]:hover, input[type="reset"]:hover, input[type="submit"]:hover, .button:hover, .added_to_cart:hover, .widget a.button:hover, .site-header-cart .widget_shopping_cart a.button:hover,
546
+
547
+ .single-product div.product .woocommerce-product-gallery .woocommerce-product-gallery__trigger,
548
+
549
+ .single-product div.product .woocommerce-product-gallery .woocommerce-product-gallery__trigger:hover,
550
+
551
+ .button.loading:after ',
552
+ ],
553
+ ],
554
+ ],
555
+ 'buttons_background_color' => [
556
+ 'type' => 'color',
557
+ 'label' => __( 'Background Color', 'customify' ),
558
+ 'live' => true,
559
+ 'default' => '#eeeeee',
560
+ 'css' => [
561
+ [
562
+ 'property' => 'background-color',
563
+ 'selector' => 'button, input[type="button"], input[type="reset"], input[type="submit"], .button, .added_to_cart, .widget a.button, .site-header-cart .widget_shopping_cart a.button,
564
+
565
+ .single-product div.product .woocommerce-product-gallery .woocommerce-product-gallery__trigger',
566
+ ],
567
+ [
568
+ 'property' => 'border-color',
569
+ 'selector' => 'button, input[type="button"], input[type="reset"], input[type="submit"], .button, .added_to_cart, .widget a.button, .site-header-cart .widget_shopping_cart a.button',
570
+ ],
571
+ // Hover
572
+ [
573
+ 'property' => 'background-color',
574
+ 'selector' => 'button:hover, input[type="button"]:hover, input[type="reset"]:hover, input[type="submit"]:hover, .button:hover, .added_to_cart:hover, .widget a.button:hover, .site-header-cart .widget_shopping_cart a.button:hover,
575
+
576
+ .single-product div.product .woocommerce-product-gallery .woocommerce-product-gallery__trigger:hover',
577
+ 'filter_value_cb' => [
578
+ 'callback' => 'pixcloud_adjust_color_brightness',
579
+ 'args' => [
580
+ - 25,
581
+ ],
582
+ ],
583
+ ],
584
+ [
585
+ 'property' => 'border-color',
586
+ 'selector' => 'button:hover, input[type="button"]:hover, input[type="reset"]:hover, input[type="submit"]:hover, .button:hover, .added_to_cart:hover, .widget a.button:hover, .site-header-cart .widget_shopping_cart a.button:hover,
587
+
588
+ .single-product div.product .woocommerce-product-gallery .woocommerce-product-gallery__trigger:hover',
589
+ 'filter_value_cb' => [
590
+ 'callback' => 'pixcloud_adjust_color_brightness',
591
+ 'args' => [
592
+ - 25,
593
+ ],
594
+ ],
595
+ ],
596
+ ],
597
+ ],
598
+ 'buttons_alt_text_color' => [
599
+ 'type' => 'color',
600
+ 'label' => __( 'Alternate Text Color', 'customify' ),
601
+ 'live' => true,
602
+ 'default' => '#ffffff',
603
+ 'css' => [
604
+ [
605
+ 'property' => 'color',
606
+ 'selector' => 'button.alt, input[type="button"].alt, input[type="reset"].alt, input[type="submit"].alt, .button.alt, .added_to_cart.alt, .widget-area .widget a.button.alt, .added_to_cart, .widget a.button.checkout',
607
+ ],
608
+ ],
609
+ ],
610
+ 'buttons_alt_background_color' => [
611
+ 'type' => 'color',
612
+ 'label' => __( 'Alternate Background Color', 'customify' ),
613
+ 'live' => true,
614
+ 'default' => '#333333',
615
+ 'css' => [
616
+ [
617
+ 'property' => 'background-color',
618
+ 'selector' => 'button.alt, input[type="button"].alt, input[type="reset"].alt, input[type="submit"].alt, .button.alt, .added_to_cart.alt, .widget-area .widget a.button.alt, .added_to_cart, .widget a.button.checkout',
619
+ ],
620
+ [
621
+ 'property' => 'border-color',
622
+ 'selector' => 'button.alt, input[type="button"].alt, input[type="reset"].alt, input[type="submit"].alt, .button.alt, .added_to_cart.alt, .widget-area .widget a.button.alt, .added_to_cart, .widget a.button.checkout',
623
+ ],
624
+ // Hover
625
+ [
626
+ 'property' => 'background-color',
627
+ 'selector' => 'button.alt:hover, input[type="button"].alt:hover, input[type="reset"].alt:hover, input[type="submit"].alt:hover, .button.alt:hover, .added_to_cart.alt:hover, .widget-area .widget a.button.alt:hover, .added_to_cart:hover, .widget a.button.checkout:hover',
628
+ 'filter_value_cb' => [
629
+ 'callback' => 'pixcloud_adjust_color_brightness',
630
+ 'args' => [
631
+ - 25,
632
+ ],
633
+ ],
634
+ ],
635
+ [
636
+ 'property' => 'border-color',
637
+ 'selector' => 'button.alt:hover, input[type="button"].alt:hover, input[type="reset"].alt:hover, input[type="submit"].alt:hover, .button.alt:hover, .added_to_cart.alt:hover, .widget-area .widget a.button.alt:hover, .added_to_cart:hover, .widget a.button.checkout:hover',
638
+ 'filter_value_cb' => [
639
+ 'callback' => 'pixcloud_adjust_color_brightness',
640
+ 'args' => [
641
+ - 25,
642
+ ],
643
+ ],
644
+ ],
645
+ ],
646
+ ],
647
+
648
+
649
+ /**
650
+ * Footer
651
+ */
652
+ 'footer_section' => [
653
+ 'type' => 'html',
654
+ 'html' => '<span id="section-title-blog-fonts" class="separator section label large">' . esc_html__( 'Footer', 'storefront' ) . '</span>',
655
+ ],
656
+ 'footer_text_color' => [
657
+ 'type' => 'color',
658
+ 'label' => __( 'Footer Text Color', 'customify' ),
659
+ 'live' => true,
660
+ 'default' => '#6d6d6d',
661
+ 'css' => [
662
+ [
663
+ 'property' => 'color',
664
+ 'selector' => '.site-footer',
665
+ ],
666
+ ],
667
+ ],
668
+ 'footer_links_color' => [
669
+ 'type' => 'color',
670
+ 'label' => __( 'Footer Links Color', 'customify' ),
671
+ 'live' => true,
672
+ 'default' => '#333333',
673
+ 'css' => [
674
+ [
675
+ 'property' => 'color',
676
+ 'selector' => '.site-footer a:not(.button)',
677
+ ],
678
+ ],
679
+ ],
680
+ 'footer_heading_color' => [
681
+ 'type' => 'color',
682
+ 'label' => __( 'Footer Headings Color', 'customify' ),
683
+ 'live' => true,
684
+ 'default' => '#333333',
685
+ 'css' => [
686
+ [
687
+ 'property' => 'color',
688
+ 'selector' => '.site-footer h1, .site-footer h2, .site-footer h3, .site-footer h4, .site-footer h5, .site-footer h6',
689
+ ],
690
+ ],
691
+ ],
692
+ 'footer_background_color' => [
693
+ 'type' => 'color',
694
+ 'label' => __( 'Footer Background', 'customify' ),
695
+ 'live' => true,
696
+ 'default' => '#f0f0f0',
697
+ 'css' => [
698
+ [
699
+ 'property' => 'background-color',
700
+ 'selector' => '.site-footer',
701
+ ],
702
+ ],
703
+ ],
704
+
705
+ /**
706
+ * Miscellaneous
707
+ */
708
+ 'misc_section' => [
709
+ 'type' => 'html',
710
+ 'html' => '<span id="section-title-blog-fonts" class="separator section label large">' . esc_html__( 'Miscellaneous', 'storefront' ) . '</span>',
711
+ ],
712
+
713
+ 'woocommerce_info_background_color' => [
714
+ 'type' => 'background-color',
715
+ 'label' => __( 'WooCommerce Info', 'customify' ),
716
+ 'live' => true,
717
+ 'default' => '#3d9cd2',
718
+ 'css' => [
719
+ [
720
+ 'property' => 'background-color',
721
+ 'selector' => '.woocommerce-info, .woocommerce-message, .woocommerce-noreviews, p.no-comments',
722
+ ],
723
+ ],
724
+ ],
725
+ ],
726
+ ],
727
+ ];
728
+
729
+ /**
730
+ * Add the Style Manager cross-theme Customizer section.
731
+ */
732
+ $config['sections']['style_manager_section'] = [
733
+ 'options' => [
734
+ 'sm_color_primary' => [
735
+ 'connected_fields' => [
736
+ 'body_link_color',
737
+ 'main_content_heading_4_color',
738
+ 'main_content_heading_5_color',
739
+ 'header_navigation_links_active_color',
740
+ 'woocommerce_info_background_color',
741
+ ],
742
+ ],
743
+ 'sm_color_secondary' => [
744
+ 'connected_fields' => [
745
+ 'main_content_heading_6_color',
746
+ 'buttons_alt_background_color',
747
+ ],
748
+ ],
749
+
750
+ 'sm_dark_primary' => [
751
+ 'connected_fields' => [
752
+ 'body_link_active_color',
753
+ 'page_title_color',
754
+ 'main_content_page_title_color',
755
+ 'main_content_heading_1_color',
756
+ 'main_content_heading_2_color',
757
+ 'main_content_heading_3_color',
758
+ 'header_navigation_links_color',
759
+ 'footer_links_color',
760
+ 'footer_heading_color',
761
+
762
+ 'buttons_text_color',
763
+ ],
764
+ ],
765
+ 'sm_dark_secondary' => [
766
+ 'connected_fields' => [
767
+ 'body_text_color',
768
+ 'header_navigation_text_color',
769
+ 'footer_text_color',
770
+ ],
771
+ ],
772
+ 'sm_light_primary' => [
773
+ 'connected_fields' => [
774
+ 'main_content_content_background_color',
775
+ 'buttons_alt_text_color',
776
+ ],
777
+ ],
778
+ 'sm_light_secondary' => [
779
+ 'connected_fields' => [
780
+ 'header_background_color',
781
+ 'buttons_background_color',
782
+ 'footer_background_color',
783
+ ],
784
+ ],
785
+ 'sm_light_tertiary' => [
786
+ 'connected_fields' => [],
787
+ ],
788
+ ],
789
+ ];
790
+
791
+ /**
792
+ * Add "instructions" to remove panels, sections, controls and/or settings.
793
+ */
794
+
795
+ $config['remove_sections'] = [
796
+ 'storefront_footer',
797
+ 'storefront_typography',
798
+ 'storefront_buttons',
799
+ ];
800
+
801
+ $config['remove_controls'] = [
802
+ 'storefront_header_background_color',
803
+ 'storefront_header_text_color',
804
+ 'storefront_header_link_color',
805
+ 'background_color',
806
+ ];
807
+
808
+ // You don't need to return anything.
includes/filter-functions.php ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Functions that can be used in the Customify config for filtering values.
4
+ *
5
+ * Think modifying colors, etc.
6
+ */
7
+
8
+ /**
9
+ * Adjust a hex color brightness
10
+ * Allows us to create hover styles for custom link colors
11
+ *
12
+ * Taken from the Storefront theme by Automattic: https://github.com/woocommerce/storefront
13
+ *
14
+ * @param string $hex hex color e.g. #111111.
15
+ * @param integer $steps factor by which to brighten/darken ranging from -255 (darken) to 255 (brighten).
16
+ * @return string brightened/darkened hex color
17
+ */
18
+ function pixcloud_adjust_color_brightness( $hex, $steps ) {
19
+ // Steps should be between -255 and 255. Negative = darker, positive = lighter.
20
+ $steps = max( -255, min( 255, $steps ) );
21
+
22
+ // Format the hex color string.
23
+ $hex = str_replace( '#', '', $hex );
24
+
25
+ if ( 3 == strlen( $hex ) ) {
26
+ $hex = str_repeat( substr( $hex, 0, 1 ), 2 ) . str_repeat( substr( $hex, 1, 1 ), 2 ) . str_repeat( substr( $hex, 2, 1 ), 2 );
27
+ }
28
+
29
+ // Get decimal values.
30
+ $r = hexdec( substr( $hex, 0, 2 ) );
31
+ $g = hexdec( substr( $hex, 2, 2 ) );
32
+ $b = hexdec( substr( $hex, 4, 2 ) );
33
+
34
+ // Adjust number of steps and keep it inside 0 to 255.
35
+ $r = max( 0, min( 255, $r + $steps ) );
36
+ $g = max( 0, min( 255, $g + $steps ) );
37
+ $b = max( 0, min( 255, $b + $steps ) );
38
+
39
+ $r_hex = str_pad( dechex( $r ), 2, '0', STR_PAD_LEFT );
40
+ $g_hex = str_pad( dechex( $g ), 2, '0', STR_PAD_LEFT );
41
+ $b_hex = str_pad( dechex( $b ), 2, '0', STR_PAD_LEFT );
42
+
43
+ return '#' . $r_hex . $g_hex . $b_hex;
44
+ }
45
+
46
+ /**
47
+ * Negate the value.
48
+ *
49
+ * @param int|float $value
50
+ * @return int|float
51
+ */
52
+ function pixcloud_negate( $value ) {
53
+ if ( ! is_numeric( $value ) ) {
54
+ return $value;
55
+ }
56
+
57
+ return - $value;
58
+ }
59
+
60
+ /**
61
+ * Ensure that value is at least the $min value.
62
+ *
63
+ * @param int|float $value
64
+ * @param int|float $min
65
+ * @return int|float
66
+ */
67
+ function pixcloud_min( $value, $min ) {
68
+ if ( ! is_numeric( $value ) || ! is_numeric( $min ) ) {
69
+ return $value;
70
+ }
71
+
72
+ if ( $value < $min ) {
73
+ return $min;
74
+ }
75
+
76
+ return $value;
77
+ }
78
+
79
+ /**
80
+ * Ensure that value is at most the $max value.
81
+ *
82
+ * @param int|float $value
83
+ * @param int|float $max
84
+ * @return int|float
85
+ */
86
+ function pixcloud_max( $value, $max ) {
87
+ if ( ! is_numeric( $value ) || ! is_numeric( $max ) ) {
88
+ return $value;
89
+ }
90
+
91
+ if ( $value > $max ) {
92
+ return $max;
93
+ }
94
+
95
+ return $value;
96
+ }
97
+
98
+ /**
99
+ * Ensure that value is between $min and $max.
100
+ *
101
+ * @param int|float $value
102
+ * @param int|float $min
103
+ * @param int|float $max
104
+ * @return int|float
105
+ */
106
+ function pixcloud_min_max( $value, $min, $max ) {
107
+ if ( ! is_numeric( $value ) || ! is_numeric( $min ) || ! is_numeric( $max ) ) {
108
+ return $value;
109
+ }
110
+
111
+ if ( $value < $min ) {
112
+ $value = $min;
113
+ }
114
+
115
+ if ( $value > $max ) {
116
+ $value = $max;
117
+ }
118
+
119
+ return $value;
120
+ }
121
+
122
+ /**
123
+ * Add something to the value.
124
+ *
125
+ * @param int|float $value
126
+ * @param int|float $add
127
+ * @return int|float
128
+ */
129
+ function pixcloud_add( $value, $add ) {
130
+ if ( ! is_numeric( $value ) || ! is_numeric( $add ) ) {
131
+ return $value;
132
+ }
133
+
134
+ return $value + $add;
135
+ }
136
+
137
+ /**
138
+ * Substract something from the value.
139
+ *
140
+ * @param int|float $value
141
+ * @param int|float $substract
142
+ * @return int|float
143
+ */
144
+ function pixcloud_substract( $value, $substract ) {
145
+ if ( ! is_numeric( $value ) || ! is_numeric( $substract ) ) {
146
+ return $value;
147
+ }
148
+
149
+ return $value - $substract;
150
+ }
151
+
152
+ /**
153
+ * Multiply the value.
154
+ *
155
+ * @param int|float $value
156
+ * @param int|float $multiply
157
+ * @return int|float
158
+ */
159
+ function pixcloud_multiply( $value, $multiply ) {
160
+ if ( ! is_numeric( $value ) || ! is_numeric( $multiply ) ) {
161
+ return $value;
162
+ }
163
+
164
+ return $value * $multiply;
165
+ }
166
+
167
+ /**
168
+ * Divide the value.
169
+ *
170
+ * @param int|float $value
171
+ * @param int|float $divide
172
+ * @return int|float
173
+ */
174
+ function pixcloud_divide( $value, $divide ) {
175
+ if ( ! is_numeric( $value ) || ! is_numeric( $divide ) || empty( $divide ) ) {
176
+ return $value;
177
+ }
178
+
179
+ return $value / $divide;
180
+ }
181
+
182
+ /**
183
+ * Divide the value and get the remainder.
184
+ *
185
+ * @param int|float $value
186
+ * @param int|float $divide
187
+ * @return int|float
188
+ */
189
+ function pixcloud_modulo( $value, $divide ) {
190
+ if ( ! is_numeric( $value ) || ! is_numeric( $divide ) || empty( $divide ) ) {
191
+ return $value;
192
+ }
193
+
194
+ return $value % $divide;
195
+ }
js/customizer/customify-palettes.js CHANGED
@@ -254,7 +254,6 @@
254
  const handleColorPalettes = () => {
255
  initializeColorPalettes();
256
  createCurrentPaletteControls();
257
- reloadConnectedFields();
258
  updateCurrentPalette();
259
  bindVariationChange();
260
 
254
  const handleColorPalettes = () => {
255
  initializeColorPalettes();
256
  createCurrentPaletteControls();
 
257
  updateCurrentPalette();
258
  bindVariationChange();
259
 
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
  === Customify - A Theme Customizer Booster ===
2
- Contributors: pixelgrade, euthelup, babbardel, vlad.olaru, cristianfrumusanu, raduconstantin
3
  Tags: customizer, css, editor, live, preview, customizer
4
  Requires at least: 4.7.0
5
  Tested up to: 4.9.5
6
- Stable tag: 1.7.0
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -45,6 +45,9 @@ With [Customify](https://github.com/pixelgrade/customify), developers can easily
45
 
46
  == Changelog ==
47
 
 
 
 
48
  = 1.7.0 =
49
  * Added **Dynamic Color Palettes** for a smoother experience
50
  * Fixed issue with the Style Manager crashing the Customizer when not using a theme with support for it.
1
  === Customify - A Theme Customizer Booster ===
2
+ Contributors: pixelgrade, euthelup, babbardel, vlad.olaru, cristianfrumusanu, raduconstantin, razvanonofrei
3
  Tags: customizer, css, editor, live, preview, customizer
4
  Requires at least: 4.7.0
5
  Tested up to: 4.9.5
6
+ Stable tag: 1.7.1
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
45
 
46
  == Changelog ==
47
 
48
+ = 1.7.1 =
49
+ * Fixed issue with **Color Palettes** overwriting custom colors in Live Preview
50
+
51
  = 1.7.0 =
52
  * Added **Dynamic Color Palettes** for a smoother experience
53
  * Fixed issue with the Style Manager crashing the Customizer when not using a theme with support for it.