How WordPress manages nested dropdown?

Actually <option> field doesn’t work with any CSS. So WordPress Developers/Designers did a simple yet nice trick for the nesting layout for <option> fields.

Level pads

Actually in your inspection you missed something there:

<select name="page_id" id="page_id">
    <option value="1" class="level-0">Level 0</option>
    <option value="2" class="level-1">&nbsp;&nbsp;&nbsp;Level 1</option>
    <option value="3" class="level-1">&nbsp;&nbsp;&nbsp;Level 1</option>
    <option value="4" class="level-2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Level 2</option>
    <option value="5" class="level-3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Level 3</option>
    <option value="6" class="level-2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Level 2</option>
    <option value="7" class="level-3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Level 3</option>
</select>

Have you noted the population of &nbsp; (HTML special character for spaces) there?

That is what creating the nesting look.

Let’s get the hand dirty

  • In WordPress wp-includes/ folder, open the file post-template.php.
  • Now find wp_dropdown_pages(, so that you can find the function showing the dropdown (Line #1016 in WP 4.3.1)
  • In that function you will see another function is functioning there: walk_page_dropdown_tree(, search for that one. (Line #1309 in WP 4.3.1)
  • In that function you will see a Walker Class is functioning there, Walker_PageDropdown, find that class now. (Line #1471 in WP 4.3.1)
  • In that class you will see a function named start_el, and within that function actually the trick is running.

Have you noticed that $pad variable there?

$pad = str_repeat('&nbsp;', $depth * 3);

Passing the $depth of the page, this str_repeat() is actually populating the spaces (&nbsp;) there. str_repeat() is a PHP function that repeats a string for specified times. And it’s working simply multiplying &nbsp; 3 times to the $depth. And that’s the trick.

Let’s do it

Now let us implement the similar thing in your case:

$_pages = get_pages( array( 'post_type'=> 'your_hierachical_cpt' ) );
<select name="my_field" id="my-field">
    <?php foreach ($_pages as $_page) {
        $depth = count( get_post_ancestors( $_page->ID ) ); //page_depth
        $pad = str_repeat('&nbsp;', $depth * 3);
        echo '<option value="'. $_page->ID .'" class="level-'. $depth .'">'. $pad . $_page->post_title .'</option>';
    } ?>
</select>

We’re having all the pages in $_pages, having each of their depth in $depth, and then following that simple trick, in $pad. And when showing <option>s, we are showing the $depth classes, and adding the $pad variable just before options’ texts.

Yay! 😀