WordPress order categories by ID

wp_dropdown_categories() will list by id by default. It utilizes get_terms() as well, and provides a hook to toward the end if you wish to filter the html of $output further than the parameters allow. (I’ve added the source below).

It has the following parameters:

  • ‘show_option_all’
    (string) Text to display for showing all categories.

    • ‘show_option_none’
      (string) Text to display for showing no categories.
    • ‘option_none_value’
      (string) Value to use when no category is selected.
    • ‘orderby’
      (string) Which column to use for ordering categories. See get_terms() for a list of accepted values. Default ‘id’ (term_id).
    • ‘order’
      (string) Whether to order terms in ascending or descending order. Accepts ‘ASC’ or ‘DESC’. Default ‘ASC’.
    • ‘pad_counts’
      (bool) See get_terms() for an argument description. Default false.
    • ‘show_count’
      (bool|int) Whether to include post counts. Accepts 0, 1, or their bool equivalents. Default 0.
    • ‘hide_empty’
      (bool|int) Whether to hide categories that don’t have any posts. Accepts 0, 1, or their bool equivalents. Default 1.
    • ‘child_of’
      (int) Term ID to retrieve child terms of. See get_terms(). Default 0.
    • ‘exclude’
      (array|string) Array or comma/space-separated string of term ids to exclude. If $include is non-empty, $exclude is ignored. Default empty array.
    • ‘echo’
      (bool|int) Whether to echo or return the generated markup. Accepts 0, 1, or their bool equivalents. Default 1.
    • ‘hierarchical’
      (bool|int) Whether to traverse the taxonomy hierarchy. Accepts 0, 1, or their bool equivalents. Default 0.
    • ‘depth’
      (int) Maximum depth. Default 0.
    • ‘tab_index’
      (int) Tab index for the select element. Default 0 (no tabindex).
    • ‘name’
      (string) Value for the ‘name’ attribute of the select element. Default ‘cat’.
    • ‘id’
      (string) Value for the ‘id’ attribute of the select element. Defaults to the value of $name.
    • ‘class’
      (string) Value for the ‘class’ attribute of the select element. Default ‘postform’.
    • ‘selected’
      (int|string) Value of the option that should be selected. Default 0.
    • ‘value_field’
      (string) Term field that should be used to populate the ‘value’ attribute of the option elements. Accepts any valid term field: ‘term_id’, ‘name’, ‘slug’, ‘term_group’, – ‘term_taxonomy_id’, ‘taxonomy’, ‘description’, ‘parent’, ‘count’. Default ‘term_id’.
    • ‘taxonomy’
      (string|array) Name of the category or categories to retrieve. Default ‘category’.
    • ‘hide_if_empty’
      (bool) True to skip generating markup if no categories are found. Default false (create select element even if no categories are found).
    • ‘required’
      (bool) Whether the element should have the HTML5 ‘required’ attribute. Default false.

function wp_dropdown_categories( $args="" ) {
    $defaults = array(
        'show_option_all'   => '',
        'show_option_none'  => '',
        'orderby'           => 'id',
        'order'             => 'ASC',
        'show_count'        => 0,
        'hide_empty'        => 1,
        'child_of'          => 0,
        'exclude'           => '',
        'echo'              => 1,
        'selected'          => 0,
        'hierarchical'      => 0,
        'name'              => 'cat',
        'id'                => '',
        'class'             => 'postform',
        'depth'             => 0,
        'tab_index'         => 0,
        'taxonomy'          => 'category',
        'hide_if_empty'     => false,
        'option_none_value' => -1,
        'value_field'       => 'term_id',
        'required'          => false,
    );

    $defaults['selected'] = ( is_category() ) ? get_query_var( 'cat' ) : 0;

    // Back compat.
    if ( isset( $args['type'] ) && 'link' == $args['type'] ) {
        _deprecated_argument( __FUNCTION__, '3.0.0',
            /* translators: 1: "type => link", 2: "taxonomy => link_category" */
            sprintf( __( '%1$s is deprecated. Use %2$s instead.' ),
                '<code>type => link</code>',
                '<code>taxonomy => link_category</code>'
            )
        );
        $args['taxonomy'] = 'link_category';
    }

    $r = wp_parse_args( $args, $defaults );
    $option_none_value = $r['option_none_value'];

    if ( ! isset( $r['pad_counts'] ) && $r['show_count'] && $r['hierarchical'] ) {
        $r['pad_counts'] = true;
    }

    $tab_index = $r['tab_index'];

    $tab_index_attribute="";
    if ( (int) $tab_index > 0 ) {
        $tab_index_attribute = " tabindex=\"$tab_index\"";
    }

    // Avoid clashes with the 'name' param of get_terms().
    $get_terms_args = $r;
    unset( $get_terms_args['name'] );
    $categories = get_terms( $r['taxonomy'], $get_terms_args );

    $name = esc_attr( $r['name'] );
    $class = esc_attr( $r['class'] );
    $id = $r['id'] ? esc_attr( $r['id'] ) : $name;
    $required = $r['required'] ? 'required' : '';

    if ( ! $r['hide_if_empty'] || ! empty( $categories ) ) {
        $output = "<select $required name="$name" id='$id' class="$class" $tab_index_attribute>\n";
    } else {
        $output="";
    }
    if ( empty( $categories ) && ! $r['hide_if_empty'] && ! empty( $r['show_option_none'] ) ) {

        /**
         * Filters a taxonomy drop-down display element.
         *
         * A variety of taxonomy drop-down display elements can be modified
         * just prior to display via this filter. Filterable arguments include
         * 'show_option_none', 'show_option_all', and various forms of the
         * term name.
         *
         * @since 1.2.0
         *
         * @see wp_dropdown_categories()
         *
         * @param string $element Taxonomy element to list.
         */
        $show_option_none = apply_filters( 'list_cats', $r['show_option_none'] );
        $output .= "\t<option value="" . esc_attr( $option_none_value ) . "" selected='selected'>$show_option_none</option>\n";
    }

    if ( ! empty( $categories ) ) {

        if ( $r['show_option_all'] ) {

            /** This filter is documented in wp-includes/category-template.php */
            $show_option_all = apply_filters( 'list_cats', $r['show_option_all'] );
            $selected = ( '0' === strval($r['selected']) ) ? " selected='selected'" : '';
            $output .= "\t<option value="0"$selected>$show_option_all</option>\n";
        }

        if ( $r['show_option_none'] ) {

            /** This filter is documented in wp-includes/category-template.php */
            $show_option_none = apply_filters( 'list_cats', $r['show_option_none'] );
            $selected = selected( $option_none_value, $r['selected'], false );
            $output .= "\t<option value="" . esc_attr( $option_none_value ) . ""$selected>$show_option_none</option>\n";
        }

        if ( $r['hierarchical'] ) {
            $depth = $r['depth'];  // Walk the full depth.
        } else {
            $depth = -1; // Flat.
        }
        $output .= walk_category_dropdown_tree( $categories, $depth, $r );
    }

    if ( ! $r['hide_if_empty'] || ! empty( $categories ) ) {
        $output .= "</select>\n";
    }
    /**
     * Filters the taxonomy drop-down output.
     *
     * @since 2.1.0
     *
     * @param string $output HTML output.
     * @param array  $r      Arguments used to build the drop-down.
     */
    $output = apply_filters( 'wp_dropdown_cats', $output, $r );

    if ( $r['echo'] ) {
        echo $output;
    }
    return $output;
}