PluginProbe
Customify / 2.10.1
Customify v2.10.1
2.10.9 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.7.1 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.6.0 1.6.0.1 1.6.5 1.7.0 1.7.1 All 77 releases
← All changes | includes/class-customify-style-manager.php +785 -1161 1.7.12.10.1 View file →
@@ -1,1328 +1,952 @@
1 1 <?php
2 +/**
3 + * This is the class that handles the overall logic for the Style Manager.
4 + *
5 + * @see https://pixelgrade.com
6 + * @author Pixelgrade
7 + * @since 1.7.0
8 + */
2 9
3 -class Customify_Style_Manager {
10 +if ( ! defined( 'ABSPATH' ) ) {
11 + exit; // Exit if accessed directly
12 +}
4 13
5 - /**
6 - * Holds the only instance of this class.
7 - * @var null|Customify_Style_Manager
8 - * @access protected
9 - * @since 1.7.0
10 - */
11 - protected static $_instance = null;
14 +if ( ! class_exists( 'Customify_Style_Manager' ) ) {
12 15
13 - /**
14 - * The main plugin object (the parent).
15 - * @var PixCustomifyPlugin
16 - * @access public
17 - * @since 1.7.0
18 - */
19 - public $parent = null;
16 + class Customify_Style_Manager {
20 17
21 - /**
22 - * External REST API endpoints used for communicating with the Pixelgrade Cloud.
23 - * @var array
24 - * @access public
25 - * @since 1.7.0
26 - */
27 - public static $externalApiEndpoints;
18 + /**
19 + * Holds the only instance of this class.
20 + * @var null|Customify_Style_Manager
21 + * @access protected
22 + * @since 1.7.0
23 + */
24 + protected static $_instance = null;
28 25
29 - /**
30 - * The current design assets config.
31 - * @var array
32 - * @access public
33 - * @since 1.7.0
34 - */
35 - public $design_assets = null;
26 + /**
27 + * The main plugin object (the parent).
28 + * @var null|PixCustomifyPlugin
29 + * @access public
30 + * @since 1.7.0
31 + */
32 + public $parent = null;
36 33
37 - /**
38 - * The external theme config.
39 - * @var array
40 - * @access public
41 - * @since 1.7.5
42 - */
43 - public $external_theme_config = null;
34 + /**
35 + * The external theme configs object.
36 + * @var null|Customify_Theme_Configs
37 + * @access public
38 + * @since 1.7.4
39 + */
40 + protected $theme_configs = null;
44 41
45 - /**
46 - * Constructor.
47 - *
48 - * @since 1.7.0
49 - *
50 - * @param $parent
51 - */
52 - protected function __construct( $parent = null ) {
53 - $this->parent = $parent;
42 + /**
43 + * The color palettes object.
44 + * @var null|Customify_Color_Palettes
45 + * @access public
46 + * @since 1.7.4
47 + */
48 + protected $color_palettes = null;
54 49
55 - // Make sure our constants are in place, if not already defined.
56 - defined( 'PIXELGRADE_CLOUD__API_BASE' ) || define( 'PIXELGRADE_CLOUD__API_BASE', 'https://cloud.pixelgrade.com/' );
50 + /**
51 + * The font palettes object.
52 + * @var null|Customify_Font_Palettes
53 + * @access public
54 + * @since 1.7.4
55 + */
56 + protected $font_palettes = null;
57 57
58 - // Save the external API endpoints in a easy to get property.
59 - self::$externalApiEndpoints = apply_filters( 'customify_style_manager_external_api_endpoints', array(
60 - 'cloud' => array(
61 - 'getDesignAssets' => array(
62 - 'method' => 'GET',
63 - 'url' => PIXELGRADE_CLOUD__API_BASE . 'wp-json/pixcloud/v1/front/design_assets',
64 - ),
65 - 'stats' => array(
66 - 'method' => 'POST',
67 - 'url' => PIXELGRADE_CLOUD__API_BASE . 'wp-json/pixcloud/v1/front/stats',
68 - ),
69 - ),
70 - ) );
71 -
72 - // Hook up.
73 - $this->add_hooks();
74 - }
75 -
76 - /**
77 - * Initiate our hooks
78 - *
79 - * @since 1.7.0
80 - */
81 - public function add_hooks() {
82 - /*
83 - * Handle the Customizer Style Manager base config.
58 + /**
59 + * The cloud fonts object.
60 + * @var null|Customify_Cloud_Fonts
61 + * @access public
62 + * @since 2.7.0
84 63 */
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 );
64 + protected $cloud_fonts = null;
88 65
89 - /*
90 - * Handle the external theme configuration logic. We use a late priority to be able to overwrite if we have to.
66 + /**
67 + * The Cloud API object.
68 + * @var null|Customify_Cloud_Api
69 + * @access public
70 + * @since 1.7.4
91 71 */
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 );
72 + protected $cloud_api = null;
96 73
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.
74 + /**
75 + * Cache for the wupdates identification data to avoid firing the filter multiple times.
76 + * @var array
77 + * @access protected
105 78 */
106 - add_action( 'customize_save_after', array( $this, 'update_custom_palette_in_use' ), 10, 1 );
79 + protected static $wupdates_ids = array();
107 80
108 - /*
109 - * Handle the logic for user feedback.
81 + /**
82 + * Constructor.
83 + *
84 + * @since 1.7.0
110 85 */
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' ) );
86 + protected function __construct() {
87 + $this->init();
88 + }
113 89
114 - /*
115 - * Scripts enqueued in the Customizer.
90 + /**
91 + * Initialize this module.
92 + *
93 + * @since 1.7.4
116 94 */
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 - }
95 + public function init() {
96 + /**
97 + * Initialize the Themes Config logic.
98 + */
99 + require_once 'class-customify-theme-configs.php';
100 + $this->theme_configs = Customify_Theme_Configs::instance();
120 101
121 - /**
122 - * Register Customizer admin scripts
123 - */
124 - function register_admin_customizer_scripts() {
125 - wp_register_script( $this->parent->get_slug() . '-swap-values', plugins_url( 'js/customizer/customify-swap-values.js', $this->parent->file ), array( 'jquery' ), $this->parent->get_version() );
126 - wp_register_script( $this->parent->get_slug() . '-palette-variations', plugins_url( 'js/customizer/customify-palette-variations.js', $this->parent->file ), array( 'jquery' ), $this->parent->get_version() );
127 - wp_register_script( $this->parent->get_slug() . '-palettes', plugins_url( 'js/customizer/customify-palettes.js', $this->parent->file ), array( 'jquery', $this->parent->get_slug() . '-palette-variations', $this->parent->get_slug() . '-swap-values' ), $this->parent->get_version() );
128 - }
102 + /**
103 + * Initialize the Color Palettes logic.
104 + */
105 + require_once 'class-customify-color-palettes.php';
106 + $this->color_palettes = Customify_Color_Palettes::instance();
129 107
130 - /**
131 - * Enqueue Customizer admin scripts
132 - */
133 - function enqueue_admin_customizer_scripts() {
134 - // If there is no style manager support, bail early.
135 - if ( ! $this->is_supported() ) {
136 - return;
137 - }
108 + /**
109 + * Initialize the Font Palettes logic.
110 + */
111 + require_once 'class-customify-font-palettes.php';
112 + $this->font_palettes = Customify_Font_Palettes::instance();
138 113
139 - wp_enqueue_script( $this->parent->get_slug() . '-palettes' );
140 - }
114 + /**
115 + * Initialize the Cloud Fonts logic.
116 + */
117 + require_once 'class-customify-cloud-fonts.php';
118 + $this->cloud_fonts = Customify_Cloud_Fonts::instance();
141 119
142 - /**
143 - * Determine if Style Manager is supported.
144 - *
145 - * @since 1.7.0
146 - *
147 - * @return bool
148 - */
149 - public function is_supported() {
150 - $has_support = (bool) current_theme_supports( 'customizer_style_manager' );
120 + /**
121 + * Initialize the Cloud API logic.
122 + */
123 + require_once 'lib/class-customify-cloud-api.php';
124 + $this->cloud_api = new Customify_Cloud_Api();
151 125
152 - return apply_filters( 'customify_style_manager_is_supported', $has_support );
153 - }
126 + // Make sure that the Design Assets class is loaded.
127 + require_once 'lib/class-customify-design-assets.php';
154 128
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;
129 + // Hook up.
130 + $this->add_hooks();
170 131 }
171 132
172 - if ( ! isset( $config['sections']['style_manager_section'] ) ) {
173 - $config['sections']['style_manager_section'] = array();
174 - }
133 + /**
134 + * Initiate our hooks
135 + *
136 + * @since 1.7.0
137 + */
138 + public function add_hooks() {
139 + /*
140 + * Handle the Customizer Style Manager base config.
141 + */
142 + add_filter( 'customify_filter_fields', array( $this, 'style_manager_section_base_config' ), 12, 1 );
175 143
176 - // The section might be already defined, thus we merge, not replace the entire section 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',
184 - // We will bypass the plugin setting regarding where to store - we will store it cross-theme in wp_options
185 - 'setting_type' => 'option',
186 - // We will force this setting id preventing prefixing and other regular processing.
187 - 'setting_id' => 'sm_color_palette',
188 - // We don't want to refresh the preview window, even though we have no direct effect on it through this field.
189 - 'live' => true,
190 - 'label' => esc_html__( 'Select a color palette:', 'customify' ),
191 - 'desc' => esc_html__( 'Conveniently change the design of your site with color palettes. Easy as pie.', 'customify' ),
192 - 'default' => 'lilac',
193 - 'choices_type' => 'color_palette',
194 - 'choices' => $this->get_color_palettes(),
195 - ),
196 - 'sm_color_palette_variation' => array(
197 - 'type' => 'radio',
198 - 'setting_type' => 'option',
199 - 'setting_id' => 'sm_color_palette_variation',
200 - 'label' => esc_html__( 'Palette Variation', 'customify' ),
201 - 'default' => 'light',
202 - 'live' => true,
203 - 'choices' => array(
204 - 'light' => esc_html__( 'light', 'customify' ),
205 - 'light_alt' => esc_html__( 'light_alt', 'customify' ),
144 + /*
145 + * Handle the grouping and reorganization of the Customizer theme sections when Style Manager is active.
146 + */
147 + add_filter( 'customify_final_config', array( $this, 'reorganize_customify_sections' ), 10, 1 );
148 + // Remove the switch theme panel from the Customizer.
149 + add_action( 'customize_register', array( $this, 'remove_switch_theme_panel' ), 12 );
150 + // Add the logic that handles sections and controls registered directly to WP_Customizer, not through the Customify config.
151 + add_action( 'customize_register', array( $this, 'reorganize_direct_sections_and_controls' ), 998 );
206 152
207 - 'dark' => esc_html__( 'dark', 'customify' ),
208 - 'dark_alt' => esc_html__( 'dark_alt', 'customify' ),
153 + /*
154 + * Handle other, more general reorganization in the Customizer, independent of Style Manager.
155 + */
156 + add_action( 'customize_register', array( $this, 'general_reorganization_of_customize_sections' ), 999, 1 );
209 157
210 - 'colorful' => esc_html__( 'colorful', 'customify' ),
211 - 'colorful_alt' => esc_html__( 'colorful_alt', 'customify' ),
212 - ),
213 - ),
214 - 'sm_color_primary' => array(
215 - 'type' => 'color',
216 - // We will bypass the plugin setting regarding where to store - we will store it cross-theme in wp_options
217 - 'setting_type' => 'option',
218 - // We will force this setting id preventing prefixing and other regular processing.
219 - 'setting_id' => 'sm_color_primary',
220 - // We don't want to refresh the preview window, even though we have no direct effect on it through this field.
221 - 'live' => true,
222 - 'label' => esc_html__( 'Color Primary', 'customify' ),
223 - 'default' => '#ffeb00',
224 - 'connected_fields' => array(),
225 - ),
226 - 'sm_color_secondary' => array(
227 - 'type' => 'color',
228 - 'setting_type' => 'option',
229 - 'setting_id' => 'sm_color_secondary',
230 - 'live' => true,
231 - 'label' => esc_html__( 'Color Secondary', 'customify' ),
232 - 'default' => '#00ecff',
233 - 'connected_fields' => array(),
234 - ),
235 - 'sm_color_tertiary' => array(
236 - 'type' => 'color',
237 - 'setting_type' => 'option',
238 - 'setting_id' => 'sm_color_tertiary',
239 - 'live' => true,
240 - 'label' => esc_html__( 'Color Tertiary', 'customify' ),
241 - 'default' => '#00ecff',
242 - 'connected_fields' => array(),
243 - ),
244 - 'sm_dark_primary' => array(
245 - 'type' => 'color',
246 - 'setting_type' => 'option',
247 - 'setting_id' => 'sm_dark_primary',
248 - 'live' => true,
249 - 'label' => esc_html__( 'Dark Primary', 'customify' ),
250 - 'default' => '#171617',
251 - 'connected_fields' => array(),
252 - ),
253 - 'sm_dark_secondary' => array(
254 - 'type' => 'color',
255 - 'setting_type' => 'option',
256 - 'setting_id' => 'sm_dark_secondary',
257 - 'live' => true,
258 - 'label' => esc_html__( 'Dark Secondary', 'customify' ),
259 - 'default' => '#383c50',
260 - 'connected_fields' => array(),
261 - ),
262 - 'sm_dark_tertiary' => array(
263 - 'type' => 'color',
264 - 'setting_type' => 'option',
265 - 'setting_id' => 'sm_dark_tertiary',
266 - 'live' => true,
267 - 'label' => esc_html__( 'Dark Tertiary', 'customify' ),
268 - 'default' => '#65726F',
269 - 'connected_fields' => array(),
270 - ),
271 - 'sm_light_primary' => array(
272 - 'type' => 'color',
273 - 'setting_type' => 'option',
274 - 'setting_id' => 'sm_light_primary',
275 - 'live' => true,
276 - 'label' => esc_html__( 'Light Primary', 'customify' ),
277 - 'default' => '#ffffff',
278 - 'connected_fields' => array(),
279 - ),
280 - 'sm_light_secondary' => array(
281 - 'type' => 'color',
282 - 'setting_type' => 'option',
283 - 'setting_id' => 'sm_light_secondary',
284 - 'live' => true,
285 - 'label' => esc_html__( 'Light Secondary', 'customify' ),
286 - 'default' => '#ffffff',
287 - 'connected_fields' => array(),
288 - ),
289 - 'sm_light_tertiary' => array(
290 - 'type' => 'color',
291 - 'setting_type' => 'option',
292 - 'setting_id' => 'sm_light_tertiary',
293 - 'live' => true,
294 - 'label' => esc_html__( 'Light Tertiary', 'customify' ),
295 - 'default' => '#ffffff',
296 - 'connected_fields' => array(),
297 - ),
298 - 'sm_swap_colors' => array(
299 - 'type' => 'button',
300 - 'setting_type' => 'option',
301 - 'setting_id' => 'sm_swap_colors',
302 - 'label' => esc_html__( 'Swap Colors', 'customify' ),
303 - 'action' => 'sm_swap_colors',
304 - ),
305 - 'sm_swap_dark_light' => array(
306 - 'type' => 'button',
307 - 'setting_type' => 'option',
308 - 'setting_id' => 'sm_swap_dark_light',
309 - 'label' => esc_html__( 'Swap Dark ⇆ Light', 'customify' ),
310 - 'action' => 'sm_swap_dark_light',
311 - ),
312 - 'sm_swap_colors_dark' => array(
313 - 'type' => 'button',
314 - 'setting_type' => 'option',
315 - 'setting_id' => 'sm_swap_colors_dark',
316 - 'label' => esc_html__( 'Swap Colors ⇆ Dark', 'customify' ),
317 - 'action' => 'sm_swap_colors_dark',
318 - ),
319 - 'sm_swap_secondary_colors_dark' => array(
320 - 'type' => 'button',
321 - 'setting_type' => 'option',
322 - 'setting_id' => 'sm_swap_secondary_colors_dark',
323 - 'label' => esc_html__( 'Swap Secondary Color ⇆ Secondary Dark', 'customify' ),
324 - 'action' => 'sm_swap_secondary_colors_dark',
325 - ),
326 - 'sm_advanced_toggle' => array(
327 - 'type' => 'button',
328 - 'setting_type' => 'option',
329 - 'setting_id' => 'sm_toggle_advanced_settings',
330 - 'label' => esc_html__( 'Toggle Advanced Settings', 'customify' ),
331 - 'action' => 'sm_toggle_advanced_settings',
332 - ),
333 - ),
334 - ) );
158 + /*
159 + * Handle the customization of controls based on theme type.
160 + */
161 + add_filter( 'customify_filter_fields', array( $this, 'pre_filter_based_on_theme_type' ), 20, 1 );
162 + add_filter( 'customify_final_config', array( $this, 'filter_based_on_theme_type' ), 20, 1 );
163 + add_action( 'customify_after_preset_control', array( $this, 'maybe_add_text_after_color_palettes' ), 10, 1 );
164 + add_action( 'customify_after_sm_palette_filter_control', array( $this, 'maybe_add_text_after_color_palette_filters' ), 10, 1 );
165 + add_action( 'customify_after_sm_radio_control', array( $this, 'maybe_add_text_after_color_palettes_customize_controls' ), 10, 1 );
335 166
336 - return $config;
337 - }
167 + /*
168 + * Handle the logic for user feedback.
169 + */
170 + add_action( 'customize_controls_print_footer_scripts', array( $this, 'output_user_feedback_modal' ) );
171 + add_action( 'wp_ajax_customify_style_manager_user_feedback', array( $this, 'user_feedback_callback' ) );
338 172
339 - /**
340 - * Add the current color palette control to the Style Manager section.
341 - *
342 - * @since 1.7.0
343 - *
344 - * @param array $config
345 - * @return array
346 - */
347 - public function add_current_color_palette_control( $config ) {
348 - // If there is no style manager support, bail early.
349 - if ( ! $this->is_supported() ) {
350 - return $config;
351 - }
173 + add_filter( 'customify_localized_js_settings', array( $this, 'add_to_localized_data' ), 10, 1 );
352 174
353 - if ( ! isset( $config['sections']['style_manager_section'] ) ) {
354 - $config['sections']['style_manager_section'] = array();
175 + /*
176 + * Scripts enqueued in the Customizer.
177 + */
178 + add_action( 'customize_controls_init', array( $this, 'register_admin_customizer_scripts' ), 10 );
179 + add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_admin_customizer_scripts' ), 10 );
355 180 }
356 181
357 - $current_palette = '';
358 - $current_palette_sets = array( 'current', 'next' );
182 + /**
183 + * Register Customizer admin scripts.
184 + */
185 + function register_admin_customizer_scripts() {
186 + $suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
359 187
360 - $master_color_controls_ids = $this->get_all_master_color_controls_ids( $config['sections']['style_manager_section']['options'] );
188 + wp_register_script( PixCustomifyPlugin()->get_slug() . '-style-manager',
189 + plugins_url( 'js/customizer/style-manager' . $suffix . '.js', PixCustomifyPlugin()->get_file() ),
190 + array( 'jquery' ), PixCustomifyPlugin()->get_version() );
191 + }
361 192
362 - foreach ( $current_palette_sets as $set ) {
363 - $current_palette .= '<div class="colors ' . $set . '">';
364 - foreach ( $master_color_controls_ids as $setting_id ) {
365 - if ( ! empty( $config['sections']['style_manager_section']['options'][ $setting_id ]['connected_fields'] ) ) {
366 - $current_palette .=
367 - '<div class="color ' . $setting_id . '" data-setting="' . $setting_id . '">' . PHP_EOL .
368 - '<div class="fill"></div>' . PHP_EOL .
369 - '<div class="picker"><i></i></div>' . PHP_EOL .
370 - '</div>' . PHP_EOL;
371 - }
193 + /**
194 + * Enqueue Customizer admin scripts
195 + */
196 + function enqueue_admin_customizer_scripts() {
197 + // If there is no style manager support, bail early.
198 + if ( ! $this->is_supported() ) {
199 + return;
372 200 }
373 - $current_palette .= '</div>';
201 +
202 + // Enqueue the needed scripts, already registered.
203 + wp_enqueue_script( PixCustomifyPlugin()->get_slug() . '-style-manager' );
374 204 }
375 205
376 - // The section might be already defined, thus we merge, not replace the entire section config.
377 - $config['sections']['style_manager_section']['options'] = array(
378 - 'sm_current_color_palette' => array(
379 - 'type' => 'html',
380 - 'html' =>
381 - '<div class="palette-container">' . PHP_EOL .
382 - '<span class="customize-control-title">Current Color Palette:</span>' . PHP_EOL .
383 - '<span class="description customize-control-description">Choose a color palette to start with. Adjust its style using the variation buttons below.</span>' . PHP_EOL .
384 - '<div class="c-palette">' . PHP_EOL .
385 - $current_palette .
386 - '<div class="c-palette__overlay">' . PHP_EOL .
387 - '<div class="c-palette__label">' .
388 - '<div class="c-palette__name">' . 'Original Style' . '</div>' .
389 - '<div class="c-palette__control variation-light active" data-target="#_customize-input-sm_color_palette_variation_control-radio-light">' .
390 - '<span class="dashicons dashicons-image-rotate"></span>' .
391 - '<div class="c-palette__tooltip">Light</div>' .
392 - '</div>' .
393 - '<div class="c-palette__control variation-dark" data-target="#_customize-input-sm_color_palette_variation_control-radio-dark">' .
394 - '<span class="dashicons dashicons-image-filter"></span>'.
395 - '<div class="c-palette__tooltip">Dark</div>' .
396 - '</div>' .
397 - '<div class="c-palette__control variation-colorful" data-target="#_customize-input-sm_color_palette_variation_control-radio-colorful">' .
398 - '<span class="dashicons dashicons-admin-appearance"></span>' .
399 - '<div class="c-palette__tooltip">Colorful</div>' .
400 - '</div>' .
401 - '</div>' . PHP_EOL .
402 - '</div>' . PHP_EOL .
403 - '</div>' . PHP_EOL .
404 - '</div>' . PHP_EOL .
405 - '<svg class="c-palette__blur" width="15em" height="15em" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg" version="1.1">' . PHP_EOL .
406 - '<defs>' . PHP_EOL .
407 - '<filter id="goo">' . PHP_EOL .
408 - '<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />' . PHP_EOL .
409 - '<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 50 -20" result="goo" />' . PHP_EOL .
410 - '<feBlend in="SourceGraphic" in2="goo" />' . PHP_EOL .
411 - '</filter>' . PHP_EOL .
412 - '</defs>' . PHP_EOL .
413 - '</svg>',
414 - ),
415 - ) + $config['sections']['style_manager_section']['options'];
206 + /**
207 + * Determine if Style Manager is supported.
208 + *
209 + * @return bool
210 + * @since 1.7.0
211 + *
212 + */
213 + public function is_supported() {
214 + $has_support = (bool) current_theme_supports( 'customizer_style_manager' );
416 215
417 - return $config;
418 - }
216 + return apply_filters( 'customify_style_manager_is_supported', $has_support );
217 + }
419 218
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 - }
219 + /**
220 + * Setup the Style Manager Customizer section base config.
221 + *
222 + * This handles the base configuration for the controls in the Style Manager section. We expect other parties (e.g. the theme),
223 + * to come and fill up the missing details (e.g. connected fields).
224 + *
225 + * @param array $config This holds required keys for the plugin config like 'opt-name', 'panels', 'settings'
226 + *
227 + * @return array
228 + * @since 1.7.0
229 + *
230 + */
231 + public function style_manager_section_base_config( $config ) {
232 + // If there is no style manager support, bail early.
233 + if ( ! $this->is_supported() ) {
234 + return $config;
235 + }
435 236
436 - $external_theme_config = false;
237 + if ( ! isset( $config['sections']['style_manager_section'] ) ) {
238 + $config['sections']['style_manager_section'] = array();
239 + }
437 240
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() ) {
241 + // The section might be already defined, thus we merge, not replace the entire section config.
242 + $config['sections']['style_manager_section'] = Customify_Array::array_merge_recursive_distinct( $config['sections']['style_manager_section'], array(
243 + 'title' => esc_html__( 'Style Manager', 'customify' ),
244 + 'section_id' => 'style_manager_section',
245 + // We will force this section id preventing prefixing and other regular processing.
246 + 'priority' => 1,
247 + 'options' => array(),
248 + ) );
249 +
442 250 return $config;
443 251 }
444 252
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 - }
253 + /**
254 + * Reorganize the Customizer sections.
255 + *
256 + * @param array $config This holds required keys for the plugin config like 'opt-name', 'panels', 'settings'.
257 + *
258 + * @return array
259 + * @since 1.7.4
260 + *
261 + */
262 + public function reorganize_customify_sections( $config ) {
263 + // If there is no style manager support, bail early.
264 + if ( ! $this->is_supported() ) {
265 + return $config;
266 + }
450 267
451 - $theme_configs = $design_assets['theme_configs'];
268 + // If there is no Style Manager section or panel, bail.
269 + if ( ! isset( $config['sections']['style_manager_section'] ) &&
270 + ! isset( $config['panels']['style_manager_panel'] ) ) {
452 271
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;
272 + return $config;
459 273 }
460 274
461 - $matches = 0;
462 - $total = 0;
463 - if ( ! empty( $theme_config['name'] ) && $theme_config['name'] == $theme->get('Name') ) {
464 - $matches++;
465 - $total++;
275 + $style_manager_section_config = false;
276 + if ( isset( $config['sections']['style_manager_section'] ) ) {
277 + $style_manager_section_config = $config['sections']['style_manager_section'];
278 + unset( $config['sections']['style_manager_section'] );
466 279 }
467 - if ( ! empty( $theme_config['slug'] ) && $theme_config['slug'] == $theme->get_stylesheet() ) {
468 - $matches++;
469 - $total++;
280 +
281 + // All the other sections.
282 + $other_theme_sections_config = $config['sections'];
283 + unset( $config['sections'] );
284 +
285 + // The Style Manager panel.
286 + if ( empty( $config['panels']['style_manager_panel'] ) ) {
287 + $style_manager_panel_config = array(
288 + 'priority' => 22, // after the Site Identity panel
289 + 'capability' => 'edit_theme_options',
290 + 'panel_id' => 'style_manager_panel',
291 + 'title' => esc_html__( 'Style Manager', 'customify' ),
292 + 'description' => wp_kses_post( __( '<strong>Style Manager</strong> is an intuitive system to help you change the look of your website and make an excellent impression.', 'customify' ) ),
293 + 'sections' => array(),
294 + 'auto_expand_sole_section' => true, // If there is only one section in the panel, auto-expand it.
295 + );
296 + } else {
297 + $style_manager_panel_config = $config['panels']['style_manager_panel'];
298 + unset( $config['panels']['style_manager_panel'] );
470 299 }
471 - if ( ! empty( $theme_config['txtd'] ) && $theme_config['txtd'] == $theme->get('TextDomain') ) {
472 - $matches++;
473 - $total++;
474 - }
475 300
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;
301 + $other_panels_config = false;
302 + if ( ! empty( $config['panels'] ) ) {
303 + $other_panels_config = $config['panels'];
304 + unset( $config['panels'] );
481 305 }
482 - }
483 306
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 - }
307 + // Maybe handle the color palettes.
308 + if ( is_array( $style_manager_section_config ) && class_exists( 'Customify_Color_Palettes' ) && Customify_Color_Palettes::instance()->is_supported() ) {
491 309
492 - // Now we have a theme config to work with. Save it for later use.
493 - $this->external_theme_config = $external_theme_config;
310 + // We need to split the fields in the Style Manager section into two: color palettes and fonts.
311 + $color_palettes_fields = array(
312 + 'sm_current_color_palette',
313 + 'sm_palettes_description',
314 + 'sm_filters_description',
315 + 'sm_customize_description',
316 + 'sm_color_matrix',
317 + 'sm_palette_filter',
318 + 'sm_coloration_level',
319 + 'sm_color_diversity',
320 + 'sm_shuffle_colors',
321 + 'sm_dark_mode',
322 + 'sm_dark_mode_advanced',
323 + 'sm_dark_color_master_slider',
324 + 'sm_dark_color_primary_slider',
325 + 'sm_dark_color_secondary_slider',
326 + 'sm_dark_color_tertiary_slider',
327 + 'sm_colors_dispersion',
328 + 'sm_colors_focus_point',
329 + 'sm_color_palette',
330 + 'sm_color_palette_variation',
331 + 'sm_color_primary',
332 + 'sm_color_primary_final',
333 + 'sm_color_secondary',
334 + 'sm_color_secondary_final',
335 + 'sm_color_tertiary',
336 + 'sm_color_tertiary_final',
337 + 'sm_dark_primary',
338 + 'sm_dark_primary_final',
339 + 'sm_dark_secondary',
340 + 'sm_dark_secondary_final',
341 + 'sm_dark_tertiary',
342 + 'sm_dark_tertiary_final',
343 + 'sm_light_primary',
344 + 'sm_light_primary_final',
345 + 'sm_light_secondary',
346 + 'sm_light_secondary_final',
347 + 'sm_light_tertiary',
348 + 'sm_light_tertiary_final',
349 + 'sm_swap_colors',
350 + 'sm_swap_dark_light',
351 + 'sm_swap_colors_dark',
352 + 'sm_swap_secondary_colors_dark',
353 + 'sm_advanced_toggle',
354 + 'sm_color_palettes_spacing_bottom',
355 + );
494 356
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 - }
357 + $color_palettes_section_config = array(
358 + 'title' => esc_html__( 'Colors', 'customify' ),
359 + 'section_id' => 'sm_color_palettes_section',
360 + 'priority' => 10,
361 + 'options' => array(),
362 + );
363 + foreach ( $color_palettes_fields as $field_id ) {
364 + if ( ! isset( $style_manager_section_config['options'][ $field_id ] ) ) {
365 + continue;
366 + }
499 367
500 - return $config;
501 - }
368 + if ( empty( $color_palettes_section_config['options'] ) ) {
369 + $color_palettes_section_config['options'] = array( $field_id => $style_manager_section_config['options'][ $field_id ] );
370 + } else {
371 + $color_palettes_section_config['options'] = array_merge( $color_palettes_section_config['options'], array( $field_id => $style_manager_section_config['options'][ $field_id ] ) );
372 + }
373 + }
502 374
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'];
375 + $style_manager_panel_config['sections']['sm_color_palettes_section'] = $color_palettes_section_config;
526 376 }
527 377
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 - }
378 + // Maybe handle the font palettes.
379 + if ( is_array( $style_manager_section_config ) && class_exists( 'Customify_Font_Palettes' ) && Customify_Font_Palettes::instance()->is_supported() ) {
532 380
533 - $config['sections'] = array(
534 - 'style_manager_section' => $style_manager_section,
535 - );
536 - }
381 + $font_palettes_fields = array(
382 + 'sm_current_font_palette',
383 + 'sm_font_palette',
384 + 'sm_font_palette_variation',
385 + 'sm_font_primary',
386 + 'sm_font_secondary',
387 + 'sm_font_body',
388 + 'sm_font_accent',
389 + 'sm_swap_fonts',
390 + 'sm_swap_primary_secondary_fonts',
391 + 'sm_font_palettes_spacing_bottom',
392 + );
537 393
538 - // Now merge things.
539 - $config['sections'] = Customify_Array::array_merge_recursive_distinct( $config['sections'],$this->external_theme_config['config']['sections'] );
394 + $font_palettes_section_config = array(
395 + 'title' => esc_html__( 'Fonts', 'customify' ),
396 + 'section_id' => 'sm_font_palettes_section',
397 + 'priority' => 20,
398 + 'options' => array(),
399 + );
400 + foreach ( $font_palettes_fields as $field_id ) {
401 + if ( ! isset( $style_manager_section_config['options'][ $field_id ] ) ) {
402 + continue;
403 + }
540 404
541 - return $config;
542 - }
405 + if ( empty( $font_palettes_section_config['options'] ) ) {
406 + $font_palettes_section_config['options'] = array( $field_id => $style_manager_section_config['options'][ $field_id ] );
407 + } else {
408 + $font_palettes_section_config['options'] = array_merge( $font_palettes_section_config['options'], array( $field_id => $style_manager_section_config['options'][ $field_id ] ) );
409 + }
410 + }
543 411
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'] );
412 + $style_manager_panel_config['sections']['sm_font_palettes_section'] = $font_palettes_section_config;
564 413 }
565 414
566 - foreach ( $this->external_theme_config['config']['remove_panels'] as $panel_id ) {
567 - $wp_customize->remove_panel( $panel_id );
415 + // Start fresh and add the Style Manager panel config
416 + if ( empty( $config['panels'] ) ) {
417 + $config['panels'] = array();
568 418 }
569 - }
419 + $config['panels']['style_manager_panel'] = $style_manager_panel_config;
570 420
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 - }
421 + // The Theme Options panel.
422 + $theme_options_panel_config = array(
423 + 'priority' => 24, // after the Style Manager panel.
424 + 'capability' => 'edit_theme_options',
425 + 'panel_id' => 'theme_options_panel',
426 + 'title' => esc_html__( 'Theme Options', 'customify' ),
427 + 'description' => esc_html__( 'Advanced options to change your site look-and-feel on a detailed level.', 'customify' ),
428 + 'sections' => array(),
429 + );
577 430
578 - foreach ( $this->external_theme_config['config']['remove_sections'] as $section_id ) {
431 + // If we have other panels we will make their sections parts of the Theme Options panel.
432 + if ( ! empty( $other_panels_config ) ) {
433 + // If we have another panel that is called Theme Options we will extract it's sections and put them directly in the Theme Options panel.
434 + $second_theme_options_sections = array();
435 + foreach ( $other_panels_config as $panel_id => $panel_config ) {
436 + $found = false;
437 + // First try the panel ID.
438 + if ( false !== strpos( strtolower( str_replace( '-', '_', $panel_id ) ), 'theme_options' ) ) {
439 + $found = true;
440 + }
579 441
580 - if ( 'widgets' === $section_id ) {
581 - global $wp_registered_sidebars;
442 + // Second, try the panel title.
443 + if ( ! $found && ! empty( $panel_config['title'] ) && false !== strpos( strtolower( str_replace( array(
444 + '-',
445 + '_'
446 + ), ' ', $panel_config['title'] ) ), ' theme options' ) ) {
447 + $found = true;
448 + }
582 449
583 - foreach ( $wp_registered_sidebars as $widget => $settings ) {
584 - $wp_customize->remove_section( 'sidebar-widgets-' . $widget );
450 + if ( $found && ! empty( $panel_config['sections'] ) ) {
451 + $second_theme_options_sections = array_merge( $second_theme_options_sections, $panel_config['sections'] );
452 + unset( $other_panels_config[ $panel_id ] );
585 453 }
586 - continue;
587 454 }
455 + if ( ! empty( $second_theme_options_sections ) ) {
456 + $theme_options_panel_config['sections'] = array_merge( $theme_options_panel_config['sections'], $second_theme_options_sections );
457 + }
588 458
589 - $wp_customize->remove_section( $section_id );
459 + // For the remaining panels, we will put their section into the Theme Options panel, but prefix their title with their respective panel title.
460 + $prefixed_sections = array();
461 + foreach ( $other_panels_config as $panel_id => $panel_config ) {
462 + if ( ! empty( $panel_config['sections'] ) ) {
463 + foreach ( $panel_config['sections'] as $section_id => $section_config ) {
464 + if ( ! empty( $section_config['title'] ) && ! empty( $panel_config['title'] ) ) {
465 + $section_config['title'] = $panel_config['title'] . ' - ' . $section_config['title'];
466 + }
467 + $prefixed_sections[ $panel_id . '_' . $section_id ] = $section_config;
468 + }
469 + }
470 + }
471 + $theme_options_panel_config['sections'] = array_merge( $theme_options_panel_config['sections'], $prefixed_sections );
590 472 }
591 - }
592 473
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'] );
474 + // If we have other sections we will add them to the Theme Options panel.
475 + if ( ! empty( $other_theme_sections_config ) ) {
476 + $theme_options_panel_config['sections'] = array_merge( $theme_options_panel_config['sections'], $other_theme_sections_config );
598 477 }
599 478
600 - foreach ( $this->external_theme_config['config']['remove_settings'] as $setting_id ) {
601 - $wp_customize->remove_setting( $setting_id );
479 + if ( empty( $config['panels']['theme_options_panel'] ) ) {
480 + $config['panels']['theme_options_panel'] = $theme_options_panel_config;
481 + } else {
482 + $config['panels']['theme_options_panel'] = array_merge( $config['panels']['theme_options_panel'], $theme_options_panel_config );
602 483 }
484 +
485 + return $config;
603 486 }
604 487
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'] );
488 + /**
489 + * Reorganize the Customizer sections and panels, without accounting for Customify's configured ones.
490 + *
491 + * @param WP_Customize_Manager $wp_customize WP_Customize_Manager instance.
492 + */
493 + public function general_reorganization_of_customize_sections( $wp_customize ) {
494 + $sections = $wp_customize->sections();
495 + if ( ! empty( $sections['pro__section'] ) ) {
496 + $sections['pro__section']->priority = 24; // After the Style Manager panel.
610 497 }
611 498
612 - foreach ( $this->external_theme_config['config']['remove_controls'] as $control_id ) {
613 - $wp_customize->remove_control( $control_id );
614 - }
499 + // Add a pretty icon to Site Identity
500 + $wp_customize->get_section( 'title_tagline' )->title = '&#x1f465; ' . esc_html__( 'Site Identity', 'customify' );
615 501 }
616 - }
617 502
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.
624 - * @return array
625 - */
626 - protected function get_color_palettes( $skip_cache = false ) {
627 - // Get the design assets data.
628 - $design_assets = $this->get_design_assets( $skip_cache );
629 - if ( false === $design_assets || empty( $design_assets['color_palettes'] ) ) {
630 - $color_palettes_config = $this->get_default_color_palettes_config();
631 - } else {
632 - $color_palettes_config = $design_assets['color_palettes'];
633 - }
503 + /**
504 + * Filter the config during the build up.
505 + *
506 + * @param array $config
507 + *
508 + * @return array
509 + */
510 + public function pre_filter_based_on_theme_type( $config ) {
511 + if ( in_array( self::get_theme_type(), array( 'theme_wporg', 'theme_modular_wporg' ) ) ) {
634 512
635 - return apply_filters( 'customify_get_color_palettes', $color_palettes_config );
636 - }
513 + add_filter( 'customify_style_manager_color_palettes_colors_classes', function ( $classes ) {
514 + $classes[] = 'js-no-picker';
637 515
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 - }
516 + return $classes;
517 + } );
518 + }
654 519
655 - return apply_filters( 'customify_get_theme_configs', $theme_configs );
656 - }
657 -
658 - /**
659 - * Get the design assets configuration.
660 - *
661 - * @since 1.7.0
662 - *
663 - * @param bool $skip_cache Optional. Whether to use the cached config or fetch a new one.
664 - * @return array
665 - */
666 - protected function get_design_assets( $skip_cache = false ) {
667 - if ( ! is_null( $this->design_assets ) ) {
668 - return $this->design_assets;
520 + return $config;
669 521 }
670 522
671 - $this->design_assets = apply_filters( 'customify_style_manager_maybe_fetch_design_assets', $this->maybe_fetch_design_assets( $skip_cache ) );
672 -
673 - return $this->design_assets;
674 - }
675 -
676 - /**
677 - * Fetch the design assets data from the Pixelgrade Cloud.
678 - *
679 - * Caches the data for 12 hours. Use local defaults if not available.
680 - *
681 - * @since 1.7.0
682 - *
683 - * @param bool $skip_cache Optional. Whether to use the cached data or fetch a new one.
684 - * @return array|false
685 - */
686 - protected function maybe_fetch_design_assets( $skip_cache = false ) {
687 - // First try and get the cached data
688 - $data = get_option( $this->_get_design_assets_cache_key() );
689 -
690 - // For performance reasons, we will ONLY fetch remotely when in the WP ADMIN area or via an ADMIN AJAX call, regardless of settings.
691 - if ( ! is_admin() ) {
692 - return $data;
523 + public function maybe_add_text_after_color_palettes( $control ) {
524 + if ( 'sm_color_palette' === $control->setting->id && in_array( self::get_theme_type(), array( 'theme_wporg', 'theme_modular_wporg' ) ) ) { ?>
525 + <li id="customize-control-sm_palettes_description_after_control" class="pix_customizer_setting customize-control customize-control-html" style="display: list-item;">
526 + <span class="description customize-control-description"><strong>Many more color palettes</strong> are available with the PRO version of your theme.</span>
527 + </li>
528 + <?php }
693 529 }
694 530
695 - // Get the cache data expiration timestamp.
696 - $expire_timestamp = get_option( $this->_get_design_assets_cache_key() . '_timestamp' );
697 -
698 - // We don't force skip the cache for AJAX requests for performance reasons.
699 - if ( ! wp_doing_ajax() && defined('CUSTOMIFY_SM_ALWAYS_FETCH_DESIGN_ASSETS' ) && true === CUSTOMIFY_SM_ALWAYS_FETCH_DESIGN_ASSETS ) {
700 - $skip_cache = true;
531 + public function maybe_add_text_after_color_palette_filters( $control ) {
532 + if ( in_array( self::get_theme_type(), array( 'theme_wporg', 'theme_modular_wporg' ) ) ) { ?>
533 + <li id="customize-control-sm_filters_description_after_control" class="pix_customizer_setting customize-control customize-control-html" style="display: list-item;">
534 + <span class="description customize-control-description"><strong>More filters</strong> are available with the PRO version of your theme.</span>
535 + </li>
536 + <?php }
701 537 }
702 538
703 - // The data isn't set, is expired or we were instructed to skip the cache; we need to fetch fresh data.
704 - if ( true === $skip_cache || false === $data || false === $expire_timestamp || $expire_timestamp < time() ) {
705 - $request_data = apply_filters( 'customify_pixelgrade_cloud_request_data', array(
706 - 'site_url' => home_url('/'),
707 - // We are only interested in data needed to identify the theme and eventually deliver only design assets suitable for it.
708 - 'theme_data' => $this->get_active_theme_data(),
709 - // We are only interested in data needed to identify the plugin version and eventually deliver design assets suitable for it.
710 - 'site_data' => $this->get_site_data(),
711 - ), $this );
712 -
713 - $request_args = array(
714 - 'method' => self::$externalApiEndpoints['cloud']['getDesignAssets']['method'],
715 - 'timeout' => 4,
716 - 'blocking' => true,
717 - 'body' => $request_data,
718 - 'sslverify' => false,
719 - );
720 - // Get the design assets from the cloud.
721 - $response = wp_remote_request( self::$externalApiEndpoints['cloud']['getDesignAssets']['url'], $request_args );
722 - // Bail in case of decode error or failure to retrieve data.
723 - // We will return the data already available.
724 - if ( is_wp_error( $response ) ) {
725 - return $data;
726 - }
727 - $response_data = json_decode( wp_remote_retrieve_body( $response ), true );
728 - // Bail in case of decode error or failure to retrieve data.
729 - // We will return the data already available.
730 - if ( null === $response_data || empty( $response_data['data'] ) || empty( $response_data['code'] ) || 'success' !== $response_data['code'] ) {
731 - return $data;
732 - }
733 -
734 - $data = apply_filters( 'customify_style_manager_fetch_design_assets', $response_data['data'] );
735 -
736 - // Cache the data in an option for 6 hours
737 - update_option( $this->_get_design_assets_cache_key() , $data, true );
738 - update_option( $this->_get_design_assets_cache_key() . '_timestamp' , time() + 6 * HOUR_IN_SECONDS, true );
539 + public function maybe_add_text_after_color_palettes_customize_controls( $control ) {
540 + if ( 'sm_coloration_level' === $control->setting->id && in_array( self::get_theme_type(), array( 'theme_wporg', 'theme_modular_wporg' ) ) ) { ?>
541 + <li id="customize-control-sm_customize_description_after_control" class="pix_customizer_setting customize-control customize-control-html" style="display: list-item;">
542 + <span class="description customize-control-description"><strong>More options</strong> are available with the PRO version of your theme.</span>
543 + </li>
544 + <?php }
739 545 }
740 546
741 - return $data;
742 - }
547 + /**
548 + * Filter the final config.
549 + *
550 + * @param array $config
551 + *
552 + * @return array
553 + */
554 + public function filter_based_on_theme_type( $config ) {
555 + if ( ! empty( $config['panels']['style_manager_panel']['sections']['sm_color_palettes_section']['options'] ) && in_array( self::get_theme_type(), array(
556 + 'theme_wporg',
557 + 'theme_modular_wporg'
558 + ) ) ) {
559 + $color_palettes_options = $config['panels']['style_manager_panel']['sections']['sm_color_palettes_section']['options'];
743 560
744 - /**
745 - * Get the design assets cache key.
746 - *
747 - * @since 1.7.0
748 - *
749 - * @return string
750 - */
751 - protected function _get_design_assets_cache_key() {
752 - return 'customify_style_manager_design_assets';
753 - }
561 + $options_to_remove = array(
562 + 'sm_color_diversity',
563 + 'sm_shuffle_colors',
564 + 'sm_dark_mode',
565 + );
566 + foreach ( $options_to_remove as $option_key ) {
567 + if ( isset( $color_palettes_options[ $option_key ] ) ) {
568 + $color_palettes_options[ $option_key ]['type'] = 'hidden_control';
569 + }
570 + }
754 571
755 - /**
756 - * Get the default (hard-coded) color palettes configuration.
757 - *
758 - * @since 1.7.0
759 - *
760 - * @return array
761 - */
762 - protected function get_default_color_palettes_config() {
763 - $default_color_palettes = array(
764 - 'vasco' => array(
765 - 'label' => esc_html__( 'Restful Beach', 'customify' ),
766 - 'preview' => array(
767 - 'background_image_url' => 'http://pxgcdn.com/images/style-manager/color-palettes/vasco-theme-palette.jpg',
768 - ),
769 - 'options' => array(
770 - 'sm_color_primary' => '#38C3C8',
771 - 'sm_color_secondary' => '#F59828',
772 - 'sm_color_tertiary' => '#FB551C',
773 - 'sm_dark_primary' => '#2b2b28',
774 - 'sm_dark_secondary' => '#2B3D39',
775 - 'sm_dark_tertiary' => '#65726F',
776 - 'sm_light_primary' => '#F5F6F1',
777 - 'sm_light_secondary' => '#E6F7F7',
778 - 'sm_light_tertiary' => '#FAEDE8',
779 - ),
780 - ),
781 - 'felt' => array(
782 - 'label' => esc_html__( 'Warm Summer', 'customify' ),
783 - 'preview' => array(
784 - 'background_image_url' => 'http://pxgcdn.com/images/style-manager/color-palettes/felt-theme-palette.jpg',
785 - ),
786 - 'options' => array(
787 - 'sm_color_primary' => '#ff6000',
788 - 'sm_color_secondary' => '#FF9200',
789 - 'sm_color_tertiary' => '#FF7019',
790 - 'sm_dark_primary' => '#1C1C1C',
791 - 'sm_dark_secondary' => '#161616',
792 - 'sm_dark_tertiary' => '#161616',
793 - 'sm_light_primary' => '#FFFCFC',
794 - 'sm_light_secondary' => '#FFF4E8',
795 - 'sm_light_tertiary' => '#F7F3F0',
796 - ),
797 - ),
798 - 'julia' => array(
799 - 'label' => esc_html__( 'Serenity', 'customify' ),
800 - 'preview' => array(
801 - 'background_image_url' => 'http://pxgcdn.com/images/style-manager/color-palettes/julia-theme-palette.jpg',
802 - ),
803 - 'options' => array(
804 - 'sm_color_primary' => '#3349B8',
805 - 'sm_color_secondary' => '#3393B8',
806 - 'sm_color_tertiary' => '#C18866',
807 - 'sm_dark_primary' => '#161616',
808 - 'sm_dark_secondary' => '#383C50',
809 - 'sm_dark_tertiary' => '#383C50',
810 - 'sm_light_primary' => '#f7f6f5',
811 - 'sm_light_secondary' => '#E7F2F8',
812 - 'sm_light_tertiary' => '#F7ECE6',
813 - ),
814 - ),
815 - 'gema' => array(
816 - 'label' => esc_html__( 'Burning Red', 'customify' ),
817 - 'preview' => array(
818 - 'background_image_url' => 'http://pxgcdn.com/images/style-manager/color-palettes/gema-theme-palette.jpg',
819 - ),
820 - 'options' => array(
821 - 'sm_color_primary' => '#E03A3A',
822 - 'sm_color_secondary' => '#F75034',
823 - 'sm_color_tertiary' => '#AD2D2D',
824 - 'sm_dark_primary' => '#000000',
825 - 'sm_dark_secondary' => '#000000',
826 - 'sm_dark_tertiary' => '#A3A3A1',
827 - 'sm_light_primary' => '#FFFFFF',
828 - 'sm_light_secondary' => '#F7F5F5',
829 - 'sm_light_tertiary' => '#F7F2F2',
830 - ),
831 - ),
832 - 'patch' => array(
833 - 'label' => esc_html__( 'Fresh Lemon', 'customify' ),
834 - 'preview' => array(
835 - 'background_image_url' => 'http://pxgcdn.com/images/style-manager/color-palettes/patch-theme-palette.jpg',
836 - ),
837 - 'options' => array(
838 - 'sm_color_primary' => '#ffeb00',
839 - 'sm_color_secondary' => '#19CDFF',
840 - 'sm_color_tertiary' => '#0BE8DD',
841 - 'sm_dark_primary' => '#171617',
842 - 'sm_dark_secondary' => '#3d3e40',
843 - 'sm_dark_tertiary' => '#b5b5b5',
844 - 'sm_light_primary' => '#FFFFFF',
845 - 'sm_light_secondary' => '#E8FAFF',
846 - 'sm_light_tertiary' => '#F2FFFE',
847 - ),
848 - ),
849 - 'silk' => array(
850 - 'label' => esc_html__( 'Floral Bloom', 'customify' ),
851 - 'preview' => array(
852 - 'background_image_url' => 'http://pxgcdn.com/images/style-manager/color-palettes/silk-theme-palette.jpg',
853 - ),
854 - 'options' => array(
855 - 'sm_color_primary' => '#A33B61',
856 - 'sm_color_secondary' => '#FCC9B0',
857 - 'sm_color_tertiary' => '#C9648A',
858 - 'sm_dark_primary' => '#000000',
859 - 'sm_dark_secondary' => '#000000',
860 - 'sm_dark_tertiary' => '#A3A3A1',
861 - 'sm_light_primary' => '#FFFFFF',
862 - 'sm_light_secondary' => '#F7F5F6',
863 - 'sm_light_tertiary' => '#F7F0F3',
864 - ),
865 - ),
866 - 'hive' => array(
867 - 'label' => esc_html__( 'Powerful', 'customify' ),
868 - 'preview' => array(
869 - 'background_image_url' => 'http://pxgcdn.com/images/style-manager/color-palettes/hive-theme-palette.jpg',
870 - ),
871 - 'options' => array(
872 - 'sm_color_primary' => '#ffeb00',
873 - 'sm_color_secondary' => '#3200B2',
874 - 'sm_color_tertiary' => '#740AC9',
875 - 'sm_dark_primary' => '#171617',
876 - 'sm_dark_secondary' => '#171617',
877 - 'sm_dark_tertiary' => '#363636',
878 - 'sm_light_primary' => '#FFFFFF',
879 - 'sm_light_secondary' => '#F2F5F7',
880 - 'sm_light_tertiary' => '#F5F2F7',
881 - ),
882 - ),
883 - 'lilac' => array(
884 - 'label' => esc_html__( 'Soft Lilac', 'customify' ),
885 - 'preview' => array(
886 - 'background_image_url' => 'http://pxgcdn.com/images/style-manager/color-palettes/lilac-palette.jpg',
887 - ),
888 - 'options' => array(
889 - 'sm_color_primary' => '#DD8CA9',
890 - 'sm_color_secondary' => '#8C9CDE',
891 - 'sm_color_tertiary' => '#E3B4A6',
892 - 'sm_dark_primary' => '#1A1A1A',
893 - 'sm_dark_secondary' => '#303030',
894 - 'sm_dark_tertiary' => '#A3A3A1',
895 - 'sm_light_primary' => '#F0F2F1',
896 - 'sm_light_secondary' => '#CED5F2',
897 - 'sm_light_tertiary' => '#F7E1DA',
898 - ),
899 - ),
900 - );
572 + if ( ! empty( $color_palettes_options['sm_palette_filter']['choices'] ) ) {
573 + unset( $color_palettes_options['sm_palette_filter']['choices']['clarendon'] );
574 + unset( $color_palettes_options['sm_palette_filter']['choices']['pastel'] );
575 + unset( $color_palettes_options['sm_palette_filter']['choices']['greyish'] );
576 + }
901 577
902 - return apply_filters( 'customify_style_manager_default_color_palettes', $default_color_palettes );
903 - }
578 + $config['panels']['style_manager_panel']['sections']['sm_color_palettes_section']['options'] = $color_palettes_options;
579 + }
904 580
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;
581 + return $config;
920 582 }
921 583
922 - $file = trailingslashit( $theme->get_template_directory() ) . $file_name;
923 - if ( ! file_exists( $file ) ) {
924 - return $design_assets;
925 - }
584 + /**
585 + * Get the current theme type from the WUpdates code.
586 + *
587 + * Generally, this is a 'theme', but it could also be 'plugin', 'theme_modular', 'theme_wporg' or other markers we wish to use.
588 + *
589 + * @return string
590 + */
591 + public static function get_theme_type() {
592 + $wupdates_identification = self::get_wupdates_identification_data();
593 + if ( empty( $wupdates_identification['type'] ) ) {
594 + return 'theme_wporg';
595 + }
926 596
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;
597 + return sanitize_title( $wupdates_identification['type'] );
935 598 }
936 599
937 - // Construct the pseudo-external theme config.
938 - // Start with a clean slate.
939 - $design_assets['theme_configs'] = array();
600 + public static function get_wupdates_identification_data( $slug = '' ) {
601 + if ( empty( $slug ) ) {
602 + $slug = basename( get_template_directory() );
603 + }
940 604
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 - );
605 + $wupdates_ids = self::get_all_wupdates_identification_data();
952 606
953 - return $design_assets;
954 - }
607 + // We really want an id (hash_id) and a type.
608 + if ( empty( $slug ) || empty( $wupdates_ids[ $slug ] ) || ! isset( $wupdates_ids[ $slug ]['id'] ) || ! isset( $wupdates_ids[ $slug ]['type'] ) ) {
609 + return false;
610 + }
955 611
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;
612 + return $wupdates_ids[ $slug ];
964 613 }
965 - }
966 614
967 - /**
968 - * Get the active theme data.
969 - *
970 - * @since 1.7.0
971 - *
972 - * @return array
973 - */
974 - public function get_active_theme_data() {
975 - $theme_data = array();
615 + public static function get_all_wupdates_identification_data() {
616 + if ( empty( self::$wupdates_ids ) ) {
617 + self::$wupdates_ids = apply_filters( 'wupdates_gather_ids', array() );
618 + }
976 619
977 - $slug = basename( get_template_directory() );
978 -
979 - $theme_data['slug'] = $slug;
980 -
981 - // Get the current theme style.css data.
982 - $current_theme = wp_get_theme( get_template() );
983 - if ( ! empty( $current_theme ) && ! is_wp_error( $current_theme ) ) {
984 - $theme_data['name'] = $current_theme->get('Name');
985 - $theme_data['themeuri'] = $current_theme->get('ThemeURI');
986 - $theme_data['version'] = $current_theme->get('Version');
987 - $theme_data['textdomain'] = $current_theme->get('TextDomain');
620 + return self::$wupdates_ids;
988 621 }
989 622
990 - // Maybe get the WUpdates theme info if it's a theme delivered from WUpdates.
991 - $wupdates_ids = apply_filters( 'wupdates_gather_ids', array() );
992 - if ( ! empty( $wupdates_ids[ $slug ] ) ) {
993 - $theme_data['wupdates'] = $wupdates_ids[ $slug ];
994 - }
623 + /**
624 + * Reorganizes sections and controls added directly to WP_Customizer, not through the config.
625 + *
626 + * @param WP_Customize_Manager $wp_customize
627 + *
628 + * @since 1.9.0
629 + *
630 + * @todo Please note that this is house cleaning and it is only necessary due to the lack of complete standardization on the theme side. We should not need this forever!
631 + *
632 + */
633 + public function reorganize_direct_sections_and_controls( $wp_customize ) {
634 + // If there is no style manager support, bail.
635 + if ( ! $this->is_supported() ) {
636 + return;
637 + }
995 638
996 - return apply_filters( 'customify_style_manager_get_theme_data', $theme_data );
997 - }
639 + $theme_options_panel = $wp_customize->get_panel( 'theme_options_panel' );
640 + // Bail if we don't have a Theme Options panel since all that we do at the moment is related to it.
641 + if ( empty( $theme_options_panel ) ) {
642 + return;
643 + }
998 644
999 - /**
1000 - * Get the site data.
1001 - *
1002 - * @since 1.7.0
1003 - *
1004 - * @return array
1005 - */
1006 - public function get_site_data() {
1007 - $site_data = array(
1008 - 'url' => home_url('/'),
1009 - 'is_ssl' => is_ssl(),
1010 - );
645 + /** @var WP_Customize_Section $section */
646 + foreach ( $wp_customize->sections() as $section ) {
647 + // These are general theme options sections that need to have their controls moved to the Theme Options > General section.
648 + if ( false !== strpos( $section->id, 'theme_options' ) ) {
649 + // Find the General theme options section, if any.
650 + $general_section = false;
651 + foreach ( $theme_options_panel->sections as $theme_options_section ) {
652 + if ( false !== strpos( $theme_options_section->id, 'general' ) ) {
653 + $general_section = $section;
654 + }
655 + }
1011 656
1012 - $site_data['wp'] = array(
1013 - 'version' => get_bloginfo('version'),
1014 - );
657 + if ( false === $general_section ) {
658 + // We need to add a general section in the Theme Options panel.
659 + $general_section = $wp_customize->add_section( 'theme_options[general]', array(
660 + 'title' => esc_html__( 'General', 'customify' ),
661 + 'panel' => $theme_options_panel->id,
662 + 'priority' => 2,
663 + ) );
664 + }
1015 665
1016 - $site_data['customify'] = array(
1017 - 'version' => PixCustomifyPlugin()->get_version(),
1018 - );
666 + // Move all the controls in the identified theme options section to the general one.
667 + /** @var WP_Customize_Control $control */
668 + foreach ( $wp_customize->controls() as $control ) {
669 + if ( $control->section !== $section->id ) {
670 + continue;
671 + }
1019 672
1020 - $site_data['color_palettes'] = array(
1021 - 'current' => $this->get_current_color_palette(),
1022 - 'variation' => $this->get_current_color_palette_variation(),
1023 - 'custom' => $this->is_using_custom_color_palette(),
1024 - );
673 + $control->section = $general_section->id;
674 + }
1025 675
1026 - return apply_filters( 'customify_style_manager_get_site_data', $site_data );
1027 - }
676 + // Finally remove the now empty section.
677 + $wp_customize->remove_section( $section->id );
1028 678
1029 - /**
1030 - * Get the current color palette ID or false if none is selected.
1031 - *
1032 - * @since 1.7.0
1033 - *
1034 - * @return string|false
1035 - */
1036 - protected function get_current_color_palette() {
1037 - return get_option( 'sm_color_palette', false );
1038 - }
1039 -
1040 - /**
1041 - * Get the current color palette variation ID or false if none is selected.
1042 - *
1043 - * @since 1.7.0
1044 - *
1045 - * @return string|false
1046 - */
1047 - protected function get_current_color_palette_variation() {
1048 - return get_option( 'sm_color_palette_variation', false );
1049 - }
1050 -
1051 - /**
1052 - * Determine if the selected color palette has been customized and remember this in an option.
1053 - *
1054 - * @since 1.7.0
1055 - *
1056 - * @return bool
1057 - */
1058 - public function update_custom_palette_in_use() {
1059 - // If there is no style manager support, bail early.
1060 - if ( ! $this->is_supported() ) {
1061 - return false;
679 + break;
680 + }
681 + }
1062 682 }
1063 683
1064 - $current_palette = $this->get_current_color_palette();
1065 - if ( empty( $current_palette ) ) {
1066 - return false;
1067 - }
684 + /**
685 + * Remove the switch/preview theme panel.
686 + *
687 + * @param WP_Customize_Manager $wp_customize
688 + *
689 + * @since 1.7.4
690 + *
691 + */
692 + public function remove_switch_theme_panel( $wp_customize ) {
693 + // If there is no style manager support, bail.
694 + if ( ! $this->is_supported() ) {
695 + return;
696 + }
1068 697
1069 - $color_palettes = $this->get_color_palettes();
1070 - if ( ! isset( $color_palettes[ $current_palette ] ) || empty( $color_palettes[ $current_palette ]['options'] ) ) {
1071 - return false;
698 + $wp_customize->remove_panel( 'themes' );
1072 699 }
1073 700
1074 - $is_custom_palette = false;
1075 - // If any of the current master colors has a different value than the one provided by the color palette,
1076 - // it means a custom color palette is in use.
1077 - $current_palette_options = $color_palettes[ $current_palette ]['options'];
1078 - foreach ( $current_palette_options as $setting_id => $value ) {
1079 - if ( $value != get_option( $setting_id ) ) {
1080 - $is_custom_palette = true;
1081 - break;
701 + /**
702 + * Add data to be available in JS.
703 + *
704 + * @since 2.7.0
705 + *
706 + * @param $localized
707 + *
708 + * @return mixed
709 + */
710 + public function add_to_localized_data( $localized ) {
711 + if ( empty( $localized['styleManager'] ) ) {
712 + $localized['styleManager'] = array();
1082 713 }
1083 - }
1084 714
1085 - update_option( 'sm_is_custom_color_palette', $is_custom_palette, true );
715 + $localized['styleManager']['userFeedback'] = array(
716 + 'nonce' => wp_create_nonce( 'customify_style_manager_user_feedback' ),
717 + 'provided' => get_option( 'style_manager_user_feedback_provided', false ),
718 + );
1086 719
1087 - do_action( 'customify_style_manager_updated_custom_palette_in_use', $is_custom_palette, $this );
720 + return $localized;
721 + }
1088 722
1089 - return true;
1090 - }
1091 -
1092 - /**
1093 - * Determine if a custom color palette is in use.
1094 - *
1095 - * @since 1.7.0
1096 - *
1097 - * @return bool
1098 - */
1099 - protected function is_using_custom_color_palette(){
1100 - return (bool) get_option( 'sm_is_custom_color_palette', false );
1101 - }
1102 -
1103 - /**
1104 - * Get all the defined Style Manager master color field ids.
1105 - *
1106 - * @since 1.7.0
1107 - *
1108 - * @param array $options
1109 - * @return array
1110 - */
1111 - public function get_all_master_color_controls_ids( $options ) {
1112 - $master_color_controls = array();
1113 -
1114 - foreach ( $options as $option_id => $option_settings ) {
1115 - if ( 'color' === $option_settings['type'] ) {
1116 - $master_color_controls[] = $option_id;
723 + /**
724 + * Output the user feedback modal markup, if we need to.
725 + *
726 + * @since 1.7.0
727 + */
728 + public function output_user_feedback_modal() {
729 + // If there is no style manager support, bail early.
730 + if ( ! $this->is_supported() ) {
731 + return;
1117 732 }
1118 - }
1119 733
1120 - return $master_color_controls;
1121 - }
734 + // We want to ask for feedback once a month.
735 + $a_month_back = time() - MONTH_IN_SECONDS;
1122 736
1123 - /**
1124 - * Output the user feedback modal markup, if we need to.
1125 - *
1126 - * @since 1.7.0
1127 - */
1128 - public function output_user_feedback_modal() {
1129 - // If there is no style manager support, bail early.
1130 - if ( ! $this->is_supported() ) {
1131 - return;
1132 - }
1133 -
1134 - // Only output if the user didn't provide feedback.
1135 - if ( ! $this->user_provided_feedback() ) { ?>
1136 - <div id="style-manager-user-feedback-modal">
1137 - <div class="modal">
1138 - <div class="modal-dialog" role="document">
1139 - <div class="modal-content">
1140 - <form id="style-manager-user-feedback" action="#" method="post">
1141 - <input type="hidden" name="type" value="1_to_5" />
1142 - <div class="modal-header">
1143 - <button type="button" class="close icon media-modal-close" data-dismiss="modal" aria-label="Close"><span class="media-modal-icon"><span class="screen-reader-text">Close media panel</span></span></button>
1144 - <!-- <a href="#" class="close button button--naked gray" data-dismiss="modal" aria-label="Close">Close</a> -->
1145 - </div>
1146 - <div class="modal-body full">
1147 - <div class="box box--large">
1148 - <div class="first-step">
1149 - <h2 class="modal-title">How would you rate your experience with using Color Palettes?</h2>
1150 - <div class="scorecard">
1151 - <span>Worst</span>
1152 - <label>
1153 - <input type="radio" name="rating" value="1" required />
1154 - <span>1</span>
1155 - </label>
1156 - <label>
1157 - <input type="radio" name="rating" value="2" required />
1158 - <span>2</span>
1159 - </label>
1160 - <label>
1161 - <input type="radio" name="rating" value="3" required />
1162 - <span>3</span>
1163 - </label>
1164 - <label>
1165 - <input type="radio" name="rating" value="4" required />
1166 - <span>4</span>
1167 - </label>
1168 - <label>
1169 - <input type="radio" name="rating" value="5" required />
1170 - <span>5</span>
1171 - </label>
1172 - <span>Best</span>
737 + // Only output if we should ask for feedback.
738 + if ( $this->should_ask_for_feedback( $a_month_back ) ) { ?>
739 + <div id="style-manager-user-feedback-modal">
740 + <div class="modal">
741 + <div class="modal-dialog" role="document">
742 + <div class="modal-content">
743 + <form id="style-manager-user-feedback" action="#" method="post">
744 + <input type="hidden" name="type" value="1_to_5"/>
745 + <div class="modal-header">
746 + <button type="button" class="close icon media-modal-close" data-dismiss="modal"
747 + aria-label="Close"><span class="media-modal-icon"><span
748 + class="screen-reader-text">Close media panel</span></span></button>
749 + <!-- <a href="#" class="close button button--naked gray" data-dismiss="modal" aria-label="Close">Close</a> -->
750 + </div>
751 + <div class="modal-body full">
752 + <div class="box box--large">
753 + <div class="first-step">
754 + <h2 class="modal-title">How would you rate your experience in finding the right colors for your site?</h2>
755 + <div class="scorecard">
756 + <span>Poor</span>
757 + <label>
758 + <input type="radio" name="rating" value="1" required/>
759 + <span>1</span>
760 + </label>
761 + <label>
762 + <input type="radio" name="rating" value="2" required/>
763 + <span>2</span>
764 + </label>
765 + <label>
766 + <input type="radio" name="rating" value="3" required/>
767 + <span>3</span>
768 + </label>
769 + <label>
770 + <input type="radio" name="rating" value="4" required/>
771 + <span>4</span>
772 + </label>
773 + <label>
774 + <input type="radio" name="rating" value="5" required/>
775 + <span>5</span>
776 + </label>
777 + <span>Great</span>
778 + </div>
1173 779 </div>
1174 - </div>
1175 - <div class="second-step hidden">
1176 - <p><strong>What makes you give <span class="rating-placeholder">5</span>*?</strong> I hope you’ll answer and help us do better:</p>
1177 - <div class="not-floating-labels">
1178 - <div class="form-row field">
1179 - <textarea name="message" placeholder="Your message.."
1180 - id="style-manager-user-feedback-message" rows="4" oninvalid="this.setCustomValidity('May we have a little more info about your experience?')" oninput="setCustomValidity('')" required></textarea>
780 + <div class="second-step hidden">
781 + <p><strong>What points along the way made this a <span
782 + class="rating-placeholder">5</span>* experience for
783 + you?</strong><br>We are counting on your insights to guide us in
784 + doing better 🙏</p>
785 + <div class="not-floating-labels">
786 + <div class="form-row field">
787 + <textarea name="message"
788 + placeholder="Describe your experience in customizing your site colors.."
789 + id="style-manager-user-feedback-message" rows="6"
790 + oninvalid="this.setCustomValidity('May we have a little more info about your experience?')"
791 + oninput="setCustomValidity('')" required></textarea>
792 + </div>
1181 793 </div>
794 + <button id="style-manager-user-feedback_btn" class="button"
795 + type="submit"><?php _e( 'Send us your insights', 'customify' ); ?></button>
1182 796 </div>
1183 - <button id="style-manager-user-feedback_btn" class="button" type="submit"><?php _e( 'Submit my feedback', 'customify' ); ?></button>
797 + <div class="thanks-step hidden">
798 + <h3 class="modal-title">Thank you so much for your feedback!</h3>
799 + <p>It means the world to us as we strive to constantly push the limits
800 + and aim higher. Stay awesome! 🤗</p>
801 + <p><em>The Pixelgrade Team</em></p>
802 + </div>
803 + <div class="error-step hidden">
804 + <h3 class="modal-title">We've hit a snag!</h3>
805 + <p>We couldn't record your feedback and we would truly appreciate it if
806 + you would try it again at a latter time. Stay awesome! 🤗</p>
807 + </div>
1184 808 </div>
1185 - <div class="thanks-step hidden">
1186 - <h3 class="modal-title">Thanks for your feedback!</h3>
1187 - <p>This will help us improve the product. Stay awesome! 🤗</p>
1188 - </div>
1189 - <div class="error-step hidden">
1190 - <h3 class="modal-title">We've hit a snag!</h3>
1191 - <p>We couldn't record your feedback and we would truly appreciate it if you would try it again at a latter time. Stay awesome! 🤗</p>
1192 - </div>
1193 809 </div>
1194 - </div>
1195 - <div class="modal-footer full">
810 + <div class="modal-footer full">
1196 811
1197 - </div>
1198 - </form>
812 + </div>
813 + </form>
814 + </div>
1199 815 </div>
1200 816 </div>
817 + <!-- End Modal -->
818 + <!-- Modal Backdrop (Shadow) -->
819 + <div class="modal-backdrop"></div>
1201 820 </div>
1202 - <!-- End Modal -->
1203 - <!-- Modal Backdrop (Shadow) -->
1204 - <div class="modal-backdrop"></div>
1205 - </div>
1206 821
1207 - <?php }
1208 - }
822 + <?php }
823 + }
1209 824
1210 - /**
1211 - * @param bool|int $timestamp_limit Optional. Timestamp to compare the time the user provided feedback.
1212 - * If the provided timestamp is earlier than the time the user provided feedback, returns false.
1213 - *
1214 - * @return bool
1215 - */
1216 - public function user_provided_feedback( $timestamp_limit = false ) {
1217 - if ( defined( 'CUSTOMIFY_SM_ALWAYS_ASK_FOR_FEEDBACK' ) && true === CUSTOMIFY_SM_ALWAYS_ASK_FOR_FEEDBACK ) {
1218 - return false;
825 + /**
826 + * Return whether user provided feedback, and if so, return the timestamp.
827 + *
828 + * @return bool|int
829 + */
830 + public function user_provided_feedback() {
831 + $user_provided_feedback = get_option( 'style_manager_user_feedback_provided' );
832 + if ( empty( $user_provided_feedback ) ) {
833 + return false;
834 + }
835 +
836 + return $user_provided_feedback;
1219 837 }
1220 838
1221 - $user_provided_feedback = get_option( 'style_manager_user_feedback_provided' );
1222 - if ( empty( $user_provided_feedback ) ) {
839 + /**
840 + * Determine if we should ask for user feedback.
841 + *
842 + * @param bool|int $timestamp_limit Optional. Timestamp to compare the time the user provided feedback.
843 + * If the provided timestamp is earlier than the time the user provided feedback, should ask again.
844 + *
845 + * @return bool
846 + */
847 + public function should_ask_for_feedback( $timestamp_limit = false ) {
848 + if ( defined( 'CUSTOMIFY_SM_ALWAYS_ASK_FOR_FEEDBACK' ) && true === CUSTOMIFY_SM_ALWAYS_ASK_FOR_FEEDBACK ) {
849 + return true;
850 + }
851 +
852 + $feedback_timestamp = $this->user_provided_feedback();
853 + if ( empty( $feedback_timestamp ) ) {
854 + return true;
855 + }
856 +
857 + if ( ! empty( $timestamp_limit ) && intval( $timestamp_limit ) > intval( $feedback_timestamp ) ) {
858 + return true;
859 + }
860 +
1223 861 return false;
1224 862 }
1225 863
1226 - if ( ! empty( $timestamp ) && is_int( $timestamp ) && $timestamp_limit > $user_provided_feedback ) {
1227 - return false;
1228 - }
864 + /**
865 + * Callback for the user feedback AJAX call.
866 + *
867 + * @since 1.7.0
868 + */
869 + public function user_feedback_callback() {
870 + check_ajax_referer( 'customify_style_manager_user_feedback', 'nonce' );
1229 871
1230 - return true;
1231 - }
872 + if ( empty( $_POST['type'] ) ) {
873 + wp_send_json_error( esc_html__( 'No type provided', 'customify' ) );
874 + }
1232 875
1233 - /**
1234 - * Callback for the user feedback AJAX call.
1235 - *
1236 - * @since 1.7.0
1237 - */
1238 - public function user_feedback_callback() {
1239 - check_ajax_referer( 'customify_style_manager_user_feedback', 'nonce' );
876 + if ( empty( $_POST['rating'] ) ) {
877 + wp_send_json_error( esc_html__( 'No rating provided', 'customify' ) );
878 + }
1240 879
1241 - if ( empty( $_POST['type'] ) ) {
1242 - wp_send_json_error( esc_html__( 'No type provided', 'customify' ) );
1243 - }
880 + $type = sanitize_text_field( $_POST['type'] );
881 + $rating = intval( $_POST['rating'] );
882 + $message = '';
883 + if ( ! empty( $_POST['message'] ) ) {
884 + $message = wp_kses_post( $_POST['message'] );
885 + }
1244 886
1245 - if ( empty( $_POST['rating'] ) ) {
1246 - wp_send_json_error( esc_html__( 'No rating provided', 'customify' ) );
1247 - }
887 + $request_data = array(
888 + 'site_url' => home_url( '/' ),
889 + 'satisfaction_data' => array(
890 + 'type' => $type,
891 + 'rating' => $rating,
892 + 'message' => $message,
893 + ),
894 + );
1248 895
1249 - $type = sanitize_text_field( $_POST['type'] );
1250 - $rating = intval( $_POST['rating'] );
1251 - $message = '';
1252 - if ( ! empty( $_POST['message'] ) ) {
1253 - $message = wp_kses_post( $_POST['message'] );
1254 - }
896 + // Send the feedback.
897 + $response = $this->cloud_api->send_stats( $request_data, true );
898 + if ( is_wp_error( $response ) ) {
899 + wp_send_json_error( esc_html__( 'Sorry, something went wrong and we couldn\'t save your feedback.', 'customify' ) );
900 + }
901 + $response_data = json_decode( wp_remote_retrieve_body( $response ), true );
902 + // Bail in case of decode error or failure to retrieve data
903 + if ( null === $response_data || empty( $response_data['code'] ) || 'success' !== $response_data['code'] ) {
904 + wp_send_json_error( esc_html__( 'Sorry, something went wrong and we couldn\'t save your feedback.', 'customify' ) );
905 + }
1255 906
1256 - $request_data = apply_filters( 'customify_pixelgrade_cloud_request_data', array(
1257 - 'site_url' => home_url( '/' ),
1258 - 'satisfaction_data' => array(
1259 - 'type' => $type,
1260 - 'rating' => $rating,
1261 - 'message' => $message,
1262 - ),
1263 - ), $this );
907 + // We need to remember that the user provided feedback (and at what timestamp).
908 + update_option( 'style_manager_user_feedback_provided', time(), true );
1264 909
1265 - $request_args = array(
1266 - 'method' => self::$externalApiEndpoints['cloud']['stats']['method'],
1267 - 'timeout' => 5,
1268 - 'blocking' => true,
1269 - 'body' => $request_data,
1270 - 'sslverify' => false,
1271 - );
1272 -
1273 - // Send the feedback.
1274 - $response = wp_remote_request( self::$externalApiEndpoints['cloud']['stats']['url'], $request_args );
1275 - if ( is_wp_error( $response ) ) {
1276 - wp_send_json_error( esc_html__( 'Sorry, something went wrong and we couldn\'t save your feedback.', 'customify' ) );
910 + wp_send_json_success( esc_html__( 'Thank you for your feedback.', 'customify' ) );
1277 911 }
1278 - $response_data = json_decode( wp_remote_retrieve_body( $response ), true );
1279 - // Bail in case of decode error or failure to retrieve data
1280 - if ( null === $response_data || empty( $response_data['code'] ) || 'success' !== $response_data['code'] ) {
1281 - wp_send_json_error( esc_html__( 'Sorry, something went wrong and we couldn\'t save your feedback.', 'customify' ) );
1282 - }
1283 912
1284 - // We need to remember that the user provided feedback (and at what timestamp).
1285 - update_option( 'style_manager_user_feedback_provided', time(), true );
913 + /**
914 + * Main Customify_Style_Manager Instance
915 + *
916 + * Ensures only one instance of Customify_Style_Manager is loaded or can be loaded.
917 + *
918 + * @return Customify_Style_Manager Main Customify_Style_Manager instance
919 + * @since 1.7.0
920 + * @static
921 + *
922 + */
923 + public static function instance() {
1286 924
1287 - wp_send_json_success( esc_html__( 'Thank you for your feedback.', 'customify' ) );
1288 - }
925 + if ( is_null( self::$_instance ) ) {
926 + self::$_instance = new self();
927 + }
1289 928
1290 - /**
1291 - * Main Customify_Style_Manager Instance
1292 - *
1293 - * Ensures only one instance of Customify_Style_Manager is loaded or can be loaded.
1294 - *
1295 - * @since 1.7.0
1296 - * @static
1297 - * @param object $parent Main PixCustomifyPlugin instance.
1298 - *
1299 - * @return Customify_Style_Manager Main Customify_Style_Manager instance
1300 - */
1301 - public static function instance( $parent = null ) {
1302 -
1303 - if ( is_null( self::$_instance ) ) {
1304 - self::$_instance = new self( $parent );
929 + return self::$_instance;
1305 930 }
1306 - return self::$_instance;
1307 - } // End instance ()
1308 931
1309 - /**
1310 - * Cloning is forbidden.
1311 - *
1312 - * @since 1.7.0
1313 - */
1314 - public function __clone() {
932 + /**
933 + * Cloning is forbidden.
934 + *
935 + * @since 1.7.0
936 + */
937 + public function __clone() {
1315 938
1316 - _doing_it_wrong( __FUNCTION__,esc_html( __( 'Cheatin&#8217; huh?' ) ), null );
1317 - } // End __clone ()
939 + _doing_it_wrong( __FUNCTION__, esc_html__( 'You should not do that!', 'customify' ), null );
940 + }
1318 941
1319 - /**
1320 - * Unserializing instances of this class is forbidden.
1321 - *
1322 - * @since 1.7.0
1323 - */
1324 - public function __wakeup() {
942 + /**
943 + * Unserializing instances of this class is forbidden.
944 + *
945 + * @since 1.7.0
946 + */
947 + public function __wakeup() {
1325 948
1326 - _doing_it_wrong( __FUNCTION__, esc_html( __( 'Cheatin&#8217; huh?' ) ), null );
1327 - } // End __wakeup ()
949 + _doing_it_wrong( __FUNCTION__, esc_html__( 'You should not do that!', 'customify' ), null );
950 + }
951 + }
1328 952 }