PluginProbe
Customify / 2.2.0
Customify v2.2.0
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
customify / includes / class-customify-style-manager.php

class-customify-style-manager.php in Customify 2.2.0, at includes/class-customify-style-manager.php

737 lines 24.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 */
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit; // Exit if accessed directly
12 }
13
14 if ( ! class_exists( 'Customify_Style_Manager' ) ) :
15
16 class Customify_Style_Manager {
17
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;
25
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;
33
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;
41
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;
49
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
58 /**
59 * The notifications object.
60 * @var null|Pixcloud_Admin_Notifications_Manager
61 * @access public
62 * @since 1.9.0
63 */
64 protected $notifications = null;
65
66 /**
67 * The Cloud API object.
68 * @var null|Customify_Cloud_Api
69 * @access public
70 * @since 1.7.4
71 */
72 protected $cloud_api = null;
73
74 /**
75 * Constructor.
76 *
77 * @since 1.7.0
78 */
79 protected function __construct() {
80 $this->init();
81 }
82
83 /**
84 * Initialize this module.
85 *
86 * @since 1.7.4
87 */
88 public function init() {
89 /**
90 * Initialize the Themes Config logic.
91 */
92 require_once 'class-customify-theme-configs.php';
93 $this->theme_configs = Customify_Theme_Configs::instance();
94
95 /**
96 * Initialize the Color Palettes logic.
97 */
98 require_once 'class-customify-color-palettes.php';
99 $this->color_palettes = Customify_Color_Palettes::instance();
100
101 /**
102 * Initialize the Font Palettes logic.
103 */
104 require_once 'class-customify-font-palettes.php';
105 $this->font_palettes = Customify_Font_Palettes::instance();
106
107 /**
108 * Initialize the Notifications logic.
109 */
110 require_once 'admin-notifications-manager/class-admin-notifications-manager.php';
111 $this->notifications = Pixcloud_Admin_Notifications_Manager::instance(
112 array(
113 'plugin_name' => 'Customify',
114 'text_domain' => 'customify',
115 'version' => '',
116 )
117 );
118
119 /**
120 * Initialize the Cloud API logic.
121 */
122 require_once 'lib/class-customify-cloud-api.php';
123 $this->cloud_api = new Customify_Cloud_Api();
124
125 // Hook up.
126 $this->add_hooks();
127 }
128
129 /**
130 * Initiate our hooks
131 *
132 * @since 1.7.0
133 */
134 public function add_hooks() {
135 /*
136 * Handle the Customizer Style Manager base config.
137 */
138 add_filter( 'customify_filter_fields', array( $this, 'style_manager_section_base_config' ), 12, 1 );
139
140 /*
141 * Handle the grouping and reorganization of the Customizer theme sections when the Style Manager is active.
142 */
143 add_filter( 'customify_final_config', array( $this, 'reorganize_sections' ), 10, 1 );
144
145 /*
146 * Handle the logic for user feedback.
147 */
148 add_action( 'customize_controls_print_footer_scripts', array( $this, 'output_user_feedback_modal' ) );
149 add_action( 'wp_ajax_customify_style_manager_user_feedback', array( $this, 'user_feedback_callback' ) );
150
151 /*
152 * Scripts enqueued in the Customizer.
153 */
154 add_action( 'customize_controls_init', array( $this, 'register_admin_customizer_scripts' ), 10 );
155 add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_admin_customizer_scripts' ), 10 );
156 }
157
158 /**
159 * Register Customizer admin scripts.
160 */
161 function register_admin_customizer_scripts() {
162 wp_register_script( PixCustomifyPlugin()->get_slug() . '-style-manager', plugins_url( 'js/customizer/style-manager.js', PixCustomifyPlugin()->get_file() ), array( 'jquery' ), PixCustomifyPlugin()->get_version() );
163 }
164
165 /**
166 * Enqueue Customizer admin scripts
167 */
168 function enqueue_admin_customizer_scripts() {
169 // If there is no style manager support, bail early.
170 if ( ! $this->is_supported() ) {
171 return;
172 }
173
174 // Enqueue the needed scripts, already registered.
175 wp_enqueue_script( PixCustomifyPlugin()->get_slug() . '-style-manager' );
176 }
177
178 /**
179 * Determine if Style Manager is supported.
180 *
181 * @since 1.7.0
182 *
183 * @return bool
184 */
185 public function is_supported() {
186 $has_support = (bool) current_theme_supports( 'customizer_style_manager' );
187
188 return apply_filters( 'customify_style_manager_is_supported', $has_support );
189 }
190
191 /**
192 * Setup the Style Manager Customizer section base config.
193 *
194 * This handles the base configuration for the controls in the Style Manager section. We expect other parties (e.g. the theme),
195 * to come and fill up the missing details (e.g. connected fields).
196 *
197 * @since 1.7.0
198 *
199 * @param array $config This holds required keys for the plugin config like 'opt-name', 'panels', 'settings'
200 * @return array
201 */
202 public function style_manager_section_base_config( $config ) {
203 // If there is no style manager support, bail early.
204 if ( ! $this->is_supported() ) {
205 return $config;
206 }
207
208 if ( ! isset( $config['sections']['style_manager_section'] ) ) {
209 $config['sections']['style_manager_section'] = array();
210 }
211
212 // The section might be already defined, thus we merge, not replace the entire section config.
213 $config['sections']['style_manager_section'] = array_replace_recursive( $config['sections']['style_manager_section'], array(
214 'title' => esc_html__( 'Style Manager', 'customify' ),
215 'section_id' => 'style_manager_section', // We will force this section id preventing prefixing and other regular processing.
216 'priority' => 1,
217 'options' => array(),
218 ) );
219
220 return $config;
221 }
222
223 /**
224 * Reorganize the Customizer sections.
225 *
226 * @since 1.7.4
227 *
228 * @param array $config This holds required keys for the plugin config like 'opt-name', 'panels', 'settings'.
229 * @return array
230 */
231 public function reorganize_sections( $config ) {
232 // If there is no style manager support, bail early.
233 if ( ! $this->is_supported() ) {
234 return $config;
235 }
236
237 // If there is no Style Manager section or panel, bail.
238 if ( ! isset( $config['sections']['style_manager_section'] ) &&
239 ! isset( $config['panels']['style_manager_panel'] ) ) {
240
241 return $config;
242 }
243
244 $style_manager_section_config = false;
245 if ( isset( $config['sections']['style_manager_section'] ) ) {
246 $style_manager_section_config = $config['sections']['style_manager_section'];
247 unset( $config['sections']['style_manager_section'] );
248 }
249
250 // All the other sections.
251 $other_theme_sections_config = $config['sections'];
252 unset( $config['sections'] );
253
254 // The Style Manager panel.
255 if ( empty( $config['panels']['style_manager_panel'] ) ) {
256 $style_manager_panel_config = array(
257 'priority' => 22,
258 'capability' => 'edit_theme_options',
259 'panel_id' => 'style_manager_panel',
260 'title' => esc_html__( 'Style Manager', 'customify' ),
261 'description' => __( '<strong>Style Manager</strong> is an intuitive system to help you change the look of your website and make an excellent impression.', 'customify' ),
262 'sections' => array(),
263 'auto_expand_sole_section' => true, // If there is only one section in the panel, auto-expand it.
264 );
265 } else {
266 $style_manager_panel_config = $config['panels']['style_manager_panel'];
267 unset( $config['panels']['style_manager_panel'] );
268 }
269
270 $other_panels_config = false;
271 if ( ! empty( $config['panels'] ) ) {
272 $other_panels_config = $config['panels'];
273 unset( $config['panels'] );
274 }
275
276 // Maybe handle the color palettes.
277 if ( is_array( $style_manager_section_config ) && class_exists( 'Customify_Color_Palettes' ) && Customify_Color_Palettes::instance()->is_supported() ) {
278
279 // We need to split the fields in the Style Manager section into two: color palettes and fonts.
280 $color_palettes_fields = array(
281 'sm_current_color_palette',
282 'sm_palettes_description',
283 'sm_filters_description',
284 'sm_customize_description',
285 'sm_color_matrix',
286 'sm_palette_filter',
287 'sm_coloration_level',
288 'sm_color_diversity',
289 'sm_shuffle_colors',
290 'sm_dark_mode',
291 'sm_dark_color_master_slider',
292 'sm_dark_color_primary_slider',
293 'sm_dark_color_secondary_slider',
294 'sm_dark_color_tertiary_slider',
295 'sm_colors_dispersion',
296 'sm_colors_focus_point',
297 'sm_color_palette',
298 'sm_color_palette_variation',
299 'sm_color_primary',
300 'sm_color_primary_final',
301 'sm_color_secondary',
302 'sm_color_secondary_final',
303 'sm_color_tertiary',
304 'sm_color_tertiary_final',
305 'sm_dark_primary',
306 'sm_dark_primary_final',
307 'sm_dark_secondary',
308 'sm_dark_secondary_final',
309 'sm_dark_tertiary',
310 'sm_dark_tertiary_final',
311 'sm_light_primary',
312 'sm_light_primary_final',
313 'sm_light_secondary',
314 'sm_light_secondary_final',
315 'sm_light_tertiary',
316 'sm_light_tertiary_final',
317 'sm_swap_colors',
318 'sm_swap_dark_light',
319 'sm_swap_colors_dark',
320 'sm_swap_secondary_colors_dark',
321 'sm_advanced_toggle',
322 'sm_spacing_bottom',
323 );
324
325 $color_palettes_section_config = array(
326 'title' => esc_html__( 'Colors', 'customify' ),
327 'section_id' => 'sm_color_palettes_section',
328 'priority' => 10,
329 'options' => array(),
330 );
331 foreach ( $color_palettes_fields as $field_id ) {
332 if ( ! isset( $style_manager_section_config['options'][ $field_id ] ) ) {
333 continue;
334 }
335
336 if ( empty( $color_palettes_section_config['options'] ) ) {
337 $color_palettes_section_config['options'] = array( $field_id => $style_manager_section_config['options'][ $field_id ] );
338 } else {
339 $color_palettes_section_config['options'] = array_merge( $color_palettes_section_config['options'], array( $field_id => $style_manager_section_config['options'][ $field_id ] ) );
340 }
341 }
342
343 $style_manager_panel_config['sections']['sm_color_palettes_section'] = $color_palettes_section_config;
344 }
345
346 // Maybe handle the font palettes.
347 if ( is_array( $style_manager_section_config ) && class_exists( 'Customify_Font_Palettes' ) && Customify_Font_Palettes::instance()->is_supported() ) {
348
349 $font_palettes_fields = array(
350 'sm_font_palette',
351 'sm_font_palette_variation',
352 'sm_font_primary',
353 'sm_font_secondary',
354 'sm_font_body',
355 'sm_swap_fonts',
356 'sm_swap_primary_secondary_fonts',
357 );
358
359 $font_palettes_section_config = array(
360 'title' => esc_html__( 'Fonts', 'customify' ),
361 'section_id' => 'sm_font_palettes_section',
362 'priority' => 20,
363 'options' => array(),
364 );
365 foreach ( $font_palettes_fields as $field_id ) {
366 if ( ! isset( $style_manager_section_config['options'][ $field_id ] ) ) {
367 continue;
368 }
369
370 if ( empty( $font_palettes_section_config['options'] ) ) {
371 $font_palettes_section_config['options'] = array( $field_id => $style_manager_section_config['options'][ $field_id ] );
372 } else {
373 $font_palettes_section_config['options'] = array_merge( $font_palettes_section_config['options'], array( $field_id => $style_manager_section_config['options'][ $field_id ] ) );
374 }
375 }
376
377 $style_manager_panel_config['sections']['sm_font_palettes_section'] = $font_palettes_section_config;
378 }
379
380 // Start fresh and add the Style Manager panel config
381 if ( empty( $config['panels'] ) ) {
382 $config['panels'] = array();
383 }
384 $config['panels']['style_manager_panel'] = $style_manager_panel_config;
385
386 // The Theme Options panel.
387 $theme_options_panel_config = array(
388 'priority' => 23,
389 'capability' => 'edit_theme_options',
390 'panel_id' => 'theme_options_panel',
391 'title' => esc_html__( 'Theme Options', 'customify' ),
392 'description' => esc_html__( 'Advanced options to change your site look-and-feel on a detailed level.', 'customify' ),
393 'sections' => array(),
394 );
395
396 // If we have other panels we will make their sections parts of the Theme Options panel.
397 if ( ! empty( $other_panels_config ) ) {
398 // 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.
399 $second_theme_options_sections = array();
400 foreach ( $other_panels_config as $panel_id => $panel_config ) {
401 $found = false;
402 // First try the panel ID.
403 if ( false !== strpos( strtolower( str_replace( '-', '_', $panel_id ) ), 'theme_options' ) ) {
404 $found = true;
405 }
406
407 // Second, try the panel title.
408 if ( ! $found && ! empty( $panel_config['title'] ) && false !== strpos( strtolower( str_replace( array( '-', '_'), ' ', $panel_config['title'] ) ), ' theme options' ) ) {
409 $found = true;
410 }
411
412 if ( $found && ! empty( $panel_config['sections'] ) ) {
413 $second_theme_options_sections = array_merge( $second_theme_options_sections, $panel_config['sections'] );
414 unset( $other_panels_config[ $panel_id ] );
415 }
416 }
417 if ( ! empty( $second_theme_options_sections ) ) {
418 $theme_options_panel_config['sections'] = array_merge( $theme_options_panel_config['sections'], $second_theme_options_sections );
419 }
420
421 // For the remaining panels, we will put their section into the Theme Options panel, but prefix their title with their respective panel title.
422 $prefixed_sections = array();
423 foreach ( $other_panels_config as $panel_id => $panel_config ) {
424 if ( ! empty( $panel_config['sections'] ) ) {
425 foreach ( $panel_config['sections'] as $section_id => $section_config ) {
426 if ( ! empty( $section_config['title'] ) && ! empty( $panel_config['title'] ) ) {
427 $section_config['title'] = $panel_config['title'] . ' - ' . $section_config['title'];
428 }
429 $prefixed_sections[ $panel_id . '_' . $section_id ] = $section_config;
430 }
431 }
432 }
433 $theme_options_panel_config['sections'] = array_merge( $theme_options_panel_config['sections'], $prefixed_sections );
434 }
435
436 // If we have other sections we will add them to the Theme Options panel.
437 if ( ! empty( $other_theme_sections_config ) ) {
438 $theme_options_panel_config['sections'] = array_merge( $theme_options_panel_config['sections'], $other_theme_sections_config );
439 }
440
441 if ( empty( $config['panels']['theme_options_panel'] ) ) {
442 $config['panels']['theme_options_panel'] = $theme_options_panel_config;
443 } else {
444 $config['panels']['theme_options_panel'] = array_merge( $config['panels']['theme_options_panel'], $theme_options_panel_config );
445 }
446
447 // Add the logic that handles sections and controls added directly to WP_Customizer, not through the config.
448 add_action( 'customize_register', array( $this, 'reorganize_direct_sections_and_controls' ), 100 );
449
450 // Remove the switch theme panel from the Customizer.
451 add_action( 'customize_register', array( $this, 'remove_switch_theme_panel' ), 12 );
452
453 return $config;
454 }
455
456 /**
457 * Reorganizes sections and controls added directly to WP_Customizer, not through the config.
458 *
459 * @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!
460 *
461 * @since 1.9.0
462 *
463 * @param WP_Customize_Manager $wp_customize
464 */
465 public function reorganize_direct_sections_and_controls( $wp_customize ) {
466 // We will do out best to identify direct sections and move their controls to the appropriate place.
467 /** @var WP_Customize_Section $section */
468 foreach ( $wp_customize->sections() as $section ) {
469 // These are general theme options sections that need to have their controls moved to the Theme Options > General section.
470 if ( false !== strpos( $section->id, 'theme_options') ) {
471 $theme_options_panel = $wp_customize->get_panel( 'theme_options_panel' );
472 $general_section = false;
473 foreach ( $theme_options_panel->sections as $theme_options_section ) {
474 if ( false !== strpos( $theme_options_section->id, 'general' ) ) {
475 $general_section = $section;
476 }
477 }
478
479 if ( false === $general_section ) {
480 // We need to add a general section in the Theme Options panel.
481 $general_section = $wp_customize->add_section( 'theme_options[general]', array(
482 'title' => esc_html__( 'General', 'customify' ),
483 'panel' => $theme_options_panel->id,
484 'priority' => 2,
485 ) );
486 }
487
488 // Move all the controls in the identified theme options section to the general one.
489 /** @var WP_Customize_Control $control */
490 foreach ( $wp_customize->controls() as $control ) {
491 if ( $control->section !== $section->id ) {
492 continue;
493 }
494
495 $control->section = $general_section->id;
496 }
497
498 // Finally remove the now empty section.
499 $wp_customize->remove_section( $section->id );
500
501 break;
502 }
503 }
504 }
505
506 /**
507 * Remove the switch/preview theme panel.
508 *
509 * @since 1.7.4
510 *
511 * @param WP_Customize_Manager $wp_customize
512 */
513 public function remove_switch_theme_panel( $wp_customize ) {
514 $wp_customize->remove_panel( 'themes' );
515 }
516
517 /**
518 * Output the user feedback modal markup, if we need to.
519 *
520 * @since 1.7.0
521 */
522 public function output_user_feedback_modal() {
523 // If there is no style manager support, bail early.
524 if ( ! $this->is_supported() ) {
525 return;
526 }
527
528 // We want to ask for feedback once a month.
529 $a_month_back = time() - MONTH_IN_SECONDS;
530
531 // Only output if we should ask for feedback.
532 if ( $this->should_ask_for_feedback( $a_month_back ) ) { ?>
533 <div id="style-manager-user-feedback-modal">
534 <div class="modal">
535 <div class="modal-dialog" role="document">
536 <div class="modal-content">
537 <form id="style-manager-user-feedback" action="#" method="post">
538 <input type="hidden" name="type" value="1_to_5" />
539 <div class="modal-header">
540 <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>
541 <!-- <a href="#" class="close button button--naked gray" data-dismiss="modal" aria-label="Close">Close</a> -->
542 </div>
543 <div class="modal-body full">
544 <div class="box box--large">
545 <div class="first-step">
546 <h2 class="modal-title">How would you rate your experience in finding the right colors for your site?</h2>
547 <div class="scorecard">
548 <span>Poor</span>
549 <label>
550 <input type="radio" name="rating" value="1" required />
551 <span>1</span>
552 </label>
553 <label>
554 <input type="radio" name="rating" value="2" required />
555 <span>2</span>
556 </label>
557 <label>
558 <input type="radio" name="rating" value="3" required />
559 <span>3</span>
560 </label>
561 <label>
562 <input type="radio" name="rating" value="4" required />
563 <span>4</span>
564 </label>
565 <label>
566 <input type="radio" name="rating" value="5" required />
567 <span>5</span>
568 </label>
569 <span>Great</span>
570 </div>
571 </div>
572 <div class="second-step hidden">
573 <p><strong>What points along the way made this a <span class="rating-placeholder">5</span>* experience for you?</strong><br>We are counting on your insights to guide us in doing better 🙏</p>
574 <div class="not-floating-labels">
575 <div class="form-row field">
576 <textarea name="message" placeholder="Describe your experience in customizing your site colors.."
577 id="style-manager-user-feedback-message" rows="6" oninvalid="this.setCustomValidity('May we have a little more info about your experience?')" oninput="setCustomValidity('')" required></textarea>
578 </div>
579 </div>
580 <button id="style-manager-user-feedback_btn" class="button" type="submit"><?php _e( 'Send us your insights', 'customify' ); ?></button>
581 </div>
582 <div class="thanks-step hidden">
583 <h3 class="modal-title">Thank you so much for your feedback!</h3>
584 <p>It means the world to us as we strive to constantly push the limits and aim higher. Stay awesome! 🤗</p>
585 <p><em>The Pixelgrade Team</em></p>
586 </div>
587 <div class="error-step hidden">
588 <h3 class="modal-title">We've hit a snag!</h3>
589 <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>
590 </div>
591 </div>
592 </div>
593 <div class="modal-footer full">
594
595 </div>
596 </form>
597 </div>
598 </div>
599 </div>
600 <!-- End Modal -->
601 <!-- Modal Backdrop (Shadow) -->
602 <div class="modal-backdrop"></div>
603 </div>
604
605 <?php }
606 }
607
608 /**
609 * Return whether user provided feedback, and if so, return the timestamp.
610 *
611 * @return bool|int
612 */
613 public function user_provided_feedback() {
614 $user_provided_feedback = get_option( 'style_manager_user_feedback_provided' );
615 if ( empty( $user_provided_feedback ) ) {
616 return false;
617 }
618
619 return $user_provided_feedback;
620 }
621
622 /**
623 * Determine if we should ask for user feedback.
624 *
625 * @param bool|int $timestamp_limit Optional. Timestamp to compare the time the user provided feedback.
626 * If the provided timestamp is earlier than the time the user provided feedback, should ask again.
627 *
628 * @return bool
629 */
630 public function should_ask_for_feedback( $timestamp_limit = false ) {
631 if ( defined( 'CUSTOMIFY_SM_ALWAYS_ASK_FOR_FEEDBACK' ) && true === CUSTOMIFY_SM_ALWAYS_ASK_FOR_FEEDBACK ) {
632 return true;
633 }
634
635 $feedback_timestamp = $this->user_provided_feedback();
636 if ( empty( $feedback_timestamp ) ) {
637 return true;
638 }
639
640 if ( ! empty( $timestamp_limit ) && intval( $timestamp_limit ) > intval( $feedback_timestamp ) ) {
641 return true;
642 }
643
644 return false;
645 }
646
647 /**
648 * Callback for the user feedback AJAX call.
649 *
650 * @since 1.7.0
651 */
652 public function user_feedback_callback() {
653 check_ajax_referer( 'customify_style_manager_user_feedback', 'nonce' );
654
655 if ( empty( $_POST['type'] ) ) {
656 wp_send_json_error( esc_html__( 'No type provided', 'customify' ) );
657 }
658
659 if ( empty( $_POST['rating'] ) ) {
660 wp_send_json_error( esc_html__( 'No rating provided', 'customify' ) );
661 }
662
663 $type = sanitize_text_field( $_POST['type'] );
664 $rating = intval( $_POST['rating'] );
665 $message = '';
666 if ( ! empty( $_POST['message'] ) ) {
667 $message = wp_kses_post( $_POST['message'] );
668 }
669
670 $request_data = array(
671 'site_url' => home_url( '/' ),
672 'satisfaction_data' => array(
673 'type' => $type,
674 'rating' => $rating,
675 'message' => $message,
676 ),
677 );
678
679 // Send the feedback.
680 $response = $this->cloud_api->send_stats( $request_data, true );
681 if ( is_wp_error( $response ) ) {
682 wp_send_json_error( esc_html__( 'Sorry, something went wrong and we couldn\'t save your feedback.', 'customify' ) );
683 }
684 $response_data = json_decode( wp_remote_retrieve_body( $response ), true );
685 // Bail in case of decode error or failure to retrieve data
686 if ( null === $response_data || empty( $response_data['code'] ) || 'success' !== $response_data['code'] ) {
687 wp_send_json_error( esc_html__( 'Sorry, something went wrong and we couldn\'t save your feedback.', 'customify' ) );
688 }
689
690 // We need to remember that the user provided feedback (and at what timestamp).
691 update_option( 'style_manager_user_feedback_provided', time(), true );
692
693 wp_send_json_success( esc_html__( 'Thank you for your feedback.', 'customify' ) );
694 }
695
696 /**
697 * Main Customify_Style_Manager Instance
698 *
699 * Ensures only one instance of Customify_Style_Manager is loaded or can be loaded.
700 *
701 * @since 1.7.0
702 * @static
703 *
704 * @return Customify_Style_Manager Main Customify_Style_Manager instance
705 */
706 public static function instance() {
707
708 if ( is_null( self::$_instance ) ) {
709 self::$_instance = new self();
710 }
711
712 return self::$_instance;
713 } // End instance ()
714
715 /**
716 * Cloning is forbidden.
717 *
718 * @since 1.7.0
719 */
720 public function __clone() {
721
722 _doing_it_wrong( __FUNCTION__,esc_html( __( 'Cheatin&#8217; huh?' ) ), null );
723 } // End __clone ()
724
725 /**
726 * Unserializing instances of this class is forbidden.
727 *
728 * @since 1.7.0
729 */
730 public function __wakeup() {
731
732 _doing_it_wrong( __FUNCTION__, esc_html( __( 'Cheatin&#8217; huh?' ) ), null );
733 } // End __wakeup ()
734 }
735
736 endif;
737