Simple tutorial – How to sort customizer sections in the panel and add order to theme.
1. You must use prefixes to do this because customizer don’t support custom classes.
ctmss_panel_
– for panelsctmss_section_
– for sectionsctmss_hidden_
– for hidden sections that has a input with values
2. Add panel to the Customizer – add_panel()
$wp_customize->add_panel( 'ctmss_panel_panelname1', array( 'title' => esc_html__( 'My Panel', 'textdomain' ), 'priority' => 150 ) );
3. Add section with text input to save new sections order. Hide this section with CSS. add_section(), add_setting(), add_control()
$wp_customize->add_section( 'ctmss_hidden_sectionname1', array( 'title' => esc_html__( 'Section hidden', 'textdomain' ), 'panel' => 'ctmss_panel_panelname1', 'priority' => 1 ) ); $wp_customize->add_setting( 'ctmss_sections_order', array( 'sanitize_callback' => 'wp_kses_post' ) ); $wp_customize->add_control( new WP_Customize_Control( $wp_customize, 'sections_order', array( 'settings' => 'ctmss_sections_order', 'type' => 'text', 'label' => esc_html__( 'Section layout', 'textdomain' ), 'section' => 'ctmss_hidden_sectionname1', ) ) );
4. Create array() with available sections. If saved values is available get it, else set default sections and order.
$default_sections = array ( 'ctmss_section_sectionname1' => array ( 'title' => esc_html__( 'Section 1', 'textdomain' ), 'description' => esc_html__( 'Section 1 Description', 'textdomain' ), ), 'ctmss_section_sectionname2' => array ( 'title' => esc_html__( 'Section 2', 'textdomain' ), 'description' => esc_html__( 'Section 2 Description', 'textdomain' ), ), 'ctmss_section_sectionname3' => array ( 'title' => esc_html__( 'Section 3', 'textdomain' ), 'description' => esc_html__( 'Section 3 Description', 'textdomain' ), ), 'ctmss_section_sectionname4' => array ( 'title' => esc_html__( 'Section 4', 'textdomain' ), 'description' => esc_html__( 'Section 4 Description', 'textdomain' ), ), ); $sortable_sections = get_theme_mod('ctmss_sections_order'); if( !isset( $sortable_sections ) || empty( $sortable_sections ) ){ set_theme_mod( 'ctmss_sections_order', implode(',', array_keys( $default_sections ) ) ); } $sortable_sections = explode(',', $sortable_sections ); foreach( $sortable_sections as $sortable_section ){ $wp_customize->add_section( $sortable_section, array( 'title' => $default_sections[$sortable_section]['title'], 'description' => $default_sections[$sortable_section]['description'], 'panel' => 'ctmss_panel_panelname1' ) ); }
5. Add controls to the sections. Example:
$wp_customize->add_setting( 'myprefix_section1_layout', array( 'default' => 'classic', 'sanitize_callback' => 'wp_kses_post' ) ); $wp_customize->add_control( new WP_Customize_Control( $wp_customize, 'section1_layout', array( 'settings' => 'myprefix_section1_layout', 'type' => 'radio', 'label' => esc_html__( 'Section layout', 'textdomain' ), 'section' => 'ctmss_section_sectionname1', 'choices' => array( 'classic' => esc_html__( 'Classic', 'textdomain' ), 'grid' => esc_html__( 'Grid', 'textdomain' ), 'list' => esc_html__( 'List', 'textdomain' ), ) ) ) ); $wp_customize->add_setting( 'myprefix_section2_layout', array( 'default' => 'classic', 'sanitize_callback' => 'wp_kses_post' ) ); $wp_customize->add_control( new WP_Customize_Control( $wp_customize, 'section2_layout', array( 'settings' => 'myprefix_section2_layout', 'type' => 'radio', 'label' => esc_html__( 'Section layout', 'textdomain' ), 'section' => 'ctmss_section_sectionname2', 'choices' => array( 'classic' => esc_html__( 'Classic', 'textdomain' ), 'grid' => esc_html__( 'Grid', 'textdomain' ), 'list' => esc_html__( 'List', 'textdomain' ), ) ) ) ); $wp_customize->add_setting( 'myprefix_section3_layout', array( 'default' => 'classic', 'sanitize_callback' => 'wp_kses_post' ) ); $wp_customize->add_control( new WP_Customize_Control( $wp_customize, 'section3_layout', array( 'settings' => 'myprefix_section3_layout', 'type' => 'radio', 'label' => esc_html__( 'Section layout', 'textdomain' ), 'section' => 'ctmss_section_sectionname3', 'choices' => array( 'classic' => esc_html__( 'Classic', 'textdomain' ), 'grid' => esc_html__( 'Grid', 'textdomain' ), 'list' => esc_html__( 'List', 'textdomain' ), ) ) ) ); $wp_customize->add_setting( 'myprefix_section4_layout', array( 'default' => 'classic', 'sanitize_callback' => 'wp_kses_post' ) ); $wp_customize->add_control( new WP_Customize_Control( $wp_customize, 'section4_layout', array( 'settings' => 'myprefix_section4_layout', 'type' => 'radio', 'label' => esc_html__( 'Section layout', 'textdomain' ), 'section' => 'ctmss_section_sectionname4', 'choices' => array( 'classic' => esc_html__( 'Classic', 'textdomain' ), 'grid' => esc_html__( 'Grid', 'textdomain' ), 'list' => esc_html__( 'List', 'textdomain' ), ) ) ) );
6. Add styles and scripts.
function my_customizer_scripts() { wp_enqueue_script( 'my_customizer_js', trailingslashit( get_template_directory_uri() ) . 'assets/js/my-customizer.js', array(), '1.0', 'all' ); } add_action('customize_controls_print_scripts', 'my_customizer_scripts'); function my_customizer_styles() { wp_enqueue_style( 'my_customizer_css', trailingslashit( get_template_directory_uri() ) . 'assets/css/my-customizer.css', array(), '1.0', 'all' ); } add_action('customize_controls_print_styles', 'my_customizer_styles');
my-customizer.css
li[id*="ctmss_hidden_"], ul[id*="ctmss_hidden_"], .ctmss_hidden { display: none !important; } .ctmss_section .accordion-section-title:active { cursor: move !important; }
my-customizer.js
jQuery( document ).ready( function($) { $('ul[id*="ctmss_panel_"]').addClass('ctmss_panel'); $('ul.ctmss_panel').each( function() { if( 0 === $(this).length ){ return true; } var panel = $(this), panelSectionHidden = panel.find('li[id*="ctmss_hidden_"]').attr('aria-owns'); panel.find('li[id*="ctmss_section_"]').addClass('ctmss_section'); panel.find('li[id*="ctmss_hidden_"]').addClass('ctmss_hidden'); // Init sortable. panel.sortable( { item: 'li.ctmss_section', axis: 'y', // Update value when we stop sorting. stop: function() { updateValue(); } }); // Updates the sorting list. function updateValue() { var inputValues = panel.find( '.ctmss_section' ).map( function() { var id = $(this).attr('id'), id = id.replace('accordion-section-',''); return id; }).get().join(','); // Add the value to the hidden field $( '#' + panelSectionHidden ).find( '.customize-control-text input' ).prop( 'value', inputValues ); // Important! Make sure to trigger change event so Customizer knows it has to save the field $( '#' + panelSectionHidden ).find( '.customize-control-text input' ).trigger('change'); console.log( inputValues ); } }); });
7. Add function to display sections.
if ( !function_exists( 'ctmss_get_sections' ) ): function ctmss_get_sections( $sections ) { $sections = explode(',', $sections); $output=""; if ( empty( $sections ) ) { return $output; } foreach( $sections as $section ) { switch ( $section ) { case 'ctmss_section_sectionname1': $output .= '<div style="width: 100%; height: 200px; padding: 40px; background: #e1e1e1;">Section 1</div>'; break; case 'ctmss_section_sectionname2': $output .= '<div style="width: 100%; height: 200px; padding: 40px; background: #e3e3e3;">Section 2</div>'; break; case 'ctmss_section_sectionname3': $output .= '<div style="width: 100%; height: 200px; padding: 40px; background: #e5e5e5;">Section 3</div>'; break; case 'ctmss_section_sectionname4': $output .= '<div style="width: 100%; height: 200px; padding: 40px; background: #e7e7e7;">Section 4</div>'; break; default: break; } } return $output; } endif;
8. Run your code where you want.
echo ctmss_get_sections( get_theme_mod('ctmss_sections_order') );
This solution works without Kirki but is easy to customize it.