ACF variables in blade template

It is awesome, that’s what I love about React.js, it’s funny, where I work, we run an MVC environment but it’s such a mess, with php logic and everything in-between mashed into the templates haha so it’s good to understand the proper way of doing it :slight_smile:

This is what I like the most. I can shove all the ugly logic I need into a controller and keep my template clean with {{ $resultOfUglyLogicOhGodDontLookAtIt }}

4 Likes

Only thing is my directory structure is getting pretty crazy. More and more structure = more and more directories :smile:

Flipping between assets, controllers, views and whatever partials inside sub-directories of all of those.

Using object syntax like this is very clever and I like it a lot! I realize it’s mostly aesthetic preference on my part, but for some reason $container->field always looks so much nicer to me than $container['field'].

2 Likes

I’m just getting started here, but this has really given me new hope for Wordpress. I always got frustrated that my template files would get so messy when you started adding logic for ACF fields and so on.

I have created this Related Posts snippet. It utilizes an ACF Bidirectional Post Relationship plugin. The code is as follows:

<?php global $post; ?>
<?php $related_posts = get_field( 'related_posts' ); ?>
<?php if ( $related_posts ): ?>
	<?php foreach ( $related_posts as $p ): ?>
    {{the_post_thumbnail( 'thumbnail', array( 'class' => 'card-img-top img-fluid' ) )}}
	{{get_permalink( $p )}} 
    {{get_the_title( $p )}}
    
	<?php endforeach; ?>
  <?php wp_reset_postdata(); ?>
<?php endif; ?>

Ideally I’d like to remove as much as the logic from the template file. I’ve seen the examples above and I think I get it, but the global $post, The loop and wp_reset_postdata confuses me.

I can’t say this is the most elegant way of doing it but perhaps something like:

Controller

public function related()
{
    global $post;

    $data = [];

    $related_posts = get_field('related_posts');

    foreach ($related_posts as $p) {

        $this_post = (object) array(
            'thumbnail' => get_the_post_thumbnail($p, 'thumbnail', array('class' => 'card-img-top img-fluid')),
            'permalink' => get_the_permalink($p),
            'title' => get_the_title($p),
        );

        array_push($data, $this_post);
    }

    return $data;
}

View

@foreach ($related as $p)

    {{ $p->thumbnail }}
    {{ $p->permalink }}
    {{ $p->title }}

@endforeach

Totally untested and assumes that your returning your related post as the post ID not an object (by looking at what you posted up). It involves two loops (one in the controller and one in the view) but it keeps the view very tidy in my opinion.

5 Likes

This 100% for me :slight_smile:

1 Like

Been using ACF Fluent (with controller of course) and have been very pleased.

Also semi related and worth checking out is:

I use both in every project I work on now. They are wonderful and really bring ACF to the next level for me.

8 Likes

Thank you. It works. However, I don’t see what the $data variable is doing?

Each field within the post gets stored in the $this_post object within the foreach loop which is then added as a new property within the $data object.

It would be fairly easy to build in an acf helper class into Controller that speeds up the process of looping through fields and then outputting to an object notation. All you would need to use in the view then would be @foreach (for repeater fields). Basic fields could be flattened using the key as the variable name.

If you’re using acf in a standard way, it could all be automated to be honest. I’m going to look into building a prototype module over the next few days should time allow.

3 Likes

Been working on something like this. All values returned to the view are returned in object notation should that be required.

In a Controller Class;

<?php

namespace App\Controllers;

use Sober\Controller\Controller;
use Sober\Controller\Module\Acf;

class Single extends Controller
{
    // all returned values from Acf, even if multidimensional arrays are in object notation 

    public function acf()
    {
        return Acf::get();
        // gets all fields
        // use $acf->repeater in view
        // use $acf->text_field in view
    }

    public function text()
    {
        return Acf::get('text_field');
        // gets 1 field and returns flattened
        // use $text in view
    }

    public function combo()
    {
        return Acf::get(['repeater_field', 'text_field']);
        // gets 2 fields, and returns in object notation using advanced custom fields key values
        // use $combo->text_field in view
        // use $combo->repeater_field in view
    }
}
4 Likes

Just did more work on automating the acf fields from Controller to view.

The returned variables are based on acfs key values. You can then override any values by using the same key value in camel case in your Controller for more control.

<?php

namespace App\Controllers;

use Sober\Controller\Controller;

class Single extends Controller
{
    protected $acf = true;

    public function textField()
    {
        return 'Override automated field';
    }
}

@debug

$site_name » string
$post » object
$text_field » string
$repeater_field » array[2]

Multilevel dimensional arrays are returned in object notation based on your acf field keys.

Repeater field example below;

<h1>Repeater Field</h1>
<ul>
  @foreach($repeater_field as $item)
    <li>{{ $item->repeater_field_item }}</li>
  @endforeach
</ul>
8 Likes

Hey all,

I’m trying to get ACF fields working and an encountering some issues.

I’m running the most recent Sage beta, and I can not figure out how to get the fields exposed as simple variables as I see everyone doing here.

Note that my image field is just returning the URL string.

Controller app/controllers/App.php:

namespace App;

use Sober\Controller\Controller;

class App extends Controller
{
    public function heroImg()
    {
        $image = get_field('hero_image');
        return $image;
    }
}

working views/partials/content-page.blade.php

@if (App::heroImg())
  <div class="bg-img" style="background-image: url('{!! App::heroImg() !!}')">
@endif

not working:

@if ($heroImg)
  <div class="bg-img" style="background-image: url('{{ $heroImg }}')">
@endif

I feel like the latter should be working based on what I see in this thread. Did I miss a step? Thank you!

I just figured this out, I missed an important bit in https://github.com/soberwp/controller/blob/master/README.md

Important: The method name is converted to snake case and becomes the variable name in the Blade view.

heroImg() becomes $hero_img and now all works fine.

Hope this helps anyone else with the same issue!

5 Likes

This looks nice! Would you mind sharing the Acf class too?

@threehz Been there, done that. It is one of the most confusing things about Controller.

I wished there was a simpler way of defining data without going through a separate function for each variable.

1 Like

Did you read the whole thread? You absolutely don’t need a separate function for each variable. Just build an array/object of your data to return within your method.

1 Like

This is clever. I feel like this is how I will do it moving forward.

1 Like

@nathobson

Did you read the whole thread? You absolutely don’t need a separate function for each variable. Just build an array/object of your data to return within your method.

Yes. My comment “been there, done that” was about snake casing of the method names BTW.

Whether you package all the variables into an array, object, or even a collection, wasn’t my point. On the Blade side, you have to do $object->related and $object->unrelated kind of thing or define separate functions for the unrelated.

Either way, when does it stop being a controller and actually be a transformer, or both. Just confusing, is all I am saying.