Hi all,
Something odd is happening on my archive page for a post type. I have a post type called community-project
, an archive template archive-community-project.blade.php
and in app/controllers
I have a controller for this ArchiveCommunityProject.php
I’m using Controller
to enable the ACF fields to be automatically available to the view via:
<?php
namespace App\Controllers;
use Sober\Controller\Controller;
class ArchiveCommunityProject extends Controller
{
protected $acf = true;
}
I have 2 Community Project posts with different custom field values for various ACF fields, however when I access these on the archive page, they are showing the same value! I’m only getting the value of the first post. The code on archive-community-project.php
looks like this:
@while (have_posts()) @php(the_post())
@php(var_dump($nomination_name))
@endwhile
nomination_name
is the name of my ACF field and post A and post B definitely have different values - so why is the archive showing the same value for both?
By the way, I’m using "soberwp/controller": "^2.0.0"
Many thanks
Kevin
Further info… just using @php(var_dump(get_field('nomination_name')))
on the template works and I get the different values
For reference: The Controller ACF integration implementation.
Archive pages behave a little strangely with some WordPress functions because functions that refer to individual posts (i.e. get_the_ID()
) will return a value for the first post in the archive when called outside of an explicit loop.
Controllers collect all the data at the “top level” which means they aren’t re-run inside the loop on your page (the @while (have_posts() ...
bit). That means that any functions you call at the controller level that refer to single posts will return the value for the first post in the loop. I believe that’s what’s happening here. If you look at the implementation I linked to above, Controller is just calling get_fields()
which assumes you’re looking to pull fields from whatever it gets when it runs get_the_ID()
—so in this case, that would be the first post in your archive loop.
In other words, you seem to be assuming that this loop:
@while (have_posts()) @php(the_post())
@php(var_dump($nomination_name))
@endwhile
will re-evaluate $nomination_name
each time the loop is run. It will not: That variable is set by the controller when it passes data to the Blade, and it doesn’t change as you run that loop. That’s why when you run @php(var_dump(get_field('nomination_name')))
you get the correct values: You’re querying each post on each iteration of the loop.
There are a number of ways you could address this, depending on what you want to do and how you want to do it: You could loop through all posts in the controller and pull out/add the data you want before passing that data on to the archive. You could just add a little logic in your Blade and simply include get_field('nomination_name')
in each iteration of your loop. IIRC, meta fields on posts are now directly accessible from the $post
object, so you should be able to just use $post->nomination_name
in your Blade loop. Or you could do something completely different, depending on your needs.
2 Likes
@alwaysblank yes you’re right, I kind of assumed that you’d get a controller for each iteration of the loop I guess in an object orientated way and that each would have it’s own values. Obviously not! That being the case I think the simplest route for this will be just to use some logic in my Blade! Thanks for the swift reply.
Kevin
1 Like
No problem! For this situation a little bit of logic in the template is probably the easiest solution, I agree.
On some other projects where I had slightly more complex needs, I started just using array_map()
to modify the existing loop, and then passing that directly to the Blade as an array that contained only the things I needed:
// app/controllers/Archive.php
public function archiveItems()
{
global $posts;
return array_map(function ($post) {
return [
'title' => $post->post_title,
'subtitle' => get_field('subtitle', $post->ID),
'link' => get_permalink($post),
]
}, $posts);
}
// resources/views/archive.blade.php
@foreach($archive_items as $item)
<h1>{{$item['title']}}</h1>
<p class="subtitle">{{$item['subtitle']}}</p>
<a href="{{$item['link']}}">Read More</a>
@endforeach
Since the controller pulls from the $posts
global, the array will always contain the correct posts (even when paginating).
1 Like
@alwaysblank That’s interesting! I will definitely have to have a play with that when I’m not quite so up against it time wise as I am with this project.