"Posts page" set in settings not using archive.blade.php, defaulting to index.blade.php

I’m having trouble getting my Posts page to use the intended template file. To try and figure out why this is, I added a var dump in wp-includes/template.php per this post.

Here is the template hierarchy WordPress is using for the page, “Blog” which I have set as my “Posts” page in WordPress settings.

array(12) { 
[0]=> string(20) "views/home.blade.php" 
[1]=> string(14) "views/home.php" 
[2]=> string(30) "resources/views/home.blade.php" 
[3]=> string(24) "resources/views/home.php" 
[4]=> string(14) "home.blade.php" 
[5]=> string(8) "home.php" 
[6]=> string(21) "views/index.blade.php" 
[7]=> string(15) "views/index.php" 
[8]=> string(31) "resources/views/index.blade.php" 
[9]=> string(25) "resources/views/index.php" 
[10]=> string(15) "index.blade.php" 
[11]=> string(9) "index.php" }

I do have an archive.blade.php file in [theme-name]/resources/views/. This file is based on index.blade.php for now. I can’t figure out why on earth it’s looking for “home” or “index” in this scenario. Do I need to tell blade that “archive.blade.php” exists? Register it somehow? I’m really at a loss here. I’ve reviewed Sage 9 docs and it says that index.blade.php is “Archive page (used by blog page, category archives, author archives and more)”. But surely it can be overridden by creating an appropriately-named archive.php template, right?

For comparison, I checked the template hierarchy output for a CPT I created called “Portfolio”. This is a page that doesn’t exist in the page list, and it is automatically using the intended template, “archive-portfolio.blade.php”, which is here: [theme-name]/resources/views/

array(12) { 
[0]=> string(33) "views/archive-portfolio.blade.php" 
[1]=> string(27) "views/archive-portfolio.php" 
[2]=> string(43) "resources/views/archive-portfolio.blade.php" 
[3]=> string(37) "resources/views/archive-portfolio.php" 
[4]=> string(27) "archive-portfolio.blade.php" 
[5]=> string(21) "archive-portfolio.php" 
[6]=> string(23) "views/archive.blade.php" 
[7]=> string(17) "views/archive.php" 
[8]=> string(33) "resources/views/archive.blade.php" 
[9]=> string(27) "resources/views/archive.php" 
[10]=> string(17) "archive.blade.php" 
[11]=> string(11) "archive.php" }

Sage just follows the WordPress template hierarchy. This graphic explains it pretty well:


The WP template heirarchy will never try and load archive.blade.php (or archive.php) for the page you’ve set as your “Posts” page; it will load home.[blade.]php and fall back to index.[blade.]php. That’s because it doesn’t consider your Posts page to be an archive. An archive page for a custom post type is an archive, hence it loads the correct page. If you want a specific template for your “Posts” page, call it home.blade.php and WP will load it.

Thank you. I’ve definitely been staring at the hierarchy chart you’ve shared over the last few days. I just always thought the posts page was considered an archive, and that archive.php was the default template for that page (unless of course there was no such template created). But now I understand that archive.php would be the default to display a list of custom post type posts in the absence of a more specific template created for that specific custom post type. So a CPT called “news” would use archive.php if there was no file called archive-news.php, and index.php if neither of those files existed. Thank you for the clarification.

The behavior does seem kind of inconsistent if you’re thinking of posts as just another “custom” post type, but I think that (probably for backward compatibility reasons) WordPress sees the built-in post post type as something different and special, and treats them differently. Unfortunately. :confused:

There is definitely a distinction in my mind between CPTs and default posts. But I have always thought of any list of posts as an “Archive” in WordPress parlance, but that a default post “archive” was also different from a CPT archive. I guess in early days the posts would more often than not be on the home page, but it seems odd to continue calling that particular template “home” when it might not have anything to do with the Home page. But thank you for clearing that up for me!

@Aaron-idf Did you happen to use custom fields and controller for this as well? I had a similar issue to you, but now that I have the template working, I’m having an issue with custom fields. I’m wondering if there is anything special about how to set up custom fields to be used on the posts page? I have a home.blade.php and a Home.php for the controller. In the controller, I can pass some test data but custom fields aren’t working the way they do on my other pages.

I imagine it has something to do with the fact that the “Posts Page” is treated as special and it doesn’t have the same page template-based association as other pages, however based on the template hierarchy it seems the home.php setup would be the place for controller/blade setup, and in WP I can manage the fields in the page I have assigned as the “Posts Page”. Maybe it has to do with how I assigned the “Posts Page” in WP?

Home.php controller

// This works
public function some_field()
    return (object) array(
        'testing' => 'Testing',

// This doesn't
public function hero()
    return (object) array(
        'background_image' => get_field('hero_reg_background_image'),
        'heading' => get_field('hero_reg_heading'),
        'text_alignment' => get_field('hero_reg_text_alignment'),

Assigned as “Posts Page” with my custom fields listed/available to edit

Any idea of how to get this working?

You’re calling get_field without specifying an ID, which means that it will attempt to “guess” the ID based on the context. When the context is within the loop on a single page/post/etc this works as you’re expecting it to work. This has to do with how WordPress thinks about archives and pages; nothing to do with the way Controllers or blades function.

In the context in which you’re calling get_field here, the ID for the page you want to use (i.e. the page you’ve set as the Posts page) is not available in that context (i.e. if you echo get_the_ID() it won’t give you the ID of your Posts page). Instead, the loop contains a collection of posts because you’re on an archive-type page, so get_field is likely trying to use the first ID in that list, but those posts don’t have the fields you’re querying so it returns nothing.

You need to specify the ID of the page you want when calling get_field, which in this case you can find by calling get_option('page_for_posts').

1 Like

Saved once again. Passing in the ID worked. Thank you very much for the answer as well as the explanation. I’d been using get_field()all this time without ever passing in anything but the field name and didn’t even think about how this was working or the optional parameter to pass the ID :disappointed: . Thanks again for the help.

This topic was automatically closed after 42 days. New replies are no longer allowed.