Rewrite rule regex help required

Our custom rewrite rule works for top-level services but not child
services.

Your rewrite rule, or the query (the second parameter for add_rewrite_rule()) is just missing a service query:

add_rewrite_rule( // wrapped for brevity
    '^consultancy/(.*)/?',

    // Here, add the &service=$matches[1]
    'index.php?post_type=service&name=$matches[1]&service=$matches[1]',

    'top'
);

But, why don’t you just use consultancy as the rewrite slug when you register the post type?

register_post_type( 'service', [
    'public'       => true,
    'rewrite'      => [ 'slug' => 'consultancy' ],
    'hierarchical' => true,
    // .. other args here.
] );

That way, you wouldn’t need the custom rewrite rule because the above 'slug' => 'consultancy' will set the permalink structure for your “service” posts to consultancy/<post name/slug>.

Can anyone suggest a modification that will get the post name from the
end of the URL?

You can use:

  • get_query_var( 'service' ) or get_query_var( 'name' ) to get the complete post name/slug path from the current URL.

    So if the URL is https://example.com/consultancy/test-service/test-service-child, you’d get test-service/test-service-child.

  • get_queried_object()->post_name to get the actual post name/slug for the queried post, i.e. without the parent path.

    So if the URL is https://example.com/consultancy/test-service/test-service-child, get_queried_object()->post_name would return test-service-child (note the child).