Sage 9 - Passing ACF data via Blade not working

Hello!

I’m working on my first project with sage 9 and when I try to pass ACF data to my custom template using the filter, it is not working. I have to say that I followed the exact same steps from the book and the doc.

Here’s my code
in app/filters.php

add_filter('sage/template/home/data', function (array $data) {
    $data['banner_title'] = get_field('banner_title');
    return $data;
});

PS: Even tried passing data to all pages class using /page/ instead, no luck.

in template-home.blade.php
<h1 class="banner-title">{{ $banner_title }}</h1>
or even tried:
<h1 class="banner-title"><?= $banner_title; ?></h1>

I prefer the filter instead of controller.
FYI, the_field('banner_title') inside the template directly works perfectly fine.

Is there something i’m missing here?

Thank you for the support!

1 Like

There are a couple things you can try here to figure out the source of the problem. The basic idea is to try different tests that each have limited variables so you can track down which of those variables isn’t working. I would try:

  1. Pass a string to banner_title instead of the result of get_field(). i.e., change to something like $data['banner_title'] = 'testing'; and see if {{ $banner_title }} returns testing'in your template. If it doesn’t, then your filter is not set up correctly, or something else is wrong with your theme’s configuration.
  2. Pass an ID to get_field() instead of letting it assume what your ID might be. It attempts to guess what page you’re accessing, but depending on the context this doesn’t always work (I make a habit of always manually passing an ID to get_field() so that I always know where it’s getting that value from.) In this case, pass it the ID of your home page, i.e. if the ID is 2, then change to this: $data['banner_title'] = get_field('banner_title', 2); If you don’t see the correct value in your template after doing this, then there’s probably an error in how you’ve set up ACF; maybe you’re using the wrong key name, or something (I usually make a habit of using the unique field IDs ACF generates instead of the key names to help make things like this easier to debug).

Thank you for the suggestions!

Alright after new tests:

add_filter('sage/template/home/data', function (array $data) {
    $data['banner_title'] = 'test';
    // $data['banner_title'] = get_field('banner_title', 6);
    var_dump($data['banner_title']);
    return $data;
});

The var_dump does show the string + ACF in the template, so I can tell that the filter works, but the blade or php echo doesn’t show anything.

For the record, I did try the global data (example shown in the book) and it doesn’t work either.

I also tried with the ID for get_field, no success.

I did not change any theme config, so i’m not sure where to check about the filter not doing it’s job or what’s wrong.

Anything else I should look out for?

PS: I have a fresh install from this week

Thank you!

I’m having the exact same problem. Fresh install of Sage 9 but can’t even seem to pass a string through…

FYI, I gave up and ended up using controller which work perfectly.

I’m just wondering why the copy paste from the book don’t work from fresh install :\

Okay! I did some digging into this, and it looks like what’s happening is that the version (currently: 9.0.0-beta.4) of soberwp/controller bundled with Sage wipes out anything you’ve put into $data through filters. If you’re not going to use Controller, then there’s an easy fix! Just remove Controller by deleting it from your composer.json, and running composer update. I’ve tested that process locally, and it works like a charm.

If you’re interested in a more in-depth examination of the problem, and how I tracked it down, read on…

By sticking a var_dump() (so elegant) in Sage’s template processing loop, I can see what it’s thinking about:

// app/filters.php

/**
 * Render page using Blade
 */
add_filter('template_include', function ($template) {
    $data = collect(get_body_class())->reduce(function ($data, $class) use ($template) {
        var_dump($data);  // Show me that hot, hot $data!
        return apply_filters("sage/template/{$class}/data", $data, $template);
    }, []);
    if ($template) {
        echo template($template, $data);
        return get_stylesheet_directory().'/index.php';
    }
    return $template;
}, PHP_INT_MAX);

// Here's what I'm trying to add:
add_filter('sage/template/blog/data', function (array $data, $template) {
    $data['augustus'] = 'ceasar';
    return $data;
}, 10, 2);

On the front end, what I see is the following:

array(0) { }
array(0) { }
array(1) { ["augustus"]=> string(6) "ceasar" }
array(1) { ["augustus"]=> string(6) "ceasar" }
array(1) { ["augustus"]=> string(6) "ceasar" }
array(1) { ["augustus"]=> string(6) "ceasar" }
array(1) { ["site_name"]=> string(7) "testing" } // UH OH
array(1) { ["site_name"]=> string(7) "testing" }
array(1) { ["site_name"]=> string(7) "testing" } 

So where’s that string coming from? From the App controller:

// app/controllers/app.php

class App extends Controller
{
    public function siteName()
    {
        return get_bloginfo('name');
    }
}

