1

We do have kirki(a theme customizer toolkit) sortable field. But i want to apply the same logic on the sections itself instead of creating another section with sortable fields. I'm using options instead of theme mods, just for better visualization right now. The things i tried so far: in functions.php I have this code below to create an option row in option table:

$sortable_sections = get_option('sortable_sections');
  if(!isset($sortable_sections) OR empty($sortable_sections)){
  add_option('sortable_sections', array('eat', 'pray','love'));
}

The code to create sections in a file named kirki-config.php which is required in functions.php as below

$sortable_sections = get_option('sortable_sections');
foreach($sortable_sections as $sortable_section){
 Kirki::add_section( $sortable_section, array(
    'title'          => esc_attr__( strtoupper($sortable_section), 'airspace' ),
    'description'    => esc_attr__( 'Insert content', 'airspace' ),
    'panel'          => 'frontpage_panel',
) );
}

the above code creates three sections with id eat, pray, love respectively.

the code in js is as below:(file hooked to admin_enqueue_scripts)

jQuery( document ).ready(function($) {

  $('#sub-accordion-panel-frontpage_panel').sortable({
    items: '.control-section-kirki-default',
    axis : 'y',
    cursor: 'move,
   update: function(){
      //here i want the code which gets the updated reordered array and passed to a  
      //php file using .sortable('serialize'), only after clicking the publish
     // button. the problem is the publish button is disabled even after
    // sections got new positions.
   }
  });
});

and in php file i want code something like as below:

$new_array = $_POST['accordion-section'];
update_option('sortable_sections', $new_array);

So there are two steps which i'm having problem to finish. 1. enabling and disabling the publish button 2.after clicking the button js variable goes to php file and updates the option.

How to achieve it, and is there any better method to achieve it?

4

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.

  • jquery .sortable('serialize') does all the heavy lifting, it gives you an array with new order, so we can use update: function(){ $('#publish_button').sortable('serialize'); } the problem is publish button only gets activated upon changes the value of the controller only. So what i want is 1. activate publish button upon sections positions changes 2. upon clicking database updates, page refreshes and then the button gets deactivated again and the sections get the new order – seeker Jul 12 '18 at 7:30
  • @seeker I updated my answer. You must create hidden field in panel with an array of sections and for save new values. – Michael Jul 12 '18 at 7:58
  • ok, how the database interaction going to work and how the new order going to be saved? – seeker Jul 12 '18 at 8:19
  • When hidden field will be changed then you can save values Publish button will be enabled. New order can be saved as array or comma-separated list - use .join(", ").To get values you can use get_theme_mod(). Updated answear. – Michael Jul 12 '18 at 8:29
  • as in step one you mentioned i need to create a hidden input field, you mean i need to create a new section with a hidden input field and then hide that new section with css, right? – seeker Jul 12 '18 at 8:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.