Make parent categories not selectable

I really doubt this is filterable, so jQuery comes to rescue 🙂

The Code

add_action( 'admin_footer-post.php', 'wpse_22836_remove_top_categories_checkbox' );
add_action( 'admin_footer-post-new.php', 'wpse_22836_remove_top_categories_checkbox' );

function wpse_22836_remove_top_categories_checkbox()
{
    global $post_type;

    if ( 'post' != $post_type )
        return;
    ?>
        <script type="text/javascript">
            jQuery("#categorychecklist>li>label input").each(function(){
                jQuery(this).remove();
            });
        </script>
    <?php
}

The Result

no parent categories


Advanced

There’s a caveat: whenever selecting a sub-category, it gets out of the hierarchy…

So, the following is the code from the excellent plugin by Scribu, Category Checklist Tree, coupled with the previous code.

On the post editing screen, after saving a post, you will notice that the checked categories are displayed on top, breaking the category hierarchy. This plugin removes that “feature”.

Either you use the previous code and install the plugin, or simply drop this in your theme’s functions.php or in a custom plugin of yours (preferable, so all your tweaks will be theme independent).

/*
Based on Category Checklist Tree, by scribu
Preserves the category hierarchy on the post editing screen
Removes parent categories checkbox selection
*/
class Category_Checklist {

    function init() {
        add_filter( 'wp_terms_checklist_args', array( __CLASS__, 'checklist_args' ) );
    }

    function checklist_args( $args ) {
        add_action( 'admin_footer', array( __CLASS__, 'script' ) );

        $args['checked_ontop'] = false;

        return $args;
    }

    // Scrolls to first checked category
    function script() {
?>
<script type="text/javascript">
    jQuery(function(){
        jQuery('[id$="-all"] > ul.categorychecklist').each(function() {
            var $list = jQuery(this);
            var $firstChecked = $list.find(':checked').first();

            if ( !$firstChecked.length )
                return;

            var pos_first = $list.find(':checkbox').position().top;
            var pos_checked = $firstChecked.position().top;

            $list.closest('.tabs-panel').scrollTop(pos_checked - pos_first + 5);
        });
        
        jQuery("#categorychecklist>li>label input").each(function(){
            jQuery(this).remove();
        });
        
    });
</script>
<?php
    }
}

Category_Checklist::init();

Leave a Comment