Search if menu item has child in wp_get_nav_menu_items hook

If you want to use the wp_get_nav_menu_items hook, then try the function below which should be hooked after the exclude_menu_items function:

// Example when NOT using a class: (you already defined the exclude_menu_items function)
add_filter( 'wp_get_nav_menu_items', 'exclude_menu_items', 10, 3 );
add_filter( 'wp_get_nav_menu_items', 'exclude_menu_items2' );

function exclude_menu_items2( $items ) {
    if ( current_user_can( 'administrator' ) ) {
        return $items;
    }

    $mores   = [];
    $parents = [];
    foreach ( $items as $key => $item ) {
        if ( '#' === $item->url && 'More' === $item->title ) {
            $mores[] = $item->ID;
        }

        if ( ! in_array( $item->menu_item_parent, $parents ) ) {
            $parents[] = $item->menu_item_parent;
        }
    }

    $mores = array_diff( $mores, $parents );
    foreach ( $items as $i => $item ) {
        if ( in_array( $item->ID, $mores ) ) {
            unset( $items[ $i ] );
        }
    }

    return $items;
}

Just make sure to run the appropriate validation so that the menu items don’t get messed, e.g. on the Menus admin screen.

And the two functions can also be combined:

function exclude_menu_items( $items, $menu, $args ) {
    if ( current_user_can( 'administrator' ) ) {
        return $items;
    }

    $mores   = [];
    $parents = [];
    foreach ( $items as $key => $item ) {
        if ( $page = get_post( $item->object_id ) ) {
            // ... your code here.
        }

        if ( ! empty( $items[ $key ] ) ) {
            if ( '#' === $item->url && 'More' === $item->title ) {
                $mores[] = $item->ID;
            }

            if ( ! in_array( $item->menu_item_parent, $parents ) ) {
                $parents[] = $item->menu_item_parent;
            }
        }
    }

    $mores = array_diff( $mores, $parents );
    foreach ( $items as $i => $item ) {
        if ( in_array( $item->ID, $mores ) ) {
            unset( $items[ $i ] );
        }
    }

    return $items;
}

And actually — when wp_nav_menu() is called — with the wp_nav_menu_objects hook, it’s simpler to remove the “More” items which have no children:

add_filter( 'wp_nav_menu_objects', function ( $items ) {
    if ( is_admin() ) { // sample validation..
        return $items;
    }

    return array_filter( $items, function ( $item ) {
        return ! ( '#' === $item->url && 'More' === $item->title &&
            ! in_array( 'menu-item-has-children', $item->classes )
        );
    } );
} );