So why is this happening? This line right here, in the code for Controller:

// vendor/soberwp/controller/controller.php

add_filter('sage/template/' . $template . '-data/data', function ($data) use ($loader, $class) {
     $controller = new $class();
     $controller->__setup();
     return array_merge(
        $loader->getAppData(), 
        $loader->getPostData(), 
        $controller->__setTreeData($data), 
        $controller->__getData()
        // This should be merging $data as well!
     );
});

The point of all this isn’t to call out @withjacoby, who is doing an excellent job (and has already fixed this issue in more up-to-date versions of Controller)—the point is to illustrate how you might go about tracking down a problem like this.

If you want to use both Controller and pass data with filters, you should be able to just manually apply this pull request: https://github.com/roots/sage/pull/2025

4 Likes

Thanks @alwaysblank

Yeah, I would really recommend moving from beta.4 to 2.0.x. A lot of code has changed since beta.4.

Just as a further explanation, the issue in beta.4 actually lies in the Controller.

$controller->__setTreeData($data) is passing the data on, but then it was clearing the $data should the user not want existing $data. It then returns a blank array to be merged in.

public function __setTreeData($data)
{
    if (!$this->class->implementsInterface('\Sober\Controller\Module\Tree') && $this->tree === false) {
        $data = [];
    }
    return $data;
}
1 Like

Thank you guys for the follow up.

I’ll update the controller version and try it out.

Maybe @ben should update it too in the sage repo for everyone.

Thanks!

I would like to release 2.0.1 before @ben updates the Sage to the new version.

Is there any update on when this change will be merged into a new Sage version?

No. In the meantime, you’re welcome to install/update any dependencies that you’d like.

Duly noted; I’m a bit new to the way Sage structures things, but I’ll read on and try.

There is already a pull request for updating Controller in Sage, just reference the three files changed in https://github.com/roots/sage/pull/2025

Coming back to this; I have merged all of the changes in the pull request. I cloned a new copy of Sage 9.0.1, and did the following:

  • Rename app/controllers/app.php and front-page.php to App.php and FrontPage.php
  • Change the namespace in both of the above files to be namespace App\Controllers;
  • Update composer.json to have "soberwp/controller": "2.0.1" and run composer require soberwp/controller:2.0.1 to update.

However, after making these changes, there is still an error about missing data when creating a filter and attempting to call the data in the template.

This is modeled after the guide at Sage 9.x: Blade Templates | Roots Documentation and the eBook.

In app/filters.php:

/**
 * Add data references for page template.
 */
add_filter('sage/template/page/data', function (array $data) {
    $data['some_data'] = "This is my data";
    return $data;
});

In resources/views/page.blade.php:

@extends('layouts.app')

@section('content')
  @while(have_posts()) @php the_post() @endphp
    @include('partials.page-header')
    @include('partials.content-page')
    <p>{{ $some_data }}</p>
  @endwhile
@endsection

On the front end, I created a page titled “about-us” and it throws an error stating that the variable some_data is undefined. As noted by @alwaysblank, we can see what is going on by adding some var_dump() calls in filters.php in the add_filter call:

/**
 * Render page using Blade
 */
add_filter('template_include', function ($template) {
    var_dump($template);  // Verify the Template being used
    $data = collect(get_body_class())->reduce(function ($data, $class) use ($template) {
        var_dump($class);  // Verify the classes being computed
        return apply_filters("sage/template/{$class}/data", $data, $template);
    }, []);
    var_dump($data);  // Verify the data that has been compiled
    if ($template) {
        echo template($template, $data);
        return get_stylesheet_directory().'/index.php';
    }
    return $template;
}, PHP_INT_MAX);

Our output shows the template is correct:

/var/www/html/wp-content/themes/wp-sage-theme/app/filters.php:68:string '/var/www/html/wp-content/themes/wp-sage-theme/resources/views/page.blade.php' (length=85)

Here is the list of classes being applied:

