How to Apply Custom Header Images to WordPress Parent Pages and Their Subpages

I’m working on a WordPress site where I need to display different header images based on page hierarchy. Here’s my setup:

+services
-- web-design
-- marketing
+products
-- item-alpha
--- details-page
-- item-beta

I want each main section (services, products) to have its own unique header image that automatically appears on all child pages too. So all pages under “services” would show the services header, and all “products” pages would display the products header.

I could use custom fields on every single page, but that seems like too much work and my clients might forget to set them. I’m thinking about modifying my template to check which top-level parent a page belongs to, then choose the right header image automatically. But I’m worried about performance if I have to climb up the page tree every time.

What’s the best approach for this? Any efficient solutions?

EDIT: I tried this code outside the WordPress loop:

<?php 
global $wp_query;
$current_id = $wp_query->post->ID;

$banner_image = get_post_meta($current_id, 'banner_image', true);

if (!$banner_image) {
    $ancestor = get_page($wp_query->post->post_parent);
    
    while (!$banner_image && $ancestor) {
        $banner_image = get_post_meta($ancestor->ID, 'banner_image', true);
        $ancestor = get_page($ancestor->post_parent);
    }
}
?>

honestly i’d just use a simple php switch statement in your header template based on the current page’s top-level parent. something like get_ancestors() to grab the root parent id, then switch on that id to display the right image. way simpler than all this meta field stuff and easier for you to maintain later.

Your code approach is on the right track but there’s a more efficient WordPress way to handle this. Instead of climbing the hierarchy manually, use get_post_ancestors() which returns all parent IDs in one call. Then loop through them to find the first one with a banner image set.

I’ve implemented something similar and found that WordPress already caches page relationships pretty well, so performance isn’t usually an issue unless you’re dealing with extremely deep hierarchies. The bigger concern is maintaining this system long-term.

Consider creating a simple admin interface or using ACF to set header images only on top-level pages, then modify your template to always fetch the top-most ancestor’s image. You could also cache the results using WordPress transients if you notice any slowdown. The key is making it foolproof for your clients while keeping the code maintainable.

I actually solved this exact problem differently by using WordPress’s built-in page template system combined with custom fields. Rather than checking hierarchy on every page load, I set up a filter that automatically inherits the banner image from the top-level parent during the save_post action. The trick is to use wp_get_post_parent_id() recursively until you hit a page with parent ID of 0, then store that top-level parent’s ID as metadata on each child page. This way you only do the hierarchy lookup once when pages are saved or updated, not on every frontend request. You can hook into save_post and automatically populate a _top_parent_id meta field for all child pages. Then in your template, just grab the banner image from that stored parent ID. Much faster than real-time traversal and your clients never need to think about it. I’ve been running this approach for two years without issues.