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 panels
ctmss_section_
- for sections
ctmss_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.