/var/www/html/wp-content/themes/wp-sage-theme/app/filters.php:70:string 'page-template-default' (length=21)
/var/www/html/wp-content/themes/wp-sage-theme/app/filters.php:70:string 'page' (length=4)
/var/www/html/wp-content/themes/wp-sage-theme/app/filters.php:70:string 'page-id-14' (length=10)
/var/www/html/wp-content/themes/wp-sage-theme/app/filters.php:70:string 'logged-in' (length=9)
/var/www/html/wp-content/themes/wp-sage-theme/app/filters.php:70:string 'admin-bar' (length=9)
/var/www/html/wp-content/themes/wp-sage-theme/app/filters.php:70:string 'no-customize-support' (length=20)
/var/www/html/wp-content/themes/wp-sage-theme/app/filters.php:70:string 'about-us' (length=8)
/var/www/html/wp-content/themes/wp-sage-theme/app/filters.php:70:string 'app-data' (length=8)
/var/www/html/wp-content/themes/wp-sage-theme/app/filters.php:70:string 'index-data' (length=10)
/var/www/html/wp-content/themes/wp-sage-theme/app/filters.php:70:string 'singular-data' (length=13)
/var/www/html/wp-content/themes/wp-sage-theme/app/filters.php:70:string 'page-data' (length=9)
/var/www/html/wp-content/themes/wp-sage-theme/app/filters.php:70:string 'page-14-data' (length=12)
/var/www/html/wp-content/themes/wp-sage-theme/app/filters.php:70:string 'page-about-us-data' (length=18)

And the end resulting data:

/var/www/html/wp-content/themes/wp-sage-theme/app/filters.php:73:
array (size=5)
  'post' => 
    object(WP_Post)[1483]
      public 'ID' => int 14
      public 'post_author' => string '1' (length=1)
      public 'post_date' => string '2018-06-21 14:04:48' (length=19)
      public 'post_date_gmt' => string '2018-06-22 00:04:48' (length=19)
      public 'post_content' => string 'Here's where you can learn more about US!  And how amazingly AWESOME we are!' (length=77)
      public 'post_title' => string 'About Us' (length=8)
      public 'post_excerpt' => string '' (length=0)
      public 'post_status' => string 'publish' (length=7)
      public 'comment_status' => string 'closed' (length=6)
      public 'ping_status' => string 'closed' (length=6)
      public 'post_password' => string '' (length=0)
      public 'post_name' => string 'about-us' (length=8)
      public 'to_ping' => string '' (length=0)
      public 'pinged' => string '' (length=0)
      public 'post_modified' => string '2018-06-21 14:04:48' (length=19)
      public 'post_modified_gmt' => string '2018-06-22 00:04:48' (length=19)
      public 'post_content_filtered' => string '' (length=0)
      public 'post_parent' => int 0
      public 'guid' => string 'http://192.168.10.10/?page_id=14' (length=32)
      public 'menu_order' => int 0
      public 'post_type' => string 'page' (length=4)
      public 'post_mime_type' => string '' (length=0)
      public 'comment_count' => string '0' (length=1)
      public 'filter' => string 'raw' (length=3)
  'site_name' => string 'SITENAME' (length=8)
  '__debugger' => 
    array (size=1)
      0 => 
        object(stdClass)[1624]
          public 'class' => string 'App' (length=3)
          public 'tree' => boolean false
          public 'methods' => 
            array (size=1)
              ...
          public 'data' => 
            array (size=2)
              ...
  '__app' => 
    array (size=3)
      'post' => 
        object(WP_Post)[1483]
          public 'ID' => int 14
          public 'post_author' => string '1' (length=1)
          public 'post_date' => string '2018-06-21 14:04:48' (length=19)
          public 'post_date_gmt' => string '2018-06-22 00:04:48' (length=19)
          public 'post_content' => string 'Here's where you can learn more about US!  And how amazingly AWESOME we are!' (length=77)
          public 'post_title' => string 'About Us' (length=8)
          public 'post_excerpt' => string '' (length=0)
          public 'post_status' => string 'publish' (length=7)
          public 'comment_status' => string 'closed' (length=6)
          public 'ping_status' => string 'closed' (length=6)
          public 'post_password' => string '' (length=0)
          public 'post_name' => string 'about-us' (length=8)
          public 'to_ping' => string '' (length=0)
          public 'pinged' => string '' (length=0)
          public 'post_modified' => string '2018-06-21 14:04:48' (length=19)
          public 'post_modified_gmt' => string '2018-06-22 00:04:48' (length=19)
          public 'post_content_filtered' => string '' (length=0)
          public 'post_parent' => int 0
          public 'guid' => string 'http://192.168.10.10/?page_id=14' (length=32)
          public 'menu_order' => int 0
          public 'post_type' => string 'page' (length=4)
          public 'post_mime_type' => string '' (length=0)
          public 'comment_count' => string '0' (length=1)
          public 'filter' => string 'raw' (length=3)
      'site_name' => string 'SITENAME' (length=8)
      '__debugger' => 
        array (size=1)
          0 => 
            object(stdClass)[1624]
              ...
  '__store' => 
    array (size=5)
      'some_data' => string 'This is my data' (length=15)
      '__debugger' => 
        array (size=1)
          0 => 
            object(stdClass)[1624]
              ...
      'post' => 
        object(WP_Post)[1483]
          public 'ID' => int 14
          public 'post_author' => string '1' (length=1)
          public 'post_date' => string '2018-06-21 14:04:48' (length=19)
          public 'post_date_gmt' => string '2018-06-22 00:04:48' (length=19)
          public 'post_content' => string 'Here's where you can learn more about US!  And how amazingly AWESOME we are!' (length=77)
          public 'post_title' => string 'About Us' (length=8)
          public 'post_excerpt' => string '' (length=0)
          public 'post_status' => string 'publish' (length=7)
          public 'comment_status' => string 'closed' (length=6)
          public 'ping_status' => string 'closed' (length=6)
          public 'post_password' => string '' (length=0)
          public 'post_name' => string 'about-us' (length=8)
          public 'to_ping' => string '' (length=0)
          public 'pinged' => string '' (length=0)
          public 'post_modified' => string '2018-06-21 14:04:48' (length=19)
          public 'post_modified_gmt' => string '2018-06-22 00:04:48' (length=19)
          public 'post_content_filtered' => string '' (length=0)
          public 'post_parent' => int 0
          public 'guid' => string 'http://192.168.10.10/?page_id=14' (length=32)
          public 'menu_order' => int 0
          public 'post_type' => string 'page' (length=4)
          public 'post_mime_type' => string '' (length=0)
          public 'comment_count' => string '0' (length=1)
          public 'filter' => string 'raw' (length=3)
      'site_name' => string 'SITENAME' (length=8)
      '__app' => 
        array (size=3)
          'post' => 
            object(WP_Post)[1483]
              ...
          'site_name' => string 'SITENAME' (length=8)
          '__debugger' => 
            array (size=1)
              ...

