Keep subcategory grandson in slug

The problem is not with WordPress — it does generate the proper permalink, be the post assigned to just grandson or son and father. It’s just that for the latter, the “chosen” category could be either son or father, but not both — and if it’s son (which has a parent category), then the permalink would have /father/son/ and not just /father/.

But the structure you want, it is possible.

And it can be better achieved with manual intervention when editing the post, where you’d want to select a primary category for the post.

And I rarely suggest 3rd party plugins in my answers, but this time, I thought you should know there’s a plugin which can help you with that. Yoast SEO also comes with a similar feature, but not sure how/whether it works with permalinks..

Or if you want to do it programmatically/manually (without any fancy UI), then a simple approach would be:

  1. Use the standard custom fields editor and add a field named primary_category with the category slug (e.g. grandson as in your example) as the field’s value.

  2. Use the post_link_category hook to filter/set the category that WordPress uses when generating post permalinks having %category% in the structure: (this code would go in the theme functions file)

    add_filter( 'post_link_category', function ( $cat, $cats, $post ) {
        if ( $post && ( $slug = get_post_meta( $post->ID, 'primary_category', true ) ) ) {
            $term = get_category_by_slug( $slug );
            $cat = $term ? $term : $cat; // use $term if it's valid
        }
        return $cat;
    }, 10, 3 );
    

Note: The code is intended for the standard category taxonomy. You’ll have to adjust it accordingly for custom taxonomies. 🙂