Roots Discourse

New to Blade: Issue with Array Map and CPT

#1

We have a custom post type called our_models to display models from a series of a product.

We’re still learning and trying to wrap our heads around Blade Controllers, etc.

So we have a controllers setup to work with ACF in App.php:

public function models()
{
    return array_map(function($model) {
        return [
            'title' => $model['model_type_name'] ?? null,
            'description' => $model['short_description'] ?? null,
            'image' => $model['image'],
            'aluminum' => $model['aluminum_colors'] ?? null,
            'poly' => $model['poly_roof_colors'] ?? null,
            'heat' => $model['heat_poly_roof_colors'] ?? null,
            'wind' => $model['wind_pressure'] ?? null,
            'snow' => $model['snow_load'] ?? null,
        ];
    }, get_field('model_series') ?? []);
}

This works great for individual posts under our post type without error and displays all the data just fine but when we’re visiting the archive for for our_models, we receive the following PHP error:

Warning: array_map(): Expected parameter 2 to be an array, bool given in /srv/www/website.com/current/web/app/themes/website/app/Controllers/App.php on line 89

which focuses on this line:

}, get_field('model_series') ?? []);

Adding a 2nd parameter like, 'options' or 'dog' or anything else, removes the PHP error but then also removes the display of all the ACF field data on each post in the custom post type single pages.

We’re trying to understand what we’re doing wrong here as none of the archive pages: 'archive-our_models.php', 'content-our_models' or similar files that are used in developing the archive page are at all referencing the controller, as far as we know or can tell.

0 Likes

#2

A controller applies to the entire endpoint it sits on top of. In this case, the controller for an archive sits on the archive endpoint.

get_field() accepts two arguments; the field name, and the post ID (or options if it’s a site option). If you call it without the second argument, it attempts to get the ID of the current post. It can only do this if there is a current post.

When you call get_field() without an ID argument on an archive controller, there is no “current post” for it to get, because there is no post ID associated with an archive endpoint. That means it returns false (or null, or some other error return value), which is obviously not the array that array_map() expects.

What you are doing wrong is calling get_field() on an archive, instead of calling it on each post that is displayed on the archive.

One way to do this is to generate an array in your archive controller for each post on the current archive page, and then do all the logic you need to on each post at that time. I’ve posted an example of that technique here: The right way to run multiple WordPress loops

0 Likes

#3

Thanks for pointing me in the right direction. We’re still having trouble wrapping this up. Apologies for any ignorance.

We have this in our filters.php file:

/** @var $wp_query \WP_Query */
 global $wp_query;

 $model['our_models'] = false;
 if ($wp_query->post_count > 0) {
     $model['our_models'] = array_map(function ($post) {
         /** @var $post \WP_Post */
         return array(
             'title' => $model['model_type_name'],
             'description' => $model['short_description'],
             'image' => $model['image'],
             'aluminum' => $model['aluminum_colors'],
             'poly' => $model['poly_roof_colors'],
             'heat' => $model['heat_poly_roof_colors'],
             'wind' => $model['wind_pressure'],
             'snow' => $model['snow_load'],
         );
     }, $wp_query->posts);
 }

Our archive-our_models.blade.php file:

@extends('layouts.archive')

@section('content')
    @if($posts)
        <ul>
            @foreach($posts as $post)
                @include('partials.content-'.get_post_type(), $post)
            @endforeach
        </ul>
    @endif
@endsection

Our content-our_models.blade.php file:

<li>
    <div>
        <h3>{{$title}}</h3>
    </div>
</li>

Currently just trying to return one field at this time. No more PHP errors but also nothing being displayed on the archive page.

Deeply appreciate any further help and guidance.

0 Likes

#4

It’s not necessary to use filters.php if you’d prefer to use Controller (as you seemed to be initially). As I said in my linked post:

I’m using Sage’s filters for my controller instead of soberwp/controller , but the principle is more or less the same

If you do want to use filters instead of Controller, then you need to wrap your logic in the appropriate filter do get your data to your template. See the appropriate section of the documentation.

If you want to keep using Controller, then just put that logic you put in filters.php in your controller, i.e.:

public function selectedposts() {
   // return array
}

Regardless of your choice for how to return your data, the code you posted won’t do anything: You pass $post to the anonymous function you pass to array_map(), but then the $post variable is never used within that function: You try and use a variable called $model which isn’t set in that scope. You need to actually get your meta fields from the $post.

0 Likes

#5

Thank you for your help! Still battling with getting the data to pass through. Does anyone have any specific examples used with ACF? That would be really helpful.

0 Likes

#6

There’s nothing special about ACF fields. They’re just fields on a post object. Here’s a very minimal example that should work:

// this is the controller
// Archive.php
public function SomePosts()
{
 if ($wp_query->post_count > 0) {
     return array_map(function ($post) {
         return [ 
            'field_one' => get_field('an_acf_field', $post->ID) ,
            'field_two' => get_field('another_acf_field', $post->ID) ,
         ];
     }, $wp_query->posts);
 }
 return false;
}
// this is the blade
// archive.blade.php

// it is import here to **not** use $posts because that would try to
// overwrite the $posts global that WordPress archives use, and that
// is kind of asking for trouble; hence $some_posts.

@if($some_posts)
   // it is important here to **not** use $post because that would try
   // and overwrite the global $post that WordPress uses, and that kind
   // is asking for trouble, hence $this_post.
   @foreach($some_posts as $this_post)
      <h1>{{ $this_post['field_one'] }}</h1>
      <p>{{ $this_post['field_two'] }}</p>
   @endforeach
@endif
0 Likes