How to allow admins to create a sidebar from the admin

I’m creating a WordPress theme and I’ve noticed that a lot of premium themes allow the users to go to Appearance->Sidebars and create a new Sidebar by simply giving it a name.
The user can then Go to widgets and assign different widgets to this sidebar and also add custom menus. This I believe is a great feature as it allows users to have different sidebars on different pages.

Now I’m familiar with Custom Post Type and Theme options and know how I would let people choose a different sidebar for different pages, but I’m just having problems in creating the first step, which is to allow people to create a sidebar on their own. Do I need to create a CPT for this? or is there some other way?

Read More

I’ve searched a lot and the best thing I came across was a plugin, which has a lot of code and does too many things and for which I cannot even find the license info.

So please advice how I can create something like this and thank you very much.

Related posts

2 comments

  1. Create a function that register sidebars, using register_sidebar, starting from an option:

    add_action('widgets_init', 'my_custom_sidebars');
    
    function my_custom_sidebars() {
      $sidebars = get_option('my_theme_sidebars'); // get all the sidebars names
      if ( ! empty($sidebars) ) {
        // add a sidebar for every sidebar name
        foreach ( $sidebars as $sidebar ) {
          if ( empty($sidebar) ) continue;
            register_sidebar(array(
              'name' => $sidebar,
              'id' => sanitize_title($sidebar),
              'before_title' => '<h1>',
              'after_title' => '</h1>'
            ));
        }
      }
    }
    

    Now you have to save an option 'my_theme_sidebars' that contain an array of sidebars name.
    Here I’m posting post the code that create a page with 10 text inputs where add the sidebar name. (I’ll use add_theme_page) You can improve it adding javascript to dynamic add fields..

    add_action('admin_menu', 'my_custom_sidebars_page');
    
    function my_custom_sidebars_page() {
      add_theme_page(
        'Sidebars',
        'Sidebars',
        'edit_theme_options',
        'my_custom_sidebars',
        'my_custom_sidebars_page_print'
       );
      // save the form if submitted
      $nonce = filter_input(INPUT_POST, 'my_custom_sidebars_nonce', FILTER_SANITIZE_STRING);
      if ( ! empty($nonce) && wp_verify_nonce($nonce, 'my_custom_sidebars') ) {
         $sidebars =  (array) $_POST['custom_sidebars'];
         update_option('my_theme_sidebars', $sidebars);
         add_action('admin_notices', 'my_custom_sidebars_notice');
      }
    }
    
    function my_custom_sidebars_page_print() {
      if (! current_user_can('edit_theme_options') ) return;
      ?>
      <div class="wrap">
        <h2>Sidebars</h2>
        <form id="sidebars" method="post">
        <?php
        wp_nonce_field('my_custom_sidebars', 'my_custom_sidebars_nonce');
        $saved = get_option('my_theme_sidebars');
        for ($i=0; $i<10; $i++) {
          $value = isset( $saved[$i] ) ? esc_attr($saved[$i]) : '';
        ?>
        <input type="text" name="custom_sidebars[]" value="<?php echo $value;?>" />
        <?php } ?>
        <p class="submit">
          <input name="submit" class="button button-primary" value="Save" type="submit">
        </p>
        </form>
      </div>
      <?php
    }
    
    function my_custom_sidebars_notice() {
      echo '<div class="updated"><p>Updated.</p></div>';
    }
    

    Now, you have you let users select the sidebars for a specific page.
    You can add a metabox for that. (See add_meta_box docs).

    add_action( 'add_meta_boxes', 'my_custom_sidebar_metabox' ); 
    
    function my_custom_sidebar_metabox() {
      $screens = array( 'post', 'page' ); // add the metabox for pages and post
      foreach ( $screens as $screen ) {
        add_meta_box('my_custom_sidebar', 'Select a Sidebar','my_custom_sidebar_box', $screen);
      }
    }
    
    function my_custom_sidebar_box( $post ) {
      $sidebars = get_option('my_theme_sidebars'); // get all the sidebars names 
      if ( empty($sidebars) ) {
        echo 'No custom sidebars registered.';
        return;
      }
      wp_nonce_field( 'my_custom_sidebar', 'my_custom_sidebar_box_nonce' );
      $value = get_post_meta( $post->ID, '_custom_sidebar', true ); // actual value
      echo '<label>Select a Sidebar</label> ';
      echo '<select name="custom_sidebar">';
      // default option
      echo '<option value=""' . selected('', $value, false) . '>Default</option>';
      // an option for every sidebar
      foreach ($sidebars as $sidebar) {
         if ( empty($sidebar) ) continue;
         $v = sanitize_title($sidebar);
         $n = esc_html($sidebar);
         echo '<option value="' . $v . '"' . selected($v, $value) .'>' .$n .'</option>';
      }
      echo '<select>';
    }
    

    Then add the function to save the metabox:

    add_action( 'save_post', 'my_custom_sidebar_metabox_save' );
    
    function my_custom_sidebar_metabox_save( $post_id ) {
      // If this is an autosave, our form has not been submitted, do nothing.
      if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
      // check nonce
      $nonce = filter_input(INPUT_POST, 'my_custom_sidebar_box_nonce', FILTER_SANITIZE_STRING);
      if ( empty($nonce) || ! wp_verify_nonce( $nonce, 'my_custom_sidebar' ) ) return;
      $type = get_post_type($post_id);
      // Check the user's permissions.
      $cap = ( 'page' === $type ) ? 'edit_page' : 'edit_post';
      if ( ! current_user_can( $cap, $post_id ) ) return;
      $custom = filter_input(INPUT_POST, 'custom_sidebar', FILTER_SANITIZE_STRING);
      // Update the meta field in the database.
      if ( empty($custom) ) {
         delete_post_meta( $post_id, '_custom_sidebar');
      } else {
        update_post_meta( $post_id, '_custom_sidebar', $custom );
      }
    }
    

    In this way your users can choose a custom sidebar for every post or page. It is saved in the meta field ‘_custom_sidebar'.

    To display the custom sidebar, your sidebar.php should contain something like:

    // change the following according to your defaults sidebar if exists
    $sidebar = 'main_sidebar'; 
    // if in singular post/page check for saved custom sidebar
    if ( is_singular() ) {
      $id = get_queried_object_id(); // get current post/page id
      $custom = get_post_meta( $id, '_custom_sidebar', true ); // get selected sidebar
      if ( ! empty($custom) ) $sidebar = $custom;
    }
    if ( is_active_sidebar( $sidebar ) ) {
    ?>
    <ul id="sidebar"><?php dynamic_sidebar( $sidebar ); ?></ul>
    <?php } ?>
    

    Finally in your pages and posts just call get_sidebar(); as usual.

  2. CODE UPDATED WITH = ADD UNLIMITED SIDEBARS (JavaScript)

    Create a function that register sidebars, using [register_sidebar][1], starting from an option:

    add_action('widgets_init', 'my_custom_sidebars');
    
    function my_custom_sidebars() {
      $sidebars = get_option('my_theme_sidebars'); // get all the sidebars names
      if ( ! empty($sidebars) ) {
        // add a sidebar for every sidebar name
        foreach ( $sidebars as $sidebar ) {
          if ( empty($sidebar) ) continue;
            register_sidebar(array(
              'name' => $sidebar,
              'id' => sanitize_title($sidebar),
              'before_title' => '<h1>',
              'after_title' => '</h1>'
            ));
        }
      }
    }
    

    UPDATED: Now you have to save an option 'my_theme_sidebars' that contain an array of sidebars name.
    Here I’m posting post the code that create a page with 10 text inputs where add the sidebar name. (I’ll use [add_theme_page][2]) You can improve it adding javascript to dynamic add fields.. Add unlimited sidebars admin page.

    add_action( 'admin_menu', 'my_sidebar_plugin_menu' );
    
    function my_sidebar_plugin_menu() {
    
    add_theme_page( 'sidebar Plugin Options', 'Add Sidebar', 'manage_options', 'my-sidebar-unique-identifier', 'my_sidebar_plugin_options' );
    
     $nonce = filter_input(INPUT_POST, 'my_custom_sidebars_nonce', FILTER_SANITIZE_STRING);
     if ( ! empty($nonce) && wp_verify_nonce($nonce, 'my_custom_sidebars') ) {
     $sidebars =  (array) $_POST['custom_sidebars'];
     update_option('my_theme_sidebars', $sidebars);
     add_action('admin_notices', 'my_custom_sidebars_notice');
      }
     }
    
     function my_sidebar_plugin_options() {
    
     wp_enqueue_script('jquery');
     wp_enqueue_script('custom_sidebar-js', get_template_directory_uri() . '/js/custom_sidebar.js');
     if ( !current_user_can( 'manage_options' ) )  {
        wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
      }
     ?>
    
     <div class="my-form">
        <div class="wrap">
     <h2>Add Custom Sidebars</h2>
    
     <form id="sidebars" method="post">
    
     <?php wp_nonce_field('my_custom_sidebars', 'my_custom_sidebars_nonce');
     $saved = get_option('my_theme_sidebars');
     $xx=get_option('my_theme_sidebars');
     //print_r($xx);
     $no=count($xx);
     ?>
    
     <div id="append">
     <p class="text-box">
            <label for="box1">Sidebar-<span class="box-number">1</span></label>
            <input type="text" name="custom_sidebars[]" value="<?php echo $xx[0]; ?>" id="box1" />
            <a href="#" class="remove-box">Remove</a>
    
        </p>
    
     <?php if($no>1){ 
        for($i=1;$i<$no;$i++){
    
     ?>     
     <p class="text-box"><label for="box' + n + '">Sidebar-<span class="box-number"><?php echo $i+1; ?></span></label> 
     <input type="text" name="custom_sidebars[]" value="<?php echo $xx[$i]; ?>" id="box' + n + '" /> 
     <a href="#" class="remove-box">Remove</a>
     </p>
     <?php }
    
     } ?></div>
     <!--<a class="add-box" href="#">Add More</a>-->
     <button type="button"  class="add-box">Add New Sidebar</button>
    
     </table>
    
     <input type="hidden" name="action" value="update" />
     <input type="hidden" name="page_options" value="no_of_sidebar,sidebar_names,boxes" />
    
     <p class="submit">
    <input type="submit" class="button-primary clsSubmit" value="<?php _e('Save Changes') ?>" />
    </p>
    
    
    </form>
    </div>
    </div>
        <?php
    }
    
    function my_custom_sidebars_notice() {
    echo '<div class="updated"><p>Sidebar(s) Updated.</p></div>';
    }
    

    Now, you have you let users select the sidebars for a specific page.
    You can add a metabox for that. (See [add_meta_box][3] docs).

    add_action( 'add_meta_boxes', 'my_custom_sidebar_metabox' ); 
    
    function my_custom_sidebar_metabox() {
      $screens = array( 'post', 'page' ); // add the metabox for pages and post
      foreach ( $screens as $screen ) {
        add_meta_box('my_custom_sidebar', 'Select a Sidebar','my_custom_sidebar_box', $screen);
      }
    }
    
    function my_custom_sidebar_box( $post ) {
      $sidebars = get_option('my_theme_sidebars'); // get all the sidebars names 
      if ( empty($sidebars) ) {
        echo 'No custom sidebars registered.';
        return;
      }
      wp_nonce_field( 'my_custom_sidebar', 'my_custom_sidebar_box_nonce' );
      $value = get_post_meta( $post->ID, '_custom_sidebar', true ); // actual value
      echo '<label>Select a Sidebar</label> ';
      echo '<select name="custom_sidebar">';
      // default option
      echo '<option value=""' . selected('', $value, false) . '>Default</option>';
      // an option for every sidebar
      foreach ($sidebars as $sidebar) {
         if ( empty($sidebar) ) continue;
         $v = sanitize_title($sidebar);
         $n = esc_html($sidebar);
         echo '<option value="' . $v . '"' . selected($v, $value) .'>' .$n .'</option>';
      }
      echo '<select>';
    }
    

    Then add the function to save the metabox:

    add_action( 'save_post', 'my_custom_sidebar_metabox_save' );
    
    function my_custom_sidebar_metabox_save( $post_id ) {
      // If this is an autosave, our form has not been submitted, do nothing.
      if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
      // check nonce
      $nonce = filter_input(INPUT_POST, 'my_custom_sidebar_box_nonce', FILTER_SANITIZE_STRING);
      if ( empty($nonce) || ! wp_verify_nonce( $nonce, 'my_custom_sidebar' ) ) return;
      $type = get_post_type($post_id);
      // Check the user's permissions.
      $cap = ( 'page' === $type ) ? 'edit_page' : 'edit_post';
      if ( ! current_user_can( $cap, $post_id ) ) return;
      $custom = filter_input(INPUT_POST, 'custom_sidebar', FILTER_SANITIZE_STRING);
      // Update the meta field in the database.
      if ( empty($custom) ) {
         delete_post_meta( $post_id, '_custom_sidebar');
      } else {
        update_post_meta( $post_id, '_custom_sidebar', $custom );
      }
    }
    

    In this way your users can choose a custom sidebar for every post or page. It is saved in the meta field ‘_custom_sidebar'.

    To display the custom sidebar, your sidebar.php should contain something like:

    // change the following according to your defaults sidebar if exists
    $sidebar = 'main_sidebar'; 
    // if in singular post/page check for saved custom sidebar
    if ( is_singular() ) {
      $id = get_queried_object_id(); // get current post/page id
      $custom = get_post_meta( $id, '_custom_sidebar', true ); // get selected sidebar
      if ( ! empty($custom) ) $sidebar = $custom;
    }
    if ( is_active_sidebar( $sidebar ) ) {
    ?>
    <ul id="sidebar"><?php dynamic_sidebar( $sidebar ); ?></ul>
    <?php } ?>
    

    Finally in your pages and posts just call get_sidebar(); as usual.

    UPDATED: Create a new JavaScript file for multi sidebars js/custom_sidebar.js

    ( function( $ ) {
    
    $('.my-form .add-box').click(function(){
    
    var n = $('.text-box').length + 1;
    var box_html = $('<p class="text-box"><label for="box' + n + '">Sidebar-<span class="box-number">' + n + '</span></label> <input type="text" name="custom_sidebars[]" value="" id="box' + n + '" /> <a href="#" class="remove-box">Remove</a></p>');
        box_html.hide();
        $('#append').append(box_html);
        box_html.fadeIn('slow');
    
        return false;
    
    
    }); 
    
    $('.my-form').on('click', '.remove-box', function(){
    $(this).parent().css( 'background-color', '#FF6C6C' );
    $(this).parent().fadeOut("slow", function() {
        $(this).remove();
        $('.box-number').each(function(index){
            $(this).text( index + 1 );
        });
    });
    return false;
    });
    
    
    
    $('.clsSubmit').click(function(){
    var m = $('.text-box').length;
    if(m==0){alert("press OK to Reset");}
    });
    

    Finally in your pages and posts just call get_sidebar(); as usual.

Comments are closed.