Of particular note is this part:

'__store' => 
    array (size=5)
      'some_data' => string 'This is my data' (length=15)
      '__debugger' => 

This results in the following page:

So my question is, at this point, what am I missing? I understand that I can bypass this by just using the controllers directly to add content to templates via functions. My question is why the filters method is not currently functioning after following the steps to get up-to-date, and what I can do to resolve it so that it does.

It looks like Controller has been modified since the earlier posts in this thread, and has gone back to overriding data. See this GitHub issue:

That issue makes it look like currently there isn’t a way (without the described workaround) to get Controller and Sage’s native filters to work together. IMO they both fill the same niche, so either one of them should allow you to do what you’re looking to do.

Got it; it seems as Sage 9 moves forward, this continues not to be a “preferred” way of doing things as it has either become non-functional, or gets fixed and then becomes non-functional again. It may be good to either remove the filters method it from the documentation, or take out the part that causes the conflict to keep occurring.

What are the implications of removing Sober/Controller from Sage? Do Sage’s native filters just work as described in the documentation if you take out Sober/Controller? Is any other functionality lost?

The filters should work as described in the documentation if Controller is removed. They functioned correctly after removing Controller in the trivial tests I did today to evaluate your issue.

Sober/Controller is not part of Sage; it’s just a cool tool for it. Removing Controller will not alter the way that Sage functions; it will just remove the functionality that Controller adds. The base Sage theme includes a few example calls to Controller static functions in blades, which will error out if you remove it, but they’re only examples: They’re not unique core functionality.

Controller essentially provides a different interface to what Sage’s filters are doing: You could think of it as an alternative filter API.

Thank you for the additional clarification.

I’m a bit baffled when it is stated that Sober/Controller isn’t a part of Sage, when it is included in a base install (as noted in Controller’s own documentation at https://github.com/soberwp/controller). It is also part of the documentation for using Sage (https://roots.io/sage/docs/blade-templates/ and pp 38 & 39 of the eBook). There is no mention of Sober/Controller being optional in the online documentation; it is shown in a brief mention at https://roots.io/sage/docs/theme-configuration-and-setup/ which shows the controllers directory in the hierarchy, and again at https://roots.io/sage/docs/blade-templates/ where it is referenced for passing data to templates, then in the eBook where it is featured as “another method”. It may be good to clarify documentation for others who are starting up with Sage 9 for the first time, or to update the install process to make soberwp/controller optional. I’ll start an issue on the docs github page.

Regardless, is best practice for filters to just include all filter calls into app/controllers/filters.php? Or split them out into separate .php files and then reference those in the filter.php file as an include / import of some type?

AFAIK there’s no agreed-upon best practice. My advice is to just do what works for your project and makes the most sense to you. I’ve been using filters exclusively on my last few projects, and I split them out with one route per file. All those files I put in app/controllers along with a PHP file that loads them all (and that PHP file is then loaded in functions.php.

Got it, thank you for the information!