2

I'd like that my categories having child-categories don't be selectable on the post article page.

What I want to do is to remove the checkbox before their label.

I've looked the filter documentation but I wasn't able to find any filter that suits my need.

  • What do you mean selectable? Can you explain please? – Jared Feb 24 '12 at 1:56
  • You can still check the parent categories to use them instead of their children. – koskoz Feb 24 '12 at 17:09
3

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();
  • Probably the Most Used tab needs to be removed as well..: jQuery('#category-tabs .hide-if-no-js').remove(); – brasofilo Jul 14 '12 at 21:31
  • 1
    This is really an elegant solution. I have one improvement: make parent categories that have children hidden, but leave those still selectable for the ones that don't have children. See my answer below. – Mike Kormendy May 17 '15 at 3:27
  • This is the wonderful solution but how do we do the same on "Quick edit" section as well? Screenshot - ge.tt/3FukTYi2 – Netizen Jan 28 '17 at 14:25
3

Almost exactly the same to brasofilo, my code below also accounts for different taxonomies and removes the checkbox for parent categories at the top level, only if they have children. This allows for other top level categories that are childless to still be selectable. I put this simple code my theme's functions.php file:

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">
(function($){
    $('[id$="-all"] > ul.categorychecklist').each(function() {
        var list = $(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);
    });

    $(".categorychecklist>li>label input").each(function(){
        if ($(this).parent().next('ul').hasClass('children')) {
            $(this).remove();
        }
    });

})(jQuery);
</script>
<?php
    }
}

Category_Checklist::init();
  • Nice one. I had to rename "Category_Checklist" to avoid an fatal error. – Henning Fischer Sep 7 '18 at 11:25
0

It can also be done with the " Category Checklist Tree " plugin to maintain the taxonomy hierarchy as brasofilo says and some CSS:

#categorychecklist > li > label.selectit > input { display: none !important; }

( #categorychecklist can be replaced with #yourcustomtaxonomychecklist to apply this to a custo taxonomy )

To add this, and other css to wordpress admin the following can be added to functions.php:

function my_admin_head() {
    echo '<link rel="stylesheet" type="text/css"
    href="'.get_bloginfo('stylesheet_directory').'/admin.css">';
}
add_action('admin_head', 'my_admin_head');

And then add the stylesheet "admin.css to your theme directory and add the css above

  • 1
    You should be enqueueing the stylesheet not echoing it directly into the head. – s_ha_dum Feb 23 '13 at 16:32
0

Here's what I used to disable the parent categories and only allow one category per post. This code changes the quick edit categories, too. I welcome someone to clean it up, I'm not confident in javascript.

I got the first part here: https://wordpress.org/support/topic/making-category-selection-radio-buttons

    /* ONLY ALLOW ONE CATEGORY PER POST */
add_action( 'admin_footer', 'catlist2radio' );
function catlist2radio(){
    echo '<script type="text/javascript">';
    echo 'jQuery("#categorychecklist .children input, #categorychecklist-pop .children input, .cat-checklist .children input")';
    echo '.each(function(){this.type="radio"});</script>';
}

/* DISABLE PARENT CATEGORIES FOR POSTS */
/*
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();
        });
    });
        jQuery(function(){
        jQuery('[id$="-all"] > ul.cat-checklist').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(".cat-checklist>li>label input").each(function(){
            jQuery(this).remove();
        });
    });
        jQuery('#category-tabs .hide-if-no-js').remove();
</script>
<?php
    }
}
Category_Checklist::init();
0

I used a combination of the above to get my solution. I liked the pure css approach, however the label click action would still change the "checked" attribute of the checkbox even though it wasn't showing. Here's my solution, note that it is hard coded to hide the first two levels of categories.

css:

#categorychecklist > li > label.selectit,
#categorychecklist > li > ul.children > li > label.selectit {cursor: text;}

#categorychecklist > li > label.selectit > input,
#categorychecklist > li > ul.children > li > label.selectit > input { display: none !important; }

js (if the checkbox is hidden, cancel the click event. Will work at any level):

$('#categorychecklist > li label.selectit').on('click', function(event) {
        if (!$(this).children("input").is(':visible'))
            event.preventDefault();
    });

And to reference on admin:

function add_admin_assets() {
    wp_enqueue_style( "admin-custom-css", get_bloginfo('template_url').'/assets/styles/custom/admin.css');
    wp_enqueue_script('admin-custom-js', get_bloginfo('template_url').'/inc/js/admin.js', array(), null, true);
}
add_action('admin_head', 'add_admin_assets');
0

The following solution prevents the checkbox being output. This seems to be much cleaner in my opinion.

I make a custom walker extending the core Walker_Category_Checklist which overrides the start_el function so it can conditionally set $args['list_only'] to true. In this case the function checks whether we have a top-level term ($category->parent == 0) which has sub-terms ($args['has_children']) and of course theres a check if we are using the right taxonomy. These conditions met, $args['list_only'] is set to true and the parent method is called, which will not output the checkbox for this element now.

class Wpse22836_Walker_Category_Checklist extends Walker_Category_Checklist {
    public function start_el( &$output, $category, $depth = 0, $args = array(), $id = 0 ) {
        if ( 'category' ==  $args['taxonomy'] 
                && $args['has_children'] 
                && 0 === $category->parent) {
            $args['list_only'] = true;
        }
        parent::start_el( $output, $category, $depth, $args, $id );
    }
}

To make WordPress use this walker class instead of the original one we can use the filter wp_terms_checklist_args in wp_terms_checklist():

add_filter( 'wp_terms_checklist_args', function( $args, $post_id ) {
    $args['walker'] = new Wpse22836_Walker_Category_Checklist();
    return $args;
}, 10, 2 );

This solution has the advantage of automatically working in all places which use the core function wp_terms_checklist() and it doesn't depend on JavaScript.

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.